quick-survey.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <view class="qs-wrap">
  3. <view class="qs-header">
  4. <text class="qs-title">快速了解你</text>
  5. <text class="qs-sub">答几道小题,为你推荐最合适的内容和方案</text>
  6. </view>
  7. <view class="qs-loading" v-if="loading">加载中...</view>
  8. <view class="qs-empty" v-else-if="!questions || questions.length === 0">暂无可用问卷</view>
  9. <view class="qs-body" v-else>
  10. <!-- 模板选择(多模板时可切换) -->
  11. <view class="qs-template-row" v-if="templates.length > 1">
  12. <text class="qs-template-label">选择话题:</text>
  13. <view class="qs-template-chip" v-for="(t, i) in templates" :key="'t' + i"
  14. :class="{ 'qs-template-chip-active': selectedTemplateId === t.id }"
  15. @click="switchTemplate(t)">
  16. <text>{{ t.title }}</text>
  17. </view>
  18. </view>
  19. <view class="qs-q" v-for="(q, qi) in questions" :key="'q' + qi">
  20. <text class="qs-q-label">{{ qi + 1 }}. {{ q.text }}</text>
  21. <view class="qs-options">
  22. <view class="qs-opt" v-for="(o, oi) in q.options" :key="'o' + qi + '_' + oi"
  23. :class="{ 'qs-opt-active': selectedIdx(qi) === oi }"
  24. @click="select(qi, oi)">
  25. <text class="qs-opt-text">{{ o.text }}</text>
  26. <text class="qs-opt-check" v-if="selectedIdx(qi) === oi">✓</text>
  27. </view>
  28. </view>
  29. </view>
  30. <view class="qs-btn" @click="submit" v-if="!submitting">
  31. <text class="qs-btn-text">提交,查看推荐</text>
  32. </view>
  33. <view class="qs-btn qs-btn-disabled" v-else>
  34. <text class="qs-btn-text">提交中...</text>
  35. </view>
  36. </view>
  37. </view>
  38. </template>
  39. <script>
  40. import { getActiveTemplates } from '../../utils/api.js'
  41. import { submitProblemSurvey } from '../../utils/api.js'
  42. export default {
  43. data() {
  44. return {
  45. templates: [],
  46. selectedTemplateId: null,
  47. templateTitle: '',
  48. questions: [],
  49. answers: [],
  50. loading: false,
  51. submitting: false
  52. }
  53. },
  54. onLoad() {
  55. this.loadTemplates()
  56. },
  57. methods: {
  58. selectedIdx(qi) {
  59. var arr = this.answers[qi]
  60. return (arr && arr.length > 0) ? arr[0] : -1
  61. },
  62. select(qi, oi) {
  63. this.answers[qi] = [oi]
  64. this.$forceUpdate()
  65. },
  66. loadTemplates() {
  67. var self = this
  68. self.loading = true
  69. uni.showLoading({ title: '加载中...', mask: true })
  70. getActiveTemplates().then(function(res) {
  71. uni.hideLoading()
  72. self.loading = false
  73. var list = res && res.data
  74. var arr = Array.isArray(list) ? list : []
  75. self.templates = arr
  76. if (arr.length > 0) {
  77. self.applyTemplate(arr[0])
  78. } else {
  79. self.questions = []
  80. }
  81. }).catch(function() {
  82. uni.hideLoading()
  83. self.loading = false
  84. self.templates = []
  85. self.questions = []
  86. })
  87. },
  88. applyTemplate(t) {
  89. this.selectedTemplateId = t.id
  90. this.templateTitle = t.title || ''
  91. var parsed = []
  92. if (t.questionsJson) {
  93. try {
  94. var p = typeof t.questionsJson === 'string' ? JSON.parse(t.questionsJson) : t.questionsJson
  95. parsed = Array.isArray(p) ? p : []
  96. } catch (e) {
  97. parsed = []
  98. }
  99. }
  100. this.questions = parsed
  101. this.answers = []
  102. },
  103. switchTemplate(t) {
  104. this.applyTemplate(t)
  105. },
  106. submit() {
  107. var self = this
  108. // 至少答一题
  109. var hasAnswer = false
  110. for (var i = 0; i < this.answers.length; i++) {
  111. if (this.answers[i] && this.answers[i].length > 0) {
  112. hasAnswer = true
  113. break
  114. }
  115. }
  116. if (!hasAnswer) {
  117. uni.showToast({ title: '请至少回答一题', icon: 'none' })
  118. return
  119. }
  120. self.submitting = true
  121. uni.showLoading({ title: '提交中...', mask: true })
  122. var answers = {}
  123. for (var qi = 0; qi < this.questions.length; qi++) {
  124. var selected = this.answers[qi] || []
  125. if (selected.length === 0) continue
  126. var q = this.questions[qi]
  127. var opt = q.options && q.options[selected[0]]
  128. if (opt && opt.id) {
  129. answers[String(opt.id)] = opt.id
  130. } else if (opt && opt.value) {
  131. answers[String(opt.value)] = opt.value
  132. } else {
  133. answers['q' + qi] = opt ? opt.text : ''
  134. }
  135. }
  136. submitProblemSurvey({
  137. problemDomainCode: '',
  138. surveyTemplateId: this.selectedTemplateId,
  139. answers: answers
  140. }).then(function(res) {
  141. uni.hideLoading()
  142. self.submitting = false
  143. if (res && (res.code === 0 || res.code === 200)) {
  144. uni.showToast({ title: '提交成功', icon: 'success' })
  145. setTimeout(function() {
  146. // 跳回首页展示定向内容
  147. uni.switchTab({ url: '/pages/index-home/index' })
  148. }, 800)
  149. } else {
  150. uni.showToast({ title: res.message || '提交失败', icon: 'none' })
  151. }
  152. }).catch(function() {
  153. uni.hideLoading()
  154. self.submitting = false
  155. uni.showToast({ title: '提交失败,请重试', icon: 'none' })
  156. })
  157. }
  158. }
  159. }
  160. </script>
  161. <style scoped>
  162. .qs-wrap {
  163. min-height: 100vh;
  164. background: #FFF7ED;
  165. padding: 40rpx 32rpx 120rpx;
  166. box-sizing: border-box;
  167. }
  168. .qs-header {
  169. margin-bottom: 32rpx;
  170. }
  171. .qs-title {
  172. display: block;
  173. font-size: 40rpx;
  174. font-weight: bold;
  175. color: #333;
  176. text-align: center;
  177. }
  178. .qs-sub {
  179. display: block;
  180. font-size: 26rpx;
  181. color: #999;
  182. text-align: center;
  183. margin-top: 10rpx;
  184. }
  185. .qs-loading, .qs-empty {
  186. text-align: center;
  187. font-size: 28rpx;
  188. color: #999;
  189. padding: 80rpx 0;
  190. }
  191. .qs-template-row {
  192. display: flex;
  193. align-items: center;
  194. flex-wrap: wrap;
  195. background: #fff;
  196. border-radius: 16rpx;
  197. padding: 16rpx 20rpx;
  198. margin-bottom: 24rpx;
  199. }
  200. .qs-template-label {
  201. font-size: 24rpx;
  202. color: #999;
  203. margin-right: 8rpx;
  204. }
  205. .qs-template-chip {
  206. font-size: 24rpx;
  207. color: #666;
  208. background: #F3F4F6;
  209. border-radius: 24rpx;
  210. padding: 6rpx 20rpx;
  211. margin: 4rpx;
  212. }
  213. .qs-template-chip-active {
  214. background: #F97316;
  215. color: #fff;
  216. }
  217. .qs-q {
  218. margin-bottom: 32rpx;
  219. }
  220. .qs-q-label {
  221. display: block;
  222. font-size: 30rpx;
  223. font-weight: 600;
  224. color: #333;
  225. margin-bottom: 16rpx;
  226. }
  227. .qs-options {
  228. display: flex;
  229. flex-wrap: wrap;
  230. gap: 16rpx;
  231. }
  232. .qs-opt {
  233. display: flex;
  234. align-items: center;
  235. background: #fff;
  236. border: 2rpx solid #E5E7EB;
  237. border-radius: 16rpx;
  238. padding: 18rpx 24rpx;
  239. margin-right: 16rpx;
  240. margin-bottom: 12rpx;
  241. }
  242. .qs-opt-active {
  243. border-color: #F97316;
  244. background: #FFF7ED;
  245. }
  246. .qs-opt-text {
  247. font-size: 28rpx;
  248. color: #333;
  249. }
  250. .qs-opt-check {
  251. color: #F97316;
  252. font-size: 28rpx;
  253. font-weight: bold;
  254. margin-left: 8rpx;
  255. }
  256. .qs-btn {
  257. background: linear-gradient(135deg, #F97316, #FB923C);
  258. border-radius: 48rpx;
  259. padding: 26rpx 0;
  260. text-align: center;
  261. margin-top: 32rpx;
  262. }
  263. .qs-btn:active {
  264. opacity: 0.9;
  265. }
  266. .qs-btn-disabled {
  267. opacity: 0.7;
  268. }
  269. .qs-btn-text {
  270. color: #fff;
  271. font-size: 32rpx;
  272. font-weight: 600;
  273. }
  274. </style>