瀏覽代碼

评卷调试

zhangjie 1 年之前
父節點
當前提交
e4106b84d0

+ 2 - 2
cypress/fixtures/task-1.json

@@ -1,5 +1,5 @@
 {
-  "libraryId": 30585,
+  "taskId": 30585,
   "studentId": 1581,
   "secretNumber": "46208374",
   "studentName": "兰福坪",
@@ -142,4 +142,4 @@
   "previous": false,
   "rejected": false,
   "self": false
-}
+}

+ 2 - 2
cypress/fixtures/task-2.json

@@ -1,5 +1,5 @@
 {
-  "libraryId": 30586,
+  "taskId": 30586,
   "studentId": 1591,
   "secretNumber": "66186163",
   "studentName": "熊天柱",
@@ -142,4 +142,4 @@
   "previous": false,
   "rejected": false,
   "self": false
-}
+}

+ 2 - 2
cypress/fixtures/task-3.json

@@ -1,5 +1,5 @@
 {
-  "libraryId": 30587,
+  "taskId": 30587,
   "studentId": 1110,
   "secretNumber": "98496150",
   "studentName": "黄帅",
@@ -142,4 +142,4 @@
   "previous": false,
   "rejected": false,
   "self": false
-}
+}

+ 1 - 1
index.html

@@ -5,7 +5,7 @@
   <meta charset="UTF-8" />
   <link rel="icon" href="/favicon.ico" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-  <title>知学知考1</title>
+  <title>知学知考</title>
 </head>
 
 <body>

二進制
public/1-1.jpg


二進制
public/1-2.jpg


+ 5 - 5
src/api/arbitratePage.ts

@@ -7,15 +7,15 @@ import {
   Task,
 } from "@/types";
 
-/** 清理仲裁任务(libraryId 与其他参数互斥填写) */
+/** 清理仲裁任务(taskId 与其他参数互斥填写) */
 export async function clearArbitrateTask(
   // 这里libraryId为string,是因为它也会从query里面取值,同时利用为null的情况不传值到后台
-  libraryId?: string,
+  taskId?: string,
   subjectCode?: string,
   groupNumber?: string
 ) {
   const form = new FormData();
-  libraryId && form.append("groupNumber", libraryId);
+  taskId && form.append("groupNumber", taskId);
   subjectCode && form.append("subjectCode", subjectCode);
   groupNumber && form.append("groupNumber", groupNumber);
   return httpApp.post<void>("/api/admin/exam/arbitrate/clear", form);
@@ -103,7 +103,7 @@ export async function getArbitrateHistory({
 
 /** 保存仲裁任务 */
 export async function saveArbitrateTask(
-  libraryId: string,
+  taskId: string,
   studentId: string,
   markerScore: number,
   scoreList: Array<number>,
@@ -112,7 +112,7 @@ export async function saveArbitrateTask(
   specialTagList?: any
 ) {
   return httpApp.post<CommonResponse>("/ap/admin/exam/arbitrate/saveTask", {
-    libraryId,
+    taskId,
     studentId,
     markerScore,
     scoreList,

+ 4 - 4
src/api/libraryInspectPage.ts

@@ -108,9 +108,9 @@ export async function getInspectedTaskStatusOfLibraryInspect({
 }
 
 /** 保存复核任务 */
-export async function saveInspectedTaskOfLibraryInspect(libraryId: string) {
+export async function saveInspectedTaskOfLibraryInspect(taskId: string) {
   const form = new FormData();
-  form.append("libraryId", libraryId);
+  form.append("taskId", taskId);
   return httpApp.post<CommonResponse>(
     "/api/admin/exam/library/inspected/save",
     form
@@ -119,7 +119,7 @@ export async function saveInspectedTaskOfLibraryInspect(libraryId: string) {
 
 /** 复核任务打回问题 */
 export async function rejectInspectedTaskOfLibraryInspect(
-  libraryId: string,
+  taskId: string,
   questionList: Array<Question>,
   reason: string
 ) {
@@ -130,7 +130,7 @@ export async function rejectInspectedTaskOfLibraryInspect(
     )
   );
   return httpApp.post<CommonResponse>("/api/admin/exam/library/rejected", {
-    libraryId,
+    taskId,
     questionList,
     reason,
   });

+ 4 - 4
src/api/libraryTrackPage.ts

@@ -9,9 +9,9 @@ interface LibraryTrackResponse {
 }
 
 /** 查看单个评卷任务的试卷轨迹 */
-export async function getSingleLibraryTask(libraryId: string) {
+export async function getSingleLibraryTask(taskId: string) {
   const form = new FormData();
-  libraryId && form.append("libraryId", libraryId);
+  taskId && form.append("taskId", taskId);
   return httpApp.post<LibraryTrackResponse>(
     "/api/admin/exam/track/library",
     form
@@ -19,9 +19,9 @@ export async function getSingleLibraryTask(libraryId: string) {
 }
 
 /** 查看单个*试评*评卷任务的试卷轨迹 */
-export async function getSingleLibraryTaskTrial(libraryId: string) {
+export async function getSingleLibraryTaskTrial(taskId: string) {
   const form = new FormData();
-  libraryId && form.append("libraryId", libraryId);
+  taskId && form.append("taskId", taskId);
   return httpApp.post<LibraryTrackResponse>(
     "/api/admin/exam/track/trialLibrary",
     form

+ 45 - 21
src/api/markPage.ts

@@ -40,10 +40,16 @@ export async function updateUISetting(
   mode?: Setting["mode"],
   uiSetting?: UISetting
 ) {
-  const form = new FormData();
-  uiSetting && form.append("uiSetting", JSON.stringify(uiSetting));
-  mode && form.append("mode", mode);
-  return httpApp.post<void>("/api/mark/updateSetting", form);
+  return httpApp.post<void>(
+    "/api/mark/updateSetting",
+    {},
+    {
+      params: {
+        mode: mode || undefined,
+        uiSetting: uiSetting ? JSON.stringify(uiSetting) : undefined,
+      },
+    }
+  );
 }
 
 /** 获取评卷历史任务 */
@@ -55,14 +61,20 @@ export async function getHistoryTask({
   secretNumber = null,
   markerScore = null,
 }: HistoryQueryParams) {
-  const form = new FormData();
-  form.append("pageNumber", pageNumber + "");
-  form.append("pageSize", pageSize + "");
-  form.append("order", order);
-  form.append("sort", sort);
-  secretNumber && form.append("secretNumber", secretNumber);
-  markerScore && form.append("markerScore", markerScore);
-  return httpApp.post<Task[]>("/api/mark/getHistory", form);
+  return httpApp.post<Task[]>(
+    "/api/mark/getHistory",
+    {},
+    {
+      params: {
+        pageNumber,
+        pageSize,
+        order,
+        sort,
+        secretNumber,
+        markerScore,
+      },
+    }
+  );
 }
 
 /** 保存评卷任务(正常保存) */
@@ -82,10 +94,16 @@ export async function saveTask() {
 
 /** 获取用户信息 */
 export async function changeUserInfo(name: string, password?: string) {
-  const form = new FormData();
-  form.append("name", name);
-  password && form.append("password", password);
-  return httpApp.post<void>("/api/mark/changeName", form);
+  return httpApp.post<void>(
+    "/api/mark/changeName",
+    {},
+    {
+      params: {
+        name,
+        password: password || undefined,
+      },
+    }
+  );
 }
 
 /** 评卷用户退出 */
@@ -94,20 +112,26 @@ export function doLogout() {
 }
 
 /** 评卷用户选择分组 */
+// ps:已经没用了 3.3.0
 export async function doSwitchGroup(markerId: number) {
-  const form = new FormData();
-  form.append("markerId", "" + markerId);
-  return httpApp.post<CommonResponse>("/api/mark/subjectSelect", form);
+  return httpApp.post<CommonResponse>(
+    "/api/mark/subjectSelect",
+    {},
+    {
+      params: { markerId },
+    }
+  );
 }
 
 /** 评卷用户选择试卷的问题类型 */
-export async function doProblemType(problemId: number) {
+export async function doProblemType({ problemType, problemRemark }) {
   if (!store.currentTask?.markResult) return;
 
   let markResult = store.currentTask?.markResult;
   markResult.problem = true;
   markResult.unselective = false;
-  markResult.problemTypeId = problemId;
+  markResult.problemType = problemType;
+  markResult.problemRemark = problemRemark || undefined;
   markResult.markerScore = null;
   markResult.scoreList = [];
   markResult.specialTagList = [];

+ 22 - 45
src/devLogin.ts

@@ -1,53 +1,30 @@
 // @ts-ignore
 import { LOGIN_CONFIG } from "@/devLoginParams";
+import { getBase64 } from "./utils/crypto";
+import { httpApp } from "@/plugins/axiosApp";
+import vls from "./utils/storage";
 
-const { loginName, password, examId, markerId, isAdmin, forceChange } =
+const { loginName, password, examId, paperNumber, groupNumber, schoolCode } =
   LOGIN_CONFIG;
 
 export async function initLogin() {
-  if (document.cookie.includes("stmms_cookie") && !forceChange) return;
-  const f = new FormData();
-  f.append("loginType", isAdmin ? "admin-login" : "mark-login");
-  f.append("loginName", loginName);
-  f.append("password", password);
+  const res = await httpApp.post("/api/admin/common/login", {
+    loginName,
+    password: getBase64(password),
+    schoolCode,
+    type: "ACCOUNT",
+  });
+  const data = res.data;
 
-  return fetch("/api/login", { body: f, method: "POST" })
-    .then(async (r) => {
-      const body = await r.text();
-      const exams = body.match(
-        /<select name="examId" id="exam-select">.*<\/select>/gims
-      );
-      console.log(exams && exams[0].replace(/\n/g, ""));
-    })
-    .then(async () => {
-      const f = new FormData();
-      f.append("examId", examId);
-      markerId && f.append("markerId", markerId || "");
-      if (!isAdmin) {
-        const res = await fetch("/api/mark/subject/query", {
-          body: f,
-          method: "POST",
-        });
-        console.log("markerId: ", await res.text());
-      }
-      return new Promise((resove) => {
-        setTimeout(() => {
-          const url = isAdmin
-            ? "/api/admin/exam/select"
-            : "/api/mark/subject-select";
-          resove(fetch(url, { body: f, method: "POST" }));
-        }, 1000);
-      });
-    });
-  // .then(() => {
-  //   console.log("login completed");
-  //   return fetch("/mark/status");
-  // })
-  // .then(async (r) => {
-  //   console.log(await r.json());
-  //   return fetch("/mark/gettask");
-  // })
-  // .then(async (r) => {
-  //   console.log(await r.json());
-  // });
+  if (data.orgInfo) vls.set("orgId", data.orgInfo.id);
+  if (data.schoolInfo && data.schoolInfo.length) {
+    const curSchool = data.schoolInfo.find((item) => item.code === schoolCode);
+    if (curSchool) {
+      vls.set("schoolId", curSchool.id);
+      vls.set("schoolName", curSchool.name);
+    }
+  }
+  vls.set("user", data);
+  vls.set("mark", { examId, paperNumber, groupNumber });
+  vls.set("token", data.accessToken);
 }

+ 19 - 9
src/devLoginParams.ts

@@ -8,18 +8,28 @@
 // export const examId="1";
 // export const markerId="419";
 
-/** 244 评卷员 */
+// 192.168.11.167:7001
 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",
+  loginName: "java",
+  password: "12345678",
+  examId: "437537682336260096",
+  paperNumber: "bh102101",
+  groupNumber: 1,
+  schoolCode: "test-school-1",
 };
+/** 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: true,

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

@@ -70,7 +70,7 @@ let isSingleStudent = !!route.query.historyId;
 const {
   subjectCode,
   groupNumber,
-  historyId: libraryId,
+  historyId: taskId,
 } = route.query as {
   subjectCode: string;
   groupNumber: string;
@@ -78,12 +78,12 @@ const {
 };
 
 async function updateClearTask() {
-  await clearArbitrateTask(libraryId, subjectCode);
+  await clearArbitrateTask(taskId, subjectCode);
 }
 
 async function updateSetting() {
   const settingRes = await getArbitrateSetting(
-    libraryId,
+    taskId,
     subjectCode,
     groupNumber
   );
@@ -176,7 +176,7 @@ watch(
 );
 
 async function getSingleStuTask() {
-  return getSingleArbitrateTask(libraryId);
+  return getSingleArbitrateTask(taskId);
 }
 
 async function getOneOfStuTask() {
@@ -203,7 +203,7 @@ const saveTaskToServer = async (
   let res;
   if (unselective) {
     res = await saveArbitrateTask(
-      store.currentTask.libraryId + "",
+      store.currentTask.taskId + "",
       store.currentTask.studentId + "",
       -1,
       [],
@@ -247,7 +247,7 @@ const saveTaskToServer = async (
       });
     }
     res = await saveArbitrateTask(
-      store.currentTask.libraryId + "",
+      store.currentTask.taskId + "",
       store.currentTask.studentId + "",
       store.currentTask.markResult.markerScore,
       store.currentTask.markResult.scoreList,

+ 1 - 1
src/features/arbitrate/ArbitrateMarkList.vue

@@ -48,7 +48,7 @@ watch(
   async () => {
     if (store.currentTask) {
       const res = await getArbitrateList(
-        store.currentTask?.libraryId as unknown as string
+        store.currentTask?.taskId as unknown as string
       );
       if (Array.isArray(res.data)) {
         list.splice(0);

+ 2 - 2
src/features/arbitrate/MarkHeader.vue

@@ -85,7 +85,7 @@ let isSingleStudent = !!route.query.historyId;
 const {
   subjectCode,
   groupNumber,
-  historyId: libraryId,
+  historyId: taskId,
 } = route.query as {
   subjectCode: string;
   groupNumber: string;
@@ -94,7 +94,7 @@ const {
 
 let clearTasks = clearArbitrateTask.bind(
   null,
-  libraryId,
+  taskId,
   subjectCode,
   groupNumber
 );

+ 5 - 5
src/features/library/inspect/LibraryInspect.vue

@@ -41,11 +41,11 @@ import EventBus from "@/plugins/eventBus";
 import { addFileServerPrefixToTask } from "@/utils/utils";
 
 const route = useRoute();
-let isSingleStudent = !!route.query.libraryId;
+let isSingleStudent = !!route.query.taskId;
 const {
   subjectCode,
   groupNumber,
-  libraryId,
+  taskId,
   markerId,
   examNumber,
   secretNumber,
@@ -56,7 +56,7 @@ const {
 } = route.query as {
   subjectCode: string;
   groupNumber: string;
-  libraryId: string; // TODO: for未来单一任务
+  taskId: string; // TODO: for未来单一任务
   markerId: string;
   examNumber: string;
   secretNumber: string;
@@ -155,7 +155,7 @@ async function getOneOfStuTask() {
 }
 
 const realLibraryId = $computed(
-  () => (isSingleStudent ? libraryId : store.currentTask?.libraryId) as string
+  () => (isSingleStudent ? taskId : store.currentTask?.taskId) as string
 );
 const saveTaskToServer = async () => {
   console.log("save inspect task to server");
@@ -189,7 +189,7 @@ const rejectQuestions = async ({
   const mkey = "reject_task_key";
   void message.loading({ content: "打回评卷任务...", key: mkey });
   const res = await rejectInspectedTaskOfLibraryInspect(
-    store.currentTask.libraryId + "",
+    store.currentTask.taskId + "",
     questions,
     reason
   );

+ 3 - 3
src/features/library/libraryTrack/LibraryTrack.vue

@@ -25,7 +25,7 @@ import { getPaper } from "@/api/jsonMark";
 import { addFileServerPrefixToTask } from "@/utils/utils";
 
 const route = useRoute();
-let libraryId = route.query.libraryId;
+let taskId = route.query.taskId;
 let subjectCode = route.query.subjectCode;
 
 async function updateSetting() {
@@ -79,9 +79,9 @@ onMounted(async () => {
 
 async function getSingleStuTask() {
   if (route.name === "TrialRoute") {
-    return getSingleLibraryTaskTrial(libraryId as string);
+    return getSingleLibraryTaskTrial(taskId as string);
   } else {
-    return getSingleLibraryTask(libraryId as string);
+    return getSingleLibraryTask(taskId as string);
   }
 }
 

+ 10 - 19
src/features/mark/Mark.vue

@@ -85,7 +85,7 @@ import AllPaperModal from "./AllPaperModal.vue";
 import SheetViewModal from "./SheetViewModal.vue";
 import SpecialTagModal from "./SpecialTagModal.vue";
 import ShortCutModal from "./ShortCutModal.vue";
-import { addFileServerPrefixToTask, preDrawImage } from "@/utils/utils";
+import { processSliceUrls } from "@/utils/utils";
 import { getPaper } from "@/api/jsonMark";
 import EventBus from "@/plugins/eventBus";
 import { getHistoryTask } from "@/api/markPage";
@@ -130,16 +130,10 @@ async function updateSetting() {
       "specialTag.modal": false,
       "shortCut.modal": false,
     };
+  } else {
+    settingRes.data.uiSetting = JSON.parse(settingRes.data.uiSetting);
   }
   store.setting = settingRes.data;
-  if (store.setting.subject?.answerUrl) {
-    store.setting.subject.answerUrl =
-      store.setting.fileServer + store.setting.subject?.answerUrl;
-  }
-  if (store.setting.subject?.paperUrl) {
-    store.setting.subject.paperUrl =
-      store.setting.fileServer + store.setting.subject?.paperUrl;
-  }
   if (store.setting.subject?.paperUrl && store.isMultiMedia) {
     await getPaper(store);
   }
@@ -147,7 +141,7 @@ async function updateSetting() {
 
 async function updateStatus() {
   const res = await getStatus();
-  if (res.data.valid) Object.assign(store.status, res.data);
+  Object.assign(store.status, res.data);
 }
 async function updateGroups() {
   const res = await getGroup();
@@ -157,17 +151,14 @@ async function updateGroups() {
 let preDrawing = false;
 async function updateTask() {
   const res = await getTask();
-  if (res.data.libraryId) {
-    let rawTask = res.data;
-    const newTask = addFileServerPrefixToTask(rawTask);
-
+  if (res.data.taskId) {
+    const newTask = res.data;
+    newTask.sheetUrls = newTask.sheetUrls || [];
+    newTask.sheetUrls = ["/1-1.jpg", "/1-2.jpg"];
     try {
       preDrawing = true;
-      if (store.isScanImage) {
-        await preDrawImage(newTask);
-      }
+      newTask.sliceUrls = await processSliceUrls(newTask);
     } finally {
-      // console.log("preDrawing失败")
       preDrawing = false;
     }
 
@@ -205,7 +196,7 @@ function nextTask() {
 }
 
 // 5秒更新一次tasks
-addInterval(nextTask, 5 * 1000);
+// addInterval(nextTask, 5 * 1000);
 
 // 不需要
 // addInterval(() => {

+ 6 - 2
src/features/mark/MarkHeader.vue

@@ -122,7 +122,11 @@
           />评卷时间段
         </div>
       </a-tooltip>
-      <a-dropdown>
+      <div class="header-text-btn">
+        <img src="@/assets/icons/icon-track-mode.svg" class="header-icon" />
+        {{ modeName }}
+      </div>
+      <!-- <a-dropdown>
         <template v-if="!store.setting.forceMode" #overlay>
           <a-menu>
             <a-menu-item key="1" @click="toggleSettingMode">
@@ -136,7 +140,7 @@
           {{ modeName }}
           <CaretDownOutlined v-if="!store.setting.forceMode" class="a-icon" />
         </div>
-      </a-dropdown>
+      </a-dropdown> -->
       <div
         class="header-text-btn"
         :title="store.setting.groupTitle + '-' + store.setting.groupNumber"

+ 1 - 4
src/features/mark/MarkHistory.vue

@@ -171,10 +171,7 @@ const currentTaskChange = async () => {
       // 恢复以前的行为,取回评失败则评卷任务为空
       await replaceCurrentTask(undefined);
     } finally {
-      // store.globalMask = false;
-      if (store.setting?.examType !== "SCAN_IMAGE") {
-        store.globalMask = false;
-      }
+      store.globalMask = false;
     }
     await replaceCurrentTask(store.historyTasks[0]);
   } else {

+ 44 - 19
src/features/mark/MarkProblemDialog.vue

@@ -5,26 +5,33 @@
     width="406px"
     :zIndex="6000"
     wrapClassName="mark-dialog"
+    @ok="handleOk"
     @cancel="handleCancel"
   >
-    <table class="table">
-      <tr>
-        <th>问题类型</th>
-        <th style="width: 76px">操作</th>
-      </tr>
-      <tr v-for="(problem, index) in store.setting.problemTypes" :key="index">
-        <td>{{ problem.name }}</td>
-        <td style="width: 76px">
-          <a-button
-            type="text"
-            class="btn-primary"
-            @click="chooseProblemType(problem.id)"
+    <a-form
+      labelAlign="right"
+      :labelCol="{ span: 5 }"
+      @keydown.stop=""
+      @keypress.stop=""
+    >
+      <a-form-item class="tw-mb-2" :required="true" label="问题类型">
+        <a-select v-model:value="formModel.problemType" placeholder="姓名">
+          <a-select-option
+            v-for="item in store.setting.problemTypes"
+            :key="item.code"
+            :value="item.code"
+            >{{ item.name }}</a-select-option
           >
-            选择
-          </a-button>
-        </td>
-      </tr>
-    </table>
+        </a-select>
+      </a-form-item>
+      <a-form-item
+        v-if="formModel.problemType === 'OTHER'"
+        class="tw-mb-2"
+        label="原因"
+      >
+        <a-input v-model:value="formModel.problemRemark" placeholder="原因" />
+      </a-form-item>
+    </a-form>
     <template #footer>
       <a-button class="btn-cancel" @click="handleCancel">取消</a-button>
     </template>
@@ -36,6 +43,7 @@ import { doProblemType, getStatus } from "@/api/markPage";
 import { message } from "ant-design-vue";
 import { store } from "@/store/store";
 import EventBus from "@/plugins/eventBus";
+import { reactive } from "vue";
 
 let visible = $ref(false);
 
@@ -43,18 +51,35 @@ const showModal = () => {
   visible = true;
 };
 
+interface FormModel {
+  problemType: string;
+  problemRemark: string;
+}
+const formModel: FormModel = reactive({
+  problemType: "",
+  problemRemark: "",
+});
+
 async function updateStatus() {
   const res = await getStatus();
   store.status = res.data;
 }
 
-const chooseProblemType = async (problemId: number) => {
+const handleOk = async () => {
   if (!store.currentTask) {
     void message.warn({ content: "没有可以标记的任务", duration: 5 });
     return;
   }
+  if (!formModel.problemType) {
+    void message.error({ content: "请选择问题类型" });
+    return;
+  }
+  if (formModel.problemType === "OTHER" && !formModel.problemRemark) {
+    void message.error({ content: "请输入原因" });
+    return;
+  }
   try {
-    const res = await doProblemType(problemId);
+    const res = await doProblemType(formModel);
     if (res?.data.success) {
       void message.success({ content: "问题卷处理成功", duration: 3 });
       visible = false;

+ 14 - 29
src/features/mark/MarkSwitchGroupDialog.vue

@@ -4,29 +4,30 @@
     title="切换分组"
     :zIndex="6000"
     centered
+    width="700px"
     wrapClassName="mark-dialog"
   >
     <table class="table">
       <tr>
         <th>分组号</th>
-        <th>分组名</th>
+        <th>试题</th>
         <th>进度</th>
         <th>操作</th>
       </tr>
       <tr
         v-for="(group, index) in store.groups"
         :key="index"
-        :class="isCurrentGroup(group.number) && 'is-current'"
+        :class="isCurrentGroup(group.groupNumber) && 'is-current'"
       >
-        <td>{{ group.number }}</td>
-        <td>{{ group.title }}</td>
+        <td>{{ group.groupNumber }}</td>
+        <td>{{ group.groupQuestions }}</td>
         <td>{{ progress(group.totalCount, group.markedCount) }}%</td>
         <td>
           <a-button
-            :disabled="isCurrentGroup(group.number)"
+            :disabled="isCurrentGroup(group.groupNumber)"
             type="text"
             class="btn-primary"
-            @click="chooseGroup(group.markerId)"
+            @click="chooseGroup(group.groupNumber)"
           >
             选择
           </a-button>
@@ -39,10 +40,11 @@
   </a-modal>
 </template>
 <script setup lang="ts">
-import { doSwitchGroup, getGroup } from "@/api/markPage";
-import { message } from "ant-design-vue";
+import { getGroup } from "@/api/markPage";
+// import { message } from "ant-design-vue";
 import { onUpdated } from "vue";
 import { store } from "@/store/store";
+import vls from "@/utils/storage";
 
 let visible = $ref(false);
 
@@ -69,27 +71,10 @@ const isCurrentGroup = (groupNumber: number) => {
   return groupNumber === store.setting.groupNumber;
 };
 
-const chooseGroup = async (markerId: number) => {
-  await doSwitchGroup(markerId)
-    .then((res) => {
-      // 切换分组相当于刷新页面,此时之前的所有的状态消失,即task/markResult不存在了
-      if (res.data.success) {
-        const body = document.querySelector("body");
-        if (body) body.innerHTML = "重新加载中...";
-        return new Promise((resolve) => setTimeout(() => resolve(true), 300));
-      } else {
-        void message.error({
-          content: res.data.message || "错误",
-          duration: 5,
-        });
-        return false;
-      }
-    })
-    .then((res) => {
-      if (res) {
-        window.location.reload();
-      }
-    });
+const chooseGroup = (groupNumber: number) => {
+  const markinfo = vls.get("mark", {});
+  vls.set("mark", { ...markinfo, groupNumber });
+  window.location.reload();
 };
 
 const handleCancel = () => {

+ 20 - 8
src/plugins/axiosApp.ts

@@ -20,6 +20,7 @@ axiosRetry(_axiosApp);
 
 // 为请求头添加鉴权信息
 function setAuth(config) {
+  const excludeUrls = ["/api/admin/common/login"];
   const token = vls.get("token");
   if (token) {
     const ids = {
@@ -34,7 +35,7 @@ function setAuth(config) {
     });
 
     // 新版鉴权
-    const sessionId = ls.get("user", { sessionId: "" }).sessionId;
+    const sessionId = vls.get("user", { sessionId: "" }).sessionId;
     const timestamp = fetchTime();
     const Authorization = getAuthorization(
       {
@@ -48,6 +49,14 @@ function setAuth(config) {
     );
     config.headers["Authorization"] = Authorization;
     config.headers["time"] = timestamp;
+
+    if (!excludeUrls.includes(config.url)) {
+      const mark = vls.get("mark");
+      config.params = {
+        ...mark,
+        ...(config.params || {}),
+      };
+    }
   }
   config.headers["deviceId"] = DEVICE_ID;
   config.headers["platform"] = PLATFORM;
@@ -63,9 +72,10 @@ _axiosApp.interceptors.request.use(
     return config;
   },
   function (error) {
-    if (error.config.setGlobalMask) {
-      store.globalMask = false;
-    }
+    // if (error.config.setGlobalMask) {
+    //   store.globalMask = false;
+    // }
+    store.globalMask = false;
     void message.error({ content: error, duration: 10 });
     console.log(error);
     return Promise.reject(error);
@@ -80,15 +90,17 @@ _axiosApp.interceptors.response.use(
     if (response.config.setGlobalMask) {
       store.globalMask = false;
     }
-    return response;
+    return response.data || {};
   },
   (error) => {
     if (error.response) {
       initSyncTime(new Date(error.response.headers.date).getTime());
     }
-    if (error.config?.setGlobalMask) {
-      store.globalMask = false;
-    }
+    // if (error.config?.setGlobalMask) {
+    //   store.globalMask = false;
+    // }
+    store.globalMask = false;
+
     const showErrorMessage = !error.config?.noErrorMessage;
     if (!error.response) {
       if (showErrorMessage) {

+ 4 - 4
src/plugins/axiosNotice.ts

@@ -1,6 +1,6 @@
 import { throttle } from "lodash-es";
 import { message } from "ant-design-vue";
-import { doLogout } from "@/api/markPage";
+// import { doLogout } from "@/api/markPage";
 
 export const notifyInvalidTokenThrottled = throttle(
   () => {
@@ -8,9 +8,9 @@ export const notifyInvalidTokenThrottled = throttle(
       content: "登录失效,请重新登录!",
       duration: 10,
     });
-    setTimeout(() => {
-      doLogout();
-    }, 3000);
+    // setTimeout(() => {
+    //   doLogout();
+    // }, 3000);
     console.log("登录失效");
   },
   1000,

+ 2 - 2
src/store/store.ts

@@ -179,10 +179,10 @@ export const initMarkStore = () => {
 
         task.__markStartTime = Date.now();
         const statusValue = store.setting.statusValue;
-        const { libraryId, studentId } = task;
+        const { taskId, studentId } = task;
         task.markResult = {
           statusValue: statusValue,
-          libraryId: libraryId,
+          taskId: taskId,
           studentId: studentId,
           spent: 0,
 

+ 1 - 1
src/styles/page.less

@@ -469,7 +469,7 @@
     display: inline-block;
     vertical-align: top;
     width: 50%;
-    padding: 0 8px;
+    padding: 0 8px 16px;
     font-size: 14px;
   }
   .board-quesion {

+ 5 - 6
src/types/index.ts

@@ -18,8 +18,6 @@ export interface MarkStore {
   setting: Setting;
   groups: Array<Group>;
   status: {
-    /** 为false时不更新以下count字段 */
-    valid: boolean;
     /** 个人评卷数量 */
     personCount: number;
     /** 总评卷数量 */
@@ -162,9 +160,10 @@ export interface AdminPageSettingForImport extends AdminPageSetting {
 }
 
 export interface Group {
-  markerId: number;
   /** 分组编号 */
   number: number;
+  /** 分组试题 */
+  groupQuestions: string;
   /** 分组title */
   title: string;
   /** 总评卷数量 */
@@ -174,9 +173,9 @@ export interface Group {
 }
 
 interface RawTask {
-  libraryId: number;
+  taskId: string;
   /** 学生ID */
-  studentId: number;
+  studentId: string;
   /** 任务编号 */
   secretNumber: string;
   /** 后端处理是否显示 */
@@ -336,7 +335,7 @@ export interface UISetting {
 }
 
 export interface MarkResult {
-  libraryId: number;
+  taskId: number;
   studentId: number;
   statusValue: "TRIAL" | "FORMAL" | null;
   /** 毫秒单位 */

+ 60 - 28
src/utils/utils.ts

@@ -13,33 +13,16 @@ import { PictureSlice, Task } from "@/types";
  * @returns Promise<HTMLImageElement>
  */
 export async function loadImage(url: string): Promise<HTMLImageElement> {
-  // if (store.currentTask && weakedMapImages.get(store.currentTask)) {
-  //   const imagesCache = weakedMapImages.get(store.currentTask);
-  //   if (imagesCache) {
-  //     // console.log("cached image", url);
-  //     const image = imagesCache.get(url);
-  //     if (image) return image;
-  //   }
-  // }
-
-  // else loading image
-
   return new Promise((resolve, reject) => {
     const image = new Image();
     image.setAttribute("crossorigin", "anonymous");
     image.src = url;
     image.onload = () => {
-      // if (store.currentTask) {
-      //   let imagesCache = weakedMapImages.get(store.currentTask);
-      //   if (!imagesCache) {
-      //     imagesCache = new Map<string, HTMLImageElement>();
-      //     weakedMapImages.set(store.currentTask, imagesCache);
-      //   }
-      //   imagesCache.set(url, image);
-      // }
       resolve(image);
     };
-    image.onerror = reject;
+    image.onerror = () => {
+      reject("图片载入错误");
+    };
   });
 }
 
@@ -167,10 +150,36 @@ export async function getDataUrlForSplitConfig(
   return dataurl;
 }
 
+export async function getDataUrlForCoverConfig(
+  image: HTMLImageElement,
+  configs: PictureSlice[]
+) {
+  const canvas = document.createElement("canvas");
+  canvas.width = image.naturalWidth;
+  canvas.height = image.naturalHeight;
+  const ctx = canvas.getContext("2d");
+  if (!ctx) {
+    console.log('canvas.getContext("2d") error');
+    throw new Error("canvas ctx error");
+  }
+  ctx.drawImage(image, 0, 0);
+  ctx.fillStyle = "#ffffff";
+  configs.forEach((config) => {
+    ctx.fillRect(config.x, config.y, config.w, config.h);
+  });
+
+  const blob: Blob = await new Promise((res) => {
+    canvas.toBlob((b) => res(b));
+  });
+  const dataurl = URL.createObjectURL(blob);
+  cacheFIFO();
+  return dataurl;
+}
+
 export async function preDrawImage(_currentTask: Task | undefined) {
   // console.log("preDrawImage=>curTask:", _currentTask);
 
-  if (!_currentTask?.libraryId) return;
+  if (!_currentTask?.taskId) return;
 
   let maxSliceWidth = 0; // 最大的裁切块宽度,图片容器以此为准
 
@@ -252,10 +261,39 @@ export async function preDrawImage(_currentTask: Task | undefined) {
   }
 }
 
+export async function processSliceUrls(_currentTask: Task | undefined) {
+  if (!_currentTask?.taskId) return;
+
+  const getNum = (num) => Math.max(Math.min(1, num), 0);
+
+  const sheetUrls = _currentTask.sheetUrls || [];
+  const sheetConfig = store.setting.sheetConfig || [];
+
+  const urls = [];
+  for (let i = 0; i < sheetUrls.length; i++) {
+    const url = sheetUrls[i];
+    const configs = sheetConfig.filter((item) => item.i === i + 1);
+    if (!configs.length) {
+      urls[i] = url;
+      continue;
+    }
+    const image = await loadImage(url);
+    configs.forEach((item) => {
+      item.x = image.naturalWidth * getNum(item.x);
+      item.y = image.naturalHeight * getNum(item.y);
+      item.w = image.naturalWidth * getNum(item.w);
+      item.h = image.naturalHeight * getNum(item.h);
+    });
+
+    urls[i] = await getDataUrlForCoverConfig(image, configs);
+  }
+  return urls;
+}
+
 export async function preDrawImageHistory(_currentTask: Task | undefined) {
   console.log("preDrawImageHistory=>curTask:", _currentTask);
 
-  if (!_currentTask?.libraryId) return;
+  if (!_currentTask?.taskId) return;
 
   let maxSliceWidth = 0; // 最大的裁切块宽度,图片容器以此为准
 
@@ -340,12 +378,6 @@ export async function preDrawImageHistory(_currentTask: Task | undefined) {
 
 export function addFileServerPrefixToTask(rawTask: Task): Task {
   const newTask = JSON.parse(JSON.stringify(rawTask)) as Task;
-
-  const fileServer = store.setting.fileServer;
-  newTask.sliceUrls = newTask.sliceUrls?.map((s) => fileServer + s);
-  newTask.sheetUrls = newTask.sheetUrls?.map((s) => fileServer + s);
-  newTask.jsonUrl = fileServer + newTask.jsonUrl;
-
   return newTask;
 }
 

+ 1 - 13
vite.config.ts

@@ -42,22 +42,10 @@ export default defineConfig({
       allow: ["./"],
     },
     proxy: {
-      // "/login": {
-      //   target: SERVER_URL,
-      //   changeOrigin: true,
-      // },
-      // "/mark": {
-      //   target: SERVER_URL,
-      //   changeOrigin: true,
-      // },
-      // "/admin": {
-      //   target: SERVER_URL,
-      //   changeOrigin: true,
-      // },
       "/api/": {
         target: SERVER_URL,
         changeOrigin: true,
-        rewrite: (path) => path.replace(/^\/api/, ""),
+        // rewrite: (path) => path.replace(/^\/api/, ""),
       },
     },
   },