Files
learning-system-portal/src/views/course/TeacherList.vue
2025-12-18 11:58:36 +08:00

812 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<!-- <Remark>
1.教师我开发的课程<br/>
2.如果是自己创建的那么邀请人就是空显示自己创建<br/>
3.建设课程邀请人流程提交审核流程都需要讨论 <br/>
4.有哪种几状态和哪几种操作需要讨论定一下 在哪种状态下可以有哪些操作<br/>
</Remark> -->
<el-row style="margin: 0 20px 20px 15px;" :gutter="8">
<el-col :span="7">
<div class="grid-content bg-purple"><el-input :maxlength="50" v-model="params.name" clearable
placeholder="课程名称" /></div>
</el-col>
<el-col :span="3">
<div class="grid-content bg-purple">
<el-select v-model="params.publish" placeholder="发布状态" clearable>
<el-option label="未发布" :value="false"></el-option>
<el-option label="已发布" :value="true"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="grid-content bg-purple">
<el-select v-model="params.enabled" placeholder="启停用状态" clearable>
<el-option label="停用" :value="false"></el-option>
<el-option label="启用" :value="true"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="grid-content bg-purple">
<el-select v-model="params.status" placeholder="审核状态" clearable>
<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>
</el-col>
<el-col :span="5">
<div class="grid-content bg-purple">
<el-button type="primary" @click="findList"> </el-button>
<el-button @click="reset"> </el-button>
</div>
</el-col>
<el-col :span="3" >
<div class="grid-content bg-purple" style="text-align: right;">
<el-button type="primary" icon="el-icon-plus" @click="addNewCourse">开发新课程</el-button>
</div>
</el-col>
</el-row>
<!--课程列表内容-->
<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>
<!-- <img :src="fileBaseUrl + item.coverImg"> -->
</div>
<div class="uc-course-info">
<div class="uc-course-name">
<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="uc-course-item">
上次修改时间{{ item.sysUpdateTime }}
</div>
<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" @mouseenter.native="$set(hoverStates, it.uniqueKey, true )"
@mouseleave.native="$set(hoverStates, it.uniqueKey, false )"
:style="{color: it.labelColor ? it.labelColor : (hoverStates[it.uniqueKey] ? '#4284F7' : '#000000')}"
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;color:#000000"
:icon-class="hoverStates[it.uniqueKey] ? it.hoverIcon : it.icon"></svg-icon>{{it.label}}</el-link>
</div>
</div>
</div>
<p v-if="loading" class="page-tip">加载中...</p>
<div v-if="couresList.length == 0 && !loading">
<div v-if="isSearh" class="zan-wu">没有查询到相关内容</div>
<div v-else class="zan-wu">暂无数据</div>
</div>
<p v-else-if="noMore" class="page-tip">没有更多了</p>
</div>
<!-- <div v-if="couresList.length > 0" style="text-align: center; margin-top:57px;">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="params.pageIndex"
:page-sizes="[10, 20, 30, 40]"
:page-size="params.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="count"
></el-pagination>
</div>
<div v-else>
</div> -->
<div></div>
<el-dialog title="二维码" :visible.sync="qrCodedialogVisible" width="700px" @close="closeCode" class="common-course-dialog">
<div>
<el-form size="medium" label-width="70px">
<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="链接" >
<div style="width:500px">
<el-input v-model="copyUrl" readonly class="input-with-select" id="text">
<el-button slot="append" @click="handleCopyUrl">复制</el-button>
</el-input>
</div>
</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" class="common-course-dialog">
<div>
<el-table :header-cell-style="{textAlign: 'center', background: 'rgba(66, 132, 247, 0.1)',
color: '#60769D'}"
:cell-style="{ textAlign: 'center' }" max-height="500" border :data="inviteTeacher" style="width: 100%;">
<el-table-column prop="auditType" width="80" label="审核类型">
<template slot-scope="scope">
{{ auditTypeEnum[scope.row.auditType] }}
</template>
</el-table-column>
<el-table-column prop="status" width="80" label="审核状态">
<template slot-scope="scope">
{{ auditEnum[scope.row.status] }}
</template>
</el-table-column>
<el-table-column prop="auditUser" width="80" label="审核人"></el-table-column>
<el-table-column prop="auditResult" width="80" label="审核结果">
<template slot-scope="scope">
{{ auditResultEnum[scope.row.auditResult] }}
</template>
</el-table-column>
<el-table-column prop="auditTime" width="220" label="审核时间"></el-table-column>
<el-table-column prop="auditRemark" label="审核意见">
<template slot-scope="scope">
<el-tooltip class="item" popper-class="tooltip-multiline" effect="dark" :content="scope.row.auditRemark" placement="top-start">
<p class="no-wrap">
{{scope.row.auditRemark}}</p>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false"> </el-button></span>
</el-dialog>
<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";
import courseForm from "@/components/Course/courseForm.vue";
import apiCourse from "@/api/modules/course.js";
import { courseType } from "@/utils/tools.js";
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"], //'offShelfApply', 'viewCurrent'
2: ["manage", "auditRecord", "qrcode"], // withdraw , 'viewCurrent'
3: ["edit", "manage", "auditRecord", "qrcode"], //'offShelfApply', 'viewCurrent'
5: ["edit", "manage", "auditRecord", "qrcode"], //'offShelfApply', 'viewCurrent'
},
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",
hoverIcon: "editHover",
},
manage: {
label: "管理",
handler: "handleManage",
icon: "manage",
hoverIcon: "manageHover",
},
// withdraw: { label: '撤回', handler: 'handleWithdraw' },
auditRecord: {
label: "审核记录",
handler: "toExamine",
icon: "check",
hoverIcon: "checkHover",
},
qrcode: {
label: "二维码",
handler: "handleQrcode",
icon: "ercode",
hoverIcon: "ercodeHover",
},
// offShelfApply: { label: '下架申请', handler: 'handleOffShelfApply' },
// viewCurrent: { label: '查看当前版本', handler: 'handleViewCurrent', icon: 'detail' },
delete: {
label: "删除",
labelColor: "#FF1718",
handler: "delItem",
icon: "del",
hoverIcon: "del",
},
};
export default {
name: "ucStudyIndex",
components: { studyItem, courseForm, courseImage },
computed: {
...mapGetters(["userInfo"]),
disabled() {
return this.loading || this.noMore;
},
},
data() {
return {
inviteTeacher: [],
dialogVisible: false,
courseType: courseType,
fileBaseUrl: process.env.VUE_APP_FILE_BASE_URL,
count: 0,
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: "审核通过",
},
auditTypeEnum: {
1: "新建",
2: "编辑",
3: "停用",
4: "启用",
},
auditResultEnum: {
0: "驳回",
1: "通过",
},
hoverStates: {},
};
},
mounted() {
if (
this.$route.query &&
this.$route.query.open &&
this.$route.query.open == "new"
) {
this.addNewCourse();
}
// this.getList();
},
watch: {
// '$route.query.open':function(val){
// if(val == 'new') {
// this.addNewCourse();
// }
// }
},
methods: {
handleM() {
console.log("handleM");
},
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) {
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, index) => ({
name: key,
label: ACTION_CONFIG[key].label,
handler: this[ACTION_CONFIG[key].handler],
icon: ACTION_CONFIG[key].icon,
hoverIcon: ACTION_CONFIG[key].hoverIcon,
labelColor: ACTION_CONFIG[key].labelColor,
uniqueKey: `${item.id}-${key}-${index}`,
}))
.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.$showMessage('复制成功', '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("此操作将撤回审核中的课程, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
apiCourse.revokeSubmit(item.id).then((res) => {
if (res.status == 200) {
if (res.result) {
this.$message({
type: "success",
message: "撤回成功!",
});
this.getNewList();
}
}
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消撤回",
});
});
},
reset() {
this.params.name = "";
this.params.publish = "";
this.params.status = "";
this.params.enabled = "";
this.params.pageIndex = 1;
this.getNewList();
this.isSearh = false;
},
toExamine(row) {
// this.detailType = row.type;
this.dialogVisible = true;
apiCourse
.auditCourseRecords({
courseId: row.id,
})
.then((res) => {
if (res.status === 200) {
this.inviteTeacher = res.result;
} else {
this.$message.error(res.message);
}
});
},
examine(row) {
if (!row.orgId) {
this.$message.error("课程还未设置资源归属,请先设置资源归属");
return;
}
let $this = this;
this.$confirm("您确定要直接提交审核所选课程吗?", "友情提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
//新的提交流程
apiUserBasic.getOrgHrbpInfo(row.orgId).then((rs) => {
if (rs.status == 200 && rs.result) {
let req = {
courseId: row.id,
email: rs.result.email,
courseUser: row.sysCreateBy,
courseName: row.name,
ucode: rs.result.userNo,
auditUser: rs.result.name,
//ukid:hrbpUser.user_id,
orgId: row.orgId,
orgName: rs.result.orgNamePath + "/" + rs.result.name,
};
apiCourse.sumbits(req).then((res) => {
if (res.status == 200) {
$this.$message.success("提交成功");
row.status = 2;
}
if (res.status == 400) {
$this.$message.error("提交失败:" + res.message);
}
});
} else {
$this.$message.error("获取HRBP审核人员失败:" + rs.message);
}
});
});
},
async delItem(row) {
this.$confirm(`<i class="el-icon-warning-outline"></i>确认删除${row.name}吗?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
dangerouslyUseHTMLString: true,
type: 'warning',
customClass: 'custom-confirm-dialog'
}).then(async () => {
let params = {
id: row.id,
title: row.name,
};
try {
// {id:课程id,多个使用逗号分隔,Boolean erasable 是否物理删除,title:课程的名称, remark 备注}
const { status } = await apiCourse.del(params);
if (status === 200) {
this.$showMessage('删除成功', 'success')
// this.$message.success("操作成功!");
this.getNewList();
} else {
this.$showMessage('删除失败', 'error')
}
} catch (error) {
console.log(error);
}
})
},
jumpRouter(item) {
if (item.published) {
// if (item.type == 10) {
// let routeData = this.$router.resolve({ path: '/course/micro?id='+item.id});
// window.open(this.webBaseUrl+routeData.href, '_blank');
// window.open(this.webBaseUrl + '/course/micro?id=' + item.id, '_blank');
// this.$router.push({path:'/course/micro',query:{id:item.id}})
// }
// if (item.type == 20) {
// let routeData = this.$router.resolve({ path: '/course/detail?id='+item.id});
// window.open(this.webBaseUrl+routeData.href, '_blank');
// window.open(this.webBaseUrl + '/course/detail?id=' + item.id, '_blank');
//this.$router.push({path:'/course/detail',query:{id:item.id}})
this.$router.push({
path: "/course/studyindex",
query: { id: item.id },
});
// }
} else {
// if (item.type == 10) {
// // window.open(`${this.webBaseUrl}/course/microPreview?id=${item.id}`);
// this.$router.push({path:'/course/microPreview',query:{id:item.id}})
// } else {
// window.open(`${this.webBaseUrl}/course/rePreview?id=${item.id}`);
this.$router.push({
path: "/course/rePreview",
query: { id: item.id },
});
// }
}
},
findList() {
this.isSearh = true;
this.getNewList();
},
getList() {
this.noMore = false;
// this.params.teacherId = this.userInfo.aid;
apiCourse.courseList(this.params).then((res) => {
this.loading = false;
if (res.status == 200) {
this.couresList = [...this.couresList, ...res.result.list];
this.count = res.result.count;
console.log(this.couresList.length, "this.count", this.count);
if (this.couresList.length >= this.count) {
this.noMore = true;
}
} else {
this.$showMessage(res.message, 'error')
}
});
},
addNewCourse() {
this.$refs.courseForm.initShow();
},
editCourse(row) {
console.log(row, "editCourse");
this.$refs.courseForm.initShow(row);
},
lastTabChange(tab, event) {
console.log(tab.name);
},
},
};
</script>
<style scoped lang="scss">
.no-wrap {
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
word-break: break-all;
white-space: nowrap;
}
.page-tip {
margin: 20px auto;
text-align: center;
font-size: 13px;
}
.list-wu {
text-align: center;
margin: 40px;
color: #333;
}
.yishenhe {
color: #2ab28b;
font-size: 18px;
}
.daishenhe {
color: #ffb30f;
font-size: 18px;
}
.weitongguo {
font-size: 18px;
color: #e62e38;
}
.caogao {
font-size: 18px;
color: #cecece;
}
.Create-coures {
position: absolute;
right: 32px;
}
// .uc-course-type1{
// padding: 3px 15px;
// background: #3e7fff;
// color: #fff;
// border-radius: 2px
// }
// .uc-course-type2{
// padding: 3px 15px;
// background: #ff8e00;
// color: #fff;
// border-radius: 2px
// }
.uc-badge {
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;
justify-content: space-around;
border-bottom: 1px solid #e8e8e8;
padding: 20px 0px 15px 0px;
margin: 0 32px 0 22px;
::v-deep .uc-course-img {
width: 212px;
img {
width: 212px;
height: 119px;
border: 1px solid #f4f4f5;
}
}
.uc-course-info {
flex: 1;
line-height: 28px;
padding: 0px 10px;
.summary-item {
padding-top: 10px;
height: 40px;
line-height: 15px;
color: #7d7d7d;
font-size: 14px;
overflow: hidden;
width: 90%;
word-break: break-all;
display: -webkit-box;
// overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.uc-course-name {
font-size: 16px;
display: -webkit-box;
white-space: pre-wrap;
// word-wrap: break-word;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
word-break: break-all;
// font-weight: 700;
}
.uc-course-item {
color: #666;
// 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 {
text-align: right;
.btn1 {
height: 44px;
padding: 10px 15px;
}
.btn2 {
height: 44px;
padding: 10px 15px;
}
.btn {
height: 44px;
padding: 10px 15px;
}
}
}
</style>