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 { } else {
// 普通用户页面认证逻辑 // 普通用户页面认证逻辑
console.log(userStore.isAuthenticated,'isAuthenticated');
if (!userStore.isAuthenticated) { if (!userStore.isAuthenticated) {
// 尝试从本地存储恢复登录状态 // 尝试从本地存储恢复登录状态
await userStore.checkAuth() await userStore.checkAuth()

View File

@@ -99,6 +99,8 @@ export const useUserStore = defineStore('user', () => {
if (response.data.success) { if (response.data.success) {
// 检查是否需要支付 // 检查是否需要支付
if (response.data.needPayment) { if (response.data.needPayment) {
setToken(response.data.token)
setUser(response.data.user)
// 需要支付的情况,返回成功状态和支付相关信息 // 需要支付的情况,返回成功状态和支付相关信息
return { return {
success: true, 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 // 转账相关API
export const transferAPI = { export const transferAPI = {
// 获取公户信息 // 获取公户信息

View File

@@ -244,6 +244,25 @@
</div> </div>
<el-icon class="check-icon" v-if="selectedPaymentMethod === 'mixed'"><Check /></el-icon> <el-icon class="check-icon" v-if="selectedPaymentMethod === 'mixed'"><Check /></el-icon>
</div> </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> </div>
</div> </div>
@@ -347,7 +366,7 @@ const router = useRouter()
const loading = ref(false) const loading = ref(false)
const paying = ref(false) const paying = ref(false)
const selectedPaymentMethod = ref('') // 当前选择的支付方式 const selectedPaymentMethod = ref('') // 支持微信支付和支付宝支付
const paymentData = ref({ const paymentData = ref({
totalAmount: 0, totalAmount: 0,
pointsAmount: 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 totalPointsPrice = paymentData.value.items.reduce((sum, item) => sum + (item.points_price * item.quantity), 0)
const EXCHANGE_RATE = 10000 // 1融豆 = 10000积分 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)) { if (!isPaymentMethodAvailable(method)) {
let message = '' let message = ''
@@ -646,8 +674,16 @@ const confirmPayment = async () => {
} }
try { try {
// 根据商品价格显示确认信息 // 根据支付方式和商品价格显示确认信息
let confirmMessage = '' let confirmMessage = ''
// 微信支付
if (selectedPaymentMethod.value === 'wechat_h5') {
confirmMessage = '确认使用微信支付?'
} else if (selectedPaymentMethod.value === 'alipay_wap') {
confirmMessage = '确认使用支付宝支付?'
} else {
// 积分或融豆支付
const totalPoints = paymentData.value.pointsAmount const totalPoints = paymentData.value.pointsAmount
const totalRongdou = paymentData.value.beansAmount const totalRongdou = paymentData.value.beansAmount
@@ -658,6 +694,7 @@ const confirmPayment = async () => {
} else if (totalRongdou === 0 && totalPoints > 0) { } else if (totalRongdou === 0 && totalPoints > 0) {
confirmMessage = `确认支付 ${totalPoints} 积分?` confirmMessage = `确认支付 ${totalPoints} 积分?`
} }
}
await ElMessageBox.confirm( await ElMessageBox.confirm(
confirmMessage, confirmMessage,
@@ -682,10 +719,30 @@ const confirmPayment = async () => {
// 向后端发送订单支付请求 // 向后端发送订单支付请求
const response = await api.post('/orders/confirm-payment', orderData) const response = await api.post('/orders/confirm-payment', orderData)
console.log(orderData)
if (response.data.success) { 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('订单创建成功!') ElMessage.success('订单创建成功!')
// 跳转到PayLoading页面传递订单ID // 跳转到PayLoading页面传递订单ID
@@ -696,11 +753,9 @@ const confirmPayment = async () => {
} }
}) })
} else { } else {
console.log(orderData)
throw new Error(response.data.message || '创建订单失败') throw new Error(response.data.message || '创建订单失败')
} }
} catch (error) { } catch (error) {
console.log(orderData)
if (error !== 'cancel') { if (error !== 'cancel') {
ElMessage.error(error.message || '创建订单失败,请重试') ElMessage.error(error.message || '创建订单失败,请重试')
} }

View File

@@ -14,15 +14,28 @@
</div> </div>
<div class="payment-methods"> <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"> <div class="method-icon">
<svg viewBox="0 0 24 24" width="24" height="24"> <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"/> <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> </svg>
</div> </div>
<span class="method-name">微信支付</span> <span class="method-name">微信支付</span>
<div class="method-check"> <div class="method-check" v-show="selectedMethod === 'wechat_h5'">
<el-icon v-if="selectedMethod === 'wechat'"><Check /></el-icon> <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> </div>
</div> </div>
@@ -58,17 +71,17 @@ import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Check, SuccessFilled, CircleCloseFilled, Loading } from '@element-plus/icons-vue' import { Check, SuccessFilled, CircleCloseFilled, Loading } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import api from '@/utils/api' import api, { paymentAPI } from '@/utils/api'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
// 响应式数据 // 响应式数据
const selectedMethod = ref('wechat') const selectedMethod = ref('wechat_h5') // 默认选择微信支付
const paymentLoading = ref(false) const paymentLoading = ref(false)
const paymentStatus = ref('') const paymentStatus = ref('')
const paymentAmount = ref(99) // 注册费用 const paymentAmount = ref(399) // 注册费用
const userInfo = reactive({ const userInfo = reactive({
userId: '', userId: '',
}) })
@@ -90,7 +103,8 @@ const getUserInfo = async () => {
// 处理支付 // 处理支付
const handlePayment = async () => { const handlePayment = async () => {
if (!selectedMethod.value) { // 验证支付方式
if (!['wechat_h5', 'alipay_wap'].includes(selectedMethod.value)) {
ElMessage.error('请选择支付方式') ElMessage.error('请选择支付方式')
return return
} }
@@ -113,25 +127,28 @@ const handlePayment = async () => {
throw new Error('无法获取用户信息,请重新登录') throw new Error('无法获取用户信息,请重新登录')
} }
// 创建支付订单 // 创建统一支付订单
const response = await api.post('/wechat-pay/create-registration-order', { const response = await paymentAPI.createOrder({
userId: userId, userId: userId,
amount: paymentAmount.value, amount: paymentAmount.value,
description: '用户注册激活费用' description: '用户注册激活费用',
}, token ? { paymentMethod: selectedMethod.value
headers: { })
Authorization: `Bearer ${token}`
}
} : {})
if (response.data.success) { 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 { } else {
throw new Error(response.data.message || '创建支付订单失败') throw new Error(response.data.message || '创建支付订单失败')
} }
@@ -148,16 +165,22 @@ const handlePayment = async () => {
const startPaymentStatusPolling = (outTradeNo, token) => { const startPaymentStatusPolling = (outTradeNo, token) => {
const pollInterval = setInterval(async () => { const pollInterval = setInterval(async () => {
try { try {
const response = await api.get(`/wechat-pay/query-status/${outTradeNo}`, token ? { const response = await paymentAPI.queryStatus(outTradeNo, token)
headers: {
Authorization: `Bearer ${token}`
}
} : {})
if (response.data.success) { if (response.data.success) {
const status = response.data.data.trade_state // 处理支付状态(微信和支付宝)
const data = response.data.data;
let isPaid = false;
if (status === 'SUCCESS') { 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) clearInterval(pollInterval)
paymentStatus.value = 'success' paymentStatus.value = 'success'
ElMessage.success('支付成功!账户已激活') ElMessage.success('支付成功!账户已激活')
@@ -174,12 +197,25 @@ const startPaymentStatusPolling = (outTradeNo, token) => {
router.push('/login') router.push('/login')
}, 2000) }, 2000)
} }
} else if (status === 'CLOSED' || status === 'REVOKED' || status === 'PAYERROR') { } 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) clearInterval(pollInterval)
paymentStatus.value = 'failed' paymentStatus.value = 'failed'
ElMessage.error('支付失败,请重试') ElMessage.error('支付失败,请重试')
} }
} }
}
} catch (error) { } catch (error) {
console.error('查询支付状态失败:', error) console.error('查询支付状态失败:', error)
} }

View File

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

View File

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