Browse Source

feat: 细节02

zhangjie 1 week ago
parent
commit
d20540ff7b

+ 40 - 3
src/api/review.ts

@@ -120,16 +120,53 @@ export function exportReviewWorkload(): Promise<AxiosResponse<Blob>> {
   );
   );
 }
 }
 
 
-// TODO: 复核导入模板下载
+// 复核导入模板下载
 export function reviewImportTemplate(): Promise<AxiosResponse<Blob>> {
 export function reviewImportTemplate(): Promise<AxiosResponse<Blob>> {
   return axios.post(
   return axios.post(
-    '/api/admin/exam/inspected/import/template/export',
+    '/api/admin/exam/inspected/import/template',
     {},
     {},
     { params, responseType: 'blob' }
     { params, responseType: 'blob' }
   );
   );
 }
 }
 
 
+// 成绩校验 -------------->
 // 获取成绩校验列表信息
 // 获取成绩校验列表信息
 export function getScoreCheckList(): Promise<ScoreCheckListPageRes> {
 export function getScoreCheckList(): Promise<ScoreCheckListPageRes> {
-  return axios.post('/api/review/score/check/list', {});
+  return axios.post('/api/admin/exam/inspected/import/list', {});
+}
+
+// 获取导入待复核数量
+export function getScoreCheckCount(): Promise<number> {
+  return axios.post('/api/admin/exam/inspected/import/todo-count', {});
+}
+
+// 重置成绩校验
+export function resetScoreCheck(): Promise<boolean> {
+  return axios.post('/api/admin/exam/inspected/import/reset', {});
+}
+
+// 导出错误日志
+export function exportScoreErrorLog(): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/exam/inspected/import/export',
+    {},
+    { responseType: 'blob' }
+  );
+}
+// 导出标记卷
+export function exportScoreMarkList(): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/exam/inspected/import/export-tag',
+    {},
+    { responseType: 'blob' }
+  );
+}
+
+// TODO:导出成绩校验记录
+export function exportScoreCheckList(): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/exam/inspected/import/export-check',
+    {},
+    { responseType: 'blob' }
+  );
 }
 }

+ 3 - 0
src/api/types/mark.ts

@@ -98,6 +98,8 @@ export interface MarkArbitrationItem {
   subjectCode: string;
   subjectCode: string;
   // 科目名称
   // 科目名称
   subjectName: string;
   subjectName: string;
+  // 密号
+  secretNumber: string;
   // 分组序号
   // 分组序号
   groupNumber: number;
   groupNumber: number;
   // 准考证号
   // 准考证号
@@ -149,6 +151,7 @@ export interface MarkTaskItem {
   rejectReason: string;
   rejectReason: string;
   // 评卷员
   // 评卷员
   markerLoginName: string;
   markerLoginName: string;
+  markName: string;
   // 评卷总分
   // 评卷总分
   markerScore: number;
   markerScore: number;
   // 给分明细
   // 给分明细

+ 11 - 11
src/router/routes/modules/base.ts

@@ -103,19 +103,19 @@ const BASE: AppRouteRecordRaw = {
         requiresAuth: true,
         requiresAuth: true,
       },
       },
     },
     },
-    {
-      path: '/rejcect-record',
-      name: 'RejectRecord',
-      component: () => import('@/views/reject/RejectRecord.vue'),
-      meta: {
-        title: '打回记录',
-        requiresAuth: true,
-      },
-    },
+    // {
+    //   path: '/rejcect-record',
+    //   name: 'RejectRecord',
+    //   component: () => import('@/views/reject/RejectRecord.vue'),
+    //   meta: {
+    //     title: '打回记录',
+    //     requiresAuth: true,
+    //   },
+    // },
     {
     {
       path: 'reject-statistics',
       path: 'reject-statistics',
       name: 'RejectStatistics',
       name: 'RejectStatistics',
-      component: () => import('@/views/reject/RejectStatistics.vue'),
+      component: () => import('@/views/reject/reject-stat/index.vue'),
       meta: {
       meta: {
         title: '打回统计',
         title: '打回统计',
         requiresAuth: true,
         requiresAuth: true,
@@ -205,7 +205,7 @@ const BASE: AppRouteRecordRaw = {
     {
     {
       path: '/score-check',
       path: '/score-check',
       name: 'ScoreCheck',
       name: 'ScoreCheck',
-      component: () => import('@/views/review/ScoreQuery.vue'),
+      component: () => import('@/views/review/ScoreCheck.vue'),
       meta: {
       meta: {
         title: '成绩校验',
         title: '成绩校验',
         requiresAuth: true,
         requiresAuth: true,

+ 1 - 10
src/store/modules/app/menuData.ts

@@ -174,21 +174,12 @@ export const adminMenus = [
   },
   },
   {
   {
     id: 802,
     id: 802,
-    name: '打回记录',
-    code: 'RejectRecord',
-    icon: '',
-    type: 'MENU',
-    parentCode: 'reject',
-    seq: 2,
-  },
-  {
-    id: 803,
     name: '打回统计',
     name: '打回统计',
     code: 'RejectStatistics',
     code: 'RejectStatistics',
     icon: '',
     icon: '',
     type: 'MENU',
     type: 'MENU',
     parentCode: 'reject',
     parentCode: 'reject',
-    seq: 3,
+    seq: 2,
   },
   },
   {
   {
     id: 9,
     id: 9,

+ 9 - 0
src/utils/download-export.ts

@@ -48,6 +48,9 @@ import {
   exportFullReviewList,
   exportFullReviewList,
   exportReviewWorkload,
   exportReviewWorkload,
   reviewImportTemplate,
   reviewImportTemplate,
+  exportScoreErrorLog,
+  exportScoreCheckList,
+  exportScoreMarkList,
 } from '@/api/review';
 } from '@/api/review';
 import { exportImageCheckData } from '@/api/check';
 import { exportImageCheckData } from '@/api/check';
 
 
@@ -149,6 +152,12 @@ const downloadConfig = {
   exportReviewWorkload,
   exportReviewWorkload,
   // 复核导入模板下载
   // 复核导入模板下载
   reviewImportTemplate,
   reviewImportTemplate,
+  // 导出成绩校验错误日志
+  exportScoreErrorLog,
+  // 导出成绩校验记录
+  exportScoreCheckList,
+  // 导出成绩标记记录
+  exportScoreMarkList,
   // check
   // check
   // 导出图片检查数据
   // 导出图片检查数据
   exportImageCheckData,
   exportImageCheckData,

+ 4 - 25
src/views/mark/ArbitrationManage.vue

@@ -64,15 +64,14 @@
       <el-table-column
       <el-table-column
         prop="groupNumber"
         prop="groupNumber"
         label="分组序号"
         label="分组序号"
-        width="110"
+        width="120"
         sortable
         sortable
       />
       />
       <el-table-column prop="examNumber" label="准考证号" width="150" />
       <el-table-column prop="examNumber" label="准考证号" width="150" />
-      <el-table-column label="状态" width="100" sortable>
+      <el-table-column prop="secretNumber" label="密号" width="150" />
+      <el-table-column prop="status" label="状态" width="100" sortable>
         <template #default="scope">
         <template #default="scope">
-          <el-tag :type="getStatusType(scope.row.status)" size="small">
-            {{ getStatusText(scope.row.status) }}
-          </el-tag>
+          {{ scope.row.statusText }}
         </template>
         </template>
       </el-table-column>
       </el-table-column>
       <el-table-column
       <el-table-column
@@ -149,26 +148,6 @@
     handleSortChange,
     handleSortChange,
   } = useTable<MarkArbitrationItem>(getArbitrationList, searchModel, false);
   } = useTable<MarkArbitrationItem>(getArbitrationList, searchModel, false);
 
 
-  // 获取状态类型
-  function getStatusType(status: string) {
-    const statusMap: Record<string, string> = {
-      pending: 'warning',
-      processed: 'success',
-      closed: 'info',
-    };
-    return statusMap[status] || 'info';
-  }
-
-  // 获取状态文本
-  function getStatusText(status: string) {
-    const statusMap: Record<string, string> = {
-      pending: '待处理',
-      processed: '已处理',
-      closed: '已关闭',
-    };
-    return statusMap[status] || status;
-  }
-
   // 处理仲裁
   // 处理仲裁
   function onHandle(row: MarkArbitrationItem) {
   function onHandle(row: MarkArbitrationItem) {
     ElMessage.info(`处理仲裁:${row.examNumber}`);
     ElMessage.info(`处理仲裁:${row.examNumber}`);

+ 6 - 2
src/views/mark/TaskManage.vue

@@ -147,7 +147,11 @@
         label="评卷员"
         label="评卷员"
         width="120"
         width="120"
         sortable
         sortable
-      />
+      >
+        <template #default="scope">
+          {{ scope.row.markerLoginName }} / {{ scope.row.markerName }}
+        </template>
+      </el-table-column>
       <el-table-column prop="markerScore" label="评卷总分" width="100" />
       <el-table-column prop="markerScore" label="评卷总分" width="100" />
       <el-table-column
       <el-table-column
         prop="markerScoreList"
         prop="markerScoreList"
@@ -210,7 +214,7 @@
 
 
   <RejectTaskDialog
   <RejectTaskDialog
     ref="rejectTaskDialogRef"
     ref="rejectTaskDialogRef"
-    :task-id="curRow.id"
+    :row-data="curRow"
     @modified="getList"
     @modified="getList"
   />
   />
 </template>
 </template>

+ 12 - 4
src/views/mark/components/RejectTaskDialog.vue

@@ -16,6 +16,14 @@
       :rules="rules"
       :rules="rules"
       label-width="100px"
       label-width="100px"
     >
     >
+      <el-form-item label="科目">
+        {{ props.rowData.subjectCode }}-{{ props.rowData.subjectName }}-{{
+          props.rowData.groupNumber
+        }}
+      </el-form-item>
+      <el-form-item label="评卷员">
+        {{ props.rowData.markerLoginName }} / {{ props.rowData.markerName }}
+      </el-form-item>
       <el-form-item label="打回原因" prop="rejectType">
       <el-form-item label="打回原因" prop="rejectType">
         <el-select
         <el-select
           v-model="formModel.rejectType"
           v-model="formModel.rejectType"
@@ -56,7 +64,7 @@
   import { ref, reactive, onMounted } from 'vue';
   import { ref, reactive, onMounted } from 'vue';
   import type { FormInstance, FormRules } from 'element-plus';
   import type { FormInstance, FormRules } from 'element-plus';
   import { ElMessage } from 'element-plus';
   import { ElMessage } from 'element-plus';
-  import type { MarkRejectTaskParam } from '@/api/types/mark';
+  import type { MarkRejectTaskParam, MarkTaskItem } from '@/api/types/mark';
   import type { RejectTypeItem } from '@/api/types/reject';
   import type { RejectTypeItem } from '@/api/types/reject';
   import { markTaskRejectOrReset } from '@/api/mark';
   import { markTaskRejectOrReset } from '@/api/mark';
   import { getRejectTypeList } from '@/api/reject';
   import { getRejectTypeList } from '@/api/reject';
@@ -74,7 +82,7 @@
   defineExpose({ open, close });
   defineExpose({ open, close });
 
 
   interface Props {
   interface Props {
-    taskId?: number; // 任务ID
+    rowData: MarkTaskItem;
   }
   }
 
 
   const props = defineProps<Props>();
   const props = defineProps<Props>();
@@ -128,8 +136,8 @@
 
 
   /* init modal */
   /* init modal */
   function modalBeforeOpen() {
   function modalBeforeOpen() {
-    if (props.taskId) {
-      formModel.id = props.taskId;
+    if (props.rowData) {
+      formModel.id = props.rowData.id;
     }
     }
   }
   }
 
 

+ 0 - 26
src/views/reject/index.vue

@@ -1,26 +0,0 @@
-<template>
-  <el-tabs v-model="activeTab" type="border-card">
-    <el-tab-pane label="打回页面" name="reject">
-      <RejectManage />
-    </el-tab-pane>
-    <el-tab-pane label="打回记录" name="record">
-      <RejectRecord />
-    </el-tab-pane>
-    <el-tab-pane label="打回统计" name="statistics">
-      <RejectStatistics />
-    </el-tab-pane>
-  </el-tabs>
-</template>
-
-<script setup lang="ts">
-  import { ref } from 'vue';
-  import RejectManage from './RejectManage.vue';
-  import RejectRecord from './RejectRecord.vue';
-  import RejectStatistics from './RejectStatistics.vue';
-
-  defineOptions({
-    name: 'RejectIndex',
-  });
-
-  const activeTab = ref('reject');
-</script>

+ 3 - 3
src/views/reject/RejectRecord.vue → src/views/reject/reject-stat/RejectRecord.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div class="part-box is-filter">
+  <div class="part-box is-border">
     <el-form inline>
     <el-form inline>
       <el-form-item label="科目">
       <el-form-item label="科目">
         <select-subject v-model="searchModel.subjectCode"></select-subject>
         <select-subject v-model="searchModel.subjectCode"></select-subject>
@@ -50,8 +50,8 @@
         <el-button @click="onExport">导出</el-button>
         <el-button @click="onExport">导出</el-button>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
-  </div>
-  <div class="part-box">
+    <el-divider class="form-divider" />
+
     <el-table
     <el-table
       class="page-table"
       class="page-table"
       :data="dataList"
       :data="dataList"

+ 3 - 3
src/views/reject/RejectStatistics.vue → src/views/reject/reject-stat/RejectStatistics.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div class="part-box is-filter">
+  <div class="part-box is-border">
     <el-form inline>
     <el-form inline>
       <el-form-item label="科目">
       <el-form-item label="科目">
         <select-subject v-model="searchModel.subjectCode"></select-subject>
         <select-subject v-model="searchModel.subjectCode"></select-subject>
@@ -14,8 +14,8 @@
         <el-button @click="onExport">导出</el-button>
         <el-button @click="onExport">导出</el-button>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
-  </div>
-  <div class="part-box">
+    <el-divider class="form-divider" />
+
     <el-table
     <el-table
       class="page-table"
       class="page-table"
       :data="dataList"
       :data="dataList"

+ 45 - 0
src/views/reject/reject-stat/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="stat-container">
+    <!-- 统计 -->
+    <RejectStatistics class="monitor-section" />
+    <!-- 记录 -->
+    <RejectRecord class="monitor-section" />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import RejectRecord from './RejectRecord.vue';
+  import RejectStatistics from './RejectStatistics.vue';
+
+  defineOptions({
+    name: 'RejectStat',
+  });
+</script>
+
+<style scoped>
+  .stat-container {
+    display: flex;
+    flex-direction: column;
+    height: calc(100vh - 136px);
+    gap: 16px;
+    overflow: hidden;
+    min-width: 800px;
+  }
+
+  .monitor-section {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    margin: 0;
+  }
+
+  .monitor-section :deep(.page-table) {
+    flex: 1;
+    overflow: auto;
+  }
+
+  .monitor-section :deep(.el-pagination) {
+    margin-top: 16px;
+    justify-content: center;
+  }
+</style>

+ 1 - 1
src/views/review/AllReview.vue

@@ -315,7 +315,7 @@
   <ImportDialog
   <ImportDialog
     ref="importDialogRef"
     ref="importDialogRef"
     title="导入数据"
     title="导入数据"
-    upload-url="/api/admin/user/class/import"
+    upload-url="/api/admin/exam/inspected/import"
     :format="['xls', 'xlsx']"
     :format="['xls', 'xlsx']"
     :download-handle="() => downloadExport('reviewImportTemplate')"
     :download-handle="() => downloadExport('reviewImportTemplate')"
     download-filename="导入模板.xlsx"
     download-filename="导入模板.xlsx"

+ 122 - 0
src/views/review/ScoreCheck.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="part-box is-border">
+    <div class="part-action">
+      <el-space wrap>
+        <el-button :loading="resetLoading" @click="onReset">重置</el-button>
+        <el-button @click="onReview">批量校验:{{ waitTaskCount }}</el-button>
+        <el-button @click="onExport('exportScoreErrorLog')">错误日志</el-button>
+        <el-button @click="onExport('exportScoreMarkList')"
+          >导出标记卷</el-button
+        >
+        <el-button @click="onExport('exportScoreCheckList')"
+          >导出全部</el-button
+        >
+      </el-space>
+    </div>
+    <el-divider class="form-divider" />
+    <el-table
+      class="page-table"
+      :data="dataList"
+      :loading="loading"
+      border
+      stripe
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column prop="studentCode" label="考生编号" width="150" />
+      <el-table-column prop="subjectName" label="科目" width="200" />
+      <el-table-column prop="fullScore" label="满分" width="100" />
+      <el-table-column label="状态" width="120">
+        <template #default="scope">
+          {{ scope.row.status }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="totalScore" label="试卷总分" width="100" />
+      <el-table-column
+        prop="subjectiveScoreList"
+        label="得分明细"
+        min-width="200"
+      >
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      v-model:current-page="pagination.pageNumber"
+      v-model:page-size="pagination.pageSize"
+      :layout="pagination.layout"
+      :total="pagination.total"
+      @size-change="pageSizeChange"
+      @current-change="toPage"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref, reactive, onMounted } from 'vue';
+  import { ElMessage } from 'element-plus';
+
+  import {
+    getScoreCheckList,
+    getScoreCheckCount,
+    resetScoreCheck,
+  } from '@/api/review';
+  import { ScoreCheckItem } from '@/api/types/review';
+  import useTable from '@/hooks/table';
+  import useLoading from '@/hooks/loading';
+  import { modalConfirm } from '@/utils/ui';
+  import { downloadExport } from '@/utils/download-export';
+
+  defineOptions({
+    name: 'ScoreCheck',
+  });
+
+  const searchModel = reactive({});
+
+  const { dataList, pagination, loading, toPage, pageSizeChange } =
+    useTable<ScoreCheckItem>(getScoreCheckList, searchModel, false);
+
+  // 待校验数量
+  const waitTaskCount = ref(0);
+  async function getWaitTaskCount() {
+    waitTaskCount.value = await getScoreCheckCount();
+  }
+
+  function onReview() {
+    if (waitTaskCount.value === 0) {
+      ElMessage.warning('当前没有待校验任务!');
+      return;
+    }
+    // TODO: 校验
+    console.log('11');
+  }
+
+  // 重置
+  const { loading: resetLoading, setLoading: setResetLoading } = useLoading();
+  async function onReset() {
+    if (resetLoading.value) return;
+
+    const confirm = await modalConfirm(`确定要重置所有任务吗?`, '提示').catch(
+      () => false
+    );
+    if (!confirm) return;
+
+    setResetLoading(true);
+    try {
+      await resetScoreCheck();
+      ElMessage.success('操作成功!');
+    } catch (error) {
+      console.error('操作失败:', error);
+    } finally {
+      setResetLoading(false);
+    }
+  }
+
+  // 导出
+  async function onExport(
+    type: 'exportScoreErrorLog' | 'exportScoreMarkList' | 'exportScoreCheckList'
+  ) {
+    await downloadExport(type);
+  }
+
+  onMounted(() => {
+    getWaitTaskCount();
+  });
+</script>

+ 0 - 83
src/views/review/ScoreQuery.vue

@@ -1,83 +0,0 @@
-<template>
-  <div class="part-box is-border">
-    <div class="part-action">
-      <el-space wrap>
-        <el-button>查重</el-button>
-        <el-button>批量校验:{{ dataList.length }}</el-button>
-        <el-button @click="onExport">导出</el-button>
-      </el-space>
-    </div>
-    <el-divider class="form-divider" />
-    <el-table
-      class="page-table"
-      :data="dataList"
-      :loading="loading"
-      border
-      stripe
-    >
-      <el-table-column type="selection" width="55" />
-      <el-table-column prop="studentCode" label="考生编号" width="150" />
-      <el-table-column prop="subjectName" label="科目" width="200" />
-      <el-table-column prop="fullScore" label="满分" width="100" />
-      <el-table-column label="状态" width="120">
-        <template #default="scope">
-          <el-tag :type="getStatusType(scope.row.status)">
-            {{ scope.row.status }}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column prop="totalScore" label="试卷总分" width="100" />
-      <el-table-column
-        prop="subjectiveScoreList"
-        label="得分明细"
-        min-width="200"
-      >
-      </el-table-column>
-    </el-table>
-    <el-pagination
-      v-model:current-page="pagination.pageNumber"
-      v-model:page-size="pagination.pageSize"
-      :layout="pagination.layout"
-      :total="pagination.total"
-      @size-change="pageSizeChange"
-      @current-change="toPage"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { reactive } from 'vue';
-  import { getScoreCheckList } from '@/api/review';
-  import { ScoreCheckItem } from '@/api/types/review';
-  import useTable from '@/hooks/table';
-  import { downloadExport } from '@/utils/download-export';
-
-  defineOptions({
-    name: 'ScoreQuery',
-  });
-
-  // 由于接口不需要参数,使用空对象
-  const searchModel = reactive({});
-
-  const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<ScoreCheckItem>(getScoreCheckList, searchModel, false);
-
-  // 获取状态标签类型
-  function getStatusType(status: string) {
-    switch (status) {
-      case '已上传':
-        return 'success';
-      case '正常':
-        return 'success';
-      case '未上传':
-        return 'warning';
-      default:
-        return 'info';
-    }
-  }
-
-  // 导出
-  async function onExport() {
-    await downloadExport('exportReviewStatList', searchModel);
-  }
-</script>

+ 3 - 10
src/views/subject/components/SetUnselectiveDialog.vue

@@ -18,9 +18,9 @@
       </div>
       </div>
 
 
       <div class="warning-text">
       <div class="warning-text">
-        <span style="color: #f56c6c">
+        <p>
           *启用一键未选做后,当前科目所有选做题给分板下均支持一键未选做的操作。
           *启用一键未选做后,当前科目所有选做题给分板下均支持一键未选做的操作。
-        </span>
+        </p>
       </div>
       </div>
     </div>
     </div>
 
 
@@ -120,13 +120,6 @@
   .warning-text {
   .warning-text {
     font-size: 14px;
     font-size: 14px;
     line-height: 1.5;
     line-height: 1.5;
-  }
-
-  :deep(.el-checkbox) {
-    font-size: 16px;
-  }
-
-  :deep(.el-checkbox__label) {
-    font-weight: 500;
+    color: var(--color-danger);
   }
   }
 </style>
 </style>