Browse Source

feat: 调试

zhangjie 1 month ago
parent
commit
283bf808c8

+ 42 - 0
README.md

@@ -50,3 +50,45 @@ src/features/student/studentInspect/MarkBody.vue 整卷渲染的组件,凡是
 3. history watch open , change currentTask
 4. body watch trackList, computed score? emit 'trackListChange'('add', questionIndex, trackList)/('removeLast', questionIndex)/('removeAll',questionIndex)
 5. markboard watch currentQuestion, normal mode -> change scoreList[index]
+
+### 本地开发配置
+
+- 启动本项目:
+
+```bash
+# 安装依赖
+npm install
+# 启动
+npm start
+```
+
+- 配置 nginx:
+
+```conf
+# 云阅卷开发
+server {
+  listen       8071;
+  server_name  localhost;
+  # 管理端
+  location / {
+    proxy_pass  http://192.168.10.83:8004;
+  }
+
+  # 阅卷端
+  location /web/ {
+    proxy_pass  http://localhost:9000;
+  }
+
+  # 接口/附件等
+  location ~ ^/(api|admin|login|mark|slice)/ {
+    proxy_pass  http://192.168.10.83:8004;
+  }
+}
+
+```
+
+- 使用管理端账号登录调试。
+
+> 说明:
+> 管理端和阅卷端虽然独立启动,但他们的接口地址是一样的。
+> 单独访问阅卷端,使用的接口是阅卷端配置的接口地址。访问 8071 地址,接口则是 nginx 配置的地址。注意两者的区别。

+ 37 - 11
src/features/mark/Mark.vue

@@ -185,6 +185,8 @@ async function updateTask() {
     // ];
     // 假数据模拟
     // rawTask.questionList[0].selective = true;
+    // rawTask.questionList[5].trackCount = 2;
+    // store.setting.trackCountPolicy = "LE";
 
     const newTask = addFileServerPrefixToTask(rawTask);
 
@@ -279,7 +281,9 @@ const showRejectedReason = (task: Task) => {
     //   "reject-task-showed",
     //   JSON.stringify(rejectShowedTasks)
     // );
-    const [reasonType, reasonDesc] = task.rejectReason.split(":");
+    const conts = task.rejectReason.split(":");
+    const reasonType = conts[0];
+    const reasonDesc = conts.slice(1).join(":");
     Modal.info({
       title: null,
       closable: false,
@@ -464,23 +468,39 @@ const saveTaskToServer = async () => {
     error: string;
   };
 
+  const checkQuestionTrackCountUnvalid = (question: Question) => {
+    const tracks = (store.currentTask?.markResult?.trackList || []).filter(
+      (track: any) =>
+        track.mainNumber == question?.mainNumber &&
+        track.subNumber == question?.subNumber
+    );
+    const trackCount = Number(question?.trackCount) || 0;
+    const countValid =
+      store.setting.trackCountPolicy === "EQ"
+        ? tracks.length === trackCount
+        : tracks.length <= trackCount;
+
+    return store.isTrackMode && trackCount > 0 && !countValid;
+  };
+
   const errors: SubmitError[] = [];
   markResult.scoreList.forEach((score, index) => {
     if (!store.currentTask) return;
     const question = store.currentTask.questionList[index]!;
+    const qno = `${question.mainNumber}-${question.subNumber}${
+      question.questionName ? "(" + question.questionName + ")" : ""
+    }`;
     let error;
     if (!isNumber(score) && !question.hasSetUnselective) {
-      error = `${question.mainNumber}-${question.subNumber}${
-        question.questionName ? "(" + question.questionName + ")" : ""
-      } 没有给分,不能提交。`;
+      error = `${qno} 没有给分,不能提交。`;
     } else if (isNumber(question.maxScore) && score > question.maxScore) {
-      error = `${question.mainNumber}-${question.subNumber}${
-        question.questionName ? "(" + question.questionName + ")" : ""
-      } 给分大于最高分不能提交。`;
+      error = `${qno} 给分大于最高分不能提交。`;
     } else if (isNumber(question.minScore) && score < question.minScore) {
-      error = `${question.mainNumber}-${question.subNumber}${
-        question.questionName ? "(" + question.questionName + ")" : ""
-      } 给分小于最低分不能提交。`;
+      error = `${qno} 给分小于最低分不能提交。`;
+    } else if (checkQuestionTrackCountUnvalid(question)) {
+      const policyName =
+        store.setting.trackCountPolicy === "EQ" ? "等于" : "小于等于";
+      error = `${qno} 限制轨迹数量${policyName}${question.trackCount}个,不能提交。`;
     }
     if (error) {
       errors.push({ question, index, error });
@@ -527,10 +547,16 @@ const saveTaskToServer = async () => {
       return;
     }
   }
+  // 强制标记校验
   if (store.setting.forceSpecialTag) {
+    // 是否全部未选做
+    const allUnselective = store.currentTask.questionList.every(
+      (item) => item.hasSetUnselective
+    );
     if (
       markResult.trackList.length === 0 &&
-      markResult.specialTagList.length === 0
+      markResult.specialTagList.length === 0 &&
+      !allUnselective
     ) {
       void message.error({
         content: "强制标记已开启,请至少使用一个标记。",

+ 19 - 9
src/features/mark/MarkBoardTrack.vue

@@ -69,7 +69,7 @@
         </div>
 
         <qm-button
-          v-if="store.currentTask"
+          v-if="canAllSelective"
           type="primary"
           shape="round"
           size="middle"
@@ -336,6 +336,12 @@ const disabledArbitrateType = computed(() => {
     store.setting?.arbitrateType === "QUESTION"
   );
 });
+const canAllSelective = computed(() => {
+  return (
+    store.setting?.enableAllSelective &&
+    store.currentTask.questionList.some((q) => q.selective)
+  );
+});
 const props = defineProps<{ modal?: boolean; arbitrateIndex?: string }>();
 const activeIndex = computed(() => {
   return (
@@ -529,11 +535,8 @@ function limitDisable() {
       track.mainNumber == curQuestion?.mainNumber &&
       track.subNumber == curQuestion?.subNumber
   );
-  return (
-    store.isTrackMode &&
-    Number(curQuestion?.trackCount) > 0 &&
-    arr.length == Number(curQuestion?.trackCount)
-  );
+  const trackCount = Number(curQuestion?.trackCount);
+  return store.isTrackMode && trackCount > 0 && arr.length >= trackCount;
 }
 watch(
   () => store.currentTask?.markResult?.trackList,
@@ -547,7 +550,11 @@ watch(
 function chooseScore(score: number) {
   if (limitDisable()) {
     const curQuestion = store.currentTask?.questionList[curQuestionIndex.value];
-    void message.error(`该题限制轨迹数量为${curQuestion.trackCount}个`);
+    const policyName =
+      store.setting.trackCountPolicy === "EQ" ? "等于" : "小于等于";
+    void message.error(
+      `该题限制轨迹数量${policyName}${curQuestion.trackCount}个`
+    );
     return;
   }
   if (store.currentScore === score) {
@@ -715,13 +722,16 @@ function submit() {
 function setAllUnselective() {
   Modal.confirm({
     centered: true,
+    icon: null,
     mask: true,
     zIndex: 6000,
-    width: "300px",
     maskStyle: { opacity: 0.97 },
-    content: `当前界面未给分的选作题将全部设置为未选,是或否?`,
+    content: `当前界面未给分的选作题将全部设置为未选,是或否?`,
     okText: "是",
     cancelText: "否",
+    bodyStyle: {
+      padding: "15px",
+    },
     onOk: () => {
       store.currentTask.questionList.forEach((q, index) => {
         if (

+ 7 - 1
src/features/student/studentInspect/MarkBoardInspect.vue

@@ -269,9 +269,15 @@ function inspect() {
   }
 
   Modal.warning({
-    zIndex: 2000,
+    zIndex: 6000,
+    icon: null,
+    width: "430px",
+    centered: true,
     title: "选择题合分异常",
     content: `该试卷选作题有异常,存在合分不够的情况,请将异常题打回!`,
+    bodyStyle: {
+      padding: "15px",
+    },
   });
 }
 

+ 2 - 0
src/store/store.ts

@@ -12,6 +12,7 @@ const initState: MarkStore = {
     sheetConfig: [],
     enableAllZero: false,
     enableSplit: true,
+    enableAllSelective: true,
     fileServer: "",
     userName: "",
     subject: <Setting["subject"]>{},
@@ -38,6 +39,7 @@ const initState: MarkStore = {
     endTime: 0,
     selective: false,
     collationLabelList: [],
+    trackCountPolicy: "LE",
   },
   status: <MarkStore["status"]>{},
   groups: [],

+ 4 - 0
src/types/index.ts

@@ -78,6 +78,8 @@ export interface Setting {
   enableAllZero: boolean;
   /** 是否允许裁切 */
   enableSplit: boolean;
+  /** 是否允许一键未选做 */
+  enableAllSelective: boolean;
   /** 图片服务地址 */
   fileServer: string;
   /** 评卷员姓名 */
@@ -119,6 +121,8 @@ export interface Setting {
   /**异常信息code映射表 */
   collationLabelList?: any;
   arbitrateType?: "QUESTION" | "GROUP" | null;
+  /** 每题轨迹数量策略 */
+  trackCountPolicy: "EQ" | "LE";
 }
 
 /** 科目信息(试卷和答案功能) */