index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <script setup lang="ts">
  2. import CouponItem from '../components/coupon/index.vue'
  3. import router from '@/router'
  4. const { userMemberInfo } = storeToRefs(useUserStore())
  5. definePage({
  6. name: 'xsb-confirmOrder',
  7. islogin: true,
  8. style: {
  9. navigationBarTitleText: '提交订单',
  10. },
  11. })
  12. const { selectedAddress, userInfo } = storeToRefs(useUserStore())
  13. const { SelectShopInfo } = storeToRefs(useSysXsbStore())
  14. const { Location } = storeToRefs(useAddressStore())
  15. type ConfirmOrderInfo = Api.shoppingCartOrderConfirm & Partial<Api.AppletOrderSkuVo>
  16. const orderInfo = ref<ConfirmOrderInfo>()
  17. const { totalProduct } = storeToRefs(useSmqjhCartStore())
  18. const isPay = ref(false)
  19. const remarks = ref('')
  20. const initialCouponId = ref<string | undefined>(undefined)
  21. const confirmedCouponId = ref<string | undefined>(undefined)
  22. const draftCouponId = ref<string | undefined>(undefined)
  23. const list = ref<string[]>(['即时配送', '自提'])
  24. const current = ref('即时配送')
  25. const model = reactive<{
  26. value1: string
  27. value2: string
  28. }>({
  29. value1: '',
  30. value2: '',
  31. })
  32. const mobilePattern = /^1[3-9]\d{9}$/
  33. const mobileRules = [{ required: true, pattern: mobilePattern, message: '请输入正确的手机号' }]
  34. const deliveryType = ref(1)
  35. const isFreeShipping = ref(false) // isFreeShipping1免邮0不免邮
  36. const isMemberGiftOrder = computed(() => !!orderInfo.value?.memberGiftItems?.length)
  37. const isSelfPickup = computed(() => current.value === '自提')
  38. const shopAddressInfo = computed(() => orderInfo.value?.shopAddressDTO)
  39. const shopDistanceText = computed(() => {
  40. const distance = shopAddressInfo.value?.distance
  41. if (distance === undefined || distance === null) {
  42. return ''
  43. }
  44. return `距你${Number(distance).toFixed(2)}km`
  45. })
  46. // 优惠券选择
  47. const couponPopup = ref(false)
  48. const couponList = ref<Api.AppMemberCouponVO[]>([])
  49. const couponTabActive = ref(0)
  50. const availableCoupons = computed(() => couponList.value.filter(it => it.isUsed === 2))
  51. const unavailableCoupons = computed(() => couponList.value.filter(it => it.isUsed !== 2))
  52. const displayCoupons = computed(() => couponTabActive.value === 0 ? availableCoupons.value : unavailableCoupons.value)
  53. const confirmedCoupon = computed(() => couponList.value.find(it => it.allowanceId === confirmedCouponId.value))
  54. const draftCoupon = computed(() => couponList.value.find(it => it.allowanceId === draftCouponId.value))
  55. const hasManualCouponSelection = computed(() => confirmedCouponId.value !== initialCouponId.value)
  56. const currentCouponDiscount = computed(() => {
  57. if (hasManualCouponSelection.value) {
  58. return Number(confirmedCoupon.value?.discountMoney || 0)
  59. }
  60. return Number(orderInfo.value?.coupon || 0)
  61. })
  62. const memberDiscountCents = computed(() => {
  63. if (!isMemberGiftOrder.value && userMemberInfo.value?.active) {
  64. return Math.round(Number(unref(orderInfo)?.memberDiscountAmount || 0) * 100)
  65. }
  66. return 0
  67. })
  68. const offsetPoints = computed(() => {
  69. const couponCents = Math.round(currentCouponDiscount.value * 100)
  70. const freightCents = isFreeShipping.value || isSelfPickup.value ? 0 : Math.round(Number(unref(orderInfo)?.transfee) * 100)
  71. const money = freightCents + Math.round(Number(unref(orderInfo)?.price) * 100) - couponCents - memberDiscountCents.value
  72. const cap = Math.max(0, money)
  73. if (Number(unref(orderInfo)?.offsetPoints) > cap) {
  74. return cap
  75. }
  76. return Number(unref(orderInfo)?.offsetPoints)
  77. })
  78. const currentCouponName = computed(() => {
  79. if (hasManualCouponSelection.value) {
  80. return getCouponDisplayName(confirmedCoupon.value)
  81. }
  82. return getCouponDisplayName(orderInfo.value)
  83. })
  84. const displayTotalPrice = computed(() => {
  85. if (!orderInfo.value) {
  86. return 0
  87. }
  88. const goodsPrice = Number(orderInfo.value.price || 0)
  89. const freight = isFreeShipping.value || isSelfPickup.value ? 0 : Number(orderInfo.value.transfee || 0)
  90. const couponDiscount = hasManualCouponSelection.value
  91. ? Number(confirmedCoupon.value?.discountMoney || 0)
  92. : Number(orderInfo.value?.coupon || 0)
  93. const pointsDiscount = offsetPoints.value / 100
  94. const memberDiscount = memberDiscountCents.value / 100
  95. return Math.max(0, Number((goodsPrice + freight - couponDiscount - pointsDiscount - memberDiscount).toFixed(2)))
  96. })
  97. const displayDiscountTotal = computed(() => Number((currentCouponDiscount.value + offsetPoints.value / 100 + memberDiscountCents.value / 100).toFixed(2)))
  98. const giftOriginalTotal = computed(() => {
  99. if (!isMemberGiftOrder.value)
  100. return 0
  101. return Number((Number(orderInfo.value?.price || 0) + Number(orderInfo.value?.transfee || 0)).toFixed(2))
  102. })
  103. onLoad((options: any) => {
  104. orderInfo.value = JSON.parse(options.data)
  105. console.log(orderInfo.value, '===商品数据===')
  106. syncCouponState()
  107. deliveryType.value = current.value === '自提' ? 2 : 3
  108. // model.value1 = userInfo.value?.nickName || ''
  109. model.value2 = userInfo.value?.mobile || ''
  110. })
  111. onShow(() => {
  112. useUserStore().getuserAddresslist()
  113. getConfirmOrder()
  114. // checkAddressFreeShipping()
  115. })
  116. watch(current, async (value) => {
  117. deliveryType.value = value === '自提' ? 2 : 3
  118. await getConfirmOrder()
  119. })
  120. function getCouponDisplayName(coupon?: Partial<Api.AppMemberCouponVO> & Record<string, any>) {
  121. return coupon?.activityName || coupon?.couponName || ''
  122. }
  123. function syncCouponState() {
  124. couponList.value = orderInfo.value?.orderCouponItemDTOS || []
  125. initialCouponId.value = orderInfo.value?.allowanceId
  126. confirmedCouponId.value = initialCouponId.value
  127. draftCouponId.value = initialCouponId.value
  128. }
  129. function getOrderConfirmParams() {
  130. const skuList = orderInfo.value?.skuList || []
  131. const firstSku = skuList[0]
  132. return {
  133. channelId: userInfo.value?.channelId,
  134. shopId: Number(firstSku?.shopId || SelectShopInfo.value?.shopId || 2),
  135. dvyType: deliveryType.value,
  136. addressId: selectedAddress.value?.id,
  137. shopSkuDTOList: skuList.map(it => ({
  138. skuId: it.skuId,
  139. num: Number(it.num || 1),
  140. })),
  141. }
  142. }
  143. async function getConfirmOrder() {
  144. if (!orderInfo.value) {
  145. return
  146. }
  147. const params: Record<string, any> = getOrderConfirmParams()
  148. if (!params.shopSkuDTOList?.length) {
  149. return
  150. }
  151. if (isSelfPickup.value) {
  152. if (!Location.value.latitude || !Location.value.longitude) {
  153. useGlobalToast().show('暂无定位缓存,无法计算自提点距离')
  154. }
  155. else {
  156. params.latitude = Location.value.latitude
  157. params.longitude = Location.value.longitude
  158. }
  159. }
  160. const res = await Apis.xsb.skuOrderConfirm({
  161. data: params,
  162. })
  163. if (isMemberGiftOrder.value) {
  164. orderInfo.value = {
  165. ...orderInfo.value,
  166. transfee: res.data.transfee ?? orderInfo.value?.transfee ?? 0,
  167. shopAddressDTO: res.data.shopAddressDTO ?? orderInfo.value?.shopAddressDTO,
  168. } as ConfirmOrderInfo
  169. }
  170. else {
  171. orderInfo.value = {
  172. ...orderInfo.value,
  173. ...res.data,
  174. skuList: res.data.sku || orderInfo.value?.skuList || [],
  175. } as ConfirmOrderInfo
  176. isFreeShipping.value = res.data.isFreeShipping === 1
  177. syncCouponState()
  178. }
  179. }
  180. function openShopLocation() {
  181. uni.openLocation({
  182. latitude: Number(shopAddressInfo.value?.shopLat) || 0,
  183. longitude: Number(shopAddressInfo.value?.shopLng) || 0,
  184. name: shopAddressInfo.value?.shopName,
  185. address: shopAddressInfo.value?.shopAddress,
  186. })
  187. }
  188. // async function checkAddressFreeShipping() {
  189. // if (isSelfPickup.value || !selectedAddress.value) {
  190. // return
  191. // }
  192. // if (selectedAddress.value.id === lastAddressId.value) {
  193. // return
  194. // }
  195. // lastAddressId.value = selectedAddress.value.id
  196. // const res = await Apis.xsb.addressFreeShippingCheck({
  197. // params: { addressId: selectedAddress.value.id },
  198. // })
  199. // if (res.data.check) {
  200. // const freeShippingData = res.data.addressFreeShippingVo
  201. // if (freeShippingData) {
  202. // isFreeShipping.value = freeShippingData.isFreeShipping === 1
  203. // if (freeShippingData.totalPrice !== undefined) {
  204. // orderInfo.value = {
  205. // ...orderInfo.value!,
  206. // totalPrice: freeShippingData.totalPrice,
  207. // } as ConfirmOrderInfo
  208. // }
  209. // if (freeShippingData.transfee !== undefined) {
  210. // orderInfo.value = {
  211. // ...orderInfo.value!,
  212. // transfee: freeShippingData.transfee,
  213. // } as ConfirmOrderInfo
  214. // }
  215. // }
  216. // console.log(orderInfo.value, '===商品数据===')
  217. // }
  218. // }
  219. async function openCouponPopup() {
  220. draftCouponId.value = confirmedCouponId.value
  221. couponPopup.value = true
  222. }
  223. function handleSelectCoupon(item: Api.AppMemberCouponVO) {
  224. if (item.isUsed !== 2 || !item.allowanceId) {
  225. return
  226. }
  227. // 再次点击已选中的券则取消选中
  228. if (draftCouponId.value === item.allowanceId) {
  229. draftCouponId.value = undefined
  230. return
  231. }
  232. draftCouponId.value = item.allowanceId
  233. }
  234. function confirmCoupon() {
  235. confirmedCouponId.value = draftCouponId.value
  236. couponPopup.value = false
  237. }
  238. async function handleH5PayResult(orderNumber: string): Promise<boolean> {
  239. const isPaySuccess = await useUserStore().pollOrderPaySuccess(orderNumber)
  240. if (isPaySuccess) {
  241. router.replace({ name: 'xsb-order' })
  242. return true
  243. }
  244. useGlobalToast().show({ msg: '暂未查询到支付成功,请稍后在订单列表查看' })
  245. isPay.value = false
  246. return false
  247. }
  248. async function handlePay() {
  249. if (!isSelfPickup.value && !selectedAddress.value) {
  250. useGlobalToast().show({ msg: '请选择收货地址' })
  251. return
  252. }
  253. if (!orderInfo.value) {
  254. useGlobalToast().show({ msg: '网络异常!请联系客服' })
  255. return
  256. }
  257. if (isSelfPickup.value) {
  258. if (!model.value1) {
  259. useGlobalToast().show({ msg: '请填写联系人' })
  260. return
  261. }
  262. if (!mobilePattern.test(model.value2)) {
  263. useGlobalToast().show({ msg: '请输入正确的手机号' })
  264. return
  265. }
  266. }
  267. isPay.value = true
  268. try {
  269. if (isMemberGiftOrder.value) {
  270. console.log('=====赠品订单')
  271. if (!selectedAddress.value) {
  272. useGlobalToast().show({ msg: '请选择收货地址' })
  273. return
  274. }
  275. await Apis.sys.giftsReceive({
  276. data: {
  277. addressId: selectedAddress.value.id,
  278. items: orderInfo.value.memberGiftItems,
  279. },
  280. })
  281. await useUserStore().paySuccess('xsb-order', 'subPack-xsb/commonTab/index')
  282. return
  283. }
  284. const orderItemList = orderInfo.value?.skuList.map((it) => {
  285. return {
  286. prodCount: it.num,
  287. skuId: it.skuId,
  288. }
  289. })
  290. const orderNumber = await useUserStore().getOrderPayMent(
  291. deliveryType.value !== 2 ? orderInfo.value.transfee : 0,
  292. 'XSB',
  293. deliveryType.value,
  294. Number(orderInfo.value?.skuList[0].shopId || SelectShopInfo.value?.shopId),
  295. orderItemList,
  296. unref(remarks),
  297. confirmedCouponId.value,
  298. isSelfPickup.value
  299. ? {
  300. consigneeName: model.value1,
  301. consigneeMobile: model.value2,
  302. }
  303. : undefined,
  304. isFreeShipping.value,
  305. )
  306. const payMent = await useUserStore().getPayMent(orderNumber)
  307. const skuList = orderInfo.value?.skuList || []
  308. await useUserStore().clearCart(skuList)
  309. totalProduct.value = null
  310. isPay.value = false
  311. if (payMent.payType !== 'point') {
  312. try {
  313. // #ifdef H5
  314. useUserStore().handleCommonWechatPay(orderNumber)
  315. await handleH5PayResult(orderNumber)
  316. // #endif
  317. // #ifdef MP-WEIXIN
  318. const res = await useUserStore().handleCommonPayMent(orderNumber)
  319. await useUserStore().getWxCommonPayment(res)
  320. await useUserStore().paySuccess('xsb-order', 'subPack-xsb/commonTab/index')
  321. // #endif
  322. }
  323. catch {
  324. await useUserStore().payError('xsb-order', 'subPack-xsb/commonTab/index')
  325. }
  326. }
  327. else {
  328. await useUserStore().handleCommonPayMent(orderNumber)
  329. await useUserStore().paySuccess('xsb-order', 'subPack-xsb/commonTab/index')
  330. }
  331. }
  332. catch {
  333. isPay.value = false
  334. }
  335. }
  336. </script>
  337. <template>
  338. <view class="page px20rpx py20rpx">
  339. <wd-segmented v-model:value="current" :options="list" />
  340. <view
  341. v-if="current === '即时配送'"
  342. class="my20rpx rounded-16rpx bg-white p24rpx"
  343. @click="router.push({ name: 'common-addressList', params: { type: 'select' } })"
  344. >
  345. <view class="flex items-center justify-between">
  346. <view v-if="!selectedAddress" class="flex items-center">
  347. <wd-icon name="location" size="18px" />
  348. <view class="ml10rpx text-28rpx">
  349. 请添加收货地址
  350. </view>
  351. </view>
  352. <view v-else>
  353. <view class="flex items-center">
  354. <view v-if="selectedAddress.defaulted" class="mr20rpx">
  355. <wd-tag type="primary">
  356. 默认
  357. </wd-tag>
  358. </view>
  359. <view class="flex items-center text-28rpx font-semibold">
  360. <view>{{ selectedAddress?.consigneeName }} </view>
  361. <view class="ml20rpx">
  362. {{ selectedAddress?.consigneeMobile }}
  363. </view>
  364. </view>
  365. </view>
  366. <view class="mt20rpx flex items-center text-24rpx text-#AAAAAA">
  367. {{ selectedAddress?.province }} {{ selectedAddress?.city }} {{ selectedAddress?.detailAddress }}
  368. </view>
  369. </view>
  370. <wd-icon name="arrow-right" size="18px" color="#aaa" />
  371. </view>
  372. </view>
  373. <view v-else class="my20rpx rounded-16rpx bg-white p24rpx">
  374. <view class="flex items-center gap-50rpx">
  375. <view class="flex-1">
  376. <view class="text-28rpx font-semibold">
  377. 自提点:{{ shopAddressInfo?.shopName || orderInfo?.shopName || '暂无门店信息' }}
  378. </view>
  379. <view class="mt-20rpx text-24rpx text-#AAAAAA">
  380. {{ shopAddressInfo?.shopAddress || '暂无门店地址' }}
  381. </view>
  382. </view>
  383. <view class="flex-shrink-0" @click="openShopLocation">
  384. <view v-if="shopDistanceText" class="mb-20rpx text-24rpx text-#AAAAAA">
  385. {{ shopDistanceText }}
  386. </view>
  387. <wd-icon name="location" size="22px" color="var(--them-color)" />
  388. </view>
  389. </view>
  390. <view>
  391. <view class="mt-20rpx flex items-center">
  392. <view class="w100rpx text-28rpx">
  393. 联系人:
  394. </view>
  395. <wd-input
  396. v-model="model.value1"
  397. prop="value1"
  398. clearable
  399. placeholder="请输入联系人"
  400. :rules="[{ required: true, message: '请填写联系人' }]"
  401. />
  402. </view>
  403. <view class="mt-20rpx flex items-center">
  404. <view class="w140rpx text-28rpx">
  405. 预留电话:
  406. </view>
  407. <wd-input
  408. v-model="model.value2"
  409. prop="value2"
  410. clearable
  411. placeholder="请输入预留电话"
  412. :rules="mobileRules"
  413. />
  414. </view>
  415. </view>
  416. </view>
  417. <view class="rounded-16rpx bg-white p24rpx">
  418. <view class="flex items-center text-28rpx font-semibold">
  419. {{ orderInfo?.shopName }}
  420. </view>
  421. <view class="my24rpx h2rpx w-full bg-#F0F0F0" />
  422. <CollapsePanel :line-height="150">
  423. <view v-for="item in orderInfo?.skuList" :key="item.id" class="mb20rpx w-full flex items-center">
  424. <view class="mr20rpx w120rpx flex-shrink-0">
  425. <image :src="item.pic" class="h120rpx w120rpx" />
  426. </view>
  427. <view class="flex-1">
  428. <view class="w-full flex items-center justify-between font-semibold">
  429. <view class="text-28rpx">
  430. <text v-if="isMemberGiftOrder" class="mr-8rpx rounded-8rpx bg-#FF4D3A px-12rpx py-4rpx text-22rpx text-#FFF">
  431. 赠品
  432. </text>
  433. {{ item.skuName }}
  434. </view>
  435. <view class="text-32rpx text-#FF4D3A">
  436. ¥{{ item.price }}
  437. </view>
  438. </view>
  439. <view class="text-24rpx text-#AAAAAA">
  440. 规格:{{ item.spec }}
  441. </view>
  442. <view class="text-24rpx text-#AAAAAA">
  443. ×{{ item.num || 1 }}
  444. </view>
  445. </view>
  446. </view>
  447. </CollapsePanel>
  448. </view>
  449. <view class="mt20rpx rounded-16rpx bg-white p24rpx">
  450. <view class="mb28rpx flex items-center justify-between text-28rpx">
  451. <view>商品金额</view>
  452. <view class="text-#FF4D3A font-semibold">
  453. ¥{{ orderInfo?.price }}
  454. </view>
  455. </view>
  456. <view v-if="!isFreeShipping" class="mb28rpx flex items-center justify-between text-28rpx">
  457. <view v-if="deliveryType == 3">
  458. 配送费(即时配送)
  459. </view>
  460. <view v-if="deliveryType == 1">
  461. 快递
  462. </view>
  463. <view v-if="deliveryType == 2">
  464. 自提
  465. </view>
  466. <view class="text-#FF4D3A font-semibold">
  467. ¥{{ deliveryType == 2 ? '0.00' : orderInfo?.transfee }}
  468. </view>
  469. </view>
  470. <view v-if="!isMemberGiftOrder && userMemberInfo.active && orderInfo?.memberBenefitDesc && orderInfo?.memberDiscountAmount" class="mb28rpx flex items-center justify-between text-28rpx">
  471. <view>{{ orderInfo?.memberBenefitDesc }}</view>
  472. <view class="text-#FF4D3A font-semibold">
  473. -¥{{ orderInfo?.memberDiscountAmount }}
  474. </view>
  475. </view>
  476. <view v-if="!isMemberGiftOrder" class="mb28rpx flex items-center justify-between text-28rpx" @click="openCouponPopup">
  477. <view>优惠券</view>
  478. <view class="flex items-center">
  479. <view v-if="currentCouponDiscount > 0" class="text-[#FF4D3A] font-semibold">
  480. -¥{{ currentCouponDiscount }}
  481. </view>
  482. <view v-else class="text-[#AAAAAA]">
  483. {{ availableCoupons.length > 0 ? `${availableCoupons.length}张可用` : '暂无可用' }}
  484. </view>
  485. <wd-icon name="arrow-right" size="18px" color="#aaa" class="ml10rpx" />
  486. </view>
  487. </view>
  488. <view v-if="!isMemberGiftOrder" class="flex items-center justify-between text-28rpx">
  489. <view>积分({{ offsetPoints }})</view>
  490. <view class="text-#FF4D3A font-semibold">
  491. - ¥{{ offsetPoints / 100 }}
  492. </view>
  493. </view>
  494. <view class="my24rpx h2rpx w-full bg-#F0F0F0" />
  495. <view class="flex items-center justify-between text-28rpx">
  496. <view class="font-semibold">
  497. 总计:
  498. </view>
  499. <view v-if="isMemberGiftOrder" class="flex items-center">
  500. <text class="mr-8rpx rounded-8rpx bg-#FF4D3A px-12rpx py-4rpx text-22rpx text-#FFF">
  501. 赠品
  502. </text>
  503. <text class="text-#AAAAAA line-through">
  504. ¥{{ giftOriginalTotal }}
  505. </text>
  506. </view>
  507. <view v-else class="text-#FF4D3A font-semibold">
  508. ¥ {{ displayTotalPrice }}
  509. </view>
  510. </view>
  511. </view>
  512. <view v-if="isMemberGiftOrder" class="mt20rpx flex items-center gap-20rpx rounded-16rpx bg-white p24rpx">
  513. <wd-icon name="warning" size="16px" color="#FF4D3A" />
  514. <text class="text-24rpx">
  515. 本商品为会员权益赠品,购买后不支持售后
  516. </text>
  517. </view>
  518. <view class="mt20rpx flex items-center rounded-16rpx bg-white p24rpx">
  519. <view class="w80rpx">
  520. 备注
  521. </view>
  522. <view class="flex-1">
  523. <wd-input v-model="remarks" placeholder="选填,请先和商家协商一致,付款后商家可见" clearable no-border />
  524. </view>
  525. </view>
  526. <view class="h250rpx" />
  527. <!-- 优惠券选择弹窗 -->
  528. <Zpopup v-model="couponPopup" :zindex="100" bg="#fff">
  529. <view class="ios box-border w-full">
  530. <view class="px-32rpx pt-32rpx">
  531. <view class="mb-24rpx text-center text-32rpx font-semibold">
  532. 优惠券
  533. </view>
  534. <view class="mb-24rpx flex items-center">
  535. <view
  536. class="mr-16rpx flex-1 rounded-full py-18rpx text-center text-28rpx"
  537. :class="couponTabActive === 0 ? 'bg-[var(--them-color)] text-white font-semibold' : 'bg-[#F0F0F0] text-[#666]'"
  538. @click="couponTabActive = 0"
  539. >
  540. 可用券({{ availableCoupons.length }})
  541. </view>
  542. <view
  543. class="flex-1 rounded-full py-18rpx text-center text-28rpx"
  544. :class="couponTabActive === 1 ? 'bg-[var(--them-color)] text-white font-semibold' : 'bg-[#F0F0F0] text-[#666]'"
  545. @click="couponTabActive = 1"
  546. >
  547. 不可用券({{ unavailableCoupons.length }})
  548. </view>
  549. </view>
  550. <view class="mb-20rpx flex items-center justify-between text-24rpx">
  551. <view class="text-[#333]">
  552. 优惠券共减
  553. </view>
  554. <view v-if="draftCoupon" class="text-right text-[#FF4D3A]">
  555. {{ getCouponDisplayName(draftCoupon) }},可减-¥{{ draftCoupon.discountMoney }}
  556. </view>
  557. <view v-else-if="currentCouponDiscount > 0 && currentCouponName" class="text-right text-[#FF4D3A]">
  558. {{ currentCouponName }},可减¥{{ currentCouponDiscount }}
  559. </view>
  560. <view v-else class="text-[#AAAAAA]">
  561. 暂未选择
  562. </view>
  563. </view>
  564. </view>
  565. <scroll-view scroll-y class="box-border h-560rpx px-32rpx">
  566. <view v-for="item in displayCoupons" :key="item.id" class="relative mb-20rpx">
  567. <view class="relative" @click="handleSelectCoupon(item)">
  568. <CouponItem :itemcoupon="item" :hide-all-btn="true" />
  569. <view
  570. class="absolute right-32rpx top-50% h-44rpx w-44rpx flex items-center justify-center -translate-y-50%"
  571. >
  572. <wd-icon v-if="draftCouponId === item.allowanceId" name="check-circle" size="44rpx" color="#FF4D3A" />
  573. <view v-else class="h-40rpx w-40rpx border-2rpx border-[#ccc] rounded-full border-solid" />
  574. </view>
  575. </view>
  576. <view
  577. v-if="item.unavailableReason"
  578. class="relative z-1 w-full rounded-b-16rpx bg-[#FFF4F3] px20rpx py18rpx text-24rpx -mt16rpx"
  579. >
  580. <view>
  581. 不可用原因
  582. </view>
  583. <view>
  584. {{ item.unavailableReason }}
  585. </view>
  586. </view>
  587. </view>
  588. <view v-if="displayCoupons.length === 0" class="py-80rpx text-center text-28rpx text-[#AAAAAA]">
  589. 暂无优惠券
  590. </view>
  591. </scroll-view>
  592. </view>
  593. <template #footer>
  594. <view class="box-border w-full px24rpx">
  595. <wd-button size="large" block type="primary" @click="confirmCoupon">
  596. 确定
  597. </wd-button>
  598. </view>
  599. </template>
  600. </Zpopup>
  601. <view class="ios footer fixed bottom-0 left-0 z-10 box-border w-full rounded-t-16rpx bg-white px24rpx">
  602. <view class="box-border w-full flex items-center justify-between py20rpx">
  603. <view v-if="isMemberGiftOrder" class="flex items-center">
  604. <text class="mr-8rpx rounded-8rpx bg-#FF4D3A px-12rpx py-4rpx text-22rpx text-#FFF">
  605. 赠品
  606. </text>
  607. <text class="text-32rpx text-#AAAAAA line-through">
  608. ¥{{ giftOriginalTotal }}
  609. </text>
  610. </view>
  611. <view v-else class="flex items-center text-#FF4D3A">
  612. <view class="font-semibold10 flex items-baseline text-36rpx">
  613. <text class="text-24rpx">
  614. </text> {{ displayTotalPrice }}
  615. </view>
  616. <view class="ml20rpx text-22rpx">
  617. 共减¥{{ displayDiscountTotal }}
  618. </view>
  619. </view>
  620. <view class="w180-btn w180rpx">
  621. <wd-button size="large" :loading="isPay" loading-color="#9ED605" @click="handlePay">
  622. 立即支付
  623. </wd-button>
  624. </view>
  625. </view>
  626. </view>
  627. </view>
  628. </template>
  629. <style scoped lang="scss">
  630. .footer {
  631. box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(0, 0, 0, 0.05);
  632. }
  633. .page {
  634. .w180-btn {
  635. :deep() {
  636. .wd-button {
  637. width: 180rpx !important;
  638. }
  639. }
  640. }
  641. }
  642. </style>