普兆健康管家前端代码仓库
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.

549 lines
15 KiB

  1. <template>
  2. <view class="page__view">
  3. <navbar :title="`问题 ${current + 1}/${total}`" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="transparent" />
  4. <view class="bar">
  5. <view class="flex tools">
  6. <view class="left">
  7. <button class="flex btn" v-if="showPreBtn" @click="pre">
  8. <image class="btn-icon" src="@/pages_order/static/report/icon-wrapper.png" mode="widthFix"></image>
  9. <text>上一题</text>
  10. </button>
  11. </view>
  12. <view class="right">
  13. 选择你的答案进入下一题
  14. </view>
  15. </view>
  16. <view class="progress">
  17. <view class="progress-bar" :style="{ width: `${progress}%` }"></view>
  18. </view>
  19. </view>
  20. <view class="main">
  21. <view class="question">{{ data.question }}</view>
  22. <template v-if="data.type === 'select'">
  23. <view class="select">
  24. <view
  25. v-for="item in data.options"
  26. :key="item.id"
  27. :class="['flex', 'select-option', item.id === value ? 'is-active' : '']"
  28. @click="onSelect(item.id)"
  29. >
  30. {{ item.label }}
  31. </view>
  32. </view>
  33. </template>
  34. <template v-else-if="data.type === 'select-box'">
  35. <view class="select-box">
  36. <view
  37. v-for="item in data.options"
  38. :key="item.id"
  39. :class="['flex', 'flex-column', 'select-box-option', item.id === value ? 'is-active' : '']"
  40. @click="onSelect(item.id)"
  41. >
  42. <!-- todo: img switch acitve: white -->
  43. <image class="img" :src="item.img" mode="aspectFit"></image>
  44. <view class="text">{{ item.label }}</view>
  45. </view>
  46. </view>
  47. </template>
  48. <template v-else-if="data.type === 'input'">
  49. <view class="input">
  50. <view class="flex input-box">
  51. <input class="input-doc" v-model="value" placeholder="请输入内容" placeholder-style="font-family: PingFang SC; font-weight: 400; line-height: 1.4; font-size: 32rpx; color: #AAAACA;" />
  52. <view class="input-unit" v-if="data.unit">{{ data.unit }}</view>
  53. </view>
  54. </view>
  55. </template>
  56. <template v-else-if="data.type === 'input-group'">
  57. <view class="input">
  58. <view class="flex input-box" v-for="(item, index) in data.options" :key="item.id">
  59. <view class="input-label" v-if="item.label">{{ item.label }}</view>
  60. <input class="input-doc" v-model="value[index]" placeholder="请输入内容" placeholder-style="font-family: PingFang SC; font-weight: 400; line-height: 1.4; font-size: 32rpx; color: #AAAACA;" />
  61. <view class="input-unit" v-if="item.unit">{{ item.unit }}</view>
  62. </view>
  63. </view>
  64. </template>
  65. <view class="flex btns">
  66. <button :class="['btn', 'btn-palin', noneFlag ? 'is-active' : '']" v-if="data.showNoneBtn" @click="onSelectNone"> </button>
  67. <button class="btn" v-if="showConfirmBtn" @click="onConfirm"> </button>
  68. <button class="btn" v-if="showSubmitBtn" @click="onSubmit"> </button>
  69. </view>
  70. <view class="desc" v-if="data.desc">
  71. <uv-parse :content="data.desc"></uv-parse>
  72. </view>
  73. </view>
  74. </view>
  75. </template>
  76. <script>
  77. export default {
  78. data() {
  79. return {
  80. step: 0,
  81. current: 0,
  82. value: null,
  83. noneFlag: false,
  84. answers: [],
  85. list: [],
  86. total: 0,
  87. }
  88. },
  89. computed: {
  90. showPreBtn() {
  91. return this.current > 0
  92. },
  93. progress() {
  94. return 100 * (this.current + 1) / this.total
  95. },
  96. showSubmitBtn() {
  97. return this.current + 1 === this.total
  98. },
  99. data() {
  100. return this.list[this.current]
  101. },
  102. showConfirmBtn() {
  103. if (this.showSubmitBtn) {
  104. return false
  105. }
  106. return ['input', 'input-group'].includes(this.data?.type)
  107. },
  108. },
  109. onLoad(arg) {
  110. this.step = parseInt(arg.step)
  111. this.current = parseInt(arg.current || 0)
  112. this.fetchQuestionList()
  113. },
  114. methods: {
  115. fetchQuestionList() {
  116. // todo
  117. this.list = [
  118. {
  119. question: '您的年龄是?',
  120. type: 'select',
  121. options: [
  122. { id: '001', label: '0-3' },
  123. { id: '002', label: '3-6' },
  124. { id: '003', label: '6-10' },
  125. { id: '004', label: '10-18' },
  126. { id: '005', label: '18-50' },
  127. { id: '006', label: '50岁+' },
  128. ]
  129. },
  130. {
  131. question: '你的性别?',
  132. type: 'select',
  133. options: [
  134. { id: '001', label: '男' },
  135. { id: '002', label: '女' },
  136. ]
  137. },
  138. {
  139. question: '你的是否本人?',
  140. type: 'select',
  141. options: [
  142. { id: '001', label: '本人' },
  143. { id: '002', label: '夫妻' },
  144. { id: '003', label: '子女' },
  145. { id: '004', label: '父母' },
  146. { id: '005', label: '(外)祖父母' },
  147. ]
  148. },
  149. {
  150. question: '你的姓名?',
  151. type: 'input',
  152. },
  153. {
  154. question: '你的体重?',
  155. type: 'input',
  156. unit: 'KG',
  157. },
  158. {
  159. question: '你是否在备孕?',
  160. type: 'select',
  161. options: [
  162. { id: '001', label: '是' },
  163. { id: '002', label: '否' },
  164. ]
  165. },
  166. {
  167. question: '是否有以下问题的困扰?',
  168. type: 'select-box',
  169. options: [
  170. { id: '001', label: '高血压', img: '/pages_order/static/report/trouble-1.png' },
  171. { id: '002', label: '高血脂', img: '/pages_order/static/report/trouble-2.png' },
  172. { id: '003', label: '高血糖', img: '/pages_order/static/report/trouble-3.png' },
  173. { id: '004', label: '免疫问题', img: '/pages_order/static/report/trouble-4.png' },
  174. { id: '005', label: '胃肠道疾病', img: '/pages_order/static/report/trouble-5.png' },
  175. { id: '006', label: '甲状腺疾病', img: '/pages_order/static/report/trouble-6.png' },
  176. { id: '007', label: '头痛头晕', img: '/pages_order/static/report/trouble-7.png' },
  177. { id: '008', label: '肝功能不全', img: '/pages_order/static/report/trouble-8.png' },
  178. { id: '009', label: '肾功能不全', img: '/pages_order/static/report/trouble-9.png' },
  179. { id: '010', label: '关节疼痛', img: '/pages_order/static/report/trouble-10.png' },
  180. { id: '011', label: '精神疾病', img: '/pages_order/static/report/trouble-11.png' },
  181. ],
  182. showNoneBtn: true,
  183. },
  184. {
  185. question: '是否接受过手术?',
  186. type: 'input',
  187. showNoneBtn: true,
  188. },
  189. {
  190. question: '您的孩子晚上能睡几个小时?',
  191. type: 'select',
  192. options: [
  193. { id: '001', label: '> 10 小时' },
  194. { id: '002', label: '8-10 小时' },
  195. { id: '003', label: '6-8 小时' },
  196. { id: '004', label: '<6 小时' },
  197. ]
  198. },
  199. {
  200. question: '是否有饮酒?',
  201. type: 'input-group',
  202. options: [
  203. { id: '001', label: '平均每周饮酒', unit: '次' },
  204. { id: '002', label: '每次饮酒', unit: 'ml' },
  205. ],
  206. showNoneBtn: true,
  207. },
  208. {
  209. question: '你经常食用富含不饱和脂肪酸的食物吗?',
  210. type: 'select',
  211. options: [
  212. { id: '001', label: '基本不吃' },
  213. { id: '002', label: '偶尔' },
  214. { id: '003', label: '经常' },
  215. ],
  216. desc: `
  217. <p>富含不饱和脂肪酸的食物包括鱼类三文鱼鳕鱼鳟鱼等坚果和种子杏仁核桃花生等植物油橄榄油亚麻籽油等</p>
  218. `
  219. },
  220. {
  221. question: '你运动的强度如何?',
  222. type: 'select',
  223. options: [
  224. { id: '001', label: '高强度' },
  225. { id: '002', label: '中等强度' },
  226. { id: '003', label: '低强度' },
  227. ],
  228. desc: `
  229. <p>
  230. 低强度运动45分钟以上散步瑜伽太极拳打扫等<br/>
  231. 中强度运动30-45 分钟 慢跑骑车健身操等<br/>
  232. 高强度运动20-30 分钟跑步跳绳游泳跳舞HIT等
  233. </p>
  234. `
  235. },
  236. ]
  237. this.answers = this.list.map(item => {
  238. let val = null
  239. if (this.data.type === 'input-group') {
  240. val = new Array(this.data.options.length).fill(0).map(() => null)
  241. }
  242. return val
  243. })
  244. this.total = this.list.length
  245. // todo: delete
  246. this.current = 0
  247. },
  248. pre() {
  249. this.current -= 1
  250. this.value = this.answers[this.current]
  251. this.noneFlag = false
  252. },
  253. next() {
  254. if (this.showSubmitBtn) {
  255. return
  256. }
  257. this.current += 1
  258. this.value = this.answers[this.current]
  259. this.noneFlag = false
  260. },
  261. onSelect(id) {
  262. this.value = id
  263. // todo: fetch submit answer of this question
  264. if (!this.showSubmitBtn) {
  265. this.$nextTick(() => {
  266. setTimeout(() => {
  267. this.next()
  268. }, 500)
  269. })
  270. }
  271. },
  272. onConfirm() {
  273. // todo: check is fill
  274. this.answers[this.current] = this.value
  275. // todo: fetch submit answer of this question
  276. this.next()
  277. },
  278. onSelectNone() {
  279. this.noneFlag = true
  280. let val = null
  281. if (this.data.type === 'input-group') {
  282. val = new Array(this.data.options.length).fill(0).map(() => null)
  283. }
  284. this.answers[this.current] = val
  285. // todo: fetch submit answer of this question
  286. this.next()
  287. },
  288. onSubmit() {
  289. // todo
  290. // todo: fetch submit answer of this step
  291. if (this.step == 3) {
  292. // todo: submit all answer and jump to the report
  293. uni.reLaunch({
  294. url: '/pages/index/report'
  295. })
  296. return
  297. }
  298. this.$utils.redirectTo(`/pages_order/report/test/step?step=${this.step + 1}`)
  299. },
  300. },
  301. }
  302. </script>
  303. <style scoped lang="scss">
  304. .page__view {
  305. width: 100vw;
  306. min-height: 100vh;
  307. background-color: $uni-bg-color;
  308. position: relative;
  309. }
  310. .bar {
  311. margin-top: 24rpx;
  312. width: 100%;
  313. padding: 0 32rpx;
  314. box-sizing: border-box;
  315. .left {
  316. text-align: left;
  317. .btn {
  318. display: inline-flex;
  319. font-family: PingFang SC;
  320. font-weight: 400;
  321. font-size: 30rpx;
  322. line-height: 1.4;
  323. color: #7451DE;
  324. &-icon {
  325. width: 32rpx;
  326. height: auto;
  327. margin-right: 8rpx;
  328. }
  329. }
  330. }
  331. .right {
  332. flex: 1;
  333. text-align: right;
  334. font-family: PingFang SC;
  335. font-weight: 400;
  336. font-size: 26rpx;
  337. line-height: 1.4;
  338. color: #989898;
  339. }
  340. }
  341. .progress {
  342. margin-top: 24rpx;
  343. width: 100%;
  344. height: 24rpx;
  345. background: #E5E5E5;
  346. border-radius: 12rpx;
  347. &-bar {
  348. height: 100%;
  349. background-image: linear-gradient(to right, #4B348F, #845CFA);
  350. border-radius: 12rpx;
  351. }
  352. }
  353. .main {
  354. width: 100%;
  355. padding: 70rpx 104rpx 0 104rpx;
  356. box-sizing: border-box;
  357. }
  358. .question {
  359. text-align: center;
  360. font-family: PingFang SC;
  361. font-weight: 400;
  362. font-size: 40rpx;
  363. line-height: 1.4;
  364. color: #000000;
  365. margin-bottom: 64rpx;
  366. }
  367. .select {
  368. &-option {
  369. padding: 30rpx 0;
  370. font-family: PingFang SC;
  371. font-weight: 400;
  372. line-height: 1.4;
  373. font-size: 32rpx;
  374. color: #252545;
  375. background-image: linear-gradient(to right, #FFFFFF, #F4F4F6, #F2F2F4);
  376. border-radius: 52rpx;
  377. box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
  378. 4rpx 4rpx 20rpx 0 #AAAACC1F,
  379. 2rpx 2rpx 4rpx 0 #AAAACC40,
  380. -1rpx -1rpx 2rpx 0 #FFFFFF;
  381. & + & {
  382. margin-top: 40rpx;
  383. }
  384. &.is-active {
  385. color: #FFFFFF;
  386. background: #7451DE;
  387. }
  388. }
  389. }
  390. .select-box {
  391. display: grid;
  392. grid-template-columns: repeat(3, 1fr);
  393. gap: 32rpx;
  394. &-option {
  395. padding: 24rpx 0;
  396. border-radius: 24rpx;
  397. background-image: linear-gradient(to right, #FFFFFF, #F2F2F4);
  398. box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
  399. 4rpx 4rpx 20rpx 0 #AAAACC1F,
  400. 2rpx 2rpx 4rpx 0 #AAAACC40,
  401. -1rpx -1rpx 2rpx 0 #FFFFFF;
  402. .img {
  403. width: 100%;
  404. height: 64rpx;
  405. }
  406. .text {
  407. margin-top: 8rpx;
  408. font-family: PingFang SC;
  409. font-weight: 400;
  410. font-size: 28rpx;
  411. line-height: 1.4;
  412. color: #969696;
  413. }
  414. &.is-active {
  415. background: #7451DE;
  416. .text {
  417. color: #FFFFFFC4;
  418. }
  419. }
  420. }
  421. }
  422. .input {
  423. &-box {
  424. width: 100%;
  425. height: 104rpx;
  426. padding: 0 40rpx;
  427. box-sizing: border-box;
  428. border-radius: 52rpx;
  429. background-image: linear-gradient(to right, #FFFFFF, #F4F4F6, #F2F2F4);
  430. box-shadow: -2rpx -2rpx 10rpx 0 #FFFFFFC4,
  431. 4rpx 4rpx 20rpx 0 #AAAACC1F,
  432. 2rpx 2rpx 4rpx 0 #AAAACC40,
  433. -1rpx -1rpx 2rpx 0 #FFFFFF;
  434. & + & {
  435. margin-top: 40rpx;
  436. }
  437. }
  438. &-doc {
  439. text-align: center;
  440. flex: 1;
  441. }
  442. &-label {
  443. padding: 21rpx 40rpx 21rpx 0;
  444. font-family: PingFang SC;
  445. font-weight: 600;
  446. font-size: 30rpx;
  447. line-height: 1.4;
  448. color: #252545;
  449. border-right: 2rpx solid #E0DFF0;
  450. }
  451. &-unit {
  452. padding: 21rpx 0 21rpx 40rpx;
  453. font-family: PingFang SC;
  454. font-weight: 600;
  455. font-size: 30rpx;
  456. line-height: 1.4;
  457. color: #252545;
  458. border-left: 2rpx solid #E0DFF0;
  459. }
  460. }
  461. .btns {
  462. margin-top: 64rpx;
  463. column-gap: 36rpx;
  464. .btn {
  465. flex: 1;
  466. padding: 24rpx 0;
  467. font-family: PingFang SC;
  468. font-weight: 600;
  469. font-size: 30rpx;
  470. line-height: 1.4;
  471. color: #FFFFFF;
  472. background-image: linear-gradient(to right, #4B348F, #845CFA);
  473. border-radius: 45rpx;
  474. &-palin {
  475. padding: 22rpx 0;
  476. font-weight: 400;
  477. color: #252545;
  478. background: transparent;
  479. border: 2rpx solid #252545;
  480. &.is-active {
  481. color: $uni-color;
  482. border-color: $uni-color;
  483. }
  484. }
  485. }
  486. }
  487. .desc {
  488. margin-top: 220rpx;
  489. font-family: PingFang SC;
  490. font-weight: 400;
  491. line-height: 1.4;
  492. font-size: 26rpx;
  493. color: #989898;
  494. }
  495. </style>