style: prettier 格式修复

This commit is contained in:
erio
2026-04-03 02:18:10 +08:00
parent 193d98d1cd
commit df16796ee8
8 changed files with 77 additions and 61 deletions
@@ -98,9 +98,7 @@ describe('POST /api/admin/refund', () => {
});
it('passes reason correctly', async () => {
const res = await POST(
createRequest({ order_id: 'order-004', reason: '用户申请退款' }),
);
const res = await POST(createRequest({ order_id: 'order-004', reason: '用户申请退款' }));
expect(res.status).toBe(200);
expect(mockProcessRefund).toHaveBeenCalledWith(
expect.objectContaining({
@@ -258,7 +258,7 @@ describe('GET /api/orders/my - canRefundRequest', () => {
const res = await GET(createRequest());
const data = await res.json();
expect(data.orders[0].canRefundRequest).toBe(true); // balance + COMPLETED + refundEnabled
expect(data.orders[0].canRefundRequest).toBe(true); // balance + COMPLETED + refundEnabled
expect(data.orders[1].canRefundRequest).toBe(false); // subscription
expect(data.orders[2].canRefundRequest).toBe(false); // PENDING
});
+16 -36
View File
@@ -289,9 +289,7 @@ describe('processRefund', () => {
mockOrderFindUnique.mockResolvedValue(order);
// 用户有一个 group_id=10 的活跃订阅,剩余 60 天
const expiresAt = new Date(Date.now() + 60 * 24 * 60 * 60 * 1000).toISOString();
mockGetUserSubscriptions.mockResolvedValue([
{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt },
]);
mockGetUserSubscriptions.mockResolvedValue([{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt }]);
const result = await processRefund({ orderId: 'order-001', deductBalance: true });
@@ -306,9 +304,7 @@ describe('processRefund', () => {
mockOrderFindUnique.mockResolvedValue(order);
// 仅剩 10 天
const expiresAt = new Date(Date.now() + 10 * 24 * 60 * 60 * 1000).toISOString();
mockGetUserSubscriptions.mockResolvedValue([
{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt },
]);
mockGetUserSubscriptions.mockResolvedValue([{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt }]);
const result = await processRefund({ orderId: 'order-001', deductBalance: true });
@@ -391,9 +387,7 @@ describe('processRefund', () => {
const order = makeSubscriptionOrder();
mockOrderFindUnique.mockResolvedValue(order);
const expiresAt = new Date(Date.now() + 60 * 24 * 60 * 60 * 1000).toISOString();
mockGetUserSubscriptions.mockResolvedValue([
{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt },
]);
mockGetUserSubscriptions.mockResolvedValue([{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt }]);
mockProviderRefund.mockRejectedValue(new Error('gateway error'));
await expect(processRefund({ orderId: 'order-001' })).rejects.toThrow('gateway error');
@@ -463,7 +457,8 @@ describe('processRefund', () => {
// detail 应包含回滚失败信息
const rollbackCall = mockAuditLogCreate.mock.calls.find(
(call: unknown[]) => ((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_ROLLBACK_FAILED',
(call: unknown[]) =>
((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_ROLLBACK_FAILED',
);
expect(rollbackCall).toBeTruthy();
const detail = JSON.parse((rollbackCall![0] as { data: { detail: string } }).data.detail);
@@ -485,9 +480,7 @@ describe('processRefund', () => {
const order = makeSubscriptionOrder();
mockOrderFindUnique.mockResolvedValue(order);
const expiresAt = new Date(Date.now() + 60 * 24 * 60 * 60 * 1000).toISOString();
mockGetUserSubscriptions.mockResolvedValue([
{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt },
]);
mockGetUserSubscriptions.mockResolvedValue([{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt }]);
mockProviderRefund.mockRejectedValue(new Error('gateway fail'));
// 第一次 extendSubscription(-30) 成功,第二次 extendSubscription(30) 失败
mockExtendSubscription
@@ -513,7 +506,8 @@ describe('processRefund', () => {
expect(completedCalls).toHaveLength(0);
const rollbackCall = mockAuditLogCreate.mock.calls.find(
(call: unknown[]) => ((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_ROLLBACK_FAILED',
(call: unknown[]) =>
((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_ROLLBACK_FAILED',
);
expect(rollbackCall).toBeTruthy();
const detail = JSON.parse((rollbackCall![0] as { data: { detail: string } }).data.detail);
@@ -562,9 +556,7 @@ describe('processRefund', () => {
const order = makeSubscriptionOrder();
mockOrderFindUnique.mockResolvedValue(order);
const expiresAt = new Date(Date.now() + 60 * 24 * 60 * 60 * 1000).toISOString();
mockGetUserSubscriptions.mockResolvedValue([
{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt },
]);
mockGetUserSubscriptions.mockResolvedValue([{ id: 101, group_id: 10, status: 'active', expires_at: expiresAt }]);
await processRefund({ orderId: 'order-001', deductBalance: true });
@@ -599,9 +591,7 @@ describe('processRefund', () => {
await processRefund({ orderId: 'order-001' });
// 网关退款金额应为 amount100)
expect(mockProviderRefund).toHaveBeenCalledWith(
expect.objectContaining({ amount: 100 }),
);
expect(mockProviderRefund).toHaveBeenCalledWith(expect.objectContaining({ amount: 100 }));
});
it('通过 providerInstanceId 查询实例配置', async () => {
@@ -706,9 +696,7 @@ describe('processRefund', () => {
mockOrderFindUnique.mockResolvedValue(order);
mockProviderRefund.mockRejectedValue(new Error('gateway fail'));
await expect(
processRefund({ orderId: 'order-001', deductBalance: false }),
).rejects.toThrow('gateway fail');
await expect(processRefund({ orderId: 'order-001', deductBalance: false })).rejects.toThrow('gateway fail');
// 不应调用 addBalance 回滚
expect(mockAddBalance).not.toHaveBeenCalled();
@@ -721,9 +709,7 @@ describe('processRefund', () => {
mockOrderFindUnique.mockResolvedValue(order);
mockProviderRefund.mockRejectedValue(new Error('gateway fail'));
await expect(
processRefund({ orderId: 'order-001', deductBalance: false }),
).rejects.toThrow('gateway fail');
await expect(processRefund({ orderId: 'order-001', deductBalance: false })).rejects.toThrow('gateway fail');
// 不扣减,不回滚
expect(mockSubtractBalance).not.toHaveBeenCalled();
@@ -782,7 +768,8 @@ describe('processRefund', () => {
);
// 不应记录 REFUND_GATEWAY_FAILED
const gatewayFailedCall = mockAuditLogCreate.mock.calls.find(
(call: unknown[]) => ((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_GATEWAY_FAILED',
(call: unknown[]) =>
((call as unknown[])[0] as { data: { action: string } }).data.action === 'REFUND_GATEWAY_FAILED',
);
expect(gatewayFailedCall).toBeUndefined();
});
@@ -893,15 +880,8 @@ describe('processRefund', () => {
await processRefund({ orderId: 'order-001' });
// 网关退款使用 payAmount
expect(mockProviderRefund).toHaveBeenCalledWith(
expect.objectContaining({ amount: 105.5 }),
);
expect(mockProviderRefund).toHaveBeenCalledWith(expect.objectContaining({ amount: 105.5 }));
// 余额扣减使用 amountrechargeAmount
expect(mockSubtractBalance).toHaveBeenCalledWith(
42,
100,
expect.any(String),
expect.any(String),
);
expect(mockSubtractBalance).toHaveBeenCalledWith(42, 100, expect.any(String), expect.any(String));
});
});
+16 -2
View File
@@ -244,7 +244,9 @@ function AdminContent() {
try {
if (order.orderType === 'subscription' && order.subscriptionGroupId) {
// 订阅订单:获取用户该分组的活跃订阅剩余天数
const subsRes = await fetch(`/api/admin/subscriptions?token=${token}&user_id=${order.userId}&group_id=${order.subscriptionGroupId}&status=active`);
const subsRes = await fetch(
`/api/admin/subscriptions?token=${token}&user_id=${order.userId}&group_id=${order.subscriptionGroupId}&status=active`,
);
if (subsRes.ok) {
const subsData = await subsRes.json();
const subs = subsData.subscriptions ?? subsData.data?.items ?? [];
@@ -313,7 +315,19 @@ function AdminContent() {
}
};
const statuses = ['', 'PENDING', 'PAID', 'RECHARGING', 'COMPLETED', 'EXPIRED', 'CANCELLED', 'FAILED', 'REFUNDING', 'REFUNDED', 'REFUND_FAILED'];
const statuses = [
'',
'PENDING',
'PAID',
'RECHARGING',
'COMPLETED',
'EXPIRED',
'CANCELLED',
'FAILED',
'REFUNDING',
'REFUNDED',
'REFUND_FAILED',
];
const statusLabels: Record<string, string> = text.statuses;
const orderTypes = ['', 'balance', 'subscription'];
const orderTypeLabels: Record<string, string> = text.orderTypes;
+7 -2
View File
@@ -1039,7 +1039,10 @@ function PaymentConfigContent() {
</span>
)}
<div className="flex items-center gap-1">
<Toggle value={inst.refundEnabled} onChange={() => toggleInstanceRefundEnabled(inst)} />
<Toggle
value={inst.refundEnabled}
onChange={() => toggleInstanceRefundEnabled(inst)}
/>
<span className={`text-[10px] ${isDark ? 'text-slate-400' : 'text-slate-500'}`}>
{t.instanceRefundEnabled}
</span>
@@ -1180,7 +1183,9 @@ function PaymentConfigContent() {
<div className="flex items-center gap-2">
<Toggle
value={instanceForm.refundEnabled}
onChange={() => setInstanceForm({ ...instanceForm, refundEnabled: !instanceForm.refundEnabled })}
onChange={() =>
setInstanceForm({ ...instanceForm, refundEnabled: !instanceForm.refundEnabled })
}
/>
<span className={`text-sm ${isDark ? 'text-slate-300' : 'text-slate-700'}`}>
{t.instanceRefundEnabled}
+9 -1
View File
@@ -32,7 +32,15 @@ interface OrderTableProps {
locale?: Locale;
}
export default function OrderTable({ orders, onRetry, onCancel, onRefund, onViewDetail, dark, locale = 'zh' }: OrderTableProps) {
export default function OrderTable({
orders,
onRetry,
onCancel,
onRefund,
onViewDetail,
dark,
locale = 'zh',
}: OrderTableProps) {
const currency = locale === 'en' ? '$' : '¥';
const text =
locale === 'en'
+26 -13
View File
@@ -49,7 +49,9 @@ export default function RefundDialog({
reasonPlaceholder: 'Enter refund reason (optional)',
forceRefund: 'Force refund (ignore balance check)',
deductLabel: isSub ? 'Deduct subscription days' : 'Deduct user balance',
deductHint: isSub ? 'Reduce subscription period for this order' : 'Subtract recharged amount from user balance',
deductHint: isSub
? 'Reduce subscription period for this order'
: 'Subtract recharged amount from user balance',
userBalance: 'User Balance',
rechargeAmount: 'Recharge Amount',
subDays: 'Order Days',
@@ -101,7 +103,10 @@ export default function RefundDialog({
const balanceInsufficient = !isSub && userBalance != null && userBalance < amount;
const daysInsufficient =
isSub && subscriptionRemainingDays != null && subscriptionDays != null && subscriptionRemainingDays < subscriptionDays;
isSub &&
subscriptionRemainingDays != null &&
subscriptionDays != null &&
subscriptionRemainingDays < subscriptionDays;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
@@ -172,18 +177,20 @@ export default function RefundDialog({
{/* 不足提示 */}
{deductBalance && balanceInsufficient && (
<div
className={['rounded-lg p-3 text-sm', dark ? 'bg-amber-900/30 text-amber-300' : 'bg-amber-50 text-amber-700'].join(
' ',
)}
className={[
'rounded-lg p-3 text-sm',
dark ? 'bg-amber-900/30 text-amber-300' : 'bg-amber-50 text-amber-700',
].join(' ')}
>
{text.insufficientBalance}
</div>
)}
{deductBalance && daysInsufficient && (
<div
className={['rounded-lg p-3 text-sm', dark ? 'bg-amber-900/30 text-amber-300' : 'bg-amber-50 text-amber-700'].join(
' ',
)}
className={[
'rounded-lg p-3 text-sm',
dark ? 'bg-amber-900/30 text-amber-300' : 'bg-amber-50 text-amber-700',
].join(' ')}
>
{text.insufficientDays}
</div>
@@ -191,7 +198,10 @@ export default function RefundDialog({
{!deductBalance && (
<div
className={['rounded-lg p-3 text-sm', dark ? 'bg-blue-900/30 text-blue-300' : 'bg-blue-50 text-blue-700'].join(' ')}
className={[
'rounded-lg p-3 text-sm',
dark ? 'bg-blue-900/30 text-blue-300' : 'bg-blue-50 text-blue-700',
].join(' ')}
>
{text.noDeduction}
</div>
@@ -199,9 +209,10 @@ export default function RefundDialog({
{warning && (
<div
className={['rounded-lg p-3 text-sm', dark ? 'bg-yellow-900/30 text-yellow-300' : 'bg-yellow-50 text-yellow-700'].join(
' ',
)}
className={[
'rounded-lg p-3 text-sm',
dark ? 'bg-yellow-900/30 text-yellow-300' : 'bg-yellow-50 text-yellow-700',
].join(' ')}
>
{warning}
</div>
@@ -241,7 +252,9 @@ export default function RefundDialog({
onClick={onCancel}
className={[
'flex-1 rounded-lg border py-2 text-sm',
dark ? 'border-slate-600 text-slate-300 hover:bg-slate-800' : 'border-gray-300 text-gray-600 hover:bg-gray-50',
dark
? 'border-slate-600 text-slate-300 hover:bg-slate-800'
: 'border-gray-300 text-gray-600 hover:bg-gray-50',
].join(' ')}
>
{text.cancel}
+1 -3
View File
@@ -1161,9 +1161,7 @@ export async function processRefund(input: RefundInput): Promise<RefundResult> {
if (order.subscriptionGroupId && order.subscriptionDays) {
try {
const userSubs = await getUserSubscriptions(order.userId);
const activeSub = userSubs.find(
(s) => s.group_id === order.subscriptionGroupId && s.status === 'active',
);
const activeSub = userSubs.find((s) => s.group_id === order.subscriptionGroupId && s.status === 'active');
if (activeSub) {
const remainingDays = Math.max(
0,