Răsfoiți Sursa

成绩查询菜单显示、班级对比添加设置表头

liurongli 1 lună în urmă
părinte
comite
0659dd8782

+ 7 - 0
src/api/analysis.ts

@@ -26,6 +26,13 @@ export const getIdByAiExamId = (data: any): Promise<ApiResponse> => {
     params: data,
   });
 };
+//是否显示分组分析菜单
+export const queryQuestionGroupByAiId = (data: any): Promise<ApiResponse> => {
+  return request({
+    url: "/api/v1/ai_analysis/queryQuestionGroupByAiId?aiExamId=" + data,
+    method: "get",
+  });
+};
 // ==========================================成绩单============================================
 //获取单科成绩单下的表头数据
 export const studentTranscriptTitle = (data: any): Promise<ApiResponse> => {

+ 1 - 1
src/components/echarts/barLineCharts.vue

@@ -471,7 +471,7 @@ defineExpose({
   align-items: center;
   gap: 10px;
   position: absolute;
-  top: -6px;
+  top: -5px;
   right: 0;
   z-index: 99;
   .right_item {

+ 1 - 1
src/components/echarts/barsCharts.vue

@@ -739,7 +739,7 @@ onBeforeUnmount(() => {
   align-items: center;
   gap: 10px;
   position: absolute;
-  top: -6px;
+  top: 0px;
   right: 0;
   z-index: 99;
   .right_item {

+ 1 - 0
src/components/echarts/radarCharts.vue

@@ -185,6 +185,7 @@ const initChart = () => {
       show: props.showLegend,
       data: legendData,
       width: props.legendWidth,
+      top:0,
       left: props.legendLeft,
       itemGap: 20,
       itemHeight: 10,

+ 12 - 0
src/store/analysis.ts

@@ -61,6 +61,14 @@ export const useAnalysisStore = defineStore("analysis", () => {
     // 同步存储到 localStorage,确保持久化
     localStorage.setItem("childMenuPath", info);
   }
+  // 是否显示分组分析菜单
+  const isShowGroupAnalysis = ref<boolean>(localStorage.getItem("isShowGroupAnalysis") === "true");////是否显示分组分析菜单
+  // 设置是否显示分组分析菜单
+  const setIsShowGroupAnalysis = (info: boolean) => {
+    isShowGroupAnalysis.value = info;
+    // 同步存储到 localStorage,确保持久化
+    localStorage.setItem("isShowGroupAnalysis", info.toString());
+  }
   // 清除 localStorage 数据并重置 store 状态
   const removeLocalStorage = () => {
     // 1. 清除 localStorage 数据
@@ -68,22 +76,26 @@ export const useAnalysisStore = defineStore("analysis", () => {
     localStorage.removeItem("analysisExamInfo");
     localStorage.removeItem("filtersData");
     localStorage.removeItem("childMenuPath");
+    localStorage.removeItem("isShowGroupAnalysis");
 
     // 2. 重置 store 中的响应式状态
     filterObject.value = {} as FilterObject; // 重置为空对象(可根据业务需要设置默认值)
     analysisExamInfo.value = {};
     filtersData.value = [];
     childMenuPath.value = '';
+    isShowGroupAnalysis.value = false;
   }
   return {
     filtersData,
     filterObject,
     analysisExamInfo,
     childMenuPath,
+    isShowGroupAnalysis,
     setFiltersData,
     setFilterObject,
     setAnalysisExamInfo,
     setChildMenuPath,
+    setIsShowGroupAnalysis,
     removeLocalStorage
   };
 });

+ 56 - 3
src/views/analysis/classComparison.vue

@@ -195,6 +195,17 @@
     @ChangeCurrentPage="ChangeCurrentPage"
     @ExportExcel="ExportExcel"
   >
+    <template #title_right>
+      <SetTableHeader
+        :data="{
+          static: state.analysisData.headerData.static,
+          dynamisc: [],
+          child: state.analysisData.headerData.child,
+        }"
+        :notEditable="['序号', '班级']"
+        @SetEnterHeaderData="SetEnterHeaderData"
+      ></SetTableHeader>
+    </template>
     <template #module_table_chart>
       <el-table :data="analysisTableData" border stripe align="left">
         <!-- 静态表头列 -->
@@ -345,10 +356,11 @@ import BarStackChartVertical from "@/components/echarts/barStackChart_vertical.v
 import BarStackChartHorizontal from "@/components/echarts/barStackChart_horzontal.vue"; //横向堆叠条形图
 import DifferenceChart from "@/components/echarts/differenceChart.vue"; //率差图
 import StudentList from "@/components/studentList.vue"; //学生列表弹窗组件
+import SetTableHeader from "@/components/SetTableHeader.vue";
 import { onMounted, reactive, computed, watch, ref } from "vue";
 import { useAnalysisStore } from "@/store/analysis";
 import { classContrastSubjectTable, publicExportFive } from "@/api/analysis";
-import { getSchoolFiveRateColor,loadingSvgIcon } from "@/utils/common";
+import { getSchoolFiveRateColor, loadingSvgIcon } from "@/utils/common";
 import { downloadExcel, GetExcelFileName } from "@/utils/exportExcel";
 import { cloneDeep } from "lodash-es";
 
@@ -477,7 +489,7 @@ interface PageState {
   groupTitle: string;
   sortValue: string;
   sortOption: SortOption[];
-  dialogData: DialogData; 
+  dialogData: DialogData;
 }
 
 // ================= 组件引用 & Store =================
@@ -1242,8 +1254,49 @@ const OpenStudentDialog = (row: any, header: HeaderItem, child: HeaderItem) => {
 const CloseDialog = (val: boolean) => {
   state.dialogData.showDialog = val;
 };
-// ================= 导出功能 =================
+//确定显示的表头数据
+const SetEnterHeaderData = (data: any) => {
+  const staticProps = data.static.filter((item) => item.display).map((item) => item.prop);
+  const childProps = data.child.filter((item) => item.display).map((item) => item.prop);
+  state.analysisData.staticHeader = state.analysisData.headerData.static.filter(
+    (header) => staticProps.includes(header.prop),
+  );
+  state.analysisData.dynamicsHeader = [];
+  state.analysisData.headerData.dynamisc.forEach((item) => {
+    let child = [];
 
+    item.headerList.forEach((childItem) => {
+      if (childProps.includes(childItem.prop)) {
+        child.push(childItem);
+      }
+    });
+    let dynamicsItem = {
+      name: item.name,
+      value: item.value,
+      prop: item.prop || "",
+      headerList: child,
+    };
+
+    state.analysisData.dynamicsHeader.push(dynamicsItem);
+  });
+  console.log(data.static,3333)
+  // 将 checkData.static 转换为对象映射
+  const checkDataStaticMap = {}; //静态对象映射
+  const checkDataChildMap = {}; //子表头对象映射
+  data.static.forEach((item) => {
+    checkDataStaticMap[item.prop] = true;
+  });
+  data.child.forEach((item: string) => {
+    checkDataChildMap[item.prop] = true;
+  });
+  // 遍历 state.checkData.static 并设置 display 属性
+  state.analysisData.headerData.static.forEach((item) => {
+    item.display = checkDataStaticMap[item.prop] || false;
+  }); //静态
+  state.analysisData.headerData.child.forEach((item) => {
+    item.display = checkDataChildMap[item.prop] || false;
+  }); //子表头
+};
 /** 导出 Excel */
 const ExportExcel = () => {
   reportModuleRef.value?.SetExportLoading?.(true);

+ 1 - 1
src/views/analysis/groupAnalysis.vue

@@ -554,7 +554,7 @@ import BarScoringRateVertical from "@/components/echarts/barScoringRate_vertical
 import DifferenceChart from "@/components/echarts/differenceChart.vue";
 import BarChart from "@/components/echarts/barChart_answer.vue";
 import StudentQuestionImg from "@/components/StudentQuestionImg.vue";
-import SetTableHeader from "@/components/setTableHeader.vue";
+import SetTableHeader from "@/components/SetTableHeader.vue";
 import StudentList from "@/components/StudentList.vue";
 import { downloadExcel, GetExcelFileName } from "@/utils/exportExcel";
 import { loadingSvgIcon } from "@/utils/common";

+ 15 - 15
src/views/analysis/index.vue

@@ -30,6 +30,7 @@ import { onMounted, ref, computed } from "vue";
 import { useRoute } from "vue-router";
 import { useAnalysisStore } from "@/store/analysis";
 import { useExamStore } from "@/store/exam";
+import { ElMessage } from 'element-plus'
 
 const examStore = useExamStore();
 const analysisStore = useAnalysisStore();
@@ -38,7 +39,6 @@ const reportContentRef = ref<HTMLElement | null>(null);
 
 // 考试科目 code
 const subjectCode = computed(() => {
-  console.log(examStore.currentExam, 33333);
   return examStore.currentExam?.examSubjectCode;
 });
 const aiExamId = computed(() => {
@@ -151,7 +151,7 @@ const filtersData = ref<FilterItem[]>([
   { label: "班级类型", type: "classType", list: [], value: "" },
   { label: "班级名称", type: "className", list: [], value: "" },
 ]);
-
+const examId = ref("2036963589738971137");//2036963589738971137
 // --- 工具函数 ---
 const updateBySchool = (school: FilterOption) => {
   if (!school || !school.selectStatusVoList) return;
@@ -243,7 +243,7 @@ const buildAndSaveFilterParams = () => {
   if (!courseObj || !schoolObj || !statusObj) return;
 
   const filterObject: FilterParams = {
-    examId: "2036963589738971137",
+    examId: examId.value,
     examLevel: 2, // 单校
     subjectCode: courseObj.subjectCode,
     subjectName: courseObj.subjectName,
@@ -286,7 +286,7 @@ const buildAndSaveFilterParams = () => {
 // 初始化加载公共筛选列表
 const getCommonSelectList = async () => {
   try {
-    const res = await findCommonSelectList({ aiExamId: "2036963589738971137" });
+    const res = await findCommonSelectList({ aiExamId: examId.value });
     if (res.code !== 200 || !res.data?.length) return;
 
     const subjectList: FilterOption[] = (res.data as SubjectItem[])
@@ -350,7 +350,7 @@ const loadAnalysisExamInfo = async () => {
     }
 
     const res = await getAnalysisExamInfo({
-      examId: "2036963589738971137",
+      examId: examId.value,
       subjectCode: currentSubjectCode,
     });
 
@@ -410,22 +410,22 @@ const handleSelectChange = (index: number, value: string) => {
   analysisStore.setFiltersData(filtersData.value);
   buildAndSaveFilterParams();
 };
-// 根据选择题判分系统ID获取考试的examId
-const GetIdByAiExamId = async () => {
-  const res = await getIdByAiExamId({
-    aiExamId: aiExamId.value,
-  });
-  if (res.code === 200 && res.data) {
-    
-  }
-};
 // 回到顶部
 const goToPageTop = () => {
   reportContentRef.value?.scrollTo({ top: 0, behavior: "smooth" });
 };
 
 onMounted(async () => {
-  await GetIdByAiExamId();
+  // 根据选择题判分系统ID获取考试的examId
+  const res = await getIdByAiExamId({
+    aiExamId: aiExamId.value,
+  });
+  if (res.code === 200 && res.data) {
+    examId.value = res.data;
+  }else{
+    ElMessage.error("获取考试信息失败");
+    // return;
+  }
   if (analysisStore?.filtersData?.length) {
     filtersData.value = analysisStore.filtersData;
   } else {

+ 1 - 1
src/views/analysis/questionAnalysis.vue

@@ -458,7 +458,7 @@ import BarScoringRateVertical from "@/components/echarts/barScoringRate_vertical
 import DifferenceChart from "@/components/echarts/differenceChart.vue"; //率差图
 import BarChart from "@/components/echarts/barChart_answer.vue"; //单柱状图
 import StudentQuestionImg from "@/components/StudentQuestionImg.vue"; // 学生小题答题卡组件
-import SetTableHeader from "@/components/setTableHeader.vue"; //设置表头
+import SetTableHeader from "@/components/SetTableHeader.vue"; //设置表头
 import StudentList from "@/components/StudentList.vue";
 import { downloadExcel, GetExcelFileName } from "@/utils/exportExcel";
 import { onMounted, reactive, watch, ref, computed, nextTick } from "vue";

+ 42 - 12
src/views/exam/components/stepItem.vue

@@ -26,6 +26,7 @@ import { ref, computed, onMounted, watch } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { useExamStore } from '@/store/exam'
 import { useAnalysisStore } from '@/store/analysis'
+import { queryQuestionGroupByAiId } from '@/api/analysis'
 
 const examStore = useExamStore()
 const analysisStore = useAnalysisStore()
@@ -56,7 +57,11 @@ const examStateStr = computed(() => {
 const examType=computed(() => {
   return examStore.currentExam?.examType  // 默认为选择题
 })
-
+// 考试步骤
+const stepFlow = computed(() => {
+  return examStore.currentExam?.stepFlow
+})
+const isShowGroupAnalysis = computed(() => analysisStore?.isShowGroupAnalysis || false);
 
 // 5. 动态菜单列表
 const menuList = computed(() => {
@@ -65,11 +70,15 @@ const menuList = computed(() => {
   if(examType.value==1)
   {
     //选择题判分
-    list = [
-      { name: '试题结构', number: '1', path: 'question', desc: '建立考试试题结构、设置标答、分组等信息', status: 0 },
-      { name: '扫描学生', number: '2', path: 'scanList', desc: '扫描学生,处理扫描异常学生等', status: 0 },
-      { name: '成绩查询', number: '3', path: 'analysis/score', desc: '设置每个主观题下的划分区信息及位置', status: 0 ,
-        menu:[
+    if(stepFlow.value < 2){
+      list = [
+        { name: '试题结构', number: '1', path: 'question', desc: '建立考试试题结构、设置标答、分组等信息', status: 0 },
+        { name: '扫描学生', number: '2', path: 'scanList', desc: '扫描学生,处理扫描异常学生等', status: 0 },
+      ];
+    }else{
+      let analysisMenu = []
+      if(isShowGroupAnalysis.value){
+        analysisMenu = [
           { name: '成绩单',number: '4', path: 'score' },
           { name: '错题分析',number: '5', path: 'errorAnalysis' },
           { name: '选项明细',number: '6', path: 'optionDetail' },
@@ -79,10 +88,27 @@ const menuList = computed(() => {
           { name: '分组分析',number: '10', path: 'groupAnalysis' },
           { name: '选项分析',number: '11', path: 'optionAnalysis' },
           { name: '命题分析',number: '12', path: 'propositionAnalysis' },
-        ]
-      },
-    ];
-   
+        ];
+      }else{
+        analysisMenu = [
+          { name: '成绩单',number: '4', path: 'score' },
+          { name: '错题分析',number: '5', path: 'errorAnalysis' },
+          { name: '选项明细',number: '6', path: 'optionDetail' },
+          { name: '水平分布',number: '7', path: 'levelDistribution' },
+          { name: '班级对比',number: '8', path: 'classComparison' },
+          { name: '小题分析',number: '9', path: 'questionAnalysis' },
+          { name: '选项分析',number: '11', path: 'optionAnalysis' },
+          { name: '命题分析',number: '12', path: 'propositionAnalysis' },
+        ];
+      }
+      list = [
+        { name: '试题结构', number: '1', path: 'question', desc: '建立考试试题结构、设置标答、分组等信息', status: 0 },
+        { name: '扫描学生', number: '2', path: 'scanList', desc: '扫描学生,处理扫描异常学生等', status: 0 },
+        { name: '成绩查询', number: '3', path: 'analysis/score', desc: '设置每个主观题下的划分区信息及位置', status: 0 ,
+          menu:analysisMenu
+        },
+      ];
+    }
   }
   else if(examType.value==2)
   {
@@ -212,8 +238,12 @@ onMounted(() => {
     stepOnIndex.value = 0
    
   }
-
-  
+  const res = queryQuestionGroupByAiId(examSubjectId.value)
+  if (res.code === 200) {
+    analysisStore.setIsShowGroupAnalysis(true);
+  }else{
+    analysisStore.setIsShowGroupAnalysis(false);
+  }
 })
 
 </script>