index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <template>
  2. <v-card class="default-width pa-5 mb-5" style="min-height: 75vh; margin-top: 70px;">
  3. <div>
  4. <!-- 头部地址选择【配送地址】【自提地址】 -->
  5. <AddressSelection v-model="addressState" class="addressBox elevation-3" />
  6. <!-- 购买的商品信息 -->
  7. <v-card class="goodsListBox my-3 pa-3 elevation-5">
  8. <s-goods-item
  9. v-for="(item, index) in state.orderInfo.items"
  10. :key="item.skuId"
  11. :img="item.picUrl"
  12. :title="item.spuName"
  13. :skuText="item.properties.map((property) => property.valueName).join(' ')"
  14. :price="item.price"
  15. :num="item.count"
  16. :style="{'marginTop': index ? '8px' : '0px'}"
  17. />
  18. </v-card>
  19. <!-- 价格信息 -->
  20. <div>
  21. <div>
  22. <!-- <div class="order-item d-flex color-666">
  23. <div class="item-title mr-3 ">商品金额:</div>
  24. <div>¥{{ fen2yuan(state.orderInfo.price.totalPrice) }}</div>
  25. </div> -->
  26. <!-- 快递配置时,信息的展示 -->
  27. <!-- <div
  28. class="order-item d-flex"
  29. v-if="addressState.deliveryType === 1"
  30. >
  31. <div class="item-title mr-3">运{{ spaces() }}费:</div>
  32. <div>
  33. <span class="text-red" v-if="state.orderInfo.price.deliveryPrice > 0">
  34. +¥{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
  35. </span>
  36. <div class="item-value" v-else>免运费</div>
  37. </div>
  38. </div> -->
  39. <!-- 门店自提时,需要填写姓名和手机号 -->
  40. </div>
  41. <div class="mt-5">
  42. <v-text-field
  43. v-model="state.orderPayload.remark"
  44. label="订单备注"
  45. placeholder="建议留言前先与商家沟通"
  46. variant="outlined"
  47. density="compact"
  48. color="primary"
  49. ></v-text-field>
  50. </div>
  51. <div class="total-box-footer d-flex flex-column align-end">
  52. <div class="d-flex">
  53. <div class="mr-3">
  54. <span class="total-num">共</span>
  55. <span class="mx-1" style="color: var(--v-primary-base);">{{ state.orderInfo.items.reduce((acc, item) => acc + item.count, 0) }}</span>
  56. <span class="total-num">件</span>
  57. </div>
  58. <div>合计支付:</div>
  59. <div class="total-num text-red"> ¥{{ fen2yuan(state.orderInfo.price.payPrice) }}元</div>
  60. </div>
  61. </div>
  62. <div class="text-center">
  63. <div>请在30分钟内完成支付,支付成功后可以随机抽取赠送的房券。</div>
  64. <v-btn class="elevation-5" color="primary" width="250">立即支付</v-btn>
  65. <div>支付时间还剩余30分27秒</div>
  66. </div>
  67. </div>
  68. </div>
  69. </v-card>
  70. </template>
  71. <script setup>
  72. defineOptions({ name: 'mall-order-settlement' })
  73. import { useRoute, useRouter } from 'vue-router'
  74. import { reactive, ref, onMounted, watch } from 'vue'
  75. import AddressSelection from '@/views/mall/components/details/order/addressSelection.vue'
  76. import sGoodsItem from '@/views/mall/components/s-goods-item'
  77. import { fen2yuan } from '@/hooks/web/useGoods'
  78. import { spaces } from '@/utils/index.js'
  79. import { getTradeConfig, createOrder, settlementOrder } from '@/api/mall/trade'
  80. import Snackbar from '@/plugins/snackbar'
  81. const route = useRoute()
  82. const router = useRouter()
  83. const { id } = route.params
  84. const { count } = route.query
  85. const state = reactive({
  86. orderPayload: {},
  87. orderInfo: {
  88. items: [], // 商品项列表
  89. price: {}, // 价格信息
  90. },
  91. showCoupon: false, // 是否展示优惠劵
  92. couponInfo: [], // 优惠劵列表
  93. showDiscount: false, // 是否展示营销活动
  94. // ========== 积分 ==========
  95. pointStatus: false, //是否使用积分
  96. });
  97. // 检测支付环境
  98. const payState = reactive({
  99. orderType: 'goods', // 订单类型; goods - 商品订单, recharge - 充值订单
  100. orderInfo: {}, // 支付单信息
  101. payStatus: 0, // 0=检测支付环境, -2=未查询到支付单信息, -1=支付已过期, 1=待支付,2=订单已支付
  102. payMethods: [], // 可选的支付方式
  103. payment: '', // 选中的支付方式
  104. });
  105. const addressState = ref({
  106. addressInfo: {}, // 选择的收货地址
  107. deliveryType: undefined, // 收货方式:1-快递配送,2-门店自提
  108. isPickUp: true, // 门店自提是否开启
  109. pickUpInfo: {}, // 选择的自提门店信息
  110. receiverName: '', // 收件人名称
  111. receiverMobile: '', // 收件人手机
  112. });
  113. async function tradeConfig () {
  114. // 获取交易配置
  115. const data = await getTradeConfig();
  116. addressState.value.isPickUp = data.deliveryPickUpEnabled;
  117. // 价格计算
  118. // 情况一:先自动选择“快递物流”
  119. addressState.value.deliveryType = 1;
  120. let orderCode = await getOrderInfo();
  121. if (orderCode === 0) {
  122. return;
  123. }
  124. // 情况二:失败,再自动选择“门店自提”
  125. if (addressState.value.isPickUp) {
  126. addressState.value.deliveryType = 2;
  127. let orderCode = await getOrderInfo();
  128. if (orderCode === 0) {
  129. return;
  130. }
  131. }
  132. // 情况三:都失败,则不选择
  133. addressState.value.deliveryType = undefined;
  134. await getOrderInfo()
  135. }
  136. // 检查库存 & 计算订单价格
  137. async function getOrderInfo() {
  138. // 计算价格
  139. const data = await settlementOrder({
  140. items: [{ skuId: id, count }],
  141. couponId: state.orderPayload.couponId,
  142. deliveryType: addressState.value.deliveryType,
  143. addressId: addressState.value.addressInfo.id, // 收件地址编号
  144. pickUpStoreId: addressState.value.pickUpInfo.id, //自提门店编号
  145. receiverName: addressState.value.receiverName, // 选择门店自提时,该字段为联系人名
  146. receiverMobile: addressState.value.receiverMobile, // 选择门店自提时,该字段为联系人手机
  147. pointStatus: state.pointStatus,
  148. combinationActivityId: state.orderPayload.combinationActivityId,
  149. combinationHeadId: state.orderPayload.combinationHeadId,
  150. seckillActivityId: state.orderPayload.seckillActivityId,
  151. pointActivityId: state.orderPayload.pointActivityId,
  152. });
  153. state.orderInfo = data;
  154. state.couponInfo = data.coupons || [];
  155. // 设置收货地址
  156. if (state.orderInfo.address) {
  157. addressState.value.addressInfo = state.orderInfo.address;
  158. }
  159. return 0;
  160. }
  161. // 使用 watch 监听地址和配送方式的变化
  162. watch(addressState, async (newAddress, oldAddress) => {
  163. // 如果收货地址或配送方式有变化,则重新计算价格
  164. if (
  165. newAddress.addressInfo.id !== oldAddress.addressInfo.id ||
  166. newAddress.deliveryType !== oldAddress.deliveryType
  167. ) {
  168. await getOrderInfo();
  169. }
  170. });
  171. onMounted(async () => {
  172. if (!id || !count) return router.go(-1)
  173. await tradeConfig()
  174. })
  175. </script>