# 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 转义。后续如果要提升为更完整的管理端,应优先补充分页加载或服务端筛选统计接口,再补齐记录级管理操作。