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

399 lines
9.5 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
  1. <template>
  2. <view class="page__view">
  3. <navbar title="确认订单" leftClick @leftClick="$utils.navigateBack" color="#191919" bgColor="#F3F2F7" />
  4. <view class="main">
  5. <view class="flex address" @click="jumpToSelectAddress">
  6. <addressView :data="addressData" :showIcon="true"></addressView>
  7. <uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
  8. </view>
  9. <view class="card" v-for="(item, index) in productList" :key="item.id">
  10. <productCard :data="item" @change="onChange(index, $event)"></productCard>
  11. </view>
  12. <view class="order" v-if="orderData">
  13. <view class="order-header">
  14. 订单信息
  15. </view>
  16. <view class="flex row">
  17. <view class="row-label">订单编号</view>
  18. <view class="row-content">{{ orderData.number }}</view>
  19. </view>
  20. <view class="flex row">
  21. <view class="row-label">下单时间</view>
  22. <view class="row-content">{{ $dayjs(orderData.createTime).format('YYYY-MM-DD HH:mm') }}</view>
  23. </view>
  24. </view>
  25. <view class="notice">
  26. <view class="notice-header">下单须知</view>
  27. <view class="notice-content">
  28. <uv-parse :content="configList['order_instructions']"></uv-parse>
  29. </view>
  30. </view>
  31. </view>
  32. <view class="bottom">
  33. <view class="agreement">
  34. <uv-checkbox-group
  35. v-model="checkboxValue"
  36. shape="circle"
  37. >
  38. <uv-checkbox
  39. size="40rpx"
  40. icon-size="40rpx"
  41. activeColor="#7451DE"
  42. :name="1"
  43. ></uv-checkbox>
  44. </uv-checkbox-group>
  45. <view class="desc">
  46. 我已阅读并同意
  47. <text class="highlight" @click="$refs.modal.open('user_agreement', '用户协议')">用户协议</text>
  48. <text class="highlight" @click="$refs.modal.open('privacy_policy', '隐私协议')">隐私协议</text>
  49. <text class="highlight" @click="$refs.modal.open('consumer_notification', '消费者告知')">消费者告知</text>
  50. </view>
  51. </view>
  52. <view class="flex bar">
  53. <view class="flex col price">
  54. <view class="price-label">合计</view>
  55. <view class="price-unit">¥</view><view class="price-value">{{ totalPrice }}</view>
  56. </view>
  57. <button class="col btn" @click="onPay">立即支付</button>
  58. </view>
  59. </view>
  60. <agreementModal ref="modal" @confirm="onConfirmAgreement"></agreementModal>
  61. <payPopup ref="payPopup" @paySuccess="onPaySuccess" @payCancel="onPayCancel"></payPopup>
  62. </view>
  63. </template>
  64. <script>
  65. import { mapState } from 'vuex'
  66. import addressView from '@/pages_order/address/addressView.vue'
  67. import productCard from './productCard.vue'
  68. import agreementModal from '@/pages_order/components/agreementModal.vue'
  69. import payPopup from '@/pages_order/order/payPopup.vue'
  70. export default {
  71. components: {
  72. addressView,
  73. productCard,
  74. agreementModal,
  75. payPopup,
  76. },
  77. data() {
  78. return {
  79. id: null,
  80. defaultAddressInfo: null,
  81. orderData: null,
  82. productList: [],
  83. checkboxValue: [],
  84. }
  85. },
  86. computed: {
  87. ...mapState(['configList', 'userInfo', 'payOrderProduct', 'addressInfo']),
  88. totalPrice() {
  89. return this.productList.reduce((price, item) => {
  90. // return price + item.price * (item.count || 1)
  91. return price + item.currentPrice
  92. }, 0)
  93. },
  94. addressData() {
  95. return this.addressInfo || this.defaultAddressInfo || null
  96. },
  97. },
  98. async onShow() {
  99. console.log('onShow')
  100. console.log('address', this.addressInfo)
  101. this.fetchDefaultAddress()
  102. },
  103. onLoad(arg) {
  104. console.log('onLoad')
  105. console.log('payOrderProduct', this.payOrderProduct)
  106. this.productList = JSON.parse(JSON.stringify(this.payOrderProduct))
  107. // todo: check include Overseas Product ?
  108. // this.$utils.navigateTo('/pages_order/order/userInfo/infoFill')
  109. },
  110. onUnload() {
  111. this.$store.commit('setAddressInfo', null)
  112. },
  113. methods: {
  114. async fetchDefaultAddress() {
  115. try {
  116. const params = {
  117. pageNo: 1,
  118. pageSize: 1,
  119. userId: this.userInfo.id,
  120. defaultFlag: 1,
  121. }
  122. let { records, total } = await this.$fetch('getAddressList', params)
  123. this.defaultAddressInfo = total ? records[0] : null
  124. } catch (err) {
  125. this.defaultAddressInfo = null
  126. }
  127. },
  128. jumpToSelectAddress() {
  129. this.$utils.navigateTo('/pages_order/address/addressList')
  130. },
  131. onChange(index, obj) {
  132. console.log('onChange', index, obj)
  133. const target = this.productList[index]
  134. target.skuId = obj.id
  135. target.specName = obj.specName
  136. target.currentPrice = obj.price
  137. this.productList[index] = target
  138. console.log('after set', this.productList)
  139. },
  140. onConfirmAgreement(confirm) {
  141. if (confirm) {
  142. this.checkboxValue = [1]
  143. } else {
  144. this.checkboxValue = []
  145. }
  146. },
  147. async onPay() {
  148. if(!this.checkboxValue.length){
  149. return uni.showToast({
  150. title: '请先同意《用户协议》《隐私协议》《消费者告知》',
  151. icon:'none'
  152. })
  153. }
  154. if (!this.addressData?.id) {
  155. return uni.showToast({
  156. title: '请选择地址',
  157. icon:'none'
  158. })
  159. }
  160. // const { id } = this.orderData
  161. const obj = {
  162. // // todo: check title
  163. // title: '营养套餐消费',
  164. // orderId: id,
  165. list: this.productList,
  166. addressId: this.addressData.id,
  167. amount: this.totalPrice,
  168. }
  169. this.$refs.payPopup.open(obj)
  170. },
  171. isDetectProduct() {
  172. // type: 产品类型(0营养剂,1预约,2课程)
  173. // return this.productList.length == 1 && this.productList[0].type == 1
  174. return this.productList.every(item => item.type == '1')
  175. },
  176. onPaySuccess() {
  177. setTimeout(() => {
  178. if (this.isDetectProduct()) {
  179. uni.reLaunch({
  180. url: `/pages_order/checkup/checkupRecords`
  181. });
  182. return
  183. }
  184. uni.reLaunch({
  185. url: `/pages_order/order/orderList/index`
  186. });
  187. }, 700)
  188. },
  189. onPayCancel() {
  190. uni.redirectTo({
  191. url: `/pages_order/order/orderList/index?index=1`
  192. });
  193. },
  194. },
  195. }
  196. </script>
  197. <style scoped lang="scss">
  198. .page__view {
  199. width: 100vw;
  200. min-height: 100vh;
  201. background-color: $uni-bg-color;
  202. position: relative;
  203. /deep/ .nav-bar__view {
  204. position: fixed;
  205. top: 0;
  206. left: 0;
  207. }
  208. }
  209. .main {
  210. padding: calc(var(--status-bar-height) + 144rpx) 32rpx 310rpx 32rpx;
  211. }
  212. .address {
  213. margin-bottom: 40rpx;
  214. justify-content: space-between;
  215. padding: 24rpx 32rpx;
  216. background: #FFFFFF;
  217. border-radius: 24rpx;
  218. }
  219. .card {
  220. & + & {
  221. margin-top: 32rpx;
  222. }
  223. }
  224. .order {
  225. margin-top: 40rpx;
  226. padding: 32rpx;
  227. background: #FAFAFF;
  228. border: 2rpx solid #FFFFFF;
  229. border-radius: 32rpx;
  230. &-header {
  231. font-family: PingFang SC;
  232. font-weight: 500;
  233. font-size: 36rpx;
  234. line-height: 1.4;
  235. color: #252545;
  236. }
  237. .row {
  238. margin-top: 32rpx;
  239. justify-content: space-between;
  240. font-family: PingFang SC;
  241. font-weight: 400;
  242. line-height: 1.4;
  243. &-label {
  244. font-size: 26rpx;
  245. color: #8B8B8B;
  246. }
  247. &-content {
  248. font-size: 28rpx;
  249. color: #393939;
  250. }
  251. }
  252. }
  253. .notice {
  254. margin-top: 40rpx;
  255. font-family: PingFang SC;
  256. font-weight: 400;
  257. &-header {
  258. font-size: 28rpx;
  259. line-height: 1.4;
  260. color: #393939;
  261. }
  262. &-content {
  263. margin-top: 24rpx;
  264. font-size: 24rpx;
  265. line-height: 1.4;
  266. color: #BABABA;
  267. }
  268. }
  269. .bottom {
  270. position: fixed;
  271. left: 0;
  272. bottom: 0;
  273. width: 100vw;
  274. // height: 270rpx;
  275. background: #FFFFFF;
  276. box-sizing: border-box;
  277. .agreement {
  278. display: flex;
  279. padding: 16rpx 40rpx;
  280. background: #EFEAFF;
  281. box-sizing: border-box;
  282. /deep/ .uv-checkbox-group {
  283. flex: none;
  284. }
  285. .desc {
  286. flex: 1;
  287. font-family: PingFang SC;
  288. font-size: 24rpx;
  289. font-weight: 400;
  290. line-height: 40rpx;
  291. color: #8B8B8B;
  292. }
  293. .highlight {
  294. color: $uni-color;
  295. }
  296. }
  297. .bar {
  298. padding: 24rpx 40rpx;
  299. padding-bottom: calc(env(safe-area-inset-bottom) + 24rpx);
  300. box-sizing: border-box;
  301. column-gap: 30rpx;
  302. .col {
  303. flex: 1;
  304. }
  305. .price {
  306. justify-content: flex-start;
  307. &-label {
  308. font-family: PingFang SC;
  309. font-weight: 400;
  310. font-size: 24rpx;
  311. line-height: 1.4;
  312. color: #626262;
  313. }
  314. &-unit {
  315. margin: 0 8rpx;
  316. font-family: PingFang SC;
  317. font-weight: 500;
  318. font-size: 24rpx;
  319. line-height: 1.4;
  320. color: #7451DE;
  321. }
  322. &-value {
  323. font-family: PingFang SC;
  324. font-weight: 500;
  325. font-size: 40rpx;
  326. line-height: 1.4;
  327. color: #7451DE;
  328. }
  329. }
  330. .btn {
  331. width: 100%;
  332. padding: 16rpx 0;
  333. box-sizing: border-box;
  334. font-family: PingFang SC;
  335. font-weight: 500;
  336. font-size: 36rpx;
  337. line-height: 1;
  338. color: #FFFFFF;
  339. background-image: linear-gradient(to right, #4B348F, #845CFA);
  340. border-radius: 41rpx;
  341. }
  342. }
  343. }
  344. </style>