Forráskód Böngészése

feat: test-成绩查询

zhangjie 3 napja
szülő
commit
2d9cfffdcd

+ 16 - 3
src/api/score.ts

@@ -1,9 +1,22 @@
-import axios from 'axios';
-import { ScoreListPageParam, ScoreListPageRes } from './types/score';
+import axios, { AxiosResponse } from 'axios';
+import {
+  ScoreListPageParam,
+  ScoreListFilter,
+  ScoreListPageRes,
+} from './types/score';
 
 // 获取成绩列表
 export function getScoreList(
   params: ScoreListPageParam
 ): Promise<ScoreListPageRes> {
-  return axios.post('/api/score/list', params);
+  return axios.post('/api/admin/exam/score/list', params);
+}
+
+// 导出成绩
+export function exportScore(
+  params: ScoreListFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post('/api/admin/exam/score/export', params, {
+    responseType: 'blob',
+  });
 }

+ 4 - 0
src/api/types/score.ts

@@ -13,6 +13,8 @@ export interface ScoreItem {
   subjectCode: string;
   // 科目名称
   subjectName: string;
+  // 科目
+  subjectText: string;
   // 层次
   subjectLevel: string;
   // 专业类型
@@ -23,6 +25,8 @@ export interface ScoreItem {
   subjectiveScoreString: string;
   // 全卷总分
   totalScoreString: string;
+  // 评分明细
+  subjectiveScoreList: string;
   // 是否缺考
   absent: boolean;
   // 是否上传

+ 1 - 0
src/api/types/student.ts

@@ -57,6 +57,7 @@ export interface StudentItem {
   // 科目
   subjectName: string;
   subjectCode: string;
+  subjectText: string;
   // 试卷类型
   paperType: string;
   // 扫描图

+ 12 - 0
src/api/user.ts

@@ -147,6 +147,18 @@ export function headerInspectorTemplate(params: {
   });
 }
 
+// 导出列表表头获取
+export function getExportFields(type: 'STUDENT' | 'SCORE'): Promise<string[]> {
+  return axios.post('/api/admin/user/export/cols/info', { type });
+}
+// 导出列表表头保存
+export function saveExportFields(data: {
+  type: 'STUDENT' | 'SCORE';
+  cols: string[];
+}): Promise<boolean> {
+  return axios.post('/api/admin/user/export/cols/save', paramsSerializer(data));
+}
+
 // 角色权限 ------->
 // 获取角色列表
 export function getRoleList(

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

@@ -52,6 +52,7 @@ import {
   exportScoreCheckList,
   exportScoreMarkList,
 } from '@/api/review';
+import { exportScore } from '@/api/score';
 import { exportImageCheckData } from '@/api/check';
 
 import useLoading from '@/hooks/loading';
@@ -158,6 +159,9 @@ const downloadConfig = {
   exportScoreCheckList,
   // 导出成绩标记记录
   exportScoreMarkList,
+  // score
+  // 导出成绩
+  exportScore,
   // check
   // 导出图片检查数据
   exportImageCheckData,

+ 153 - 20
src/views/score/ScoreQuery.vue

@@ -133,6 +133,11 @@
         <el-space wrap>
           <el-button type="primary" @click="toPage(1)">查询</el-button>
           <el-button @click="onExport">导出</el-button>
+          <table-field
+            v-model="headFields"
+            :fields="tableFields"
+            @change="handleFieldChange"
+          ></table-field>
         </el-space>
       </el-form-item>
     </el-form>
@@ -146,56 +151,138 @@
       stripe
       @sort-change="handleSortChange"
     >
-      <el-table-column prop="examNumber" label="准考证号" width="120" />
-      <el-table-column prop="name" label="姓名" min-width="100" />
-      <el-table-column prop="studentCode" label="学号" width="120" sortable />
-      <el-table-column prop="subjectName" label="科目" min-width="200" />
-      <el-table-column prop="subjectLevel" label="层次" min-width="100" />
-      <el-table-column prop="subjectCategory" label="专业类型" width="100" />
       <el-table-column
+        v-if="checkFieldVisible('examNumber')"
+        prop="examNumber"
+        label="准考证号"
+        width="120"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('name')"
+        prop="name"
+        label="姓名"
+        min-width="100"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('studentCode')"
+        prop="studentCode"
+        label="学号"
+        width="120"
+        sortable
+      />
+      <el-table-column
+        v-if="checkFieldVisible('subjectText')"
+        prop="subjectText"
+        label="科目"
+        min-width="200"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('subjectLevel')"
+        prop="subjectLevel"
+        label="层次"
+        min-width="100"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('subjectCategory')"
+        prop="subjectCategory"
+        label="专业类型"
+        width="100"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('objectiveScore')"
         prop="objectiveScoreString"
         label="客观总分"
         width="110"
         sortable
       />
       <el-table-column
+        v-if="checkFieldVisible('subjectiveScore')"
         prop="subjectiveScoreString"
         label="主观总分"
         width="110"
         sortable
       />
       <el-table-column
+        v-if="checkFieldVisible('totalScore')"
         prop="totalScoreString"
         label="全卷总分"
         min-width="110"
         sortable
       />
-      <el-table-column label="是否缺考" width="110" sortable>
+      <el-table-column
+        v-if="checkFieldVisible('subjectiveScoreList')"
+        prop="subjectiveScoreList"
+        label="评分明细"
+        min-width="200"
+        sortable
+      />
+      <el-table-column
+        v-if="checkFieldVisible('absentText')"
+        label="是否缺考"
+        width="110"
+        sortable
+      >
         <template #default="scope">
           <el-tag :type="scope.row.absent ? 'danger' : 'success'">
             {{ scope.row.absent ? '是' : '否' }}
           </el-tag>
         </template>
       </el-table-column>
-      <el-table-column label="是否上传" width="100">
+      <el-table-column
+        v-if="checkFieldVisible('uploadText')"
+        label="是否上传"
+        width="100"
+      >
         <template #default="scope">
           <el-tag :type="scope.row.upload ? 'success' : 'warning'">
             {{ scope.row.upload ? '是' : '否' }}
           </el-tag>
         </template>
       </el-table-column>
-      <el-table-column label="是否违纪" width="100">
+      <el-table-column
+        v-if="checkFieldVisible('breach')"
+        label="是否违纪"
+        width="100"
+      >
         <template #default="scope">
           <el-tag :type="scope.row.breach ? 'danger' : 'success'">
             {{ scope.row.breach ? '是' : '否' }}
           </el-tag>
         </template>
       </el-table-column>
-      <el-table-column prop="college" label="学院" min-width="100" sortable />
-      <el-table-column prop="className" label="班级" min-width="100" />
-      <el-table-column prop="teacher" label="任课老师" min-width="100" />
-      <el-table-column prop="examSite" label="考点" min-width="100" sortable />
-      <el-table-column prop="examRoom" label="考场" min-width="100" />
+      <el-table-column
+        v-if="checkFieldVisible('college')"
+        prop="college"
+        label="学院"
+        min-width="100"
+        sortable
+      />
+      <el-table-column
+        v-if="checkFieldVisible('className')"
+        prop="className"
+        label="班级"
+        min-width="100"
+        sortable
+      />
+      <el-table-column
+        v-if="checkFieldVisible('teacher')"
+        prop="teacher"
+        label="任课老师"
+        min-width="100"
+      />
+      <el-table-column
+        v-if="checkFieldVisible('examSite')"
+        prop="examSite"
+        label="考点"
+        min-width="100"
+        sortable
+      />
+      <el-table-column
+        v-if="checkFieldVisible('examRoom')"
+        prop="examRoom"
+        label="考场"
+        min-width="100"
+      />
       <el-table-column label="操作" width="100" fixed="right">
         <template #default="scope">
           <el-button type="primary" link @click="viewDetail(scope.row)">
@@ -216,10 +303,12 @@
 </template>
 
 <script setup lang="ts">
-  import { reactive } from 'vue';
+  import { onMounted, reactive, ref } from 'vue';
   import { getScoreList } from '@/api/score';
+  import { getExportFields, saveExportFields } from '@/api/user';
   import { ScoreItem, ScoreListFilter } from '@/api/types/score';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'ScoreQuery',
@@ -243,16 +332,60 @@
     examRoom: '',
   });
 
-  const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<ScoreItem>(getScoreList, searchModel, false);
+  const {
+    dataList,
+    pagination,
+    loading,
+    toPage,
+    pageSizeChange,
+    handleSortChange,
+  } = useTable<ScoreItem>(getScoreList, searchModel, false);
 
-  function onExport() {
-    // TODO: 实现导出功能
-    console.log('导出成绩数据');
+  // 表头配置
+  const tableFields = [
+    { name: '准考证号', field: 'examNumber' },
+    { name: '姓名', field: 'name' },
+    { name: '学号', field: 'studentCode' },
+    { name: '科目', field: 'subjectText' },
+    { name: '层次', field: 'subjectLevel' },
+    { name: '专业类型', field: 'subjectCategory' },
+    { name: '客观总分', field: 'objectiveScore' },
+    { name: '主观总分', field: 'subjectiveScore' },
+    { name: '全卷总分', field: 'totalScore' },
+    { name: '评分明细', field: 'subjectiveScoreList' },
+    { name: '是否缺考', field: 'absentText' },
+    { name: '是否上传', field: 'uploadText' },
+    { name: '是否违纪', field: 'breach' },
+    { name: '学院', field: 'college' },
+    { name: '班级', field: 'className' },
+    { name: '任课老师', field: 'teacher' },
+    { name: '考点', field: 'examSite' },
+    { name: '考场', field: 'examRoom' },
+  ];
+  const defaultCols = tableFields.map((item) => item.field);
+  const headFields = ref(defaultCols);
+  const checkFieldVisible = (field: string) => {
+    return headFields.value.includes(field);
+  };
+  async function getExportCols() {
+    const cols = await getExportFields('SCORE');
+    headFields.value = cols && cols.length ? cols : defaultCols;
+  }
+  async function handleFieldChange() {
+    await saveExportFields({ type: 'SCORE', cols: headFields.value });
+  }
+
+  async function onExport() {
+    await downloadExport('exportScore', searchModel);
   }
 
   function viewDetail(row: ScoreItem) {
     // TODO: 实现查看详情功能
     console.log('查看成绩详情', row);
   }
+
+  onMounted(async () => {
+    await getExportCols();
+    await toPage(1);
+  });
 </script>

+ 30 - 12
src/views/student/StudentManage.vue

@@ -180,7 +180,11 @@
         <el-button @click="onExport">导出</el-button>
       </el-space>
 
-      <table-field v-model="headFields" :fields="tableFields"></table-field>
+      <table-field
+        v-model="headFields"
+        :fields="tableFields"
+        @change="handleFieldChange"
+      ></table-field>
     </div>
   </div>
   <div class="part-box">
@@ -222,8 +226,8 @@
         sortable
       />
       <el-table-column
-        v-if="checkFieldVisible('subjectCode')"
-        prop="subjectCode"
+        v-if="checkFieldVisible('subjectText')"
+        prop="subjectText"
         label="科目"
         min-width="120"
         sortable
@@ -247,7 +251,7 @@
         width="100"
       />
       <el-table-column
-        v-if="checkFieldVisible('upload')"
+        v-if="checkFieldVisible('scanStatus')"
         label="扫描识别"
         width="100"
       >
@@ -265,14 +269,14 @@
         </template>
       </el-table-column>
       <el-table-column
-        v-if="checkFieldVisible('sheetCount')"
+        v-if="checkFieldVisible('paperCount')"
         prop="sheetCount"
         label="扫描张数"
         width="120"
         sortable
       />
       <el-table-column
-        v-if="checkFieldVisible('manualAbsent')"
+        v-if="checkFieldVisible('breachText')"
         label="人工指定"
         width="100"
       >
@@ -406,9 +410,10 @@
 </template>
 
 <script setup lang="ts">
-  import { reactive, ref, computed } from 'vue';
+  import { reactive, ref, computed, onMounted } from 'vue';
   import { CaretBottom } from '@element-plus/icons-vue';
   import { ElMessage } from 'element-plus';
+  import { getExportFields, saveExportFields } from '@/api/user';
   import { getStudentList, deleteStudent, resetBreach } from '@/api/student';
   import { StudentItem, StudentListFilter } from '@/api/types/student';
   import useTable from '@/hooks/table';
@@ -464,13 +469,13 @@
     { name: '密号', field: 'secretNumber' },
     { name: '姓名', field: 'name' },
     { name: '学号', field: 'studentCode' },
-    { name: '科目', field: 'subjectCode' },
+    { name: '科目', field: 'subjectText' },
     { name: '试卷类型', field: 'paperType' },
     { name: '层次', field: 'subjectLevel' },
     { name: '专业类型', field: 'subjectCategory' },
-    { name: '扫描识别', field: 'upload' },
-    { name: '扫描张数', field: 'sheetCount' },
-    { name: '人工指定', field: 'manualAbsent' },
+    { name: '扫描识别', field: 'scanStatus' },
+    { name: '扫描张数', field: 'paperCount' },
+    { name: '人工指定', field: 'breachText' },
     { name: '批次编号', field: 'batchCode' },
     { name: '签到表编号', field: 'packageCode' },
     { name: '学院', field: 'college' },
@@ -479,10 +484,18 @@
     { name: '考点', field: 'examSite' },
     { name: '考场', field: 'examRoom' },
   ];
-  const headFields = ref(tableFields.map((item) => item.field));
+  const defaultCols = tableFields.map((item) => item.field);
+  const headFields = ref(defaultCols);
   const checkFieldVisible = (field: string) => {
     return headFields.value.includes(field);
   };
+  async function getExportCols() {
+    const cols = await getExportFields('SCORE');
+    headFields.value = cols && cols.length ? cols : defaultCols;
+  }
+  async function handleFieldChange() {
+    await saveExportFields({ type: 'SCORE', cols: headFields.value });
+  }
 
   // table action
   const curRow = ref({} as StudentItem);
@@ -609,4 +622,9 @@
   function onExport() {
     downloadExport('exportStudent', searchModel);
   }
+
+  onMounted(async () => {
+    await getExportCols();
+    await toPage(1);
+  });
 </script>