mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/fe-manage.git
synced 2025-12-22 01:06:45 +08:00
Merge branch 'zcwy-teacher-manage' into master_1202
This commit is contained in:
@@ -108,6 +108,89 @@
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/lecturerlist") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "讲师列表",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/teachingrecord") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "授课记录",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/lecturerfeemanagement") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "讲师费管理",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/lecturerfeestatistics") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "讲师费统计",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/organization") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "培训发生组织",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}if (
|
||||
n.indexOf("/lecturerSystem") !== -1
|
||||
) {
|
||||
state.list = [
|
||||
{
|
||||
name: "讲师管理",
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
name: "讲师体系管理",
|
||||
href: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (
|
||||
n.indexOf("/projectadd") !== -1 ||
|
||||
n.indexOf("/ProjectAdd") !== -1
|
||||
|
||||
@@ -56,6 +56,10 @@ const props = defineProps({
|
||||
accept: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:value', 'change'])
|
||||
@@ -67,6 +71,12 @@ const handleUploadChange = ({ file, fileList }) => {
|
||||
fileList.value = [];
|
||||
return message.error("请上传正确的文件格式");
|
||||
}
|
||||
if(props.size && file.size > props.size){
|
||||
removeUpload()
|
||||
message.destroy();
|
||||
message.error("文件大小超过5MB!");
|
||||
return
|
||||
}
|
||||
emit('update:value', fileList)
|
||||
emit('change', fileList)
|
||||
}
|
||||
|
||||
@@ -415,6 +415,59 @@
|
||||
<router-link to="/teacheropinion">意见</router-link>
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
<a-sub-menu key="sub24" @titleClick="titleClick" v-if="checkMenu('lecturer')">
|
||||
<template #icon>
|
||||
<div class="imgBox">
|
||||
<img style="width: 15px; height: 15px" src="../assets/images/navleft/project.png" />
|
||||
</div>
|
||||
</template>
|
||||
<template #title>讲师管理</template>
|
||||
<a-menu-item key="sub24-1" v-if="checkMenu('lecturer')">
|
||||
<span
|
||||
:class="{
|
||||
circleActive: selectedKeys[0] === 'sub24-1' ? true : false,
|
||||
circle: selectedKeys[0] === 'sub24-1' ? false : true,
|
||||
}"
|
||||
></span>
|
||||
<router-link to="/lecturerlist">讲师列表</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub24-2">
|
||||
<span
|
||||
:class="{
|
||||
circleActive : selectedKeys[0] === 'sub24-2' ? true : false,
|
||||
circle: selectedKeys[0] === 'sub24-2' ? false : true,
|
||||
}"
|
||||
></span>
|
||||
<router-link to="/teachingrecord">授课记录</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub24-3">
|
||||
<span
|
||||
:class="{
|
||||
circleActive: selectedKeys[0] === 'sub24-3' ? true : false,
|
||||
circle: selectedKeys[0] === 'sub24-3' ? false : true,
|
||||
}"
|
||||
></span>
|
||||
<router-link to="/lecturerfeemanagement">讲师费管理</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub24-4">
|
||||
<span
|
||||
:class="{
|
||||
circleActive: selectedKeys[0] === 'sub24-4' ? true : false,
|
||||
circle: selectedKeys[0] === 'sub24-4' ? false : true,
|
||||
}"
|
||||
></span>
|
||||
<router-link to="/lecturerfeestatistics">讲师费统计</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub24-5">
|
||||
<span
|
||||
:class="{
|
||||
circleActive: selectedKeys[0] === 'sub24-5' ? true : false,
|
||||
circle: selectedKeys[0] === 'sub24-5' ? false : true,
|
||||
}"
|
||||
></span>
|
||||
<router-link to="/organization">培训发生组织</router-link>
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
<a-menu-item key="sub13" @titleClick="titleClick" v-if="checkMenu('articlemanage')">
|
||||
<div class="imgBox">
|
||||
<img
|
||||
@@ -623,8 +676,6 @@
|
||||
</div>
|
||||
<router-link to="/dictmanage">字典管理</router-link>
|
||||
</a-menu-item>
|
||||
|
||||
|
||||
</a-menu>
|
||||
</div>
|
||||
<div
|
||||
@@ -687,6 +738,9 @@
|
||||
<a-menu-item key="sub22" @titleClick="titleClick">
|
||||
<router-link to="/tooldown">教师专区</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub24" @titleClick="titleClick">
|
||||
<router-link to="/lecturerlist">讲师管理</router-link>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="sub13" @titleClick="titleClick">
|
||||
<router-link to="/articlemanage">文章</router-link>
|
||||
</a-menu-item>
|
||||
@@ -710,7 +764,6 @@
|
||||
<a-menu-item key="sub20" v-if="checkMenu('dictmanage')">
|
||||
<router-link to="/dictmanage">字典</router-link>
|
||||
</a-menu-item>
|
||||
|
||||
</a-menu>
|
||||
</div>
|
||||
</div>
|
||||
@@ -752,6 +805,12 @@ export default {
|
||||
"sub21",
|
||||
"sub22",
|
||||
"sub23",
|
||||
"sub24",
|
||||
"sub25",
|
||||
"sub26",
|
||||
"sub27",
|
||||
"sub28",
|
||||
"sub29",
|
||||
],
|
||||
openKeys: localStorage.getItem("openKeys")
|
||||
? JSON.parse(localStorage.getItem("openKeys"))
|
||||
@@ -968,11 +1027,47 @@ export default {
|
||||
pagename: "问答管理",
|
||||
},
|
||||
{
|
||||
href: "/evaluationupload",
|
||||
href: "/insidelecturer",
|
||||
openKeys: "sub23",
|
||||
selectedKeys: "sub23-1",
|
||||
pagename: "测评上传",
|
||||
},
|
||||
{
|
||||
href: "/lecturerlist",
|
||||
openKeys: "sub24",
|
||||
selectedKeys: "sub24-1",
|
||||
pagename: "讲师列表",
|
||||
},
|
||||
{
|
||||
href: "/teachingrecord",
|
||||
openKeys: "sub24",
|
||||
selectedKeys: "sub24-2",
|
||||
pagename: "授课记录",
|
||||
},
|
||||
{
|
||||
href: "/lecturerfeemanagement",
|
||||
openKeys: "sub24",
|
||||
selectedKeys: "sub24-3",
|
||||
pagename: "讲师费管理",
|
||||
},
|
||||
{
|
||||
href: "/lecturerfeestatistics",
|
||||
openKeys: "sub24",
|
||||
selectedKeys: "sub24-4",
|
||||
pagename: "讲师费统计",
|
||||
},
|
||||
{
|
||||
href: "/organization",
|
||||
openKeys: "sub24",
|
||||
selectedKeys: "sub24-5",
|
||||
pagename: "培训发生组织",
|
||||
},
|
||||
{
|
||||
href: "/lecturerSystem",
|
||||
openKeys: "sub29",
|
||||
selectedKeys: "sub29",
|
||||
pagename: "讲师体系管理",
|
||||
},
|
||||
{
|
||||
href: "/download",
|
||||
openKeys: "sub15",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
import {defineProps, defineExpose, ref, computed, onMounted, defineEmits, nextTick} from "vue";
|
||||
import {defineProps, defineExpose, ref, computed, onMounted, defineEmits, nextTick,watch} from "vue";
|
||||
import {usePage, useRequest, useRowsPageNoInit} from "@/api/request";
|
||||
import {useResetRef} from "@/utils/useCommon";
|
||||
|
||||
@@ -65,7 +65,15 @@
|
||||
showSizeChanger:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
selectedRowKeys:{
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedRows:{
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(["update:params", "update:selectedRowKeys", "update:selectedRows"]);
|
||||
const rowSelectKeys = ref([]);
|
||||
@@ -74,7 +82,12 @@
|
||||
const postParam = computed(() => ({ ...params.value, ...props.params }));
|
||||
|
||||
const { data, loading, total, fetch: onFetch } = props.request(props.url, postParam);
|
||||
|
||||
watch(()=>data.value,(val)=>{
|
||||
if(val&&props.selectedRowKeys){
|
||||
rowSelectKeys.value = props.selectedRowKeys
|
||||
selectsData.value = props.selectedRows
|
||||
}
|
||||
})
|
||||
const rowSelection = computed(() => (props.type ? {
|
||||
type: props.type,
|
||||
columnWidth: 20,
|
||||
@@ -108,6 +121,22 @@
|
||||
|
||||
function onSelectChange(e, l) {
|
||||
rowSelectKeys.value = e;
|
||||
const array = []
|
||||
l.includes(undefined)&&(
|
||||
selectsData.value = [...selectsData.value,...l],
|
||||
selectsData.value = selectsData.value.filter(t => t),
|
||||
selectsData.value = Array.from(new Set(selectsData.value.map(item => item.id)))
|
||||
.map(id => selectsData.value.find(item => item.id === id)),
|
||||
selectsData.value.map(item=>{
|
||||
e.some(i=>{
|
||||
if(item.id === i){
|
||||
array.push(item)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}),
|
||||
l = array
|
||||
)
|
||||
selectsData.value = l;
|
||||
emit("update:selectedRowKeys", e);
|
||||
emit("update:selectedRows", l);
|
||||
@@ -160,6 +189,7 @@
|
||||
|
||||
const fetch = () => nextTick(onFetch);
|
||||
|
||||
|
||||
defineExpose({ fetch, reset, resetSelected, clear, toLoading, remove , params });
|
||||
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class="body">
|
||||
<div><span>{{ content }}</span></div>
|
||||
</div>
|
||||
<div class="del_btnbox">
|
||||
<div class="del_btnbox" v-if="isCloseBtn">
|
||||
<div class="del_btn btn2" @click="close" v-if="cancel">
|
||||
<div class="btnText">取消</div>
|
||||
</div>
|
||||
@@ -30,6 +30,11 @@
|
||||
<div class="btnText">确定</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="del_btnbox" v-else>
|
||||
<div class="del_btn btn2" @click="close">
|
||||
<div class="btnText">关闭</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
@@ -64,6 +69,10 @@ const props = defineProps({
|
||||
type: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
isCloseBtn: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
const types = {
|
||||
|
||||
646
src/components/lecturer/ImportWork.vue
Normal file
646
src/components/lecturer/ImportWork.vue
Normal file
@@ -0,0 +1,646 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal
|
||||
:visible="showWork"
|
||||
:footer="null"
|
||||
:closable="closableQR"
|
||||
wrapClassName="codeModal"
|
||||
style="margin-top: 400px"
|
||||
:zIndex="9"
|
||||
@cancel="qr_exit"
|
||||
>
|
||||
<div class="QR">
|
||||
<div class="qr_header"></div>
|
||||
<div class="qr_main">
|
||||
<div class="qrm_header">
|
||||
<span style="title">{{ title }}</span>
|
||||
<div class="close_exit" @click="closeCodeModal"></div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="contents">
|
||||
<div class="drawerMain">
|
||||
<div class="main">
|
||||
<div class="minatitl">
|
||||
<div class="up1">请下载</div>
|
||||
<div class="up2" @click="downTemplate" style="cursor: pointer">
|
||||
模板
|
||||
</div>
|
||||
<div class="up1">,按要求填写数据并导入</div>
|
||||
</div>
|
||||
<div class="upload">
|
||||
<div class="text">上传:</div>
|
||||
<div class="right">
|
||||
<div style="height: 176px; margin-bottom: 20px">
|
||||
<a-upload-dragger v-model:fileList="fileList" :action="importHomeWork" name="uploadFile"
|
||||
:headers="headers"
|
||||
@change="handleChange" :showUploadList="false">
|
||||
<p class="ant-upload-drag-icon">
|
||||
<inbox-outlined></inbox-outlined>
|
||||
</p>
|
||||
<p class="ant-upload-text">点击或将文件拖拽到此处上传</p>
|
||||
<p class="ant-upload-hint">支持扩展名:.xls/.xlsx</p>
|
||||
</a-upload-dragger>
|
||||
</div>
|
||||
<div class="loadstate">
|
||||
<div class="loadborder" v-if="uploadpercent < 100 && uploadpercent !== -1">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="stateloading">正在上传</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
<div class="curloading">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loadborder" v-if="uploadErr">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="statedefeat">上传失败</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
|
||||
<div class="curloading">
|
||||
<div style="color: #387df7; margin-left: 20px; cursor: pointer">
|
||||
下载失败数据
|
||||
</div>
|
||||
</div>
|
||||
<div class="defeat" style="display: flex; align-items: center">
|
||||
<div style="color: #ff7474">
|
||||
{{ succNum }}条数据导入成功,{{ errNum }}条数据导入失败
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loadborder" v-if="uploadpercent === 100">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="statesucce">上传成功</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
<div class="curloading">
|
||||
<div class="cancel" style="margin-left: 20px; cursor: pointer" @click="removeUpload">
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="errNum">
|
||||
<div class="downloadErr" @click="downloadEeeorData">
|
||||
下载失败数据
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="uploadpercent === 100" class="defeat" style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 500px;
|
||||
height: 40px;" :style="{
|
||||
background: errNum
|
||||
? 'rgba(255, 116, 116, 0.1)'
|
||||
: 'rgba(53, 174, 105, 0.1)',
|
||||
border: errNum ? '1px solid #ff7474' : '1px solid #35AE69',
|
||||
}">
|
||||
<img style="width: 14px; height: 14px; margin-left: 16px" :src="
|
||||
errNum
|
||||
? require('../../assets/images/err.png')
|
||||
: require('../../assets/images/success.png')
|
||||
" />
|
||||
<div style="margin-left: 8px" :style="{ color: errNum ? '#ff7474' : 'rgba(0,0,0,0.65)' }">
|
||||
{{ succNum }}条数据导入成功,{{ errNum }}条数据导入失败
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn">
|
||||
<button class="btn1" @click="closeCodeModal">取消</button>
|
||||
<button class="btn2" @click="closeCodeModal">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watch,ref,computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { useStore } from "vuex";
|
||||
import * as api from "../../api/index1";
|
||||
import {getCookieForName} from "@/api/method";
|
||||
export default {
|
||||
name: "importWork",
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
showWork: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
title:{
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
template:{
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const state = reactive({
|
||||
fileType: ["xls", "xlsx"],
|
||||
importHomeWork:
|
||||
process.env.VUE_APP_BASE_API + props.url,
|
||||
uploadpercent: -1,
|
||||
uploadErr: false, //上传失败
|
||||
addLoading: false,
|
||||
fileList: [],
|
||||
succNum: 0, //成功数据数
|
||||
errNum: 0, //失败数据数
|
||||
downloadErrUrl: null, //下载失败数据
|
||||
fileName: "",
|
||||
});
|
||||
const headers = { token: getCookieForName("token") };
|
||||
|
||||
const closeCodeModal = () => {
|
||||
ctx.emit("update:showWork", false);
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
state.uploadErr = false; //上传失败
|
||||
};
|
||||
|
||||
//上传文件
|
||||
const handleChange = (info) => {
|
||||
if (info) {
|
||||
var FileExt = info.file.name.replace(/.+\./, "");
|
||||
if (["xls", "xlsx"].indexOf(FileExt.toLowerCase()) === -1) {
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
message.destroy();
|
||||
message.error("请按模板格式上传文件");
|
||||
return;
|
||||
}
|
||||
}
|
||||
let isLt1M = info.file.size < 512000000;
|
||||
console.log(info.file.size, isLt1M)
|
||||
if (!isLt1M) {
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
message.destroy();
|
||||
message.error("文件大小超出500M,请重新上传");
|
||||
return;
|
||||
}
|
||||
|
||||
state.addLoading = true;
|
||||
state.uploadpercent = parseInt(info.file.percent);
|
||||
console.log("我是文件上传的进度---------->", info.file.percent);
|
||||
const status = info.file.status;
|
||||
console.log(info.file,'status')
|
||||
if (status !== "uploading") {
|
||||
// console.log(info.file, info.fileList);
|
||||
}
|
||||
if (status === "done") {
|
||||
state.fileName = info.file.name;
|
||||
if(!info.file.response.data){
|
||||
message.error(`${info.file.name}上传失败`);
|
||||
}
|
||||
let i = 0;
|
||||
let timeouts = setTimeout(() => {
|
||||
// clearInterval(timer)
|
||||
state.addLoading = false;
|
||||
message.destroy();
|
||||
message.error(`文件导入超时`);
|
||||
}, 30000);
|
||||
// let timer = setInterval(() => {
|
||||
// let uid = info.file.response.data;
|
||||
// api
|
||||
// .getImportStatus(uid)
|
||||
// .then((res) => {
|
||||
// console.log("查询导入状态", res);
|
||||
// if (res.data.code === 200) {
|
||||
// if (res.data.data.status !== "START") {
|
||||
// i++;
|
||||
// if (i === 1) {
|
||||
// message.destroy();
|
||||
// message.success(`${info.file.name}上传成功`);
|
||||
// state.addLoading = false;
|
||||
// props.searchTaskList && props.searchTaskList();
|
||||
// }
|
||||
// state.succNum = res.data.data.successNum;
|
||||
// state.errNum = res.data.data.failedNum;
|
||||
// state.downloadErrUrl = res.data.data.url;
|
||||
// console.log("props.getStudent", props.getStudent);
|
||||
// clearInterval(timer);
|
||||
// clearTimeout(timeouts);
|
||||
// }
|
||||
// } else {
|
||||
// state.addLoading = false;
|
||||
// message.destroy();
|
||||
// clearTimeout(timeouts);
|
||||
// }
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// state.addLoading = false;
|
||||
// clearInterval(timer);
|
||||
// clearTimeout(timeouts);
|
||||
// console.log("查询导入状态失败", err);
|
||||
// });
|
||||
// }, 500);
|
||||
} else if (status === "error") {
|
||||
state.uploadErr = true;
|
||||
message.error(`${info.file.name}上传失败`);
|
||||
}
|
||||
};
|
||||
//删除
|
||||
const removeUpload = () => {
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
state.uploadErr = false; //上传失败
|
||||
state.succNum = 0;
|
||||
state.errNum = 0;
|
||||
state.downloadErrUrl = null;
|
||||
state.addLoading = false;
|
||||
};
|
||||
// 下载失败数据
|
||||
const downloadEeeorData = () => {
|
||||
if (state.downloadErrUrl !== "") {
|
||||
window.open(process.env.VUE_APP_FILE_PATH + state.downloadErrUrl);
|
||||
}
|
||||
};
|
||||
function downTemplate() {
|
||||
window.open(`${process.env.VUE_APP_BASE}/template/${props.template}.xlsx`);
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
closeCodeModal,
|
||||
handleChange,
|
||||
downTemplate,
|
||||
headers,
|
||||
removeUpload,
|
||||
downloadEeeorData,
|
||||
};
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.codeModal {
|
||||
.ant-modal {
|
||||
.ant-modal-content {
|
||||
width: 479px !important;
|
||||
.ant-modal-body {
|
||||
.QR {
|
||||
z-index: 11;
|
||||
width: 700px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.21);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 10%;
|
||||
transform: translate(-50%, -50%);
|
||||
.qr_header {
|
||||
position: absolute;
|
||||
width: calc(100%);
|
||||
height: 40px;
|
||||
// background: linear-gradient(
|
||||
// rgba(78, 166, 255, 0.2) 0%,
|
||||
// rgba(78, 166, 255, 0) 100%
|
||||
// );
|
||||
}
|
||||
.qr_main {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.qrm_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding-left: 26px;
|
||||
font-size: 16px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 22px;
|
||||
}
|
||||
.close_exit {
|
||||
position: absolute;
|
||||
right: 42px;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(@/assets/images/coursewareManage/close.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.line{
|
||||
height: 1px;
|
||||
margin-top: 16px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.contents{
|
||||
display: flex;
|
||||
min-height: 500px;
|
||||
.drawerMain {
|
||||
min-width: 600px;
|
||||
margin: 0px 32px 0px 32px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
overflow-y: auto;
|
||||
|
||||
.minatitl {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
.up1 {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.up2 {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload {
|
||||
margin-top: 32px;
|
||||
display: flex;
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.right {
|
||||
margin-left: 6px;
|
||||
|
||||
.load {
|
||||
width: 500px;
|
||||
height: 176px;
|
||||
background: #f5f9fd;
|
||||
border-radius: 4px;
|
||||
// opacity: 0.3;
|
||||
border: 1px dashed #caddfd;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.cloud {
|
||||
margin-top: 52px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background-image: url(../../assets/images/basicinfo/cloud.png);
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
margin-top: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tipz {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.loadstate {
|
||||
width: 500px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
.loadborder {
|
||||
width: 500px;
|
||||
height: 173px;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #eaeaea;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
margin-left: 20px;
|
||||
position: relative;
|
||||
|
||||
.defeat {
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
left: 46px;
|
||||
top: 38px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 30px;
|
||||
height: 34px;
|
||||
background-image: url(../../assets/images/basicinfo/exl.png);
|
||||
}
|
||||
|
||||
.timebox {
|
||||
margin-left: 15px;
|
||||
margin-top: -5px;
|
||||
|
||||
.timetop {
|
||||
display: flex;
|
||||
width: 262px;
|
||||
justify-content: space-between;
|
||||
|
||||
// margin-bottom: 8px;
|
||||
.tit {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.stateloading {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
}
|
||||
|
||||
.statedefeat {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #ff7474;
|
||||
}
|
||||
|
||||
.statesucce {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #35ae69;
|
||||
}
|
||||
}
|
||||
|
||||
.prog {
|
||||
width: 262px;
|
||||
height: 5px;
|
||||
background: #eaf1fe;
|
||||
border-radius: 4px;
|
||||
|
||||
.inprogloading {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #4ea6ff;
|
||||
}
|
||||
|
||||
//下载失败条
|
||||
.inprogdefeat {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #ff7474;
|
||||
}
|
||||
|
||||
//下载成功条
|
||||
.inprogsucce {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #57c887;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.curloading {
|
||||
margin-left: 15px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
|
||||
.cur {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.downloadErr {
|
||||
width: 120px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #387df7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
margin-left: 66px;
|
||||
margin-top: 16px;
|
||||
position: absolute;
|
||||
bottom: 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnn {
|
||||
height: 72px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.16);
|
||||
|
||||
.btn1 {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid #4ea6ff;
|
||||
border-radius: 8px;
|
||||
color: #4ea6ff;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn2 {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background: #4ea6ff;
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
margin-left: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
523
src/components/project/AddApprover.vue
Normal file
523
src/components/project/AddApprover.vue
Normal file
@@ -0,0 +1,523 @@
|
||||
<template>
|
||||
<div class="CommonStudent">
|
||||
<a-drawer destroyOnClose :visible="visiable" class="drawerStyle ProjCheckship CommonStudent" placement="right" width="40%">
|
||||
<div class="drawerMain" id="ProjCheckship" style="">
|
||||
<div class="header">
|
||||
<div class="headerTitle">
|
||||
选择{{title}}
|
||||
</div>
|
||||
<img style="width: 29px; height: 29px; cursor: pointer" src="../../assets/images/basicinfo/close.png"
|
||||
@click="closeDrawer"/>
|
||||
</div>
|
||||
<div style="display: flex; overflow-x: auto; overflow-y: auto">
|
||||
<div class="tabs" style="min-width: 800px">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane :key="1" tab="快速选人">
|
||||
<div :style="{ height: screenHeight - 235 + 'px' }">
|
||||
<div class="tab1">
|
||||
<a-form-item label="姓名">
|
||||
<a-input v-model:value="nameSearch.keyword" style="width: 270px; height: 40px; border-radius: 8px"
|
||||
placeholder="请输入姓名"/>
|
||||
<a-button type="primary" @click="onSearchStu" style="margin-left: 20px; border-radius: 4px">
|
||||
<template #icon>
|
||||
<SearchOutlined/>
|
||||
</template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button type="primary" @click="resetStu" style="margin-left: 20px; border-radius: 4px">重置
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="chooseLeft" style="display: grid; grid-template-columns: 250px auto">
|
||||
<div :style="{
|
||||
height: screenHeight - 180 + 'px',
|
||||
overflowY: 'auto',
|
||||
}" style="border: 1px solid #f0f0f0">
|
||||
<div class="tree" style="margin: 10px 4px 220px 10px">
|
||||
<a-tree allow-clear tree-default-expand-all :tree-data="treeData" :loading="orgLoading"
|
||||
:load-data="onLoadData" v-model:selectedKeys="stuTreeSelectKeys"
|
||||
v-model:expandedKeys="stuTreeExpandedKeys" :fieldNames="{
|
||||
children: 'treeChildList',
|
||||
key: 'id',
|
||||
title: 'name',
|
||||
value: 'name',
|
||||
}" @select="stuStuOrgSelect">
|
||||
</a-tree>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tableBox tabb" style="
|
||||
margin: 0px 4px 120px 10px;
|
||||
border: 1px solid #f0f0f0;
|
||||
">
|
||||
<BaseTable ref="stuTableRef" :columns="stuColumns" :url="USER_LIST_PAGE" pageKey="pageNo"
|
||||
v-model:params="nameSearch" :request="useNewRowsPageNoInit"
|
||||
v-model:selectedRows="stuSelectRows" v-model:selectedRowKeys="stuSelectRowKeys" type="checkbox"></BaseTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
<div class="right1" style="min-width: 200px">
|
||||
<div class="onerow">
|
||||
<div class="onleft">
|
||||
<div class="already">已选</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :style="{ 'max-height': screenHeight - 235 + 'px' }" style="overflow-y: auto">
|
||||
<div class="selecteds">
|
||||
<div class="person">快速选人</div>
|
||||
<div v-for="(item, i) in stuSelectRows" :key="i">
|
||||
<div v-if="i < 11">
|
||||
<div class="chose">
|
||||
{{ item.realName }}
|
||||
<div class="ch" @click="stuTableRef.remove(i)"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="person">
|
||||
<div class="chose">
|
||||
{{ item.realName }}
|
||||
<div class="ch" @click="stuTableRef.remove(i)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!person && stuSelectRows.length > 10" class="ifsw">
|
||||
<div @click="person = !person" class="“sw”">查看更多></div>
|
||||
</div>
|
||||
<div v-if="person && stuSelectRows.length > 10" class="ifsw">
|
||||
<div @click="person = !person" class="sw">收起<</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex;justify-content: center;" class="btnn" >
|
||||
<button class="btn2" style="width: 100px; height:38px;background:
|
||||
#4ea6ff;border: none;margin-right: 15px; border-radius: 8px;color:aliceblue" @click="closeDrawer">取消</button>
|
||||
<button class="btn2" style="width: 100px;
|
||||
height:38px;background: #4ea6ff;border: none; border-radius: 8px ;color:aliceblue" @click="submitAuth">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
<a-button @click="openDrawer" type="link" style="width:100%">
|
||||
<slot></slot>
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {message} from "ant-design-vue";
|
||||
import {computed, defineEmits, defineProps, ref, watch,onMounted} from "vue";
|
||||
import {useNewRowsPageNoInit, request, useRequest, useTotalPage} from "@/api/request";
|
||||
import {
|
||||
saveStu,
|
||||
} from "@/api/index1";
|
||||
import dialog from "@/utils/dialog";
|
||||
import BaseTable from "@/components/common/BaseTable";
|
||||
import {AUDIENCE_LIST, ORG_CHILD_LIST, ORG_LIST, STUDENT_LIST, USER_LIST_PAGE} from "@/api/apis";
|
||||
import {addTutor,getOnlineLearningList}from '@/api/examineApi.js'
|
||||
import {boeRequest} from "@/api/request";
|
||||
const emit = defineEmits({});
|
||||
const props = defineProps({
|
||||
arrayList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
onMounted(()=>{
|
||||
// onlineLearningList()
|
||||
})
|
||||
const courseList = ref([])
|
||||
const onlineLearningList = () =>{
|
||||
boeRequest('/activityApi/examine/getOnlineLearningList post').then(res=>{
|
||||
courseList.value = res.data.filter(item=>item.status == 0).map(item => item.courseId)
|
||||
})
|
||||
}
|
||||
const stuSelectRows = ref([]);
|
||||
|
||||
const stuSelectRowKeys = ref([]);
|
||||
const stuTableRef = ref();
|
||||
const teaunm = ref([])
|
||||
watch(stuSelectRows,(val)=>{
|
||||
if(val.length == 0){
|
||||
teaunm.value = []
|
||||
return
|
||||
}
|
||||
teaunm.value = val.map((res,index)=>{
|
||||
return {
|
||||
userName:res?.realName,
|
||||
userNo:res?.userNo,
|
||||
type: props.type,
|
||||
userId: res?.id,
|
||||
label: res?.realName + res?.userNo,
|
||||
...res
|
||||
}
|
||||
})
|
||||
},{deep:true})
|
||||
const person = ref(false);
|
||||
const visiable = ref(false);
|
||||
const activeKey = ref(1);
|
||||
|
||||
const nameSearch = ref({
|
||||
keyword: "",
|
||||
departId: '',
|
||||
});
|
||||
const stuTreeSelectKeys = ref([]);
|
||||
const stuTreeExpandedKeys = ref([]);
|
||||
const audienceName = ref({
|
||||
keyword: "",
|
||||
});
|
||||
|
||||
const { data: treeData, loading: orgLoading } = useRequest(
|
||||
ORG_LIST,
|
||||
{ keyword: "" },
|
||||
);
|
||||
|
||||
const stuColumns = ref([
|
||||
{
|
||||
title: "姓名",
|
||||
dataIndex: "realName",
|
||||
key: "realName",
|
||||
width: 80,
|
||||
align: "center",
|
||||
className: "h",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "工号",
|
||||
dataIndex: "userNo",
|
||||
key: "userNo",
|
||||
width: 80,
|
||||
align: "center",
|
||||
className: "h",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "归属组织",
|
||||
dataIndex: "orgName",
|
||||
key: "orgName",
|
||||
width: 80,
|
||||
align: "center",
|
||||
className: "h",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "部门",
|
||||
dataIndex: "departName",
|
||||
key: "departName",
|
||||
width: 80,
|
||||
align: "center",
|
||||
className: "h",
|
||||
ellipsis: true,
|
||||
},
|
||||
]);
|
||||
const screenHeight = ref(document.body.clientHeight);
|
||||
|
||||
const closeDrawer = () => {
|
||||
deleteDepSelect();
|
||||
visiable.value = false;
|
||||
nameSearch.value.keyword = "";
|
||||
};
|
||||
|
||||
|
||||
function onLoadData(treeNode) {
|
||||
return request(ORG_CHILD_LIST, { keyword: "", orgId: treeNode.id }).then(
|
||||
(r) => {
|
||||
treeNode.dataRef.treeChildList = r.data;
|
||||
treeData.value = [...treeData.value];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const openDrawer = () => {
|
||||
visiable.value = true;
|
||||
stuSelectRows.value = props.arrayList
|
||||
stuSelectRowKeys.value = props.arrayList.map(item=>item.userId)
|
||||
};
|
||||
|
||||
function onSearchStu() {
|
||||
stuTableRef.value.reset(nameSearch.value);
|
||||
}
|
||||
|
||||
function stuStuOrgSelect(e) {
|
||||
nameSearch.value.departId = e.join("");
|
||||
stuTableRef.value.fetch();
|
||||
}
|
||||
|
||||
const resetStu = () => {
|
||||
nameSearch.value.keyword = "";
|
||||
stuTableRef.value.reset({ keyword: "", departId: '' });
|
||||
};
|
||||
//清空选择部门信息
|
||||
const deleteDepSelect = () => {
|
||||
stuSelectRows.value = [];
|
||||
};
|
||||
|
||||
//确定添加授权
|
||||
const submitAuth = () => {
|
||||
emit('update:arrayList',teaunm.value)
|
||||
emit('valueChange',teaunm.value,props.type)
|
||||
visiable.value = false;
|
||||
emit("finash", false);
|
||||
};
|
||||
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
watch(visiable, () => {
|
||||
audienceName.value.keyword = "";
|
||||
nameSearch.value.departId = '';
|
||||
stuTreeExpandedKeys.value = [];
|
||||
stuTreeSelectKeys.value = [];
|
||||
nameSearch.value.keyword = "";
|
||||
audienceName.value.keyword = "";
|
||||
|
||||
if (!visiable.value) {
|
||||
stuTableRef.value && stuTableRef.value.clear();
|
||||
stuTableRef.value && stuTableRef.value.reset({ keyword: "", departId: '' });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.CommonStudent > .ant-drawer-content-wrapper {
|
||||
min-width: 1200px !important;
|
||||
width: 1200px !important;
|
||||
}
|
||||
|
||||
.CommonStudent {
|
||||
.ant-btn-primary {
|
||||
background-color: #4ea6ff !important;
|
||||
}
|
||||
|
||||
.cus-select {
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tableBox .ant-table-row .ant-table-cell {
|
||||
height: 48px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4f5156;
|
||||
line-height: 29px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.tableBox .ant-table-thead tr th {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ant-tabs-tabpane {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-tabs {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.right1 {
|
||||
border-left: 1px solid #f2f6fe;
|
||||
margin-left: 20px;
|
||||
|
||||
.onerow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-right: 40px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
width: 100%;
|
||||
|
||||
.onleft {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
|
||||
.already {
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-left: 32px;
|
||||
white-space: nowrap;
|
||||
// margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.count {
|
||||
color: #4ea6ff;
|
||||
font-size: 16px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.peo {
|
||||
color: rgba(51, 51, 51, 1);
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.clbox {
|
||||
margin-right: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
width: 104px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
background: #4ea6ff;
|
||||
|
||||
.colose {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
// border-radius: 8px;
|
||||
// background: #ffffff;
|
||||
// position: relative;
|
||||
background-image: url(../../assets/images/basicinfo/ch.png);
|
||||
background-size: 100%;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.allclear {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selecteds {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: 32px;
|
||||
|
||||
.person {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
border-top: 1px solid #f2f6fe;
|
||||
}
|
||||
|
||||
.chose {
|
||||
width: 64px;
|
||||
height: 24px;
|
||||
margin-top: 25px;
|
||||
margin-right: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(56, 139, 225, 1);
|
||||
color: rgba(56, 139, 225, 1);
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
|
||||
.ch {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url(../../assets/images/basicinfo/ch.png);
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
.ifsw {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: center;
|
||||
color: #4ea6ff;
|
||||
}
|
||||
|
||||
.sw {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: justify;
|
||||
color: #4ea6ff;
|
||||
margin-top: 23px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.dept {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
border-top: 1px solid #f2f6fe;
|
||||
}
|
||||
|
||||
.chose1 {
|
||||
//width: 90px;
|
||||
height: 24px;
|
||||
margin-top: 25px;
|
||||
margin-right: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(56, 139, 225, 1);
|
||||
color: rgba(56, 139, 225, 1);
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
|
||||
.span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ch1 {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url(../../assets/images/basicinfo/ch.png);
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
border-top: 1px solid #f2f6fe;
|
||||
}
|
||||
|
||||
.chose2 {
|
||||
//width: 120px;
|
||||
height: 24px;
|
||||
margin-top: 25px;
|
||||
margin-right: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid rgba(56, 139, 225, 1);
|
||||
color: rgba(56, 139, 225, 1);
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
|
||||
.span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ch2 {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url(../../assets/images/basicinfo/ch.png);
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
265
src/components/project/AddContent.vue
Normal file
265
src/components/project/AddContent.vue
Normal file
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<div class="twoDimensionalCode">
|
||||
<!--选择教师专长页面 -->
|
||||
<a-modal
|
||||
:visible="showContent"
|
||||
:footer="null"
|
||||
:closable="closableQR"
|
||||
wrapClassName="codeModal"
|
||||
style="margin-top: 400px"
|
||||
:zIndex="9999"
|
||||
@cancel="qr_exit"
|
||||
>
|
||||
<div class="QR">
|
||||
<div class="qr_header"></div>
|
||||
<div class="qr_main">
|
||||
<div class="qrm_header">
|
||||
<span style="title">{{Addtitle}}</span>
|
||||
<div class="close_exit" @click="closeCodeModal"></div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<a-tree
|
||||
checkable
|
||||
:tree-data="treeData"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
v-model:checkedKeys="checkedKeys"
|
||||
@check="onCheck"
|
||||
:fieldNames="{
|
||||
key: 'id',
|
||||
title: 'name',
|
||||
value: 'name',
|
||||
}"
|
||||
>
|
||||
<!-- <template #title0010><span style="color: #1890ff">sss</span></template> -->
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="headers">
|
||||
<div>已选择标签<span style="color: #4ea6ff;margin-left:5px;">{{treeAddData?.length}}</span>个</div>
|
||||
<div class="header_right" @click="clearTree">清空</div>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<div
|
||||
class="tag"
|
||||
v-for="(item, index) in treeAddData"
|
||||
:key="index"
|
||||
>
|
||||
<div>{{ item?.name }}</div>
|
||||
<div @click="deleteTree(item)" class="tag_delete">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 20px;" @click="closeCodeModal">取消</a-button>
|
||||
<a-button type="primary" @click="queryCreate">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
<!--二维码页面 -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { reactive, toRefs, watch,ref,computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { useStore } from "vuex";
|
||||
export default {
|
||||
name: "AddContent",
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
showContent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
Addtitle:{
|
||||
type:String,
|
||||
default: true,
|
||||
},
|
||||
AddContentList:{
|
||||
type:Array,
|
||||
default: ()=>[],
|
||||
}
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const state = reactive({
|
||||
qrcodeSize: 800,
|
||||
codeInfo: {},
|
||||
courseUrl: "https://www.baidu.com/",
|
||||
showUrl: false,
|
||||
domain: location.protocol+'//'+location.host,
|
||||
treeAddData:[],
|
||||
});
|
||||
const store = useStore();
|
||||
const treeData = computed(() => store.state.content_type)
|
||||
watch(()=>props.showContent, (val) => {
|
||||
if(!val){
|
||||
expandedKeys.value = []
|
||||
selectedKeys.value = []
|
||||
checkedKeys.value = []
|
||||
}else{
|
||||
state.treeAddData = props?.AddContentList
|
||||
checkedKeys.value = props?.AddContentList?.map(item=>item.id)
|
||||
}
|
||||
});
|
||||
const onCheck = (checkedKeys, {checked: bool, checkedNodes, node, event}) => {
|
||||
state.treeAddData = checkedNodes.filter(node => !node.children || node.children.length === 0);
|
||||
console.log(state.treeAddData,'state.treeAddData')
|
||||
}
|
||||
const deleteTree = (item) => {
|
||||
state.treeAddData = state.treeAddData.filter(node => node.id !== item.id);
|
||||
checkedKeys.value = state.treeAddData.map(item=>item.id)
|
||||
}
|
||||
const clearTree = () => {
|
||||
state.treeAddData = [];
|
||||
checkedKeys.value = [];
|
||||
}
|
||||
const queryCreate = () => {
|
||||
ctx.emit("update:AddContentList", state.treeAddData);
|
||||
closeCodeModal()
|
||||
}
|
||||
const closeCodeModal = () => {
|
||||
ctx.emit("update:showContent", false);
|
||||
};
|
||||
const expandedKeys = ref([]);
|
||||
const selectedKeys = ref([]);
|
||||
const checkedKeys = ref([]);
|
||||
return {
|
||||
...toRefs(state),
|
||||
closeCodeModal,
|
||||
queryCreate,
|
||||
deleteTree,
|
||||
clearTree,
|
||||
onCheck,
|
||||
expandedKeys,
|
||||
selectedKeys,
|
||||
checkedKeys,
|
||||
treeData,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.twoDimensionalCode {
|
||||
}
|
||||
.codeModal {
|
||||
.ant-modal {
|
||||
.ant-modal-content {
|
||||
width: 479px !important;
|
||||
.ant-modal-body {
|
||||
.QR {
|
||||
z-index: 9999;
|
||||
width: 700px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.21);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 10%;
|
||||
transform: translate(-50%, -50%);
|
||||
.qr_header {
|
||||
position: absolute;
|
||||
width: calc(100%);
|
||||
height: 40px;
|
||||
// background: linear-gradient(
|
||||
// rgba(78, 166, 255, 0.2) 0%,
|
||||
// rgba(78, 166, 255, 0) 100%
|
||||
// );
|
||||
}
|
||||
.qr_main {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.qrm_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding-left: 26px;
|
||||
font-size: 16px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 22px;
|
||||
}
|
||||
.close_exit {
|
||||
position: absolute;
|
||||
right: 42px;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(@/assets/images/coursewareManage/close.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.line{
|
||||
height: 1px;
|
||||
margin-top: 16px;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
.content{
|
||||
display: flex;
|
||||
min-height: 500px;
|
||||
.left{
|
||||
width: 50%;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
padding: 30px 15px;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.right{
|
||||
width: 50%;
|
||||
// max-height: 600px;
|
||||
// overflow-y: auto;
|
||||
.headers{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 30px 15px;
|
||||
.header_right{
|
||||
color: #666666;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.tags{
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
padding: 0 15px;
|
||||
.tag{
|
||||
height: 44px;
|
||||
padding: 0 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.tag_delete{
|
||||
display: none;
|
||||
color: #4ea6ff;
|
||||
transform: rotate(45deg);
|
||||
font-size: 26px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.tag:hover .tag_delete {
|
||||
display: block;
|
||||
}
|
||||
.tag:hover {
|
||||
background-color: aliceblue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
height: 60px;
|
||||
text-align: right;
|
||||
padding: 13px 30px;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
327
src/components/project/AddOrgContent.vue
Normal file
327
src/components/project/AddOrgContent.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div class="twoDimensionalCode">
|
||||
<!--选择教师专长页面 -->
|
||||
<a-modal
|
||||
:visible="showContent"
|
||||
:footer="null"
|
||||
:closable="closableQR"
|
||||
wrapClassName="codeModal"
|
||||
style="margin-top: 400px"
|
||||
:zIndex="9999"
|
||||
@cancel="closeCodeModal"
|
||||
>
|
||||
<div class="QR">
|
||||
<div class="qr_header"></div>
|
||||
<div class="qr_main">
|
||||
<div class="qrm_header">
|
||||
<span style="title">{{Addtitle}}</span>
|
||||
<div class="close_exit" @click="closeCodeModal"></div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<a-tree checkable checkStrictly :tree-data="treeData" :loading="orgLoading"
|
||||
:load-data="onLoadData" v-model:expandedKeys="expandedKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
v-model:checkedKeys="checkedKeys" :fieldNames="{
|
||||
children: 'treeChildList',
|
||||
key: 'id',
|
||||
title: 'name',
|
||||
value: 'name',
|
||||
}" @check="onCheck">
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="headers">
|
||||
<div>已选择标签<span style="color: #4ea6ff;margin-left:5px;">{{treeAddData?.length}}</span>个</div>
|
||||
<div class="header_right" @click="clearTree">清空</div>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<div
|
||||
class="tag"
|
||||
v-for="(item, index) in treeAddData"
|
||||
:key="index"
|
||||
>
|
||||
<div class="tag_text" :title="`${item?.orgName} - (原:${item?.affiliationName || '-'})`">{{ item?.orgName }} - (原:{{ item?.affiliationName || '-' }})</div>
|
||||
<div @click="deleteTree(item)" class="tag_delete">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<a-button style="margin-right: 20px;" @click="closeCodeModal">取消</a-button>
|
||||
<a-button type="primary" @click="queryCreate">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, toRefs, watch,ref,computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { useStore } from "vuex";
|
||||
import { ORG_CHILD_LIST, ORG_LIST} from "@/api/apis";
|
||||
import { defineProps,defineEmits } from "vue";
|
||||
import { request, useRequest} from "@/api/request";
|
||||
import * as lecturerApi from "@/api/Lecturer.js";
|
||||
const props = defineProps({
|
||||
showContent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
Addtitle:{
|
||||
type:String,
|
||||
default: true,
|
||||
},
|
||||
AddContentList:{
|
||||
type:Array,
|
||||
default: ()=>[],
|
||||
}
|
||||
})
|
||||
const emit = defineEmits({})
|
||||
const treeAddData = ref([])
|
||||
const { data: treeData, loading: orgLoading } = useRequest(
|
||||
ORG_LIST,
|
||||
{ keyword: "" },
|
||||
);
|
||||
function onLoadData(treeNode) {
|
||||
return request(ORG_CHILD_LIST, { keyword: "", orgId: treeNode.id }).then(
|
||||
(r) => {
|
||||
//等待接口联调
|
||||
r?.data?.map(item=>{
|
||||
notLists?.value?.some(i=>{
|
||||
if(i.orgId == item.id){
|
||||
item.disabled = true
|
||||
item.name = item.name + '(' + i.orgName + ')'
|
||||
return true
|
||||
}
|
||||
})
|
||||
return item
|
||||
})
|
||||
treeNode.dataRef.treeChildList = r.data;
|
||||
treeData.value = [...treeData.value];
|
||||
}
|
||||
);
|
||||
}
|
||||
watch(()=>props.showContent, (val) => {
|
||||
if(!val){
|
||||
expandedKeys.value = []
|
||||
selectedKeys.value = []
|
||||
checkedKeys.value = []
|
||||
}else{
|
||||
console.log(props.AddContentList,'xixiixix')
|
||||
getNot()
|
||||
treeAddData.value = props?.AddContentList
|
||||
orgLists.value = props?.AddContentList
|
||||
checkedKeys.value = props?.AddContentList?.map(item=>item.orgId)
|
||||
}
|
||||
});
|
||||
const notLists = ref([])
|
||||
const getNot = () => {
|
||||
lecturerApi.getUnSelectOrg().then(res=>{
|
||||
if(res.data.code == 200){
|
||||
notLists.value = res.data.data
|
||||
}
|
||||
if(treeData.value.length){
|
||||
treeData.value.map(item=>{
|
||||
item.name = item.name?.split('(')[0]
|
||||
notLists.value.some(i=>{
|
||||
if(i.orgId == item.id){
|
||||
item.disabled = true
|
||||
item.name = item.name + '(' + i.orgName + ')'
|
||||
return true
|
||||
}
|
||||
})
|
||||
return item
|
||||
})
|
||||
}
|
||||
}).catch(err=>{
|
||||
message.error(err.data.msg)
|
||||
})
|
||||
}
|
||||
const orgLists = ref([])
|
||||
const onCheck = async (checkedKeys, {checked: bool, checkedNodes, node, event}) => {
|
||||
// "965356037047586816"
|
||||
let length = treeAddData.value.length
|
||||
if(checkedNodes.length > length){
|
||||
await lecturerApi.getSelectOrg(node.id).then(res=>{
|
||||
const targetNode = checkedNodes.find(item=>item.id == res?.data?.data[0]?.orgId)
|
||||
if(targetNode){
|
||||
orgLists.value.push(Object.assign(targetNode,res?.data?.data[0]));
|
||||
}
|
||||
}).catch(err=>{
|
||||
message.error('获取被占用组织失败,请重新尝试')
|
||||
})
|
||||
}
|
||||
treeAddData.value = checkedNodes.map(item => {
|
||||
if (!item || !item.id) {
|
||||
return item;
|
||||
}
|
||||
try {
|
||||
const orgItem = orgLists.value?.find(i => i && i.orgId == item.id);
|
||||
if (orgItem) {
|
||||
item.isSelect = orgItem.isSelect;
|
||||
item.orgName = orgItem.orgName;
|
||||
item.leaders = orgItem.leaders;
|
||||
item.affiliationName = orgItem.affiliationName
|
||||
}
|
||||
return {
|
||||
orgId: item.id,
|
||||
orgName: item.name,
|
||||
affiliationId: item.id,
|
||||
...item
|
||||
};
|
||||
} catch (err) {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
// treeAddData.value = checkedNodes;
|
||||
console.log(treeAddData.value,'checkedNodes',orgLists.value)
|
||||
}
|
||||
const clearTree = () => {
|
||||
treeAddData.value = [];
|
||||
checkedKeys.value = [];
|
||||
orgLists.value = [];
|
||||
}
|
||||
const deleteTree = (item) => {
|
||||
treeAddData.value = treeAddData.value.filter(node => node.orgId !== item.orgId);
|
||||
checkedKeys.value = treeAddData.value.map(item=>item.orgId)
|
||||
}
|
||||
const closeCodeModal = () => {
|
||||
emit("update:showContent", false);
|
||||
clearTree()
|
||||
};
|
||||
const queryCreate = () => {
|
||||
emit("update:AddContentList", treeAddData.value);
|
||||
closeCodeModal()
|
||||
}
|
||||
const expandedKeys = ref([]);
|
||||
const selectedKeys = ref([]);
|
||||
const checkedKeys = ref([]);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.twoDimensionalCode {
|
||||
}
|
||||
.codeModal {
|
||||
.ant-modal {
|
||||
.ant-modal-content {
|
||||
width: 479px !important;
|
||||
.ant-modal-body {
|
||||
.QR {
|
||||
z-index: 9999;
|
||||
width: 700px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.21);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 10%;
|
||||
transform: translate(-50%, -50%);
|
||||
.qr_header {
|
||||
position: absolute;
|
||||
width: calc(100%);
|
||||
height: 40px;
|
||||
// background: linear-gradient(
|
||||
// rgba(78, 166, 255, 0.2) 0%,
|
||||
// rgba(78, 166, 255, 0) 100%
|
||||
// );
|
||||
}
|
||||
.qr_main {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.qrm_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding-left: 26px;
|
||||
font-size: 16px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 22px;
|
||||
}
|
||||
.close_exit {
|
||||
position: absolute;
|
||||
right: 42px;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(@/assets/images/coursewareManage/close.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.line{
|
||||
height: 1px;
|
||||
margin-top: 16px;
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
.content{
|
||||
display: flex;
|
||||
min-height: 500px;
|
||||
.left{
|
||||
width: 50%;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
padding: 30px 15px;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.right{
|
||||
width: 50%;
|
||||
// max-height: 600px;
|
||||
// overflow-y: auto;
|
||||
.headers{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 30px 15px;
|
||||
.header_right{
|
||||
color: #666666;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.tags{
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
padding: 0 15px;
|
||||
.tag{
|
||||
height: 44px;
|
||||
padding: 0 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.tag_text{
|
||||
max-width: 240px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.tag_delete{
|
||||
display: none;
|
||||
color: #4ea6ff;
|
||||
transform: rotate(45deg);
|
||||
font-size: 26px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.tag:hover .tag_delete {
|
||||
display: block;
|
||||
}
|
||||
.tag:hover {
|
||||
background-color: aliceblue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
height: 60px;
|
||||
text-align: right;
|
||||
padding: 13px 30px;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
370
src/components/project/BatchLecturer.vue
Normal file
370
src/components/project/BatchLecturer.vue
Normal file
@@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<a-drawer
|
||||
:visible="visible"
|
||||
:closable="false"
|
||||
class="RouterFaceStus"
|
||||
placement="right"
|
||||
width="70%"
|
||||
>
|
||||
<div class="drawerMains">
|
||||
<div class="headers" style="margin-top:-24px;">
|
||||
<div class="headerTitle">{{ name }}</div>
|
||||
<img
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="@/assets/images/basicinfo/close.png"
|
||||
@click="closeDrawer"
|
||||
/>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="box">
|
||||
<div style="margin-bottom: 20px;font-size: 18px;font-weight: 700;">选择讲师费汇总:<span style="color:red;margin-left:20px;">{{payableExpense.toFixed(2)||0}}元</span></div>
|
||||
<div class="table" style="padding-bottom:72px;">
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
|
||||
>
|
||||
<template #action="{ record }">
|
||||
<div class="action">
|
||||
<div style="color: #1890ff;cursor: pointer;" class="btn" v-if="selectedRowKeys.includes(record.id)" @click="removeList(record)">取消选择</div>
|
||||
<div style="color: #1890ff;cursor: pointer;" class="btn" v-else @click="addList(record)">选择</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn">
|
||||
<button class="btn1" @click="closeDrawer">取消</button>
|
||||
<button class="btn2" @click="queryDrawer">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
<script setup lang="jsx">
|
||||
import {computed, defineEmits,defineProps, ref, watch} from "vue";
|
||||
import * as api from '@/api/Lecturer'
|
||||
import { message } from "ant-design-vue";
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
name:{
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
watch(()=>props.visible,(val)=>{
|
||||
if(val){
|
||||
loading.value = true
|
||||
api.getListByStatus().then(res=>{
|
||||
if(res.data.code == 200 ){
|
||||
tableData.value = res.data.data
|
||||
}else{
|
||||
message.error(res.data.msg)
|
||||
}
|
||||
loading.value = false
|
||||
}).catch(err=>{
|
||||
message.error(err.data.msg)
|
||||
loading.value = false
|
||||
})
|
||||
}else{
|
||||
selectedRowKeys.value = []
|
||||
selectsData.value = []
|
||||
}
|
||||
})
|
||||
const loading = ref(false)
|
||||
const selectedRowKeys = ref([])
|
||||
const selectsData = ref([]);
|
||||
const onSelectChange = (e, l) => {
|
||||
selectedRowKeys.value = e
|
||||
selectsData.value = l
|
||||
}
|
||||
const emit = defineEmits(['selectedRowKeys','update:visible'])
|
||||
const addList = (item) => {
|
||||
selectedRowKeys.value.push(item.id)
|
||||
selectsData.value.push(item)
|
||||
}
|
||||
const payableExpense = ref(0)
|
||||
watch(()=>selectsData.value.length,(val)=>{
|
||||
if(val){
|
||||
payableExpense.value = selectsData.value.reduce((a,b)=>{
|
||||
return Number(a) + Number(b.payableExpense)
|
||||
},0)
|
||||
}else{
|
||||
payableExpense.value = 0
|
||||
}
|
||||
})
|
||||
const removeList = (item) => {
|
||||
selectedRowKeys.value = selectedRowKeys.value.filter(t=> t != item.id)
|
||||
selectsData.value = selectsData.value.filter(t=>t.id != item.id)
|
||||
}
|
||||
const columns = [
|
||||
{
|
||||
title: '讲师名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '讲师工号',
|
||||
dataIndex: 'userNo',
|
||||
key: 'userNo',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '所属组织',
|
||||
dataIndex: 'orgName',
|
||||
key: 'orgName',
|
||||
align: 'center',
|
||||
ellipsis: true,
|
||||
customCell :() => {return {style: {maxWidth: '200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis',cursor:'pointer'}}},
|
||||
},
|
||||
|
||||
{
|
||||
title: '讲师体系',
|
||||
dataIndex: 'tsystemName',
|
||||
key: 'tsystemName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '讲师等级',
|
||||
dataIndex: 'tlevelName',
|
||||
key: 'tlevelName',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '发薪地',
|
||||
dataIndex: 'payrollPlace',
|
||||
key: 'payrollPlace',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: '课程类型',
|
||||
dataIndex: 'courseType',
|
||||
key: 'courseType',
|
||||
align: 'center',
|
||||
customRender: ({ text,record })=>{
|
||||
switch (text) {
|
||||
case 0:
|
||||
return "在线课"
|
||||
case 1:
|
||||
return "面授课"
|
||||
case 2:
|
||||
return "课程开发"
|
||||
case 3:
|
||||
return "作业员入模培训"
|
||||
case 4:
|
||||
return "其他"
|
||||
default:
|
||||
return "-"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '课程名称',
|
||||
dataIndex: 'courseName',
|
||||
key: 'courseName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '授课/开发课程日期',
|
||||
dataIndex: 'teachingDate',
|
||||
key: 'teachingDate',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '授课/开发课程时长',
|
||||
dataIndex: 'teachingTime',
|
||||
key: 'teachingTime',
|
||||
align: 'center',
|
||||
customRender: ({ text,record })=>{
|
||||
return (text/60).toFixed(2)+'小时'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '参训人数',
|
||||
dataIndex: 'studys',
|
||||
key: 'studys',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'0'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '评分',
|
||||
dataIndex: 'score',
|
||||
key: 'score',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '课酬基准',
|
||||
dataIndex: 'levelPay',
|
||||
key: 'levelPay',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '计划费用',
|
||||
dataIndex: 'expense',
|
||||
key: 'expense',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '应发费用',
|
||||
dataIndex: 'payableExpense',
|
||||
key: 'payableExpense',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
slots: { customRender: "action" },
|
||||
},
|
||||
]
|
||||
const tableData = ref([])
|
||||
const closeDrawer = () => {
|
||||
emit("update:visible", false);
|
||||
selectedRowKeys.value = []
|
||||
selectsData.value = []
|
||||
}
|
||||
const queryDrawer = () => {
|
||||
if(!selectedRowKeys.value.length){
|
||||
message.error('请选择需要审批的数据')
|
||||
return
|
||||
}
|
||||
emit("selectedRowKeys", selectedRowKeys.value)
|
||||
// closeDrawer()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
.RouterFaceStus {
|
||||
.drawerMains {
|
||||
min-width: 600px;
|
||||
// margin: 0px 32px 0px 32px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.headers {
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
.content{
|
||||
margin: 0 20px;
|
||||
.head{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
.list{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #666;
|
||||
min-width: 260px;
|
||||
padding: 20px 10px;
|
||||
color: #ffffff;
|
||||
border-radius:6px;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
.left{
|
||||
width: 35%;
|
||||
text-align:right;
|
||||
margin-right:30px;
|
||||
.text{
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
.right{
|
||||
.text{
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.active{
|
||||
background-color: #f5f5f5;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
.box{
|
||||
.top{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
.item{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnn {
|
||||
height: 72px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.16);
|
||||
background-color: #fff;
|
||||
|
||||
.btn1 {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid #4ea6ff;
|
||||
border-radius: 8px;
|
||||
color: #4ea6ff;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn2 {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background: #4ea6ff;
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
margin-left: 15px;
|
||||
color: #fff;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
660
src/components/project/ConfirmLecturer.vue
Normal file
660
src/components/project/ConfirmLecturer.vue
Normal file
@@ -0,0 +1,660 @@
|
||||
<template>
|
||||
<a-drawer
|
||||
:visible="visible"
|
||||
:closable="false"
|
||||
class="RouterFaceStus"
|
||||
placement="right"
|
||||
width="64%"
|
||||
:zIndex="1001"
|
||||
>
|
||||
<div class="drawerMains">
|
||||
<div class="headers" style="margin-top:-24px;">
|
||||
<div class="headerTitle">{{ name }}</div>
|
||||
<img
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="@/assets/images/basicinfo/close.png"
|
||||
@click="closeDrawer"
|
||||
/>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="head">
|
||||
<div class="list" :class="index==indexList?'active':''" @click="clickItem(item,index)" v-for="(item,index) in forData">
|
||||
<div class="left">
|
||||
<div>培训发生组织</div>
|
||||
<div class="text">汇总金额</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="org" :title="item?.trainOrgName">{{item?.trainOrgName||'-'}}</div>
|
||||
<div class="text org" :title="item?.summaryTotal">{{item?.summaryTotal||'-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="top">
|
||||
<div class="item">
|
||||
<a-input @pressEnter="searchData(true)" style="border-radius: 8px;width:240px;height: 40px;" v-model:value="nameUserNo" placeholder="请输入工号/讲师名称进行搜索" allowClear />
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-range-picker format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" style="border-radius: 8px;width:360px;height: 40px;" v-model:value="dateValue" />
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-button type="primary" @click="searchData(true)" style="margin-right:20px;border-radius:8px;width: 100px;height: 40px;">搜索</a-button>
|
||||
<a-button type="primary" @click="resetData()" style="border-radius:8px;width: 100px;height: 40px;">重置</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table">
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="searchTrue?searchList:expenseList"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
:loading="loadingData"
|
||||
>
|
||||
<template #action="{ record,index }">
|
||||
<div class="action">
|
||||
<div @click="removeId(record,index)" class="btn" style="color: #40a9ff;cursor: pointer;">移除</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn">
|
||||
<button class="btn1" @click="config">确认提交审批</button>
|
||||
<button class="btn1" @click="qureyDrawer">确定</button>
|
||||
<button class="btn2" @click="closeDrawer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
<div>
|
||||
<a-modal
|
||||
:visible="modalVisible"
|
||||
:footer="null"
|
||||
:title="null"
|
||||
:centere="true"
|
||||
:closable="false"
|
||||
style="margin-top: 400px"
|
||||
:zIndex="1001"
|
||||
@cancel="close"
|
||||
>
|
||||
<div class="delete">
|
||||
<div class="del_header"></div>
|
||||
<div class="del_main">
|
||||
<div class="header">
|
||||
<div class="del-icons">
|
||||
<img src="@/assets/images/coursewareManage/QR.png" alt=""/>
|
||||
</div>
|
||||
<span>操作确认</span>
|
||||
<div class="close_exit" @click="close"></div>
|
||||
</div>
|
||||
<div class="title">本月可提交审批次数: <span style="color:#4ea6ff"> {{ numTime }} / 10 </span></div>
|
||||
<div class="body">
|
||||
<div>
|
||||
<span>请仔细核对讲师费信息,确认无误后,将自动进入(BPM系统)审批流程。</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="del_btnbox">
|
||||
<div class="del_btn btn2" @click="close">
|
||||
<div class="btnText">取消</div>
|
||||
</div>
|
||||
<div class="del_btn btn2" @click="handleConfirm">
|
||||
<div class="btnText">确定</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="jsx">
|
||||
import {computed, defineEmits,defineProps, ref, watch} from "vue";
|
||||
import {message} from "ant-design-vue";
|
||||
import * as api from '@/api/Lecturer'
|
||||
import dialog from "@/utils/dialog";
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
name:{
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
ids:{
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
const loadingData = ref(false)
|
||||
const modalVisible = ref(false)
|
||||
const numTime = ref(0)
|
||||
const close = () => {
|
||||
modalVisible.value = false;
|
||||
}
|
||||
const handleConfirm = () => {
|
||||
if(numTime.value >= 10){
|
||||
message.error('提交审批次数已达上限')
|
||||
return
|
||||
}
|
||||
numTime.value+=1
|
||||
localStorage.setItem('numTime',numTime.value)
|
||||
const ids = forData.value.flatMap(item => item.expenseList.map(item => item.id));
|
||||
if(!ids.length){
|
||||
return message.error('暂无可提交的数据')
|
||||
}
|
||||
api.teacherExpenseConfirm({ids:ids?.join(',')}).then(res=>{
|
||||
console.log(res,'resssss')
|
||||
api.submitApproval({ids:res.data?.data?.join(',')}).then(res=>{
|
||||
console.log(res,'resssss')
|
||||
message.success('提交成功')
|
||||
close()
|
||||
closeDrawer()
|
||||
emit('visibleFalse',false)
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
close()
|
||||
closeDrawer()
|
||||
emit('visibleFalse',false)
|
||||
})
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
close()
|
||||
closeDrawer()
|
||||
emit('visibleFalse',false)
|
||||
})
|
||||
}
|
||||
const forData = ref()
|
||||
const indexList = ref(0)
|
||||
const expenseList = ref([])
|
||||
const searchList = ref([])
|
||||
const clickItem = (item,i) => {
|
||||
expenseList.value = item.expenseList
|
||||
indexList.value = i
|
||||
resetData()
|
||||
}
|
||||
watch(()=>props.visible,(val)=>{
|
||||
if(val){
|
||||
loadingData.value = true
|
||||
numTime.value = Number(localStorage.getItem('numTime')||0)
|
||||
api.getListByAffiliation(
|
||||
{
|
||||
name: '',
|
||||
ids: props.ids,
|
||||
beginTime: '',
|
||||
endTime: '',
|
||||
}
|
||||
).then(res=>{
|
||||
if(res.data.code === 200){
|
||||
forData.value = res.data.data
|
||||
expenseList.value = res.data.data[indexList.value]?.expenseList || []
|
||||
}
|
||||
loadingData.value = false
|
||||
resetData()
|
||||
}).catch(()=>{
|
||||
message.error('获取数据失败,请重新尝试')
|
||||
loadingData.value = false
|
||||
})
|
||||
}else{
|
||||
nameUserNo.value = null
|
||||
dateValue.value = null
|
||||
}
|
||||
})
|
||||
const removeId = (e,i) =>{
|
||||
dialog({
|
||||
content: "是否确认移除",
|
||||
ok: () =>{
|
||||
forData.value?.forEach(item=>{
|
||||
item.expenseList?.some((i,l)=>{
|
||||
if(i.id == e.id){
|
||||
return item.expenseList.splice(l,1)
|
||||
}
|
||||
})
|
||||
})
|
||||
if(searchTrue.value){
|
||||
searchList.value = searchList.value.filter(item=>item.id !== e.id)
|
||||
expenseList.value = expenseList.value.filter(item=>item.id !== e.id)
|
||||
}else{
|
||||
expenseList.value = expenseList.value.filter(item=>item.id !== e.id)
|
||||
}
|
||||
forData.value[indexList.value].summaryTotal = forData.value[indexList.value]?.summaryTotal - e.payableExpense
|
||||
}
|
||||
})
|
||||
}
|
||||
const nameUserNo = ref(null)
|
||||
const dateValue = ref(null)
|
||||
const searchTrue = ref(false)
|
||||
const searchData = (val) => {
|
||||
searchTrue.value = val
|
||||
if(!nameUserNo.value&&!dateValue.value){
|
||||
searchList.value = expenseList.value;
|
||||
return
|
||||
}
|
||||
//搜索 数组expenseList.value 参数名字或者工号:nameUserNo.value 日期:dateValue.value
|
||||
const filteredList = expenseList.value.filter(item => {
|
||||
const isNameMatch = (item.name + item.userNo).includes(nameUserNo.value);
|
||||
const teachingDateTimestamp = new Date(item.teachingDate).getTime();
|
||||
if(dateValue.value==null){
|
||||
return isNameMatch
|
||||
}
|
||||
const startDateTimestamp = new Date(dateValue.value[0]).getTime();
|
||||
const endDateTimestamp = new Date(dateValue.value[1]).getTime();
|
||||
const isDateInRange = teachingDateTimestamp >= startDateTimestamp && teachingDateTimestamp <= endDateTimestamp;
|
||||
if(nameUserNo.value&&startDateTimestamp&&endDateTimestamp){
|
||||
return isNameMatch && isDateInRange;
|
||||
}
|
||||
return isNameMatch || isDateInRange;
|
||||
});
|
||||
searchList.value = filteredList;
|
||||
}
|
||||
const resetData = () => {
|
||||
nameUserNo.value = null
|
||||
dateValue.value = null
|
||||
searchData(false)
|
||||
}
|
||||
const emit = defineEmits(['update:visible'])
|
||||
const columns = [
|
||||
{
|
||||
title: '讲师名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '讲师工号',
|
||||
dataIndex: 'userNo',
|
||||
key: 'userNo',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '所属组织',
|
||||
dataIndex: 'orgName',
|
||||
key: 'orgName',
|
||||
align: 'center',
|
||||
ellipsis: true,
|
||||
customCell :() => {return {style: {maxWidth: '200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis',cursor:'pointer'}}},
|
||||
},
|
||||
|
||||
{
|
||||
title: '讲师体系',
|
||||
dataIndex: 'tsystemName',
|
||||
key: 'tsystemName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '讲师等级',
|
||||
dataIndex: 'tlevelName',
|
||||
key: 'tlevelName',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '发薪地',
|
||||
dataIndex: 'payrollPlace',
|
||||
key: 'payrollPlace',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: '课程类型',
|
||||
dataIndex: 'courseType',
|
||||
key: 'courseType',
|
||||
align: 'center',
|
||||
customRender: ({ text,record })=>{
|
||||
switch (text) {
|
||||
case 0:
|
||||
return "在线课"
|
||||
case 1:
|
||||
return "面授课"
|
||||
case 2:
|
||||
return "课程开发"
|
||||
case 3:
|
||||
return "作业员入模培训"
|
||||
case 4:
|
||||
return "其他"
|
||||
default:
|
||||
return "-"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '课程名称',
|
||||
dataIndex: 'courseName',
|
||||
key: 'courseName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '授课/开发课程日期',
|
||||
dataIndex: 'teachingDate',
|
||||
key: 'teachingDate',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '授课/开发课程时长',
|
||||
dataIndex: 'teachingTime',
|
||||
key: 'teachingTime',
|
||||
align: 'center',
|
||||
customRender: ({ text,record })=>{
|
||||
return (text/60).toFixed(2)+'小时'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '参训人数',
|
||||
dataIndex: 'studys',
|
||||
key: 'studys',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'0'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '评分',
|
||||
dataIndex: 'score',
|
||||
key: 'score',
|
||||
align: 'center',
|
||||
customRender: ({ text })=>{
|
||||
return text||'-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '课酬基准',
|
||||
dataIndex: 'levelPay',
|
||||
key: 'levelPay',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '计划费用',
|
||||
dataIndex: 'expense',
|
||||
key: 'expense',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '应发费用',
|
||||
dataIndex: 'payableExpense',
|
||||
key: 'payableExpense',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
slots: { customRender: "action" },
|
||||
},
|
||||
]
|
||||
const closeDrawer = () => emit("update:visible", false);
|
||||
const qureyDrawer = () => {
|
||||
const ids = forData.value.flatMap(item => item.expenseList.map(item => item.id));
|
||||
if(!ids.length){
|
||||
return message.error('暂无可提交的数据')
|
||||
}
|
||||
dialog({
|
||||
content: '是否确认讲师费信息无误?提交后按“培训发生组织”汇总至审批中心,等待验证后“提交”进入审批流程。',
|
||||
ok: () => {
|
||||
api.teacherExpenseConfirm({ids:ids?.join(',')}).then(res=>{
|
||||
console.log(res,'resssss')
|
||||
message.success('提交成功')
|
||||
closeDrawer()
|
||||
emit('visibleFalse',false)
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
closeDrawer()
|
||||
emit('visibleFalse',false)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const config = () => {
|
||||
if(!expenseList.value.length){
|
||||
message.error('暂无可提交的数据')
|
||||
return
|
||||
}
|
||||
modalVisible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.delete {
|
||||
min-width: 424px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.21);
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 10%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.del_header {
|
||||
position: absolute;
|
||||
width: calc(100%);
|
||||
height: 40px;
|
||||
background: linear-gradient(
|
||||
rgba(78, 166, 255, 0.2) 0%,
|
||||
rgba(78, 166, 255, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.del_main {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding-left: 26px;
|
||||
font-size: 16px;
|
||||
|
||||
.del-icons {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.close_exit {
|
||||
position: absolute;
|
||||
right: 42px;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(@/assets/images/coursewareManage/close.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
}
|
||||
.title{
|
||||
padding: 0 30px;
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.body {
|
||||
width: 100%;
|
||||
padding: 0 30px;
|
||||
margin: 34px auto 56px auto;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.del_btnbox {
|
||||
display: flex;
|
||||
margin: 30px auto;
|
||||
justify-content: center;
|
||||
|
||||
.del_btn {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background: rgba(64, 158, 255, 0);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 14px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.btnText {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.btn1 {
|
||||
border: 1px solid rgba(64, 158, 255, 1);
|
||||
color: #4ea6ff;
|
||||
}
|
||||
|
||||
.btn2 {
|
||||
background-color: #4ea6ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.RouterFaceStus {
|
||||
.drawerMains {
|
||||
min-width: 600px;
|
||||
// margin: 0px 32px 0px 32px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.headers {
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
.content{
|
||||
margin: 0 20px;
|
||||
.head{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
.list{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f5f5f5;
|
||||
min-width: 260px;
|
||||
padding: 20px 10px;
|
||||
color: #ffffff;
|
||||
border-radius:6px;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
.left{
|
||||
width: 35%;
|
||||
min-width: 86px;
|
||||
text-align:right;
|
||||
margin-right:30px;
|
||||
color: rgba(116, 120, 141, 0.603921568627451);
|
||||
.text{
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
.right{
|
||||
color: #646C9A;
|
||||
.org{
|
||||
max-width: 148px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.text{
|
||||
margin-top:20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.active{
|
||||
background-color: #4ea6ff;
|
||||
.left{
|
||||
color: #ffffff;
|
||||
}
|
||||
.right{
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.box{
|
||||
padding-bottom: 80px;
|
||||
.top{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
.item{
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnn {
|
||||
height: 72px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.16);
|
||||
background-color: #fff;
|
||||
z-index: 9;
|
||||
.btn2 {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid #4ea6ff;
|
||||
border-radius: 8px;
|
||||
color: #4ea6ff;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.btn1 {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background: #4ea6ff;
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
margin-right: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
114
src/components/project/Editor.vue
Normal file
114
src/components/project/Editor.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<!--
|
||||
* @Author: wangzhiyu <w19165802736@163.com>
|
||||
* @version: 1.0.0
|
||||
* @Date: 2024-04-7 11:04:25
|
||||
* @LastEditTime: 2024-04-08 21:44:20
|
||||
* @Descripttion: 富文本编辑器组件
|
||||
-->
|
||||
<template>
|
||||
<div style="border: 1px solid #ccc; width: 100%;position:relative; ">
|
||||
<Toolbar style="border-bottom: 1px solid #ccc ;font-size:4px" :editor="editorRef" :defaultConfig="toolbarConfig" mode="simple" />
|
||||
<Editor style="height: 100px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" mode="simple" @onCreated="handleCreated" @onChange="handleChange" @customPaste="customPaste" />
|
||||
<span style="position:absolute;right:6px;bottom:4px;">{{ valueLength }}/200</span>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
// 富文本编辑器文档链接: https://www.wangeditor.com/v5/getting-started.html
|
||||
// 引入富文本编辑器CSS
|
||||
import '@wangeditor/editor/dist/css/style.css';
|
||||
import { onBeforeUnmount, ref, shallowRef,watch,defineProps, defineEmits } from 'vue';
|
||||
// 导入富文本编辑器的组件
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: ()=>'',
|
||||
},
|
||||
});
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef();
|
||||
const emit = defineEmits(['update:value'])
|
||||
// 内容 HTML
|
||||
const valueHtml = ref('');
|
||||
watch(()=>valueHtml.value,(val)=>{
|
||||
emit('update:value',val)
|
||||
|
||||
})
|
||||
watch(()=>props.value,(val)=>{
|
||||
valueHtml.value = val
|
||||
})
|
||||
const toolbarConfig = {
|
||||
excludeKeys: [
|
||||
'insertLink', // 排除菜单组,写菜单组 key 的值即可
|
||||
"group-image",
|
||||
"todo",
|
||||
"insertVideo",
|
||||
"insertTable"
|
||||
]
|
||||
|
||||
};
|
||||
const editorConfig = ref({ placeholder: '请输入内容...', MENU_CONF: {} });
|
||||
|
||||
// 自定义图片上传
|
||||
editorConfig.value.MENU_CONF['uploadImage'] = {
|
||||
async customUpload(file, insertFn) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
fileUp(formData).then((res) => {
|
||||
if (res.data.code === 200) {
|
||||
// 最后插入图片 url alt href
|
||||
console.log(
|
||||
"上传图片结果",
|
||||
process.env.VUE_APP_FILE_PATH + res.data.data
|
||||
);
|
||||
insertFn(
|
||||
process.env.VUE_APP_FILE_PATH + res.data.data,
|
||||
file.name,
|
||||
res.data.data
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// 自定义视频上传
|
||||
editorConfig.value.MENU_CONF['uploadVideo'] = {
|
||||
async customUpload(file, insertFn) {
|
||||
console.log('上传视频', file);
|
||||
},
|
||||
};
|
||||
const valueLength = ref(0)
|
||||
const handleChange = (editor) => {
|
||||
const reg = /<[^<>]+>/g;
|
||||
const value = valueHtml.value.replace(reg, "");
|
||||
valueLength.value = value.length
|
||||
if (valueLength.value > 200) {
|
||||
valueHtml.value = '<p>' + value.slice(0, 200) + '</p>'
|
||||
editor.setHtml(valueHtml.value);
|
||||
}
|
||||
};
|
||||
// 富文本编辑器生成后触发
|
||||
const handleCreated = editor => {
|
||||
editorRef.value = editor; // 记录 editor 实例,重要!
|
||||
console.log(editorConfig.value.MENU_CONF, 'editorConfig.value');
|
||||
};
|
||||
|
||||
// 监听富文本编辑器粘贴行为
|
||||
const customPaste = (editor, event, callback) => {
|
||||
// 获取粘贴的纯文本
|
||||
const text = event.clipboardData.getData('text/plain');
|
||||
if (text) {
|
||||
editor.insertText(text);
|
||||
event.preventDefault();
|
||||
callback(false);
|
||||
}
|
||||
};
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
125
src/components/project/ImageUpload.vue
Normal file
125
src/components/project/ImageUpload.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div>
|
||||
<input type="file" @change="handleFileUpload" />
|
||||
<img :src="avatarUrl" alt="Avatar" v-if="avatarUrl" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
avatarUrl: '' // 存储头像的 URL(Base64 编码或服务器 URL)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleFileUpload(event) {
|
||||
const file = event.target.files[0]; // 获取用户选择的文件
|
||||
if (!file) return;
|
||||
|
||||
// 创建一个 FileReader 实例
|
||||
const reader = new FileReader();
|
||||
|
||||
// 读取文件内容,并在读取完成后设置 img 的 src
|
||||
reader.onload = (e) => {
|
||||
this.avatarUrl = e.target.result; // e.target.result 是 Base64 编码的字符串
|
||||
};
|
||||
|
||||
// 读取文件内容(作为 DataURL)
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
// 如果你需要上传文件到服务器,可以在这里添加代码
|
||||
// 例如,使用 Axios 发送 POST 请求到服务器
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<!-- <template>
|
||||
<a-upload
|
||||
:file-list="files"
|
||||
:action="FILE_UPLOAD_URL"
|
||||
:show-upload-list="showUploadList"
|
||||
:multiple="multiple"
|
||||
:before-upload="beforeUpload"
|
||||
:headers="headers"
|
||||
@change="handleChange"
|
||||
ref="imageRef"
|
||||
>
|
||||
<template v-for="(_, key, index) in $slots" :key="index" v-slot:[key]>
|
||||
<slot :name="key"></slot>
|
||||
</template>
|
||||
</a-upload>
|
||||
</template>
|
||||
<script setup>
|
||||
import {defineProps, defineEmits, defineExpose, ref, watch} from "vue";
|
||||
import {message} from "ant-design-vue";
|
||||
import {FILE_UPLOAD_URL} from "@/api/config";
|
||||
import {getCookieForName} from "@/api/method";
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: fals
|
||||
},
|
||||
showUploadList: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileType: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits({})
|
||||
|
||||
const files = ref([])
|
||||
const imageRef = ref()
|
||||
const headers = { token: getCookieForName("token") };
|
||||
watch(props, () => {
|
||||
props.value.length !== files.value.length && (files.value = props.value)
|
||||
})
|
||||
|
||||
function handleChange({file, fileList}) {
|
||||
file.response && file.response.code === 200 && (file.url = file.response.data)
|
||||
files.value = fileList
|
||||
emit('update:value', fileList)
|
||||
}
|
||||
|
||||
function beforeUpload(file) {
|
||||
if (!props.fileType.includes(file.name.split(".").slice(-1).join(''))) {
|
||||
message.error(
|
||||
"不支持该格式"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function remove(i) {
|
||||
files.value.splice(i, 1)
|
||||
emit('update:value', files.value)
|
||||
}
|
||||
|
||||
function reUpload(i) {
|
||||
if (files.value[i].status === 'ready' || files.value[i].status === 'uploading') {
|
||||
imageRef.value.abort(files.value[i].raw)
|
||||
files.value[i].status = 'abort';
|
||||
} else if (files.value[i].status === 'fail' || files.value[i].status === 'abort') {
|
||||
imageRef.value.handleStart(files.value[i].raw)
|
||||
imageRef.value.submit()
|
||||
}
|
||||
}
|
||||
|
||||
function abort(i) {
|
||||
imageRef.value.abort(files.value[i].raw)
|
||||
}
|
||||
|
||||
|
||||
defineExpose({reUpload, remove, abort})
|
||||
|
||||
</script> -->
|
||||
|
||||
637
src/components/project/ImportWork.vue
Normal file
637
src/components/project/ImportWork.vue
Normal file
@@ -0,0 +1,637 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-modal
|
||||
:visible="showWork"
|
||||
:footer="null"
|
||||
:closable="closableQR"
|
||||
wrapClassName="codeModal"
|
||||
style="margin-top: 400px"
|
||||
:zIndex="9"
|
||||
@cancel="qr_exit"
|
||||
>
|
||||
<div class="QR">
|
||||
<div class="qr_header"></div>
|
||||
<div class="qr_main">
|
||||
<div class="qrm_header">
|
||||
<span style="title">{{ title }}</span>
|
||||
<div class="close_exit" @click="closeCodeModal"></div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="contents">
|
||||
<div class="drawerMain">
|
||||
<div class="main">
|
||||
<div class="minatitl">
|
||||
<div class="up1">请下载</div>
|
||||
<div class="up2" @click="downTemplate" style="cursor: pointer">
|
||||
模板
|
||||
</div>
|
||||
<div class="up1">,按要求填写数据并导入</div>
|
||||
</div>
|
||||
<div class="upload">
|
||||
<div class="text">上传:</div>
|
||||
<div class="right">
|
||||
<div style="height: 176px; margin-bottom: 20px">
|
||||
<a-upload-dragger v-model:fileList="fileList" :action="importHomeWork" :name="fileName" :multiple="true"
|
||||
:headers="headers"
|
||||
@change="handleChange" :showUploadList="false">
|
||||
<p class="ant-upload-drag-icon">
|
||||
<inbox-outlined></inbox-outlined>
|
||||
</p>
|
||||
<p class="ant-upload-text">点击或将文件拖拽到此处上传</p>
|
||||
<p class="ant-upload-hint">支持扩展名:.xls/.xlsx</p>
|
||||
</a-upload-dragger>
|
||||
</div>
|
||||
<div class="loadstate">
|
||||
<div class="loadborder" v-if="uploadpercent < 100 && uploadpercent !== -1">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="stateloading">正在上传</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
<div class="curloading">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loadborder" v-if="uploadErr">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="statedefeat">上传失败</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
|
||||
<div class="curloading">
|
||||
<div style="color: #387df7; margin-left: 20px; cursor: pointer">
|
||||
下载失败数据
|
||||
</div>
|
||||
</div>
|
||||
<div class="defeat" style="display: flex; align-items: center">
|
||||
<div style="color: #ff7474">
|
||||
{{ succNum }}条数据导入成功,{{ errNum }}条数据导入失败
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loadborder" v-if="uploadpercent === 100">
|
||||
<div class="content">
|
||||
<div class="img"></div>
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ fileName }}</div>
|
||||
<div class="statesucce">上传成功</div>
|
||||
</div>
|
||||
<a-progress :percent="uploadpercent" />
|
||||
</div>
|
||||
<div class="curloading">
|
||||
<div class="cancel" style="margin-left: 20px; cursor: pointer" @click="removeUpload">
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="errNum">
|
||||
<div class="downloadErr" @click="downloadEeeorData">
|
||||
下载失败数据
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="uploadpercent === 100" class="defeat" style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 500px;
|
||||
height: 40px;" :style="{
|
||||
background: errNum
|
||||
? 'rgba(255, 116, 116, 0.1)'
|
||||
: 'rgba(53, 174, 105, 0.1)',
|
||||
border: errNum ? '1px solid #ff7474' : '1px solid #35AE69',
|
||||
}">
|
||||
<img style="width: 14px; height: 14px; margin-left: 16px" :src="
|
||||
errNum
|
||||
? require('../../assets/images/err.png')
|
||||
: require('../../assets/images/success.png')
|
||||
" />
|
||||
<div style="margin-left: 8px" :style="{ color: errNum ? '#ff7474' : 'rgba(0,0,0,0.65)' }">
|
||||
{{ succNum }}条数据导入成功,{{ errNum }}条数据导入失败
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn">
|
||||
<button class="btn1" @click="closeCodeModal">取消</button>
|
||||
<button class="btn2" @click="closeCodeModal">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watch,ref,computed } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { useStore } from "vuex";
|
||||
import * as api from "../../api/index1";
|
||||
import {getCookieForName} from "@/api/method";
|
||||
export default {
|
||||
name: "importWork",
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
showWork: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
title:{
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
fileName:{
|
||||
type: String,
|
||||
default: 'file',
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const state = reactive({
|
||||
fileType: ["xls", "xlsx"],
|
||||
importHomeWork:
|
||||
process.env.VUE_APP_BASE_API + props.url,
|
||||
uploadpercent: -1,
|
||||
uploadErr: false, //上传失败
|
||||
addLoading: false,
|
||||
fileList: [],
|
||||
succNum: 0, //成功数据数
|
||||
errNum: 0, //失败数据数
|
||||
downloadErrUrl: null, //下载失败数据
|
||||
fileName: "",
|
||||
});
|
||||
const headers = { token: getCookieForName("token") };
|
||||
|
||||
const closeCodeModal = () => {
|
||||
ctx.emit("update:showWork", false);
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
state.uploadErr = false; //上传失败
|
||||
};
|
||||
|
||||
//上传文件
|
||||
const handleChange = (info) => {
|
||||
if (info) {
|
||||
var FileExt = info.file.name.replace(/.+\./, "");
|
||||
if (["xls", "xlsx"].indexOf(FileExt.toLowerCase()) === -1) {
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
message.destroy();
|
||||
message.error("请上传正确的文件格式");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
state.addLoading = true;
|
||||
state.uploadpercent = parseInt(info.file.percent);
|
||||
console.log("我是文件上传的进度---------->", info.file.percent);
|
||||
const status = info.file.status;
|
||||
console.log(info.file,'status')
|
||||
if (status !== "uploading") {
|
||||
// console.log(info.file, info.fileList);
|
||||
}
|
||||
if (status === "done") {
|
||||
state.fileName = info.file.name;
|
||||
if(!info.file.response.data){
|
||||
message.error(`${info.file.name}上传失败`);
|
||||
}
|
||||
let i = 0;
|
||||
let timeouts = setTimeout(() => {
|
||||
// clearInterval(timer)
|
||||
state.addLoading = false;
|
||||
message.destroy();
|
||||
message.error(`文件导入超时`);
|
||||
}, 30000);
|
||||
// let timer = setInterval(() => {
|
||||
// let uid = info.file.response.data;
|
||||
// api
|
||||
// .getImportStatus(uid)
|
||||
// .then((res) => {
|
||||
// console.log("查询导入状态", res);
|
||||
// if (res.data.code === 200) {
|
||||
// if (res.data.data.status !== "START") {
|
||||
// i++;
|
||||
// if (i === 1) {
|
||||
// message.destroy();
|
||||
// message.success(`${info.file.name}上传成功`);
|
||||
// state.addLoading = false;
|
||||
// props.searchTaskList && props.searchTaskList();
|
||||
// }
|
||||
// state.succNum = res.data.data.successNum;
|
||||
// state.errNum = res.data.data.failedNum;
|
||||
// state.downloadErrUrl = res.data.data.url;
|
||||
// console.log("props.getStudent", props.getStudent);
|
||||
// clearInterval(timer);
|
||||
// clearTimeout(timeouts);
|
||||
// }
|
||||
// } else {
|
||||
// state.addLoading = false;
|
||||
// message.destroy();
|
||||
// clearTimeout(timeouts);
|
||||
// }
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// state.addLoading = false;
|
||||
// clearInterval(timer);
|
||||
// clearTimeout(timeouts);
|
||||
// console.log("查询导入状态失败", err);
|
||||
// });
|
||||
// }, 500);
|
||||
} else if (status === "error") {
|
||||
state.uploadErr = true;
|
||||
message.error(`${info.file.name}上传失败`);
|
||||
}
|
||||
};
|
||||
//删除
|
||||
const removeUpload = () => {
|
||||
state.fileList = [];
|
||||
state.uploadpercent = -1;
|
||||
state.uploadErr = false; //上传失败
|
||||
state.succNum = 0;
|
||||
state.errNum = 0;
|
||||
state.downloadErrUrl = null;
|
||||
state.addLoading = false;
|
||||
};
|
||||
// 下载失败数据
|
||||
const downloadEeeorData = () => {
|
||||
if (state.downloadErrUrl !== "") {
|
||||
window.open(process.env.VUE_APP_FILE_PATH + state.downloadErrUrl);
|
||||
}
|
||||
};
|
||||
function downTemplate() {
|
||||
window.open(`${process.env.VUE_APP_BASE_API}/admin/student/exportHomeWorkTemplate?taskId=${props.id || ''}&type=${props.type || ''}&pid=${props.pid || ''}&thirdType=3`);
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
closeCodeModal,
|
||||
handleChange,
|
||||
downTemplate,
|
||||
headers,
|
||||
removeUpload,
|
||||
downloadEeeorData,
|
||||
};
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.codeModal {
|
||||
.ant-modal {
|
||||
.ant-modal-content {
|
||||
width: 479px !important;
|
||||
.ant-modal-body {
|
||||
.QR {
|
||||
z-index: 11;
|
||||
width: 700px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.21);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 10%;
|
||||
transform: translate(-50%, -50%);
|
||||
.qr_header {
|
||||
position: absolute;
|
||||
width: calc(100%);
|
||||
height: 40px;
|
||||
// background: linear-gradient(
|
||||
// rgba(78, 166, 255, 0.2) 0%,
|
||||
// rgba(78, 166, 255, 0) 100%
|
||||
// );
|
||||
}
|
||||
.qr_main {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.qrm_header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding-left: 26px;
|
||||
font-size: 16px;
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 22px;
|
||||
}
|
||||
.close_exit {
|
||||
position: absolute;
|
||||
right: 42px;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url(@/assets/images/coursewareManage/close.png);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
.line{
|
||||
height: 1px;
|
||||
margin-top: 16px;
|
||||
background-color: #666666;
|
||||
}
|
||||
.contents{
|
||||
display: flex;
|
||||
min-height: 500px;
|
||||
.drawerMain {
|
||||
min-width: 600px;
|
||||
margin: 0px 32px 0px 32px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
overflow-y: auto;
|
||||
|
||||
.minatitl {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
.up1 {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.up2 {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload {
|
||||
margin-top: 32px;
|
||||
display: flex;
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.right {
|
||||
margin-left: 6px;
|
||||
|
||||
.load {
|
||||
width: 500px;
|
||||
height: 176px;
|
||||
background: #f5f9fd;
|
||||
border-radius: 4px;
|
||||
// opacity: 0.3;
|
||||
border: 1px dashed #caddfd;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.cloud {
|
||||
margin-top: 52px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background-image: url(../../assets/images/basicinfo/cloud.png);
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
margin-top: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tipz {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.loadstate {
|
||||
width: 500px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
.loadborder {
|
||||
width: 500px;
|
||||
height: 173px;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #eaeaea;
|
||||
margin-bottom: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
margin-left: 20px;
|
||||
position: relative;
|
||||
|
||||
.defeat {
|
||||
width: 400px;
|
||||
position: absolute;
|
||||
left: 46px;
|
||||
top: 38px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 30px;
|
||||
height: 34px;
|
||||
background-image: url(../../assets/images/basicinfo/exl.png);
|
||||
}
|
||||
|
||||
.timebox {
|
||||
margin-left: 15px;
|
||||
margin-top: -5px;
|
||||
|
||||
.timetop {
|
||||
display: flex;
|
||||
width: 262px;
|
||||
justify-content: space-between;
|
||||
|
||||
// margin-bottom: 8px;
|
||||
.tit {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.stateloading {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
}
|
||||
|
||||
.statedefeat {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #ff7474;
|
||||
}
|
||||
|
||||
.statesucce {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #35ae69;
|
||||
}
|
||||
}
|
||||
|
||||
.prog {
|
||||
width: 262px;
|
||||
height: 5px;
|
||||
background: #eaf1fe;
|
||||
border-radius: 4px;
|
||||
|
||||
.inprogloading {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #4ea6ff;
|
||||
}
|
||||
|
||||
//下载失败条
|
||||
.inprogdefeat {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #ff7474;
|
||||
}
|
||||
|
||||
//下载成功条
|
||||
.inprogsucce {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #57c887;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.curloading {
|
||||
margin-left: 15px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
|
||||
.cur {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.downloadErr {
|
||||
width: 120px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #387df7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
margin-left: 66px;
|
||||
margin-top: 16px;
|
||||
position: absolute;
|
||||
bottom: 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btnn {
|
||||
height: 72px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.16);
|
||||
|
||||
.btn1 {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid #4ea6ff;
|
||||
border-radius: 8px;
|
||||
color: #4ea6ff;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn2 {
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background: #4ea6ff;
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
margin-left: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
432
src/components/project/LookExternalLecturer.vue
Normal file
432
src/components/project/LookExternalLecturer.vue
Normal file
@@ -0,0 +1,432 @@
|
||||
|
||||
<template>
|
||||
<a-drawer :visible="visible" placement="right" :closable="false" :maskClosable="false"
|
||||
width="80%" :title="false">
|
||||
<!-- 外部讲师查看详情 -->
|
||||
<div class="LookExternalLecturer">
|
||||
<div class="header" style="margin-top: -24px;">
|
||||
<div class="headerTitle">查看讲师</div>
|
||||
<!-- <router-link :to="{ path: '/lecturerList', query: { activeKey: '2', } }"> -->
|
||||
<img
|
||||
@click="handleBack"
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="../../assets/images/basicinfo/close.png"
|
||||
/>
|
||||
<!-- </router-link> -->
|
||||
</div>
|
||||
<!-- <a-divider style="height: 1px; background-color: #b7b8b7 ;margin: 0;" /> -->
|
||||
<a-layout-content>
|
||||
<!-- 讲师信息 -->
|
||||
<div style="width: 100%;margin-top: 10px;">
|
||||
<span class="line" style="margin-left:12px;"></span>
|
||||
<a-descriptions title="讲师信息" style="padding:0 20px;" bordered :column="3" :contentStyle="rowCenters" :labelStyle="rowCenter">
|
||||
<!-- 一层 -->
|
||||
<a-descriptions-item label="讲师头像"> <a-image
|
||||
:width="55" style="border-radius: 50%;"
|
||||
:src=formParam.photo
|
||||
/></a-descriptions-item>
|
||||
<a-descriptions-item label="讲师姓名">{{formParam.name||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="手机号码">{{formParam.mobile||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="供应商">{{formParam.supplier||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="讲师邮箱">{{formParam.email||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="授课时长" :span="2">{{formParam.teaching||'-'}}
|
||||
<span style="margin-left: 5px;" v-if="formParam.teaching != null">分钟</span>
|
||||
<span style="margin-left: 10px ; padding: 2px;" v-if="formParam.teaching != null">({{
|
||||
(formParam.teaching / 60).toFixed(2) }}小时)</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<div style="margin-top: 18px;"></div>
|
||||
<span class="line" style="margin-left:12px;"></span>
|
||||
<!-- 记录 -->
|
||||
<a-descriptions title="其他信息" bordered :column="4" style="padding:0 20px;" :contentStyle="rowCenters" :labelStyle="rowCenter" >
|
||||
<!-- 一层 -->
|
||||
<a-descriptions-item label="讲师介绍" :span="4" >
|
||||
<div v-if="formParam.description !=null&&resp(formParam.description)" style="min-width: 500px;" v-html="formParam.description" ></div>
|
||||
<div v-else>-</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="备注" :span="4">
|
||||
<div v-if="formParam.remark ==null || formParam.remark =='<p><br></p>'" style="min-width: 500px;">- </div>
|
||||
<div style="min-width: 500px;">{{formParam.remark ===null?'':formParam.remark}}</div>
|
||||
<!-- </a-tag>
|
||||
</div> -->
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<!-- -->
|
||||
<div style="margin-top: 9px;"></div>
|
||||
<a-tabs v-model:activeKey="activeKey" style="padding:0 20px;">
|
||||
<a-tab-pane key="1" tab="授课记录">
|
||||
<a-table :header-cell-style="{ 'text-align': 'center' }" :columns="teacherrecordsColumns"
|
||||
:sroll="{ x: '1000' }"
|
||||
:data-source="teacherrecordstableData" :loading="teacherrecordsLoading" @expand="expandTable" :pagination="pagination">
|
||||
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
<script lang ="jsx">
|
||||
import { useRouter,useRoute } from "vue-router";
|
||||
import { reactive, toRefs, ref,computed,watch } from "vue"
|
||||
import {getTeacherById} from "../../api/Lecturer";
|
||||
import { getNewInTeacherCourseList } from "../../api/Teaching";
|
||||
// import boe from '@/assets/boe.jpg'
|
||||
import avatar from '@/assets/avatar.png'
|
||||
import dayjs from "dayjs";
|
||||
export default{
|
||||
name :"LookExternalLecturer",
|
||||
components:{
|
||||
|
||||
},
|
||||
props:{
|
||||
visible:{
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
id:{
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
setup(props,emits){
|
||||
const router=useRouter();
|
||||
const state = reactive({
|
||||
activeKey:'1',
|
||||
formParam: {
|
||||
},
|
||||
promotionrecordsLoading: false, //晋级记录遮罩层
|
||||
teacherrecordsLoading: false,// 授课记录遮罩层
|
||||
teacherrecordstableDataTotal: 0,//授课记录列表总条数
|
||||
teacherrepromotableDataTotal: -1,//晋级记录总条数
|
||||
teacherrecords: {
|
||||
recordType:2,
|
||||
pageNo: "1",
|
||||
pageSize: "10",
|
||||
id: null
|
||||
},
|
||||
teacherrepromo:{
|
||||
id:null,
|
||||
pageNo: "1",
|
||||
pageSize: "10",
|
||||
}
|
||||
});
|
||||
watch(()=>props.visible,(val)=>{
|
||||
if(val){
|
||||
TeacherSystem(props.id)
|
||||
}else{
|
||||
state.formParam = {}
|
||||
teacherrecordstableData.value = []
|
||||
}
|
||||
})
|
||||
//外部讲师详情
|
||||
const TeacherSystem = (id) => {
|
||||
getTeacherById({id,}).then((res) => {
|
||||
console.log("内部讲师详情", res.data);
|
||||
state.formParam = res.data.data
|
||||
state.formParam.photo = state.formParam.photo ===null ?avatar : state.formParam.photo
|
||||
state.formParam.teachingDate = res.data.data.teachingDate ? dayjs(res.data.data.teachingDate, 'YYYY-MM-DD HH:mm'):'',
|
||||
getteacherrecordstableData()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("内部讲师详情", err);
|
||||
});
|
||||
}
|
||||
//返回上一层
|
||||
const handleBack=()=>{
|
||||
emits.emit('update:visible',false)
|
||||
};
|
||||
//授课记录列表
|
||||
const teacherrecordsColumns = ref([
|
||||
// {
|
||||
// title: '课程编号',
|
||||
// dataIndex: 'offcourseId',
|
||||
// key: 'offcourseId',
|
||||
// ellipsis: true, align: "center",
|
||||
// width: 120,
|
||||
// },
|
||||
{
|
||||
title: '课程编号',
|
||||
dataIndex: 'courseId',
|
||||
key: 'courseId',
|
||||
align: "center",
|
||||
customRender: ({text, index})=>{
|
||||
return index+1;
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '课程名称',
|
||||
dataIndex: 'courseName',
|
||||
key: 'courseName',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '课程日期',
|
||||
dataIndex: 'teachingDate',
|
||||
key: 'teachingDate',
|
||||
ellipsis: true, align: "center",
|
||||
width: 200,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{dayjs(value.record?.teachingDate).format("YYYY-MM-DD HH:mm")}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '内容分类',
|
||||
dataIndex: 'courseTypeName',
|
||||
key: 'courseTypeName',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '课程类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{String(value.record.type)
|
||||
? {
|
||||
"0": "在线课",
|
||||
"1": "面授课",
|
||||
"2": "课程开发",
|
||||
"3": "作业员入模培训",
|
||||
"4": "其他",
|
||||
}[value.record.type + ""]
|
||||
: "-"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '学习总人数',
|
||||
dataIndex: 'studys',
|
||||
key: 'studys',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '授课时长(分钟)',
|
||||
dataIndex: 'teaching',
|
||||
key: 'teaching',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '评分',
|
||||
dataIndex: 'score',
|
||||
key: 'score',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '开课状态',
|
||||
dataIndex: 'courseStatus',
|
||||
key: 'courseStatus',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{value.record.courseStatus == 0 || value.record.courseStatus == 1
|
||||
? {
|
||||
"0": "未开课",
|
||||
"1": "开课",
|
||||
}[value.record.courseStatus + ""] || ""
|
||||
: "-"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
key: 'remark',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (text)=>{
|
||||
return (
|
||||
<div>
|
||||
{text.record.remark || "-"}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
])
|
||||
//授课记录列表数据
|
||||
const teacherrecordstableData = ref([
|
||||
])
|
||||
const getteacherrecordstableData = () => {
|
||||
state.teacherrecordsLoading = true
|
||||
state.teacherrecords.name = state.formParam.name
|
||||
let obj = { ...state.teacherrecords }
|
||||
// api接口
|
||||
getNewInTeacherCourseList(obj).then((res) => {
|
||||
teacherrecordstableData.value = res.data.data.records
|
||||
state.teacherrecordstableDataTotal = Number(res.data.data.total);
|
||||
state.teacherrecordsLoading = false
|
||||
})
|
||||
};
|
||||
const pagination = computed(() => ({
|
||||
total: state.teacherrecordstableDataTotal,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper:true,
|
||||
current: state.teacherrecords.pageNo,
|
||||
pageSize: state.teacherrecords.pageSize,
|
||||
onChange: paginationChange,
|
||||
}));
|
||||
const paginationChange = (e,pageSize) => {
|
||||
state.teacherrecords.pageNo = e;
|
||||
state.teacherrecords.pageSize = pageSize
|
||||
getteacherrecordstableData();
|
||||
};
|
||||
//授课翻页
|
||||
const teacherchangePagination = (page) => {
|
||||
state.searchParam.pageNo = page;
|
||||
// state.pageNo = page;
|
||||
state.searchParam.pageSize = pageSize;
|
||||
getTableDate();
|
||||
state.teacherrecords.pageNo = page;
|
||||
getteacherrecordstableData();
|
||||
};
|
||||
const resp = (val) => {
|
||||
if(val){
|
||||
const reg = /<[^<>]+>/g;
|
||||
const value = val.replace(reg, "");
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return{
|
||||
...toRefs(state),
|
||||
router,
|
||||
resp,
|
||||
TeacherSystem,
|
||||
handleBack,
|
||||
rowCenter:{"text-align":"center",'width':'120px'},
|
||||
rowCenters:{'min-width':'176px'},
|
||||
teacherrecordstableData,
|
||||
teacherrecordsColumns,
|
||||
getteacherrecordstableData,
|
||||
teacherchangePagination,
|
||||
pagination,
|
||||
paginationChange,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.LookExternalLecturer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.header {
|
||||
padding: 0px 32px;
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
// margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
.filter {
|
||||
margin-left: 38px;
|
||||
margin-right: 38px;
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
.select {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.backbtn{
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
border: none;
|
||||
color: #4ea6ff;
|
||||
width: 80px;
|
||||
height:64px
|
||||
}
|
||||
//小竖线
|
||||
.line{
|
||||
float:left; width: 3px; height: 25px; background: #4ea6ff;border-radius: 30%; margin-right: 5px;
|
||||
}
|
||||
::v-deep .ant-descriptions-header{
|
||||
margin-bottom: 18px ;
|
||||
margin-top: 18px;
|
||||
}
|
||||
.goback {
|
||||
float: right;
|
||||
padding-right: 70px;
|
||||
//padding-top: 37px;
|
||||
position: relative;
|
||||
|
||||
.return {
|
||||
display: inline-block;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin-top: 12px;
|
||||
margin-right: 10px;
|
||||
background-image: url("../../assets/images/projectadd/return.png");
|
||||
}
|
||||
|
||||
.returntext {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
color: #4ea6ff;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-select-selection-overflow-item {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
::v-deep .ant-select-multiple .ant-select-selection-item {
|
||||
height: 34px
|
||||
}
|
||||
.tableBox {
|
||||
padding-bottom: 20px;
|
||||
margin: 20px 38px 30px;
|
||||
::v-deep .ant-select-dropdown{
|
||||
display: inline-block;
|
||||
}
|
||||
::v-deep .ant-select-selection-item{
|
||||
margin-left: 3px;
|
||||
}
|
||||
::v-deep .ant-pagination-options-size-changer.ant-select{
|
||||
width: 84px;
|
||||
}
|
||||
.pa {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
569
src/components/project/LookInsideLecturer.vue
Normal file
569
src/components/project/LookInsideLecturer.vue
Normal file
@@ -0,0 +1,569 @@
|
||||
<template>
|
||||
<a-drawer :visible="visible" placement="right" :closable="false" :maskClosable="false"
|
||||
width="80%" :title="false">
|
||||
<!-- 内部讲师查看详情 -->
|
||||
<div class="LookInsideLecturer">
|
||||
<div class="header" style="margin-top: -24px;">
|
||||
<div class="headerTitle">查看讲师</div>
|
||||
<!-- <router-link :to="{ path: '/lecturerList', query: { activeKey: '1', } }"> -->
|
||||
<img
|
||||
@click="handleClose"
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="../../assets/images/basicinfo/close.png"
|
||||
/>
|
||||
<!-- </router-link> -->
|
||||
</div>
|
||||
<a-layout-content>
|
||||
<!-- 讲师信息 -->
|
||||
<div style="width: 100%;margin-top: 10px;padding: 20px;">
|
||||
<span class="line"></span>
|
||||
<a-descriptions title="讲师信息" bordered :column="4" :contentStyle="rowCenter" :labelStyle="rowCenters">
|
||||
<!-- 一层 -->
|
||||
<a-descriptions-item label="讲师头像">
|
||||
<a-image :width="55" style="border-radius: 50%;" :src=formParam.photo />
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="讲师姓名">{{formParam.name}}/{{formParam.userNo}}</a-descriptions-item>
|
||||
<a-descriptions-item label="讲师体系">{{formParam.tsystemName || '-'}}</a-descriptions-item>
|
||||
<!-- 二层 -->
|
||||
<a-descriptions-item label="讲师级别">{{formParam.tlevelName||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="认证状态">{{ formParam.certStatus==0?'未认证' :formParam.certStatus==1 ?'已认证':'-'}}
|
||||
<span>
|
||||
<a-button type="text" class="moreidbtn" v-if="formParam.certStatus == 1"
|
||||
@click="handleup">查看认证资料</a-button>
|
||||
</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="授课时长"> <span v-if="formParam.teaching!= null" >{{ (Number(formParam.teaching) /60 ).toFixed(2)}}小时</span><span v-else>-</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="发薪地 ">{{formParam.salaryName||'-'}}</a-descriptions-item>
|
||||
<!-- 三层 -->
|
||||
<a-descriptions-item label="在职状态">{{formParam.waitStatus=='0'?'在职' :formParam.waitStatus=='1' ?'离职':'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="账号状态">{{formParam.status=='0'?'临时' :formParam.status=='1' ?'启用':formParam.status==2 ?'停用':'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="创建方式">{{formParam.createFrom=='0'?'自动录入' :formParam.createFrom=='1'?'手动录入':'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item style="max-width: 400px;" label="所属组织" >
|
||||
<span :title="formParam.orgName">{{ formParam.orgNames || '-' }}</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<div style="margin-top: 10px;"></div>
|
||||
<span class="line" ></span>
|
||||
<a-descriptions title="其他信息" bordered :column="4" :contentStyle="rowCenter" :labelStyle="rowCenters" >
|
||||
<!-- 一层 -->
|
||||
<a-descriptions-item style="max-width: 200px;" label="讲师介绍" :span="4" >
|
||||
<div v-if="formParam.description !=null&&resp(formParam.description)" style="min-width: 500px;" v-html="formParam.description" ></div>
|
||||
<div v-else>-</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="工作职责" :span="4">
|
||||
<div v-if="formParam.workExperience !=null&&resp(formParam.workExperience)" style="min-width: 500px;" v-html="formParam.workExperience" ></div>
|
||||
<div v-else>-</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="擅长课程" :span="4">
|
||||
<div v-if="formParam.courses !=null&&resp(formParam.courses)" style="min-width: 500px;" v-html="formParam.courses" ></div>
|
||||
<div v-else>-</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="教师专长" :span="4">
|
||||
<a-tag v-if="formParam.expertiseNames" color="blue" style="margin-right:10px" v-for="item in formParam.expertiseNames?.split(',')">{{item}}</a-tag>
|
||||
<span v-else>-</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<!-- 记录 -->
|
||||
<div style="margin-top: 8px;"></div>
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="1" tab="授课记录">
|
||||
<a-table :header-cell-style="{ 'text-align': 'center' }" :columns="teacherrecordsColumns"
|
||||
|
||||
:data-source="teacherrecordstableData" :loading="teacherrecordsLoading" :scroll="{ x: '1000' }" :pagination="pagination">
|
||||
</a-table>
|
||||
<div style="float: right;">
|
||||
<a-pagination
|
||||
v-if="tableDataTotal > 10"
|
||||
:showSizeChanger="true"
|
||||
:showQuickJumper="false"
|
||||
:hideOnSinglePage="false"
|
||||
:pageSize="searchParam.pageSize"
|
||||
:current="searchParam.pageNo"
|
||||
:total="tableDataTotal"
|
||||
class="pagination"
|
||||
@change="changePagination"
|
||||
/>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="晋级记录">
|
||||
<a-table :header-cell-style="{ 'text-align': 'center' }" style="border: 1px solid #f2f6fe" :columns="promotionrecordsColumns"
|
||||
|
||||
:data-source="promotionrecordstableData" :loading="promotionrecordsLoading" @expand="expandTable" :pagination="false">
|
||||
<template #bodyCell="{ record, column,index }" >
|
||||
</template>
|
||||
</a-table>
|
||||
<div style="float: right;">
|
||||
<a-pagination
|
||||
v-if="teacherrepromotableDataTotal > 10"
|
||||
:showSizeChanger="true"
|
||||
:showQuickJumper="false"
|
||||
:hideOnSinglePage="true"
|
||||
:pageSize="teacherrepromo.pageSize"
|
||||
:current="teacherrepromo.pageNo"
|
||||
:total="teacherrepromotableDataTotal"
|
||||
class="pagination"
|
||||
@change="teacherrepromoPagination"
|
||||
/>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
<script lang ="jsx">
|
||||
import { useRouter,useRoute } from "vue-router";
|
||||
import { reactive, toRefs, ref, computed,watch } from "vue"
|
||||
import { useStore } from "vuex";
|
||||
import {getTeacherById ,getTeacherLogList} from "../../api/Lecturer";
|
||||
import { getNewInTeacherCourseList } from "../../api/Teaching";
|
||||
import avatar from '@/assets/avatar.png'
|
||||
import Avatarman from '@/assets/Avatarman.png'
|
||||
import Avatarwoman from '@/assets/Avatarwoman.png'
|
||||
import dayjs from "dayjs";
|
||||
export default{
|
||||
name :"LookInsideLecturer",
|
||||
components:{
|
||||
|
||||
},
|
||||
props:{
|
||||
visible:{
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
id:{
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
setup(props,emits){
|
||||
const router=useRouter();
|
||||
const state = reactive({
|
||||
activeKey:'1',
|
||||
formParam: {
|
||||
},
|
||||
promotionrecordsLoading: false, //晋级记录遮罩层
|
||||
teacherrecordsLoading: false,// 授课记录遮罩层
|
||||
teacherrecordstableDataTotal: 0,//授课记录列表总条数
|
||||
teacherrepromotableDataTotal: -1,//晋级记录总条数
|
||||
teacherrecords: {
|
||||
recordType:1,
|
||||
pageNo: "1",
|
||||
pageSize: "10",
|
||||
id: null
|
||||
},
|
||||
teacherrepromo:{
|
||||
userId:null,
|
||||
pageNo: "1",
|
||||
pageSize: "10",
|
||||
}
|
||||
});
|
||||
watch(() => props.visible, (val) => {
|
||||
console.log(val,'xixixiixix')
|
||||
if(val){
|
||||
const id = props.id
|
||||
TeacherSystem(id)
|
||||
}
|
||||
})
|
||||
const isOrgNames = (val) => {
|
||||
if(val){
|
||||
const parts = val.split('/');
|
||||
const reversedParts = parts.reverse();
|
||||
state.formParam.orgNames = reversedParts.join('/');
|
||||
}
|
||||
}
|
||||
const handleClose = () => {
|
||||
emits.emit('update:visible',false)
|
||||
}
|
||||
//内部讲师详情
|
||||
const TeacherSystem = (id) => {
|
||||
getTeacherById({id,}).then((res) => {
|
||||
let objA= res.data.data
|
||||
console.log(objA ,'11111111111')
|
||||
state.formParam = objA
|
||||
state.formParam.photo = state.formParam.photo ==null ?
|
||||
state.formParam.gender == 1 ? Avatarman :
|
||||
state.formParam.gender ==2 ? Avatarwoman : avatar : state.formParam.photo
|
||||
state.teacherrepromo.userId=res.data.data.id
|
||||
console.log(state.teacherrepromo.id);
|
||||
isOrgNames(state.formParam.orgName)
|
||||
getteacherrecordstableData()
|
||||
promotionrecordstableData.value = res.data.data.levelLogList
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("内部讲师详情", err);
|
||||
});
|
||||
}
|
||||
const resp = (val) => {
|
||||
if(val){
|
||||
const reg = /<[^<>]+>/g;
|
||||
const value = val.replace(reg, "");
|
||||
return value
|
||||
}
|
||||
}
|
||||
//授课记录列表
|
||||
const teacherrecordsColumns = ref([
|
||||
{
|
||||
title: '课程编号',
|
||||
dataIndex: 'courseId',
|
||||
key: 'courseId',
|
||||
align: "center",
|
||||
customRender: ({text, index})=>{
|
||||
return index+1;
|
||||
},
|
||||
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '课程名称',
|
||||
dataIndex: 'courseName',
|
||||
key: 'courseName',
|
||||
ellipsis: true,
|
||||
align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '课程日期',
|
||||
dataIndex: 'teachingDate',
|
||||
key: 'teachingDate',
|
||||
ellipsis: true, align: "center",
|
||||
width: 200,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{dayjs(value.record?.teachingDate).format("YYYY-MM-DD HH:mm")}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "内容分类",
|
||||
width: 100,
|
||||
dataIndex: "courseTypeName",
|
||||
ellipsis: true,
|
||||
key: "keywords",
|
||||
align: "center",
|
||||
},
|
||||
{
|
||||
title: '课程类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{String(value.record.type)
|
||||
? {
|
||||
"0": "在线课",
|
||||
"1": "面授课",
|
||||
"2": "课程开发",
|
||||
"3": "作业员入模培训",
|
||||
"4": "其他",
|
||||
}[value.record.type + ""]
|
||||
: "-"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '学习总人数',
|
||||
dataIndex: 'studys',
|
||||
key: 'studys',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '授课时长(分钟)',
|
||||
dataIndex: 'teaching',
|
||||
key: 'teaching',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '评分',
|
||||
dataIndex: 'score',
|
||||
key: 'score',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '开课状态',
|
||||
dataIndex: 'courseStatus ',
|
||||
key: 'courseStatus ',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{value.record.courseStatus == 0 || value.record.courseStatus == 1
|
||||
? {
|
||||
"0": "未开课",
|
||||
"1": "开课",
|
||||
}[value.record.courseStatus + ""] || ""
|
||||
: "-"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark ',
|
||||
key: 'remark ',
|
||||
ellipsis: true,
|
||||
align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>{value.record.remark || '-'}</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
])
|
||||
//授课记录列表数据
|
||||
const teacherrecordstableData = ref([
|
||||
])
|
||||
const getteacherrecordstableData = () => {
|
||||
state.teacherrecordsLoading = true
|
||||
state.teacherrecords.name = state.formParam.name
|
||||
let obj = { ...state.teacherrecords }
|
||||
// api接口
|
||||
getNewInTeacherCourseList(obj).then((res) => {
|
||||
console.log(res);
|
||||
teacherrecordstableData.value = res.data.data.records
|
||||
state.teacherrecordstableDataTotal = Number(res.data.data.total);
|
||||
state.teacherrecordsLoading = false
|
||||
|
||||
})
|
||||
};
|
||||
const pagination = computed(() => ({
|
||||
total: state.teacherrecordstableDataTotal,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper:true,
|
||||
current: state.teacherrecords.pageNo,
|
||||
pageSize: state.teacherrecords.pageSize,
|
||||
onChange: paginationChange,
|
||||
}));
|
||||
const paginationChange = (e,pageSize) => {
|
||||
state.teacherrecords.pageNo = e;
|
||||
state.teacherrecords.pageSize = pageSize
|
||||
getteacherrecordstableData();
|
||||
};
|
||||
//授课翻页
|
||||
const teacherchangePagination = (page) => {
|
||||
state.teacherrecords.pageNo = page;
|
||||
// state.pageNo = page;
|
||||
state.teacherrecords.pageSize = pageSize;
|
||||
getteacherrecordstableData();
|
||||
};
|
||||
//晋级记录翻页
|
||||
const teacherrepromoPagination = (page) => {
|
||||
state.teacherrepromo.pageNo = page;
|
||||
// getpromotionrecordstableData();
|
||||
};
|
||||
//晋级记录列表
|
||||
const promotionrecordsColumns = ref([
|
||||
{
|
||||
title: '变更时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '变更方式',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
customRender: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{value.record.type == 1 ? "自动" : value.record.type == 0 ? '手动':"-"}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '变更结果',
|
||||
dataIndex: 'result',
|
||||
key: 'result',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
dataIndex: 'updateName',
|
||||
key: 'updateName',
|
||||
ellipsis: true, align: "center",
|
||||
width: 120,
|
||||
},
|
||||
])
|
||||
//晋级记录列表数据
|
||||
const promotionrecordstableData = ref([
|
||||
])
|
||||
// const getpromotionrecordstableData = () => {
|
||||
// state.promotionrecordsLoading = true
|
||||
// // state.teacherrepromo.kid = state.kid
|
||||
// getTeacherLogList(state.teacherrepromo).then((res) => {
|
||||
// promotionrecordstableData.value = res.data.data.records
|
||||
// state.teacherrepromotableDataTotal = Number(res.data.data.total);
|
||||
// })
|
||||
// state.promotionrecordsLoading = false
|
||||
// };
|
||||
const goback = ()=>{
|
||||
router.back()
|
||||
}
|
||||
const store = useStore();
|
||||
// // 内容分类
|
||||
// const sysTypeOptions = computed(() => {return store.state.content_type;});
|
||||
// //内容分类
|
||||
// const getSysTypeMap = (code) => {
|
||||
// if(code=="")return
|
||||
// // console.log(store.state.sysTypeMap,'map集合');
|
||||
// return store.state.sysTypeMap.get(code)
|
||||
// }
|
||||
// getSysTypeMap()
|
||||
const handleup = ()=>{
|
||||
window.open (
|
||||
`${process.env.VUE_APP_BOE_API_URL}/upload${state.formParam.certification}`
|
||||
);
|
||||
}
|
||||
return{
|
||||
...toRefs(state),
|
||||
router,
|
||||
goback,
|
||||
handleup,
|
||||
// getSysTypeMap,
|
||||
// sysTypeOptions,
|
||||
TeacherSystem,
|
||||
handleClose,
|
||||
isOrgNames,
|
||||
rowCenter:{"text-align":"left",'min-width':'176px'},
|
||||
rowCenters:{"text-align":"center",'width':'160px','min-width':'110px'},
|
||||
teacherrecordstableData,
|
||||
teacherrecordsColumns,
|
||||
resp,
|
||||
getteacherrecordstableData,
|
||||
teacherchangePagination,
|
||||
pagination,
|
||||
paginationChange,
|
||||
teacherrepromoPagination,
|
||||
promotionrecordsColumns,
|
||||
promotionrecordstableData,
|
||||
// getpromotionrecordstableData,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.LookInsideLecturer {
|
||||
.header {
|
||||
padding: 0px 32px;
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
// margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
}
|
||||
}
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.filter {
|
||||
margin-left: 38px;
|
||||
margin-right: 38px;
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
.select {
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.backbtn{
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
border: none;
|
||||
color: #4ea6ff;
|
||||
width: 80px;
|
||||
height:64px
|
||||
}
|
||||
//小竖线
|
||||
.line{
|
||||
float:left; width: 3px; height: 25px; background: #4ea6ff;border-radius: 30%; margin-right: 5px;
|
||||
}
|
||||
::v-deep .ant-descriptions-header{
|
||||
margin-bottom: 18px ;
|
||||
}
|
||||
.goback {
|
||||
float: right;
|
||||
padding-right: 70px;
|
||||
//padding-top: 37px;
|
||||
position: relative;
|
||||
|
||||
.return {
|
||||
display: inline-block;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
margin-top: 12px;
|
||||
margin-right: 10px;
|
||||
background-image: url("../../assets/images/projectadd/return.png");
|
||||
}
|
||||
|
||||
.returntext {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
color: #4ea6ff;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.moreidbtn {
|
||||
border: none;
|
||||
color: #4ea6ff;
|
||||
width: 80px
|
||||
}
|
||||
|
||||
::v-deep .ant-select-selection-overflow-item {
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
::v-deep .ant-select-multiple .ant-select-selection-item {
|
||||
height: 34px
|
||||
}
|
||||
.tableBox {
|
||||
padding-bottom: 20px;
|
||||
margin: 20px 38px 30px;
|
||||
::v-deep .ant-select-dropdown{
|
||||
display: inline-block;
|
||||
}
|
||||
::v-deep .ant-select-selection-item{
|
||||
margin-left: 3px;
|
||||
}
|
||||
::v-deep .ant-pagination-options-size-changer.ant-select{
|
||||
width: 84px;
|
||||
}
|
||||
.pa {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -16,9 +16,8 @@
|
||||
v-model:value="labelValue"
|
||||
style="width: 100%"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
placeholder="请选择归属组织"
|
||||
:placeholder="placeholder"
|
||||
:labelInValue="true"
|
||||
allow-clear
|
||||
v-model:treeExpandedKeys="stuTreeExpandedKeys"
|
||||
:loading="orgLoading"
|
||||
:load-data="onLoadData"
|
||||
@@ -46,6 +45,10 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择归属组织"
|
||||
}
|
||||
});
|
||||
const emit = defineEmits({});
|
||||
const stuTreeExpandedKeys = ref([]);
|
||||
|
||||
108
src/components/project/ProjectManagerLecturer.vue
Normal file
108
src/components/project/ProjectManagerLecturer.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<a-select
|
||||
:getPopupContainer="
|
||||
(triggerNode) => {
|
||||
return triggerNode.parentNode || document.body;
|
||||
}
|
||||
"
|
||||
v-model:value="managerArray"
|
||||
:placeholder="placeholder"
|
||||
:options="options"
|
||||
allowClear
|
||||
showSearch
|
||||
mode="multiple"
|
||||
:disabled="disabled"
|
||||
@search="searchMember"
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
@focus="focus"
|
||||
:show-arrow="true"
|
||||
style="width: 100%"
|
||||
:maxTagTextLength="3"
|
||||
:maxTagCount="4"
|
||||
>
|
||||
<template v-if="loading" #notFoundContent>
|
||||
<a-spin size="small"/>
|
||||
</template>
|
||||
</a-select>
|
||||
</template>
|
||||
<script setup>
|
||||
import {computed, defineEmits, defineProps, onMounted, ref, watch} from "vue";
|
||||
import {throttle} from "@/api/method";
|
||||
import {getUserList} from "@/api/Lecturer.js";
|
||||
|
||||
const props = defineProps({
|
||||
disabled: Boolean,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请输入搜索关键字",
|
||||
},
|
||||
arrayList:{
|
||||
type: Array,
|
||||
default: ()=>[]
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
const emit = defineEmits({})
|
||||
const managerArray = ref([])
|
||||
const loading = ref(false)
|
||||
onMounted(()=>{
|
||||
managerArray.value = props.arrayList
|
||||
options.value = props.arrayList
|
||||
})
|
||||
watch(()=>props.arrayList, ()=>{
|
||||
managerArray.value = props.arrayList
|
||||
})
|
||||
const options = ref([])
|
||||
const keyword = ref('')
|
||||
const getList = () => {
|
||||
loading.value = true
|
||||
getUserList(keyword.value).then(res=>{
|
||||
loading.value = false
|
||||
if(res.data.code == 200){
|
||||
options.value = res.data.data.list.map(e => ({
|
||||
label: e.realName + e.userNo,
|
||||
value: e.id,
|
||||
userId: e.id,
|
||||
userNo: e.userNo,
|
||||
userName: e.realName,
|
||||
}))
|
||||
// console.log(options.value,'xixixixi')
|
||||
}
|
||||
}).catch(()=>{
|
||||
loading.value = false
|
||||
options.value =[]
|
||||
})
|
||||
}
|
||||
const throttList = throttle(getList, 600);
|
||||
//搜索学员
|
||||
const searchMember = (val) => {
|
||||
keyword.value = val
|
||||
throttList()
|
||||
};
|
||||
const focus = () => {
|
||||
keyword.value = ''
|
||||
getList()
|
||||
}
|
||||
function blur() {
|
||||
keyword.value = ''
|
||||
}
|
||||
|
||||
function change(e, l) {
|
||||
console.log(e, l,'xixixixiixix')
|
||||
keyword.value = ''
|
||||
l?.map(item => item.type = props.type)
|
||||
if (Array.isArray(l)) {
|
||||
emit('update:arrayList',l)
|
||||
emit('update:value', l.map(t => t.value).join(','))
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -29,7 +29,7 @@
|
||||
<script setup>
|
||||
import {computed, defineEmits, defineProps, onMounted, ref, watch} from "vue";
|
||||
import {useThrottlePage} from "@/api/request";
|
||||
import {USER_LIST} from "@/api/apis";
|
||||
import {USER_LIST_NEW} from "@/api/apis";
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
@@ -56,12 +56,12 @@ const emit = defineEmits({})
|
||||
|
||||
const isOpen = ref(false)
|
||||
|
||||
const memberParam = ref({keyword: '', pageNo:1, pageSize: 20})
|
||||
const memberParam = ref({name: '', pageNo:1, pageSize: 20})
|
||||
|
||||
const {data: userList, loading} = useThrottlePage(USER_LIST, memberParam.value, false)
|
||||
const {data: userList, loading} = useThrottlePage(USER_LIST_NEW, memberParam.value, false)
|
||||
|
||||
const options = computed(() => userList.value.filter(e => !(props.value + '').includes(e.id)).map(e => ({
|
||||
label: e.realName + e.userNo,
|
||||
label: e.name + '(' + e.mobile + ')',
|
||||
value: e.id //,
|
||||
// ...e,
|
||||
// audienceList: null
|
||||
@@ -93,18 +93,18 @@ const searchMember = (keyword) => {
|
||||
isOpen.value = true
|
||||
userList.value = []
|
||||
memberParam.value.pageNo = 1
|
||||
memberParam.value.keyword = keyword
|
||||
memberParam.value.name = keyword
|
||||
console.log('searchMember', memberParam.value)
|
||||
};
|
||||
|
||||
function blur() {
|
||||
isOpen.value = false
|
||||
memberParam.value.keyword = ''
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.pageNo = 1
|
||||
}
|
||||
|
||||
function change(e, l) {
|
||||
memberParam.value.keyword = ''
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.pageNo = 1
|
||||
isOpen.value = false
|
||||
Array.isArray(l) && (selectOptions.value = l)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<script setup>
|
||||
import {computed, defineEmits, defineProps, onMounted, ref, watch} from "vue";
|
||||
import {useThrottlePage} from "@/api/request";
|
||||
import {USER_LIST} from "@/api/apis";
|
||||
import {USER_LIST_NEW} from "@/api/apis";
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
@@ -56,12 +56,12 @@ const emit = defineEmits({})
|
||||
|
||||
const isOpen = ref(false)
|
||||
|
||||
const memberParam = ref({keyword: '', pageNo:1, pageSize: 20})
|
||||
const memberParam = ref({name: '', pageNo:1, pageSize: 20})
|
||||
|
||||
const {data: userList, loading} = useThrottlePage(USER_LIST, memberParam.value, false)
|
||||
const {data: userList, loading} = useThrottlePage(USER_LIST_NEW, memberParam.value, false)
|
||||
|
||||
const options = computed(() => userList.value.filter(e => !(props.value + '').includes(e.id)).map(e => ({
|
||||
label: e.realName + e.userNo,
|
||||
label: e.name + '(' + e.mobile + ')' ,
|
||||
value: e.id // ,
|
||||
// ...e,
|
||||
// audienceList: null
|
||||
@@ -93,18 +93,18 @@ const searchMember = (keyword) => {
|
||||
isOpen.value = true
|
||||
userList.value = []
|
||||
memberParam.value.pageNo = 1
|
||||
memberParam.value.keyword = keyword
|
||||
memberParam.value.name = keyword
|
||||
console.log('searchMember', memberParam.value)
|
||||
};
|
||||
|
||||
function blur() {
|
||||
isOpen.value = false
|
||||
memberParam.value.keyword = ''
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.pageNo = 1
|
||||
}
|
||||
|
||||
function change(e, l) {
|
||||
memberParam.value.keyword = ''
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.pageNo = 1
|
||||
isOpen.value = false
|
||||
Array.isArray(l) && (selectOptions.value = l)
|
||||
|
||||
140
src/components/project/ProjectManagerOutTeacher.vue
Normal file
140
src/components/project/ProjectManagerOutTeacher.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<a-select
|
||||
:getPopupContainer="
|
||||
(triggerNode) => {
|
||||
return triggerNode.parentNode || document.body;
|
||||
}
|
||||
"
|
||||
v-model:value="managerArray"
|
||||
:placeholder="placeholder"
|
||||
:filterOption="false"
|
||||
:options="isOpen?options:selectOptions"
|
||||
allowClear
|
||||
showSearch
|
||||
:disabled="disabled"
|
||||
@popupScroll="memberScroll"
|
||||
@search="searchMember"
|
||||
:open="isOpen"
|
||||
@change="change"
|
||||
@blur="blur"
|
||||
:show-arrow="false"
|
||||
style="width: 100%"
|
||||
>
|
||||
<template v-if="loading" #notFoundContent>
|
||||
<a-spin size="small"/>
|
||||
</template>
|
||||
</a-select>
|
||||
</template>
|
||||
<script setup>
|
||||
import {computed, defineEmits, defineProps, onMounted, ref, watch} from "vue";
|
||||
import {useThrottlePage} from "@/api/request";
|
||||
import { getTeacherList } from "@/api/Lecturer";
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
mobile: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: Boolean,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请输入搜索关键字",
|
||||
},
|
||||
mode: String
|
||||
})
|
||||
|
||||
const selectOptions = ref([])
|
||||
|
||||
const managerArray = computed(() => props.value === '' ? null : props.value)
|
||||
|
||||
const emit = defineEmits({})
|
||||
|
||||
const isOpen = ref(false)
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
const memberParam = ref({name: '', pageNo:1, pageSize: 999,teacherType:2 ,status:1})
|
||||
|
||||
const userList = ref([])
|
||||
const loading = ref(false)
|
||||
const getOutTeacher = () => {
|
||||
getTeacherList(memberParam.value).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
userList.value = res.data.data.records
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
const options = computed(() => userList.value.map(e => ({
|
||||
|
||||
// label: e.name + '(' + e.userNo + ')' + e.organizationName,
|
||||
label:e.name,
|
||||
value: e.name,
|
||||
...e,
|
||||
audienceList: null
|
||||
})))
|
||||
|
||||
watch(props, init)
|
||||
|
||||
function init() {
|
||||
//第一次进来 编辑赋值
|
||||
// if (props.value && (props.value + '') !== selectOptions.value.map(e => e.value).join(',')) {
|
||||
// selectOptions.value = (props.value + '').split(',').map((e, i) => ({label: props.name.split(',')[i], value: e}))
|
||||
// }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('onMounted')
|
||||
init()
|
||||
getOutTeacher()
|
||||
})
|
||||
|
||||
|
||||
const memberScroll = ({target: {scrollHeight, scrollTop, clientHeight}}) => {
|
||||
scrollHeight === (clientHeight + scrollTop) && memberParam.value.pageNo++
|
||||
};
|
||||
const debounceObject = debounce(getOutTeacher,1000)
|
||||
//搜索学员
|
||||
const searchMember = (keyword) => {
|
||||
console.log('searchMember', keyword)
|
||||
loading.value = true
|
||||
isOpen.value = true
|
||||
userList.value = []
|
||||
memberParam.value.pageNo = 1
|
||||
memberParam.value.teacherType=2
|
||||
memberParam.value.name = keyword
|
||||
console.log('searchMember', memberParam.value)
|
||||
debounceObject()
|
||||
};
|
||||
|
||||
function blur() {
|
||||
isOpen.value = false
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.pageNo = 1
|
||||
memberParam.value.teacherType=2
|
||||
}
|
||||
|
||||
function change(e, l) {
|
||||
memberParam.value.name = ''
|
||||
memberParam.value.teacherType=2
|
||||
memberParam.value.pageNo = 1
|
||||
isOpen.value = false
|
||||
Array.isArray(l) && (selectOptions.value = l)
|
||||
Array.isArray(selectOptions.value) && emit('onChange', e, l)
|
||||
emit('update:name', l?.label)
|
||||
emit('update:value', l?.value)
|
||||
emit('update:mobile', l?.label)
|
||||
}
|
||||
|
||||
</script>
|
||||
435
src/components/project/SearchTeacher.vue
Normal file
435
src/components/project/SearchTeacher.vue
Normal file
@@ -0,0 +1,435 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-popover v-model:visible="visible" placement="bottom" trigger="click">
|
||||
<template #content v-if="!disabled">
|
||||
<div class="pover">
|
||||
<div class="search">
|
||||
<a-select
|
||||
v-model:value="selectName"
|
||||
style="width: 100%"
|
||||
placeholder="请查询姓名或工号"
|
||||
:options="isOpen?options:selectOptions"
|
||||
:filter-option="false"
|
||||
allowClear
|
||||
showSearch
|
||||
:open="isOpen"
|
||||
:defaultOpen="false"
|
||||
@search="searchMembers"
|
||||
@change="handleChange"
|
||||
@blur="blur"
|
||||
>
|
||||
<template #suffixIcon><ZoomInOutlined twoToneColor="#eb2f96" /></template>
|
||||
<template v-if="loading" #notFoundContent>
|
||||
<a-spin size="small"/>
|
||||
</template>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="tree">
|
||||
<a-tree show-icon allow-clear tree-default-expand-all :tree-data="treeData" :loading="orgLoading"
|
||||
:load-data="onLoadData" v-model:selectedKeys="stuTreeSelectKeys"
|
||||
v-model:expandedKeys="stuTreeExpandedKeys" :fieldNames="{
|
||||
children: 'treeChildList',
|
||||
key: 'id',
|
||||
title: 'name',
|
||||
value: 'name',
|
||||
}" @select="stuStuOrgSelect" style="max-height: 260px;overflow-y: auto;width: 250px;">
|
||||
<template #smile>
|
||||
<UserOutlined />
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<div class="btn0 btn1" @click="notChange">取消</div>
|
||||
<!-- <div class="btn0 btn2" @click="changeOut">确定</div> -->
|
||||
<a-button :loading="loadingChange" @click="changeOut" class="btn0 btn2" type="primary">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-select
|
||||
v-model:value="selectData"
|
||||
style="width: 100%"
|
||||
placeholder="请选择讲师"
|
||||
:options="selectOptions"
|
||||
:filter-option="false"
|
||||
:open="false"
|
||||
:defaultOpen="false"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<template v-if="loading" #notFoundContent>
|
||||
<a-spin size="small"/>
|
||||
</template>
|
||||
</a-select>
|
||||
</a-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref,defineProps,defineEmits,watch,onMounted } from 'vue';
|
||||
import { request, useRequest} from "@/api/request";
|
||||
import { message } from "ant-design-vue"
|
||||
import { ORG_CHILD_LIST, ORG_LIST,USER_LIST_PAGE} from "@/api/apis";
|
||||
import { getTeacherByDepartId,getTeacherByNameOrUserNo,getSystemInfoByUserId,getTeacherList } from "@/api/Lecturer";
|
||||
import { ZoomInOutlined,UserOutlined } from '@ant-design/icons-vue';
|
||||
const props = defineProps({
|
||||
value:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
lable:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
newlable:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
system:{
|
||||
type: Object,
|
||||
default: ()=>{},
|
||||
},
|
||||
level:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
orgId:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
id:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
payrollPlaceCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
payrollPlaceName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
lecturer: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:value','update:lable','update:system','update:level','update:newlable','update:orgId','update:id','update:payrollPlaceCode','update:payrollPlaceName'])
|
||||
const visible = ref(false);
|
||||
const selectData = ref(null);
|
||||
watch(()=>props.value,(val)=>{
|
||||
if(val){
|
||||
selectData.value = val
|
||||
}else{
|
||||
selectData.value = null
|
||||
}
|
||||
},{immediate:true})
|
||||
const teacherName = ref('')
|
||||
const selectName = ref(null)
|
||||
const options = ref([]);
|
||||
const selectOptions = ref([])
|
||||
const isOpen = ref(false);
|
||||
const loading = ref(false);
|
||||
function blur() {
|
||||
isOpen.value = false
|
||||
}
|
||||
const orgName = ref('')
|
||||
const orgId = ref('')
|
||||
const payrollPlaceCode = ref('')
|
||||
const payrollPlaceName = ref('')
|
||||
const systemName = ref(null)
|
||||
const levelName = ref('')
|
||||
const neworgName = ref('')
|
||||
const teacherId = ref('')
|
||||
const handleChange = (e,l) => {
|
||||
isOpen.value = false
|
||||
// emit('update:value',e)
|
||||
teacherName.value = e
|
||||
orgName.value = l.orgName
|
||||
// systemName.value = l.systemName
|
||||
levelName.value = l.levelName
|
||||
teacherId.value = l.key
|
||||
orgId.value = l.orgId
|
||||
payrollPlaceCode.value = l.payrollPlaceCode
|
||||
payrollPlaceName.value = l.payrollPlaceName
|
||||
if( l.orgName !==null ){
|
||||
neworgName.value= orgName.value.split('/')
|
||||
neworgName.value= neworgName.value[ neworgName.value.length-1]
|
||||
}
|
||||
emit('tlevel',l)
|
||||
};
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
const searchMembers = (keyword) => {
|
||||
isOpen.value = true
|
||||
options.value = []
|
||||
loading.value = true
|
||||
if(keyword == '' || keyword == null){
|
||||
isOpen.value = false
|
||||
loading.value = false
|
||||
options.value = []
|
||||
}else{
|
||||
debounceObject(keyword)
|
||||
}
|
||||
};
|
||||
const searchMember = (keyword) => {
|
||||
const obj = {
|
||||
keyword,
|
||||
pageNo:'1',
|
||||
pageSize:'50',
|
||||
departId:'',
|
||||
}
|
||||
props.lecturer && getTeacherByNameOrUserNo(obj).then((res) => {
|
||||
if(res.data.status == 200){
|
||||
loading.value = false
|
||||
options.value = res.data.result.list.map((item) => {
|
||||
return {
|
||||
value: item.realName+'/'+item.userNo,
|
||||
label: item.realName+'('+item.userNo+')'+item.orgName,
|
||||
system: item.realName+'('+item.userNo+')'+item.tSystemName,
|
||||
level: item.realName+'('+item.userNo+')'+item.sLevelName,
|
||||
key: item.id,
|
||||
orgName: item.orgName,
|
||||
orgId: item.departId,
|
||||
tSystemName:item.tSystemName,
|
||||
sLevelName:item.sLevelName,
|
||||
payrollPlaceCode: item.payrollPlaceCode,
|
||||
payrollPlaceName:item.payrollPlaceName,
|
||||
avatar: item.avatar,
|
||||
gender: item.gender
|
||||
}
|
||||
})
|
||||
}else{
|
||||
loading.value = false
|
||||
}
|
||||
}).catch(()=>{
|
||||
loading.value = false
|
||||
})
|
||||
const params = {
|
||||
pageNo: 1,
|
||||
pageSize: 50,
|
||||
name: keyword,
|
||||
status: 1,
|
||||
}
|
||||
!props.lecturer && getTeacherList(params).then(res=>{
|
||||
console.log(res,'ressss')
|
||||
if(res.data.code == 200){
|
||||
loading.value = false
|
||||
options.value = res.data.data.records.map((item) => {
|
||||
return {
|
||||
value: item.name+'/'+item.userNo,
|
||||
label: item.name+'('+item.userNo+')'+item.tsystemName,
|
||||
system: item.name+'('+item.userNo+')'+item.tsystemName,
|
||||
level: item.name+'('+item.userNo+')'+item.sLevelName,
|
||||
key: item.id,
|
||||
orgName: item.orgName,
|
||||
orgId: item.orgId,
|
||||
tSystemName:item.tsystemName,
|
||||
sLevelName:item.sLevelName,
|
||||
payrollPlaceCode: item.salaryId,
|
||||
payrollPlaceName:item.salaryName,
|
||||
tlevelName: item.tlevelName, //讲师级别
|
||||
tlevelId: item.tlevelId, //讲师级别id
|
||||
// salaryName: item.salaryName, //发薪地
|
||||
// salaryId: item.salaryId,
|
||||
levelPay: item.levelPay
|
||||
}
|
||||
})
|
||||
}
|
||||
}).catch(()=>{
|
||||
loading.value = false
|
||||
})
|
||||
};
|
||||
const debounceObject = debounce(searchMember, 1500);
|
||||
const filterOption = (input, option) => {
|
||||
console.log(input,option,'xixixixi')
|
||||
};
|
||||
|
||||
const stuTreeSelectKeys = ref([]);
|
||||
const stuTreeExpandedKeys = ref([]);
|
||||
const teacherById = ref(null)
|
||||
const { data: treeData, loading: orgLoading } = useRequest(
|
||||
ORG_LIST,
|
||||
{ keyword: "" },
|
||||
);
|
||||
function onLoadData(treeNode) {
|
||||
teacherById.value = treeNode.id
|
||||
const promises = [];
|
||||
const childDatas = []
|
||||
promises.push(
|
||||
getTeacherByDepartId({organizationId:teacherById.value}).then((res) => {
|
||||
if(res.data.code == 200){
|
||||
res.data.data.list.map(item=>{
|
||||
return (
|
||||
item.isLeaf = true,
|
||||
item.name = item.realName + '/' + item.userNo,
|
||||
item.slots = {icon:'smile'}
|
||||
)
|
||||
})
|
||||
childDatas.unshift(...res.data.data.list)
|
||||
}
|
||||
}).catch((err)=>{
|
||||
console.log(err,'err')
|
||||
})
|
||||
);
|
||||
promises.push(
|
||||
request(ORG_CHILD_LIST, { keyword: "", orgId: treeNode.id }).then((r) => {
|
||||
// treeNode.dataRef.treeChildList = r.data;
|
||||
childDatas.push(...r.data)
|
||||
treeData.value = [...treeData.value];
|
||||
})
|
||||
);
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
treeNode.dataRef.treeChildList = childDatas;
|
||||
treeData.value = [...treeData.value];
|
||||
});
|
||||
}
|
||||
function stuStuOrgSelect(e, {selected: bool, selectedNodes, node, event}) {
|
||||
console.log(selectedNodes)
|
||||
teacherName.value = ''
|
||||
orgName.value = ''
|
||||
orgId.value = ''
|
||||
systemName.value = null
|
||||
levelName.value = ''
|
||||
teacherId.value = ''
|
||||
payrollPlaceCode.value = ''
|
||||
payrollPlaceName.value = ''
|
||||
if(selectedNodes[0].isLeaf){
|
||||
teacherName.value = selectedNodes[0].name
|
||||
orgName.value = selectedNodes[0].orgName
|
||||
orgId.value = selectedNodes[0].departId
|
||||
// systemName.value = selectedNodes[0].systemName
|
||||
levelName.value = selectedNodes[0].levelName
|
||||
teacherId.value = selectedNodes[0].id
|
||||
// emit('update:value',selectedNodes[0].realName)
|
||||
payrollPlaceCode.value = selectedNodes[0].payrollPlaceCode
|
||||
payrollPlaceName.value = selectedNodes[0].payrollPlaceName
|
||||
}
|
||||
}
|
||||
watch(()=>visible.value,(val)=>{
|
||||
if(val){
|
||||
stuTreeSelectKeys.value = []
|
||||
stuTreeExpandedKeys.value = []
|
||||
teacherName.value = ''
|
||||
orgName.value = ''
|
||||
orgId.value = ''
|
||||
systemName.value = null
|
||||
levelName.value = ''
|
||||
neworgName.value=''
|
||||
selectName.value = null
|
||||
// selectData.value = ''
|
||||
teacherId.value = ''
|
||||
loadingChange.value = false
|
||||
// teacherId.value = '1012311820121276416'
|
||||
// changeneworg()
|
||||
payrollPlaceCode.value = ''
|
||||
payrollPlaceName.value = ''
|
||||
}
|
||||
})
|
||||
const notChange = () => {
|
||||
visible.value = false
|
||||
teacherName.value = ''
|
||||
orgName.value = ''
|
||||
orgId.value = ''
|
||||
systemName.value = null
|
||||
levelName.value = ''
|
||||
neworgName.value=''
|
||||
teacherId.value = ''
|
||||
loadingChange.value = false
|
||||
payrollPlaceCode.value = ''
|
||||
payrollPlaceName.value = ''
|
||||
}
|
||||
const loadingChange = ref(false)
|
||||
watch(()=>teacherId.value,(val)=>{
|
||||
if(val){
|
||||
loadingChange.value = true
|
||||
getSystemInfoByUserId(teacherId.value).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
systemName.value = {
|
||||
systemId:res.data.data?.id,
|
||||
systemName:res.data.data?.systemName,
|
||||
systemCode:res.data.data?.systemCode,
|
||||
levelVoList: res.data.data?.levelVoList?.map(item=>{
|
||||
return (
|
||||
item.label = item.levelName,
|
||||
item.value = item.id,
|
||||
item
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
loadingChange.value = false
|
||||
emit('update:system',systemName.value)
|
||||
}).catch(err=>{
|
||||
message.error('讲师体系获取失败,请重新选择')
|
||||
loadingChange.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
const changeOut = () => {
|
||||
if(!teacherName.value){
|
||||
message.error('请选择讲师')
|
||||
return
|
||||
}
|
||||
const neworgName = ref('')
|
||||
// const changeneworg= ()=>{
|
||||
// if( orgName !==null ){
|
||||
// neworgName=orgName.split('/')
|
||||
|
||||
// neworgName= neworgName[neworgName.length-1]
|
||||
// }
|
||||
selectData.value = teacherName.value
|
||||
emit('update:value',teacherName.value)
|
||||
emit('update:lable',orgName.value)
|
||||
emit('update:orgId',orgId.value)
|
||||
emit('update:system',systemName.value)
|
||||
emit('update:level',levelName.value)
|
||||
emit('update:newlable',neworgName.value)
|
||||
emit('update:id',teacherId.value)
|
||||
emit('update:payrollPlaceCode',payrollPlaceCode.value)
|
||||
emit('update:payrollPlaceName',payrollPlaceName.value)
|
||||
notChange()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pover{
|
||||
.search{
|
||||
margin-top: 10px;
|
||||
}
|
||||
.tree{
|
||||
margin-top: 5px;
|
||||
border: 1px solid rgba(215, 215, 215, 1);
|
||||
}
|
||||
.btn{
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
.btn0{
|
||||
width: 70px;
|
||||
height: 25px;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
line-height: 25px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn1{
|
||||
margin-right: 10px;
|
||||
background-color: rgba(170, 170, 170, 1);
|
||||
}
|
||||
.btn2{
|
||||
background-color: rgba(50, 107, 250, 1);
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
251
src/components/project/UploadDragger.vue
Normal file
251
src/components/project/UploadDragger.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<a-upload-dragger :data="{ ...params }" :multiple="false" :accept="accept" :action="uploadUrl" :maxCount="maxCount"
|
||||
@change="handleUploadChange" v-model:file-list="fileList" style="width:50%;">
|
||||
<p class="ant-upload-drag-icon">
|
||||
<UploadOutlined />
|
||||
</p>
|
||||
<p class="ant-upload-text">将文件拖到此处,或点击上传</p>
|
||||
<template #itemRender="{ file }">
|
||||
<div class="loadstate">
|
||||
<div class="loadborder">
|
||||
<div class="content">
|
||||
<div class="timebox">
|
||||
<div class="timetop">
|
||||
<div class="tit">{{ file.name }}</div>
|
||||
<div class="stateloading">{{
|
||||
{
|
||||
done: "上传成功",
|
||||
uploading: "正在上传",
|
||||
error: "上传失败",
|
||||
removed: "正在上传",
|
||||
}[file.status]
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<a-progress :percent="file.percent" />
|
||||
</div>
|
||||
<div class="curloading">
|
||||
<!-- <div class="cur">100%</div> -->
|
||||
<div class="cancel" style="margin-left: 20px; cursor: pointer" @click="removeUpload">
|
||||
删除
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-upload-dragger>
|
||||
</template>
|
||||
<script setup>
|
||||
import { UploadOutlined } from '@ant-design/icons-vue'
|
||||
import { defineProps, ref, defineExpose,watch,onMounted } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
const props = defineProps({
|
||||
uploadUrl: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
maxCount: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
accept: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
loadTrue: {
|
||||
type:String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
onMounted(() => {
|
||||
if(props.loadTrue){
|
||||
fileList.value = [{
|
||||
name:props.loadTrue,
|
||||
status: 'done',
|
||||
percent: 100,
|
||||
}]
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['update:value', 'change'])
|
||||
const fileList = ref([]);
|
||||
const handleUploadChange = ({ file, fileList }) => {
|
||||
console.log(file, fileList, 'file');
|
||||
var FileExt = file.name.replace(/.+\./, "");
|
||||
if (props.accept && props.accept.split(',').indexOf('.' + FileExt.toLowerCase()) === -1) {
|
||||
fileList.value = [];
|
||||
return message.error("请上传正确的文件格式");
|
||||
}
|
||||
if(props.size && file.size > props.size){
|
||||
removeUpload()
|
||||
message.destroy();
|
||||
message.error("文件大小超过5MB!");
|
||||
return
|
||||
}
|
||||
emit('update:value', fileList)
|
||||
emit('change', fileList)
|
||||
}
|
||||
const removeUpload = () => {
|
||||
fileList.value = [];
|
||||
emit('removeList', false)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
fileList,
|
||||
removeUpload
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.loadstate {
|
||||
width: 500px;
|
||||
margin-bottom: 26px;
|
||||
|
||||
.loadborder {
|
||||
width: 396px;
|
||||
height: 70px;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #eaeaea;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
margin-left: 20px;
|
||||
position: relative;
|
||||
|
||||
.defeat {
|
||||
width: 262px;
|
||||
padding: 10px 20px;
|
||||
position: absolute;
|
||||
left: 46px;
|
||||
top: 42px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: 32px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #387df7;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
.detext {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
}
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 30px;
|
||||
height: 34px;
|
||||
// background-image: url(@/assets/images/basicinfo/exl.png);
|
||||
}
|
||||
|
||||
.timebox {
|
||||
margin-left: 15px;
|
||||
margin-top: -5px;
|
||||
|
||||
.timetop {
|
||||
display: flex;
|
||||
width: 262px;
|
||||
justify-content: space-between;
|
||||
|
||||
.tit {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
width: 200px;
|
||||
height: 21px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.stateloading {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
}
|
||||
|
||||
.statedefeat {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #ff7474;
|
||||
}
|
||||
|
||||
.statesucce {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #35ae69;
|
||||
}
|
||||
}
|
||||
|
||||
.prog {
|
||||
width: 262px;
|
||||
height: 5px;
|
||||
background: #eaf1fe;
|
||||
border-radius: 4px;
|
||||
|
||||
.inprogloading {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #4ea6ff;
|
||||
}
|
||||
|
||||
//下载失败条
|
||||
.inprogdefeat {
|
||||
width: 55%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #ff7474;
|
||||
}
|
||||
|
||||
//下载成功条
|
||||
.inprogsucce {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
|
||||
background: #57c887;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.curloading {
|
||||
margin-left: 15px;
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
|
||||
.cur {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #387df7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
451
src/components/project/lockLecturer.vue
Normal file
451
src/components/project/lockLecturer.vue
Normal file
@@ -0,0 +1,451 @@
|
||||
<template>
|
||||
<div @click="openDrawer">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<a-drawer
|
||||
:visible="visible"
|
||||
class="drawerStyle impotergroupleader"
|
||||
placement="right"
|
||||
width="80%"
|
||||
>
|
||||
<div class="drawerMain">
|
||||
<div class="header">
|
||||
<div class="headerTitle">{{ title }}</div>
|
||||
<img
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="../../assets/images/basicinfo/close.png"
|
||||
@click="closeDrawer"
|
||||
/>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="title">
|
||||
<div class="line"></div>
|
||||
<div class="text">培训发生组织基本信息</div>
|
||||
</div>
|
||||
<div class="desc">
|
||||
<a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item :labelStyle="{ width: '165px' }" label="培训发生组织编号">{{formData?.affiliationCode||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item :labelStyle="{ width: '165px' }" label="培训发生组名称">{{formData?.affiliationName||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="是否为根节点">{{formData?.isParent==1?'否':'是'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="组织担当">{{formData?.act||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="formData?.isParent==1" label="一级审批人">{{formData?.one||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="formData?.isParent==1" label="二级审批人">{{formData?.two||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="formData?.isParent==1" label="三级审批人">{{formData?.three||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">
|
||||
{{{1:'待提交', 2:'审核中',3: '已完成',4: '审核失败',5:'待审核'}[formData?.status]}}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
<a-tabs @change="change" v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="1" tab="管理组织列表">
|
||||
<div style="margin-bottom: 30px">
|
||||
<a-table :columns="columns" :data-source="formData?.tableData" :pagination="false"/>
|
||||
</div>
|
||||
<div style="margin-bottom: 100px">
|
||||
<!-- <a-descriptions :column="2" bordered>
|
||||
<a-descriptions-item label="培训发生组织编号">{{formData?.affiliationCode||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="培训发生组名称">{{formData?.affiliationName||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="是否为根节点">{{formData?.isParent==1?'否':'是'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="组织担当">{{formData?.act||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="一级审批人">{{formData?.one||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="二级审批人">{{formData?.two||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="三级审批人">{{formData?.three||'-'}}</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">
|
||||
{{['-','待审核', '审核中', '已完成', '审核失败'][formData?.type]}}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions> -->
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="审批记录" force-render>
|
||||
<div style="margin-bottom: 20px">
|
||||
<a-table :columns="columnsTwo" :loading="formData?.loadingTwo" :data-source="formData?.tableDataTwo" :pagination="pagination">
|
||||
<template #action="{ record }">
|
||||
<div class="action">
|
||||
<div style="color: #1890ff;cursor: pointer;" class="btn" @click="lookList(record)">查看</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
<div style="margin-bottom: 100px">
|
||||
<a-table v-if="threeList" :columns="columnsThree" :loading="formData?.loadingThree" :data-source="formData?.tableDataThree" :pagination="false"/>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn" v-if="formData?.status==1||formData?.status==4">
|
||||
<!-- <button class="btn2" @click="closeDrawer">取消</button>
|
||||
<button class="btn2" @click="closeDrawer">确定</button> -->
|
||||
<button class="btn2" @click="confirm">撤销编辑内容</button>
|
||||
</div>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import {defineEmits, defineProps, ref,watch,reactive,computed} from "vue";
|
||||
import dialog from '@/utils/dialog'
|
||||
import * as api from '@/api/Lecturer'
|
||||
import { message } from 'ant-design-vue';
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
defalut: ""
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const emit = defineEmits({});
|
||||
const columns = [
|
||||
{
|
||||
title: '组织的名称',
|
||||
dataIndex: 'orgName',
|
||||
key: 'orgName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'updateStatus',
|
||||
key: 'updateStatus',
|
||||
align: 'center',
|
||||
customRender: ({text})=>{
|
||||
switch (text) {
|
||||
case 0:
|
||||
return <span>未更改</span>;
|
||||
case 1:
|
||||
return <span>新增</span>;
|
||||
case 2:
|
||||
return <span>移除</span>;
|
||||
case 3:
|
||||
return <span>编辑</span>;
|
||||
default:
|
||||
return <span>-</span>;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
align: 'center',
|
||||
customRender: ({text})=>{
|
||||
switch (text) {
|
||||
case 1:
|
||||
return <span>待提交</span>;
|
||||
case 2:
|
||||
return <span>审核中</span>;
|
||||
case 3:
|
||||
return <span>已完成</span>;
|
||||
case 4:
|
||||
return <span>审核失败</span>;
|
||||
case 5:
|
||||
return <span>待审核</span>;
|
||||
default:
|
||||
return <span>-</span>;
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
const formData = ref({})
|
||||
const columnsThree = [
|
||||
{
|
||||
title: '层级审批人',
|
||||
dataIndex: 'employeeNames',
|
||||
key: 'employeeNames',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'approvalStatus',
|
||||
key: 'approvalStatus',
|
||||
align: 'center',
|
||||
customRender: ({text})=>{
|
||||
switch (text) {
|
||||
case -1:
|
||||
return <span>未处理</span>;
|
||||
case 3:
|
||||
return <span>通过</span>;
|
||||
case 4:
|
||||
return <span>拒绝</span>;
|
||||
default:
|
||||
return <span>-</span>;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '审批人',
|
||||
dataIndex: 'employeeName',
|
||||
key: 'employeeName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '审批时间',
|
||||
dataIndex: 'approvalTime',
|
||||
key: 'approvalTime',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '审批建议',
|
||||
dataIndex: 'approvalMsg',
|
||||
key: 'approvalMsg',
|
||||
align: 'center',
|
||||
ellipsis: true,
|
||||
width: 200,
|
||||
customRender: ({text})=>{
|
||||
return <span>{text||'-'}</span>
|
||||
}
|
||||
},
|
||||
]
|
||||
const columnsTwo = ref([
|
||||
{
|
||||
title: '审批提交时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '审批状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
align: 'center',
|
||||
customRender: ({text})=>{
|
||||
switch (text) {
|
||||
case 0:
|
||||
return <span>待提交</span>;
|
||||
case 1:
|
||||
return <span>待审核</span>;
|
||||
case 2:
|
||||
return <span>审核中</span>;
|
||||
case 3:
|
||||
return <span>审核通过</span>;
|
||||
case 4:
|
||||
return <span>拒绝</span>;
|
||||
case 5:
|
||||
return <span>撤销中</span>;
|
||||
case 6:
|
||||
return <span>已撤销</span>;
|
||||
default:
|
||||
return <span>-</span>;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '审批人',
|
||||
dataIndex: 'employeeName',
|
||||
key: 'employeeName',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'address',
|
||||
key:'age',
|
||||
align: 'center',
|
||||
slots: { customRender: "action" },
|
||||
}
|
||||
])
|
||||
const approvalData = ref(null)
|
||||
const threeList = ref(false)
|
||||
const lookList = (record) => {
|
||||
console.log(record,'resssssss')
|
||||
if(!threeList.value||record.approvalId!=approvalData.value){
|
||||
threeList.value = true
|
||||
approvalData.value = record.approvalId
|
||||
formData.value.loadingThree = true
|
||||
api.getApprovalResultByApprovalIdList(record.approvalId).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
formData.value.tableDataThree = res.data.data
|
||||
}
|
||||
formData.value.loadingThree = false
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
formData.value.loadingThree = false
|
||||
message.error(err.data.msg)
|
||||
})
|
||||
}else{
|
||||
threeList.value = false
|
||||
approvalData.value = null
|
||||
}
|
||||
}
|
||||
const visible = ref(false);
|
||||
watch(visible, (val)=>{
|
||||
if(val){
|
||||
threeList.value = false
|
||||
activeKey.value = '1'
|
||||
api.getAffiliationById(props.id).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
formData.value = res.data.data
|
||||
formData.value.act = filterList(formData.value.affiliationUserList,0)
|
||||
formData.value.one = filterList(formData.value.affiliationUserList,1)
|
||||
formData.value.two = filterList(formData.value.affiliationUserList,2)
|
||||
formData.value.three = filterList(formData.value.affiliationUserList,3)
|
||||
formData.value.tableData = res.data.data.affiliationOrgList
|
||||
}
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
})
|
||||
// getTwoData()
|
||||
}
|
||||
})
|
||||
const getTwoData = () => {
|
||||
formData.value.loadingTwo = true
|
||||
api.getByBusinessIdList(params).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
formData.value.tableDataTwo = res.data.data.records
|
||||
params.total = res.data.data.total
|
||||
}
|
||||
formData.value.loadingTwo = false
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
formData.value.loadingTwo = false
|
||||
})
|
||||
}
|
||||
const params = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
businessType: 2,
|
||||
businessId: props.id
|
||||
})
|
||||
const pagination = computed(() => ({
|
||||
total: params.total,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper:true,
|
||||
current: params.pageNo,
|
||||
pageSize: params.pageSize,
|
||||
onChange: paginationChange,
|
||||
}));
|
||||
const paginationChange = (e,pageSize) => {
|
||||
params.pageNo = e;
|
||||
params.pageSize = pageSize
|
||||
getTwoData()
|
||||
};
|
||||
const filterList = (val,index) => {
|
||||
return val?.filter(item=>item.type==index).map(item=>item.userName).join(',')
|
||||
}
|
||||
const closeDrawer = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
const confirm = () => {
|
||||
dialog({
|
||||
content: "您确定撤销编辑吗?撤销后将恢复到'已完成”前状态,且无法恢复。请谨慎操作。",
|
||||
ok: () => {
|
||||
api.recovery(props.id).then(res=>{
|
||||
if(res.data.code == 200){
|
||||
message.success("撤销成功")
|
||||
visible.value = false;
|
||||
emit('searchList',true)
|
||||
}
|
||||
}).catch(err=>{
|
||||
message.destroy()
|
||||
message.error(err.data.msg)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const activeKey = ref("1");
|
||||
const change = (val)=>{
|
||||
// console.log(val,'val')
|
||||
if(val==2){
|
||||
getTwoData()
|
||||
}
|
||||
}
|
||||
function openDrawer() {
|
||||
visible.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.impotergroupleader > .ant-drawer-content-wrapper {
|
||||
min-width: 800px !important;
|
||||
width: 800px !important;
|
||||
}
|
||||
.impotergroupleader {
|
||||
.drawerMain {
|
||||
min-width: 600px;
|
||||
margin:0;
|
||||
padding: 0px 32px 0px 32px;
|
||||
overflow-x: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
height: 73px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.headerTitle {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
line-height: 25px;
|
||||
// margin-left: 24px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.content{
|
||||
padding-right: 20px;
|
||||
.title{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
.line{
|
||||
width: 5px;
|
||||
height: 15px;
|
||||
background: #4ea6ff;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.text{
|
||||
|
||||
}
|
||||
}
|
||||
.desc{
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.btnn {
|
||||
height: 72px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0px 1px 35px 0px rgba(118, 136, 166, 0.16);
|
||||
|
||||
.btn1 {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
border: 1px solid #4ea6ff;
|
||||
border-radius: 8px;
|
||||
color: #4ea6ff;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn2 {
|
||||
cursor: pointer;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background: #4ea6ff;
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
margin-left: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user