feat(client): 购买页三档 + 支付页 render_type 多态(crypto/redirect/qr 预留)+ 导航接线
购买页三档 pro(月/季/年,金额来自 GET /v1/pay/catalog)选档 → 选支付方式 → 下单; 支付页按 session.render_type 多态渲染(crypto_address 地址+精确金额+复制、redirect 外链拉起、qr 预留复制兜底),轮询用 Task 6 的 paymentFlowProvider,409 CURRENCY_MISMATCH 走「换方式开新单」。同时收口 paymentFlowProvider 非 autoDispose 带来的轮询生命周期缺口——支付页 dispose 时停轮询(cancel() 延后到微任务执行,避免 在自身 unmount 期间同步改 state 炸 Riverpod 断言)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
@@ -9,6 +9,8 @@ import '../screens/account_page.dart';
|
||||
import '../screens/connect_page.dart';
|
||||
import '../screens/contact_page.dart';
|
||||
import '../screens/nodes_page.dart';
|
||||
import '../screens/payment_page.dart';
|
||||
import '../screens/purchase_page.dart';
|
||||
import '../screens/settings_page.dart';
|
||||
import '../screens/stats_page.dart';
|
||||
import '../state/app_providers.dart';
|
||||
@@ -46,6 +48,8 @@ class DesktopShell extends ConsumerWidget {
|
||||
NavView.plans: t.choosePlan,
|
||||
NavView.redeem: t.redeemTitle,
|
||||
NavView.devices: t.myDevices,
|
||||
NavView.purchase: t.purchaseTitle,
|
||||
NavView.payment: t.paymentTitle,
|
||||
};
|
||||
|
||||
void go(NavView v) => ref.read(navViewProvider.notifier).state = v;
|
||||
@@ -66,15 +70,27 @@ class DesktopShell extends ConsumerWidget {
|
||||
return const SettingsPage();
|
||||
// 账户下钻子页(内容区,顶栏带返回)
|
||||
case NavView.plans:
|
||||
return PlansScreen(t: t, embedded: true, onChoose: (_) => go(NavView.redeem));
|
||||
// 只有 pro 走 pay v2 购买通道;team 等仍走既有兑换/联系人工流程。
|
||||
return PlansScreen(t: t, embedded: true, onChoose: (code) => go(code == 'pro' ? NavView.purchase : NavView.redeem));
|
||||
case NavView.redeem:
|
||||
return RedeemScreen(t: t, embedded: true);
|
||||
case NavView.devices:
|
||||
return DevicesScreen(t: t, embedded: true);
|
||||
case NavView.purchase:
|
||||
return PurchaseScreen(t: t, embedded: true, onOrderCreated: () => go(NavView.payment));
|
||||
case NavView.payment:
|
||||
return PaymentScreen(t: t, embedded: true, onDone: () => go(NavView.account));
|
||||
}
|
||||
}
|
||||
|
||||
final isSub = kAccountSubViews.contains(view);
|
||||
// 子页返回目标:payment → purchase(换方式/失败重试仍在购买语境内);
|
||||
// 其余下钻子页(含 purchase 本身)→ account。
|
||||
VoidCallback? backTarget() {
|
||||
if (view == NavView.payment) return () => go(NavView.purchase);
|
||||
if (kAccountSubViews.contains(view)) return () => go(NavView.account);
|
||||
return null;
|
||||
}
|
||||
|
||||
return ColoredBox(
|
||||
color: c.bg,
|
||||
child: Row(children: [
|
||||
@@ -83,7 +99,7 @@ class DesktopShell extends ConsumerWidget {
|
||||
child: Column(children: [
|
||||
ContentTopBar(
|
||||
title: titles[view] ?? t.brand,
|
||||
onBack: isSub ? () => go(NavView.account) : null,
|
||||
onBack: backTarget(),
|
||||
),
|
||||
Expanded(child: content()),
|
||||
]),
|
||||
|
||||
Reference in New Issue
Block a user