first commit
This commit is contained in:
549
basic_uis/ui_business.md
Normal file
549
basic_uis/ui_business.md
Normal file
@@ -0,0 +1,549 @@
|
||||
# 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<SmsAuthBloc, SmsAuthState>(
|
||||
listener: _pageListener,
|
||||
builder: _createLayout,
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 回调类型定义
|
||||
|
||||
```dart
|
||||
/// 确认按钮锁定状态变化回调
|
||||
typedef OnSubmitBtnLockChanged = void Function(bool locked);
|
||||
|
||||
/// 用于覆盖短信校验接口的回调
|
||||
typedef SmsCallbackOverride = Future<bool> 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<LoginPage> {
|
||||
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<bool> 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<ServiceItem> 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<CustomFormPage> {
|
||||
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状态变化日志
|
||||
- 验证表单验证逻辑
|
||||
|
||||
Reference in New Issue
Block a user