فهرست منبع

feat: 问题卷管理

zhangjie 1 هفته پیش
والد
کامیت
e04aebf3fd

+ 1 - 0
auto-imports.d.ts

@@ -7,4 +7,5 @@
 export {}
 declare global {
   const ElMessage: typeof import('element-plus/es')['ElMessage'];
+  const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'];
 }

+ 17 - 0
src/api/issue-paper.ts

@@ -0,0 +1,17 @@
+import axios from 'axios';
+import {
+  IssuePaperListPageRes,
+  IssuePaperListPageParam,
+} from './types/issue-paper';
+
+// 获取问题卷列表
+export function getIssuePaperList(
+  params: IssuePaperListPageParam
+): Promise<IssuePaperListPageRes> {
+  return axios.post('/api/score/list', { params });
+}
+
+// 重置问题卷
+export function resetIssuePaper(ids: number[]): Promise<any> {
+  return axios.post('/api/score/reset', { ids });
+}

+ 4 - 2
src/api/score.ts

@@ -2,6 +2,8 @@ import axios from 'axios';
 import { ScoreListPageParam, ScoreListPageRes } from './types/score';
 
 // 获取成绩列表
-export function getScoreList(params: ScoreListPageParam) {
-  return axios.post<ScoreListPageRes>('/api/score/list', { params });
+export function getScoreList(
+  params: ScoreListPageParam
+): Promise<ScoreListPageRes> {
+  return axios.post('/api/score/list', { params });
 }

+ 45 - 0
src/api/types/issue-paper.ts

@@ -0,0 +1,45 @@
+import { PageResult, PageParams } from './common';
+
+// 问题卷
+export interface IssuePaperItem {
+  id: number;
+  // 科目
+  subject: string;
+  // 分组序号
+  groupNo: number;
+  // 状态
+  status: string;
+  // 准考证号
+  examNo: string;
+  // 密号
+  secretNo: string;
+  // 姓名
+  name: string;
+  // 评卷员
+  reviewer: string;
+  // 提交时间
+  submitTime: string;
+  // 问题类型
+  issueType: string;
+  // 处理人
+  handler: string;
+  // 处理时间
+  handleTime: string;
+}
+export type IssuePaperListPageRes = PageResult<IssuePaperItem>;
+
+//
+export interface IssuePaperListFilter {
+  // 科目
+  subject: string;
+  // 分组序号
+  groupNo: number | undefined;
+  // 问题类型
+  issueType: string;
+  // 状态
+  status: string;
+  // 密号
+  secretNo: string;
+}
+
+export type IssuePaperListPageParam = PageParams<IssuePaperListFilter>;

+ 9 - 0
src/router/routes/modules/base.ts

@@ -36,6 +36,15 @@ const BASE: AppRouteRecordRaw = {
         requiresAuth: true,
       },
     },
+    {
+      path: '/issue-paper',
+      name: 'IssuePaper',
+      component: () => import('@/views/issue-paper/IssuePaper.vue'),
+      meta: {
+        title: '问题试卷',
+        requiresAuth: true,
+      },
+    },
     {
       path: '/score-query',
       name: 'ScoreQuery',

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

@@ -141,7 +141,7 @@ export const adminMenus = [
   {
     id: 13,
     name: '问题卷管理',
-    url: 'IssuePaperManage',
+    url: 'IssuePaper',
     type: 'MENU',
     parentId: -1,
     sequence: 2,

+ 218 - 0
src/views/issue-paper/IssuePaper.vue

@@ -0,0 +1,218 @@
+<template>
+  <div class="part-box is-filter">
+    <el-form inline>
+      <el-form-item label="科目">
+        <select-subject v-model="searchModel.subject"></select-subject>
+      </el-form-item>
+      <el-form-item label="分组">
+        <el-select
+          v-model="searchModel.groupNo"
+          placeholder="请选择"
+          clearable
+          style="width: 120px"
+        >
+          <el-option label="请选择" value="" />
+          <!-- TODO: 添加分组选项 -->
+        </el-select>
+      </el-form-item>
+      <el-form-item label="问题">
+        <el-select
+          v-model="searchModel.issueType"
+          placeholder="请选择"
+          clearable
+          style="width: 120px"
+        >
+          <el-option label="请选择" value="" />
+          <!-- TODO: 添加问题类型选项 -->
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态">
+        <el-select
+          v-model="searchModel.status"
+          placeholder="请选择"
+          clearable
+          style="width: 120px"
+        >
+          <el-option label="请选择" value="" />
+          <!-- TODO: 添加状态选项 -->
+        </el-select>
+      </el-form-item>
+      <el-form-item label="密号">
+        <el-input
+          v-model="searchModel.secretNo"
+          placeholder="请输入密号"
+          clearable
+          style="width: 120px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-space wrap>
+          <el-button type="primary" @click="toPage(1)">查询</el-button>
+          <el-button :disabled="selectedRows.length === 0" @click="batchReset">
+            批量重置
+          </el-button>
+          <el-button @click="exportData">导出</el-button>
+        </el-space>
+      </el-form-item>
+    </el-form>
+  </div>
+  <div class="part-box">
+    <el-table
+      ref="tableRef"
+      class="page-table"
+      :data="dataList"
+      :loading="loading"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" />
+      <el-table-column property="subject" label="科目" min-width="120" />
+      <el-table-column property="groupNo" label="分组序号" min-width="100" />
+      <el-table-column property="status" label="状态" min-width="100">
+        <template #default="scope">
+          <el-tag :type="getStatusType(scope.row.status)">
+            {{ scope.row.status }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column property="examNo" label="准考证号" min-width="120" />
+      <el-table-column property="secretNo" label="密号" min-width="100" />
+      <el-table-column property="name" label="姓名" min-width="100" />
+      <el-table-column property="reviewer" label="评卷员" min-width="100" />
+      <el-table-column property="submitTime" label="提交时间" min-width="150" />
+      <el-table-column property="issueType" label="问题类型" min-width="120" />
+      <el-table-column property="handler" label="处理人" min-width="100" />
+      <el-table-column property="handleTime" label="处理时间" min-width="150" />
+      <el-table-column label="操作" width="120" fixed="right">
+        <template #default="scope">
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="resetSingle(scope.row)"
+          >
+            重置
+          </el-button>
+          <el-button
+            type="primary"
+            link
+            size="small"
+            @click="viewDetail(scope.row)"
+          >
+            查看
+          </el-button>
+        </template>
+      </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, ref } from 'vue';
+  import { ElTable, ElMessage } from 'element-plus';
+  import { getIssuePaperList, resetIssuePaper } from '@/api/issue-paper';
+  import {
+    IssuePaperItem,
+    IssuePaperListFilter,
+  } from '@/api/types/issue-paper';
+  import useTable from '@/hooks/table';
+  import { modalConfirm } from '@/utils/ui';
+
+  defineOptions({
+    name: 'IssuePaperQuery',
+  });
+
+  const tableRef = ref<InstanceType<typeof ElTable>>();
+  const selectedRows = ref<IssuePaperItem[]>([]);
+
+  const searchModel = reactive<IssuePaperListFilter>({
+    subject: '',
+    groupNo: undefined,
+    issueType: '',
+    status: '',
+    secretNo: '',
+  });
+
+  const { dataList, pagination, loading, toPage, pageSizeChange } =
+    useTable<IssuePaperItem>(getIssuePaperList, searchModel, false);
+
+  function handleSelectionChange(selection: IssuePaperItem[]) {
+    selectedRows.value = selection;
+  }
+
+  function getStatusType(status: string) {
+    switch (status) {
+      case '已处理':
+        return 'success';
+      case '处理中':
+        return 'warning';
+      case '待处理':
+        return 'danger';
+      default:
+        return 'info';
+    }
+  }
+
+  async function batchReset() {
+    if (selectedRows.value.length === 0) {
+      ElMessage.warning('请选择要重置的数据');
+      return;
+    }
+
+    const confirm = await modalConfirm(
+      `确定要重置选中的 ${selectedRows.value.length} 条数据吗?`,
+      '批量重置确认'
+    ).catch(() => false);
+    if (!confirm) return;
+
+    try {
+      // 调用批量重置接口
+      const ids = selectedRows.value.map((row) => row.id);
+      await resetIssuePaper(ids);
+      ElMessage.success('批量重置成功');
+
+      // 清空选择
+      tableRef.value?.clearSelection();
+      // 刷新数据
+      toPage(pagination.pageNumber);
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+  async function resetSingle(row: IssuePaperItem) {
+    const confirm = await modalConfirm(
+      `确定要重置「${row.name}」的问题卷吗?`,
+      '重置确认'
+    ).catch(() => false);
+    if (!confirm) return;
+
+    try {
+      // 调用单个重置接口
+      await resetIssuePaper([row.id]);
+      ElMessage.success('重置成功');
+
+      // 刷新数据
+      toPage(pagination.pageNumber);
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+  function exportData() {
+    // TODO: 实现导出功能
+    console.log('导出问题卷数据');
+  }
+
+  function viewDetail(row: IssuePaperItem) {
+    // TODO: 实现查看详情功能
+    console.log('查看问题卷详情', row);
+  }
+</script>