diff --git a/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..5850b08 100644 Binary files a/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/client/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..f8b6594 100644 Binary files a/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/client/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..c5dfb0a 100644 Binary files a/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/client/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..8dc8ba6 100644 Binary files a/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/client/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..0638d8a 100644 Binary files a/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/client/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/client/assets/brand/logo_mark.png b/client/assets/brand/logo_mark.png new file mode 100644 index 0000000..871a5cf Binary files /dev/null and b/client/assets/brand/logo_mark.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index dc9ada4..3084564 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index 7353c41..05692fc 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 797d452..27e351e 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 6ed2d93..bf75174 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index 4cd7b00..b2e58e7 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index fe73094..d50fd6a 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index 321773c..7314fb7 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 797d452..27e351e 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 502f463..e1ccbf4 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 0ec3034..b5935c3 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 0ec3034..b5935c3 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index e9f5fea..8d5bed8 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index 84ac32a..8b89f29 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index 8953cba..2333834 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 0467bf1..a10d86f 100644 Binary files a/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/client/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/client/lib/screens/auth/login_screen.dart b/client/lib/screens/auth/login_screen.dart index 281b52a..74e8064 100644 --- a/client/lib/screens/auth/login_screen.dart +++ b/client/lib/screens/auth/login_screen.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import '../../core/responsive/responsive.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -34,6 +35,16 @@ class _LoginScreenState extends ConsumerState { bool _obscure = true; String? _errorMessage; + // 客服邮箱(授权续费 / 锁定协助)。与官网 web/_data/site.json 的 support.email 保持一致。 + static const _supportEmail = 'yammy2023@163.com'; + + /// 当前错误是否为「授权锁定」——后端返回固定文案 + /// `license locked, please renew or contact support`(见 service.ErrLicenseLocked)。 + bool get _isLicenseLocked { + final m = _errorMessage?.toLowerCase() ?? ''; + return m.contains('license') && (m.contains('lock') || m.contains('expire')); + } + List _hotelCodeHistory = []; List _usernameHistory = []; @@ -242,6 +253,94 @@ class _LoginScreenState extends ConsumerState { } } + Future _openRenewSite() async { + await launchUrl( + Uri.parse(AppConfig.publicBaseUrl), + mode: LaunchMode.externalApplication, + ); + } + + Future _copySupportEmail() async { + await Clipboard.setData(const ClipboardData(text: _supportEmail)); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('已复制客服邮箱:$_supportEmail')), + ); + } + + /// 授权锁定时的可操作提示:告诉用户「去哪里解决」——前往官网续费 / 联系客服。 + Widget _buildLicenseLockedNotice() { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: AppTheme.danger.withAlpha(15), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: AppTheme.danger.withAlpha(80)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Row( + children: [ + Icon(Icons.lock_clock_outlined, + color: AppTheme.danger, size: 18), + SizedBox(width: 8), + Expanded( + child: Text( + '授权已过期,账号已锁定', + style: TextStyle( + color: AppTheme.danger, + fontSize: 14, + fontWeight: FontWeight.w600), + ), + ), + ], + ), + const SizedBox(height: 6), + const Text( + '当前门店授权已到期,暂时无法登录。请续费授权后重试,或联系客服协助开通。', + style: TextStyle( + color: AppTheme.textSecondary, fontSize: 13, height: 1.4), + ), + const SizedBox(height: 12), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + ElevatedButton.icon( + onPressed: _openRenewSite, + icon: const Icon(Icons.open_in_new, size: 16), + label: const Text('前往官网续费'), + style: ElevatedButton.styleFrom( + backgroundColor: AppTheme.danger, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 14, vertical: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4)), + ), + ), + OutlinedButton.icon( + onPressed: _copySupportEmail, + 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)), + padding: const EdgeInsets.symmetric( + horizontal: 14, vertical: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4)), + ), + ), + ], + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { // 被踢下线 / 会话失效:登出后跳回登录页,弹一次提示并清空 @@ -283,20 +382,12 @@ class _LoginScreenState extends ConsumerState { child: Column( mainAxisSize: MainAxisSize.min, children: [ - // Logo + // Logo(岩美酒库品牌 mark,与 App 图标一致) Container( width: 80, height: 80, decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - AppTheme.primaryLight, - AppTheme.primaryDark - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: AppTheme.primary.withAlpha(102), @@ -305,12 +396,19 @@ class _LoginScreenState extends ConsumerState { ), ], ), - child: const Icon(Icons.wine_bar, - color: Colors.white, size: 44), + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + child: Image.asset( + 'assets/brand/logo_mark.png', + width: 80, + height: 80, + fit: BoxFit.cover, + ), + ), ), const SizedBox(height: 20), const Text( - '酒库管理系统', + '岩美酒库', style: TextStyle( fontSize: 24, fontWeight: FontWeight.w700, @@ -320,7 +418,7 @@ class _LoginScreenState extends ConsumerState { ), const SizedBox(height: 6), const Text( - '酒店仓库管理解决方案', + '专业酒水仓储 · 进销存一体化管理', style: TextStyle( fontSize: 13, color: AppTheme.textSecondary), @@ -448,32 +546,35 @@ class _LoginScreenState extends ConsumerState { // Inline error if (_errorMessage != null) ...[ const SizedBox(height: 12), - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 10), - decoration: BoxDecoration( - color: AppTheme.danger.withAlpha(15), - borderRadius: BorderRadius.circular(4), - border: Border.all( - color: AppTheme.danger.withAlpha(80)), - ), - child: Row( - children: [ - const Icon(Icons.error_outline, - color: AppTheme.danger, size: 16), - const SizedBox(width: 8), - Expanded( - child: Text( - _errorMessage!, - style: const TextStyle( - color: AppTheme.danger, - fontSize: 13), + if (_isLicenseLocked) + _buildLicenseLockedNotice() + else + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 10), + decoration: BoxDecoration( + color: AppTheme.danger.withAlpha(15), + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: AppTheme.danger.withAlpha(80)), + ), + child: Row( + children: [ + const Icon(Icons.error_outline, + color: AppTheme.danger, size: 16), + const SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage!, + style: const TextStyle( + color: AppTheme.danger, + fontSize: 13), + ), ), - ), - ], + ], + ), ), - ), ], const SizedBox(height: 24), @@ -530,7 +631,7 @@ class _LoginScreenState extends ConsumerState { right: 0, child: Center( child: Text( - '© 2026 酒库管理系统 v1.0.0', + '© 2026 岩美酒库 v1.0.0', style: TextStyle( color: Colors.white.withAlpha(102), fontSize: 12), ), diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png index 82b6f9d..641032c 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png index 13b35eb..dbb3483 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png index 0a3f5fa..ccbeca1 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png index bdb5722..d75f349 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png index f083318..3dfd089 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png index 326c0e7..871a5cf 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png index 2f1632c..d837b23 100644 Binary files a/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and b/client/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/client/pubspec.yaml b/client/pubspec.yaml index 4f66528..44d7b2e 100644 --- a/client/pubspec.yaml +++ b/client/pubspec.yaml @@ -44,3 +44,4 @@ flutter: assets: - assets/fonts/NotoSansSC-Regular.ttf - assets/config/app_info.json + - assets/brand/logo_mark.png diff --git a/client/web/favicon.png b/client/web/favicon.png index 8aaa46a..ccbeca1 100644 Binary files a/client/web/favicon.png and b/client/web/favicon.png differ diff --git a/client/web/icons/Icon-192.png b/client/web/icons/Icon-192.png index b749bfe..0638d8a 100644 Binary files a/client/web/icons/Icon-192.png and b/client/web/icons/Icon-192.png differ diff --git a/client/web/icons/Icon-512.png b/client/web/icons/Icon-512.png index 88cfd48..871a5cf 100644 Binary files a/client/web/icons/Icon-512.png and b/client/web/icons/Icon-512.png differ diff --git a/client/web/icons/Icon-maskable-192.png b/client/web/icons/Icon-maskable-192.png index eb9b4d7..6af87d1 100644 Binary files a/client/web/icons/Icon-maskable-192.png and b/client/web/icons/Icon-maskable-192.png differ diff --git a/client/web/icons/Icon-maskable-512.png b/client/web/icons/Icon-maskable-512.png index d69c566..1c7aef3 100644 Binary files a/client/web/icons/Icon-maskable-512.png and b/client/web/icons/Icon-maskable-512.png differ