This commit is contained in:
2025-09-05 16:53:11 +08:00
parent 82879fc920
commit 1bb83df40b
7 changed files with 157 additions and 50 deletions

View File

@@ -300,6 +300,8 @@ router.beforeEach(async (to, from, next) => {
}
} else {
// 普通用户页面认证逻辑
console.log(userStore.isAuthenticated,'isAuthenticated');
if (!userStore.isAuthenticated) {
// 尝试从本地存储恢复登录状态
await userStore.checkAuth()

View File

@@ -99,6 +99,8 @@ export const useUserStore = defineStore('user', () => {
if (response.data.success) {
// 检查是否需要支付
if (response.data.needPayment) {
setToken(response.data.token)
setUser(response.data.user)
// 需要支付的情况,返回成功状态和支付相关信息
return {
success: true,

View File

@@ -214,6 +214,21 @@ export const uploadAPI = {
}
}
// 支付相关API
export const paymentAPI = {
// 获取支付方式
getMethods: () => request.get('/payment/methods'),
// 创建支付订单
createOrder: (data) => request.post('/payment/create-order', data),
// 查询支付状态
queryStatus: (outTradeNo) => request.get(`/payment/query-status/${outTradeNo}`),
// 获取支付记录
getOrders: (params = {}) => request.get('/payment/orders', { params })
}
// 转账相关API
export const transferAPI = {
// 获取公户信息

View File

@@ -244,6 +244,25 @@
</div>
<el-icon class="check-icon" v-if="selectedPaymentMethod === 'mixed'"><Check /></el-icon>
</div>
<!-- 支付宝支付选项 -->
<div
class="payment-option"
:class="{ active: selectedPaymentMethod === 'alipay_wap' }"
@click="selectPaymentMethod('alipay_wap')"
>
<div class="payment-icon" style="color: #1677FF;">
<svg viewBox="0 0 24 24" width="20" height="20">
<path fill="#1677FF" d="M12 2C6.48 2 2 6.48 2 12c0 2.85 1.2 5.41 3.11 7.24C7.64 20.69 9.68 21.5 12 21.5s4.36-.81 6.89-2.26C20.8 17.41 22 14.85 22 12c0-5.52-4.48-10-10-10zm4.64 14.32c-.78.61-1.74 1.07-2.82 1.34-.65.16-1.33.24-2.02.24-1.85 0-3.58-.72-4.88-2.03C5.72 14.67 5 12.94 5 11.09c0-1.85.72-3.58 2.03-4.88C8.33 5 10.06 4.28 11.91 4.28c1.85 0 3.58.72 4.88 2.03C18 7.52 18.72 9.25 18.72 11.1c0 1.85-.72 3.58-2.03 4.88z"/>
<path fill="#1677FF" d="M15.5 9.5h-7c-.28 0-.5.22-.5.5s.22.5.5.5h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5zm0 2h-7c-.28 0-.5.22-.5.5s.22.5.5.5h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5zm-2 2h-5c-.28 0-.5.22-.5.5s.22.5.5.5h5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5z"/>
</svg>
</div>
<div class="payment-info">
<div class="payment-name">支付宝支付</div>
<div class="payment-desc">使用支付宝进行支付</div>
</div>
<el-icon class="check-icon" v-if="selectedPaymentMethod === 'alipay_wap'"><Check /></el-icon>
</div>
</div>
</div>
</div>
@@ -347,7 +366,7 @@ const router = useRouter()
const loading = ref(false)
const paying = ref(false)
const selectedPaymentMethod = ref('') // 当前选择的支付方式
const selectedPaymentMethod = ref('') // 支持微信支付和支付宝支付
const paymentData = ref({
totalAmount: 0,
pointsAmount: 0,
@@ -387,6 +406,15 @@ const selectPaymentMethod = async (method) => {
const totalPointsPrice = paymentData.value.items.reduce((sum, item) => sum + (item.points_price * item.quantity), 0)
const EXCHANGE_RATE = 10000 // 1融豆 = 10000积分
// 支付宝支付和微信支付直接选择,不需要余额检查
if (method === 'alipay_wap' || method === 'wechat_h5') {
selectedPaymentMethod.value = method
paymentData.value.totalAmount = totalPointsPrice
paymentData.value.pointsAmount = 0
paymentData.value.beansAmount = 0
return
}
// 检查支付方式是否可用
if (!isPaymentMethodAvailable(method)) {
let message = ''
@@ -646,17 +674,26 @@ const confirmPayment = async () => {
}
try {
// 根据商品价格显示确认信息
// 根据支付方式和商品价格显示确认信息
let confirmMessage = ''
const totalPoints = paymentData.value.pointsAmount
const totalRongdou = paymentData.value.beansAmount
if (totalPoints > 0 && totalRongdou > 0) {
confirmMessage = `确认支付 ${totalPoints} 积分 + ${totalRongdou} 融豆?`
} else if (totalPoints === 0 && totalRongdou > 0) {
confirmMessage = `确认支付 ${totalRongdou} 融豆?`
} else if (totalRongdou === 0 && totalPoints > 0) {
confirmMessage = `确认支付 ${totalPoints} 积分?`
// 微信支付
if (selectedPaymentMethod.value === 'wechat_h5') {
confirmMessage = '确认使用微信支付?'
} else if (selectedPaymentMethod.value === 'alipay_wap') {
confirmMessage = '确认使用支付宝支付?'
} else {
// 积分或融豆支付
const totalPoints = paymentData.value.pointsAmount
const totalRongdou = paymentData.value.beansAmount
if (totalPoints > 0 && totalRongdou > 0) {
confirmMessage = `确认支付 ${totalPoints} 积分 + ${totalRongdou} 融豆?`
} else if (totalPoints === 0 && totalRongdou > 0) {
confirmMessage = `确认支付 ${totalRongdou} 融豆?`
} else if (totalRongdou === 0 && totalPoints > 0) {
confirmMessage = `确认支付 ${totalPoints} 积分?`
}
}
await ElMessageBox.confirm(
@@ -682,10 +719,30 @@ const confirmPayment = async () => {
// 向后端发送订单支付请求
const response = await api.post('/orders/confirm-payment', orderData)
console.log(orderData)
if (response.data.success) {
console.log(orderData)
// 微信支付
if (selectedPaymentMethod.value === 'wechat_h5') {
// 获取支付URL并跳转
const payUrl = response.data.data?.payUrl
if (payUrl) {
// 跳转到第三方支付页面
window.location.href = payUrl
return // 不再执行后续代码
}
}
// 支付宝支付
if (selectedPaymentMethod.value === 'alipay_wap') {
// 获取支付URL并跳转
const payUrl = response.data.data?.payUrl
if (payUrl) {
// 跳转到支付宝支付页面
window.location.href = payUrl
return // 不再执行后续代码
}
}
ElMessage.success('订单创建成功!')
// 跳转到PayLoading页面传递订单ID
@@ -696,11 +753,9 @@ const confirmPayment = async () => {
}
})
} else {
console.log(orderData)
throw new Error(response.data.message || '创建订单失败')
}
} catch (error) {
console.log(orderData)
if (error !== 'cancel') {
ElMessage.error(error.message || '创建订单失败,请重试')
}

View File

@@ -14,15 +14,28 @@
</div>
<div class="payment-methods">
<div class="method-item" :class="{ active: selectedMethod === 'wechat' }" @click="selectedMethod = 'wechat'">
<div class="method-item" :class="{ active: selectedMethod === 'wechat_h5' }" @click="selectedMethod = 'wechat_h5'">
<div class="method-icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<path fill="#07C160" d="M8.5 6.5c-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5 2.5-1.1 2.5-2.5-1.1-2.5-2.5-2.5zm7 0c-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5 2.5-1.1 2.5-2.5-1.1-2.5-2.5-2.5zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8 0-1.12.23-2.18.64-3.15.41-.97 1.01-1.85 1.78-2.62.77-.77 1.65-1.37 2.62-1.78C9.82 4.23 10.88 4 12 4s2.18.23 3.15.64c.97.41 1.85 1.01 2.62 1.78.77.77 1.37 1.65 1.78 2.62.41.97.64 2.03.64 3.15 0 4.41-3.59 8-8 8z"/>
</svg>
</div>
<span class="method-name">微信支付</span>
<div class="method-check">
<el-icon v-if="selectedMethod === 'wechat'"><Check /></el-icon>
<div class="method-check" v-show="selectedMethod === 'wechat_h5'">
<el-icon><Check /></el-icon>
</div>
</div>
<div class="method-item" :class="{ active: selectedMethod === 'alipay_wap' }" @click="selectedMethod = 'alipay_wap'">
<div class="method-icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<path fill="#1677FF" d="M12 2C6.48 2 2 6.48 2 12c0 2.85 1.2 5.41 3.11 7.24C7.64 20.69 9.68 21.5 12 21.5s4.36-.81 6.89-2.26C20.8 17.41 22 14.85 22 12c0-5.52-4.48-10-10-10zm4.64 14.32c-.78.61-1.74 1.07-2.82 1.34-.65.16-1.33.24-2.02.24-1.85 0-3.58-.72-4.88-2.03C5.72 14.67 5 12.94 5 11.09c0-1.85.72-3.58 2.03-4.88C8.33 5 10.06 4.28 11.91 4.28c1.85 0 3.58.72 4.88 2.03 1.31 1.3 2.03 3.03 2.03 4.88 0 1.85-.72 3.58-2.03 4.88-.25.25-.52.48-.8.69-.28.21-.57.4-.87.56z"/>
<path fill="#1677FF" d="M15.5 9.5h-7c-.28 0-.5.22-.5.5s.22.5.5.5h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5zm0 2h-7c-.28 0-.5.22-.5.5s.22.5.5.5h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5zm-2 2h-5c-.28 0-.5.22-.5.5s.22.5.5.5h5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5z"/>
</svg>
</div>
<span class="method-name">支付宝支付</span>
<div class="method-check" v-show="selectedMethod === 'alipay_wap'">
<el-icon><Check /></el-icon>
</div>
</div>
</div>
@@ -58,17 +71,17 @@ import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Check, SuccessFilled, CircleCloseFilled, Loading } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/user'
import api from '@/utils/api'
import api, { paymentAPI } from '@/utils/api'
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
// 响应式数据
const selectedMethod = ref('wechat')
const selectedMethod = ref('wechat_h5') // 默认选择微信支付
const paymentLoading = ref(false)
const paymentStatus = ref('')
const paymentAmount = ref(99) // 注册费用
const paymentAmount = ref(399) // 注册费用
const userInfo = reactive({
userId: '',
})
@@ -90,7 +103,8 @@ const getUserInfo = async () => {
// 处理支付
const handlePayment = async () => {
if (!selectedMethod.value) {
// 验证支付方式
if (!['wechat_h5', 'alipay_wap'].includes(selectedMethod.value)) {
ElMessage.error('请选择支付方式')
return
}
@@ -113,25 +127,28 @@ const handlePayment = async () => {
throw new Error('无法获取用户信息,请重新登录')
}
// 创建支付订单
const response = await api.post('/wechat-pay/create-registration-order', {
// 创建统一支付订单
const response = await paymentAPI.createOrder({
userId: userId,
amount: paymentAmount.value,
description: '用户注册激活费用'
}, token ? {
headers: {
Authorization: `Bearer ${token}`
}
} : {})
description: '用户注册激活费用',
paymentMethod: selectedMethod.value
})
if (response.data.success) {
const { h5_url, out_trade_no } = response.data.data
const { outTradeNo, payUrl } = response.data.data
// 跳转到微信H5支付页面
window.location.href = h5_url
// 根据支付方式跳转到对应支付页面
if (selectedMethod.value === 'wechat_h5') {
// 微信支付 - 跳转到支付页面
window.location.href = payUrl
} else if (selectedMethod.value === 'alipay_wap') {
// 支付宝支付 - 跳转到支付页面
window.location.href = payUrl
}
// 开始轮询支付状态
startPaymentStatusPolling(out_trade_no, token)
startPaymentStatusPolling(outTradeNo, token)
} else {
throw new Error(response.data.message || '创建支付订单失败')
}
@@ -148,16 +165,22 @@ const handlePayment = async () => {
const startPaymentStatusPolling = (outTradeNo, token) => {
const pollInterval = setInterval(async () => {
try {
const response = await api.get(`/wechat-pay/query-status/${outTradeNo}`, token ? {
headers: {
Authorization: `Bearer ${token}`
}
} : {})
if (response.data.success) {
const status = response.data.data.trade_state
const response = await paymentAPI.queryStatus(outTradeNo, token)
if (status === 'SUCCESS') {
if (response.data.success) {
// 处理支付状态(微信和支付宝)
const data = response.data.data;
let isPaid = false;
if (selectedMethod.value === 'wechat_h5') {
// 微信支付状态判断
isPaid = data.trade_state === 'SUCCESS';
} else if (selectedMethod.value === 'alipay_wap') {
// 支付宝支付状态判断
isPaid = data.trade_status === 'TRADE_SUCCESS';
}
if (isPaid) {
clearInterval(pollInterval)
paymentStatus.value = 'success'
ElMessage.success('支付成功!账户已激活')
@@ -174,10 +197,23 @@ const startPaymentStatusPolling = (outTradeNo, token) => {
router.push('/login')
}, 2000)
}
} else if (status === 'CLOSED' || status === 'REVOKED' || status === 'PAYERROR') {
clearInterval(pollInterval)
paymentStatus.value = 'failed'
ElMessage.error('支付失败,请重试')
} else {
// 检查支付失败状态
let isFailed = false;
if (selectedMethod.value === 'wechat_h5') {
// 微信支付失败状态
isFailed = data.trade_state === 'CLOSED' || data.trade_state === 'REVOKED' || data.trade_state === 'PAYERROR';
} else if (selectedMethod.value === 'alipay_wap') {
// 支付宝支付失败状态
isFailed = data.trade_status === 'TRADE_CLOSED';
}
if (isFailed) {
clearInterval(pollInterval)
paymentStatus.value = 'failed'
ElMessage.error('支付失败,请重试')
}
}
}
} catch (error) {

View File

@@ -467,10 +467,6 @@ const handleRegister = async () => {
// 跳转到支付页面
router.push({
path: '/payment',
query: {
token: result.token,
userId: result.user.id
}
})
} else {
ElMessage.success('注册成功!请登录')

View File

@@ -11,6 +11,7 @@ export default defineConfig({
}
},
server: {
host: '0.0.0.0', // 添加这一行
port: 5173,
proxy: {
'/api': {