first commit

This commit is contained in:
2025-09-24 14:08:54 +08:00
commit 40784642cf
83 changed files with 37832 additions and 0 deletions

349
basic_uis/README.md Normal file
View File

@@ -0,0 +1,349 @@
# Basic UIs 基础UI组件模块群
## 模块群概述
Basic UIs 模块群是 OneApp 的用户界面基础设施提供了完整的UI组件生态系统。该模块群包含了基础UI组件、业务UI组件和通用UI组件为整个应用提供统一的设计语言和用户体验。
## 子模块列表
### 核心UI组件
1. **[ui_basic](./ui_basic.md)** - 基础UI组件库
- 按钮、输入框、卡片等基础组件
- 布局容器和交互组件
- 主题系统和响应式设计
2. **[ui_business](./ui_business.md)** - 业务UI组件库
- 车辆状态展示组件
- 消息中心组件
- 地理位置组件
- 用户同意组件
3. **[basic_uis](./basic_uis.md)** - 通用UI组件集合
- 组件库整合和统一导出
- 跨模块UI组件管理
- 全局UI配置和工具
4. **[general_ui_component](./general_ui_component.md)** - 通用UI组件
- 可复用的通用组件
- 跨业务场景组件
- 第三方组件封装
## 模块架构
### 分层设计
```
应用层 UI 组件
业务层 UI 组件 (ui_business)
基础层 UI 组件 (ui_basic)
Flutter Framework
```
### 组件分类
#### 1. 基础组件层 (ui_basic)
- **原子组件**: Button, TextField, Icon, Text
- **分子组件**: Card, ListTile, AppBar, Dialog
- **布局组件**: Container, Row, Column, Stack
- **交互组件**: GestureDetector, InkWell, RefreshIndicator
#### 2. 业务组件层 (ui_business)
- **车辆组件**: VehicleStatusCard, VehicleControlPanel
- **消息组件**: MessageListView, MessageTile
- **位置组件**: LocationPicker, MapView
- **表单组件**: BusinessForm, ConsentDialog
#### 3. 通用组件层 (basic_uis & general_ui_component)
- **复合组件**: SearchBar, NavigationDrawer
- **特效组件**: AnimatedWidget, TransitionWidget
- **工具组件**: LoadingOverlay, ErrorBoundary
## 设计原则
### 1. 一致性原则
- **视觉一致性**: 统一的颜色、字体、间距规范
- **交互一致性**: 统一的交互模式和反馈机制
- **行为一致性**: 相同功能组件的行为保持一致
### 2. 可访问性原则
- **语义标签**: 为屏幕阅读器提供清晰的语义
- **键盘导航**: 支持键盘和辅助设备导航
- **对比度**: 满足无障碍对比度要求
- **字体缩放**: 支持系统字体缩放设置
### 3. 响应式原则
- **屏幕适配**: 适应不同屏幕尺寸和密度
- **方向适配**: 支持横竖屏切换
- **设备适配**: 针对手机、平板的优化
- **性能适配**: 根据设备性能调整渲染策略
### 4. 可扩展性原则
- **插件化**: 支持组件插件化扩展
- **主题化**: 支持多主题和自定义主题
- **国际化**: 支持多语言和本地化
- **配置化**: 通过配置控制组件行为
## 主题系统
### 主题架构
```dart
class OneAppTheme {
// 颜色系统
static ColorScheme get colorScheme => ColorScheme.fromSeed(
seedColor: const Color(0xFF1976D2),
);
// 字体系统
static TextTheme get textTheme => const TextTheme(
displayLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
titleLarge: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.normal),
);
// 组件主题
static ThemeData get lightTheme => ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
textTheme: textTheme,
appBarTheme: const AppBarTheme(/* ... */),
elevatedButtonTheme: ElevatedButtonThemeData(/* ... */),
);
}
```
### 设计令牌 (Design Tokens)
```dart
class DesignTokens {
// 间距系统
static const double spacingXs = 4.0;
static const double spacingSm = 8.0;
static const double spacingMd = 16.0;
static const double spacingLg = 24.0;
static const double spacingXl = 32.0;
// 圆角系统
static const double radiusXs = 4.0;
static const double radiusSm = 8.0;
static const double radiusMd = 12.0;
static const double radiusLg = 16.0;
// 阴影系统
static const List<BoxShadow> shadowSm = [
BoxShadow(
color: Color(0x0D000000),
blurRadius: 2,
offset: Offset(0, 1),
),
];
}
```
## 组件开发规范
### 1. 组件结构
```dart
class ExampleComponent extends StatelessWidget {
// 1. 必需参数
final String title;
// 2. 可选参数
final String? subtitle;
final VoidCallback? onTap;
// 3. 样式参数
final TextStyle? titleStyle;
final EdgeInsets? padding;
// 4. 构造函数
const ExampleComponent({
Key? key,
required this.title,
this.subtitle,
this.onTap,
this.titleStyle,
this.padding,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(/* 实现 */);
}
}
```
### 2. 命名规范
- **组件名称**: 使用PascalCase`VehicleStatusCard`
- **参数名称**: 使用camelCase`onPressed`
- **常量名称**: 使用camelCase`defaultPadding`
- **枚举名称**: 使用PascalCase`ButtonType`
### 3. 文档规范
```dart
/// 车辆状态卡片组件
///
/// 用于展示车辆的基本状态信息,包括电量、里程、锁定状态等。
/// 支持点击交互和自定义样式。
///
/// 示例用法:
/// ```dart
/// VehicleStatusCard(
/// status: vehicleStatus,
/// onTap: () => Navigator.push(...),
/// )
/// ```
class VehicleStatusCard extends StatelessWidget {
/// 车辆状态数据
final VehicleStatus status;
/// 点击回调函数
final VoidCallback? onTap;
}
```
## 性能优化策略
### 1. 渲染优化
- **Widget缓存**: 缓存不变的Widget实例
- **RepaintBoundary**: 隔离重绘区域
- **Const构造**: 使用const构造函数
- **Build优化**: 避免在build方法中创建对象
### 2. 内存优化
- **资源释放**: 及时释放Controller和Stream
- **图片缓存**: 合理使用图片缓存策略
- **对象池**: 复用频繁创建的对象
- **弱引用**: 避免内存泄漏
### 3. 加载优化
- **懒加载**: 按需加载组件和资源
- **预加载**: 预测性加载关键资源
- **分包加载**: 大型组件分包异步加载
- **缓存策略**: 智能缓存机制
## 测试策略
### 1. 单元测试
```dart
testWidgets('VehicleStatusCard displays correct information', (tester) async {
const status = VehicleStatus(
vehicleName: 'Test Vehicle',
batteryLevel: 80,
isLocked: true,
);
await tester.pumpWidget(
MaterialApp(
home: VehicleStatusCard(status: status),
),
);
expect(find.text('Test Vehicle'), findsOneWidget);
expect(find.text('80%'), findsOneWidget);
expect(find.byIcon(Icons.lock), findsOneWidget);
});
```
### 2. Widget测试
- **渲染测试**: 验证组件正确渲染
- **交互测试**: 测试用户交互响应
- **状态测试**: 测试状态变化
- **样式测试**: 验证样式正确应用
### 3. 集成测试
- **页面流程测试**: 测试完整用户流程
- **性能测试**: 测试组件性能表现
- **兼容性测试**: 测试不同设备兼容性
- **可访问性测试**: 测试无障碍功能
## 构建和发布
### 1. 版本管理
- **语义化版本**: 遵循 semver 规范
- **变更日志**: 详细的变更记录
- **向后兼容**: 保证API向后兼容
- **废弃通知**: 提前通知API废弃
### 2. 发布流程
```bash
# 1. 运行测试
flutter test
# 2. 更新版本号
# 编辑 pubspec.yaml
# 3. 更新变更日志
# 编辑 CHANGELOG.md
# 4. 发布包
flutter pub publish
```
## 使用指南
### 1. 快速开始
```dart
import 'package:ui_basic/ui_basic.dart';
import 'package:ui_business/ui_business.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: OneAppTheme.lightTheme,
home: MyHomePage(),
);
}
}
```
### 2. 组件使用
```dart
// 基础组件使用
BasicButton(
text: '确定',
type: ButtonType.primary,
onPressed: () {},
)
// 业务组件使用
VehicleStatusCard(
status: vehicleStatus,
onTap: () {},
)
```
### 3. 主题定制
```dart
MaterialApp(
theme: OneAppTheme.lightTheme.copyWith(
primarySwatch: Colors.green,
// 其他自定义配置
),
)
```
## 最佳实践
### 1. 组件设计
- **单一职责**: 每个组件功能单一明确
- **可组合性**: 支持组件组合使用
- **可配置性**: 提供丰富的配置选项
- **可预测性**: 相同输入产生相同输出
### 2. API设计
- **直观性**: API命名直观易理解
- **一致性**: 相似功能API保持一致
- **扩展性**: 预留扩展空间
- **文档化**: 提供完整文档和示例
### 3. 性能考虑
- **懒加载**: 按需加载减少初始化开销
- **缓存策略**: 合理使用缓存提升性能
- **异步处理**: 避免阻塞UI线程
- **资源管理**: 及时释放不需要的资源
## 总结
Basic UIs 模块群为 OneApp 提供了完整的UI基础设施通过分层设计、统一规范和完善的工具链实现了高效的UI开发和一致的用户体验。模块群具有良好的可扩展性和可维护性能够支撑大型应用的UI需求并为未来的功能扩展提供了坚实的基础。

737
basic_uis/basic_uis.md Normal file
View File

@@ -0,0 +1,737 @@
# Basic UIs 通用UI组件集合模块
## 模块概述
`basic_uis` 是 OneApp 基础UI模块群中的通用UI组件集合模块负责整合和统一管理所有的UI组件库。该模块提供了一站式的UI组件解决方案包含了动画效果、权限管理、分享功能、地图集成等丰富的UI功能组件。
### 基本信息
- **模块名称**: basic_uis
- **版本**: 0.0.7
- **描述**: 通用UI组件集合包
- **Flutter 版本**: >=1.17.0
- **Dart 版本**: >=3.0.0 <4.0.0
## 功能特性
### 核心功能
1. **UI组件整合**
- 统一的UI组件导出
- 组件库版本管理
- 跨模块组件协调
- 全局UI配置管理
2. **高级UI组件**
- 下拉刷新组件集成
- Lottie动画支持
- WebView组件封装
- 地图视图集成
3. **用户交互组件**
- 权限管理UI组件
- 分享功能UI集成
- 图片保存组件
- 设置页面组件
4. **系统集成组件**
- 位置服务UI
- 应用设置界面
- 用户同意组件
- Toast消息提示
## 技术架构
### 目录结构
```
lib/
├── basic_uis.dart # 模块入口文件
├── src/ # 源代码目录
│ ├── components/ # 通用组件
│ ├── animations/ # 动画组件
│ ├── permissions/ # 权限组件
│ ├── sharing/ # 分享组件
│ ├── webview/ # WebView组件
│ ├── location/ # 位置组件
│ ├── settings/ # 设置组件
│ └── utils/ # 工具类
├── widgets/ # Widget导出
└── themes/ # 主题配置
```
### 依赖关系
#### UI框架依赖
- `easy_refresh: ^3.0.5` - 下拉刷新组件
- `lottie: ^3.1.0` - Lottie动画
- `fluttertoast: ^8.2.2` - Toast提示
- `helpers: ^1.2.3+1` - 辅助工具
#### 功能组件依赖
- `basic_webview: ^0.2.4+4` - WebView组件
- `permission_handler: ^10.4.5` - 权限管理
- `image_gallery_saver: any` - 图片保存
- `share_plus: 7.2.1` - 分享功能
- `flutter_inappwebview: ^6.0.0` - 应用内WebView
#### 业务组件依赖
- `app_consent: ^0.2.19` - 用户同意组件
- `ui_mapview: ^0.2.18` - 地图视图组件
- `app_settings: ^4.3.1` - 应用设置
- `location: ^6.0.1` - 位置服务
#### 内部依赖
- `basic_utils` - 基础工具本地路径
## 核心组件分析
### 1. 模块入口 (`basic_uis.dart`)
**功能职责**:
- 统一导出所有UI组件
- 初始化全局UI配置
- 管理组件生命周期
```dart
library basic_uis;
// 基础组件导出
export 'src/components/enhanced_refresh_indicator.dart';
export 'src/components/lottie_animation_widget.dart';
export 'src/components/permission_request_dialog.dart';
export 'src/components/share_action_sheet.dart';
// WebView组件导出
export 'src/webview/enhanced_webview.dart';
export 'src/webview/webview_controller.dart';
// 位置组件导出
export 'src/location/location_picker_widget.dart';
export 'src/location/map_integration_widget.dart';
// 设置组件导出
export 'src/settings/app_settings_page.dart';
export 'src/settings/permission_settings_widget.dart';
// 工具类导出
export 'src/utils/ui_helpers.dart';
export 'src/utils/toast_utils.dart';
class BasicUIs {
static bool _isInitialized = false;
/// 初始化Basic UIs模块
static Future<void> initialize() async {
if (_isInitialized) return;
// 初始化Toast配置
await _initializeToast();
// 初始化权限处理器
await _initializePermissions();
// 初始化分享服务
await _initializeShare();
// 初始化WebView配置
await _initializeWebView();
_isInitialized = true;
}
}
```
### 2. 增强下拉刷新组件 (`src/components/enhanced_refresh_indicator.dart`)
```dart
class EnhancedRefreshIndicator extends StatefulWidget {
final Widget child;
final Future<void> Function() onRefresh;
final Future<void> Function()? onLoadMore;
final RefreshIndicatorConfig? config;
final bool enablePullUp;
final bool enablePullDown;
const EnhancedRefreshIndicator({
Key? key,
required this.child,
required this.onRefresh,
this.onLoadMore,
this.config,
this.enablePullUp = true,
this.enablePullDown = true,
}) : super(key: key);
@override
State<EnhancedRefreshIndicator> createState() => _EnhancedRefreshIndicatorState();
}
class _EnhancedRefreshIndicatorState extends State<EnhancedRefreshIndicator> {
late EasyRefreshController _controller;
@override
Widget build(BuildContext context) {
return EasyRefresh(
controller: _controller,
onRefresh: widget.enablePullDown ? _onRefresh : null,
onLoad: widget.enablePullUp && widget.onLoadMore != null ? _onLoad : null,
header: _buildRefreshHeader(),
footer: _buildLoadFooter(),
child: widget.child,
);
}
Widget _buildRefreshHeader() {
return ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '正在刷新...',
processingText: '正在刷新...',
processedText: '刷新完成',
noMoreText: '没有更多数据',
failedText: '刷新失败',
messageText: '最后更新于 %T',
);
}
Widget _buildLoadFooter() {
return ClassicFooter(
dragText: '上拉加载',
armedText: '释放加载',
readyText: '正在加载...',
processingText: '正在加载...',
processedText: '加载完成',
noMoreText: '没有更多数据',
failedText: '加载失败',
);
}
}
```
### 3. Lottie动画组件 (`src/animations/lottie_animation_widget.dart`)
```dart
class LottieAnimationWidget extends StatefulWidget {
final String assetPath;
final double? width;
final double? height;
final bool repeat;
final bool autoPlay;
final AnimationController? controller;
final VoidCallback? onComplete;
const LottieAnimationWidget({
Key? key,
required this.assetPath,
this.width,
this.height,
this.repeat = true,
this.autoPlay = true,
this.controller,
this.onComplete,
}) : super(key: key);
@override
State<LottieAnimationWidget> createState() => _LottieAnimationWidgetState();
}
class _LottieAnimationWidgetState extends State<LottieAnimationWidget>
with TickerProviderStateMixin {
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = widget.controller ??
AnimationController(vsync: this);
if (widget.autoPlay) {
_animationController.forward();
}
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
widget.onComplete?.call();
if (widget.repeat) {
_animationController.repeat();
}
}
});
}
@override
Widget build(BuildContext context) {
return Lottie.asset(
widget.assetPath,
width: widget.width,
height: widget.height,
controller: _animationController,
onLoaded: (composition) {
_animationController.duration = composition.duration;
if (widget.autoPlay) {
_animationController.forward();
}
},
);
}
@override
void dispose() {
if (widget.controller == null) {
_animationController.dispose();
}
super.dispose();
}
}
```
### 4. 权限请求对话框 (`src/permissions/permission_request_dialog.dart`)
```dart
class PermissionRequestDialog extends StatelessWidget {
final Permission permission;
final String title;
final String description;
final String? rationale;
final VoidCallback? onGranted;
final VoidCallback? onDenied;
const PermissionRequestDialog({
Key? key,
required this.permission,
required this.title,
required this.description,
this.rationale,
this.onGranted,
this.onDenied,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Row(
children: [
Icon(_getPermissionIcon(), color: Theme.of(context).primaryColor),
const SizedBox(width: 12),
Expanded(child: Text(title)),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(description),
if (rationale != null) ...[
const SizedBox(height: 16),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(Icons.info_outline,
color: Colors.blue, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
rationale!,
style: TextStyle(
color: Colors.blue[700],
fontSize: 14,
),
),
),
],
),
),
],
],
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
onDenied?.call();
},
child: const Text('拒绝'),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
final status = await permission.request();
if (status.isGranted) {
onGranted?.call();
} else {
onDenied?.call();
if (status.isPermanentlyDenied) {
_showSettingsDialog(context);
}
}
},
child: const Text('允许'),
),
],
);
}
IconData _getPermissionIcon() {
switch (permission) {
case Permission.camera:
return Icons.camera_alt;
case Permission.microphone:
return Icons.mic;
case Permission.location:
return Icons.location_on;
case Permission.storage:
return Icons.storage;
case Permission.photos:
return Icons.photo_library;
default:
return Icons.security;
}
}
void _showSettingsDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('权限设置'),
content: const Text('请在设置中手动开启所需权限'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
openAppSettings();
},
child: const Text('去设置'),
),
],
),
);
}
}
```
### 5. 分享操作表 (`src/sharing/share_action_sheet.dart`)
```dart
class ShareActionSheet extends StatelessWidget {
final ShareContent content;
final List<SharePlatform> platforms;
final Function(SharePlatform)? onPlatformSelected;
const ShareActionSheet({
Key? key,
required this.content,
required this.platforms,
this.onPlatformSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildHandle(),
const SizedBox(height: 20),
Text(
'分享到',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 20),
_buildPlatformGrid(context),
const SizedBox(height: 20),
_buildMoreActions(context),
],
),
);
}
Widget _buildPlatformGrid(BuildContext context) {
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 1,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
),
itemCount: platforms.length,
itemBuilder: (context, index) {
final platform = platforms[index];
return _buildPlatformItem(context, platform);
},
);
}
Widget _buildPlatformItem(BuildContext context, SharePlatform platform) {
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
onPlatformSelected?.call(platform);
_shareToplatform(platform);
},
child: Column(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: platform.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
platform.icon,
color: platform.color,
size: 30,
),
),
const SizedBox(height: 8),
Text(
platform.name,
style: Theme.of(context).textTheme.bodySmall,
textAlign: TextAlign.center,
),
],
),
);
}
Future<void> _shareToplatform(SharePlatform platform) async {
try {
switch (platform.type) {
case SharePlatformType.system:
await Share.share(content.text, subject: content.title);
break;
case SharePlatformType.wechat:
// 微信分享逻辑
break;
case SharePlatformType.weibo:
// 微博分享逻辑
break;
case SharePlatformType.qq:
// QQ分享逻辑
break;
}
} catch (e) {
ToastUtils.showError('分享失败: $e');
}
}
}
```
## 工具类
### Toast工具类 (`src/utils/toast_utils.dart`)
```dart
class ToastUtils {
static void showSuccess(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.green,
textColor: Colors.white,
fontSize: 16.0,
);
}
static void showError(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0,
);
}
static void showInfo(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.blue,
textColor: Colors.white,
fontSize: 16.0,
);
}
static void showWarning(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.orange,
textColor: Colors.white,
fontSize: 16.0,
);
}
}
```
## 使用示例
### 基础使用
```dart
class BasicUIsExample extends StatefulWidget {
@override
_BasicUIsExampleState createState() => _BasicUIsExampleState();
}
class _BasicUIsExampleState extends State<BasicUIsExample> {
@override
void initState() {
super.initState();
_initializeBasicUIs();
}
Future<void> _initializeBasicUIs() async {
await BasicUIs.initialize();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Basic UIs Example')),
body: EnhancedRefreshIndicator(
onRefresh: _handleRefresh,
onLoadMore: _handleLoadMore,
child: ListView(
children: [
// Lottie动画示例
LottieAnimationWidget(
assetPath: 'assets/animations/loading.json',
width: 100,
height: 100,
),
// 权限请求示例
ListTile(
title: Text('请求相机权限'),
onTap: () => _requestCameraPermission(),
),
// 分享功能示例
ListTile(
title: Text('分享内容'),
onTap: () => _showShareSheet(),
),
// Toast示例
ListTile(
title: Text('显示Toast'),
onTap: () => ToastUtils.showSuccess('操作成功'),
),
],
),
),
);
}
Future<void> _handleRefresh() async {
await Future.delayed(Duration(seconds: 2));
ToastUtils.showSuccess('刷新完成');
}
Future<void> _handleLoadMore() async {
await Future.delayed(Duration(seconds: 1));
}
void _requestCameraPermission() {
showDialog(
context: context,
builder: (context) => PermissionRequestDialog(
permission: Permission.camera,
title: '相机权限',
description: '需要相机权限来拍照和录制视频',
rationale: '此权限用于扫描二维码和拍照功能',
onGranted: () => ToastUtils.showSuccess('权限已授予'),
onDenied: () => ToastUtils.showError('权限被拒绝'),
),
);
}
void _showShareSheet() {
showModalBottomSheet(
context: context,
builder: (context) => ShareActionSheet(
content: ShareContent(
title: 'OneApp',
text: '快来体验OneApp的强大功能',
url: 'https://oneapp.com',
),
platforms: [
SharePlatform.system(),
SharePlatform.wechat(),
SharePlatform.weibo(),
SharePlatform.qq(),
],
onPlatformSelected: (platform) {
ToastUtils.showInfo('分享到${platform.name}');
},
),
);
}
}
```
## 性能优化
### 组件优化
- **懒加载**: 按需加载重型组件
- **Widget缓存**: 缓存不变的Widget实例
- **动画优化**: 合理使用动画避免过度渲染
- **内存管理**: 及时释放资源和控制器
### 集成优化
- **依赖管理**: 避免重复依赖和版本冲突
- **包大小**: 优化资源文件减少包大小
- **初始化**: 异步初始化避免阻塞启动
- **缓存策略**: 合理使用缓存提升性能
## 测试策略
### Widget测试
- **组件渲染测试**: 验证组件正确渲染
- **交互测试**: 测试用户交互响应
- **动画测试**: 测试动画效果
- **权限测试**: 测试权限请求流程
### 集成测试
- **模块集成测试**: 测试模块间协作
- **第三方服务测试**: 测试外部服务集成
- **性能测试**: 测试组件性能表现
- **兼容性测试**: 测试平台兼容性
## 最佳实践
### 组件使用
1. **统一入口**: 通过BasicUIs统一初始化
2. **配置管理**: 集中管理组件配置
3. **错误处理**: 完善的错误处理机制
4. **用户体验**: 注重用户交互体验
### 开发规范
1. **代码规范**: 遵循统一的代码规范
2. **文档完善**: 提供详细的使用文档
3. **版本管理**: 合理的版本发布策略
4. **测试覆盖**: 保证充分的测试覆盖
## 总结
`basic_uis` 模块作为 OneApp 的通用UI组件集合整合了丰富的UI功能组件和第三方服务为应用开发提供了一站式的UI解决方案通过统一的管理和标准化的接口大大提升了开发效率和用户体验的一致性模块具有良好的扩展性和可维护性能够适应不断变化的UI需求

View File

@@ -0,0 +1,446 @@
# General UI Component 通用UI组件模块
## 模块概述
`general_ui_component` 是 OneApp 基础UI模块群中的通用UI组件模块专门提供可复用的通用界面组件。该模块实现了通用的项目组件和分享对话框等核心功能。
### 基本信息
- **模块名称**: general_ui_component
- **版本**: 0.0.1
- **描述**: 通用UI组件库
- **Flutter 版本**: >=1.17.0
## 核心组件
### 1. 项目组件 (ItemAComponent)
基于真实项目代码的通用项目展示组件:
```dart
/// 通用项目组件A用于显示带图标和标题的项目
class ItemAComponent extends StatelessWidget {
/// Logo图片URL
String logoImg = '';
/// 标题文本
String title = '';
/// 点击回调函数
OnItemAClick onItemAClick;
/// 项目索引
int index;
/// 自定义尺寸(可选)
double? size;
ItemAComponent({
required this.title,
required this.logoImg,
required this.onItemAClick,
required this.index,
this.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);
```
### 2. 分享对话框 (ShareDialog)
基于真实项目代码的分享功能对话框:
```dart
/// 分享对话框组件
class Sharedialog extends StatelessWidget {
/// 项目点击回调
OnItemAClick onItemAClick;
/// 分享项目名称列表
List<String> itemNameList;
/// 底部操作组件(可选)
Widget? bottomActionWidget;
Sharedialog({
required this.onItemAClick,
required this.itemNameList,
this.bottomActionWidget,
});
@override
Widget build(BuildContext context) {
if (itemNameList.isNotEmpty) {
List<Widget> itemWidgetList = [];
for (int i = 0; i < itemNameList.length; i++) {
// 添加间距
if (bottomActionWidget != null) {
itemWidgetList.add(SizedBox(
width: width(designWidgetWidth: 36),
));
}
// 根据类型创建不同的分享项目
switch (itemNameList[i]) {
case 'weibo':
itemWidgetList.add(_createShareItem(
title: BasicUisIntlDelegate.current.Weibo,
logoImg: 'packages/basic_uis/assets/icon/weibo.png',
index: i,
));
break;
case 'weixin':
itemWidgetList.add(_createShareItem(
title: BasicUisIntlDelegate.current.WeChat,
logoImg: 'packages/basic_uis/assets/icon/wechat.png',
index: i,
));
break;
case 'friends':
itemWidgetList.add(_createShareItem(
title: BasicUisIntlDelegate.current.FriendCircle,
logoImg: 'packages/basic_uis/assets/icon/moments.png',
index: i,
));
break;
case 'copy':
itemWidgetList.add(_createShareItem(
title: BasicUisIntlDelegate.current.copyLink,
logoImg: 'packages/basic_uis/assets/icon/copy_link.png',
index: i,
size: width(designWidgetWidth: 20),
));
break;
}
}
return Container(
child: Wrap(
children: itemWidgetList,
),
);
}
return Container();
}
/// 创建分享项目组件
Widget _createShareItem({
required String title,
required String logoImg,
required int index,
double? size,
}) {
return ItemAComponent(
title: title,
logoImg: logoImg,
index: index,
size: size,
onItemAClick: (int index) => onItemAClick(index),
);
}
}
```
## 技术架构
### 目录结构
基于实际项目结构:
```
lib/
├── ItemAComponent.dart # 通用项目组件
└── share/ # 分享功能相关
├── dialog/ # 分享对话框
│ └── ShareDialog.dart # 分享对话框实现
└── util/ # 分享工具类
```
### 依赖关系
基于实际项目依赖:
```dart
// 国际化支持
import 'package:basic_uis/generated/l10n.dart';
import 'package:basic_utils/generated/l10n.dart';
// UI基础组件
import 'package:ui_basic/ui_basic.dart';
// 基础工具
import 'package:basic_utils/basic_utils.dart';
// 缓存图片组件
import 'package:basic_uis/src/common_components/cache_image_component.dart';
```
## 使用指南
### 1. ItemAComponent 使用示例
```dart
import 'package:general_ui_component/ItemAComponent.dart';
class ServiceGridPage extends StatelessWidget {
final List<ServiceItem> services = [
ServiceItem('充电服务', 'assets/icons/charging.png'),
ServiceItem('维修保养', 'assets/icons/maintenance.png'),
ServiceItem('道路救援', 'assets/icons/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}');
// 处理服务选择逻辑
}
}
class ServiceItem {
final String name;
final String iconUrl;
ServiceItem(this.name, this.iconUrl);
}
```
### 2. ShareDialog 分享功能使用
```dart
import 'package:general_ui_component/share/dialog/ShareDialog.dart';
class ShareExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => _showShareDialog(context),
child: Text('分享内容'),
);
}
void _showShareDialog(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) => Sharedialog(
itemNameList: ['weixin', 'friends', 'weibo', 'copy'],
onItemAClick: _handleShareAction,
bottomActionWidget: Padding(
padding: EdgeInsets.all(16.0),
child: Text('选择分享方式'),
),
),
);
}
void _handleShareAction(int index) {
switch (index) {
case 0:
print('分享到微信');
break;
case 1:
print('分享到朋友圈');
break;
case 2:
print('分享到微博');
break;
case 3:
print('复制链接');
break;
}
}
}
## 依赖配置
### pubspec.yaml 关键依赖
```yaml
dependencies:
flutter:
sdk: flutter
# 国际化支持
basic_uis:
path: ../basic_uis
# 基础工具
basic_utils:
path: ../../oneapp_basic_utils/basic_utils
# UI基础组件
ui_basic:
path: ../ui_basic
dev_dependencies:
build_runner: any
freezed: ^2.3.5
flutter_lints: ^5.0.0
```
## 最佳实践
### 1. 组件复用
```dart
// 推荐:创建配置化的服务列表
Widget buildServiceGrid({
required List<ServiceItem> services,
required OnItemAClick onItemClick,
}) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.0,
),
itemCount: services.length,
itemBuilder: (context, index) {
final service = services[index];
return ItemAComponent(
title: service.name,
logoImg: service.iconUrl,
index: index,
onItemAClick: onItemClick,
);
},
);
}
```
### 2. 分享功能集成
```dart
// 推荐:封装分享功能
class ShareHelper {
static void showShareDialog(
BuildContext context,
String content, {
List<String> platforms = const ['weixin', 'friends', 'weibo', 'copy'],
}) {
showModalBottomSheet(
context: context,
builder: (context) => Sharedialog(
itemNameList: platforms,
onItemAClick: (index) => _handleShare(context, content, platforms[index]),
),
);
}
static void _handleShare(BuildContext context, String content, String platform) {
// 实际分享逻辑实现
Navigator.pop(context);
}
}
```
### 3. 主题适配
```dart
// 推荐:支持主题切换
ItemAComponent(
title: service.name,
logoImg: service.iconUrl,
index: index,
onItemAClick: onItemClick,
// 自动适配当前主题
)
```
## 项目集成
### 模块依赖关系
```dart
// 实际项目中的依赖导入
import 'package:basic_uis/generated/l10n.dart'; // 国际化
import 'package:basic_utils/basic_utils.dart'; // 工具类
import 'package:ui_basic/ui_basic.dart'; // UI基础
import 'package:flutter/material.dart'; // Flutter核心
```
### 使用建议
1. **性能优化**:使用`const`构造函数优化重建性能
2. **内存管理**:及时释放不用的控制器和监听器
3. **主题一致性**使用OneColors主题颜色系统
4. **国际化支持**使用BasicUisIntlDelegate进行文本国际化
## 总结
`general_ui_component` 模块提供了OneApp项目中的核心通用UI组件包括
- **ItemAComponent**: 通用项目展示组件,支持圆形图标和文本标题
- **ShareDialog**: 分享功能对话框,支持微信、朋友圈、微博、复制等分享方式
- **完整的依赖管理**: 与OneApp其他模块的良好集成
- **国际化支持**: 完整的中英文多语言支持
这些组件为OneApp提供了统一的UI设计语言和交互模式确保了应用界面的一致性和可维护性。

407
basic_uis/ui_basic.md Normal file
View File

@@ -0,0 +1,407 @@
# UI Basic 基础UI组件模块
## 模块概述
`ui_basic` 是 OneApp 基础UI模块群中的核心组件库提供了应用开发中常用的基础UI组件和交互元素。该模块封装了通用的界面组件、布局容器、表单元素等为整个应用提供统一的设计语言和用户体验。
### 基本信息
- **模块名称**: ui_basic
- **版本**: 0.2.45
- **仓库**: https://gitlab-rd0.maezia.com/dssomobile/oneapp/dssomobile-oneapp-ui-basic
- **Flutter 版本**: >=1.17.0
- **Dart 版本**: >=2.17.0 <4.0.0
- **发布服务器**: http://175.24.250.68:4000/
## 功能特性
### 核心功能
基于实际项目的UI组件库包含丰富的组件和第三方集成
1. **基础组件库**
- 按钮组件OneIconButtonCommonButton
- 输入组件BasicTextFieldBasicMultiTextFieldVehiclePlateField
- 展示组件OneTagOneCardProgressWidget
- 导航组件CommonTitleBarCommonTabbar
2. **交互组件**
- 上拉下拉刷新pull_to_refresh集成
- 轮播图组件OneSwipercarousel_slider集成
- 对话框和弹窗OneDialogXCommonBottomSheet
- 加载指示器LoadingWidgetCommonLoadingWidget
3. **多媒体组件**
- 图片组件GlinettImageImageWidgetCachedNetworkImage集成
- 扫码组件QrScannerWidgetflutter_scankit集成
- 相机组件CameraWidgetcamera集成
- SVG支持flutter_svg集成
4. **富文本和图表**
- HTML富文本渲染flutter_html集成
- 图表组件OneChartfl_chart集成
- ECharts集成FlutterEcharts
- 评分组件RatingWidgetflutter_rating_bar集成
## 技术架构
### 目录结构
```
lib/
├── ui_basic.dart # 模块入口文件
├── src/ # 源代码目录
│ ├── components/ # 基础组件
│ ├── containers/ # 布局容器
│ ├── interactions/ # 交互组件
│ ├── themes/ # 主题配置
│ ├── utils/ # 工具类
│ └── constants/ # 常量定义
├── widgets/ # 组件导出
└── themes/ # 主题文件
```
### 依赖关系
基于实际项目的pubspec.yaml配置展示真实的依赖架构
#### 框架依赖
```yaml
# 核心框架依赖
dependencies:
basic_network: ^0.2.3+4 # 网络通信基础
basic_modular: ^0.2.3 # 模块化框架
basic_modular_route: ^0.2.1 # 路由管理
basic_intl_flutter: ^0.2.2+1 # 国际化支持
basic_theme_core: ^0.2.5 # 主题核心
ui_basic_annotation: ^0.2.0 # UI框架注解
```
#### UI和交互依赖
```yaml
# UI组件和交互依赖
dependencies:
provider: ^6.0.5 # 状态管理
flutter_html: ^3.0.0-beta.2 # HTML富文本渲染
badges: ^3.1.1 # 角标组件
pull_to_refresh: ^2.0.0 # 上拉下拉刷新
carousel_slider: ^4.2.1 # 轮播图组件
cached_network_image: ^3.3.0 # 缓存网络图片
flutter_svg: ^2.0.6 # SVG图片支持
flutter_smart_dialog: ^4.9.1 # 智能对话框
visibility_detector: ^0.4.0+2# 可见性检测
fl_chart: ^0.x.x # 图表组件
```
#### 多媒体和工具依赖
```yaml
# 多媒体和工具依赖
dependencies:
camera: ^0.10.5+2 # 相机功能
image_picker: ^1.1.2 # 图片选择
image_cropper: ^9.1.0 # 图片裁剪
flutter_image_compress: ^2.0.3# 图片压缩
flutter_scankit: 2.0.3+1 # 扫码工具
url_launcher: ^6.1.11 # URL跳转
flutter_rating_bar: ^4.0.1 # 评分组件
sprintf: ^7.0.0 # 字符串格式化
dartz: ^0.10.1 # 函数式编程
rxdart: ^0.27.7 # 响应式编程
```
## 核心组件分析
### 1. 模块入口 (`ui_basic.dart`)
基于真实项目的模块导出结构包含大量第三方库集成和自定义组件
**功能职责**:
- 统一导出所有UI组件和第三方库
- 集成badgecached_network_imageflutter_html等核心UI库
- 导出自定义组件如OneColorsOneTextStyleOneIcons
- 提供car_func_block等车辆相关UI组件
```dart
// 实际的模块导出结构ui_basic.dart
library ui_basic;
// 第三方UI库集成
export 'package:badges/badges.dart';
export 'package:cached_network_image/cached_network_image.dart';
export 'package:flutter_html/flutter_html.dart';
export 'package:flutter_svg/flutter_svg.dart';
export 'package:visibility_detector/visibility_detector.dart';
export 'package:bottom_sheet/bottom_sheet.dart';
export 'package:fl_chart/fl_chart.dart';
// 自定义组件导出
export 'src/colors/colors.dart' show OneColors;
export 'src/fonts/fonts.dart' show OneTextStyle, TextFont, OneBasicText;
export 'src/icon/icon.dart' show OneIcons;
// UI组件导出
export 'src/components/appbar/common_title_bar.dart';
export 'src/components/button/buttons.dart';
export 'src/components/dialog/dialog_export.dart';
export 'src/components/loading/loading_widget.dart';
export 'src/components/text_field/basic_text_field.dart';
export 'src/components/cards/cards_export.dart';
// 车辆功能组件
export 'src/car_func_block/car_func_block_class.dart';
export 'src/car_func_block/car_func_block_manager.dart';
// 工具类导出
export 'src/utils/qr_scanner_util/qr_scanner_util.dart';
export 'src/utils/image_util/image_util.dart';
export 'src/utils/launcher/launch_util.dart';
```
### 2. 主题颜色系统 (`src/colors/colors.dart`)
基于主题核心框架的动态颜色系统支持主题切换和自定义颜色
```dart
// 实际的颜色系统实现
class OneColors {
/// 主题色 Primary Color
static Color get primary =>
theme.ofStandard().themeData?.appColors?.primary ??
const Color(0xFFEED484);
/// 背景色 Bgc
static Color get bgc =>
theme.ofStandard().themeData?.appColors?.backgroundColors.bgc ??
const Color(0xFFFFFFFF);
/// 背景色 辅助1-5
static Color get bgcSub1 =>
theme.ofStandard().themeData?.appColors?.backgroundColors.bgcSub1 ??
const Color(0xFFFFFFFF);
// ... 更多背景色变体
/// 动态主题获取
static ITheme get theme => uiBasicPlatformInfoDeps.theme != null
? uiBasicPlatformInfoDeps.theme!
: DefaultTheme(
DefaultStandardResource(),
DefaultUiKitResource(),
);
}
```
### 4. 按钮组件 (`src/components/button/buttons.dart`)
基于真实项目的按钮组件实现支持多种按钮类型和状态管理
```dart
// 实际的按钮状态枚举
enum BtnLoadingStatus {
/// 初始化
idle,
/// 加载中
loading,
}
/// 按钮类型枚举
enum BtnType {
/// TextButton
text,
/// ElevatedButton
elevated,
/// OutlineButton
outline,
}
/// 实际的图标按钮组件
class OneIconButton extends StatelessWidget {
const OneIconButton({
required this.child,
this.iconSize,
this.cubit,
this.onPress,
this.style,
Key? key,
}) : super(key: key);
/// 按钮内容
final Widget child;
/// 字体大小
final double? iconSize;
/// 状态管理
final OneIconButtonCubit? cubit;
/// 点击回调
final VoidCallback? onPress;
/// 样式配置
final ButtonStyle? style;
@override
Widget build(BuildContext context) {
// 实际的按钮实现逻辑
// 支持状态管理和样式定制
}
}
/// 通用按钮组件
class CommonButton extends StatelessWidget {
// 支持加载状态、不同按钮类型、自定义样式等
// 集成BLoC状态管理和主题系统
}
```
### 5. 文本输入组件 (`src/components/text_field/`)
包含多种文本输入组件的真实实现
```dart
// 基础文本输入字段
export 'src/components/text_field/basic_text_field.dart';
export 'src/components/text_field/basic_multi_text_field.dart';
export 'src/components/text_field/clear_text_field.dart';
export 'src/components/text_field/edit_text/edit_text.dart';
// 特殊用途文本字段
export 'src/components/text_field/vehicle_plate_field/vehicle_plate_field_widget.dart';
// 实际支持的功能:
// - 基础文本输入
// - 多行文本输入
// - 带清除按钮的文本输入
// - 车牌号输入专用组件
// - 集成表单验证和状态管理
```
### 7. 第三方UI库集成
ui_basic模块集成了大量优秀的第三方UI库提供开箱即用的功能
```dart
// 图标和标记组件
export 'package:badges/badges.dart'; // 角标组件
export 'package:font_awesome_flutter/font_awesome_flutter.dart'; // FontAwesome图标
// 图片和多媒体
export 'package:cached_network_image/cached_network_image.dart'; // 缓存网络图片
export 'package:flutter_svg/flutter_svg.dart'; // SVG支持
export 'package:dd_js_util/dd_js_util.dart'; // 九宫格图片选择
// 富文本和格式化
export 'package:flutter_html/flutter_html.dart'; // HTML渲染
export 'package:sprintf/sprintf.dart'; // 字符串格式化
export 'package:auto_size_text/auto_size_text.dart'; // 自适应文本
// 交互组件
export 'package:bottom_sheet/bottom_sheet.dart'; // 底部弹出框
export 'package:visibility_detector/visibility_detector.dart'; // 可见性检测
export 'package:extended_tabs/extended_tabs.dart'; // 扩展Tab组件
// 图表组件
export 'package:fl_chart/fl_chart.dart'; // Flutter图表库
// 轮播组件
export 'package:flutter_swiper_null_safety_flutter3/flutter_swiper_null_safety_flutter3.dart';
```
### 8. 工具类组件 (`src/utils/`)
丰富的工具类支持涵盖图片处理扫码启动器等功能
```dart
// 图片相关工具
export 'src/utils/image_util/image_util.dart';
export 'src/utils/image_solution/image_solution_tools.dart';
export 'src/utils/image_cropper_util/nativate_image_cropper.dart';
// 扫码相关
export 'src/utils/qr_processor/qr_processor.dart';
export 'src/utils/qr_scanner_util/qr_scanner_util.dart';
// 系统交互
export 'src/utils/launcher/launch_util.dart'; // URL启动器
export 'src/utils/imm/custom_imm.dart'; // 输入法管理
// 订单管理
export 'src/utils/order_category_manager/order_category_factory.dart';
export 'src/utils/order_category_manager/order_category_manager.dart';
// 其他工具
export 'src/utils/keep_alive.dart'; // KeepAlive包装器
export 'src/utils/widget_utils.dart'; // Widget工具类
export 'src/utils/methods.dart' show formatDate; // 格式化方法
```
### 9. 特色组件
针对OneApp应用特点开发的专用组件
```dart
// 车牌号相关
export 'src/components/one_license_plate_number/one_license_plate_number.dart';
export 'src/components/text_field/vehicle_plate_field/vehicle_plate_field_widget.dart';
// 车辆HVAC相关
export 'src/components/widgets/car_hvac_other_widget.dart';
// 香氛组件
export 'src/components/fragrance/fragrance_widget.dart';
// 步进器组件
export 'src/components/stepper/stepper_widget.dart';
// 验证码组件
export 'src/components/verification_code/verification_box.dart';
export 'src/components/verification_code/code_widget.dart';
// 时间选择器
export 'src/components/time_picker/common_time_picker.dart';
export 'src/components/time_picker/ym_time_picker.dart';
// 可扩展GridView
export 'src/components/gridview/expandable_gridview.dart';
// 瀑布流ScrollView
export 'src/components/widgets/staggered_scrollview_widget.dart';
export 'src/components/widgets/reorderable_staggered_scroll_view_widget.dart';
```
## 性能优化
### 组件优化策略
- **Widget缓存**: 缓存不变的Widget实例
- **局部更新**: 使用Consumer精确控制更新范围
- **延迟构建**: 使用Builder延迟构建复杂组件
- **内存管理**: 及时释放资源和控制器
### 渲染优化
- **RepaintBoundary**: 隔离重绘区域
- **ListView.builder**: 使用懒加载列表
- **Image优化**: 合理使用缓存和压缩
- **动画优化**: 使用硬件加速动画
## 测试策略
### Widget测试
- **组件渲染测试**: 验证组件正确渲染
- **交互测试**: 测试用户交互响应
- **主题测试**: 验证主题正确应用
- **响应式测试**: 测试不同屏幕尺寸适配
### 单元测试
- **工具类测试**: 测试工具方法功能
- **状态管理测试**: 测试状态变化逻辑
- **数据模型测试**: 测试数据序列化
## 最佳实践
### 组件设计原则
1. **单一职责**: 每个组件功能单一明确
2. **可复用性**: 设计通用的可复用组件
3. **可配置性**: 提供丰富的配置选项
4. **一致性**: 保持设计风格一致
### 使用建议
1. **主题使用**: 优先使用主题颜色和样式
2. **响应式设计**: 考虑不同屏幕尺寸适配
3. **无障碍访问**: 添加语义标签和辅助功能
4. **性能考虑**: 避免不必要的重建和重绘
## 总结
`ui_basic` 模块作为 OneApp 的基础UI组件库提供了丰富的界面组件和交互元素通过统一的设计语言灵活的主题系统和完善的组件生态为整个应用提供了一致的用户体验模块具有良好的可扩展性和可维护性能够满足各种界面开发需求

549
basic_uis/ui_business.md Normal file
View 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状态变化日志
- 验证表单验证逻辑