# Genex Flutter 移动端开发指南 > Consumer App(消费者端)+ Merchant App(商户核销端) --- ## 1. 技术栈概览 | 技术 | 版本 | 用途 | |------|------|------| | **Flutter** | 3.x | 跨平台UI框架 | | **Dart** | 3.x | 开发语言 | | **Riverpod** | 2.x | 状态管理(Provider替代方案,编译安全) | | **GoRouter** | 最新 | 声明式路由、深链接 | | **Dio** | 5.x | HTTP客户端 | | **Freezed** | 最新 | 不可变数据模型代码生成 | | **Hive/Isar** | 最新 | 本地持久化 | | **WebSocket** | 内置 | AI Agent实时通信、行情推送 | | **flutter_localizations** | 内置 | 国际化 | --- ## 2. 项目架构:Clean Architecture + Riverpod ### 2.1 目录结构 ``` genex_mobile/ ├── lib/ │ ├── main.dart # 应用入口 │ ├── app/ │ │ ├── app.dart # MaterialApp配置 │ │ ├── router.dart # GoRouter路由定义 │ │ └── theme/ # 主题配置 │ ├── core/ │ │ ├── constants/ # 常量(API地址、术语映射表) │ │ ├── network/ # Dio配置、拦截器、错误处理 │ │ ├── storage/ # 本地存储封装 │ │ ├── utils/ # 工具类 │ │ └── extensions/ # Dart扩展方法 │ ├── features/ # 按功能模块组织 │ │ ├── auth/ # 注册/登录 │ │ │ ├── data/ │ │ │ │ ├── datasources/ # 远程/本地数据源 │ │ │ │ ├── models/ # DTO(Freezed生成) │ │ │ │ └── repositories/ # Repository实现 │ │ │ ├── domain/ │ │ │ │ ├── entities/ # 领域实体 │ │ │ │ ├── repositories/ # Repository接口 │ │ │ │ └── usecases/ # 用例 │ │ │ └── presentation/ │ │ │ ├── providers/ # Riverpod Providers │ │ │ ├── pages/ # 页面Widget │ │ │ └── widgets/ # 模块专用组件 │ │ ├── coupons/ # 券浏览/购买/持有 │ │ ├── trading/ # 二级市场交易 │ │ ├── wallet/ # 余额/资产/交易记录 │ │ ├── redeem/ # 券使用/核销 │ │ ├── transfer/ # P2P转赠 │ │ ├── profile/ # 个人中心/KYC │ │ ├── ai_agent/ # AI Agent对话/建议 │ │ └── merchant/ # 商户端核销(共享模块) │ ├── shared/ │ │ ├── widgets/ # 全局共享组件 │ │ ├── providers/ # 全局Provider │ │ └── models/ # 共享数据模型 │ └── l10n/ # 国际化资源 ├── test/ # 单元/Widget测试 ├── integration_test/ # 集成测试 └── pubspec.yaml ``` ### 2.2 Clean Architecture 分层 ``` ┌────────────────────────────────────────┐ │ Presentation Layer │ │ Pages → Widgets → Riverpod Providers │ ├────────────────────────────────────────┤ │ Domain Layer │ │ Entities → UseCases → Repository(接口)│ ├────────────────────────────────────────┤ │ Data Layer │ │ Models(DTO) → DataSources → Repo实现 │ └────────────────────────────────────────┘ ``` **依赖方向**:Presentation → Domain ← Data(Domain层不依赖任何外层) --- ## 3. 核心模块实现 ### 3.1 术语映射(全局执行) > 所有面向用户的UI文本必须使用Web2术语,禁止出现区块链术语。 ```dart // lib/core/constants/terminology.dart class Terminology { // 用户界面术语 → 底层技术术语 static const Map mapping = { '我的账户': '链上钱包地址', '我的券': 'ERC-721/1155 NFT资产', '我的余额': '链上稳定币(USDC)余额', '转赠给朋友': 'P2P链上转移', '购买': '链上原子交换', '核销/使用': '合约兑付(Redemption)', '订单号': '交易哈希(TX Hash)', '安全验证': '链上签名(MPC钱包后台执行)', }; } ``` ### 3.2 认证模块 ```dart // lib/features/auth/domain/entities/user.dart @freezed class User with _$User { const factory User({ required String id, required String phone, // 或 email required KycLevel kycLevel, // L0/L1/L2/L3 required WalletMode walletMode, // standard/pro String? displayName, String? avatar, }) = _User; } enum KycLevel { L0, L1, L2, L3 } enum WalletMode { standard, pro } ``` ```dart // lib/features/auth/domain/usecases/register_usecase.dart class RegisterUseCase { final AuthRepository _repo; RegisterUseCase(this._repo); /// 注册:手机号/邮箱 → 后台自动创建MPC钱包,用户无感知 Future> call(RegisterParams params) { return _repo.register( phone: params.phone, email: params.email, password: params.password, ); } } ``` ### 3.3 券资产模块 ```dart // lib/features/coupons/domain/entities/coupon.dart @freezed class Coupon with _$Coupon { const factory Coupon({ required String id, // 券ID(链上唯一) required String issuerName, // 发行方名称 required double faceValue, // 面值 required double currentPrice, // 当前市场价 required DateTime expiryDate, // 到期日期 required CouponStatus status, // 可用/已使用/已过期 required CouponType type, // utility/security String? imageUrl, String? description, List? usageConditions, }) = _Coupon; } enum CouponStatus { available, used, expired, listed } enum CouponType { utility, security } ``` ```dart // lib/features/coupons/presentation/providers/coupon_providers.dart final couponListProvider = FutureProvider.autoDispose>((ref) { final repo = ref.watch(couponRepositoryProvider); return repo.getMyCoupons(); }); final couponDetailProvider = FutureProvider.autoDispose.family( (ref, couponId) { final repo = ref.watch(couponRepositoryProvider); return repo.getCouponDetail(couponId); }, ); ``` ### 3.4 交易模块 ```dart // lib/features/trading/domain/entities/order.dart @freezed class TradeOrder with _$TradeOrder { const factory TradeOrder({ required String orderId, // 订单号(映射TX Hash) required String couponId, required OrderSide side, // buy/sell required double price, required OrderStatus status, required DateTime createdAt, }) = _TradeOrder; } enum OrderSide { buy, sell } enum OrderStatus { pending, matched, settled, cancelled } ``` **Utility Track价格校验(前端 + 后端双重验证)**: ```dart // lib/features/trading/presentation/providers/sell_provider.dart class SellNotifier extends StateNotifier { // Utility Track券:卖出价 ≤ 面值 bool validatePrice(double sellPrice, double faceValue, CouponType type) { if (type == CouponType.utility && sellPrice > faceValue) { return false; // 消费型券不允许溢价 } return true; } } ``` ### 3.5 P2P转赠 ```dart // 转赠流程:输入朋友手机号 → 翻译层解析为链上地址 → 链上P2P转移 class TransferUseCase { final TransferRepository _repo; TransferUseCase(this._repo); Future> call({ required String couponId, required String recipientPhone, // 手机号(非链上地址) }) { return _repo.transferByPhone( couponId: couponId, recipientPhone: recipientPhone, ); // 后端翻译层:手机号 → 链上地址 → Gas代付 → 链上P2P转移 } } ``` --- ## 4. AI Agent 集成 ### 4.1 架构 ``` ┌──────────────────────────────┐ │ AI Agent UI Layer │ │ 悬浮按钮 / 对话面板 / 建议条 │ ├──────────────────────────────┤ │ AI Agent SDK │ │ 对话管理 / 上下文组装 / 流式 │ ├──────────────────────────────┤ │ WebSocket连接 │ │ Agent Gateway API │ └──────────────────────────────┘ ``` ### 4.2 悬浮入口按钮 ```dart // lib/features/ai_agent/presentation/widgets/ai_fab.dart class AiAgentFab extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final unreadCount = ref.watch(aiUnreadCountProvider); return Positioned( right: 16, bottom: 80, child: GestureDetector( onTap: () => _showAgentPanel(context), onLongPress: () => _showQuickActions(context), child: Stack( children: [ CircleAvatar( radius: 28, child: Icon(Icons.smart_toy_outlined), ), if (unreadCount > 0) Positioned( right: 0, top: 0, child: Badge(count: unreadCount), ), ], ), ), ); } } ``` ### 4.3 对话面板(流式输出) ```dart // lib/features/ai_agent/presentation/pages/agent_chat_panel.dart class AgentChatPanel extends ConsumerStatefulWidget { @override _AgentChatPanelState createState() => _AgentChatPanelState(); } class _AgentChatPanelState extends ConsumerState { final _channel = WebSocketChannel.connect( Uri.parse('wss://api.gogenex.com/agent/ws'), ); void _sendMessage(String text) { final context = _buildContext(); // 组装上下文 _channel.sink.add(jsonEncode({ 'type': 'chat', 'message': text, 'context': context, })); } Map _buildContext() { return { 'user_profile': ref.read(userProfileProvider).toJson(), 'current_page': GoRouter.of(context).location, 'coupon_portfolio': ref.read(myCouponsProvider).toSummary(), 'recent_actions': ref.read(recentActionsProvider), }; } } ``` ### 4.4 消费者端AI场景 | 场景 | 实现方式 | |------|---------| | 智能选券推荐 | 首页Feed中插入AI推荐卡片 | | 价格顾问 | 券详情页底部AI分析标签 | | 到期管理 | 我的券列表AI排序+推送提醒 | | 出售定价 | 出售页面AI建议价格+解释 | | 自然语言搜索 | 对话面板返回筛选券卡片 | --- ## 5. 商户端核销模块 ### 5.1 核销方式 | 方式 | 场景 | 技术 | |------|------|------| | 扫码核销 | 门店扫消费者券码 | Camera → QR解码 → API调用 | | 输码核销 | 手动输入券码 | 文本输入 → API调用 | | 离线核销 | 网络不可用 | 本地验证 → 队列缓存 → 联网同步 | ### 5.2 离线核销实现 ```dart // lib/features/merchant/data/services/offline_redeem_service.dart class OfflineRedeemService { final _queue = HiveBox('offline_queue'); final _localValidator = LocalCouponValidator(); /// 离线核销:本地验证 + 缓存 + 联网自动同步 Future redeemOffline(String couponCode) async { // 1. 本地验证(预下载的有效券列表 + 签名验证) final isValid = await _localValidator.validate(couponCode); if (!isValid) return RedeemResult.invalid(); // 2. 本地标记已核销,加入同步队列 await _queue.add(PendingRedemption( couponCode: couponCode, timestamp: DateTime.now(), storeId: currentStoreId, )); return RedeemResult.pendingSync(); } /// 联网后自动同步 Future syncPendingRedemptions() async { final pending = _queue.values.toList(); for (final item in pending) { try { await _api.confirmRedemption(item); await _queue.delete(item.key); } catch (_) { // 重试逻辑 } } } } ``` --- ## 6. 网络层 ### 6.1 Dio配置 ```dart // lib/core/network/api_client.dart class ApiClient { late final Dio _dio; ApiClient() { _dio = Dio(BaseOptions( baseUrl: 'https://api.gogenex.com/api/v1', connectTimeout: Duration(seconds: 10), receiveTimeout: Duration(seconds: 30), )); _dio.interceptors.addAll([ AuthInterceptor(), // JWT Token注入 LoggingInterceptor(), // 日志 RetryInterceptor(), // 重试策略 ErrorInterceptor(), // 统一错误处理 ]); } } ``` ### 6.2 错误处理 ```dart // lib/core/network/failure.dart @freezed class Failure with _$Failure { const factory Failure.network({String? message}) = NetworkFailure; const factory Failure.server({required int code, String? message}) = ServerFailure; const factory Failure.auth({String? message}) = AuthFailure; const factory Failure.validation({required Map errors}) = ValidationFailure; } ``` --- ## 7. 状态管理模式(Riverpod) ```dart // 只读数据查询 final couponListProvider = FutureProvider.autoDispose>((ref) async { return ref.watch(couponRepoProvider).getAll(); }); // 可变状态管理 final cartProvider = StateNotifierProvider((ref) { return CartNotifier(ref.watch(orderRepoProvider)); }); // 异步操作 final purchaseProvider = FutureProvider.family((ref, params) { return ref.watch(orderRepoProvider).purchase(params); }); ``` --- ## 8. 应用构建配置 ### 8.1 多环境配置 ```dart // lib/core/config/env.dart enum Environment { dev, staging, prod } class AppConfig { static late Environment env; static String get apiBase => switch (env) { Environment.dev => 'https://dev-api.gogenex.com', Environment.staging => 'https://staging-api.gogenex.com', Environment.prod => 'https://api.gogenex.com', }; } ``` ### 8.2 Flavor构建 ```yaml # Consumer App flutter run --flavor consumer -t lib/main_consumer.dart # Merchant App flutter run --flavor merchant -t lib/main_merchant.dart ``` Consumer和Merchant共享核心模块(`core/`、`shared/`),通过不同入口和路由配置区分功能。 --- ## 9. 测试策略 | 层级 | 工具 | 覆盖目标 | |------|------|---------| | 单元测试 | `flutter_test` + `mocktail` | UseCase、Repository、Provider | | Widget测试 | `flutter_test` | 关键页面组件 | | 集成测试 | `integration_test` | 购买流程、核销流程、转赠流程 | | Golden测试 | `golden_toolkit` | UI快照回归 | ```dart // test/features/trading/sell_notifier_test.dart void main() { test('Utility券不允许溢价出售', () { final notifier = SellNotifier(); expect( notifier.validatePrice(110.0, 100.0, CouponType.utility), false, // 110 > 面值100,拒绝 ); expect( notifier.validatePrice(85.0, 100.0, CouponType.utility), true, // 85 < 面值100,允许 ); }); } ``` --- ## 10. 性能优化 | 策略 | 实现 | |------|------| | 图片懒加载 | `cached_network_image` + CDN | | 列表虚拟化 | `ListView.builder` + 分页加载 | | 离线缓存 | Hive本地数据库 + 增量同步 | | 启动优化 | 延迟初始化非核心服务 | | 包体积 | Tree-shaking + 延迟加载 | | 内存管理 | `autoDispose` Provider自动释放 | --- ## 11. 安全规范 - JWT Token存储于Flutter Secure Storage(非SharedPreferences) - 敏感操作(大额交易、转赠)需二次验证(PIN/生物识别) - API通信全链路HTTPS,Certificate Pinning - 本地数据加密存储(Hive加密Box) - 禁止在日志中输出敏感信息(Token、用户手机号) - ProGuard/R8混淆(Android) --- ## 12. 发布流程 ``` 开发 → 提交PR → CI自动测试 → Code Review → 合入main ↓ 自动构建(GitHub Actions / GitLab CI) ↓ ┌────────────────┼────────────────┐ ↓ ↓ ↓ Dev Build Staging Build Prod Build (内部测试) (TestFlight/Beta) (App Store/Play Store) ``` --- *文档版本: v1.0* *基于: Genex 券交易平台 - 软件需求规格说明书 v4.1* *技术栈: Flutter 3.x + Riverpod + Clean Architecture*