Compare commits

...

3 Commits

7 changed files with 2365 additions and 519 deletions

View File

@@ -103,6 +103,14 @@ const getUsersByIds = function(ids) {
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
}
/**
* 根据关键字检索用户(创建人下拉)
* @param {string} keyword
*/
const selectUser = function(keyword = '') {
return ajax.postJson(baseURL,'/user/selectuser',{ keyword });
}
export default {
userParentOrg,
findOrgsByKeyword,
@@ -116,5 +124,6 @@ export default {
getInAudienceIds,
getUsersByIds,
updateUser,
logout
logout,
selectUser
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
<template>
<el-dialog
title="置顶排序"
:visible.sync="dialogVisible"
custom-class="g-dialog top-course-sorter-dialog"
width="820px"
:close-on-click-modal="false"
@closed="handleClosed"
append-to-body
>
<div class="top-course-sorter" v-loading="loading">
<div class="top-course-sorter__table" v-if="topList.length">
<div class="sorter-header">
<div class="header-cell header-cell--handle"></div>
<div class="header-cell header-cell--order">排序</div>
<div class="header-cell header-cell--name">课程名称</div>
<div class="header-cell header-cell--teacher">授课教师</div>
</div>
<div
class="sorter-row"
v-for="(item, index) in topList"
:key="item.id"
draggable="true"
@dragstart="handleDragStart(index, $event)"
@dragover.prevent
@drop="handleDrop(index)"
@dragend="handleDragEnd"
:class="{ 'is-dragging': draggingIndex === index }"
>
<div class="row-cell row-cell--handle">
<i class="el-icon-s-operation"></i>
</div>
<div class="row-cell row-cell--order">{{ index + 1 }}</div>
<div class="row-cell row-cell--name" :title="item.name">{{ item.name }}</div>
<div class="row-cell row-cell--teacher" :title="item.teacherName || '-'">
{{ item.teacherName || '-' }}
</div>
</div>
</div>
<el-empty v-else-if="!loading" description="暂无置顶课程"></el-empty>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :disabled="!topList.length" :loading="saving" @click="handleSave">确定</el-button>
</span>
</el-dialog>
</template>
<script>
import apiCourse from '@/api/modules/course.js';
export default {
name: 'TopCourseSorter',
data() {
return {
dialogVisible: false,
loading: false,
saving: false,
topList: [],
draggingIndex: null,
};
},
methods: {
open() {
this.dialogVisible = true;
this.fetchTopList();
},
async fetchTopList() {
this.loading = true;
try {
const res = await apiCourse.fetchTopCourseList();
if (res.status === 200) {
this.topList = Array.isArray(res.result) ? [...res.result] : [];
} else {
this.$message.error(res.message || '获取置顶课程失败');
this.topList = [];
}
} catch (error) {
this.$message.error(error.message || '获取置顶课程失败');
this.topList = [];
} finally {
this.loading = false;
}
},
handleDragStart(index, event) {
this.draggingIndex = index;
if (event && event.dataTransfer) {
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('text/plain', index);
}
},
handleDrop(targetIndex) {
if (this.draggingIndex === null || this.draggingIndex === targetIndex) {
return;
}
const movingItem = this.topList.splice(this.draggingIndex, 1)[0];
this.topList.splice(targetIndex, 0, movingItem);
this.draggingIndex = targetIndex;
},
handleDragEnd() {
this.draggingIndex = null;
},
async handleSave() {
if (!this.topList.length) {
this.$message.warning('暂无需要保存的排序');
return;
}
const payload = this.topList.map((item, index) => ({
id: item.id,
sortWeight: index,
}));
this.saving = true;
try {
const res = await apiCourse.updateTopCourseSort(payload);
if (res.status === 200) {
this.$message.success('排序更新成功');
this.$emit('sorted');
this.dialogVisible = false;
} else {
throw new Error(res.message || '排序更新失败');
}
} catch (error) {
this.$message.error(error.message || '排序更新失败');
} finally {
this.saving = false;
}
},
handleClosed() {
this.topList = [];
this.draggingIndex = null;
this.loading = false;
this.saving = false;
},
},
};
</script>
<style lang="scss" scoped>
.top-course-sorter {
min-height: 200px;
padding-top: 8px;
}
.top-course-sorter__table {
border: 1px solid #ebeef5;
border-radius: 6px;
overflow: hidden;
}
.sorter-header,
.sorter-row {
display: grid;
grid-template-columns: 60px 80px 1fr 160px;
align-items: center;
}
.sorter-header {
background-color: #f5f7fa;
height: 48px;
font-weight: 600;
color: #303133;
border-bottom: 1px solid #ebeef5;
}
.sorter-row {
min-height: 56px;
border-bottom: 1px solid #f2f6fc;
cursor: move;
transition: background-color 0.2s ease;
}
.sorter-row:last-child {
border-bottom: none;
}
.sorter-row:hover {
background-color: #f9fbff;
}
.sorter-row.is-dragging {
opacity: 0.7;
background-color: #ecf5ff;
}
.header-cell,
.row-cell {
padding: 0 16px;
display: flex;
align-items: center;
}
.header-cell--handle,
.row-cell--handle {
justify-content: center;
}
.header-cell--order,
.row-cell--order {
justify-content: flex-start;
}
.row-cell--name,
.row-cell--teacher {
color: #303133;
}
.row-cell--name {
font-weight: 500;
}
.row-cell--teacher {
color: #666;
}
.row-cell--handle i {
font-size: 20px;
color: #c0c4cc;
}
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -29,6 +29,7 @@ export const pages=[
{title:'课程首页',path:'index',component:'course/Index',hidden:true},
{title:'课程建设',path:'mylist',component:'course/TeacherList',hidden:true},
{title:'课程管理',path:'manage',component:'course/ManageList',hidden:false},
{title:'课程管理新版',path:'manage-remote',component:'course/ManageListRemote',hidden:false},
{title:'课程统计',path:'stat',component:'course/StatIndex',hidden:false},
{title:'课件管理',path:'courseware',component:'course/Courseware',hidden:false},
{title:'报名管理',path:'msignup',component:'study/ManageSignup',hidden:true},
@@ -117,6 +118,7 @@ export const iframes=[
{title:'嵌入测试', path:'/iframe/index',hidden:false,component:'portal/iframe'},
{title:'课件管理', path:'/iframe/course/coursewares',hidden:false,component:'course/Courseware'},
{title:'课程管理', path:'/iframe/course/manages',hidden:false,component:'course/ManageList'},
{title:'课程管理新版', path:'/iframe/course/manage-remote',hidden:false,component:'course/ManageListRemote'},
{title:'考试试题管理', path:'/iframe/exam/questions',hidden:false,component:'exam/Question'},
{title:'查看答卷', path:'/iframe/exam/viewanswer',hidden:false,component:'exam/viewAnswer'},
{title:'考试试卷管理', path:'/iframe/exam/papers',hidden:false,component:'exam/TestPaper'},

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
<div id="couser-list-content" class="couser-list-content">
<div class="course-banner">
<portal-header current="course" textColor="#fff" :keywords="keyword" @emitInput="emitInput"
@showClass="showClass"></portal-header>
@showClass="showClass"></portal-header>
</div>
<div style="padding-top:30px">
<div class="xcontent2">
@@ -11,7 +11,7 @@
<span v-if="navTitle.length">></span>
<template v-if="navTitle.length">
<div class="oneTitle" v-for="(item, index) in navTitle" :key="item.id"
@click="handleOptionClick(item, index)">
@click="handleOptionClick(item, index)">
<span class="titleName">&nbsp;{{ item.name }}&nbsp;</span>
<span v-if="index !== navTitle.length - 1">></span>
</div>
@@ -39,25 +39,28 @@
:class="{ courseTwoActive: twoList.id == twoId || twoList.checked }" @mouseleave.stop="leaveIndex"
@mouseenter.stop="changeIndex(twoList.id)">
<!-- 三级分类 -->
<el-popover class="popover" popper-class='coursePopperClass' placement="right-start" width="536"
:disabled="!twoList.children.length" :open-delay="0" :close-delay="0" trigger="hover"
:visible-arrow="false" @hide="leaveIndex" @show="changeIndex(twoList.id)" transition="none">
<div class="course-two-content" slot="reference">{{
twoList.name }}</div>-
<!-- 内容 -->
<div class="course-three-box">
<div class="course-three-box-title">
{{ twoList.name }}
</div>
<div style="padding: 0 40px;display: flex;flex-wrap: wrap;">
<div :class="threeList.checked ? 'threeActive' : ''" v-for="threeList in twoList.children"
:key="threeList.id" @click.stop="handleOptionClick(threeList, 3, twoList.children)"
class="course-three">
<span>{{ threeList.name }}</span>
<el-menu>
<el-submenu :index="String(twoIndex)" v-if="twoList.children && twoList.children.length > 0">
<template slot="title">
<div class="course-two-content">
{{ twoList.name }}
</div>
</div>
</div>
</el-popover>
</template>
<el-menu-item-group>
<div style="padding: 0 40px;display: flex;flex-wrap: wrap;">
<div :class="threeList.checked ? 'threeActive' : ''" v-for="threeList in twoList.children"
:key="threeList.id" @click.stop="handleOptionClick(threeList, 3, twoList.children)"
class="course-three">
<span>{{ threeList.name }}</span>
</div>
</div>
</el-menu-item-group>
</el-submenu>
<el-menu-item :index="String(twoIndex)" v-else>
<div slot="title" class="course-two-content"> {{ twoList.name }}</div>
</el-menu-item>
</el-menu>
<!-- </el-popover> -->
</div>
</div>
</div>
@@ -459,6 +462,7 @@ export default {
},
data() {
return {
menuActiveIndex: '-1', //无默认选中
hotTagsList: [],
newData: false,//线上品牌系列隐藏
navTitle: [],
@@ -1657,6 +1661,38 @@ export default {
</script>
<style scoped lang="scss">
.course-three-box-title{
font-size: 16px;
font-weight: 600;
height: 68px;
line-height: 80px;
background: linear-gradient(180deg, rgba(78,166,255,0.2) 0%,
rgba(78,166,255,0) 100%);padding-left: 40px;
}
.course-three{
border-radius: 6px;
border: 1px solid #C7CBD2;display: inline-block;
height: 30px;
line-height: 30px;
padding: 0 10px;
margin-right: 20px;
margin-bottom: 10px;
cursor: pointer;
color: rgb(48, 49, 51);
&:hover{
color: #387DF7;
border: 1px solid #387DF7 !important;
}
}
.threeActive{
color: #387DF7;
border: 1px solid #387DF7 !important;
}
.couser-list-content {
min-height: 110%;
}
@@ -1717,10 +1753,29 @@ export default {
}
}
// 三级列表
.course-list {
background-color: #fff;
::v-deep .el-submenu__title, .el-menu-item {
height: 38px;
padding: 0 5px!important;
}
::v-deep .el-menu-item.is-active {
background-color: inherit;
color: inherit;
}
::v-deep .el-submenu__title {
background-color: inherit;
color: inherit;
}
.course-one {
position: relative;
@@ -1734,7 +1789,7 @@ export default {
// 二级的高亮
.courseTwoActive {
color: #387DF7;
color: #387DF7 !important;
border-image: linear-gradient(90deg, rgba(47, 101, 236, 1), rgba(228, 236, 255, 1)) 1 1 !important;
}

View File

@@ -123,13 +123,20 @@
<div>
<div class="course-interact">
<div class="score" style="display: flex;">
<div v-if="!scoreInfo.has" style="margin-left:10px;cursor: pointer;padding-top:18px">
<div v-if="!scoreInfo.has" 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">
<div style="padding-top:30px"><el-button @click="addScore">提交评分</el-button></div>
</div> -->
<el-rate v-model="scoreInfo.score" @change="addScore"></el-rate>
<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>
</div>
<!-- <el-tag class="ref-score" slot="reference">去评分</el-tag> -->
<!-- </el-popover> -->
</div>
@@ -188,7 +195,7 @@
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose">
<el-submenu :index="item.section.id">
<el-submenu :index="item.section.id" v-if="catalogTree.length > 1">
<template slot="title">
<div style="display: flex;justify-content: space-between;">
<div style="width: 240px;font-weight: 700;font-size: 16px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;" :title="item.section.name">{{item.section.name}}</div>
@@ -215,6 +222,27 @@
</div>
</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>
<div>
<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="">
</div>
</div>
</el-menu-item>
</div>
</el-menu-item-group>
</div>
</el-menu>
</div>
<!-- <div v-for="(item, index) in catalogTree" :key="index" :name="index">
@@ -390,6 +418,7 @@
},
data() {
return {
isShowScoreConfirm: false,
protocolDialogVisible: false,
tentative: false,
isContentTypeTwo: null,
@@ -533,6 +562,13 @@
}
},
methods: {
handleCancelScore() {
this.isShowScoreConfirm = false;
this.scoreInfo.score = 5
},
showConfirmScore() {
this.isShowScoreConfirm = true;
},
handleOpen(key,path){
if(this.isFalse){
this.defaultOpeneds = [key]