Browse Source

Merge branch 'master' of http://git.qmth.com.cn/markingcloud/stmms-web into release_1.4.0

刘洋 2 năm trước cách đây
mục cha
commit
7d3c8011b8

+ 72 - 72
src/devLoginParams.ts

@@ -1,72 +1,72 @@
-/** 224 评卷员 */
-// export const LOGIN_CONFIG = {
-// };
-// export const isAdmin= false;
-// export const forceChange=true;
-// export const loginName="1-431-5-1";
-// export const password="123456";
-// export const examId="1";
-// export const markerId="419";
-
-/** 244 评卷员 */
-export const LOGIN_CONFIG = {
-  isAdmin: false,
-  forceChange: true,
-  loginName: "1-339-5-1",
-  // loginName: "liuyang",
-  password: "123456",
-  examId: "1",
-  markerId: "147",
-  // markerId: "482",
-  // markerId: "483",
-};
-// export const LOGIN_CONFIG = {
-//   isAdmin: false,
-//   forceChange: false,
-//   loginName: "spj111-01",
-//   // loginName: "spj432-01",
-//   // loginName: "liuyang",
-//   password: "123456",
-//   examId: "232",
-//   markerId: "2688",
-//   // markerId: "2692",
-//   // markerId: "482",
-//   // markerId: "483",
-// };
-/** 224 管理员 */
-// export const LOGIN_CONFIG = {
-//   isAdmin: true,
-//   forceChange: true,
-//   loginName: "admin-test",
-//   password: "123456",
-//   examId: "1",
-//   markerId: "339",
-// };
-
-/** 255 评卷员 */
-// export const LOGIN_CONFIG = {
-//   isAdmin: false,
-//   forceChange: true,
-//   loginName: "4-1-1",
-//   password: "123456",
-//   examId: "128",
-//   markerId: "2258",
-// };
-
-/** 225 管理员 */
-
-// export const LOGIN_CONFIG = {
-//   isAdmin: true,
-//   forceChange: true,
-//   loginName: "admin3",
-//   password: "123456",
-//   examId: "130",
-//   markerId: "null",
-// };
-
-// export const loginName = "admin-ch";
-// export const password = "123456";
-// export const examId = "1";
-// export const markerId = "null";
-// export const isAdmin = true;
-// export const forceChange = true;
+/** 224 评卷员 */
+// export const LOGIN_CONFIG = {
+// };
+// export const isAdmin= false;
+// export const forceChange=true;
+// export const loginName="1-431-5-1";
+// export const password="123456";
+// export const examId="1";
+// export const markerId="419";
+
+/** 244 评卷员 */
+// export const LOGIN_CONFIG = {
+//   isAdmin: false,
+//   forceChange: true,
+//   loginName: "1-339-5-1",
+//   // loginName: "liuyang",
+//   password: "123456",
+//   examId: "1",
+//   markerId: "147",
+//   // markerId: "482",
+//   // markerId: "483",
+// };
+// export const LOGIN_CONFIG = {
+//   isAdmin: false,
+//   forceChange: false,
+//   loginName: "spj111-01",
+//   // loginName: "spj432-01",
+//   // loginName: "liuyang",
+//   password: "123456",
+//   examId: "232",
+//   markerId: "2688",
+//   // markerId: "2692",
+//   // markerId: "482",
+//   // markerId: "483",
+// };
+/** 224 管理员 */
+export const LOGIN_CONFIG = {
+  isAdmin: true,
+  forceChange: true,
+  loginName: "admin-test",
+  password: "123456",
+  examId: "1",
+  markerId: "339",
+};
+
+/** 255 评卷员 */
+// export const LOGIN_CONFIG = {
+//   isAdmin: false,
+//   forceChange: true,
+//   loginName: "4-1-1",
+//   password: "123456",
+//   examId: "128",
+//   markerId: "2258",
+// };
+
+/** 225 管理员 */
+
+// export const LOGIN_CONFIG = {
+//   isAdmin: true,
+//   forceChange: true,
+//   loginName: "admin3",
+//   password: "123456",
+//   examId: "130",
+//   markerId: "null",
+// };
+
+// export const loginName = "admin-ch";
+// export const password = "123456";
+// export const examId = "1";
+// export const markerId = "null";
+// export const isAdmin = true;
+// export const forceChange = true;

+ 18 - 5
src/features/admin/confirmPaper/ConfirmPaper.vue

@@ -1,5 +1,5 @@
 <template>
-  <div v-if="!dataError" class="tw-h-screen">
+  <div v-if="!dataError" class="tw-h-screen confirm-paper">
     <header
       class="tw-flex tw-gap-2 tw-justify-between tw-items-center header-container"
     >
@@ -51,14 +51,14 @@
         class="tw-flex tw-flex-col tw-justify-between"
       >
         <div class="tw-m-2 tw-flex-1 tw-overflow-auto">
-          <div v-if="pageType === 'DATA_CHECK'">
+          <div v-if="pageType === 'DATA_CHECK'" class="tw-my-2 top-block">
             是否缺考:
             <a-radio-group v-if="student" v-model:value="student.absent">
               <a-radio :value="true">是</a-radio>
               <a-radio :value="false">否</a-radio>
             </a-radio-group>
           </div>
-          <div v-if="pageType === 'DATA_CHECK'" class="tw-my-2">
+          <div v-if="pageType === 'DATA_CHECK'" class="tw-my-2 top-block">
             试卷类型:
             <a-input
               v-if="student"
@@ -90,7 +90,8 @@
                   <a-input
                     class="normal-input"
                     :class="{
-                      'long-input': group.mainTitle.match(/多选|多项|不定项/),
+                      'long-input': group.mainTitle.match(/单选|多选|多项|不定项/),
+                      'middle-input': group.mainTitle.match(/判断/),
                     }"
                     :value="question.answer"
                     :maxLength="
@@ -501,6 +502,10 @@ function rotateRight() {
   width: 94px;
   padding: 4px;
 }
+.normal-input.middle-input{
+  width: 61px !important;
+  padding: 4px;
+}
 .header-container {
   position: relative;
   height: 56px;
@@ -537,4 +542,12 @@ function rotateRight() {
   visibility: hidden;
   opacity: 0;
 }
-</style>
+.confirm-paper .top-block{
+  background-color:#fff;
+  height:50px;
+  padding:0 20px;
+  display:flex;
+  align-items:center;
+  border-radius:6px;
+}
+</style>

+ 6 - 2
src/features/arbitrate/Arbitrate.vue

@@ -52,7 +52,7 @@ import PaperModal from "../mark/PaperModal.vue";
 import { getPaper } from "@/api/jsonMark";
 import { getArbitrateHistory } from "@/api/arbitratePage";
 import EventBus from "@/plugins/eventBus";
-import { addFileServerPrefixToTask } from "@/utils/utils";
+import { addFileServerPrefixToTask,preDrawImage } from "@/utils/utils";
 import { isNumber } from "lodash-es";
 import type { Question } from "@/types";
 
@@ -114,7 +114,11 @@ async function updateTask() {
 
   if (res.data.studentId) {
     let rawTask = res.data;
-    store.currentTask = addFileServerPrefixToTask(rawTask);
+    let t = addFileServerPrefixToTask(rawTask);
+    if (store.isScanImage && !!t) {
+        await preDrawImage(t);
+      }
+    store.currentTask = t;
   } else {
     store.message = res.data.message;
   }

+ 5 - 3
src/features/mark/CommonMarkBody.vue

@@ -70,9 +70,9 @@
         {{ store.currentQuestion?.mainNumber }}-{{
           store.currentQuestion?.subNumber
         }}({{
-          store.currentTask?.markResult.scoreList[
+          store.currentTask?.markResult?store.currentTask?.markResult.scoreList[
             store.currentQuestion?.__index || 0
-          ] || " "
+          ] : " "
         }})
       </div>
       <div class="text">
@@ -460,6 +460,8 @@ async function processSplitConfig() {
 // should not render twice at the same time
 let renderLock = false;
 const renderPaperAndMark = async () => {
+  console.log('renderPagerAndMark=>store.curTask:',store.currentTask);
+  
   if (!store.currentTask) return;
   if (!store.isScanImage) return;
   if (renderLock) {
@@ -513,7 +515,7 @@ const renderPaperAndMark = async () => {
 watch(
   () => store.currentTask,
   () => {
-    setTimeout(renderPaperAndMark,1)
+    setTimeout(renderPaperAndMark,50)
   }
 );
 //#endregion : 计算裁切图和裁切图上的分数轨迹和特殊标记轨迹

+ 12 - 8
src/features/mark/Mark.vue

@@ -159,6 +159,17 @@ async function updateTask() {
   if (res.data.libraryId) {
     let rawTask = res.data;
     const newTask = addFileServerPrefixToTask(rawTask);
+
+    try {
+      preDrawing = true;
+      if (store.isScanImage) {
+        await preDrawImage(newTask);
+      }
+    } finally {
+      // console.log("preDrawing失败")
+      preDrawing = false;
+    }
+
     store.tasks.push(newTask);
     if (!store.historyOpen) {
       // 在正评中,才能替换task
@@ -176,14 +187,7 @@ async function updateTask() {
       // 如果不是当前任务,则先等3秒再去取任务,以免和其他请求争夺网络资源
       await new Promise((resolve) => setTimeout(resolve, 3000));
     }
-    try {
-      preDrawing = true;
-      if (store.isScanImage) {
-        await preDrawImage(newTask);
-      }
-    } finally {
-      preDrawing = false;
-    }
+
   } else {
     store.message = res.data.message;
   }

+ 2 - 2
src/features/mark/MarkBoardKeyBoard.vue

@@ -33,9 +33,9 @@
         <div class="total-score tw-ml-5 tw-font-bold">
           <transition-group name="score-number-animation" tag="span">
             <span
-              :key="store.currentTaskEnsured.markResult.markerScore || 0"
+              :key="store.currentTaskEnsured.markResult?store.currentTaskEnsured.markResult.markerScore+'' :'0'"
               class="tw-inline-block"
-              >{{ store.currentTaskEnsured.markResult.markerScore }}</span
+              >{{ store.currentTaskEnsured.markResult?store.currentTaskEnsured.markResult.markerScore:'' }}</span
             >
           </transition-group>
         </div>

+ 19 - 6
src/features/mark/MarkHistory.vue

@@ -116,7 +116,8 @@ import {
 } from "@ant-design/icons-vue";
 import { cloneDeep } from "lodash-es";
 import EventBus from "@/plugins/eventBus";
-import { addFileServerPrefixToTask } from "@/utils/utils";
+import { addFileServerPrefixToTask,preDrawImageHistory} from "@/utils/utils";
+import { message } from "ant-design-vue";
 
 const {
   title = "回评",
@@ -162,13 +163,16 @@ const currentTaskChange = async () => {
       });
     } catch (e) {
       // 恢复以前的行为,取回评失败则评卷任务为空
-      replaceCurrentTask(undefined);
+      await replaceCurrentTask(undefined);
     } finally {
       // store.globalMask = false;
+      if(store.setting?.examType !== 'SCAN_IMAGE'){
+        store.globalMask = false;
+      }
     }
-    replaceCurrentTask(store.historyTasks[0]);
+    await replaceCurrentTask(store.historyTasks[0]);
   } else {
-    replaceCurrentTask(store.tasks[0]);
+    await replaceCurrentTask(store.tasks[0]);
     store.historyTasks.splice(0);
     secretNumberInput = "";
     currentPage = 1;
@@ -253,15 +257,24 @@ async function updateHistoryTask({
     let data = cloneDeep(res.data) ;
     data = data.map(addFileServerPrefixToTask);
     store.historyTasks = data;
-    replaceCurrentTask(store.historyTasks[0]);
+    replaceCurrentTask(store.historyTasks[0]).catch((err)=>{
+      console.log(err);
+      void message.error('切换至回评任务失败');
+    });
   }
   if(!res?.data || !res?.data.length){
     store.globalMask = false;
   }
 }
 
-function replaceCurrentTask(task: Task | undefined) {
+async function replaceCurrentTask(task: Task | undefined) {
+  console.log('replaceCurrentTask:',task);
+  
+  if (store.isScanImage && !!task) {
+    await preDrawImageHistory(task);
+  }
   store.currentTask = task;
+
 }
 
 function previousPage() {

+ 83 - 2
src/utils/utils.ts

@@ -167,12 +167,15 @@ export async function getDataUrlForSplitConfig(
   return dataurl;
 }
 
-export async function preDrawImage(_currentTask: Task) {
+export async function preDrawImage(_currentTask: Task | undefined) {
+  console.log('preDrawImage=>curTask:',store.currentTask);
+  
   if (!_currentTask?.libraryId) return;
 
   let maxSliceWidth = 0; // 最大的裁切块宽度,图片容器以此为准
 
-  const hasSliceConfig = store.currentTask?.sliceConfig?.length;
+  // const hasSliceConfig = store.currentTask?.sliceConfig?.length;
+  const hasSliceConfig = _currentTask?.sliceConfig?.length;
 
   const images = [];
 
@@ -241,6 +244,84 @@ export async function preDrawImage(_currentTask: Task) {
   }
 }
 
+export async function preDrawImageHistory(_currentTask: Task | undefined) {
+  console.log('preDrawImageHistory=>curTask:',store.currentTask);
+  
+  if (!_currentTask?.libraryId) return;
+
+  let maxSliceWidth = 0; // 最大的裁切块宽度,图片容器以此为准
+
+  // const hasSliceConfig = store.currentTask?.sliceConfig?.length;
+  const hasSliceConfig = _currentTask?.sliceConfig?.length;
+
+  const images = [];
+
+  if (hasSliceConfig) {
+    // 必须要先加载一遍,把“选择整图”的宽高重置后,再算总高度
+    const sliceNum = _currentTask.sliceUrls.length;
+    if (_currentTask.sliceConfig.some((v) => v.i > sliceNum)) {
+      console.warn("裁切图设置的数量小于该学生的总图片数量");
+    }
+    _currentTask.sliceConfig = _currentTask.sliceConfig.filter(
+      (v) => v.i <= sliceNum
+    );
+    for (const sliceConfig of _currentTask.sliceConfig) {
+      const url = _currentTask.sliceUrls[sliceConfig.i - 1];
+      const image = await loadImage(url);
+      images[sliceConfig.i] = image;
+      if (sliceConfig.w === 0 && sliceConfig.h === 0) {
+        // 选择整图时,w/h 为0
+        sliceConfig.w = image.naturalWidth;
+        sliceConfig.h = image.naturalHeight;
+      }
+    }
+
+    maxSliceWidth = Math.max(..._currentTask.sliceConfig.map((v) => v.w));
+
+    // 用来保存sliceImage在整个图片容器中(不包括image-seperator)的高度范围
+    for (const sliceConfig of _currentTask.sliceConfig) {
+      const url = _currentTask.sliceUrls[sliceConfig.i - 1];
+      const image = images[sliceConfig.i];
+
+      try {
+        await getDataUrlForSliceConfig(image, sliceConfig, maxSliceWidth, url);
+      } catch (error) {
+        console.log("preDrawImage failed: ", error);
+      }
+    }
+  } else {
+    for (const url of _currentTask.sliceUrls) {
+      const image = await loadImage(url);
+      images.push(image);
+    }
+
+    const splitConfigPairs = store.setting.splitConfig.reduce<
+      [number, number][]
+    >((a, v, index) => {
+      index % 2 === 0 ? a.push([v, -1]) : (a.at(-1)![1] = v);
+      return a;
+    }, []);
+
+    const maxSplitConfig = Math.max(...store.setting.splitConfig);
+    maxSliceWidth =
+      Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;
+
+    for (const url of _currentTask.sliceUrls) {
+      for (const config of splitConfigPairs) {
+        const indexInSliceUrls = _currentTask.sliceUrls.indexOf(url) + 1;
+        const image = images[indexInSliceUrls - 1];
+
+        try {
+          await getDataUrlForSplitConfig(image, config, maxSliceWidth, url);
+        } catch (error) {
+          console.log("preDrawImage failed: ", error);
+        }
+      }
+    }
+  }
+}
+
+
 export function addFileServerPrefixToTask(rawTask: Task): Task {
   const newTask = JSON.parse(JSON.stringify(rawTask)) as Task;
 

+ 1 - 0
vite.config.ts

@@ -4,6 +4,7 @@ import ViteComponents from "unplugin-vue-components/vite";
 import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
 
 const SERVER_URL = "http://192.168.10.224";
+
 const path = require("path");
 
 function mockDevLogin(): Plugin {