教师端1期需求

This commit is contained in:
赵依梦
2025-12-07 11:03:44 +08:00
committed by joshen
parent 9dd8efc9aa
commit c2242631a0
13 changed files with 1564 additions and 79 deletions

View File

@@ -8,30 +8,38 @@
</Remark> -->
<div style="display: flex;justify-content:space-between;position: relative;">
<div style="display: flex;justify-content: flex-start; padding: 12px 32px 10px 12px;">
<!-- <div style="padding-left: 10px;">
<el-select style="width: 120px;" v-model="params.type" clearable placeholder="课程类型">
<el-option label="全部" :value="null"></el-option>
<el-option label="微课" :value="10"></el-option>
<el-option label="在线课" :value="20"></el-option>
</el-select>
</div> -->
<div style="margin-left:10px"><el-input :maxlength="50" v-model="params.name" placeholder="课程名称" clearable></el-input></div>
<div style="padding-left: 10px;">
<el-select style="width: 120px;" v-model="params.status" clearable placeholder="状态">
<el-option label="全部" :value="null"></el-option>
<el-option label="草稿" :value="1"></el-option>
<el-option label="待审核" :value="2"></el-option>
<el-option label="已审核" :value="5"></el-option>
<el-select style="width: 120px;" v-model="params.publish" clearable placeholder="发布状态">
<!-- <el-option label="全部" :value="null"></el-option> -->
<el-option label="未发布" :value="false"></el-option>
<el-option label="已发布" :value="true"></el-option>
</el-select>
</div>
<div style="margin-left:10px"><el-input v-model="params.keyword" placeholder="名称关键字" clearable></el-input></div>
<div style="padding-left: 10px;"><el-button type="primary" icon="el-icon-search" @click="findList()">搜索</el-button></div>
<div style="padding: 0px 5px;"><el-button icon="el-icon-refresh-right" type="primary" @click="reset">重置</el-button></div>
<div style="padding-left: 10px;">
<el-select style="width: 120px;" v-model="params.enabled" clearable placeholder="启停用状态">
<!-- <el-option label="全部" :value="null"></el-option> -->
<el-option label="停用" :value="false"></el-option>
<el-option label="启用" :value="true"></el-option>
</el-select>
</div>
<div style="padding-left: 10px;">
<el-select style="width: 120px;" v-model="params.status" clearable placeholder="审核状态">
<!-- <el-option label="全部" :value="null"></el-option> -->
<!-- <el-option label="无审核状态" :value="1"></el-option> -->
<el-option label="审核中" :value="2"></el-option>
<el-option label="审核驳回" :value="3"></el-option>
<el-option label="审核通过" :value="5"></el-option>
</el-select>
</div>
<div style="padding-left: 10px;"><el-button type="primary" icon="el-icon-search" @click="findList">查询</el-button></div>
<div style="padding: 0px 5px;"><el-button icon="el-icon-refresh-right" @click="reset">重置</el-button></div>
<div class="Create-coures"><el-button type="primary" @click="addNewCourse()" icon="el-icon-plus">新建课程</el-button></div>
</div>
</div>
<!--课程列表内容-->
<div style="">
<div v-infinite-scroll="load" style="overflow:auto;height:1000px" infinite-scroll-distance="50" :infinite-scroll-immediate="false" :infinite-scroll-disabled="disabled">
<div class="uc-course" v-for="(item, idx) in couresList" :key="idx" @click="jumpRouter(item)">
<div class="uc-course-img" style="width: 212px;height:119px">
<course-image :course="item"></course-image>
@@ -39,34 +47,27 @@
</div>
<div class="uc-course-info">
<div class="uc-course-name">
<!-- <span class="uc-course-type1">{{courseType(item.type)}}</span> -->
<span v-if="item.type == 10" class="uc-course-type1">录播</span>
<span v-if="item.type == 20" class="uc-course-type1">录播</span>
<span class="caogao" v-if="item.status == 1">草稿</span>
<span class="daishenhe" v-if="item.status == 2">待审核</span>
<span class="weitongguo" v-if="item.status == 3">审核未通过</span>
<span class="yishenhe" v-if="item.status == 5">已审核</span>
<!-- <a :href="`${webBaseUrl}/course/detail?id=${item.id}`" target="_blank"> {{item.name}}</a> -->
<span style="font-size:18px;color:#333">{{ item.name }}</span>
<el-tooltip class="item" effect="dark" :content="item.name" placement="top-start">
<span style="font-size:18px;color:#333">{{ item.name }}</span>
</el-tooltip>
</div>
<div class="summary-item">
<div>{{ item.summary }}</div>
</div>
<div class="uc-course-text">
<div class="uc-course-item">
上次修改时间{{ item.sysUpdateTime }}
<span type="text" style="margin-left:10px;font-size:14px;cursor: pointer;color:#666" @click.stop="toExamine(item)">查看审核记录</span>
</div>
</div>
<div class="uc-course-btns" style="line-height: 30px;">
<el-link style="display:block" :underline="false" @click.stop="examine(item)" type="primary" v-if="item.status == 1" icon="el-icon-document-checked">提交审核</el-link>
<el-link style="display:block" :underline="false" @click.stop="editCourse(item)" v-if="item.status == 3 || item.status == 4" type="primary" icon="el-icon-edit">编辑</el-link>
<el-link style="display:block" :underline="false" @click.stop="editCourse(item)" v-if="item.status == 1" type="primary" icon="el-icon-edit">去开发</el-link>
<el-link style="display:block" :underline="false" @click.stop="delItem(item)" v-if="item.status == 1" type="danger" icon="el-icon-delete">删除</el-link>
<el-link style="display:block" :underline="false" @click.stop="withdraw(item)" v-if="item.status == 2" type="info" icon="el-icon-delete">撤回</el-link>
<div class="uc-course-item">
<div class="status-item">发布状态{{ item.published ? '发布' : '未发布' }}</div>
<div class="status-item">启停用状态{{ item.enabled ? '启用' : '停用' }}</div>
<div class="status-item">审核状态<el-link :type="getStatusLabel(item.status).type" @click.stop="" :underline="false">{{getStatusLabel(item.status).label}}</el-link></div>
</div>
<div class="btn-container">
<el-link class="btn-item" v-for="(it, idx) in availableActions(item)" :key="idx" :underline="false" type="primary" @click.stop="it.handler(item)"><svg-icon style="margin-right: 5px;font-size:19px;padding-top: 4px;" :icon-class="it.icon"></svg-icon>{{it.label}}</el-link>
</div>
</div>
</div>
<p v-if="loading" class="page-tip">加载中...</p>
<p v-if="noMore" class="page-tip">没有更多了</p>
</div>
<div v-if="couresList.length > 0" style="text-align: center; margin-top:57px;">
<!-- <div v-if="couresList.length > 0" style="text-align: center; margin-top:57px;">
<el-pagination
background
@size-change="handleSizeChange"
@@ -83,29 +84,62 @@
<div v-if="isSearh" class="zan-wu">没有查询到相关内容</div>
<div v-else class="zan-wu">暂无数据</div>
</div>
</div>
</div> -->
<div></div>
<el-dialog title="二维码" :visible.sync="qrCodedialogVisible" width="900px" @close="closeCode" custom-class="g-dialog">
<div>
<el-form size="medium" label-width="100px">
<el-form-item label="二维码" >
<div id="qrcode" ref="qrcode" class="qrcode-img" @mouseenter="showDownloadButton = true" @mouseleave="showDownloadButton = false">
<div v-show="showDownloadButton" @click="downloadQrcode" class="downloadn-container">
<i class="el-icon-download" style="color: #409EFF;font-size:18px;margin-bottom:5px"></i>
<span>下载</span>
</div>
</div>
</el-form-item>
<el-form-item label="链接">
<el-input v-model="copyUrl" readonly class="input-with-select" id="text">
<el-button slot="append" @click="handleCopyUrl">复制</el-button>
</el-input>
</el-form-item>
<el-form-item label="">上述内容兼容PC端与移动端您可按需分享</el-form-item>
</el-form>
</div>
<span slot="footer" class="dialog-footer"><el-button @click="closeCode"> </el-button></span>
</el-dialog>
<!-- TODO 修改展示字段 -->
<el-dialog title="审核记录" :visible.sync="dialogVisible" width="900px" custom-class="g-dialog">
<div>
<el-table max-height="500" border :data="inviteTeacher" style="width: 100%;">
<el-table-column prop="sysCreateBy" label="姓名" width="180"></el-table-column>
<el-table-column prop="type" label="审核状态">
<el-table-column prop="type" label="审核类型">
<template slot-scope="scope">
{{ scope.row.auditState ? '通过' : '不通过' }}
</template>
</el-table-column>
<el-table-column prop="type" label="审核状态">
<template slot-scope="scope">
{{ auditEnum[scope.row.status] }}
</template>
</el-table-column>
<el-table-column prop="auditUser" label="审核人"></el-table-column>
<el-table-column prop="auditTime" label="审核结果"></el-table-column>
<el-table-column prop="auditTime" label="审核时间"></el-table-column>
<el-table-column prop="auditRemark" label="备注"></el-table-column>
<el-table-column prop="auditRemark" label="审核意见"></el-table-column>
</el-table>
</div>
<span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false"> </el-button></span>
<span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false"> </el-button></span>
</el-dialog>
<course-form ref="courseForm" @submitSuccess="getList"></course-form>
<course-form ref="courseForm" @submitSuccess="getNewList"></course-form>
</div>
</template>
<script>
import QRCode from 'qrcodejs2';
import courseImage from '@/components/Course/courseImage.vue';
import { mapGetters } from 'vuex';
import studyItem from '@/components/Course/studyItem.vue';
@@ -116,11 +150,53 @@ import apiAudit from '@/api/system/audit.js';
import apiHRBP from '@/api/boe/HRBP.js';
import apiOrg from '@/api/system/organiza.js';
import apiUserBasic from '@/api/boe/userbasic.js';
// 状态权限映射
const STATUS_PERMISSIONS = {
// 未发布状态
unpublished: {
1: ['edit', 'delete'], // 无审核状态
2: ['auditRecord'], // 审核中'withdraw'
3: ['edit', 'delete', 'auditRecord'] // 审核驳回
},
// 已发布状态
published: {
enabled: {
1: ['edit', 'manage', 'auditRecord', 'qrcode', 'viewCurrent'], //'offShelfApply'
2: ['manage', 'auditRecord', 'qrcode', 'viewCurrent'], // withdraw
3: ['edit', 'manage', 'auditRecord', 'qrcode', 'viewCurrent'], //'offShelfApply'
5: ['edit', 'manage', 'auditRecord', 'qrcode', 'viewCurrent'] //'offShelfApply'
},
disabled: {
// 所有状态在停用时操作一致
1: ['manage', 'auditRecord', 'viewCurrent'],
2: ['manage', 'auditRecord', 'viewCurrent'],
3: ['manage', 'auditRecord', 'viewCurrent'],
5: ['manage', 'auditRecord', 'viewCurrent']
}
}
}
// 操作配置映射表
const ACTION_CONFIG = {
edit: { label: '编辑', handler: 'editCourse', icon: 'edit' },
manage: { label: '管理', handler: 'handleManage', icon: 'manage' },
// withdraw: { label: '撤回', handler: 'handleWithdraw' },
auditRecord: { label: '审核记录', handler: 'toExamine', icon: 'edit' },
qrcode: { label: '二维码', handler: 'handleQrcode', icon: 'ercode' },
// offShelfApply: { label: '下架申请', handler: 'handleOffShelfApply' },
viewCurrent: { label: '查看当前版本', handler: 'handleViewCurrent', icon: 'detail' },
delete: { label: '删除', handler: 'delItem', icon: 'del' },
}
export default {
name: 'ucStudyIndex',
components: { studyItem, courseForm, courseImage },
computed: {
...mapGetters(['userInfo'])
...mapGetters(['userInfo']),
disabled() {
return this.loading || this.noMore;
},
},
data() {
@@ -130,17 +206,28 @@ export default {
courseType: courseType,
fileBaseUrl: process.env.VUE_APP_FILE_BASE_URL,
count: 0,
params: { keyword: '', type: '', status: '', createUser: '', pageIndex: 1, pageSize: 10, sysCreateAid: '' },
params: { name: '', publish: '', status: '', enabled: '', pageIndex: 0, pageSize: 10 },
couresList: [],
flag: true,
isSearh:false,
qrCodedialogVisible: false,
copyUrl: '',
qrcodeImgUrl: '',
showDownloadButton: false, // 是否显示下载按钮
loading: false,
noMore: false,
auditEnum: {
1: '未审核',
2: '审核不通过',
9: '审核通过'
},
};
},
mounted() {
if(this.$route.query && this.$route.query.open && this.$route.query.open == 'new') {
this.addNewCourse();
}
this.getList();
// this.getList();
},
watch:{
// '$route.query.open':function(val){
@@ -150,6 +237,126 @@ export default {
// }
},
methods: {
load() {
this.loading = true
this.params.pageIndex++
this.getList()
},
getNewList() {
this.couresList = [];
this.params.pageIndex = 1;
this.getList();
},
getStatusLabel(code) {
if (code == '1') {
return {type:'info',label:'-'}
} else if (code == '2') {
return {type:'warning',label:'审核中'}
} else if (code == '3') {
return {type:'danger',label:'审核驳回'}
} else if (code == '5') {
return {type:'success',label:'审核通过'}
}
},
// 获取可用的操作配置
availableActions(item) {
debugger
const { status, published, enabled } = item
let actionKeys = []
if (!published) {
// 未发布状态
actionKeys = STATUS_PERMISSIONS.unpublished[status] || []
} else {
// 已发布状态
const stateKey = enabled ? 'enabled' : 'disabled'
actionKeys = STATUS_PERMISSIONS.published[stateKey][status] || []
}
return actionKeys.map(key => ({
name: key,
label: ACTION_CONFIG[key].label,
handler: this[ACTION_CONFIG[key].handler],
icon: ACTION_CONFIG[key].icon
})).filter(Boolean)
},
handleManage(item) {
sessionStorage.setItem('courseDetail',JSON.stringify(item));
this.$router.push({ path: '/course/coursemanage' });
},
downloadQrcode() {
let img = document.getElementById("qrcode").getElementsByTagName("img")[0];
let canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
let tempUrl = canvas.toDataURL("image/png");
// 创建a标签下载
let link = document.createElement('a'); //创建a标签
link.style.display = 'none'; //使其隐藏
link.download = tempUrl;
link.setAttribute('target', '_blank');
link.href = tempUrl; //赋予文件下载地址
link.setAttribute('download', '二维码.jpg'); //设置下载属性 以及文件名
document.body.appendChild(link); //a标签插至页面中
link.click(); //强制触发a标签事件
document.body.removeChild(link);
},
handleCopyUrl() {
document.getElementById("text").select()
document.execCommand("Copy")
this.$message.success("复制成功")
},
handleQrcode(row) {
this.qrCodedialogVisible = true;
let urlPre=window.location.protocol+'//'+window.location.host;
//动态的地址
//urlPre=urlPre+'/m?returnUrl='+urlPre+'/mobile/pages/login/loading?returnUrl=';
//固定的地址
// let returnUrl=urlPre+'/mobile/pages/login/loading?returnUrl=/pages/study/courseStudy?id='+row.id;
// let mobilePre=urlPre+'/m?returnUrl=';
// this.qrcodeImgUrl = mobilePre+encodeURIComponent(returnUrl);
// this.copyUrl=urlPre+this.webBaseUrl+'/course/studyindex?id='+row.id;
// if(row.type==20){
// this.copyUrl=urlPre+this.webBaseUrl+'/course/detail?id='+row.id;
// }
this.copyUrl = this.qrcodeImgUrl = process.env.VUE_APP_BOE_WEB_URL + '/systemapi/xboe/m/course/manage/redirectDetail?courseId=' + row.id
console.log('qrcodeImgUrl', this.qrcodeImgUrl)
console.log('webBaseUrl', this.webBaseUrl)
// 使用$nextTick确保数据渲染
this.$nextTick(() => {
this.crateQrcode();
});
},
// 生成二维码
crateQrcode() {
let qrcode = new QRCode('qrcode', {
width: 150,
height: 150, // 高度
text: this.qrcodeImgUrl // 二维码内容
// render: 'canvas' // 设置渲染方式(有两种方式 table和canvas默认是canvas
// background: '#f0f'
// foreground: '#ff0'
});
console.log('qrcode', qrcode)
},
// 关闭弹框,清除已经生成的二维码
closeCode() {
this.qrCodedialogVisible = false
// 逐个节点移除防止事件一起移除
let images = document.querySelectorAll('.qrcode-img img');
images.forEach(img => img.remove());
let canvas = document.querySelectorAll('.qrcode-img canvas');
canvas.forEach(canvas => canvas.remove());
},
// 撤回接口
withdraw(item) {
this.$confirm('此操作将撤回审核中的课程, 是否继续?', '提示', {
@@ -165,7 +372,7 @@ export default {
type: 'success',
message: '撤回成功!'
});
this.getList();
this.getNewList();
}
}
});
@@ -178,17 +385,20 @@ export default {
});
},
reset() {
this.params.keyword = '';
this.params.status = '';
this.params.type = '';
this.params.name = ''
this.params.publish = ''
this.params.status = ''
this.params.enabled = ''
this.params.pageIndex = 1;
this.getList();
this.isSearh = false;
// this.getList();
this.isSearh = false;
},
toExamine(row) {
// this.detailType = row.type;
this.dialogVisible = true;
apiAudit.page(1, row.id).then(res => {
apiCourse.auditCourseRecords({
courseId: row.id
}).then(res => {
if (res.status === 200) {
this.inviteTeacher = res.result;
} else {
@@ -271,7 +481,8 @@ export default {
})
},
delItem(row) {
this.$confirm('您确定要删除所选课程吗?', '删除提示', {
console.log('delItem', row);
this.$confirm(`确认删除${row.name}吗?`, '删除提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
@@ -303,7 +514,9 @@ export default {
// this.$store.dispatch("userTrigger", event);
// }
this.getList();
this.getNewList();
} else {
this.$message.success('操作失败!');
}
} catch (error) {
console.log(error);
@@ -339,36 +552,30 @@ export default {
}
},
findList() {
this.params.pageIndex = 1;
this.isSearh = true;
this.getList();
this.getNewList();
},
getList() {
this.params.aid = this.userInfo.aid;
apiCourse.pageList(this.params).then(res => {
this.params.teacherId = this.userInfo.aid;
apiCourse.courseList(this.params).then(res => {
this.loading = false;
if (res.status == 200) {
this.couresList = res.result.list;
this.couresList = [...this.couresList, ...res.result.list];
this.count = res.result.count;
if (this.couresList.length >= this.count){
this.noMore = true;
}
} else {
this.$message.error(res.message);
}
});
},
handleSizeChange(val) {
this.params.pageSize = val;
// this.params.pageIndex = 1;
this.getList();
},
handleCurrentChange(val) {
this.params.pageIndex = val;
this.getList();
},
addNewCourse() {
this.$refs.courseForm.initShow();
},
editCourse(row) {
console.log(row, 'editCourse');
this.$refs.courseForm.initShow(row);
},
lastTabChange(tab, event) {
@@ -379,6 +586,11 @@ export default {
</script>
<style scoped lang="scss">
.page-tip {
margin: 20px auto;
text-align: center;
font-size: 13px;
}
.list-wu{
text-align: center;
margin: 40px;
@@ -422,6 +634,35 @@ export default {
margin-top: 10px;
margin-right: 40px;
}
.qrcode-img {
width: 150px;
height: 150px;
display: block;
position: relative;
.downloadn-container {
position: absolute;
width: 40px;
height: 45px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99;
background: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
cursor: pointer;
span {
color: #409EFF;
display: block;
font-size: 12px;
line-height: 12px;
}
}
}
.uc-course {
cursor: pointer;
display: flex;
@@ -466,9 +707,25 @@ export default {
word-break:break-all;
// font-weight: 700;
}
.uc-course-text {
.uc-course-item {
color: #666;
margin-top: 28px;
// margin-top: 4px;
font-size: 14px;
display: flex;
// flex-wrap: nowrap;
.status-item {
margin-right: 20px;
flex-shrink: 0;
}
}
.btn-container {
margin-top: 10px;
display: flex;
.btn-item {
margin-right: 20px;
}
}
}
.uc-course-btns {