questionAnalysis.vue 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. <template>
  2. <ReportModule
  3. :showTitle="true"
  4. :titleList="[state.groupTitle]"
  5. :showDescribe="true"
  6. tableOrChart="chart"
  7. :showPrintBtn="false"
  8. :showExportBtn="false"
  9. >
  10. <template #title_right>
  11. <EchartType
  12. :chartTypeList="state.problemAnalysisData.chartTypeList"
  13. :current="state.problemAnalysisData.chartType"
  14. @ChangeEchartType="
  15. (val) => ChangeEchartType(val, 'problemAnalysisData')
  16. "
  17. />
  18. </template>
  19. <template #module_table_chart>
  20. <template v-if="state.problemAnalysisData.data.length > 0">
  21. <BarLineCharts
  22. v-if="state.problemAnalysisData.chartType == 'line_bar_chart'"
  23. :legendList="state.problemAnalysisData.legendList"
  24. :showBarLegendIndex="state.problemAnalysisData.showBarLegendIndex"
  25. title="得分率"
  26. :data="state.problemAnalysisData.data"
  27. @HandleChartClick="HandleChartClick"
  28. @ChangeChartOrder="
  29. (sortType, legendData, barIndex) =>
  30. ChangeChartOrder(sortType, legendData, barIndex, 1)
  31. "
  32. >
  33. </BarLineCharts>
  34. <BarsCharts
  35. v-if="state.problemAnalysisData.chartType == 'vertical_bar'"
  36. :key="state.chartKey"
  37. :data="state.problemAnalysisData.data"
  38. :legendList="state.problemAnalysisData.legendList"
  39. :showSortSelectbox="true"
  40. unit="%"
  41. title="得分率"
  42. :isClick="true"
  43. @HandleChartClick="HandleChartClick"
  44. @ChangeChartOrder="
  45. (sortType, legendData, barIndex) =>
  46. ChangeChartOrder(sortType, legendData, barIndex, 1)
  47. "
  48. >
  49. </BarsCharts>
  50. <RadarCharts
  51. v-if="state.problemAnalysisData.chartType == 'radar_chart'"
  52. :key="state.chartKey"
  53. :data="state.problemAnalysisData.data"
  54. :legendList="state.problemAnalysisData.legendList"
  55. :showCheckBox="true"
  56. :openShowAllLegend="true"
  57. :isClick="true"
  58. @HandleChartClick="HandleChartClick"
  59. >
  60. </RadarCharts>
  61. </template>
  62. <div
  63. v-else
  64. class="no_content_data"
  65. v-loading="state.dataLoading"
  66. :element-loading-text="state.loadingText"
  67. :element-loading-spinner="loadingSvgIcon"
  68. element-loading-background="#ffffff"
  69. >
  70. <span>暂无数据</span>
  71. </div>
  72. </template>
  73. <template #module_describe>
  74. 展示每道试题的得分率图。得分率指实际得分/考核分的比值,换算成的百分数。可以用于分析每道试题的难易程度和质量,试题得分率高意味着试题难度低或者学生整体水平高;得分率低意味着试题难度较高或者考生整体水平较低。点击每道试题的柱或雷达图的题号可在下方查看该题每个班的得分率情况。
  75. </template>
  76. </ReportModule>
  77. <ReportModule
  78. :showTitle="true"
  79. :titleList="[state.groupTitle, state.questionTitle]"
  80. :showDescribe="true"
  81. tableOrChart="chart"
  82. :showPrintBtn="false"
  83. :showExportBtn="false"
  84. >
  85. <template #title_right>
  86. <EchartType
  87. :chartTypeList="state.questionScoreStatsData.chartTypeList"
  88. :current="state.questionScoreStatsData.chartType"
  89. @ChangeEchartType="
  90. (val) => ChangeEchartType(val, 'questionScoreStatsData')
  91. "
  92. />
  93. </template>
  94. <template #module_table_chart>
  95. <template v-if="state.questionScoreStatsData.datax.length > 0">
  96. <BarScoringRateVertical
  97. v-if="state.questionScoreStatsData.chartType == 'vertical_bar'"
  98. :datax="state.questionScoreStatsData.datax"
  99. :datay="state.questionScoreStatsData.dataStackY"
  100. :tooltipData="state.questionScoreStatsData.tooltipData"
  101. :isShowMarkLine="true"
  102. :average="state.questionScoreStatsData.rate"
  103. :markLineData="state.questionScoreStatsData.markLineData"
  104. :color="['#3BA272', '#EE6666']"
  105. typeName="得分率"
  106. :isClick="true"
  107. @HandleChartClick="HandleQuestionScoreChartClick"
  108. ></BarScoringRateVertical>
  109. <DifferenceChart
  110. v-if="state.questionScoreStatsData.chartType == 'difference_chart'"
  111. :datax="state.questionScoreStatsData.datax"
  112. :datay="state.questionScoreStatsData.datay"
  113. unit="%"
  114. type="1"
  115. title="得分率"
  116. :rate="state.questionScoreStatsData.rate"
  117. @HandleChartClick="HandleQuestionScoreChartClick"
  118. >
  119. </DifferenceChart>
  120. </template>
  121. <div
  122. v-else
  123. class="no_content_data"
  124. v-loading="state.dataLoading"
  125. :element-loading-text="state.loadingText"
  126. :element-loading-spinner="loadingSvgIcon"
  127. element-loading-background="#ffffff"
  128. >
  129. <span>暂无数据</span>
  130. </div>
  131. </template>
  132. <template #module_describe>
  133. 说明:通过上面图形,可查看该题每个班的得分率情况,由图中可以看出,得分率最高为<span
  134. style="color: #3ba272"
  135. >{{ state.questionScoreStatsData.maxClass }}</span
  136. >,最低为<span style="color: #ee6666">{{
  137. state.questionScoreStatsData.minClass
  138. }}</span
  139. >。点击每个班级的柱可在下方查看该班各个选项/得分的人数分布。
  140. </template>
  141. </ReportModule>
  142. <ReportModule
  143. :showTitle="true"
  144. :titleList="[state.groupTitle, state.questionTitle, state.classTitle]"
  145. :showDescribe="true"
  146. tableOrChart="qita"
  147. :showPrintBtn="false"
  148. :showExportBtn="false"
  149. >
  150. <template #module_qita>
  151. <div class="content_left answer">
  152. <BarChart
  153. v-if="state.questionAnswerData.datax.length"
  154. :datax="state.questionAnswerData.datax"
  155. :datay="state.questionAnswerData.datay"
  156. typeName="人数"
  157. :showNuitY="false"
  158. unit="人"
  159. :unitX="
  160. state.questionAnswerData.questionType == '单选题' ||
  161. state.questionAnswerData.questionType == '多选题' ||
  162. state.questionAnswerData.questionType == '判断题'
  163. ? ''
  164. : '分'
  165. "
  166. :showMarkPoint="false"
  167. :isShowMarkLine="false"
  168. :color="state.questionAnswerData.color"
  169. :answerValue="state.questionAnswerData.answerValue"
  170. :answerScore="state.questionAnswerData.answerScore"
  171. :fullMark="state.questionAnswerData.fullMark"
  172. :isClick="true"
  173. @HandleChartClick="HandleQuestionAnswerChartClick"
  174. style="height: 300px"
  175. ></BarChart>
  176. <div
  177. v-else
  178. class="module_chart no_content_data"
  179. v-loading="state.dataLoading"
  180. :element-loading-text="state.loadingText"
  181. :element-loading-spinner="loadingSvgIcon"
  182. element-loading-background="#ffffff"
  183. >
  184. <span>暂无数据</span>
  185. </div>
  186. </div>
  187. <div class="content_right answer table_42">
  188. <el-table
  189. border
  190. :data="state.questionAnswerData.tableData"
  191. stripe
  192. align="left"
  193. :header-row-style="HeaderRowStyle"
  194. >
  195. <el-table-column :label="state.classTitle" align="center">
  196. <el-table-column
  197. prop="title"
  198. align="center"
  199. label="名称"
  200. ></el-table-column>
  201. <el-table-column
  202. prop="value"
  203. align="center"
  204. label="数值"
  205. ></el-table-column>
  206. </el-table-column>
  207. </el-table>
  208. </div>
  209. </template>
  210. <template #module_describe>
  211. 说明:通过柱图,可查看该题下该班所有学生的选项或试题得分情况。点击每个柱可查看该选项或分数的学生明细和答题卡答题情况。
  212. </template>
  213. </ReportModule>
  214. <ReportModule
  215. :showTitle="true"
  216. :titleList="[
  217. state.groupTitle,
  218. state.questionTitle,
  219. state.classTitle,
  220. state.optionTitle,
  221. ]"
  222. :showDescribe="true"
  223. tableOrChart="qita"
  224. :showPrintBtn="false"
  225. :showExportBtn="false"
  226. >
  227. <template #title_right>
  228. <el-button
  229. class="default_button"
  230. v-if="
  231. state.questionAnswerData.questionType != '单选题' &&
  232. state.questionAnswerData.questionType != '多选题' &&
  233. state.questionAnswerData.questionType != '判断题'
  234. "
  235. @click="VisibleQuestionCard"
  236. >
  237. <img src="@/assets/icon/card_view.webp" />批量查看
  238. </el-button>
  239. </template>
  240. <template #module_qita>
  241. <div class="content_left paper_card">
  242. <StudentQuestionImg :paperInfo="state.paperInfos"></StudentQuestionImg>
  243. </div>
  244. <div class="content_right paper_card table_42">
  245. <el-table
  246. border
  247. :data="state.majorAnswerData.tableData"
  248. stripe
  249. highlight-current-row
  250. align="left"
  251. height="401px"
  252. row-key="studentRegistrationCode"
  253. :row-style="{ cursor: 'pointer' }"
  254. :row-class-name="TableRowClassName"
  255. @row-click="HandleRowClick"
  256. >
  257. <el-table-column
  258. prop="studentUserName"
  259. align="center"
  260. label="学生"
  261. show-overflow-tooltip
  262. ></el-table-column>
  263. <el-table-column
  264. label="班级"
  265. prop="className"
  266. align="center"
  267. min-width="70"
  268. show-overflow-tooltip
  269. ></el-table-column>
  270. <el-table-column
  271. prop="questionScore"
  272. align="center"
  273. label="得分"
  274. width="70"
  275. show-overflow-tooltip
  276. ></el-table-column>
  277. <el-table-column
  278. prop="paperScore"
  279. align="center"
  280. label="成绩"
  281. width="70"
  282. show-overflow-tooltip
  283. ></el-table-column>
  284. <el-table-column align="center" label="操作">
  285. <template #default="scope">
  286. <el-button text @click.stop="handleClick(scope.row)"
  287. >查看答题卡</el-button
  288. >
  289. </template>
  290. </el-table-column>
  291. </el-table>
  292. </div>
  293. </template>
  294. <template #module_describe>
  295. 说明:点击左侧表格列可切换学生查看具体学生答题图片,点击学生姓名可在下方查看学生均衡分析,点击学生成绩可查看学生答题卡原卷。
  296. </template>
  297. </ReportModule>
  298. <ReportModule
  299. ref="reportModuleRef"
  300. :showTitle="true"
  301. :titleList="[state.groupTitle]"
  302. :showDescribe="true"
  303. tableOrChart="table"
  304. :showPrintBtn="false"
  305. :showExportBtn="true"
  306. :currentPage="state.majorTableData.currentPage"
  307. :pageSize="state.majorTableData.pageSize"
  308. :total="state.majorTableData.total"
  309. @ChangePageSize="ChangePageSize"
  310. @ChangeCurrentPage="ChangeCurrentPage"
  311. @ExportExcel="ExportExcel"
  312. >
  313. <template #title_right>
  314. <SetTableHeader
  315. :data="{
  316. static: state.majorTableData.headerData,
  317. dynamisc: state.majorTableData.changeHeaderData,
  318. child: state.majorTableData.childHeaderData,
  319. }"
  320. :isShowDynamisc="false"
  321. :notEditable="['questionName']"
  322. @SetEnterHeaderData="SetEnterHeaderData"
  323. ></SetTableHeader>
  324. </template>
  325. <template #module_table_chart>
  326. <el-table
  327. :data="state.majorTableData.tableData"
  328. ref="majorTable"
  329. border
  330. stripe
  331. align="left"
  332. :key="state.majorTableData.tableKey"
  333. >
  334. <template v-for="item in state.majorTableData.headerData">
  335. <el-table-column
  336. v-if="item.display"
  337. :key="item.prop"
  338. align="center"
  339. :prop="item.prop"
  340. :min-width="item.label.length > 4 ? 110 : 90"
  341. :label="item.label"
  342. fixed="left"
  343. show-overflow-tooltip
  344. >
  345. <template #default="scope">
  346. {{ scope.row[item.prop] || "-"
  347. }}{{
  348. item.prop == "estimatedScoreRate" && scope.row[item.prop]
  349. ? "%"
  350. : ""
  351. }}
  352. </template>
  353. </el-table-column>
  354. </template>
  355. <template v-for="parent in state.majorTableData.changeHeaderData">
  356. <el-table-column
  357. v-if="parent.display"
  358. align="center"
  359. :prop="parent.prop"
  360. :label="parent.label"
  361. :key="parent.prop"
  362. >
  363. <template v-for="item in state.majorTableData.childHeaderData">
  364. <el-table-column
  365. v-if="item.display"
  366. :prop="`${parent.prop}_${item.prop}`"
  367. :key="`${parent.prop}_${item.prop}`"
  368. align="center"
  369. :label="item.label"
  370. :min-width="item.label.length > 4 ? 100 : 80"
  371. show-overflow-tooltip
  372. >
  373. <template #default="scope">
  374. <span v-if="item.prop.indexOf('Rate') > -1">{{
  375. scope.row[`${parent.prop}_${item.prop}`]
  376. ? `${scope.row[`${parent.prop}_${item.prop}`]}%`
  377. : "-"
  378. }}</span>
  379. <span
  380. v-else
  381. @click="OpenStudentDialog(item, parent, scope.row)"
  382. :class="{
  383. table_row_blue:
  384. (item.prop.indexOf('Count') > -1 ||
  385. item.prop.indexOf('Number') > -1) &&
  386. scope.row?.[`${parent.prop}_${item.prop}`] > 0,
  387. }"
  388. >{{
  389. scope.row?.[`${parent.prop}_${item.prop}`] ?? "-"
  390. }}</span
  391. >
  392. </template>
  393. </el-table-column>
  394. </template>
  395. </el-table-column>
  396. </template>
  397. </el-table>
  398. </template>
  399. </ReportModule>
  400. <!-- 批量查看小题答题卡 -->
  401. <QuestionCard
  402. :subjectId="analysisStore.filterObject.subjectId"
  403. :questionId="state.cardQuestionId"
  404. :platformNumbers="state.cardRegistrationCodeList"
  405. :groupTitle="state.groupTitle"
  406. :groupName="state.groupName"
  407. :questionTitle="state.questionTitle"
  408. :classTitle="state.classTitle"
  409. :optionTitle="state.optionTitle"
  410. :showDialog="state.showQuestionCardDialog"
  411. @CloseDialog="CloseQuestionCardDialog"
  412. ></QuestionCard>
  413. <!-- 学生答题卡组件 -->
  414. <StudentPaper
  415. :modelValue="state.showStudentPaperDialog"
  416. :paperInfo="state.paperInfo"
  417. :pageTitle="state.paperTitle"
  418. @updateModelValue="UpdateModelValue"
  419. ></StudentPaper>
  420. <StudentList
  421. :showDialog.sync="state.dialogData.showDialog"
  422. :title="state.dialogData.title"
  423. :tableTitle="state.dialogData.tableTitle"
  424. :apiName="state.dialogData.apiName"
  425. :studentParam="{
  426. fiveRateName: state.dialogData.fiveRateName, //当前选择的五率的名称
  427. selectSubjectName: state.dialogData.selectSubjectName, //当前选择的科目名称
  428. selectSchoolLevel: state.dialogData.selectSchoolLevel, //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  429. selectSchoolName: state.dialogData.selectSchoolName, //当前选择的学校名称:联校 组合学校 单校名称
  430. selectClassLevel: state.dialogData.selectClassLevel, //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  431. selectClassName: state.dialogData.selectClassName, //当前选择的班级名称:年级 组合班级 单班
  432. questionId: state.dialogData.questionId, //试题ID
  433. isPaper: state.dialogData.isPaper, //是否为全卷0-非1-是全卷
  434. quesScoreType: state.dialogData.quesScoreType, //选择的类型0-满分人数 1-0分人数 3-优秀率、良好率等
  435. knowledgeId: state.dialogData.knowledgeId, //如果选择的是知识点,则需要返回知识点ID
  436. questionGroupName: state.dialogData.questionGroupName, //试题分组的名称
  437. groupTitle: state.dialogData.groupTitle,
  438. }"
  439. @CloseDialog="CloseDialog"
  440. >
  441. </StudentList>
  442. </template>
  443. <script lang="ts" setup>
  444. import ReportModule from "@/components/ReportModule.vue";
  445. import EchartType from "@/components/EchartType.vue";
  446. import QuestionCard from "@/components/QuestionCard.vue";
  447. import StudentPaper from "@/components/StudentPaper.vue"; //学生答题卡组件
  448. import { useAnalysisStore } from "@/store/analysis";
  449. import {
  450. questionAnalysis,
  451. queryAnswerListByAnswerAndScore,
  452. publicExport,
  453. } from "@/api/analysis";
  454. import BarLineCharts from "@/components/echarts/barLineCharts.vue"; //柱状图折线图组合图组件
  455. import RadarCharts from "@/components/echarts/radarCharts.vue"; //雷达图
  456. import BarsCharts from "@/components/echarts/barsCharts.vue"; //多柱状图组件
  457. import BarScoringRateVertical from "@/components/echarts/barScoringRate_vertical.vue"; //得分率 纵向柱状图
  458. import DifferenceChart from "@/components/echarts/differenceChart.vue"; //率差图
  459. import BarChart from "@/components/echarts/barChart_answer.vue"; //单柱状图
  460. import StudentQuestionImg from "@/components/StudentQuestionImg.vue"; // 学生小题答题卡组件
  461. import SetTableHeader from "@/components/SetTableHeader.vue"; //设置表头
  462. import StudentList from "@/components/StudentList.vue";
  463. import { downloadExcel, GetExcelFileName } from "@/utils/exportExcel";
  464. import { onMounted, reactive, watch, ref, computed, nextTick } from "vue";
  465. import { loadingSvgIcon } from "@/utils/common";
  466. import { cloneDeep } from "lodash-es";
  467. const analysisStore = useAnalysisStore();
  468. const reportModuleRef = ref<any>(null);
  469. const getExamName = computed(() => {
  470. return analysisStore.analysisExamInfo.examName || "";
  471. });
  472. // 1. 为 reactive 添加 <any> 泛型,解决空数组推断为 never[] 及深层对象属性访问报错
  473. const state = reactive<any>({
  474. groupTitle: "小题分析",
  475. groupName: "", // 分组名称
  476. questionTitle: "", //题目名称
  477. classTitle: "", //班级名称
  478. optionTitle: "", //选项名称
  479. problemAnalysisData: {
  480. chartType: "line_bar_chart", //默认显示折线图柱状图line_bar_chart
  481. chartTypeList: [
  482. { label: "组合图", value: "line_bar_chart" },
  483. { label: "柱状图", value: "vertical_bar" },
  484. { label: "雷达图", value: "radar_chart" },
  485. ],
  486. legendList: [],
  487. defaultLegendList: [],
  488. showBarLegendIndex: 1,
  489. questionList: [], // 题目列表
  490. questionTableList: [], // 小题分析table
  491. groupList: [], // 分组题目列表
  492. groupTableList: [], // 分组table
  493. headerList: [],
  494. changeHeaderList: [],
  495. childHeaderList: [],
  496. questionListIndex: 0, //题目 索引
  497. data: [], //柱状图
  498. }, //小题分析数据
  499. questionScoreStatsData: {
  500. checked: false,
  501. isIndeterminate: true,
  502. markLineData: [], //平均分
  503. chartTypeList: [
  504. { label: "柱状图", value: "vertical_bar" },
  505. { label: "率差图", value: "difference_chart" },
  506. ],
  507. chartType: "vertical_bar", //默认显示率差图vertical_bar
  508. datax: [], //x轴数据
  509. datay: [], //Y轴数据
  510. dataStackY: [], //Y轴数据
  511. tooltipData: [], //
  512. rate: 60, //中间x的刻度线的值 数字类型
  513. maxClass: "", // 得分率最高班
  514. minClass: "", // 得分率最低班
  515. }, //小题分析 /第N题
  516. questionAnswerData: {
  517. datax: [], //x轴数据
  518. datay: [], //Y轴数据
  519. color: "#5470C6",
  520. answerValue: "", //正确答案 柱状图显示绿色
  521. answerScore: [], //答案所能得的分数
  522. questionType: "", //类型
  523. fullMark: "", //满分
  524. tableData: [],
  525. classListIndex: 0, // 索引
  526. }, //小题分析 /第N题 / N班
  527. majorAnswerData: {
  528. paperUrl: "", //试卷地址
  529. tableData: [], //表格数据
  530. rowIndex: 0,
  531. }, // 通过答案或者分数查询某题作答情况
  532. majorStudentData: {
  533. tableData: [],
  534. legendList: [],
  535. radarChartData: [],
  536. excellentCourseList: "", //优秀科目
  537. inferiorCourseList: "", //弱势科目
  538. }, //科目得分率
  539. majorTableData: {
  540. tableKey: 0,
  541. tableData: [], //小题分析表数据
  542. allTableData: [],
  543. headerData: [], //固定表头数据
  544. changeHeaderData: [], //动态表头数据
  545. childHeaderData: [], //子级表头数据
  546. pageSize: 10, //每页显示数据
  547. total: 0, //总数
  548. currentPage: 1, //当前页
  549. }, //小题分析表 + 题目分组分析
  550. chartKey: 0,
  551. dataLoading: false,
  552. loadingText: "加载中,请稍后...",
  553. paperInfo: {
  554. examPaperId: "", //考试科目id
  555. platformNumber: "", //学籍号平台号
  556. questionId: "", //题目id
  557. }, //学生试卷信息
  558. paperTitle: "", //学生试卷标题
  559. showStudentPaperDialog: false, //是否显示学生答题卡弹窗
  560. paperInfos: {
  561. examPaperId: "", //考试科目id
  562. platformNumber: "", //学籍号平台号
  563. questionId: "", //题目id
  564. },
  565. dialogData: {
  566. apiName: "questionStudentInfo",
  567. showDialog: false,
  568. title: "",
  569. tableTitle: "",
  570. fiveRateName: "", //当前选择的五率的名称
  571. selectSubjectName: "", //当前选择的科目名称
  572. selectSchoolLevel: "", //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  573. selectSchoolName: "", //当前选择的学校名称:联校 组合学校 单校名称
  574. selectClassLevel: "", //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  575. selectClassName: "", //当前选择的班级名称:年级 组合班级 单班
  576. questionId: "", //试题ID
  577. isPaper: "", //是否为全卷0-非1-是全卷
  578. quesScoreType: "", //选择的类型0-满分人数 1-0分人数 3-优秀率、良好率等
  579. knowledgeId: "", //如果选择的是知识点,则需要返回知识点ID
  580. questionGroupName: "", //试题分组的名称
  581. groupTitle: "",
  582. },
  583. showQuestionCardDialog: false,
  584. cardQuestionId: "", // 批量查看答题卡试题id
  585. cardRegistrationCodeList: [], // 批量查看答题卡学生账号数组
  586. });
  587. // 2. 为 ref 添加 <any> 泛型
  588. const majorTable = ref<any>(null);
  589. // 3. 为所有函数参数补充 :any 类型声明,解决隐式 any 报错
  590. //排序
  591. const ChangeChartOrder = (sortType: any, legendData: any, barIndex: any, number: any) => {
  592. const isHasEstimatedScore = state.problemAnalysisData.headerList.find(
  593. (item: any) => item.prop == "estimatedScore",
  594. ); //是否存在预估满分
  595. const fullVolume = state.problemAnalysisData.questionList.filter(
  596. (item: any) => item.showCode == 999,
  597. ); //全卷
  598. const questionList = state.problemAnalysisData.questionList.filter(
  599. (item: any) => item.showCode != 999,
  600. );
  601. const newBarIndex = isHasEstimatedScore ? barIndex - 1 : barIndex;
  602. if (sortType == "2") {
  603. //从低到高
  604. questionList.sort(function (a: any, b: any) {
  605. return (
  606. (a?.classList?.[newBarIndex]?.questionStats?.scoreRate || 0) -
  607. (b?.classList?.[newBarIndex]?.questionStats?.scoreRate || 0)
  608. );
  609. });
  610. } else if (sortType == "3") {
  611. //从高到低
  612. questionList.sort(function (a: any, b: any) {
  613. return (
  614. (b?.classList?.[newBarIndex]?.questionStats?.scoreRate || 0) -
  615. (a?.classList?.[newBarIndex]?.questionStats?.scoreRate || 0)
  616. );
  617. });
  618. } else {
  619. //默认排序 按题号排序
  620. questionList.sort(function (a: any, b: any) {
  621. return (a?.showCode || 0) - (b.showCode || 0);
  622. });
  623. }
  624. state.problemAnalysisData.questionList = [...questionList, ...fullVolume];
  625. let chartData: any[] = [],
  626. chartTitle: any[] = [];
  627. state.problemAnalysisData.questionList.forEach((ques: any) => {
  628. const scoreRateArr = ques.classList.map(
  629. (item: any) => item?.questionStats?.scoreRate || 0,
  630. );
  631. if (isHasEstimatedScore) {
  632. chartData.push([
  633. ques.questionName,
  634. ques.estimatedScoreRate,
  635. ...scoreRateArr,
  636. ]);
  637. } else {
  638. chartData.push([ques.questionName, ...scoreRateArr]);
  639. }
  640. });
  641. const newChangeHeaderList = isHasEstimatedScore
  642. ? [
  643. { ...isHasEstimatedScore, isG: false, type: 1 },
  644. ...state.problemAnalysisData.changeHeaderList,
  645. ]
  646. : [...state.problemAnalysisData.changeHeaderList];
  647. newChangeHeaderList.forEach((item: any) => {
  648. chartTitle.push(item.label);
  649. });
  650. chartTitle.unshift("group");
  651. chartData.unshift(chartTitle); // 柱状图 图例标题
  652. chartData.pop(); // 删除最后一行 全卷
  653. state.problemAnalysisData.data = chartData;
  654. state.problemAnalysisData.legendList = legendData;
  655. //小题分析 /第N题
  656. GetQuestionStatsData(0);
  657. };
  658. //试题图表切换公共方法
  659. const ChangeEchartType = (value: any, prop: any) => {
  660. if (prop == "problemAnalysisData") {
  661. ChangeChartOrder("1", state.problemAnalysisData.defaultLegendList, "", 1);
  662. }
  663. state[prop].chartType = value;
  664. };
  665. //获取小题分析数据
  666. const GetQuestionAnalysisData = () => {
  667. state.problemAnalysisData.data = []; //柱状图折线图 X轴
  668. state.dataLoading = true;
  669. questionAnalysis({
  670. ...analysisStore.filterObject,
  671. analysisType: 0, //0-小题分析 1大题分析 2-知识点 3-能力点 question_group_code(4,5,6,7,8) 11-题型分析
  672. })
  673. .then((res: any) => {
  674. if (
  675. res.code == 200 &&
  676. res.data &&
  677. res.data.questionList &&
  678. res.data.questionList.length
  679. ) {
  680. const { data } = res;
  681. const questionList = data.questionList || [];
  682. const changeHeaderList = data.changeHeaderList || []; //柱状图折线图 班级名称
  683. const headerListData = data.headerList || [];
  684. state.problemAnalysisData.groupList = [];
  685. state.problemAnalysisData.groupTableList = [];
  686. state.problemAnalysisData.questionList = questionList;
  687. state.problemAnalysisData.questionTableList = cloneDeep(questionList);
  688. state.problemAnalysisData.headerList = headerListData.filter((item: any) => item.prop != "knowledge");//不显示知识点
  689. state.problemAnalysisData.changeHeaderList = changeHeaderList;
  690. state.problemAnalysisData.childHeaderList = data.childHeaderList || [];
  691. state.chartKey++;
  692. //Y轴数据
  693. let chartData: any[] = [];
  694. let legendList: any[] = [];
  695. const isHasEstimatedScore = state.problemAnalysisData.headerList.find(
  696. (item: any) => item.prop == "estimatedScore",
  697. ); //是否存在预估满分
  698. chartData = questionList.map((item: any) => {
  699. return isHasEstimatedScore
  700. ? [item.questionName, item.estimatedScoreRate]
  701. : [item.questionName];
  702. });
  703. questionList.forEach((ques: any, key: number) => {
  704. const scoreRateArr = ques.classList.map(
  705. (item: any) => item?.questionStats?.scoreRate || 0,
  706. );
  707. chartData[key].push(...scoreRateArr);
  708. });
  709. let chartTitle: any[] = [],
  710. titleType: any[] = [],
  711. classSelectLegend: any[] = [];
  712. const newChangeHeaderList = isHasEstimatedScore
  713. ? [
  714. { ...isHasEstimatedScore, isG: false, type: 1 },
  715. ...changeHeaderList,
  716. ]
  717. : [...changeHeaderList];
  718. newChangeHeaderList.forEach((item: any) => {
  719. chartTitle.push(item.label);
  720. titleType.push(item.type ? item.type : ""); //1柱状图 2折线
  721. if (
  722. item.prop != "0" &&
  723. item.prop != "estimatedScore" &&
  724. item.prop.indexOf("school_group") == -1
  725. ) {
  726. classSelectLegend.push(item.label);
  727. }
  728. });
  729. chartTitle.unshift("group");
  730. if (analysisStore.filterObject.classLevel != 2) {
  731. //0 年级 1 组合班级 2具体班级
  732. let startIndex = 1,
  733. endIndex = 3;
  734. if (analysisStore.filterObject.schoolLevel == 2) {
  735. //0-联考 1-学校分组 2-具体学校
  736. startIndex =
  737. titleType.lastIndexOf(1) > -1 ? titleType.lastIndexOf(1) + 1 : 1;
  738. endIndex = titleType.indexOf(2) > -1 ? titleType.indexOf(2) + 2 : 3; //单校时显示联校、组合校、年级是柱子;班级组合、班级是折线。
  739. } else {
  740. //联校 组合学校 默认当前的为第一个选中的柱子
  741. const barFirtIndex =
  742. titleType.lastIndexOf(1) > -1 ? titleType.lastIndexOf(1) + 1 : 1;
  743. startIndex = barFirtIndex;
  744. endIndex = barFirtIndex + 2;
  745. }
  746. legendList =
  747. chartTitle.length > 1 ? chartTitle.slice(startIndex, endIndex) : [];
  748. state.problemAnalysisData.showBarLegendIndex = endIndex - 2;
  749. } else {
  750. //单班 联校和组合学校不默认显示
  751. legendList = classSelectLegend;
  752. state.problemAnalysisData.showBarLegendIndex =
  753. changeHeaderList.length - 1;
  754. }
  755. chartData.unshift(chartTitle); // 柱状图 图例标题
  756. chartData.pop(); // 删除最后一行 全卷
  757. state.problemAnalysisData.data = chartData;
  758. state.problemAnalysisData.legendList = legendList;
  759. state.problemAnalysisData.defaultLegendList = cloneDeep(legendList);
  760. //小题分析 /第N题
  761. GetQuestionStatsData(0);
  762. // 获取项目分析表
  763. GetMajorTableData();
  764. } else {
  765. state.problemAnalysisData.groupList = [];
  766. state.problemAnalysisData.groupTableList = [];
  767. state.problemAnalysisData.questionList = [];
  768. state.problemAnalysisData.questionTableList = [];
  769. state.problemAnalysisData.showBarLegendIndex = 1;
  770. state.problemAnalysisData.headerList = [];
  771. state.problemAnalysisData.changeHeaderList = [];
  772. state.problemAnalysisData.childHeaderList = [];
  773. state.questionScoreStatsData.datax = [];
  774. state.questionScoreStatsData.datay = [];
  775. state.questionScoreStatsData.dataStackY = [];
  776. state.questionScoreStatsData.tooltipData = [];
  777. state.questionScoreStatsData.rate = 0;
  778. state.questionScoreStatsData.maxClass = "";
  779. state.questionScoreStatsData.minClass = "";
  780. state.questionAnswerData.datax = [];
  781. state.questionAnswerData.datay = [];
  782. state.questionAnswerData.answerValue = "";
  783. state.questionAnswerData.answerScore = [];
  784. state.questionAnswerData.questionType = "";
  785. state.questionAnswerData.fullMark = "";
  786. state.questionAnswerData.tableData = [];
  787. state.questionAnswerData.classListIndex = 0;
  788. state.majorAnswerData.tableData = [];
  789. state.majorAnswerData.paperUrl = "";
  790. state.majorAnswerData.rowIndex = 0;
  791. state.majorStudentData.tableData = [];
  792. state.majorStudentData.legendList = [];
  793. state.majorStudentData.radarChartData = [];
  794. state.majorStudentData.excellentCourseList = "";
  795. state.majorStudentData.inferiorCourseList = "";
  796. state.majorTableData.tableData = [];
  797. state.majorTableData.headerData = [];
  798. state.majorTableData.changeHeaderData = [];
  799. state.majorTableData.childHeaderData = [];
  800. state.majorTableData.pageSize = 10;
  801. state.majorTableData.total = 0;
  802. state.majorTableData.currentPage = 1;
  803. }
  804. })
  805. .finally(() => {
  806. state.dataLoading = false;
  807. });
  808. };
  809. // 点击柱状图折线图
  810. const HandleChartClick = (index: any, name: any) => {
  811. GetQuestionStatsData(index); //小题分析
  812. };
  813. // 获取小题分析 /第N题
  814. const GetQuestionStatsData = (index: any) => {
  815. const questionData = cloneDeep(state.problemAnalysisData.questionList[index]);
  816. state.problemAnalysisData.questionListIndex = index;
  817. state.questionTitle = questionData?.questionName || "";
  818. if (questionData) {
  819. state.questionScoreStatsData.datax = []; // x轴数据
  820. state.questionScoreStatsData.datay = []; // Y轴数据
  821. state.questionScoreStatsData.dataStackY = []; // Y轴数据
  822. state.questionScoreStatsData.tooltipData = []; // 提示框内容
  823. let dataStackY: any[] = [];
  824. const isHasEstimatedScore = state.problemAnalysisData.headerList.find(
  825. (item: any) => item.prop == "estimatedScore",
  826. ); //是否存在预估满分
  827. if (questionData.classList.length > 1) {
  828. const key = state.problemAnalysisData.showBarLegendIndex;
  829. state.questionScoreStatsData.markLineData = []; //辅助线
  830. const classList = questionData?.classList || [];
  831. if (
  832. analysisStore.filterObject.classLevel == 0 ||
  833. analysisStore.filterObject.classLevel == 1
  834. ) {
  835. //0 年级 1 组合班级 2具体班级
  836. state.questionScoreStatsData.rate = Number(
  837. classList?.[key - 1]?.questionStats?.scoreRate || 0,
  838. );
  839. } else {
  840. state.questionScoreStatsData.rate = Number(
  841. classList?.[key]?.questionStats?.scoreRate || 0,
  842. );
  843. }
  844. //辅助线
  845. classList.forEach((item: any, index: number) => {
  846. const keyIndex =
  847. analysisStore.filterObject.classLevel == 0 ||
  848. analysisStore.filterObject.classLevel == 1
  849. ? key - (isHasEstimatedScore ? 2 : 1)
  850. : key;
  851. if (index <= keyIndex) {
  852. const rate = Number(item?.questionStats?.scoreRate || 0);
  853. state.questionScoreStatsData.markLineData.push({
  854. legendName: item.groupName,
  855. value: rate,
  856. isShow: index == keyIndex ? true : false, //是否显示
  857. });
  858. }
  859. });
  860. questionData.classList = questionData.classList.slice(
  861. isHasEstimatedScore ? key - 1 : key,
  862. ); // 取折线图数据
  863. } else {
  864. state.questionScoreStatsData.rate = 60;
  865. }
  866. questionData.classList.forEach((item: any) => {
  867. state.questionScoreStatsData.datax.push(item.groupName);
  868. state.questionScoreStatsData.datay.push(item.questionStats.scoreRate);
  869. dataStackY.push(item.questionStats.lossRate);
  870. state.questionScoreStatsData.tooltipData.push({
  871. list: [
  872. {
  873. name: "失分率",
  874. value: `${item.questionStats.lossRate}%`,
  875. },
  876. ],
  877. });
  878. });
  879. // 获取最大值
  880. const max = Math.max(...state.questionScoreStatsData.datay);
  881. // 获取最小值
  882. const min = Math.min(...state.questionScoreStatsData.datay);
  883. const maxValue = max.toFixed(2);
  884. const minValue = min.toFixed(2);
  885. let maxClass: any[] = [],
  886. minClass: any[] = [];
  887. state.questionScoreStatsData.datay.forEach((item: any, index: number) => {
  888. if (Number(item) == Number(maxValue)) {
  889. maxClass.push(state.questionScoreStatsData.datax[index]);
  890. }
  891. if (Number(item) == Number(minValue)) {
  892. minClass.push(state.questionScoreStatsData.datax[index]);
  893. }
  894. });
  895. state.questionScoreStatsData.minClass = minClass.join("、");
  896. state.questionScoreStatsData.maxClass = maxClass.join("、");
  897. state.questionScoreStatsData.dataStackY = [
  898. state.questionScoreStatsData.datay,
  899. dataStackY,
  900. ];
  901. }
  902. console.log("打印questionScoreStatsData1111", state.questionScoreStatsData);
  903. // 获取小题分析 /第N题 / 第N班
  904. GetQuestionAnswerData(state.problemAnalysisData.showBarLegendIndex);
  905. };
  906. //切换 获取小题分析 /第N题 获取第N班答题列表
  907. const HandleQuestionScoreChartClick = (index: any) => {
  908. GetQuestionAnswerData(index + state.problemAnalysisData.showBarLegendIndex);
  909. };
  910. // 获取小题分析 /第N题 / 第N班 选项
  911. const GetQuestionAnswerData = (index: any) => {
  912. const isHasEstimatedScore = state.problemAnalysisData.headerList.find(
  913. (item: any) => item.prop == "estimatedScore",
  914. ); //是否存在预估满分
  915. const newINdex = isHasEstimatedScore ? index - 1 : index;
  916. const classList =
  917. state.problemAnalysisData.questionList?.[
  918. state.problemAnalysisData.questionListIndex
  919. ]?.classList?.[newINdex];
  920. state.questionAnswerData.answerValue =
  921. state.problemAnalysisData.questionList[
  922. state.problemAnalysisData.questionListIndex
  923. ].answerValue; //正确答案
  924. state.questionAnswerData.questionType =
  925. state.problemAnalysisData.questionList[
  926. state.problemAnalysisData.questionListIndex
  927. ].questionType; //类型
  928. state.questionAnswerData.fullMark =
  929. state.problemAnalysisData.questionList[
  930. state.problemAnalysisData.questionListIndex
  931. ].fullMark; //满分
  932. state.questionAnswerData.classListIndex = newINdex;
  933. if (classList) {
  934. const answerList = classList.questionStats.answerList || [];
  935. state.classTitle = classList.groupName;
  936. state.questionAnswerData.datax = []; // x轴数据
  937. state.questionAnswerData.datay = []; // Y轴数据
  938. let sum = 0;
  939. answerList.forEach((item: any) => {
  940. sum += item.studentNum;
  941. state.questionAnswerData.datax.push(item.name);
  942. state.questionAnswerData.datay.push(item.studentNum);
  943. state.questionAnswerData.answerScore.push(item.score);
  944. });
  945. state.questionAnswerData.tableData = [
  946. {
  947. title: "得分率",
  948. value: `${classList.questionStats.scoreRate}%`,
  949. },
  950. {
  951. title: "平均分",
  952. value: `${classList.questionStats.averageScore}`,
  953. },
  954. {
  955. title: "最高分",
  956. value: `${classList.questionStats.maxScore}`,
  957. },
  958. {
  959. title: "最低分",
  960. value: `${classList.questionStats.minScore}`,
  961. },
  962. {
  963. title: "人数",
  964. value: `${sum}人`,
  965. },
  966. ];
  967. if (analysisStore.filterObject.schoolLevel == 2) {
  968. //单校时展示
  969. // 获取答题情况
  970. GetAnswerListByAnswerAndScore(
  971. 0,
  972. answerList && answerList[0] ? answerList[0].name : "",
  973. );
  974. }
  975. }
  976. };
  977. // 点击柱状图小题分析 /第N题 / 第N班 选项 获取答题情况
  978. const HandleQuestionAnswerChartClick = (index: any, name: any) => {
  979. if (analysisStore.filterObject.schoolLevel == 2) {
  980. //单校时展示
  981. GetAnswerListByAnswerAndScore(index, name);
  982. }
  983. };
  984. //通过答案或者分数查询某题作答情况
  985. const GetAnswerListByAnswerAndScore = (index: any, name: any) => {
  986. state.optionTitle = name; //选项名称
  987. const question =
  988. state.problemAnalysisData.questionList[
  989. state.problemAnalysisData.questionListIndex
  990. ];
  991. const classItem = question.classList[state.questionAnswerData.classListIndex];
  992. const classItemKeys = Object.keys(classItem);
  993. const reportParam: any = {
  994. ...analysisStore.filterObject,
  995. };
  996. Object.keys(analysisStore.filterObject).forEach((item) => {
  997. if (classItemKeys.indexOf(item) > -1) {
  998. reportParam[item] = classItem[item];
  999. }
  1000. });
  1001. const answer =
  1002. question.classList[state.questionAnswerData.classListIndex].questionStats
  1003. .answerList[index];
  1004. const params = {
  1005. ...reportParam,
  1006. questionId: question.questionId, // 试题id
  1007. registrationCodeList: answer?.registrationCodeList || [], // 学生账号数组
  1008. };
  1009. state.cardQuestionId = params.questionId; // 批量查看答题卡试题id
  1010. state.cardRegistrationCodeList = params.registrationCodeList; // 批量查看答题卡学生账号数组
  1011. queryAnswerListByAnswerAndScore(params).then((res: any) => {
  1012. if (res.code == 200) {
  1013. state.majorAnswerData.tableData = res.data || [];
  1014. HandleRowClick(
  1015. state.majorAnswerData.tableData.length > 0
  1016. ? state.majorAnswerData.tableData[0]
  1017. : {},
  1018. );
  1019. } else {
  1020. state.majorAnswerData.tableData = [];
  1021. }
  1022. });
  1023. };
  1024. // 点击某行学生某题作答情况
  1025. const HandleRowClick = (row: any) => {
  1026. console.log("row", row);
  1027. if (row?.studentRegistrationCode) {
  1028. //答题卡
  1029. const question =
  1030. state.problemAnalysisData.questionList[
  1031. state.problemAnalysisData.questionListIndex
  1032. ];
  1033. state.paperInfos = {
  1034. examPaperId: analysisStore.filterObject.subjectId, //考试科目id
  1035. platformNumber: row.studentRegistrationCode, //学籍号平台号
  1036. questionId: question.questionId, //题目id
  1037. };
  1038. state.majorAnswerData.rowIndex = state.majorAnswerData.tableData.findIndex(
  1039. (item: any) => item.studentRegistrationCode == row?.studentRegistrationCode,
  1040. );
  1041. } else {
  1042. state.paperInfos = {};
  1043. }
  1044. };
  1045. // 获取项目分析表
  1046. const GetMajorTableData = () => {
  1047. state.majorTableData.tableKey += 1;
  1048. state.majorTableData.headerData = state.problemAnalysisData.headerList;
  1049. state.majorTableData.changeHeaderData =
  1050. state.problemAnalysisData.changeHeaderList;
  1051. state.majorTableData.childHeaderData =
  1052. state.problemAnalysisData.childHeaderList;
  1053. const headerPropData = state.problemAnalysisData.headerList.map(
  1054. (item: any) => item.prop,
  1055. ); //表头字段名
  1056. const childHeaderPropData = state.problemAnalysisData.childHeaderList.map(
  1057. (item: any) => item.prop,
  1058. ); //动态表头字段名
  1059. let allTableData: any[] = [];
  1060. const allList = state.problemAnalysisData.questionTableList;
  1061. allList.forEach((item: any) => {
  1062. let itemObj: any = {
  1063. questionId: item?.questionId || "",
  1064. knowledgeId: item?.knowledgeId || "",
  1065. };
  1066. const classList = item.classList;
  1067. headerPropData.forEach((title: any) => {
  1068. itemObj[title] = Array.isArray(item[title])
  1069. ? item[title].join("、")
  1070. : item[title];
  1071. });
  1072. classList.forEach((el: any) => {
  1073. if (
  1074. el.questionStats?.headDataBOList &&
  1075. el.questionStats.headDataBOList.length > 0
  1076. ) {
  1077. el.questionStats.headDataBOList.forEach((bo: any) => {
  1078. el.questionStats[`${bo.name}Rate`] = bo.rate;
  1079. el.questionStats[`${bo.name}StudentNumber`] = bo.studentNumber;
  1080. });
  1081. } else {
  1082. el.questionStats = [];
  1083. }
  1084. childHeaderPropData.forEach((field: any) => {
  1085. itemObj[`${el.groupId}_${field}`] = el.questionStats[field];
  1086. });
  1087. });
  1088. allTableData.push(itemObj);
  1089. });
  1090. state.majorTableData.total = allTableData.length; //总条数
  1091. state.majorTableData.allTableData = allTableData;
  1092. GetPageMajorTableData();
  1093. //重置表格滚动条位置
  1094. ResetTableScroll(); //重置表格滚动条位置
  1095. };
  1096. //重置表格滚动条位置
  1097. const ResetTableScroll = () => {
  1098. nextTick(() => {
  1099. if (majorTable.value) {
  1100. const tableBody = majorTable.value.$el.querySelector(
  1101. ".el-table__body-wrapper",
  1102. );
  1103. if (tableBody) {
  1104. tableBody.scrollTop = 0; //清除纵向滚动条位置
  1105. tableBody.scrollLeft = 0; // 清除横向滚动条位置
  1106. }
  1107. }
  1108. });
  1109. };
  1110. // 分页获取分析表
  1111. const GetPageMajorTableData = () => {
  1112. const start =
  1113. (state.majorTableData.currentPage - 1) * state.majorTableData.pageSize;
  1114. const end = start + state.majorTableData.pageSize;
  1115. state.majorTableData.tableData = state.majorTableData.allTableData.slice(
  1116. start,
  1117. end,
  1118. );
  1119. };
  1120. //设置表头字段显示隐藏
  1121. const SetEnterHeaderData = (data: any) => {
  1122. if (data.static && data.static.length > 0) {
  1123. state.problemAnalysisData.headerList = [...data.static];
  1124. }
  1125. if (data.dynamisc && data.dynamisc.length > 0) {
  1126. state.problemAnalysisData.changeHeaderList = [...data.dynamisc];
  1127. }
  1128. if (data.child && data.child.length > 0) {
  1129. state.problemAnalysisData.childHeaderList = [...data.child];
  1130. }
  1131. GetMajorTableData();
  1132. };
  1133. // 人员弹框
  1134. const OpenStudentDialog = (childHeader: any, parent: any, row: any) => {
  1135. if (
  1136. (childHeader.prop.indexOf("Count") > -1 ||
  1137. childHeader.prop.indexOf("Number") > -1) &&
  1138. row?.[`${parent.prop}_${childHeader.prop}`] > 0
  1139. ) {
  1140. state.dialogData.showDialog = true;
  1141. state.dialogData.title = childHeader.label;
  1142. state.dialogData.tableTitle = parent.label;
  1143. state.dialogData.fiveRateName = "";
  1144. if (
  1145. childHeader.prop == "topStudentNumber" ||
  1146. childHeader.prop == "excellentStudentNumber" ||
  1147. childHeader.prop == "goodStudentNumber" ||
  1148. childHeader.prop == "passStudentNumber" ||
  1149. childHeader.prop == "lowStudentNumber"
  1150. ) {
  1151. state.dialogData.fiveRateName = childHeader.label.replace(/人数/g, ""); //当前选择的五率的名称
  1152. }
  1153. state.dialogData.selectSubjectName = analysisStore.filterObject.subjectName; //当前选择的科目名称
  1154. if (parent.prop == "0") {
  1155. state.dialogData.selectSchoolLevel = 0; //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  1156. state.dialogData.selectSchoolName = parent.label; //当前选择的学校名称:联校 组合学校 单校名称
  1157. state.dialogData.selectClassLevel = 0; //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  1158. state.dialogData.selectClassName = "年级"; //当前选择的班级名称:年级 组合班级 单班
  1159. } else if (parent.prop.indexOf("school_group") > -1) {
  1160. state.dialogData.selectSchoolLevel = 1; //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  1161. state.dialogData.selectSchoolName = parent.label; //当前选择的学校名称:联校 组合学校 单校名称
  1162. state.dialogData.selectClassLevel = 0; //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  1163. state.dialogData.selectClassName = "年级"; //当前选择的班级名称:年级 组合班级 单班
  1164. } else if (
  1165. parent.prop.indexOf("school") > -1 &&
  1166. parent.prop.indexOf("school_group") == -1
  1167. ) {
  1168. state.dialogData.selectSchoolLevel = 2; //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  1169. state.dialogData.selectSchoolName = parent.label; //当前选择的学校名称:联校 组合学校 单校名称
  1170. state.dialogData.selectClassLevel = 0; //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  1171. state.dialogData.selectClassName = "年级"; //当前选择的班级名称:年级 组合班级 单班
  1172. } else if (parent.prop.indexOf("class_group") > -1) {
  1173. state.dialogData.selectSchoolLevel = 2; //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  1174. state.dialogData.selectSchoolName = analysisStore.filterObject.schoolName; //当前选择的学校名称:联校 组合学校 单校名称
  1175. state.dialogData.selectClassLevel = 1; //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  1176. state.dialogData.selectClassName = parent.label; //当前选择的班级名称:年级 组合班级 单班
  1177. } else {
  1178. state.dialogData.selectSchoolLevel = 2; //当前选择的学校级别:0-联考 1-学校分组 2-具体学校
  1179. state.dialogData.selectSchoolName = analysisStore.filterObject.schoolName; //当前选择的学校名称:联校 组合学校 单校名称
  1180. state.dialogData.selectClassLevel = 2; //当前选择的班级级别:0-年级 1-组合班级 2-具体班级
  1181. state.dialogData.selectClassName = parent.label; //当前选择的班级名称:年级 组合班级 单班
  1182. }
  1183. state.dialogData.questionId = row.questionId; //试题ID
  1184. state.dialogData.isPaper = row.questionName == "全卷" ? 1 : 0; //是否为全卷0-非1-是全卷
  1185. if (childHeader.prop == "fullMarkCount") {
  1186. state.dialogData.quesScoreType = 0; //选择的类型0-满分人数 1-0分人数 3-优秀率、良好率等
  1187. } else if (childHeader.prop == "zeroMarkCount") {
  1188. state.dialogData.quesScoreType = 1; //选择的类型0-满分人数 1-0分人数 3-优秀率、良好率等
  1189. } else {
  1190. state.dialogData.quesScoreType = 3; //选择的类型0-满分人数 1-0分人数 3-优秀率、良好率等
  1191. }
  1192. state.dialogData.knowledgeId = row.knowledgeId; //如果选择的是知识点,则需要返回知识点ID
  1193. state.dialogData.questionGroupName = row?.groupName || ""; //试题分组的名称
  1194. state.dialogData.groupTitle = state.groupTitle.replace(/分析/g, "");
  1195. }
  1196. };
  1197. // 关闭人员弹框
  1198. const CloseDialog = (val: any) => {
  1199. state.dialogData.showDialog = val;
  1200. };
  1201. // 分页获取分析表
  1202. const ChangeCurrentPage = (val: any) => {
  1203. state.majorTableData.currentPage = val;
  1204. GetMajorTableData(); //加载分析表格数据
  1205. };
  1206. const ChangePageSize = (val: number) => {
  1207. state.majorTableData.pageSize = val;
  1208. state.majorTableData.currentPage = 1;
  1209. GetMajorTableData(); //加载分析表格数据
  1210. };
  1211. // 导出Excel
  1212. const ExportExcel = () => {
  1213. // 1. 设置加载状态
  1214. reportModuleRef.value?.SetExportLoading?.(true);
  1215. // 2. 参数
  1216. const examName = getExamName.value;
  1217. let params: any = {
  1218. fileName: `${GetExcelFileName(examName, analysisStore.filterObject, state.groupTitle)}`,
  1219. examName: examName, //考试名称
  1220. sheetName: state.groupTitle, //sheet页名称
  1221. };
  1222. const staticHeaderData = state.problemAnalysisData.headerList.filter(
  1223. (item: any) => item.display,
  1224. );
  1225. const childHeaderData = state.problemAnalysisData.childHeaderList.filter(
  1226. (item: any) => item.display,
  1227. );
  1228. const dynamicsHeaderData = state.problemAnalysisData.changeHeaderList.filter(
  1229. (item: any) => item.display,
  1230. );
  1231. params.staticHeaderData = staticHeaderData;
  1232. params.childHeaderData = childHeaderData;
  1233. params.dynamicsHeaderData = dynamicsHeaderData;
  1234. let dataList: any[] = [];
  1235. state.majorTableData.allTableData.forEach((item: any) => {
  1236. const rowData: any[] = [];
  1237. staticHeaderData.forEach((header: any) => {
  1238. rowData.push(item?.[header.prop] || "-");
  1239. });
  1240. dynamicsHeaderData.forEach((parent: any) => {
  1241. childHeaderData.forEach((child: any) => {
  1242. const itemValue = item[`${parent.prop}_${child.prop}`];
  1243. if (child.prop.indexOf("Rate") > -1) {
  1244. const rate = itemValue ? `${itemValue}%` : "-";
  1245. rowData.push(rate);
  1246. } else {
  1247. rowData.push(itemValue ?? "-");
  1248. }
  1249. });
  1250. });
  1251. dataList.push(rowData);
  1252. });
  1253. params.dataList = dataList;
  1254. // 3. 调用通用下载方法,并在完成后重置加载状态
  1255. downloadExcel(publicExport, params).finally(() => {
  1256. reportModuleRef.value?.SetExportLoading?.(false);
  1257. });
  1258. };
  1259. //设置表头样式
  1260. const HeaderRowStyle = ({ row, rowIndex }: any) => {
  1261. if (rowIndex === 1) {
  1262. return {
  1263. display: "none",
  1264. };
  1265. }
  1266. };
  1267. const TableRowClassName = ({ row, rowIndex }: any) => {
  1268. if (rowIndex === state.majorAnswerData.rowIndex) {
  1269. return "current-row";
  1270. }
  1271. return "";
  1272. };
  1273. //查看答题卡
  1274. const handleClick = (row: any) => {
  1275. state.paperInfo = {
  1276. examPaperId: analysisStore.filterObject.subjectId, //考试科目id
  1277. platformNumber: row.studentRegistrationCode, //学籍号平台号
  1278. questionId: "", //题目id
  1279. };
  1280. state.paperTitle = `${getExamName.value}-${analysisStore.filterObject.subjectName}-${row.className}-${row.studentUserName}`; //学生姓名
  1281. state.showStudentPaperDialog = true;
  1282. };
  1283. //更新弹窗状态
  1284. const UpdateModelValue = (val: boolean) => {
  1285. state.showStudentPaperDialog = val;
  1286. };
  1287. //批量查看小题答题卡
  1288. const VisibleQuestionCard = () => {
  1289. state.showQuestionCardDialog = true;
  1290. };
  1291. //关闭弹框
  1292. const CloseQuestionCardDialog = () => {
  1293. state.showQuestionCardDialog = false;
  1294. };
  1295. const pageInit = () => {
  1296. state.problemAnalysisData.chartTypeList =
  1297. analysisStore.filterObject.classLevel != 2
  1298. ? [
  1299. { label: "组合图", value: "line_bar_chart" },
  1300. { label: "柱状图", value: "vertical_bar" },
  1301. { label: "雷达图", value: "radar_chart" },
  1302. ]
  1303. : [
  1304. { label: "柱状图", value: "vertical_bar" },
  1305. { label: "雷达图", value: "radar_chart" },
  1306. ];
  1307. state.problemAnalysisData.chartType =
  1308. analysisStore.filterObject.classLevel != 2
  1309. ? "line_bar_chart"
  1310. : "vertical_bar";
  1311. state.questionScoreStatsData.chartType = "vertical_bar";
  1312. state.majorTableData.currentPage = 1;
  1313. state.majorAnswerData.rowIndex = 0;
  1314. GetQuestionAnalysisData(); //获取小题分析数据
  1315. };
  1316. // 监听筛选条件
  1317. watch(
  1318. () => analysisStore.filterObject,
  1319. async () => {
  1320. pageInit();
  1321. },
  1322. { deep: true },
  1323. );
  1324. onMounted(() => {
  1325. pageInit();
  1326. });
  1327. </script>
  1328. <style lang="scss" scoped>
  1329. .content_left {
  1330. &.answer {
  1331. width: calc(100% - 220px);
  1332. }
  1333. &.paper_card {
  1334. width: calc(100% - 480px);
  1335. height: 400px;
  1336. background-color: #f5f5f5;
  1337. border-radius: 10px;
  1338. }
  1339. }
  1340. .content_right {
  1341. height: 100%;
  1342. display: flex;
  1343. align-items: center;
  1344. margin: auto 0 auto auto;
  1345. padding-bottom: 0;
  1346. &.answer {
  1347. width: 200px;
  1348. }
  1349. &.paper_card {
  1350. width: 460px;
  1351. }
  1352. :deep(.el-table) {
  1353. border-left: 0px;
  1354. border-right: 0px;
  1355. .el-table__cell {
  1356. height: 44px;
  1357. }
  1358. }
  1359. }
  1360. </style>