From a7298b643cbf586fb08490ddae04b956a99c1000 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Thu, 25 Jun 2026 00:20:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor(client):=20=E5=BE=80=E6=9D=A5/?= =?UTF-8?q?=E8=AE=BE=E5=A4=87/=E7=99=BB=E5=BD=95/=E5=85=B3=E4=BA=8E?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E8=BF=81=E7=A7=BB=E5=88=B0=20context.tokens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- client/lib/screens/about/about_screen.dart | 16 ++--- client/lib/screens/auth/login_screen.dart | 66 +++++++++---------- .../devices/device_management_screen.dart | 58 ++++++++-------- .../lib/screens/partners/partners_screen.dart | 50 +++++++------- client/test/login_flow_test.dart | 3 +- client/test/login_screen_test.dart | 3 +- 6 files changed, 99 insertions(+), 97 deletions(-) diff --git a/client/lib/screens/about/about_screen.dart b/client/lib/screens/about/about_screen.dart index 0da6be0..4dda016 100644 --- a/client/lib/screens/about/about_screen.dart +++ b/client/lib/screens/about/about_screen.dart @@ -8,7 +8,7 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../core/config/app_config.dart'; import '../../core/config/app_info.dart'; -import '../../core/theme/app_theme.dart'; +import '../../core/theme/context_tokens.dart'; import '../../core/update/app_updater.dart'; import '../../core/utils/dialog_util.dart'; import '../../providers/feedback_provider.dart'; @@ -42,7 +42,7 @@ class _AboutScreenState extends ConsumerState { _AboutRow( label: '最新版本', value: 'v${updateInfo.latestVersion}', - valueColor: AppTheme.success, + valueColor: context.tokens.success, trailing: TextButton( onPressed: () => startInAppUpdate(context, updateInfo), child: const Text('立即更新'), @@ -52,7 +52,7 @@ class _AboutScreenState extends ConsumerState { _AboutRow( label: '最新版本', value: updateInfo != null ? '已是最新' : '检查中…', - valueColor: AppTheme.textSecondary, + valueColor: context.tokens.muted, trailing: TextButton( onPressed: () async { final messenger = ScaffoldMessenger.of(context); @@ -469,10 +469,10 @@ class _AboutSection extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, - style: const TextStyle( + style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: AppTheme.primaryDark)), + color: context.tokens.primaryDark)), const Divider(height: 24), ...children, ], @@ -504,14 +504,14 @@ class _AboutRow extends StatelessWidget { SizedBox( width: 88, child: Text(label, - style: const TextStyle( - fontSize: 13, color: AppTheme.textSecondary)), + style: TextStyle( + fontSize: 13, color: context.tokens.muted)), ), Expanded( child: Text(value, style: TextStyle( fontSize: 13, - color: valueColor ?? AppTheme.textPrimary, + color: valueColor ?? context.tokens.text, fontWeight: FontWeight.w500)), ), if (trailing != null) trailing!, diff --git a/client/lib/screens/auth/login_screen.dart b/client/lib/screens/auth/login_screen.dart index 444670d..9ba3a3b 100644 --- a/client/lib/screens/auth/login_screen.dart +++ b/client/lib/screens/auth/login_screen.dart @@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher.dart'; import '../../core/auth/auth_state.dart'; import '../../core/config/app_config.dart'; import '../../core/config/app_constants.dart'; -import '../../core/theme/app_theme.dart'; +import '../../core/theme/context_tokens.dart'; import '../../core/storage/login_history.dart'; import '../../providers/connectivity_provider.dart'; import '../../repositories/auth_repository.dart'; @@ -111,7 +111,7 @@ class _LoginScreenState extends ConsumerState { showDialog( context: context, builder: (ctx) => AlertDialog( - icon: const Icon(Icons.lock_outline, color: AppTheme.danger), + icon: Icon(Icons.lock_outline, color: context.tokens.danger), title: const Text('登录已失效'), content: Text(msg), actions: [ @@ -305,23 +305,23 @@ class _LoginScreenState extends ConsumerState { width: double.infinity, padding: const EdgeInsets.all(14), decoration: BoxDecoration( - color: AppTheme.danger.withAlpha(15), + color: context.tokens.danger.withAlpha(15), borderRadius: BorderRadius.circular(6), - border: Border.all(color: AppTheme.danger.withAlpha(80)), + border: Border.all(color: context.tokens.danger.withAlpha(80)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ Icon(Icons.lock_clock_outlined, - color: AppTheme.danger, size: 18), - SizedBox(width: 8), + color: context.tokens.danger, size: 18), + const SizedBox(width: 8), Expanded( child: Text( '授权已过期,账号已锁定', style: TextStyle( - color: AppTheme.danger, + color: context.tokens.danger, fontSize: 14, fontWeight: FontWeight.w600), ), @@ -329,10 +329,10 @@ class _LoginScreenState extends ConsumerState { ], ), const SizedBox(height: 6), - const Text( + Text( '当前门店授权已到期,暂时无法登录。请续费授权后重试,或联系客服协助开通。', style: TextStyle( - color: AppTheme.textSecondary, fontSize: 13, height: 1.4), + color: context.tokens.muted, fontSize: 13, height: 1.4), ), const SizedBox(height: 12), Wrap( @@ -344,7 +344,7 @@ class _LoginScreenState extends ConsumerState { icon: const Icon(Icons.open_in_new, size: 16), label: const Text('前往官网续费'), style: ElevatedButton.styleFrom( - backgroundColor: AppTheme.danger, + backgroundColor: context.tokens.danger, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 10), @@ -357,8 +357,8 @@ class _LoginScreenState extends ConsumerState { icon: const Icon(Icons.support_agent_outlined, size: 16), label: const Text('复制客服邮箱'), style: OutlinedButton.styleFrom( - foregroundColor: AppTheme.danger, - side: BorderSide(color: AppTheme.danger.withAlpha(120)), + foregroundColor: context.tokens.danger, + side: BorderSide(color: context.tokens.danger.withAlpha(120)), padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 10), shape: RoundedRectangleBorder( @@ -384,7 +384,7 @@ class _LoginScreenState extends ConsumerState { } }); return Scaffold( - backgroundColor: AppTheme.primaryDark, + backgroundColor: context.tokens.primaryDark, body: Stack( children: [ Positioned.fill( @@ -419,7 +419,7 @@ class _LoginScreenState extends ConsumerState { borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( - color: AppTheme.primary.withAlpha(102), + color: context.tokens.primary.withAlpha(102), blurRadius: 12, offset: const Offset(0, 4), ), @@ -436,21 +436,21 @@ class _LoginScreenState extends ConsumerState { ), ), const SizedBox(height: 20), - const Text( + Text( '岩美酒库', style: TextStyle( fontSize: 24, fontWeight: FontWeight.w700, - color: AppTheme.primaryDark, + color: context.tokens.primaryDark, letterSpacing: 1, ), ), const SizedBox(height: 6), - const Text( + Text( '专业酒水仓储 · 进销存一体化管理', style: TextStyle( fontSize: 13, - color: AppTheme.textSecondary), + color: context.tokens.muted), ), const SizedBox(height: 32), @@ -470,7 +470,7 @@ class _LoginScreenState extends ConsumerState { _hotelShowing ? Icons.arrow_drop_up : Icons.arrow_drop_down, - color: AppTheme.textSecondary, + color: context.tokens.muted, ) : null, ), @@ -499,7 +499,7 @@ class _LoginScreenState extends ConsumerState { _usernameShowing ? Icons.arrow_drop_up : Icons.arrow_drop_down, - color: AppTheme.textSecondary, + color: context.tokens.muted, ) : null, ), @@ -583,21 +583,21 @@ class _LoginScreenState extends ConsumerState { padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10), decoration: BoxDecoration( - color: AppTheme.danger.withAlpha(15), + color: context.tokens.danger.withAlpha(15), borderRadius: BorderRadius.circular(4), border: Border.all( - color: AppTheme.danger.withAlpha(80)), + color: context.tokens.danger.withAlpha(80)), ), child: Row( children: [ - const Icon(Icons.error_outline, - color: AppTheme.danger, size: 16), + Icon(Icons.error_outline, + color: context.tokens.danger, size: 16), const SizedBox(width: 8), Expanded( child: Text( _errorMessage!, - style: const TextStyle( - color: AppTheme.danger, + style: TextStyle( + color: context.tokens.danger, fontSize: 13), ), ), @@ -637,11 +637,11 @@ class _LoginScreenState extends ConsumerState { Uri.parse('${AppConfig.publicBaseUrl}/register/'), mode: LaunchMode.externalApplication, ), - child: const Text( + child: Text( '还没有门店账号?前往官网注册', style: TextStyle( fontSize: 15, - color: AppTheme.textSecondary, + color: context.tokens.muted, ), ), ), @@ -721,14 +721,14 @@ class _HistoryMenuItemState extends State<_HistoryMenuItem> { padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), child: Row( children: [ - const Icon(Icons.history, - size: 14, color: AppTheme.textSecondary), + Icon(Icons.history, + size: 14, color: context.tokens.muted), const SizedBox(width: 8), Text( widget.value, - style: const TextStyle( + style: TextStyle( fontSize: 14, - color: AppTheme.textPrimary, + color: context.tokens.text, ), ), ], diff --git a/client/lib/screens/devices/device_management_screen.dart b/client/lib/screens/devices/device_management_screen.dart index 7e83bc6..ac751aa 100644 --- a/client/lib/screens/devices/device_management_screen.dart +++ b/client/lib/screens/devices/device_management_screen.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import '../../core/auth/auth_state.dart'; -import '../../core/theme/app_theme.dart'; +import '../../core/theme/context_tokens.dart'; import '../../models/session.dart'; import '../../providers/session_provider.dart'; import '../../widgets/data_table_card.dart'; @@ -35,8 +35,8 @@ class DeviceManagementScreen extends ConsumerWidget { const SizedBox(width: 12), Text( canKick ? '管理员可强制下线其他登录设备' : '仅查看,无操作权限', - style: const TextStyle( - fontSize: 12, color: AppTheme.textSecondary), + style: TextStyle( + fontSize: 12, color: context.tokens.muted), ), const Spacer(), IconButton( @@ -56,12 +56,12 @@ class DeviceManagementScreen extends ConsumerWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.error_outline, - size: 40, color: AppTheme.textSecondary), + Icon(Icons.error_outline, + size: 40, color: context.tokens.muted), const SizedBox(height: 12), Text('加载失败:$e', style: - const TextStyle(color: AppTheme.textSecondary)), + TextStyle(color: context.tokens.muted)), const SizedBox(height: 12), ElevatedButton( onPressed: () => @@ -86,13 +86,13 @@ class DeviceManagementScreen extends ConsumerWidget { children: [ Icon(Icons.circle, size: 9, - color: online ? AppTheme.success : AppTheme.textSecondary), + color: online ? context.tokens.success : context.tokens.muted), const SizedBox(width: 4), Text(online ? '在线' : '离线', style: TextStyle( fontSize: 13, color: - online ? AppTheme.success : AppTheme.textSecondary)), + online ? context.tokens.success : context.tokens.muted)), ], ); @@ -101,15 +101,15 @@ class DeviceManagementScreen extends ConsumerWidget { Widget? kickButton(DeviceSession s, {bool dense = false}) { if (!canKick) return null; if (s.isCurrent) { - return const Text('当前设备', - style: TextStyle(fontSize: 12, color: AppTheme.textSecondary)); + return Text('当前设备', + style: TextStyle(fontSize: 12, color: context.tokens.muted)); } return TextButton( key: Key('btn_kick_${s.id}'), onPressed: () => _confirmKick(context, ref, s), child: Text('强制下线', style: TextStyle( - fontSize: dense ? 13 : 12, color: AppTheme.danger)), + fontSize: dense ? 13 : 12, color: context.tokens.danger)), ); } @@ -144,16 +144,16 @@ class DeviceManagementScreen extends ConsumerWidget { ], rows: sessions.isEmpty ? [ - const DataRow(cells: [ + DataRow(cells: [ DataCell(Text('暂无在线设备', - style: TextStyle(color: AppTheme.textSecondary))), - DataCell(SizedBox()), - DataCell(SizedBox()), - DataCell(SizedBox()), - DataCell(SizedBox()), - DataCell(SizedBox()), - DataCell(SizedBox()), - DataCell(SizedBox()), + style: TextStyle(color: context.tokens.muted))), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), ]) ] : sessions.map((s) { @@ -170,12 +170,12 @@ class DeviceManagementScreen extends ConsumerWidget { padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 1), decoration: BoxDecoration( - color: AppTheme.primary.withAlpha(26), + color: context.tokens.primary.withAlpha(26), borderRadius: BorderRadius.circular(4), ), - child: const Text('本机', + child: Text('本机', style: TextStyle( - fontSize: 11, color: AppTheme.primary)), + fontSize: 11, color: context.tokens.primary)), ), ], ], @@ -183,10 +183,10 @@ class DeviceManagementScreen extends ConsumerWidget { DataCell(Text('${s.platformLabel} · ${s.platformClassLabel}')), DataCell(Text(s.deviceName.isEmpty ? '-' : s.deviceName)), DataCell(Text(s.ip.isEmpty ? '-' : s.ip, - style: const TextStyle( + style: TextStyle( fontFamily: 'monospace', fontSize: 12, - color: AppTheme.textSecondary))), + color: context.tokens.muted))), DataCell(Text(fmt(s.createdAt))), DataCell(Text(fmt(s.lastSeenAt))), DataCell(onlineBadge(s.online)), @@ -213,7 +213,7 @@ class DeviceManagementScreen extends ConsumerWidget { ElevatedButton( onPressed: () => Navigator.of(ctx).pop(true), style: ElevatedButton.styleFrom( - backgroundColor: AppTheme.danger, + backgroundColor: context.tokens.danger, foregroundColor: Colors.white), child: const Text('强制下线'), ), @@ -224,13 +224,13 @@ class DeviceManagementScreen extends ConsumerWidget { try { await ref.read(sessionListProvider.notifier).forceLogout(s.id); if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('已下线'), backgroundColor: AppTheme.success)); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('已下线'), backgroundColor: context.tokens.success)); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text('操作失败:$e'), backgroundColor: AppTheme.danger)); + content: Text('操作失败:$e'), backgroundColor: context.tokens.danger)); } } } diff --git a/client/lib/screens/partners/partners_screen.dart b/client/lib/screens/partners/partners_screen.dart index 539b5f0..21d9df5 100644 --- a/client/lib/screens/partners/partners_screen.dart +++ b/client/lib/screens/partners/partners_screen.dart @@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/models/page_result.dart'; import '../../core/responsive/responsive.dart'; import '../../core/config/app_constants.dart'; -import '../../core/theme/app_theme.dart'; +import '../../core/theme/context_tokens.dart'; import '../../models/partner.dart'; import '../../providers/partner_provider.dart'; import '../../widgets/data_table_card.dart'; @@ -59,10 +59,10 @@ class _PartnersScreenState extends ConsumerState { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.cloud_off, size: 40, color: AppTheme.textSecondary), + Icon(Icons.cloud_off, size: 40, color: context.tokens.muted), const SizedBox(height: 12), - const Text('暂无数据,网络不可用', - style: const TextStyle(color: AppTheme.textSecondary)), + Text('暂无数据,网络不可用', + style: TextStyle(color: context.tokens.muted)), const SizedBox(height: 12), ElevatedButton( onPressed: () => @@ -102,10 +102,10 @@ class _PartnersScreenState extends ConsumerState { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.cloud_off, size: 40, color: AppTheme.textSecondary), + Icon(Icons.cloud_off, size: 40, color: context.tokens.muted), const SizedBox(height: 12), - const Text('暂无数据,网络不可用', - style: const TextStyle(color: AppTheme.textSecondary)), + Text('暂无数据,网络不可用', + style: TextStyle(color: context.tokens.muted)), const SizedBox(height: 12), ElevatedButton( onPressed: () => @@ -159,8 +159,8 @@ class _PartnersScreenState extends ConsumerState { style: TextStyle( fontSize: 12, color: p.status == 'enabled' - ? AppTheme.success - : AppTheme.textSecondary, + ? context.tokens.success + : context.tokens.muted, ), ), fields: [ @@ -182,8 +182,8 @@ class _PartnersScreenState extends ConsumerState { child: TextButton( key: Key('btn_delete_${p.id}'), onPressed: () => onDelete(p), - child: const Text('删除', - style: TextStyle(fontSize: 13, color: AppTheme.danger)), + child: Text('删除', + style: TextStyle(fontSize: 13, color: context.tokens.danger)), ), ), ], @@ -251,7 +251,7 @@ class _PartnersScreenState extends ConsumerState { const DataCell(SizedBox()), DataCell(Text(isSupplier ? '暂无供应商' : '暂无客户', style: - const TextStyle(color: AppTheme.textSecondary))), + TextStyle(color: context.tokens.muted))), const DataCell(SizedBox()), const DataCell(SizedBox()), const DataCell(SizedBox()), @@ -263,10 +263,10 @@ class _PartnersScreenState extends ConsumerState { .map((p) => DataRow( cells: [ DataCell(Text(p.code ?? '-', - style: const TextStyle( + style: TextStyle( fontFamily: 'monospace', fontSize: 12, - color: AppTheme.textSecondary))), + color: context.tokens.muted))), DataCell(SizedBox( width: 180, child: Text(p.name, @@ -286,8 +286,8 @@ class _PartnersScreenState extends ConsumerState { style: TextStyle( fontSize: 13, color: p.status == 'enabled' - ? AppTheme.success - : AppTheme.textSecondary, + ? context.tokens.success + : context.tokens.muted, ), )), DataCell(Row( @@ -307,10 +307,10 @@ class _PartnersScreenState extends ConsumerState { child: TextButton( key: Key('btn_delete_${p.id}'), onPressed: () => onDelete(p), - child: const Text('删除', + child: Text('删除', style: TextStyle( fontSize: 12, - color: AppTheme.danger)), + color: context.tokens.danger)), ), ), ], @@ -354,7 +354,7 @@ class _PartnersScreenState extends ConsumerState { ElevatedButton( onPressed: () => Navigator.of(ctx).pop(true), style: ElevatedButton.styleFrom( - backgroundColor: AppTheme.danger, + backgroundColor: context.tokens.danger, foregroundColor: Colors.white), child: const Text('删除'), ), @@ -373,15 +373,15 @@ class _PartnersScreenState extends ConsumerState { .deletePartner(partner.id); } if (mounted) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text('删除成功'), - backgroundColor: AppTheme.success)); + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('删除成功'), + backgroundColor: context.tokens.success)); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('删除失败:$e'), - backgroundColor: AppTheme.danger)); + backgroundColor: context.tokens.danger)); } } } @@ -466,7 +466,7 @@ class _PartnerFormDialogState extends ConsumerState<_PartnerFormDialog> { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(widget.partner != null ? '更新成功' : '创建成功'), - backgroundColor: AppTheme.success, + backgroundColor: context.tokens.success, ), ); } @@ -475,7 +475,7 @@ class _PartnerFormDialogState extends ConsumerState<_PartnerFormDialog> { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('保存失败:$e'), - backgroundColor: AppTheme.danger), + backgroundColor: context.tokens.danger), ); } } finally { diff --git a/client/test/login_flow_test.dart b/client/test/login_flow_test.dart index 1263de5..cf15d3f 100644 --- a/client/test/login_flow_test.dart +++ b/client/test/login_flow_test.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:jiu_client/core/auth/auth_state.dart'; +import 'package:jiu_client/core/theme/themes.dart'; import 'package:jiu_client/providers/connectivity_provider.dart'; import 'package:jiu_client/repositories/auth_repository.dart'; import 'package:jiu_client/screens/auth/login_screen.dart'; @@ -29,7 +30,7 @@ Widget _buildApp() { (_) => ConnectivityNotifier(skipInit: true), ), ], - child: MaterialApp.router(routerConfig: router), + child: MaterialApp.router(theme: buildTheme('a'), routerConfig: router), ); } diff --git a/client/test/login_screen_test.dart b/client/test/login_screen_test.dart index 64f3734..d4ae452 100644 --- a/client/test/login_screen_test.dart +++ b/client/test/login_screen_test.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; +import 'package:jiu_client/core/theme/themes.dart'; import 'package:jiu_client/providers/connectivity_provider.dart'; import 'package:jiu_client/screens/auth/login_screen.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -29,7 +30,7 @@ Widget _buildTestApp() { (_) => ConnectivityNotifier(skipInit: true), ), ], - child: MaterialApp.router(routerConfig: router), + child: MaterialApp.router(theme: buildTheme('a'), routerConfig: router), ); }