# UI Business - 业务UI组件模块文档 ## 模块概述 `ui_business` 是 OneApp 基础UI模块群中的业务UI组件库,提供与具体业务场景相关的UI组件和工具。该模块包含账户相关组件、订单相关组件、同意书组件等业务特定的界面元素和交互逻辑。 ### 基本信息 - **模块名称**: ui_business - **模块路径**: oneapp_basic_uis/ui_business - **类型**: Flutter Package Module - **主要功能**: 业务UI组件、账户组件、订单组件、同意书组件 ### 核心特性 - **账户UI组件**: 提供登录、短信验证、证书拍照等账户相关UI - **订单UI组件**: 订单相关的业务界面组件 - **同意书组件**: 用户协议和同意书相关UI - **国际化支持**: 支持中英文多语言 - **表单验证**: 集成表单验证和数据处理 - **路由守卫**: 业务路由保护和权限控制 ## 目录结构 ``` ui_business/ ├── lib/ │ ├── ui_account.dart # 账户相关组件导出 │ ├── ui_order.dart # 订单相关组件导出 │ ├── ui_consent.dart # 同意书相关组件导出 │ ├── ui_common.dart # 通用业务组件导出 │ ├── route_guard.dart # 路由守卫 │ ├── customer_care.dart # 客服相关 │ ├── poi_to_car.dart # POI到车功能 │ ├── src/ # 源代码目录 │ │ ├── ui_account/ # 账户相关组件 │ │ │ ├── widgets/ # 账户UI组件 │ │ │ │ ├── sms_auth/ # 短信验证组件 │ │ │ │ ├── check_spin/ # 验证转动组件 │ │ │ │ ├── certificates_photo/ # 证书拍照 │ │ │ │ └── time_picker/ # 时间选择器 │ │ │ ├── models/ # 账户数据模型 │ │ │ ├── mgmt/ # 账户管理 │ │ │ └── ui_config.dart # UI配置 │ │ ├── ui_order/ # 订单相关组件 │ │ └── constants/ # 常量定义 │ ├── generated/ # 生成的国际化文件 │ └── l10n/ # 国际化资源 ├── assets/ # 资源文件 └── pubspec.yaml # 依赖配置 ``` ## 核心架构组件 ### 1. 短信验证组件 (SmsAuthWidget) 提供短信验证码输入和验证功能的完整UI组件: ```dart /// 短信验证组件 class SmsAuthWidget extends StatelessWidget { /// 构造器 /// /// [verificationType] 验证码类型:1-登录注册 2-重置密码 3-设置/重置spin /// [callback] 事件回调 /// [formKey] 表单键 /// [onSubmitBtnLockChanged] 确认按钮锁定回调 /// [smsCallbackOverride] 覆盖默认操作 /// [lockPhoneEdit] 是否锁定手机号修改 SmsAuthWidget({ required this.verificationType, required this.formKey, required this.callback, required this.lockPhoneEdit, this.onSubmitBtnLockChanged, this.smsCallbackOverride, Key? key, }) : super(key: key); /// 默认超时时间 static const defaultTimeout = 60; /// 类型:1-登录注册 2-重置密码 3-设置/重置spin final String verificationType; /// 表单键 final SmsAuthFormKey formKey; /// 结果回调 final void Function(SmsAuthResult result) callback; /// 确认按钮锁定状态变化回调 final OnSubmitBtnLockChanged? onSubmitBtnLockChanged; /// 短信校验覆盖回调 final SmsCallbackOverride? smsCallbackOverride; /// 是否锁定手机号修改 final bool lockPhoneEdit; @override Widget build(BuildContext context) => BlocProvider( create: (ctx) => _bloc = SmsAuthBloc(smsCallbackOverride) ..add(const SmsAuthEvent.getLocalProfile()), child: BlocConsumer( listener: _pageListener, builder: _createLayout, ), ); } ``` ### 2. 回调类型定义 ```dart /// 确认按钮锁定状态变化回调 typedef OnSubmitBtnLockChanged = void Function(bool locked); /// 用于覆盖短信校验接口的回调 typedef SmsCallbackOverride = Future Function( PhoneNumber phone, VerificationCode smsCode, ); ``` ### 3. 手机号掩码扩展 ```dart extension _PhoneStringExtension on String { /// 手机号掩码显示,中间4位用*替换 String get maskPhone { final buffer = StringBuffer(); int i = 0; for (final c in characters) { if ([3, 4, 5, 6].contains(i)) { buffer.write('*'); } else { buffer.write(c); } i++; } return buffer.toString(); } } ``` ### 4. 通用项目组件 (ItemAComponent) 来自general_ui_component模块的通用组件: ```dart /// 通用项目组件A class ItemAComponent extends StatelessWidget { ItemAComponent({ required this.title, required this.logoImg, required this.onItemAClick, required this.index, this.size, }); /// Logo图片URL String logoImg = ''; /// 标题文本 String title = ''; /// 点击回调 OnItemAClick onItemAClick; /// 索引 int index; /// 自定义尺寸 double? size; @override Widget build(BuildContext context) { return InkWell( highlightColor: Colors.transparent, splashColor: Colors.transparent, child: Column( children: [ Stack( alignment: Alignment.center, children: [ Container( width: width(designWidgetWidth: 48), height: width(designWidgetWidth: 48), decoration: BoxDecoration( shape: BoxShape.circle, color: OneColors.bgcSub2, ), ), SizedBox( height: size ?? width(designWidgetWidth: 40), width: size ?? width(designWidgetWidth: 40), child: CacheImageComponent( imageUrl: logoImg, ), ), ], ), Padding( padding: EdgeInsets.only(top: 5.0), child: Text( title, style: OneTextStyle.content( color: const Color(0xFF7C7F81), ), ), ) ], ), onTap: () => onItemAClick(index), ); } } typedef OnItemAClick = Function(int index); ``` ## 使用指南 ### 1. 短信验证组件使用 ```dart import 'package:ui_business/ui_account.dart'; class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State { late SmsAuthFormKey _formKey; bool _submitBtnLocked = true; @override void initState() { super.initState(); _formKey = SmsAuthFormKey(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('短信验证')), body: Padding( padding: EdgeInsets.all(16.0), child: Column( children: [ SmsAuthWidget( verificationType: '1', // 登录注册类型 formKey: _formKey, lockPhoneEdit: false, callback: _handleSmsResult, onSubmitBtnLockChanged: (locked) { setState(() { _submitBtnLocked = locked; }); }, ), SizedBox(height: 20), ElevatedButton( onPressed: _submitBtnLocked ? null : _handleSubmit, child: Text('确认'), ), ], ), ), ); } void _handleSmsResult(SmsAuthResult result) { switch (result.state) { case SmsAuthResultEnum.success: // 验证成功,处理登录逻辑 print('验证成功,UUID: ${result.uuid}'); Navigator.pushReplacementNamed(context, '/home'); break; case SmsAuthResultEnum.failed: // 验证失败 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('验证失败,请重试')), ); break; } } void _handleSubmit() { // 触发表单验证和提交 _formKey.controllerList.forEach((controller) => controller()); } } ``` ### 2. 自定义短信验证回调 ```dart // 自定义短信验证逻辑 Future customSmsVerification( PhoneNumber phone, VerificationCode smsCode ) async { try { // 调用自定义API进行验证 final response = await MyApiService.verifySms( phone: phone.value, code: smsCode.value, ); return response.success; } catch (e) { print('短信验证异常: $e'); return false; } } // 使用自定义验证回调 SmsAuthWidget( verificationType: '1', formKey: _formKey, lockPhoneEdit: false, callback: _handleSmsResult, smsCallbackOverride: customSmsVerification, // 使用自定义验证 ) ``` ### 3. 通用组件列表使用 ```dart import 'package:general_ui_component/ItemAComponent.dart'; class ServiceListPage extends StatelessWidget { final List services = [ ServiceItem('充电服务', 'assets/images/charging.png'), ServiceItem('维修保养', 'assets/images/maintenance.png'), ServiceItem('道路救援', 'assets/images/rescue.png'), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('服务列表')), body: GridView.builder( padding: EdgeInsets.all(16.0), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 1.0, crossAxisSpacing: 16.0, mainAxisSpacing: 16.0, ), itemCount: services.length, itemBuilder: (context, index) { final service = services[index]; return ItemAComponent( title: service.name, logoImg: service.iconUrl, index: index, onItemAClick: _handleServiceClick, ); }, ), ); } void _handleServiceClick(int index) { final service = services[index]; print('点击了服务: ${service.name}'); // 处理服务点击逻辑 } } ``` ### 4. 国际化支持 ```dart import 'package:ui_business/generated/l10n.dart'; class LocalizedWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: [ Text(S.of(context).smsVerificationPage_hint_code), Text(S.of(context).smsVerificationPage_btn_get), ], ); } } ``` ## 依赖配置 ### pubspec.yaml 关键依赖 ```yaml dependencies: flutter: sdk: flutter # 基础UI组件 ui_basic: path: ../ui_basic # 基础工具 basic_utils: path: ../../oneapp_basic_utils/basic_utils # 模块化路由 basic_modular: path: ../../oneapp_basic_utils/basic_modular # 账户服务 clr_account: path: ../../oneapp_account/clr_account # 状态管理 flutter_bloc: ^8.0.0 # 国际化 flutter_localizations: sdk: flutter intl: ^0.17.0 dev_dependencies: # 国际化代码生成 intl_utils: ^2.8.0 ``` ## 国际化配置 ### l10n/intl_zh.arb (中文) ```json { "smsVerificationPage_hint_code": "请输入验证码", "smsVerificationPage_btn_get": "获取验证码", "smsVerificationsPage_error_invalidCode": "验证码格式不正确" } ``` ### l10n/intl_en.arb (英文) ```json { "smsVerificationPage_hint_code": "Please enter verification code", "smsVerificationPage_btn_get": "Get Code", "smsVerificationsPage_error_invalidCode": "Invalid verification code format" } ``` ## 表单验证 ### SmsAuthFormKey 使用 ```dart class CustomFormPage extends StatefulWidget { @override _CustomFormPageState createState() => _CustomFormPageState(); } class _CustomFormPageState extends State { late SmsAuthFormKey _formKey; @override void initState() { super.initState(); _formKey = SmsAuthFormKey(); } @override Widget build(BuildContext context) { return Form( key: _formKey, child: Column( children: [ // 表单字段 ElevatedButton( onPressed: () { if (_formKey.validate()) { _formKey.save(); // 使用表单数据 print('手机号: ${_formKey.phone}'); print('短信码: ${_formKey.sms}'); } }, child: Text('提交'), ), ], ), ); } } ``` ## 最佳实践 ### 1. 错误处理 ```dart // 推荐:完整的错误处理 void _handleSmsResult(SmsAuthResult result) { switch (result.state) { case SmsAuthResultEnum.success: // 成功处理 _navigateToNextPage(result); break; case SmsAuthResultEnum.failed: // 失败处理,显示用户友好的错误信息 _showErrorMessage('验证失败,请检查验证码是否正确'); break; case SmsAuthResultEnum.timeout: // 超时处理 _showErrorMessage('验证超时,请重新获取验证码'); break; } } ``` ### 2. 资源管理 ```dart // 推荐:及时释放资源 @override void dispose() { _formKey.dispose(); super.dispose(); } ``` ### 3. 无障碍支持 ```dart // 推荐:添加语义标签 Semantics( label: '验证码输入框', hint: '请输入6位数字验证码', child: SmsAuthWidget( // 配置参数 ), ) ``` ## 问题排查 ### 常见问题 1. **验证码收不到**: 检查手机号格式和网络连接 2. **倒计时不工作**: 确认CountDownButton状态管理正确 3. **国际化文本不显示**: 检查l10n配置和S.of(context)使用 ### 调试技巧 - 使用Flutter Inspector查看Widget树 - 检查BLoC状态变化日志 - 验证表单验证逻辑