瀏覽代碼

feat: api-科目分析

zhangjie 1 周之前
父節點
當前提交
00477f7ab9

+ 87 - 15
src/api/analysis.ts

@@ -1,73 +1,145 @@
-import axios from 'axios';
+import axios, { AxiosResponse } from 'axios';
 
 import {
   ScoreSegmentListRes,
   TotalAnalysisListRes,
   CollegeAnalysisListParam,
+  CollegeAnalysisFilter,
   CollegeAnalysisListRes,
   TeacherAnalysisListParam,
+  TeacherAnalysisFilter,
   TeacherAnalysisListRes,
   ClassAnalysisListParam,
+  ClassAnalysisFilter,
   ClassAnalysisListRes,
   QuestionAnalysisListParam,
+  QuestionAnalysisFilter,
   QuestionAnalysisListRes,
   BigQuestionAnalysisListRes,
   ScoreSegmentListParam,
+  ScoreSegmentFilter,
   AnalysisListPageParam,
+  AnalysisListFilter,
 } from './types/analysis';
 
 // 总量分析列表
 export function getTotalAnalysisList(
   params: AnalysisListPageParam
 ): Promise<TotalAnalysisListRes> {
-  return axios.post('/api/analysis/total', {}, { params });
+  return axios.post('/api/admin/report/subject', {}, { params });
+}
+// 总量分析导出
+export function exportTotalAnalysisList(
+  params: AnalysisListFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/subject/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
 // 分段统计列表
 export function getSegmentAnalysisList(
   params: ScoreSegmentListParam
 ): Promise<ScoreSegmentListRes> {
-  return axios.post('/api/analysis/segment', {}, { params });
+  return axios.post('/api/admin/report/range', {}, { params });
+}
+
+// 分段统计导出
+export function exportSegmentAnalysisList(
+  params: ScoreSegmentFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/range/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
 // 学院分析列表
 export function getCollegeAnalysisList(
   params: CollegeAnalysisListParam
 ): Promise<CollegeAnalysisListRes> {
-  return axios.post('/api/analysis/college', {}, { params });
+  return axios.post('/api/admin/report/college', {}, { params });
+}
+// 学院分析导出
+export function exportCollegeAnalysisList(
+  params: CollegeAnalysisFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/college/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
 // 任课老师分析列表
 export function getTeacherAnalysisList(
   params: TeacherAnalysisListParam
 ): Promise<TeacherAnalysisListRes> {
-  return axios.post('/api/analysis/teacher', {}, { params });
+  return axios.post('/api/admin/report/teacher', {}, { params });
+}
+// 任课老师分析导出
+export function exportTeacherAnalysisList(
+  params: TeacherAnalysisFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/teacher/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
 // 班级分析列表
 export function getClassAnalysisList(
   params: ClassAnalysisListParam
 ): Promise<ClassAnalysisListRes> {
-  return axios.post('/api/analysis/class', {}, { params });
+  return axios.post('/api/admin/report/teacher/class', {}, { params });
+}
+// 班级分析导出
+export function exportClassAnalysisList(
+  params: ClassAnalysisFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/teacher/class/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
-// 客观题分析列表
-export function getObjectiveQuestionAnalysisList(
+// 客观题分析列表
+export function getQuestionAnalysisList(
   params: QuestionAnalysisListParam
 ): Promise<QuestionAnalysisListRes> {
-  return axios.post('/api/analysis/question', {}, { params });
+  return axios.post('/api/admin/report/question', {}, { params });
 }
 
-// 主观题分析列表
-export function getSubjectiveQuestionAnalysisList(
-  params: QuestionAnalysisListParam
-): Promise<QuestionAnalysisListRes> {
-  return axios.post('/api/analysis/question', {}, { params });
+// 主客观题分析导出
+export function exportQuestionAnalysisList(
+  params: QuestionAnalysisFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/question/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }
 
 // 大题分析列表
 export function getBigQuestionAnalysisList(
   params: AnalysisListPageParam
 ): Promise<BigQuestionAnalysisListRes> {
-  return axios.post('/api/analysis/big-question', {}, { params });
+  return axios.post('/api/admin/report/group', {}, { params });
+}
+
+// 大题分析导出
+export function exportBigQuestionAnalysisList(
+  params: AnalysisListFilter
+): Promise<AxiosResponse<Blob>> {
+  return axios.post(
+    '/api/admin/report/group/export',
+    {},
+    { params, responseType: 'blob' }
+  );
 }

+ 66 - 60
src/api/types/analysis.ts

@@ -2,34 +2,36 @@ import { PageResult, PageParams } from './common';
 
 export interface AnalysisListFilter {
   // 科目
-  subject: string | null;
+  subjectCode: string;
 }
 export type AnalysisListPageParam = PageParams<AnalysisListFilter>;
 
 // 总量分析项目
 export interface TotalAnalysisItem {
   // 科目名称
-  subject: string;
+  subjectName: string;
+  // 科目代码
+  subjectCode: string;
   // 报考人数
-  totalStudents: number;
+  totalCount: number;
   // 缺考人数
-  absentStudents: number;
+  absentCount: number;
   // 违纪人数
-  violationStudents: number;
+  breachCount: number;
   // 有效考试人数
-  validStudents: number;
+  realityCount: number;
   // 平均分
-  averageScore: number;
+  avgScore: number;
   // 最高分
-  highestScore: number;
+  maxScore: number;
   // 最低分
-  lowestScore: number;
+  minScore: number;
   // 及格人数
-  passStudents: number;
+  passCount: number;
   // 及格率
   passRate: number;
   // 优秀人数
-  excellentStudents: number;
+  excellentCount: number;
   // 优秀率
   excellentRate: number;
 }
@@ -38,42 +40,44 @@ export type TotalAnalysisListRes = PageResult<TotalAnalysisItem>;
 // 分段统计项目
 export interface ScoreSegmentItem {
   // 分数段
-  segment: string;
+  range: string;
   // 人数
-  students: number;
+  rangeCount: number;
   // 频率(%)
-  rate: number;
+  rangeRate: number;
 }
 export type ScoreSegmentListRes = PageResult<ScoreSegmentItem>;
 
 export interface ScoreSegmentFilter {
   // 科目
-  subject: string;
+  subjectCode: string;
   // 分数间隔类型
-  intervalType: string;
+  range: string;
+  // 客观题
+  objective: boolean;
 }
 export type ScoreSegmentListParam = PageParams<ScoreSegmentFilter>;
 
 // 学院分析
 export interface CollegeAnalysisItem {
   // 学生院系
-  college: string;
+  collegeName: string;
   // 报考人数
-  totalStudents: number;
+  totalCount: number;
   // 有效人数
-  validStudents: number;
+  realityCount: number;
   // 平均分
-  averageScore: number;
+  avgScore: number;
   // 最高分
-  highestScore: number;
+  maxScore: number;
   // 最低分
-  lowestScore: number;
+  minScore: number;
   // 及格人数
-  passStudents: number;
+  passCount: number;
   // 及格率
   passRate: number;
   // 优秀人数
-  excellentStudents: number;
+  excellentCount: number;
   // 优秀率
   excellentRate: number;
 }
@@ -81,44 +85,44 @@ export type CollegeAnalysisListRes = PageResult<CollegeAnalysisItem>;
 
 export interface CollegeAnalysisFilter {
   // 科目
-  subject: string;
+  subjectCode: string;
   // 学生院系
-  college: string;
+  collegeName: string;
 }
 export type CollegeAnalysisListParam = PageParams<CollegeAnalysisFilter>;
 
 // 任课老师分析
 export interface TeacherAnalysisItem {
   // 任课老师
-  teacher: string;
+  teacherName: string;
   // 报考人数
-  totalStudents: number;
+  totalCount: number;
   // 有效人数
-  validStudents: number;
+  realityCount: number;
   // 及格人数
-  passStudents: number;
+  passCount: number;
   // 优秀人数
-  excellentStudents: number;
+  excellentCount: number;
   // 最高分
-  highestScore: number;
+  maxScore: number;
   // 最低分
-  lowestScore: number;
+  minScore: number;
   // 及格率
   passRate: number;
   // 优秀率
   excellentRate: number;
   // 平均分
-  averageScore: number;
+  avgScore: number;
   // 平均相对分
-  averageRelativeScore: number;
+  relativeAvgScore: number;
 }
 export type TeacherAnalysisListRes = PageResult<TeacherAnalysisItem>;
 
 export interface TeacherAnalysisFilter {
   // 科目
-  subject: string;
+  subjectCode: string;
   // 任课老师
-  teacher: string;
+  teacherName: string;
 }
 export type TeacherAnalysisListParam = PageParams<TeacherAnalysisFilter>;
 
@@ -127,21 +131,21 @@ export interface ClassAnalysisItem {
   // 班级
   className: string;
   // 报考人数
-  totalStudents: number;
+  totalCount: number;
   // 有效人数
-  validStudents: number;
+  realityCount: number;
   // 平均分
-  averageScore: number;
+  avgScore: number;
   // 最高分
-  highestScore: number;
+  maxScore: number;
   // 最低分
-  lowestScore: number;
+  minScore: number;
   // 及格人数
-  passStudents: number;
+  passCount: number;
   // 及格率
   passRate: number;
   // 优秀人数
-  excellentStudents: number;
+  excellentCount: number;
   // 优秀率
   excellentRate: number;
 }
@@ -149,7 +153,7 @@ export type ClassAnalysisListRes = PageResult<ClassAnalysisItem>;
 
 export interface ClassAnalysisFilter {
   // 科目
-  subject: string;
+  subjectCode: string;
   // 班级
   className: string;
 }
@@ -160,15 +164,15 @@ export interface QuestionAnalysisItem {
   // 题目名称
   questionName: string;
   // 大题号
-  bigQuestionNo: number;
+  mainNumber: number;
   // 小题号
-  smallQuestionNo: number;
+  subNumber: number;
   // 单题分数
-  singleQuestionScore: number;
+  score: number;
   // 单题平均分
-  singleQuestionAverageScore: number;
+  avgScore: number;
   // 单题标准差
-  singleQuestionStandardDeviation: number;
+  stdev: number;
   // 得分率
   scoreRate: number;
   // 满分率
@@ -180,35 +184,37 @@ export type QuestionAnalysisListRes = PageResult<QuestionAnalysisItem>;
 
 export interface QuestionAnalysisFilter {
   // 科目
-  subject: string;
+  subjectCode: string;
   // 试卷类型
   paperType?: string;
+  // 是否客观题
+  objective: boolean;
 }
 export type QuestionAnalysisListParam = PageParams<QuestionAnalysisFilter>;
 
 // 大题分析项目
 export interface BigQuestionAnalysisItem {
   // 大题名称
-  bigQuestionName: string;
+  mainTitle: string;
   // 大题号
-  bigQuestionNo: number;
+  mainNumber: number;
   // 满分
   totalScore: number;
   // 最高分
-  highestScore: number;
+  maxScore: number;
   // 最低分
-  lowestScore: number;
+  minScore: number;
   // 平均分
-  averageScore: number;
+  avgScore: number;
   // 标准差
-  standardDeviation: number;
+  stdev: number;
   // 差异系数
-  differenceCoefficient: number;
+  coefficient: number;
   // 得分率
   scoreRate: number;
   // 零分人数
-  zeroScoreStudents: number;
+  zeroCount: number;
   // 满分人数
-  fullScoreStudents: number;
+  fullCount: number;
 }
 export type BigQuestionAnalysisListRes = PageResult<BigQuestionAnalysisItem>;

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

@@ -23,6 +23,15 @@ import {
 import { exportScanStatByPoint, exportScanStatByCourse } from '@/api/scan';
 import { exportRejectStat, exportRejectRecord } from '@/api/reject';
 import { exportIssuePaper } from '@/api/issue-paper';
+import {
+  exportTotalAnalysisList,
+  exportSegmentAnalysisList,
+  exportCollegeAnalysisList,
+  exportTeacherAnalysisList,
+  exportClassAnalysisList,
+  exportQuestionAnalysisList,
+  exportBigQuestionAnalysisList,
+} from '@/api/analysis';
 
 import useLoading from '@/hooks/loading';
 
@@ -76,6 +85,21 @@ const downloadConfig = {
   // issue paper
   // 导出问题卷
   exportIssuePaper,
+  // analysis
+  // 总量分析导出
+  exportTotalAnalysisList,
+  // 分段分析导出
+  exportSegmentAnalysisList,
+  // 学院分析导出
+  exportCollegeAnalysisList,
+  // 教师分析导出
+  exportTeacherAnalysisList,
+  // 班级分析导出
+  exportClassAnalysisList,
+  // 问题分析导出
+  exportQuestionAnalysisList,
+  // 大题分析导出
+  exportBigQuestionAnalysisList,
 };
 type DownloadType = keyof typeof downloadConfig;
 

+ 17 - 33
src/views/analysis/BigQuestionAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item>
         <el-space wrap>
@@ -21,32 +21,24 @@
       stripe
     >
       <el-table-column type="index" label="序号" width="60" />
-      <el-table-column
-        prop="bigQuestionName"
-        label="大题名称"
-        min-width="150"
-      />
-      <el-table-column prop="bigQuestionNo" label="大题号" min-width="80" />
+      <el-table-column prop="mainTitle" label="大题名称" min-width="150" />
+      <el-table-column prop="mainNumber" label="大题号" min-width="80" />
       <el-table-column prop="totalScore" label="满分" min-width="80" />
-      <el-table-column prop="highestScore" label="最高分" min-width="100" />
-      <el-table-column prop="lowestScore" label="最低分" min-width="100" />
-      <el-table-column prop="averageScore" label="平均分" min-width="100">
+      <el-table-column prop="maxScore" label="最高分" min-width="100" />
+      <el-table-column prop="minScore" label="最低分" min-width="100" />
+      <el-table-column prop="avgScore" label="平均分" min-width="100">
         <template #default="scope">
-          {{ scope.row.averageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column prop="standardDeviation" label="标准差" min-width="100">
+      <el-table-column prop="stdev" label="标准差" min-width="100">
         <template #default="scope">
-          {{ scope.row.standardDeviation?.toFixed(2) }}
+          {{ scope.row.stdev?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column
-        prop="differenceCoefficient"
-        label="差异系数"
-        min-width="100"
-      >
+      <el-table-column prop="coefficient" label="差异系数" min-width="100">
         <template #default="scope">
-          {{ scope.row.differenceCoefficient?.toFixed(2) }}
+          {{ scope.row.coefficient?.toFixed(2) }}
         </template>
       </el-table-column>
       <el-table-column label="得分率" min-width="100">
@@ -54,16 +46,8 @@
           {{ (scope.row.scoreRate * 100).toFixed(2) }}%
         </template>
       </el-table-column>
-      <el-table-column
-        prop="zeroScoreStudents"
-        label="零分人数"
-        min-width="100"
-      />
-      <el-table-column
-        prop="fullScoreStudents"
-        label="满分人数"
-        min-width="100"
-      />
+      <el-table-column prop="zeroCount" label="零分人数" min-width="100" />
+      <el-table-column prop="fullCount" label="满分人数" min-width="100" />
     </el-table>
     <el-pagination
       v-model:current-page="pagination.pageNumber"
@@ -84,13 +68,14 @@
     AnalysisListFilter,
   } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'BigQuestionAnalysis',
   });
 
   const searchModel = reactive<AnalysisListFilter>({
-    subject: null,
+    subjectCode: null,
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
@@ -100,8 +85,7 @@
       false
     );
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出大题分析数据');
+  async function exportData() {
+    await downloadExport('exportBigQuestionAnalysisList', searchModel);
   }
 </script>

+ 13 - 17
src/views/analysis/ClassAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="班级">
         <el-input
@@ -30,26 +30,22 @@
     >
       <el-table-column type="index" label="序号" width="60" />
       <el-table-column prop="className" label="班级" min-width="150" />
-      <el-table-column prop="totalStudents" label="报考人数" min-width="100" />
-      <el-table-column prop="validStudents" label="有效人数" min-width="100" />
-      <el-table-column prop="averageScore" label="平均分" min-width="100">
+      <el-table-column prop="totalCount" label="报考人数" min-width="100" />
+      <el-table-column prop="realityCount" label="有效人数" min-width="100" />
+      <el-table-column prop="avgScore" label="平均分" min-width="100">
         <template #default="scope">
-          {{ scope.row.averageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column prop="highestScore" label="最高分" min-width="100" />
-      <el-table-column prop="lowestScore" label="最低分" min-width="100" />
-      <el-table-column prop="passStudents" label="及格人数" min-width="100" />
+      <el-table-column prop="maxScore" label="最高分" min-width="100" />
+      <el-table-column prop="minScore" label="最低分" min-width="100" />
+      <el-table-column prop="passCount" label="及格人数" min-width="100" />
       <el-table-column label="及格率" min-width="100">
         <template #default="scope">
           {{ (scope.row.passRate * 100).toFixed(2) }}%
         </template>
       </el-table-column>
-      <el-table-column
-        prop="excellentStudents"
-        label="优秀人数"
-        min-width="100"
-      />
+      <el-table-column prop="excellentCount" label="优秀人数" min-width="100" />
       <el-table-column label="优秀率" min-width="100">
         <template #default="scope">
           {{ (scope.row.excellentRate * 100).toFixed(2) }}%
@@ -72,21 +68,21 @@
   import { getClassAnalysisList } from '@/api/analysis';
   import { ClassAnalysisItem, ClassAnalysisFilter } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'ClassAnalysis',
   });
 
   const searchModel = reactive<ClassAnalysisFilter>({
-    subject: null,
+    subjectCode: null,
     className: '',
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
     useTable<ClassAnalysisItem>(getClassAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出班级分析数据');
+  async function exportData() {
+    await downloadExport('exportClassAnalysisList', searchModel);
   }
 </script>

+ 16 - 20
src/views/analysis/CollegeAnalysis.vue

@@ -2,11 +2,11 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="学生院系">
         <el-input
-          v-model="searchModel.college"
+          v-model="searchModel.collegeName"
           placeholder="请输入学院名称"
           clearable
           style="width: 200px"
@@ -29,27 +29,23 @@
       stripe
     >
       <el-table-column type="index" label="序号" width="60" />
-      <el-table-column prop="college" label="学生院系" min-width="150" />
-      <el-table-column prop="totalStudents" label="报考人数" min-width="100" />
-      <el-table-column prop="validStudents" label="有效人数" min-width="100" />
-      <el-table-column prop="averageScore" label="平均分" min-width="100">
+      <el-table-column prop="collegeName" label="学生院系" min-width="150" />
+      <el-table-column prop="totalCount" label="报考人数" min-width="100" />
+      <el-table-column prop="realityCount" label="有效人数" min-width="100" />
+      <el-table-column prop="avgScore" label="平均分" min-width="100">
         <template #default="scope">
-          {{ scope.row.averageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column prop="highestScore" label="最高分" min-width="100" />
-      <el-table-column prop="lowestScore" label="最低分" min-width="100" />
-      <el-table-column prop="passStudents" label="及格人数" min-width="100" />
+      <el-table-column prop="maxScore" label="最高分" min-width="100" />
+      <el-table-column prop="minScore" label="最低分" min-width="100" />
+      <el-table-column prop="passCount" label="及格人数" min-width="100" />
       <el-table-column label="及格率" min-width="100">
         <template #default="scope">
           {{ (scope.row.passRate * 100).toFixed(2) }}%
         </template>
       </el-table-column>
-      <el-table-column
-        prop="excellentStudents"
-        label="优秀人数"
-        min-width="100"
-      />
+      <el-table-column prop="excellentCount" label="优秀人数" min-width="100" />
       <el-table-column label="优秀率" min-width="100">
         <template #default="scope">
           {{ (scope.row.excellentRate * 100).toFixed(2) }}%
@@ -75,21 +71,21 @@
     CollegeAnalysisFilter,
   } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'CollegeAnalysis',
   });
 
   const searchModel = reactive<CollegeAnalysisFilter>({
-    subject: null,
-    college: '',
+    subjectCode: null,
+    collegeName: '',
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
     useTable<CollegeAnalysisItem>(getCollegeAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出学院分析数据');
+  async function exportData() {
+    await downloadExport('exportCollegeAnalysisList', searchModel);
   }
 </script>

+ 15 - 30
src/views/analysis/ObjectiveQuestionAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="试卷类型">
         <el-select
@@ -34,29 +34,17 @@
     >
       <el-table-column type="index" label="序号" width="60" />
       <el-table-column prop="questionName" label="题目名称" min-width="150" />
-      <el-table-column prop="bigQuestionNo" label="大题号" min-width="80" />
-      <el-table-column prop="smallQuestionNo" label="小题号" min-width="80" />
-      <el-table-column
-        prop="singleQuestionScore"
-        label="单题分数"
-        min-width="100"
-      />
-      <el-table-column
-        prop="singleQuestionAverageScore"
-        label="单题平均分"
-        min-width="120"
-      >
+      <el-table-column prop="mainNumber" label="大题号" min-width="80" />
+      <el-table-column prop="subNumber" label="小题号" min-width="80" />
+      <el-table-column prop="score" label="单题分数" min-width="100" />
+      <el-table-column prop="avgScore" label="单题平均分" min-width="120">
         <template #default="scope">
-          {{ scope.row.singleQuestionAverageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column
-        prop="singleQuestionStandardDeviation"
-        label="单题标准差"
-        min-width="120"
-      >
+      <el-table-column prop="stdev" label="单题标准差" min-width="120">
         <template #default="scope">
-          {{ scope.row.singleQuestionStandardDeviation?.toFixed(2) }}
+          {{ scope.row.stdev?.toFixed(2) }}
         </template>
       </el-table-column>
       <el-table-column label="得分率" min-width="100">
@@ -84,31 +72,28 @@
 
 <script setup lang="ts">
   import { reactive } from 'vue';
-  import { getObjectiveQuestionAnalysisList } from '@/api/analysis';
+  import { getQuestionAnalysisList } from '@/api/analysis';
   import {
     QuestionAnalysisItem,
     QuestionAnalysisFilter,
   } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'ObjectiveQuestionAnalysis',
   });
 
   const searchModel = reactive<QuestionAnalysisFilter>({
-    subject: null,
+    subjectCode: null,
+    objective: true,
     paperType: '',
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<QuestionAnalysisItem>(
-      getObjectiveQuestionAnalysisList,
-      searchModel,
-      false
-    );
+    useTable<QuestionAnalysisItem>(getQuestionAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出客观题分析数据');
+  async function exportData() {
+    await downloadExport('exportQuestionAnalysisList', searchModel);
   }
 </script>

+ 20 - 12
src/views/analysis/SegmentAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="分数间隔类型">
         <el-select
@@ -13,9 +13,14 @@
         >
           <el-option label="5分间隔" value="5" />
           <el-option label="10分间隔" value="10" />
-          <el-option label="20分间隔" value="20" />
         </el-select>
       </el-form-item>
+      <el-form-item>
+        <el-checkbox
+          v-model="searchModel.objective"
+          label="仅统计客观题"
+        ></el-checkbox>
+      </el-form-item>
       <el-form-item>
         <el-space wrap>
           <el-button type="primary" @click="toPage(1)">查询</el-button>
@@ -33,16 +38,18 @@
       stripe
     >
       <el-table-column type="index" label="序号" width="60" />
-      <el-table-column prop="segment" label="分数段" min-width="120" />
-      <el-table-column prop="students" label="人数" min-width="100" />
+      <el-table-column prop="range" label="分数段" min-width="120" />
+      <el-table-column prop="rangeCount" label="人数" min-width="100" />
       <el-table-column label="频率" min-width="100">
-        <template #default="scope"> {{ scope.row.rate.toFixed(2) }}% </template>
+        <template #default="scope">
+          {{ scope.row.rangeRate.toFixed(2) }}%
+        </template>
       </el-table-column>
       <el-table-column label="分布图" min-width="200">
         <template #default="scope">
           <el-progress
-            :percentage="scope.row.rate"
-            :color="getSegmentColor(scope.row.rate)"
+            :percentage="scope.row.rangeRate"
+            :color="getSegmentColor(scope.row.rangeRate)"
             :show-text="false"
           />
         </template>
@@ -64,14 +71,16 @@
   import { getSegmentAnalysisList } from '@/api/analysis';
   import { ScoreSegmentItem, ScoreSegmentFilter } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'SegmentAnalysis',
   });
 
   const searchModel = reactive<ScoreSegmentFilter>({
-    subject: null,
-    intervalType: '10',
+    subjectCode: null,
+    range: '10',
+    objective: false,
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
@@ -84,8 +93,7 @@
     return '#67c23a';
   }
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出分段统计数据');
+  async function exportData() {
+    await downloadExport('exportSegmentAnalysisList', searchModel);
   }
 </script>

+ 15 - 30
src/views/analysis/SubjectiveQuestionAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item>
         <el-space wrap>
@@ -22,29 +22,17 @@
     >
       <el-table-column type="index" label="序号" width="60" />
       <el-table-column prop="questionName" label="题目名称" min-width="150" />
-      <el-table-column prop="bigQuestionNo" label="大题号" min-width="80" />
-      <el-table-column prop="smallQuestionNo" label="小题号" min-width="80" />
-      <el-table-column
-        prop="singleQuestionScore"
-        label="单题分数"
-        min-width="100"
-      />
-      <el-table-column
-        prop="singleQuestionAverageScore"
-        label="单题平均分"
-        min-width="120"
-      >
+      <el-table-column prop="mainNumber" label="大题号" min-width="80" />
+      <el-table-column prop="subNumber" label="小题号" min-width="80" />
+      <el-table-column prop="score" label="单题分数" min-width="100" />
+      <el-table-column prop="avgScore" label="单题平均分" min-width="120">
         <template #default="scope">
-          {{ scope.row.singleQuestionAverageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column
-        prop="singleQuestionStandardDeviation"
-        label="单题标准差"
-        min-width="120"
-      >
+      <el-table-column prop="stdev" label="单题标准差" min-width="120">
         <template #default="scope">
-          {{ scope.row.singleQuestionStandardDeviation?.toFixed(2) }}
+          {{ scope.row.stdev?.toFixed(2) }}
         </template>
       </el-table-column>
       <el-table-column label="得分率" min-width="100">
@@ -72,30 +60,27 @@
 
 <script setup lang="ts">
   import { reactive } from 'vue';
-  import { getSubjectiveQuestionAnalysisList } from '@/api/analysis';
+  import { getQuestionAnalysisList } from '@/api/analysis';
   import {
     QuestionAnalysisItem,
     QuestionAnalysisFilter,
   } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'SubjectiveQuestionAnalysis',
   });
 
   const searchModel = reactive<QuestionAnalysisFilter>({
-    subject: null,
+    subjectCode: null,
+    objective: false,
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
-    useTable<QuestionAnalysisItem>(
-      getSubjectiveQuestionAnalysisList,
-      searchModel,
-      false
-    );
+    useTable<QuestionAnalysisItem>(getQuestionAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出主观题分析数据');
+  async function exportData() {
+    await downloadExport('exportQuestionAnalysisList', searchModel);
   }
 </script>

+ 18 - 22
src/views/analysis/TeacherAnalysis.vue

@@ -2,11 +2,11 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item label="任课老师">
         <el-input
-          v-model="searchModel.teacher"
+          v-model="searchModel.teacherName"
           placeholder="请输入老师姓名"
           clearable
           style="width: 200px"
@@ -29,17 +29,13 @@
       stripe
     >
       <el-table-column type="index" label="序号" width="60" />
-      <el-table-column prop="teacher" label="任课老师" min-width="120" />
-      <el-table-column prop="totalStudents" label="报考人数" min-width="100" />
-      <el-table-column prop="validStudents" label="有效人数" min-width="100" />
-      <el-table-column prop="passStudents" label="及格人数" min-width="100" />
-      <el-table-column
-        prop="excellentStudents"
-        label="优秀人数"
-        min-width="100"
-      />
-      <el-table-column prop="highestScore" label="最高分" min-width="100" />
-      <el-table-column prop="lowestScore" label="最低分" min-width="100" />
+      <el-table-column prop="teacherName" label="任课老师" min-width="120" />
+      <el-table-column prop="totalCount" label="报考人数" min-width="100" />
+      <el-table-column prop="realityCount" label="有效人数" min-width="100" />
+      <el-table-column prop="passCount" label="及格人数" min-width="100" />
+      <el-table-column prop="excellentCount" label="优秀人数" min-width="100" />
+      <el-table-column prop="maxScore" label="最高分" min-width="100" />
+      <el-table-column prop="minScore" label="最低分" min-width="100" />
       <el-table-column label="及格率" min-width="100">
         <template #default="scope">
           {{ (scope.row.passRate * 100).toFixed(2) }}%
@@ -50,18 +46,18 @@
           {{ (scope.row.excellentRate * 100).toFixed(2) }}%
         </template>
       </el-table-column>
-      <el-table-column prop="averageScore" label="平均分" min-width="100">
+      <el-table-column prop="avgScore" label="平均分" min-width="100">
         <template #default="scope">
-          {{ scope.row.averageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
       <el-table-column
-        prop="averageRelativeScore"
+        prop="relativeAvgScore"
         label="平均相对分"
         min-width="120"
       >
         <template #default="scope">
-          {{ scope.row.averageRelativeScore?.toFixed(2) }}
+          {{ scope.row.relativeAvgScore?.toFixed(2) }}
         </template>
       </el-table-column>
     </el-table>
@@ -84,21 +80,21 @@
     TeacherAnalysisFilter,
   } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'TeacherAnalysis',
   });
 
   const searchModel = reactive<TeacherAnalysisFilter>({
-    subject: null,
-    teacher: '',
+    subjectCode: null,
+    teacherName: '',
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
     useTable<TeacherAnalysisItem>(getTeacherAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出任课老师分析数据');
+  async function exportData() {
+    await downloadExport('exportTeacherAnalysisList', searchModel);
   }
 </script>

+ 16 - 24
src/views/analysis/TotalAnalysis.vue

@@ -2,7 +2,7 @@
   <div class="part-box is-border">
     <el-form inline>
       <el-form-item label="科目">
-        <select-subject v-model="searchModel.subject"></select-subject>
+        <select-subject v-model="searchModel.subjectCode"></select-subject>
       </el-form-item>
       <el-form-item>
         <el-space wrap>
@@ -21,37 +21,29 @@
       stripe
     >
       <el-table-column type="index" label="序号" width="60" />
-      <el-table-column prop="subject" label="科目名称" min-width="120" />
-      <el-table-column prop="totalStudents" label="报考人数" min-width="100" />
-      <el-table-column prop="absentStudents" label="缺考人数" min-width="100" />
+      <el-table-column prop="subjectName" label="科目名称" min-width="120" />
+      <el-table-column prop="totalCount" label="报考人数" min-width="100" />
+      <el-table-column prop="absentCount" label="缺考人数" min-width="100" />
+      <el-table-column prop="breachCount" label="违纪人数" min-width="100" />
       <el-table-column
-        prop="violationStudents"
-        label="违纪人数"
-        min-width="100"
-      />
-      <el-table-column
-        prop="validStudents"
+        prop="realityCount"
         label="有效考试人数"
         min-width="120"
       />
-      <el-table-column prop="averageScore" label="平均分" min-width="100">
+      <el-table-column prop="avgScore" label="平均分" min-width="100">
         <template #default="scope">
-          {{ scope.row.averageScore?.toFixed(2) }}
+          {{ scope.row.avgScore?.toFixed(2) }}
         </template>
       </el-table-column>
-      <el-table-column prop="highestScore" label="最高分" min-width="100" />
-      <el-table-column prop="lowestScore" label="最低分" min-width="100" />
-      <el-table-column prop="passStudents" label="及格人数" min-width="100" />
+      <el-table-column prop="maxScore" label="最高分" min-width="100" />
+      <el-table-column prop="minScore" label="最低分" min-width="100" />
+      <el-table-column prop="passCount" label="及格人数" min-width="100" />
       <el-table-column label="及格率" min-width="100">
         <template #default="scope">
           {{ (scope.row.passRate * 100).toFixed(2) }}%
         </template>
       </el-table-column>
-      <el-table-column
-        prop="excellentStudents"
-        label="优秀人数"
-        min-width="100"
-      />
+      <el-table-column prop="excellentCount" label="优秀人数" min-width="100" />
       <el-table-column label="优秀率" min-width="100">
         <template #default="scope">
           {{ (scope.row.excellentRate * 100).toFixed(2) }}%
@@ -74,20 +66,20 @@
   import { getTotalAnalysisList } from '@/api/analysis';
   import { TotalAnalysisItem, AnalysisListFilter } from '@/api/types/analysis';
   import useTable from '@/hooks/table';
+  import { downloadExport } from '@/utils/download-export';
 
   defineOptions({
     name: 'TotalAnalysis',
   });
 
   const searchModel = reactive<AnalysisListFilter>({
-    subject: null,
+    subjectCode: null,
   });
 
   const { dataList, pagination, loading, toPage, pageSizeChange } =
     useTable<TotalAnalysisItem>(getTotalAnalysisList, searchModel, false);
 
-  function exportData() {
-    // TODO: 实现导出功能
-    console.log('导出总量分析数据');
+  async function exportData() {
+    await downloadExport('exportTotalAnalysisList', searchModel);
   }
 </script>