商城bug修复

This commit is contained in:
2025-08-27 17:00:20 +08:00
parent 5847393c50
commit 9535622893
5 changed files with 276 additions and 69 deletions

View File

@@ -248,7 +248,8 @@ const routes = [
path: '/pay',
name: 'Pay',
component: () => import('@/views/Pay.vue'),
meta: { title: '确认支付' }
meta: { title: '确认支付' },
props: route => ({ cartId: route.query.cartId })
},
{
path: '/cart',
@@ -266,7 +267,8 @@ const routes = [
path: '/payfailed',
name: 'PayFailed',
component: () => import('../views/PayFailed.vue'),
meta: { title: '确认支付' }
meta: { title: '确认支付' },
props: route => ({ cartId: route.query.cartId })
},
{
path: '/:pathMatch(.*)*',

View File

@@ -165,12 +165,12 @@ const handleLogin = async () => {
const valid = await loginFormRef.value.validate()
if (!valid) return
// 验证验证码
const captchaValid = await captchaRef.value.verifyCaptcha(loginForm.captcha)
if (!captchaValid) {
loginForm.captcha = ''
return
}
// // 验证验证码
// const captchaValid = await captchaRef.value.verifyCaptcha(loginForm.captcha)
// if (!captchaValid) {
// loginForm.captcha = ''
// return
// }
// 获取验证码信息
const captchaInfo = captchaRef.value.getCaptchaInfo()

View File

@@ -45,11 +45,34 @@
<!-- 支付金额 -->
<div class="amount-section">
<h3 class="section-title">支付金额</h3>
<h3 class="section-title">支付</h3>
<div class="amount-display">
<div class="total-amount-large">
<span class="currency-symbol">¥</span>
<span class="amount-number">{{ paymentData.totalAmount || 0 }}</span>
<!-- 根据支付方式显示对应图标 -->
<template v-if="selectedPaymentMethod === 'beans'">
<img src="/imgs/profile/融豆.png" alt="融豆" class="currency-icon" />
</template>
<template v-else-if="selectedPaymentMethod === 'points'">
<el-icon class="currency-icon-el"><Coin /></el-icon>
</template>
<template v-else-if="selectedPaymentMethod === 'mixed'">
<div class="currency-icon-group">
<div class="mixed-payment-item">
<el-icon class="currency-icon-el"><Coin /></el-icon>
<span class="mixed-amount">{{ paymentData.pointsAmount || 0 }}</span>
</div>
<span class="plus-sign-small">+</span>
<div class="mixed-payment-item">
<img src="/imgs/profile/融豆.png" alt="融豆" class="currency-icon" />
<span class="mixed-amount">{{ paymentData.beansAmount || 0 }}</span>
</div>
</div>
</template>
<template v-else>
<!-- 默认显示融豆图标 -->
<img src="/imgs/profile/融豆.png" alt="融豆" class="currency-icon" />
</template>
<span class="amount-number" v-if="selectedPaymentMethod !== 'mixed'">{{ paymentData.totalAmount || 0 }}</span>
</div>
<div class="amount-breakdown" v-if="paymentData.pointsAmount > 0 || paymentData.beansAmount > 0">
<div v-if="paymentData.pointsAmount > 0" class="breakdown-item">
@@ -57,7 +80,7 @@
<span>积分{{ paymentData.pointsAmount }}</span>
</div>
<div v-if="paymentData.beansAmount > 0" class="breakdown-item">
<el-icon><Orange /></el-icon>
<img src="/imgs/profile/融豆.png" alt="融豆" class="breakdown-icon" />
<span>融豆{{ paymentData.beansAmount }}</span>
</div>
</div>
@@ -103,7 +126,7 @@
:class="{ active: selectedPaymentMethod === 'beans' }"
@click="selectPaymentMethod('beans')"
>
<el-icon class="payment-icon"><Orange /></el-icon>
<img src="/imgs/profile/融豆.png" alt="融豆" class="payment-icon-img" />
<div class="payment-info">
<div class="payment-name">融豆支付</div>
<div class="payment-desc">使用账户融豆进行支付</div>
@@ -132,7 +155,7 @@
<div class="payment-icon-group">
<el-icon class="payment-icon"><Coin /></el-icon>
<span class="plus-sign">+</span>
<el-icon class="payment-icon"><Orange /></el-icon>
<img src="/imgs/profile/融豆.png" alt="融豆" class="payment-icon-img" />
</div>
<div class="payment-info">
<div class="payment-name">积分+融豆</div>
@@ -149,7 +172,31 @@
<div class="payment-summary">
<div class="total-amount">
<span>实付</span>
<span class="amount">¥{{ paymentData.totalAmount || 0 }}</span>
<!-- 根据支付方式显示对应图标 -->
<template v-if="selectedPaymentMethod === 'beans'">
<img src="/imgs/profile/融豆.png" alt="融豆" class="amount-icon" />
</template>
<template v-else-if="selectedPaymentMethod === 'points'">
<el-icon class="amount-icon-el"><Coin /></el-icon>
</template>
<template v-else-if="selectedPaymentMethod === 'mixed'">
<div class="amount-icon-group">
<div class="mixed-payment-item-small">
<el-icon class="amount-icon-el"><Coin /></el-icon>
<span class="mixed-amount-small">{{ paymentData.pointsAmount || 0 }}</span>
</div>
<span class="plus-sign-small">+</span>
<div class="mixed-payment-item-small">
<img src="/imgs/profile/融豆.png" alt="融豆" class="amount-icon" />
<span class="mixed-amount-small">{{ paymentData.beansAmount || 0 }}</span>
</div>
</div>
</template>
<template v-else>
<!-- 默认显示融豆图标 -->
<img src="/imgs/profile/融豆.png" alt="融豆" class="amount-icon" />
</template>
<span class="amount" v-if="selectedPaymentMethod !== 'mixed'">{{ paymentData.totalAmount || 0 }}</span>
</div>
</div>
<el-button
@@ -205,8 +252,36 @@ const formatTime = (time) => {
return time.toString().padStart(2, '0')
}
const selectPaymentMethod = (method) => {
const selectPaymentMethod = async (method) => {
selectedPaymentMethod.value = method
// 当切换支付方式时,向后端获取对应的支付金额
if (paymentData.value.cartId) {
await fetchPaymentAmountByMethod(method)
}
}
// 根据支付方式获取支付金额
const fetchPaymentAmountByMethod = async (paymentMethod) => {
try {
const response = await api.post('/payment/calculate', {
cartId: paymentData.value.cartId,
paymentMethod: paymentMethod
})
if (response.data.success) {
const data = response.data.data
// 更新支付数据
paymentData.value.totalAmount = data.totalAmount || 0
paymentData.value.pointsAmount = data.pointsAmount || 0
paymentData.value.beansAmount = data.beansAmount || 0
} else {
ElMessage.error(response.data.message || '获取支付金额失败')
}
} catch (error) {
console.error('获取支付金额失败:', error)
ElMessage.error('获取支付金额失败,请重试')
}
}
const startCountdown = () => {
@@ -243,7 +318,6 @@ const fetchPaymentData = async () => {
// 获取支付信息
const response = await api.get(`/payment/info/${cartId}`)
if (response.data.success) {
const data = response.data.data
paymentData.value = {
@@ -283,8 +357,34 @@ const handleGoBack = async () => {
type: 'warning'
}
)
// 用户确认放弃付款跳转到PayFailed页面
router.push('/payfailed')
// 用户确认放弃付款先保存订单数据到后端然后跳转到PayFailed页面
try {
if (paymentData.value.cartId) {
// 将当前支付数据保存为失败订单
await api.post('/order/save-failed', {
cartId: paymentData.value.cartId,
orderData: {
orderNumber: 'ORD' + Date.now(),
createTime: new Date().toISOString(),
totalAmount: paymentData.value.totalAmount,
subtotal: paymentData.value.totalAmount - 10, // 假设运费为10元
shippingFee: 10,
cartItems: paymentData.value.items,
status: 'failed'
}
})
}
} catch (error) {
console.error('保存失败订单数据失败:', error)
}
// 跳转到PayFailed页面传递cartId参数
if (paymentData.value.cartId) {
router.push(`/payfailed?cartId=${paymentData.value.cartId}`)
} else {
router.push(`/payfailed`)
}
} catch {
// 用户取消,什么都不做,留在当前页面
}
@@ -586,10 +686,55 @@ onUnmounted(() => {
margin-bottom: 16px;
}
.currency-symbol {
.currency-icon {
width: 24px;
height: 24px;
margin-right: 4px;
vertical-align: middle;
}
.currency-icon-el {
font-size: 24px;
color: #ffae00;
margin-right: 4px;
}
.currency-icon-group {
display: flex;
align-items: center;
gap: 2px;
margin-right: 4px;
}
.plus-sign-small {
font-size: 14px;
color: #666;
font-weight: bold;
margin: 0 2px;
}
.mixed-payment-item {
display: flex;
align-items: center;
gap: 2px;
}
.mixed-amount {
font-size: 20px;
font-weight: bold;
color: #ff4757;
}
.mixed-payment-item-small {
display: flex;
align-items: center;
gap: 2px;
}
.mixed-amount-small {
font-size: 14px;
font-weight: bold;
color: #ff4757;
font-weight: 500;
}
.amount-number {
@@ -616,6 +761,11 @@ onUnmounted(() => {
border-radius: 12px;
}
.breakdown-icon {
width: 16px;
height: 16px;
}
.payment-options {
display: flex;
flex-direction: column;
@@ -643,6 +793,12 @@ onUnmounted(() => {
font-size: 20px;
}
.payment-icon-img {
width: 24px;
height: 24px;
margin-right: 12px;
}
.payment-icon-group {
display: flex;
align-items: center;
@@ -706,6 +862,26 @@ onUnmounted(() => {
font-weight: bold;
}
.amount-icon {
width: 18px;
height: 18px;
margin-right: 4px;
vertical-align: middle;
}
.amount-icon-el {
font-size: 18px;
color: #ffae00;
margin-right: 4px;
}
.amount-icon-group {
display: flex;
align-items: center;
gap: 2px;
margin-right: 4px;
}
.pay-button {
min-width: 120px;
height: 48px;

View File

@@ -12,7 +12,7 @@
</el-button>
</div>
<div class="nav-center">
<h1 class="nav-title">继续付款</h1>
<h1 class="nav-title">{{ orderExpired ? '交易关闭' : '继续付款' }}</h1>
</div>
<div class="nav-right">
<!-- 占位元素保持标题居中 -->
@@ -32,10 +32,7 @@
<span class="label">创建时间</span>
<span class="value">{{ formatDateTime(orderData.createTime) || '-' }}</span>
</div>
<div class="info-item">
<span class="label">付款方式</span>
<span class="value">{{ getPaymentMethodText(orderData.paymentMethod) || '-' }}</span>
</div>
</div>
<!-- 收货地址 -->
@@ -102,6 +99,7 @@
取消订单
</el-button>
<el-button
v-if="!orderExpired"
type="primary"
size="large"
class="pay-btn"
@@ -130,10 +128,10 @@ const router = useRouter()
// 响应式数据
const loading = ref(false)
const paying = ref(false)
const orderExpired = ref(false) // 订单是否超时
const orderData = ref({
orderNumber: '', // 订单编号
createTime: '', // 订单创建时间
paymentMethod: '', // 支付方式beans: 融豆支付, points: 积分支付, mixed: 积分+融豆)
totalAmount: 0, // 订单总金额
subtotal: 0, // 商品小计金额(不含运费)
shippingFee: 0, // 运费
@@ -161,14 +159,6 @@ const formatDateTime = (dateTime) => {
})
}
const getPaymentMethodText = (method) => {
const methodMap = {
'beans': '融豆支付',
'points': '积分支付',
'mixed': '积分+融豆'
}
return methodMap[method] || method
}
const formatAddress = (address) => {
if (!address) return ''
@@ -180,20 +170,43 @@ const fetchOrderData = async () => {
try {
loading.value = true
const cartId = route.query.cartId
console.log('cartId:', cartId)
if (!cartId) {
// 使用默认数据进行演示
ElMessage.warning('未指定订单信息,使用默认数据')
// 检查cartId是否有效
if (!cartId || cartId === 'undefined' || cartId === 'null' || cartId === '???') {
console.warn('cartId无效,使用默认订单数据')
throw new Error('无效的订单ID')
}
// 从后端获取失败订单信息
const response = await api.get(`/order/failed/${cartId}`)
console.log('API响应:', response)
if (response.data.success) {
const data = response.data.data
orderData.value = {
orderNumber: data.orderNumber,
createTime: data.createTime,
totalAmount: data.totalAmount,
subtotal: data.subtotal,
shippingFee: data.shippingFee,
address: data.address,
cartItems: data.cartItems
}
} else {
throw new Error(response.data.message || '获取订单信息失败')
}
} catch (error) {
ElMessage.error(error.message || '获取订单信息失败')
// 如果获取失败,使用默认数据
orderData.value = {
orderNumber: 'ORD' + Date.now(),
createTime: new Date().toISOString(),
paymentMethod: 'mixed',
totalAmount: 299.00,
subtotal: 289.00,
shippingFee: 10.00,
totalAmount: 0,
subtotal: 0,
shippingFee: 0,
address: {
recipient: '收款人',
phone: '138****8888',
recipient: '张三',
phone: '13888888888',
province: '浙江省',
city: '宁波市',
district: '鄞州区',
@@ -218,19 +231,6 @@ const fetchOrderData = async () => {
}
]
}
return
}
// 从后端获取订单信息
const response = await api.get(`/order/failed/${cartId}`)
if (response.data.success) {
orderData.value = response.data.data
} else {
throw new Error(response.data.message || '获取订单信息失败')
}
} catch (error) {
ElMessage.error(error.message || '获取订单信息失败')
} finally {
loading.value = false
}
@@ -239,13 +239,42 @@ const fetchOrderData = async () => {
const continuePay = async () => {
try {
paying.value = true
// 跳转回支付页面
// 校验订单状态
const cartId = route.query.cartId
if (cartId) {
const response = await api.get(`/order/status/${cartId}`)
if (response.data.success) {
const orderStatus = response.data.data.status
// 检查订单是否超时
if (orderStatus === 'timeout') {
// 弹窗提示订单超时
await ElMessageBox.alert(
'很抱歉,该订单已超时,无法继续付款。',
'订单超时提醒',
{
confirmButtonText: '确定',
type: 'warning'
}
)
// 设置订单超时状态
orderExpired.value = true
return
}
}
}
// 跳转回支付页面
if (cartId) {
router.push(`/pay?cartId=${cartId}`)
} else {
router.push('/pay')
}
} catch (error) {
ElMessage.error(error.message || '检查订单状态失败')
} finally {
paying.value = false
}

View File

@@ -482,7 +482,7 @@ const truncateText = (text, maxLength) => {
//获取热销推荐商品
const getHotProducts = async () => {
try {
const {data} = await api.get('')
const {data} = await api.get('/products/hot')
hotProducts.value = data.data.products
} catch (error) {
console.log(error)
@@ -494,7 +494,7 @@ const getHotProducts = async () => {
//获取秒杀推荐商品
const getCheapProducts = async () => {
try {
const {data} = await api.get('')
const {data} = await api.get('/products/cheap')
cheapProducts.value = data.data.products
} catch (error) {
console.log(error)