firset submit

This commit is contained in:
NiSen
2023-06-13 13:31:01 +08:00
parent d1271a8c74
commit 593158ebf3
471 changed files with 187636 additions and 37 deletions

View File

@@ -0,0 +1,924 @@
<template>
<a-drawer
:visible="FSvisible"
class="drawerStyle RouterFaceStu"
placement="right"
width="1200"
@after-visible-change="afterVisibleChange"
>
<div class="drawerMain">
<div class="header">
<div class="headerTitle">面授{{ datasource?.name }}</div>
<img
style="width: 29px; height: 29px; cursor: pointer"
src="../../../assets/images/basicinfo/close.png"
@click="closeDrawer"
/>
</div>
<div class="main">
<a-spin v-if="loading" :spinning="loading"/>
<div v-else class="titl">
<div
style="width: 100%;height:220px;display: flex;flex-wrap: nowrap;overflow-x: scroll;">
<div v-for="(item,n) in data" :key="n" style="cursor: pointer;">
<div
@click="ChoiceCourse(n)"
style="width: 360px;height:180px;margin-right: 32px;display: flex;flex-direction: column;padding: 16px;"
:style="{background:n===coursePlanIndex?'rgb(247, 251, 253)':'rgb(250, 250, 250)'}">
<div style="font-size: 16px;">{{ data.length - n }}次开课</div>
<div style="font-size: 14px;margin-top: 12px;">{{ item.name }}</div>
<div style="font-size: 14px;">
<img src="../../../assets/images/courseManage/time.png" style="width:16px;height:16px;">
{{ item.beginTime }} ~ {{ item.endTime }}
</div>
<div style="font-size: 14px;margin-top: 6px;margin-bottom: 6px;">
<img src="../../../assets/images/courseManage/position.png" style="width:16px;height:16px;">
{{ item.address }}
</div>
<div style="font-size: 14px;">
<img src="../../../assets/images/courseManage/persion.png" style="width:16px;height:16px;">
{{ item.teacher }}
</div>
</div>
</div>
</div>
</div>
<div class="search" v-if="data?.length">
<div class="leftchoose">
<div class="namecon" style="margin-right: 30px">
<div class="name">姓名</div>
<a-input
v-model:value="params.studentName"
style="width: 200px; height: 40px; border-radius: 8px"
placeholder="请输入姓名"
/>
</div>
<div class="namecon">
<div class="name">签到状态</div>
<div class="select">
<a-select
v-model:value="params.finishStatus"
style="width: 200px"
placeholder="请选择"
:options="signOptions"
allowClear
></a-select>
</div>
</div>
</div>
<div class="btns">
<div
class="btn btn1"
style="margin-right: 20px"
@click="searchTaskList"
>
<div class="img1"></div>
<div class="wz">搜索</div>
</div>
<div class="btn btn1" @click="resetStudentPage">
<div class="img2"></div>
<div class="wz">重置</div>
</div>
</div>
</div>
<div class="btnss" style="margin-top: 20px" v-if="checkPer(permissions,createId) && data?.length">
<div
class="btn btn1"
style="margin-right: 20px"
@click="qrcodeVisibleSign()"
>
<div class="wz">签到二维码</div>
</div>
<div
class="btn btn1"
style="margin-right: 20px"
v-if="data[coursePlanIndex]?.assessmentId"
@click="qrcodeAssement()"
>
<div class="wz">评估二维码</div>
</div>
<div
class="btn btn1"
style="margin-right: 20px"
@click="qrcodeVisible()"
>
<div class="wz">开课二维码</div>
</div>
<CommonStudent
:type="3"
:isGroup="true"
:id="data[coursePlanIndex]?.id"
:infoId="infoId"
:infoType="type"
@finash="submitCall"
>
<a-button class="cus-btn" style="background: #4ea6ff; color: #fff">
<template #icon><img style="margin-right: 10px" src="../../../assets/images/courseManage/add0.png"/>
</template>
添加学员
</a-button>
</CommonStudent>
<CommonImport @change="change" title="导入学员" :template-url="stuTemplateUrl" :data="{ targetId: offcoursePlanId, type:3 }" :url="`/admin/student/importStudent`" name="uploadFile">
<div class="btn btn1" style="margin-right: 20px;margin-left: 20px">
<div class="img1"></div>
<div class="wz">导入学员</div>
</div>
</CommonImport>
<div class="btn btn1" @click="batchSign" style="margin-right: 20px">
<div class="wz">批量签到</div>
</div>
<div class="btn btn1" @click="exportTaskStu" style="margin-right: 20px">
<div class="img2"></div>
<div class="wz">导出签到数据</div>
</div>
<div class="btn btn1" @click="exportAssessment" v-if="data[coursePlanIndex]?.assessmentId">
<div class="img2"></div>
<div class="wz">导出评估数据</div>
</div>
</div>
<div class="tableBox" style="margin-top: 30px">
<BaseTable ref="tableRef" :url="STUDENT_LIST" v-model:params="params" :columns="columns" :init="false"
v-model:selectedRows="courseSelectRows"
type="checkbox"/>
</div>
</div>
<div class="btnn">
<button class="btn1" @click="closeDrawer">取消</button>
<button class="btn2" @click="closeDrawer">确定</button>
</div>
</div>
</a-drawer>
</template>
<script setup>
import {computed, defineEmits, ref, watch} from "vue";
import * as api from "@/api/index1";
import BaseTable from "@/components/common/BaseTable";
import {message} from "ant-design-vue";
import {checkPer} from "@/utils/utils";
import {COURSE_PLAN_LIST, STUDENT_LIST} from "@/api/apis";
import dialog from "@/utils/dialog";
import qrCode from "@/utils/qrCode";
import {useRequest} from "@/api/request";
import CommonImport from "@/components/common/CommonImport";
import CommonStudent from "@/components/student/CommonStudent";
import dayjs from "dayjs";
import {delStudentList} from "@/api/index1";
const coursePlanIndex = ref(0);
const tableRef = ref();
const stuTemplateUrl = ref(process.env.VUE_APP_FILE_PATH + process.env.VUE_APP_UP_LOAD_STUDENT_TEMPLATE);
const emit = defineEmits([]);
const signOptions = ref([
{
id: 1,
value: 1,
label: "签到",
},
{
id: 2,
value: 0,
label: "请假",
},
]);
const props = defineProps({
type: {
type: Number,
default: 1,
},
createId: {
type: Number,
default: null,
},
permissions: {
type: String,
default: null,
},
FSvisible: {
type: Boolean,
default: false,
},
datasource: {
type: Object,
default: function() {
return {};
},
},
});
const params = ref({ pid: 0, type: 3 });
const courseSelectRows = ref([]);
const infoId = computed(() => props.type === 1 ? props.datasource.projectId : props.datasource.routerId);
const taskId = computed(() => props.type === 1 ? props.datasource.projectTaskId : props.datasource.routerTaskId);
const offcoursePlanId = computed(() => data.value[coursePlanIndex.value]?.id || "");
const inAttendanceTime = computed(() => dayjs(data.value[coursePlanIndex.value]?.endTime).isAfter(dayjs()));
const planParams = computed(() => ({
type: props.type,
offcourseId: props.datasource?.courseId,
taskId: props.datasource?.id
}));
const columns = ref([
{
title: "工号",
dataIndex: "studentUserNo",
key: "studentUserNo",
width: 120,
align: "center",
ellipsis: true,
className: "h",
customRender: (text) => <div class="racona"><span> {text.record.studentUserNo || "-"} </span></div>
},
{
title: "姓名",
dataIndex: "studentName",
key: "studentName",
width: 50,
align: "left",
className: "classify",
scopedSlots: { customRender: "action" },
customRender: (text) => <div class="racona"><span> {text.record.studentName || "-"} </span></div>
},
{
title: "部门",
dataIndex: "studentDepartName",
key: "studentDepartName",
width: 60,
ellipsis: true,
align: "center",
className: "h",
customRender: (text) => <div class="racona"><span> {text.record.studentDepartName || "-"} </span></div>
},
{
title: "岗位",
dataIndex: "studentJobName",
key: "studentJobName",
width: 50,
align: "center",
ellipsis: true,
className: "h",
customRender: (text) => <div class="racona"><span> {text.record.studentJobName || "-"}</span></div>
},
{
title: "签到时间",
dataIndex: "signTime",
key: "signTime",
width: 110,
align: "center",
ellipsis: true,
className: "h",
customRender: (text) => <div class="racona"><span>{text.record.signTime || "-"}</span></div>
},
{
title: "考勤",
dataIndex: "signStatus",
key: "signStatus",
width: 110,
align: "center",
ellipsis: true,
className: "h",
customRender: (text) =>
<span>{text.record.signStatus ? "签到" : text.record.leaveStatus ? "请假" : inAttendanceTime.value ? "-" : "缺勤"}</span>
},
{
title: "签到状态",
dataIndex: "signStatus",
key: "signStatus",
width: 110,
align: "center",
ellipsis: true,
className: "h",
customRender: (text) =>
<span>{(text.record.signStatus || text.record.leaveStatus) ? "正常" : inAttendanceTime.value ? "-" : "异常"}</span>
},
{
title: "考勤情况",
ellipsis: true,
className: "h",
dataIndex: "opacation",
key: "opacation",
width: 130,
align: "center",
customRender: (text) =>
<div class="opa">
<a-radio checked={text.record.signStatus} onClick={() => stuSign(text)}>签到</a-radio>
<a-radio checked={text.record.leaveStatus} onClick={() => stuSign(text)}>请假</a-radio>
</div>
},
{
title: "操作",
ellipsis: true,
className: "h",
dataIndex: "opacation",
key: "opacation",
width: 130,
align: "center",
customRender: (text) =>
<div class="opa">
<a className="opa" style={{color: '#666'}} onClick={()=>removeStu(text.record.id)}>删除</a>
</div>
},
]);
const { data = [], loading, fetchData } = useRequest(COURSE_PLAN_LIST, planParams, false);
watch(() => data.value, () => {
coursePlanIndex.value = 0
params.value.pid = data.value[coursePlanIndex.value]?.id || 0;
tableRef.value.fetch();
});
// 开课签到二维码名字
const openCourseName = ref("");
const ChoiceCourse = (n) => {
openCourseName.value = data.value[n].name;
coursePlanIndex.value = n;
params.value.pid = data.value[n].id;
tableRef.value.fetch();
};
const removeStu=(id)=> dialog({
content: "确定删除该学员吗?",
ok: () => delStudentList({ ids: [id] }).then(() => fetchData())
})
const closeDrawer = () => emit("update:FSvisible", false);
//批量签到
const batchSign = () => {
if (!courseSelectRows.value.length) {
return message.warn("请选择要签到的学员");
}
dialog({
content: "确定批量签到吗?",
ok: async () => {
message.success("批量签到成功");
tableRef.value.toLoading();
await api.attendanceSign({
courseId: offcoursePlanId.value,
ids: courseSelectRows.value?.map(t => t.studentId),
taskId: taskId.value,
taskType: props.datasource.type,
type: 3
});
tableRef.value.fetch();
},
});
};
function stuSign(text) {
text.record.signStatus = !text.record.signStatus;
text.record.leaveStatus = !text.record.signStatus;
text.record.signStatus && (text.record.signTime = dayjs().format("YYYY-MM-DD HH:mm:ss"));
text.record.signStatus || (text.record.signTime = "");
text.record.signStatus && api.attendanceSign({
courseId: offcoursePlanId.value,
ids: [text.record.studentId],
studentName: text.record.studentName,
taskId: taskId.value,
taskType: props.datasource.type,
type: 3
});
text.record.leaveStatus && api.attendanceLeave({
courseId: offcoursePlanId.value,
ids: [text.record.studentId],
studentName: text.record.studentName,
taskId: taskId.value,
taskType: props.datasource.type,
type: 3
});
}
//搜索学员
const searchTaskList = () => tableRef.value.fetch();
//添加学员
function submitCall(flag) {
tableRef.value.toLoading();
flag && tableRef.value.fetch();
}
// 导出数据
function exportTaskStu() {
window.open(`${process.env.VUE_APP_BASE_API}/admin/student/exportTaskStudent?type=3&pid=${offcoursePlanId.value}&thirdType=2`);
}
const exportAssessment = () =>window.open(`${process.env.VUE_APP_BASE_API}/admin/assessment/manage/exportCoursePlanAssessmentMessage?chapterId=${props.type === 1 ? props.datasource.stageId : props.datasource.chapterId}&type=${props.type}&pid=${props.type === 1 ? props.datasource.projectId : props.datasource.routerId}&courseId=${data.value[coursePlanIndex.value].assessmentId}&taskId=${props.datasource.id}&taskType=${props.datasource.type}`);
function afterVisibleChange(bool) {
bool && fetchData()
}
function resetStudentPage() {
tableRef.value.reset({ pid: data.value[coursePlanIndex.value]?.id, type: 3 });
}
//二维码
const qrcodeVisible = () => {
qrCode({
title: "【开课】二维码",
name: openCourseName.value?openCourseName.value:data.value[0]?.name,
// url: `${location.protocol}//${location.host}${process.env.VUE_APP_BASE_API}/admin/student/studentSign?taskId=${props.datasource.id}&taskType=${props.datasource.type}&type=${props.type}`,
url: `${location.protocol}//${location.host}${process.env.VUE_APP_BASE_API}/stu/project/redirectDetail?courseId=${data.value[coursePlanIndex.value]?.id}`,
});
};
// 签到二维码
const qrcodeVisibleSign = () => {
qrCode({
title: "【签到】二维码",
name: openCourseName.value?openCourseName.value:data.value[0]?.name,
// url: `${location.protocol}//${location.host}${process.env.VUE_APP_BASE_API}/admin/student/studentSign?taskId=${props.datasource.id}&taskType=${props.datasource.type}&type=${props.type}`,
url: `${location.protocol}//${location.host}${process.env.VUE_APP_BASE_API}/admin/student/studentSign?taskId=${data.value[coursePlanIndex.value]?.id}&taskType=${2}&type=${3}`,
});
};
const qrcodeAssement = () =>{
qrCode({
title: "【评估】二维码",
name: data.value[coursePlanIndex.value]?.assessmentName,
url: `${location.protocol}//${location.host}/student-h5/investigatpage?id=${data.value[coursePlanIndex.value]?.id}&type=3&infoId=${data.value[coursePlanIndex.value]?.id}&courseId=${data.value[coursePlanIndex.value].assessmentId}&chapterOrStageId=0`,
});
}
const change = (e) => {
console.log(e)
if(e==="end"){
// 请求刷新数据
tableRef.value.fetch();
}
}
</script>
<style lang="scss">
.me {
.ant-modal-body {
padding: 0px;
}
}
.CopyModal {
.ant-modal {
width: 424px !important;
height: 258px !important;
.ant-modal-content {
width: 424px !important;
height: 258px !important;
.ant-modal-body {
width: 424px !important;
height: 258px !important;
padding: 0 !important;
.delete {
z-index: 999;
width: 424px;
height: 258px;
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: 68px;
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;
.icon {
width: 16px;
height: 16px;
margin-right: 10px;
background-image: url(@/assets/images/coursewareManage/QR.png);
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%;
}
}
.body {
width: 100%;
margin: 34px auto 56px auto;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
// background-color: red;
position: relative;
.back {
position: absolute;
top: 30px;
font-size: 12px;
font-weight: 400;
color: #666666;
}
}
.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;
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;
margin-right: 14px;
}
.btn2 {
background-color: #4ea6ff;
color: #ffffff;
}
}
}
}
}
}
}
}
.RouterFaceStu {
// // width: 80%;
// .ant-drawer-content-wrapper {
// // max-width: 1000px;
// .ant-drawer-header {
// display: none !important;
// }
// .ant-drawer-body {
// padding: 0;
// }
// }
.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;
.headerTitle {
font-size: 18px;
font-weight: 600;
color: #333333;
line-height: 25px;
// margin-left: 24px;
}
}
.main {
width: 100%;
height: 100%;
overflow: auto;
padding-right: 10px;
padding-bottom: 90px;
.titl {
display: flex;
.endtime {
font-size: 16px;
font-weight: 500;
color: #333333;
}
}
.search {
width: 100%;
display: flex;
flex-wrap: wrap;
margin-top: 20px;
justify-content: space-between;
.leftchoose {
display: flex;
margin-right: 20px;
.namecon {
display: flex;
flex-wrap: nowrap;
margin-bottom: 10px;
.name {
margin-top: 8px;
white-space: nowrap;
}
// .name {
// margin-top: 8px;
// color: rgba(0, 0, 0, 0.85);
// font-size: 14px;
// font-weight: 400;
// }
}
}
.btns {
display: flex;
flex-wrap: nowrap;
.btn {
cursor: pointer;
width: 100px;
height: 40px;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
.img1 {
width: 15px;
height: 17px;
background-image: url(../../../assets/images/courseManage/search0.png);
background-size: 100% 100%;
margin-right: 7px;
}
.img2 {
width: 16px;
height: 18px;
background-image: url(../../../assets/images/courseManage/reset0.png);
background-size: 100% 100%;
margin-right: 7px;
}
}
.btn1 {
background: #4ea6ff;
color: #ffffff;
}
.btn2 {
background: #ffffff;
color: #4ea6ff;
border: 1px solid #4ea6ff;
}
}
}
.btnss {
display: flex;
flex-wrap: nowrap;
.btn {
cursor: pointer;
width: 130px;
height: 40px;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
.img1 {
width: 19px;
height: 19px;
background-image: url(../../../assets/images/basicinfo/in.png);
background-size: 100% 100%;
margin-right: 7px;
}
.img2 {
width: 17px;
height: 16px;
background-image: url(../../../assets/images/coursewareManage/export1.png);
background-size: 100% 100%;
margin-right: 7px;
}
}
.btn1 {
background: #4ea6ff;
color: #ffffff;
}
.btn2 {
background: #ffffff;
margin-right: 20px;
color: #4ea6ff;
border: 1px solid #4ea6ff;
}
}
.line {
width: 100%;
height: 40px;
background-color: #e9f6fe;
display: flex;
justify-content: center;
align-items: center;
margin-top: 20px;
border: 1px solid #c3e6fc;
.inline {
width: 95%;
height: 100%;
display: flex;
justify-content: space-between;
// background-color: #bfa;
.left {
height: 100%;
display: flex;
align-items: center;
.img {
width: 14px;
height: 15px;
background-image: url(../../../assets/images/leveladd/gan.png);
background-size: 100% 100%;
}
.text {
color: #999ba3;
}
.text2 {
color: #4ea6ff;
margin-left: 5px;
margin-right: 5px;
}
.text3 {
color: #999ba3;
margin-left: 20px;
}
}
.right {
font-size: 14px;
font-weight: 400;
color: #387df7;
height: 100%;
display: flex;
align-items: center;
cursor: pointer;
}
}
}
.pad {
width: 96%;
height: 10px;
background-color: #fff;
position: absolute;
}
.tableBox {
// margin-bottom: 80px;
.classify {
// margin-left: 11px !important;
// padding-left: 9px !important;
padding-left: 0px !important;
}
.ant-checkbox-wrapper {
align-items: center;
margin-top: -2px;
}
.ant-table-selection-column {
padding: 0px !important;
// padding-left: 45px !important;
}
.ant-table-thead > tr > th {
background-color: rgba(239, 244, 252, 1);
}
th.h {
background-color: #eff4fc !important;
}
.ant-table-tbody
> tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
> td {
background: #f6f9fd;
}
.opa {
background-color: rgba(255, 255, 255, 0);
.ant-checkbox + span {
font-size: 14px;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
line-height: 22px;
margin-top: 5px;
}
}
}
// .tab {
// .ant-table-thead > tr > th {
// background-color: rgba(239, 244, 252, 1) !important;
// }
// th.h {
// background-color: #eff4fc !important;
// }
// .ant-table-tbody
// > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
// > td {
// background: #f6f9fd;
// }
// }
}
.btnn {
height: 72px;
width: 100%;
position: absolute;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
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;
}
}
}
// .botm {
// width: 100%;
// height: 100%;
// background-color: red;
// // flex-shrink: 1;
// }
}
</style>