Sfoglia il codice sorgente

feat: 数据检查初始页面

zhangjie 10 mesi fa
parent
commit
52ce05247d

+ 61 - 0
src/render/ap/dataCheck.ts

@@ -0,0 +1,61 @@
+import { request } from "@/utils/request";
+
+import {
+  DataCheckListFilter,
+  DataCheckListParams,
+  DataCheckListResult,
+  DataCheckOmrFieldEditParams,
+  DataCheckOmrEditParams,
+} from "./types/dataCheck";
+import { RequestActionResult } from "./types/common";
+
+// 图片检查
+// 查询答题卡扫描详情
+export const dataCheckList = (
+  data: DataCheckListParams
+): Promise<DataCheckListResult> =>
+  request({
+    url: "/api/admin/scan/answer/query",
+    method: "post",
+    data,
+  });
+
+// 按考生导出答题卡扫描详情
+export const dataCheckStudentExport = (
+  data: DataCheckListFilter
+): Promise<{ url: string }> =>
+  request({
+    url: "/api/admin/scan/answer/student/export",
+    method: "post",
+    data,
+  });
+
+// 按考场导出答题卡扫描详情
+export const dataCheckRoomExport = (
+  data: DataCheckListFilter
+): Promise<{ url: string }> =>
+  request({
+    url: "/api/admin/scan/answer/exam-room/export",
+    method: "post",
+    data,
+  });
+
+// 按类型修改卷型、识别结果等
+export const dataCheckOmrFieldEdit = (
+  data: DataCheckOmrFieldEditParams
+): Promise<RequestActionResult> =>
+  request({
+    url: "/api/admin/scan/answer/omr/field/edit",
+    method: "post",
+    data,
+  });
+
+// 修改答题卡识别结果
+export const dataCheckOmrEdit = (
+  data: DataCheckOmrEditParams
+): Promise<RequestActionResult> =>
+  request({
+    url: "/api/admin/scan/answer/omr/edit",
+    method: "post",
+    data,
+  });

+ 137 - 0
src/render/ap/types/dataCheck.ts

@@ -0,0 +1,137 @@
+import { PageResult, PageParams, ExamSubjectParams } from "./common";
+
+export type DataStatus = "SCANNED" | "UNEXIST" | "MANUAL_ABSENT";
+export type ExamStatus = "OK" | "ABSENT" | "UNCHECK";
+export type PaperTypeStatus = "OK" | "BLANK" | "ERROR";
+
+export interface DataCheckListFilter {
+  examId: string;
+  status: DataStatus[];
+  examStatus: ExamStatus;
+  examNumber: string;
+  studentCode: string;
+  name: string;
+  packageCode: string;
+  campusCode: string;
+  subjectCode: string;
+  examSite: string;
+  examRoom: string;
+  province: string;
+  paperTypeStatus: PaperTypeStatus;
+  device: string;
+  absentSuspect: boolean;
+  omrAbsent: boolean;
+  assigned: boolean;
+  incomplete: boolean;
+  questionFilled: boolean;
+  subjectiveFilled: boolean;
+  withOmrDetail: boolean;
+}
+
+export type DataCheckListParams = PageParams<DataCheckListFilter>;
+
+export interface PaperPageItem {
+  index: number;
+  sheetUri: string;
+  sliceUri: string[];
+  // withOmrDetail=true时有识别结果,显示最新的判定结果
+  absent: boolean;
+  breach: boolean;
+  paperType: string;
+  question: string[];
+  selective: string[];
+  recogData: string;
+}
+
+// 某张缺页时没有id和pages等其他字段
+export interface PaperItem {
+  id?: string;
+  number: number;
+  // 是否人工绑定
+  assigned?: boolean;
+  // 各页图片与识别结果
+  pages?: PaperPageItem[];
+}
+
+export interface DataCheckListItem {
+  id: string;
+  examNumber: string;
+  studentCode: string;
+  name: string;
+  subjectCode: string;
+  subjectName: string;
+  packageCode: string;
+  campusCode: string;
+  campusName: string;
+  examSite: string;
+  examSiteName: string;
+  examRoom: string;
+  seatNumber: number;
+  examStatus: ExamStatus;
+  // 扫描状态
+  status: DataStatus;
+  absentSuspect: boolean;
+  omrAbsent: boolean;
+  assigned: boolean;
+  incomplete: boolean;
+  // 识别试卷类型,若无则为null
+  paperType: string;
+  // 最新使用卡格式编号
+  cardNumber: number;
+  // 手动修改的管理员信息
+  updator: string;
+  updateTime: number;
+  device: string;
+  // 考生最新关联的各张图片
+  papers: PaperItem[];
+}
+
+export type DataCheckListResult = PageResult<DataCheckListItem>;
+
+export type OmrFiledType =
+  | "ABSENT"
+  | "REACH"
+  | "PAPER_TYPE"
+  | "SELECTIVE"
+  | "QUESTION";
+
+export interface DataCheckOmrFieldEditParams {
+  examId: string;
+  examNumber: string;
+  paperNumber: string;
+  pageIndex: number;
+  field: OmrFiledType;
+  questionIndex: number;
+  value: string;
+}
+
+interface OmrEditPaperPageInfo {
+  index: number;
+  // 不修改的字段为null,否则需要提交完整结果
+  // type与原始的卡格式定义相同
+  absent: {
+    type: "FILL_AREA";
+    result: boolean;
+  } | null;
+  breach: boolean | null;
+  paperType: {
+    type: "BARCODE";
+    result: string;
+  } | null;
+  question: {
+    type: "FILL_AREA";
+    result: string[];
+  } | null;
+  // selective: null;
+}
+
+interface OmrEditPaperInfo {
+  number: number;
+  pages: OmrEditPaperPageInfo[];
+}
+
+export interface DataCheckOmrEditParams {
+  examId: string;
+  examNumber: string;
+  papers: OmrEditPaperInfo[];
+}

+ 5 - 0
src/render/hooks/useTable.ts

@@ -35,6 +35,10 @@ export default function useTable<T extends Record<string, any>>(
     await getList();
   }
 
+  function setPageSize(size: number) {
+    pageSize.value = size;
+  }
+
   async function pageSizeChange(size: number) {
     pageSize.value = size;
     await toPage(1);
@@ -66,6 +70,7 @@ export default function useTable<T extends Record<string, any>>(
     dataList,
     pagination,
     loading,
+    setPageSize,
     getRowIndex,
     getList,
     toPage,

+ 8 - 0
src/render/router/routes.ts

@@ -38,6 +38,14 @@ const routes: RouteRecordRaw[] = [
           title: "扫描管理",
         },
       },
+      {
+        path: "data-check",
+        name: "DataCheck",
+        component: () => import("@/views/DataCheck/index.vue"),
+        meta: {
+          title: "数据检查",
+        },
+      },
       // 图片检查
       {
         path: "image-check",

+ 1 - 0
src/render/views/CurExam/index.vue

@@ -182,6 +182,7 @@
               <div
                 class="flex items-center cursor-pointer"
                 :style="{ color: token.colorPrimary }"
+                @click="toPage('DataCheck')"
               >
                 <span>进入</span>
                 <RightOutlined />

+ 79 - 0
src/render/views/DataCheck/index.vue

@@ -0,0 +1,79 @@
+<template>
+  <div class="data-check">
+    <div class="check-menu">
+      <div class="check-menu-body">
+        <ul>
+          <li v-for="item in dataList" :key="item.id">{{ item.examNumber }}</li>
+        </ul>
+      </div>
+      <div class="check-menu-page">
+        <div class="page-total">共{{ pagination.total }}页</div>
+        <div class="page-jumper">
+          <a-button @click="onPrevPage">
+            <template #icon> <CaretLeftOutlined /></template>
+          </a-button>
+          <a-button @click="onNextPage">
+            <template #icon> <CaretRightOutlined /></template>
+          </a-button>
+          <span>
+            前往
+            <a-input-number
+              v-model:value="formData.oddNumber"
+              :min="1"
+              :max="10"
+              :precision="0"
+              :controls="false"
+            ></a-input-number>
+          </span>
+        </div>
+      </div>
+    </div>
+    <div class="check-body"></div>
+    <div class="check-action"></div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import type { TableProps } from "ant-design-vue";
+import { CaretLeftOutlined, CaretRightOutlined } from "@ant-design/icons-vue";
+
+import useTable from "@/hooks/useTable";
+
+import { DataCheckListFilter, DataCheckListItem } from "@/ap/types/dataCheck";
+import { dataCheckList } from "@/ap/dataCheck";
+
+defineOptions({
+  name: "DataCheck",
+});
+
+const searchModel = reactive({
+  examId: route.params.examId,
+  subjectCode: route.params.subjectCode,
+});
+
+const { dataList, loading, pagination, getList, toPage, setPageSize } =
+  useTable<DataCheckListItem>(dataCheckList, searchModel, false);
+
+setPageSize(30);
+
+// page
+function onPrevPage() {
+  const { total, current } = pagination;
+  if (current <= 1) {
+    message.error("没有上一页了");
+    return;
+  }
+  toPage(current);
+}
+
+function onNextPage() {
+  const { total, current } = pagination;
+  if (current >= total) {
+    message.error("没有下一页了");
+    return;
+  }
+  toPage(current);
+}
+</script>