Procházet zdrojové kódy

Merge branch 'refs/heads/release' into dev

zhangchong před 1 týdnem
rodič
revize
e71600847c

+ 71 - 0
src/api/examTrain/marking.ts

@@ -0,0 +1,71 @@
+/*
+ * @Author: zjq
+ * @description 考试培训-在线培训-阅卷管理
+ */
+import request from '@/utils/request';
+/**
+ * @description 获取阅卷列表
+ * @param {object} data
+ */
+export const getMarkingList = (data?: object) => {
+	return request({
+		url: '/api/v1/UserExam/GetGradingPagedList',
+		method: 'post',
+		data,
+	});
+};
+/**
+ * @description 获取阅卷详情人员
+ * @param {object} params
+ */
+export const getMarkingDetailUser = (params?: object) => {
+	return request({
+		url: '/api/v1/UserExam/GetUserList',
+		method: 'get',
+		params,
+	});
+};
+/**
+ * @description 根据试卷人员ID获取阅卷详情
+ * @param {object} params
+ */
+export const getMarkingDetailByUser = (params?: object) => {
+	return request({
+		url: '/api/v1/UserExam/GetGradingQuestions',
+		method: 'get',
+		params,
+	});
+};
+/**
+ * @description 批量阅卷
+ * @param {object} data
+ */
+export const batchMarking = (data: object) => {
+	return request({
+		url: '/api/v1/UserExam/BatchGrading',
+		method: 'post',
+		data,
+	});
+}
+/**
+ * @description 完成阅卷
+ * @param {object} data
+ */
+export const finishMarking = (data: object) => {
+	return request({
+		url: '/api/v1/UserExam/CompleteGrading',
+		method: 'post',
+		data,
+	});
+};
+/**
+ * @description 获取阅卷试题
+ * @param {object} params
+ */
+export const getMarkingQuestion = (params?: object) => {
+	return request({
+		url: '/api/v1/UserExam/GetGradingQuestions',
+		method: 'post',
+		data: params,
+	});
+};

+ 10 - 0
src/router/route.ts

@@ -775,6 +775,16 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
 			isDynamic: true,
 		},
 	},
+	{
+		path: '/examTrain/exam/marking/mark/:examId/:tagsViewName/:isView?',
+		name: 'examTrainExamMarkingEdit',
+		component: () => import('@/views/examTrain/exam/marking/components/Exam-Marking.vue'),
+		meta: {
+			title: '阅卷',
+			isKeepAlive: true,
+			isDynamic: true,
+		},
+	},
 ];
 /**
  * 定义404、401界面

+ 2 - 2
src/views/business/order/enterprise.vue

@@ -180,8 +180,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="期满时间" prop="exTime">

+ 2 - 2
src/views/business/order/index.vue

@@ -239,8 +239,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="期满时间" prop="exTime">

+ 2 - 2
src/views/business/publish/todo.vue

@@ -77,8 +77,8 @@
 			<el-form :model="state.queryParams" ref="drawerRuleFormRef" @submit.native.prevent label-width="100px" :disabled="gridOptions.loading">
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="是否会签" prop="IsCountersign">

+ 2 - 2
src/views/business/travel/index.vue

@@ -193,8 +193,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="期满时间" prop="exTime">

+ 2 - 2
src/views/business/visit/index.vue

@@ -75,8 +75,8 @@
 			<el-form :model="state.queryParams" ref="drawerRuleFormRef" @submit.native.prevent label-width="100px" :disabled="state.loading">
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="是否会签" prop="IsCountersign">

+ 2 - 2
src/views/business/visit/provinceTodo.vue

@@ -89,8 +89,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="是否会签" prop="IsCountersign">

+ 2 - 2
src/views/business/visit/todo.vue

@@ -118,8 +118,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="是否会签" prop="IsCountersign">

+ 1 - 1
src/views/dataShare/extended.vue

@@ -53,7 +53,7 @@
 				>
 					<vxe-column type="seq" width="70"></vxe-column>
 					<vxe-column field="provinceNo" title="省本地编码"></vxe-column>
-					<vxe-column field="overduetype" title="超期类型"></vxe-column>
+					<vxe-column field="overdueType" title="超期类型"></vxe-column>
 				</vxe-table>
 			</div>
 		</div>

+ 331 - 0
src/views/examTrain/exam/marking/components/Exam-Marking-View.vue

@@ -0,0 +1,331 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" draggable destroy-on-close :show-close="false" width="80%" :before-close="closeDialog">
+		<template #header="{ close, titleId, titleClass }">
+			<div class="topContent">
+				<div class="titleBox">
+					<span class="title">自我练习</span>
+				</div>
+				<div class="submitBox">
+					<el-button type="info" @click="closeDialog">关 闭</el-button>
+				</div>
+			</div>
+		</template>
+		<el-row :gutter="10" v-loading="state.loading">
+			<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6">
+				<div class="examListContent" v-for="item in state.questionTypeData">
+					<p class="examType">{{ item.questionTypeDesc }}</p>
+					<ul class="examList">
+						<li
+							class="examListItem"
+							:class="{ select: questionsItem.id == state.selQuestionID, right: questionsItem.isRight, error: !questionsItem.isRight }"
+							v-for="questionsItem in item.questions"
+							@click="onSelQuestion(questionsItem.id)"
+						>
+							{{ questionsItem.sortIndex }}
+						</li>
+					</ul>
+				</div>
+			</el-col>
+			<el-col :xs="18" :sm="18" :md="18" :lg="18" :xl="18">
+				<div class="questionBox" v-if="state.questionDetail">
+					<p class="questionTitle">题干:{{ state.questionDetail.title }}</p>
+					<div class="questionAnswer">
+						<div v-if="[0, 2].includes(state.questionDetail.questionType)">
+							<el-radio-group style="display: block" v-model="state.selRadioValue">
+								<el-form-item :label="item.label + '. '" v-for="item in state.questionDetail.practiceQuestionOptionsDtos" style="margin-bottom: 10px">
+									<el-radio :label="item.content" :value="item.questionOptionId" disabled />
+								</el-form-item>
+							</el-radio-group>
+						</div>
+						<div v-else-if="state.questionDetail.questionType == 1">
+							<el-checkbox-group v-model="state.selCheckboxValue">
+								<el-form-item :label="item.label + '. '" v-for="item in state.questionDetail.practiceQuestionOptionsDtos" style="margin-bottom: 10px">
+									<el-checkbox :label="item.content" :value="item.questionOptionId" disabled />
+								</el-form-item>
+							</el-checkbox-group>
+						</div>
+					</div>
+				</div>
+				<div class="referenceAnswer" v-if="state.questionDetail">
+					<span>参考答案:</span>
+					<p>{{ state.questionDetail.answerDesc || '略' }}</p>
+				</div>
+				<div class="referenceAnswer" v-if="state.questionDetail && state.questionDetail.practiceQuestionKnowladgeDtos.length > 0">
+					<span>关联知识:</span>
+					<p v-for="item in state.questionDetail.practiceQuestionKnowladgeDtos" @click="onKnowladgeTo(item)">{{ item.title }}</p>
+				</div>
+				<div class="referenceAnswer" v-if="state.questionDetail && state.questionDetail.practiceQuestionSourcewareDtos.length > 0">
+					<span>关联课件:</span>
+					<p v-for="item in state.questionDetail.practiceQuestionSourcewareDtos" @click="onSourcewareTo(item)">{{ item.name }}</p>
+				</div>
+			</el-col>
+		</el-row>
+		<template #footer>
+			<span class="dialog-footer" v-if="state.selQuestionID">
+				<el-button type="primary" @click="onLastQuestion" :loading="state.loading">上一题</el-button>
+				<el-button type="primary" @click="onNextQuestion" :loading="state.loading">下一题</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { excludeSelfById } from '@/utils/tools';
+import other from '@/utils/other';
+import { fileDownloadByUrl } from '@/api/public/file';
+import { getViewPracticeQuestions, getPracticeView } from '@/api/examTrain/practice';
+
+const router = useRouter(); // 路由
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗
+	loading: false, // 加载
+	practiceId: '', // 用户练习id
+	questionTypeData: [] as any[], // 试卷题型数据
+	questionsData: [] as any[], // 试题集合
+	selQuestionID: '', // 选择的问题id
+	questionDetail: null, // 选择的问题明细
+	selRadioValue: '', // 单选题选择的值
+	selCheckboxValue: [] as any[], // 多选题选择的值
+});
+// 打开弹窗
+const openDialog = async (rows: any) => {
+	state.dialogVisible = true;
+	state.practiceId = rows.id;
+	state.loading = true;
+	getQuestionsData();
+};
+const getQuestionsData = async () => {
+	try {
+		const { result } = await getViewPracticeQuestions(state.practiceId);
+		let sortIndexNum = 1;
+		result.forEach((item) => {
+			switch (item.questionType) {
+				case 0:
+					item.questionTypeDesc = '单选题';
+					break;
+				case 1:
+					item.questionTypeDesc = '多选题';
+					break;
+				case 2:
+					item.questionTypeDesc = '判断题';
+					break;
+				default:
+					break;
+			}
+			item.questions.forEach((it) => {
+				it.sortIndex = sortIndexNum;
+				it.questionType = item.questionType;
+				state.questionsData.push(it);
+				sortIndexNum++;
+			});
+		});
+		state.questionTypeData = result;
+		state.loading = false;
+	} catch (error) {
+		// 打印错误信息
+		console.error(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+	state.questionTypeData = [];
+	state.questionsData = [];
+	state.selQuestionID = '';
+	state.questionDetail = null;
+	state.selRadioValue = '';
+	state.selCheckboxValue = [];
+};
+// 上一题下一题
+const onLastQuestion = () => {
+	let index: number = state.questionsData.findIndex((it) => it.id == state.selQuestionID);
+	index = index - 1 == -1 ? state.questionsData.length : index - 1;
+	onSelQuestion(state.questionsData[index].id);
+};
+const onNextQuestion = () => {
+	let index: number = state.questionsData.findIndex((it) => it.id == state.selQuestionID);
+	index = index + 1 == state.questionsData.length ? 0 : index + 1;
+	onSelQuestion(state.questionsData[index].id);
+};
+// 选择的问题id 提交当前试题答案,再请求下一道题详情 value: 请求下一题详情id
+const onSelQuestion = async (value: any) => {
+	state.loading = true;
+	onGetQuestionDetail(value);
+};
+const onGetQuestionDetail = async (value) => {
+	// 初始化选择选择/填写的答案
+	state.selRadioValue = '';
+	state.selCheckboxValue = [];
+	// 请求下一道题
+	state.selQuestionID = value;
+	try {
+		const { result } = await getPracticeView(state.selQuestionID);
+		state.questionDetail = result;
+		let answerDesc = '';
+		state.questionDetail.practiceQuestionOptionsDtos.forEach((it) => {
+			it.isAnswer && (answerDesc += it.label);
+		});
+		state.questionDetail.answerDesc = answerDesc;
+		if ([0, 2].includes(state.questionDetail.questionType)) {
+			let obj = state.questionDetail.practiceQuestionOptionsDtos.find((x: any) => x.isSelected === true);
+			state.selRadioValue = obj ? obj.questionOptionId : '';
+		} else if (state.questionDetail.questionType == 1) {
+			let arr = [] as any[];
+			state.questionDetail.practiceQuestionOptionsDtos.forEach((it) => {
+				if (it.isSelected) arr.push(it);
+			});
+			state.selCheckboxValue = arr ? arr.map((x: any) => x.questionOptionId) : [];
+		}
+		state.loading = false;
+	} catch (error) {
+		// 打印错误信息
+		console.error(error);
+	}
+};
+// 跳转知识详情页面
+const onKnowladgeTo = (row: any) => {
+	router.push({
+		name: 'knowledgePreview',
+		params: {
+			id: row.knowladgeId,
+			isAddPv: 'isAddPv',
+			tagsViewName: row.title,
+		},
+	});
+};
+// 课件预览下载
+const onSourcewareTo = (row: any) => {
+	ElMessageBox.confirm(`您确定要下载课件,是否继续?`, '提示', {
+		confirmButtonText: '确认',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		cancelButtonClass: 'default-button',
+		autofocus: false,
+	})
+		.then(() => {
+			fileDownloadByUrl({
+				Source: 'hotline',
+				Id: row.attachmentId,
+			}).then((res: any) => {
+				let blob: Blob = new Blob([res.data], { type: res.data.type }); // 创建blob 设置blob文件类型 data 设置为后端返回的文件(例如mp3,jpeg) type:这里设置后端返回的类型 为 mp3
+				let down: HTMLAnchorElement = document.createElement('a'); // 创建A标签
+				let href: string = window.URL.createObjectURL(blob); // 创建下载的链接
+				down.href = href; // 下载地址
+				down.download = row.name; // 下载文件名
+				document.body.appendChild(down);
+				down.click(); // 模拟点击A标签
+				document.body.removeChild(down); // 下载完成移除元素
+				window.URL.revokeObjectURL(href); // 释放blob对象
+			});
+		})
+		.catch(() => {});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>
+<style lang="scss">
+.topContent {
+	padding: 10px 30px;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+.topContent .surplusBox {
+	text-align: center;
+}
+.topContent .surplusBox .surplus {
+	font-size: 18px;
+	color: #000000;
+}
+.topContent .titleBox {
+	text-align: center;
+}
+.topContent .titleBox .title {
+	font-size: 20px;
+	font-weight: bold;
+	letter-spacing: 1px;
+	color: #000000;
+}
+.topContent .submitBox {
+	text-align: right;
+	vertical-align: top;
+}
+.examListContent .examType {
+	font-weight: bold;
+	color: #000000;
+}
+.examListContent .examList {
+	padding: 5px 0 10px;
+}
+.examListContent .examList .examListItem {
+	display: inline-block;
+	margin: 5px 10px 5px 0;
+	text-align: center;
+	width: 50px;
+	height: 35px;
+	line-height: 35px;
+	cursor: pointer;
+	position: relative;
+	border: #f2f2f2 1px solid;
+}
+.examListContent .examList .right::after {
+	content: ' ';
+	width: 5px;
+	height: 5px;
+	position: absolute;
+	top: 2px;
+	right: 3px;
+	background-color: #009688;
+	border-radius: 50%;
+}
+.examListContent .examList .error::after {
+	content: ' ';
+	width: 5px;
+	height: 5px;
+	position: absolute;
+	top: 2px;
+	right: 3px;
+	background-color: #ff5722;
+	border-radius: 50%;
+}
+.examListContent .examList .select {
+	background-color: #1890ff;
+	color: #fff;
+}
+.questionBox {
+	padding: 20px 10px 0;
+}
+.questionBox .questionTitle {
+	margin-bottom: 10px;
+	font-size: 16px;
+}
+.questionBox .questionAnswer {
+	padding: 0 20px;
+}
+.referenceAnswer {
+	background-color: #ebf9ff;
+	margin: 15px 40px 15px 30px;
+	padding: 10px;
+}
+.referenceAnswer span {
+	display: block;
+}
+.referenceAnswer p {
+	width: calc(100% - 80px);
+	display: block;
+	margin-top: 10px;
+	color: #1890ff;
+	cursor: pointer;
+}
+</style>

+ 283 - 0
src/views/examTrain/exam/marking/components/Exam-Marking.vue

@@ -0,0 +1,283 @@
+<template>
+	<div class="exam-train-exam-marking-edit-container layout-padding">
+		<div class="exam-train-exam-marking-edit-container-box pd20 h100">
+			<splitpanes :horizontal="false">
+				<pane min-size="16" max-size="25" size="16" class="left-container">
+					<p class="border-title mb20">考试人员</p>
+					<el-scrollbar ref="scrollBarRef" style="height: calc(100% - 55px)" always>
+						<el-auto-resizer class="table">
+							<template #default="{ height }">
+								<el-skeleton :loading="state.userLoading" animated :rows="10">
+									<template #default>
+										<el-tree-v2
+											:data="state.userList"
+											highlight-current
+											:expand-on-click-node="false"
+											node-key="id"
+											:props="{ children: 'children', label: 'userName' }"
+											@node-click="handleNodeClick"
+											:current-node-key="state.userList[0]?.id"
+											ref="treeRef"
+											:item-size="36"
+											empty-text="暂无数据"
+											:height="height"
+										>
+										</el-tree-v2>
+									</template>
+								</el-skeleton>
+							</template>
+						</el-auto-resizer>
+					</el-scrollbar>
+				</pane>
+				<pane class="right-container">
+					<p class="border-title mb20">阅卷试卷</p>
+					<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+						<el-scrollbar style="height: calc(100% - 32px)" always v-loading="state.loading">
+							<div class="h100 w100 exam-container">
+								<div v-for="item in state.examList" :key="item.id" class="exam-item">
+									<p class="exam-item-questionName">题目:{{ item.questionName }}</p>
+									<p class="exam-item-answer">回答答案:{{ item.answer }}</p>
+									<el-divider></el-divider>
+									<p class="exam-item-referenceAnswer">参考答案:{{ item.referenceAnswer }}</p>
+									<div class="exam-item-score">
+										分数:
+										<span v-if="isView">{{ item.score }}</span>
+										<el-input-number
+											v-model="item.score"
+											:step="1"
+											:precision="0"
+											:min="0"
+											:max="100"
+											placeholder="请填写分数"
+											style="width: 200px"
+											v-else
+										></el-input-number>
+									</div>
+									<el-divider></el-divider>
+								</div>
+							</div>
+						</el-scrollbar>
+					</div>
+					<div class="flex-center-between flex-center-align">
+						<el-text type="danger" tag="b" class="mr20" v-if="!isView">温馨提示:保存仅保存当前用户的试卷分数</el-text>
+						<span v-else></span>
+						<div>
+							<el-button type="primary" @click="onSave(ruleFormRef)" :loading="state.loading" v-if="!isView">保存</el-button>
+							<!--							<el-button type="primary" @click="onSubmit" :loading="state.loading">提交</el-button>-->
+							<el-button class="default-button" @click="onCancel" :loading="state.loading">关闭 </el-button>
+						</div>
+					</div>
+				</pane>
+			</splitpanes>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts" name="examTrainExamMarkingEdit">
+import { computed, onMounted, reactive, ref } from 'vue';
+import type { FormInstance } from 'element-plus';
+import { ElMessage } from 'element-plus';
+import mittBus from '@/utils/mitt';
+import { useRoute, useRouter } from 'vue-router';
+import { Splitpanes, Pane } from 'splitpanes';
+import 'splitpanes/dist/splitpanes.css';
+import { Local } from '@/utils/storage';
+import other from '@/utils/other';
+import { throttle, transformFile, guid } from '@/utils/tools';
+import { addExamManage, editExamManage, getExamManageDetail, getTestPaperQuestionCount } from '@/api/examTrain/examManage';
+import { getMarkingDetailByUser, getMarkingDetailUser } from '@/api/examTrain/marking';
+
+// 定义变量内容
+const state = reactive<any>({
+	loading: false,
+	userList: [], // 用户列表
+	queryParams: {},
+	userLoading: false,
+	UserId: null, // 用户ID
+	examList: [], // 试卷列表
+});
+
+const route = useRoute(); // 获取路由
+const router = useRouter(); // 路由跳转
+const ruleFormRef = ref<any>(); // 表单ref
+// 点击人员查询试卷
+const handleNodeClick = (data: any) => {
+	state.userId = data.id;
+	getExamManageDetailData();
+};
+// 获取用户列表
+const routeParams = route.params;
+const getUserList = async () => {
+	const mockUserList = [
+		{
+			id: '999',
+			userName: '张伟',
+		},
+		{
+			id: '888',
+			userName: '吴迪',
+		},
+	];
+	state.userLoading = true;
+	try {
+		/*	const { result } = await getMarkingDetailUser({ ExamId: route.params.examId });
+		state.userList = result ?? [];
+		state.userLoading = false;
+		state.UserId = result[0]?.userId;
+		await getExamManageDetailData();*/
+		state.userList = other.deepClone(mockUserList);
+		state.UserId = mockUserList[0]?.id;
+		setTimeout(() => {
+			state.userLoading = false;
+			getExamManageDetailData();
+		}, 500);
+	} catch (error) {
+		console.error(error);
+		state.userLoading = false;
+	}
+};
+// 获取试卷内容
+const getExamManageDetailData = async () => {
+	state.loading = true;
+	try {
+		/*		const { result } = await getMarkingDetailByUser({ ExamId: route.params.examId, UserId: state.UserId });
+		console.log(result);*/
+		setTimeout(() => {
+			// 模拟数据
+			if (isView) {
+				state.examList = [
+					{
+						id: '1',
+						questionName: '经销商员工管理,如新增员工信息需()在创建角色。',
+						answer: '电脑上',
+						referenceAnswer: '(电脑端)',
+						score: 100,
+					},
+					{
+						id: '2',
+						questionName: '上级经销商一键入库后,()无法一键入库只能扫码入库。',
+						answer: '',
+						referenceAnswer: '(分销商)',
+						score: 0,
+					},
+					{
+						id: '3',
+						questionName: '客户需妥善管理经销商登录密码,密码重置需(),暂不支持自行重置。',
+						answer: '管理员',
+						referenceAnswer: '(超级管理员)',
+						score: 100,
+					},
+				];
+			} else {
+				state.examList = [
+					{
+						id: '1',
+						questionName: '经销商员工管理,如新增员工信息需()在创建角色。',
+						answer: '电脑上',
+						referenceAnswer: '(电脑端)',
+						score: null,
+					},
+					{
+						id: '2',
+						questionName: '上级经销商一键入库后,()无法一键入库只能扫码入库。',
+						answer: '分销商',
+						referenceAnswer: '(分销商)',
+						score: null,
+					},
+					{
+						id: '3',
+						questionName: '客户需妥善管理经销商登录密码,密码重置需(),暂不支持自行重置。',
+						answer: '管理员',
+						referenceAnswer: '(超级管理员)',
+						score: null,
+					},
+				];
+			}
+			state.loading = false;
+		}, 500);
+	} catch (error) {
+		console.error(error);
+		state.loading = false;
+	}
+};
+// 保存提交
+const onSave = throttle((formEl: FormInstance | undefined) => {
+	state.loading = true;
+	handleSuccess();
+	/*	if (!formEl) return;
+	 formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const submitObj = other.deepClone(state.ruleForm);
+		 handleSuccess();
+	});*/
+}, 300);
+// 提交
+const onSubmit = () => {};
+// 取消
+const onCancel = () => {
+	state.loading = true;
+	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
+	mittBus.emit('clearCache', 'examTrainExamMarking');
+	router.push({
+		path: '/examTrain/exam/marking',
+	});
+	state.loading = false;
+};
+const handleSuccess = () => {
+	setTimeout(() => {
+		state.loading = false;
+		ElMessage.success('保存成功');
+	}, 500);
+	// 关闭当前 tagsView
+	/*	mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
+	mittBus.emit('clearCache', 'examTrainExamMarking');
+	router.push({
+		path: '/examTrain/exam/marking',
+	});*/
+};
+// 是否查看
+const isView = computed(() => {
+	return route.params.isView === 'true';
+});
+onMounted(() => {
+	state.queryParams.ExamId = routeParams.examId;
+	getUserList();
+});
+</script>
+<style lang="scss" scoped>
+.exam-train-exam-marking-edit-container {
+	.exam-train-exam-marking-edit-container-box {
+		background-color: var(--el-color-white);
+		overflow: hidden;
+	}
+	.right-container {
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+	}
+}
+:deep(.el-tree-node__content) {
+	height: 40px;
+}
+.exam-container {
+	.exam-item {
+		margin-bottom: 20px;
+		&-questionName {
+			font-size: 16px;
+			margin-bottom: 10px;
+		}
+		&-answer {
+			text-indent: 1em;
+			margin-bottom: 10px;
+		}
+		&-referenceAnswer {
+			display: block;
+			background-color: var(--hotline-bg-color);
+			margin: 0 10px 10px 10px;
+			padding: 10px 5px;
+			text-indent: 1em;
+		}
+	}
+}
+</style>

+ 188 - 0
src/views/examTrain/exam/marking/index.vue

@@ -0,0 +1,188 @@
+<template>
+	<div class="exam-train-exam-marking-container layout-padding">
+		<div class="layout-padding-auto layout-padding-view pd20">
+			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent :disabled="state.tableLoading">
+				<el-form-item label="是否批改" prop="isCheck">
+					<el-select v-model="state.queryParams.isCheck" clearable placeholder="请选择是否批改" @change="handleQuery">
+						<el-option label="已批改完成" :value="true" />
+						<el-option label="未批改完成" :value="false" />
+					</el-select>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+						<SvgIcon name="ele-Refresh" class="mr5" />重置
+					</el-button>
+				</el-form-item>
+			</el-form>
+			<vxe-toolbar
+				ref="toolbarRef"
+				:loading="state.tableLoading"
+				custom
+				:refresh="{
+					queryMethod: handleQuery,
+				}"
+			>
+			</vxe-toolbar>
+			<div style="overflow: hidden; width: 100%; height: 100%; flex: 1">
+				<vxe-table
+					border
+					:loading="state.tableLoading"
+					:data="state.tableData"
+					:column-config="{ resizable: true }"
+					:row-config="{ isCurrent: true, isHover: true, height: 30, useKey: true }"
+					ref="tableRef"
+					height="auto"
+					auto-resize
+					show-overflow
+					:print-config="{}"
+					:scrollY="{ enabled: true, gt: 100 }"
+					id="examTrainExamMarking"
+					:custom-config="{ storage: true }"
+					showHeaderOverflow
+				>
+					<vxe-column field="examCode" title="考试编号" width="200"></vxe-column>
+					<vxe-column field="examName" title="考试标题" min-width="200"></vxe-column>
+					<vxe-column field="totalScore" title="考试总分" width="150"></vxe-column>
+					<vxe-column field="cutoffScore" title="合格分数" width="150"></vxe-column>
+					<vxe-column field="isCheck" title="是否批改" width="150">
+						<template #default="{ row }">
+							{{ row.isCheck ? '已批改完成' : '未批改完成' }}
+						</template>
+					</vxe-column>
+					<vxe-column field="remark" title="备注" min-width="200"></vxe-column>
+					<vxe-column title="操作" fixed="right" width="80" align="center" :show-overflow="false">
+						<template #default="{ row }">
+							<el-button link type="primary" @click="onView(row)" title="查看" v-if="row.isCheck"> 查看 </el-button>
+							<el-button link type="primary" @click="onMarking(row)" title="阅卷" v-else> 阅卷 </el-button>
+						</template>
+					</vxe-column>
+				</vxe-table>
+			</div>
+			<pagination
+				@pagination="queryList"
+				:total="state.total"
+				v-model:current-page="state.queryParams.PageIndex"
+				v-model:page-size="state.queryParams.PageSize"
+				:disabled="state.tableLoading"
+			/>
+		</div>
+		<!-- 阅卷查看	-->
+		<exam-marking-view ref="examMarkingViewRef" />
+	</div>
+</template>
+
+<script lang="tsx" setup name="examTrainExamMarking">
+import { ref, reactive, onMounted, defineAsyncComponent } from 'vue';
+import 'splitpanes/dist/splitpanes.css';
+import Other from '@/utils/other';
+import { FormInstance } from 'element-plus';
+import { getMarkingList } from '@/api/examTrain/marking';
+import { useRouter } from 'vue-router';
+import other from '@/utils/other';
+
+// 引入组件
+const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
+const ExamMarkingView = defineAsyncComponent(() => import('@/views/examTrain/exam/marking/components/Exam-Marking-View.vue')); // 阅卷查看
+
+// 定义变量内容
+const state = reactive<any>({
+	queryParams: {
+		PageIndex: 1, //页码
+		PageSize: 20, //每页条数
+		isCheck: null, // 是否批改
+	},
+	tableLoading: false, //表格loading
+	tableData: [], //表格数据
+	total: 0, //总条数
+});
+/** 搜索按钮操作 节流操作 */
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+/** 获取试题列表 */
+const requestParams = ref<EmptyObjectType>({});
+const queryList = () => {
+	state.tableLoading = true;
+	requestParams.value = Other.deepClone(state.queryParams);
+	const data = [
+		{
+			examCode: '20251001',
+			examName: '2025年秋季学期数学期末考试',
+			totalScore: 100,
+			cutoffScore: 60,
+			isCheck: true,
+			remark: '2025年秋季学期数学期末考试',
+			id: '0',
+		},
+		{
+			examCode: '20251002',
+			examName: '2025年秋季学期英语期末考试',
+			totalScore: 100,
+			cutoffScore: 60,
+			isCheck: false,
+			remark: '2025年秋季学期英语期末考试',
+			id: '1',
+		},
+	];
+	// 模拟查询
+	setTimeout(() => {
+		if (state.queryParams.isCheck === null) {
+			state.tableLoading = false;
+			state.tableData = other.deepClone(data);
+			return;
+		}
+		console.log('请求参数', requestParams.value);
+		// 模拟数据
+		state.tableData = data.filter((item) => item.isCheck === state.queryParams.isCheck);
+		state.tableLoading = false;
+	}, 500);
+	/*	getMarkingList(requestParams.value)
+		.then((response: any) => {
+			state.tableData = response?.result.items ?? [];
+			state.total = response?.result.pagination.totalCount ?? 0;
+			state.tableLoading = false;
+		})
+		.catch(() => {
+			state.tableLoading = false;
+		});*/
+};
+/** 重置按钮操作 */
+const ruleFormRef = ref<RefType>(); // 表单ref
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+// 阅卷
+const router = useRouter(); //路由
+const onMarking = (row: any) => {
+	router.push({
+		name: 'examTrainExamMarkingEdit',
+		params: {
+			tagsViewName: `阅卷 ${row.examName}`,
+			examId: row.id,
+		},
+	});
+};
+// 阅卷查看
+const onView = (row: any) => {
+	router.push({
+		name: 'examTrainExamMarkingEdit',
+		params: {
+			tagsViewName: `阅卷 ${row.examName}`,
+			examId: row.id,
+			isView: 'true',
+		},
+	});
+};
+const tableRef = ref<RefType>();
+const toolbarRef = ref<RefType>();
+onMounted(() => {
+	queryList();
+	if (tableRef.value && toolbarRef.value) {
+		tableRef.value.connect(toolbarRef.value);
+	}
+});
+</script>

+ 2 - 2
src/views/todo/edit/index.vue

@@ -146,8 +146,8 @@
 				</el-form-item>
 				<el-form-item label="归档类型" prop="FiledType">
 					<el-select v-model="state.queryParams.FiledType" placeholder="请选择归档类型" @change="handleQuery" clearable>
-						<el-option label="中心归档" value="10" />
-						<el-option label="部门归档" value="20" />
+						<el-option label="中心归档" :value="10" />
+						<el-option label="部门归档" :value="20" />
 					</el-select>
 				</el-form-item>
 				<el-form-item label="期满时间" prop="exTime">

+ 1 - 8
src/views/todo/seats/accept/lzAccept.vue

@@ -423,7 +423,7 @@
 </template>
 
 <script setup lang="ts" name="orderAccept">
-import { computed, defineAsyncComponent, onActivated, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
+import { computed, defineAsyncComponent, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
 import { ElLoading, FormInstance } from 'element-plus';
 import { ElMessage } from 'element-plus';
 import { storeToRefs } from 'pinia';
@@ -1358,13 +1358,6 @@ onMounted(async () => {
 onUnmounted(() => {
 	window.removeEventListener('beforeunload', handleBeforeUnload);
 });
-onActivated(() => {
-	// 判断当前路由参数是否和已有数据匹配,不匹配就重新加载
-	if (state.ruleForm.fromPhone !== route.query.fromTel) {
-		resetForm();
-		loadBaseData();
-	}
-});
 </script>
 <style lang="scss" scoped>
 .check-group {