瀏覽代碼

feat: 类型检查

zhangjie 8 月之前
父節點
當前提交
8f9eed4cd3

+ 5 - 5
src/render/ap/imageCheck.ts

@@ -3,19 +3,19 @@ import { request } from "@/utils/request";
 
 import {
   ExamParams,
-  ExamPageParams,
+  ExamSubjectParams,
   RequestActionResult,
 } from "./types/common";
 import {
-  ImageCheckListPageResult,
+  ImageCheckListItem,
   ImageCheckFailedListPageResult,
   ImageCheckFailedParams,
 } from "./types/imageCheck";
 
 // 图片检查
 export const imageCheckList = (
-  data: ExamPageParams
-): Promise<ImageCheckListPageResult> =>
+  data: ExamParams
+): Promise<ImageCheckListItem[]> =>
   request({
     url: "/api/admin/check/image/list",
     method: "post",
@@ -32,7 +32,7 @@ export const imageCheckFailedList = (
   });
 
 export const imageCheckFailedExport = (
-  data: ImageCheckFailedParams
+  data: ExamSubjectParams
 ): Promise<AxiosResponse<Blob>> =>
   request({
     url: "/api/admin/check/image/failed/export",

+ 1 - 1
src/render/ap/resultExport.ts

@@ -69,7 +69,7 @@ export const markSiteSave = (
     data,
   });
 
-export const markSiteDelete = (id: string): Promise<RequestActionResult> =>
+export const markSiteDelete = (id: number): Promise<RequestActionResult> =>
   request({
     url: "/api/admin/mark-site/delete",
     method: "post",

+ 2 - 1
src/render/ap/review.ts

@@ -8,6 +8,7 @@ import {
   ReviewTaskSaveParams,
   ReviewTaskHistoryParams,
   ReviewTaskHistoryResult,
+  ReviewTaskResetParams,
   ReviewWarningTaskExportParams,
 } from "./types/review";
 
@@ -66,7 +67,7 @@ export const reviewTaskRelease = (
 
 // 复核校验重置
 export const reviewTaskReset = (
-  data: ExamSubjectParams
+  data: ReviewTaskResetParams
 ): Promise<RequestActionResult> =>
   request({
     url: "/api/admin/check/assigned/reset",

+ 0 - 1
src/render/ap/types/common.ts

@@ -17,7 +17,6 @@ export type ExamPageParams = PageParams<ExamParams>;
 export interface ExamSubjectParams {
   examId: number;
   subjectCode: string;
-  password: string;
 }
 export type ExamSubjectPageParams = PageParams<ExamSubjectParams>;
 

+ 2 - 2
src/render/ap/types/recognizeCheck.ts

@@ -9,7 +9,7 @@ export interface RecognizeConditionItem {
 
 export interface RecognizeCheckTaskConditionItem {
   code: string;
-  value: number | null;
+  value: number | undefined;
 }
 
 // 识别对照管理
@@ -41,7 +41,7 @@ export interface RecognizeCheckTaskSetConditionItem {
   code: string;
   name: string;
   needValue: boolean;
-  value: number | null;
+  value: number | undefined;
 }
 
 export interface RecognizeCheckTaskSaveParams {

+ 6 - 0
src/render/ap/types/review.ts

@@ -43,6 +43,12 @@ export interface ReviewTaskHistoryFilter {
 export type ReviewTaskHistoryParams = PageParams<ReviewTaskHistoryFilter>;
 export type ReviewTaskHistoryResult = PageResult<ReviewTaskListItem>;
 
+export interface ReviewTaskResetParams {
+  examId: number;
+  subjectCode: string;
+  password: string;
+}
+
 export type ReviewExportType = "STUDENT_CODE" | "EXAM_ROOM";
 
 export interface ReviewWarningTaskExportParams {

+ 25 - 14
src/render/store/modules/user/index.ts

@@ -12,18 +12,22 @@ interface RecogFillSetType {
   borderWidth: number;
 }
 
-export const useUserStore = defineStore<
-  "user",
-  {
-    heatBeatWorker: Worker | null;
-    curExam: Exam | null;
-    imageCheckLoopTime: number;
-    userInfo: any;
-    recogFillSet: RecogFillSetType;
-  },
-  any,
-  any
->("user", {
+interface UserInfo {
+  role: "SCHOOL_ADMIN" | "SCAN_ADMIN" | "AUDITOR";
+  name: string;
+  sessionId: string;
+  accessToken: string;
+}
+
+interface UserState {
+  heatBeatWorker: Worker | null;
+  curExam: Exam;
+  imageCheckLoopTime: number;
+  userInfo: UserInfo;
+  recogFillSet: RecogFillSetType;
+}
+
+export const useUserStore = defineStore("user", {
   persist: [
     {
       storage: sessionStorage,
@@ -34,11 +38,18 @@ export const useUserStore = defineStore<
       paths: ["curExam", "imageCheckLoopTime", "recogFillSet"],
     },
   ],
-  state: () => ({
+  state: (): UserState => ({
     heatBeatWorker: null,
     heatBeatIsActive: false,
     userInfo: null,
-    curExam: null,
+    curExam: {
+      enable: true,
+      id: 0,
+      mode: "",
+      name: "",
+      schoolName: "",
+      updateTime: 0,
+    },
     imageCheckLoopTime: 0,
     recogFillSet: {
       fillColor: "#f53f3f ",

+ 1 - 1
src/render/utils/tool.ts

@@ -333,7 +333,7 @@ export function getFileUrl(url: string) {
 export function getSliceFileUrl(
   url: string,
   area: { x: number; y: number; w: number; h: number }
-) {
+): Promise<string> {
   return new Promise((resolve, reject) => {
     const img = new Image();
     img.src = getFileUrl(url);

+ 17 - 9
src/render/views/DataCheck/ScanImage/index.vue

@@ -77,6 +77,8 @@ import {
   RightOutlined,
   PictureFilled,
 } from "@ant-design/icons-vue";
+import { message } from "ant-design-vue";
+
 import { computed, nextTick, ref, unref } from "vue";
 import {
   objAssign,
@@ -184,7 +186,7 @@ function updateRecogList() {
   const ABC = abc.split("");
   regdata.question.forEach((gGroup) => {
     gGroup.fill_result.forEach((qRecog) => {
-      const result = dataCheckStore.curPage.question.result[index] || "";
+      const result = dataCheckStore.curPage?.question.result[index] || "";
       qRecog.index = ++index;
 
       const questionResult = result ? result.split("") : [];
@@ -212,10 +214,7 @@ function parseRecogBlocks() {
   const curBorderWidth = Math.max(1, borderWidth * rate);
 
   recogBlocks.value = unref(recogList.value).map((item) => {
-    const nitem: RecogBlock = { ...item };
-    nitem.areaImg = "";
-
-    nitem.fillAreaStyle = {
+    const fillAreaStyle = {
       position: "absolute",
       left: `${item.fillArea.x * rate}px`,
       top: `${item.fillArea.y * rate}px`,
@@ -223,7 +222,7 @@ function parseRecogBlocks() {
       height: `${item.fillArea.h * rate}px`,
       zIndex: 9,
     };
-    nitem.fillOptionStyles = item.optionSizes
+    const fillOptionStyles = item.optionSizes
       .map((op) => {
         const opStyle = {
           position: "absolute",
@@ -232,6 +231,7 @@ function parseRecogBlocks() {
           width: `${op.w * rate}px`,
           height: `${op.h * rate}px`,
           zIndex: 9,
+          border: "",
         };
 
         if (op.filled && fillShow) {
@@ -244,10 +244,17 @@ function parseRecogBlocks() {
           return opStyle;
         }
 
-        return;
+        return opStyle;
       })
       .filter((item) => item);
 
+    const nitem: RecogBlock = {
+      ...item,
+      fillAreaStyle,
+      fillOptionStyles,
+      areaImg: "",
+    };
+
     return nitem;
   });
 }
@@ -255,6 +262,7 @@ function parseRecogBlocks() {
 // area click
 const recogEditDialogRef = ref();
 async function onAreaClick(data: RecogBlock) {
+  if (!curPage.value) return;
   curRecogBlock.value = data;
   // 基于 fillArea 四周扩展一个 fillSize 尺寸
   const area = {
@@ -264,7 +272,7 @@ async function onAreaClick(data: RecogBlock) {
     h: data.fillArea.h + data.fillSize.h * 2,
   };
   curRecogBlock.value.areaImg = await getSliceFileUrl(
-    curPage.value?.sheetUri,
+    curPage.value.sheetUri,
     area
   );
   nextTick(() => {
@@ -273,7 +281,7 @@ async function onAreaClick(data: RecogBlock) {
 }
 
 async function onRecogEditConfirm(result: string[]) {
-  if (!curRecogBlock.value) return;
+  if (!curRecogBlock.value || !dataCheckStore.curPage) return;
 
   const data = curRecogBlock.value;
 

+ 6 - 6
src/render/views/DataCheck/SliceImage/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="slice-image">
+  <div v-if="curStudent" class="slice-image">
     <div v-for="item in curStudent.papers" :key="item.id" class="image-paper">
       <div
         v-for="(page, pindex) in item.pages"
@@ -15,7 +15,7 @@
             :key="sindex"
             class="image-item"
           >
-            <img :src="getFileUrl(url)" :alt="sindex + 1" />
+            <img :src="getFileUrl(url)" :alt="`${sindex + 1}`" />
             <div class="image-action">
               <import-btn
                 upload-url="/api/admin/scan/answer/slice/update"
@@ -89,14 +89,14 @@ const curSliceInfo = ref({
 
 const cardData = ref<CardPage[]>([]);
 
-function getPageTitle(paperNumber, pageIndex) {
+function getPageTitle(paperNumber: number, pageIndex: number) {
   return `卡${paperNumber}${pageIndex === 0 ? "正面" : "反面"}`;
 }
 
 // 编辑
 const cutImageDialogRef = ref();
 function onEditSlice(paperNumber: number, pageIndex: number, index: number) {
-  const paper = curStudent.value.papers[paperNumber - 1];
+  const paper = curStudent.value?.papers[paperNumber - 1];
   if (!paper) return;
 
   curSliceInfo.value = {
@@ -145,7 +145,7 @@ async function cutImageModified(file: File) {
 
 // 上传
 function onUpdateSlice(paperNumber: number, pageIndex: number, index: number) {
-  const paper = curStudent.value.papers[paperNumber - 1];
+  const paper = curStudent.value?.papers[paperNumber - 1];
   if (!paper) return;
 
   curSliceInfo.value = {
@@ -157,7 +157,7 @@ function onUpdateSlice(paperNumber: number, pageIndex: number, index: number) {
   };
 }
 
-function updateSliceSuccess(data: { url: string }) {
+function updateSliceSuccess(data: { uri: string }) {
   dataCheckStore.modifySliceUri({
     ...curSliceInfo.value,
     pageIndex: curSliceInfo.value.pageIndex - 1,

+ 5 - 6
src/render/views/DataCheck/types.ts

@@ -13,10 +13,9 @@ export interface StudentPage extends PaperPageItem {
 }
 
 export interface QuestionInfo {
-  examNumber: string;
-  name: string;
-  examSite: string;
-  seatNumber: number;
-  paperType: string;
-  examStatus: string;
+  examNumber: string | undefined;
+  name: string | undefined;
+  examSite: string | undefined;
+  seatNumber: number | undefined;
+  paperType: string | undefined;
 }

+ 1 - 1
src/render/views/ImageCheck/ImageFailed.vue

@@ -77,7 +77,7 @@ const columns: TableProps["columns"] = [
 
 const searchModel = reactive({
   examId: Number(route.params.examId),
-  subjectCode: route.params.subjectCode,
+  subjectCode: route.params.subjectCode as string,
 });
 
 const { dataList, pagination, loading } = useTable<ImageCheckFailedListItem>(

+ 13 - 4
src/render/views/RecognizeCheck/ModifyRecognizeCheckTask.vue

@@ -39,7 +39,7 @@
             :options="conditionList"
             :field-names="fieldNames"
             style="width: 200px"
-            @change="(val) => conditionChange(val, index)"
+            @change="() => conditionChange(index)"
           ></a-select>
         </a-form-item>
 
@@ -141,7 +141,15 @@ const deleteDisabled = computed(() => formData.conditions.length <= 1);
 // condition action
 const fieldNames = { label: "name", value: "code" };
 
-function conditionChange(val: string, index: number) {
+function conditionChange(index: number) {
+  const val = formData.conditions[index].code;
+  if (!val) {
+    formData.conditions[index].needValue = false;
+    formData.conditions[index].name = "";
+    formData.conditions[index].value = undefined;
+    return;
+  }
+
   const curCondition = props.conditionList.find((item) => item.code === val);
   if (!curCondition) return;
 
@@ -154,7 +162,7 @@ function onAddCondition(index: number) {
     code: "",
     name: "",
     needValue: false,
-    value: null,
+    value: undefined,
   });
 }
 function onDeleteCondition(index: number) {
@@ -202,6 +210,7 @@ function modalOpenHandle() {
     formData.conditions = props.rowData.conditions.map((item) => {
       return {
         ...item,
+        name: conditionMap[item.code]?.name,
         needValue: conditionMap[item.code]?.needValue,
       };
     });
@@ -210,7 +219,7 @@ function modalOpenHandle() {
     formData.subjectCode = "";
     formData.examId = userStore.curExam.id;
     formData.conditions = [
-      { code: "", name: "", needValue: false, value: null },
+      { code: "", name: "", needValue: false, value: undefined },
     ];
   }
 }

+ 4 - 4
src/render/views/RecognizeCheck/RecognizeArbitrate.vue

@@ -163,7 +163,7 @@ const curTask = ref<RecognizeArbitrateItem | null>(null);
 async function getNewTask() {
   recentPrevTaskId.value = 0;
 
-  const res = await recognizeArbitrateTask(groupId).catch(() => false);
+  const res = await recognizeArbitrateTask(groupId).catch(() => {});
   curTask.value = res || null;
   if (!curTask.value) {
     curArbitrateTaskDetailIndex.value = 0;
@@ -337,13 +337,13 @@ async function getPrevTask() {
 
 async function getNextTask() {
   // 执行待仲裁任务时,取新的任务
-  if (recentTask.value.id === curTask.value.id) {
+  if (recentTask.value?.id === curTask.value?.id) {
     await getNewTask();
     return;
   }
 
   // 执行历史记录最后一个任务时,取缓存的待仲裁任务
-  if (recentPrevTaskId.value === curTask.value.id) {
+  if (recentPrevTaskId.value === curTask.value?.id) {
     recentPrevTaskId.value = 0;
     curTask.value = recentTask.value;
     curArbitrateTaskDetails.value = recentArbitrateTaskDetails.value;
@@ -354,7 +354,7 @@ async function getNextTask() {
 
   const res = await recognizeArbitrateHistory({
     groupId,
-    id: curTask.value.id as number,
+    id: curTask.value?.id as number,
     next: true,
   }).catch(() => null);
 

+ 4 - 3
src/render/views/RecognizeCheck/index.vue

@@ -104,6 +104,7 @@ import useTable from "@/hooks/useTable";
 import {
   RecognizeCheckListItem,
   RecognizeConditionItem,
+  RecognizeCheckTaskSaveParams,
 } from "@/ap/types/recognizeCheck";
 import {
   recognizeCheckListPage,
@@ -149,12 +150,12 @@ const columns: TableProps["columns"] = [
   {
     title: "任务条件",
     dataIndex: "condition",
-    minWidth: "200px",
+    minWidth: 200,
   },
   {
     title: "科目",
     dataIndex: "subjectName",
-    minWidth: "120px",
+    minWidth: 120,
   },
   {
     title: "状态",
@@ -261,7 +262,7 @@ function onEdit(index: number) {
   modifyRecognizeCheckTaskRef.value?.open();
 }
 
-function onArbitrate(index) {
+function onArbitrate(index: number) {
   const record = dataList.value[index];
   router.push({ name: "RecognizeArbitrate", params: { groupId: record.id } });
 }

+ 1 - 1
src/render/views/ResultExport/BreachImport.vue

@@ -90,7 +90,7 @@ async function getData() {
 }
 
 const importDialogRef = ref();
-const uploadData = ref<Record<string, string>>({});
+const uploadData = ref<Record<string, string | number>>({});
 async function onImport(index: number) {
   const record = dataList.value[index];
   uploadData.value = {

+ 3 - 3
src/render/views/ResultExport/DbfExport.vue

@@ -58,7 +58,7 @@ import {
   dbfPackageExport,
   dbfExportTaskDownload,
 } from "@/ap/resultExport";
-import { markSiteSetParams } from "@/ap/types/resultExport";
+import { MarkSiteSetParams } from "@/ap/types/resultExport";
 import { useUserStore } from "@/store";
 
 import ModifySiteCode from "./ModifySiteCode.vue";
@@ -95,7 +95,7 @@ const columns: TableProps["columns"] = [
   },
 ];
 
-const siteCodeData = ref({} as markSiteSetParams);
+const siteCodeData = ref({} as MarkSiteSetParams);
 async function getScanSiteCode() {
   const res = await markSiteCodeInfo({ examId: userStore.curExam.id });
   siteCodeData.value = { scanSite: res, examId: userStore.curExam.id };
@@ -105,7 +105,7 @@ const modifySiteCodeRef = ref();
 function onSetSiteCode() {
   modifySiteCodeRef.value?.open();
 }
-function siteCodeModified(data: markSiteSetParams) {
+function siteCodeModified(data: MarkSiteSetParams) {
   siteCodeData.value = data;
 }
 

+ 4 - 4
src/render/views/ResultExport/ModifySiteCode.vue

@@ -33,7 +33,7 @@ import { markSiteCodeSet } from "@/ap/resultExport";
 import useLoading from "@/hooks/useLoading";
 import useModal from "@/hooks/useModal";
 import { objAssign, objModifyAssign } from "@/utils/tool";
-import { markSiteSetParams } from "@/ap/types/resultExport";
+import { MarkSiteSetParams } from "@/ap/types/resultExport";
 
 defineOptions({
   name: "ModifyMarkSite",
@@ -49,15 +49,15 @@ const defaultFormData = {
 };
 
 const props = defineProps<{
-  rowData: markSiteSetParams;
+  rowData: MarkSiteSetParams;
 }>();
 const emit = defineEmits(["modified"]);
 
 const formRef = ref();
-const formData: UnwrapRef<markSiteSetParams> = reactive({
+const formData: UnwrapRef<MarkSiteSetParams> = reactive({
   ...defaultFormData,
 });
-const rules: FormRules<keyof markSiteSetParams> = {
+const rules: FormRules<keyof MarkSiteSetParams> = {
   scanSite: [
     {
       required: true,

+ 1 - 1
src/render/views/ResultExport/StudentStatus.vue

@@ -100,7 +100,7 @@ async function getData() {
 }
 
 const importDialogRef = ref();
-const uploadData = ref<Record<string, string>>({});
+const uploadData = ref<Record<string, string | number>>({});
 async function onImport(index: number) {
   const record = dataList.value[index];
   curRow.value = record;

+ 3 - 3
src/render/views/Review/ResetConfirmDialog.vue

@@ -49,7 +49,7 @@ const userStore = useUserStore();
 
 const quoteContent = computed(() => {
   return `将重置${userStore.curExam.name}${
-    props.subject?.subjectCode || ""
+    props.subject?.code || ""
   }的复核校验任务,请输入当前管理员密码`;
 });
 
@@ -73,7 +73,7 @@ const { start: startLoopSync, stop: stopLoopSync } = useLoop(checkStatus, 1000);
 async function checkStatus() {
   const res = await reviewTaskResetStatus({
     examId: userStore.curExam.id,
-    subjectCode: props.subject?.subjectCode || "",
+    subjectCode: props.subject?.code || "",
   }).catch(() => {});
   if (res) {
     if (!res.synching) {
@@ -94,7 +94,7 @@ async function confirm() {
 
   const res = await reviewTaskReset({
     examId: userStore.curExam.id,
-    subjectCode: props.subject?.subjectCode || "",
+    subjectCode: props.subject?.code || "",
     password: formData.password,
   }).catch(() => false);
   if (!res) return;

+ 5 - 3
src/render/views/Review/ReviewAction.vue

@@ -231,7 +231,9 @@ async function getHistory() {
 }
 
 function updateTaskStatus(assignedSuspect: boolean) {
-  const row = dataList.value.find((item) => item.id === reviewStore.curTask.id);
+  const row = dataList.value.find(
+    (item) => item.id === reviewStore.curTask?.id
+  );
   if (!row) return;
   row.assignedSuspect = assignedSuspect;
 }
@@ -247,10 +249,10 @@ function onSearch() {
 }
 
 function onReset() {
-  let subjectData: SubjectItem | null = null;
+  let subjectData: SubjectItem | null | undefined = null;
   if (resetCourseCode.value) {
     subjectData = courses.value.find(
-      (item) => item.subjectCode === resetCourseCode.value
+      (item) => item.code === resetCourseCode.value
     );
     subjectData = subjectData || null;
   }

+ 2 - 2
src/render/views/Review/ReviewImage.vue

@@ -49,9 +49,9 @@ function onImgScroll(e: Event) {
 
   if (curTargetIndex && targetIndex !== curTargetIndex) return;
 
-  curTargetIndex = targetIndex;
+  curTargetIndex = targetIndex as string;
   const siblingsDoms = (
-    targetDom.parentElement.parentElement as HTMLElement
+    targetDom.parentElement?.parentElement as HTMLElement
   ).querySelectorAll(".review-image-item");
 
   siblingsDoms.forEach((elem) => {