ai视频二期功能提交-编辑ai摘要

This commit is contained in:
sunli_tydic
2025-12-16 14:21:06 +08:00
parent ea6989cddc
commit 04e163b63e
6 changed files with 2606 additions and 2169 deletions

View File

@@ -0,0 +1,141 @@
import ajax from '@/utils/xajax.js'
const BASE_URL = process.env.NODE_ENV=='development'?'/aiVideo':'';
/**
* AI摘要-摘要课程详情
* @param {Object} data
* {
courseId: "COURSE_001"//课程id
}
*/
const getCourse = function(data) {
return ajax.postJson(BASE_URL+'/aiVideo/getCourse', data);
}
/**
* AI摘要-摘要详情
* @param {Object} data
* {
courseId: "COURSE_001"//课程id
}
*/
const selectVideoSummary = function(data) {
return ajax.postJson(BASE_URL+'/videoSummary/selectVideoSummary', data);
}
/**
* AI摘要-更新摘要详情
* @param {Object} data
* {
courseId:课程的id
summaryContent: 摘要内容
}
*/
const updateVideoSummary = function(data) {
return ajax.postJson(BASE_URL+'/videoSummary/updateVideoSummary', data);
}
/**
* AI摘要-根据视频id查询详情
* @param {Object} id 视频id
*/
const selectById = function(id) {
return ajax.postJson(BASE_URL+'/videoSummary/selectById/'+id);
}
/**
* AI摘要-下载课程摘要文本
* @param {Object} courseId 课程 的id
*/
const downloadSummaryTxt = function(courseId) {
let requestParam ={
url: BASE_URL+'/videoSummary/downloadSummaryTxt?courseId='+courseId,
timeout: 0, // 下载不设置超时
responseType: 'blob', // 表明返回服务器返回的数据类型
}
return ajax.get(requestParam);
}
/**
* AI摘要-重新生成课程摘要
* {
courseId: "COURSE_001"//课程id
}
*/
const retrySummaryTxt = function(data) {
return ajax.postJson(BASE_URL+'/videoSummary/retrySummaryTxt',data);
}
/**
* AI翻译-获取视频语种下拉框
* @param {Object} videoId 视频的id
*/
const getTextDropdown = function(videoId) {
return ajax.postJson(BASE_URL+'/subtitle/getTextDropdown',{videoId});
}
/**
* AI翻译-获取视频指定语种字幕
* @param {object} data
{
"videoId": "VIDEO_111",
"language": "zh-CN"
}
*/
const getTextDetail = function(data) {
return ajax.postJson(BASE_URL+'/subtitle/getTextDetail',data);
}
/**
* AI翻译-更新字幕
* @param {Object} data
* {
"videoId": "VIDEO_001",
"language": "zh-CN",
"vttContent": "dddd"
}
*/
const updateText = function(data) {
return ajax.postJson(BASE_URL+'/subtitle/updateText',data);
}
/**
* AI翻译-下载字幕
* @param {Object} params
{
videoId: 视频的id,
language: 语种
}
*/
const downloadText = function(studyId,contentId) {
return ajax.get(BASE_URL+'/subtitle/downloadText', params);
}
/**
* AI翻译-同步跟更新字幕
* @param {Object} data
{
"videoId": "VIDEO_010",
"language": "zh-CN"
}
* @returns
*/
const regenerate = function(data) {
return ajax.postJson(BASE_URL+'/subtitle/regenerate',data);
}
export default {
selectVideoSummary,
updateVideoSummary,
selectById,
retrySummaryTxt,
updateText,
downloadText,
getTextDetail,
regenerate,
getTextDropdown,
downloadSummaryTxt,
getCourse,
}

View File

@@ -463,7 +463,7 @@
<el-button type="text" @click="changeAIKey('aiAbstract')">
{{ aiSetting.aiAbstract === 1 ? '下架' : '上架' }}
</el-button>
<el-button v-show="false" type="text" >编辑</el-button>
<el-button v-show="isV2" type="text" @click="toAiAbstract">编辑</el-button>
</div>
</div>
@@ -490,7 +490,7 @@
<el-button type="text" @click="changeAIKey('aiTranslate')">
{{ aiSetting.aiTranslate === 1 ? '下架' : '上架' }}
</el-button>
<el-button v-show="false" type="text" >编辑</el-button>
<el-button v-show="isV2" type="text" @click="toAiTranslate">编辑</el-button>
</div>
</div>
@@ -657,6 +657,7 @@ export default {
aiAbstractTip: '一键提炼课程视频核心要点,助力学员课前高效掌握重点,快速筛选学习资源', // 提示信息
aiDraftTip: '分段展示视频内容并精准同步时间轴,实现视频进度与文稿双向定位,学习内容触手可及', //提示信息
aiTranslateTip: '智能转换视频字幕与语音为多语种,支持全球学员按需切换语言,打破学习边界', // 提示信息
isV2: true,
};
},
mounted() {
@@ -1297,7 +1298,23 @@ export default {
console.log('index', index, this.aiPermission);
}
})
},
toAiAbstract() {
this.$router.push({
path: '/iframe/course/aiAbstract',
query: {
id: this.aiSetting.id
}
})
},
toAiTranslate() {
this.$router.push({
path: '/iframe/course/aiTranslate',
query: {
id: this.aiSetting.id
}
})
},
}
};
</script>

View File

@@ -1,27 +1,32 @@
<template>
<div class="aiAbstract">
<div class="ai-left">
<div class="left-title">{{courseName}}</div>
<ul class="ai-list">
<li class="ai-item" v-for="(item, index) in videoList" @click="currentVideo = item" :class="{'active': currentVideo.id === item.id}" :key="index">
<div class="ai-item-title">{{item.name}}</div>
<div class="ai-left" v-if="sections.length > 0">
<div class="left-title">{{courseInfo.name}}</div>
<ul class="ai-list" >
<template v-for="c in chapterList">
<li class="ai-item" v-for="(item, index) in c.children" @click="handleSelectVideo(item, index+1)" :class="{'active': currentVideo.id === item.id}" :key="index">
<div class="ai-item-title">{{item.chapterName}}-{{'视频' + (index + 1)}}</div>
</li>
</template>
</ul>
</div>
<div class="ai-right">
<div class="right-title">
<h3>{{currentVideo.name}}</h3>
<h3>{{videoName}}</h3>
<div>
<el-button type="primary" @click="status = 1">下架本课程AI摘要</el-button>
<el-button type="primary" @click="handleSummaryStatus">{{courseInfo.aiAbstract == 1 ? '下架' : '上架'}}本课程AI摘要</el-button>
</div>
</div>
<div class="ai-content">
<div class="videoBox">
<videoPlayer :src="testUrl" style="height: auto;"> </videoPlayer>
<videoPlayer
:src="blobUrl"
:blobId="blobId"
style="height: auto;"> </videoPlayer>
<div class="video-content">
<h4>视频摘要</h4>
<p>
{{currentVideo.aiAbstract}}
{{videoSummary}}
</p>
</div>
</div>
@@ -29,17 +34,18 @@
<div class="opera-title">
<h4>课程摘要</h4>
<div class="opera-btn">
<el-button type="primary" plain round size="mini" @click="status = 2">重新生成</el-button>
<el-button type="primary" plain round size="mini" @click="status = 4">编辑</el-button>
<el-button plain round size="mini" @click="status = 3">取消</el-button>
<el-button v-if="type == 1" type="primary" plain round size="mini" @click="retrySummaryTxt">重新生成</el-button>
<el-button v-if="type == 1" type="primary" plain round size="mini" @click="type = 4">编辑</el-button>
<el-button v-if="type == 4" plain round size="mini" @click="type = 1">取消</el-button>
<el-button v-if="type == 4" type="primary" plain round size="mini" @click="updateSummary">确认</el-button>
</div>
</div>
<div class="opera-content" v-show="status != 4">
<span v-show="status == 1">{{ aiAbstract }}</span>
<p v-show="status == 2" style="color: rgba(207, 207, 207, 1);text-align: center;margin-top: 48%;">AI 摘要重新生成中过程可能耗时较长<br>无需在此等待哦</p>
<img v-show="status == 3" src="@/assets/images/course/generationFailed.png" alt="" width="150" height="159" style="display: flex;margin: 35% auto 0 auto;">
<div class="opera-content" v-show="type != 4">
<span v-show="type == 1">{{ aiAbstract }}</span>
<p v-show="type == 2" style="color: rgba(207, 207, 207, 1);text-align: center;margin-top: 48%;">AI 摘要重新生成中过程可能耗时较长<br>无需在此等待哦</p>
<img v-show="type == 3" src="@/assets/images/course/generationFailed.png" alt="" width="150" height="159" style="display: flex;margin: 35% auto 0 auto;">
</div>
<el-input v-show="status == 4"
<el-input v-show="type == 4"
type="textarea"
placeholder="请输入内容"
autosize
@@ -52,7 +58,13 @@
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import videoPlayer from "@/components/VideoPlayer/index.vue";
import apiStudy from "@/api/modules/courseStudy.js";
import cookies from "vue-cookies";
import apiAiVideo from "@/api/modules/courseAiVideo.js";
import apiCourse from '@/api/modules/course.js';
import { encrypt } from "@/utils/jsencrypt.js";
export default {
name: 'aiAbstract',
// ai播放器相关
@@ -61,39 +73,201 @@ export default {
},
data() {
return {
courseName: '企业经营法则--课程单元',
videoList: [
{
id: 1,
name: '1. 开源节流1',
aiAbstract: '人工智能AI是让计算机模拟人类智能的技术核心包括机器学习、深度学习等。主要分为弱 AI专注特定任务和强 AI通用智能两类。应用涵盖医疗诊断、自动驾驶、语音助手等多个领域。它通过数据学习模式实现预测和适应能力正在改变生活方式和工作方式。未来发展需平衡创新与伦理考量确保对人类社会有益。'
},
{
id: 2,
name: '2. 企业经营法则总述',
aiAbstract: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
{
id: 3,
name: '3. 企业经营法则总述',
aiAbstract: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
{
id: 4,
name: '4. 企业经营法则总述',
aiAbstract: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
],
testUrl: 'https://vjs.zencdn.net/v/oceans.mp4',
chapterList: [],
videoName: '',
currentVideo: {},
aiAbstract: '人工智能AI是让计算机模拟人类智能的技术核心包括机器学习、深度学习等。主要分为弱 AI专注特定任务和强 AI通用智能两类。应用涵盖医疗诊断、自动驾驶、语音助手等多个领域。它通过数据学习模式实现预测和适应能力正在改变生活方式和工作方式。未来发展需平衡创新与伦理考量确保对人类社会有益。',
status: '1', // 1: 正常 2: 生成中 3: 错误 4: 编辑中
aiAbstract: '',
type: '1', // 1: 正常 2: 生成中 3: 错误 4: 编辑中
courseId: '',
courseInfo: {},
sections: [],
blobId: '',
blobUrl: '',
videoSummary: '',
}
},
mounted() {
this.currentVideo = this.videoList[0];
created() {
this.courseId = this.$route.query.id;
console.log(this.courseId);
this.getCourseInfo();
this.getCourseSummary();
},
methods: {}
mounted() {
},
methods: {
...mapMutations({
SET_selectableLang: 'video/SET_selectableLang',
SET_courseInfo: 'video/SET_courseInfo',
}),
// 上下架状态
handleSummaryStatus() {
apiCourse.benchAiSet({courseList:[{id: this.courseId, aiAbstract: this.courseInfo.aiAbstract == 1 ? 0 : 1}]}).then(res => {
if(res.status === 200){
this.$message.success(this.courseInfo.aiAbstract == 1 ? '下架成功!' : '上架成功!');
this.getCourseInfo();
}else{
this.$message.error(this.courseInfo.aiAbstract == 1 ? '下架失败!' : '上架失败!');
}
})
},
// 下载摘要 - 不需要
downloadSummary() {
apiAiVideo.downloadSummaryTxt(this.courseId)
.then((rs) => {
console.log('下载',rs);
// 1. 创建 Blob 的临时 URL
const url = URL.createObjectURL(rs);
// 2. 创建隐藏的 <a> 标签
const a = document.createElement('a');
a.href = url;
a.download = '课程摘要.txt'; // 设置下载的文件名
a.style.display = 'none';
// 3. 添加到文档中并触发点击
document.body.appendChild(a);
a.click();
// 4. 清理
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url); // 释放 URL 对象
}, 100);
})
},
updateSummary() {
apiAiVideo.updateVideoSummary({
courseId: this.courseId,
summaryContent: this.aiAbstract,
})
.then((rs) => {
if (rs.rspCode == '0000') {
this.type = '1';
this.getCourseSummary();
}
})
},
retrySummaryTxt() {
this.type = '2';
apiAiVideo.retrySummaryTxt({
courseId: this.courseId,
})
.then((rs) => {
if (rs.rspCode == '0000') {
this.type = '1';
this.getCourseSummary();
} else {
this.type = '3';
}
})
},
getVideoSummary(id) {
apiAiVideo.selectById(id)
.then((rs) => {
this.videoSummary = ''
if (rs.rspCode == '0000') {
this.videoSummary = rs.data.briefSummary || '';
} else {
this.$message.error('获取视频摘要失败!');
}
})
.catch((err) => {
this.videoSummary = ''
this.$message.error('获取视频摘要失败!');
})
},
getCourseSummary() {
apiAiVideo.getCourse({
courseId: this.courseId,
})
.then((rs) => {
this.aiAbstract = rs.data.summaryContent || '';
})
},
createPlayUrl(fid, u) {
let nowDate = new Date();
let ctime = parseInt(nowDate.getTime() / 1000);
let beforeUrl = parseInt(nowDate.getTime() / 1000) + "/" + fid;
let urlSign = encodeURIComponent(encrypt(beforeUrl));
cookies.set("PLAYSIGN_TIME", ctime); //写客户端的cookie保存
//以下判断是为了区分本地环境和服务器环境
if (process.env.NODE_ENV == "development") {
this.blobUrl = process.env.VUE_APP_FILE_BASE_URL + u;
} else {
this.blobUrl =
process.env.VUE_APP_BASE_API +
"/xboe/m/course/cware/resource?sign=" +
urlSign;
}
},
handleSelectVideo(item, index) {
console.log('选择了该视频', item);
this.SET_selectableLang(item?.boeaiSubtitleRspList);
this.videoName = item.chapterName ? item.chapterName + "-视频" + index : this.courseInfo.name;
this.currentVideo = item;
let curriculumData = {};
if (item.content.startsWith("{")) {
curriculumData = JSON.parse(item.content);
} else {
curriculumData.url = item.content;
}
this.getVideoSummary(item.id);
this.blobId = item.id;
this.createPlayUrl(item.contentRefId, curriculumData.url);
},
getCourseInfo() {
apiStudy.studyIndexPost({
cid: this.courseId,
addView: false,
audiences: '',
})
.then((rs) => {
if (rs.status == 200) {
this.courseInfo = rs.result.course || {};
this.SET_courseInfo(this.courseInfo);
const contents = rs.result.contents?.filter(item => item.contentType == 10) || [];
this.sections = rs.result.sections || [];
if (this.sections.length > 0) {
let treeList = [];
let hasOne = false;
this.sections.forEach(section => {
let treeNode = {
...section,
children: [],
};
contents.forEach(item => {
if (section.id == item.csectionId) {
item.chapterName = section.name || '';
treeNode.children.push(item);
if (!hasOne) {
this.handleSelectVideo(item, 1);
hasOne = true;
}
}
})
treeList.push(treeNode);
})
this.chapterList = treeList;
} else {
this.handleSelectVideo(contents[0], 1);
}
console.log('33333',this.courseInfo, this.courseInfo.name);
this.aiAbstract = this.courseInfo.summaryContent
if (contents.length == 0) {
$this.$message.error("课程内容已删除或课程已不再使用");
return;
}
if (!rs.result.course.enabled) {
$this.$message.error(
"十分抱歉,此课程已停用,如需使用,请联系管理员。"
);
return;
}
}
})
}
}
};
</script>
@@ -156,6 +330,7 @@ export default {
display: flex;
padding: 0 28px;
height: 76px;
min-height: 76px;
border-bottom: 1px solid rgba(229, 231, 235, 1);
display: flex;
justify-content: space-between;

View File

@@ -1,23 +1,30 @@
<template>
<div class="aiTranslate">
<div class="ai-left">
<div class="left-title">{{courseName}}</div>
<ul class="ai-list">
<li class="ai-item" v-for="(item, index) in videoList" @click="currentVideo = item" :class="{'active': currentVideo.id === item.id}" :key="index">
<div class="ai-item-title">{{item.name}}</div>
<div class="ai-left" v-if="sections.length > 0">
<div class="left-title">{{courseInfo.name}}</div>
<ul class="ai-list" >
<template v-for="c in chapterList">
<li class="ai-item" v-for="(item, index) in c.children" @click="handleSelectVideo(item, index+1)" :class="{'active': currentVideo.id === item.id}" :key="index">
<div class="ai-item-title">{{item.chapterName}}-{{'视频' + (index + 1)}}</div>
</li>
</template>
</ul>
</div>
<div class="ai-right">
<div class="right-title">
<h3>{{currentVideo.name}}</h3>
<h3>{{videoName}}</h3>
<div>
<el-button type="primary" @click="status = 1">下架本课程AI翻译</el-button>
<el-button type="primary" @click="handleSummaryStatus()">
{{ courseInfo.aiTranslate == 1 ? '下架本课程AI翻译' : '上架本课程AI翻译' }}
</el-button>
</div>
</div>
<div class="ai-content">
<div class="videoBox">
<videoPlayer :src="testUrl" style="height: auto;"> </videoPlayer>
<videoPlayer
:src="blobUrl"
:blobId="blobId"
style="height: auto;"> </videoPlayer>
<div class="video-content">
<div class="select-lang">
<img src="@/assets/images/course/languageIcon.png" alt="" width="10" height="10">
@@ -45,26 +52,26 @@
>
</el-option>
</el-select>
<el-button type="primary" @click="status = 2">加载字幕</el-button>
<el-button type="primary" @click="type = 2">加载字幕</el-button>
</div>
<div class="opera-content">
<div class="bg-gray" v-show="status != 4">
<p v-show="status == 1" v-html="aiTranslate"></p>
<p v-show="status == 2" style="color: rgba(207, 207, 207, 1);text-align: center;margin-top: 48%;">AI 翻译重新生成中过程可能耗时较长<br>无需在此等待哦</p>
<img v-show="status == 3" src="@/assets/images/course/generationFailed.png" alt="" width="150" height="159" style="display: flex;margin: 35% auto 0 auto;">
<img v-show="status == 5" src="@/assets/images/course/selectLanguage.png" alt="" width="112" height="130" style="display: flex;margin: 35% auto 0 auto;">
<div class="bg-gray" v-show="type != 4">
<p v-show="type == 1" v-html="aiTranslate"></p>
<p v-show="type == 2" style="color: rgba(207, 207, 207, 1);text-align: center;margin-top: 48%;">AI 翻译重新生成中过程可能耗时较长<br>无需在此等待哦</p>
<img v-show="type == 3" src="@/assets/images/course/generationFailed.png" alt="" width="150" height="159" style="display: flex;margin: 35% auto 0 auto;">
<img v-show="type == 5" src="@/assets/images/course/selectLanguage.png" alt="" width="112" height="130" style="display: flex;margin: 35% auto 0 auto;">
</div>
<el-input v-show="status == 4"
<el-input v-show="type == 4"
type="textarea"
placeholder="请输入内容"
autosize
v-model="aiTranslate">
</el-input>
<div class="opera-btn">
<el-button v-show="status == 1" type="primary" plain round size="mini" @click="updateDialogVisible = true">重新生成</el-button>
<el-button v-show="status == 1" type="primary" plain round size="mini" @click="status = 4">编辑</el-button>
<el-button v-show="status == 4" plain round size="mini" @click="status = 1">取消</el-button>
<el-button v-show="status == 4" type="primary" plain round size="mini" @click="status = 1">确认</el-button>
<el-button v-show="type == 1" type="primary" plain round size="mini" @click="updateDialogVisible = true">重新生成</el-button>
<el-button v-show="type == 1" type="primary" plain round size="mini" @click="type = 4">编辑</el-button>
<el-button v-show="type == 4" plain round size="mini" @click="type = 1">取消</el-button>
<el-button v-show="type == 4" type="primary" plain round size="mini" @click="type = 1">确认</el-button>
</div>
</div>
</div>
@@ -109,7 +116,8 @@
<script>
import videoPlayer from "@/components/VideoPlayer/index.vue";
import { mapGetters } from 'vuex';
import { mapGetters, mapMutations } from 'vuex';
import apiCourse from '@/api/modules/course.js';
export default {
name: 'aiTranslate',
// ai播放器相关
@@ -119,28 +127,6 @@ export default {
data() {
return {
courseName: '企业经营法则--课程单元',
videoList: [
{
id: 1,
name: '1. 开源节流1',
aiTranslate: '人工智能AI是让计算机模拟人类智能的技术核心包括机器学习、深度学习等。主要分为弱 AI专注特定任务和强 AI通用智能两类。应用涵盖医疗诊断、自动驾驶、语音助手等多个领域。它通过数据学习模式实现预测和适应能力正在改变生活方式和工作方式。未来发展需平衡创新与伦理考量确保对人类社会有益。'
},
{
id: 2,
name: '2. 企业经营法则总述',
aiTranslate: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
{
id: 3,
name: '3. 企业经营法则总述',
aiTranslate: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
{
id: 4,
name: '4. 企业经营法则总述',
aiTranslate: '本课程将介绍企业经营法则的总述,包括企业经营的基本原理、经营策略、经营模式等。'
},
],
testUrl: 'https://vjs.zencdn.net/v/oceans.mp4',
currentVideo: {},
aiTranslate: `
@@ -153,7 +139,7 @@ today I want to share with you the topic of
00:00:05/00:00:09
"The Development History and Future Prospects of Computer Technology -
`,
status: '1', // 1: 正常 2: 生成中 3: 错误 4: 编辑中 5: 未选择语种
type: '1', // 1: 正常 2: 生成中 3: 错误 4: 编辑中 5: 未选择语种
selectedLang: [
{
label: '英文',
@@ -184,17 +170,124 @@ today I want to share with you the topic of
updateDialogVisible: false,
selectDialogVisible: false,
selectLang: [],
chapterList: [],
videoName: '',
testUrl: 'https://vjs.zencdn.net/v/oceans.mp4',
currentVideo: {},
aiAbstract: '',
courseId: '',
courseInfo: {},
sections: [],
blobId: '',
blobUrl: '',
}
},
computed: {
...mapGetters(['selectAllLang']),
},
mounted() {
this.currentVideo = this.videoList[0];
this.courseId = this.$route.query.id;
console.log(this.courseId);
this.getCourseInfo();
},
methods: {
...mapMutations({
SET_selectableLang: 'video/SET_selectableLang',
SET_courseInfo: 'video/SET_courseInfo',
}),
setLanguage(){
this.selectDialogVisible = true;
},
handleSummaryStatus() {
apiCourse.benchAiSet({courseList:[{id: this.courseId, aiTranslate: this.courseInfo.aiTranslate == 1 ? 0 : 1}]}).then(res => {
if(res.status === 200){
this.$message.success(this.courseInfo.aiTranslate == 1 ? '下架成功!' : '上架成功!');
this.getCourseInfo();
}else{
this.$message.error(this.courseInfo.aiTranslate == 1 ? '下架失败!' : '上架失败!');
}
})
},
createPlayUrl(fid, u) {
let nowDate = new Date();
let ctime = parseInt(nowDate.getTime() / 1000);
let beforeUrl = parseInt(nowDate.getTime() / 1000) + "/" + fid;
let urlSign = encodeURIComponent(encrypt(beforeUrl));
cookies.set("PLAYSIGN_TIME", ctime); //写客户端的cookie保存
//以下判断是为了区分本地环境和服务器环境
if (process.env.NODE_ENV == "development") {
this.blobUrl = process.env.VUE_APP_FILE_BASE_URL + u;
} else {
this.blobUrl =
process.env.VUE_APP_BASE_API +
"/xboe/m/course/cware/resource?sign=" +
urlSign;
}
},
handleSelectVideo(item, index) {
this.SET_selectableLang(item?.boeaiSubtitleRspList);
this.videoName = item.chapterName ? item.chapterName + "-视频" + index : this.courseInfo.name;
this.currentVideo = item;
let curriculumData = {};
if (item.content.startsWith("{")) {
curriculumData = JSON.parse(item.content);
} else {
curriculumData.url = item.content;
}
this.blobId = item.id;
this.createPlayUrl(item.contentRefId, curriculumData.url);
},
getCourseInfo() {
apiStudy.studyIndexPost({
cid: this.courseId,
addView: false,
audiences: '',
})
.then((rs) => {
if (rs.status == 200) {
this.courseInfo = rs.result.course || {};
this.SET_courseInfo(this.courseInfo);
const contents = rs.result.contents?.filter(item => item.contentType == 10) || [];
this.sections = rs.result.sections || [];
if (this.sections.length > 0) {
let treeList = [];
let hasOne = false;
this.sections.forEach(section => {
let treeNode = {
...section,
children: [],
};
contents.forEach(item => {
if (section.id == item.csectionId) {
item.chapterName = section.name || '';
treeNode.children.push(item);
if (!hasOne) {
this.handleSelectVideo(item, 1);
hasOne = true;
}
}
})
treeList.push(treeNode);
})
this.chapterList = treeList;
} else {
this.handleSelectVideo(contents[0], 1);
}
console.log('33333',this.courseInfo, this.courseInfo.name);
this.aiAbstract = this.courseInfo.summaryContent
if (contents.length == 0) {
$this.$message.error("课程内容已删除或课程已不再使用");
return;
}
if (!rs.result.course.enabled) {
$this.$message.error(
"十分抱歉,此课程已停用,如需使用,请联系管理员。"
);
return;
}
}
})
}
}
};

View File

@@ -847,30 +847,30 @@
</div>
</template>
<script>
// ai播放器相关
import { mapGetters, mapMutations } from "vuex";
import followButton from "@/components/Follow/button.vue";
import portalHeader from "@/components/PortalHeader.vue";
import portalFooter from "@/components/PortalFooter.vue";
import comments from "@/components/Portal/comments.vue";
import noteComments from "@/components/Portal/noteComment.vue";
import interactBar from "@/components/Portal/interactBar.vue";
import audioPlayer from "@/components/AudioPlayer/index.vue";
import videoPlayer from "@/components/VideoPlayer/index.vue";
import hyperLink from "@/components/Course/hyperLink.vue";
import studyUtil from "@/utils/study.js";
import { encrypt } from "@/utils/jsencrypt.js";
import cookies from "vue-cookies";
import apiStat from "@/api/phase2/stat.js";
import apiStudy from "@/api/modules/courseStudy.js";
import apiVideoStudy from "@/api/modules/videoStudy.js";
import apiCourseGrade from "@/api/modules/courseGrade.js";
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import apiCoursePortal from "@/api/modules/coursePortal.js";
import apiUser from "@/api/system/user.js";
import apiCourseFile from "@/api/modules/courseFile.js";
import {
// ai播放器相关
import { mapGetters, mapMutations } from "vuex";
import followButton from "@/components/Follow/button.vue";
import portalHeader from "@/components/PortalHeader.vue";
import portalFooter from "@/components/PortalFooter.vue";
import comments from "@/components/Portal/comments.vue";
import noteComments from "@/components/Portal/noteComment.vue";
import interactBar from "@/components/Portal/interactBar.vue";
import audioPlayer from "@/components/AudioPlayer/index.vue";
import videoPlayer from "@/components/VideoPlayer/index.vue";
import hyperLink from "@/components/Course/hyperLink.vue";
import studyUtil from "@/utils/study.js";
import { encrypt } from "@/utils/jsencrypt.js";
import cookies from "vue-cookies";
import apiStat from "@/api/phase2/stat.js";
import apiStudy from "@/api/modules/courseStudy.js";
import apiVideoStudy from "@/api/modules/videoStudy.js";
import apiCourseGrade from "@/api/modules/courseGrade.js";
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import apiCoursePortal from "@/api/modules/coursePortal.js";
import apiUser from "@/api/system/user.js";
import apiCourseFile from "@/api/modules/courseFile.js";
import {
resListMap,
resOwnerListMap,
courseType,
@@ -878,20 +878,20 @@
toScore,
cutOrgNamePath,
userAvatarText,
} from "@/utils/tools.js";
import pdfPreview from "@/components/PdfPreview/index.vue";
import courseImage from "@/components/Course/courseImage.vue";
import exam from "@/components/Course/exam";
import homework from "@/components/Course/homework";
import assess from "@/components/Course/assess";
import myNote from "../../components/Course/myNote.vue";
// ai播放器相关
import aiScript from "../../components/Course/aiScript.vue";
import apiFollow from "@/api/phase2/userfollow.js";
import apiMessage from "@/api/system/message.js";
// import Vue from 'vue';
// Vue.forceUpdate();
export default {
} from "@/utils/tools.js";
import pdfPreview from "@/components/PdfPreview/index.vue";
import courseImage from "@/components/Course/courseImage.vue";
import exam from "@/components/Course/exam";
import homework from "@/components/Course/homework";
import assess from "@/components/Course/assess";
import myNote from "../../components/Course/myNote.vue";
// ai播放器相关
import aiScript from "../../components/Course/aiScript.vue";
import apiFollow from "@/api/phase2/userfollow.js";
import apiMessage from "@/api/system/message.js";
// import Vue from 'vue';
// Vue.forceUpdate();
export default {
name: "atticle",
components: {
courseImage,
@@ -2397,37 +2397,37 @@
this.cleanAppendTime();
this.stopStudyTime();
},
};
};
</script>
<style lang="scss" scoped>
::v-deep .el-icon-arrow-down {
::v-deep .el-icon-arrow-down {
color: #000;
font-weight: 900;
font-size: 16px;
}
.el-menu,
.el-menu-item,
.el-submenu__title {
}
.el-menu,
.el-menu-item,
.el-submenu__title {
background-color: transparent !important; /* 设置背景色为透明,以移除默认的背景颜色变化 */
color: inherit !important; /* 确保文字颜色不变,如果需要的话 */
}
}
/* 取消选中效果 */
.el-menu-item.is-active,
.el-submenu__title.is-active {
/* 取消选中效果 */
.el-menu-item.is-active,
.el-submenu__title.is-active {
background-color: transparent !important; /* 移除选中时的背景色 */
color: inherit !important; /* 保持文字颜色与未选中时一致,如果需要的话 */
}
}
/* 如果有特定的 hover 样式,也可以取消 */
.el-menu-item:hover,
.el-submenu__title:hover {
/* 如果有特定的 hover 样式,也可以取消 */
.el-menu-item:hover,
.el-submenu__title:hover {
background-color: transparent !important; /* 移除鼠标悬停时的背景色变化 */
color: inherit !important; /* 保持文字颜色不变 */
}
//内容块样式定义
.course-content {
}
//内容块样式定义
.course-content {
min-height: 745px;
margin: 20px auto;
@@ -2491,9 +2491,9 @@
width: 420px;
}
}
}
}
.control-tab {
.control-tab {
margin: 35px 30px 10px 30px;
border-bottom: 1px solid #d8d8d8;
@@ -2508,9 +2508,9 @@
color: #333333;
font-weight: 600;
}
}
}
.course-info-tab {
.course-info-tab {
display: flex;
padding-top: 30px;
margin-left: 47px;
@@ -2536,9 +2536,9 @@
top: 128%;
}
}
}
}
.course-info-row {
.course-info-row {
padding: 10px 0;
font-size: 18px;
color: #343434;
@@ -2552,9 +2552,9 @@
color: #666666;
word-break: break-all;
}
}
//右侧老师部分头部及标题
.cteacher-top {
}
//右侧老师部分头部及标题
.cteacher-top {
background-color: #fff;
margin-top: 0px;
.cteacher-top-bar {
@@ -2568,15 +2568,15 @@
font-weight: 600;
line-height: 50px;
}
}
//右侧老师部分 老师列表
.cteacher-list {
}
//右侧老师部分 老师列表
.cteacher-list {
background-color: #fff;
padding: 10px 30px 30px 30px;
}
}
//以下是未整理的样式,上面的整理之后的样式
.coures-note {
//以下是未整理的样式,上面的整理之后的样式
.coures-note {
min-height: 500px;
padding-left: 17px;
padding-top: 10px;
@@ -2589,9 +2589,9 @@
.note-info {
}
}
}
.player-box {
.player-box {
position: absolute;
width: 100%;
max-width: 300px;
@@ -2616,64 +2616,64 @@
.player-rate {
margin-top: 35px;
}
}
}
.score-text {
.score-text {
font-size: 18px;
color: #ffb30f;
font-family: "Arial";
margin-left: 23px;
// font-weight: 600;
}
}
// .score {
// display: flex;
// justify-content: center;
// align-items: center;
// .score {
// display: flex;
// justify-content: center;
// align-items: center;
// .el-rate {
// display: inline-block;
// }
// // margin-bottom: 19px;
// .score-no {
// color: #ffb30f;
// padding: 5px 0;
// background: #efefef;
// border-radius: 20px;
// width: 65px;
// font-size: 12px;
// font-weight: 600;
// text-align: center;
// }
// }
// .el-rate {
// display: inline-block;
// }
// // margin-bottom: 19px;
// .score-no {
// color: #ffb30f;
// padding: 5px 0;
// background: #efefef;
// border-radius: 20px;
// width: 65px;
// font-size: 12px;
// font-weight: 600;
// text-align: center;
// }
// }
.portal-content-title {
.portal-content-title {
font-weight: 600;
padding: 10px;
font-size: 22px;
line-height: 40px;
color: #333333;
word-break: break-all;
}
}
.type-kuang {
.type-kuang {
color: #666666;
border: 1px solid #666666;
}
}
.type-click {
.type-click {
color: #ffb30f !important;
border: 1px solid #ffb30f !important;
}
}
::v-deep .el-rate__icon {
::v-deep .el-rate__icon {
font-size: 22px;
margin-right: 6px;
color: #ff8e00;
transition: 0.3s;
}
}
.ref-score {
.ref-score {
// background: #e4e4e4;
// width: 64px;
// height: 32px;
@@ -2683,16 +2683,16 @@
// color: #000;
// font-size: 14px;
// border: none;
}
}
.icon-small {
.icon-small {
width: 16px;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
}
.con-audio {
.con-audio {
padding: 50px;
text-align: center;
@@ -2705,9 +2705,9 @@
min-height: 300px;
padding: 60px 50px 80px 50px;
}
}
}
.hyper-link {
.hyper-link {
padding-left: 20px;
text-align: center;
padding-top: 100px;
@@ -2715,9 +2715,9 @@
.hyper-link-row {
padding: 20px;
}
}
}
.catalog-box {
.catalog-box {
background: #fff;
// padding: 15px 0px;
@@ -2728,19 +2728,19 @@
color: #333333;
padding-left: 20px;
}
}
}
.collapse-title {
.collapse-title {
flex: 1 0 90%;
order: 1;
}
}
.el-collapse-item__header {
.el-collapse-item__header {
flex: 1 0 auto;
order: -1;
}
}
.course-interact {
.course-interact {
flex: 1; // 20%高度
height: 54px;
// padding-top: 10px;
@@ -2751,18 +2751,18 @@
display: flex;
justify-content: space-between;
box-sizing: border-box;
}
}
.interact-btn {
.interact-btn {
margin-right: 10px;
}
}
.uc-badge {
.uc-badge {
margin-top: 10px;
margin-right: 40px;
}
}
.cres-list {
.cres-list {
list-style-type: decimal;
margin: 0px;
@@ -2773,9 +2773,9 @@
.current {
color: #1ea0fa;
}
}
}
.uc-course {
.uc-course {
display: flex;
justify-content: space-around;
border: 1px solid #f0f0f0;
@@ -2808,9 +2808,9 @@
.uc-course-btns {
width: 150px;
}
}
}
.catalog-cell-state2 {
.catalog-cell-state2 {
height: 24px;
width: 58px;
line-height: 20px;
@@ -2821,9 +2821,9 @@
border-radius: 6px;
margin-left: 2px;
background: #ffedd6;
}
}
.catalog-cell-state9 {
.catalog-cell-state9 {
height: 24px;
width: 58px;
line-height: 20px;
@@ -2836,9 +2836,9 @@
background: #edf2fd;
// margin-left: 68%;
// background-color: #BED2F8;
}
}
.catalog-cell-state1 {
.catalog-cell-state1 {
height: 24px;
width: 58px;
line-height: 20px;
@@ -2849,9 +2849,9 @@
font-size: 12px;
margin-left: 2px;
background: #fff0f0;
}
}
.catalog {
.catalog {
height: 100%;
max-width: 500px;
overflow: auto;
@@ -2887,9 +2887,9 @@
color: #5c5c5c;
}
}
}
}
.video-div {
.video-div {
position: absolute;
z-index: 999999999;
top: 0;
@@ -2921,9 +2921,9 @@
}
}
}
}
}
::v-deep .el-tag {
::v-deep .el-tag {
background-color: #ecf5ff;
border-color: #409eff;
display: inline-block;
@@ -2937,14 +2937,14 @@
border-radius: 0px;
box-sizing: border-box;
white-space: nowrap;
}
}
::v-deep .teacher .teacher-avator .teacher-text {
::v-deep .teacher .teacher-avator .teacher-text {
background: none;
border: none;
}
}
.teacher {
.teacher {
background-color: #ffffff;
display: flex;
width: 100%;
@@ -2988,14 +2988,14 @@
word-break: break-all;
}
}
}
}
.breadname {
.breadname {
margin-bottom: 15px;
}
}
//目录的样式更改
::v-deep .el-collapse-item {
//目录的样式更改
::v-deep .el-collapse-item {
.el-collapse-item__header {
// position: relative;
direction: rtl;
@@ -3013,9 +3013,9 @@
display: none;
}
}
}
}
.course-units {
.course-units {
padding: 10px 30px;
.units-info {
padding: 0 30px;
@@ -3041,13 +3041,13 @@
// margin-right: 20px;
}
}
}
}
.more {
.more {
float: right;
}
}
.coures-title {
.coures-title {
margin-left: 82px;
font-size: 20px;
font-weight: 600;
@@ -3077,32 +3077,32 @@
color: #ffffff;
margin: 0 20px;
}
}
}
::v-deep.el-breadcrumb__item:first-child .el-breadcrumb__inner a,
.el-breadcrumb__inner .is-link {
::v-deep.el-breadcrumb__item:first-child .el-breadcrumb__inner a,
.el-breadcrumb__inner .is-link {
color: #fff !important;
}
}
::v-deep.el-breadcrumb__item:last-child .el-breadcrumb__inner {
::v-deep.el-breadcrumb__item:last-child .el-breadcrumb__inner {
color: #fff !important;
}
}
::v-deep.hear-nav {
::v-deep.hear-nav {
color: #fff !important;
}
}
.breadcrumb-nav {
.breadcrumb-nav {
color: #ffffff;
}
}
.coures-bg {
.coures-bg {
width: 100%;
height: 200px;
background: url("../../../public/images/couresdetail.png");
}
}
.protocol {
.protocol {
.protocol-title {
font-size: 20px;
font-weight: 600;
@@ -3114,5 +3114,5 @@
font-size: 14px;
line-height: 25px;
}
}
}
</style>

View File

@@ -144,6 +144,17 @@ module.exports = {
'^/manageApi': '/manageApi'
}
},
'/systemapi/aiVideo': {
// 目标代理服务器地址
// target: 'http://127.0.0.1:9090',
target: 'http://10.29.0.168:8088',
changeOrigin: true,
logLevel: 'debug',
secure: false,
pathRewrite: {
'^/systemapi/aiVideo': ''
}
},
'/systemapi': {
// 目标代理服务器地址
// target: 'http://127.0.0.1:9090',