From 6459f8bff3e568e65e6dc617f22c686cf5a8db44 Mon Sep 17 00:00:00 2001 From: zhouwx <1175765986@qq.com> Date: 星期一, 15 七月 2024 16:35:06 +0800 Subject: [PATCH] 组卷 --- src/views/onlineEducation/groupExams/components/examDialog.vue | 140 +++++++-- src/views/onlineEducation/classHourBatch/index.vue | 6 src/views/onlineEducation/offlineEducation/components/recordDialog.vue | 1 src/views/onlineEducation/groupExams/components/examChooseStudent.vue | 248 +++++++++++++++++ package.json | 1 src/views/onlineEducation/groupExams/components/student.vue | 184 +++++++++++++ src/views/onlineEducation/systemManage/company/index.vue | 9 src/views/onlineEducation/count/index.vue | 90 +++++- src/views/onlineEducation/groupExams/index.vue | 37 ++ src/router/index.js | 13 src/api/onlineEducation/exam.js | 82 ++-- src/views/onlineEducation/classHourBatch/components/classHourChange.vue | 16 12 files changed, 711 insertions(+), 116 deletions(-) diff --git a/package.json b/package.json index ad42e19..296e942 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "js-base64": "^3.7.5", "js-cookie": "3.0.1", "jsencrypt": "3.3.1", + "moment": "^2.30.1", "nprogress": "0.2.0", "p-limit": "^5.0.0", "pinia": "2.0.22", diff --git a/src/api/onlineEducation/exam.js b/src/api/onlineEducation/exam.js index 3292d01..2eddade 100644 --- a/src/api/onlineEducation/exam.js +++ b/src/api/onlineEducation/exam.js @@ -41,47 +41,47 @@ }) } -//批次与学员关系 -//批次下的学员列表(分页) -// export function getBatchStudent(param) { -// return request({ -// url: '/phase-student/list', -// method: 'get', -// params: param -// }) -// } -// // 校验学员是否已存在 -// export function checkStudentUnique(data) { -// return request({ -// url: '/phase-student/checkStudentUnique', -// method: 'post', -// data: data -// }) -// } -// // 批量新增学员 -// export function batchAddStudent(data) { -// return request({ -// url: '/phase-student/batchAdd', -// method: 'post', -// data: data -// }) -// } -// // 批量删除学员 -// export function batchDelStudent(data) { -// return request({ -// url: '/phase-student/batchDelete', -// method: 'delete', -// data: data -// }) -// } -// -// // 批量删除学员 -// export function delBatchStu(userId) { -// return request({ -// url: '/phase-student/' + userId, -// method: 'delete' -// }) -// } +//试卷与学员关系 +//试卷下的学员列表(分页) +export function getExamStudent(param) { + return request({ + url: '/paper-student/list', + method: 'get', + params: param + }) +} +// 校验学员是否已存在 +export function checkExamStudentUnique(data) { + return request({ + url: '/paper-student/checkStudentUnique', + method: 'post', + data: data + }) +} + // 批量新增学员 +export function examAddStudent(data) { + return request({ + url: '/paper-student/batchAdd', + method: 'post', + data: data + }) +} + // 批量删除学员 +export function examDelStudent(data) { + return request({ + url: '/paper-student/batchDelete', + method: 'delete', + data: data + }) +} + + // 删除学员 +export function delExamStu(userId) { + return request({ + url: '/paper-student/' + userId, + method: 'delete' + }) +} // // //企业课时变更记录列表(分页) // export function getCompanyPeriod(param) { diff --git a/src/router/index.js b/src/router/index.js index b5e29b4..0856c65 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -79,6 +79,19 @@ } ] }, + { + path: '/examStu', + component: Layout, + redirect: '/examStu', + children: [ + { + path: '/examStu', + component: () => import('@/views/onlineEducation/groupExams/components/student.vue'), + name: 'ExamStu', + meta: { title: '考试学员',icon: 'form', affix: true } + } + ] + }, // { // path: '', // component: Layout, diff --git a/src/views/onlineEducation/classHourBatch/components/classHourChange.vue b/src/views/onlineEducation/classHourBatch/components/classHourChange.vue index 51d6e63..8d2c5fe 100644 --- a/src/views/onlineEducation/classHourBatch/components/classHourChange.vue +++ b/src/views/onlineEducation/classHourBatch/components/classHourChange.vue @@ -9,8 +9,8 @@ <el-table v-loading="state.loading" :data="state.dataList" :border="true"> <el-table-column label="创建时间" prop="createTime" align="center" width="180" /> <el-table-column label="变动来源" prop="origin" align="center" /> - <el-table-column label="变动情况" prop="modifyPeriod" align="center" /> - <el-table-column label="变动后剩余(分)" prop="remainPeriod" align="center" /> + <el-table-column label="变动情况" prop="modifyPeriodMin" align="center" /> + <el-table-column label="变动后剩余" prop="remainPeriodMin" align="center" /> <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">--> <!-- <template #default="scope">--> <!-- <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>--> @@ -54,7 +54,8 @@ dataList: [], queryParams: { pageNum: 1, - pageSize: 10 + pageSize: 10, + companyId: null }, total: 0, title: '' @@ -63,13 +64,20 @@ const openDialog = async (value) => { state.title = '课时余量变动明细' dialogVisible.value = true; + state.queryParams.companyId = value await getList() } const getList = async () => { state.loading = true const res = await getCompanyPeriod(state.queryParams) if(res.code == 200){ - state.dataList = res.data.list + state.dataList = res.data.list.map(item => { + return { + ...item, + modifyPeriodMin: item.modifyPeriod ? (item.modifyPeriod /60).toFixed(2).replace(/\.00$/, '')+'分钟' : '', + remainPeriodMin: item.remainPeriod ? (item.remainPeriod /60).toFixed(2).replace(/\.00$/, '')+'分钟' : '' + } + }) state.total = res.data.total }else{ ElMessage.warning(res.message) diff --git a/src/views/onlineEducation/classHourBatch/index.vue b/src/views/onlineEducation/classHourBatch/index.vue index af6dc53..13380d4 100644 --- a/src/views/onlineEducation/classHourBatch/index.vue +++ b/src/views/onlineEducation/classHourBatch/index.vue @@ -74,7 +74,8 @@ dataList: [], isAdmin: false, companyName: '', - remainPeriod: null + remainPeriod: null, + companyId: null }); @@ -89,6 +90,7 @@ data.remainPeriod = userInfo.remainPeriod ? (userInfo.remainPeriod /60).toFixed(2).replace(/\.00$/, ''):'' data.isAdmin = false; data.companyName = userInfo.companyName + data.companyId = userInfo.companyId } await getList() }) @@ -146,6 +148,6 @@ } const openDetail = () => { - classHourRef.value.openDialog() + classHourRef.value.openDialog(data.companyId) } </script> diff --git a/src/views/onlineEducation/count/index.vue b/src/views/onlineEducation/count/index.vue index 3146e79..31bc89f 100644 --- a/src/views/onlineEducation/count/index.vue +++ b/src/views/onlineEducation/count/index.vue @@ -1,8 +1,8 @@ <template> <div class="app-container"> <div style="margin-bottom: 10px"> - <el-form style="display: flex"> - <el-form-item label="企业:"> + <el-form style="display: flex;flex-wrap: wrap"> + <el-form-item label="企业:" v-if="state.isAdmin"> <el-select v-model="state.queryParams.companyId" style="width: 100%" @@ -27,7 +27,7 @@ range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" - value-format="YYYY-MM-DD 00:00:00" + format="YYYY-MM-DD" /> </el-form-item> <el-form-item style="margin-left: 50px"> @@ -47,15 +47,31 @@ <!-- 表格数据 --> <el-table v-loading="loading" :data="state.dataList" :border="true" row-key="id"> <el-table-column label="序号" type="index" align="center" width="80" /> - <el-table-column label="企业名称" prop="sort" align="center" /> - <el-table-column label="企业编号" prop="sort" align="center" width="80" /> - <el-table-column label="总批次/人数" prop="sort" align="center" width="80" /> - <el-table-column label="三级" prop="sort" align="center" width="80" /> - <el-table-column label="二级" prop="sort" align="center" width="80" /> - <el-table-column label="一级" prop="sort" align="center" width="80" /> - <el-table-column label="考试人次" prop="sort" align="center" width="80" /> - <el-table-column label="合格人次" prop="sort" align="center" width="80" /> - <el-table-column label="考试合格率" prop="sort" align="center" width="80" /> + <el-table-column label="企业名称" prop="companyName" align="center" /> + <el-table-column label="企业编号" prop="companyCode" align="center" /> + <el-table-column label="总批次/人数" prop="sort" align="center" > + <template #default="scope"> + <span>{{scope.row.phaseStudentCount && scope.row.phaseCount ? scope.row.phaseCount + '/' +scope.row.phaseStudentCount:''}}</span> + </template> + </el-table-column> + <el-table-column label="三级" prop="sort" align="center" > + <template #default="scope"> + <span>{{scope.row.level3StudentCount && scope.row.level3PhaseCount ? scope.row.level3PhaseCount+ '/' +scope.row.level3StudentCount:''}}</span> + </template> + </el-table-column> + <el-table-column label="二级" prop="sort" align="center" > + <template #default="scope"> + <span>{{scope.row.level2StudentCount && scope.row.level2PhaseCount ? scope.row.level2PhaseCount+ '/' +scope.row.level2StudentCount:''}}</span> + </template> + </el-table-column> + <el-table-column label="一级" prop="sort" align="center" > + <template #default="scope"> + <span>{{scope.row.level1StudentCount && scope.row.level1PhaseCount ? scope.row.level1PhaseCount+ '/' +scope.row.level1StudentCount:''}}</span> + </template> + </el-table-column> + <el-table-column label="考试人次" prop="paperStudentCount" align="center" /> + <el-table-column label="合格人次" prop="passStudentCount" align="center" /> + <el-table-column label="合格率" prop="passRate" align="center" /> </el-table> <pagination v-show="state.total > 0" @@ -71,10 +87,12 @@ <script setup> import {getCurrentInstance, onMounted, reactive, ref, toRefs} from "vue"; import {ElMessage, ElMessageBox} from "element-plus"; +import moment from "moment"; import {delClassification, getClassification} from "@/api/onlineEducation/courseClass"; import {getCompany} from "@/api/onlineEducation/company"; import {getCompanyCount} from "@/api/onlineEducation/count"; +import Cookies from "js-cookie"; const { proxy } = getCurrentInstance(); const loading = ref(false); const areaRef = ref(); @@ -94,11 +112,19 @@ companyList: [], pageNum: 1, pageSize: 10, + isAdmin: false }); //页面加载 onMounted(() => { - getCompanyList(); + setDate(); + const userInfo = JSON.parse(Cookies.get('userInfo')) + console.log("userInfo",userInfo) + state.isAdmin = userInfo.userType === 0; + if(state.isAdmin){ + getCompanyList(); + } + getList(); }); @@ -106,7 +132,14 @@ loading.value = true; const res = await getCompanyCount(state.queryParams); if(res.code === 200){ - state.dataList = res.data + state.dataList = res.data.list.map(item => { + return { + ...item, + passRate: item.passStudentCount!=null && item.paperStudentCount!=null ? (item.passStudentCount / item.paperStudentCount).toFixed(2) *100 + '%': '' + + } + }) + state.total = res.data.total }else{ ElMessage.warning(res.message) } @@ -150,23 +183,44 @@ getCompanyList('') }, 500) } +const setDate = () => { + let isDate = new Date() + let sTime = `${isDate.getFullYear()}-${isDate.getMonth() + 1}-${isDate.getDate()-7}` + let eTime = `${isDate.getFullYear()}-${isDate.getMonth() + 1}-${isDate.getDate()}` + sTime = `${sTime}` + eTime = `${eTime}` + searchTime.value = [sTime,eTime]; + state.queryParams.startTime = searchTime.value[0]+' 00:00:00' + state.queryParams.endTime = searchTime.value[1]+' 00:00:00' +} const changeTime=(value)=>{ + console.log('11',searchTime.value) if(!value){ state.queryParams.endTime = "" state.queryParams.startTime = "" } + searchTime.value[0]=moment(searchTime.value[0]).format('YYYY-MM-DD') + searchTime.value[1]=moment(searchTime.value[1]).format('YYYY-MM-DD') } const searchClick = () => { if(searchTime.value && searchTime.value.length>0){ - state.queryParams.startTime = searchTime.value[0] - state.queryParams.endTime = searchTime.value[1] + state.queryParams.startTime = searchTime.value[0] + ' 00:00:00' + state.queryParams.endTime = searchTime.value[1] + ' 00:00:00' } getList(); } + /** 重置新增的表单以及其他数据 */ function reset() { - data.queryParams.name = ''; - data.queryParams.pageNum = 1; + state.queryParams = { + companyId: '', + type: null, + endTime: '', + startTime: '', + pageNum: 1, + pageSize: 10, + } + searchTime.value = []; getList(); } diff --git a/src/views/onlineEducation/groupExams/components/examChooseStudent.vue b/src/views/onlineEducation/groupExams/components/examChooseStudent.vue new file mode 100644 index 0000000..698b1c6 --- /dev/null +++ b/src/views/onlineEducation/groupExams/components/examChooseStudent.vue @@ -0,0 +1,248 @@ +<template> + <div class="notice"> + <el-dialog + v-model="dialogVisible" + :title="title" + width="50%" + :before-close="handleClose" + > + <div style="margin-bottom: 20px"> + <el-checkbox v-model="state.bindBatchStu" @change="changeBind">绑定批次人员</el-checkbox> + <el-select + v-if="state.bindBatchStu" + multiple + collapse-tags + collapse-tags-tooltip + v-model="state.form.phaseIds" + style="width: 160px;margin: 0 20px" + v-loadMoreNew:[reselectExam]="handleScroll" + :popper-class="reselectExam.name" + class="item-width" + placeholder="请选择批次" + > + <el-option + v-for="item in state.batchList" + :key="item.id" + :label="item.name" + :value="item.id" + /> + </el-select> + </div> + + <!-- 表格数据 --> + <el-table + ref="tableRef" + v-loading="loading" + :data="state.dataList" + :border="true" + :row-key="getRowKey" + @selection-change="handleSelectionChange" + v-model="state.selectRowKeys" + > + <el-table-column type="selection" :reserve-selection="true" width="55" align="center" /> +<!-- <el-table-column label="序号" type="index" align="center" width="80" />--> + <el-table-column label="工号" prop="empno" align="center" width="60" /> + <el-table-column label="姓名" prop="name" align="center" /> + <el-table-column label="性别" prop="sex" align="center" > + <template #default="scope"> + <span>{{scope.row.sex == 0 ? '男':'女'}}</span> + </template> + </el-table-column> + <el-table-column label="手机号" prop="phone" align="center" width="130"/> + <el-table-column label="身份证" prop="idNo" align="center" width="200" :show-overflow-tooltip="true"/> +<!-- <el-table-column label="创建人" prop="createBy" align="center"/>--> + <el-table-column label="工作岗位" prop="post" align="center"/> + <el-table-column label="职务" prop="duty" align="center"/> +<!-- <el-table-column label="一人一档" prop="duty" align="center" width="120">--> +<!-- <template #default="scope">--> +<!-- <el-button link type="primary">培训考试记录</el-button>--> +<!-- </template>--> +<!-- </el-table-column>--> + </el-table> + + <pagination + v-show="state.total> 0" + :total="state.total" + v-model:page="state.queryParams.pageNum" + v-model:limit="state.queryParams.pageSize" + @pagination="getList" + /> + <template #footer> + <span class="dialog-footer"> + <el-button @click="handleClose" size="default">取 消</el-button> + <el-button type="primary" @click="onSubmit" size="default" v-preReClick>确认</el-button> + </span> + </template> + </el-dialog> + </div> +</template> +<script setup> +import {nextTick, reactive, ref, toRefs} from 'vue' +import {ElMessage} from "element-plus"; +import Cookies from "js-cookie"; +import { + addQuestionBank, + checkQuestionBankName, + editQuestionBank, + getQuestionBank +} from "@/api/onlineEducation/questionBank"; +import {getStudent} from "@/api/onlineEducation/student"; +import {batchAddStudent, getBatch} from "@/api/onlineEducation/batch"; +import {examAddStudent} from "@/api/onlineEducation/exam"; + +const dialogVisible = ref(false); +const title = ref(""); +const tableRef = ref(); +const length = ref() +const emit = defineEmits(["getList"]); +const startUsername = ref(''); +const classifyRef = ref(null) +const state = reactive({ + form: { + paperId: null, + phaseIds: [], + studentIds: [] + }, + isAdmin: false, + total: 0, + queryParams: { + pageNum: 1, + pageSize: 10 + }, + dataList: [], + totalItems: 0, // 总数据条数,从后端接口获取 + phaseId: null, + chooseStu: [], + companyId: null, + selectRowKeys: [], + batchList: [], + batchPageNum: 1, // 当前页码 + batchPageSize: 10, // 每页显示的数量 + hasMoreItemsBatch: null, // 是否还有更多选项 + bindBatchStu: false + +}) +const loading = ref(false); + +const reselectExam = reactive({ + name: 'ExamBatch' +}) +const getRowKey = (row) => { + return row.id +} +const openDialog = async (data) => { + // state.selectRowKeys = [10,11] + + state.form.paperId = data.queryParams.paperId + title.value = '学员选择'; + dialogVisible.value = true; + await getList() + await loadMoreBatchData() +} + +const getList = async () => { + loading.value = true + const res = await getStudent(state.queryParams) + if(res.code == 200){ + state.dataList = res.data.list + state.total = res.data.total + // await nextTick(() => { + // const currentIds = state.dataList.map(row => row.id) + // const selectIds = state.selectRowKeys.filter(id => currentIds.includes(id)) + // state.dataList.forEach(row => { + // if (selectIds.includes(row.id)) { + // tableRef.value.toggleRowSelection(row, true); + // } + // }) + // }); + }else{ + ElMessage.warning(res.message) + } + loading.value = false +} + +const onSubmit = async () => { + const res = await examAddStudent(state.form) + if(res.code === 200){ + ElMessage({ + type: 'success', + message: '新增成功' + }); + }else{ + ElMessage.warning(res.message) + } + emit("getList") + reset(); + dialogVisible.value = false; +} + +const handleClose = () => { + reset(); + dialogVisible.value = false; + emit("getList") +} +const reset = () => { + state.form = { + paperId: null, + phaseIds: [], + studentIds: [] + } + state.bindBatchStu = false; + state.batchList = []; + state.batchPageNum = 1; + state.batchPageSize = 10; + state.hasMoreItemsBatch = null; + tableRef.value.clearSelection(); + state.dataList = [] + state.total = 0 + state.queryParams ={ + pageNum: 1, + pageSize: 10 + } +} +const handleSelectionChange = (val) => { + state.form.studentIds = val.map(item => item.id) + console.log("选中的行", state.form.studentIds) +} + +const handleScroll = () => { + if(state.batchPageNum >= state.hasMoreItemsBatch) return + state.batchPageNum++; + loadMoreBatchData() +} +const loadMoreBatchData = async () => { + console.log(' Bank'); + const queryParams = { + pageNum: state.batchPageNum, + pageSize: state.batchPageSize, + } + const res = await getBatch(queryParams) + if (res.code == 200) { + state.hasMoreItemsBatch = res.data.totalPage + const data = res.data + state.batchList = state.batchList.concat(data.list) + }else{ + ElMessage.warning(res.message) + } +} +const changeBind = (val) => { + console.log('vv',val) +} +defineExpose({ + openDialog +}); + +</script> + +<style scoped lang="scss"> +.notice{ + :deep(.el-form .el-form-item__label) { + font-size: 15px; + } + .file { + display: flex; + flex-direction: column; + align-items: flex-start; + } +} +</style> diff --git a/src/views/onlineEducation/groupExams/components/examDialog.vue b/src/views/onlineEducation/groupExams/components/examDialog.vue index e2ec21c..6f12c6d 100644 --- a/src/views/onlineEducation/groupExams/components/examDialog.vue +++ b/src/views/onlineEducation/groupExams/components/examDialog.vue @@ -4,6 +4,7 @@ v-model="dialogVisible" width="800px" :before-close="handleClose" + destroy-on-close > <el-form :model="state.form" size="default" ref="busRef" :rules="state.formRules" label-width="150px" > <span style="font-size: 20px;font-weight: 800;margin-left: 20px">考试配置</span> @@ -28,15 +29,18 @@ <div style="display: flex"> <div class="group"> <div> - 单选:<el-input style="max-width: 40px"></el-input> 题 + 单选:<el-input style="max-width: 40px" v-model.trim="state.form.singleNum"></el-input> 题 </div> <div style="margin-left: 20px"> - 每题:<el-input style="max-width: 40px"></el-input> 分 + 每题:<el-input style="max-width: 40px" v-model.trim="state.form.singleScore"></el-input> 分 </div> </div> <div class="group" > <div> - 共 <span style="max-width: 30px">xxx</span> 分 + 共 + <span style="max-width: 30px" v-show="state.form.singleNum && state.form.singleScore">{{state.form.singleNum * state.form.singleScore}}</span> +<!-- <span v-else></span>--> + 分 </div> <el-select clearable @@ -54,33 +58,36 @@ :value="item.id" /> </el-select> - <el-radio-group v-model="radio" > + <el-radio-group v-model="state.form.singleMethod" > <el-radio :label="1" style="max-width: 30px">随机</el-radio> - <el-radio :label="2">默认</el-radio> + <el-radio :label="2">顺序</el-radio> </el-radio-group> </div> </div> <div style="display: flex"> <div class="group"> <div> - 多选:<el-input style="max-width: 40px"></el-input> 题 + 多选:<el-input style="max-width: 40px" v-model="state.form.multiNum"></el-input> 题 </div> <div style="margin-left: 20px"> - 每题:<el-input style="max-width: 40px"></el-input> 分 + 每题:<el-input style="max-width: 40px" v-model="state.form.multiScore"></el-input> 分 </div> </div> <div class="group" > - <div> - 共 <span style="max-width: 30px">xxx</span> 分 + <div > + 共 + <span style="max-width: 30px" v-show="state.form.multiNum && state.form.multiScore">{{state.form.multiNum * state.form.multiScore}}</span> +<!-- <span v-else></span>--> + 分 </div> <el-select clearable - v-model="state.form.singleBankId" + v-model="state.form.multiBankId" style="width: 160px;margin: 0 20px" v-loadMoreNew:[reselectSingle]="handleScroll" :popper-class="reselectSingle.name" class="item-width" - placeholder="请选择单选题题库" + placeholder="请选择多选题题库" > <el-option v-for="item in state.bankListSingle" @@ -89,33 +96,36 @@ :value="item.id" /> </el-select> - <el-radio-group v-model="radio" > + <el-radio-group v-model="state.form.multiMethod" > <el-radio :label="1" style="max-width: 30px">随机</el-radio> - <el-radio :label="2">默认</el-radio> + <el-radio :label="2">顺序</el-radio> </el-radio-group> </div> </div> <div style="display: flex"> <div class="group"> <div> - 判断:<el-input style="max-width: 40px"></el-input> 题 + 判断:<el-input style="max-width: 40px" v-model="state.form.judgeNum"></el-input> 题 </div> <div style="margin-left: 20px"> - 每题:<el-input style="max-width: 40px"></el-input> 分 + 每题:<el-input style="max-width: 40px" v-model="state.form.judgeScore"></el-input> 分 </div> </div> <div class="group" > <div> - 共 <span style="max-width: 30px">xxx</span> 分 + 共 + <span style="max-width: 30px" v-show="state.form.judgeNum && state.form.judgeScore">{{state.form.judgeNum * state.form.judgeScore}}</span> +<!-- <span v-else></span>--> + 分 </div> <el-select clearable - v-model="state.form.singleBankId" + v-model="state.form.judgeBankId" style="width: 160px;margin: 0 20px" v-loadMoreNew:[reselectSingle]="handleScroll" :popper-class="reselectSingle.name" class="item-width" - placeholder="请选择单选题题库" + placeholder="请选择判断题题库" > <el-option v-for="item in state.bankListSingle" @@ -124,24 +134,32 @@ :value="item.id" /> </el-select> - <el-radio-group v-model="radio" > + <el-radio-group v-model="state.form.judgeMethod" > <el-radio :label="1" style="max-width: 30px">随机</el-radio> - <el-radio :label="2">默认</el-radio> + <el-radio :label="2">顺序</el-radio> </el-radio-group> </div> </div> - <span class="group" style="margin-bottom: 10px">共计:xxx分</span> + <span class="group" style="margin-bottom: 20px">共计: + {{state.form.judgeNum * state.form.judgeScore+state.form.multiNum * state.form.multiScore+state.form.singleNum * state.form.singleScore}} + 分</span> <div style="display: flex;justify-content: space-between;align-items: center"> - <el-form-item label="合格分数:" prop=""> - <el-input-number v-model="num" :min="1" :max="10" style="margin-right: 10px" /> (大于等于) + <el-form-item label="合格分数:" prop="passScore"> + <el-input-number v-model="state.form.passScore" :min="1" :max="1000" style="margin-right: 10px" /> (大于等于) </el-form-item> - <el-form-item label="限制时长:" prop=""> - <el-input v-model="num1" style="max-width: 200px" > + <el-form-item label="限制时长:" prop="limitTime"> + <el-input v-model="state.form.limitTime" style="max-width: 200px" :disabled="state.form.limited === 0"> <template #append>分钟</template> </el-input> </el-form-item> - </div> + </div> + <el-form-item label="是否限制考试时长:" prop="limited" style="margin-left: 60px"> + <el-radio-group v-model="state.form.limited" @change="changeLimit" > + <el-radio :label="0" style="max-width: 30px">否</el-radio> + <el-radio :label="1">是</el-radio> + </el-radio-group> + </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> @@ -169,7 +187,7 @@ editQuestionBank, getQuestionBank } from "@/api/onlineEducation/questionBank"; -import {checkExamName} from "@/api/onlineEducation/exam"; +import {addExam, checkExamName, editExam} from "@/api/onlineEducation/exam"; const dialogVisible = ref(false); const title = ref(""); @@ -214,11 +232,30 @@ name: '', categoryId: null, companyName: '', - companyId: null + companyId: null, + judgeBankId: null, + judgeMethod: 1, + judgeNum: null, + judgeScore: null, + multiBankId: null, + multiMethod: 1, + multiNum: null, + multiScore: null, + singleBankId: null, + singleMethod: 1, + singleNum: null, + singleScore: null, + limited: 1, + limitTime: null, + passScore: null + }, formRules: { name: [{required: true, trigger: "blur", validator: validateName}], categoryId: [{required: true, message: '请选择课程分类', trigger: 'blur'}], + limited: [{required: true, message: '请选择课程分类', trigger: 'blur'}], + limitTime: [{required: true, message: '请选择课程分类', trigger: 'blur'}], + passScore: [{required: true, message: '请选择课程分类', trigger: 'blur'}] }, classifyList: [], isAdmin: false, @@ -247,9 +284,7 @@ } title.value = type === 'addFirst' || type === 'add' ? '新增' : type ==='edit' ? '编辑' : '' ; if(type === 'edit') { - state.form.id = value.id - state.form.name = value.name - state.form.categoryId = value.categoryId + state.form = value startUsername.value = value.name; }else if(type === 'add' && value ){ state.form.parentId = value.id @@ -258,18 +293,18 @@ } const onSubmit = async () => { - if(state.isAdmin){ - ElMessage({ - type: 'warning', - message: '管理员暂无权限' - }); - return; - } + // if(state.isAdmin){ + // ElMessage({ + // type: 'warning', + // message: '管理员暂无权限' + // }); + // return; + // } const valid = await busRef.value.validate(); if(valid){ if(title.value === '新增'){ const {id, ...data} = JSON.parse(JSON.stringify(state.form)) - const res = await addQuestionBank(data) + const res = await addExam(data) if(res.code === 200){ ElMessage({ type: 'success', @@ -284,7 +319,7 @@ dialogVisible.value = false; }else if(title.value === '编辑'){ const {...data} = JSON.parse(JSON.stringify(state.form)) - const res = await editQuestionBank(data) + const res = await editExam(data) if(res.code === 200){ ElMessage({ type: 'success', @@ -348,7 +383,22 @@ name: '', categoryId: null, companyName: '', - companyId: null + companyId: null, + judgeBankId: null, + judgeMethod: 1, + judgeNum: null, + judgeScore: null, + multiBankId: null, + multiMethod: 1, + multiNum: null, + multiScore: null, + singleBankId: null, + singleMethod: 1, + singleNum: null, + singleScore: null, + limited: 0, + limitTime: null, + passScore: null } } const handleScroll = () => { @@ -372,6 +422,14 @@ ElMessage.warning(res.message) } } + +const changeLimit = (val) => { + state.form.limitTime = null + if(val === 0) { + state.form.limitTime = 0 + } + +} defineExpose({ openDialog }); diff --git a/src/views/onlineEducation/groupExams/components/student.vue b/src/views/onlineEducation/groupExams/components/student.vue new file mode 100644 index 0000000..63b6e46 --- /dev/null +++ b/src/views/onlineEducation/groupExams/components/student.vue @@ -0,0 +1,184 @@ +<template> + <div class="app-container"> + <div style="margin-bottom: 10px;display: flex;align-items: center;justify-content: space-between"> + <el-button + type="primary" + plain + icon="Plus" + @click="openDialog()" + >选择学员</el-button> + <el-button + type="danger" + plain + icon="Delete" + @click="handleDeleteBatch" + >批量删除</el-button> + </div> + <!-- 表格数据 --> + <el-table ref="tableRef" v-loading="loading" :data="dataList" :border="true" :row-key="getRowKey" @selection-change="handleSelectionChange"> + <el-table-column type="selection" :reserve-selection="true" width="55" align="center" /> + <el-table-column label="序号" type="index" align="center" width="80" /> + <el-table-column label="试卷名称" align="center" > + <template #default="scope"> + <span>{{scope.row.examPaper.name}}</span> + </template> + </el-table-column> + <el-table-column label="学员名称" prop="studentName" align="center" > + <template #default="scope"> + <span>{{scope.row.student.name}}</span> + </template> + </el-table-column> + <el-table-column label="手机号" prop="studentPhone" align="center" > + <template #default="scope"> + <span>{{scope.row.student.phone}}</span> + </template> + </el-table-column> + <el-table-column label="成绩" prop="score" align="center" /> + <el-table-column label="是否合格" prop="passed" align="center" > + <template #default="scope"> + <span>{{scope.row.passed === 0 ? '不合格' : '合格'}}</span> + </template> + </el-table-column> + <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180"> + <template #default="scope"> + <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + + <pagination + v-show="total > 0" + :total="total" + v-model:page="queryParams.pageNum" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + + <exam-choose-student ref="dialogRef" @getList=getList></exam-choose-student> + </div> +</template> + +<script setup> +import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue"; +import {ElMessage, ElMessageBox} from "element-plus"; +import Cookies from "js-cookie"; +import {delQuestionBank, getQuestionBank} from "@/api/onlineEducation/questionBank"; +import {batchDelStudent, delBatchStu, getBatchStudent} from "@/api/onlineEducation/batch"; +import {useRoute} from 'vue-router' +import {delExamStu, examDelStudent, getExamStudent} from "@/api/onlineEducation/exam"; +import ExamChooseStudent from "@/views/onlineEducation/groupExams/components/examChooseStudent.vue"; +const route = useRoute() + + +const { proxy } = getCurrentInstance(); +const loading = ref(false); +const dialogRef = ref(); +const tableRef = ref(); +const data = reactive({ + queryParams: { + paperId: null, + pageNum: 1, + pageSize: 10, + }, + total: 0, + dataList: [], + isAdmin: false, + chooseStu: [] + +}); + +const { queryParams, total, dataList } = toRefs(data); + +onMounted(async ()=>{ + const userInfo = JSON.parse(Cookies.get('userInfo')) + console.log("userInfo",userInfo) + if(userInfo.userType === 0){ + data.isAdmin = true; + }else { + data.isAdmin = false; + } + const val = JSON.parse(route.query.val) + // data.queryParams.pageId = val.id + data.queryParams.paperId = val.id + await getList() +}) +onUnmounted(()=>{ + +}) + +const getRowKey = (row) => { + return row.id +} +const getList = async () => { + loading.value = true + const res = await getExamStudent(data.queryParams) + if(res.code == 200){ + data.dataList = res.data.list + data.total = res.data.total + }else{ + ElMessage.warning(res.message) + } + loading.value = false +} + +const openDialog = () => { + dialogRef.value.openDialog(data); +} + +/** 重置新增的表单以及其他数据 */ +function reset() { + proxy.resetForm("roleRef"); +} +const handleSelectionChange = (val) => { + + console.log("选中的行", val) + data.chooseStu = val.map(item => item.id) +} +const handleDelete = (val) => { + ElMessageBox.confirm( + '确定删除此条数据?', + '提示', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }) + .then( async() => { + const res = await delExamStu(val.id) + if(res.code == 200){ + ElMessage.success('数据删除成功') + await getList() + tableRef.value.clearSelection(); + }else{ + ElMessage.warning(res.message) + } + }) +} +const handleDeleteBatch = () => { + if(data.chooseStu && data.chooseStu.length <=0){ + ElMessage.warning('请选择要删除的学员'); + return false; + } + ElMessageBox.confirm( + '确定删除选择的所有数据?', + '提示', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning', + }) + .then( async() => { + // const param = { + // phaseStudentIds: data.chooseStu + // } + const res = await examDelStudent(data.chooseStu) + if(res.code == 200){ + ElMessage.success('数据删除成功') + await getList() + }else{ + ElMessage.warning(res.message) + } + }) +} + +</script> diff --git a/src/views/onlineEducation/groupExams/index.vue b/src/views/onlineEducation/groupExams/index.vue index 03fca18..3a305d3 100644 --- a/src/views/onlineEducation/groupExams/index.vue +++ b/src/views/onlineEducation/groupExams/index.vue @@ -14,11 +14,28 @@ <el-table-column label="企业名称" prop="companyName" align="center" /> <el-table-column label="创建账户" prop="createBy" align="center" /> <el-table-column label="科目/类别" prop="categoryName" align="center" /> - <el-table-column label="考生人数" prop="" align="center" /> - <el-table-column label="合格人数" prop="" align="center" /> - <el-table-column label="平均分数" prop="" align="center" /> - <el-table-column label="合格率" prop="" align="center" /> - <el-table-column label="限制时长" prop="limitTime" align="center" /> + <el-table-column label="考生人数" prop="" align="center"> + <template #default="scope"> + <span>{{scope.row.paperStudentInfoVO.studentCount}}</span> + </template> + </el-table-column> + <el-table-column label="合格人数" prop="" align="center"> + <template #default="scope"> + <span>{{scope.row.paperStudentInfoVO.passStudentCount}}</span> + </template> + </el-table-column> + <el-table-column label="平均分数" prop="" align="center" > + <template #default="scope"> + <span>{{scope.row.paperStudentInfoVO.avgScore}}</span> + </template> + </el-table-column> + <el-table-column label="合格率" prop="passRate" align="center" /> + <el-table-column label="限制时长" prop="limitTime" align="center" > + <template #default="scope"> + <span v-if="scope.row.limitTime == 0">不限时</span> + <span v-else>{{scope.row.limitTime}}</span> + </template> + </el-table-column> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180"> <template #default="scope"> <el-button link type="primary" @click="toStuChoose(scope.row)">学生数据</el-button> @@ -91,7 +108,13 @@ loading.value = true const res = await getExam(data.queryParams) if(res.code == 200){ - data.dataList = res.data.list + data.dataList = res.data.list.map(item => { + return { + ...item, + passRate: item.paperStudentInfoVO.passStudentCount ===0 && item.paperStudentInfoVO.studentCount ===0 ? '0%': (item.paperStudentInfoVO.passStudentCount / item.paperStudentInfoVO.studentCount).toFixed(2) *100 + '%' + } + }) + data.total = res.data.total }else{ ElMessage.warning(res.message) @@ -128,7 +151,7 @@ } const toStuChoose = (val) => { const v = JSON.stringify(val) - router.push({ path: "/chooseStu", query: { val: v } }); + router.push({ path: "/examStu", query: { val: v } }); } const openDetail = () => { diff --git a/src/views/onlineEducation/offlineEducation/components/recordDialog.vue b/src/views/onlineEducation/offlineEducation/components/recordDialog.vue index 692fe97..3dc57a0 100644 --- a/src/views/onlineEducation/offlineEducation/components/recordDialog.vue +++ b/src/views/onlineEducation/offlineEducation/components/recordDialog.vue @@ -82,7 +82,6 @@ </template> <script setup> import {reactive, ref, toRefs, defineEmits, nextTick, onMounted} from 'vue' -import InfiniteList from 'vue3-infinite-list'; import { View } from "@element-plus/icons-vue"; import scorllSelect from '@/components/scrollSelect/index.vue' import {ElMessage, ElMessageBox} from "element-plus"; diff --git a/src/views/onlineEducation/systemManage/company/index.vue b/src/views/onlineEducation/systemManage/company/index.vue index cbb5355..13f6aaf 100644 --- a/src/views/onlineEducation/systemManage/company/index.vue +++ b/src/views/onlineEducation/systemManage/company/index.vue @@ -20,7 +20,7 @@ <el-table-column label="总课时(分)" prop="totalPeriodMin" align="center"/> <el-table-column label="课时变动详情" align="center" class-name="small-padding fixed-width" > <template #default="scope"> - <el-button link type="primary">查看详情</el-button> + <el-button link type="primary" @click="openDetail(scope.row)">查看详情</el-button> </template> </el-table-column> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200" > @@ -41,6 +41,7 @@ /> <company-dialog ref="dialogRef" @getList=getList></company-dialog> + <class-hour-change ref="classHourRef" @getList=getList></class-hour-change> </div> </template> @@ -49,6 +50,7 @@ import {ElMessage, ElMessageBox} from "element-plus"; import {delCompany, getCompany} from "@/api/onlineEducation/company"; import companyDialog from "./components/companyDialog.vue"; +import classHourChange from '@/views/onlineEducation/classHourBatch/components/classHourChange.vue' const { proxy } = getCurrentInstance(); const loading = ref(false); @@ -63,7 +65,7 @@ }); const { queryParams, total, dataList } = toRefs(data); - +const classHourRef = ref(); onMounted(()=>{ getList() }) @@ -119,4 +121,7 @@ }) } +const openDetail = (val) => { + classHourRef.value.openDialog(val.id) +} </script> -- Gitblit v1.9.2