mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal.git
synced 2025-12-15 05:46:43 +08:00
Merge branch '251114-feature-course-online' of https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-portal into 251114-feature-course-online
# Conflicts: # src/api/modules/course.js # src/data/pages.js
This commit is contained in:
@@ -103,6 +103,14 @@ const getUsersByIds = function(ids) {
|
|||||||
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
|
return ajax.postJson(baseURL,'/user/getUserMessageToDai',ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据关键字检索用户(创建人下拉)
|
||||||
|
* @param {string} keyword
|
||||||
|
*/
|
||||||
|
const selectUser = function(keyword = '') {
|
||||||
|
return ajax.postJson(baseURL,'/user/selectuser',{ keyword });
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
userParentOrg,
|
userParentOrg,
|
||||||
findOrgsByKeyword,
|
findOrgsByKeyword,
|
||||||
@@ -116,5 +124,6 @@ export default {
|
|||||||
getInAudienceIds,
|
getInAudienceIds,
|
||||||
getUsersByIds,
|
getUsersByIds,
|
||||||
updateUser,
|
updateUser,
|
||||||
logout
|
logout,
|
||||||
|
selectUser
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,6 +269,14 @@ const pageList = function(query) {
|
|||||||
return ajax.post('/xboe/m/course/manage/pagelist', query);
|
return ajax.post('/xboe/m/course/manage/pagelist', query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程管理分页查询(新)
|
||||||
|
* @param {Object} query
|
||||||
|
*/
|
||||||
|
const managePage = function(query) {
|
||||||
|
return ajax.postJson('/xboe/m/course/manage/page', query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**计算待审核课程*/
|
/**计算待审核课程*/
|
||||||
const countWaitAudit = function() {
|
const countWaitAudit = function() {
|
||||||
@@ -355,6 +363,21 @@ const setTop = function(data) {
|
|||||||
return ajax.post('/xboe/m/course/manage/top', data);
|
return ajax.post('/xboe/m/course/manage/top', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取置顶课程列表
|
||||||
|
*/
|
||||||
|
const fetchTopCourseList = function() {
|
||||||
|
return ajax.get('/xboe/m/course/manage/topList');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新置顶课程排序
|
||||||
|
* @param {Array<{id:string,sortWeight:number}>} data
|
||||||
|
*/
|
||||||
|
const updateTopCourseSort = function(data) {
|
||||||
|
return ajax.postJson('/xboe/m/course/manage/top-sortchange', data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理员的设置启用停用
|
* 管理员的设置启用停用
|
||||||
* @param {Object} query {ids:课程id,多个使用逗号分隔,title:课程的名称, Boolean enabled 是否启用}
|
* @param {Object} query {ids:课程id,多个使用逗号分隔,title:课程的名称, Boolean enabled 是否启用}
|
||||||
@@ -423,7 +446,12 @@ const exportCourseAudit=function(query){
|
|||||||
课程的导出和已审核的课程导出
|
课程的导出和已审核的课程导出
|
||||||
*/
|
*/
|
||||||
const exportCourse = function(query) {
|
const exportCourse = function(query) {
|
||||||
return ajax.post('/xboe/m/course/manage/exportCourse',query);
|
return ajax.get({
|
||||||
|
url: '/xboe/m/course/manage/export',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
responseType: 'blob'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断受众id是否有关联
|
//判断受众id是否有关联
|
||||||
@@ -464,6 +492,7 @@ export default {
|
|||||||
getDictIds,
|
getDictIds,
|
||||||
saveContent,
|
saveContent,
|
||||||
pageList,
|
pageList,
|
||||||
|
managePage,
|
||||||
setEnabled,
|
setEnabled,
|
||||||
del,
|
del,
|
||||||
publish,
|
publish,
|
||||||
@@ -480,6 +509,8 @@ export default {
|
|||||||
auditAndPublish,
|
auditAndPublish,
|
||||||
getAssess,
|
getAssess,
|
||||||
setTop,
|
setTop,
|
||||||
|
fetchTopCourseList,
|
||||||
|
updateTopCourseSort,
|
||||||
delSection,
|
delSection,
|
||||||
getExam,
|
getExam,
|
||||||
delContent,
|
delContent,
|
||||||
|
|||||||
234
src/components/Course/TopCourseSorter.vue
Normal file
234
src/components/Course/TopCourseSorter.vue
Normal 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>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -30,6 +30,7 @@ export const pages=[
|
|||||||
{title:'课程建设',path:'mylist',component:'course/TeacherList',hidden:true},
|
{title:'课程建设',path:'mylist',component:'course/TeacherList',hidden:true},
|
||||||
{title:'课程管理',path:'manage',component:'course/ManageList',hidden:false},
|
{title:'课程管理',path:'manage',component:'course/ManageList',hidden:false},
|
||||||
{title:'课程管理',path:'coursemanage',component:'course/CourseManage',hidden:true},
|
{title:'课程管理',path:'coursemanage',component:'course/CourseManage',hidden:true},
|
||||||
|
{title:'课程管理新版',path:'manage-remote',component:'course/ManageListRemote',hidden:false},
|
||||||
{title:'课程统计',path:'stat',component:'course/StatIndex',hidden:false},
|
{title:'课程统计',path:'stat',component:'course/StatIndex',hidden:false},
|
||||||
{title:'课件管理',path:'courseware',component:'course/Courseware',hidden:false},
|
{title:'课件管理',path:'courseware',component:'course/Courseware',hidden:false},
|
||||||
{title:'报名管理',path:'msignup',component:'study/ManageSignup',hidden:true},
|
{title:'报名管理',path:'msignup',component:'study/ManageSignup',hidden:true},
|
||||||
@@ -118,6 +119,7 @@ export const iframes=[
|
|||||||
{title:'嵌入测试', path:'/iframe/index',hidden:false,component:'portal/iframe'},
|
{title:'嵌入测试', path:'/iframe/index',hidden:false,component:'portal/iframe'},
|
||||||
{title:'课件管理', path:'/iframe/course/coursewares',hidden:false,component:'course/Courseware'},
|
{title:'课件管理', path:'/iframe/course/coursewares',hidden:false,component:'course/Courseware'},
|
||||||
{title:'课程管理', path:'/iframe/course/manages',hidden:false,component:'course/ManageList'},
|
{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/questions',hidden:false,component:'exam/Question'},
|
||||||
{title:'查看答卷', path:'/iframe/exam/viewanswer',hidden:false,component:'exam/viewAnswer'},
|
{title:'查看答卷', path:'/iframe/exam/viewanswer',hidden:false,component:'exam/viewAnswer'},
|
||||||
{title:'考试试卷管理', path:'/iframe/exam/papers',hidden:false,component:'exam/TestPaper'},
|
{title:'考试试卷管理', path:'/iframe/exam/papers',hidden:false,component:'exam/TestPaper'},
|
||||||
|
|||||||
1479
src/views/course/ManageListRemote.vue
Normal file
1479
src/views/course/ManageListRemote.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user