From de494060ad5b468b65e1f280f55204b60f00e9a3 Mon Sep 17 00:00:00 2001 From: wwwwwwwww <526125649@qq.com> Date: Wed, 10 Jun 2026 11:49:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=89=8D=E5=8F=B0=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=8E=B7=E5=8F=96=E6=94=AF=E4=BB=98=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video-gen-api/app/api/v1/payments.py | 40 ++++++++--- video-gen-api/app/services/payment.py | 20 ++++-- video-gen-app/src/api/index.ts | 4 ++ .../src/components/Layout/AppLayout.tsx | 67 ++++++++++++------- 4 files changed, 94 insertions(+), 37 deletions(-) diff --git a/video-gen-api/app/api/v1/payments.py b/video-gen-api/app/api/v1/payments.py index 3f606892..4fc6f89a 100644 --- a/video-gen-api/app/api/v1/payments.py +++ b/video-gen-api/app/api/v1/payments.py @@ -21,6 +21,17 @@ from app.services.payment import ( router = APIRouter(prefix="/payments", tags=["payments"]) +@router.get("/methods") +async def get_payment_methods(db: AsyncSession = Depends(get_db)): + """Return which payment methods are enabled (from admin config).""" + from app.services.payment import _get_payment_configs + configs = await _get_payment_configs(db) + return { + "alipay": configs.get("payment_alipay_enabled", "").lower() == "true", + "wechat": configs.get("payment_wechat_enabled", "").lower() == "true", + } + + @router.post("/recharge", response_model=PaymentOrderOut) async def recharge( req: RechargeRequest, @@ -30,6 +41,14 @@ async def recharge( if req.method not in ("wechat", "alipay"): raise HTTPException(status_code=400, detail="不支持的支付方式") + # Check if the selected payment method is enabled in admin config + from app.services.payment import _get_payment_configs, _is_mock_mode + configs = await _get_payment_configs(db) + if not _is_mock_mode(configs): + enabled_key = f"payment_{req.method}_enabled" + if configs.get(enabled_key, "").lower() != "true": + raise HTTPException(status_code=400, detail="该支付方式未启用") + result = await db.execute( select(RechargePackage).where( RechargePackage.id == req.plan, @@ -40,15 +59,18 @@ async def recharge( pkg = result.scalar_one_or_none() if not pkg: raise HTTPException(status_code=400, detail="无效的套餐") - order = await create_recharge_order( - db, - current_user.id, - credits=pkg.credits, - price=pkg.price, - label=pkg.name, - bonus_credits=pkg.bonus_credits, - method=req.method, - ) + try: + order = await create_recharge_order( + db, + current_user.id, + credits=pkg.credits, + price=pkg.price, + label=pkg.name, + bonus_credits=pkg.bonus_credits, + method=req.method, + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) return order diff --git a/video-gen-api/app/services/payment.py b/video-gen-api/app/services/payment.py index 9261cb36..bd388e86 100644 --- a/video-gen-api/app/services/payment.py +++ b/video-gen-api/app/services/payment.py @@ -97,6 +97,22 @@ async def create_recharge_order( Returns the order; for Alipay the ``qr_url`` attribute will be populated with the scan-to-pay URL. """ + # Read config from database first + db_configs = await _get_payment_configs(db) + mock_mode = _is_mock_mode(db_configs) + + # In real mode, validate that the payment method is enabled and configured + if not mock_mode: + enabled_key = f"payment_{method}_enabled" + if db_configs.get(enabled_key, "").lower() != "true": + raise ValueError("该支付方式未启用,请联系管理员") + if method == "alipay": + if not db_configs.get("payment_alipay_app_id") or not db_configs.get("payment_alipay_private_key"): + raise ValueError("支付宝支付未完成配置,请联系管理员") + elif method == "wechat": + if not db_configs.get("payment_wechat_mch_id") or not db_configs.get("payment_wechat_api_key"): + raise ValueError("微信支付未完成配置,请联系管理员") + total_credits = credits + bonus_credits order = PaymentOrder( id=generate_id(), @@ -110,10 +126,6 @@ async def create_recharge_order( db.add(order) await db.flush() - # Read config from database - db_configs = await _get_payment_configs(db) - mock_mode = _is_mock_mode(db_configs) - if mock_mode: # Mock: immediately complete payment order.status = "paid" diff --git a/video-gen-app/src/api/index.ts b/video-gen-app/src/api/index.ts index fad28707..08635b16 100644 --- a/video-gen-app/src/api/index.ts +++ b/video-gen-app/src/api/index.ts @@ -319,6 +319,10 @@ export async function getRechargePackages(): Promise { return api.get('/recharge-packages'); } +export async function getPaymentMethods(): Promise<{ alipay: boolean; wechat: boolean }> { + return api.get('/payments/methods'); +} + export async function createRechargeOrder(planId: string, method: string = 'wechat'): Promise { return api.post('/payments/recharge', { plan: planId, method }); } diff --git a/video-gen-app/src/components/Layout/AppLayout.tsx b/video-gen-app/src/components/Layout/AppLayout.tsx index aca844bc..29d2e9c9 100644 --- a/video-gen-app/src/components/Layout/AppLayout.tsx +++ b/video-gen-app/src/components/Layout/AppLayout.tsx @@ -27,7 +27,7 @@ import { } from '@ant-design/icons'; import { Outlet, useNavigate, useLocation } from 'react-router-dom'; import { useAuthStore } from '../../store/useAuthStore'; -import { getMenuConfigs, getRechargePackages, createRechargeOrder, getPaymentOrders, getNotifications, markNotificationRead, getSiteInfo } from '../../api'; +import { getMenuConfigs, getRechargePackages, getPaymentMethods, createRechargeOrder, getPaymentOrders, getNotifications, markNotificationRead, getSiteInfo } from '../../api'; import NotificationPopup from '../NotificationPopup'; interface MenuConfig { @@ -93,6 +93,7 @@ const AppLayout: React.FC = () => { const [paymentMethod, setPaymentMethod] = useState('alipay'); const [paying, setPaying] = useState(false); const pollingTimerRef = useRef | null>(null); + const [enabledMethods, setEnabledMethods] = useState<{ alipay: boolean; wechat: boolean }>({ alipay: false, wechat: false }); // 监听预览弹窗状态,关闭浮动按钮 useEffect(() => { @@ -140,6 +141,12 @@ const AppLayout: React.FC = () => { getRechargePackages().then(data => { setRechargeOptions(data.filter((p: any) => p.is_active !== false && p.isActive !== false)); }).catch(() => {}); + getPaymentMethods().then(data => { + setEnabledMethods(data); + // Auto-select the first enabled method + if (data.alipay) setPaymentMethod('alipay'); + else if (data.wechat) setPaymentMethod('wechat'); + }).catch(() => {}); loadNotifications(); }, [user]); @@ -559,32 +566,44 @@ const AppLayout: React.FC = () => { {/* Payment method selection */} -
- 选择支付方式 - setPaymentMethod(e.target.value)} - style={{ display: 'flex', gap: 12 }}> - - - 支付宝 - - - - 微信支付 - - -
+ {(!enabledMethods.alipay && !enabledMethods.wechat) ? ( +
+ + ⚠️ 暂无可用的支付方式,请联系管理员开启支付功能 + +
+ ) : ( +
+ 选择支付方式 + setPaymentMethod(e.target.value)} + style={{ display: 'flex', gap: 12 }}> + {enabledMethods.alipay && ( + + + 支付宝 + + )} + {enabledMethods.wechat && ( + + + 微信支付 + + )} + +
+ )}
-