From 1a0a7bd5ef86ff933ff411029193bf2e920f03fd Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Wed, 10 Jun 2026 23:50:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(client):=20=E5=B0=86=20=5FbuildLicenseBanne?= =?UTF-8?q?r/=5FshowLicenseExpiryDialog=20=E7=A7=BB=E5=9B=9E=20=5FAppShell?= =?UTF-8?q?State?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两个方法误放入 _StatusItem 类,导致 Windows CI 编译报错: - _buildLicenseBanner/showLicenseExpiryDialog 对 _AppShellState 未定义 - _StatusItem 内 context.go() 调用找不到 context getter Co-Authored-By: Claude Sonnet 4.6 --- client/lib/screens/shell/app_shell.dart | 169 ++++++++++++------------ 1 file changed, 84 insertions(+), 85 deletions(-) diff --git a/client/lib/screens/shell/app_shell.dart b/client/lib/screens/shell/app_shell.dart index bb6e356..a109c02 100644 --- a/client/lib/screens/shell/app_shell.dart +++ b/client/lib/screens/shell/app_shell.dart @@ -476,6 +476,90 @@ class _AppShellState extends ConsumerState { ), ); } + + Widget _buildLicenseBanner(LicenseInfo lic) { + final Color bg; + final String msg; + switch (lic.phase) { + case 'locked': + bg = AppTheme.danger; + msg = '授权已锁定,所有写操作已停用 — 请立即续费或激活新授权码'; + case 'readonly': + bg = const Color(0xFFB71C1C); + msg = '授权已过期,当前为只读模式(剩余宽限期 ${lic.daysRemaining ?? 0} 天后彻底锁定)'; + default: // grace + bg = const Color(0xFFE65100); + msg = '授权将于 ${lic.daysRemaining ?? 0} 天后到期,请及时续费'; + } + return Container( + width: double.infinity, + color: bg, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), + child: Row( + children: [ + const Icon(Icons.warning_amber_rounded, + size: 16, color: Colors.white), + const SizedBox(width: 8), + Expanded( + child: Text(msg, + style: const TextStyle(color: Colors.white, fontSize: 13), + overflow: TextOverflow.ellipsis), + ), + TextButton( + onPressed: () => context.go('/settings'), + style: TextButton.styleFrom(foregroundColor: Colors.white70), + child: const Text('去激活'), + ), + ], + ), + ); + } + + void _showLicenseExpiryDialog(BuildContext ctx, LicenseInfo lic) { + final String title; + final String body; + final Color titleColor; + switch (lic.phase) { + case 'locked': + title = '授权已锁定'; + body = '您的授权已到期超过 15 天,所有写操作已停用。\n请前往「设置 → 授权」激活新的授权码,或联系客服续费。'; + titleColor = AppTheme.danger; + case 'readonly': + title = '授权已过期 · 只读模式'; + body = '您的授权已过期,系统进入只读模式,无法执行任何写操作。\n到期 15 天后将彻底锁定登录,请尽快续费。'; + titleColor = AppTheme.danger; + default: // grace + title = '授权即将到期'; + body = '您的授权将在 ${lic.daysRemaining ?? 0} 天后到期,到期后系统进入只读模式。\n请提前联系客服续费,避免影响正常使用。'; + titleColor = Colors.orange[800]!; + } + showDialog( + context: ctx, + barrierDismissible: true, + builder: (_) => AlertDialog( + title: Row(children: [ + Icon(Icons.warning_amber_rounded, color: titleColor, size: 20), + const SizedBox(width: 8), + Text(title, style: TextStyle(color: titleColor, fontSize: 16)), + ]), + content: Text(body, style: const TextStyle(fontSize: 14)), + actions: [ + TextButton( + onPressed: () => Navigator.pop(_), + child: const Text('稍后处理'), + ), + ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: titleColor), + onPressed: () { + Navigator.pop(_); + ctx.go('/settings'); + }, + child: const Text('立即前往', style: TextStyle(color: Colors.white)), + ), + ], + ), + ); + } } class _NavItem { @@ -579,91 +663,6 @@ class _StatusItem extends StatelessWidget { ], ); } - - Widget _buildLicenseBanner(LicenseInfo lic) { - final Color bg; - final String msg; - switch (lic.phase) { - case 'locked': - bg = AppTheme.danger; - msg = '授权已锁定,所有写操作已停用 — 请立即续费或激活新授权码'; - case 'readonly': - bg = const Color(0xFFB71C1C); - msg = '授权已过期,当前为只读模式(剩余宽限期 ${lic.daysRemaining ?? 0} 天后彻底锁定)'; - default: // grace - bg = const Color(0xFFE65100); - msg = '授权将于 ${lic.daysRemaining ?? 0} 天后到期,请及时续费'; - } - return Container( - width: double.infinity, - color: bg, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), - child: Row( - children: [ - const Icon(Icons.warning_amber_rounded, - size: 16, color: Colors.white), - const SizedBox(width: 8), - Expanded( - child: Text(msg, - style: const TextStyle(color: Colors.white, fontSize: 13), - overflow: TextOverflow.ellipsis), - ), - TextButton( - onPressed: () => context.go('/settings'), - style: - TextButton.styleFrom(foregroundColor: Colors.white70), - child: const Text('去激活'), - ), - ], - ), - ); - } - - void _showLicenseExpiryDialog(BuildContext ctx, LicenseInfo lic) { - final String title; - final String body; - final Color titleColor; - switch (lic.phase) { - case 'locked': - title = '授权已锁定'; - body = '您的授权已到期超过 15 天,所有写操作已停用。\n请前往「设置 → 授权」激活新的授权码,或联系客服续费。'; - titleColor = AppTheme.danger; - case 'readonly': - title = '授权已过期 · 只读模式'; - body = '您的授权已过期,系统进入只读模式,无法执行任何写操作。\n到期 15 天后将彻底锁定登录,请尽快续费。'; - titleColor = AppTheme.danger; - default: // grace - title = '授权即将到期'; - body = '您的授权将在 ${lic.daysRemaining ?? 0} 天后到期,到期后系统进入只读模式。\n请提前联系客服续费,避免影响正常使用。'; - titleColor = Colors.orange[800]!; - } - showDialog( - context: ctx, - barrierDismissible: true, - builder: (_) => AlertDialog( - title: Row(children: [ - Icon(Icons.warning_amber_rounded, color: titleColor, size: 20), - const SizedBox(width: 8), - Text(title, style: TextStyle(color: titleColor, fontSize: 16)), - ]), - content: Text(body, style: const TextStyle(fontSize: 14)), - actions: [ - TextButton( - onPressed: () => Navigator.pop(_), - child: const Text('稍后处理'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom(backgroundColor: titleColor), - onPressed: () { - Navigator.pop(_); - ctx.go('/settings'); - }, - child: const Text('立即前往', style: TextStyle(color: Colors.white)), - ), - ], - ), - ); - } } class _StatusDivider extends StatelessWidget {