Compare commits

...

176 Commits

Author SHA1 Message Date
sunli_tydic
caa9b23766 ai视频一期功能提交 2025-11-21 17:26:34 +08:00
sunli_tydic
4b4c0943d8 添加改动标识 ai播放器相关 2025-11-21 14:30:09 +08:00
sunli_tydic
b31f02bf23 ai视频一期功能提交 2025-11-20 17:30:31 +08:00
sunli_tydic
003fece291 ai功能静态 2025-11-19 16:27:07 +08:00
sunli_tydic
986a47f22a 视频ai文稿 ai摘要静态 2025-11-18 15:13:57 +08:00
Caojr
782bcc31e5 szx-1282 超时清空展示文件 2025-11-04 15:54:23 +08:00
Caojr
1a95852912 szx-1282 超时清空展示文件 2025-11-04 14:55:16 +08:00
Caojr
f5d865ccc3 szx-1282 增加超时配置 2025-11-04 13:47:02 +08:00
Caojr
65673561d8 szx-1280 编辑时长无效问题修复 2025-10-31 16:16:29 +08:00
Caojr
2cbb379fa6 样式修改 2025-10-29 18:10:07 +08:00
670788339
6d4af3aa2d 还原视频状态 调试 2025-10-24 13:29:09 +08:00
joshen
5ebee96ce4 Merge remote-tracking branch 'yx/202599-da' 2025-09-29 17:42:32 +08:00
408d6a1612 修复视频 status 状态 2025-09-29 17:26:53 +08:00
b1508ad226 更新精品课图片 2025-09-26 09:18:51 +08:00
a9764bf2f8 更新精品课图片 2025-09-26 09:15:55 +08:00
joshen
c3f53515b9 Merge branch '202599-da' 2025-09-19 18:58:47 +08:00
087be5dd38 fix: 修复分数异常展示的问题 2025-09-19 13:43:23 +08:00
joshen
1772c972b9 Merge branch '202599-da' 2025-09-18 18:51:50 +08:00
dong.ai
91bafcb5b9 调整字体展示位置 2025-09-15 17:15:47 +08:00
dong.ai
8c533c5f3a 修改字体大小 2025-09-15 17:02:45 +08:00
dong.ai
bb17784501 修改图片大小,背景图片 2025-09-15 16:32:23 +08:00
dong.ai
69530fe6ad 标题展示隐藏判断2 2025-09-15 14:01:32 +08:00
dong.ai
b1cd8e2f63 标题展示隐藏判断 2025-09-15 13:57:19 +08:00
dong.ai
7335dd4eba 首页教师名称展示 2025-09-15 13:45:35 +08:00
3860087fac feat: 增加搜索标签展示,修复样式问题,提示语修改 2025-09-15 11:36:08 +08:00
046509f70d fix: 修复课程名称展示异常的问题 2025-09-15 10:06:35 +08:00
bf0ae91184 feat: 优化调用显示方案 2025-09-15 10:06:35 +08:00
f61742a0b9 fix: 修复教师无法展示的问题 2025-09-14 22:09:03 +08:00
dong.ai
c886a80193 教师展示 2025-09-14 21:30:12 +08:00
05ad90b025 fix: 修复标签无法正常高亮的问题 2025-09-14 21:23:56 +08:00
f3833a23fa style: 优化选择年份和边距 2025-09-14 21:16:02 +08:00
d957a8d44b fix: 修复 主页图片无法正常展示的问题 2025-09-14 21:16:01 +08:00
dong.ai
89ed79828f 修复跳转详情2 2025-09-14 21:09:57 +08:00
dong.ai
b926590edc 修改跳转详情 2025-09-14 21:04:21 +08:00
19bc757dc2 fix: 修复 systype 错误的问题 2025-09-14 20:59:38 +08:00
f3a1036b64 feat: 样式修改,功能修复 2025-09-14 20:50:42 +08:00
3c1650b751 Merge branch '2025-912-hz' into 202599-da
# Conflicts:
#	src/api/phase2/index.js
2025-09-14 20:30:44 +08:00
ff2bdb4ae5 fix: 修复获取课程精品课标记时间年份列表
# Conflicts:
#	src/api/phase2/index.js
2025-09-14 20:29:53 +08:00
dong.ai
14fb53ccd3 解决冲突 2025-09-14 20:10:29 +08:00
dong.ai
72f9661150 Merge branch '202599-da' of https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal into 202599-da 2025-09-14 19:43:10 +08:00
dong.ai
7806afc5f7 还原代码 2025-09-14 19:40:05 +08:00
e1af233c5f feat: 完成精品课程专区的内容 2025-09-14 19:39:41 +08:00
2738493030 fix: 修复刷新页面自动调整错误的问题 2025-09-14 19:39:08 +08:00
480a4f5564 chore: 修正路由名称拼写错误 2025-09-14 19:39:06 +08:00
dong.ai
205bf5469f 字段展示 2025-09-14 19:08:21 +08:00
dong.ai
30897a1fa5 修改展示 2025-09-14 19:02:38 +08:00
dong.ai
1c59cffd3e 标题展示 2025-09-14 18:54:18 +08:00
dong.ai
6e9f93d6c9 字段处理 2025-09-14 18:48:47 +08:00
dong.ai
3ee4a2fd6e 调整首页字段展示 2025-09-14 18:11:33 +08:00
dong.ai
1b442ef040 首页跳转详情 2025-09-14 17:50:31 +08:00
dong.ai
4693cb0db1 收藏图标展示 2025-09-14 17:43:35 +08:00
dong.ai
92fecbec80 收藏图表展示 2025-09-14 17:36:13 +08:00
dong.ai
be63f5a1aa 收藏图片展示 2025-09-14 17:28:04 +08:00
dong.ai
c9899eda6b 修改收藏 2025-09-14 17:20:15 +08:00
dong.ai
0f52a69beb 收藏展示 2025-09-14 17:07:30 +08:00
dong.ai
3410afedcf 收藏发消息接口字段 2025-09-14 16:45:13 +08:00
dong.ai
33866c0f49 修改收藏 2025-09-14 16:28:36 +08:00
dong.ai
c9e51fc21f 完善收藏 2025-09-14 16:03:49 +08:00
dong.ai
a42668c929 调整背景样式 2025-09-14 15:29:45 +08:00
dong.ai
01d4bc0536 调整背景图样式 2025-09-14 14:52:19 +08:00
dong.ai
d52e8b389b 修改首页展示样式 2025-09-14 13:55:28 +08:00
dong.ai
e9a86d0364 修改入参格式 2025-09-14 12:25:56 +08:00
dong.ai
0e43ca5e82 修改请求头类型 2025-09-14 12:01:08 +08:00
dong.ai
0771460f60 首页精品课部分 2025-09-14 11:45:27 +08:00
dong.ai
1a2829d70a 精品课列表接口 2025-09-13 19:58:11 +08:00
dong.ai
68eda7efcc 首页添加精品课模块 2025-09-13 15:39:35 +08:00
0b0789feda feat: 右侧菜单高度调整为 650 2025-09-09 17:51:26 +08:00
70bb87a17a feat: 溢出控制高度的代码, 防止内容塌陷 2025-09-09 17:51:25 +08:00
4e60811542 feat: 溢出控制高度的代码, 防止内容塌陷 2025-09-09 17:51:24 +08:00
670788339
075fdb1913 认证讲师库删除年份后缀 2025-09-09 17:39:58 +08:00
670788339
8c7569ae4e banner跳转 2025-09-04 16:46:09 +08:00
670788339
56f565cbf3 banner跳转暂时注释 2025-09-02 08:46:33 +08:00
670788339
c15f52e325 banner跳转 2025-09-01 15:37:12 +08:00
670788339
98c10e703e 教师专区banner点击跳转 2025-09-01 13:21:12 +08:00
670788339
2078c128c9 教师专区banner点击跳转 2025-09-01 13:12:22 +08:00
joshen
e8fe7b4fd3 fix: 修复火狐报错的弹窗提醒 2025-08-14 14:03:53 +08:00
joshen
029d5b0791 修复1181案例不显示案主信息 2025-08-05 15:26:27 +08:00
joshen
12a6ed8fea Merge remote-tracking branch '104/master-0626' into master-0626 2025-08-05 14:30:02 +08:00
joshen
363492866f 修复1181案例不显示案主信息 2025-08-05 14:29:24 +08:00
joshen
d237dc99ee 修改弹框可见 2025-07-25 21:01:58 +08:00
joshen
995933ae56 Merge remote-tracking branch '104-git/master-0626' into master-0626 2025-07-25 20:53:15 +08:00
joshen
dff81df91d 修改弹框可见 2025-07-25 20:52:43 +08:00
670788339
0864704c4c 仅内网可见-管理员端 调试 2025-07-23 17:53:43 +08:00
670788339
58fc6264fe 仅内网可见-管理员端 调试 2025-07-23 17:45:30 +08:00
670788339
5276813eba 仅内网可见-管理员端 调试 2025-07-23 17:28:36 +08:00
670788339
3485435c9e 仅内网可见-管理员端 调试 2025-07-23 17:24:51 +08:00
670788339
2ee3daedf6 仅内网可见-管理员端 调试 2025-07-23 17:10:19 +08:00
joshen
5d0d64abbf 修改背景颜色 2025-07-23 16:49:08 +08:00
joshen
ea97aee4af 修复评分会点错 2025-07-23 15:07:30 +08:00
joshen
a968062936 修复视频进度条拖动 2025-07-23 14:40:06 +08:00
joshen
6d11475456 修改边界颜色 2025-07-23 13:45:38 +08:00
joshen
a7396e0a6a 修改边界颜色 2025-07-23 13:37:42 +08:00
670788339
ac236e8d7c 仅内网可见-管理员端 调试 2025-07-21 21:17:18 +08:00
670788339
f537608e4f 仅内网可见-管理员端 调试 2025-07-21 21:10:41 +08:00
670788339
c7f4a224ff 仅内网可见-管理员端 调试 2025-07-21 20:59:06 +08:00
670788339
a4d088a3ae 仅内网可见-管理员端 调试 2025-07-21 20:44:20 +08:00
670788339
3cd2c5f433 仅内网可见-管理员端 调试 2025-07-21 20:33:47 +08:00
670788339
8c69fac9be 仅内网可见-管理员端 调试 2025-07-21 20:24:39 +08:00
670788339
4033eb2294 仅内网可见-管理员端 调试 2025-07-21 20:18:33 +08:00
670788339
ec469db72a 仅内网可见-管理员端 调试 2025-07-21 20:15:20 +08:00
670788339
5e1ea2469b 仅内网可见-管理员端 调试 2025-07-21 20:11:41 +08:00
670788339
2baa5c61a4 仅内网可见-管理员端 调试 2025-07-21 20:10:25 +08:00
670788339
b627398b7d 仅内网可见-管理员端 调试 2025-07-21 19:57:51 +08:00
670788339
7be5c072d9 仅内网可见-管理员端 调试 2025-07-21 19:37:32 +08:00
670788339
de14f9f561 仅内网可见-管理员端 调试 2025-07-21 19:26:19 +08:00
joshen
44f79c93a5 修改前端 2025-07-21 19:24:24 +08:00
joshen
e501b8d23f 修改前端 2025-07-21 19:16:49 +08:00
joshen
ea8143db2b 修改前端 2025-07-21 18:57:40 +08:00
joshen
89277f8868 修改前端 2025-07-21 18:35:09 +08:00
joshen
13af8ba4e0 前端参数调整 2025-07-21 15:21:19 +08:00
joshen
e3735e4b92 前端参数调整 2025-07-21 15:09:39 +08:00
joshen
f4c9b921bb 前端参数调整 2025-07-21 15:02:46 +08:00
joshen
ed899cdd2c Merge remote-tracking branch 'aliyun/master-0720-lyc' into master-0720-lyc 2025-07-21 15:00:08 +08:00
王卓煜
c24b54957a 内网环境判断 2025-07-21 14:57:51 +08:00
joshen
1dc9c941d7 Merge remote-tracking branch 'aliyun/master-0720-lyc' into master-0720-lyc 2025-07-21 14:45:56 +08:00
王卓煜
33c9d2140f 内网环境判断 2025-07-21 14:42:42 +08:00
王卓煜
afd1bec458 内网环境判断 2025-07-21 14:33:05 +08:00
joshen
202bf7b123 test2 2025-07-21 11:19:59 +08:00
joshen
ce1d662350 Merge remote-tracking branch 'aliyun/master-0720-lyc' into master-0720-lyc 2025-07-21 11:01:12 +08:00
王卓煜
81602506c7 内网环境判断 2025-07-21 11:00:33 +08:00
joshen
053a2a60b2 Merge remote-tracking branch 'aliyun/master-0720-lyc' into master-0720-lyc 2025-07-21 10:47:32 +08:00
王卓煜
b9f23eb657 内网环境判断 2025-07-21 10:46:30 +08:00
joshen
ceeb3efcf5 Merge remote-tracking branch 'aliyun/master-0720-lyc' into master-0720-lyc 2025-07-21 10:43:23 +08:00
王卓煜
147366f738 内网环境判断 2025-07-21 10:33:44 +08:00
joshen
4ac09a8793 test2 2025-07-20 18:27:45 +08:00
joshen
9c768337c6 test2 2025-07-20 18:23:55 +08:00
joshen
e202946fe7 test2 2025-07-20 18:16:54 +08:00
joshen
fbddf6806a test 2025-07-20 18:11:37 +08:00
670788339
3cfa3ffec3 仅内网可见-管理员端 调试 2025-07-20 17:47:53 +08:00
670788339
a8bcd3832b 仅内网可见-管理员端 调试 2025-07-20 16:56:47 +08:00
670788339
d9f69001a5 仅内网可见-管理员端 调试 2025-07-20 16:38:42 +08:00
670788339
93e769be42 仅内网可见-管理员端 调试 2025-07-20 16:15:02 +08:00
670788339
206f0e825d 仅内网可见-管理员端 2025-07-20 15:39:37 +08:00
670788339
3bb4b519f1 仅内网可见-管理员端 2025-07-20 14:16:02 +08:00
joshen
fe790389ca 日志打印 2025-07-17 11:24:07 +08:00
joshen
44a5baec18 日志打印 2025-07-17 10:14:42 +08:00
670788339
ee8a76c4df 作业提交按钮判断 2025-07-09 13:48:31 +08:00
670788339
12c1bdb1a8 查询考试限制加大 2025-06-27 16:53:34 +08:00
670788339
df0e1ad0ed Merge branch 'csg-250625-lyc' into master-0626 2025-06-26 15:47:36 +08:00
670788339
ea54ea2c20 热点-替换图片 2025-06-25 16:42:45 +08:00
670788339
5fe9d2eb96 热点-替换图片 2025-06-25 15:24:34 +08:00
chensg
b6562e5c9c 修改25年热点论坛组件名称 2025-06-16 14:07:25 +08:00
chensg
a0dcd27f8c 修改2025热点论坛 2025-06-16 13:37:22 +08:00
chensg
8bc2bc96a8 添加2025热点论坛 2025-06-16 11:25:28 +08:00
670788339
ab2ac961f5 替换图片 2025-06-13 09:17:26 +08:00
670788339
6727dd838b 替换图片 2025-06-12 09:36:58 +08:00
joshen
28aa639e1c Merge remote-tracking branch 'yx/master-20250428-shl' 2025-05-13 15:42:12 +08:00
joshen
05d48f5313 Merge remote-tracking branch 'yx/250415-bugfix-shl' 2025-05-13 15:41:28 +08:00
sunhonglai
7a67aca620 修改教师端我的授课记录查询和导出 2025-04-29 16:33:42 +08:00
sunhonglai
a810da8978 修改教师端我的授课记录查询和导出 2025-04-29 16:29:36 +08:00
sunhonglai
b4538150df 修改教师端我的授课记录查询和导出 2025-04-29 16:20:57 +08:00
sunhonglai
e79abe7aee 修改教师端我的授课记录查询和导出 2025-04-29 16:07:35 +08:00
sunhonglai
65dfa4f0e3 修改教师端我的授课记录查询和导出 2025-04-29 16:01:30 +08:00
sunhonglai
4784b02ca4 修改教师端我的授课记录查询和导出 2025-04-29 15:44:55 +08:00
sunhonglai
45e006a4e7 修改教师端我的授课记录查询和导出 2025-04-29 15:34:09 +08:00
sunhonglai
577357ccd0 修改教师端我的授课记录查询和导出 2025-04-29 15:03:58 +08:00
sunhonglai
f92954aa6b 修改教师端我的授课记录查询和导出 2025-04-29 14:53:51 +08:00
sunhonglai
d59b5a9e06 修改教师端我的授课记录查询和导出 2025-04-29 14:53:24 +08:00
sunhonglai
4be009a6d8 修改教师端我的授课记录查询和导出 2025-04-29 14:13:34 +08:00
sunhonglai
b5f01c6357 修改教师端我的授课记录查询和导出 2025-04-29 13:55:05 +08:00
sunhonglai
78cbb21155 修改教师端我的授课记录查询和导出 2025-04-29 13:47:56 +08:00
sunhonglai
adc33e5892 修改教师端我的授课记录查询和导出 2025-04-29 13:36:24 +08:00
sunhonglai
a9de4ad77c 修改教师端我的授课记录查询和导出 2025-04-29 11:49:39 +08:00
sunhonglai
a3c85cbd19 修改教师端我的授课记录查询和导出 2025-04-29 11:46:40 +08:00
sunhonglai
9a6727e52f 修改教师端我的授课记录查询和导出 2025-04-29 11:40:29 +08:00
sunhonglai
7cee4b5ad1 修改教师端我的授课记录查询和导出 2025-04-29 11:33:51 +08:00
sunhonglai
c3b5f1baf0 修改教师端我的授课记录查询和导出 2025-04-29 11:23:45 +08:00
sunhonglai
505e3ce00c 修改进度条文案 2025-04-21 14:37:53 +08:00
sunhonglai
ff908554fd 修改上报时长接口 2025-04-21 11:10:21 +08:00
sunhonglai
e031dcd935 修改上报时长接口 2025-04-18 09:42:06 +08:00
sunhonglai
2139e15813 修改上报时长接口 2025-04-18 09:41:46 +08:00
sunhonglai
8497deea52 增加日志打印 2025-04-18 09:27:01 +08:00
sunhonglai
8746904cb9 学习时长上报接口合并 2025-04-18 08:51:48 +08:00
sunhonglai
213e5abce3 去掉无用注释影响后绪修改逻辑 2025-04-16 14:01:43 +08:00
sunhonglai
dc7f942303 先修改对应的后端接口 2025-04-16 10:19:56 +08:00
sunhonglai
4c1c370879 清除无用注释,影响排查要搜索修改的代码 2025-04-16 08:51:10 +08:00
52 changed files with 8938 additions and 4056 deletions

BIN
public/images/qualityBg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -62,15 +62,62 @@ const courseRecordList = function(data) {
return ajax.postJson('/b1/system/teacher/teacher-course-list',data);
}
const getListByToken = function(data) {
return ajax2.get('/manageApi',`/admin/teacherRecord/getListByToken?courseName=${data.courseName}&page=${data.page}&pageSize=${data.pageSize}`);
return ajax2.get('/manageApi',`/admin/teacherRecord/getListByToken?courseName=${data.courseName}&pageNo=${data.pageNo}&pageSize=${data.pageSize}`);
}
/**
* 导出授课记录
*
* @param {Object} data
*/
const courseRecordExport2 = function(data) {
return axios.request({
baseURL: "/manageApi",
url: '/admin/export/exportInTeacherRecord',
method: 'get',
data:data,
headers:{'Content-Type':'application/json;charset=utf-8'},
responseType: 'blob'
})
}
/**
* 导出课程下的学员信息
*
*/
const exportStudentOfCourse2 = function(courseId,courseType) {
return axios.request({
baseURL: "/manageApi",
url: '/admin/export/exportTeacherRecordStudentInfo?courseId='+courseId+'&courseType='+courseType,
method: 'get'
// headers:{'Content-Type':'application/json;charset=utf-8'},
// responseType: 'blob'
})
}
/**
* 导出教师下的所有授课记录下的学员信息
*
*/
const exportStudentOfTearcher2 = function(userId) {
return axios.request({
baseURL: "/manageApi",
url: '/b1/system/teacher/teacher-course-student-export?userId='+userId,
method: 'post',
headers:{'Content-Type':'application/json;charset=utf-8'},
responseType: 'blob'
})
}
export default {
courseRecordExport,
courseRecordExport2,
courseRecordList,
getListByToken,
exportStudentOfCourse,
exportStudentOfTearcher
exportStudentOfCourse2,
exportStudentOfTearcher,
exportStudentOfTearcher2,
}

208
src/api/httpAjax.js Normal file
View File

@@ -0,0 +1,208 @@
import axios from 'axios'
import qs from 'qs'
import {Notification, MessageBox, Message} from 'element-ui'
import store from '@/store'
import {getToken} from '@/utils/token'
import errorCode from '@/utils/errorCode'
/**
*request请求 axios.request(config)
*requestJson请求 axios.request(config)
*get请求 axios.get(url[, config])
*post请求 axios.post(url[, data[, config]])
*postJson请求 axios.post(url[, data[, config]])
*put请求 axios.put(url[, data[, config]])
*putJson请求 axios.put(url[, data[, config]])
*patch请求 axios.patch(url[, data[, config]])
*patchJson请求 axios.patch(url[, data[, config]])
*delete请求 axios.delete(url[, config])
*/
// const ReLoginUrl=process.env.VUE_APP_LOGIN_URL;
const TokenName = 'token';
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
//只是用于发送json对象数据时使用post,put,patch
/**axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'**/
//只是用于发送json对象数据时使用post,put,patch
//用于普通的发送请求
const formRequest = axios.create({
//headers:{'Content-Type':'application/x-www-form-urlencoded'},
// axios中请求配置有baseURL选项表示请求URL公共部分
// baseURL: process.env.VUE_APP_CESOURCE_BASE_API,
//超时
timeout: 10000,
})
//发送json对象的拦截器
formRequest.interceptors.request.use(config => {
//是否需要设置 token
const isToken = (config.headers || {}).isToken === false
let curToken = getToken();
//curToken='eyJ0eXBlIjoidG9rZW4iLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC91LmJvZS5jb20iLCJpYXQiOjE2NzIzMTE2MTIsImV4cCI6MTY3MjMxODgxMiwiR2l2ZW5OYW1lIjoiYm9ldSIsInVzZXJJZCI6IjZCMDQ5RkFGLUMzMTQtN0NDRi0wRDI4LTBEMjNGNEM0MjUzMSIsInVJZCI6Ijk2NTM0MjAyNzQ5NzYwNzE2OCIsInBlcm1pc3Npb24iOiIifQ==.a4f41376e994c5fcd3ab537ce17572ef4c633863f87785cf7b6ffa353e2ed51c';
if (curToken && !isToken) {
config.headers[TokenName] = curToken // 让每个请求携带自定义token 请根据实际情况自行修改
}
return config
}, error => {
console.log(error)
Promise.reject(error)
});
formRequest.interceptors.response.use(res => {
//console.log(res);
const code = res.data.status || 200;
if (code === 200) {
return res.data
} else {
if (code === 401) {
// store.dispatch('LogOut').then(() => {
// location.href = this.webBaseUrl + ReLoginUrl;
// })
console.error('', res.data);
return Promise.reject(new Error('接口返回未登录'))
} else if (code === 403) {
var msg = '当前操作没有权限';
Message({message: msg, type: 'error'});
return Promise.reject(new Error(msg))
} else {
//Message({message: res.data.message, type: 'error'});
//console.log('err' + res.data.error);
return res.data
}
}
},
error => {
console.log('err', error)
let {message} = error;
if (message == "Network Error") {
message = "网络异常,请稍后重试";
} else if (message.includes("timeout")) {
message = "网络异常或接口错误,请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({
message: message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
/**
* request请求,可以自定义参数
*/
const request = formRequest.request;
/**
* get请求 ,只有url
*/
const get = function (baseURL, url) {
return request({
baseURL,
url: url,
method: 'get',
headers: {'Content-Type': 'application/json'}
})
}
/**
* post请求
* @param {Object} url
* @param {Object} postData
*/
const post = function (baseURL, url, postData) {
// if (postData) {
// postData = qs.stringify(postData);
// }
return request({
baseURL,
url: url,
method: 'post',
data: postData,
headers: {'Content-Type': 'application/json'}
})
}
//post请求
const postForm = function (baseURL, url, data) {
return request({
baseURL,
url,
data,
method: 'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
}
// const postJson=jsonRequest.post;
const postJson = function (baseURL, url, postData) {
return request({
baseURL,
url: url,
method: 'post',
data: postData,
headers: {'Content-Type': 'application/json;charset=utf-8'},
})
}
// 导出文件请求定义
const postJsonToFile = function (baseURL, url, postData) {
return request({
baseURL,
url: url,
method: 'post',
data: postData,
headers: {'Content-Type': 'application/json;charset=utf-8'},
responseType: 'blob'
})
}
const getJsonToFile = function (baseURL, url, postData) {
return request({
baseURL,
url: url,
method: 'get',
data: postData,
headers: {'Content-Type': 'application/json;charset=utf-8'},
responseType: 'blob'
})
}
/**
* put请求
*/
const put = function (baseURL, url, data) {
if (data) {
data = qs.stringify(data);
}
return request({
baseURL,
url: url,
method: 'put',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
}
const putJson = function (baseURL, url, data) {
return request({
baseURL,
url: url,
method: 'put',
data: data,
headers: {'Content-Type': 'application/json;charset=utf-8'},
})
}
export default {
tokenName: TokenName,
request,
get,
post,
postJson,
postJsonToFile,
put,
putJson,
getJsonToFile
}

View File

@@ -1,7 +1,7 @@
/**
* 课程的操作,课程的添加,修改,列表查询,课程的审核发布等操作。
* 针对于管理员,教师的功能
*
*
**/
import ajax from '@/utils/xajax.js'
@@ -170,7 +170,9 @@ const updateContentOrders = function(cid,items) {
const detail = function(id) {
return ajax.get('/xboe/m/course/manage/detail?id=' + id);
}
const getDictIds = function(pid,type) {
return ajax.get(`/xboe/m/course/manage/getDictIds?pid=${pid}&type=${type}`);
}
/**
* 更新内容的名称
* @param {Object} data
@@ -274,7 +276,7 @@ const countWaitAudit = function() {
}
/**
* [已用courseAudit中的hrbpAuditList替换]
* [已用courseAudit中的hrbpAuditList替换]
* 当前用户需要审核的课程列表
* @param {Object} query 同pageList
*/
@@ -283,9 +285,9 @@ const auditList = function(query) {
}
/**
* 【已移到courseAudit中】
* 教师需要审核的课程列表
/**
* 【已移到courseAudit中】
* 教师需要审核的课程列表
*/
const teacherAuditList = function(query) {
return ajax.post('/xboe/m/course/audit/teacher-course', query);
@@ -446,6 +448,7 @@ export default {
findUpdateLogs,
getUpdateLog,
detail,
getDictIds,
saveContent,
pageList,
setEnabled,

View File

@@ -22,7 +22,7 @@ const pageList = function(data) {
/**
* 选择课件的查询,这里也是分页查询,只是返回的内容,字段会很少,用于课件制作那选择已有课件内容。
*
*
* @param {Object} data
* 查询参数如上面pageList方法
*/
@@ -47,7 +47,9 @@ const findList = function(data) {
}
*/
const saveUpload = function(data) {
return ajax.post('/xboe/m/course/file/upload/save', data);
return ajax.post('/xboe/m/course/file/upload/save', data, {
timeout: 60000
});
}
/**
@@ -88,4 +90,4 @@ export default {
batchUpdate,
detail,
delFile
}
}

View File

@@ -114,6 +114,10 @@ const studyVideoTime = function(data) {
return ajax.post('/xboe/school/study/course/study-video-time',data);
}
const updateStudyVideoTime = function(data) {
return ajax.post('/xboe/school/study/course/updateStudyVideoTime',data);
}
/**
* 获取上一次的学习内容
* @returns
@@ -408,6 +412,7 @@ export default {
studyIndex,
studyInfo,
studyVideoTime,
updateStudyVideoTime,
lastStudy,
studyContent,
appendStudyTime,

View File

@@ -38,7 +38,7 @@ const detailTeacher=function (id){
* tlevelId级别
* salaryId发薪地
* tsystemId
* } query
* @returns
*/

View File

@@ -1,5 +1,7 @@
import ajax from '@/utils/xajax.js'
import http from '../unionAjax'
import httpAjax from '../httpAjax'
const baseURL = process.env.VUE_APP_MANAGER_API_PATH;
@@ -47,6 +49,18 @@ const articlelist=function (type){
const courselist=function (data){
return ajax.post('/xboe/portal/index/courselist',data);
}
// 精品课信息列表
const qualitylist=function (data){
return httpAjax.post(baseURL,'/quality/home/qualityItem',data);
}
// 精品课分页查询
export const qualityPageList=function (data){
return httpAjax.post(baseURL,'/quality/home/qualityPages',data);
}
// 课程精品课标记时间年份列表
export const qualityCourseTimeMark=function (){
return httpAjax.post(baseURL,'/quality/manage/qualityYearList',{});
}
/**
* 首页新课程推荐列表
*/
@@ -61,5 +75,7 @@ export default {
articlelist,
courselist,
newCases,
getRecommendList
getRecommendList,
qualitylist,
qualityPageList
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,403 @@
<template>
<div class="ai-script">
<!-- 搜索和语言选择区域 -->
<div class="search-container">
<el-input
v-model="searchKeyword"
placeholder="请输入关键词查找文稿内容"
class="search-input"
prefix-icon="el-icon-search"
@keyup.enter.native="searchContent"
@input="handleInputChange"
clearable
native-type="text"
/>
<div class="language-selector">
<span class="language-label">语言</span>
<el-select v-model="selectedLanguage" class="language-select" @change="changeLanguage" placeholder="请选择语言">
<el-option v-for="lang in selectableLang" :key="lang.srclang" :label="getSelectLabel(lang)" :value="lang.srclang"></el-option>
</el-select>
</div>
</div>
<!-- 内容展示区域 -->
<div class="content-container">
<!-- 动态渲染内容块 -->
<div v-for="(item, index) in contentList" :key="index" class="content-item" :class="{'active': currentTime >= item.start && currentTime <= item.end}">
<div class="timestamp">
<div class="timestamp-text">
<i class="el-icon-time"></i>
{{ formatTime(item.start) }}
</div>
</div>
<el-card class="content-text" @click.native="scrollToTime(item.start)">
<div v-html="item.highlightedContent || item.text"></div>
</el-card>
</div>
</div>
</div>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
export default {
name: 'ai-script',
data() {
return {
searchKeyword: '',
selectedLanguage: 'zh-CN',
originalContentList: [],
contentList: [], // 用于显示的内容列表
isUserScrolling: false, // 用户是否正在滚动
userScrollTimeout: null // 滚动超时计时器
}
},
computed: {
...mapGetters([
'currentTime',
'selectableLang'
]),
},
mounted: function() {
// 添加滚动事件监听,检测用户手动滚动
const container = document.querySelector('.content-container');
if (container) {
container.addEventListener('scroll', this.handleUserScroll);
}
},
beforeDestroy: function() {
// 清理事件监听和计时器
const container = document.querySelector('.content-container');
if (container) {
container.removeEventListener('scroll', this.handleUserScroll);
}
if (this.userScrollTimeout) {
clearTimeout(this.userScrollTimeout);
}
},
watch: {
// 监听currentTime变化自动滚动到当前激活项
currentTime: function(newTime) {
// 只有当用户没有手动滚动时才执行自动滚动
if (!this.isUserScrolling) {
this.$nextTick(function() {
const activeElement = document.querySelector('.content-item.active');
if (activeElement) {
// 获取内容容器
const container = document.querySelector('.content-container');
// 计算元素是否在可视区域内
const containerRect = container.getBoundingClientRect();
const elementRect = activeElement.getBoundingClientRect();
// 如果元素不在可视区域内,则滚动到可视区域
if (elementRect.top < containerRect.top || elementRect.bottom > containerRect.bottom) {
// 计算元素相对于容器的偏移量而不是使用scrollIntoView
// 这样只会滚动content-container内部不会影响页面滚动
// 计算元素相对于容器的位置
const elementOffsetTop = activeElement.offsetTop;
const containerScrollTop = container.scrollTop;
const containerHeight = container.clientHeight;
const elementHeight = activeElement.clientHeight;
// 计算目标滚动位置,使元素居中显示
// 考虑容器的内边距和元素本身的高度
let targetScrollTop = elementOffsetTop - (containerHeight / 2) + (elementHeight / 2);
// 确保目标滚动位置不会小于0
targetScrollTop = Math.max(0, targetScrollTop);
// 确保目标滚动位置不会导致元素超出容器底部
const maxScrollTop = container.scrollHeight - containerHeight;
targetScrollTop = Math.min(targetScrollTop, maxScrollTop);
// 使用requestAnimationFrame实现平滑滚动
const startScrollTop = containerScrollTop;
const distance = targetScrollTop - startScrollTop;
const duration = 300; // 滚动持续时间,毫秒
let startTime = null;
function animateScroll(currentTime) {
if (!startTime) startTime = currentTime;
const timeElapsed = currentTime - startTime;
container.scrollTo({
top: startScrollTop + distance - elementHeight - 120,
behavior: 'smooth'
});
if (timeElapsed < duration) {
requestAnimationFrame(animateScroll);
}
}
requestAnimationFrame(animateScroll);
}
}
});
}
}
},
created() {
// 初始化时根据语言选择显示内容
this.changeLanguage(this.selectedLanguage)
},
methods: {
// 动态获取选择框的标签
getSelectLabel(lang) {
if (lang.srclang == 'zh-CN') {
return lang.label;
}
return `${lang.name} (${lang.label})`;
},
formatTime (time) {
// 格式化时间为HH:MM:SS如01:00:00
const hours = Math.floor(time / 3600);
const minutes = Math.floor((time % 3600) / 60);
const seconds = Math.floor(time % 60);
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
},
// 跳转到指定时间点
scrollToTime(time) {
console.log('跳转到时间点:', time);
this.$emit('changeCurrentTime', time);
// 设置用户滚动状态,避免自动滚动干扰
this.isUserScrolling = true;
if (this.userScrollTimeout) {
clearTimeout(this.userScrollTimeout);
}
this.userScrollTimeout = setTimeout(() => {
this.isUserScrolling = false;
}, 3000);
},
// 处理用户滚动事件
handleUserScroll: function() {
this.isUserScrolling = true;
// 清除之前的计时器
if (this.userScrollTimeout) {
clearTimeout(this.userScrollTimeout);
}
// 设置新的计时器3秒后恢复自动滚动
this.userScrollTimeout = setTimeout(() => {
this.isUserScrolling = false;
}, 3000);
},
searchContent () {
// 搜索功能实现
if (!this.searchKeyword.trim()) {
// 如果搜索关键词为空,显示所有内容
this.contentList = this.originalContentList.map(item => ({ ...item }));
return;
}
const keyword = this.searchKeyword.trim();
// 过滤包含关键词的内容
const filteredList = this.originalContentList.filter(item =>
item.text.includes(keyword)
);
if (filteredList.length === 0) {
// 如果没有搜索到内容,显示提示
this.$message({
message: '未找到相关内容',
type: 'info'
});
this.contentList = this.originalContentList.map(item => ({ ...item }));
} else {
// 对搜索到的内容进行关键词高亮处理
this.contentList = filteredList.map(item => ({
...item,
highlightedContent: this.highlightKeyword(item.text, keyword)
}));
console.log(this.contentList)
}
},
highlightKeyword(content, keyword) {
// 对关键词进行转义,防止正则表达式特殊字符的影响
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// 使用正则表达式全局匹配关键词并添加高亮标记
const regex = new RegExp(`(${escapedKeyword})`, 'gi');
return content.replace(regex, '<span style="color: rgba(6, 125, 255, 1); background: rgba(6, 125, 255, 0.1);">$1</span>');
},
changeLanguage (event) {
// this.selectedLanguage = event
this.selectableLang.forEach(item => {
if (item.srclang === event) {
console.log('当前语言:', item)
if (!item.originalContentList) {
try {
item.originalContentList = JSON.parse(item.subtitleData)
} catch (error) {
console.error('ai文稿格式有问题')
}
}
this.originalContentList = item.originalContentList || []
// 初始化时显示所有内容
this.contentList = this.originalContentList.map(item => ({ ...item }));
console.log('ai文稿数据', this.originalContentList)
}
})
console.log('切换语言:', event)
},
handleInputChange() {
// 当输入框内容变化时,如果为空则重置显示所有内容
if (!this.searchKeyword.trim()) {
this.contentList = this.originalContentList.map(item => ({ ...item }));
}
}
}
}
</script>
<style lang="scss" scoped>
.ai-script {
padding: 15px 0;
background-color: #fff;
border-radius: 8px;
}
.search-container {
display: flex;
align-items: center;
gap: 20px;
margin: 0 20px 15px 20px;
}
.search-box {
position: relative;
flex: 1;
max-width: 400px;
}
.search-input {
flex: 1;
}
:deep(.el-input__inner) {
border-radius: 20px;
border-color: #2688FF;
}
:deep(.el-input__inner:focus) {
border-color: #1a6fe0;
box-shadow: 0 0 0 2px rgba(38, 136, 255, 0.2);
}
:deep(.el-input__prefix) {
left: 15px;
}
:deep(.el-input__icon) {
color: #2688FF;
}
.language-selector {
display: flex;
align-items: center;
gap: 10px;
}
.language-label {
font-size: 14px;
color: #333;
}
.language-select {
width: 90px;
}
:deep(.el-select__inner) {
border-radius: 4px;
}
.content-container {
display: flex;
flex-direction: column;
gap: 20px;
max-height: 410px;
overflow-y: auto;
padding: 0 20px;
}
.content-item {
display: flex;
flex-direction: column;
gap: 7px;
}
.timestamp {
display: flex;
align-items: center;
font-size: 14px;
color: #666;
padding: 5px 0;
.timestamp-text{
display: flex;
align-items: center;
gap: 5px;
border-radius: 12px;
padding: 2px 12px;
font-size: 14px;
font-weight: 500;
line-height: 20px;
letter-spacing: 0.3px;
}
}
:deep(.el-icon-time) {
color: #2688FF;
}
.content-text {
cursor: pointer;
line-height: 1.6;
font-size: 14px;
color: rgba(102, 102, 102, 1);
border-radius: 6px;
overflow: hidden;
background: rgba(250, 250, 250, 1);
line-height: 22px;
letter-spacing: 0.28px;
}
.active {
.timestamp-text{
color: rgba(6, 125, 255, 1);
background: rgba(6, 125, 255, 0.1);
}
.content-text{
border: 1px solid rgba(116, 182, 255, 1);
box-shadow: 0px 0px 7px 0px rgba(6, 125, 255, 0.24);
background: rgba(250, 250, 250, 1);
}
}
:deep(.el-card__body) {
padding: 15px;
}
:deep(.el-card.is-hover-shadow:focus, .el-card.is-hover-shadow:hover) {
box-shadow: 0 2px 12px 0 rgba(38, 136, 255, 0.2);
}
/* 响应式设计 */
@media (max-width: 768px) {
.search-container {
flex-direction: column;
align-items: stretch;
}
.search-box {
max-width: none;
}
.language-selector {
justify-content: flex-end;
}
}
</style>

View File

@@ -50,7 +50,7 @@
<el-input-number v-model="duration" size="mini" :min="1" :max="100"></el-input-number>
</span>
</div>
<el-upload class="upload-demo" :headers="headers" :data="data" drag :action="uploadFileUrl" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload">
<el-upload ref="uploadRef" class="upload-demo" :headers="headers" :data="data" drag :action="uploadFileUrl" :on-success="handleUploadSuccess" :before-upload="handleBeforeUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">文件大小限制{{curComType.maxSizeName}},支持的文件类型{{curComType.fileTypes.join(',')}}</div>
@@ -195,6 +195,7 @@
// this.cware.content.content=result.filePath;
}else{
this.$message.error(rs.message);
this.$refs.uploadRef.clearFiles();
}
});
}else{

View File

@@ -141,6 +141,7 @@
<el-radio style="margin-right: 10px;" v-model="courseInfo.device" :label="1">PC端可见</el-radio>
<el-radio style="margin-right: 10px;" v-model="courseInfo.device" :label="2">移动端可见</el-radio>
<el-radio style="margin-right: 10px;" v-model="courseInfo.device" :label="3">多端可见</el-radio>
<el-radio style="margin-right: 10px;" v-model="courseInfo.device" v-if="isPermission" :label="4">仅内网访问</el-radio>
</el-form-item>
<el-form-item v-if="!weike.onlyRequired" label="课程来源">
<el-radio-group v-model="courseInfo.source">
@@ -157,6 +158,43 @@
placeholder="请尽量填写课程简介,用于列表中显示,可以让用户更容易了解课程信息">
</el-input>
</el-form-item>
<el-form-item label="AI设置">
<div style="margin-top: 7px;">
<div style="display: flex; align-items: center;gap: 5px;">
<el-switch v-model="courseInfo.aiSet" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiSetTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
<div v-show="courseInfo.aiSet==1" style="margin-left: -20px;">
<div style="display: flex; justify-content: space-between;;align-items: center;gap: 5px;margin: 10px 0;">
<div style="display: flex; align-items: center;gap: 5px;">
<span>AI摘要</span>
<el-switch v-model="courseInfo.aiAbstract" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiAbstractTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
<div style="display: flex; align-items: center;gap: 5px;">
<span>AI文稿</span>
<el-switch v-model="courseInfo.aiDraft" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiDraftTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
</div>
<div style="display: flex; align-items: center;gap: 5px;margin: 10px 0;margin-left: -30px;">
<span>AI翻译语种</span>
<el-select v-model="courseInfo.languageCode" placeholder="请选择" multiple filterable style="width: 240px;">
<el-option v-for="item in selectAllLang" :key="item.key" :label="item.label" :value="item.srclang"> </el-option>
</el-select>
<el-tooltip class="item" effect="dark" :content="aiTranslateTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
</div>
</div>
</el-form-item>
</el-col>
<el-col :span="14">
<div @click="checkCourse"><weikeContent ref="weikeContent" :reset="weikeReset" :contents="contentInfo.list" :course="courseInfo" min-height="644px"></weikeContent></div>
@@ -305,6 +343,7 @@
<el-radio v-model="courseInfo.device" :label="1">PC端可见</el-radio>
<el-radio v-model="courseInfo.device" :label="2">移动端可见</el-radio>
<el-radio v-model="courseInfo.device" :label="3">多端可见</el-radio>
<el-radio style="margin-right: 10px;" v-model="courseInfo.device" v-if="isPermission" :label="4">仅内网访问</el-radio>
</el-col>
<el-col :span="10">
<el-form-item label="课程来源">
@@ -327,6 +366,44 @@
placeholder="请尽量填写课程简介,用于列表中显示,可以让用户更容易了解课程信息">
</el-input>
</el-form-item>
<!-- ai播放器相关 -->
<el-form-item label="AI设置">
<div style="margin-top: 7px;">
<div style="display: flex; align-items: center;gap: 5px;">
<el-switch v-model="courseInfo.aiSet" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiSetTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
<div v-show="courseInfo.aiSet==1" style="margin-left: -20px;">
<div style="display: flex;align-items: center;gap: 80px;margin: 20px 0;">
<div style="display: flex; align-items: center;gap: 5px;">
<span>AI摘要</span>
<el-switch v-model="courseInfo.aiAbstract" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiAbstractTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
<div style="display: flex; align-items: center;gap: 5px;">
<span>AI文稿</span>
<el-switch v-model="courseInfo.aiDraft" :active-value="1" :inactive-value="0"></el-switch>
<el-tooltip class="item" effect="dark" :content="aiDraftTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
</div>
<div style="display: flex; align-items: center;gap: 5px;margin: 20px 0;margin-left: -30px;">
<span>AI翻译语种</span>
<el-select v-model="courseInfo.languageCode" placeholder="请选择" multiple filterable style="flex:1">
<el-option v-for="item in selectAllLang" :key="item.key" :label="item.label" :value="item.srclang"> </el-option>
</el-select>
<el-tooltip class="item" effect="dark" :content="aiTranslateTip" placement="top">
<i class="el-icon-question" style="margin-left: 5px; color: #909399; cursor: pointer;"></i>
</el-tooltip>
</div>
</div>
</div>
</el-form-item>
<!-- v-if="!weike.onlyRequired" -->
<!-- <el-form-item label="课程描述">
<WxEditor v-model="courseInfo.overview" :minHeight="50"></WxEditor>
@@ -488,6 +565,8 @@ export default {
refType:''
},
visibleShow:false,
isPermission:false,
dicts:[],
extendRefId:'',
extendRefType:'',
courseTeachers: [], //课程的老师
@@ -527,14 +606,23 @@ export default {
dlgShow: false
},
rightTypeId: {},
catalogSortDialogShow: false
catalogSortDialogShow: false,
selectedOrg: {
orgId: null,
name: ''
},
aiSetTip: '是否将课程进行AI处理', //提示信息
aiAbstractTip: '一键提炼课程视频核心要点,助力学员课前高效掌握重点,快速筛选学习资源', // 提示信息
aiDraftTip: '分段展示视频内容并精准同步时间轴,实现视频进度与文稿双向定位,学习内容触手可及', //提示信息
aiTranslateTip: '智能转换视频字幕与语音为多语种,支持全球学员按需切换语言,打破学习边界', // 提示信息
};
},
created() {
this.getSceneData();
},
computed: {
...mapGetters(['resOwnerMap', 'sysTypeMap','userInfo','identity']),
// ai播放器相关
...mapGetters(['resOwnerMap', 'sysTypeMap','userInfo','identity', 'selectAllLang']),
catalogTree() {
let treeList = [];
let $this = this;
@@ -552,14 +640,18 @@ export default {
},
watch: {
courseInfo: {
handler(newVal) {
//需要保存
handler(newVal, oldVal) {
// 需要保存
this.requireSaveCourse = true;
console.log("--- watch比较 = ", oldVal.orgId, newVal.orgId);
this.checkOrgPermission(newVal.orgId);
},
deep: true
}
},
mounted() {
this.getDictIds();
let extendFlag=this.$route.query.f; //是否是管理端过来的
this.extendRefId=this.$route.query.refId;
this.extendRefType=this.$route.query.refType;
@@ -581,6 +673,19 @@ export default {
this.loadUserGroup();
},
methods: {
// 检查机构权限
checkOrgPermission(orgId) {
console.log("--- 监测组织id orgId = ",orgId)
console.log("--- this.isPermission = ",this.isPermission)
console.log("--- device = ",this.courseInfo.device)
if (!orgId) {
this.isPermission = false;
return;
}
console.log("--- this.dicts = ",this.dicts)
this.isPermission = this.dicts.includes(orgId);
console.log("--- 监听结束 this.isPermission = ",this.isPermission)
},
// 关键字的更改
changeKeywords(option){
if(option.target.value){
@@ -885,11 +990,27 @@ export default {
this.courseCoverurl = '';
this.courseInfo.coverImg = '';
},
//获取字典信息
async getDictIds() {
console.log("--- 获取字典信息 1 = ", this.dicts);
try {
const response = await apiCourse.getDictIds(637, 1); // 确保返回 Promise
console.log("--- 获取字典信息 2 result= ", response);
if (response.status === 200) {
this.dicts = response.result.dicts; // 正确提取 dicts
console.log("--- 获取字典信息 3 = ", this.dicts);
}
} catch (error) {
console.error("获取字典信息失败:", error);
}
},
//获取课程信息
async getDetail(id) {
this.curCourseId = id;
this.orgName='';
let $this = this;
this.isPermission = false;
let $this = this;
try {
const { result, status } = await apiCourse.detail(id);
if (status === 200) {
@@ -906,7 +1027,23 @@ export default {
this.contentInfo.list = result.contents;
this.sectionInfo.list = result.sections;
this.courseTeachers = result.teachers; //课程的老师信息
this.isPermission = result.isPermission; //课程的老师信息
this.dicts = result.dicts; //课程的老师信息
console.log("--- 编辑查看 this.isPermission = ",this.isPermission)
console.log("--- 编辑查看 this.dicts = ",this.dicts)
// ai播放器相关
// 如果ai设置为空则给默认值 - 会看成新增状态
if(this.courseInfo.aiSet === null || this.courseInfo.aiSet === '' || this.courseInfo.aiSet === undefined){
this.courseInfo.isAddAI = 1; //暂时是否是新增
this.courseInfo.aiSet = 1;
this.courseInfo.aiAbstract = 1;
this.courseInfo.aiDraft = 1;
this.courseInfo.aiTranslate = 1;
this.courseInfo.languageCode = ['zh-CN', 'en-US'];
} else {
// 获取ai设置信息
this.courseInfo.isAddAI = 0;
}
if(!this.courseInfo.orgId){
//根据课程创建者获取机构id
apiUser.getOrgSimpleByUserId(result.course.sysCreateAid).then(ors=>{

View File

@@ -109,7 +109,7 @@ export default {
if(res.status==200){
this.info=res.result;
//检查是否过期
if(res.result.deadTime!=''){
if(res.result.deadTime!='' && res.result.deadTime != null){
var d = new Date(res.result.deadTime);
var now=new Date();
if(now.getTime() > d.getTime()){

View File

@@ -44,7 +44,7 @@
<!-- <svg-icon v-else style="margin-right: 0;" :style="{'font-size':(size+2)+'px'}" :icon-class="isFavorite?'scactive2':'xihuan'"></svg-icon> -->
<div v-else class="is_favorite" :class="isFavorite?'is_favorite_a':'is_favorite'"></div>
</el-tooltip>
<span v-if="!courseExclusive" class="interact-bar-value"> {{ data.favorites? data.favorites:0}}</span>
<span v-if="!courseExclusive" class="interact-bar-value"> {{ data.favorites? data.favorites:data.hasCollect?number(data.hasCollect):1}}</span>
</div>
<div v-if="shares" @click="addShare()" :style="`min-width: ${nodeWidth};`" class="interact-bar-btn" :class="{cursor:!readonly}">
<el-tooltip effect="light" content="分享" placement="top" :visible-arrow="false" popper-class="text-tooltip">
@@ -114,6 +114,8 @@ export default {
shares:0,
praises:0,
views:0,
courseId:'',
courseName:''
}
}
},
@@ -234,7 +236,7 @@ export default {
created(){
},
mounted() {
if(this.data && this.data.id && !this.readonly){
if(this.data && (this.data.id||this.data.courseId) && !this.readonly){
this.checkHas();
}
@@ -308,7 +310,7 @@ export default {
}
let msgPageParams=this.pageParams;
if(!msgPageParams){
msgPageParams=this.data.id;
msgPageParams=this.data.id ?this.data.id: this.data.courseId;
}
let message={
content,
@@ -331,9 +333,9 @@ export default {
})
},
checkHas(){
if(this.type>0 && !this.readonly && this.data.id){
if(this.type>0 && !this.readonly && (this.data.id||this.data.courseId)){
if(this.favorites){
apiFavorites.has(this.type,this.data.id).then(rs=>{
apiFavorites.has(this.type,(this.data.id || this.data.courseId)).then(rs=>{
if(rs.status==200 && rs.result){
this.isFavorite=true;
}else{
@@ -506,9 +508,11 @@ export default {
return;
}
//需要判断是否已点赞,已点赞的不再加
console.log(this.data,'---------------');
let postData={
objType:this.type,
objId:this.data.id,
objId:this.data.id ?this.data.id: this.data.courseId,
title:'',
}
if(this.loading) {
@@ -516,7 +520,7 @@ export default {
}
this.loading=true;
if(this.type==1){
postData.title=this.data.name;
postData.title=this.data.name?this.data.name:this.data.courseName;
}else if(this.type==60){
postData.title=this.data.content;
} else if(this.type==5){
@@ -525,7 +529,7 @@ export default {
postData.title=this.data.title;
}
if(this.isFavorite) {// 已经收藏,再次点击取消收藏
apiFavorites.remove(this.type,this.data.id).then(res=>{
apiFavorites.remove(this.type,this.data.id ?this.data.id: this.data.courseId).then(res=>{
this.loading=false;
if(res.status==200){
this.isFavorite=false;
@@ -554,7 +558,7 @@ export default {
this.$store.dispatch("unicomFavorites",true)
}
//if(this.type===2||this.type===4){
this.messageSave(this.data.id,this.data.title,this.userInfo.name,this.data.sysCreateBy,this.data.sysCreateAid,'收藏了我发布的');
this.messageSave(this.data.id ?this.data.id: this.data.courseId,this.data.title,this.userInfo.name,this.data.sysCreateBy,this.data.sysCreateAid,'收藏了我发布的');
//}
this.$message({message:'已加入收藏',type:'success'});
//this.$emit('addFavorite',res.result);//添加收藏,如果是true代表添加成功false代表已存在

View File

@@ -13,9 +13,9 @@
</router-link>
</div>
<div class="top-nav" :style="{color:textColor}" :class="current == 'course' ? activeNav : ''">
<router-link to="/course">课程
<a @click="handleChangeCourse">课程
<div :class="current == 'course' ? 'nav-bottbor' : ''"></div>
</router-link>
</a>
</div>
<div class="top-nav" :style="{color:textColor}" :class="current == 'case' ? activeNav : ''">
<router-link to="/case">案例
@@ -214,6 +214,12 @@ export default {
//this.loadPopupConfig();
},
methods: {
handleChangeCourse() {
const paths = ["/course","/qualityCourse"]
// 如果是 课程 和 精品课程, 那么就不再重定向
const needReload = paths.findIndex(e=> e === this.$route.path) === -1
if (needReload) this.$router.push({path: paths[0]})
},
setCurIdentity(iden){
this.$store.dispatch('SetCurIdentity',iden);

View File

@@ -119,7 +119,35 @@
</div>
<div class="player-time">{{ currentTimeFormat }} / {{ fullTimeFormat }}</div>
</div>
<!-- ai播放器相关 -->
<div class="player-controls-bottom-right">
<div class="player-controls-btn box-aiTranslate">
<div v-show="isSubtitle" class="player-controls-btn cursor-pointer btn-speed">
<span>{{!currentLang ? 'AI翻译' : currentLangLabel}}</span>
<div class="speed-control">
<ul class="speed-control-list">
<li
v-for="item in selectableLang"
:key="item.srclang"
@click="changeLang(item)"
:data-value="item.srclang"
class="one-line-ellipsis"
:title="item.label"
:class="{'current': currentLang === item.srclang}"
>{{ item.label }}</li>
</ul>
</div>
</div>
<div v-show="isSubtitle" style="margin-top: -3px;">|</div>
<div class="player-controls-btn" style="display: flex;gap: 0.3rem;align-items: center;">
<span>字幕</span>
<el-switch
@change="toggleSubtitle"
v-model="isSubtitle">
</el-switch>
</div>
<div style="margin-top: -3px;">|</div>
</div>
<div class="player-controls-btn cursor-pointer btn-speed">
<span>{{currentSpeed === 1 ? '倍速' : `${currentSpeed}x`}}</span>
<div class="speed-control">
@@ -224,6 +252,7 @@
import volumeBar from "@/components/VideoPlayer/volume-bar.vue";
import progressBar from "@/components/VideoPlayer/progress-bar.vue";
import playerBarrageScreen from "@/components/VideoPlayer/player-barrage-screen.vue";
import { mapGetters, mapMutations } from 'vuex';
export default {
name: "barrage-videoplayer",
@@ -301,10 +330,18 @@ export default {
fullTimeFormat: "00:00:00", // 视频总长度的文字
barrageTimelineStart: 0, // 弹幕时间轴的起始时间点(手动调整进度条触发更新)
isInit:false, // 是否初始化过
// ai播放器相关
isSubtitle: true, // 是否开启字幕
currentLangLabel:'', // 当前字幕语言
};
},
// ai播放器相关
computed: {
...mapGetters(['selectableLang','currentLang'])
},
created() {
// ai播放器相关
this.SET_currentLang('');
},
mounted() {
this.videoDom = this.$refs.video;
@@ -317,7 +354,7 @@ export default {
}
setInterval(() => {
//console.log('this.currentProgress::',this.currentProgress,this.isDrag,this.videoDom.currentTime , this.videoDom.duration)
console.log('当前状态:',this.currentProgress,this.isDrag,this.videoDom.currentTime , this.videoDom.duration)
// 视频播放时本地记录视频实时播放时长,视频设置了禁止拖动时执行
if(!this.isDrag){
var time = localStorage.getItem('videoProgressData')
@@ -364,6 +401,11 @@ export default {
}
// 根据视频的readyState判断下一帧是否已加载并控制loading的显示
this.isShowLoading = this.videoDom.readyState < 3;
console.log("当前缓存:"+this.videoDom.readyState)
if (this.videoDom.readyState < 3){
console.log("详细信息",this.videoDom)
console.log("卡了",this.videoDom.readyState)
}
//if()
//console.log(this.videoDom.readyState,'this.videoDom.readyState');
}, 1000);
@@ -406,6 +448,11 @@ export default {
// });
},
methods: {
// ai播放器相关
...mapMutations({
SET_currentLang: 'video/SET_currentLang',
SET_currentTime: 'video/SET_currentTime',
}),
//当视频由于需要缓冲下一帧而停止,解决一直计时的问题
onWaiting(){
console.log('触发了onWairing');
@@ -512,6 +559,7 @@ export default {
this.currentProgress = progressVideo;
this.barrageTimelineStart = newCurrentTime;
this.videoDom.currentTime = newCurrentTime;
this.updateProgressText();
},
/* 提高视频音量
*/
@@ -618,6 +666,8 @@ export default {
},
onAudioTimeUpdate() {
const currentTime = this.$refs.video.currentTime;
// ai播放器相关
this.SET_currentTime(currentTime)
this.$emit('onTimeUpdate', currentTime);
},
/**
@@ -635,9 +685,77 @@ export default {
this.$emit('onFullscreen',false);//全屏
}
}
},
/** ai播放器相关
* 切换字幕
*/
toggleSubtitle(value) {
if (this.videoDom && this.videoDom.textTracks && this.videoDom.textTracks.length >0) {
if (!value) {
// 关闭字幕
this.videoDom.textTracks[this.videoDom.textTracks.length - 1].mode = 'hidden';
} else {
// 打开字幕
this.videoDom.textTracks[this.videoDom.textTracks.length - 1].mode = 'showing';
}
}
},
/** ai播放器相关
* 切换字幕语言
*/
changeLang(item) {
this.SET_currentLang(item.srclang);
this.currentLangLabel = item.label;
console.log("changeLang",item);
// 先移除所有字幕轨道
Array.from(this.videoDom.querySelectorAll('track')).forEach(t => t.remove());
if(!item.vttContent){
console.log("字幕内容为空!")
return;
}
if(!item.srcUrl){
try{
const blob = new Blob([item.vttContent], { type: 'text/vtt' });
item.srcUrl = URL.createObjectURL(blob);
}catch(e){
console.log("字幕格式错误",e)
}
}
const trackEl = document.createElement('track');
trackEl.kind = 'subtitles';
trackEl.srclang = item.srclang;
trackEl.label = item.label;
trackEl.src = item.srcUrl;
trackEl.default = true; // 确保字幕默认启用
// 使用箭头函数保持this上下文
trackEl.addEventListener('load', () => {
console.log('字幕加载成功!');
// console.log('#########Track cues:', trackEl.track.cues);
});
trackEl.addEventListener('error', () => {
console.error('字幕加载失败!');
});
// 确保视频已加载到可添加轨道的状态
if (this.videoDom.readyState >= 1) {
this.videoDom.appendChild(trackEl);
this.videoDom.textTracks[this.videoDom.textTracks.length - 1].mode = 'showing';
} else {
this.videoDom.addEventListener('loadedmetadata', () => {
this.videoDom.appendChild(trackEl);
this.videoDom.textTracks[this.videoDom.textTracks.length - 1].mode = 'showing';
}, { once: true });
}
},
seekToTime(time) {
if (!this.videoDom) return;
this.videoDom.currentTime = time + 0.01;
this.isPlaying = true;
this.videoDom.play();
},
}
},
watch: {
currentVolume: function () {
@@ -901,6 +1019,12 @@ export default {
color: #fff;
margin-bottom: 0.5rem;
}
.box-aiTranslate{
display: flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
}
@media (device-width: 100vw) {
.player-controls-btn .player-controls-icon {
/* height: 26px; */

View File

@@ -37,7 +37,6 @@ export default {
},
isDrag:{
type: Boolean,
default: true,
},
blobId:{
type: String,

View File

@@ -2,7 +2,6 @@ import Vue from 'vue'
import VueRouter from 'vue-router'
/* Layout */
import Layout from '@/layout/index'
import LayoutPortal from '@/layout/portal'
import Grateful from '@/views/grateful'
Vue.use(VueRouter)
@@ -362,7 +361,15 @@ export const constantRoutes = [{
path: '/500',
component: (resolve) => require(['@/views/error/500'], resolve),
hidden: true
},
{
path: '/qualityCourse',
hidden: true,
component: (resolve) => require(['@/views/portal/course/qualityCourse'], resolve),
name: 'qualityCourse',
meta: {title: '精品课课程', keepAlive: true, icon: 'dashboard', noCache: true, affix: false},
}
]
const router = new VueRouter({

View File

@@ -28,5 +28,10 @@ const getters = {
studyTaskCount:state => state.user.studyTaskCount,
praisesUnicom:state =>state.pdf.praisesUnicom,
favoritesUnicom:state =>state.pdf.favoritesUnicom,
// ai播放器相关
selectAllLang:state => state.video.selectAllLang,
selectableLang:state => state.video.selectableLang,
currentLang:state => state.video.currentLang,
currentTime:state => state.video.currentTime,
}
export default getters

View File

@@ -12,6 +12,7 @@ import resOwner from './modules/resOwner'
import majorType from './modules/majorType'
import orgDomain from './modules/orgDomain'
import pdf from './modules/pdf'
import video from './modules/video' // ai播放器相关
Vue.use(Vuex)
@@ -27,7 +28,8 @@ const store = new Vuex.Store({
resOwner,
majorType,
orgDomain,
pdf
pdf,
video
},
getters
})

137
src/store/modules/video.js Normal file
View File

@@ -0,0 +1,137 @@
// ai播放器相关
const state = {
selectAllLang: [
{
key: 'ZH_CN',
srclang: 'zh-CN',
label: '中文',
name: '中文',
},
{
key: 'EN_US',
srclang: 'en-US',
label: '英语',
name: 'English',
},
{
key: 'JA_JP',
srclang: 'ja-JP',
label: '日语',
name: '日本語',
},
{
key: 'KO_KR',
srclang: 'ko-KR',
label: '韩语',
name: '한국어',
},
{
key: 'FR_FR',
srclang: 'fr-FR',
label: '法语',
name: 'français',
},
{
key: 'DE_DE',
srclang: 'de-DE',
label: '德语',
name: 'Deutsch',
},
{
key: 'ES_ES',
srclang: 'es-ES',
label: '西班牙语',
name: 'español',
},
{
key: 'RU_RU',
srclang: 'ru-RU',
label: '俄语',
name: 'русский',
},
{
key: 'PT_BR',
srclang: 'pt-BR',
label: '葡萄牙语',
name: 'português',
},
{
key: 'IT_IT',
srclang: 'it-IT',
label: '意大利语',
name: 'italiano',
},
{
key: 'AR_SA',
srclang: 'ar-SA',
label: '阿拉伯语',
name: 'العربية',
},
{
key: 'TH_TH',
srclang: 'th-TH',
label: '泰语',
name: 'ไทย',
},
{
key: 'VI_VN',
srclang: 'vi-VN',
label: '越南语',
name: 'tiếng Việt',
},
{
key: 'ID_ID',
srclang: 'id-ID',
label: '印度尼西亚语',
name: 'Bahasa Indonesia',
},
{
key: 'HI_IN',
srclang: 'hi-IN',
label: '印地语',
name: 'हिन्दी',
}
], // 全部语言列表
selectableLang: [], // 可选语言列表+字幕信息
currentLang: '', // 当前选中语言
currentTime: -1, // 当前视频时间
}
const mutations = {
SET_currentLang: (state, lang) => {
state.currentLang = lang
},
SET_selectableLang: (state, list = []) => {
let selectableLang = []
list.forEach(item => {
let selectItem = state.selectAllLang.find(selectItem => selectItem.srclang === item.language)
if (selectItem) {
selectableLang.push({
...item,
...selectItem,
})
}
})
state.selectableLang = selectableLang
},
SET_currentTime: (state, time) => {
state.currentTime = time
},
}
const actions = {
unicomPraises({ commit }, data) {
commit('SET_praisesUnicom', data)
},
unicomFavorites({ commit }, data) {
commit('SET_favoritesUnicom', data)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}

View File

@@ -153,9 +153,85 @@
</div>
</div>
<div class="xindex-content">
<!-- 推荐课程 -->
<div class="modules xcontent2">
<!-- <div class="xcontent2-main"> -->
<!--内容块-->
<!-- </div> -->
<!-- 精品课模块 -->
<div class="xcontent2-main">
<div class="modules-title xindex-main" v-if="this.qusisityList.list.length > 0">
<!-- <span class="modules-text" style="color: #3D86F4;">精品课</span> -->
<span class="quyer-tag" style="margin-left: 0px;">
<!-- <img src="../assets/images/tutoring1.pn" alt=""> -->
<img class="modules-text" style="height: 28px;" src="../assets/images/course/courseTitle.png" alt="">
</span>
<span class="more">
<router-link to="/qualityCourse">查看更多>></router-link>
</span>
</div>
<div
v-for="(course, eIndex) in exquisiteList"
:key="'cc' + eIndex"
class="xindex-course courseBg"
style="position: relative;margin-top: 20px;"
>
<div style="position: absolute; right: 25px; bottom: 72px">
<interactBar
nodeWidth="20px"
:courseExclusive="true"
:type="1"
:data="course"
:comments="false"
:praises="false"
:shares="false"
:views="false"
>
</interactBar>
<!-- <svg-icon style="font-size: 32px;margin-top: -5px;" icon-class="collectedCourse"></svg-icon> -->
</div>
<a @click="toCourseDetail(course)">
<div class="xindex-course-image">
<course-image :course="course"></course-image>
<!-- <span v-if="course.type == 20 || 10" class="course-type"
>录播课</span
> -->
<img v-if="course.type == 20 || 10" src="../assets/images/course/courseTag.png" class="course-type" style="background: none;" alt="">
</div>
<div
style="width: 80%"
:title="course.courseName"
class="course-title portal-title-tow two-line-ellipsis"
>
{{ course.courseName }}
</div>
<div class="course-author">
<div class="course-author-left">
{{ course.authorInfo.name }}
<span class="study-num"
>{{ formatNum(course.studyNum) }}人学习</span
>
</div>
<div style="display: flex">
<div v-if="course.courseScore">
<span class="course-score-value" style="margin-left: 10px"
>{{ toScore(course.courseScore) }}</span
>
</div>
<div v-else class="course-score-no">未评分</div>
</div>
</div>
</a>
</div>
<!--内容块-->
<div class="modules-title xindex-main">
<span class="modules-text">推荐课程</span>
@@ -1137,6 +1213,9 @@ export default {
orderType: 2,
list: [],
},
qusisityList: {
list: [],
},
// 推荐课程
recommendedList:{
list: [],
@@ -1164,6 +1243,7 @@ export default {
},
mounted() {
this.getCourseData(1);
this.getEsqusiteList();
this.getRecommendList();
this.getPositive()
this.getCaseData();
@@ -1227,6 +1307,10 @@ export default {
courseComputedTwoList(){
return this.courseList.list.slice(3)
},
// 精品课展示
exquisiteList() {
return this.qusisityList.list.slice(0,3)
},
},
methods: {
getPositive() {
@@ -1421,21 +1505,27 @@ export default {
//二期调整,直接改成一个地址
//return this.webBaseUrl + '/course/detail?id=' + item.id;
let $this = this;
let cId = "";
if (item.id) {
cId = item.id;
} else {
cId = item.courseId;
}
if (item.type == 10) {
//return this.webBaseUrl + "/course/studyindex?id=" + item.id;
//console.log("直接进入学习页面");
this.$router.push("/course/studyindex?id=" + item.id);
this.$router.push("/course/studyindex?id=" + cId);
} else if (item.type == 20) {
apiCourseStudy.hasSignup(item.id).then((rs) => {
apiCourseStudy.hasSignup(cId).then((rs) => {
if (rs.status == 200) {
//return $this.webBaseUrl + "/course/studyindex?id=" + item.id;
this.$router.push("/course/studyindex?id=" + item.id);
//return $this.webBaseUrl + "/course/studyindex?id=" + cId;
this.$router.push("/course/studyindex?id=" + cId);
} else {
//return $this.webBaseUrl + "/course/detail?id=" + item.id;
this.$router.push("/course/detail?id=" + item.id);
//return $this.webBaseUrl + "/course/detail?id=" + cId;
this.$router.push("/course/detail?id=" + cId);
}
});
//return $this.webBaseUrl + "/course/detail?id=" + item.id;
//return $this.webBaseUrl + "/course/detail?id=" + cId;
}
},
orderTypeFilter(val) {
@@ -1472,6 +1562,29 @@ export default {
}
})
},
//精品课展示
getEsqusiteList(){
let course = {
aid: this.userInfo.aid,
}
apiIndex.qualitylist(course).then((res) => {
let courseIds = [];
res.data.result.forEach((item) => {
item.authorInfo = {
aid: "",
name: "",
orgInfo: "",
avatar: "",
code: "",
sex: null,
};
courseIds.push(item.courseId);
});
this.loadCouserTeacher(res.data.result, courseIds);
console.log(res.data.result,'--------------------------');
this.qusisityList.list = res.data.result;
})
},
getCourseData(pageIndex) {
this.isNext = false;
let { orderType, num } = this.courseList;
@@ -1671,7 +1784,7 @@ export default {
let userIds = [];
list.forEach((item, index) => {
cres.result.some((courseTeahcer) => {
if (courseTeahcer.courseId == item.id) {
if (courseTeahcer.courseId == (item.id||item.courseId)) {
if (courseTeahcer.teacherIds) {
userIds.push(courseTeahcer.teacherIds[0]);
item.authorInfo.aid = courseTeahcer.teacherIds[0];
@@ -2661,6 +2774,7 @@ export default {
// padding-bottom: 10px;
display: flex;
justify-content: space-between;
margin-bottom: 20px;
.course-author-left {
font-size: 14px;
@@ -3009,4 +3123,17 @@ export default {
}
}
}
.courseBg{
// width: 332px;
// height: 323px;
// background: url("../assets/images/course/courseBackground.png") no-repeat;
// background-size: 100% 100%; /* 或 use 'contain' */
// background-position: center;
// border: none;
border-radius: 12px;
background: linear-gradient(135deg, #e6f7ff, #f0f8ff, #ffffff);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
border: 1px solid #d9edf7;
//overflow: hidden;
}
</style>

View File

@@ -483,8 +483,11 @@ export default {
} else if (this.form.device2 === true) {
this.form.device = 2;
}
//时长,秒与分钟的转化
//if(this.form.)
// 时长,秒与分钟的转化
if (this.form.minute) {
this.form.duration = this.form.minute * 60;
}
try {
const { status,message} = await coueseFile.batchUpdate([this.form]);
if (status === 200) {

View File

@@ -60,101 +60,108 @@
</div>
<div style="width:390px">
<el-button type="primary" @click="searchData(true)" icon="el-icon-search" >搜索</el-button>
<el-button icon="el-icon-refresh-right" type="primary" style="margin-left:5px" @click="reset">重置</el-button>
<el-button icon="el-icon-refresh-right" type="primary" style="margin-left:5px" @click="reset">重置</el-button>
</div>
</div>
<el-row :gutter="20" style="margin-top:10px">
<el-col :span="4">
<!-- <el-button icon="el-icon-folder" type="primary" size="small">导出</el-button> -->
<el-button class="Create-coures" type="primary" @click="addNewCourse()" icon="el-icon-plus">新建课程</el-button>
</el-col >
<!-- ai播放器相关 -->
<el-col :span="24">
<!-- <el-button icon="el-icon-folder" type="primary" size="small">导出</el-button> -->
<el-button class="Create-coures" type="primary" @click="addNewCourse()" icon="el-icon-plus">新建课程</el-button>
<el-button type="primary" @click="setLanguage()" icon="el-icon-connection" :disabled="selectedCourses.length === 0">设置语种</el-button>
<el-button type="primary" @click="enableAI()" icon="el-icon-switch-button" :disabled="selectedCourses.length === 0">开启AI处理</el-button>
</el-col >
</el-row>
</div>
<div style="margin-right:30px;">
<el-table style="margin:10px 32px 10px 22px;" :data="pageData" border stripe>
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column v-if="forChoose" label="选择" width="80">
<template slot-scope="scope" v-if="scope.row.published">
<el-button type="default" size="mini" @click="handleChoose(scope.row)">选择</el-button>
</template>
</el-table-column>
<el-table-column label="名称" prop="name" width="200" show-overflow-tooltip>
<template slot-scope="scope">
<span class="previewStyle" @click="viewTopic(scope.row)">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="内容分类" prop="sysType" sortable width="240px">
<template slot-scope="scope">
<span>{{sysTypeName(scope.row.sysType1)}}</span>
<span v-if="scope.row.sysType2 !=''">/{{sysTypeName(scope.row.sysType2)}}</span>
<span v-if="scope.row.sysType3 !=''">/{{sysTypeName(scope.row.sysType3)}}</span>
</template>
</el-table-column>
<el-table-column label="关键字" :show-overflow-tooltip="true" prop="name" width="200px">
<template slot-scope="scope">
{{ scope.row.keywords }}
</template>
</el-table-column>
<!-- <el-table-column label="资源归属" sortable prop="author" width="240px">
<template slot-scope="scope">
<span>{{resOwnerName(scope.row.resOwner1)}}</span>
<span v-if="scope.row.resOwner2 != ''">/{{resOwnerName(scope.row.resOwner2)}}</span>
<span v-if="scope.row.resOwner3 != ''">/{{resOwnerName(scope.row.resOwner3)}}</span>
</template>
</el-table-column> -->
<!-- <el-table-column label="授课方式" prop="type" width="120px">
<template slot-scope="scope">
{{ courseType(scope.row.type)}}
</template>
</el-table-column> -->
<el-table-column label="状态" prop="status" width="120px">
<template slot-scope="scope">
<!-- 1未提交 2.已提交 = 未审核 5 已审核 -->
<span v-if="scope.row.status == 1">未提交</span>
<span v-if="scope.row.status == 2">待审核</span>
<span v-if="scope.row.status == 5">已审核</span>
<span v-if="scope.row.status == 3">审核未通过</span>
</template>
</el-table-column>
<el-table-column label="是否发布" width="130px">
<template slot-scope="scope">
{{ scope.row.published == true ? '已发布' : '未发布' }}
</template>
</el-table-column>
<el-table-column label="创建人" prop="sysCreateBy"></el-table-column>
<el-table-column label="创建时间" prop="sysCreateTime" width="230px" show-overflow-tooltip></el-table-column>
<el-table-column label="是否停用" width="130px">
<template slot-scope="scope">
{{ scope.row.enabled == true ? '启用' : '停用' }}
</template>
</el-table-column>
<el-table-column label="是否置顶" width="130px">
<template slot-scope="scope">
{{ scope.row.isTop == true ? '置顶' : '未置顶' }}
</template>
</el-table-column>
<el-table-column label="操作" width="180px" fixed="right">
<template slot-scope="scope" class="btn-gl">
<!-- 20240621 修改scope.row.isPermission = fasle 时不展示操作按钮-->
<el-button type="text" size="mini" v-if="scope.row.isPermission && scope.row.status == 5 && !scope.row.published" @click="releaseData(scope.row)">发布</el-button>
<el-button v-if="scope.row.isPermission && pageManage && scope.row.published" @click="showStudent(scope.row)" type="text" size="mini">学员</el-button>
<el-button v-if="scope.row.isPermission && !forChoose && scope.row.published" @click="showManageStudy(scope.row)" type="text" size="mini">管理</el-button>
<el-button v-if="scope.row.isPermission && !forChoose && scope.row.status == 2" @click="withdraw(scope.row)" type="text" size="mini">撤回</el-button>
<el-button v-if="scope.row.isPermission && scope.row.status != 2" type="text" size="mini" @click="editCurriculum(scope.row)">编辑</el-button>
<el-button v-if="scope.row.isPermission && (scope.row.status != 2 && !scope.row.published) || scope.row.isPermission &&!scope.row.enabled" type="text" size="mini" @click="delItem(scope.row)">删除</el-button>
<el-dropdown v-if="scope.row.isPermission && scope.row.published" type="text" size="mini" style="margin-left:10px">
<el-button type="text" size="mini">更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="copyCourse(scope.row)">复制</el-dropdown-item>
<el-dropdown-item v-if="scope.row.published" @click.native="isDisable(scope.row)">{{scope.row.enabled? '停用':'启用'}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.published" @click.native="showQrimage(scope.row)">二维码</el-dropdown-item><!--发布之后才可以查看二维码-->
<el-dropdown-item v-if="scope.row.published" @click.native="setTop(scope.row)">{{scope.row.isTop? '取消置顶':'置顶'}}</el-dropdown-item>
<!-- ai播放器相关 -->
<el-table style="margin:10px 32px 10px 22px;" :data="pageData" border stripe @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column v-if="forChoose" label="选择" width="80">
<template slot-scope="scope" v-if="scope.row.published">
<el-button type="default" size="mini" @click="handleChoose(scope.row)">选择</el-button>
</template>
</el-table-column>
<el-table-column label="名称" prop="name" width="200" show-overflow-tooltip>
<template slot-scope="scope">
<span class="previewStyle" @click="viewTopic(scope.row)">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="内容分类" prop="sysType" sortable width="240px">
<template slot-scope="scope">
<span>{{sysTypeName(scope.row.sysType1)}}</span>
<span v-if="scope.row.sysType2 !=''">/{{sysTypeName(scope.row.sysType2)}}</span>
<span v-if="scope.row.sysType3 !=''">/{{sysTypeName(scope.row.sysType3)}}</span>
</template>
</el-table-column>
<el-table-column label="关键字" :show-overflow-tooltip="true" prop="name" width="200px">
<template slot-scope="scope">
{{ scope.row.keywords }}
</template>
</el-table-column>
<!-- <el-table-column label="资源归属" sortable prop="author" width="240px">
<template slot-scope="scope">
<span>{{resOwnerName(scope.row.resOwner1)}}</span>
<span v-if="scope.row.resOwner2 != ''">/{{resOwnerName(scope.row.resOwner2)}}</span>
<span v-if="scope.row.resOwner3 != ''">/{{resOwnerName(scope.row.resOwner3)}}</span>
</template>
</el-table-column> -->
<!-- <el-table-column label="授课方式" prop="type" width="120px">
<template slot-scope="scope">
{{ courseType(scope.row.type)}}
</template>
</el-table-column> -->
<el-table-column label="状态" prop="status" width="120px">
<template slot-scope="scope">
<!-- 1未提交 2.已提交 = 未审核 5 已审核 -->
<span v-if="scope.row.status == 1">未提交</span>
<span v-if="scope.row.status == 2">审核</span>
<span v-if="scope.row.status == 5">已审核</span>
<span v-if="scope.row.status == 3">审核未通过</span>
</template>
</el-table-column>
<el-table-column label="是否发布" width="130px">
<template slot-scope="scope">
{{ scope.row.published == true ? '已发布' : '未发布' }}
</template>
</el-table-column>
<el-table-column label="创建人" prop="sysCreateBy"></el-table-column>
<el-table-column label="创建时间" prop="sysCreateTime" width="230px" show-overflow-tooltip></el-table-column>
<el-table-column label="是否停用" width="130px">
<template slot-scope="scope">
{{ scope.row.enabled == true ? '启用' : '停用' }}
</template>
</el-table-column>
<el-table-column label="是否置顶" width="130px">
<template slot-scope="scope">
{{ scope.row.isTop == true ? '置顶' : '未置顶' }}
</template>
</el-table-column>
<el-table-column label="操作" width="180px" fixed="right">
<template slot-scope="scope" class="btn-gl">
<!-- 20240621 修改scope.row.isPermission = fasle 时不展示操作按钮-->
<!-- ai播放器相关 -->
<el-button v-if="scope.row.isPermission && scope.row.status != 2" type="text" size="mini" @click="setAI(scope.row)">AI设置</el-button>
<el-button type="text" size="mini" v-if="scope.row.isPermission && scope.row.status == 5 && !scope.row.published" @click="releaseData(scope.row)">发布</el-button>
<el-button v-if="scope.row.isPermission && pageManage && scope.row.published" @click="showStudent(scope.row)" type="text" size="mini">学员</el-button>
<el-button v-if="scope.row.isPermission && !forChoose && scope.row.published" @click="showManageStudy(scope.row)" type="text" size="mini">管理</el-button>
<el-button v-if="scope.row.isPermission && !forChoose && scope.row.status == 2" @click="withdraw(scope.row)" type="text" size="mini">撤回</el-button>
<el-button v-if="scope.row.isPermission && scope.row.status != 2" type="text" size="mini" @click="editCurriculum(scope.row)">编辑</el-button>
<el-button v-if="scope.row.isPermission && (scope.row.status != 2 && !scope.row.published) || scope.row.isPermission &&!scope.row.enabled" type="text" size="mini" @click="delItem(scope.row)">删除</el-button>
<el-dropdown v-if="scope.row.isPermission && scope.row.published" type="text" size="mini" style="margin-left:10px">
<el-button type="text" size="mini">更多<i class="el-icon-arrow-down el-icon--right"></i></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="copyCourse(scope.row)">复制</el-dropdown-item>
<el-dropdown-item v-if="scope.row.published" @click.native="isDisable(scope.row)">{{scope.row.enabled? '停用':'启用'}}</el-dropdown-item>
<el-dropdown-item v-if="scope.row.published" @click.native="showQrimage(scope.row)">二维码</el-dropdown-item><!--发布之后才可以查看二维码-->
<el-dropdown-item v-if="scope.row.published" @click.native="setTop(scope.row)">{{scope.row.isTop? '取消置顶':'置顶'}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</div>
@@ -287,6 +294,231 @@
<div>
<course-form ref="courseForm" @submitSuccess="searchData" @close="searchData"></course-form>
</div>
<!-- ai播放器相关 -->
<!-- 设置语种弹框 -->
<el-dialog
title="AI翻译"
:visible.sync="languageSetting.dlgShow"
width="500px"
:close-on-click-modal="false"
>
<div style="margin-bottom: 20px;">
<div style="margin-bottom: 15px;">请选择课程所支持语种</div>
<el-select
v-model="languageSetting.selectedLanguages"
multiple
placeholder="请选择语种"
style="width: 100%;"
>
<el-option
v-for="lang in selectAllLang"
:key="lang.srclang"
:label="lang.label"
:value="lang.srclang"
></el-option>
</el-select>
</div>
<div style="color: #ff4d4f; font-size: 12px;">
仅支持对已开启AI处理的课程进行批量语种设置所选的课程中有{{languageSetting.aiSetNoNum}}个未开启AI处理的课程以上配置仅对{{languageSetting.aiSetNum}}个已开启AI处理的课程生效
</div>
<template #footer>
<el-button @click="languageSetting.dlgShow = false">取消</el-button>
<el-button type="primary" @click="confirmLanguageSetting">确认</el-button>
</template>
</el-dialog>
<!-- 开启AI处理弹框 -->
<el-dialog
title="开启AI处理"
:visible.sync="aiProcessSetting.dlgShow"
width="400px"
>
<div class="ai-process-dialog">
<!-- AI处理状态 -->
<div class="form-item">
<span class="form-label">
<el-tooltip class="item" effect="dark" :content="aiSetTip" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
AI处理
</span>
<span class="status-text">
{{ aiProcessSetting.aiSet === 1 ? '开启' : '关闭' }}
</span>
<el-switch
v-model="aiProcessSetting.aiSet"
:active-value="1"
:inactive-value="0"
></el-switch>
</div>
<div v-show="aiProcessSetting.aiSet === 1">
<!-- 是否生成AI摘要 -->
<div class="form-item">
<span class="form-label">
<el-tooltip class="item" effect="dark" :content="aiAbstractTip" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
AI摘要
</span>
<span class="status-text">
{{ aiProcessSetting.aiAbstract === 1 ? '开启' : '关闭' }}
</span>
<el-switch
v-model="aiProcessSetting.aiAbstract"
:active-value="1"
:inactive-value="0"
>
</el-switch>
</div>
<!-- 是否生成AI文稿 -->
<div class="form-item">
<span class="form-label">
<el-tooltip class="item" effect="dark" :content="aiDraftTip" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
AI文稿
</span>
<span class="status-text">
{{ aiProcessSetting.aiDraft === 1 ? '开启' : '关闭' }}
</span>
<el-switch
v-model="aiProcessSetting.aiDraft"
:active-value="1"
:inactive-value="0"
>
</el-switch>
</div>
<!-- 课程支持语种选择 -->
<div class="form-item" style="flex-flow: column;align-items: baseline;">
<span class="form-label">
<el-tooltip class="item" effect="dark" :content="aiTranslateTip" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
AI翻译语种
</span>
<el-select
v-model="aiProcessSetting.languageCode"
multiple
style="width: 100%;"
placeholder="请选择语种"
>
<el-option
v-for="lang in selectAllLang"
:key="lang.srclang"
:label="lang.label"
:value="lang.srclang"
></el-option>
</el-select>
</div>
</div>
<!-- 提示信息 -->
<div class="tips">
<span>已跳过{{aiProcessSetting.aiSetNum}}个已开启AI处理的课程仅更新剩余{{aiProcessSetting.aiSetNoNum}}</span>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="aiProcessSetting.dlgShow = false">取消</el-button>
<el-button type="primary" @click="confirmAiProcess">确认</el-button>
</span>
</el-dialog>
<!-- AI设置弹框 -->
<el-dialog
title="AI设置"
:visible.sync="aiSetting.dlgShow"
width="500px"
>
<div class="ai-setting-dialog">
<!-- AI功能状态 -->
<div class="form-item">
<span class="form-label">
<el-tooltip class="item" effect="dark" content="是否将课程进行AI处理" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
AI功能状态
</span>
<span class="status-text">
{{ aiSetting.aiSet === 1 ? '已开放' : '未开放' }}
</span>
<el-switch
v-model="aiSetting.aiSet"
:active-value="1"
:inactive-value="0"
></el-switch>
</div>
<div v-show="aiSetting.aiSet === 1">
<!-- AI摘要状态 -->
<div class="form-item">
<span class="form-label">AI摘要状态</span>
<span class="status-badge" :class="{'status-badge--active': aiSetting.aiAbstract === 1}">
{{ aiSetting.aiAbstract === 1 ? '已上架' : '已下架' }}
</span>
<div class="action-buttons">
<el-button type="text" @click="aiSetting.aiAbstract = 0">
{{ aiSetting.aiAbstract === 0 ? '上架' : '下架' }}
</el-button>
<el-button type="text" >编辑</el-button>
</div>
</div>
<!-- AI文稿状态 -->
<div class="form-item">
<span class="form-label">AI文稿状态</span>
<span class="status-badge" :class="{'status-badge--active': aiSetting.aiDraft === 1}">
{{ aiSetting.aiDraft === 1 ? '已上架' : '已下架' }}
</span>
<div class="action-buttons">
<el-button type="text" @click="aiSetting.aiDraft = 0">
{{ aiSetting.aiDraft === 0 ? '上架' : '下架' }}
</el-button>
</div>
</div>
<!-- AI翻译状态 -->
<div class="form-item">
<span class="form-label">AI翻译状态</span>
<span class="status-badge" :class="{'status-badge--active': aiSetting.aiTranslate === 1}">
{{ aiSetting.aiTranslate === 1 ? '已上架' : '已下架' }}
</span>
<div class="action-buttons">
<el-button type="text" @click="aiSetting.aiTranslate = 0">
{{ aiSetting.aiTranslate === 0 ? '上架' : '下架' }}
</el-button>
<el-button type="text" >编辑</el-button>
</div>
</div>
<!-- 支持语种 -->
<div class="form-item">
<span class="form-label">支持语种</span>
<div class="languages-list">
<div class="language-tag">
中文
<span class="status-badge">已下架</span>
</div>
<div class="language-tag">
英语
<span class="status-badge">生成中</span>
</div>
<div class="language-tag">
越南语
<span class="status-badge status-badge--active">已上架</span>
</div>
</div>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="aiSetting.dlgShow = false">取消</el-button>
<el-button type="primary" @click="confirmAISetting">确认</el-button>
</span>
</el-dialog>
</div>
</template>
@@ -307,8 +539,9 @@ import apiUserbasic from "@/api/boe/userbasic.js"
export default {
name: 'manageCourse',
components: {courseForm, manager, auditCourse1, auditCourse2,adminPage},
// ai播放器相关
computed: {
...mapGetters(['resOwnerMap','sysTypeMap','userInfo']),
...mapGetters(['resOwnerMap','sysTypeMap','userInfo', 'selectAllLang']),
},
data() {
return {
@@ -392,6 +625,32 @@ export default {
},
extendRefId:'',
extendRefType:'',
// ai播放器相关
selectedCourses: [], //已选课程
languageSetting: { // 设置语种弹框
dlgShow: false,
languageCode: ['zh-CN', 'en-US'] // 默认选中的语种
},
aiProcessSetting: { // 开启AI处理弹框
dlgShow: true,
aiSet: 1,
aiAbstract: 1,
aiDraft: 1,
languageCode: ['zh-CN', 'en-US'] // 默认选中的语种
},
aiSetting: { // AI设置弹框
dlgShow: false,
courseId: '',
aiSet: 1,
aiAbstract: 1, // 1:上架 0:下架
aiDraft: 1, // 1:上架 0:下架
aiTranslate: 1, // 1:上架 0:下架
languageCode: ['zh-CN', 'en-US', 'vi-VN'] // 支持的语种
},
aiSetTip: '是否将课程进行AI处理', //提示信息
aiAbstractTip: '一键提炼课程视频核心要点,助力学员课前高效掌握重点,快速筛选学习资源', // 提示信息
aiDraftTip: '分段展示视频内容并精准同步时间轴,实现视频进度与文稿双向定位,学习内容触手可及', //提示信息
aiTranslateTip: '智能转换视频字幕与语音为多语种,支持全球学员按需切换语言,打破学习边界', // 提示信息
};
},
mounted() {
@@ -449,6 +708,7 @@ export default {
inputOn() {
this.$forceUpdate();
},
// 置顶
setTop(row) {
let params = {
@@ -885,6 +1145,143 @@ export default {
saveNewCatalogZhang() {
this.catalogs.addNewZhang = false;
},
// ai播放器相关
handleSelectionChange(val){
this.selectedCourses = val;
console.log(val);
},
// 获取选中课程的AI信息
getAIInfoByList(list = []) {
let selectNum = 0; // 选中的课程数量
let aiSetNum = 0; // 已设置AI的课程数量
let aiSetNoNum = 0; // 未设置AI的课程数量
list.forEach(item => {
if(item.aiSet === 1){
aiSetNum++;
}else{
aiSetNoNum++;
}
});
return {
selectNum,
aiSetNum,
aiSetNoNum
}
},
// AI设置
setAI(row) {
this.aiSetting.courseId = row.id;
// 这里可以添加获取当前课程AI设置的逻辑
this.aiSetting.dlgShow = true;
},
// 确认AI设置
confirmAISetting() {
const { courseId, aiSet, aiAbstract, aiDraft, aiTranslate } = this.aiSetting;
// 这里可以添加保存AI设置的API调用
console.log('保存AI设置', {
courseId,
aiSet,
aiAbstract,
aiDraft,
aiTranslate
});
// 模拟成功保存
this.$message.success('AI设置保存成功');
this.aiSetting.dlgShow = false;
// 可以选择是否刷新列表数据
},
setLanguage() {
if (this.selectedCourses.length > 0) {
this.languageSetting = {...this.languageSetting, ...this.getAIInfoByList(this.selectedCourses)}
this.languageSetting.dlgShow = true;
}
},
enableAI() {
// 开启AI处理按钮点击事件
if (this.selectedCourses.length > 0) {
this.aiProcessSetting = {...this.aiProcessSetting, ...this.getAIInfoByList(this.selectedCourses)}
this.aiProcessSetting.dlgShow = true;
}
},
async confirmLanguageSetting() {
try {
// 收集选中的课程ID
const courseIds = this.selectedCourses.map(course => course.id).join(',');
// 获取选择的语种
const languages = this.languageSetting.selectedLanguages.join(',');
// 这里可以根据实际需求调用API进行语种设置
console.log('批量设置课程语种', { courseIds, languages });
// 显示成功提示
this.$message({
type: 'success',
message: `已成功为${this.selectedCourses.length}个课程设置语种`,
offset: 50
});
// 关闭弹框
this.languageSetting.dlgShow = false;
// 刷新数据(如果需要)
// this.searchData();
} catch (error) {
console.error('设置语种失败', error);
this.$message({
type: 'error',
message: '设置语种失败,请稍后重试',
offset: 50
});
}
},
async confirmAiProcess() {
try {
// 收集选中的课程ID
const courseIds = this.selectedCourses.map(course => course.id).join(',');
// 获取AI处理配置
const { aiSet, aiAbstract, aiDraft, selectedLanguages } = this.aiProcessSetting;
// 这里可以根据实际需求调用API进行AI处理设置
console.log('批量开启AI处理', {
courseIds,
aiSet,
aiAbstract,
aiDraft,
languages: selectedLanguages.join(',')
});
// 模拟计算跳过和更新的课程数量
const totalCourses = this.selectedCourses.length;
const skippedCount = Math.floor(totalCourses * 0.2); // 假设20%的课程已开启AI处理
const updatedCount = totalCourses - skippedCount;
// 显示成功提示
this.$message({
type: 'success',
message: `已跳过${skippedCount}个已开启AI处理的课程成功为${updatedCount}个课程更新AI处理设置`,
offset: 50
});
// 关闭弹框
this.aiProcessSetting.dlgShow = false;
// 刷新数据
this.searchData();
} catch (error) {
console.error('开启AI处理失败', error);
this.$message({
type: 'error',
message: '开启AI处理失败请稍后重试',
offset: 50
});
}
},
}
};
</script>
@@ -953,4 +1350,38 @@ export default {
.el-dialog__body {
overflow: hidden;
}
.form-item{
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.tips {
color: #f56c6c;
font-size: 12px;
margin: 10px 0;
line-height: 1.5;
}
.status-badge{
display: inline-block;
padding: 3px 13px;
border-radius: 20px;
font-size: 12px;
background: rgba(254, 249, 195, 1);
color: rgba(133, 77, 14, 1);
font-size: 12px;
font-weight: 500;
line-height: 17px;
letter-spacing: 0px;
}
.status-badge--active{
background: rgba(220, 252, 231, 1);
color: rgba(22, 101, 52, 1);
}
.languages-list{
display: flex;
flex-wrap: wrap;
gap: 20px;
}
</style>

View File

@@ -1,206 +1,276 @@
<template>
<div style="padding: 12px 32px 10px 12px;">
<div style="display: flex;justify-content: flex-start;">
<div style="display: flex;justify-content: flex-start;">
<div><el-input v-model="keyword" placeholder="输入课程名称搜索" clearable></el-input></div>
<div style="padding-left: 10px;"><el-button @click="recordList()" type="primary" icon="el-icon-search">搜索</el-button></div>
<div style="padding: 0px 5px;"><el-button icon="el-icon-refresh-right" @click="keyword = ''" type="primary" >重置</el-button></div>
<div style="padding: 0px 5px;"><el-button type="primary" @click="exportFile()" icon="el-icon-search" size="small" round>导出</el-button></div>
<div style="padding: 0px 5px;"><el-button type="primary" @click="exportStudentOfTearcher()" icon="el-icon-search" size="small" round>导出学员信息</el-button></div>
</div>
<div class="Export">
<!-- <div style="padding-left: 10px;"><el-button type="primary" @click="exportFile()" icon="el-icon-search" size="small" round>导出</el-button></div> -->
<!-- <div style="padding: 0px 5px;"><el-button icon="el-icon-refresh-right" type="primary" size="small" round>导出学员信息</el-button></div> -->
</div>
<div style="margin-top:20px;">
<el-table :data="pageData" border stripe>
<el-table-column
label="课程时间"
prop="courseTime"
width="200px">
</el-table-column>
<el-table-column
label="课程名称"
prop="courseName"
width="200px">
</el-table-column>
<el-table-column
label="开课场地"
prop="address"
width="240px">
</el-table-column>
<el-table-column
label="所属课程"
prop="parentCourse"
width="120px">
</el-table-column>
<el-table-column
label="所属项目"
prop="parentProject"
></el-table-column>
<el-table-column
label="所属路径"
prop="parentRoute"
width="200px"
></el-table-column>
<el-table-column
label="学习总人数"
prop="studentNumber"
width="100px"
></el-table-column>
<el-table-column
label="时长(分钟)"
width="100px"
prop="period"
></el-table-column>
<el-table-column
label="评分"
width="100px"
prop="score"
></el-table-column>
<el-table-column
label="操作"
align="center"
width="150px"
prop="cz"
fixed="right"
>
<div>
<el-input v-model="keyword" placeholder="输入课程名称搜索" clearable></el-input>
</div>
<div style="padding-left: 10px;">
<el-button @click="recordList()" type="primary" icon="el-icon-search">搜索</el-button>
</div>
<div style="padding: 0px 5px;">
<el-button icon="el-icon-refresh-right" @click="keyword = ''" type="primary">重置</el-button>
</div>
<div style="padding: 0px 5px;">
<el-button type="primary" @click="exportFile()" icon="el-icon-search" size="small" round>导出</el-button>
</div>
<!-- <div style="padding: 0px 5px;">-->
<!-- <el-button type="primary" @click="exportStudentOfTearcher()" icon="el-icon-search" size="small" round>-->
<!-- 导出学员信息-->
<!-- </el-button>-->
<!-- </div>-->
</div>
<div class="Export">
<!-- <div style="padding-left: 10px;"><el-button type="primary" @click="exportFile()" icon="el-icon-search" size="small" round>导出</el-button></div> -->
<!-- <div style="padding: 0px 5px;"><el-button icon="el-icon-refresh-right" type="primary" size="small" round>导出学员信息</el-button></div> -->
</div>
<div style="margin-top:20px;">
<el-table :data="pageData" border stripe>
<el-table-column
label="序号"
prop="index"
width="100px">
<template v-slot="scope">
<el-button type="text" @click="exportStudentOfCourse(scope.row.courseId)" size="small">导出学员信息</el-button>
</template>
</el-table-column>
</el-table>
</div>
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column
label="讲师工号"
prop="userNo"
width="100px">
</el-table-column>
<el-table-column
label="讲师姓名"
prop="teacherName"
width="200px">
</el-table-column>
<el-table-column
label="课程名称"
prop="courseName"
width="200px">
</el-table-column>
<el-table-column
label="培训发生组织"
prop="trainOrgName"
width="200px">
</el-table-column>
<el-table-column label="课程类型" prop="type" width="120px">
<template v-slot="scope">
<span>{{
{
"0": "在线课",
"1": "面授课",
"2": "课程开发",
"3": "作业员入模培训",
"4": "其他",
}[scope.row.type + '']
}}</span>
</template>
</el-table-column>
<el-table-column
label="授课/课程日期"
prop="teachingDate"
width="200px">
</el-table-column>
<div style="text-align: center; margin-top:57px">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageInfo.page"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageInfo.total"
></el-pagination>
</div>
<el-table-column
label="内容分类"
prop="courseTypeName"
width="200px">
</el-table-column>
<el-table-column label="开课状态" width="100px" prop="courseStatus">
<template v-slot="scope">
<span>{{
{
"0": "未开课",
"1": "已开课",
}[scope.row.courseStatus + '']
}}</span>
</template>
</el-table-column>
<el-table-column
label="授课时长(分钟)"
prop="teaching"
width="120px"
></el-table-column>
<el-table-column
label="参训人数"
prop="studys"
width="120px"
></el-table-column>
<el-table-column
label="评分"
prop="score"
width="100px"
></el-table-column>
<el-table-column
label="是否生成讲师费"
prop="createdFee"
width="100px"
>
<template v-slot="scope">
<span>{{
{
"0": "否",
"1": "是",
}[scope.row.createdFee + '']
}}</span>
</template>
</el-table-column>
<el-table-column
label="备注"
width="200px"
prop="remark"
></el-table-column>
<el-table-column
label="操作"
align="center"
width="150px"
prop="cz"
fixed="right"
>
<template v-slot="scope">
<el-button type="text" @click="exportStudentOfCourse(scope.row.courseId, scope.row.type)"
size="small">导出学员信息
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div style="text-align: center; margin-top:57px">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageInfo.page"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageInfo.total"
></el-pagination>
</div>
</div>
</template>
<script>
import apiCourse from '../../api/boe/courseRecord.js';
import { mapGetters } from 'vuex';
import {mapGetters} from 'vuex';
export default {
data(){
return {
pageData:[],
keyword:'',
pageInfo:{},
}
},
data() {
return {
pageData: [],
keyword: '',
pageInfo: {
pageIndex:1,
pageSize:10,
},
}
},
mounted() {
this.recordList();
},
computed: {
...mapGetters(['userInfo'])
},
methods: {
// 导出所有记录
exportFile() {
// let req = {
// }
// apiCourse.courseRecordExport2(req).then(res => {
// const link = document.createElement('a');// 创建a标签
// let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'}); // 设置文件类型
// link.style.display = "none";
// link.href = URL.createObjectURL(blob); // 创建URL
// link.setAttribute("download", "授课记录.xls");
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// })
// 取pageData记录第一条
if (this.pageData.length > 0) {
let teacherId = this.pageData[0].teacherId;
window.open(
`/manageApi/admin/export/exportInTeacherRecord?teacherId=${teacherId}`
);
}
},
mounted() {
this.recordList(1);
// 导出课程下的学员信息
exportStudentOfCourse(courseId, courseType) {
// apiCourse.exportStudentOfCourse2(courseId, courseType).then(res => {
// const link = document.createElement('a');// 创建a标签
// let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'}); // 设置文件类型
// link.style.display = "none";
// link.href = URL.createObjectURL(blob); // 创建URL
// link.setAttribute("download", "授课记录.xls");
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// })
},
computed: {
...mapGetters(['userInfo'])
},
window.open(
`/manageApi/admin/export/exportTeacherRecordStudentInfo?courseId=${courseId}&courseType=${courseType}`
);
},
methods: {
// 导出教师下的所有授课记录下的学员信息
exportStudentOfTearcher() {
let userId = this.userInfo.sysId;
apiCourse.exportStudentOfTearcher2(userId).then(res => {
const link = document.createElement('a');// 创建a标签
let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'}); // 设置文件类型
link.style.display = "none";
link.href = URL.createObjectURL(blob); // 创建URL
link.setAttribute("download", "授课记录.xls");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
},
// 导出所有记录
exportFile(){
let req = {
userId: this.userInfo.sysId
// userId:"70F80F4E-34BA-10AB-894A-8FA812B19637"
}
apiCourse.courseRecordExport(req).then(res=>{
const link = document.createElement('a');// 创建a标签
let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'}); // 设置文件类型
link.style.display = "none";
link.href = URL.createObjectURL(blob); // 创建URL
link.setAttribute("download", "授课记录.xls");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
},
// 导出课程下的学员信息
exportStudentOfCourse(courseId){
let userId = this.userInfo.sysId;
apiCourse.exportStudentOfCourse(userId,courseId).then(res=>{
const link = document.createElement('a');// 创建a标签
let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'}); // 设置文件类型
link.style.display = "none";
link.href = URL.createObjectURL(blob); // 创建URL
link.setAttribute("download", "授课记录.xls");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
},
// 导出教师下的所有授课记录下的学员信息
exportStudentOfTearcher(){
let userId = this.userInfo.sysId;
// let userId = '5D36C207-64F4-C512-312D-C9598257695C';
apiCourse.exportStudentOfTearcher(userId).then(res=>{
const link = document.createElement('a');// 创建a标签
let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'}); // 设置文件类型
link.style.display = "none";
link.href = URL.createObjectURL(blob); // 创建URL
link.setAttribute("download", "授课记录.xls");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
},
recordList(pageIndex){
let req = {
//     userId:"6B049FAF-C314-7CCF-0D28-0D23F4C42531",
userId: this.userInfo.sysId,
keyword:this.keyword,
    page:pageIndex,
    pageSize:10
}
apiCourse.courseRecordList(req).then(res=>{
if(res.status == 200) {
this.pageData = res.result.list;
this.pageInfo = res.result.pageInfo;
} else {
recordList() {
let req = {
courseName: this.keyword,
pageNo: this.pageInfo.pageIndex,
pageSize: this.pageInfo.pageSize
}
apiCourse.getListByToken(req).then(res => {
if (res.status == 200) {
this.pageData = res.data.records;
this.pageInfo.pageSize = Number(res.data.size);
this.pageInfo.total = Number(res.data.total);
this.pageInfo.page = Number(res.data.current);
} else {
this.$message({
type: 'error',
message: res.message
});
}
})
},
// 每页显示的条数事件
handleSizeChange(val){
this.pageInfo.pageSize = val;
this.recordList(1);
},
// 显示制定页的数据
handleCurrentChange(val){
this.pageInfo.pageIndex = val;
this.recordList(this.pageInfo.pageIndex);
},
},
type: 'error',
message: res.message
});
}
})
},
// 每页显示的条数事件
handleSizeChange(val) {
this.pageInfo.pageIndex = 1;
this.pageInfo.pageSize = val;
this.recordList();
},
// 显示制定页的数据
handleCurrentChange(val) {
this.pageInfo.pageIndex = val;
this.recordList(this.pageInfo.pageIndex);
},
},
}
</script>
<style lang="scss" scoped>
.Export{
display: flex;
padding-top: 10px;
.Export {
display: flex;
padding-top: 10px;
}
</style>

View File

@@ -954,7 +954,7 @@ export default {
},
findPapers() {
let params={
pageSize:200,
pageSize:10000,
name:''
}
apiPaper.querypaper(params).then((res) => {

View File

@@ -5,8 +5,8 @@
<!-- 当轮播图等于一张时 -->
<swiper :options="swiperOptiontwo">
<swiper-slide style="margin: 0 auto" v-for="(item, idx) in resonimg" :key="'a' + idx"
class="swiper-slide games pointer">
<div class="bannbox" :style="{
class="swiper-slide games pointer" >
<div class="bannbox" @click="handleCarouselClick(item)" :style="{
background: `url(${fileBaseUrl + item.image
}) center center no-repeat`,
}"></div>
@@ -17,8 +17,8 @@
<div id="container" style="z-index: 99" v-else>
<swiper :options="swiperOption" ref="mySwiper" v-if="resonimg.length > 1">
<swiper-slide style="margin: 0 auto" v-for="(item, idx) in resonimg" :key="'b' + idx"
class="swiper-slide games pointer">
<div class="bannbox" :style="{
class="swiper-slide games pointer" >
<div class="bannbox" @click="handleCarouselClick(item)" :style="{
background: `url(${fileBaseUrl + item.image
}) center center no-repeat`,
}"></div>
@@ -220,7 +220,7 @@ export default {
autoplay: false,
// noSwiping: true,
},
resonimg: [],
// resonimg: [],
swiperOption: {
autoplay: {
delay: 2000,
@@ -249,6 +249,13 @@ export default {
this.getToolData()
},
methods: {
// 添加点击轮播图跳转的方法
handleCarouselClick(item) {
if (item.url) {
window.open(item.url, '_blank');
}
},
downTool(toolInfo) {
console.log(toolInfo);
window.open(`/activityApi/xboe/m/boe/tools/url/download?urlStr=${process.env.VUE_APP_BOE_WEB_URL}/upload${toolInfo.filePath}&fileName=${toolInfo.name}`)

View File

@@ -8,7 +8,7 @@
<div class="navTop">
<div>
<router-link to="/grateful" class="nav">首页</router-link>&nbsp;>&nbsp;
<span style="cursor: pointer;" class="nav">认证讲师库2023</span>
<span style="cursor: pointer;" class="nav">认证讲师库</span>
</div>
<div style="position: relative;">
<el-input class="portal-input" placeholder="请输入课程名称" style="border-radius: 20px !important; "

View File

@@ -5,7 +5,7 @@
<!-- </div> -->
<!-- 底部 -->
<div class="grateful">
<img src="../../assets/images/grateful/gratefulFooter.png" alt="" />
<img src="../../assets/images/grateful/gratefulFooter20250613.png" alt="" />
</div>
</div>
</template>

View File

@@ -0,0 +1,179 @@
<template>
<div class="hot">
<div>
<div class="center">
<div class="item" :style="{marginRight:(i%2==0||i==0)?'49px':'0'}" v-for="item,i in imgData" :key="i">
<img class="img" @click="goLearn(item.url)" :src="require(`../../assets/images/hotforum/${item.img}.png`)" alt="">
</div>
</div>
<div style="display: flex;justify-content: center;margin-bottom: 52px;">
<img src="../../assets/images/hotforum/foot.png" alt="">
</div>
</div>
</div>
</template>
<script>
export default {
name: "hotforum",
data() {
return {
imgData:[
{img:'01',url:'1265897142383042560'},
{img:'02',url:'1265697724606210048'},
{img:'003',url:'1280185851054231552'},
{img:'04',url:'1321778585966247936'},
],
}
},
methods: {
goLearn(item){
if(item){
// this.$router.push({path:'/course/detail',query:{id:item}})
window.open(`https://u.boe.com/pc/course/detail?id=${item}`)
}
},
},
}
</script>
<style lang="scss" scoped>
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center{
max-width: 1270px;
max-height: 700px;
margin-bottom: 5%;
margin-top: 22%;
display: flex;
flex-wrap: wrap;
.item{
width: 610px;
height: 330px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 14px;
padding-top: 31px;
margin-bottom: 59px;
cursor: pointer;
.img{
width: 581px;
height: 283px;
}
}
}
/* 当窗口宽度大于3068px时的样式 */
}
@media (min-width: 3000px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 2560px;
max-height: 1300px;
margin-bottom: 5%;
margin-top: 30vh;
display: flex;
flex-wrap: wrap;
.item {
width: 1220px;
height: 660px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 28px;
padding-top: 62px;
margin-bottom: 59px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
@media (min-height: 1500px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 1068px;
max-height: 580px;
margin-bottom: 5%;
margin-top: 30vh;
display: flex;
flex-wrap: wrap;
.item {
width: 500px;
height: 271px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 14px;
padding-top: 26px;
margin-bottom: 30px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
@media (min-width: 1928px) and (max-width: 3000px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 1800px;
max-height: 1100px;
margin-bottom: 5%;
margin-top: 35vh;
display: flex;
flex-wrap: wrap;
.item {
width: 860px;
height: 466px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 28px;
padding-top: 48px;
margin-bottom: 70px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
</style>

View File

@@ -1,7 +1,24 @@
<template>
<div class="hot">
<div class="hot25">
<div>
<div class="center">
<div class="title25" style="">
<img class="img" src="../../assets/images/hotforum/2025.png" alt="">
</div>
<div class="center" style="margin-top: 60px;">
<div class="item" style="margin-right: 49px;">
<img class="img" @click="goLearn('1351506180295131136')" src="../../assets/images/hotforum/2501.jpg" alt="">
</div>
<div class="item">
<img class="img" @click="goLearn('1375146833375027200')" src="../../assets/images/hotforum/2503.png" alt="">
</div>
</div>
<div class="line" style="margin: 0 auto;margin-top: 60px;width: 100%;text-align: center;">
<img class="img" src="../../assets/images/hotforum/line.png" alt="">
</div>
<div class="title24" style="margin: 0 auto;margin-top: 60px;width: 100%;text-align: center;">
<img class="img" src="../../assets/images/hotforum/2024.png" alt="">
</div>
<div class="center" style="margin-top: 60px;">
<div class="item" :style="{marginRight:(i%2==0||i==0)?'49px':'0'}" v-for="item,i in imgData" :key="i">
<img class="img" @click="goLearn(item.url)" :src="require(`../../assets/images/hotforum/${item.img}.png`)" alt="">
</div>
@@ -11,11 +28,12 @@
</div>
</div>
</div>
</template>
<script>
export default {
name: "hotforum",
name: "hotforumNew",
data() {
return {
imgData:[
@@ -24,6 +42,10 @@
{img:'003',url:'1280185851054231552'},
{img:'04',url:'1321778585966247936'},
],
imgData25:[
{img:'2501',url:'1351506180295131136'},
{img:'2503',url:'1375146833375027200'},
],
}
},
methods: {
@@ -38,20 +60,22 @@
</script>
<style lang="scss" scoped>
.hot{
.hot25{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
background: url("../../assets/images/hotforum/back25.png") no-repeat;
background-size: cover;
display: flex;
justify-content: center;
.title25{
margin: 0 auto;margin-top: 100px;width: 100%;text-align: center;
}
.center{
max-width: 1270px;
max-height: 700px;
margin-bottom: 5%;
margin-top: 22%;
display: flex;
flex-wrap: wrap;
.item{
@@ -71,109 +95,109 @@
}
/* 当窗口宽度大于3068px时的样式 */
}
@media (min-width: 3000px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 2560px;
max-height: 1300px;
margin-bottom: 5%;
margin-top: 30vh;
display: flex;
flex-wrap: wrap;
// @media (min-width: 3000px) {
// .hot{
// width: 100%;
// // max-width: 1920px;
// min-height: 100%;
// // min-height: 1373px;
// background: url("../../assets/images/hotforum/back.jpg") no-repeat;
// background-size: 100% 100%;
// display: flex;
// justify-content: center;
// .center {
// max-width: 2560px;
// max-height: 1300px;
// margin-bottom: 5%;
// margin-top: 30vh;
// display: flex;
// flex-wrap: wrap;
.item {
width: 1220px;
height: 660px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 28px;
padding-top: 62px;
margin-bottom: 59px;
// .item {
// width: 1220px;
// height: 660px;
// background: url("../../assets/images/hotforum/border.png") no-repeat;
// background-size: 100%;
// padding: 28px;
// padding-top: 62px;
// margin-bottom: 59px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
@media (min-height: 1500px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 1068px;
max-height: 580px;
margin-bottom: 5%;
margin-top: 30vh;
display: flex;
flex-wrap: wrap;
// .img {
// width: 100%; // 图片宽度占满item宽度
// height: auto; // 自动调整高度
// }
// }
// }
// }
// }
// @media (min-height: 1500px) {
// .hot{
// width: 100%;
// // max-width: 1920px;
// min-height: 100%;
// // min-height: 1373px;
// background: url("../../assets/images/hotforum/back.jpg") no-repeat;
// background-size: 100% 100%;
// display: flex;
// justify-content: center;
// .center {
// max-width: 1068px;
// max-height: 580px;
// margin-bottom: 5%;
// margin-top: 30vh;
// display: flex;
// flex-wrap: wrap;
.item {
width: 500px;
height: 271px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 14px;
padding-top: 26px;
margin-bottom: 30px;
// .item {
// width: 500px;
// height: 271px;
// background: url("../../assets/images/hotforum/border.png") no-repeat;
// background-size: 100%;
// padding: 14px;
// padding-top: 26px;
// margin-bottom: 30px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
@media (min-width: 1928px) and (max-width: 3000px) {
.hot{
width: 100%;
// max-width: 1920px;
min-height: 100%;
// min-height: 1373px;
background: url("../../assets/images/hotforum/back.jpg") no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
.center {
max-width: 1800px;
max-height: 1100px;
margin-bottom: 5%;
margin-top: 35vh;
display: flex;
flex-wrap: wrap;
// .img {
// width: 100%; // 图片宽度占满item宽度
// height: auto; // 自动调整高度
// }
// }
// }
// }
// }
// @media (min-width: 1928px) and (max-width: 3000px) {
// .hot{
// width: 100%;
// // max-width: 1920px;
// min-height: 100%;
// // min-height: 1373px;
// background: url("../../assets/images/hotforum/back.jpg") no-repeat;
// background-size: 100% 100%;
// display: flex;
// justify-content: center;
// .center {
// max-width: 1800px;
// max-height: 1100px;
// margin-bottom: 5%;
// margin-top: 35vh;
// display: flex;
// flex-wrap: wrap;
.item {
width: 860px;
height: 466px;
background: url("../../assets/images/hotforum/border.png") no-repeat;
background-size: 100%;
padding: 28px;
padding-top: 48px;
margin-bottom: 70px;
// .item {
// width: 860px;
// height: 466px;
// background: url("../../assets/images/hotforum/border.png") no-repeat;
// background-size: 100%;
// padding: 28px;
// padding-top: 48px;
// margin-bottom: 70px;
.img {
width: 100%; // 图片宽度占满item宽度
height: auto; // 自动调整高度
}
}
}
}
}
// .img {
// width: 100%; // 图片宽度占满item宽度
// height: auto; // 自动调整高度
// }
// }
// }
// }
// }
</style>

View File

@@ -20,7 +20,7 @@
</div>
<div class="label">
<author :aid="caseDetail.sysCreateAid" :onlyAvatar="true" :avatar="authorInfo.avatar"
:sex="authorInfo.sex"></author>
:sex="authorInfo.sex" :name="authorInfo.name"></author>
<span>案主{{ authorInfo.name }} ({{ authorInfo.orgInfo }})</span>
<!-- <span>案主{{ authorInfo.name }}</span>
<span>工号{{ authorInfo.code }}</span>

View File

@@ -1609,7 +1609,7 @@ export default {
})
console.log(res?.result?.list ,'有没有数据2');
this.caseList.list = res.result.list
// this.getCaseUserData(res.result.list);
this.getCaseUserData(res.result.list);
// 给所有的赋值
this.caseList.count = res.result.count;
this.caseList.showPagCount = res.result.count;

View File

@@ -376,8 +376,25 @@
<div class="couresstartTime">
<span v-if="cinfo.type == 30 && cinfo.startTime">开课时间{{ cinfo.startTime }}</span>
</div>
<div class="course-info">
<!-- ai播放器相关 -->
<div class="course-info" style="align-items: center;">
<el-popover
placement="top-start"
:width="cinfo.summaryContent && cinfo.summaryContent.length > 200 ? '402' : '253'"
trigger="hover"
popper-class="course-popover"
>
<div class="course-popover-content">
<h4>课程摘要</h4>
<div v-if="cinfo.summaryContent" class="course-popover-content-text" >{{ cinfo.summaryContent }}</div>
<div v-else class="course-popover-noContent" >
<img src="../../../assets/images/course/noData.png" alt="">
<span>暂无数据</span>
</div>
</div>
<!-- <img slot="reference" src="../../../assets/images/course/courseAbstract.png" alt="摘要" style="width: 94px;height: 44px;margin-left: -10px;"> -->
<img v-show="cinfo.aiAbstract == '1'" slot="reference" src="../../../assets/images/course/courseAbstract.png" alt="摘要" style="width: 94px;height: 44px;margin-left: -10px;">
</el-popover>
<div class="course-info-user" style="max-width: 100px;" v-if="cinfo.teacher">
<el-tooltip :content="cinfo.teacher" placement="bottom" effect="light">
<span class="course-info-author">{{ cinfo.teacher }}</span>
@@ -387,13 +404,13 @@
<span class="course-info-studys">{{ formatNum(cinfo.studies) }}人学习</span>
</div>
<div class="course-info-score">
<div style="display: flex;">
<div style="display: flex; align-items: center;">
<interactBar :type="1" nodeWidth="20px" :data="cinfo" :courseExclusive="true" :comments="false"
:praises="false" :shares="false" :views="false"></interactBar>
<div v-if="cinfo.score">
<span class="course-score-value">{{ toScore(cinfo.score) }}</span>
<span class="course-score-value" style="white-space: nowrap;">{{ toScore(cinfo.score) }}</span>
</div>
<div v-else class="course-score-no">未评分</div>
<div v-else class="course-score-no" style="white-space: nowrap;">未评分</div>
</div>
</div>
</div>
@@ -2422,3 +2439,43 @@ console.log(res.result.list,'data')
.option-active {
color: #387DF7;
}</style>
<!-- ai播放器相关 -->
<style lang="scss">
.course-popover{
border-radius: 12px;
box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.12);
.course-popover-content{
h4{
margin: 0 0 7px 0;
font-size: 14px;
font-weight: 500;
line-height: 17px;
letter-spacing: 0.3px;
color: rgba(0, 0, 0, 1);
}
.course-popover-content-text{
font-size: 12px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.26px;
color: rgba(102, 102, 102, 1);
}
.course-popover-noContent{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: rgba(0, 0, 0, 0.34);
font-size: 12px;
font-weight: 400;
line-height: 14px;
letter-spacing: 0.26px;
padding-bottom: 20px;
img{
width: 96px;
height: 50px;
}
}
}
}
</style>

View File

@@ -225,7 +225,7 @@
</el-card>
</el-col>
</el-row>
</div>
<portal-footer></portal-footer>
</div>
@@ -653,7 +653,7 @@ export default {
itemId:this.coursewareInfo.studyItemId,
videoTime:intTime
}
apicourseStudy.studyVideoTime(postData).then(rs=>{
apicourseStudy.updateStudyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}
@@ -693,7 +693,7 @@ export default {
itemId:this.coursewareInfo.studyItemId,
videoTime:intTime
}
apicourseStudy.studyVideoTime(postData).then(rs=>{
apicourseStudy.updateStudyVideoTime(postData).then(rs=>{
if(rs.status!=200){
console.log('记录播放时间错误');
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff