Files
wdsxh/pagesPoints/goods/order.vue
2026-04-29 15:33:58 +08:00

421 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- +----------------------------------------------------------------------
| 麦沃德科技赋能开发者助力商协会发展
+----------------------------------------------------------------------
| Copyright (c) 20172024 www.wdsxh.cn All rights reserved.
+----------------------------------------------------------------------
| 沃德商协会系统并不是自由软件不加密并不代表开源未经许可不可自由转售和商用
+----------------------------------------------------------------------
| Author: MY WORLD Team <bd@maiwd.cn> www.maiwd.cn
+----------------------------------------------------------------------
| 订单确认 开发者: 麦沃德科技-半夏
+---------------------------------------------------------------------- -->
<template>
<page-meta :page-style="'overflow:' + (pageShow ? 'hidden' : 'visible')"></page-meta>
<view class="container" :style="{ '--theme-color': themeColor }">
<!-- 标题栏 -->
<title-bar :showBack="true" title="订单确认"></title-bar>
<!-- 内容区 -->
<view class="container-main" v-if="loadEnd">
<!-- 地址选择 -->
<view class="main-address" @click="chooseAddress()">
<view class="address-box flex align-items-center">
<view class="box-text flex-item">{{addressData.address || "请选择收货地址"}}</view>
<view class="box-icon" :style="{'background-image': 'url('+ iconMore +')'}" v-if="iconMore"></view>
</view>
<view class="address-info flex flex-wrap" v-if="addressData.name && addressData.tel">
<text>{{addressData.name || ""}}</text>
<text>{{addressData.tel || ""}}</text>
</view>
</view>
<!-- 商品信息 -->
<view class="main-goods flex align-items-center">
<image class="goods-image" :src="goodsData.image" mode="aspectFill"></image>
<view class="goods-info flex-item">
<view class="info-top text-ellipsis-more">{{goodsData.name}}</view>
<view class="info-bottom">
<view class="bottom-points">{{goodsData.points}}积分</view>
<view class="bottom-select">
<view class="select-btn" :class="{disabled: parseInt(goodsData.number) <= 1}" @click="changeNumber(1)">
<image class="icon" src="/static/mall/subtraction.png" mode="aspectFit"></image>
</view>
<view class="select-text text-ellipsis" @click="changeNumber(3)">{{goodsData.number}}</view>
<view class="select-btn" @click="changeNumber(2)">
<image class="icon" src="/static/mall/addition.png" mode="aspectFit"></image>
</view>
</view>
</view>
</view>
</view>
<!-- 积分消耗 -->
<view class="main-points flex align-items-center">
<view class="points-title">积分消耗</view>
<view class="points-value flex-item">-{{totalPoints}}积分</view>
</view>
<!-- 底部按钮 -->
<view class="main-footer">
<view class="footer-btn" @click="handleSettlement()" v-if="userMobile">结算</view>
<button class="footer-btn clear" open-type="getPhoneNumber" @getphonenumber="bindPhoneNumber" v-else>结算</button>
<view class="safe-padding"></view>
</view>
</view>
<!-- 选择地址弹窗 -->
<address-modal ref="addressModal" @confirm="changeAddress" @onChange="pageChange"></address-modal>
<!-- 选择数量弹窗 -->
<quantity-modal ref="quantityModal" @confirm="changeQuantity" @onChange="pageChange"></quantity-modal>
</view>
</template>
<script>
import { mapState } from "vuex"
import svgData from "@/common/svg.js"
import addressModal from "@/pagesPoints/component/modal/address.vue"
import quantityModal from "@/pagesPoints/component/modal/quantity.vue"
export default {
components: {
addressModal,
quantityModal,
},
data() {
return {
// 页面是否阻止滚动
pageShow: false,
// 是否加载完成
loadEnd: false,
// 商品数据
goodsData: {},
// 已选地址
addressData: {},
};
},
computed: {
...mapState({
themeColor: state => state.app.themeColor,
iconMore: state => {
return svgData.svgToUrl("more", state.app.themeColor)
},
userMobile: state => state.user.mobile,
}),
totalPoints() {
var result = parseFloat(parseFloat(this.goodsData.points) * parseInt(this.goodsData.number)).toFixed(2)
return Number(result);
},
},
onLoad() {
uni.showLoading({
title: "加载中"
})
this.getGoodsDetails(() => {
uni.hideLoading()
this.loadEnd = true
})
},
methods: {
// 改变页面滚动状态
pageChange(state) {
this.pageShow = state
},
// 获取商品详情
getGoodsDetails(fn) {
if (this.$store.state.app?.pointsOrder) {
this.goodsData = this.$store.state.app.pointsOrder
this.getAddress(fn)
} else {
uni.hideLoading()
uni.showModal({
title: "提示",
content: "请选择商品后下单",
showCancel: false,
confirmText: "返回",
confirmColor: this.themeColor,
complete: () => {
uni.navigateBack()
}
})
}
},
// 获取默认地址
getAddress(fn) {
this.$util.request("mall.address.list", {
is_default: 1
}).then(res => {
if (res.code == 1) {
if (res.data[0]) this.addressData = res.data[0]
if (fn) fn()
} else {
if (fn) fn()
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
if (fn) fn()
console.error('获取默认地址', error)
})
},
// 绑定手机号
bindPhoneNumber(e) {
if (e.detail.errMsg == "getPhoneNumber:ok") {
uni.showLoading({
mask: true,
title: "加载中",
})
uni.login({
provider: 'weixin',
success: loginRes => {
let data = e.detail
data.code = loginRes.code
this.$util.request("login.bindMobile", data).then(res => {
uni.hideLoading()
if (res.code == 1) {
this.$store.commit('user/updateMobile', res.data.phoneNumber)
this.handleSettlement()
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
uni.hideLoading()
console.error('获取用户手机号码 ', error)
})
},
fail: () => {
uni.hideLoading()
uni.showToast({
icon: "none",
title: "授权手机号失败,请重试"
})
}
});
} else {
uni.showToast({
title: '获取手机号失败,请重新获取',
icon: 'none'
})
}
},
// 选择地址
chooseAddress() {
this.$refs.addressModal.open(this.addressData.id)
},
// 改变选择的地址
changeAddress(item) {
this.addressData = item
},
// 改变商品数量
changeNumber(type) {
if (type == 1) {
if (parseInt(this.goodsData.number) > 1) {
const goodsNumber = parseInt(this.goodsData.number) - 1
this.changeQuantity(goodsNumber)
}
} else if (type == 2) {
const goodsNumber = parseInt(this.goodsData.number) + 1
this.changeQuantity(goodsNumber)
} else if (type == 3) {
this.$refs.quantityModal.open(this.goodsData.number)
}
},
// 选择商品数量
changeQuantity(number) {
this.$set(this.goodsData, "number", parseInt(number))
},
// 提交订单
handleSettlement() {
if (!this.addressData || !this.addressData.id) {
uni.showToast({
title: "请选择收货地址",
icon: "none"
})
return;
}
uni.showLoading({
title: "加载中",
mask: true
})
this.$util.request("points.createOrder", {
goods_id: this.goodsData.id,
number: this.goodsData.number,
address_id: this.addressData.id,
}).then(res => {
uni.hideLoading()
if (res.code == 1) {
uni.redirectTo({
url: "/pagesPoints/goods/success?id=" + res.data.order_id
})
} else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(error => {
console.error('兑换商品', error)
})
},
}
}
</script>
<style lang="scss">
.container {
.container-main {
padding: 32rpx 32rpx 144rpx;
.main-address {
border-radius: 20rpx;
padding: 32rpx;
background: #FFF;
.address-box {
.box-text {
color: #5A5B6E;
font-size: 32rpx;
line-height: 44rpx;
margin-right: 64rpx;
}
.box-icon {
width: 32rpx;
height: 32rpx;
background-size: 32rpx;
}
}
.address-info {
margin-top: 24rpx;
color: #979797;
font-size: 28rpx;
line-height: 40rpx;
gap: 16rpx;
}
}
.main-goods {
margin-top: 32rpx;
border-radius: 20rpx;
background: #FFF;
padding: 32rpx;
.goods-image {
width: 160rpx;
min-width: 160rpx;
height: 160rpx;
border-radius: 20rpx;
}
.goods-info {
flex: 1;
height: 160rpx;
margin-left: 32rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: hidden;
.info-top {
color: #5A5B6E;
font-size: 28rpx;
line-height: 40rpx;
}
.info-bottom {
display: flex;
align-items: center;
.bottom-points {
color: var(--theme-color);
font-size: 36rpx;
font-weight: 600;
line-height: 40rpx;
text {
font-size: 24rpx;
}
}
.bottom-select {
flex: 1;
margin-left: 16rpx;
display: flex;
justify-content: flex-end;
align-items: center;
overflow: hidden;
.select-btn {
width: 32rpx;
min-width: 32rpx;
height: 32rpx;
border-radius: 50%;
background: var(--theme-color);
&.disabled {
opacity: .5;
}
.icon {
width: 100%;
height: 100%;
}
}
.select-text {
color: #000;
font-size: 28rpx;
line-height: 32rpx;
height: 32rpx;
margin: 0 16rpx;
text-align: center;
}
}
}
}
}
.main-points {
margin-top: 32rpx;
padding: 32rpx;
border-radius: 16rpx;
background: #FFF;
.points-title {
color: #979797;
font-size: 28rpx;
line-height: 40rpx;
}
.points-value {
margin-left: 32rpx;
text-align: right;
color: var(--theme-color);
font-size: 28rpx;
line-height: 40rpx;
}
}
.main-footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 96;
background: #FFF;
border-top: 1rpx solid #F6F7FB;
padding: 16rpx 24rpx;
.footer-btn {
color: #FFF;
text-align: center;
font-size: 32rpx;
line-height: 44rpx;
padding: 22rpx 32rpx;
border-radius: 16rpx;
background: var(--theme-color);
}
}
}
}
</style>