Jelajahi Sumber

feat: 缺考调整

zhangjie 9 bulan lalu
induk
melakukan
5885a0e8fd

+ 17 - 0
src/render/ap/examStatusCheck.ts

@@ -0,0 +1,17 @@
+import { request } from "@/utils/request";
+
+import {
+  ExamStatusSaveParams,
+  ExamStatusSaveResult,
+} from "./types/examStatusCheck";
+import { RequestActionResult } from "./types/common";
+
+// 提交
+export const examStatusSave = (
+  data: ExamStatusSaveParams
+): Promise<ExamStatusSaveResult> =>
+  request({
+    url: "/api/admin/check/exam-status/save",
+    method: "post",
+    data,
+  });

+ 10 - 0
src/render/ap/types/examStatusCheck.ts

@@ -0,0 +1,10 @@
+import { ExamStatus } from "./dataCheck";
+
+export interface ExamStatusSaveParams {
+  id: number;
+  examStatus: ExamStatus;
+}
+
+export interface ExamStatusSaveResult {
+  examStatus: ExamStatus;
+}

+ 4 - 0
src/render/constants/enumerate.ts

@@ -20,6 +20,10 @@ export const EXAM_STATUS = {
   ABSENT: "缺考",
   UNCHECK: "待审核",
 };
+export const EXAM_SIMPLE_STATUS = {
+  ABSENT: "是",
+  OK: "否",
+};
 
 export const IMAGE_TYPE = {
   ORIGIN: "原图",

+ 2 - 0
src/render/hooks/dictOption.ts

@@ -4,6 +4,7 @@ import {
   DATA_CHECK_TYPE,
   PAPER_TYPE_STATUS,
   EXAM_STATUS,
+  EXAM_SIMPLE_STATUS,
   IMAGE_TYPE,
 } from "@/constants/enumerate";
 
@@ -11,6 +12,7 @@ const dicts = {
   DATA_CHECK_TYPE,
   PAPER_TYPE_STATUS,
   EXAM_STATUS,
+  EXAM_SIMPLE_STATUS,
   IMAGE_TYPE,
 };
 

+ 2 - 2
src/render/store/modules/dataCheck/index.ts

@@ -16,9 +16,9 @@ interface DataCheckState {
 
 type UpdateFieldParams = Pick<DataCheckOmrFieldEditParams, "field" | "value">;
 
-export const useDataCheckStore = defineStore("review", {
+export const useDataCheckStore = defineStore("dataCheck", {
   state: (): DataCheckState => ({
-    tabKey: "ORIGIN",
+    imageType: "ORIGIN",
     curPage: null,
     curPageIndex: -1,
     curStudent: null,

+ 45 - 21
src/render/views/DataCheck/CheckAction.vue

@@ -51,7 +51,7 @@
             </div>
             <a-button class="ant-simple m-l-8px" type="link">查看全部</a-button>
           </a-form-item>
-          <a-form-item label="查找条件">
+          <a-form-item label="姓名">
             <a-input
               v-model:value="searchModel.name"
               placeholder="请输入"
@@ -76,6 +76,7 @@
                   placeholder="请选择"
                   :options="booleanOptions"
                   style="width: 85px"
+                  allow-clear
                 ></a-select>
               </a-form-item>
             </a-col>
@@ -85,7 +86,8 @@
                   v-model:value="searchModel.subjectiveFilled"
                   placeholder="请选择"
                   :options="booleanOptions"
-                  style="width: 85px"
+                  style="width: 100%"
+                  allow-clear
                 ></a-select>
               </a-form-item>
             </a-col>
@@ -96,6 +98,7 @@
                   placeholder="请选择"
                   :options="booleanOptions"
                   style="width: 85px"
+                  allow-clear
                 ></a-select>
               </a-form-item>
             </a-col>
@@ -105,28 +108,33 @@
                   v-model:value="searchModel.paperTypeStatus"
                   placeholder="请选择"
                   :options="paperTypeOptions"
+                  style="width: 100%"
+                  allow-clear
+                ></a-select>
+              </a-form-item>
+            </a-col>
+          </a-row>
+          <a-row>
+            <a-col :span="16">
+              <a-form-item label="缺考">
+                <a-select
+                  v-model:value="searchModel.examStatus"
+                  placeholder="请选择"
+                  :options="examStatusOptions"
                   style="width: 85px"
+                  allow-clear
                 ></a-select>
               </a-form-item>
             </a-col>
+            <a-col :span="8">
+              <a-form-item>
+                <a-button class="m-r-8px" type="primary" @click="onCustomSearch"
+                  >查询</a-button
+                >
+                <a-button @click="onExport('custom')">导出</a-button>
+              </a-form-item>
+            </a-col>
           </a-row>
-          <div class="box-justify">
-            <a-form-item label="缺考">
-              <a-radio-group
-                v-model:value="searchModel.incomplete"
-                name="incomplete"
-                :options="booleanOptions"
-              >
-              </a-radio-group>
-            </a-form-item>
-
-            <div>
-              <a-button class="m-r-8px" type="primary" @click="onCustomSearch"
-                >查询</a-button
-              >
-              <a-button @click="onExport('custom')">导出</a-button>
-            </div>
-          </div>
         </a-form>
       </a-collapse-panel>
       <a-collapse-panel key="3">
@@ -147,7 +155,9 @@
         <QuestionPanel
           v-model:questions="questions"
           :info="questionInfo"
+          :simple="isSliceImage"
           @change="onQuestionsChange"
+          @exam-status-change="onExamStatusChange"
         />
       </a-collapse-panel>
     </a-collapse>
@@ -168,9 +178,10 @@ import {
 import { message } from "ant-design-vue";
 
 import { useUserStore, useDataCheckStore } from "@/store";
-import { DataCheckListFilter } from "@/ap/types/dataCheck";
+import { DataCheckListFilter, ExamStatus } from "@/ap/types/dataCheck";
 import { SubjectItem } from "@/ap/types/base";
 import { dataCheckStudentExport, dataCheckRoomExport } from "@/ap/dataCheck";
+import { examStatusSave } from "@/ap/examStatusCheck";
 import useDictOption from "@/hooks/dictOption";
 import useLoading from "@/hooks/useLoading";
 import { ImageType, booleanOptionList } from "@/constants/enumerate";
@@ -191,6 +202,7 @@ const dataCheckStore = useDataCheckStore();
 const { optionList: dataCheckOptions } = useDictOption("DATA_CHECK_TYPE");
 const { optionList: paperTypeOptions } = useDictOption("PAPER_TYPE_STATUS");
 const { optionList: imageTypeOptions } = useDictOption("IMAGE_TYPE");
+const { optionList: examStatusOptions } = useDictOption("EXAM_STATUS");
 const booleanOptions = ref(booleanOptionList);
 const panelKey = ref(["1", "2", "3", "4"]);
 
@@ -230,9 +242,14 @@ const searchModel = reactive<DataCheckListFilter>({ ...initSearchModel });
 const searchSubjectCode = ref("");
 const searchCustomSubjectCode = ref("");
 const searchDataCheckType = ref();
-const imageType = ref("" as ImageType);
+const imageType = ref(dataCheckStore.imageType);
 const actionType = ref("common");
 
+// imageType
+const isSliceImage = computed(() => {
+  return dataCheckStore.imageType === "SLICE";
+});
+
 const examNumberCountCont = computed(() => {
   const examNumbers = (searchModel.examNumber || "")
     .split("\n")
@@ -295,6 +312,13 @@ async function onQuestionsChange() {
     .catch(() => {});
 }
 
+async function onExamStatusChange(val: ExamStatus) {
+  if (!dataCheckStore.curStudent) return;
+
+  await examStatusSave({ id: dataCheckStore.curStudent.id, examStatus: val });
+  dataCheckStore.curStudent.examStatus = val;
+}
+
 // 导出
 const { loading: downloading, setLoading } = useLoading();
 const exportTypeDialogRef = ref();

+ 35 - 13
src/render/views/DataCheck/QuestionPanel.vue

@@ -14,21 +14,27 @@
         {{ info.examSite }}
       </a-descriptions-item>
       <a-descriptions-item label="卷型号" :span="6">
-        <a-button class="ant-gray m-r-4px">{{ info.paperType }}</a-button>
-        <a-button>
-          <template #icon><SwapOutlined /></template>
-        </a-button>
+        <template v-if="simple">
+          {{ info.paperType }}
+        </template>
+        <template v-else>
+          <a-button class="ant-gray m-r-4px">{{ info.paperType }}</a-button>
+          <a-button>
+            <template #icon><SwapOutlined /></template>
+          </a-button>
+        </template>
       </a-descriptions-item>
-      <a-descriptions-item label="缺考" :span="4">
+      <a-descriptions-item v-if="!simple" label="缺考" :span="4">
         <a-radio-group
-          v-model:value="incomplete"
-          name="incomplete"
-          :options="booleanOptions"
+          v-model:value="examStatus"
+          name="examStatus"
+          :options="examStatusOptions"
+          @change="onExamStatusChange"
         >
         </a-radio-group>
       </a-descriptions-item>
     </a-descriptions>
-    <div ref="panelBodyRef" class="panel-body">
+    <div v-if="!simple" ref="panelBodyRef" class="panel-body">
       <div class="panel-body-title">
         <h4>客观题</h4>
         <p>多于一个填涂显示>号,未填涂显示#号</p>
@@ -66,8 +72,8 @@
 import { computed, ref, watch } from "vue";
 import { message } from "ant-design-vue";
 import { SwapOutlined } from "@ant-design/icons-vue";
-import { booleanOptionList } from "@/constants/enumerate";
 import { QuestionInfo } from "./types";
+import useDictOption from "@/hooks/dictOption";
 
 import { vEleClickOutsideDirective } from "@/directives/eleClickOutside";
 
@@ -79,19 +85,25 @@ const props = withDefaults(
   defineProps<{
     questions: string[];
     info: QuestionInfo;
+    simple: boolean;
   }>(),
   {
     questions: () => [],
+    simple: false,
   }
 );
-const emit = defineEmits(["update:questions", "change"]);
+const emit = defineEmits(["update:questions", "change", "examStatusChange"]);
 
-const booleanOptions = ref(booleanOptionList);
-const incomplete = ref();
+const { optionList: examStatusOptions } = useDictOption("EXAM_SIMPLE_STATUS");
+const examStatus = ref("");
 const questionList = ref([]);
 const curQuestion = ref("");
 const curQuestionIndex = ref(-1);
 
+function onExamStatusChange() {
+  emit("examStatusChange", examStatus.value);
+}
+
 function getQuestionNo(index: number) {
   const no = index + 1;
   return no < 10 ? `0${no}` : `${no}`;
@@ -172,6 +184,13 @@ watch(
     immediate: true,
   }
 );
+
+watch(
+  () => props.info,
+  (val) => {
+    examStatus.value = val.examStatus;
+  }
+);
 </script>
 
 <style lang="less" scoped>
@@ -248,6 +267,9 @@ watch(
         }
       }
     }
+    .ant-descriptions-item-content {
+      align-items: center;
+    }
 
     .ant-radio-wrapper span.ant-radio + * {
       padding-inline-start: 4px;

+ 25 - 9
src/render/views/DataCheck/index.vue

@@ -69,7 +69,7 @@ const dataCheckStore = useDataCheckStore();
 
 let searchModel = {} as DataCheckListFilter;
 const pageNumber = ref(1);
-const pageSize = ref(10);
+const pageSize = ref(20);
 const total = ref(0);
 const studentList = ref<DataCheckListItem[]>([]);
 const dataList = ref<StudentPage[]>([]);
@@ -163,20 +163,36 @@ function selectPage(index: number) {
   updateRecogList();
 }
 
-function onPrevPage() {
-  const { total, current } = pagination;
-  if (current <= 1) {
-    message.error("没有上一页了");
+async function onPrevPage() {
+  if (dataCheckStore.curPageIndex <= 0) {
+    if (pageNumber.value === 1) {
+      message.error("没有上一张了");
+      return;
+    }
+
+    pageNumber.value--;
+    await getList();
+    selectPage(dataList.value.length - 1);
     return;
   }
-  toPage(current);
+
+  selectPage(dataCheckStore.curPageIndex - 1);
 }
 
-function onNextPage() {
-  if (curPageIndex.value >= curPaper.value?.pages?.length) {
+async function onNextPage() {
+  if (dataCheckStore.curPageIndex >= dataList.value.length - 1) {
+    if (pageNumber.value >= total.value) {
+      message.error("没有下一张了");
+      return;
+    }
+
+    pageNumber.value++;
+    await getList();
+    selectPage(0);
+    return;
   }
 
-  selectPage(++curPageIndex.value);
+  selectPage(dataCheckStore.curPageIndex + 1);
 }
 
 // recog data

+ 1 - 0
src/render/views/DataCheck/types.ts

@@ -16,4 +16,5 @@ export interface QuestionInfo {
   examSite: string;
   seatNumber: number;
   paperType: string;
+  examStatus: string;
 }

+ 0 - 0
src/render/views/ExamStatusCheck/index.vue