incorrectQuestionsList.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <!-- 历史错题 -->
  2. <template>
  3. <view class="safetyEducationExamination-incorrectQuestions">
  4. <!-- 顶部知识点标签 -->
  5. <!-- <scroll-view scroll-x class="tag-scroll">
  6. <view class="tag-scroll-inner">
  7. <text
  8. v-for="(tag, index) in typeTags"
  9. :key="index"
  10. class="filter-tag"
  11. :class="{ 'filter-tag-active': activeTagIndex === index }"
  12. @click="onTagChange(index)"
  13. >{{ tag.label }}</text>
  14. </view>
  15. </scroll-view> -->
  16. <!-- 错题列表 -->
  17. <scroll-view scroll-y class="scroll-content" @scrolltolower="onScrollToLower">
  18. <view class="panel">
  19. <view v-for="(item, index) in questionList" :key="index" class="question-card">
  20. <view class="row-between mb8">
  21. <view class="q-head">
  22. <text class="q-type-badge">{{ questionTypeName(item.questionType) }}</text>
  23. <text v-if="examName" class="text-xs text-gray q-exam-name">{{ examName }}</text>
  24. </view>
  25. <text class="tag text-xs" :class="item.errorCount >= 3 ? 'tag-red' : 'tag-orange'">答错{{ item.errorCount || 0 }}次</text>
  26. </view>
  27. <view class="q-content">
  28. <text class="text-sm">{{ item.questionContent }}</text>
  29. </view>
  30. <view v-if="item.userAnswer || item.correctAnswer" class="answer-box">
  31. <view v-if="item.userAnswer" class="mb4">
  32. <text class="text-xs text-gray">我的答案:</text>
  33. <text class="text-xs text-red fw500">{{ item.userAnswer }}</text>
  34. </view>
  35. <view v-if="item.correctAnswer">
  36. <text class="text-xs text-gray">正确答案:</text>
  37. <text class="text-xs text-green fw500">{{ item.correctAnswer }}</text>
  38. </view>
  39. </view>
  40. <view v-if="item.analysis" class="analysis-box">
  41. <text>解析:{{ item.analysis }}</text>
  42. </view>
  43. </view>
  44. <view v-if="!questionList[0] && !loading" class="empty-tip">暂无错题记录</view>
  45. <view v-if="loading" class="loading-tip">加载中...</view>
  46. <view v-if="noMore && questionList[0]" class="loading-tip">没有更多了</view>
  47. </view>
  48. </scroll-view>
  49. </view>
  50. </template>
  51. <script>
  52. import {
  53. examElKnowledgePointTreeList,
  54. examElExamAttemptAnswerAttemptAnswer,
  55. } from '@/pages_safetyEducationExamination/api/index.js'
  56. // 题型映射
  57. const QUESTION_TYPE_MAP = {
  58. 1: '单选题',
  59. 2: '多选题',
  60. 3: '判断题',
  61. };
  62. export default {
  63. data() {
  64. return {
  65. attemptId: '',
  66. examName: '',
  67. typeTags: [{ label: '全部', value: null }],
  68. activeTagIndex: 0,
  69. questionList: [],
  70. loading: false,
  71. page: 1,
  72. pageSize: 10,
  73. total: 0,
  74. noMore: false,
  75. }
  76. },
  77. onLoad(options) {
  78. this.attemptId = options.attemptId || '';
  79. this.examName = options.examName ? decodeURIComponent(options.examName) : '';
  80. if (!this.attemptId) {
  81. uni.showToast({ title: '考试信息无效', icon: 'none' });
  82. setTimeout(() => uni.navigateBack(), 1500);
  83. return;
  84. }
  85. // this.loadTypeTags();
  86. this.loadQuestionList();
  87. },
  88. methods: {
  89. questionTypeName(type) {
  90. return QUESTION_TYPE_MAP[type] || '';
  91. },
  92. // 知识点标签
  93. async loadTypeTags() {
  94. try {
  95. const { data } = await examElKnowledgePointTreeList({ dataScope: 1 });
  96. if (data.code === 200 && data.data) {
  97. const tags = (data.data || []).map(item => ({
  98. label: item.knowledgePointName,
  99. value: item.id,
  100. }));
  101. this.$set(this, 'typeTags', [{ label: '全部', value: null }, ...tags]);
  102. }
  103. } catch (e) {
  104. console.error('获取知识点类型失败', e);
  105. }
  106. },
  107. onTagChange(index) {
  108. if (this.activeTagIndex === index) return;
  109. this.activeTagIndex = index;
  110. this.resetList();
  111. },
  112. resetList() {
  113. this.page = 1;
  114. this.noMore = false;
  115. this.$set(this, 'questionList', []);
  116. this.loadQuestionList();
  117. },
  118. // 错题列表(分页)
  119. async loadQuestionList() {
  120. if (this.loading || this.noMore) return;
  121. this.loading = true;
  122. try {
  123. // const tag = this.typeTags[this.activeTagIndex];
  124. const { data } = await examElExamAttemptAnswerAttemptAnswer({
  125. page: this.page,
  126. pageSize: this.pageSize,
  127. attemptId: this.attemptId,
  128. // knowledgePointId: tag ? tag.value : undefined,
  129. });
  130. if (data.code === 200) {
  131. const records = data.data.records || [];
  132. const newList = this.page === 1 ? records : [...this.questionList, ...records];
  133. this.$set(this, 'questionList', newList);
  134. this.total = data.data.total;
  135. if (newList.length >= this.total) {
  136. this.noMore = true;
  137. } else {
  138. this.page++;
  139. }
  140. }
  141. } catch (e) {
  142. console.error('获取错题列表失败', e);
  143. } finally {
  144. this.loading = false;
  145. }
  146. },
  147. onScrollToLower() {
  148. this.loadQuestionList();
  149. },
  150. },
  151. }
  152. </script>
  153. <style lang="stylus" scoped>
  154. .safetyEducationExamination-incorrectQuestions
  155. height 100%
  156. display flex
  157. flex-direction column
  158. overflow hidden
  159. background-color #f0f4fb
  160. // 知识点标签横滚
  161. .tag-scroll
  162. background #fff
  163. white-space nowrap
  164. padding 20rpx 24rpx 16rpx
  165. flex-shrink 0
  166. .tag-scroll-inner
  167. display inline-flex
  168. gap 16rpx
  169. .filter-tag
  170. display inline-block
  171. font-size 22rpx
  172. padding 10rpx 24rpx
  173. border-radius 40rpx
  174. background #f4f6fa
  175. color #8896a7
  176. white-space nowrap
  177. .filter-tag-active
  178. background #1857d4
  179. color #fff
  180. box-shadow 0 4rpx 16rpx rgba(24,87,212,0.3)
  181. // 滚动区
  182. .scroll-content
  183. flex 1
  184. overflow hidden
  185. .panel
  186. padding 16rpx 24rpx 32rpx
  187. // 错题卡片
  188. .question-card
  189. background #fff
  190. border 1rpx solid #dde3ed
  191. border-radius 20rpx
  192. padding 28rpx
  193. margin-bottom 20rpx
  194. .row-between
  195. display flex
  196. align-items center
  197. justify-content space-between
  198. .q-head
  199. display flex
  200. align-items center
  201. .q-type-badge
  202. background #1857d4
  203. color #fff
  204. font-size 24rpx
  205. padding 4rpx 16rpx
  206. border-radius 8rpx
  207. .q-exam-name
  208. margin-left 16rpx
  209. .q-content
  210. line-height 1.7
  211. margin-bottom 20rpx
  212. // 答案区
  213. .answer-box
  214. background #f4f6fa
  215. border-radius 16rpx
  216. padding 20rpx
  217. margin-bottom 20rpx
  218. // 解析区
  219. .analysis-box
  220. background #f6ffed
  221. border-radius 16rpx
  222. padding 20rpx
  223. font-size 26rpx
  224. line-height 1.7
  225. color #4a5568
  226. // 标签
  227. .tag
  228. display inline-flex
  229. align-items center
  230. padding 4rpx 16rpx
  231. border-radius 40rpx
  232. font-weight 500
  233. .tag-orange
  234. background #fef6ec
  235. color #e67e22
  236. .tag-red
  237. background #fff5f5
  238. color #e53e3e
  239. .text-xs
  240. font-size 22rpx
  241. .text-sm
  242. font-size 24rpx
  243. .text-gray
  244. color #8896a7
  245. .text-green
  246. color #0d8f6f
  247. .text-red
  248. color #e53e3e
  249. .fw500
  250. font-weight 500
  251. .mb4
  252. margin-bottom 8rpx
  253. .mb8
  254. margin-bottom 16rpx
  255. // 提示
  256. .empty-tip
  257. text-align center
  258. line-height 80rpx
  259. color #aaa
  260. font-size 24rpx
  261. .loading-tip
  262. text-align center
  263. line-height 60rpx
  264. color #aaa
  265. font-size 22rpx
  266. </style>