2025-03-08 08:09:31 +08:00
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { useCartStore } from "@/pinia/stores/cart"
|
2025-03-17 08:30:57 +08:00
|
|
|
|
import { useWxStore } from "@/pinia/stores/wx"
|
2025-04-12 11:32:01 +08:00
|
|
|
|
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
2025-03-08 08:09:31 +08:00
|
|
|
|
import { storeToRefs } from "pinia"
|
|
|
|
|
import { showConfirmDialog } from "vant"
|
2025-03-17 08:30:57 +08:00
|
|
|
|
import { submitOrderApi } from "@/common/apis/shop"
|
|
|
|
|
import type { SubmitOrderRequestData, WxJsApiPreCreateResponse } from "@/common/apis/shop/type"
|
|
|
|
|
import { useRouter } from 'vue-router'
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
2025-03-08 08:09:31 +08:00
|
|
|
|
|
|
|
|
|
const cartStore = useCartStore()
|
|
|
|
|
const { cartItems, totalPrice } = storeToRefs(cartStore)
|
|
|
|
|
|
2025-03-17 08:30:57 +08:00
|
|
|
|
const wxStore = useWxStore()
|
2025-04-12 11:32:01 +08:00
|
|
|
|
const { openid, balance, corpid, userid: qyUserid } = storeToRefs(wxStore)
|
|
|
|
|
|
|
|
|
|
const ab98UserStore = useAb98UserStore()
|
|
|
|
|
const { tel, userid: ab98Userid } = storeToRefs(ab98UserStore)
|
2025-03-08 08:09:31 +08:00
|
|
|
|
|
2025-04-02 09:33:47 +08:00
|
|
|
|
const selectedPayment = ref<'wechat' | 'balance'>('wechat')
|
2025-03-08 08:09:31 +08:00
|
|
|
|
const contact = ref("")
|
|
|
|
|
const remark = ref("")
|
|
|
|
|
const submitting = ref(false)
|
|
|
|
|
|
2025-03-17 08:30:57 +08:00
|
|
|
|
function callWxJsApi(paymentInfo: WxJsApiPreCreateResponse) {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
function onBridgeReady() {
|
|
|
|
|
(window as any).WeixinJSBridge.invoke(
|
|
|
|
|
'getBrandWCPayRequest',
|
|
|
|
|
{
|
|
|
|
|
appId: paymentInfo.appId,
|
|
|
|
|
timeStamp: paymentInfo.timeStamp,
|
|
|
|
|
nonceStr: paymentInfo.nonceStr,
|
2025-04-02 09:33:47 +08:00
|
|
|
|
package: paymentInfo.package.startsWith('prepay_id=')
|
|
|
|
|
? paymentInfo.package
|
2025-03-21 17:00:06 +08:00
|
|
|
|
: `prepay_id=${paymentInfo.package}`,
|
2025-03-17 08:30:57 +08:00
|
|
|
|
signType: paymentInfo.signType,
|
|
|
|
|
paySign: paymentInfo.paySign
|
|
|
|
|
},
|
|
|
|
|
(res: { err_msg: string }) => {
|
|
|
|
|
if (res.err_msg === "get_brand_wcpay_request:ok") {
|
|
|
|
|
resolve(true);
|
|
|
|
|
} else {
|
|
|
|
|
reject(new Error('支付未完成'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof (window as any).WeixinJSBridge === 'undefined') {
|
|
|
|
|
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
|
|
|
|
|
} else {
|
|
|
|
|
onBridgeReady();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-08 08:09:31 +08:00
|
|
|
|
async function handleSubmit() {
|
|
|
|
|
if (!cartItems.value.length) {
|
|
|
|
|
return showConfirmDialog({
|
|
|
|
|
title: "提示",
|
|
|
|
|
message: "请先选择商品后再结算"
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-17 08:30:57 +08:00
|
|
|
|
if (!openid.value) {
|
2025-03-08 08:09:31 +08:00
|
|
|
|
return showConfirmDialog({
|
2025-03-17 08:30:57 +08:00
|
|
|
|
title: "登录提示",
|
|
|
|
|
message: "请从微信中打开"
|
2025-03-08 08:09:31 +08:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 09:33:47 +08:00
|
|
|
|
// 移除原有的支付方式选择弹窗代码
|
|
|
|
|
|
2025-03-08 08:09:31 +08:00
|
|
|
|
submitting.value = true
|
|
|
|
|
try {
|
2025-04-12 11:32:01 +08:00
|
|
|
|
// 判断用户类型:
|
|
|
|
|
// 2 - 企业微信用户(corpid存在)
|
|
|
|
|
// 1 - 汇邦云用户(qyUserid存在)
|
|
|
|
|
// 0 - 外部用户
|
|
|
|
|
const isInternal = corpid.value ? 2 : qyUserid.value ? 1 : 0;
|
2025-03-17 08:30:57 +08:00
|
|
|
|
const requestData: SubmitOrderRequestData = {
|
2025-04-02 09:33:47 +08:00
|
|
|
|
openid: openid.value,
|
|
|
|
|
userid: wxStore.userid,
|
|
|
|
|
corpid: wxStore.corpid,
|
2025-03-17 08:30:57 +08:00
|
|
|
|
goodsList: cartItems.value.map(item => ({
|
|
|
|
|
goodsId: item.product.id,
|
|
|
|
|
quantity: item.quantity
|
2025-04-02 09:33:47 +08:00
|
|
|
|
})),
|
2025-04-12 11:32:01 +08:00
|
|
|
|
paymentType: selectedPayment.value,
|
|
|
|
|
mobile: tel.value,
|
|
|
|
|
qyUserid: isInternal === 2 ? qyUserid.value : ab98Userid.value,
|
|
|
|
|
isInternal: isInternal
|
2025-03-17 08:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 09:33:47 +08:00
|
|
|
|
const { code, data } = await submitOrderApi(requestData)
|
|
|
|
|
|
|
|
|
|
if (code !== 0) {
|
|
|
|
|
throw new Error("订单提交失败")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (selectedPayment.value === 'wechat') {
|
|
|
|
|
if (data.paymentInfo) {
|
|
|
|
|
await callWxJsApi(data.paymentInfo);
|
|
|
|
|
}
|
2025-03-17 08:30:57 +08:00
|
|
|
|
} else {
|
2025-04-02 09:33:47 +08:00
|
|
|
|
// 余额支付成功处理
|
|
|
|
|
wxStore.setBalance(data.newBalance || 0);
|
|
|
|
|
try {
|
|
|
|
|
await showConfirmDialog({
|
|
|
|
|
title: "支付成功",
|
|
|
|
|
message: `余额支付成功,剩余余额:¥${data.newBalance?.toFixed(2)}`
|
|
|
|
|
})
|
|
|
|
|
} catch (error) {
|
|
|
|
|
}
|
2025-03-17 08:30:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-02 09:33:47 +08:00
|
|
|
|
router.push({
|
|
|
|
|
path: '/order-success',
|
|
|
|
|
query: { orderId: data.orderId }
|
|
|
|
|
});
|
2025-03-08 08:09:31 +08:00
|
|
|
|
cartStore.clearCart()
|
2025-03-17 08:30:57 +08:00
|
|
|
|
} catch (error) {
|
2025-04-02 09:33:47 +08:00
|
|
|
|
if (error !== 'user_cancel') {
|
2025-03-17 08:30:57 +08:00
|
|
|
|
showConfirmDialog({
|
|
|
|
|
title: "支付失败",
|
|
|
|
|
message: error instanceof Error ? error.message : "支付流程中断"
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-03-08 08:09:31 +08:00
|
|
|
|
} finally {
|
|
|
|
|
submitting.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="checkout-container">
|
2025-03-17 08:30:57 +08:00
|
|
|
|
<van-nav-bar title="结算页面" left-text="返回" left-arrow fixed @click-left="() => $router.go(-1)" />
|
|
|
|
|
|
2025-03-08 08:09:31 +08:00
|
|
|
|
<div class="content-wrapper">
|
|
|
|
|
<!-- 原有商品列表等代码保持不动 -->
|
|
|
|
|
<van-cell-group class="product-list">
|
2025-03-17 08:30:57 +08:00
|
|
|
|
<van-cell v-for="item in cartItems" :key="item.product.id" class="product-item">
|
2025-03-08 08:09:31 +08:00
|
|
|
|
<template #icon>
|
2025-03-17 08:30:57 +08:00
|
|
|
|
<van-image :src="item.product.image" width="60" height="60" class="product-image" />
|
2025-03-08 08:09:31 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<div class="product-info">
|
|
|
|
|
<div class="product-name van-ellipsis">
|
|
|
|
|
{{ item.product.name }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="price-row">
|
|
|
|
|
<span class="product-price">
|
|
|
|
|
¥{{ item.product.price.toFixed(2) }}
|
|
|
|
|
</span>
|
|
|
|
|
<span class="quantity">
|
|
|
|
|
×{{ item.quantity }}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</van-cell>
|
|
|
|
|
</van-cell-group>
|
|
|
|
|
|
|
|
|
|
<van-cell-group class="contact-form">
|
2025-04-02 09:33:47 +08:00
|
|
|
|
<van-field label="支付方式" :model-value="selectedPayment" readonly>
|
|
|
|
|
<template #input>
|
|
|
|
|
<van-radio-group v-model="selectedPayment" direction="horizontal">
|
2025-04-11 11:11:13 +08:00
|
|
|
|
<van-radio name="wechat" v-if="!wxStore.corpid">
|
2025-04-02 09:33:47 +08:00
|
|
|
|
<van-icon name="wechat" class="method-icon" />
|
|
|
|
|
微信支付
|
|
|
|
|
</van-radio>
|
|
|
|
|
<van-radio name="balance" :disabled="balance < totalPrice">
|
|
|
|
|
<van-icon name="balance-o" class="method-icon" />
|
|
|
|
|
余额支付(当前:¥{{ balance.toFixed(2) }})
|
|
|
|
|
</van-radio>
|
|
|
|
|
</van-radio-group>
|
|
|
|
|
</template>
|
|
|
|
|
</van-field>
|
2025-03-08 08:09:31 +08:00
|
|
|
|
</van-cell-group>
|
|
|
|
|
|
|
|
|
|
<!-- 提交订单栏 -->
|
|
|
|
|
<div class="submit-bar">
|
|
|
|
|
<div class="total-price">
|
|
|
|
|
合计:¥{{ totalPrice.toFixed(2) }}
|
|
|
|
|
</div>
|
2025-03-17 08:30:57 +08:00
|
|
|
|
<van-button type="primary" size="large" :loading="submitting" loading-text="提交中..." @click="handleSubmit">
|
2025-03-08 08:09:31 +08:00
|
|
|
|
提交订单
|
|
|
|
|
</van-button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.van-nav-bar {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 0;
|
|
|
|
|
width: 100%;
|
|
|
|
|
z-index: 999;
|
|
|
|
|
background: #fff;
|
|
|
|
|
border-bottom: 1px solid #ebedf0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.content-wrapper {
|
2025-03-17 08:30:57 +08:00
|
|
|
|
padding-top: 46px;
|
|
|
|
|
/* 导航栏高度 */
|
2025-03-08 08:09:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkout-container {
|
|
|
|
|
padding: 12px 16px 80px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-list {
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-item {
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-image {
|
|
|
|
|
margin-right: 12px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
height: 60px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.price-row {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.product-price {
|
|
|
|
|
color: #e95d5d;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.quantity {
|
|
|
|
|
color: #666;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-icon {
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.method-label {
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.submit-bar {
|
|
|
|
|
position: fixed;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
background: #fff;
|
|
|
|
|
padding: 10px 16px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.total-price {
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
color: #e95d5d;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
</style>
|