<!-- 单个商品购买页面 --> <template> <view class="flex-col justify-start relative page"> <view class="flex-col group_1"> <!-- 地址信息 --> <view class="flex-col section_2" @click="loadPop" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"> <view class="flex-row justify-between"> <view class="flex-col"> <text class="self-center font text">{{ addressRealInfo.region }}</text> <view class="flex-row items-center self-stretch"> <image class="shrink-0 image" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FXZHjzkRH-dingwei.png" /> <text class="font_2 text_2 ml-8">{{ addressRealInfo.detailAddress }}</text> </view> </view> <view class="flex-row self-start group"> <text class="font_3 text_3">更换地址</text> <image class="shrink-0 image_2" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FfhDZdkOK-rightpink.png" /> </view> </view> <view class="flex-row items-center group_2 mt-4"> <text class="font_2 text_4">{{ addressRealInfo.name }}</text> <text class="font_2 text_5">手机:{{ addressRealInfo.phone }}</text> </view> </view> <!-- 商品信息 --> <view class="flex-col section_3"> <view class="flex-col self-stretch"> <view class="flex-row items-end group_18"> <view class="flex-row items-end flex-1 group_19"> <image class="shrink-0 image_3 image_4" :src="productObject.goodImg.split(';')[0]" /> <view class="flex-col flex-1 ml-17"> <view class="flex-row"> <text class="font">{{ productObject.name }}</text> <text class="font text_1">【{{ productObject.type }}】</text> </view> <view class="flex-row items-center mt-52"> <image class="image_7" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FjIVFaWXA-rmb.png" /> <text class="font_4 ml-2">{{ productObject.price.toFixed(2) }}</text> <!-- <text class="font_6 text_27 ml-2">00</text> --> </view> </view> </view> <view class="flex-row shrink-0 ml-21"> <image class="image_5" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FJYaNIhRB-short.png" @click="shortNum" /> <view class="flex-col justify-start items-center text-wrapper ml-2"><text class="font_5">{{ quantity }}</text></view> <image class="image_6 ml-2" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FXbkFIxCw-add.png" @click="addNum" /> </view> </view> </view> <view class="flex-row items-center self-center mt-48" style="margin-top: 56rpx;"> <view class="group_9"> <text class="font_2 text_12">注:购买商品均视为同意</text> <text class="font_2 text_13">用户须知</text> </view> <image class="shrink-0 image_8 ml-2" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FXjPffNQe-question.png" /> </view> </view> <view class="flex-col section_5"> <view class="flex-row justify-between items-center group_14"> <view class="flex-row"> <text class="font_7 text_14">商品总价</text> <text class="font_8 ml-7">共{{ quantity }}件商品</text> </view> <view class="flex-row items-center"> <image class="shrink-0 image_9" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FjIVFaWXA-rmb.png" /> <text class="font_9">{{ sumprice.toFixed(2) }}</text> </view> </view> <view class="flex-col mt-25"> <view class="flex-row justify-between group_10" @click="openCoupon" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"> <text class="font_7">优惠券</text> <view class="flex-row"> <text class="font_8" :style="{color: textColor}">{{ templateString }}</text> <image class="shrink-0 image_7 ml-3" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FTrywtERT-right.png" /> </view> </view> <view class="flex-col mt-9"> <!-- <view class="flex-row justify-between items-center group_11" v-if="couponIsShow"> <text class="font_7 text_15">{{ couponVO.name }}优惠</text> <view class="flex-row items-center"> <image class="shrink-0 image_9 image_10" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FJmxvlQvD-rmbpink.png" /> <text class="font_3 text_16">减</text> <text class="font_9 text_17">0.00</text> </view> </view> --> <view class="flex-row justify-between items-center group_12"> <text class="font_7 text_18">合计</text> <view class="flex-row items-center"> <image class="shrink-0 image_9" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FjIVFaWXA-rmb.png" /> <text class="font_9">{{ sfAmount.toFixed(2) }}</text> </view> </view> </view> </view> </view> <view class="flex-col section_6"> <text class="self-start font_7 text_19">订单备注</text> <view class="flex-col justify-start items-start self-stretch text-wrapper_2 mt-11"> <!-- <text class="font_2 text_20">备注建议提前协商(250字以内)</text> --> <textarea @input="textAssign" auto-height style="width: 360px;"></textarea> </view> </view> </view> <view class="flex-row justify-between items-center section_7 pos_8"> <view class="flex-row items-center"> <image class="shrink-0 image_9 image_11" src="https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FJmxvlQvD-rmbpink.png" /> <text class="text_21">应付:</text> <text class="text_22">{{ sfAmount.toFixed(2) }}</text> <!-- <text class="text_24">00</text> --> </view> <view class="flex-col justify-start items-center text-wrapper_3" @click="wxPayFd" :style="{ pointerEvents: isLoading ? 'none' : 'auto' }"> <text class="font_7 text_23">微信支付</text></view> </view> </view> <uni-popup ref="popup" background-color="#fff"> <view class="popup-content"> <addressComponentVue></addressComponentVue> </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 lang="ts"> import {nextTick, onMounted, ref, toRaw} from 'vue' import emitter from '../../../utils/emitter' import { onLoad , onShow } from "@dcloudio/uni-app"; import { baseUrl } from '../../../api/request'; import addressComponentVue from '../component/addressComponent.vue';//导入组件 import couponPopupVue from '../../coupon/component/couponPopup.vue'; import { stateMap } from '../../../common/global'; import * as math from 'mathjs' //一些暂时变量 const sumprice = ref(0) //总价格 //11.4开发 不应该删掉的 const popup = ref(null) //弹窗对象 const addressRealInfo = ref({ detailAddress: '请选择/添加地址' }) //地址页 选择地址传过来的值 进入页面首先是默认地址,若无默认地址,则为空 const productObject = ref({}) //商品对象 const labelList = ref([]) //老套路,商品标签 const userInfo = wx.getStorageSync('userInfo') //用户信息 const orderItemList = ref({}) const totalInfo = ref([]) //购物车传过来的批量商品 const note = ref('') const postCartArr = ref([]) const quantity = ref(1) //商品数量 const couponIsShow = ref(false) 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('') onMounted(() => { getFonts() // 将关闭弹窗方法传入弹窗页面,绑定弹窗按钮可关闭弹窗 emitter.on('closeAddress', () => { nextTick(() => { if (popup.value) { popup.value.close() } }) }) emitter.on('closeCoupon', () => { nextTick(() => { if (coupon.value) { coupon.value.close() } }) }) emitter.on('cancelCoupon', () => { templateString.value = myCouponList.value.length + '张优惠券可用' sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' }) emitter.on('getCouponObj', (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) }) console.log('===============start===============') }) onLoad( async (options)=>{ totalInfo.value = JSON.parse(options.cartInfo) await getProduct() await getMyCouponList() }) onShow(()=>{ userInfo.value = wx.getStorageSync('userInfo') //从微信缓存中获取用户信息 getDefaultAddress() }) 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) } 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 = () => { clearTimeout(wxPayTimer) showLoading() isShow.value = true wxPayTimer = setTimeout(async () => { await createOrder() }, 1000) } function showLoading() { if (!loading) { wx.showLoading({ title: '加载中...', }); loading = true; isLoading.value = true } } function hideLoading() { if (loading) { wx.hideLoading(); loading = false; isLoading.value = false } } //减少当前商品数量 const shortNum = ()=>{ if(quantity.value > 1) { quantity.value -= 1 //计算商品价格 sumprice.value = math.round(sumprice.value-productObject.value.price,2) sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' fd() } } //增加当前商品数量 const addNum = ()=>{ if( quantity.value < productObject.value.inventory ) { //数量肯定不能大于库存 quantity.value += 1 sumprice.value = math.round(sumprice.value+productObject.value.price,2) //解决js计算精度问题 sfAmount.value = sumprice.value useCouponId.value = null textColor.value = '#818181' fd() } } //加载弹窗。默认从底部弹出 const loadPop =() =>{ popup.value.open('bottom') } //获取用户默认地址 const getDefaultAddress = async () =>{ const res = await uni.request({ url: baseUrl + '/address/list', method: 'POST', header: { cookie: wx.getStorageSync('cookie') } }) //根据for循环遍历默认地址 for(let key in res.data.data) { if(res.data.data[key].isDefault === 1) { addressRealInfo.value = res.data.data[key] } } } const createOrder = async () => { //创建单个商品订单的方法 console.log('地址信息-->',addressRealInfo.value); formatArr() console.log('postCartArr--->',postCartArr.value); const resOrder = await uni.request({ //向后端发送生成订单请求 url: baseUrl + '/order/add', method: 'POST', header: { cookie: wx.getStorageSync('cookie') }, data: { orderType: productObject.value.type === '服务类' ? 'service' : 'product', userName: userInfo.userName, addressId: addressRealInfo.value.id, //地址信息id // contactsId: null, //联系人信息id couponId: useCouponId.value, //优惠卷id note: note.value, orderItemMainInfoAddRequestList: toRaw(postCartArr.value) } }) console.log('后台返回订单响应==>',resOrder.data); if(resOrder.data.code === 1) { wxPay(resOrder.data.data) } } //根据商品id获取单个商品信息 const getProduct = async ()=> { const res = await uni.request({ url: baseUrl + '/goods/getById', method: 'POST', header: { cookie: wx.getStorageSync('cookie') }, data: { id: totalInfo.value } }) console.log('展示订单页面的商品信息-->',res.data); if( res.data.code === 1 ) { dealRes(res) } } const dealRes =(res)=> { //处理来自后端的数据 productObject.value = res.data.data sumprice.value = res.data.data.price sfAmount.value = res.data.data.price console.log('productArr--->',productObject.value); } const formatArr = () =>{ //格式化 postCartArr.value.splice(0,postCartArr.value.length) postCartArr.value.push({ goodId: totalInfo.value, quantity: quantity.value }) console.log(postCartArr.value); } const wxPay = async ( oid )=> { //传入订单id 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({ content: '支付成功', showCancel: false }) uni.redirectTo({ url: '/pages/order/product-paysuccess/product-paysuccess?oid=' + JSON.stringify(oid) }) console.log('支付成功res--->',res); }, fail(e) { uni.showModal({ content: '支付失败,原因为:' + e.errMsg, showCancel: false }) uni.redirectTo({ url: '/pages/order/product-paysuccess/product-paysuccess?oid=' + JSON.stringify(oid) }) console.log('e.errMsg--->',e.errMsg); } }) }catch(error) { console.error('支付请求失败',error); uni.showModal({ content: '支付请求失败,请重试。', showCancel: false }) } } //获取字体 const getFonts =()=>{ uni.loadFontFace({ family: 'FangZhengFonts', source: `url("https://carbon2.obs.cn-north-4.myhuaweicloud.com/fonts/FangZhengFonts.TTF")`, success:(res) =>{ console.log('success',res); }, fail:(err) => { console.log('err',err); } }) } const textAssign = (e) => { //文本输入框赋值方法 // console.log(e); note.value = e.detail.value console.log('note--->',note.value); } </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; } .ml-17 { margin-left: 31.88rpx; } .ml-21 { margin-left: 39.38rpx; } .ml-7 { margin-left: 13.13rpx; } .mt-25 { margin-top: 46.88rpx; } .ml-3 { margin-left: 5.63rpx; } .mt-9 { margin-top: 16.88rpx; } .mt-11 { margin-top: 20.63rpx; } .page { background-color: #f8e8c1; background-image: url('https://carbon2.obs.cn-north-4.myhuaweicloud.com:443/feiyi%2Ftest%2F0%2FQfLHXSAU-feiyigongfangbeijin.png'); background-size: 100% 100%; background-repeat: no-repeat; width: 100%; overflow-y: auto; overflow-x: hidden; height: 100vh; } .group_1 { padding: 18.75rpx 15rpx 247.5rpx 16.88rpx; } .section_2 { padding: 21.07rpx 18.75rpx 18.51rpx 20.63rpx; background-color: #ffffff; border-radius: 18.75rpx; } .font { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.54rpx; color: #323232; } .text { margin-left: 54rpx; line-height: 25.74rpx; } .image { width: 43.13rpx; height: 43.13rpx; } .font_2 { font-size: 22.5rpx; font-family: FangZhengFonts; line-height: 22.54rpx; color: #818181; } .text_2 { line-height: 22.07rpx; } .group { margin-top: 36.54rpx; } .font_3 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 25.54rpx; color: #ffaaa5; } .text_3 { line-height: 24.41rpx; } .image_2 { width: 24.38rpx; height: 24.38rpx; } .group_2 { padding: 0 59.23rpx; } .text_4 { color: #5a5a5a; line-height: 19.42rpx; } .text_5 { margin-left: 24rpx; line-height: 15.04rpx; } .section_3 { margin-top: 16.88rpx; padding: 22.5rpx 0 35.63rpx; background-color: #ffffff; border-radius: 18.75rpx; } .group_18 { padding-left: 26.27rpx; padding-right: 24.36rpx; margin-bottom: 20rpx; } .group_19 { margin-bottom: 3.75rpx; } .image_3 { border-radius: 9.38rpx; width: 146.25rpx; height: 165rpx; } .image_4 { margin-bottom: 9.38rpx; } .text_1 { line-height: 25.01rpx; } .image_7 { width: 30rpx; height: 30rpx; } .font_4 { 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.23rpx; color: #323232; } .text_27 { line-height: 17.53rpx; } .image_5 { border-radius: 9.38rpx 0rpx 0rpx 9.38rpx; width: 45rpx; height: 45rpx; } .text-wrapper { padding: 16.31rpx 0 16.46rpx; background-color: #ffaaa5; width: 58.13rpx; height: 45rpx; } .font_5 { font-size: 26.25rpx; font-family: FangZhengFonts; line-height: 17.23rpx; color: #ffffff; } .image_6 { border-radius: 0rpx 9.38rpx 9.38rpx 0rpx; width: 45rpx; height: 45rpx; } .group_9 { line-height: 21.71rpx; height: 21.71rpx; } .text_12 { line-height: 21.71rpx; } .text_13 { color: #ed4845; line-height: 21rpx; } .image_8 { width: 26.25rpx; height: 26.25rpx; } .section_5 { margin-top: 16.88rpx; padding: 31.88rpx 13.13rpx 5.63rpx; background-color: #ffffff; border-radius: 18.75rpx; } .group_14 { padding: 0 24.02rpx; } .font_7 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 29.18rpx; color: #323232; } .text_14 { line-height: 28.13rpx; } .font_8 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 29.18rpx; color: #818181; } .image_9 { width: 33.75rpx; height: 33.75rpx; } .font_9 { font-size: 30rpx; font-family: FangZhengFonts; line-height: 20.04rpx; color: #323232; } .group_10 { padding: 25rpx 3.75rpx 25rpx 22.97rpx; } .group_11 { padding: 26.25rpx 10.42rpx 28.13rpx 24.62rpx; border-bottom: solid 1.88rpx #dfdfdf; } .text_15 { line-height: 29.42rpx; } .image_10 { margin-left: 21.6rpx; } .text_16 { margin-left: -55.35rpx; line-height: 25.74rpx; } .text_17 { margin-left: 33.68rpx; color: #ffaaa5; } .group_12 { padding: 26.25rpx 23.94rpx 28.13rpx 23.44rpx; } .text_18 { line-height: 27.77rpx; } .section_6 { margin-top: 16.88rpx; padding: 17.81rpx 24.13rpx 22.5rpx; background-color: #ffffff; border-radius: 18.75rpx; } .text_19 { color: #000000; line-height: 29.53rpx; } .text-wrapper_2 { margin-left: 3.99rpx; margin-right: 3.99rpx; padding: 22.35rpx 20rpx; background-color: #ffefef; border-radius: 9.38rpx; } .text_20 { margin-left: 21.15rpx; line-height: 21.81rpx; } .section_7 { padding: 16.88rpx 25.31rpx 15rpx; background-color: #ffffff; } .pos_8 { position: fixed; left: 0; right: 0; bottom: 0; } .image_11 { margin-left: 85.31rpx; } .text_21 { margin-left: -119.06rpx; color: #000000; font-size: 30rpx; font-family: FangZhengFonts; line-height: 26.49rpx; } .text_22 { margin-left: 28.5rpx; color: #ffaaa5; font-size: 37.5rpx; font-family: Open Sans; font-weight: 700; line-height: 27.62rpx; } .text_24 { color: #ffaaa5; font-size: 30rpx; font-family: Open Sans; 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_23 { color: #ffffff; line-height: 27.77rpx; } @import url(../../../common/css/global.css); </style>