mbti-test.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <template>
  2. <view class="mbt-page">
  3. <view class="mbt-header">
  4. <text class="mbt-progress-text">{{ currentIndex + 1 }} / {{ questions.length }}</text>
  5. </view>
  6. <view class="mbt-progress-bar">
  7. <view class="mbt-progress-fill" :style="{ width: progress + '%', background: '#6366F1' }"></view>
  8. </view>
  9. <view class="mbt-loading" v-if="loading">
  10. <text>加载题库...</text>
  11. </view>
  12. <template v-else>
  13. <view class="mbt-card">
  14. <text class="mbt-dim-tag" :style="{ background: currentDimColor }">{{ currentDimName }}</text>
  15. <text class="mbt-q-text">{{ currentQuestion.questionText }}</text>
  16. <view class="mbt-opts">
  17. <view class="mbt-opt" :class="{ 'mbt-opt-sel': answer === 'A' }" @click="selectAnswer('A')">
  18. <text class="mbt-opt-label">{{ currentQuestion.optionA }}</text>
  19. <view class="mbt-opt-radio" :class="{ on: answer === 'A' }"></view>
  20. </view>
  21. <view class="mbt-opt" :class="{ 'mbt-opt-sel': answer === 'B' }" @click="selectAnswer('B')">
  22. <text class="mbt-opt-label">{{ currentQuestion.optionB }}</text>
  23. <view class="mbt-opt-radio" :class="{ on: answer === 'B' }"></view>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="mbt-footer">
  28. <button class="mbt-btn mbt-btn-prev" :disabled="currentIndex === 0" @click="prev">上一题</button>
  29. <button class="mbt-btn mbt-btn-next" :disabled="!answer" @click="next">{{ currentIndex === questions.length - 1 ? '提交' : '下一题' }}</button>
  30. </view>
  31. </template>
  32. </view>
  33. </template>
  34. <script>
  35. import { getMbtiQuestions, submitMbti } from '@/utils/api'
  36. export default {
  37. data() {
  38. return {
  39. loading: true,
  40. questions: [],
  41. answers: {},
  42. currentIndex: 0,
  43. memberId: 0
  44. }
  45. },
  46. computed: {
  47. currentQuestion() { return this.questions[this.currentIndex] || {} },
  48. currentDimName() {
  49. var map = { E: '外向/内向', I: '外向/内向', S: '实感/直觉', N: '实感/直觉', T: '思考/情感', F: '思考/情感', J: '判断/知觉', P: '判断/知觉' }
  50. return map[this.currentQuestion.dimension] || ''
  51. },
  52. currentDimColor() {
  53. var map = { E: '#6366F1', I: '#6366F1', S: '#10B981', N: '#10B981', T: '#FF6B9D', F: '#FF6B9D', J: '#F59E0B', P: '#F59E0B' }
  54. return map[this.currentQuestion.dimension] || '#6366F1'
  55. },
  56. progress() { return this.questions.length > 0 ? Math.round((this.currentIndex + 1) / this.questions.length * 100) : 0 },
  57. answer() { return this.answers[this.currentQuestion.id] || '' }
  58. },
  59. onLoad(options) {
  60. this.memberId = options.memberId ? parseInt(options.memberId) : 0
  61. this.loadQuestions()
  62. },
  63. methods: {
  64. loadQuestions() {
  65. var self = this
  66. getMbtiQuestions().then(function(res) {
  67. if (res.code === 200 && res.data) self.questions = res.data
  68. self.loading = false
  69. }).catch(function() { self.loading = false })
  70. },
  71. selectAnswer(val) { this.answers[this.currentQuestion.id] = val },
  72. prev() { if (this.currentIndex > 0) this.currentIndex-- },
  73. next() {
  74. if (!this.answer) return
  75. if (this.currentIndex < this.questions.length - 1) {
  76. this.currentIndex++
  77. } else {
  78. this.submit()
  79. }
  80. },
  81. submit() {
  82. var self = this
  83. var answers = []
  84. var ids = Object.keys(this.answers)
  85. for (var i = 0; i < ids.length; i++) {
  86. answers.push({ questionId: parseInt(ids[i]), answer: this.answers[ids[i]] })
  87. }
  88. uni.showLoading({ title: '计算中...', mask: true })
  89. submitMbti({ familyMemberId: this.memberId, answers: answers }).then(function(res) {
  90. uni.hideLoading()
  91. if (res.code === 200) {
  92. uni.navigateTo({ url: '/pages/family/mbti-result?id=' + res.data.id })
  93. } else {
  94. uni.showToast({ title: res.message || '提交失败', icon: 'none' })
  95. }
  96. }).catch(function() {
  97. uni.hideLoading()
  98. uni.showToast({ title: '网络异常', icon: 'none' })
  99. })
  100. }
  101. }
  102. }
  103. </script>
  104. <style scoped>
  105. .mbt-page { min-height: 100vh; background: #F5FAFE; padding-bottom: 180rpx }
  106. .mbt-header { padding: 20rpx 30rpx; text-align: right }
  107. .mbt-progress-text { font-size: 24rpx; color: #999 }
  108. .mbt-progress-bar { height: 6rpx; background: #E0E7FF; margin: 0 30rpx; border-radius: 3rpx; overflow: hidden }
  109. .mbt-progress-fill { height: 100%; transition: width .3s }
  110. .mbt-loading { display: flex; justify-content: center; padding: 100rpx 0 }
  111. .mbt-card { background: #fff; margin: 20rpx 30rpx; border-radius: 24rpx; padding: 30rpx 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05) }
  112. .mbt-dim-tag { display: inline-block; font-size: 22rpx; color: #fff; padding: 4rpx 16rpx; border-radius: 16rpx; margin-bottom: 16rpx }
  113. .mbt-q-text { font-size: 30rpx; font-weight: 500; color: #333; line-height: 1.5; margin-bottom: 24rpx }
  114. .mbt-opts { display: flex; flex-direction: column; gap: 16rpx }
  115. .mbt-opt { flex: 1; padding: 24rpx; border: 2rpx solid #F0F0F0; border-radius: 16rpx; display: flex; align-items: center; justify-content: space-between; transition: border-color .2s, background .2s }
  116. .mbt-opt-sel { border-color: #6366F1; background: #F0F4FF }
  117. .mbt-opt-label { font-size: 26rpx; color: #333; line-height: 1.4 }
  118. .mbt-opt-radio { width: 24rpx; height: 24rpx; border: 2rpx solid #D1D5DB; border-radius: 50%; flex-shrink: 0 }
  119. .mbt-opt-radio.on { background: #6366F1; border-color: #6366F1 }
  120. .mbt-footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #F0F0F0; display: flex; gap: 20rpx; box-sizing: border-box }
  121. .mbt-btn { flex: 1; height: 88rpx; line-height: 88rpx; font-size: 30rpx; border-radius: 44rpx; border: none; text-align: center }
  122. .mbt-btn-prev { background: #fff; color: #6366F1; border: 2rpx solid #6366F1 }
  123. .mbt-btn-next { background: linear-gradient(135deg, #6366F1, #818CF8); color: #fff; font-weight: 600 }
  124. </style>