Files
gxtyzx-uniapp/src/package/goods/checkout.vue
T
2024-08-08 01:53:51 +08:00

738 lines
23 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.
<template>
<view class="container">
<uni-card :border="false" :is-shadow="false">
<view class="delivery flex justify-between items-center bg-white m-a p-10">
<uv-button :customStyle="{ borderRadius: '30px', backgroundColor: `${deliveryType === 0 ? '#ff0000' : '#c9c9c9'}`, color: '#ffffff', padding: '0rpx 80rpx' }" :text="'快递配送'" @click="onDeliveryType(0)"></uv-button>
<uv-button :customStyle="{ borderRadius: '30px', backgroundColor: `${deliveryType === 0 ? '#c9c9c9' : '#ff0000'}`, color: '#ffffff', padding: '0rpx 80rpx' }" :text="'上门自提'" @click="onDeliveryType(1)"></uv-button>
</view>
</uni-card>
<uni-card :border="false" :is-shadow="false" v-if="address.name">
<uv-cell
v-if="deliveryType === 0"
:title="`${address.name} &nbsp; ${address.phone}`"
:label="`${address.address}`"
icon="map"
:cellStyle="{ padding: '5px 0' }"
:border="false"
@click="openAddressList"
>
<template v-slot:right-icon>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-cell>
<uv-cell
v-if="deliveryType === 1"
:title="`${cart.shops[0].shopName}`"
:label="`${cart.shops[0].address}`"
icon="map"
:cellStyle="{ padding: '5px 0' }"
:border="false"
>
<template v-slot:right-icon>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-cell>
</uni-card>
<block v-for="(item,index) in cart.shops">
<uni-card :border="false" :padding="10">
<template v-slot:title>
<view class="mt-20 flex items-center">
<uv-avatar :src="item.shopLogo" size="22"></uv-avatar>
<view class="title ml-2">{{ item.shopName }}</view>
</view>
</template>
<!-- <view class="preferential web-text-secondary">满2件总价9折,还差 1 件</view>-->
<uv-cell-group :customStyle="{backgroundColor: '#ffffff', marginBottom: '20px'}" :border="false">
<uv-cell v-for="(cart,index2) in item.carts" :cellStyle="{padding: '12px 0'}" :border="false">
<template v-slot:title>
<view class="goods-title flex items-center w-full">
<uv-image
:src="cart.image"
width="80" height="80" radius="5"/>
<view class="goods-info flex w-full flex-col justify-between">
<view class="goods-name">
<uv-text :lines="1" bold :text="cart.goodsName"></uv-text>
<uv-text class="py-2 text-20" type="info" :text="cart.spec || '无规格'" suffixIcon="arrow-down"
:iconStyle="{marginLeft: '8px', fontSize: '10px'}"></uv-text>
</view>
<view class="goods-price flex justify-between">
<view class="price text-red-500">¥{{ cart.price }}</view>
<view class="tool-btn web-text-secondary">
x {{ cart.cartNum }}
</view>
</view>
</view>
</view>
</template>
</uv-cell>
</uv-cell-group>
</uni-card>
</block>
<uni-card title="选择支付方式" :border="false" :is-shadow="false">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(item, index) in payment" :key="index">
<uv-cell
:title="`${item.name}`"
:icon="`${item.image}`"
:cellStyle="{ padding: '20rpx 10rpx', borderRadius: '8rpx', backgroundColor: item.type === payType ? '#f6fff1' : '' }"
:border="false"
@click="onPayType(item.type)"
>
{{ item.type }}
<template v-slot:right-icon>
<uv-icon name="checkbox-mark" v-if="item.type === payType"></uv-icon>
</template>
</uv-cell>
</block>
</uv-cell-group>
<view slot="actions" class="card-actions">
<view class="card-actions-item" @click="actionsClick('分享')">
<!-- <span class="web-text-danger">已优惠¥0.00</span>-->
<span style="vertical-align:super">¥</span>
<uv-count-to :startVal="0" decimals="2" duration="100" color="#ff0000" bold
prefix="$" :endVal="cart.totalPrice || 0.00"></uv-count-to>
</view>
</view>
</uni-card>
<view class="xieyi web-cell web-text-secondary web-cell-align-top">
<view class="web-cell web-cell-content web-cell-align-top">
<uv-avatar src="https://oss.wsdns.cn/20240723/2f9ae761ebb343fcbcaccd7441c88e20.png" size="20" v-if="!disabled" @click="onDisabled"></uv-avatar>
<uv-avatar src="https://oss.wsdns.cn/20240723/cc887e4a1cd749ebb5a1cfa2484c01f2.png" size="20" v-else @click="onDisabled"></uv-avatar>
<view class="text" @click="onDisabled">
<text>同意以下服务条款</text>
<text class="link" @click.stop="navTo('/package/article/detail?articleId=501')">《牛八哥预定条款》</text>
<text class="link" @click.stop="navTo('/package/article/detail?articleId=502')">《用户服务协议和隐私政策》
</text>
</view>
</view>
</view>
<!-- 支付按钮 -->
<uv-gap height="50"></uv-gap>
<view class="checkout-car">
<view class="car-total">
<text style="color: #ebcf00">合计¥</text>
<uv-count-to :startVal="0" decimals="2" duration="100" color="#ebcf00" bold :endVal="cart.totalPrice"></uv-count-to>
</view>
<uv-button
class="save-btn"
:disabled="!disabled || cart.totalPrice === 0"
:customStyle="{ background: 'linear-gradient(to right, #f5a4a4, #ff0000)', borderRadius: '0 30px 30px 0', color: '#ffffff', border: 'none', padding: '22px 30px' }"
text="提交订单"
@click="save"
></uv-button>
</view>
</view>
<!-- 收货地址选择弹窗 -->
<uni-popup ref="userAddressForm" type="center" border-radius="10px 10px 0 0">
<uni-card title="选择收货地址" :border="false" :is-shadow="false" :padding="0">
<view class="address-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(item, index) in addressList" :key="index">
<uv-cell :cellStyle="{ padding: '10px 0' }" @click="onAddress(item)">
<template v-slot:icon>
<uv-avatar :text="item.type" fontSize="12" size="32" randomBgColor></uv-avatar>
</template>
<template v-slot:title>
<view class="flex flex-col">
<view class="title-bar">
<text class="web-text-heading" style="font-weight: 700">{{ item.name }}</text>
<text class="web-text-secondary">{{ item.phone }}</text>
<uni-tag v-if="item.isDefault" text="默认" size="mini" inverted type="success"></uni-tag>
</view>
<view class="title-bar web-text-secondary">
{{ item.address }}
</view>
</view>
</template>
<template v-slot:right-icon>
<uni-icons type="right" style="color: #999999"></uni-icons>
</template>
</uv-cell>
</block>
<uv-button class="add-address" :customStyle="{ borderRadius: '30px' }" text="收货地址管理"
@click="navTo('/package/user/address')"></uv-button>
</uv-cell-group>
</view>
</view>
</uni-card>
</uni-popup>
<!-- 自提点地址选择弹窗 -->
<uni-popup ref="shopAddressForm" type="center" border-radius="10px 10px 0 0">
<uni-card title="选择自提门店" :border="false" :is-shadow="false" :padding="0">
<view class="address-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff' }" :border="false">
<block v-for="(item, index) in shopList" :key="index">
<uv-cell :cellStyle="{ padding: '10px 0' }" @click="onShopAddress(item)">
<!-- <template v-slot:icon>-->
<!-- <uv-avatar text="门店" fontSize="12" size="32" randomBgColor></uv-avatar>-->
<!-- </template>-->
<template v-slot:title>
<view class="flex flex-col">
<view class="title-bar">
<text class="web-text-heading" style="font-weight: 700">{{ item.merchantName }}</text>
</view>
<view class="title-bar web-text-secondary">
{{ item.address || '良庆镇五象大道401号南宁航洋信和广场1号楼4楼' }}
</view>
</view>
</template>
<template v-slot:right-icon>
<uni-icons type="right" style="color: #999999"></uni-icons>
</template>
</uv-cell>
</block>
</uv-cell-group>
</view>
</view>
</uni-card>
</uni-popup>
<!-- 支付密码弹窗 -->
<uni-popup ref="payPasswordForm" type="center" border-radius="10px 10px 0 0">
<uni-card title="请输入支付密码" :border="false" :is-shadow="false" :padding="0">
<view class="pay-password-card">
<uni-forms ref="form" :label-width="80">
<uni-forms-item label="支付密码" name="payPassword" required>
<uv-code-input mode="box" dot :space="0" :maxlength="6" hairline v-model="payPassword"
@finish="onPayPassword"></uv-code-input>
</uni-forms-item>
<!-- <uv-button
class="to-pay-btn"
:customStyle="{ background: 'linear-gradient(to right, #f5a4a4, #ff0000)', borderRadius: '30px', color: '#ffffff' }"
text="确定支付"
:disabled="disabledPayPayPassword"
@click="onPayPassword"
></uv-button> -->
</uni-forms>
<text @click="navTo(`/package/user/pay-password`)" class="web-text-primary">忘记支付密码?</text>
</view>
</uni-card>
</uni-popup>
<uni-popup ref="popup" style="margin-bottom: 200px;">
<uni-card :title="`规格`" extra="关闭" :border="false" :is-shadow="false" :padding="0" @click="closeCarInfo">
<uv-cell-group :customStyle="{backgroundColor: '#ffffff'}" :border="false">
<block v-for="(item,index) in orderInfo" :key="index">
<uv-cell :title="`${item.fieldName} ¥${item.price}`" :label="`${item.dateTime}`"
:cellStyle="{padding: '10px 5px'}">
<template v-slot:right-icon>
<uni-icons type="trash" size="20" color="#f76b4e" @click="remove(item)"></uni-icons>
<text class="web-text-secondary" style="font-size: 24rpx;" @click="remove(item)">移除</text>
</template>
</uv-cell>
</block>
</uv-cell-group>
</uni-card>
<uv-gap height="70"></uv-gap>
</uni-popup>
<!-- 登录组件 -->
<ws-login ref="login" @done="reload"/>
</template>
<script>
import * as Api from '@/api/shop/order';
import * as CartApi from '@/api/shop/cart';
import * as UserAddressApi from '@/api/shop/userAddress';
import * as PaymentApi from '@/api/system/payment';
import * as MerchantApi from '@/api/shop/merchant';
import {checkPayPassword} from '@/api/passport/login';
import {storeToRefs} from 'pinia';
import {getWeek, getKey} from '@/utils/common';
import {useCartStore} from '@/store/modules/cart';
import {useUserStore} from '@/store/modules/user';
import {useMpStore} from "@/store/modules/mp";
import UvAvatar from "@/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue";
import UvCell from "@/uni_modules/uv-cell/components/uv-cell/uv-cell.vue";
import UvImage from "@/uni_modules/uv-image/components/uv-image/uv-image.vue";
import UniCard from "@/uni_modules/uni-card/components/uni-card/uni-card.vue";
import UvGap from "@/uni_modules/uv-gap/components/uv-gap/uv-gap.vue";
const mpStore = useMpStore();
const userStore = useUserStore();
const cartStore = useCartStore();
const {goodsList, totalPrice, carNum, merchantId, merchantName, merchantCode, type, dateTime} = storeToRefs(cartStore);
export default {
components: {UvGap, UniCard, UvImage, UvCell, UvAvatar},
data() {
return {
goodsId: 0,
userInfo: {},
list: [],
config: {},
address: {},
addressList: [],
shopList: [],
shopAddress: {},
deliveryType: 0,
merchant: {},
where: {
id: undefined,
type: 0,
isNew: undefined,
selected: undefined,
},
cart: {},
week: 0,
goodsList,
// 订单总金额
totalPrice,
reducePrice: 0,
merchantId,
merchantName,
merchantCode,
getWeek,
payType: 1,
payment: [],
isLogin: false,
disabled: true,
// 支付密码是否正确
isPayPasswordCorrect: false,
disabledPayPayPassword: false,
payPassword: ''
};
},
onLoad(where) {
this.where = where;
this.reload();
},
onShow() {
// 登录状态
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
this.isLogin = true;
}
this.openLogin();
},
methods: {
async reload() {
const app = this;
const {where} = this;
// 当前小程序信息
const info = await mpStore.fetchMpInfo();
// 配置信息
app.config = info.config
// 当前登录用户信息
const userInfo = await userStore.fetchUserInfo();
app.userInfo = userInfo;
// 加载购物车数据
CartApi.listCart(where).then(data => {
if(data){
app.cart = data
console.log(app.cart.shops);
}
})
UserAddressApi.pageUserAddress({
userId: uni.getStorageSync('user_id')
}).then((res) => {
app.addressList = res.list;
const arr = res.list.filter((d) => d.isDefault === true);
app.address = arr[0];
});
MerchantApi.pageMerchant({type: 0}).then(res => {
app.shopList = res.list;
app.shopAddress = res.list[0];
})
// 读取支付方式列表
PaymentApi.select({status: true}).then((list) => {
app.payment = list
.filter((d) => d.type < 2)
.map((d) => {
if (d.code === 'balancePay') {
d.name = `${d.name} (¥${userInfo.balance})`;
}
return d;
});
});
},
onDisabled() {
this.disabled = !this.disabled;
},
navTo(url) {
uni.navigateTo({
url
});
},
openUrl(url) {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
} else {
uni.navigateTo({
url
});
}
},
onAddress(item) {
this.address = item;
this.$refs.userAddressForm.close();
},
onShopAddress(item){
this.shopAddress = item;
this.$refs.shopAddressForm.close();
},
// 切换支付方式
onPayType(index) {
this.payType = index;
},
openAddressList() {
if(this.deliveryType === 0){
this.$refs.userAddressForm.open('center');
}
if(this.deliveryType === 1){
this.$refs.shopAddressForm.open('center');
}
},
// 弹出登录提示框
openLogin() {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
}
},
onDeliveryType(index){
this.deliveryType = index
},
// 验证支付密码
onPayPassword() {
if (this.payPassword == '' || !this.payPassword) {
uni.showToast({
title: '请输入支付密码',
icon: 'none'
});
return false;
}
this.disabledPayPayPassword = true;
const {payPassword} = this;
checkPayPassword({payPassword})
.then((res) => {
this.disabledPayPayPassword = false;
this.isPayPasswordCorrect = true;
this.save();
})
.catch((err) => {
uni.showToast({
title: err.message,
icon: 'none'
});
this.disabledPayPayPassword = false;
});
},
openCarInfo(cart) {
if (cart.spec) {
this.$refs.popup.open('bottom')
}
},
save() {
const app = this;
const {totalPrice,shops} = this.cart;
console.log(totalPrice)
if (!this.disabled) {
uni.showToast({
title: '请先阅读并同意服务协议',
icon: 'none'
});
return false;
}
if (totalPrice === 0) {
uni.showToast({
title: '订单信息不存在',
icon: 'none'
});
return false;
}
if (app.payType === 0 && !this.isPayPasswordCorrect) {
this.$refs.payPasswordForm.open('center');
return false;
}
uni.showLoading({
title: '订单提交中.'
});
console.log({
type: 0, // 0商城订单
merchantId: shops[0]?.shopId,
merchantName: shops[0]?.shopName,
totalPrice: totalPrice,
payPrice: totalPrice,
goodsList: shops[0].carts,
comments: shops[0]?.shopName,
// 微信支付
payType: app.payType,
// 下单日期
dateTime: app.dateTime
})
Api.addOrder({
type: 0, // 0商城订单
merchantId: shops[0]?.shopId,
merchantName: shops[0]?.shopName,
totalPrice: totalPrice,
payPrice: totalPrice,
goodsList: shops[0].carts,
comments: shops[0]?.shopName,
// 微信支付
payType: app.payType,
// 下单日期
dateTime: app.dateTime
})
.then((data) => {
const orderInfo = data;
// 调起微信支付
if (app.payType == 1) {
// #ifdef MP-WEIXIN
uni.requestPayment({
provider: orderInfo.provider, // 服务提供商
timeStamp: orderInfo.timeStamp, // 时间戳
nonceStr: orderInfo.nonceStr, // 随机字符串
package: orderInfo.package,
signType: orderInfo.signType, // 签名算法
paySign: orderInfo.paySign, // 签名
success: function (res) {
// 业务逻辑。。。
uni.showToast({
title: '支付成功',
icon: 'success'
});
setTimeout(function () {
app.disabled = false;
uni.navigateTo({
url: '/package/goods/order'
});
}, 500);
},
fail: function (err) {
console.log('支付失败', err);
app.disabled = false;
uni.navigateTo({
url: '/package/goods/order'
});
}
});
// #endif
}
// 使用余额支付
if (app.payType == 0) {
if(orderInfo){
uni.showToast({
title: '支付成功',
icon: 'success'
});
setTimeout(function () {
app.disabled = false;
app.$refs.payPasswordForm.close();
uni.reLaunch({
url: '/package/goods/order',
success: function (e) {
var page = getCurrentPages()[0];
if (page == undefined || page == null) return;
page.onLoad();
}
});
}, 2000);
}
// if (!orderInfo) {
// return uni.showToast({
// title: '支付失败',
// icon: 'error'
// });
// }
// if (orderInfo) {
// uni.showToast({
// title: '支付成功',
// icon: 'success'
// });
// setTimeout(function () {
// app.disabled = false;
// app.$refs.payPasswordForm.close();
// uni.reLaunch({
// url: '/package/goods/order',
// success: function (e) {
// var page = getCurrentPages()[0];
// if (page == undefined || page == null) return;
// page.onLoad();
// }
// });
// }, 2000);
// }
}
uni.hideLoading();
})
.catch((res) => {
uni.showToast({
title: res.message || '请检查您的网络.',
icon: 'none'
});
uni.hideLoading();
});
}
}
};
</script>
<style>
page {
background-size: 100%;
background-repeat: no-repeat;
background-color: #f0f2f5;
width: 750rpx;
overflow-x: hidden;
}
</style>
<style lang="scss" scoped>
.container {
}
.checkout-car {
width: 700rpx;
left: 25rpx;
z-index: 9999;
position: fixed;
bottom: 30rpx;
display: flex;
justify-content: space-between;
background-color: #000000;
border-radius: 100px;
align-items: center;
.car-selected {
color: #ccc;
display: flex;
align-items: center;
padding: 0 20rpx;
}
.car-total {
display: flex;
color: #ebcf00;
align-items: center;
padding-left: 40rpx;
.save-btn {
}
}
}
.card-actions {
display: flex;
flex-direction: row;
justify-content: flex-end;
height: 45px;
border-top: 1px #eee solid;
}
.card-actions-item {
display: flex;
flex-direction: row;
align-items: center;
.web-text-heading {
font-size: 38rpx;
margin-left: 28rpx;
}
}
.card-actions-item-text {
font-size: 12px;
color: #666;
margin-left: 5px;
}
.address-body {
width: 660rpx;
margin: auto;
}
.add-address {
width: 600rpx !important;
margin: 40rpx auto;
}
.btn-bar {
width: 700rpx;
left: 25rpx;
position: fixed;
bottom: 30rpx;
margin: auto;
clear: both;
}
.title-bar {
display: flex;
.web-text-heading {
margin-right: 20rpx;
}
.web-text-secondary {
margin-right: 20rpx;
}
}
.xieyi {
margin-bottom: 80rpx;
padding: 0 30rpx;
.text {
margin-left: 5rpx;
.link {
color: #0f80ff;
}
}
}
.pay-password-card {
width: 600rpx;
min-height: 300rpx;
margin: 30rpx auto;
background-color: #ffffff;
text-align: center;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
.web-text-primary {
line-height: 2rem;
padding: 20rpx 0;
}
}
.title-bar {
padding: 1rpx 10rpx;
}
.to-pay-btn {
width: 400rpx !important;
margin: 40rpx auto;
}
.goods-title {
display: flex;
margin-left: 8rpx;
.goods-info {
margin-left: 10rpx;
}
}
.delivery{
}
</style>