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

665 lines
16 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
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
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. <view class="flex address" v-if="addressData">
  6. <addressView :data="addressData" :showIcon="true" :enableCopy="true"></addressView>
  7. </view>
  8. <template v-if="orderData">
  9. <view class="card detail">
  10. <view class="flex card-top">
  11. <view class="title">订单详情</view>
  12. <view :class="['flex', 'status', `status-${status}`]">{{ statusDesc }}</view>
  13. </view>
  14. <view class="card-main">
  15. <view class="flex product" v-for="item in orderData.appletOrderProductList" :key="item.id">
  16. <image class="img" :src="getCoverImg(item.image)" mode="scaleToFill"></image>
  17. <view class="info">
  18. <view class="row">{{ item.productName }}</view>
  19. <view class="flex row">
  20. <view class="row-label">产品类型</view>
  21. <view class="row-content">{{ getTypeDesc(item.type) || '--' }}</view>
  22. </view>
  23. <view class="flex row">
  24. <view class="row-label">产品内容</view>
  25. <view class="row-content">{{ item.content || '--' }}</view>
  26. </view>
  27. <view class="flex price">
  28. <text class="price-label">价格</text>
  29. <text class="price-unit">¥</text><text class="price-value">{{ item.price }}</text>
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. <view class="flex row card-bottom">
  35. <view class="row-label">总价格</view>
  36. <view class="flex row-content price">¥<text class="price-value">{{ orderData.orderAmount }}</text></view>
  37. </view>
  38. </view>
  39. <view v-if="orderData.process && orderData.process.length" class="card service">
  40. <view class="flex card-top">
  41. <view class="title">售后信息</view>
  42. </view>
  43. <view class="card-main">
  44. <uv-steps
  45. current="0"
  46. direction="column"
  47. dot
  48. activeColor="#10A934"
  49. inactiveColor="#C6C6C6"
  50. >
  51. <uv-steps-item
  52. v-for="(item, index) in orderData.process"
  53. :key="item.id"
  54. >
  55. <template #title>
  56. <view class="flex step-header">
  57. <view :class="['step-title', index == 0 ? 'highlight' : '']">{{ item.title }}</view>
  58. <view class="step-time">{{ item.createTime }}</view>
  59. </view>
  60. </template>
  61. <template #desc>
  62. <view class="step-desc">{{ item.text }}</view>
  63. </template>
  64. </uv-steps-item>
  65. </uv-steps>
  66. </view>
  67. </view>
  68. <view class="card info">
  69. <view class="flex card-top">
  70. <view class="title">订单信息</view>
  71. </view>
  72. <view class="card-main">
  73. <view class="flex row">
  74. <view class="row-label">订单编号</view>
  75. <view class="row-content">{{ orderData.orderNo }}</view>
  76. </view>
  77. <view class="flex row">
  78. <view class="row-label">下单时间</view>
  79. <view class="row-content">{{ $dayjs(orderData.orderDate).format('YYYY-MM-DD HH:mm') }}</view>
  80. </view>
  81. </view>
  82. </view>
  83. </template>
  84. <view class="notice">
  85. <view class="notice-header">下单须知</view>
  86. <view class="notice-content">
  87. <uv-parse :content="configList['order_instructions']"></uv-parse>
  88. </view>
  89. </view>
  90. </view>
  91. <view class="flex bottom" v-if="[0, 1, 2, 3, 4].includes(status)">
  92. <view class="flex bar">
  93. <button plain class="flex flex-column btn btn-service" open-type="contact">
  94. <image class="btn-service-icon" src="@/pages_order/static/order/icon-service.png" mode="widthFix"></image>
  95. <view>联系客服</view>
  96. </button>
  97. <view class="flex cols">
  98. <!-- 待支付 -->
  99. <template v-if="status == 0">
  100. <view class="flex col price">
  101. <view class="price-label">合计</view>
  102. <text class="price-unit">¥</text><text class="price-value">{{ orderData.orderAmount }}</text>
  103. </view>
  104. <button class="flex col btn btn-primary" @click="onPay">立即支付</button>
  105. </template>
  106. <!-- 待发货 -->
  107. <template v-else-if="status == 1">
  108. <button class="flex col btn" @click="onApplyService">申请售后</button>
  109. <!-- 自采检测 -->
  110. <!-- <template v-if="detectProduct && detectProduct.subscribeType == 0">
  111. <button class="flex col btn btn-primary" @click="onDetectModify">修改</button>
  112. </template> -->
  113. </template>
  114. <!-- 待收货 -->
  115. <template v-else-if="status == 2">
  116. <button class="flex col btn" @click="onApplyService">申请售后</button>
  117. <button class="flex col btn btn-primary" @click="onConfirmReceipt">确认收货</button>
  118. <!-- 检测 subscribeType: 0自采1上门2到店3已取消 -->
  119. <!-- <template v-if="detectProduct">
  120. 自采检测
  121. <template v-if="detectProduct.subscribeType == 0">
  122. <button class="flex col btn btn-primary" @click="onDetectSendBack">线上回寄试剂盒</button>
  123. </template>
  124. <template v-else>
  125. <button class="flex col btn btn-primary" @click="onDetectBook">检测预约</button>
  126. </template>
  127. </template>
  128. 其他商品
  129. <template v-else>
  130. <button class="flex col btn btn-primary" @click="onConfirmReceipt">确认收货</button>
  131. </template> -->
  132. </template>
  133. <!-- 待评价 -->
  134. <template v-else-if="status == 3">
  135. <button class="flex col btn" @click="onApplyService">申请售后</button>
  136. <button class="flex col btn btn-primary" @click="onComment">立即评价</button>
  137. </template>
  138. <!-- 已完成 -->
  139. <template v-else-if="status == 4">
  140. <button class="flex col btn" @click="onApplyService">申请售后</button>
  141. </template>
  142. </view>
  143. </view>
  144. </view>
  145. <payPopup ref="payPopup" @paySuccess="getData"></payPopup>
  146. <serviceSelectPopup ref="serviceSelectPopup"></serviceSelectPopup>
  147. </view>
  148. </template>
  149. <script>
  150. import addressView from '@/pages_order/address/addressView.vue'
  151. import payPopup from '@/pages_order/order/payPopup.vue'
  152. import serviceSelectPopup from '@/pages_order/applyService/serviceSelectPopup.vue'
  153. // 订单状态 0待支付 1待发货 2待收货 3待评价 4已完成
  154. const STATUS_AND_DESC_MAPPING = {
  155. 0: '待支付',
  156. 1: '待发货',
  157. 2: '待收货',
  158. 3: '待评价',
  159. 4: '已完成',
  160. 5: '售后',
  161. }
  162. // 产品类型(0营养剂,1预约,2课程)
  163. const TYPE_AND_DESC_MAPPING = {
  164. 0: '营养剂',
  165. 1: '检测',
  166. 2: '课程',
  167. }
  168. export default {
  169. components: {
  170. addressView,
  171. payPopup,
  172. serviceSelectPopup,
  173. },
  174. data() {
  175. return {
  176. id: null,
  177. addressData: null,
  178. orderData: null,
  179. }
  180. },
  181. computed: {
  182. status() {
  183. const { orderStatus, afterSales } = this.orderData || {}
  184. if (afterSales) {
  185. return 5
  186. }
  187. return orderStatus
  188. },
  189. statusDesc() {
  190. return STATUS_AND_DESC_MAPPING[this.status]
  191. },
  192. // detectProduct() {
  193. // const { appletOrderProductList } = this.orderData || {}
  194. // if (appletOrderProductList?.length == 1 && appletOrderProductList?.[0]?.type == 1) { // type: 产品类型(0营养剂,1预约,2课程)
  195. // return appletOrderProductList[0]
  196. // }
  197. // return null
  198. // },
  199. },
  200. onShow() {
  201. console.log('onShow')
  202. if (!this.id) {
  203. return
  204. }
  205. this.getData()
  206. },
  207. onLoad(arg) {
  208. this.id = arg.id
  209. this.getData()
  210. },
  211. onPullDownRefresh() {
  212. this.getData()
  213. },
  214. methods: {
  215. async getData() {
  216. try {
  217. const result = await this.$fetch('detailOrder', { id: this.id })
  218. const {
  219. customerName,
  220. customerPhone,
  221. deliveryAddressDetail,
  222. ...orderData
  223. } = result
  224. this.addressData = {
  225. name: customerName,
  226. phone: customerPhone,
  227. detail: deliveryAddressDetail,
  228. }
  229. this.orderData = orderData
  230. } catch (err) {
  231. }
  232. uni.stopPullDownRefresh()
  233. },
  234. getTypeDesc(type) {
  235. return TYPE_AND_DESC_MAPPING[type]
  236. },
  237. getCoverImg(image) {
  238. return image?.split?.(',')?.[0] || ''
  239. },
  240. onPay() {
  241. const {
  242. id,
  243. title,
  244. orderAmount
  245. } = this.orderData
  246. const obj = {
  247. id,
  248. title,
  249. orderAmount,
  250. }
  251. this.$refs.payPopup.open(obj)
  252. },
  253. async onConfirmReceipt() {
  254. try {
  255. await this.$fetch('confirmOrder', { id: this.orderData.id })
  256. uni.showToast({
  257. icon: 'success',
  258. title: '确认收货成功',
  259. });
  260. this.getData()
  261. } catch (err) {
  262. }
  263. },
  264. onComment() {
  265. this.$utils.navigateTo(`/pages_order/comment/commentWrite?orderId=${this.orderData.id}`)
  266. },
  267. onApplyService() {
  268. console.log('orderData', this.orderData)
  269. const {
  270. id,
  271. appletOrderProductList,
  272. } = this.orderData
  273. const obj = {
  274. id,
  275. appletOrderProductList: appletOrderProductList.map(item => ({ ...item, statusDesc: this.statusDesc })),
  276. }
  277. this.$refs.serviceSelectPopup.open(obj)
  278. },
  279. onDetectModify() {
  280. // todo
  281. },
  282. onDetectSendBack() {
  283. // todo
  284. },
  285. onDetectBook() {
  286. // todo
  287. },
  288. },
  289. }
  290. </script>
  291. <style scoped lang="scss">
  292. .page__view {
  293. width: 100vw;
  294. min-height: 100vh;
  295. background-color: $uni-bg-color;
  296. position: relative;
  297. /deep/ .nav-bar__view {
  298. position: fixed;
  299. top: 0;
  300. left: 0;
  301. }
  302. }
  303. .main {
  304. padding: calc(var(--status-bar-height) + 144rpx) 32rpx 224rpx 32rpx;
  305. }
  306. .address {
  307. padding: 24rpx 32rpx;
  308. background: #FFFFFF;
  309. border-radius: 24rpx;
  310. justify-content: flex-start;
  311. }
  312. .card {
  313. margin-top: 40rpx;
  314. padding: 32rpx;
  315. background: #FAFAFF;
  316. border: 2rpx solid #FFFFFF;
  317. border-radius: 32rpx;
  318. &-top {
  319. margin-bottom: 32rpx;
  320. justify-content: space-between;
  321. .title {
  322. font-family: PingFang SC;
  323. font-weight: 500;
  324. font-size: 36rpx;
  325. line-height: 1.4;
  326. color: #252545;
  327. }
  328. .status {
  329. display: inline-flex;
  330. min-width: 120rpx;
  331. padding: 6rpx 0;
  332. box-sizing: border-box;
  333. font-family: PingFang SC;
  334. font-weight: 400;
  335. font-size: 24rpx;
  336. line-height: 1.4;
  337. color: #252545;
  338. background: #F3F3F3;
  339. border-radius: 12rpx;
  340. &-0 {
  341. color: #FF860E;
  342. background: #FFF4E9;
  343. }
  344. &-1 {
  345. color: #2799E0;
  346. background: #EEF7FD;
  347. }
  348. &-2 {
  349. color: #7D27E0;
  350. background: #F5EEFD;
  351. }
  352. &-5 {
  353. color: #E53C29;
  354. background: #FDE7E5;
  355. }
  356. }
  357. }
  358. .row {
  359. justify-content: space-between;
  360. font-family: PingFang SC;
  361. font-weight: 400;
  362. font-size: 28rpx;
  363. line-height: 1.4;
  364. &-label {
  365. flex: none;
  366. color: #8B8B8B;
  367. }
  368. &-content {
  369. color: #393939;
  370. }
  371. }
  372. &.detail {
  373. .product {
  374. margin-bottom: 32rpx;
  375. column-gap: 24rpx;
  376. .img {
  377. flex: none;
  378. width: 120rpx;
  379. height: 120rpx;
  380. }
  381. .info {
  382. flex: 1;
  383. padding: 24rpx 32rpx;
  384. background: #FFFFFF;
  385. border-radius: 32rpx;
  386. .row {
  387. margin-bottom: 16rpx;
  388. justify-content: flex-start;
  389. column-gap: 4rpx;
  390. }
  391. .price {
  392. justify-content: flex-start;
  393. column-gap: 8rpx;
  394. font-family: PingFang SC;
  395. font-weight: 500;
  396. line-height: 1.4;
  397. &-label {
  398. font-weight: 400;
  399. font-size: 26rpx;
  400. color: #8B8B8B;
  401. }
  402. &-unit {
  403. font-size: 24rpx;
  404. color: #7451DE;
  405. }
  406. &-value {
  407. font-size: 32rpx;
  408. color: #7451DE;
  409. }
  410. }
  411. }
  412. }
  413. .card-bottom {
  414. .price {
  415. column-gap: 8rpx;
  416. font-family: PingFang SC;
  417. font-weight: 500;
  418. font-size: 24rpx;
  419. line-height: 1.4;
  420. color: #7451DE;
  421. &-value {
  422. font-size: 32rpx;
  423. }
  424. }
  425. }
  426. }
  427. &.info {
  428. .row + .row {
  429. margin-top: 32rpx;
  430. }
  431. }
  432. &.service {
  433. .step {
  434. &-header {
  435. justify-content: flex-start;
  436. column-gap: 24rpx;
  437. padding-left: 24rpx;
  438. }
  439. &-title {
  440. font-family: PingFang SC;
  441. font-weight: 400;
  442. font-size: 30rpx;
  443. line-height: 1.4;
  444. color: #000000;
  445. &.highlight {
  446. font-weight: 500;
  447. color: #10A934;
  448. }
  449. }
  450. &-time {
  451. font-family: PingFang SC;
  452. font-weight: 400;
  453. font-size: 24rpx;
  454. line-height: 1.4;
  455. color: #8B8B8B;
  456. }
  457. &-desc {
  458. padding: 16rpx 0 16rpx 24rpx;
  459. font-family: PingFang SC;
  460. font-weight: 400;
  461. font-size: 24rpx;
  462. line-height: 1.4;
  463. color: #777777;
  464. }
  465. }
  466. }
  467. }
  468. .notice {
  469. margin-top: 40rpx;
  470. font-family: PingFang SC;
  471. font-weight: 400;
  472. &-header {
  473. font-size: 28rpx;
  474. line-height: 1.4;
  475. color: #393939;
  476. }
  477. &-content {
  478. margin-top: 24rpx;
  479. font-size: 24rpx;
  480. line-height: 1.4;
  481. color: #BABABA;
  482. }
  483. }
  484. .bottom {
  485. position: fixed;
  486. left: 0;
  487. bottom: 0;
  488. z-index: 2;
  489. width: 100vw;
  490. // height: 200rpx;
  491. padding: 24rpx 40rpx;
  492. padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
  493. background: #FFFFFF;
  494. box-sizing: border-box;
  495. align-items: flex-start;
  496. .bar {
  497. width: 100%;
  498. column-gap: 32rpx;
  499. }
  500. .btn {
  501. background: transparent;
  502. border: none;
  503. &-service {
  504. flex: none;
  505. row-gap: 4rpx;
  506. font-family: PingFang SC;
  507. font-weight: 400;
  508. font-size: 22rpx;
  509. line-height: 1.1;
  510. color: #999999;
  511. &-icon {
  512. width: 52rpx;
  513. height: auto;
  514. }
  515. }
  516. }
  517. .cols {
  518. flex: 1;
  519. column-gap: 32rpx;
  520. .col {
  521. flex: 1;
  522. }
  523. .btn {
  524. padding: 14rpx 0;
  525. box-sizing: border-box;
  526. font-family: PingFang SC;
  527. font-weight: 500;
  528. font-size: 36rpx;
  529. line-height: 1.4;
  530. color: #252545;
  531. border: 2rpx solid #252545;
  532. border-radius: 41rpx;
  533. &-primary {
  534. padding: 16rpx 0;
  535. color: #FFFFFF;
  536. background-image: linear-gradient(to right, #4B348F, #845CFA);
  537. border: none;
  538. }
  539. }
  540. .price {
  541. column-gap: 8rpx;
  542. font-family: PingFang SC;
  543. font-weight: 400;
  544. font-size: 24rpx;
  545. line-height: 1.4;
  546. &-label {
  547. color: #626262;
  548. }
  549. &-unit,
  550. &-value {
  551. font-weight: 500;
  552. color: #7451DE;
  553. .highlight {
  554. font-size: 40rpx;
  555. }
  556. }
  557. &-value {
  558. font-size: 40rpx;
  559. }
  560. }
  561. }
  562. }
  563. </style>