feat: 实现站内USDT收银台支付流程

- 后端: payment.go 支付处理(创建订单/回调通知/状态查询/签名算法)
- 后端: 新增公开支付通道API(PublicList,不暴露config)
- 前端: Checkout.vue 收银台页面(倒计时/二维码/支付轮询)
- 前端: Cart.vue 对接动态支付通道,选择bepusdt跳转收银台
- 前端: API添加paymentChannelApi和orderApi支付方法
- 路由: 注册checkout路由和支付相关API
This commit is contained in:
2026-05-26 16:43:31 +08:00
parent 675b365b8b
commit 09f1ee4601
9 changed files with 1002 additions and 19 deletions
+34 -18
View File
@@ -226,7 +226,7 @@ import {
Wallet, Coin, ChatDotRound
} from '@element-plus/icons-vue'
import { useCartStore } from '../../store/cart'
import { systemApi, addressApi, orderApi } from '../../api'
import { systemApi, addressApi, orderApi, paymentChannelApi } from '../../api'
import { getFirstImage } from '../../utils/image'
import BackNav from '../../components/BackNav.vue'
@@ -252,21 +252,23 @@ const addressForm = reactive({
is_default: false
})
const allPaymentMethods = [
{ value: 'balance', label: '余额支付', icon: markRaw(Wallet) },
{ value: 'alipay', label: '支付宝', icon: markRaw(Coin) },
{ value: 'wechat', label: '微信支付', icon: markRaw(ChatDotRound) },
]
const typeIconMap: Record<string, any> = {
balance: markRaw(Wallet),
alipay: markRaw(Coin),
wechat: markRaw(ChatDotRound),
bepusdt: markRaw(Coin),
bank: markRaw(CreditCard),
other: markRaw(Coin),
}
const paymentChannels = ref<any[]>([])
const availablePayments = computed(() => {
const enabledStr = settings.value.enabled_payments
if (!enabledStr) return [allPaymentMethods[0]]
try {
const enabled = JSON.parse(enabledStr)
return allPaymentMethods.filter(m => enabled.includes(m.value))
} catch {
return [allPaymentMethods[0]]
}
return paymentChannels.value.map(ch => ({
value: ch.code,
label: ch.name,
icon: typeIconMap[ch.type] || markRaw(Coin),
}))
})
const selectAll = computed({
@@ -321,8 +323,15 @@ async function fetchSettings() {
try {
const res: any = await systemApi.getPublicSettings()
settings.value = res.data || {}
if (availablePayments.value.length > 0 && !selectedPayment.value) {
selectedPayment.value = availablePayments.value[0].value
} catch {}
}
async function fetchPaymentChannels() {
try {
const res: any = await paymentChannelApi.list()
paymentChannels.value = res.data || []
if (paymentChannels.value.length > 0 && !selectedPayment.value) {
selectedPayment.value = paymentChannels.value[0].code
}
} catch {}
}
@@ -416,14 +425,20 @@ async function handleCheckout() {
submitting.value = true
try {
await orderApi.create({
const res: any = await orderApi.create({
shipping_address_id: selectedAddressId.value,
payment_method: selectedPayment.value,
cart_item_ids: selectedIds.value
})
ElMessage.success('订单创建成功')
await cartStore.fetchCart()
router.push('/orders')
const orderId = res.data?.id
const selectedChannel = paymentChannels.value.find(ch => ch.code === selectedPayment.value)
if (selectedChannel?.type === 'bepusdt' && orderId) {
router.push(`/checkout/${orderId}`)
} else {
router.push('/orders')
}
} catch (err: any) {
ElMessage.error(err.response?.data?.error || '订单创建失败')
} finally {
@@ -441,6 +456,7 @@ onMounted(() => {
cartStore.fetchCart()
fetchSettings()
fetchAddresses()
fetchPaymentChannels()
})
</script>