Merge branch '20251124-fix-1302' of http://10.251.129.121/boeu/learning-system-portal into test1024

This commit is contained in:
joshen
2025-11-27 15:21:00 +08:00

View File

@@ -26,8 +26,7 @@
<!--
<span class="bcourse-score" v-if="courseInfo.score>0">{{toScore(courseInfo.score)}} </span>
<span class="bcourse-score" v-else>无评分</span>
-->
</div>
--></div>
</div>
</div>
<div class="course-content xcontent">
@@ -70,7 +69,9 @@
<img
class="icon-small"
v-if="isPraise"
:src="require('@/assets/images/icon/praise-active.png')"
:src="
require('@/assets/images/icon/praise-active.png')
"
/>
<img
class="icon-small"
@@ -254,7 +255,13 @@
<div class="score" style="display: flex">
<div
v-if="!scoreInfo.has"
style="margin-left: 10px; cursor: pointer; padding-top: 10px;display: flex;align-items: center;"
style="
margin-left: 10px;
cursor: pointer;
padding-top: 10px;
display: flex;
align-items: center;
"
>
<!-- <el-popover placement="top" width="300" trigger="hover"> -->
<!-- <div style="text-align:center;line-height:50px;padding:20px 0px">
@@ -264,12 +271,24 @@
<p style="margin-right: 10px">告诉我们您的喜欢程度</p>
<el-rate
v-model="scoreInfo.score"
@change="showConfirmScore" :allow-half="true"
></el-rate><div v-if="isShowScoreConfirm">
<span class="score-text">{{ toScore(scoreInfo.score) }}</span>
<span style="font-size: 18px;"></span>
<el-button style="margin-left:10px" type="primary" size="mini" @click="addScore" >确定</el-button>
<el-button size="mini" @click="handleCancelScore">取消</el-button>
@change="showConfirmScore"
:allow-half="true"
></el-rate>
<div v-if="isShowScoreConfirm">
<span class="score-text">{{
toScore(scoreInfo.score)
}}</span>
<span style="font-size: 18px"></span>
<el-button
style="margin-left: 10px"
type="primary"
size="mini"
@click="addScore"
>确定</el-button
>
<el-button size="mini" @click="handleCancelScore"
>取消</el-button
>
</div>
<!-- <el-tag class="ref-score" slot="reference">去评分</el-tag> -->
<!-- </el-popover> -->
@@ -335,7 +354,9 @@
<img
class="icon-small"
v-if="isTrample"
:src="require('@/assets/images/icon/trample-active.png')"
:src="
require('@/assets/images/icon/trample-active.png')
"
/>
<img
class="icon-small"
@@ -388,7 +409,9 @@
</div>
<!-- 课程单元 -->
<div class="course-units" v-if="tab == 1">
<div style="min-height: 350px; max-height: 650px; overflow-y: auto">
<div
style="min-height: 350px; max-height: 650px; overflow-y: auto"
>
<div class="catalog" v-if="courseInfo.type == 20">
<div
v-for="(item, index) in catalogTree"
@@ -404,10 +427,16 @@
@open="handleOpen"
@close="handleClose"
>
<el-submenu :index="item.section.id" v-if="catalogTree.length > 1">
<el-submenu
:index="item.section.id"
v-if="catalogTree.length > 1"
>
<template slot="title">
<div
style="display: flex; justify-content: space-between"
style="
display: flex;
justify-content: space-between;
"
>
<div
style="
@@ -442,7 +471,9 @@
>
<div
class="units-info"
:class="{ 'units-active': contentData.id == ele.id }"
:class="{
'units-active': contentData.id == ele.id,
}"
@click="showRes(ele, i, index, item)"
>
<el-menu-item
@@ -480,7 +511,8 @@
<!-- <img v-if="contentData.id == ele.id" :src="`${webBaseUrl}/images/playicon.png`" alt=""> -->
<img
v-if="
contentData.id == ele.id && ele.status == 9
contentData.id == ele.id &&
ele.status == 9
"
style="width: 16px; height: 16px"
src="@/assets/images/over.png"
@@ -488,7 +520,8 @@
/>
<img
v-if="
contentData.id == ele.id && ele.status == 0
contentData.id == ele.id &&
ele.status == 0
"
style="width: 16px; height: 16px"
src="@/assets/images/nowNot.png"
@@ -506,7 +539,8 @@
/>
<img
v-if="
contentData.id != ele.id && ele.status == 9
contentData.id != ele.id &&
ele.status == 9
"
style="width: 16px; height: 16px"
src="@/assets/images/notNew.png"
@@ -514,7 +548,8 @@
/>
<img
v-if="
contentData.id != ele.id && ele.status == 0
contentData.id != ele.id &&
ele.status == 0
"
style="width: 16px; height: 16px"
src="@/assets/images/not.png"
@@ -537,20 +572,106 @@
</el-menu-item-group>
</el-submenu>
<div v-else>
<el-menu-item-group v-for="(ele, i) in item.children" :key="i">
<div class="units-info" :class="{'units-active':contentData.id == ele.id}" @click="showRes(ele,i,index,item)">
<el-menu-item :index="ele.id" style="padding: 0;padding-left: 10px;">
<div style="display: flex;justify-content: space-between;">
<div style="width: 200px;font-size: 16px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;" :title="ele.contentName">{{i+1}}. {{ ele.contentName }}</div>
<el-menu-item-group
v-for="(ele, i) in item.children"
:key="i"
>
<div
class="units-info"
:class="{
'units-active': contentData.id == ele.id,
}"
@click="showRes(ele, i, index, item)"
>
<el-menu-item
:index="ele.id"
style="padding: 0; padding-left: 10px"
>
<div
style="
display: flex;
justify-content: space-between;
"
>
<div
style="
width: 200px;
font-size: 16px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
:title="ele.contentName"
>
{{ i + 1 }}. {{ ele.contentName }}
</div>
<div>
<span v-if="contentData.id == ele.id" style="color: #387DF7;font-size: 14px;margin-right: 4px;">学习中</span>
<span
v-if="contentData.id == ele.id"
style="
color: #387df7;
font-size: 14px;
margin-right: 4px;
"
>学习中</span
>
<!-- <img v-if="contentData.id == ele.id" :src="`${webBaseUrl}/images/playicon.png`" alt=""> -->
<img v-if="contentData.id == ele.id && ele.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/over.png" alt="">
<img v-if="contentData.id == ele.id && ele.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/nowNot.png" alt="">
<img v-if="contentData.id == ele.id && (ele.status != 9&&ele.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/ban1.png" alt="">
<img v-if="contentData.id != ele.id && ele.status == 9" style="width: 16px;height: 16px;" src="@/assets/images/notNew.png" alt="">
<img v-if="contentData.id != ele.id && ele.status == 0" style="width: 16px;height: 16px;" src="@/assets/images/not.png" alt="">
<img v-if="contentData.id != ele.id && (ele.status != 9&&ele.status != 0)" style="width: 16px;height: 16px;" src="@/assets/images/newBan.png" alt="">
<img
v-if="
contentData.id == ele.id &&
ele.status == 9
"
style="width: 16px; height: 16px"
src="@/assets/images/over.png"
alt=""
/>
<img
v-if="
contentData.id == ele.id &&
ele.status == 0
"
style="width: 16px; height: 16px"
src="@/assets/images/nowNot.png"
alt=""
/>
<img
v-if="
contentData.id == ele.id &&
ele.status != 9 &&
ele.status != 0
"
style="width: 16px; height: 16px"
src="@/assets/images/ban1.png"
alt=""
/>
<img
v-if="
contentData.id != ele.id &&
ele.status == 9
"
style="width: 16px; height: 16px"
src="@/assets/images/notNew.png"
alt=""
/>
<img
v-if="
contentData.id != ele.id &&
ele.status == 0
"
style="width: 16px; height: 16px"
src="@/assets/images/not.png"
alt=""
/>
<img
v-if="
contentData.id != ele.id &&
ele.status != 9 &&
ele.status != 0
"
style="width: 16px; height: 16px"
src="@/assets/images/newBan.png"
alt=""
/>
</div>
</div>
</el-menu-item>
@@ -593,7 +714,11 @@
<div style="margin-left: 5px">
<span
v-if="contentData.id == list.id"
style="color: #387df7; font-size: 14px; margin-right: 4px"
style="
color: #387df7;
font-size: 14px;
margin-right: 4px;
"
>学习中</span
>
<img
@@ -695,7 +820,9 @@
srcset=""
/>
目标人群:
<div class="course-info-text">{{ courseInfo.forUsers }}</div>
<div class="course-info-text">
{{ courseInfo.forUsers }}
</div>
</div>
<div class="course-info-row">
<img
@@ -765,14 +892,29 @@
title="点击进入他的主页"
>
<div v-if="item.authorInfo && item.authorInfo.avatar">
<el-avatar :src="fileBaseUrl + item.authorInfo.avatar" shape="circle" :size="50"></el-avatar>
<el-avatar
:src="fileBaseUrl + item.authorInfo.avatar"
shape="circle"
:size="50"
></el-avatar>
</div>
<div v-else-if="item.photo">
<el-avatar :src="item.photo" shape="circle" :size="50"></el-avatar>
<el-avatar
:src="item.photo"
shape="circle"
:size="50"
></el-avatar>
</div>
<div v-else class="teacher-text">
<div v-if="item.authorInfo && item.authorInfo.sex === 1"><img src="../../../public/images/Avatarwoman.png" alt=""></div>
<div v-else><img src="../../../public/images/Avatarman.png" alt=""></div>
<div v-if="item.authorInfo && item.authorInfo.sex === 1">
<img
src="../../../public/images/Avatarwoman.png"
alt=""
/>
</div>
<div v-else>
<img src="../../../public/images/Avatarman.png" alt="" />
</div>
</div>
</div>
<div class="teacher-info">
@@ -816,30 +958,31 @@
</el-dialog>
<!-- <div><portal-footer></portal-footer></div> -->
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { mapGetters } from "vuex";
import followButton from "@/components/Follow/button.vue";
import portalHeader from "@/components/PortalHeader.vue";
import portalFooter from "@/components/PortalFooter.vue";
import comments from "@/components/Portal/comments.vue";
import noteComments from "@/components/Portal/noteComment.vue";
import interactBar from "@/components/Portal/interactBar.vue";
import audioPlayer from '@/components/AudioPlayer/index.vue';
import videoPlayer from '@/components/VideoPlayer/index.vue';
import hyperLink from '@/components/Course/hyperLink.vue';
import studyUtil from '@/utils/study.js';
import { encrypt } from '@/utils/jsencrypt.js';
import cookies from 'vue-cookies';
import apiStat from '@/api/phase2/stat.js';
import apiStudy from '@/api/modules/courseStudy.js';
import audioPlayer from "@/components/AudioPlayer/index.vue";
import videoPlayer from "@/components/VideoPlayer/index.vue";
import hyperLink from "@/components/Course/hyperLink.vue";
import studyUtil from "@/utils/study.js";
import { encrypt } from "@/utils/jsencrypt.js";
import cookies from "vue-cookies";
import apiStat from "@/api/phase2/stat.js";
import apiStudy from "@/api/modules/courseStudy.js";
import apiVideoStudy from "@/api/modules/videoStudy.js";
import apiCourseGrade from '@/api/modules/courseGrade.js';
import apiPraises from '@/api/modules/praises.js';
import apiTrample from '@/api/modules/trample.js';
import apiCoursePortal from '@/api/modules/coursePortal.js';
import apiUser from '@/api/system/user.js';
import apiCourseFile from '@/api/modules/courseFile.js';
import apiCourseGrade from "@/api/modules/courseGrade.js";
import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js";
import apiCoursePortal from "@/api/modules/coursePortal.js";
import apiUser from "@/api/system/user.js";
import apiCourseFile from "@/api/modules/courseFile.js";
import {
resListMap,
resOwnerListMap,
@@ -847,16 +990,16 @@
getType,
toScore,
cutOrgNamePath,
userAvatarText
} from '@/utils/tools.js';
import pdfPreview from '@/components/PdfPreview/index.vue';
import courseImage from '@/components/Course/courseImage.vue';
import exam from '@/components/Course/exam';
import homework from '@/components/Course/homework';
import assess from '@/components/Course/assess';
import myNote from '../../components/Course/myNote.vue';
userAvatarText,
} from "@/utils/tools.js";
import pdfPreview from "@/components/PdfPreview/index.vue";
import courseImage from "@/components/Course/courseImage.vue";
import exam from "@/components/Course/exam";
import homework from "@/components/Course/homework";
import assess from "@/components/Course/assess";
import myNote from "../../components/Course/myNote.vue";
import apiFollow from "@/api/phase2/userfollow.js";
import apiMessage from '@/api/system/message.js'
import apiMessage from "@/api/system/message.js";
// import Vue from 'vue';
// Vue.forceUpdate();
export default {
@@ -876,7 +1019,7 @@
myNote,
noteComments,
portalFooter,
followButton
followButton,
},
data() {
return {
@@ -885,54 +1028,54 @@
tentative: false,
isContentTypeTwo: null,
isContentType: null,
activeId: '',
activeId: "",
isFalse: false,
defaultOpeneds: [],
sendEventProgress: 0,
trueFalse: true,
audiences:'',
audiences: "",
isCrowd: false,
cutOrgNamePath,
scormUrl:'',//当前播放的scormUrl
scormUrl: "", //当前播放的scormUrl
loading: false,
controlHeight: 400, //左边控制区域的内容高度
timer: '',
timer: "",
notePlay: null,
intTimeNote: '',
intTimeNote: "",
courestab: 2, //默认是课程评论
curCFile: {
converStatus: 4,
},
Internet: 3, //1是成功 2是是失败 3是检测中
radio: '',
radio: "",
interactRuning: false,
playerBoxShow: false,
userAvatarText,
publicPath: process.env.VUE_APP_PUBLIC_PATH,
showiframe: false,
toScore,
courseId: '', //当前课程的id
studyId: '', //当前学习的id
initContentId: '', //初始化当前学习的内容节
blobUrl: '', //播放的文件地址新添加采用blob方式
courseId: "", //当前课程的id
studyId: "", //当前学习的id
initContentId: "", //初始化当前学习的内容节
blobUrl: "", //播放的文件地址新添加采用blob方式
contentData: {
studyItemId: '',
status: 1
studyItemId: "",
status: 1,
}, //当前的显示的内容
conLink: {
openType: 1,
url: ''
url: "",
}, //对于超连接的内容
curriculumData: {
url: '',
url: "",
isDrag: true,
completeSetup: 0,
setupTage: 0,
second: 0
second: 0,
}, // 课件内容
courseInfo: {
id: '',
name: ''
id: "",
name: "",
}, //课程信息
totalContent: 0, //课程内容数量
pageCount: 0,
@@ -943,27 +1086,27 @@
teachers: [],
toUsers: [], //对于@教师的处理
getType: getType,
ctabName: 'catalog',
ctabName: "catalog",
resType: null,
renderCourse: true,
activeNames: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
scoreInfo: {
dlgShow: false,
score: 5,
has: false
has: false,
},
isPraise: false,
isTrample: false,
appendStartTime: null, //记录追加的开始时间
appendHandle: null, //追加学习时长的timeout句柄
isAppendTime: false, //是否追加学习时长
appentId: '', //当前追加的学习时长的id,此字段已经不再使用
appentId: "", //当前追加的学习时长的id,此字段已经不再使用
appentInterval: 15, //追加学习时间的间隔 5秒加一次
handleTimeout: null,
completed: [],
tab: 1,
notetab: 1,
localTimeKey:'boeu-study-time' ,//本地存储的学习时长的key json格式
localTimeKey: "boeu-study-time", //本地存储的学习时长的key json格式
localTimeValue: 0, //计算的时间
appendStudyOtherHandle: null,
cumulativeDuration: 0, //非音频累计时长
@@ -972,14 +1115,14 @@
warn: "测试内容",
warnTitle: "测试标题",
isFinishingStudyItem: false, // 防止重复调用完成状态更新接口
}
};
},
mounted() {
this.getInternet();
// 增加的用户受众id
let localKey = "user_" + this.userInfo.sysId + "_gids";
let hasIds = sessionStorage.getItem(localKey);
this.audiences = hasIds ?? ''
this.audiences = hasIds ?? "";
this.$watermark.set(this.userInfo.name + this.userInfo.loginName);
this.courseId = this.$route.query.id;
this.initContentId = this.$route.query.contentId;
@@ -988,19 +1131,19 @@
this.loadData();
},
computed: {
...mapGetters(['userInfo']),
...mapGetters(["userInfo"]),
catalogTree() {
let treeList = [];
this.completed = [];
let $this = this;
$this.sectionList.forEach(sec => {
$this.sectionList.forEach((sec) => {
let treeNode = {
section: sec,
children: []
children: [],
};
sec.status = 1;
let finishCount = 0;
$this.contentList.forEach(c => {
$this.contentList.forEach((c) => {
if (c.csectionId == sec.id) {
if (c.status > 1) {
sec.status = 2;
@@ -1021,30 +1164,29 @@
});
// console.log(treeList,'treeList')
return treeList;
}
},
},
methods: {
handleCancelScore() {
this.isShowScoreConfirm = false;
this.scoreInfo.score = 5
this.scoreInfo.score = 5;
},
showConfirmScore() {
this.isShowScoreConfirm = true;
},
handleOpen(key, path) {
if (this.isFalse) {
this.defaultOpeneds = [key]
this.defaultOpeneds = [key];
}
this.isFalse = false
},
handleClose(key,path){
this.isFalse = false;
},
handleClose(key, path) {},
toUserHome(tea) {
this.$router.push({path:this.$xpage.getHomePath(tea.teacherId)})
this.$router.push({ path: this.$xpage.getHomePath(tea.teacherId) });
},
noteChange() {
//视频点定位,直接到播放的视频位置
this.timer = new Date().getTime()
this.timer = new Date().getTime();
},
//清空追加学习时长事件
cleanAppendTime() {
@@ -1055,7 +1197,7 @@
//非音视频课学习时长的增加,每一分钟保存一次
appendStudyOtherTime() {
//console.log('开始追加学习时长',this.isAppendTime);
if (this.studyId == '') {
if (this.studyId == "") {
return;
}
if (!this.contentData.id) {
@@ -1080,23 +1222,24 @@
$this.maxDuration = 0;
}
}, 1000 * 60);
},
sendStudyOtherTime(totalTime) {
//静默处理
apiStat.sendEvent({
"key": "StudyCourseOther",//课程学习的key
"title": "非音视频课内容",//事件的标题
"parameters":"second:" + totalTime,//second:value 本次的学习时长
"content": "学习课程",//事件的内容
"objId": this.courseInfo.id,//课程的id
"objType": "1",//类型
"source":"page",
"objInfo": ""+this.courseInfo.name,
"aid":this.userInfo.aid, //当前登录人的id
"aname":this.userInfo.name,//当前人的姓名
"status": 1 //状态
}).then(rs=>{
apiStat
.sendEvent({
key: "StudyCourseOther", //课程学习的key
title: "非音视频课内容", //事件的标题
parameters: "second:" + totalTime, //second:value 本次的学习时长
content: "学习课程", //事件的内容
objId: this.courseInfo.id, //课程的id
objType: "1", //类型
source: "page",
objInfo: "" + this.courseInfo.name,
aid: this.userInfo.aid, //当前登录人的id
aname: this.userInfo.name, //当前人的姓名
status: 1, //状态
})
.then((rs) => {
if (rs.status != 200) {
console.log(rs.message);
}