Files
bishe-STM32/docs/04_Qt管理端文档.md
T
2026-05-01 20:29:02 +08:00

629 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Qt管理端当前功能文档
## 1. 文档目的
本文档用于说明 `QT/` 管理端重构后的实际架构、当前已经实现的功能、服务端接口依赖、构建方式和已知限制。
本文结论以当前源码为准,不再沿用旧版 Widgets 管理端中 `MainWindow`、`NetworkApiManager`、多个独立 `Dialog` 的描述。
## 2. 模块定位
Qt 管理端是人脸识别考勤系统的跨平台管理客户端,主要负责:
- 从服务端拉取考勤记录、统计信息和配置数据。
- 查看、筛选、导出考勤记录。
- 按学生维度生成本地统计报表。
- 管理服务端地址、签到时间段、学生姓名映射、班级名称映射。
- 管理 K210 上传的人脸照片和人脸 ID 到学号的绑定关系。
- 在服务端不可达时给出简短状态提示,并自动重连。
当前 Qt 端已经重构为 Qt 6 Quick/QML 架构,主要源码位置如下:
| 模块 | 路径 | 说明 |
| --- | --- | --- |
| 程序入口 | `QT/main.cpp` | 初始化应用信息、图标、QML 引擎和 `AppController` |
| 主界面 | `QT/qml/Main.qml` | 单窗口 QML 页面,包含记录、统计、配置、人脸、关于五个页面 |
| 业务中枢 | `QT/src/AppController.*` | 连接 QML 和业务逻辑,负责筛选、统计、配置保存、重连调度 |
| 网络接口 | `QT/src/ApiClient.*` | 封装 HTTP API、请求超时、加密响应解密和 JSON 解析 |
| 数据结构 | `QT/src/AttendanceTypes.h` | 考勤记录、统计项、签到时段等结构定义 |
| 列表模型 | `QT/src/*ListModel.*` | 向 QML 暴露记录、统计、时间段、映射、人脸列表 |
| 加密工具 | `QT/src/CryptoUtils.*` | AES-128-CBC Base64 响应解密 |
| AES 实现 | `QT/src/crypto/tiny_aes.hpp` | AES 底层实现 |
| 构建配置 | `QT/CMakeLists.txt` | Qt 6 CMake 构建、资源、图标、Android 配置 |
| 平台资源 | `QT/assets/`、`QT/android/`、`QT/cmake/` | 桌面图标、Android 图标与平台模板 |
## 3. 技术栈与界面结构
当前客户端使用:
- C++17
- Qt 6.2+
- Qt Quick / Qt Quick Controls 2
- Qt Core、Gui、Qml、Quick、QuickControls2、Network
- CMake 3.16+
界面由 `ApplicationWindow` 承载,内部使用 `StackLayout` 切换五个页面:
- 考勤记录
- 统计分析
- 配置中心
- 人脸管理
- 关于
QML 不直接访问网络。所有页面操作统一调用 `AppController` 暴露的 `Q_INVOKABLE` 方法和 `Q_PROPERTY` 状态,数据表格通过 `RecordListModel`、`StatisticsListModel`、`TimeSlotListModel`、`MappingListModel`、`FaceListModel` 渲染。
## 4. 当前已实现功能
### 4.1 启动与服务连接
应用启动流程:
1. `main.cpp` 创建 `QGuiApplication`。
2. 设置应用名称、版本、组织名和窗口图标。
3. Android 平台启用原生文字渲染,改善中文粗体显示。
4. 创建 `AppController`。
5. 将 `appController` 注入 QML 上下文。
6. 加载 `qrc:/qml/Main.qml`。
`AppController` 构造时会:
- 读取本地服务端地址、映射配置和时间段配置。
- 设置 `ApiClient` 的服务端地址。
- 启动健康检查。
- 如果服务端可用,同步记录、统计、时间段和映射配置。
- 如果服务端不可用,进入自动重连流程。
默认服务端地址:
```text
http://127.0.0.1:8082
```
用户可以在“配置中心”修改服务端地址。保存后会写入 `QSettings` 的 `server/url`,下次启动会读取并使用。
### 4.2 自动重连与状态提示
当前实现了基于 `/api/v1/system/health` 的连接检查:
- 网络请求超时时间为 5 秒。
- 服务端不可达时显示简短提示:`服务器未连接,稍后重试`。
- 自动重连间隔为 5 秒。
- 重连期间显示:`正在重连服务器`。
- 服务恢复后自动刷新记录、统计、时间段、映射和人脸相关数据。
底部 Toast 会展示状态信息,避免把底层网络错误、URL 和长异常文本直接暴露给用户。
### 4.3 考勤记录查看
“考勤记录”页用于查看服务端同步下来的签到记录。
当前实现:
- 默认请求最新 `1000` 条记录。
- 顶部显示总记录数、今日签到数、筛选结果数。
- 记录按签到时间倒序显示。
- 支持刷新记录。
- 支持清空服务端全部考勤记录。
- 支持导出当前筛选结果为 CSV。
记录表格字段:
- 签到时间
- 班级
- 学号
- 姓名
- 置信度
- 状态
显示规则:
- 班级优先使用“班级编号 -> 班级名称”映射;未配置时显示原班级编号。
- 姓名优先使用“学号 -> 姓名”映射;未配置时回退到服务端记录中的原始姓名。
- 状态会被归一化判断是否成功,成功和失败在界面上使用不同样式显示。
### 4.4 记录筛选
记录页支持本地筛选。筛选条件包括:
- 班级
- 学号
- 姓名关键字
- 日期范围
日期范围支持:
- 全部时间
- 今天
- 最近 7 天
- 最近 30 天
- 指定日期
筛选基于当前已经加载到客户端内存中的记录执行,不会为每次筛选重新请求服务端。
### 4.5 记录导出与清空
当前筛选结果可以导出为 CSV 文件。
导出内容包括:
```text
# 考勤记录导出
# 导出时间: yyyy-MM-dd HH:mm:ss
# 记录总数: N
签到时间,班级编号,班级名称,学号,姓名,置信度,状态
```
“清空记录”会调用服务端 `/api/v1/attendance/records/clear`。界面在执行前会弹出确认对话框,并提示该操作不可恢复。
需要注意:当前界面只开放“清空全部记录”,没有在记录表中开放单条删除或批量删除入口。
### 4.6 统计分析
“统计分析”页基于当前加载到客户端的考勤记录,在本地按学生维度计算统计结果。
支持:
- 快捷选择统计范围。
- 手动输入开始日期和结束日期。
- 显示统计学生数、统计记录数、统计范围。
- 导出统计报表 CSV。
统计字段:
- 学号
- 姓名
- 总签到次数
- 今日签到次数
- 最后签到时间
- 平均置信度
导出字段:
```text
学号,姓名,总签到次数,今日签到,最后签到时间,平均置信度
```
统计结果不是服务端全量统计,而是对当前客户端已经拉取的最多 `1000` 条记录进行本地计算。
### 4.7 配置中心
“配置中心”集中管理服务连接、签到时间段和名称映射。
#### 服务端地址
支持:
- 查看当前服务端地址。
- 修改并保存服务端地址。
- 测试服务端连接。
保存后会写入本地 `QSettings`:
```text
server/url
```
#### 签到时间段
支持:
- 查看当前时间段。
- 新增时间段。
- 编辑时间段。
- 删除时间段。
- 恢复默认时间段。
- 从服务端同步时间段。
- 保存时间段到本地并上传服务端。
默认时间段:
| 名称 | 开始时间 | 结束时间 | 默认状态 |
| --- | --- | --- | --- |
| 上午签到 | 08:00 | 09:30 | 启用 |
| 中午签退 | 12:00 | 13:00 | 启用 |
| 下午签到 | 14:00 | 15:00 | 启用 |
| 晚上签退 | 17:00 | 18:30 | 启用 |
本地文件:
```text
timeslot_config.json
```
#### 名称映射
支持两类映射:
- 学号 -> 姓名
- 班级编号 -> 班级名称
支持操作:
- 新增映射。
- 直接编辑映射键和值。
- 删除映射。
- 从服务端加载映射配置。
- 保存到本地并上传服务端。
本地文件:
```text
mapping_config.json
```
映射会影响记录列表和统计报表中的姓名、班级显示。
### 4.8 人脸管理
“人脸管理”页用于维护 K210 上传的人脸照片和人脸 ID 到学号的绑定关系。
当前实现:
- 从服务端同步人脸照片 ID。
- 从服务端同步全部学生 ID。
- 从服务端同步人脸 ID 到学号的映射。
- 合并照片 ID 和学生 ID,生成统一管理列表。
- 显示照片或“无照片”状态。
- 编辑人脸 ID 对应的学号。
- 保存人脸映射到服务端。
- 删除指定人脸。
- 删除时可选择同时删除该学生相关考勤记录。
照片加载方式:
```text
ApiClient -> GET /api/v1/faces/photos/{id} -> 本地 file:// 缓存 -> QML Image
```
这样可以在请求照片时携带 `X-Api-Token`,避免 QML `Image` 直接访问受鉴权接口导致照片加载失败。
### 4.9 关于页面
“关于”页展示:
- 系统简介。
- 功能范围。
- 毕业设计说明。
- 作者和仓库信息。
当前关于页是 QML 页面的一部分,不再是独立窗口。
### 4.10 桌面端和移动端适配
当前 QML 已对窄屏进行适配:
- `phoneLayout` 用于手机宽度布局。
- 顶部导航在窄屏下使用紧凑按钮。
- 筛选区、统计卡片和配置区会根据宽度调整列数。
- 表格在窄屏下隐藏部分非关键列或调整宽度。
- Android 端使用原生文字渲染并降低粗体权重,减少中文粗体重影。
## 5. 服务端 API 依赖
客户端基于服务端地址拼接 `/api` 前缀访问接口。刷新全部数据时优先使用统一同步接口:
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| `GET` | `/api/v1/sync/state?client=qt&last_version={version}` | 按版本同步 Qt 所需完整状态 |
服务端版本无变化时返回 `changed:false`,Qt 不再重复拉取全部数据。局部刷新和保存操作使用下列 v1 子接口。
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| `GET` | `/api/v1/attendance/records?limit={limit}&offset={offset}` | 获取考勤记录 |
| `GET` | `/api/v1/attendance/statistics` | 获取总数、今日数和服务端时间 |
| `POST` | `/api/v1/attendance/records/clear` | 清空全部记录 |
| `DELETE` | `/api/v1/attendance/records?timestamp={timestamp}&student_id={studentId}` | 删除单条记录,当前 API 层保留,界面未开放 |
| `GET` | `/api/v1/config/time-slots` | 获取签到时段 |
| `POST` | `/api/v1/config/time-slots` | 保存签到时段 |
| `GET` | `/api/v1/config/mappings` | 获取学生和班级映射 |
| `POST` | `/api/v1/config/mappings` | 保存学生和班级映射 |
| `GET` | `/api/v1/faces/mappings` | 获取人脸 ID 到学号映射 |
| `POST` | `/api/v1/faces/mappings` | 保存人脸 ID 到学号映射 |
| `GET` | `/api/v1/faces/photos` | 获取照片 ID 列表 |
| `GET` | `/api/v1/faces/student-ids` | 获取所有学生 ID |
| `GET` | `/api/v1/faces/photos/{id}` | 获取人脸照片 |
| `DELETE` | `/api/v1/faces/{studentId}` | 删除人脸信息 |
| `DELETE` | `/api/v1/faces/{studentId}?delete_records=true` | 删除人脸信息并删除相关考勤记录 |
| `GET` | `/api/v1/system/health` | 健康检查 |
### 5.1 考勤记录格式
`/api/v1/attendance/records` 解密后应返回 JSON 数组,单条记录示例:
```json
{
"timestamp": "2026-04-24 08:10:23",
"student_id": "20240001",
"name": "张三",
"confidence": 0.9821,
"status": "success",
"class_id": "1"
}
```
字段处理规则:
- `timestamp` 需要符合 `yyyy-MM-dd HH:mm:ss`。
- `student_id` 不能为空。
- `class_id` 为空时客户端按 `"0"` 处理。
- `status` 可以是字符串、布尔值或数字,客户端会统一转换为显示状态。
- `timestamp` 以 `0000-` 开头的记录会被忽略。
### 5.2 统计数据格式
```json
{
"total": 120,
"today": 8,
"server_time": "2026-04-24 10:30:00"
}
```
### 5.3 签到时段格式
```json
{
"time_slots": [
{
"name": "上午签到",
"start_time": "08:00",
"end_time": "09:30",
"enabled": true
}
]
}
```
### 5.4 映射配置格式
```json
{
"student_name_map": {
"20240001": "张三"
},
"class_name_map": {
"1": "软件工程一班"
}
}
```
### 5.5 人脸映射格式
```json
{
"mappings": {
"face_001": "20240001"
}
}
```
## 6. 加密响应
客户端对 `/api/v1/attendance/records` 和 `/api/v1/attendance/statistics` 请求添加请求头:
```text
X-Encrypted-Response: true
```
客户端期望服务端返回 Base64 编码的 AES-128-CBC 密文。收到响应后处理流程为:
1. Base64 解码。
2. AES-128-CBC 解密。
3. PKCS#7 去填充。
4. 解析 JSON。
加密参数位于 `QT/src/CryptoUtils.cpp`:
| 参数 | 值 |
| --- | --- |
| 算法 | AES-128-CBC |
| Padding | PKCS#7 |
| Key | `2b 7e 15 16 28 ae d2 a6 ab f7 15 88 09 cf 4f 3c` |
| IV | `00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f` |
如果服务端没有按加密格式返回,记录和统计接口会解析失败。
## 7. 本地配置持久化
应用使用 `QSettings` 和 `QStandardPaths::AppDataLocation` 保存本地状态。
应用信息:
```text
ApplicationName: 人脸识别考勤系统
ApplicationVersion: 3.0.0
OrganizationName: STM32 Face Recognition
```
本地保存内容:
| 配置 | 保存方式 |
| --- | --- |
| 服务端地址 | `QSettings`,键名 `server/url` |
| 学生姓名映射和班级名称映射 | `mapping_config.json` |
| 签到时段配置 | `timeslot_config.json` |
`mapping_config.json` 和 `timeslot_config.json` 位于 Qt 返回的 `AppDataLocation` 目录中,不在项目源码目录内。
## 8. 构建与运行
### 8.1 推荐构建方式
当前推荐使用 CMake 构建。旧版 `qmake` / `.pro` 文档不再适用于重构后的 Qt Quick 版本。
基础要求:
- Qt 6.2 或更高版本
- CMake 3.16 或更高版本
- 支持 C++17 的编译器
Windows 桌面端推荐使用 Qt 6.x MinGW 64-bit Kit。
### 8.2 Qt Creator 构建
1. 打开 Qt Creator。
2. 打开 `QT/CMakeLists.txt`。
3. 选择 Desktop Qt 6.x 或 Android Kit。
4. 等待 CMake 配置完成。
5. 构建目标 `apprewrite_qt`。
6. 桌面端直接运行;Android 端部署到设备或模拟器。
### 8.3 命令行构建
Windows 示例:
```powershell
cmake -S QT -B QT/build -DCMAKE_PREFIX_PATH=D:/Qt/6.10.0/mingw_64
cmake --build QT/build --target apprewrite_qt
```
Linux 示例:
```bash
cmake -S QT -B QT/build -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x/gcc_64
cmake --build QT/build --target apprewrite_qt
```
安装:
```bash
cmake --install QT/build
```
当前 `QT/CMakeLists.txt` 将运行产物输出到:
```text
QT/dist
```
### 8.4 Windows 独立运行
直接双击 `apprewrite_qt.exe` 时,如果提示缺少 `Qt6Gui.dll`、`Qt6Core.dll` 等运行库,需要使用和构建 Kit 一致的 `windeployqt` 收集依赖。
示例:
```powershell
D:\Qt\6.10.0\mingw_64\bin\windeployqt.exe QT\dist\apprewrite_qt.exe
```
如果路径包含中文导致部署工具异常,可以把 exe 复制到纯英文路径后部署。
### 8.5 Android 构建
Android 相关配置位于 `QT/CMakeLists.txt`:
```cmake
QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android"
QT_ANDROID_APP_NAME "${REWRITE_QT_DISPLAY_NAME}"
QT_ANDROID_APP_ICON "@mipmap/ic_launcher"
```
补充配置位于 `QT/android/gradle.properties`:
```properties
android.overridePathCheck=true
android.useAndroidX=true
```
说明:
- `android.overridePathCheck=true` 用于绕过 Windows 下 Android Gradle 对中文路径的检查。
- `android.useAndroidX=true` 用于启用 AndroidX。
- Android 应用显示名为“人脸识别考勤系统”。
- Android 启动图标位于 `QT/android/res/mipmap-*`。
## 9. 图标与资源
桌面图标资源位于:
```text
QT/assets/favicon.ico
QT/assets/favicon-16x16.png
QT/assets/favicon-32x32.png
QT/assets/favicon-48x48.png
QT/assets/favicon-64x64.png
QT/assets/favicon-128x128.png
QT/assets/favicon-192x192.png
QT/assets/favicon-256x256.png
```
Android 启动图标位于:
```text
QT/android/res/mipmap-mdpi/ic_launcher.png
QT/android/res/mipmap-hdpi/ic_launcher.png
QT/android/res/mipmap-xhdpi/ic_launcher.png
QT/android/res/mipmap-xxhdpi/ic_launcher.png
QT/android/res/mipmap-xxxhdpi/ic_launcher.png
```
Linux 桌面文件模板位于:
```text
QT/cmake/rewrite_qt.desktop.in
```
Windows 图标资源模板位于:
```text
QT/cmake/app_icon.rc.in
```
## 10. 当前已知限制
### 10.1 记录和统计最多基于当前加载的 1000 条记录
`AppController::refreshRecords()` 当前固定调用:
```cpp
m_apiClient.fetchRecords(1000, 0);
```
因此记录列表、筛选结果和本地统计都只覆盖客户端当前加载的记录。如果服务端历史记录超过 `1000` 条,统计页不等于全量历史统计。
### 10.2 筛选和统计为本地计算
班级、学号、姓名、日期筛选以及统计分析都在客户端内存中完成,不会向服务端传递筛选条件。
优点是交互响应快;限制是数据范围受当前加载记录影响。
### 10.3 单条删除 API 保留但界面未开放
`ApiClient` 中保留了 `deleteRecord()` 和 `/api/v1/attendance/records` 调用,`AppController` 也连接了删除完成信号,但当前 QML 记录表没有提供单条删除或批量删除入口。
因此当前对外说明时,不应把“单条记录删除”或“批量删除记录”描述为已开放功能。
### 10.4 自动刷新不是定时拉取记录
当前代码实现的是服务端不可达后的自动重连检查,不是固定周期自动刷新记录。
用户需要手动点击“刷新”或“刷新全部数据”同步最新数据;服务恢复连接时也会自动刷新。
### 10.5 时间输入缺少强校验
签到时间段编辑框使用字符串输入,代码按 `HH:mm` 解析。如果输入非法时间,模型层不会弹出明确错误提示,可能产生无效时间值。后续可补充输入掩码或校验提示。
### 10.6 CSV 导出未做字段转义
导出逻辑直接用逗号拼接字段。如果姓名、班级名或状态中包含逗号、换行或引号,CSV 可能被表格软件解析成错误列。后续可补充标准 CSV 转义函数。
### 10.7 照片 URL 依赖服务端静态接口
人脸照片由 `ApiClient` 通过 `/api/v1/faces/photos/{id}` 携带鉴权头下载,并缓存为本地 `file://` 地址后交给 QML 显示。如果服务端返回格式或图片 ID 与学生 ID 规则变化,客户端的人脸列表合并逻辑需要同步调整。
## 11. 当前结论
重构后的 Qt 管理端已经从旧版 Widgets 多窗口结构迁移为 Qt 6 Quick/QML 单窗口客户端。当前核心链路已经完整:
- 服务端连接与健康检查。
- 加密记录和统计接口访问。
- 考勤记录查看、筛选、导出、清空。
- 本地统计分析和统计导出。
- 服务端地址、时间段、学生映射、班级映射配置。
- 人脸照片、人脸映射和删除管理。
- Windows 桌面端与 Android 端构建配置。
当前主要不足集中在数据分页、全量统计、记录级删除入口、输入校验和 CSV 转义。后续如果要提升为更完整的管理端,应优先补充分页加载或服务端筛选统计接口,再补齐记录级管理操作。