修正(会员弹层):升级报价未到时不再把标准价显示为本次补付

- 新增 amountPending:升级报价缺失时金额区显示占位符,CTA 只显示「补差升级」
- 补一条回归测试覆盖报价加载中的确认页
This commit is contained in:
2026-10-04 10:32:50 +08:00
parent 93837a736d
commit 951b44b582
2 changed files with 60 additions and 6 deletions
@@ -261,6 +261,49 @@ describe('PlatformProfileRechargeModal', () => {
expect(onSubmitMembershipCheckout).toHaveBeenCalledWith('max', 'yearly');
});
test('shows a placeholder instead of the list price while the upgrade quote is loading', async () => {
const user = userEvent.setup();
render(
<PlatformProfileRechargeModal
center={{
mudPointBalance: buildMudPointBalance(615),
membership: buildActiveMembership('plus', 'yearly'),
pointProducts: buildPointProducts(),
membershipPlans: [STARTER_PLAN, PLUS_PLAN, MAX_PLAN],
latestOrder: null,
hasPointsRecharged: true,
}}
isLoading={false}
error={null}
submittingProductId={null}
nativePayment={null}
membershipQuote={null}
isLoadingMembershipQuote={true}
membershipQuoteError={null}
onClose={vi.fn()}
onRetry={vi.fn()}
onBuy={vi.fn()}
onRequestMembershipQuote={vi.fn()}
onSubmitMembershipCheckout={vi.fn()}
onConfirmNativePayment={vi.fn()}
onCloseNativePayment={vi.fn()}
/>,
);
await user.click(screen.getByRole('button', { name: 'Max 年付 补差升级' }));
const checkout = screen.getByRole('dialog', { name: '确认套餐变更' });
// 报价未到:金额占位,不能把 Max 标准年价(¥6990)当成「本次补付」。
expect(within(checkout).getByText('—')).toBeTruthy();
expect(
within(checkout).queryByRole('button', { name: /^补差升级 ¥/ }),
).toBeNull();
expect(
within(checkout).getByRole('button', { name: '补差升级' }),
).toHaveProperty('disabled', true);
});
test('recharge tab picks a point product and forwards the buy action', async () => {
const user = userEvent.setup();
const onBuy = vi.fn();
@@ -1013,9 +1013,20 @@ function PlatformRechargeCheckoutDialog({
membershipQuote.cycleKind === target.cycleKind
? membershipQuote
: null;
// 升级金额只能来自服务端报价:报价未到 / 失败时不能拿新套餐标准价冒充「本次补付」。
const amountPending = isUpgrade && !quoteForTarget;
const amountCents = quoteForTarget
? quoteForTarget.amountCents
: listPriceCents;
const amountText = amountPending ? '—' : formatRechargePrice(amountCents);
let ctaLabel: string;
if (!isUpgrade) {
ctaLabel = `支付 ${amountText}`;
} else if (amountPending) {
ctaLabel = '补差升级';
} else {
ctaLabel = `补差升级 ${amountText}`;
}
const canSubmit =
Boolean(plan) &&
!submitting &&
@@ -1072,12 +1083,9 @@ function PlatformRechargeCheckoutDialog({
title={isUpgrade ? '确认套餐变更' : '确认订单'}
submitting={submitting}
amountCents={amountCents}
amountPending={amountPending}
amountLabel={isUpgrade ? '本次补付' : '本次支付'}
ctaLabel={
isUpgrade
? `补差升级 ${formatRechargePrice(amountCents)}`
: `支付 ${formatRechargePrice(amountCents)}`
}
ctaLabel={ctaLabel}
ctaDisabled={!canSubmit}
onClose={onClose}
onSubmit={() => {
@@ -1103,6 +1111,7 @@ function PlatformRechargeCheckoutDialog({
function PlatformRechargeCheckoutShell({
title,
amountCents,
amountPending = false,
amountLabel = '本次支付',
ctaLabel,
ctaDisabled = false,
@@ -1115,6 +1124,8 @@ function PlatformRechargeCheckoutShell({
}: {
title: string;
amountCents: number;
/** 金额未知(升级报价未到 / 失败)时只显示占位符,避免拿标准价冒充补差金额。 */
amountPending?: boolean;
amountLabel?: string;
ctaLabel: string;
ctaDisabled?: boolean;
@@ -1142,7 +1153,7 @@ function PlatformRechargeCheckoutShell({
{amountLabel}
</div>
<div className="mt-1 text-3xl font-black tabular-nums text-[var(--platform-text-strong)]">
{formatRechargePrice(amountCents)}
{amountPending ? '—' : formatRechargePrice(amountCents)}
</div>
</div>
{errorState ? <div className="mt-4">{errorState}</div> : null}