diff --git a/src/__tests__/app/pay/alipay-short-link-route.test.ts b/src/__tests__/app/pay/alipay-short-link-route.test.ts
index 351fc98..ede7734 100644
--- a/src/__tests__/app/pay/alipay-short-link-route.test.ts
+++ b/src/__tests__/app/pay/alipay-short-link-route.test.ts
@@ -190,9 +190,7 @@ describe('GET /pay/[orderId]', () => {
);
const response = await GET(
- createRequest(
- 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 Mobile/15E148',
- ),
+ createRequest('Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 Mobile/15E148'),
{
params: Promise.resolve({ orderId: 'order-001' }),
},
diff --git a/src/__tests__/lib/alipay/client.test.ts b/src/__tests__/lib/alipay/client.test.ts
index a69786b..e1c1982 100644
--- a/src/__tests__/lib/alipay/client.test.ts
+++ b/src/__tests__/lib/alipay/client.test.ts
@@ -1,4 +1,3 @@
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
vi.mock('@/lib/config', () => ({
diff --git a/src/__tests__/lib/order/status-access.test.ts b/src/__tests__/lib/order/status-access.test.ts
index 6524918..39ed8d4 100644
--- a/src/__tests__/lib/order/status-access.test.ts
+++ b/src/__tests__/lib/order/status-access.test.ts
@@ -1,4 +1,3 @@
-
import { describe, expect, it, vi } from 'vitest';
vi.mock('@/lib/config', () => ({
diff --git a/src/__tests__/payment-flow.test.ts b/src/__tests__/payment-flow.test.ts
index 79d0388..c141612 100644
--- a/src/__tests__/payment-flow.test.ts
+++ b/src/__tests__/payment-flow.test.ts
@@ -101,12 +101,7 @@ function shouldAutoRedirect(opts: {
qrCode?: string | null;
isMobile: boolean;
}): boolean {
- return (
- !opts.expired &&
- !isStripeType(opts.paymentType) &&
- !!opts.payUrl &&
- (opts.isMobile || !opts.qrCode)
- );
+ return !opts.expired && !isStripeType(opts.paymentType) && !!opts.payUrl && (opts.isMobile || !opts.qrCode);
}
// ============================================================
@@ -381,9 +376,7 @@ describe('Payment Flow - PC/Mobile, QR/Redirect', () => {
});
it('Mobile: uses H5 order, returns payUrl (no qrCode)', async () => {
- mockWxpayCreateH5Order.mockResolvedValue(
- 'https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx123',
- );
+ mockWxpayCreateH5Order.mockResolvedValue('https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx123');
const request: CreatePaymentRequest = {
orderId: 'order-wx-002',
diff --git a/src/app/admin/dashboard/page.tsx b/src/app/admin/dashboard/page.tsx
index d30095d..d3a96ff 100644
--- a/src/app/admin/dashboard/page.tsx
+++ b/src/app/admin/dashboard/page.tsx
@@ -39,33 +39,34 @@ function DashboardContent() {
const isDark = theme === 'dark';
const isEmbedded = uiMode === 'embedded';
- const text = locale === 'en'
- ? {
- missingToken: 'Missing admin token',
- missingTokenHint: 'Please access the admin page from the Sub2API platform.',
- invalidToken: 'Invalid admin token',
- requestFailed: 'Request failed',
- loadFailed: 'Failed to load data',
- title: 'Dashboard',
- subtitle: 'Recharge order analytics and insights',
- daySuffix: 'd',
- orders: 'Order Management',
- refresh: 'Refresh',
- loading: 'Loading...',
- }
- : {
- missingToken: '缺少管理员凭证',
- missingTokenHint: '请从 Sub2API 平台正确访问管理页面',
- invalidToken: '管理员凭证无效',
- requestFailed: '请求失败',
- loadFailed: '加载数据失败',
- title: '数据概览',
- subtitle: '充值订单统计与分析',
- daySuffix: '天',
- orders: '订单管理',
- refresh: '刷新',
- loading: '加载中...',
- };
+ const text =
+ locale === 'en'
+ ? {
+ missingToken: 'Missing admin token',
+ missingTokenHint: 'Please access the admin page from the Sub2API platform.',
+ invalidToken: 'Invalid admin token',
+ requestFailed: 'Request failed',
+ loadFailed: 'Failed to load data',
+ title: 'Dashboard',
+ subtitle: 'Recharge order analytics and insights',
+ daySuffix: 'd',
+ orders: 'Order Management',
+ refresh: 'Refresh',
+ loading: 'Loading...',
+ }
+ : {
+ missingToken: '缺少管理员凭证',
+ missingTokenHint: '请从 Sub2API 平台正确访问管理页面',
+ invalidToken: '管理员凭证无效',
+ requestFailed: '请求失败',
+ loadFailed: '加载数据失败',
+ title: '数据概览',
+ subtitle: '充值订单统计与分析',
+ daySuffix: '天',
+ orders: '订单管理',
+ refresh: '刷新',
+ loading: '加载中...',
+ };
const [days, setDays] = useState(30);
const [data, setData] = useState(null);
@@ -138,7 +139,8 @@ function DashboardContent() {
<>
{DAYS_OPTIONS.map((d) => (
))}
@@ -162,7 +164,7 @@ function DashboardContent() {
)}
{loading ? (
- {text.loading}
+ {text.loading}
) : data ? (
@@ -190,9 +192,7 @@ function DashboardPageFallback() {
export default function DashboardPage() {
return (
-
}
- >
+
}>
);
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index 8bebbd1..671aea4 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -52,67 +52,68 @@ function AdminContent() {
const isDark = theme === 'dark';
const isEmbedded = uiMode === 'embedded';
- const text = locale === 'en'
- ? {
- missingToken: 'Missing admin token',
- missingTokenHint: 'Please access the admin page from the Sub2API platform.',
- invalidToken: 'Invalid admin token',
- requestFailed: 'Request failed',
- loadOrdersFailed: 'Failed to load orders',
- retryConfirm: 'Retry recharge for this order?',
- retryFailed: 'Retry failed',
- retryRequestFailed: 'Retry request failed',
- cancelConfirm: 'Cancel this order?',
- cancelFailed: 'Cancel failed',
- cancelRequestFailed: 'Cancel request failed',
- loadDetailFailed: 'Failed to load order details',
- title: 'Order Management',
- subtitle: 'View and manage all recharge orders',
- dashboard: 'Dashboard',
- refresh: 'Refresh',
- loading: 'Loading...',
- statuses: {
- '': 'All',
- PENDING: 'Pending',
- PAID: 'Paid',
- RECHARGING: 'Recharging',
- COMPLETED: 'Completed',
- EXPIRED: 'Expired',
- CANCELLED: 'Cancelled',
- FAILED: 'Recharge failed',
- REFUNDED: 'Refunded',
- },
- }
- : {
- missingToken: '缺少管理员凭证',
- missingTokenHint: '请从 Sub2API 平台正确访问管理页面',
- invalidToken: '管理员凭证无效',
- requestFailed: '请求失败',
- loadOrdersFailed: '加载订单列表失败',
- retryConfirm: '确认重试充值?',
- retryFailed: '重试失败',
- retryRequestFailed: '重试请求失败',
- cancelConfirm: '确认取消该订单?',
- cancelFailed: '取消失败',
- cancelRequestFailed: '取消请求失败',
- loadDetailFailed: '加载订单详情失败',
- title: '订单管理',
- subtitle: '查看和管理所有充值订单',
- dashboard: '数据概览',
- refresh: '刷新',
- loading: '加载中...',
- statuses: {
- '': '全部',
- PENDING: '待支付',
- PAID: '已支付',
- RECHARGING: '充值中',
- COMPLETED: '已完成',
- EXPIRED: '已超时',
- CANCELLED: '已取消',
- FAILED: '充值失败',
- REFUNDED: '已退款',
- },
- };
+ const text =
+ locale === 'en'
+ ? {
+ missingToken: 'Missing admin token',
+ missingTokenHint: 'Please access the admin page from the Sub2API platform.',
+ invalidToken: 'Invalid admin token',
+ requestFailed: 'Request failed',
+ loadOrdersFailed: 'Failed to load orders',
+ retryConfirm: 'Retry recharge for this order?',
+ retryFailed: 'Retry failed',
+ retryRequestFailed: 'Retry request failed',
+ cancelConfirm: 'Cancel this order?',
+ cancelFailed: 'Cancel failed',
+ cancelRequestFailed: 'Cancel request failed',
+ loadDetailFailed: 'Failed to load order details',
+ title: 'Order Management',
+ subtitle: 'View and manage all recharge orders',
+ dashboard: 'Dashboard',
+ refresh: 'Refresh',
+ loading: 'Loading...',
+ statuses: {
+ '': 'All',
+ PENDING: 'Pending',
+ PAID: 'Paid',
+ RECHARGING: 'Recharging',
+ COMPLETED: 'Completed',
+ EXPIRED: 'Expired',
+ CANCELLED: 'Cancelled',
+ FAILED: 'Recharge failed',
+ REFUNDED: 'Refunded',
+ },
+ }
+ : {
+ missingToken: '缺少管理员凭证',
+ missingTokenHint: '请从 Sub2API 平台正确访问管理页面',
+ invalidToken: '管理员凭证无效',
+ requestFailed: '请求失败',
+ loadOrdersFailed: '加载订单列表失败',
+ retryConfirm: '确认重试充值?',
+ retryFailed: '重试失败',
+ retryRequestFailed: '重试请求失败',
+ cancelConfirm: '确认取消该订单?',
+ cancelFailed: '取消失败',
+ cancelRequestFailed: '取消请求失败',
+ loadDetailFailed: '加载订单详情失败',
+ title: '订单管理',
+ subtitle: '查看和管理所有充值订单',
+ dashboard: '数据概览',
+ refresh: '刷新',
+ loading: '加载中...',
+ statuses: {
+ '': '全部',
+ PENDING: '待支付',
+ PAID: '已支付',
+ RECHARGING: '充值中',
+ COMPLETED: '已完成',
+ EXPIRED: '已超时',
+ CANCELLED: '已取消',
+ FAILED: '充值失败',
+ REFUNDED: '已退款',
+ },
+ };
const [orders, setOrders] = useState
([]);
const [total, setTotal] = useState(0);
@@ -321,7 +322,9 @@ function AdminContent() {
/>
{/* Order Detail */}
- {detailOrder && setDetailOrder(null)} dark={isDark} locale={locale} />}
+ {detailOrder && (
+ setDetailOrder(null)} dark={isDark} locale={locale} />
+ )}
);
}
@@ -339,9 +342,7 @@ function AdminPageFallback() {
export default function AdminPage() {
return (
- }
- >
+ }>
);
diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts
index fe4c262..5ffb1b6 100644
--- a/src/app/api/user/route.ts
+++ b/src/app/api/user/route.ts
@@ -15,7 +15,10 @@ export async function GET(request: NextRequest) {
const token = request.nextUrl.searchParams.get('token')?.trim();
if (!token) {
- return NextResponse.json({ error: locale === 'en' ? 'Missing token parameter' : '缺少 token 参数' }, { status: 401 });
+ return NextResponse.json(
+ { error: locale === 'en' ? 'Missing token parameter' : '缺少 token 参数' },
+ { status: 401 },
+ );
}
try {
@@ -28,7 +31,10 @@ export async function GET(request: NextRequest) {
}
if (tokenUser.id !== userId) {
- return NextResponse.json({ error: locale === 'en' ? 'Forbidden to access this user' : '无权访问该用户信息' }, { status: 403 });
+ return NextResponse.json(
+ { error: locale === 'en' ? 'Forbidden to access this user' : '无权访问该用户信息' },
+ { status: 403 },
+ );
}
const env = getEnv();
@@ -77,9 +83,7 @@ export async function GET(request: NextRequest) {
helpImageUrl: env.PAY_HELP_IMAGE_URL ?? null,
helpText: env.PAY_HELP_TEXT ?? null,
stripePublishableKey:
- enabledTypes.includes('stripe') && env.STRIPE_PUBLISHABLE_KEY
- ? env.STRIPE_PUBLISHABLE_KEY
- : null,
+ enabledTypes.includes('stripe') && env.STRIPE_PUBLISHABLE_KEY ? env.STRIPE_PUBLISHABLE_KEY : null,
sublabelOverrides: Object.keys(sublabelOverrides).length > 0 ? sublabelOverrides : null,
},
});
@@ -89,6 +93,9 @@ export async function GET(request: NextRequest) {
return NextResponse.json({ error: locale === 'en' ? 'User not found' : '用户不存在' }, { status: 404 });
}
console.error('Get user error:', error);
- return NextResponse.json({ error: locale === 'en' ? 'Failed to fetch user info' : '获取用户信息失败' }, { status: 500 });
+ return NextResponse.json(
+ { error: locale === 'en' ? 'Failed to fetch user info' : '获取用户信息失败' },
+ { status: 500 },
+ );
}
}
diff --git a/src/app/api/wxpay/notify/route.ts b/src/app/api/wxpay/notify/route.ts
index 880c749..de006d2 100644
--- a/src/app/api/wxpay/notify/route.ts
+++ b/src/app/api/wxpay/notify/route.ts
@@ -22,15 +22,11 @@ export async function POST(request: NextRequest) {
return Response.json({ code: 'SUCCESS', message: '成功' });
}
const success = await handlePaymentNotify(notification, provider.name);
- return Response.json(
- success ? { code: 'SUCCESS', message: '成功' } : { code: 'FAIL', message: '处理失败' },
- { status: success ? 200 : 500 },
- );
+ return Response.json(success ? { code: 'SUCCESS', message: '成功' } : { code: 'FAIL', message: '处理失败' }, {
+ status: success ? 200 : 500,
+ });
} catch (error) {
console.error('Wxpay notify error:', error);
- return Response.json(
- { code: 'FAIL', message: '处理失败' },
- { status: 500 },
- );
+ return Response.json({ code: 'FAIL', message: '处理失败' }, { status: 500 });
}
}
diff --git a/src/app/globals.css b/src/app/globals.css
index a346e3a..669fdf1 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -8,5 +8,11 @@
body {
background: var(--background);
color: var(--foreground);
- font-family: system-ui, -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+ font-family:
+ system-ui,
+ -apple-system,
+ 'PingFang SC',
+ 'Hiragino Sans GB',
+ 'Microsoft YaHei',
+ sans-serif;
}
diff --git a/src/app/pay/orders/page.tsx b/src/app/pay/orders/page.tsx
index 3a1bcac..96afe70 100644
--- a/src/app/pay/orders/page.tsx
+++ b/src/app/pay/orders/page.tsx
@@ -30,8 +30,16 @@ function OrdersContent() {
const text = {
missingAuth: pickLocaleText(locale, '缺少认证信息', 'Missing authentication information'),
- visitOrders: pickLocaleText(locale, '请从 Sub2API 平台正确访问订单页面', 'Please open the orders page from Sub2API'),
- sessionExpired: pickLocaleText(locale, '登录态已失效,请从 Sub2API 重新进入支付页。', 'Session expired. Please re-enter from Sub2API.'),
+ visitOrders: pickLocaleText(
+ locale,
+ '请从 Sub2API 平台正确访问订单页面',
+ 'Please open the orders page from Sub2API',
+ ),
+ sessionExpired: pickLocaleText(
+ locale,
+ '登录态已失效,请从 Sub2API 重新进入支付页。',
+ 'Session expired. Please re-enter from Sub2API.',
+ ),
loadFailed: pickLocaleText(locale, '订单加载失败,请稍后重试。', 'Failed to load orders. Please try again later.'),
networkError: pickLocaleText(locale, '网络错误,请稍后重试。', 'Network error. Please try again later.'),
switchingMobileTab: pickLocaleText(locale, '正在切换到移动端订单 Tab...', 'Switching to mobile orders tab...'),
@@ -40,7 +48,11 @@ function OrdersContent() {
backToPay: pickLocaleText(locale, '返回充值', 'Back to Top Up'),
loading: pickLocaleText(locale, '加载中...', 'Loading...'),
userPrefix: pickLocaleText(locale, '用户', 'User'),
- authError: pickLocaleText(locale, '缺少认证信息,请从 Sub2API 平台正确访问订单页面', 'Missing authentication information. Please open the orders page from Sub2API.'),
+ authError: pickLocaleText(
+ locale,
+ '缺少认证信息,请从 Sub2API 平台正确访问订单页面',
+ 'Missing authentication information. Please open the orders page from Sub2API.',
+ ),
};
const [isIframeContext, setIsIframeContext] = useState(true);
diff --git a/src/app/pay/page.tsx b/src/app/pay/page.tsx
index 8a4a7b6..4c7b1ab 100644
--- a/src/app/pay/page.tsx
+++ b/src/app/pay/page.tsx
@@ -156,8 +156,7 @@ function PayContent() {
}
}
}
- } catch {
- }
+ } catch {}
};
const loadMoreOrders = async () => {
@@ -203,7 +202,11 @@ function PayContent() {
{pickLocaleText(locale, '缺少认证信息', 'Missing authentication info')}
- {pickLocaleText(locale, '请从 Sub2API 平台正确访问充值页面', 'Please open the recharge page from the Sub2API platform')}
+ {pickLocaleText(
+ locale,
+ '请从 Sub2API 平台正确访问充值页面',
+ 'Please open the recharge page from the Sub2API platform',
+ )}
@@ -216,7 +219,11 @@ function PayContent() {
{pickLocaleText(locale, '用户不存在', 'User not found')}
- {pickLocaleText(locale, '请检查链接是否正确,或联系管理员', 'Please check whether the link is correct or contact the administrator')}
+ {pickLocaleText(
+ locale,
+ '请检查链接是否正确,或联系管理员',
+ 'Please check whether the link is correct or contact the administrator',
+ )}
@@ -272,15 +279,33 @@ function PayContent() {
if (!res.ok) {
const codeMessages: Record = {
- INVALID_TOKEN: pickLocaleText(locale, '认证已失效,请重新从平台进入充值页面', 'Authentication expired. Please re-enter the recharge page from the platform'),
- USER_INACTIVE: pickLocaleText(locale, '账户已被禁用,无法充值,请联系管理员', 'This account is disabled and cannot be recharged. Please contact the administrator'),
- TOO_MANY_PENDING: pickLocaleText(locale, '您有过多待支付订单,请先完成或取消现有订单后再试', 'You have too many pending orders. Please complete or cancel existing orders first'),
- USER_NOT_FOUND: pickLocaleText(locale, '用户不存在,请检查链接是否正确', 'User not found. Please check whether the link is correct'),
+ INVALID_TOKEN: pickLocaleText(
+ locale,
+ '认证已失效,请重新从平台进入充值页面',
+ 'Authentication expired. Please re-enter the recharge page from the platform',
+ ),
+ USER_INACTIVE: pickLocaleText(
+ locale,
+ '账户已被禁用,无法充值,请联系管理员',
+ 'This account is disabled and cannot be recharged. Please contact the administrator',
+ ),
+ TOO_MANY_PENDING: pickLocaleText(
+ locale,
+ '您有过多待支付订单,请先完成或取消现有订单后再试',
+ 'You have too many pending orders. Please complete or cancel existing orders first',
+ ),
+ USER_NOT_FOUND: pickLocaleText(
+ locale,
+ '用户不存在,请检查链接是否正确',
+ 'User not found. Please check whether the link is correct',
+ ),
DAILY_LIMIT_EXCEEDED: data.error,
METHOD_DAILY_LIMIT_EXCEEDED: data.error,
PAYMENT_GATEWAY_ERROR: data.error,
};
- setError(codeMessages[data.code] || data.error || pickLocaleText(locale, '创建订单失败', 'Failed to create order'));
+ setError(
+ codeMessages[data.code] || data.error || pickLocaleText(locale, '创建订单失败', 'Failed to create order'),
+ );
return;
}
@@ -481,11 +506,24 @@ function PayContent() {
{pickLocaleText(locale, '支付说明', 'Payment Notes')}
- - {pickLocaleText(locale, '订单完成后会自动到账', 'Balance will be credited automatically after the order completes')}
- - {pickLocaleText(locale, '如需历史记录请查看「我的订单」', 'Check "My Orders" for payment history')}
+ -
+ {pickLocaleText(
+ locale,
+ '订单完成后会自动到账',
+ 'Balance will be credited automatically after the order completes',
+ )}
+
+ -
+ {pickLocaleText(
+ locale,
+ '如需历史记录请查看「我的订单」',
+ 'Check "My Orders" for payment history',
+ )}
+
{config.maxDailyAmount > 0 && (
-
- {pickLocaleText(locale, '每日最大充值', 'Maximum daily recharge')} ¥{config.maxDailyAmount.toFixed(2)}
+ {pickLocaleText(locale, '每日最大充值', 'Maximum daily recharge')} ¥
+ {config.maxDailyAmount.toFixed(2)}
)}
@@ -551,18 +589,17 @@ function PayContent() {
/>
)}
-
-{step === 'result' && orderResult && finalOrderState && (
-
-)}
+ {step === 'result' && orderResult && finalOrderState && (
+
+ )}
{helpImageOpen && helpImageUrl && (
}
- >
+ }>
);
diff --git a/src/app/pay/result/page.tsx b/src/app/pay/result/page.tsx
index a573dc4..8a4c656 100644
--- a/src/app/pay/result/page.tsx
+++ b/src/app/pay/result/page.tsx
@@ -1,4 +1,3 @@
-
'use client';
import { useSearchParams } from 'next/navigation';
@@ -58,27 +57,60 @@ function closeCurrentWindow() {
function getStatusConfig(order: PublicOrderStatusSnapshot | null, locale: Locale, hasAccessToken: boolean) {
if (!order) {
return locale === 'en'
- ? { label: 'Payment Error', color: 'text-red-600', icon: '✗', message: hasAccessToken ? 'Unable to load the order status. Please try again later.' : 'Missing order access token. Please go back to the recharge page.' }
- : { label: '支付异常', color: 'text-red-600', icon: '✗', message: hasAccessToken ? '未查询到订单状态,请稍后重试。' : '订单访问凭证缺失,请返回原充值页查看订单结果。' };
+ ? {
+ label: 'Payment Error',
+ color: 'text-red-600',
+ icon: '✗',
+ message: hasAccessToken
+ ? 'Unable to load the order status. Please try again later.'
+ : 'Missing order access token. Please go back to the recharge page.',
+ }
+ : {
+ label: '支付异常',
+ color: 'text-red-600',
+ icon: '✗',
+ message: hasAccessToken ? '未查询到订单状态,请稍后重试。' : '订单访问凭证缺失,请返回原充值页查看订单结果。',
+ };
}
if (order.rechargeSuccess) {
return locale === 'en'
- ? { label: 'Recharge Successful', color: 'text-green-600', icon: '✓', message: 'Your balance has been credited successfully.' }
+ ? {
+ label: 'Recharge Successful',
+ color: 'text-green-600',
+ icon: '✓',
+ message: 'Your balance has been credited successfully.',
+ }
: { label: '充值成功', color: 'text-green-600', icon: '✓', message: '余额已成功到账!' };
}
if (order.paymentSuccess) {
if (order.rechargeStatus === 'paid_pending' || order.rechargeStatus === 'recharging') {
return locale === 'en'
- ? { label: 'Top-up Processing', color: 'text-blue-600', icon: '⟳', message: 'Payment succeeded, and the balance top-up is being processed.' }
+ ? {
+ label: 'Top-up Processing',
+ color: 'text-blue-600',
+ icon: '⟳',
+ message: 'Payment succeeded, and the balance top-up is being processed.',
+ }
: { label: '充值处理中', color: 'text-blue-600', icon: '⟳', message: '支付成功,余额正在充值中...' };
}
if (order.rechargeStatus === 'failed') {
return locale === 'en'
- ? { label: 'Payment Successful', color: 'text-amber-600', icon: '!', message: 'Payment succeeded, but the balance top-up has not completed yet. Please check again later or contact the administrator.' }
- : { label: '支付成功', color: 'text-amber-600', icon: '!', message: '支付成功,但余额充值暂未完成,请稍后查看订单结果或联系管理员。' };
+ ? {
+ label: 'Payment Successful',
+ color: 'text-amber-600',
+ icon: '!',
+ message:
+ 'Payment succeeded, but the balance top-up has not completed yet. Please check again later or contact the administrator.',
+ }
+ : {
+ label: '支付成功',
+ color: 'text-amber-600',
+ icon: '!',
+ message: '支付成功,但余额充值暂未完成,请稍后查看订单结果或联系管理员。',
+ };
}
}
@@ -90,7 +122,12 @@ function getStatusConfig(order: PublicOrderStatusSnapshot | null, locale: Locale
if (order.status === 'EXPIRED') {
return locale === 'en'
- ? { label: 'Order Expired', color: 'text-gray-500', icon: '⏰', message: 'This order has expired. Please create a new order.' }
+ ? {
+ label: 'Order Expired',
+ color: 'text-gray-500',
+ icon: '⏰',
+ message: 'This order has expired. Please create a new order.',
+ }
: { label: '订单已超时', color: 'text-gray-500', icon: '⏰', message: '订单已超时,请重新充值。' };
}
@@ -224,11 +261,7 @@ function ResultContent() {
)
) : (
-
);
@@ -331,9 +342,7 @@ export default function PaymentForm({
{locale === 'en'
diff --git a/src/components/PaymentQRCode.tsx b/src/components/PaymentQRCode.tsx
index 28118e0..cbda0fc 100644
--- a/src/components/PaymentQRCode.tsx
+++ b/src/components/PaymentQRCode.tsx
@@ -4,12 +4,7 @@ import { useEffect, useMemo, useState, useCallback, useRef } from 'react';
import QRCode from 'qrcode';
import type { Locale } from '@/lib/locale';
import type { PublicOrderStatusSnapshot } from '@/lib/order/status';
-import {
- isStripeType,
- getPaymentMeta,
- getPaymentIconSrc,
- getPaymentChannelLabel,
-} from '@/lib/pay-utils';
+import { isStripeType, getPaymentMeta, getPaymentIconSrc, getPaymentChannelLabel } from '@/lib/pay-utils';
import { buildOrderStatusUrl } from '@/lib/order/status-url';
import { TERMINAL_STATUSES } from '@/lib/constants';
@@ -84,24 +79,38 @@ export default function PaymentQRCode({
scanPay: locale === 'en' ? 'Please scan with your payment app' : '请使用支付应用扫码支付',
back: locale === 'en' ? 'Back' : '返回',
cancelOrder: locale === 'en' ? 'Cancel Order' : '取消订单',
- h5Hint: locale === 'en' ? 'After payment, please return to this page. The system will confirm automatically.' : '支付完成后请返回此页面,系统将自动确认',
+ h5Hint:
+ locale === 'en'
+ ? 'After payment, please return to this page. The system will confirm automatically.'
+ : '支付完成后请返回此页面,系统将自动确认',
paid: locale === 'en' ? 'Order Paid' : '订单已支付',
paidCancelBlocked:
- locale === 'en' ? 'This order has already been paid and cannot be cancelled. The recharge will be credited automatically.' : '该订单已支付完成,无法取消。充值将自动到账。',
+ locale === 'en'
+ ? 'This order has already been paid and cannot be cancelled. The recharge will be credited automatically.'
+ : '该订单已支付完成,无法取消。充值将自动到账。',
backToRecharge: locale === 'en' ? 'Back to Recharge' : '返回充值',
credited: locale === 'en' ? 'Credited ¥' : '到账 ¥',
- stripeLoadFailed: locale === 'en' ? 'Failed to load payment component. Please refresh and try again.' : '支付组件加载失败,请刷新页面重试',
- initFailed: locale === 'en' ? 'Payment initialization failed. Please go back and try again.' : '支付初始化失败,请返回重试',
+ stripeLoadFailed:
+ locale === 'en'
+ ? 'Failed to load payment component. Please refresh and try again.'
+ : '支付组件加载失败,请刷新页面重试',
+ initFailed:
+ locale === 'en' ? 'Payment initialization failed. Please go back and try again.' : '支付初始化失败,请返回重试',
loadingForm: locale === 'en' ? 'Loading payment form...' : '正在加载支付表单...',
payFailed: locale === 'en' ? 'Payment failed. Please try again.' : '支付失败,请重试',
successProcessing: locale === 'en' ? 'Payment successful, processing your order...' : '支付成功,正在处理订单...',
processing: locale === 'en' ? 'Processing...' : '处理中...',
payNow: locale === 'en' ? 'Pay' : '支付',
popupBlocked:
- locale === 'en' ? 'Popup was blocked by your browser. Please allow popups for this site and try again.' : '弹出窗口被浏览器拦截,请允许本站弹出窗口后重试',
+ locale === 'en'
+ ? 'Popup was blocked by your browser. Please allow popups for this site and try again.'
+ : '弹出窗口被浏览器拦截,请允许本站弹出窗口后重试',
redirectingPrefix: locale === 'en' ? 'Redirecting to ' : '正在跳转到',
redirectingSuffix: locale === 'en' ? '...' : '...',
- redirectRetryHint: locale === 'en' ? 'If the payment app does not open automatically, go back and try again.' : '如未自动拉起支付应用,请返回上一页后重新发起支付。',
+ redirectRetryHint:
+ locale === 'en'
+ ? 'If the payment app does not open automatically, go back and try again.'
+ : '如未自动拉起支付应用,请返回上一页后重新发起支付。',
notRedirectedPrefix: locale === 'en' ? 'Not redirected? Open ' : '未跳转?点击前往',
goPaySuffix: locale === 'en' ? '' : '',
gotoPrefix: locale === 'en' ? 'Open ' : '前往',
@@ -327,8 +336,7 @@ export default function PaymentQRCode({
onStatusChange(data);
}
}
- } catch {
- }
+ } catch {}
}, [orderId, onStatusChange, statusAccessToken]);
useEffect(() => {
@@ -372,8 +380,7 @@ export default function PaymentQRCode({
} else {
await pollStatus();
}
- } catch {
- }
+ } catch {}
};
const meta = getPaymentMeta(paymentType || 'alipay');
@@ -412,7 +419,9 @@ export default function PaymentQRCode({
{amount.toFixed(2)}
)}
-
+
{expired ? t.expired : `${t.remaining}: ${timeLeft}`}
@@ -428,9 +437,7 @@ export default function PaymentQRCode({
dark ? 'border-slate-700' : 'border-gray-300',
].join(' ')}
>
-
- {t.initFailed}
-
+ {t.initFailed}
) : !stripeLoaded ? (
@@ -440,10 +447,14 @@ export default function PaymentQRCode({
) : stripeError && !stripeLib ? (
- {stripeError}
+
+ {stripeError}
+
) : (
<>
{stripeSubmitting ? (
@@ -505,7 +514,10 @@ export default function PaymentQRCode({
) : shouldAutoRedirect ? (
<>
-
+
{`${t.redirectingPrefix}${channelLabel}${t.redirectingSuffix}`}
@@ -517,11 +529,11 @@ export default function PaymentQRCode({
className={`flex w-full items-center justify-center gap-2 rounded-lg py-3 font-medium text-white shadow-md ${meta.buttonClass}`}
>
{iconSrc &&

}
- {redirected ? `${t.notRedirectedPrefix}${channelLabel}` : `${t.gotoPrefix}${channelLabel}${t.gotoSuffix}`}
+ {redirected
+ ? `${t.notRedirectedPrefix}${channelLabel}`
+ : `${t.gotoPrefix}${channelLabel}${t.gotoSuffix}`}
-
- {t.h5Hint}
-
+
{t.h5Hint}
>
) : (
<>
@@ -584,9 +596,7 @@ export default function PaymentQRCode({
onClick={handleCancel}
className={[
'flex-1 rounded-lg border py-2 text-sm',
- dark
- ? 'border-red-700 text-red-400 hover:bg-red-900/30'
- : 'border-red-300 text-red-600 hover:bg-red-50',
+ dark ? 'border-red-700 text-red-400 hover:bg-red-900/30' : 'border-red-300 text-red-600 hover:bg-red-50',
].join(' ')}
>
{t.cancelOrder}
diff --git a/src/components/admin/DailyChart.tsx b/src/components/admin/DailyChart.tsx
index 4d7a7e7..997d180 100644
--- a/src/components/admin/DailyChart.tsx
+++ b/src/components/admin/DailyChart.tsx
@@ -85,7 +85,9 @@ export default function DailyChart({ data, dark, locale = 'zh' }: DailyChartProp
{chartTitle}
-
{emptyText}
+
+ {emptyText}
+
);
}
@@ -121,7 +123,11 @@ export default function DailyChart({ data, dark, locale = 'zh' }: DailyChartProp
tickLine={false}
width={60}
/>
-
} />
+
+ }
+ />
- {currency}{entry.totalAmount.toLocaleString()}
+ {currency}
+ {entry.totalAmount.toLocaleString()}
{entry.orderCount} |
diff --git a/src/components/admin/OrderDetail.tsx b/src/components/admin/OrderDetail.tsx
index e0c916c..317d482 100644
--- a/src/components/admin/OrderDetail.tsx
+++ b/src/components/admin/OrderDetail.tsx
@@ -49,77 +49,78 @@ interface OrderDetailProps {
export default function OrderDetail({ order, onClose, dark, locale = 'zh' }: OrderDetailProps) {
const currency = locale === 'en' ? '$' : '¥';
- const text = locale === 'en'
- ? {
- title: 'Order Details',
- auditLogs: 'Audit Logs',
- operator: 'Operator',
- emptyLogs: 'No logs',
- close: 'Close',
- yes: 'Yes',
- no: 'No',
- orderId: 'Order ID',
- userId: 'User ID',
- userName: 'Username',
- email: 'Email',
- amount: 'Amount',
- status: 'Status',
- paymentSuccess: 'Payment Success',
- rechargeSuccess: 'Recharge Success',
- rechargeStatus: 'Recharge Status',
- paymentChannel: 'Payment Channel',
- provider: 'Provider',
- rechargeCode: 'Recharge Code',
- paymentTradeNo: 'Payment Trade No.',
- clientIp: 'Client IP',
- sourceHost: 'Source Host',
- sourcePage: 'Source Page',
- createdAt: 'Created At',
- expiresAt: 'Expires At',
- paidAt: 'Paid At',
- completedAt: 'Completed At',
- failedAt: 'Failed At',
- failedReason: 'Failure Reason',
- refundAmount: 'Refund Amount',
- refundReason: 'Refund Reason',
- refundAt: 'Refunded At',
- forceRefund: 'Force Refund',
- }
- : {
- title: '订单详情',
- auditLogs: '审计日志',
- operator: '操作者',
- emptyLogs: '暂无日志',
- close: '关闭',
- yes: '是',
- no: '否',
- orderId: '订单号',
- userId: '用户ID',
- userName: '用户名',
- email: '邮箱',
- amount: '金额',
- status: '状态',
- paymentSuccess: '支付成功',
- rechargeSuccess: '充值成功',
- rechargeStatus: '充值状态',
- paymentChannel: '支付渠道',
- provider: '提供商',
- rechargeCode: '充值码',
- paymentTradeNo: '支付单号',
- clientIp: '客户端IP',
- sourceHost: '来源域名',
- sourcePage: '来源页面',
- createdAt: '创建时间',
- expiresAt: '过期时间',
- paidAt: '支付时间',
- completedAt: '完成时间',
- failedAt: '失败时间',
- failedReason: '失败原因',
- refundAmount: '退款金额',
- refundReason: '退款原因',
- refundAt: '退款时间',
- forceRefund: '强制退款',
- };
+ const text =
+ locale === 'en'
+ ? {
+ title: 'Order Details',
+ auditLogs: 'Audit Logs',
+ operator: 'Operator',
+ emptyLogs: 'No logs',
+ close: 'Close',
+ yes: 'Yes',
+ no: 'No',
+ orderId: 'Order ID',
+ userId: 'User ID',
+ userName: 'Username',
+ email: 'Email',
+ amount: 'Amount',
+ status: 'Status',
+ paymentSuccess: 'Payment Success',
+ rechargeSuccess: 'Recharge Success',
+ rechargeStatus: 'Recharge Status',
+ paymentChannel: 'Payment Channel',
+ provider: 'Provider',
+ rechargeCode: 'Recharge Code',
+ paymentTradeNo: 'Payment Trade No.',
+ clientIp: 'Client IP',
+ sourceHost: 'Source Host',
+ sourcePage: 'Source Page',
+ createdAt: 'Created At',
+ expiresAt: 'Expires At',
+ paidAt: 'Paid At',
+ completedAt: 'Completed At',
+ failedAt: 'Failed At',
+ failedReason: 'Failure Reason',
+ refundAmount: 'Refund Amount',
+ refundReason: 'Refund Reason',
+ refundAt: 'Refunded At',
+ forceRefund: 'Force Refund',
+ }
+ : {
+ title: '订单详情',
+ auditLogs: '审计日志',
+ operator: '操作者',
+ emptyLogs: '暂无日志',
+ close: '关闭',
+ yes: '是',
+ no: '否',
+ orderId: '订单号',
+ userId: '用户ID',
+ userName: '用户名',
+ email: '邮箱',
+ amount: '金额',
+ status: '状态',
+ paymentSuccess: '支付成功',
+ rechargeSuccess: '充值成功',
+ rechargeStatus: '充值状态',
+ paymentChannel: '支付渠道',
+ provider: '提供商',
+ rechargeCode: '充值码',
+ paymentTradeNo: '支付单号',
+ clientIp: '客户端IP',
+ sourceHost: '来源域名',
+ sourcePage: '来源页面',
+ createdAt: '创建时间',
+ expiresAt: '过期时间',
+ paidAt: '支付时间',
+ completedAt: '完成时间',
+ failedAt: '失败时间',
+ failedReason: '失败原因',
+ refundAmount: '退款金额',
+ refundReason: '退款原因',
+ refundAt: '退款时间',
+ forceRefund: '强制退款',
+ };
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
diff --git a/src/components/admin/OrderTable.tsx b/src/components/admin/OrderTable.tsx
index 465463c..5ce4c3b 100644
--- a/src/components/admin/OrderTable.tsx
+++ b/src/components/admin/OrderTable.tsx
@@ -32,37 +32,38 @@ interface OrderTableProps {
export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, dark, locale = 'zh' }: OrderTableProps) {
const currency = locale === 'en' ? '$' : '¥';
- const text = locale === 'en'
- ? {
- orderId: 'Order ID',
- userName: 'Username',
- email: 'Email',
- notes: 'Notes',
- amount: 'Amount',
- status: 'Status',
- paymentMethod: 'Payment',
- source: 'Source',
- createdAt: 'Created At',
- actions: 'Actions',
- retry: 'Retry',
- cancel: 'Cancel',
- empty: 'No orders',
- }
- : {
- orderId: '订单号',
- userName: '用户名',
- email: '邮箱',
- notes: '备注',
- amount: '金额',
- status: '状态',
- paymentMethod: '支付方式',
- source: '来源',
- createdAt: '创建时间',
- actions: '操作',
- retry: '重试',
- cancel: '取消',
- empty: '暂无订单',
- };
+ const text =
+ locale === 'en'
+ ? {
+ orderId: 'Order ID',
+ userName: 'Username',
+ email: 'Email',
+ notes: 'Notes',
+ amount: 'Amount',
+ status: 'Status',
+ paymentMethod: 'Payment',
+ source: 'Source',
+ createdAt: 'Created At',
+ actions: 'Actions',
+ retry: 'Retry',
+ cancel: 'Cancel',
+ empty: 'No orders',
+ }
+ : {
+ orderId: '订单号',
+ userName: '用户名',
+ email: '邮箱',
+ notes: '备注',
+ amount: '金额',
+ status: '状态',
+ paymentMethod: '支付方式',
+ source: '来源',
+ createdAt: '创建时间',
+ actions: '操作',
+ retry: '重试',
+ cancel: '取消',
+ empty: '暂无订单',
+ };
const thCls = `px-4 py-3 text-left text-xs font-medium uppercase ${dark ? 'text-slate-400' : 'text-gray-500'}`;
const tdMuted = `whitespace-nowrap px-4 py-3 text-sm ${dark ? 'text-slate-400' : 'text-gray-500'}`;
@@ -133,7 +134,8 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, da
{order.userEmail || '-'} |
{order.userNotes || '-'} |
- {currency}{order.amount.toFixed(2)}
+ {currency}
+ {order.amount.toFixed(2)}
|
-
- {title}
-
+ {title}
{data.map((method) => {
const meta = getPaymentMeta(method.paymentType);
@@ -56,7 +54,8 @@ export default function PaymentMethodChart({ data, dark, locale = 'zh' }: Paymen
{label}
- {currency}{method.amount.toLocaleString()} · {method.percentage}%
+ {currency}
+ {method.amount.toLocaleString()} · {method.percentage}%
diff --git a/src/components/admin/RefundDialog.tsx b/src/components/admin/RefundDialog.tsx
index 93ce537..25dd66a 100644
--- a/src/components/admin/RefundDialog.tsx
+++ b/src/components/admin/RefundDialog.tsx
@@ -74,10 +74,7 @@ export default function RefundDialog({
return (
e.stopPropagation()}
>
{text.title}
@@ -90,7 +87,10 @@ export default function RefundDialog({
{text.amount}
- {currency}{amount.toFixed(2)}
+
+ {currency}
+ {amount.toFixed(2)}
+
{warning && (
diff --git a/src/lib/alipay/codec.ts b/src/lib/alipay/codec.ts
index 8ab0c9a..5aa591a 100644
--- a/src/lib/alipay/codec.ts
+++ b/src/lib/alipay/codec.ts
@@ -4,7 +4,10 @@ const BODY_CHARSET_RE = /(?:^|&)charset=([^&]+)/i;
function normalizeCharset(charset: string | null | undefined): string | null {
if (!charset) return null;
- const normalized = charset.trim().replace(/^['"]|['"]$/g, '').toLowerCase();
+ const normalized = charset
+ .trim()
+ .replace(/^['"]|['"]$/g, '')
+ .toLowerCase();
if (!normalized) return null;
switch (normalized) {
@@ -67,9 +70,7 @@ export function decodeAlipayPayload(rawBody: string | Buffer, headers: Record , privateKey: string)
/** 用支付宝公钥验证签名(回调验签:排除 sign 和 sign_type) */
export function verifySign(params: Record, alipayPublicKey: string, sign: string): boolean {
const filtered = Object.entries(params)
- .filter(([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null)
+ .filter(
+ ([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null,
+ )
.sort(([a], [b]) => a.localeCompare(b));
const signStr = filtered.map(([key, value]) => `${key}=${value}`).join('&');
diff --git a/src/lib/order/service.ts b/src/lib/order/service.ts
index 442b5c8..ea05a4d 100644
--- a/src/lib/order/service.ts
+++ b/src/lib/order/service.ts
@@ -62,7 +62,11 @@ export async function createOrder(input: CreateOrderInput): Promise= MAX_PENDING_ORDERS) {
throw new OrderError(
'TOO_MANY_PENDING',
- message(locale, `待支付订单过多(最多 ${MAX_PENDING_ORDERS} 笔)`, `Too many pending orders (${MAX_PENDING_ORDERS})`),
+ message(
+ locale,
+ `待支付订单过多(最多 ${MAX_PENDING_ORDERS} 笔)`,
+ `Too many pending orders (${MAX_PENDING_ORDERS})`,
+ ),
429,
);
}
@@ -228,13 +232,21 @@ export async function createOrder(input: CreateOrderInput): Promise {
function assertRetryAllowed(order: { status: string; paidAt: Date | null }, locale: Locale): void {
if (!order.paidAt) {
- throw new OrderError('INVALID_STATUS', message(locale, '订单未支付,不允许重试', 'Order is not paid, retry denied'), 400);
+ throw new OrderError(
+ 'INVALID_STATUS',
+ message(locale, '订单未支付,不允许重试', 'Order is not paid, retry denied'),
+ 400,
+ );
}
if (isRefundStatus(order.status)) {
- throw new OrderError('INVALID_STATUS', message(locale, '退款相关订单不允许重试', 'Refund-related order cannot retry'), 400);
+ throw new OrderError(
+ 'INVALID_STATUS',
+ message(locale, '退款相关订单不允许重试', 'Refund-related order cannot retry'),
+ 400,
+ );
}
if (order.status === ORDER_STATUS.FAILED || order.status === ORDER_STATUS.PAID) {
@@ -586,14 +603,22 @@ function assertRetryAllowed(order: { status: string; paidAt: Date | null }, loca
}
if (order.status === ORDER_STATUS.RECHARGING) {
- throw new OrderError('CONFLICT', message(locale, '订单正在充值中,请稍后重试', 'Order is recharging, retry later'), 409);
+ throw new OrderError(
+ 'CONFLICT',
+ message(locale, '订单正在充值中,请稍后重试', 'Order is recharging, retry later'),
+ 409,
+ );
}
if (order.status === ORDER_STATUS.COMPLETED) {
throw new OrderError('INVALID_STATUS', message(locale, '订单已完成', 'Order already completed'), 400);
}
- throw new OrderError('INVALID_STATUS', message(locale, '仅已支付和失败订单允许重试', 'Only paid and failed orders can retry'), 400);
+ throw new OrderError(
+ 'INVALID_STATUS',
+ message(locale, '仅已支付和失败订单允许重试', 'Only paid and failed orders can retry'),
+ 400,
+ );
}
export async function retryRecharge(orderId: string, locale: Locale = 'zh'): Promise {
@@ -638,7 +663,11 @@ export async function retryRecharge(orderId: string, locale: Locale = 'zh'): Pro
const derived = deriveOrderState(latest);
if (derived.rechargeStatus === 'recharging' || latest.status === ORDER_STATUS.PAID) {
- throw new OrderError('CONFLICT', message(locale, '订单正在充值中,请稍后重试', 'Order is recharging, retry later'), 409);
+ throw new OrderError(
+ 'CONFLICT',
+ message(locale, '订单正在充值中,请稍后重试', 'Order is recharging, retry later'),
+ 409,
+ );
}
if (derived.rechargeStatus === 'success') {
@@ -646,10 +675,18 @@ export async function retryRecharge(orderId: string, locale: Locale = 'zh'): Pro
}
if (isRefundStatus(latest.status)) {
- throw new OrderError('INVALID_STATUS', message(locale, '退款相关订单不允许重试', 'Refund-related order cannot retry'), 400);
+ throw new OrderError(
+ 'INVALID_STATUS',
+ message(locale, '退款相关订单不允许重试', 'Refund-related order cannot retry'),
+ 400,
+ );
}
- throw new OrderError('CONFLICT', message(locale, '订单状态已变更,请刷新后重试', 'Order status changed, refresh and retry'), 409);
+ throw new OrderError(
+ 'CONFLICT',
+ message(locale, '订单状态已变更,请刷新后重试', 'Order status changed, refresh and retry'),
+ 409,
+ );
}
await prisma.auditLog.create({
@@ -682,7 +719,11 @@ export async function processRefund(input: RefundInput): Promise {
const order = await prisma.order.findUnique({ where: { id: input.orderId } });
if (!order) throw new OrderError('NOT_FOUND', message(locale, '订单不存在', 'Order not found'), 404);
if (order.status !== ORDER_STATUS.COMPLETED) {
- throw new OrderError('INVALID_STATUS', message(locale, '仅已完成订单允许退款', 'Only completed orders can be refunded'), 400);
+ throw new OrderError(
+ 'INVALID_STATUS',
+ message(locale, '仅已完成订单允许退款', 'Only completed orders can be refunded'),
+ 400,
+ );
}
const rechargeAmount = Number(order.amount);
@@ -716,7 +757,11 @@ export async function processRefund(input: RefundInput): Promise {
data: { status: ORDER_STATUS.REFUNDING },
});
if (lockResult.count === 0) {
- throw new OrderError('CONFLICT', message(locale, '订单状态已变更,请刷新后重试', 'Order status changed, refresh and retry'), 409);
+ throw new OrderError(
+ 'CONFLICT',
+ message(locale, '订单状态已变更,请刷新后重试', 'Order status changed, refresh and retry'),
+ 409,
+ );
}
try {
diff --git a/src/lib/order/status.ts b/src/lib/order/status.ts
index 30a9fe8..b87475e 100644
--- a/src/lib/order/status.ts
+++ b/src/lib/order/status.ts
@@ -101,7 +101,8 @@ export function getOrderDisplayState(
label: '支付成功',
color: 'text-amber-600',
icon: '!',
- message: '支付已完成,但余额充值暂未完成。系统可能会自动重试,请稍后在订单列表查看;如长时间未到账请联系管理员。',
+ message:
+ '支付已完成,但余额充值暂未完成。系统可能会自动重试,请稍后在订单列表查看;如长时间未到账请联系管理员。',
};
}
}
diff --git a/src/lib/pay-utils.ts b/src/lib/pay-utils.ts
index 6b349e0..902b70d 100644
--- a/src/lib/pay-utils.ts
+++ b/src/lib/pay-utils.ts
@@ -1,9 +1,4 @@
-import {
- ORDER_STATUS,
- PAYMENT_TYPE,
- PAYMENT_PREFIX,
- REDIRECT_PAYMENT_TYPES,
-} from './constants';
+import { ORDER_STATUS, PAYMENT_TYPE, PAYMENT_PREFIX, REDIRECT_PAYMENT_TYPES } from './constants';
import type { Locale } from './locale';
export interface UserInfo {
@@ -211,7 +206,10 @@ export function getPaymentTypeLabel(type: string, locale: Locale = 'zh'): string
return locale === 'en' ? `${meta.label} (${meta.provider})` : `${meta.label}(${meta.provider})`;
}
-export function getPaymentDisplayInfo(type: string, locale: Locale = 'zh'): { channel: string; provider: string; sublabel?: string } {
+export function getPaymentDisplayInfo(
+ type: string,
+ locale: Locale = 'zh',
+): { channel: string; provider: string; sublabel?: string } {
const meta = getPaymentText(type, locale);
return { channel: meta.label, provider: meta.provider, sublabel: meta.sublabel };
}
diff --git a/src/lib/sub2api/client.ts b/src/lib/sub2api/client.ts
index 814a62e..1e1e8d8 100644
--- a/src/lib/sub2api/client.ts
+++ b/src/lib/sub2api/client.ts
@@ -125,12 +125,7 @@ export async function subtractBalance(
}
}
-export async function addBalance(
- userId: number,
- amount: number,
- notes: string,
- idempotencyKey: string,
-): Promise {
+export async function addBalance(userId: number, amount: number, notes: string, idempotencyKey: string): Promise {
const env = getEnv();
const response = await fetch(`${env.SUB2API_BASE_URL}/api/v1/admin/users/${userId}/balance`, {
method: 'POST',
|