Commit 5bd72d8e authored by 张宏's avatar 张宏

应用名称及图标修改

parent 95546f15
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="smart_hotel_app"
android:label="智能酒店"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
......
......@@ -3,10 +3,9 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
android:src="@drawable/launch_image" />
</item>
</layer-list>
......@@ -3,10 +3,9 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
android:src="@drawable/launch_image" />
</item>
</layer-list>
......@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Smart Hotel App</string>
<string>智能酒店</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
......
......@@ -17,7 +17,7 @@ class ServiceStatsBlock extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
padding: EdgeInsets.only(top: 20.w, bottom: 20.w),
decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(24.r),
color: Color.fromRGBO(242, 243, 245, 1.0),
......
......@@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.4.1"
archive:
dependency: transitive
description:
name: archive
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
url: "https://pub.dev"
source: hosted
version: "4.0.9"
args:
dependency: transitive
description:
......@@ -145,6 +153,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
url: "https://pub.dev"
source: hosted
version: "0.4.2"
clock:
dependency: transitive
description:
......@@ -286,6 +302,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.6"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
......@@ -424,6 +448,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.1.2"
image:
dependency: transitive
description:
name: image
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
url: "https://pub.dev"
source: hosted
version: "4.8.0"
io:
dependency: transitive
description:
......@@ -656,6 +688,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.2"
posix:
dependency: transitive
description:
name: posix
sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07"
url: "https://pub.dev"
source: hosted
version: "6.5.0"
provider:
dependency: transitive
description:
......
......@@ -62,6 +62,7 @@ dev_dependencies:
flutter_lints: ^2.0.0
auto_route_generator: ^7.3.2
build_runner: ^2.4.9
flutter_launcher_icons: ^0.13.1
# 依赖覆盖 - 解决 win32-5.2.0 与 Dart 3.10 兼容性问题
dependency_overrides:
......@@ -111,3 +112,9 @@ flutter:
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
flutter_launcher_icons:
android: "ic_launcher"
ios: true
image_path: "lib/assets/login/logo@2x.png"
min_sdk_android: 21
# 智慧酒店 App - 技术及流程文档
++ /dev/null
# 智慧酒店 App - 技术及流程文档
## 一、项目概览
| 项目 | 说明 |
|------|------|
| 项目名称 | smart_hotel_app |
| 类型 | Flutter 移动端 App |
| 用途 | 智慧酒店运营管理(设备告警、客房服务、经营看板、能耗分析) |
| Dart SDK | >=3.2.5 <4.0.0 |
| 设计稿基准 | 750 x 1334 (逻辑像素) |
| 路由方案 | auto_route (代码生成) |
| 状态管理 | flutter_bloc (BLoC 模式) |
| 网络请求 | Dio (单例封装) |
| 安全存储 | flutter_secure_storage |
---
## 二、技术栈
### 2.1 核心依赖
| 依赖 | 版本 | 用途 |
|------|------|------|
| `flutter_bloc` | ^8.1.5 | 状态管理(BLoC 模式) |
| `equatable` | ^2.0.5 | 值对象相等性比较(用于 Event/State) |
| `auto_route` | ^7.9.2 | 声明式路由管理 |
| `auto_route_generator` | ^7.3.2 | 路由代码生成器(dev) |
| `build_runner` | ^2.4.9 | 代码生成运行器(dev) |
| `dio` | ^5.4.0 | HTTP 网络请求 |
| `flutter_secure_storage` | ^9.0.0 | 安全本地存储(Token、密码) |
| `flutter_screenutil` | ^5.9.3 | 屏幕适配(基于 750x1334 设计稿) |
| `fluttertoast` | ^8.2.5 | Toast 提示 |
| `fl_chart` | ^1.2.0 | 图表组件(温度曲线、能耗柱状图等) |
| `loading_animation_widget` | ^1.3.0 | 加载动画 |
| `flutter_switch` | ^0.3.2 | 开关组件 |
### 2.2 静态资源
```
lib/assets/
├── icon/ # 图标(jth.png, person1.png, right.png)
├── login/ # 登录页 logo
└── tab/ # 底部导航 tab 图标(选中/未选中)
```
---
## 三、项目目录结构
```
lib/
├── main.dart # 应用入口,初始化依赖,BLoC 监听
├── assets/ # 静态图片资源
│ ├── icon/
│ ├── login/
│ └── tab/
├── blocs/ # 状态管理(BLoC 模式)
│ └── auth/
│ ├── auth_bloc.dart # 认证 BLoC 逻辑
│ ├── auth_event.dart # 认证事件定义
│ └── auth_state.dart # 认证状态定义
├── http/ # 网络请求层
│ ├── dio_request.dart # Dio 单例封装(GET/POST/PUT/DELETE/PATCH/上传/下载)
│ ├── response_model.dart # 统一响应模型 ResponseModel<T>
│ ├── exceptions/ # 异常定义
│ │ ├── app_exception.dart # 基础异常类
│ │ ├── business_exception.dart # 业务异常(400/401/403)
│ │ ├── cancel_exception.dart # 请求取消异常
│ │ ├── network_exception.dart # 网络超时异常
│ │ └── server_exception.dart # 服务端异常(404/500+)
│ └── interceptors/ # Dio 拦截器
│ ├── request_interceptor.dart # 请求拦截器(添加 Token/UUID/Header)
│ ├── response_interceptor.dart # 响应拦截器(日志打印)
│ └── error_interceptor.dart # 错误拦截器(异常转换 + 401 事件触发)
├── models/ # 数据模型
│ └── bo/ # 业务对象(Business Object)
│ └── user_info_bo.dart # 用户信息模型
├── repositories/ # 数据仓库层
│ └── auth_repository.dart # 认证仓库(调用 API)
├── routes/ # 路由配置
│ ├── app_router.dart # 路由定义(手动编写)
│ └── app_router.gr.dart # 路由生成代码(auto_route 自动生成)
├── services/ # 业务服务层
│ └── auth_service.dart # 认证服务(登录/Token 过期检查)
├── utils/ # 工具类
│ ├── constants.dart # 全局常量(BaseUrl/超时/业务码/Token 等)
│ ├── event_bus.dart # 全局事件总线(TokenExpiredEvent / LogoutEvent)
│ ├── logger.dart # 日志工具(Log.info/error/request/response)
│ └── storage/ # 本地存储
│ └── storage_service.dart # SecureStorage 封装(Token/记住密码)
└── views/ # 页面视图
├── layout/
│ └── default_view.dart # 主布局(BottomNavigationBar + Tab 页)
├── login/ # 登录模块
│ ├── login_view.dart # 登录页面
│ ├── controller.dart # 登录控制器
│ └── child/ # 登录子组件
│ ├── btn_login.dart # 登录按钮
│ ├── btn_reset.dart # 重置按钮
│ ├── password_field.dart # 密码输入框
│ ├── remember_password_row.dart # 记住密码行
│ └── username_field.dart # 用户名输入框
├── home/ # 首页(告警)模块
│ ├── index/ # 首页概览
│ │ ├── index_view.dart
│ │ ├── controller.dart
│ │ └── child/
│ │ ├── task_head_block.dart # 头部标题
│ │ ├── task_total_block.dart # 任务统计卡片
│ │ ├── temperature_block.dart # 温度告警块
│ │ ├── voltage_operate_block.dart # 电压操作块
│ │ └── equipment_list_block.dart # 设备列表
│ ├── abnormal/ # 异常详情页
│ │ ├── abnormal_detail_view.dart
│ │ ├── controller.dart
│ │ └── child/
│ │ ├── alarm_info_block.dart
│ │ ├── temperature_block.dart
│ │ └── temperature_char_block.dart
│ └── device/ # 设备详情页
│ ├── device_detail_view.dart
│ ├── controller.dart
│ └── child/
│ ├── device_parms_block.dart
│ ├── power_char_block.dart
│ └── state_info_block.dart
├── service/ # 服务模块
│ ├── index/ # 服务概览
│ │ ├── index_view.dart
│ │ ├── controller.dart
│ │ └── child/
│ │ ├── service_head_block.dart
│ │ ├── service_stats_block.dart
│ │ └── room_management_block.dart
│ └── room/ # 客房详情页
│ ├── room_detail_view.dart
│ ├── controller.dart
│ └── child/
│ ├── room_info_block.dart
│ ├── device_control_block.dart
│ └── bottom_operation_block.dart
├── report/ # 看板/报表模块
│ ├── index/ # 经营概览看板
│ │ ├── index_view.dart
│ │ ├── controller.dart
│ │ └── child/
│ │ ├── report_header_block.dart
│ │ ├── report_metrics_block.dart
│ │ ├── weekly_power_chart.dart
│ │ ├── room_status_distribution.dart
│ │ ├── device_online_rate.dart
│ │ └── quick_actions_block.dart
│ ├── energy/ # 能耗分析页
│ │ ├── energy_detail_view.dart
│ │ ├── controller.dart
│ │ └── child/
│ │ ├── energy_stats_card_block.dart
│ │ ├── hourly_chart_block.dart
│ │ └── zone_chart_block.dart
│ └── room/ # 房间能耗详情页
│ ├── room_detail.dart
│ └── controller.dart
├── profile/ # 我的页面
│ └── index_view.dart
└── search/ # 搜索页
└── index_view.dart
```
---
## 四、架构分层
项目采用清晰的分层架构,数据流向为单向:
```
┌─────────────────────────────────────────────────┐
│ UI 层 (views/) │
│ - View: 页面组件 (@RoutePage) │
│ - Controller: 页面逻辑控制器 │
│ - child/: 可复用 UI 子组件 │
└──────────────┬──────────────────────────────────┘
│ 依赖注入 (context.read<Bloc>())
┌──────────────▼──────────────────────────────────┐
│ 状态管理层 (blocs/) │
│ - Bloc: 状态机逻辑 │
│ - Event: 输入事件 (extends Equatable) │
│ - State: 输出状态 (extends Equatable) │
└──────────────┬──────────────────────────────────┘
│ 调用 Service
┌──────────────▼──────────────────────────────────┐
│ 业务服务层 (services/) │
│ - 封装业务逻辑,协调 Repository 和 Storage │
└──────────────┬──────────────────────────────────┘
│ 调用 Repository
┌──────────────▼──────────────────────────────────┐
│ 数据仓库层 (repositories/) │
│ - 调用 DioRequest 发送 HTTP 请求 │
└──────────────┬──────────────────────────────────┘
│ 调用 Dio
┌──────────────▼──────────────────────────────────┐
│ 网络层 (http/) │
│ - DioRequest: 单例 HTTP 客户端 │
│ - Interceptors: 请求/响应/错误拦截 │
│ - ResponseModel<T>: 统一响应模型 │
│ - Exceptions: 分类异常处理 │
└──────────────┬──────────────────────────────────┘
┌────▼────┐
│ 后端 API │
└─────────┘
```
**横切层:**
- `utils/storage/` - 本地安全存储(Token/记住密码)
- `utils/event_bus.dart` - 全局事件总线(Token 过期通知)
- `utils/logger.dart` - 日志工具
- `utils/constants.dart` - 全局配置常量
---
## 五、核心流程
### 5.1 应用启动流程
```
main()
├─ WidgetsFlutterBinding.ensureInitialized()
├─ runApp(MyApp())
└─ MyApp.initState()
├─ StorageService() 初始化
├─ DioRequest.instance.init(_storageService) // 初始化网络层
├─ AuthRepository() 创建
├─ AuthService(authRepository, storageService) 创建
├─ AuthBloc(authService, storageService) 创建
├─ AppRouter() 创建路由
├─ 监听 eventBus.on<TokenExpiredEvent>() // Token 过期全局监听
└─ _checkTokenOnStartup() // 检查本地 Token 有效
├─ 有 Token 且已过期 → AuthTokenExpiredEvent → 跳转登录页
└─ 无 Token 或有效 → 正常
```
### 5.2 路由结构
```
LoginRoute (initial: true) # 初始页面 - 登录页
DefaultLayoutRoute # 主布局(带 BottomNavigationBar)
├── HomeRoute (initial) # Tab1 - 设备告警看板
├── ServiceIndexRoute # Tab2 - 客房服务
├── ReportIndexRoute # Tab3 - 经营看板
└── ProfileRoute # Tab4 - 我的
SearchRoute # 搜索页(独立路由)
AbnormalDetailRoute # 告警详情页(push)
DeviceDetailRoute # 设备详情页(push)
ServiceRoomDetailRoute # 客房详情页(push,传参 roomNumber)
ReportEnergyDetailRoute # 能耗分析页(push)
ReportRoomDetailRoute # 房间能耗详情页(push)
```
**路由生成规则:** `@RoutePage()` 注解在有 `View``Route` 后缀的页面类上,运行 `build_runner` 自动生成 `app_router.gr.dart`
### 5.3 登录流程
```
LoginView
├─ initState: 加载记住的账号密码
│ └─ storageService.getRememberCredentials()
├─ 用户点击登录按钮
│ └─ LoginController.login()
│ ├─ 表单校验
│ ├─ 记住密码 → storageService.saveRememberCredentials()
│ └─ authBloc.add(AuthLoginRequested(username, password))
└─ AuthBloc 状态流转:
AuthLoginRequested
├─ emit(AuthLoading) → UI 显示 loading
├─ authService.login(username, password)
│ ├─ authRepository.login() → POST /login
│ ├─ 返回成功 → storageService.saveToken()
│ └─ 返回失败 → throw
├─ 成功 → emit(AuthSuccess(userInfo))
└─ 失败 → emit(AuthFailure(error))
```
### 5.4 网络请求流程
```
Repository
└─ DioRequest.instance.get/post/put/delete()
├─ 生成唯一 UUID 用于请求追踪
├─ 创建 CancelToken(支持取消)
├─ RequestInterceptor.onRequest()
│ ├─ 添加 UUID 到 Header (X-Request-UUID)
│ ├─ 添加时间戳 (X-Timestamp)
│ ├─ 注入 Bearer Token (Authorization)
│ └─ 打印请求日志
├─ 发送 HTTP 请求
├─ ResponseInterceptor.onResponse()
│ └─ 打印响应日志
├─ 错误时 → ErrorInterceptor.onError()
│ ├─ 按 DioExceptionType 分类:
│ │ ├─ 超时 → NetworkException
│ │ ├─ 400 → BusinessException
│ │ ├─ 401 → BusinessException + 发送 TokenExpiredEvent
│ │ ├─ 403 → BusinessException
│ │ ├─ 404 → ServerException
│ │ ├─ 500+ → ServerException
│ │ └─ cancel → CancelException
│ └─ 打印错误日志
└─ 统一返回 ResponseModel<T>
├─ code: HTTP 状态码
├─ msg: 消息
├─ data: 泛型数据(支持 fromJsonT 转换)
├─ success: code == 200
├─ uuid: 请求追踪 ID
└─ timestamp: 时间戳
```
### 5.5 Token 管理流程
```
Token 存储:
├─ 登录成功 → storageService.saveToken(token, expiryHours: 24)
│ ├─ 保存 token 到 FlutterSecureStorage
│ └─ 保存过期时间戳 (当前时间 + 24h)
├─ 每次请求 → RequestInterceptor 自动注入 Bearer Token
├─ API 返回 401 → ErrorInterceptor 触发 eventBus.emit(TokenExpiredEvent())
│ └─ main.dart 中监听 → authBloc.add(AuthTokenExpiredEvent())
│ ├─ storageService.deleteToken()
│ └─ emit(AuthTokenExpired)
│ └─ AuthBloc 监听 → appRouter.replaceAll([LoginRoute()])
└─ 手动退出 → authBloc.add(AuthLogoutRequestedEvent())
├─ storageService.deleteToken()
└─ emit(AuthLoggedOut)
└─ AuthBloc 监听 → appRouter.replaceAll([LoginRoute()])
```
### 5.6 全局状态监听流程(main.dart)
```
MaterialApp.router
└─ MultiBlocListener
└─ BlocListener<AuthBloc, AuthState>
├─ AuthSuccess → router.replaceAll([DefaultLayoutRoute()]) // 进入主页
├─ AuthTokenExpired → SnackBar 提示 + router.replaceAll([LoginRoute()])
└─ AuthLoggedOut → router.replaceAll([LoginRoute()])
```
---
## 六、视图层开发规范
### 6.1 页面结构模板
每个页面模块遵循统一的组织方式:
```
views/<模块>/<子页面>/
├── xxx_view.dart # 页面组件(@RoutePage() 注解)
├── controller.dart # 页面逻辑控制器(纯 Dart 类,持有 BuildContext)
└── child/ # 页面级子组件(Block 粒度)
├── xxx_block.dart
└── ...
```
### 6.2 View 规范
- 使用 `@RoutePage()` 注解,由 auto_route 自动生成路由
- 使用 `StatefulWidget`,在 `initState` 中创建 Controller
- 通过 `LayoutBuilder` + `SingleChildScrollView` + `ConstrainedBox` 实现可滚动布局
- 子组件采用 Block 粒度拆分,通过构造函数传入 controller 或数据
### 6.3 Controller 规范
- 纯 Dart 类(非 Widget),持有 `BuildContext` 用于路由跳转
- 负责业务逻辑:数据获取、表单处理、路由导航
- 通过 `context.pushRoute(XxxRoute())` 进行页面跳转
- 通过 `context.popRoute()` 返回上一页
### 6.4 BLoC 使用规范
- **Event**: 继承 `Equatable`,重写 `props` 用于状态比较
- **State**: 继承 `Equatable`,每种状态一个子类
- `AuthInitial` - 初始状态
- `AuthLoading` - 加载中
- `AuthSuccess` - 成功(携带数据)
- `AuthFailure` - 失败(携带错误信息)
- `AuthTokenExpired` - Token 过期
- `AuthLoggedOut` - 已登出
- **Bloc**: 在 `main.dart` 中统一创建,通过 `BlocProvider.value()` 注入
- **UI 中使用**: `context.read<AuthBloc>().add(Event())` 发送事件
- **UI 中监听**: `BlocListener` 监听状态变化做副作用(跳转、弹窗)
- **UI 中构建**: `BlocBuilder` 根据状态构建不同 UI
---
## 七、关键业务模块说明
| 模块 | 路由 | 功能描述 |
|------|------|----------|
| **登录** | LoginRoute | 用户名/密码登录,记住密码,BLoC 状态管理 |
| **告警看板 (Home)** | HomeRoute | 设备告警概览:待处理任务、温度告警、电压告警、设备列表 |
| **告警详情** | AbnormalDetailRoute | 温度异常详情:温度曲线图(fl_chart)、告警信息、操作处理 |
| **设备详情** | DeviceDetailRoute | 智能空开详情:运行状态、参数、功率曲线图 |
| **客房服务** | ServiceIndexRoute | 客房管理:按楼层查看房间、送电/断电、跳转房间详情 |
| **客房详情** | ServiceRoomDetailRoute | 单客房详情:房间信息、设备控制、底部操作 |
| **经营看板** | ReportIndexRoute | 管理层看板:用电指标、客房状态分布、设备在线率、快捷操作 |
| **能耗分析** | ReportEnergyDetailRoute | 今日/月度能耗统计、24小时柱状图、区域占比图 |
| **房间能耗** | ReportRoomDetailRoute | 单独房间的能耗详情(页面待完善) |
| **搜索** | SearchRoute | 搜索功能(页面待完善) |
| **我的** | ProfileRoute | 个人中心(页面待完善) |
---
## 八、常量配置 (Constants)
| 配置项 | 值 | 说明 |
|--------|-----|------|
| baseUrl | http://localhost:8080 | 后端 API 地址 |
| connectTimeout | 30000ms | 连接超时 |
| receiveTimeout | 30000ms | 接收超时 |
| sendTimeout | 30000ms | 发送超时 |
| successCode | 200 | 业务成功码 |
| tokenExpiredCode | 401 | Token 过期码 |
| forbiddenCode | 403 | 无权限码 |
| maxRetries | 3 | 最大重试次数 |
| tokenExpiryHours | 24 | Token 过期时间(小时) |
---
## 九、开发命令
```bash
# 生成路由代码(修改 app_router.dart 后必须执行)
flutter pub run build_runner build --delete-conflicting-outputs
# 或使用 watch 模式(自动监听变更)
flutter pub run build_runner watch --delete-conflicting-outputs
# 运行项目
flutter run
# 依赖更新
flutter pub get
```
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment