Selaa lähdekoodia

题型难度分布

Michael Wang 3 vuotta sitten
vanhempi
commit
063c01310d

+ 71 - 0
src/features/paperAnalysis/DistriTable.vue

@@ -0,0 +1,71 @@
+<template>
+  <table class="custom-table">
+    <tr>
+      <td rowspan="2">题型</td>
+      <td rowspan="2">题量</td>
+      <td rowspan="2">满分</td>
+      <td rowspan="2">难度</td>
+      <td colspan="3">高难度</td>
+      <td colspan="3">中等难度</td>
+      <td colspan="3">低难度</td>
+    </tr>
+    <tr>
+      <td>题量</td>
+      <td>分值</td>
+      <td>%</td>
+      <td>题量</td>
+      <td>分值</td>
+      <td>%</td>
+      <td>题量</td>
+      <td>分值</td>
+      <td>%</td>
+    </tr>
+    <tr v-for="(item2, index) in props.questions" :key="index">
+      <td>
+        {{ item2.groupName || "全卷" }}
+      </td>
+      <td>
+        {{ item2.questionCount }}
+      </td>
+      <td>
+        {{ item2.totalScore }}
+      </td>
+      <td>
+        {{ item2.difficulty }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.high.questionCount }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.high.fullScore }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.high.percent }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.middle.questionCount }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.middle.fullScore }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.middle.percent }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.low.questionCount }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.low.fullScore }}
+      </td>
+      <td>
+        {{ item2.difficulityLevel.low.percent }}
+      </td>
+    </tr>
+  </table>
+</template>
+
+<script setup lang="ts">
+import { QuestionGroup } from "@/types";
+
+const props = defineProps<{ questions: QuestionGroup[] }>();
+</script>

+ 25 - 10
src/features/paperAnalysis/PaperAnalysis.vue

@@ -1,29 +1,38 @@
 <template>
   <div>
     <div class="tw-bg-white tw-p-5 tw-rounded-xl tw-mb-5">
-      <ProjectSelect :project-id="projectId" v-model:value="projectId" />
+      <ProjectSelect
+        disabled
+        :project-id="projectId"
+        v-model:value="projectId"
+      />
       <span class="tw-mr-4"></span>
-      <CourseSelect :root-org-id="rootOrgId" v-model:value="courseId" />
+      <CourseSelect
+        disabled
+        :root-org-id="rootOrgId"
+        v-model:value="courseId"
+      />
       <span class="tw-mr-4"></span>
-      <PaperTypeSelect v-model:value="paperType" />
+      <PaperTypeSelect disabled v-model:value="paperType" />
       <span class="tw-mr-4"></span>
-      试卷名称: <a-input disabled :value="paperName" style="width: 100px" />
+      试卷名称: <a-input disabled :value="paperName" style="width: 120px" />
       <span class="tw-mr-4"></span>
       <a-button @click="search" class="query-btn">查询</a-button>
 
-      <div class="tw-mt-4">
+      <div class="tw-float-right">
         <a-button @click="goBack">返回</a-button>
       </div>
     </div>
 
     <div class="tw-bg-white tw-p-5 tw-rounded-xl">
-      <a-radio-group v-model:value="activeTab" class="tw-mb-4">
+      <a-radio-group v-model:value="activeTab">
         <a-radio-button value="1">试卷题目编排</a-radio-button>
         <a-radio-button value="2">试题特征量数</a-radio-button>
         <a-radio-button value="3">题型难度分布</a-radio-button>
         <a-radio-button value="4">题型难度分布</a-radio-button>
         <a-radio-button value="5">试题难度分组分布</a-radio-button>
       </a-radio-group>
+      <div class="tw-my-4"></div>
 
       <div v-if="activeTab === '1'">
         <QuestionBianPai :questions="paperQuestions" />
@@ -56,7 +65,6 @@ import { goBack } from "@/utils/utils";
 import { watch, onMounted, ref, toRaw } from "vue-demi";
 import { useRoute } from "vue-router";
 import ProjectSelect from "@/components/ProjectSelect.vue";
-import router from "@/router";
 import {
   getPaper,
   getPaperQuestionGroups,
@@ -110,15 +118,22 @@ async function fetchData() {
   });
   paperQuestions = res2.data;
 
+  const res4 = await getSasPaper(paperId);
+  res4.data.difficulityLevel = JSON.parse(res4.data.difficulityLevel || "[]");
+  res4.data.discriminationLevel = JSON.parse(
+    res4.data.discriminationLevel || "[]"
+  );
+  console.log(res4.data);
+  sasPaper = res4.data;
+
   const res3 = await getPaperQuestionGroups(projectId, paperId);
   res3.data = res3.data.map((q) => {
     q.difficulityLevel = JSON.parse(q.difficulityLevel || "[]");
+    q.discriminationLevel = JSON.parse(q.discriminationLevel || "[]");
     return q;
   });
+  res3.data.push(res4.data);
   paperQuestionGroups = res3.data;
-
-  const res4 = await getSasPaper(paperId);
-  sasPaper = res4.data;
 }
 
 onMounted(async () => {

+ 16 - 14
src/features/paperAnalysis/QuestionAttr.vue

@@ -1,6 +1,8 @@
 <template>
   <div>
-    <a-button @click="openModal">说明</a-button>
+    <div class="tw-flex tw-justify-end tw-mb-2">
+      <a-button @click="openModal">说明</a-button>
+    </div>
 
     <a-table
       style="width: 100%; overflow-x: scroll"
@@ -21,67 +23,67 @@ const columns = [
   {
     title: "大题号",
     dataIndex: "mainNumber",
-    width: 80,
+    width: 50,
   },
   {
     title: "小题号",
     dataIndex: "subNumber",
-    width: 80,
+    width: 50,
   },
   {
     title: "满分",
     dataIndex: "totalScore",
-    width: 150,
+    width: 80,
   },
   {
     title: "最高分",
     dataIndex: "maxScore",
-    width: 150,
+    width: 80,
   },
   {
     title: "最低分",
     dataIndex: "minScore",
-    width: 150,
+    width: 80,
   },
   {
     title: "平均分",
     dataIndex: "avgScore",
-    width: 150,
+    width: 80,
   },
   {
     title: "标准差",
     dataIndex: "stdev",
-    width: 150,
+    width: 80,
   },
   {
     title: "差异系数",
     dataIndex: "coefficient",
-    width: 150,
+    width: 100,
   },
   {
     title: "难度",
     dataIndex: "difficulty",
-    width: 150,
+    width: 80,
   },
   {
     title: "区分度",
     dataIndex: "discrimination",
-    width: 150,
+    width: 80,
   },
   {
     title: "零分人数",
     dataIndex: "zeroCount",
-    width: 150,
+    width: 100,
   },
   {
     title: "满分人数 ",
     dataIndex: "fullCount",
-    width: 150,
+    width: 100,
   },
   {
     title: "有效卷数",
     dataIndex: "effectiveCount",
-    width: 150,
+    width: 100,
   },
 ];
 

+ 3 - 3
src/features/paperAnalysis/QuestionBianPai.vue

@@ -1,12 +1,12 @@
 <template>
-  <div>
-    <a-button @click="openModal">说明</a-button>
-
+  <div class="tw-flex">
     <a-table
       row-key="id"
       :columns="columns"
       :data-source="props.questions"
     ></a-table>
+
+    <a-button @click="openModal">说明</a-button>
   </div>
 </template>
 

+ 152 - 84
src/features/paperAnalysis/QuestionTypeDifficulty.vue

@@ -1,18 +1,145 @@
 <template>
   <div>
     <a-button @click="importModalVisible = true">题型分布设置</a-button>
-    <a-button @click="openModal">说明</a-button>
 
-    <a-table
-      style="width: 100%; overflow-x: scroll"
-      row-key="id"
-      :columns="columns"
-      :data-source="props.questions"
-    ></a-table>
+    <div v-if="props.questions.some((q) => q.type === 'TYPE1')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">题型题目难度等级构成分布(一)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'TYPE1' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'TYPE2')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">题型题目难度等级构成分布(二)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'TYPE2' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'TYPE3')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">题型题目难度等级构成分布(三)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'TYPE3' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'CONTENT1')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">内容题目难度等级构成分布(一)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'CONTENT1' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'CONTENT2')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">内容题目难度等级构成分布(二)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'CONTENT2' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'CONTENT3')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">内容题目难度等级构成分布(三)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'CONTENT3' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'ABILITY1')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">能力题目难度等级构成分布(一)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'ABILITY1' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'ABILITY2')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">能力题目难度等级构成分布(二)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'ABILITY2' || !q.type)
+        "
+      />
+    </div>
+
+    <div v-if="props.questions.some((q) => q.type === 'ABILITY3')">
+      <div class="tw-flex tw-justify-between tw-items-center tw-my-4">
+        <h3 class="section-title">能力题目难度等级构成分布(三)</h3>
+        <div class="tw-flex tw-gap-2">
+          <a-button @click="openModal07">说明</a-button>
+        </div>
+      </div>
+
+      <DistriTable
+        :questions="
+          props.questions.filter((q) => q.type === 'ABILITY3' || !q.type)
+        "
+      />
+    </div>
 
     <a-modal
       v-model:visible="importModalVisible"
-      title="批量科目导入"
+      title="题型设置导入"
       @ok="handleImport"
       ok-text="确定"
       cancel-text="取消"
@@ -22,9 +149,9 @@
           <input id="file-input" :multiple="false" type="file" />
         </a-form-item>
         <a-form-item label="下载模板">
-          <a-button class="download-tpl-btn" @click="downloadTpl"
-            >下载模板</a-button
-          >
+          <a-button class="download-tpl-btn" @click="downloadTpl">
+            下载模板
+          </a-button>
         </a-form-item>
       </a-form>
     </a-modal>
@@ -34,82 +161,15 @@
 <script setup lang="ts">
 import { importQuestionGroups } from "@/api/paperAnalysisPage";
 import EventBus from "@/plugins/eventBus";
-import { Question } from "@/types";
+import { QuestionGroup } from "@/types";
 import { downloadFileURL } from "@/utils/utils";
 import { message } from "ant-design-vue";
+import DistriTable from "./DistriTable.vue";
+
+const props = defineProps<{ questions: QuestionGroup[]; projectId: number }>();
 
-const props = defineProps<{ questions: Question[]; projectId: number }>();
-
-const columns = [
-  {
-    title: "大题号",
-    dataIndex: "mainNumber",
-    width: 80,
-  },
-  {
-    title: "小题号",
-    dataIndex: "subNumber",
-    width: 80,
-  },
-  {
-    title: "满分",
-    dataIndex: "totalScore",
-    width: 150,
-  },
-  {
-    title: "最高分",
-    dataIndex: "maxScore",
-    width: 150,
-  },
-  {
-    title: "最低分",
-    dataIndex: "minScore",
-    width: 150,
-  },
-  {
-    title: "平均分",
-    dataIndex: "avgScore",
-    width: 150,
-  },
-  {
-    title: "标准差",
-    dataIndex: "stdev",
-    width: 150,
-  },
-  {
-    title: "差异系数",
-    dataIndex: "coefficient",
-    width: 150,
-  },
-  {
-    title: "难度",
-    dataIndex: "difficulty",
-    width: 150,
-  },
-  {
-    title: "区分度",
-    dataIndex: "discrimination",
-    width: 150,
-  },
-  {
-    title: "零分人数",
-    dataIndex: "zeroCount",
-    width: 150,
-  },
-  {
-    title: "满分人数 ",
-    dataIndex: "fullCount",
-    width: 150,
-  },
-  {
-    title: "有效卷数",
-    dataIndex: "effectiveCount",
-    width: 150,
-  },
-];
-
-function openModal() {
-  EventBus.emit("SHOW_SETTING", "DESCRIBE06");
+function openModal07() {
+  EventBus.emit("SHOW_SETTING", "DESCRIBE07");
 }
 
 /** <handleImport> */
@@ -132,3 +192,11 @@ async function downloadTpl() {
   downloadFileURL("/api/ess/sasQuestionGroup/template");
 }
 </script>
+
+<style scoped>
+.section-title {
+  color: #212534;
+  font-size: 16px;
+  font-weight: 700;
+}
+</style>

+ 2 - 2
src/plugins/axiosNotice.ts

@@ -20,9 +20,9 @@ export const notifyInvalidTokenThrottled = throttle(
           redirectTo: router.currentRoute.value.fullPath,
         })
       );
-    }, 3000);
+    }, 1000);
     console.log("登录失效");
   },
-  5000,
+  1000,
   { trailing: false }
 );

+ 70 - 0
src/types/index.ts

@@ -37,3 +37,73 @@ export interface Question {
   difficulityLevel: number[];
   difficulityGroupLevel: number[];
 }
+
+// Generated by https://quicktype.io
+
+export interface QuestionGroup {
+  avgScore: number;
+  coefficient: number;
+  courseId: number;
+  createTime: string;
+  difficulityLevel: {
+    high: {
+      questionCount: number;
+      fullScore: number;
+      percent: number;
+    };
+    middle: {
+      questionCount: number;
+      fullScore: number;
+      percent: number;
+    };
+    low: {
+      questionCount: number;
+      fullScore: number;
+      percent: number;
+    };
+  };
+  difficulty: number;
+  discrimination: number;
+  discriminationLevel: {
+    excellent: {
+      questionCount: number;
+      fullScore: number;
+    };
+    good: {
+      questionCount: number;
+      fullScore: number;
+    };
+    general: {
+      questionCount: number;
+      fullScore: number;
+    };
+    bad: {
+      questionCount: number;
+      fullScore: number;
+    };
+  };
+  fullCount: number;
+  groupName: string;
+  id: number;
+  maxScore: number;
+  minScore: number;
+  objective: boolean;
+  paperId: number;
+  projectId: number;
+  questionCount: number;
+  realityCount: number;
+  stdev: number;
+  totalScore: number;
+  type:
+    | "TYPE1"
+    | "TYPE2"
+    | "TYPE3"
+    | "CONTENT1"
+    | "CONTENT2"
+    | "CONTENT3"
+    | "ABILITY1"
+    | "ABILITY2"
+    | "ABILITY3";
+  updateTime: string;
+  zeroCount: number;
+}