Selaa lähdekoodia

feat: test-打回卷

zhangjie 2 päivää sitten
vanhempi
commit
61cc3cb8e8

+ 7 - 5
src/api/types/reject.ts

@@ -28,15 +28,17 @@ export type RejectListPageRes = PageResult<RejectItem>;
 
 export interface RejectListFilter {
   /** 科目 */
-  subjectCode: string | null;
+  subjectCode: string;
   /** 分组序号 */
-  groupNumber: number;
+  groupNumber?: number;
   /** 打回原因 */
-  rejectReason: string;
+  rejectTypeId?: number;
   /** 评卷员 */
-  markerId: string | null;
+  markerId?: number;
   /** 打回人 */
-  headerId: string | null;
+  headerId?: number;
+  // 状态
+  status?: string;
 }
 export type RejectListPageParams = PageParams<RejectListFilter>;
 

+ 21 - 5
src/components/select-data/index.vue

@@ -27,7 +27,7 @@
     name: 'SelectData',
   });
 
-  type ValueType = number | Array<number> | null;
+  type ValueType = number | Array<number> | undefined;
 
   const props = withDefaults(
     defineProps<{
@@ -37,11 +37,13 @@
       placeholder?: string;
       type: SelectType;
       params?: Record<string, any>;
+      paramRequired?: boolean;
     }>(),
     {
       clearable: true,
       disabled: false,
       placeholder: '请选择',
+      paramRequired: false,
     }
   );
   const emit = defineEmits(['update:modelValue', 'change']);
@@ -49,23 +51,37 @@
 
   const selected = ref<number | Array<number> | undefined>();
   const { optionList, search } = useSearch(props.type);
-  search(props.params);
 
   const onChange = () => {
     const selectedData = optionList.value.filter(
       (item) => selected.value === item.value
     );
-    emit('update:modelValue', selectedData[0].value || null);
+    emit('update:modelValue', selectedData[0].value || undefined);
     emit('change', selectedData[0]);
   };
 
   watch(
     () => props.params,
     (val, oldval) => {
-      if (!val) return;
+      optionList.value = [];
+      if (!val) {
+        if (!props.paramRequired) {
+          search({});
+        }
+        return;
+      }
 
       if (JSON.stringify(val) !== JSON.stringify(oldval)) {
-        search(val);
+        if (!props.paramRequired) {
+          search(val);
+          return;
+        }
+        if (
+          Object.keys(val).length > 0 &&
+          Object.values(val).every((item) => Boolean(item))
+        ) {
+          search(val);
+        }
       }
     },
     {

+ 16 - 1
src/components/select-data/search.ts

@@ -2,6 +2,7 @@ import axios from 'axios';
 import { ref } from 'vue';
 
 import useLoading from '@/hooks/loading';
+import { MarkGroupItem } from '@/api/types/mark';
 
 export interface OptionListItem {
   value: number;
@@ -28,7 +29,21 @@ const selectConfig: Record<string, SelectConfigValue> = {
   // 问题卷分类
   problemType: '/api/admin/exam/problem/type/list',
   // 打回卷分类
-  rejectType: '/api/admin/exam/reject/type/find',
+  rejectType: '/api/admin/exam/reject/type/list',
+  // 评卷员
+  marker: '/api/admin/exam/marker/query',
+  // 打回人
+  header: '/api/admin/exam/header/query',
+  // 分组
+  group: {
+    url: '/api/admin/exam/group/list',
+    transform: (data: MarkGroupItem[]) => {
+      return data.map((item) => ({
+        value: item.groupNumber,
+        label: `${item.groupNumber}-${item.mainNumber}`,
+      }));
+    },
+  },
 };
 export type SelectType = keyof typeof selectConfig;
 

+ 21 - 5
src/components/select-option/index.vue

@@ -27,7 +27,7 @@
     name: 'SelectOption',
   });
 
-  type ValueType = string | Array<string> | null;
+  type ValueType = string | Array<string> | undefined;
 
   const props = withDefaults(
     defineProps<{
@@ -37,11 +37,13 @@
       placeholder?: string;
       type: SelectType;
       params?: Record<string, any>;
+      paramRequired?: boolean;
     }>(),
     {
       clearable: true,
       disabled: false,
       placeholder: '请选择',
+      paramRequired: false,
     }
   );
   const emit = defineEmits(['update:modelValue', 'change']);
@@ -49,23 +51,37 @@
 
   const selected = ref<string | Array<string> | undefined>();
   const { optionList, search } = useSearch(props.type);
-  search(props.params);
 
   const onChange = () => {
     const selectedData = optionList.value.filter(
       (item) => selected.value === item.value
     );
-    emit('update:modelValue', selectedData[0].value || null);
+    emit('update:modelValue', selectedData[0].value || undefined);
     emit('change', selectedData[0]);
   };
 
   watch(
     () => props.params,
     (val, oldval) => {
-      if (!val) return;
+      optionList.value = [];
+      if (!val) {
+        if (!props.paramRequired) {
+          search({});
+        }
+        return;
+      }
 
       if (JSON.stringify(val) !== JSON.stringify(oldval)) {
-        search(val);
+        if (!props.paramRequired) {
+          search(val);
+          return;
+        }
+        if (
+          Object.keys(val).length > 0 &&
+          Object.values(val).every((item) => item)
+        ) {
+          search(val);
+        }
       }
     },
     {

+ 5 - 2
src/store/modules/app/index.ts

@@ -64,10 +64,13 @@ const useAppStore = defineStore('app', {
     appInfo(state: AppState): AppState {
       return { ...state };
     },
-    isMultiExam() {
+    isMultiExam(): boolean {
       return this.curExam && this.curExam.type === 'MULTI_MEDIA';
     },
-    displayExamName() {
+    examId(): number | undefined {
+      return this.curExam?.id || undefined;
+    },
+    displayExamName(): string {
       return this.curExam?.id ? `${this.curExam.id}-${this.curExam.name}` : '';
     },
   },

+ 39 - 38
src/views/reject/RejectManage.vue

@@ -5,45 +5,43 @@
         <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="分组">
-        <el-input-number
-          v-model.number="searchModel.groupNumber"
-          :min="1"
-          :max="999"
-          :step="1"
-          :precision="0"
-          :controls="false"
-          step-strictly
-          placeholder="请输入"
-          style="width: 120px"
-        >
-        </el-input-number>
+        <select-data
+          v-model="searchModel.groupNumber"
+          type="group"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item label="打回原因">
-        <el-input
-          v-model.trim="searchModel.rejectReason"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.rejectTypeId"
+          type="rejectType"
+          :params="{ examId: appStore.examId }"
+        />
       </el-form-item>
       <el-form-item label="评卷员">
-        <el-input
-          v-model.trim="searchModel.markerId"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.markerId"
+          type="marker"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+            groupNumber: searchModel.groupNumber,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item label="打回人">
-        <el-input
-          v-model.trim="searchModel.headerId"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.headerId"
+          type="header"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+            groupNumber: searchModel.groupNumber,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="toPage(1)">查询</el-button>
@@ -100,21 +98,24 @@
   import { RejectItem, RejectListFilter } from '@/api/types/reject';
   import useTable from '@/hooks/table';
   import { timestampFilter } from '@/utils/filter';
+  import { useAppStore } from '@/store';
 
   defineOptions({
     name: 'RejectManage',
   });
 
+  const appStore = useAppStore();
+
   const searchModel = reactive<RejectListFilter>({
-    subjectCode: null,
+    subjectCode: '',
     groupNumber: undefined,
-    rejectReason: '',
-    markerId: null,
-    headerId: null,
+    rejectTypeId: undefined,
+    markerId: undefined,
+    headerId: undefined,
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<RejectItem>(getRejectList, searchModel, false);
+    useTable<RejectItem>(getRejectList, searchModel, true);
 
   function onViewDetail(row: RejectItem) {
     // TODO: 实现查看详情功能

+ 40 - 38
src/views/reject/reject-stat/RejectRecord.vue

@@ -5,45 +5,43 @@
         <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="分组">
-        <el-input-number
-          v-model.number="searchModel.groupNumber"
-          :min="1"
-          :max="999"
-          :step="1"
-          :precision="0"
-          :controls="false"
-          step-strictly
-          placeholder="请输入"
-          style="width: 120px"
-        >
-        </el-input-number>
+        <select-data
+          v-model="searchModel.groupNumber"
+          type="group"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item label="打回原因">
-        <el-input
-          v-model.trim="searchModel.rejectReason"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.rejectTypeId"
+          type="rejectType"
+          :params="{ examId: appStore.examId }"
+        />
       </el-form-item>
       <el-form-item label="评卷员">
-        <el-input
-          v-model.trim="searchModel.markerId"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.markerId"
+          type="marker"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+            groupNumber: searchModel.groupNumber,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item label="打回人">
-        <el-input
-          v-model.trim="searchModel.headerId"
-          placeholder="请输入"
-          clearable
-          style="width: 120px"
-        >
-        </el-input>
+        <select-data
+          v-model="searchModel.headerId"
+          type="header"
+          :params="{
+            subjectCode: searchModel.subjectCode,
+            groupNumber: searchModel.groupNumber,
+          }"
+          param-required
+        />
       </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="toPage(1)">查询</el-button>
@@ -92,21 +90,25 @@
   import useTable from '@/hooks/table';
   import { timestampFilter } from '@/utils/filter';
   import { downloadExport } from '@/utils/download-export';
+  import { useAppStore } from '@/store';
 
   defineOptions({
     name: 'RejectRecord',
   });
 
+  const appStore = useAppStore();
+
   const searchModel = reactive<RejectListFilter>({
-    subjectCode: null,
+    subjectCode: '',
     groupNumber: undefined,
-    rejectReason: '',
-    markerId: null,
-    headerId: null,
+    rejectTypeId: undefined,
+    markerId: undefined,
+    headerId: undefined,
+    status: 'finish',
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<RejectItem>(getRejectRecordList, searchModel, false);
+    useTable<RejectItem>(getRejectRecordList, searchModel, true);
 
   async function onExport() {
     await downloadExport('exportRejectRecord', searchModel);

+ 1 - 1
src/views/reject/reject-stat/RejectStatistics.vue

@@ -105,7 +105,7 @@
   } = useTable<RejectStatisticsItem>(
     getRejectStatisticsList,
     searchModel,
-    false
+    true
   );
 
   function formatPercentage(rate: number): string {

+ 1 - 1
src/views/reject/reject-stat/index.vue

@@ -20,7 +20,7 @@
   .stat-container {
     display: flex;
     flex-direction: column;
-    height: calc(100vh - 136px);
+    height: calc(100vh - 90px);
     gap: 16px;
     overflow: hidden;
     min-width: 800px;