风险测评小程序前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
9.7 KiB

  1. <template>
  2. <view class="page__view">
  3. <navbar title="答题测评" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" />
  4. <!-- 答题完成 -->
  5. <template v-if="total && current === total">
  6. <view class="flex main is-finish">
  7. <view class="card">
  8. <image class="card-bg" src="@/pages_order/static/test/bg-test-finsih.png" mode="widthFix"></image>
  9. <view class="flex flex-column card-content">
  10. <view class="text">恭喜你</view>
  11. <view class="text">您已完成所有测评题目</view>
  12. <button class="btn" @click="onCreateReport">生成报告</button>
  13. </view>
  14. </view>
  15. </view>
  16. </template>
  17. <!-- 答题中 -->
  18. <template v-else-if="currentQuestion">
  19. <view class="bar">
  20. <view class="flex info">
  21. <view>答题进度</view>
  22. <view>
  23. <text class="highlight">{{ current + 1 }}</text>
  24. <text>{{ `/${total}` }}</text>
  25. </view>
  26. </view>
  27. <view class="progress">
  28. <view class="progress-bar" :style="{ width: `${progress}%` }"></view>
  29. </view>
  30. </view>
  31. <view class="main">
  32. <view class="card">
  33. <view class="card-header">
  34. <view class="flex tips">
  35. <image class="icon" src="@/pages_order/static/test/icon-warning.png" mode="widthFix"></image>
  36. <view>请根据真实情况谨慎作答点击下一题提交答案无法更改</view>
  37. </view>
  38. <view class="question">{{ currentQuestion.question }}</view>
  39. </view>
  40. <view class="card-content">
  41. <view class="select">
  42. <view
  43. v-for="item in currentQuestion.options"
  44. :key="item.id"
  45. :class="['select-option', item.id === value ? 'is-active' : '']"
  46. @click="onSelect(item.id)"
  47. >
  48. {{ item.content }}
  49. </view>
  50. </view>
  51. </view>
  52. </view>
  53. </view>
  54. <view class="bottom">
  55. <button v-if="isLast" class="btn" @click="finish">提交</button>
  56. <button v-else class="btn" @click="next">下一题</button>
  57. </view>
  58. </template>
  59. </view>
  60. </template>
  61. <script>
  62. export default {
  63. data() {
  64. return {
  65. current: null,
  66. tabs: [],
  67. value: null,
  68. answers: [],
  69. batchNo: null,
  70. questionsList: [],
  71. total: 0,
  72. }
  73. },
  74. computed: {
  75. preIdx() {
  76. let index = this.tabs.findIndex(index => index === this.current)
  77. return index - 1
  78. },
  79. progress() {
  80. return 100 * (this.current + 1) / this.total
  81. },
  82. isLast() {
  83. return this.progress === 100
  84. },
  85. currentQuestion() {
  86. return this.questionsList[this.current]
  87. },
  88. },
  89. onLoad(arg) {
  90. const { ids, examId, current } = arg
  91. this.current = parseInt(current || 0)
  92. this.fetchQuestionList(ids, examId)
  93. this.value = this.answers[this.current]
  94. console.log('currentQuestion', this.currentQuestion)
  95. },
  96. methods: {
  97. async fetchQuestionList(categories, examId) {
  98. let result
  99. if (examId) {
  100. result = await this.$fetch('queryExamById', { examId })
  101. } else {
  102. result = await this.$fetch('queryQuestionList', { categories })
  103. }
  104. const { batchNo, pageList } = result
  105. this.batchNo = batchNo
  106. this.questionsList = pageList.map((item, index) => {
  107. const { id, question, answerList } = item
  108. return {
  109. id,
  110. // question: `${index + 1}、${question}`,
  111. question,
  112. options: answerList.map((option, oIdx) => {
  113. return {
  114. id: option.id,
  115. // content: `${String.fromCharCode(oIdx+65)}、${option.answer}`
  116. content: `${option.answerNo}${option.answer}`
  117. }
  118. }),
  119. }
  120. })
  121. this.total = this.questionsList.length
  122. this.answers = this.questionsList.map(() => null)
  123. console.log('questionsList', this.questionsList)
  124. console.log('answers', this.answers)
  125. },
  126. async fetchAnswer() {
  127. try {
  128. const { id: questionId } = this.currentQuestion
  129. console.log('currentQuestion', this.currentQuestion)
  130. console.log('value', this.value)
  131. if (!this.value) {
  132. console.log('未答题')
  133. uni.showToast({
  134. title: '请答题',
  135. icon:'none'
  136. })
  137. return false
  138. }
  139. let params = {
  140. batchNo: this.batchNo,
  141. questionId,
  142. answerId: this.value,
  143. }
  144. await this.$fetch('updateAnswer', params)
  145. this.answers[this.current] = this.value
  146. return true
  147. } catch (err) {
  148. console.log('fetchAnswer', err)
  149. return false
  150. }
  151. },
  152. async fetchFinish() {
  153. // todo: delete
  154. // todo
  155. // await this.$fetch('submitPaper', { id: this.paperInfo.reportId })
  156. this.current = this.total
  157. console.log('fetchFinish', this.current, this.currentQuestion)
  158. // todo
  159. // uni.reLaunch({
  160. // url: '/pages/index/report'
  161. // })
  162. },
  163. async next() {
  164. let succ = await this.fetchAnswer()
  165. if (!succ) {
  166. return
  167. }
  168. this.current += 1
  169. this.value = this.answers[this.current]
  170. },
  171. async finish() {
  172. let succ = await this.fetchAnswer()
  173. if (!succ) {
  174. return
  175. }
  176. this.fetchFinish()
  177. },
  178. async onSelect(id) {
  179. this.value = id
  180. },
  181. async onSelectMulitple(id) {
  182. this.value = this.value.includes(id) ? this.value.filter(item => item !== id) : this.value.concat(id)
  183. },
  184. onCreateReport() {
  185. uni.redirectTo({
  186. url: `/pages_order/report/pay?batchNo=${this.batchNo}`
  187. })
  188. },
  189. },
  190. }
  191. </script>
  192. <style scoped lang="scss">
  193. .page__view {
  194. width: 100vw;
  195. min-height: 100vh;
  196. background: linear-gradient(164deg, #014FA2, #014FA2, #2E8AED);
  197. position: relative;
  198. }
  199. .bar {
  200. margin-top: 42rpx;
  201. width: 100%;
  202. padding: 0 47rpx;
  203. box-sizing: border-box;
  204. .info {
  205. justify-content: flex-start;
  206. column-gap: 13rpx;
  207. font-size: 28rpx;
  208. color: #A1D6FF;
  209. .highlight {
  210. color: #FFFFFF;
  211. margin-right: 8rpx;
  212. }
  213. }
  214. .progress {
  215. margin-top: 20rpx;
  216. width: 100%;
  217. height: 16rpx;
  218. background: rgba($color: #FFFFFF, $alpha: 0.35);
  219. border-radius: 8rpx;
  220. &-bar {
  221. height: 100%;
  222. background: #FFFFFF;
  223. border-radius: 8rpx;
  224. }
  225. }
  226. }
  227. .main {
  228. width: 100%;
  229. padding: 73rpx 33rpx;
  230. box-sizing: border-box;
  231. }
  232. .card {
  233. position: relative;
  234. width: 100%;
  235. min-height: 876rpx;
  236. padding: 27rpx 0;
  237. box-sizing: border-box;
  238. background: #FFFFFF;
  239. border-radius: 16rpx;
  240. &:after {
  241. content: ' ';
  242. position: absolute;
  243. bottom: 0;
  244. left: 50%;
  245. transform: translate(-50%, 100%);
  246. width: calc(100% - 20rpx * 2);
  247. height: 28rpx;
  248. background: rgba($color: #E9EFF2, $alpha: 0.29);
  249. border-bottom-left-radius: 16rpx;
  250. border-bottom-right-radius: 16rpx;
  251. }
  252. &-header {
  253. padding: 0 33rpx;
  254. .tips {
  255. column-gap: 3rpx;
  256. padding: 12rpx 5rpx;
  257. font-size: 22rpx;
  258. color: #DB5742;
  259. border: 3rpx solid #DB5742;
  260. border-radius: 7rpx;
  261. margin-bottom: 26rpx;
  262. .icon {
  263. width: 31rpx;
  264. height: auto;
  265. }
  266. }
  267. }
  268. &-content {
  269. padding: 0 24rpx;
  270. }
  271. }
  272. .question {
  273. font-family: PingFang SC;
  274. font-weight: 400;
  275. font-size: 28rpx;
  276. line-height: 50rpx;
  277. color: #000000;
  278. margin-bottom: 64rpx;
  279. }
  280. .select {
  281. &-option {
  282. margin-top: 44rpx;
  283. padding: 22rpx 28rpx;
  284. line-height: 1.3;
  285. font-size: 28rpx;
  286. color: #707070;
  287. background: #F3F3F3;
  288. border-radius: 28rpx;
  289. &.is-active {
  290. color: #014FA2;
  291. background: rgba($color: #014FA2, $alpha: 0.22);
  292. }
  293. }
  294. }
  295. .bottom {
  296. position: fixed;
  297. left: 0;
  298. bottom: 0;
  299. width: 100%;
  300. padding: 17rpx 72rpx;
  301. padding-bottom: calc(env(safe-area-inset-bottom) + 17rpx);
  302. background: #FFFFFF;
  303. box-sizing: border-box;
  304. .btn {
  305. width: 100%;
  306. padding: 26rpx 0;
  307. font-size: 30rpx;
  308. line-height: 1.4;
  309. color: #FFFFFF;
  310. background: #014FA2;
  311. border-radius: 42rpx;
  312. }
  313. }
  314. .desc {
  315. margin-top: 220rpx;
  316. font-family: PingFang SC;
  317. font-weight: 400;
  318. line-height: 1.4;
  319. font-size: 26rpx;
  320. color: #989898;
  321. }
  322. .main.is-finish {
  323. height: calc(100vh - (var(--status-bar-height) + 120rpx));
  324. padding: 0 33rpx;
  325. padding-bottom: calc(var(--status-bar-height) + 120rpx);
  326. .card {
  327. min-height: 745rpx;
  328. padding: 0;
  329. background: transparent;
  330. &-bg {
  331. width: 100%;
  332. height: auto;
  333. }
  334. &-content {
  335. position: absolute;
  336. top: 0;
  337. left: 0;
  338. justify-content: flex-end;
  339. width: 100%;
  340. height: 100%;
  341. padding: 69rpx 94rpx;
  342. box-sizing: border-box;
  343. .text {
  344. font-size: 32rpx;
  345. font-weight: 600;
  346. color: #000000;
  347. }
  348. .text + .text {
  349. margin-top: 45rpx;
  350. }
  351. .btn {
  352. margin-top: 139rpx;
  353. padding: 29rpx 183rpx;
  354. box-sizing: border-box;
  355. line-height: 1.4;
  356. white-space: nowrap;
  357. color: #FFFFFF;
  358. background: #014FA2;
  359. border-radius: 50rpx;
  360. }
  361. }
  362. }
  363. }
  364. </style>