feat(payment): add complete payment system with multi-provider support

Add a full payment and subscription system supporting EasyPay (Alipay/WeChat),
Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
This commit is contained in:
erio
2026-04-10 21:08:51 +08:00
parent 00c08c574e
commit 63d1860dc0
166 changed files with 42743 additions and 220 deletions

View File

@@ -201,13 +201,73 @@ const routes: RouteRecordRaw[] = [
{
path: '/purchase',
name: 'PurchaseSubscription',
component: () => import('@/views/user/PurchaseSubscriptionView.vue'),
component: () => import('@/views/user/PaymentView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: false,
title: 'Purchase Subscription',
titleKey: 'purchase.title',
descriptionKey: 'purchase.description'
titleKey: 'nav.buySubscription',
descriptionKey: 'purchase.description',
requiresPayment: true
}
},
{
path: '/orders',
name: 'OrderList',
component: () => import('@/views/user/UserOrdersView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: false,
title: 'My Orders',
titleKey: 'nav.myOrders',
requiresPayment: true
}
},
{
path: '/payment/qrcode',
name: 'PaymentQRCode',
component: () => import('@/views/user/PaymentQRCodeView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: false,
title: 'Payment',
titleKey: 'payment.qr.scanToPay',
requiresPayment: true
}
},
{
path: '/payment/result',
name: 'PaymentResult',
component: () => import('@/views/user/PaymentResultView.vue'),
meta: {
requiresAuth: false,
requiresAdmin: false,
title: 'Payment Result',
titleKey: 'payment.result.success',
requiresPayment: false
}
},
{
path: '/payment/stripe',
name: 'StripePayment',
component: () => import('@/views/user/StripePaymentView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: false,
title: 'Stripe Payment',
titleKey: 'payment.stripePay',
requiresPayment: true
}
},
{
path: '/payment/stripe-popup',
name: 'StripePopup',
component: () => import('@/views/user/StripePopupView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: false,
title: 'Payment',
requiresPayment: true
}
},
{
@@ -384,6 +444,45 @@ const routes: RouteRecordRaw[] = [
}
},
// ==================== Payment Admin Routes ====================
{
path: '/admin/orders/dashboard',
name: 'AdminPaymentDashboard',
component: () => import('@/views/admin/orders/AdminPaymentDashboardView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: true,
title: 'Payment Dashboard',
titleKey: 'nav.paymentDashboard',
requiresPayment: true
}
},
{
path: '/admin/orders',
name: 'AdminOrders',
component: () => import('@/views/admin/orders/AdminOrdersView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: true,
title: 'Order Management',
titleKey: 'nav.orderManagement',
requiresPayment: true
}
},
{
path: '/admin/orders/plans',
name: 'AdminPaymentPlans',
component: () => import('@/views/admin/orders/AdminPaymentPlansView.vue'),
meta: {
requiresAuth: true,
requiresAdmin: true,
title: 'Subscription Plans',
titleKey: 'nav.paymentPlans',
requiresPayment: true
}
},
// ==================== 404 Not Found ====================
{
path: '/:pathMatch(.*)*',
@@ -500,6 +599,16 @@ router.beforeEach((to, _from, next) => {
return
}
// Check payment requirement (internal payment system only)
if (to.meta.requiresPayment) {
const paymentEnabled = appStore.cachedPublicSettings?.payment_enabled
if (!paymentEnabled) {
next(authStore.isAdmin ? '/admin/dashboard' : '/dashboard')
return
}
}
// 简易模式下限制访问某些页面
if (authStore.isSimpleMode) {
const restrictedPaths = [

View File

@@ -42,5 +42,21 @@ declare module 'vue-router' {
* @default false
*/
hideInMenu?: boolean
/**
* Whether this route requires internal payment system to be enabled
* @default false
*/
requiresPayment?: boolean
/**
* i18n key for the page title
*/
titleKey?: string
/**
* i18n key for the page description
*/
descriptionKey?: string
}
}