index.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <!-- 刷题练习列表 -->
  2. <template>
  3. <view class="safetyEducationExamination-practice">
  4. <!-- 顶部类型标签 -->
  5. <view class="tag-bar" v-if="!hideTagBar">
  6. <scroll-view scroll-x class="tag-scroll">
  7. <view class="tag-scroll-inner">
  8. <text
  9. v-for="(tag, index) in typeTags"
  10. :key="index"
  11. class="tag-item"
  12. :class="{ 'tag-item-active': activeTagIndex === index }"
  13. @click="onTagChange(index)"
  14. >{{ tag.label }}</text>
  15. </view>
  16. </scroll-view>
  17. </view>
  18. <!-- 列表 -->
  19. <scroll-view scroll-y class="scroll-content">
  20. <view class="panel">
  21. <view
  22. v-for="(item, index) in practiceList"
  23. :key="index"
  24. class="practice-card"
  25. @click="goToPractice(item)"
  26. >
  27. <view class="card-top">
  28. <text class="tag" :class="item.tagClass">{{ item.knowledgePointName }}</text>
  29. <text class="total-count" :style="'color:' + item.progressColor">{{ item.totalCount }} 题</text>
  30. </view>
  31. <text class="card-title">{{ item.knowledgePointName }}</text>
  32. <text class="card-sub" :class="item.practiceStatus > 0 ? '' : 'text-gray'">
  33. {{ item.practiceStatus > 0 ? '已答 ' + item.answeredCount + ' 题 · 正确率 ' + item.correctRate + '%' : '未开始' }}
  34. </text>
  35. <view class="progress-row">
  36. <view class="progress-wrap">
  37. <view class="progress-bar" :style="'width:' + (item.progress || 0) + '%;background:' + item.progressColor"></view>
  38. </view>
  39. <text class="progress-text" :style="'color:' + item.progressColor">{{ item.progress || 0 }}%</text>
  40. </view>
  41. </view>
  42. <view v-if="!practiceList[0] && !loading" class="empty-tip">暂无题库数据</view>
  43. <view v-if="loading" class="loading-tip">加载中...</view>
  44. </view>
  45. </scroll-view>
  46. </view>
  47. </template>
  48. <script>
  49. import {
  50. examUserPracticeList,
  51. examElKnowledgePointTreeList,
  52. } from '@/pages_safetyEducationExamination/api/index.js'
  53. // 根据索引返回标签样式类和进度条颜色
  54. const TAG_COLORS = [
  55. { tagClass: 'tag-blue', color: '#1677ff' },
  56. { tagClass: 'tag-green', color: '#52c41a' },
  57. { tagClass: 'tag-orange', color: '#fa8c16' },
  58. { tagClass: 'tag-purple', color: '#722ed1' },
  59. { tagClass: 'tag-cyan', color: '#13c2c2' },
  60. ];
  61. export default {
  62. data() {
  63. return {
  64. typeTags: [{ label: '全部', value: null }],
  65. activeTagIndex: 0,
  66. practiceList: [],
  67. loading: false,
  68. // 跳转参数
  69. hideTagBar: false,
  70. disciplineTypeId: null,
  71. knowledgePointId: null,
  72. }
  73. },
  74. onLoad(options) {
  75. // 接收跳转参数
  76. if (options.disciplineTypeId || options.knowledgePointId) {
  77. this.disciplineTypeId = options.disciplineTypeId || null;
  78. this.knowledgePointId = options.knowledgePointId || null;
  79. this.hideTagBar = true;
  80. }
  81. },
  82. created() {
  83. this.loadTypeTags();
  84. },
  85. onShow() {
  86. this.loadPracticeList();
  87. },
  88. methods: {
  89. // 加载知识点类型标签(dataScope=2)
  90. async loadTypeTags() {
  91. try {
  92. const { data } = await examElKnowledgePointTreeList({ dataScope: 2 });
  93. if (data.code === 200 && data.data) {
  94. const tags = (data.data || []).map(item => ({
  95. label: item.knowledgePointName,
  96. value: item.id,
  97. }));
  98. this.$set(this, 'typeTags', [{ label: '全部', value: null }, ...tags]);
  99. }
  100. } catch (e) {
  101. console.error('获取知识点类型失败', e);
  102. }
  103. },
  104. // 加载题库分组列表
  105. async loadPracticeList() {
  106. if (this.loading) return;
  107. this.loading = true;
  108. try {
  109. const tag = this.typeTags[this.activeTagIndex];
  110. const obj = {
  111. page: 1,
  112. pageSize: 50,
  113. knowledgePointId: this.knowledgePointId || tag.value || undefined,
  114. disciplineTypeId: this.disciplineTypeId || undefined,
  115. };
  116. const { data } = await examUserPracticeList(obj);
  117. if (data.code === 200) {
  118. const records = (data.data.records || []).map((item, index) => {
  119. const colorInfo = TAG_COLORS[index % TAG_COLORS.length];
  120. return {
  121. ...item,
  122. tagClass: colorInfo.tagClass,
  123. progressColor: item.practiceStatus > 0 ? colorInfo.color : '#bbb',
  124. };
  125. });
  126. this.$set(this, 'practiceList', records);
  127. }
  128. } catch (e) {
  129. console.error('获取题库列表失败', e);
  130. } finally {
  131. this.loading = false;
  132. }
  133. },
  134. onTagChange(index) {
  135. this.activeTagIndex = index;
  136. this.loadPracticeList();
  137. },
  138. goToPractice(item) {
  139. // 跳转刷题详情,传递 knowledgePointId
  140. },
  141. },
  142. }
  143. </script>
  144. <style lang="stylus" scoped>
  145. .safetyEducationExamination-practice
  146. height 100%
  147. display flex
  148. flex-direction column
  149. overflow hidden
  150. background-color #f0f4fb
  151. // 顶部标签栏
  152. .tag-bar
  153. background #fff
  154. border-bottom 1rpx solid #e8edf3
  155. flex-shrink 0
  156. padding 0 24rpx
  157. .tag-scroll
  158. white-space nowrap
  159. .tag-scroll-inner
  160. display inline-flex
  161. gap 16rpx
  162. padding 16rpx 0
  163. .tag-item
  164. display inline-block
  165. font-size 24rpx
  166. padding 10rpx 24rpx
  167. border-radius 30rpx
  168. background #eef1f6
  169. color #666
  170. border 1rpx solid transparent
  171. white-space nowrap
  172. .tag-item-active
  173. background #e6f0ff
  174. color #1677ff
  175. border-color #91caff
  176. font-weight 600
  177. // 内容滚动区
  178. .scroll-content
  179. flex 1
  180. overflow hidden
  181. .panel
  182. padding 24rpx
  183. // 题库卡片
  184. .practice-card
  185. background #fff
  186. border-radius 20rpx
  187. padding 24rpx 28rpx
  188. margin-bottom 20rpx
  189. box-shadow 0 2rpx 12rpx rgba(0,0,0,0.04)
  190. border 1rpx solid #dde3ed
  191. .card-top
  192. display flex
  193. justify-content space-between
  194. align-items center
  195. margin-bottom 16rpx
  196. // 标签
  197. .tag
  198. font-size 20rpx
  199. padding 4rpx 12rpx
  200. border-radius 8rpx
  201. border 1rpx solid transparent
  202. .tag-blue
  203. background #e6f4ff
  204. color #1677ff
  205. border-color #91caff
  206. .tag-green
  207. background #f6ffed
  208. color #389e0d
  209. border-color #b7eb8f
  210. .tag-orange
  211. background #fff7e6
  212. color #d46b08
  213. border-color #ffd591
  214. .tag-purple
  215. background #f9f0ff
  216. color #722ed1
  217. border-color #d3adf7
  218. .tag-cyan
  219. background #e6fffb
  220. color #08979c
  221. border-color #87e8de
  222. .total-count
  223. font-size 22rpx
  224. color #1677ff
  225. font-weight 600
  226. .text-hint
  227. color #bbb
  228. // 卡片文字
  229. .card-title
  230. display block
  231. font-size 28rpx
  232. font-weight 600
  233. color #222
  234. margin-bottom 8rpx
  235. .card-sub
  236. display block
  237. font-size 22rpx
  238. color #666
  239. margin-bottom 16rpx
  240. .text-gray
  241. color #999
  242. // 进度条
  243. .progress-row
  244. display flex
  245. align-items center
  246. gap 12rpx
  247. .progress-wrap
  248. flex 1
  249. height 10rpx
  250. background #eef1f6
  251. border-radius 10rpx
  252. overflow hidden
  253. .progress-bar
  254. height 100%
  255. border-radius 10rpx
  256. background #1677ff
  257. transition width 0.3s
  258. .progress-text
  259. font-size 22rpx
  260. font-weight 700
  261. width 64rpx
  262. text-align right
  263. // 提示
  264. .empty-tip
  265. text-align center
  266. line-height 80rpx
  267. color #aaa
  268. font-size 24rpx
  269. .loading-tip
  270. text-align center
  271. line-height 60rpx
  272. color #aaa
  273. font-size 22rpx
  274. </style>