// screens/license/license_screen.dart — 授权管理独立一级屏(原型 license.html / // m-license.html),三 tab:授权信息 / 在线购买续费 / 订单管理。 // 桌面 `/license`、移动 `/me/license` 复用同一 Widget,内部按 context.isMobile // 切换两种形态(桌面:头部+DsSeg+卡片区;移动:通栏 DsSeg+滚动内容)。 // // tab 可见性: // - 「在线购买续费」iOS App Store 合规态(hideExternalPurchaseUi)整 tab 隐藏; // - 「订单管理」GET /license/purchases 仅管理员可用(后端判权),非管理员隐藏该 tab。 import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart'; import '../../core/auth/auth_state.dart'; import '../../core/config/store_compliance.dart'; import '../../core/responsive/responsive.dart'; import '../../core/theme/app_dims.g.dart'; import '../../core/theme/context_tokens.dart'; import '../../core/utils/money.dart'; import '../../core/utils/web_launch.dart'; import '../../providers/license_purchase_provider.dart'; import '../../widgets/ds/ds_atoms.dart'; import 'license_orders_tab.dart'; import '../settings/license_panel.dart'; import '../settings/purchase_card.dart'; import '../settings/settings_card.dart'; enum _LicSection { info, buy, orders } class LicenseScreen extends ConsumerStatefulWidget { const LicenseScreen({super.key}); @override ConsumerState createState() => _LicenseScreenState(); } class _LicenseScreenState extends ConsumerState { _LicSection _section = _LicSection.info; void _goInfo() => setState(() => _section = _LicSection.info); void _goBuy() => setState(() => _section = _LicSection.buy); @override Widget build(BuildContext context) { final t = context.tokens; final role = ref.watch(authStateProvider.select((s) => s.user?.role)); final isAdmin = role == 'admin' || role == 'superadmin'; final showBuy = !hideExternalPurchaseUi; final showOrders = isAdmin; // 当前 tab 若因权限/合规态变得不可见,回退到「授权信息」。 if ((_section == _LicSection.buy && !showBuy) || (_section == _LicSection.orders && !showOrders)) { _section = _LicSection.info; } final sections = [ _LicSection.info, if (showBuy) _LicSection.buy, if (showOrders) _LicSection.orders, ]; final mobile = context.isMobile; final segLabels = { _LicSection.info: '授权信息', _LicSection.buy: mobile ? '购买 / 续费' : '在线购买 / 续费', _LicSection.orders: '订单管理', }; Widget seg = DsSeg( items: [for (final s in sections) segLabels[s]!], index: sections.indexOf(_section).clamp(0, sections.length - 1), onChanged: (i) => setState(() => _section = sections[i]), ); Widget body = switch (_section) { _LicSection.info => _infoBody(mobile), _LicSection.buy => _buyBody(mobile, isAdmin), _LicSection.orders => LicenseOrdersTab( onGoInfo: _goInfo, onGoBuy: showBuy ? _goBuy : null, ), }; if (mobile) { return Container( color: t.bg, child: Column( children: [ Padding( padding: const EdgeInsets.fromLTRB(14, 12, 14, 0), child: Align(alignment: Alignment.centerLeft, child: seg), ), const SizedBox(height: 12), Expanded(child: body), ], ), ); } return Container( color: t.bg, padding: const EdgeInsets.fromLTRB(26, 22, 26, 22), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildHeader(context, ref, t), const SizedBox(height: 18), Align(alignment: Alignment.centerLeft, child: seg), const SizedBox(height: 18), Expanded(child: body), ], ), ); } Widget _buildHeader(BuildContext context, WidgetRef ref, dynamic t) { final sub = switch (_section) { _LicSection.info => '授权状态 · 兑换券 · 降级规则', _LicSection.buy => '选择套餐支付宝支付 · 到账自动续期', _LicSection.orders => () { final result = ref.watch(purchaseListProvider).valueOrNull; if (result == null) return '订单流水'; return '共 ${result.total} 笔 · ' '累计 ¥${yuanFromMinor(result.summary.paidTotalMinor)}'; }(), }; return Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text('授权管理', style: TextStyle( fontSize: AppDims.fsH1, fontWeight: FontWeight.w700, color: t.heading)), const SizedBox(width: AppDims.sp3), Padding( padding: const EdgeInsets.only(bottom: 2), child: Text(sub, style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)), ), const Spacer(), if (_section == _LicSection.orders) DsButton('刷新', icon: LucideIcons.refreshCw, onPressed: () => ref.read(purchaseListProvider.notifier).reload()), ], ); } Widget _infoBody(bool mobile) { final child = mobile ? const LicensePanel() : ConstrainedBox( constraints: const BoxConstraints(maxWidth: 720), child: const LicensePanel(), ); return SingleChildScrollView( padding: mobile ? const EdgeInsets.fromLTRB(14, 0, 14, 14) : EdgeInsets.zero, child: child, ); } Widget _buyBody(bool mobile, bool isAdmin) { final card = SettingsCard( title: '在线购买 / 续费', desc: isAdmin ? '选择套餐支付宝支付,到账后授权自动续期' : '在线购买仅门店管理员可操作', child: isAdmin ? const PurchaseCard() : Builder(builder: (ctx) { final t = ctx.tokens; return Row(children: [ Text('在线购买请联系门店管理员 · ', style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)), InkWell( onTap: () => launchAuthedWebPath(ref, '/#pricing'), child: Text('查看套餐价格 →', style: TextStyle( fontSize: AppDims.fsSm, fontWeight: FontWeight.w600, color: t.primary)), ), ]); }), ); final child = mobile ? card : ConstrainedBox(constraints: const BoxConstraints(maxWidth: 560), child: card); return SingleChildScrollView( padding: mobile ? const EdgeInsets.fromLTRB(14, 0, 14, 14) : EdgeInsets.zero, child: child, ); } }