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

381 lines
9.0 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view class="page__view">
  3. <navbar title="营养方案" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#FFFFFF" />
  4. <view class="main">
  5. <reportCard :data="detail">
  6. <view class="section header">
  7. <view>营养师基于你生活习惯和营养目标推荐</view>
  8. <view class="highlight">量身定制的营养方案</view>
  9. </view>
  10. <view class="section" v-for="(step, index) in list" :key="step.key">
  11. <view class="flex section-header">
  12. <view class="section-header-index">
  13. <text>{{ index + 1 }}</text>
  14. <image class="section-header-index-icon" :src="step.url" mode="widthFix"></image>
  15. </view>
  16. <view class="section-header-title">
  17. <view class="section-header-title-name">{{ step.name }}</view>
  18. <view class="section-header-title-desc">{{ step.desc }}</view>
  19. </view>
  20. </view>
  21. <view class="section-content">
  22. <view class="card" v-for="(item, idx) in step.children" :key="item.key" >
  23. <productCard :data="item" @select="onSelect(index, idx, $event)" ></productCard>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="section tips">
  28. *以上是根据你的营养目标以及饮食运动作息状况给出的针对性健康建议可以辅助你达成营养目标同时养成良好的生活习惯
  29. </view>
  30. </reportCard>
  31. </view>
  32. <view class="flex bottom">
  33. <view class="left">
  34. <button class="btn btn-comment" @click="jumpToComment">
  35. <view>查看评价</view>
  36. <view class="flex"><text class="highlight">{{ `${comment}` }}</text><uv-icon name="arrow-right" color="#C6C6C6" size="28rpx"></uv-icon></view>
  37. </button>
  38. </view>
  39. <view class="flex right">
  40. <button
  41. class="flex btn btn-cart"
  42. :disabled="!selectedCount"
  43. :class="[selectedCount ? '' : 'is-disabled']"
  44. @click="onAddCart"
  45. >
  46. <text>加入购物车</text>
  47. </button>
  48. <button
  49. class="flex btn btn-settle"
  50. :class="[selectedCount ? '' : 'is-disabled']"
  51. :disabled="!selectedCount"
  52. @click="onBuy"
  53. >
  54. <text>结算</text>
  55. <text v-if="selectedCount">{{ `(${selectedCount})` }}</text>
  56. </button>
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. import reportCard from '@/pages_order/components/reportCard.vue';
  63. import productCard from './productCard.vue';
  64. export default {
  65. components: {
  66. reportCard,
  67. productCard,
  68. },
  69. data() {
  70. return {
  71. productId: '',
  72. detail: {},
  73. list: [],
  74. comment: 0,
  75. }
  76. },
  77. computed: {
  78. selectedCount() {
  79. let count = 0
  80. this.list.forEach(step => {
  81. step.children.forEach(item => {
  82. item.selected && count++
  83. })
  84. })
  85. return count
  86. },
  87. },
  88. async onLoad(arg) {
  89. const { id } = arg
  90. await this.fetchReportData(id)
  91. this.fetchCommentNum(this.productId)
  92. },
  93. methods: {
  94. async fetchCommentNum(productId) {
  95. try {
  96. this.comment = await this.$fetch('productEvaluateNum', { productId })
  97. } catch (err) {
  98. }
  99. },
  100. async fetchReportData(id) {
  101. try {
  102. const { productList, ...detail } = await this.$fetch('getReportDetail', { id })
  103. const detectList = []
  104. const nutrientList = []
  105. const courseList = []
  106. const ids = []
  107. productList.forEach(item => {
  108. // 产品类型(0营养剂,1预约,2课程)
  109. const { id, type, specs, currentPrice } = item
  110. ids.push(id)
  111. const spec = specs?.[0] || {}
  112. const obj = {
  113. ...item,
  114. specId: spec.id,
  115. specName: spec.specName,
  116. currentPrice: spec.price || currentPrice,
  117. selected: true,
  118. }
  119. switch(type) {
  120. case '0':
  121. nutrientList.push(obj)
  122. break;
  123. case '1':
  124. detectList.push(obj)
  125. break;
  126. case '2':
  127. courseList.push(obj)
  128. break;
  129. default:
  130. break;
  131. }
  132. })
  133. this.detail = detail
  134. this.list = [
  135. {
  136. id: '001',
  137. name: '检测方案',
  138. desc: '刚开始健康检测?专家推荐先做这几项',
  139. url: '/pages_order/static/report/report-nutrition-1.png',
  140. children: detectList
  141. },
  142. {
  143. id: '002',
  144. name: '基础方案',
  145. desc: `刚开始吃维生素?营养师建议从这${nutrientList.length}颗开始`,
  146. url: '/pages_order/static/report/report-nutrition-2.png',
  147. children: nutrientList
  148. },
  149. // todo: check is need?
  150. {
  151. id: '003',
  152. name: '课程方案',
  153. desc: '',
  154. url: '/pages_order/static/report/report-detail-3.png',
  155. children: courseList
  156. },
  157. ]
  158. this.productId = ids.join(',')
  159. console.log('list', this.list)
  160. console.log('productId', this.productId)
  161. } catch (err) {
  162. }
  163. },
  164. onSelect(stepIdx, childIdx, selected) {
  165. this.list[stepIdx].children[childIdx].selected = selected
  166. },
  167. getSelectedList() {
  168. return this.list.reduce((arr, step) => {
  169. const selectedArr = step.children.filter(product => product.selected)
  170. return arr.concat(selectedArr)
  171. }, [])
  172. },
  173. jumpToComment() {
  174. this.$utils.navigateTo(`/pages_order/comment/commentRecordsOfProduct?productId=${this.productId}`)
  175. },
  176. onAddCart() {
  177. const selectedList = this.getSelectedList()
  178. this.$store.dispatch('addCartBatch', selectedList)
  179. },
  180. onBuy() {
  181. const selectedList = this.getSelectedList()
  182. this.$store.commit('createOrder', selectedList)
  183. },
  184. },
  185. }
  186. </script>
  187. <style scoped lang="scss">
  188. .page__view {
  189. width: 100vw;
  190. min-height: 100vh;
  191. background-color: $uni-bg-color;
  192. position: relative;
  193. /deep/ .nav-bar__view {
  194. position: fixed;
  195. top: 0;
  196. left: 0;
  197. }
  198. }
  199. .main {
  200. padding: calc(var(--status-bar-height) + 152rpx) 32rpx 272rpx 32rpx;
  201. }
  202. .section {
  203. & + & {
  204. margin-top: 48rpx;
  205. padding-top: 12rpx;
  206. border-top: 2rpx dashed #989898;
  207. }
  208. &-header {
  209. justify-content: flex-start;
  210. &-index {
  211. position: relative;
  212. font-family: HarmonyOS Sans;
  213. font-weight: 700;
  214. font-size: 96rpx;
  215. line-height: 1.4;
  216. color: #D9D9D9;
  217. &-icon {
  218. position: absolute;
  219. left: 34rpx;
  220. top: 70rpx;
  221. width: 40rpx;
  222. height: 40rpx;
  223. }
  224. }
  225. &-title {
  226. margin-left: 32rpx;
  227. font-family: PingFang SC;
  228. line-height: 1.4;
  229. color: #252545;
  230. &-name {
  231. font-weight: 600;
  232. font-size: 40rpx;
  233. }
  234. &-desc {
  235. font-weight: 400;
  236. font-size: 26rpx;
  237. }
  238. }
  239. }
  240. &-content {
  241. padding-top: 18rpx;
  242. }
  243. }
  244. .section.header {
  245. font-family: PingFang SC;
  246. font-weight: 400;
  247. font-size: 36rpx;
  248. line-height: 1.2;
  249. color: #252545CC;
  250. .highlight {
  251. font-size: 48rpx;
  252. line-height: 1.4;
  253. font-weight: 600;
  254. font-family: PingFang SC;
  255. color: transparent;
  256. background-image: linear-gradient(to right, #4B348F, #845CFA);
  257. background-clip: text;
  258. display: inline-block;
  259. }
  260. }
  261. .tips {
  262. font-family: PingFang SC;
  263. font-weight: 400;
  264. font-size: 18rpx;
  265. line-height: 1.4;
  266. color: #989898;
  267. }
  268. .card {
  269. & + & {
  270. margin-top: 32rpx;
  271. }
  272. }
  273. .bottom {
  274. width: 100%;
  275. position: fixed;
  276. left: 0;
  277. bottom: 0;
  278. padding: 24rpx 40rpx;
  279. padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
  280. box-sizing: border-box;
  281. background: #FFFFFF;
  282. column-gap: 16rpx;
  283. .left {
  284. }
  285. .right {
  286. flex: 1;
  287. column-gap: 32rpx;
  288. }
  289. .btn {
  290. &-comment {
  291. display: inline-block;
  292. width: auto;
  293. text-align: left;
  294. font-family: PingFang SC;
  295. font-weight: 400;
  296. font-size: 24rpx;
  297. line-height: 1.4;
  298. color: #626262;
  299. .highlight {
  300. margin-right: 4rpx;
  301. font-family: 600;
  302. font-size: 30rpx;
  303. color: #252545;
  304. }
  305. }
  306. &-cart {
  307. flex: 1;
  308. padding: 14rpx 0;
  309. font-family: PingFang SC;
  310. font-size: 36rpx;
  311. font-weight: 500;
  312. line-height: 1;
  313. color: #252545;
  314. border: 2rpx solid #252545;
  315. border-radius: 41rpx;
  316. }
  317. &-settle {
  318. flex: 1;
  319. padding: 16rpx 0;
  320. font-family: PingFang SC;
  321. font-size: 36rpx;
  322. font-weight: 500;
  323. line-height: 1;
  324. color: #FFFFFF;
  325. background-image: linear-gradient(to right, #4B348F, #845CFA);
  326. border-radius: 41rpx;
  327. }
  328. &.is-disabled {
  329. opacity: 0.5;
  330. }
  331. }
  332. }
  333. </style>