<template> <!-- 批量服务类商品购买 --> <view class="flex-col page" :style="{ backgroundImage: 'url(' + bkgPubilcPath + ')' }"> <view class="flex-row justify-between items-center section_2" @click="loadPop"> <view class="flex-row items-center"> <image class="shrink-0 image" :src="orderUrl + '/serviceWaitPay/lxr.png'" /> <text class="text ml-10" style="font-size: 30rpx;">{{ contactRealInfo.name }} {{ contactRealInfo.phone }}</text> </view> <view class="flex-row items-center group" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"> <text class="font text_2">更换联系人</text> <image class="image_2" :src="orderUrl + '/serviceWaitPay/yjt.png'" /> </view> </view> <view class="flex-col section_3"> <view class="flex-col"> <view class="flex-row items-end list-item mt-13" v-for="(item, index) in productArr" :key="index"> <image class="shrink-0 image_3" mode="aspectFill" :src="publicPath + item.cartExperienceGoodVO.goodImg" /> <view class="flex-col flex-1 group_5"> <view class="flex-row self-stretch group_3"> <!-- <text class="font">{{ item.cartExperienceGoodVO }}</text> --> <text class="font text_3">【{{ item.cartExperienceGoodVO.type }}】 {{item.cartExperienceGoodVO.name}} </text> </view> <text class="self-start font_2 text_7 mt-9">已选时间:{{ item.reservationDate }} {{ getWeekday(item.reservationDate) }}</text> <text class="self-start font_3 text_8 mt-9">{{ item.timeSlot }}</text> <view class="flex-row justify-between items-end self-stretch mt-9"> <view class="flex-row items-center"> <!-- <image class="shrink-0 image_6" src="https://ide.code.fun/api/image?token=67be64de4ae84d0012274ced&name=4a3c5c3a5c83be7a7b0551c598ed6037.png" /> --> <text class="font_5 ml-3">¥{{ item.cartExperienceGoodVO.price }}</text> <!-- <text class="font_6 ml-3">00</text> --> </view> <image class="image_4" :src="orderUrl + '/serviceWaitPay/sub.png'" @click="shortNum(index)" /> </view> </view> <view class="flex-row shrink-0 group_4"> <view class="flex-col justify-start items-center text-wrapper"><text class="font_4 text_6">{{ item.quantity }}</text></view> <image class="image_5 ml-2" :src="orderUrl + '/serviceWaitPay/add.png'" @click="addNum(index)" /> </view> </view> </view> <!-- <view class="flex-row justify-center items-center group_9 mt-15"> <view class="group_10"> <text class="font_7 text_11">注:购买商品均视为同意</text> <text class="font_7 text_12">用户须知</text> </view> <image class="image_7 ml-2" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FcoxrJLJf-quesrion.png" /> </view> --> </view> <view class="flex-col section_4"> <view class="flex-row justify-between items-center my-coupon"> <view class="flex-row"> <text class="font_8 text_13">商品总价</text> <text class="font_9 ml-7">共{{ productArr.length }}件商品</text> </view> <view class="flex-row items-center group_11"> <!-- <image class="shrink-0 image_8" src="https://ide.code.fun/api/image?token=67be64de4ae84d0012274ced&name=eb4f44af1db8b709d9d4b2aecf5159be.png" /> --> <text class="font_10">¥{{ sumprice.toFixed(2) }}</text> </view> </view> <view class="flex-row justify-between my-coupon" @click="openCoupon" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"> <text class="font_8">优惠券</text> <view class="flex-row group_12"> <text class="font_9" :style="{color: textColor}">{{ templateString }}</text> <image class="shrink-0 image_9 ml-3" :src="orderUrl + '/serviceWaitPay/yjt2.png'" /> </view> </view> <view class="flex-row justify-between items-center my-coupon"> <text class="font_8 text_14">合计</text> <view class="flex-row items-center group_13"> <!-- <image class="shrink-0 image_8" src="https://ide.code.fun/api/image?token=67be64de4ae84d0012274ced&name=0f3f4f80197a7b3647f307901f6a3bea.png" /> --> <text class="font_10">¥{{ sfAmount.toFixed(2) }}</text> </view> </view> </view> <view class="flex-col section_5"> <text class="self-start font_8 text_15">订单备注</text> <textarea maxlength="250" placeholder-style="font-size: 25rpx;" v-model="note" placeholder="备注建议提前协商(250字以内)" class="flex-col justify-start items-start self-stretch text-wrapper_2 mt-11"> </textarea> </view> <view class="flex-row justify-between items-center section_6"> <view class="flex-row items-center"> <!-- <image class="shrink-0 image_8 image_10" :src="orderUrl + '/serviceWaitPay/money.png'" /> --> <text class="text_17">应付:</text> <text class="text_18">¥{{ sfAmount.toFixed(2) }}</text> <!-- <text class="text_20">00</text> --> </view> <view class="flex-col justify-start items-center text-wrapper_3" @click="wxPayFd" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"><text class="font_8 text_19">微信支付</text></view> </view> </view> <uni-popup ref="popup" background-color="#fff" :mask-click="false"> <view class="popup-content"> <contactsComponentVue></contactsComponentVue> </view> </uni-popup> <uni-popup ref="coupon"> <view class="coupon-popup"> <couponPopupVue></couponPopupVue> </view> </uni-popup> <!-- 遮罩层 --> <view v-if="isShow" class="overlay"></view> </template> <script setup> import {nextTick, onMounted, onUnmounted, ref, toRaw} from 'vue' import emitter from '../../../utils/emitter' import { onLoad , onShow } from "@dcloudio/uni-app"; import { baseUrl } from '../../../api/request'; import { stateMap } from '../../../common/global'; import { sum } from 'mathjs'; import couponPopupVue from '../../coupon/component/couponPopup.vue'; import contactsComponentVue from '../component/contactsComponent.vue'; //联系人弹窗\ import contactPopVue from '../../mine/component/contactPop.vue'; //新增联系人弹窗 import { getFonts } from '../../../common/globalFont'; import * as math from 'mathjs' import { dealResult } from '../../../common/globalFunction'; import { orderUrl } from '../../../common/globalImagesUrl'; import { publicPath,bkgPubilcPath } from '../../../common/globalImagesUrl'; //一些暂时变量 const sumprice = ref(0) //总价格 const popup = ref(null) //弹窗对象 const contactRealInfo = ref({ name: '请选择联系人' }) //地址页 选择地址传过来的值 进入页面首先是默认地址,若无默认地址,则为空 const productArr = ref([]) //商品对象 const userInfo = wx.getStorageSync('userInfo') //用户信息 const orderItemList = ref({}) const totalInfo = ref([]) //购物车传过来的批量商品 const note = ref('') const postCartArr = ref([]) const singleService = ref({}) //单个服务类商品 const cnt = ref(1) //单个服务类商品的商品数量 const coupon = ref(null) const couponObj = ref({}) const templateString = ref('') const conditionAmount = ref(0) const sfAmount = ref(0) const myCouponList = ref([]) const cookie = wx.getStorageSync("cookie") //请求头 const useCouponId = ref(null) const textColor = ref('') const delContactByIdHandler = (val) => { console.log('===============>', val) if (contactRealInfo.value.id === val) { console.log(3333) contactRealInfo.value = {} contactRealInfo.value.name = '请选择联系人' } } const closeHandler = () => { close() } const contactsNowInfoHandler = (val) => { contactRealInfo.value = val } const closeCouponHandler = () => { nextTick(() => { if (coupon.value) { coupon.value.close() } }) } const cancelCouponHandler = () => { templateString.value = myCouponList.value.length + '张优惠券可用' sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' } const getCouponObjHandler = (val) => { couponObj.value = val templateString.value = "-¥" + val.couponVO.conditionAmount.toFixed(2) conditionAmount.value = val.couponVO.conditionAmount sfAmount.value = sumprice.value - conditionAmount.value useCouponId.value = val.id textColor.value = '#FFB6B9' console.log(val) } onLoad( async (options)=>{ getFonts() if(options.cartInfo === undefined) { singleService.value = JSON.parse(options.obj) cnt.value = JSON.parse(options.cnt) console.log('单个服务类--->',singleService.value); console.log('商品数量---->',cnt.value); } else { totalInfo.value = JSON.parse(options.cartInfo) console.log('options.cartInfo-->',JSON.parse(options.cartInfo)); console.log('totalInfo.value-->',toRaw(totalInfo.value) ); await getProduct() //获取商品列表 } await getMyCouponList() }) const updateContactObjHandler = (val) => { if (contactRealInfo.value.id === val.id) { contactRealInfo.value = val } } onMounted(() => { //将关闭弹窗方法传入弹窗页面,绑定弹窗按钮可关闭弹窗 emitter.on('close', closeHandler) //获取联系人信息 emitter.on('contactsNowInfo', contactsNowInfoHandler) emitter.on('closeCoupon', closeCouponHandler) emitter.on('cancelCoupon', cancelCouponHandler) emitter.on('getCouponObj', getCouponObjHandler) emitter.on('delContactById', delContactByIdHandler) emitter.on('updateContactObj', updateContactObjHandler) }) onUnmounted(() => { //将关闭弹窗方法传入弹窗页面,绑定弹窗按钮可关闭弹窗 emitter.off('close', closeHandler) //获取联系人信息 emitter.off('contactsNowInfo', contactsNowInfoHandler) emitter.off('closeCoupon', closeCouponHandler) emitter.off('cancelCoupon', cancelCouponHandler) emitter.off('getCouponObj', getCouponObjHandler) emitter.off('delContactById', delContactByIdHandler) emitter.off('updateContactObj', updateContactObjHandler) }) //关闭弹窗 const close = () => { nextTick(() => { if (popup.value) { popup.value.close() } }) } //加载弹窗。默认从底部弹出 const loadPop =() =>{ popup.value.open('bottom') } //获取用户默认联系人 const getDefaultContact = async () =>{ const res = await uni.request({ url: baseUrl + '/contacts/list', method: 'POST', header: { cookie: wx.getStorageSync('cookie') } }) //根据for循环遍历默认地址 let contactArr = res.data.data for(let key in contactArr) { if(contactArr[key].isDefault === 1) { contactRealInfo.value = contactArr[key] } } if (JudgeIsNullity(contactRealInfo.value.name)) { contactRealInfo.value.name = '请选择联系人' } } const createOrder = async () => { //服务类购物车的购买方法 console.log('联系人信息-->',contactRealInfo.value); formatArr() console.log('postCartArr--->',postCartArr.value); const res = await uni.request({ //向后端发送生成订单请求 url: baseUrl + '/order/add/experience/cart', method: 'POST', header: { cookie: wx.getStorageSync('cookie') }, data: { orderType: productArr.value[0].cartExperienceGoodVO.type === '服务类' ? 'service' : 'product', userName: userInfo.userName, contactsId: contactRealInfo.value.id, //联系人信息id couponId: useCouponId.value, //优惠卷id note: note.value, cartOrderItemAddRequestList: toRaw(postCartArr.value) } }) if (!dealResult(res)) { hideLoading() isShow.value = false return } wxPay(res.data.data) } //根据商品id数组获取商品信息 const getProduct = async ()=> { const res = await uni.request({ url: baseUrl + '/cartExperience/submit/list', method: 'POST', header: { cookie: wx.getStorageSync('cookie') }, data: { idList: totalInfo.value } }) console.log('展示订单页面的商品信息-->',res.data); if( res.data.code === 1 ) { dealRes(res) } } const dealRes =(res)=> { //处理来自后端的数据 productArr.value = res.data.data console.log('productArr--->',productArr.value); productArr.value.forEach((item)=>{ sumprice.value += item.cartExperienceGoodVO.price * item.quantity //计算总金额 }) sfAmount.value = sumprice.value } //减少当前商品数量 const shortNum = (index)=>{ if(productArr.value[index].quantity > 1) { productArr.value[index].quantity -= 1 //计算商品价格 sumprice.value = math.round(sumprice.value - productArr.value[index].cartExperienceGoodVO.price) } sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' fd() } //增加当前商品数量 const addNum = (index)=>{ if( productArr.value[index].quantity < productArr.value[index].restNumber ) { //数量肯定不能大于库存 productArr.value[index].quantity += 1 sumprice.value = math.round(sumprice.value + productArr.value[index].cartExperienceGoodVO.price) //计算商品价格 sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' fd() } } const formatArr = () =>{ //格式化 postCartArr.value.splice(0,postCartArr.value.length) productArr.value.forEach((item,index)=>{ postCartArr.value.push({ cartExperienceId: totalInfo.value[index], quantity: item.quantity }) }) } const wxPay = async( oid )=> { //传入订单id console.log('oid--->',oid); try { const res = await uni.request({ url: baseUrl + '/wechat/payment/create', method: 'POST', header: { 'cookie': wx.getStorageSync("cookie") }, data: { id: oid } }) const paymentData = res.data.data wx.requestPayment({ appid: paymentData.appId, nonceStr: paymentData.nonceStr, package: paymentData.packageVal, paySign: paymentData.paySign, timeStamp: paymentData.timeStamp, signType: paymentData.signType, success(res) { uni.showModal({ title: '提示', content: '支付成功', showCancel: false }) }, fail(e) { }, complete () { uni.redirectTo({ url: '/pages/subPack/my-order/myServiceOrderDetail/myServiceOrderDetail?id=' + oid }) } }) }catch(error) { uni.showModal({ title: '提示', content: '支付失败,请刷新后重试', showCancel: false }) } } //防抖相关变量 let debounceTimer = null; let wxPayTimer = null; let loading = false; let isLoading = ref(false) let isShow = ref(false) const fd = () => { //防抖 clearTimeout(debounceTimer) showLoading() debounceTimer = setTimeout(async () => { await getMyCouponList() hideLoading() }, 1000) } const wxPayFd = () => { //微信支付按钮防抖 if (contactRealInfo.value.phone === null || contactRealInfo.value.phone === '' || contactRealInfo.value.phone === undefined) { uni.showToast({ title: '请选择联系人', icon: 'error' }) return ; } showLoading() isShow.value = true createOrder() } function showLoading() { //加载弹窗 if (!loading) { wx.showLoading({ title: '加载中...', }); loading = true; isLoading.value = true } } function hideLoading() { //关闭弹窗 if (loading) { wx.hideLoading(); loading = false; isLoading.value = false } } const openCoupon = () => { emitter.emit('getTotalPrice', sumprice.value) coupon.value.open('bottom') } const getMyCouponList = async () => { //获取优惠卷列表 const res = await uni.request({ url: baseUrl + '/coupon/list/use', method: 'POST', header: { cookie }, data: { currentAmount: sumprice.value, isAvailable: true } }) myCouponList.value = res.data.data templateString.value = myCouponList.value.length + '张优惠券可用' console.log('============================>', myCouponList.value) } function getWeekday(dateStr) { const date = new Date(dateStr); const weekdays = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]; return weekdays[date.getDay()]; } </script> <style lang="scss" scoped> .overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.4); /* 半透明黑色背景 */ z-index: 999; } .popup-content { height: 300px; align-items: center; justify-content: center; // background-color: #fff; border-radius: 20rpx 20rpx 0 0; } .coupon-popup { height: 1200rpx; justify-content: center; background-color: #fff; border-radius: 20rpx 20rpx 0 0; } .my-coupon { padding: 25rpx 3.75rpx 25rpx 22.97rpx; } .mt-13 { margin-top: 24.38rpx; } .mt-9 { margin-top: 16.88rpx; } .mt-15 { margin-top: 28.13rpx; } .ml-7 { margin-left: 13.13rpx; } .ml-3 { margin-left: 5.63rpx; } .mt-11 { margin-top: 20.63rpx; } .page { padding-top: 24.38rpx; background-color: #fff; background-size: 100% 100%; background-repeat: no-repeat; width: 100%; overflow-y: auto; overflow-x: hidden; height: 100vh; } .section_2 { margin-left: 24.38rpx; margin-right: 22.5rpx; padding: 20.63rpx 23.08rpx 24.98rpx 27.54rpx; background-color: #ffffff; border-radius: 18.75rpx; } .image { width: 50.63rpx; height: 50.5rpx; } .text { color: #818181; font-size: 37.5rpx; font-family: FangZhengFonts; line-height: 32.38rpx; } .group { width: 167.03rpx; display: flex; justify-content: space-around; } .image_2 { width: 25.5rpx; height: 25.5rpx; } .font { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.54rpx; color: #323232; } .text_2 { color: #ffaaa5; } .section_3 { margin: 31.27rpx 15rpx 0 16.88rpx; padding: 20.63rpx 18.75rpx 24.38rpx; background-color: #ffffff; border-radius: 18.75rpx; } .list-item:first-child { margin-top: 0; } .image_3 { border-radius: 9.38rpx; width: 142.5rpx; height: 166.88rpx; } .group_5 { margin-left: 30.04rpx; margin-top: 4.2rpx; } .group_3 { padding: 0 3.83rpx; } .text_3 { line-height: 25.01rpx; } .font_2 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.54rpx; color: #818181; } .text_7 { margin-left: 8.01rpx; line-height: 24.62rpx; } .font_3 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #818181; } .text_8 { margin-left: 9.21rpx; } .image_6 { width: 35.63rpx; height: 30rpx; } .font_5 { font-size: 33.75rpx; font-family: FangZhengFonts; line-height: 22.54rpx; color: #323232; } .font_6 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #323232; } .image_4 { border-radius: 9.38rpx 0rpx 0rpx 9.38rpx; width: 45rpx; height: 45rpx; } .group_4 { margin-left: 3.75rpx; margin-right: 5.63rpx; } .text-wrapper { padding: 11.31rpx 0 11.46rpx; background-color: #ffaaa5; width: 58.13rpx; height: 45rpx; } .font_4 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.53rpx; color: #ffffff; } .text_6 { line-height: 26.25rpx; } .image_5 { border-radius: 0rpx 9.38rpx 9.38rpx 0rpx; width: 45rpx; height: 45rpx; } .group_9 { padding: 0 138.81rpx; } .group_10 { line-height: 21.71rpx; height: 21.71rpx; } .font_7 { font-size: 22.5rpx; font-family: FangZhengFonts; line-height: 22.54rpx; color: #818181; } .text_11 { line-height: 21.71rpx; } .text_12 { color: #ed4845; line-height: 21rpx; } .image_7 { width: 26.25rpx; height: 26.25rpx; } .section_4 { margin: 30rpx 16.88rpx 0 16.88rpx; padding: 20rpx 19.22rpx 20.63rpx; background-color: #ffffff; border-radius: 18.75rpx; } .font_8 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 29.18rpx; color: #323232; } .text_13 { line-height: 28.13rpx; } .font_9 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 29.18rpx; color: #818181; } .group_11 { margin-right: 9.38rpx; } .image_8 { width: 33.75rpx; height: 33.75rpx; } .font_10 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 20.04rpx; color: #323232; } .group_12 { margin-right: 5.16rpx; } .image_9 { width: 30rpx; height: 30rpx; } .text_14 { line-height: 27.77rpx; } .group_13 { margin-right: 13.37rpx; } .section_5 { margin: 28.13rpx 15rpx 110rpx 18.75rpx; padding: 17.81rpx 24.13rpx 22.5rpx; background-color: #ffffff; border-radius: 18.75rpx; } .text_15 { color: #323232; line-height: 29.53rpx; } .text-wrapper_2 { height: 200rpx; width: 650rpx; padding: 22.35rpx; box-sizing: border-box; background-color: #ffefef; border-radius: 9.38rpx; margin: 20rpx auto 0; } .text_16 { margin-left: 21.15rpx; line-height: 21.81rpx; } .section_6 { position: fixed; left: 0; right: 0; bottom: 0; // margin-top: 333.75rpx; padding: 16.88rpx 25.31rpx 15rpx; background-color: #ffffff; } .image_10 { margin-left: 85.31rpx; } .text_17 { // margin-left: -119.06rpx; color: #323232; font-size: 30rpx; font-family: FangZhengFonts; line-height: 26.49rpx; } .text_18 { // margin-left: 28.5rpx; color: #ffaaa5; font-size: 37.5rpx; font-family: FangZhengFonts; font-weight: 700; line-height: 27.62rpx; } .text_20 { color: #ffaaa5; font-size: 30rpx; font-family: FangZhengFonts; font-weight: 700; line-height: 22.05rpx; } .text-wrapper_3 { padding: 20.51rpx 0 22.97rpx; background-color: #ffaaa5; border-radius: 75rpx; width: 204.38rpx; height: 71.25rpx; } .text_19 { color: #ffffff; line-height: 27.77rpx; } .popup-content { height: 800rpx; } @import url(../../../common/css/global.css); </style>