studentReport.vue 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  1. <template>
  2. <!-- 学生报告 -->
  3. <BookFlip v-loading="loading" element-loading-spinner="el-icon-loading" element-loading-background="rgba(255, 255, 255, 0.5)" :element-loading-text="loadingText" :book-pages="bookPageImages" bookBg="student" :requestLoading="loading" :openLoading="openLoading" :coverTitle="`${stuClasName}${studentName}分析报告册`" subtitle="供参考学生使用" ref="bookFlipBox" @OpenBookImages="OpenBookImages" @PdfLoadEnd="PdfLoadEnd">
  4. <!-- 自定义每页内容 -->
  5. <template #default="slotProps">
  6. <template v-if="slotProps.type == 'web_mode'">
  7. <div class="area_page" style="position: absolute;top: -9999999px;z-index: -10;height: auto;min-height: 1285px;">
  8. <!-- 用于获取div的高度 默认隐藏不显示 -->
  9. <div class="area_title" ref="areaReportTitle">
  10. <p>{{ reportTitle }}</p>
  11. <p>{{ stuClasName }}{{ studentName }}分析报告</p>
  12. </div>
  13. <div class="area_module" ref="standardScoreChartDes">
  14. <div class="area_module_describe" v-if="multiSubjectData.maxSubject || multiSubjectData.minSubject" style="margin-top: 0;">
  15. 说明:从标准分情况来看,这次考试<template v-if="multiSubjectData.maxSubject"><span style="color: #3ba272">{{ multiSubjectData.maxSubject }}</span>表现突出,请继续保持</template><template v-if="multiSubjectData.minSubject">;<span style="color: #ee6666">{{ multiSubjectData.minSubject }}</span>标准分明显低于其他学科,可能会对总体排名造成影响,可结合错题梳理核心知识点,精准定位薄弱环节,制定针对性的提升计划,以实现各科均衡发展,进一步巩固整体成绩</template>。
  16. </div>
  17. </div>
  18. <div class="area_module" ref="multiSuggestionModule">
  19. <div class="area_module_title">总结建议</div>
  20. <div class="area_module_describe" style="margin-top: 0;" v-html="suggestionHtml"></div>
  21. <div class="pring_jg"></div>
  22. </div>
  23. <template v-for="(subject,subKey) in multiSubjectData.singleSubject">
  24. <div class="area_module" :ref="`singleSubjectSuggestion_${subKey}`" v-if="singleSubjectData?.[subKey]?.suggestionHtml">
  25. <div class="area_module_title">总结建议</div>
  26. <div class="area_module_describe" style="margin-top: 0;" v-html="singleSubjectData?.[subKey]?.suggestionHtml"></div>
  27. <div class="pring_jg"></div>
  28. </div>
  29. </template>
  30. <!-- 知识点分层 -->
  31. <template v-for="know in knowLedgeLayeringData">
  32. <div class="area_module" :ref="`knowLedgeLayering_${know.subjectCode}`">
  33. <div class="area_module_title">{{know.groupName}}分层分析</div>
  34. <div class="area_module_table">
  35. <ul class="student_know_paper">
  36. <li>
  37. <div class="li_left">
  38. <span>满分区</span>
  39. <span>(得满分的知识点)</span>
  40. </div>
  41. <div class="li_know">{{ know.knowLedgeLayering.fullScore }}{{ know.knowLedgeLayering.fullScore ? '。':'' }}</div>
  42. </li>
  43. <li>
  44. <div class="li_left">
  45. <span>突破升级区</span>
  46. <span>(得分率高于同层次,但低于上一层次平均水平的知识点)</span>
  47. </div>
  48. <div class="li_know">{{ know.knowLedgeLayering.breakThrough }}{{ know.knowLedgeLayering.breakThrough ? '。':'' }}</div>
  49. </li>
  50. <li>
  51. <div class="li_left">
  52. <span>就近发展区</span>
  53. <span>(得分率低于同层次平均水平的知识点)</span>
  54. </div>
  55. <div class="li_know">{{ know.knowLedgeLayering.develop }}{{ know.knowLedgeLayering.develop ? '。':'' }}</div>
  56. </li>
  57. </ul>
  58. </div>
  59. <div class="pring_jg"></div>
  60. </div>
  61. </template>
  62. </div>
  63. <div class="area_page web_area_page" v-for="page in pageCount" :key="`${pageKey}_${page}`">
  64. <template v-if="page == 1">
  65. <div class="area_title">
  66. <p>{{ reportTitle }}</p>
  67. <p>{{ stuClasName }}{{ studentName }}分析报告</p>
  68. </div>
  69. <div class="area_header bg_purple">
  70. <img :src="headerLeftIcon" class="header_icon_left" />
  71. 总分成绩分析
  72. <img :src="headerRightIcon" class="header_icon_right" />
  73. </div>
  74. <div class="pring_jg"></div>
  75. </template>
  76. <template v-for="(tableData,index) in multiSubjectData.tableList">
  77. <template v-for="(itemTable,itemIndex) in tableData">
  78. <div class="area_module" v-if="multiSubjectData.tablePagesNum[index][itemIndex] == page && itemTable.length > 0">
  79. <div class="area_module_title">成绩单</div>
  80. <div class="area_module_table">
  81. <el-table border :data="itemTable" stripe align="center">
  82. <el-table-column v-for="header in (multiSubjectData?.staticHeaderData ?? [])" align="center" :label="header.name" min-width="100" show-overflow-tooltip>
  83. <template slot-scope="scope">
  84. {{ scope.row?.[header.prop] || '-' }}
  85. </template>
  86. </el-table-column>
  87. <el-table-column v-for="header in (multiSubjectData?.headerList?.[index]?.[itemIndex] ?? [])" align="center" :label="header.name" min-width="100" show-overflow-tooltip>
  88. <template slot-scope="scope">
  89. <template v-if="header.prop == 'score'">
  90. <!-- * 1-得分显示分数,小题分显示分数,2-得分显示分数,小题分显示对错
  91. * 3-得分显示对错,小题分显示分数,4-得分显示对错,小题分显示对错
  92. * 5-得分显示等级,小题分显示分数,6-得分显示等级,小题分显示对错 -->
  93. <template v-if="multiSubjectData.studentOpenness == 3 || multiSubjectData.studentOpenness == 4">
  94. <template v-if="!isNaN(scope.row?.[header.prop])">
  95. <img class="right_or_wrong_icon" v-if="scope.row.fullScore == scope.row?.[header.prop]" src="@/assets/report/score_yes_icon.webp" />
  96. <img class="right_or_wrong_icon" v-else-if="scope.row?.[header.prop] == 0" src="@/assets/report/score_no_icon.webp" />
  97. <img class="right_or_wrong_icon" v-else src="@/assets/report/score_dimidiate_icon.webp" />
  98. </template>
  99. <template v-else>{{ scope.row?.[header.prop] ?? '-' }}</template>
  100. </template>
  101. <template v-else>{{ scope.row?.[header.prop] ?? '-' }}</template>
  102. </template>
  103. <template v-else-if="header.prop == 'groupClassRanks' || header.prop == 'groupClassMaxScoreList' || header.prop == 'groupClassAvgScoreList'">{{ GetGroupClassValue(scope.row?.[header.prop],header.prop,header.code)}}</template>
  104. <template v-else>{{ scope.row?.[header.prop] ?? '-' }}</template>
  105. </template>
  106. </el-table-column>
  107. </el-table>
  108. </div>
  109. </div>
  110. <template v-if="multiSubjectData.tablePagesNum[index][itemIndex] == page && itemTable.length > 0">
  111. <div class="pring_jg" style="height: 29px;border-bottom: 1px solid #F3F3F3;box-sizing: border-box;"></div>
  112. <div class="pring_jg"></div>
  113. </template>
  114. </template>
  115. </template>
  116. <div class="area_module" v-if="multiSubjectData.chartPagesNum==page && ((multiSubjectData.standardScoreAnalysisStatus === 0 && schoolType == 2) || schoolType == 1) && multiSubjectData.datay.length>0">
  117. <div class="area_module_title">标准分分析图</div>
  118. <div class="area_module_chart">
  119. <DifferenceChart v-if="multiSubjectData.datay.length" :datax="multiSubjectData.datax" unit="" :datay="multiSubjectData.datay" :isClick="false" :rate="0" :gridLeft="0" :gridRight="0" :gridTop="20" :fontSize="14" :fontColor="'#333333'" :showDataZoom="false" style="height: 270px !important;min-height: 270px !important;"></DifferenceChart>
  120. </div>
  121. <div class="area_module_describe" v-if="multiSubjectData.maxSubject || multiSubjectData.minSubject">
  122. 说明:从标准分情况来看,这次考试<template v-if="multiSubjectData.maxSubject"><span style="color: #3ba272">{{ multiSubjectData.maxSubject }}</span>表现突出,请继续保持</template><template v-if="multiSubjectData.minSubject">;<span style="color: #ee6666">{{ multiSubjectData.minSubject }}</span>标准分明显低于其他学科,可能会对总体排名造成影响,可结合错题梳理核心知识点,精准定位薄弱环节,制定针对性的提升计划,以实现各科均衡发展,进一步巩固整体成绩</template>。
  123. </div>
  124. <div class="pring_jg"></div>
  125. </div>
  126. <div class="area_module" v-if="historyExamData.pageNum==page && historyExamData.chartData.length > 0 && multiSubjectData.showHistory==1">
  127. <div class="area_module_title">历次标准分追踪分析图</div>
  128. <div class="area_module_chart">
  129. <LineChart v-if="historyExamData.datay.length>0" :datax="historyExamData.datax" :datay="historyExamData.datay" :title="historyExamData.title"
  130. :extraText="false" :showBackground="false" :isShowLabel="true" labelColor="#333333" :legendList="historyExamData.legendList" :tooltipData="historyExamData.tooltipData" :gridLeft="0" :gridRight="0" :gridTop="25" :fontSize="14" :fontColor="'#333333'" :showCheckBox="false" reportHeight="270px" style="min-height:270px!important;">
  131. </LineChart>
  132. </div>
  133. <div class="pring_jg"></div>
  134. </div>
  135. <div class="area_module" v-if="suggestionHtml && multiSuggestionPageNum == page">
  136. <div class="area_module_title">总结建议</div>
  137. <div class="area_module_describe" style="margin-top: 0;" v-html="suggestionHtml"></div>
  138. <div class="pring_jg"></div>
  139. </div>
  140. <!-- 单科 -->
  141. <template v-for="(subject,subKey) in multiSubjectData.singleSubject">
  142. <template v-if="singleSubjectData?.[subKey]?.titlePageNum == page">
  143. <div class="area_header bg_purple">
  144. <img :src="headerLeftIcon" class="header_icon_left" />
  145. {{subject.subjectName}}成绩分析
  146. <img :src="headerRightIcon" class="header_icon_right" />
  147. </div>
  148. <div class="pring_jg"></div>
  149. </template>
  150. <!-- 成绩单 -->
  151. <template v-for="(tableData,index) in (singleSubjectData?.[subKey]?.scrolTableList || [])">
  152. <template v-for="(itemTable,itemIndex) in tableData">
  153. <div class="area_module" v-if="singleSubjectData?.[subKey]?.scrolTablePagesNum?.[index]?.[itemIndex] == page && itemTable.length > 0">
  154. <div class="area_module_title">成绩单</div>
  155. <div class="area_module_table">
  156. <el-table border :data="itemTable" stripe align="center">
  157. <el-table-column v-for="header in (singleSubjectData?.[subKey]?.scrolHeaderList?.[index]?.[itemIndex] ?? [])" align="center" :label="header.name" min-width="100" show-overflow-tooltip>
  158. <template slot-scope="scope">
  159. <template v-if="header.prop=='score'">
  160. <!-- * 1-得分显示分数,小题分显示分数,2-得分显示分数,小题分显示对错
  161. * 3-得分显示对错,小题分显示分数,4-得分显示对错,小题分显示对错
  162. * 5-得分显示等级,小题分显示分数,6-得分显示等级,小题分显示对错 -->
  163. <template v-if="(scope.row.studentOpenness == 3 || scope.row.studentOpenness == 4) && scope.row?.score">
  164. <template v-if="!isNaN(scope?.row?.score)">
  165. <img class="right_or_wrong_icon" v-if="scope.row.fullScore == scope.row.score" src="@/assets/report/score_yes_icon.webp" />
  166. <img class="right_or_wrong_icon" v-else-if="scope.row.score === 0" src="@/assets/report/score_no_icon.webp" />
  167. <img class="right_or_wrong_icon" v-else src="@/assets/report/score_dimidiate_icon.webp" />
  168. </template>
  169. <template v-else>{{ scope.row.score }}</template>
  170. </template>
  171. <template v-else>{{ scope?.row?.[header.prop] ?? '-' }}</template>
  172. </template>
  173. <template v-else-if="header.prop == 'groupClassRanks' || header.prop == 'groupClassMaxScoreList' || header.prop == 'groupClassAvgScoreList'">{{ GetGroupClassValue(scope.row?.[header.prop],header.prop,header.code) }}</template>
  174. <template v-else>{{ scope?.row?.[header.prop] ?? '-' }}</template>
  175. </template>
  176. </el-table-column>
  177. </el-table>
  178. </div>
  179. </div>
  180. <template v-if="singleSubjectData?.[subKey]?.scrolTablePagesNum?.[index]?.[itemIndex] == page && itemTable.length > 0">
  181. <div class="pring_jg" style="height: 29px;border-bottom: 1px solid #F3F3F3;box-sizing: border-box;"></div>
  182. <div class="pring_jg"></div>
  183. </template>
  184. </template>
  185. </template>
  186. <!-- 小题分 大题 知识点 能力要素 自定义分组 -->
  187. <template v-for="group in (singleSubjectData?.[subKey]?.groupQuestionData || [])">
  188. <div class="area_module" v-if="group.chartPagesNum == page && group.datay.length > 0 && group.type!='smallQuestionData'">
  189. <div class="area_module_title">{{group.groupName}}分析图</div>
  190. <div class="area_module_chart" v-if="group.datay.length > 0">
  191. <BarChart v-if="group.type=='bigQuestionData'" :datax="group.datax" :datay="group.datay" unit="" typeName="" :showNuitY="false" :unit="'%'" :showTooltip="false" :isShowMarkLine="false" :gridLeft="0" :gridRight="0" :gridTop="20" :fontSize="14" :fontColor="'#333333'" :showDataZoom="false" style="height: 270px;"></BarChart>
  192. <RadarCharts v-else :showLegend="false" :reportHeight="`300px`" :showDataLabel="true" :showTooltip="false" :data="group.radarChartData" :unit="'%'" :legendList="[]" legendLeft="center" :showCheckBox="false" :openShowAllLegend="false" :showRadiusAxis="false" :fontSize="14" :fontColor="'#333333'" :style="{height: 'auto',minHeight:'100% !important'}"></RadarCharts>
  193. </div>
  194. <div class="pring_jg"></div>
  195. </div>
  196. <template v-for="(tableData,index) in group.tableList">
  197. <template v-for="(itemTable,itemIndex) in tableData">
  198. <div class="area_module" v-if="group.tablePagesNum[index][itemIndex] == page && itemTable.length > 0">
  199. <div class="area_module_title">{{group.groupName}}分析表</div>
  200. <div class="area_module_table">
  201. <el-table border :data="itemTable" stripe align="center">
  202. <el-table-column v-for="header in (group?.staticHeader ?? [])" align="center" :label="header.name" :min-width="header.prop=='smallQuestionNames'?120:90" show-overflow-tooltip>
  203. <template slot-scope="scope">
  204. {{ scope.row[header.prop] || '-' }}
  205. </template>
  206. </el-table-column>
  207. <el-table-column v-for="header in (group?.headerList?.[index]?.[itemIndex] ?? [])" align="center" :label="header.name" :min-width="header.prop=='smallQuestionNames'?120:90" show-overflow-tooltip>
  208. <template slot-scope="scope">
  209. <template v-if="header.prop == 'score'">
  210. <!-- * 1-得分显示分数,小题分显示分数,2-得分显示分数,小题分显示对错
  211. * 3-得分显示对错,小题分显示分数,4-得分显示对错,小题分显示对错
  212. * 5-得分显示等级,小题分显示分数,6-得分显示等级,小题分显示对错 -->
  213. <template v-if="group.studentOpenness == 2 || group.studentOpenness == 4 || group.studentOpenness == 6">
  214. <template v-if="!isNaN(scope?.row?.score)">
  215. <img class="right_or_wrong_icon" v-if="scope.row.fullScore == scope.row.score" src="@/assets/report/score_yes_icon.webp" />
  216. <img class="right_or_wrong_icon" v-else-if="scope.row.score == 0" src="@/assets/report/score_no_icon.webp" />
  217. <img class="right_or_wrong_icon" v-else src="@/assets/report/score_dimidiate_icon.webp" />
  218. </template>
  219. <template v-else>{{ scope?.row?.score ?? '-' }}</template>
  220. </template>
  221. <template v-else>{{ scope.row.score || '-' }}</template>
  222. </template>
  223. <!-- 包含小题 -->
  224. <template v-else-if="header.prop == 'smallQuestionNames' && scope?.row?.[header.prop] && Object.prototype.toString.call(scope.row[header.prop]) == '[object Array]'">
  225. {{ scope.row[header.prop].join('、') }}
  226. </template>
  227. <template v-else-if="header.prop=='scoreRateStr'">
  228. <template v-if="scope?.row?.scoreRate && !isNaN(scope?.row?.scoreRate)">
  229. <span style="color:#EE6666;" v-if="Number(scope?.row?.scoreRate) < 60">{{ scope?.row?.[header.prop] }}</span>
  230. <span style="color:#FAC858;" v-else-if="Number(scope?.row?.scoreRate) >= 60 && Number(scope?.row?.scoreRate) < 80">{{ scope?.row?.[header.prop] }}</span>
  231. <span style="color:#3BA272;" v-else-if="Number(scope?.row?.scoreRate) >= 80 && Number(scope?.row?.scoreRate) <= 100">{{ scope?.row?.[header.prop] }}</span>
  232. <span v-else>{{ scope?.row?.[header.prop] ?? '-'}}</span>
  233. </template>
  234. <template v-else>{{ scope?.row?.[header.prop] ?? '-'}}</template>
  235. </template>
  236. <template v-else-if="header.prop == 'difficultyName'">
  237. <span :class="GetDifficultyClass(scope.row[header.prop])"></span>
  238. <span>{{ GetDifficultyName(scope.row[header.prop]) }}</span>
  239. </template>
  240. <template v-else-if="header.prop == 'classGroupAvgScoreMap' || header.prop == 'classGroupScoreRateMap'">{{ scope.row?.[header.prop]?.[header.code] || '-' }}{{ scope.row?.[header.prop]?.[header.code]&&header.prop=='classGroupScoreRateMap'?'%':''}}</template>
  241. <template v-else>{{ scope.row[header.prop] || '-' }}</template>
  242. </template>
  243. </el-table-column>
  244. </el-table>
  245. </div>
  246. </div>
  247. <template v-if="group.tablePagesNum[index][itemIndex] == page && itemTable.length > 0">
  248. <div class="pring_jg" style="height: 29px;border-bottom: 1px solid #F3F3F3;box-sizing: border-box;"></div>
  249. <div class="pring_jg"></div>
  250. </template>
  251. </template>
  252. </template>
  253. <div class="area_module" v-if="group.type=='knowledgePointQuestionData' && group?.knowLedgeLayering && page == knowLedgeLayeringPageNum[subKey]">
  254. <div class="area_module_title">{{group.groupName}}分层分析</div>
  255. <div class="area_module_table">
  256. <ul class="student_know_paper">
  257. <li>
  258. <div class="li_left">
  259. <span>满分区</span>
  260. <span>(得满分的知识点)</span>
  261. </div>
  262. <div class="li_know">{{ group.knowLedgeLayering.fullScore }}{{ group.knowLedgeLayering.fullScore ? '。':'' }}</div>
  263. </li>
  264. <li>
  265. <div class="li_left">
  266. <span>突破升级区</span>
  267. <span>(得分率高于同层次,但低于上一层次平均水平的知识点)</span>
  268. </div>
  269. <div class="li_know">{{ group.knowLedgeLayering.breakThrough }}{{ group.knowLedgeLayering.breakThrough ? '。':'' }}</div>
  270. </li>
  271. <li>
  272. <div class="li_left">
  273. <span>就近发展区</span>
  274. <span>(得分率低于同层次平均水平的知识点)</span>
  275. </div>
  276. <div class="li_know">{{ group.knowLedgeLayering.develop }}{{ group.knowLedgeLayering.develop ? '。':'' }}</div>
  277. </li>
  278. </ul>
  279. </div>
  280. <div class="pring_jg"></div>
  281. </div>
  282. </template>
  283. <!-- 历次 -->
  284. <div class="area_module" v-if="singleSubjectData?.[subKey]?.historyExamData?.pageNum==page && singleSubjectData[subKey].historyExamData.chartData.length > 0 && singleSubjectData[subKey]?.showHistory==1">
  285. <div class="area_module_title">历次标准分追踪分析图</div>
  286. <div class="area_module_chart">
  287. <LineChart v-if="singleSubjectData?.[subKey]?.historyExamData?.datay.length>0" :datax="singleSubjectData[subKey].historyExamData.datax" :datay="singleSubjectData[subKey].historyExamData.datay" :title="singleSubjectData[subKey].historyExamData.title"
  288. :extraText="false" :showBackground="false" :isShowLabel="true" labelColor="#333333" :legendList="singleSubjectData[subKey].historyExamData.legendList" :tooltipData="singleSubjectData[subKey].historyExamData.tooltipData" :gridLeft="0" :gridRight="0" :gridTop="25" :fontSize="14" :fontColor="'#333333'" :showCheckBox="false" reportHeight="270px" style="min-height:270px!important;">
  289. </LineChart>
  290. </div>
  291. <div class="pring_jg"></div>
  292. </div>
  293. <div class="area_module" v-if="singleSubjectData?.[subKey]?.suggestionHtml && singleSubjectData?.[subKey]?.suggestionPageNum == page">
  294. <div class="area_module_title">总结建议</div>
  295. <div class="area_module_describe" style="margin-top: 0;" v-html="singleSubjectData?.[subKey]?.suggestionHtml"></div>
  296. <div class="pring_jg"></div>
  297. </div>
  298. <!-- 答题卡 -->
  299. <template v-for="(paperItem,paperIndex) in (singleSubjectData?.[subKey]?.paperImageList || [])">
  300. <div class="area_module area_module_img" v-if="singleSubjectData?.[subKey]?.paperImagePageNum?.[paperIndex] == page">
  301. <PaperImage v-if="paperItem.picUrl" :paperImgUrl="paperItem.picUrl" :usedCardType="singleSubjectData?.[subKey]?.usedCardType" :drawData="paperItem.questionVOS || []" :isDrag="false" :isWheel="false" :isShowContextMenu="false" rotateDeg="-90"></PaperImage>
  302. </div>
  303. </template>
  304. </template>
  305. <div class="area_page_number">第 {{ page }} 页</div>
  306. </div>
  307. </template>
  308. <template v-else>
  309. <!-- 生成翻书效果 -->
  310. <div class="gradient"></div>
  311. <img :src="slotProps.content" style="width: 100%;height: 100%;" />
  312. </template>
  313. </template>
  314. </BookFlip>
  315. </template>
  316. <script>
  317. import BookFlip from './components/bookFlip.vue';
  318. import BarChart from "@/views/analysisReport/components/dCharts/barChart"; //单柱状图组件
  319. import RadarCharts from "@/views/analysisReport/components/dCharts/radarCharts";//G10-G1雷达图
  320. import DifferenceChart from "@/views/analysisReport/components/dCharts/differenceChart"; //率差图
  321. import LineChart from "@/views/analysisReport/components/dCharts/lineChart";//折线图
  322. import PaperImage from '@/components/PaperImage.vue';//答题卡
  323. import { mapGetters } from "vuex";
  324. import {getApiName} from '@/utils/common';
  325. // import { jsPDF } from "jspdf";
  326. import html2canvas from "html2canvas";
  327. export default {
  328. components: { BookFlip, BarChart, RadarCharts, DifferenceChart, LineChart,PaperImage},
  329. data() {
  330. return {
  331. pageKey:1,
  332. headerLeftIcon: require("@/assets/report/header_left_student.webp"),
  333. headerRightIcon: require("@/assets/report/header_right_student.webp"),
  334. // 书页数据(长度为4,偶数页)
  335. colors: this.$global.getScorePerformanceAnalysis(),//按顺序显示的20个颜色值
  336. pageCount:15,//页数 第一页不处理
  337. printPageHeight:1245,//A4纸高度 去掉边距 40
  338. chartHeight:270,//echart 高度
  339. moduleHeightData:[],//每个模块的高度
  340. modulePageData:[],//每个模块对应的页码
  341. stuClasName:'',
  342. multiSubjectData: {
  343. tablePagesNum:[],
  344. tableList:[],
  345. headerList:[],
  346. staticHeaderData:[],
  347. singleSubject:[],
  348. standardScoreAnalysisStatus: 0,
  349. studentOpenness: '', //学生信息
  350. datax: [], //图数据
  351. datay: [], //图数据
  352. tooltipData: [],
  353. maxSubject: '',
  354. minSubject: '',
  355. showHistory:0
  356. },//总分成绩分析
  357. historyExamData: {
  358. pageNum:'',
  359. chartData: [],
  360. datax: [],
  361. datay: [],
  362. title: [],
  363. legendList: [],
  364. tooltipData:[]
  365. }, //总分历次信息(联考)
  366. suggestionHtml: null,//总结建议
  367. multiSuggestionPageNum:'',//总分 总结建议
  368. singleSubjectData:[],//单科数据
  369. knowLedgeLayeringData:[],//知识点分层
  370. knowLedgeLayeringPageNum:[],//知识点分层分页
  371. bookPageImages:[],//生成的图片地址
  372. // showReportLoading:false,
  373. targetProgress:0,
  374. timer:null,
  375. loading:true,
  376. loadingText:'拼命加载中(1%)……',
  377. openLoading:false,
  378. };
  379. },
  380. computed: {
  381. reportTitle() {
  382. return this?.$store?.state?.report?.examSelectItem?.examName ?? '';
  383. },
  384. reportParam() {
  385. return {
  386. examLevel: this.$store.state.report.examLevel, // 任务等级联考还是单校
  387. // schoolId: this.$store.state.report.studentReportFilterObject.schoolId, // 学校id
  388. // contrastExamIds: this.$store.state.report.lastExamSelectIds, //多次考试任务对比ID,不包含当前任务ID
  389. // examId: this.$store.state.report.examId, // 当前考试ID
  390. // subjectCode: this.$store.state.report.studentReportFilterObject.subjectCode, //科目code
  391. // subjectGroupType: this.$store.state.report.filterObject.subjectGroupType, // 科目是否为组合
  392. // isTotal: this.$store.state.report.filterObject.isTotal, //是否为总分科目 1为总分 0为非总分
  393. // classIdCode: this.$store.state.report.studentReportFilterObject.classIdCode, // 班级idcode
  394. // classGroupName: this.$store.state.report.studentReportFilterObject.classGroupName, // 班级名称
  395. // registrationName: this.$store.state.report.studentReportFilterObject.registrationName, // 学籍名称
  396. // studentName:this.$store.state.report.studentReportFilterObject.studentName, //学生名称
  397. // registrationCode:this.$store.state.report.studentReportFilterObject.registrationCode //学生学籍号
  398. examLevel: this.$store.state.report.filterObject.examLevel, //1-联考 2-单校
  399. contrastExamIds: this.$store.state.report.filterObject.contrastExamIds, //多次考试任务对比ID,不包含当前任务ID
  400. examId: this.$store.state.report.filterObject.examId, //考试id
  401. subjectCode: 0, //this.$store.state.report.filterObject.subjectCode 科目code
  402. subjectGroupType: this.$store.state.report.filterObject.subjectGroupType, //是否为组合科目 1为组合科目 0为非组合科目
  403. isTotal: this.$store.state.report.filterObject.isTotal //是否为总分科目 1为总分 0为非总分
  404. }
  405. },//分析报告公共参数变量
  406. ...mapGetters(["userInfo"]),
  407. studentName() {
  408. return this.userInfo.userName;
  409. },
  410. schoolType() {
  411. return sessionStorage.getItem('schoolType') //1:单校 2:联校
  412. },
  413. },
  414. watch: {
  415. // 监听 filterObject 对象变化(注意要开启深度监听)
  416. async reportParam() {
  417. // clearTimeout(this.timer); // 清除定时器,停止重复执行
  418. // this.timer = null;
  419. this.PageInit();//初始加载数据
  420. },//监听筛选数据变化
  421. },
  422. async created() {
  423. this.setHtmlFontSize();
  424. // 监听窗口缩放,实时更新
  425. window.addEventListener('resize', this.setHtmlFontSize);
  426. // 可选:监听页面加载完成后再设置一次(避免初始渲染问题)
  427. window.addEventListener('load', this.setHtmlFontSize);
  428. this.PageInit();//页面初始加载数据
  429. },
  430. destroyed(){
  431. // 根组件卸载时销毁监听
  432. window.removeEventListener('resize', this.setHtmlFontSize);
  433. document.documentElement.style.fontSize = '';
  434. },
  435. methods: {
  436. //初始化设置
  437. setHtmlFontSize(){
  438. // 设计稿宽度(根据实际设计稿调整,例如 1920px)
  439. const designWidth = 1920;
  440. // 设计稿中 1rem 对应的 px 值(例如 16px)
  441. const baseFontSize = 16;
  442. // 获取当前浏览器窗口宽度
  443. const windowWidth = document.documentElement.clientWidth || window.innerWidth;
  444. // 计算当前窗口下的 html font-size(按设计稿比例缩放)
  445. const htmlFontSize = (windowWidth / designWidth) * baseFontSize;
  446. // 应用到 html 元素
  447. document.documentElement.style.fontSize = `${htmlFontSize}px`;
  448. },
  449. async PageInit() {
  450. // let currentProgress = 1;
  451. // this.loadingText = `拼命加载中(1%)……`;
  452. // this.timer = setInterval(() => {
  453. // currentProgress++;
  454. // this.loadingText = `拼命加载中(${currentProgress}%)……`;
  455. // }, 500);
  456. this.loading = true;
  457. this.openLoading = false;
  458. this.bookPageImages = [];
  459. // this.targetProgress = 1;
  460. // this.showReportLoading = true;
  461. this.pageCount = 15;
  462. this.$nextTick(()=>{
  463. const titleHeight = this.$refs?.areaReportTitle?.offsetHeight || 0;
  464. const reportTitleHeight = titleHeight + 82;
  465. this.moduleHeightData = [reportTitleHeight];//每个模块的高度 初始标题高度
  466. })
  467. this.modulePageData = [1];
  468. this.multiSuggestionPageNum = '';//总分 总结建议
  469. this.singleSubjectData = [];//单科数据
  470. this.knowLedgeLayeringData = [];//知识点分层
  471. this.knowLedgeLayeringPageNum = [];//知识点分层分页
  472. this.pageKey += 1;
  473. //多科成绩总览 科目标准分分析
  474. await this.QueryMultiSubjectData();
  475. //学生端查询总分,多科历次信息(联考)
  476. await this.QueryHistoryExamData();
  477. // 学生端查询总分,多科总结建议信息(联考)
  478. await this.QuerySuggestionData();
  479. let index = 0;
  480. for (const element of this.multiSubjectData.singleSubject){
  481. //单科每个模块标题分页
  482. this.singleSubjectData.push({
  483. titlePageNum:this.SingleChartPage(82),
  484. scrolTablePagesNum:[],//成绩单
  485. scrolTableList:[],
  486. scrolHeaderList:[],
  487. groupQuestionData:[],//小题分组、大题分组、知识点、自定义分组
  488. historyExamData:{
  489. pageNum:'',
  490. chartData: [],
  491. datax: [],
  492. datay: [],
  493. title: [],
  494. legendList: [],
  495. tooltipData:[]
  496. },
  497. suggestionPageNum:'',//总结建议分页
  498. suggestionHtml: '',//总结建议
  499. paperImageList:[],//答题卡
  500. paperImagePageNum:[],//答题卡页码
  501. showHistory:0
  502. })
  503. await this.QueryOneSubjectData(element.subjectCode,index);
  504. await this.QueryOneSubjectSmallQuestionData(element.subjectCode,index);
  505. await this.QueryOneSubjectGroupQuestionData(element.subjectCode,index);
  506. await this.QueryOneSubjectCustomGroupQuestion(element.subjectCode,index);
  507. //学生端查询单科-历次查询(联考)
  508. await this.QueryOneSubjectHistoryExamData(element.subjectCode,index);
  509. await this.QueryOneSubjectSuggestionData(element.subjectCode,index);
  510. await this.FindStudentCard(element.subjectCode,index);
  511. index++; // 每次循环后索引+1
  512. }
  513. this.pageCount = this.modulePageData.length > 0 ? Math.max(...this.modulePageData) : 1;
  514. this.loading = false;
  515. this.$emit('isPdfDataLoadEnd');//是否显示下载pdf按钮
  516. console.log(this.pageCount,this.modulePageData,this.moduleHeightData,777777)
  517. // this.$nextTick(()=>{
  518. // setTimeout(()=>{
  519. // // clearTimeout(this.timer); // 清除定时器,停止重复执行
  520. // // this.GetPageImages(currentProgress);
  521. // this.GetPageImages();
  522. // },2000)
  523. // })
  524. },
  525. //下载预览图片
  526. OpenBookImages(){
  527. if(this.bookPageImages.length){
  528. this.$refs.bookFlipBox.showFullScreen()
  529. }else{
  530. this.openLoading = true;
  531. this.$nextTick(()=>{
  532. setTimeout(()=>{
  533. this.GetPageImages();
  534. },2000)
  535. })
  536. }
  537. },
  538. //获取图片
  539. async GetPageImages(){
  540. //获取所有的area_page 元素
  541. const elements = document.querySelectorAll(".web_mode .web_area_page");
  542. // const stepLens = elements?.length || 1;
  543. // const remainingProgress = 100 - progress;//剩余进度
  544. // const perStepProgress = Math.floor(remainingProgress / stepLens) || 1; // 每次增加的进度 向下取整
  545. // const pdf = new jsPDF("p", "pt", "a4"); // 'p'表示纵向,'a4'表示A4纸张尺寸
  546. // const pdfWidth = pdf.internal.pageSize.getWidth(); //获取pdf的宽度
  547. // const pdfHeight = pdf.internal.pageSize.getHeight(); //获取pdf的高度
  548. // let yPos = 0; //当前图像在pdf页面上的垂直位置的变量
  549. let i = 1;
  550. // let currentProgress = progress;
  551. for (const element of elements) {
  552. await html2canvas(element, {
  553. scale: 2, // 增加缩放比例
  554. useCORS: true, // 允许跨域
  555. logging: false, // 是否打印调试日志(开发时开启,生产关闭)
  556. letterRendering: true, // 文字抗锯齿 启用字母渲染
  557. }).then(async (canvas) => {
  558. // const imgData = canvas.toDataURL("image/png");
  559. const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
  560. const imgUrl = URL.createObjectURL(blob);
  561. console.log(imgUrl,89999)
  562. this.bookPageImages.push(imgUrl);
  563. // currentProgress = Math.min(Math.round((i / stepLens) * 100),100);
  564. // currentProgress = Math.min(progress + i * perStepProgress,100);
  565. // this.targetProgress = currentProgress
  566. // this.loadingText = `拼命加载中(${currentProgress}%)……`;
  567. // const imgProps = pdf.getImageProperties(imgData); // 获取图像的属性,包括宽度和高度
  568. // const imgWidth = imgProps.width;
  569. // const imgHeight = imgProps.height;
  570. // const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight); //计算图片的缩放比例
  571. // const adjustWidth = imgWidth * ratio;
  572. // const adjustHeight = imgHeight * ratio;
  573. // // 在添加每个图像之前,检查当前页面的高度是否足够。如果不够,则添加新页面,并将 yPos 重置为 0
  574. // if (yPos + adjustHeight > pdfHeight) {
  575. // pdf.addPage();
  576. // yPos = 0;
  577. // }
  578. // // 将图像添加到pdf中
  579. // pdf.addImage(imgData, "PNG", 0, yPos, adjustWidth, adjustHeight);
  580. // yPos += adjustHeight;
  581. // // 如果添加图像后剩余空间不足一页,则添加新页面
  582. // if (yPos > pdfHeight) {
  583. // pdf.addPage();
  584. // yPos = 0;
  585. // }
  586. i++;
  587. })
  588. }
  589. // if(currentProgress < 100){
  590. // this.loadingText = `拼命加载中(100%)……`;
  591. // }
  592. // 保存pdf文件
  593. // pdf.save("联校报告册.pdf");
  594. // this.showReportLoading = false;
  595. setTimeout(()=>{
  596. // this.loading = false;
  597. this.openLoading = false;
  598. this.$refs.bookFlipBox.showFullScreen()
  599. },500)
  600. },
  601. //总分成绩分析
  602. async QueryMultiSubjectData() {
  603. await this.$api.reportStudent[getApiName()].queryMultiSubjectData({
  604. ...this.reportParam,
  605. subjectGroupType: 1, // 科目是否为组合
  606. isTotal: 1, //是否为总分科目 1为总分 0为非总分
  607. }).then(res => {
  608. if (res.code == 200 && res.data) {
  609. const titleData = res?.data?.titleData || [];
  610. this.multiSubjectData.studentOpenness = res?.data?.studentOpenness ?? '';
  611. this.multiSubjectData.showHistory = res?.data?.showHistory || 0;
  612. const headerData = titleData.filter(item=>item.prop!='imgUrlList' && item.prop!='subjectName');
  613. const staticHeaderData = titleData.filter(item=>item.prop=='subjectName');
  614. const tableData = res?.data?.tableData || [];
  615. this.stuClasName = tableData?.find(item=>item.subjectCode==0)?.className || '';
  616. //表格分页
  617. const pageTableData = this.TableRowAndColumnPage(headerData,tableData,7,1);//8列一个表
  618. this.multiSubjectData.tablePagesNum = pageTableData.tablePagesNum;
  619. this.multiSubjectData.tableList = pageTableData.tableList;
  620. this.multiSubjectData.headerList = pageTableData.headerList;
  621. this.multiSubjectData.staticHeaderData = staticHeaderData;//静态表头
  622. //标准分分析图
  623. this.multiSubjectData.datax = []
  624. this.multiSubjectData.datay = []
  625. this.multiSubjectData.tooltipData = []
  626. this.multiSubjectData.standardScoreAnalysisStatus = res?.data?.standardScoreAnalysisStatus ?? 1;
  627. //总分
  628. const totalScore = tableData.filter(item => item.isTotal == 1)
  629. //组合
  630. const subjectGroup = tableData.filter(
  631. item => item.isTotal == 0 && item.subjectGroupType == 1
  632. )
  633. //单科
  634. const singleSubject = tableData.filter(
  635. item => item.isTotal == 0 && item.subjectGroupType == 0
  636. )
  637. this.multiSubjectData.singleSubject = singleSubject;//单科
  638. const chartData = [...totalScore, ...subjectGroup, ...singleSubject];
  639. let datax = [],datay = [];
  640. chartData.forEach(item => {
  641. this.multiSubjectData.datax.push(item?.subjectName ?? '-')
  642. this.multiSubjectData.datay.push(!item?.standardScore || item?.standardScore == '-' ? 0 : item?.standardScore)
  643. if (item.isTotal == 0 && item.subjectGroupType == 0) {
  644. datax.push(item?.subjectName ?? '')
  645. datay.push(item?.standardScore ?? 0)
  646. }
  647. })
  648. let maxSubject = [],minSubject = []
  649. datay.forEach((item, k) => {
  650. if (Number(item) > 0) {
  651. maxSubject.push(datax[k])
  652. }
  653. if (Number(item) < 0) {
  654. minSubject.push(datax[k])
  655. }
  656. })
  657. this.multiSubjectData.maxSubject = maxSubject.join('、')
  658. this.multiSubjectData.minSubject = minSubject.join('、')
  659. //标准分分析图分页
  660. this.$nextTick(()=>{
  661. if((this.multiSubjectData.standardScoreAnalysisStatus === 0 && this.schoolType == 2) || this.schoolType == 1){
  662. const desHeight = this.$refs?.standardScoreChartDes?.offsetHeight || 0;
  663. const divHeight = 383 + desHeight;
  664. this.multiSubjectData.chartPagesNum = this.SingleChartPage(this.multiSubjectData.datay.length > 0 ? divHeight : 0);
  665. }else{
  666. this.multiSubjectData.chartPagesNum = this.SingleChartPage(0);
  667. }
  668. // console.log(divHeight,desHeight,this.multiSubjectData.chartPagesNum,13322133)
  669. })
  670. } else {
  671. this.multiSubjectData.studentOpenness = '';
  672. this.multiSubjectData.showHistory = 0;
  673. this.multiSubjectData.tablePagesNum = [];
  674. this.multiSubjectData.tableList = [];
  675. this.multiSubjectData.headerList = [];
  676. this.multiSubjectData.singleSubject = [];
  677. // 标准分分析
  678. this.multiSubjectData.datax = []
  679. this.multiSubjectData.datay = []
  680. this.multiSubjectData.tooltipData = []
  681. this.multiSubjectData.standardScoreAnalysisStatus = 1;
  682. this.multiSubjectData.maxSubject = []
  683. this.multiSubjectData.minSubject = []
  684. this.multiSubjectData.chartPagesNum = '';//标准分分析图分页
  685. }
  686. })
  687. },
  688. //总分,多科历次信息
  689. async QueryHistoryExamData() {
  690. await this.$api.reportStudent[getApiName()].queryHistoryExamData({
  691. ...this.reportParam,
  692. subjectGroupType: 1, // 科目是否为组合
  693. isTotal: 1, //是否为总分科目 1为总分 0为非总分
  694. }).then(res => {
  695. if (res.code == 200 && res.data) {
  696. const detailData = (res.data?.detailData || []).reverse();
  697. this.historyExamData.chartData = detailData;
  698. const selectNames = res.data.selectNames || [];
  699. const selectVal = selectNames?.[0]?.prop ?? '';
  700. this.historyExamData.datax = [];
  701. let datay = [],tooltipData = [];
  702. detailData.forEach(item => {
  703. this.historyExamData.datax.push(item.examName)
  704. datay.push(item[selectVal])
  705. tooltipData.push({
  706. name: selectNames?.[0]?.name ?? '',
  707. value: item[selectVal]
  708. })
  709. })
  710. this.historyExamData.datay = [datay];
  711. this.historyExamData.tooltipData = [tooltipData];
  712. this.historyExamData.pageNum = this.SingleChartPage(this.historyExamData.chartData.length > 0 && this.multiSubjectData.showHistory==1 ? 363 : 0);
  713. } else {
  714. this.historyExamData.chartData = [];
  715. this.historyExamData.tooltipData = [];
  716. this.historyExamData.datax = [];
  717. this.historyExamData.datay = [];
  718. this.historyExamData.pageNum = '';
  719. }
  720. })
  721. },
  722. // 学生端查询总分,多科总结建议信息(联考)
  723. async QuerySuggestionData() {
  724. await this.$api.reportStudent[getApiName()].querySuggestionData({
  725. ...this.reportParam,
  726. subjectGroupType: 1, // 科目是否为组合
  727. isTotal: 1, //是否为总分科目 1为总分 0为非总分
  728. }).then(res => {
  729. if (res.code == 200 && res.data) {
  730. const data = res.data;
  731. const upSubjectList = data.upSubjectData || [];
  732. const downSubjectList = data.downSubjectData || [];
  733. const upSubjectData = upSubjectList.map(item => {
  734. if (data.studentOpenness == 1 || data.studentOpenness == 2) {
  735. return `${item.subjectName}(得分${item.score})`
  736. } else {
  737. return `${item.subjectName}(${item.score})`
  738. }}).join('、')
  739. const downSubjectData = downSubjectList.map(item => {
  740. if (data.studentOpenness == 1 || data.studentOpenness == 2) {
  741. return `${item.subjectName}(得分${item.score})`
  742. } else {
  743. return `${item.subjectName}(${item.score})`
  744. }}).join('、')
  745. if(data?.fullScore && data?.fullScore!='-'){
  746. const scoreText = data?.studentOpenness == 1 || data?.studentOpenness == 2 ? '总分' : '总分标准分为'
  747. const unit = data?.studentOpenness == 1 || data?.studentOpenness == 2 ? '分' : '';
  748. this.suggestionHtml = `${data?.studentName || ''}同学,本次考试${scoreText}<span style="color: #2e64fa">${data?.fullScore}</span>${unit},整体处于${data?.summarySuggestionLevel},`;
  749. if(upSubjectData){
  750. this.suggestionHtml += `<span style="color: #3ba272">${upSubjectData}</span>是你的优势学科,建议通过提分练习进行强化,继续保持这类学科的优势性${downSubjectData ? ';' : '。'}`;
  751. }
  752. if(downSubjectData){
  753. this.suggestionHtml += `<span style="color: #f56c6c">${downSubjectData}</span>是你的劣势学科,建议先加强学习,熟练掌握薄弱知识点的基础,然后通过提分练习进行巩固和强化,争取下次考试获得更优异的成绩!`;
  754. }
  755. }else{
  756. this.suggestionHtml = null
  757. }
  758. } else {
  759. this.suggestionHtml = null
  760. }
  761. this.$nextTick(()=>{
  762. const suggestionHeight = this.$refs?.multiSuggestionModule?.offsetHeight || 0;
  763. // console.log(suggestionHeight,99888)
  764. this.multiSuggestionPageNum = this.SingleChartPage(this.suggestionHtml?suggestionHeight:0);
  765. })
  766. })
  767. },
  768. //学生端查询单科-我的成绩
  769. async QueryOneSubjectData(subjectCode,index) {
  770. await this.$api.reportStudent[getApiName()].queryOneSubjectData({
  771. ...this.reportParam,
  772. subjectGroupType: 0, // 科目是否为组合
  773. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  774. subjectCode:subjectCode
  775. }).then(res => {
  776. if (res.code == 200 && res.data) {
  777. const headData = [{
  778. name:'班级',
  779. prop:'className',
  780. display:true
  781. },{
  782. name:'原始分',
  783. prop:'score',
  784. display:res?.data?.scoreStatus === 0 //0-显示,1-不显示
  785. },{
  786. name:`赋分${res?.data?.schoolId=='620212977630539776'?'(标准分)':''}`,
  787. prop:'rateScore',
  788. display:res?.data?.rateScoreStatus === 0 //0-显示,1-不显示
  789. },{
  790. name:'班排',
  791. prop:'classRank',
  792. display:res?.data?.classRankStatus === 0
  793. },{
  794. name:'年排',
  795. prop:'schoolRank',
  796. display:res?.data?.schoolRankStatus === 0
  797. },{
  798. name:'联排',
  799. prop:'examRank',
  800. display:res?.data?.examRankStatus === 0 && this.reportParam.examLevel == 1 && this.schoolType == 2
  801. },{
  802. name:'区排',
  803. prop:'regionRank',
  804. display:res?.data?.regionRankStatus === 0
  805. },{
  806. name:'实考人数',
  807. prop:'examNum',
  808. display:res?.data?.examNumStatus === 0
  809. },{
  810. name:'赋分等级',
  811. prop:'rateScoreName',
  812. display:res?.data?.rateScoreNameStatus === 0
  813. },{
  814. name:'标准分',
  815. prop:'standardScore',
  816. display:(res?.data?.standardScoreStatus === 0 && this.schoolType == 2) || this.schoolType == 1
  817. },{
  818. name:'学业等级',
  819. prop:'gradeName',
  820. display:(res?.data?.gradeNameStatus === 0 && this.schoolType == 2) || this.schoolType == 1
  821. },{
  822. name:'得分率',
  823. prop:'scoreRate',
  824. display:res?.data?.scoreRateStatus === 0
  825. },{
  826. name:'班级最高分',
  827. prop:'classMaxScore',
  828. display:res?.data?.classMaxScoreStatus === 0 && this.schoolType == 2
  829. },{
  830. name:'年级最高分',
  831. prop:'gradeMaxScore',
  832. display:res?.data?.gradeMaxScoreStatus === 0 && this.schoolType == 2
  833. },{
  834. name:'联校最高分',
  835. prop:'examMaxScore',
  836. display:res?.data?.examMaxScoreStatus === 0 && this.reportParam.examLevel == 1 && this.schoolType == 2
  837. },{
  838. name:'班级均分',
  839. prop:'classAvgScore',
  840. display:res?.data?.classAvgScoreStatus === 0 && this.schoolType == 2
  841. },{
  842. name:'年级均分',
  843. prop:'gradeAvgScore',
  844. display:res?.data?.gradeAvgScoreStatus === 0 && this.schoolType == 2
  845. },{
  846. name:'联校均分',
  847. prop:'examAvgScore',
  848. display:res?.data?.examAvgScoreStatus === 0 && this.reportParam.examLevel == 1 && this.schoolType == 2
  849. }]
  850. const groupClassRanks = res.data.groupClassRanks || [];
  851. const groupClassMaxScoreList = res.data.groupClassMaxScoreList || [];
  852. const groupClassAvgScoreList = res.data.groupClassAvgScoreList || [];
  853. groupClassRanks.forEach(item=>{
  854. headData.push({
  855. name:`${item.classGroupName}排名`,
  856. prop:'groupClassRanks',
  857. code:item.classGroupCode,
  858. display:item.classGroupRankStatus === 1
  859. })
  860. })
  861. groupClassMaxScoreList.forEach(item=>{
  862. headData.push({
  863. name:`${item.classGroupName}最高分`,
  864. prop:'groupClassMaxScoreList',
  865. code:item.classGroupCode,
  866. display:item.classGroupResultScoreStatus === 1
  867. })
  868. })
  869. groupClassAvgScoreList.forEach(item=>{
  870. headData.push({
  871. name:`${item.classGroupName}均分`,
  872. prop:'groupClassAvgScoreList',
  873. code:item.classGroupCode,
  874. display:item.classGroupResultScoreStatus === 1
  875. })
  876. })
  877. const tableData = [res.data] || [];
  878. const headerList = headData.filter(item=>item.display);
  879. const pageTableData = this.TableRowAndColumnPage(headerList,tableData,8,1);//8列一个表
  880. this.singleSubjectData[index].scrolTablePagesNum = pageTableData.tablePagesNum;
  881. this.singleSubjectData[index].scrolTableList = pageTableData.tableList;
  882. this.singleSubjectData[index].scrolHeaderList = pageTableData.headerList;//表头
  883. this.singleSubjectData[index].showHistory = res?.data?.showHistory || 0;
  884. } else {
  885. this.singleSubjectData[index].scrolTablePagesNum = [];
  886. this.singleSubjectData[index].scrolTableList = [];
  887. this.singleSubjectData[index].scrolHeaderList = [];//表头
  888. this.singleSubjectData[index].showHistory = 0;
  889. }
  890. })
  891. },
  892. //学生端查询单科-小题分析(表格-图表)
  893. async QueryOneSubjectSmallQuestionData(subjectCode,index) {
  894. await this.$api.reportStudent[getApiName()].queryOneSubjectSmallQuestionData({
  895. ...this.reportParam,
  896. subjectGroupType: 0, // 科目是否为组合
  897. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  898. subjectCode:subjectCode
  899. }).then(res => {
  900. if (res.code == 200 && res?.data?.tableData?.length > 0) {
  901. const tableData = res.data.tableData || [];
  902. const titleData = res.data.titleData || [];
  903. const studentOpenness = res.data?.studentOpenness ?? '';//控制得分显示对错或值
  904. this.TableChartData(tableData, titleData, studentOpenness, index,'smallQuestionData','小题',subjectCode);
  905. }
  906. })
  907. },
  908. //学生端查询单科-大题分析,知识点分析,能力要素分析(联考)
  909. async QueryOneSubjectGroupQuestionData(subjectCode,index) {
  910. await this.$api.reportStudent[getApiName()].queryOneSubjectGroupQuestionData({
  911. ...this.reportParam,
  912. subjectGroupType: 0, // 科目是否为组合
  913. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  914. subjectCode:subjectCode
  915. }).then(async res => {
  916. if (res.code == 200 && res.data) {
  917. const { bigQuestion, knowledgePointQuestion, abilityQuestion } = res.data
  918. if (bigQuestion && bigQuestion?.tableData?.length > 0) {
  919. const tableData = bigQuestion.tableData || [];
  920. const titleData = bigQuestion.titleData || [];
  921. const studentOpenness = bigQuestion?.studentOpenness ?? '';
  922. this.TableChartData(tableData, titleData, studentOpenness, index,'bigQuestionData','大题',subjectCode);
  923. }
  924. if (knowledgePointQuestion && knowledgePointQuestion?.tableData?.length > 0) {
  925. const tableData = knowledgePointQuestion.tableData || [];
  926. const titleData = knowledgePointQuestion.titleData || [];
  927. const studentOpenness = knowledgePointQuestion?.studentOpenness ?? '';
  928. this.TableChartData(tableData, titleData, studentOpenness, index,'knowledgePointQuestionData','知识点',subjectCode);
  929. if(this.schoolType == 2){
  930. // 等待 DOM 更新完成后获取高度
  931. await this.$nextTick();
  932. await new Promise(resolve => setTimeout(resolve, 2000)); // 额外延迟确保浏览器挂载
  933. //处理知识点分层分页
  934. const refName = `knowLedgeLayering_${subjectCode}`;
  935. const domHeight = this.$refs[refName]?.[0]?.offsetHeight || 0;
  936. this.knowLedgeLayeringPageNum.push(this.SingleChartPage(domHeight));
  937. }
  938. }
  939. if (abilityQuestion && abilityQuestion?.tableData?.length > 0) {
  940. const tableData = abilityQuestion.tableData || [];
  941. const titleData = abilityQuestion.titleData || [];
  942. const studentOpenness = abilityQuestion?.studentOpenness ?? '';
  943. this.TableChartData(tableData, titleData, studentOpenness, index,'abilityQuestionData','能力要素',subjectCode);
  944. }
  945. }
  946. })
  947. },
  948. //学生端查询单科-自定义分组(联考)
  949. async QueryOneSubjectCustomGroupQuestion(subjectCode,index) {
  950. await this.$api.reportStudent[getApiName()].queryOneSubjectCustomGroupQuestion({
  951. ...this.reportParam,
  952. subjectGroupType: 0, // 科目是否为组合
  953. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  954. subjectCode:subjectCode
  955. }).then(res => {
  956. if (res.code == 200 && res.data) {
  957. const customQuestionData = res?.data?.customQuestionData ?? []
  958. if (customQuestionData && customQuestionData.length > 0) {
  959. customQuestionData.forEach((item, key) => {
  960. const tableData = item?.questionData?.tableData || []
  961. const titleData = item?.questionData?.titleData || []
  962. const studentOpenness = res.data?.studentOpenness ?? ''
  963. this.TableChartData(tableData, titleData, studentOpenness, index,`customQuestionData${key}`,item.customName,subjectCode);
  964. })
  965. }
  966. }
  967. })
  968. },
  969. //学生端查询单科-历次查询(联考)
  970. async QueryOneSubjectHistoryExamData(subjectCode,index) {
  971. await this.$api.reportStudent[getApiName()].queryOneSubjectHistoryExamData({
  972. ...this.reportParam,
  973. subjectGroupType: 0, // 科目是否为组合
  974. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  975. subjectCode:subjectCode
  976. }).then(res => {
  977. if (res.code == 200 && res.data) {
  978. const detailData = (res.data?.detailData || []).reverse();
  979. // console.log(this.singleSubjectData[index],98899)
  980. this.singleSubjectData[index].historyExamData.chartData = detailData;
  981. const selectNames = res.data.selectNames || [];
  982. const selectVal = selectNames?.[0]?.prop ?? '';
  983. this.singleSubjectData[index].datax = [];
  984. let datay = [],tooltipData = [];
  985. detailData.forEach(item => {
  986. this.singleSubjectData[index].historyExamData.datax.push(item.examName)
  987. datay.push(item[selectVal])
  988. tooltipData.push({
  989. name: selectNames?.[0]?.name ?? '',
  990. value: item[selectVal]
  991. })
  992. })
  993. this.singleSubjectData[index].historyExamData.datay = [datay];
  994. this.singleSubjectData[index].historyExamData.tooltipData = [tooltipData];
  995. this.singleSubjectData[index].historyExamData.pageNum = this.SingleChartPage(this.singleSubjectData[index].historyExamData.chartData.length > 0 && this.singleSubjectData[index]?.showHistory==1 ? 363 : 0);
  996. }
  997. })
  998. },
  999. //学生端查询单科-总结建议
  1000. async QueryOneSubjectSuggestionData(subjectCode,index) {
  1001. await this.$api.reportStudent[getApiName()].queryOneSubjectSuggestionData({
  1002. ...this.reportParam,
  1003. subjectGroupType: 0, // 科目是否为组合
  1004. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  1005. subjectCode:subjectCode
  1006. }).then(res => {
  1007. if (res.code == 200 && res.data) {
  1008. const data = res.data
  1009. //* 1-得分显示分数,小题分显示分数,2-得分显示分数,小题分显示对错
  1010. //* 3-得分显示对错,小题分显示分数,4-得分显示对错,小题分显示对错
  1011. //* 5-得分显示等级,小题分显示分数,6-得分显示等级,小题分显示对错
  1012. const upSubjectList = data?.upSubjectData || [];
  1013. const downSubjectList = data?.downSubjectData || [];
  1014. const upSubjectData = upSubjectList.map(item => {
  1015. if (data.studentOpenness == 1 || data.studentOpenness == 2) {
  1016. return `${item.subjectName}得分<span style="color: #3BA272;">${item.score}</span>分`
  1017. } else {
  1018. return `${item.subjectName}标准分为<span style="color: #3BA272;">${item.score}</span>`
  1019. }
  1020. }).join('、')
  1021. const downSubjectData = downSubjectList.map(item => {
  1022. if (data.studentOpenness == 1 || data.studentOpenness == 2) {
  1023. return `${item.subjectName}得分<span style="color: #EE6666;">${item.score}</span>分`
  1024. } else {
  1025. return `${item.subjectName}标准分为<span style="color: #EE6666;">${item.score}</span>`
  1026. }
  1027. }).join('、')
  1028. this.singleSubjectData[index].suggestionHtml = '';
  1029. if (data.studentName && (upSubjectData || downSubjectData)) {
  1030. this.singleSubjectData[index].suggestionHtml = `${data.studentName}同学,本次考试`
  1031. }
  1032. if (upSubjectData) {
  1033. this.singleSubjectData[index].suggestionHtml += `${upSubjectData},是你的优势学科,建议通过提分练习进行强化,继续保持这类学科的优势性!`
  1034. }
  1035. if (downSubjectData) {
  1036. this.singleSubjectData[index].suggestionHtml += `${downSubjectData},是你的劣势学科,建议先加强学习,熟练掌握薄弱知识点的基础,然后通过提分练习进行巩固和强化,争取下次考试获得更优异的成绩!`
  1037. }
  1038. this.$nextTick(()=>{
  1039. const suggestionHeight = this.$refs?.[`singleSubjectSuggestion_${index}`]?.[0]?.offsetHeight || 0;
  1040. // console.log(suggestionHeight,8999111)
  1041. this.singleSubjectData[index].suggestionPageNum = this.SingleChartPage(this.singleSubjectData[index].suggestionHtml?suggestionHeight:0);
  1042. })
  1043. } else {
  1044. this.singleSubjectData[index].suggestionHtml = ''
  1045. }
  1046. })
  1047. },
  1048. //答题卡
  1049. async FindStudentCard(subjectCode,index){
  1050. await this.$api.reportStudent[getApiName()].findStudentCard({
  1051. examId:this.reportParam.examId,
  1052. subjectCode:subjectCode,
  1053. registrationCode:this.reportParam.registrationCode
  1054. }).then(res => {
  1055. if (res.code == 200 && res.data) {
  1056. let paperImageList = res.data.pageVOS || [];
  1057. //先添加总分数据
  1058. let totalScore = {
  1059. questionName: '总分',
  1060. fullScore: res?.data?.fullScore || '',
  1061. score: res?.data?.levelName ?? res?.data?.totalScore,
  1062. displayType: res.data.displayType, //显示类型 0-分数 1-对错 2-等级
  1063. displayName: res.data.displayName, //显示值
  1064. correctType: res.data.correctType, //显示对错的时候 0-错 1-半对 2-全对
  1065. questionAnswer: '',
  1066. answer: '',
  1067. samplingPosition: '{"x":195,"y":247,"page":1}'
  1068. }
  1069. if (paperImageList.length > 0 && paperImageList[0].questionVOS) {
  1070. paperImageList[0].questionVOS.unshift(totalScore)
  1071. }
  1072. this.singleSubjectData[index].paperImageList = paperImageList;
  1073. this.singleSubjectData[index].usedCardType = res?.data?.usedCardType ?? 1;
  1074. for(let i = 0;i<paperImageList.length;i++){
  1075. const pageNum = this.SingleChartPage(this.printPageHeight);
  1076. this.singleSubjectData[index].paperImagePageNum.push(pageNum);
  1077. }
  1078. }
  1079. })
  1080. },
  1081. //处理数据
  1082. async TableChartData(tableData, titleData, studentOpenness, index,type,groupName,subjectCode) {
  1083. //柱状图
  1084. let datax = [],datay = [],radarChart = []
  1085. tableData.forEach(item => {
  1086. datax.push(item.questionName)
  1087. const scoreRate = item?.scoreRate ?? ''
  1088. datay.push(scoreRate)
  1089. radarChart.push([item.questionName, scoreRate])
  1090. })
  1091. //雷达图
  1092. const radarChartData = [['group', '得分率'], ...radarChart]
  1093. let chartHeight = 0;//小题分析只显示table 不显示图
  1094. if(type=='bigQuestionData'){
  1095. chartHeight = datay.length > 0 ? 363 : 0; //柱状图
  1096. }else if (type == 'smallQuestionData'){
  1097. chartHeight = 0;
  1098. } else{
  1099. chartHeight = datay.length > 0 ? 393 : 0;//雷达图
  1100. }
  1101. const chartPagesNum = this.SingleChartPage(chartHeight);
  1102. const HeadData = titleData.filter(item=>item.prop!='smallQuestionNames');
  1103. const staticHeader = HeadData.slice(0,1);//固定表头
  1104. const dynamicHeader = HeadData.slice(1);//动态分组标头
  1105. const pageTableData = this.TableRowAndColumnPage(dynamicHeader,tableData,7,1);//8列一个表
  1106. const tablePagesNum = pageTableData.tablePagesNum;
  1107. const tableList = pageTableData.tableList;
  1108. const headerList = pageTableData.headerList;//表头
  1109. //查询单科-知识点分层分析表(联考)
  1110. let knowLedgeLayering = null;
  1111. if(type == 'knowledgePointQuestionData' && this.schoolType== 2){
  1112. await this.$api.reportStudent[getApiName()].queryStudentKnowLedgeLayering({
  1113. ...this.reportParam,
  1114. subjectGroupType: 0, // 科目是否为组合
  1115. isTotal: 0, //是否为总分科目 1为总分 0为非总分
  1116. subjectCode:subjectCode
  1117. }).then(res => {
  1118. if (res.code == 200 && res.data) {
  1119. const { breakThrough,develop,fullScore } = res.data;
  1120. knowLedgeLayering = {
  1121. breakThrough:breakThrough || '',
  1122. develop:develop || '',
  1123. fullScore:fullScore || ''
  1124. }
  1125. //知识点
  1126. this.knowLedgeLayeringData.push({
  1127. subjectCode:subjectCode,
  1128. groupName:groupName,
  1129. knowLedgeLayering:knowLedgeLayering
  1130. })
  1131. }else{
  1132. knowLedgeLayering = null;
  1133. }
  1134. })
  1135. }
  1136. this.singleSubjectData[index].groupQuestionData.push({
  1137. type:type,
  1138. groupName:groupName,
  1139. studentOpenness:studentOpenness,
  1140. staticHeader:staticHeader,
  1141. headerList:headerList,
  1142. tableList:tableList,
  1143. tablePagesNum:tablePagesNum,
  1144. chartPagesNum:chartPagesNum,
  1145. datax:datax,
  1146. datay:datay,
  1147. radarChartData:radarChartData,
  1148. knowLedgeLayering:knowLedgeLayering
  1149. })
  1150. },
  1151. //按照原始顺序累加,当总和超过A4高度1285时,将当前元素放入下一组
  1152. groupByThreshold(arr, threshold) {
  1153. const result = [];
  1154. let currentGroup = [];
  1155. let currentSum = 0;
  1156. for (let i = 0; i < arr.length; i++) {
  1157. const num = arr[i];
  1158. // 如果当前组为空,直接添加
  1159. if (currentGroup.length === 0) {
  1160. currentGroup.push(num);
  1161. currentSum += num;
  1162. }
  1163. // 如果加上当前元素会超过阈值,则创建新组
  1164. else if (currentSum + num > threshold) {
  1165. result.push(currentGroup);
  1166. currentGroup = [num];
  1167. currentSum = num;
  1168. }
  1169. // 否则添加到当前组
  1170. else {
  1171. currentGroup.push(num);
  1172. currentSum += num;
  1173. }
  1174. }
  1175. // 添加最后一组
  1176. if (currentGroup.length > 0) {
  1177. result.push(currentGroup);
  1178. }
  1179. return result;
  1180. },
  1181. /*
  1182. *对表格横向和竖向分页
  1183. *dynamicHeader 动态表头
  1184. *tableData 表格数据
  1185. *groupSize 动态表头分页大小
  1186. *headNum 表头行数
  1187. */
  1188. TableRowAndColumnPage(dynamicHeader,tableData,groupSize,headNum){
  1189. /*
  1190. * 每个模块的高度
  1191. */
  1192. const tableTitle = 49;//表格标题高度
  1193. const tableHeadHeight = 41;//表头高度
  1194. const tableGap = 49;//表格和图表之间的间距
  1195. //对表格横向分页
  1196. const groupDynamicHeader = [];
  1197. for (let i = 0; i < dynamicHeader.length; i += groupSize) {
  1198. const group = dynamicHeader.slice(i, i + groupSize);
  1199. //表格补充
  1200. if(group.length > 0 && group.length!=groupSize && i > 0){
  1201. const tdLens = groupSize - group.length;
  1202. for(let j = 0; j < tdLens; j ++){
  1203. group.push({})
  1204. }
  1205. }
  1206. groupDynamicHeader.push(group)
  1207. }
  1208. let tablePagesNum = [],tableList = [],headerList = [];//当前模块所有table页码 表格 表格高度
  1209. for (let i = 0; i < groupDynamicHeader.length; i ++) {
  1210. let itemTablePagesNum = [],itemTableList = [],itemHeadder= [], moduleHeightData = [] ,isShowSplitLine = [];//每个table的页码 表格 表格高度 isShowSplitLine:表格是否显示分割线
  1211. //计算最后一页模块的高度
  1212. let lastPageDataSum = 0;
  1213. const lastPageNum = this.modulePageData.length > 0 ? this.modulePageData[this.modulePageData.length - 1] : 1;//最后一页页码
  1214. this.modulePageData.forEach((item,p)=>{
  1215. if(item == lastPageNum){
  1216. lastPageDataSum += this.moduleHeightData[p];
  1217. }
  1218. })
  1219. const remainHeight = this.printPageHeight - lastPageDataSum - (tableHeadHeight * headNum) - tableTitle - 41;//41 是距离底部的边距
  1220. const remainTableRow = Math.floor(remainHeight / 40);//剩余可放多少行
  1221. if(remainTableRow > 1){
  1222. const tableLens = tableData.length ?? 0;//表格行数量
  1223. if(tableLens > remainTableRow){//判断第二页是否有值
  1224. const pageTableHeight = this.printPageHeight - (tableHeadHeight * headNum) - tableTitle - 41;// 一页能放下的table的高度 41 是距离底部的边距
  1225. const tableRowNum = Math.floor(pageTableHeight / 40);//一页可放多少行
  1226. //第一页数据
  1227. const firstTableData = tableData.slice(0,remainTableRow);
  1228. itemTableList.push(firstTableData)
  1229. itemHeadder.push(groupDynamicHeader[i])
  1230. isShowSplitLine.push(false);//是否显示表格底部的分割线 第一页不显示
  1231. //第一页页码
  1232. // this.modulePageData.push(lastPageNum);
  1233. //当前表格第一页页码
  1234. itemTablePagesNum.push(lastPageNum);//图表分页页码
  1235. // 第一页高度
  1236. const tableHeight1 = firstTableData.length > 0 ? (tableHeadHeight * headNum) + tableTitle + tableGap + firstTableData.length * 40 : 0;
  1237. moduleHeightData.push(tableHeight1)
  1238. const otherTableData = tableData.slice(remainTableRow);//接取完上一页剩下的表格数据
  1239. // 按步长遍历,每次截取 表格行数 元素
  1240. for (let j = 0; j < otherTableData.length; j += tableRowNum) {
  1241. const group = otherTableData.slice(j, j + tableRowNum);
  1242. const key = j/tableRowNum;
  1243. //表格数据
  1244. itemTableList.push(group);
  1245. itemHeadder.push(groupDynamicHeader[i])
  1246. isShowSplitLine.push(false);//是否显示表格底部的分割线
  1247. //页码
  1248. // this.modulePageData.push(lastPageNum + key + 1);
  1249. //当前表格分页页码
  1250. itemTablePagesNum.push(lastPageNum + key + 1);
  1251. //高度
  1252. const tableHeight = group.length > 0 ? (tableHeadHeight * headNum) + tableTitle + tableGap + group.length * 40 : 0;
  1253. moduleHeightData.push(tableHeight)
  1254. }
  1255. }else{
  1256. const tableData1 = tableData.slice(0,remainTableRow);
  1257. const tableData2 = tableData.slice(remainTableRow);
  1258. itemTableList.push(tableData1,tableData2);
  1259. itemHeadder.push(groupDynamicHeader[i],groupDynamicHeader[i])
  1260. // this.modulePageData.push(lastPageNum,lastPageNum);
  1261. //页码
  1262. itemTablePagesNum.push(lastPageNum,lastPageNum)
  1263. //高度
  1264. const tableHeight1 = tableData1.length > 0 ? (tableHeadHeight * headNum) + tableTitle + tableGap + tableData1.length * 40 : 0;
  1265. const tableHeight2 = tableData2.length > 0 ? (tableHeadHeight * headNum) + tableTitle + tableGap + tableData2.length * 40 : 0;
  1266. moduleHeightData.push(tableHeight1,tableHeight2)
  1267. }
  1268. }else{
  1269. const pageTableHeight = this.printPageHeight - (tableHeadHeight * headNum) - tableTitle - 41;// 一页能放下的table的高度 41 是距离底部的边距
  1270. const tableRowNum = Math.floor(pageTableHeight / 40);//一页可放多少行
  1271. // 按步长遍历,每次截取 表格行数 元素
  1272. for (let j = 0; j < tableData.length; j += tableRowNum) {
  1273. const group = tableData.slice(j, j + tableRowNum);
  1274. const key = j/tableRowNum;
  1275. //表格数据
  1276. itemTableList.push(group);
  1277. itemHeadder.push(groupDynamicHeader[i])
  1278. // this.modulePageData.push(lastPageNum + key + 1);
  1279. //页码
  1280. itemTablePagesNum.push(lastPageNum + key + 1)
  1281. //高度
  1282. const tableHeight = group.length > 0 ? (tableHeadHeight * headNum) + tableTitle + tableGap + group.length * 40 : 0;
  1283. moduleHeightData.push(tableHeight)
  1284. }
  1285. }
  1286. this.modulePageData.push(...itemTablePagesNum);
  1287. this.moduleHeightData.push(...moduleHeightData);
  1288. // console.log(this.modulePageData,111333)
  1289. tableList.push(itemTableList)
  1290. headerList.push(itemHeadder)
  1291. tablePagesNum.push(itemTablePagesNum);//当前模块表格的分页页码
  1292. }
  1293. return {headerList,tablePagesNum,tableList}
  1294. },
  1295. /*
  1296. *单个图分页
  1297. *chartHeight 图表高度
  1298. */
  1299. SingleChartPage(chartHeight){
  1300. let chartPagesNum = '';//各分析图 高度
  1301. const prevModuleLastPageNum = this.modulePageData.length > 0 ? this.modulePageData[this.modulePageData.length - 1] : 1;//上一模块 最后一页页码
  1302. //上一模块最后一页高度 和 当前模块 echart高度
  1303. let prevModuleLastPageHeight = [],moduleChartHeight = [];
  1304. this.modulePageData.forEach((item,i)=>{
  1305. if(item == prevModuleLastPageNum){
  1306. prevModuleLastPageHeight.push(this.moduleHeightData[i])
  1307. moduleChartHeight.push(this.moduleHeightData[i]);//最后一页高度
  1308. }
  1309. })
  1310. // 将当前模块 echart高度
  1311. this.moduleHeightData.push(chartHeight)
  1312. moduleChartHeight.push(chartHeight)
  1313. //进行分页 满足一页的高度放在一起
  1314. const printPageGroup = this.groupByThreshold([...moduleChartHeight], this.printPageHeight);
  1315. //每个模块对应的页码
  1316. for (let i = 0; i < printPageGroup.length; i++) {
  1317. const arr = printPageGroup[i]
  1318. for (let j = 0; j < arr.length; j++) {
  1319. if(i == 0){//第一页
  1320. if(j > prevModuleLastPageHeight.length - 1){
  1321. this.modulePageData.push(prevModuleLastPageNum)
  1322. chartPagesNum = prevModuleLastPageNum
  1323. }
  1324. }else{
  1325. this.modulePageData.push(prevModuleLastPageNum + i);
  1326. chartPagesNum = prevModuleLastPageNum + i
  1327. }
  1328. }
  1329. }
  1330. return chartPagesNum
  1331. },
  1332. GetDifficultyClass(val) {
  1333. if (val == 1) {
  1334. return 'difficulty easy'
  1335. } else if (val == 2) {
  1336. return 'difficulty relatively_easy'
  1337. } else if (val == 3) {
  1338. return 'difficulty general'
  1339. } else if (val == 4) {
  1340. return 'difficulty more_difficult'
  1341. } else if (val == 5) {
  1342. return 'difficulty difficult'
  1343. } else {
  1344. return ''
  1345. }
  1346. },
  1347. GetDifficultyName(val) {
  1348. if (val == 1) {
  1349. return '容易'
  1350. } else if (val == 2) {
  1351. return '较易'
  1352. } else if (val == 3) {
  1353. return '一般'
  1354. } else if (val == 4) {
  1355. return '较难'
  1356. } else if (val == 5) {
  1357. return '困难'
  1358. } else {
  1359. return '-'
  1360. }
  1361. },
  1362. GetGroupClassValue(data,prop,code){
  1363. const obj = data.find(item=>item.classGroupCode==code);
  1364. const val = prop=='groupClassRanks'?obj?.classGroupRankRate:obj?.groupClassResultScore;
  1365. return val ?? '-'
  1366. },
  1367. //点击顶部下载PDF按钮导出
  1368. DownloadPdf(){
  1369. if(this.$refs.bookFlipBox){
  1370. this.$refs.bookFlipBox.DownloadPdfNew();
  1371. }
  1372. },
  1373. //向父级页面传值关闭下载Pdf按钮loading
  1374. PdfLoadEnd(){
  1375. this.$emit('closePdfLoading')
  1376. },
  1377. }
  1378. };
  1379. </script>
  1380. <style scoped lang="scss">
  1381. .area_module_describe{
  1382. margin-top: 20px;
  1383. }
  1384. .card-container {
  1385. display: flex;
  1386. flex-wrap: wrap;
  1387. /* 允许换行 */
  1388. /* 设置元素之间间隔 */
  1389. gap: 10px;
  1390. .card {
  1391. // flex: 0 1 calc((100% - 240px) / 5);
  1392. flex-grow: 1; /* 使每个div平分可用空间 */
  1393. flex-basis: 0; /* 初始基础大小为0 */
  1394. width: 20%;
  1395. // max-width: 320px;
  1396. // width: 238px;
  1397. /* 每个卡片占据 18% 宽度,确保能在一行显示五个,考虑间隔 */
  1398. // flex: 0 0 16.5%; /* 每个卡片占据 18% 宽度,确保能在一行显示五个,考虑间隔 */
  1399. // border: 2px dashed #ccc;
  1400. border-radius: 10px;
  1401. padding: 12px 6px;
  1402. box-sizing: border-box;
  1403. text-align: center;
  1404. color: #fff;
  1405. /* 文字颜色可以根据背景调整 */
  1406. background-size: cover;
  1407. background-position: center;
  1408. height: 70px;
  1409. /* 可调整高度 */
  1410. // margin-bottom: 20px; /* 卡片底部间距 */
  1411. position: relative;
  1412. }
  1413. .background-image {
  1414. position: absolute;
  1415. top: 0;
  1416. right: 0;
  1417. /* 背景图片宽度 */
  1418. width: 100%;
  1419. height: 70px;
  1420. background-size: contain;
  1421. background-repeat: no-repeat;
  1422. background-position: center right;
  1423. z-index: 1;
  1424. /* 确保背景图片在文本之下 */
  1425. border-radius: 10px;
  1426. }
  1427. .statistic,.value {
  1428. position: relative;
  1429. z-index: 2;
  1430. /* 确保文本在背景图片之上 */
  1431. }
  1432. .statistic {
  1433. font-size: 13px;
  1434. font-weight: 400;
  1435. line-height: 22px;
  1436. text-align: left;
  1437. z-index: 2;
  1438. }
  1439. .value {
  1440. font-size: 16px;
  1441. font-weight: 600;
  1442. line-height: 20px;
  1443. text-align: left;
  1444. margin-top: 5px;
  1445. z-index: 2;
  1446. }
  1447. }
  1448. .area_module{
  1449. .area_module_content{
  1450. display: flex;
  1451. width: 100%;
  1452. justify-content: space-between;
  1453. .area_module_chart{
  1454. width: 35% !important;
  1455. }
  1456. .area_module_table{
  1457. width: 65% !important;
  1458. }
  1459. }
  1460. .area_module_chart{
  1461. &.justify_content{
  1462. display: flex;
  1463. gap: 0px 48px;
  1464. flex-wrap: wrap;
  1465. .item_progress{
  1466. width: 170px;
  1467. height: 180px;
  1468. display: inline-flex;
  1469. align-items: center;
  1470. position: relative;
  1471. :deep(.el-progress--circle) {
  1472. .el-progress__text{
  1473. font-size: 14px !important;
  1474. color: #5470C6 !important;
  1475. background: rgba(84,112,198,0.1);
  1476. width: 120px;
  1477. height: 120px;
  1478. border-radius: 50%;
  1479. position: absolute;
  1480. left: 50%;
  1481. top: 50%;
  1482. transform: translate(-50%, -50%);
  1483. display: flex;
  1484. align-items: center;
  1485. justify-content: center;
  1486. padding-top: 30px;
  1487. box-sizing: border-box;
  1488. }
  1489. }
  1490. .item_progress_name{
  1491. position: absolute;
  1492. left: 50%;
  1493. top: 37%;
  1494. transform: translate(-50%,0);
  1495. font-weight: 500;
  1496. font-size: 16px !important;
  1497. color: #5470C6 !important;
  1498. }
  1499. }
  1500. }
  1501. }
  1502. .area_module_table{
  1503. &.error{
  1504. :deep() .el-table{
  1505. .el-table__header-wrapper{
  1506. .el-table__header{
  1507. .is-group{
  1508. tr{
  1509. th.el-table__cell:nth-last-child(3){
  1510. border-right: 1px solid #EBEEF5;
  1511. }
  1512. &:nth-child(2){
  1513. display:none;
  1514. }
  1515. }
  1516. }
  1517. }
  1518. }
  1519. .el-table__cell{
  1520. &.white_space_normal{
  1521. .cell{
  1522. white-space: normal;
  1523. padding:10px 0 10px 10px !important;
  1524. }
  1525. }
  1526. }
  1527. // &.el-table--striped {
  1528. // .el-table__body {
  1529. // tr{
  1530. // &.el-table__row--striped{
  1531. // &.row_color_FFFFFF {
  1532. // td.el-table__cell{
  1533. // background: #FFFFFF;
  1534. // }
  1535. // }
  1536. // }
  1537. // }
  1538. // }
  1539. // }
  1540. // &.el-table--striped .el-table__body tr.el-table__row.row_color_FAFAFA td.el-table__cell{
  1541. // background: #FAFAFA;
  1542. // }
  1543. // &.el-table--striped .el-table__body tr.el-table__row--striped.row_color_FAFAFA td.el-table__cell{
  1544. // background: #FAFAFA;
  1545. // }
  1546. // &.el-table--enable-row-hover .el-table__body tr.row_color_FFFFFF:hover > td {
  1547. // background-color: transparent !important;
  1548. // }
  1549. }
  1550. }
  1551. .student_know_paper{
  1552. width: 100%;
  1553. box-sizing: border-box;
  1554. display: flex;
  1555. flex-direction: column;
  1556. border-radius: 6px;
  1557. border: 1px solid #EBEEF5;
  1558. li{
  1559. width: 100%;
  1560. border-top: 1px solid #EBEEF5;
  1561. box-sizing: border-box;
  1562. display: inline-flex;
  1563. &:first-child{
  1564. border-top: 0;
  1565. .li_left{
  1566. background-color: #EEF1FB;
  1567. span{
  1568. color: #5470C6;
  1569. }
  1570. }
  1571. }
  1572. &:nth-child(2){
  1573. .li_left{
  1574. background-color: #ECF6F1;
  1575. span{
  1576. color: #3BA272;
  1577. }
  1578. }
  1579. }
  1580. &:nth-child(3){
  1581. .li_left{
  1582. background-color: #FFFAEF;
  1583. span{
  1584. color: #FAC858;
  1585. }
  1586. }
  1587. }
  1588. .li_left{
  1589. width: 300px;
  1590. padding: 24px;
  1591. border-right: 1px solid #EBEEF5;
  1592. box-sizing: border-box;
  1593. display: inline-flex;
  1594. flex-direction: column;
  1595. justify-content: center;
  1596. flex-shrink: 0;
  1597. span{
  1598. font-weight: 500;
  1599. font-size: 20px;
  1600. line-height: 28px;
  1601. display: block;
  1602. text-align: center;
  1603. &:nth-child(2){
  1604. margin-top: 4px;
  1605. line-height: 20px;
  1606. font-weight: 400;
  1607. font-size: 14px;
  1608. color: #999999;
  1609. }
  1610. }
  1611. }
  1612. .li_know{
  1613. flex: 1;
  1614. padding: 20px;
  1615. box-sizing: border-box;
  1616. font-weight: 400;
  1617. font-size: 14px;
  1618. color: #666666;
  1619. line-height: 24px;
  1620. text-align: justified;
  1621. display: inline-flex;
  1622. align-items: center;
  1623. }
  1624. }
  1625. }
  1626. }
  1627. .difficulty {
  1628. width: 6px;
  1629. height: 6px;
  1630. display: inline-flex;
  1631. border-radius: 50%;
  1632. margin-right: 4px;
  1633. &.easy {
  1634. background: #3ba272;
  1635. }
  1636. &.relatively_easy {
  1637. background: #fac858;
  1638. }
  1639. &.general {
  1640. background: #5470c6;
  1641. }
  1642. &.more_difficult {
  1643. background: #ea7acb;
  1644. }
  1645. &.difficult {
  1646. background: #ee6666;
  1647. }
  1648. }
  1649. }
  1650. </style>