# 化学品智能管理终端 App 业务与技术分析

## 1. 文档说明

本文基于当前仓库源码静态阅读整理，目标是说明该 Android 终端 App 的：

- 业务功能模块
- 关键业务路径
- 业务规则与角色权限
- 主要技术实现策略
- 软硬件接入方式
- 关键源码位置

仓库定位不是通用库存 App，而是**实验室化学品安全管理一体机/壁挂终端**，围绕“实验室、化学品、安全柜/柜门、领用归还、废弃、预警、MSDS、双人认证、RFID/扫码/蓝牙秤/打印”等能力展开。

---

## 2. 项目整体定位

### 2.1 产品定位

该项目是一个部署在实验室场景下的化学品智能管理终端，典型硬件环境包括：

- 壁挂 Android 一体机
- 智能化学品柜/柜门锁控设备
- 蓝牙电子秤
- 标签打印设备
- 摄像头
- 内置刷卡/扫码/人脸识别硬件
- 可能的 RFID 标签与串口扫码外设

### 2.2 核心业务目标

从代码可以确认，该系统主要解决以下问题：

1. 实验室化学品合规入库
2. 化学品领用与现场校验
3. 化学品归还、空瓶处理、废弃出库
4. 柜门/柜锁权限控制与开锁操作
5. 安全管控类化学品双人认证
6. 电子台账、MSDS、安全预警闭环
7. 一体机设备联网、心跳、升级、异常恢复

---

## 3. 项目结构总览

### 3.1 Gradle 模块

- 主应用模块：`app`
- 串口模块：`serialport`

关键文件：

- `settings.gradle:23`
- `app/build.gradle:6`
- `serialport/build.gradle:5`

### 3.2 主要包结构

#### 业务 UI

- `app/src/main/java/xn/hxp/ui/login` 登录
- `app/src/main/java/xn/hxp/ui/verify` 双人认证/二次校验
- `app/src/main/java/xn/hxp/ui/plan` 入库计划、手动录入、待入库、开锁
- `app/src/main/java/xn/hxp/ui/uses` 领用、预警
- `app/src/main/java/xn/hxp/ui/still` 归还、MSDS、静态资料
- `app/src/main/java/xn/hxp/ui/discard` 废弃、电子台账
- `app/src/main/java/xn/hxp/ui/inquiry` 查询
- `app/src/main/java/xn/hxp/ui/warehousing` 标签、库存相关页面
- `app/src/main/java/xn/hxp/ui/fragments` 台账/查询子页面
- `app/src/main/java/xn/hxp/ui/adapter` 列表适配器

#### 网络层

- `app/src/main/java/com/rc/httpcore/client/retrofit/ApiService.java`
- `app/src/main/java/com/rc/httpcore/client/retrofit/ChemicalRetrofit.kt`
- `app/src/main/java/com/rc/httpcore/client/ApiRepository.kt`
- `app/src/main/java/com/rc/httpcore/HttpClient.kt`
- `app/src/main/java/com/rc/httpcore/client/HttpTool.java`

#### 系统/硬件能力

- `app/src/main/java/xn/hxp/utils/Tool.java`
- `app/src/main/java/xn/hxp/utils/bluetooth/SppTool.java`
- `app/src/main/java/xn/hxp/receiver/PortScanService.kt`
- `app/src/main/java/xn/hxp/receiver/UsbReceiver.kt`
- `app/src/main/java/xn/hxp/receiver/PortScanHelper*`

#### 本地数据

- `app/src/main/java/xn/hxp/ui/plan/room/**`
- `app/src/main/java/xn/hxp/utils/SharedPreferencesHelper.kt`

---

## 4. 应用入口与运行模式

### 4.1 Application 全局初始化

应用入口类：

- `app/src/main/java/xn/hxp/app/ChemicalApp.kt:32`

核心职责：

1. 初始化全局状态
   - `userData`
   - `subjectId`
   - `subjectName`
   - `confs`
   - `labInfo`
   - `subRoom`
   - `administrators`
   - `responsibles`

2. 初始化终端能力
   - 蓝牙 SPP：`SppTool.init()`
   - FastBle：`BleManager`
   - DialogX
   - X5 WebView
   - Toaster
   - 日志系统

3. 异常恢复策略
   - 使用 `ANRWatchDog`
   - 卡顿后先重启 App，多次卡顿后直接重启设备
   - 见 `ChemicalApp.kt:64-81`

### 4.2 启动页逻辑

启动页：

- `app/src/main/java/xn/hxp/ui/StartActivity.java:34`

启动流程：

1. 长按 logo 可进入设置页
2. 自动补齐关键权限
3. 从本地配置恢复服务地址与相机参数
4. 调 `HttpTool.getCheck()` 获取设备绑定实验室信息
5. 将实验室信息写入全局变量
6. 进入主页 `MainActivity`

关键点：

- 权限不是常规弹窗申请，而是直接执行 `pm grant`
- 说明系统运行于受控设备环境
- 见 `StartActivity.java:80-96`

### 4.3 主页职责

主页：

- `app/src/main/java/xn/hxp/ui/MainActivity.java:87`

主页主要做三件事：

1. 加载实验室配置与当前柜体轮播
2. 提供所有主业务入口
3. 维护登录状态、自动登出、设备心跳

关键逻辑：

- 拉基础配置：`basicConfig`，见 `MainActivity.java:295`
- 拉柜体列表：`getCabinetIn`，见 `MainActivity.java:249`
- 心跳上报：每 20 秒调用 `HttpTool.heartbeat()`，见 `MainActivity.java:194-217`
- 自动登出：根据 `signOutTime` 计时，见 `MainActivity.java:394-418`

---

## 5. 业务功能模块

## 5.1 登录与身份认证模块

### 页面

- `ui/login/SwipeActivity.kt` 刷卡登录
- `ui/login/ScanLoginActivity.kt` 扫码登录
- `ui/login/FaceLoginActivity.java` 人脸登录
- `ui/login/FacialCardActivity.kt` 人脸+刷卡组合登录

### 业务能力

支持多种登录方式，由实验室配置控制：

- 人脸
- 刷卡
- 扫码
- 人脸+刷卡
- 人脸+扫码
- 刷卡+扫码
- 多方式混合

配置来源：

- `ConfigBean.loginType`，见 `ConfigBean.kt:9`
- 主页分流逻辑见 `MainActivity.java:325-384`
- 查询页分流逻辑见 `InquiryActivity.java:623-678`

### 认证后权限判定

刷卡登录流程：

1. 刷卡获取 token：`auth/cardNum`
2. 校验当前人在当前实验室的身份：`userCardValidation`
3. 读取用户角色字段
4. 允许或拒绝进入系统

关键代码：

- `SwipeActivity.kt:147-167`
- `SwipeActivity.kt:164-205`
- `ChemicalRetrofit.kt:100-111`

角色模型：

- `UserValidationBean.kt:4-26`

可确认角色：

- 校级管理员 `schoolLevelAdmin`
- 院级管理员 `collegeAdmin`
- 实验室负责人 `adminUser`
- 安全负责人 `safeUser`
- 柜锁管理员 `cabinetAdmin`
- 化学品归属人 `belongUser`
- 课题组成员 `toipcUser`
- 实验室准入 `apply`
- 白名单 `white`

### 业务结论

登录不是单纯账号体系，而是**与实验室、柜门、化学品权限模型深度耦合的身份校验入口**。

---

## 5.2 双人认证模块

### 页面

- `ui/verify/TwoVerificationActivity.kt`
- 以及同类辅助页面：`TwoPersonActivity.kt`、`SwipeCodeTwoActivity.kt`、`ScanCodeTwoActivity.kt`

### 用途

双人认证被用于多个高风险业务节点：

- 新增入库
- 领用
- 归还/废弃/空瓶等返回类操作
- 待入库确认

关键字段：

- `mTag` 表示业务场景
- 注释可直接确认：
  - `0` 新增入库
  - `1` 归还/废弃/空瓶等
  - `2` 待入库
  - `3` 领用认证
- 见 `TwoVerificationActivity.kt:83`

### 支持的认证方式

由 `ConfigBean.verifyType` 配置：

- `1` 人脸
- `2` 刷卡
- `3` 扫码
- 组合形态：`1,2`、`1,3`、`2,3`、多方式组合

见：

- `ConfigBean.kt:31`
- `UseActivity.kt:233-320`
- `ChemicalsAlsoActivity.kt:110-146, 414-429`
- `WasteChemicalsActivity.kt:297-330`
- `ChemicalLabelingActivity.kt:185-217`

### 认证实现方式

#### 人脸

- 摄像头采图 + `checkUserFaceByPic`
- 登录与认证接口分离
- 认证接口可带 `subId/doorId/stockId/waitId`

关键代码：

- `ApiService.java:337-340`
- `ChemicalRetrofit.kt:860-885`
- `TwoVerificationActivity.kt:514-516`

#### 刷卡

- 通过 USB/串口输入卡号
- 调用 `useCardVerify`
- 请求参数带 `doorId`、`chemicalLevel` 等业务上下文

关键代码：

- `ChemicalRetrofit.kt:125-139`
- `ChemicalRetrofit.kt:601-616`
- `TwoVerificationActivity.kt:1336-1337`

#### 扫码

- 终端本地生成二维码
- 小程序扫码后由后台回传登录/验证状态
- 轮询 `aioScanLogin`

关键代码：

- `TwoVerificationActivity.kt:142-146`
- `TwoVerificationActivity.kt:1658`
- `ApiService.java:236-237`

### 认证结果存储

通过 `DoubleDialogBean` 记录两位认证人，并写入本地 SharedPreferences：

- `TwoVerificationActivity.kt:464`
- `SharedPreferencesHelper.kt:42-70`

后续开锁、归还、废弃等操作会读取这两位认证人的 `userId/name` 写入业务请求。

### 业务结论

双人认证是本系统安全策略中心，认证不是独立动作，而是**带业务上下文的二次授权**。

---

## 5.3 入库模块

入库分为两个层次：

1. 计划/待入库编排
2. 实际入库提交

### 5.3.1 计划入库总控页

页面：

- `ui/plan/PlanAddActivity.java`
- 辅助类：`ui/plan/PlanAddActivityHelp.java`

职责：

- 读取实验室及柜体信息
- 初始化本地 Room 临时表
- 展示待录入清单
- 手动录入或扫码录入化学品
- 在提交前判断哪些柜门需要开锁
- 跳转开锁页或直接提交入库

关键代码：

- `PlanAddActivity.java:100-155`
- `PlanAddActivity.java:157-255`
- `PlanAddActivityHelp.java:61-144`
- `PlanAddActivityHelp.java:317-391`

### 5.3.2 手动录入页

页面：

- `ui/plan/add/AddActivity.java`
- 辅助：`ui/plan/add/AddActivityHelp.java`

支持信息：

- 化学品名称搜索
- CAS 搜索
- 类别选择
- 归属人搜索
- 课题组搜索
- 规格/单位/密度/净含量/数量
- 管控/非管控属性
- 存储柜层选择

关键代码：

- `AddActivity.java:151-239`
- `AddActivityHelp.java:96-191`
- `AddActivityHelp.java:198-305`

### 5.3.3 扫码录入

`PlanAddActivityHelp` 中提供扫码监听：

- 既兼容“18 位时间戳式码”
- 也兼容 `code=xxx&type=9` 的 URL 型码
- 最终统一通过 `scanCodeChemical` 查询化学品信息

关键代码：

- `PlanAddActivityHelp.java:254-315`
- `PlanAddActivityHelp.java:181-252`

### 5.3.4 入库前校验与确认

录入时会：

1. 通过 `getControlConfigs(chemicalLevel)` 获取化学品控制策略
2. 调 `certitude` 做化学品确认/补全
3. 如需要，先打印标签
4. 如需要，走蓝牙称重
5. 最终写入本地待入库列表

关键代码：

- `AddActivityHelp.java:372-451`
- `AddActivityHelp.java:453-458`

### 5.3.5 实际入库提交

`PlanAddActivityHelp.save()` 会把本地待入库临时数据组装为后端要求的 `HxpChemicalVo` 列表，并调用：

- `HttpTool.addChemical()` -> `chemical/aio/addStock`

关键代码：

- `PlanAddActivityHelp.java:317-391`
- `HttpTool.java:101-108`

### 5.3.6 已申领未入库

主页上“存储/新增入库”入口会先判断是否存在“已申领未入库”记录：

- 有数据时弹出选择：进入 `AlreadyActivity` 或 `PlanAddActivity`
- 无数据时直接进入 `PlanAddActivity`

关键代码：

- `MainActivity.java:645-684`

### 业务结论

入库不是简单表单提交，而是**柜位选择 + 化学品确认 + 打印/RFID/称重 + 柜门开锁 + 最终提交**的复合流程。

---

## 5.4 领用模块

页面：

- `ui/uses/UseActivity.kt`

### 核心流程

1. 加载可领用库存列表
2. 选择柜体与柜门
3. 如柜门要求双人认证，则先走双人认证
4. 如是智能锁柜门，先开锁
5. 在开门后的弹窗里刷 RFID/扫码标签
6. 拉取当前化学品库存详情
7. 选择领用数量/方式
8. 如需要称重则读取蓝牙秤
9. 提交领用记录

### 关键特征

#### 柜门选择与双人认证

- 柜门字段 `verify` 决定是否要求双人认证
- `isControl` 决定化学品是否为管控类
- 智能锁通过 `unlockingMethod == 2` 识别

见：

- `UseActivity.kt:198-275`

#### 领用方式

- `mJoinType = 1` 表示称重
- `mJoinType = 2` 表示手动录入
- 见 `UseActivity.kt:81`

#### RFID 查询

- 通过 `getByRfid` 获取领用对象
- 见 `UseActivity.kt:426`
- 对应接口：`ApiService.java:165-176`

#### 蓝牙称重

- `weighData()`、`connectToDeviceWithTimeout()` 等函数负责接秤
- 使用 SPP 蓝牙读取称重值
- 见 `UseActivity.kt:475-585`

#### 再次开门

- 领用弹窗支持“再次开门”，且代码明确说明再次开门**不再需要双人认证**
- 见 `UseActivity.kt:351-362`

#### 异常上报

- 只要开过智能锁却中途返回，就会调用 `outTimeWarn` 做异常数据上报
- 见 `UseActivity.kt:107-113`
- `UseActivity.kt:1318`

### 业务结论

领用流程是该系统最典型的“人-柜-物”闭环流程：**选柜门 -> 授权 -> 开门 -> 识别化学品 -> 称重/录入 -> 提交使用记录**。

---

## 5.5 归还模块

页面：

- `ui/still/ChemicalsAlsoActivity.kt`

### 核心流程

1. 查询待归还列表 `useList`
2. 选择具体记录或扫描 RFID
3. 加载归还详情 `backDetail`
4. 如需要双人认证则先认证
5. 如是智能锁则开柜门
6. 根据业务选择：
   - 正常归还
   - 空瓶处理
   - 废弃出库
7. 如需要称重则接蓝牙秤
8. 调 `giveBack/returnGiveBack` 提交

### 可确认能力

- 补打标签
- 更换 RFID / RFID 补打
- 正常归还
- 空瓶流程
- 废弃流程
- 再次开门
- 超时异常上报

关键代码：

- `ChemicalsAlsoActivity.kt:105-170`
- `ChemicalsAlsoActivity.kt:172-235`
- `ChemicalsAlsoActivity.kt:248-320`
- `ChemicalsAlsoActivity.kt:643-747`
- `ChemicalsAlsoActivity.kt:959`
- `ChemicalsAlsoActivity.kt:1488`

### 业务状态线索

从代码可推断：

- `useStatus = 4`：归还相关状态
- `useStatus = 3`：废弃相关状态
- `returnType = mJoinType`：归还方式区分称重/录入

见：

- `ChemicalsAlsoActivity.kt:530-531`
- `ChemicalsAlsoActivity.kt:602-603`
- `ChemicalsAlsoActivity.kt:822-828`

### 业务结论

归还页面不是单一“归还”，而是将**归还、空瓶、废弃、补标、换 RFID** 集中在一个化学品出库回流工作台中。

---

## 5.6 废弃模块

页面：

- `ui/discard/WasteChemicalsActivity.kt`

### 核心流程

1. 查询可废弃化学品列表 `stockDetailsList`
2. 选择对象或扫描标签/RFID
3. 加载详情 `discardDetail`
4. 如需要则双人认证
5. 录入废弃原因
6. 生成 `GiveBackBean`
7. 调 `giveBack` 完成废弃出库
8. 如果已开过门但未完成，则调用 `outTimeWarn`

关键代码：

- `WasteChemicalsActivity.kt:93-168`
- `WasteChemicalsActivity.kt:237-264`
- `WasteChemicalsActivity.kt:297-330`
- `WasteChemicalsActivity.kt:520`
- `WasteChemicalsActivity.kt:940`
- `WasteChemicalsActivity.kt:1237`

### 业务状态线索

- 废弃提交时 `useStatus = 3`
- `returnType = 1`
- `remark = "repeal"`
- 带 `disuseReason`

见：

- `WasteChemicalsActivity.kt:106-120`

### 业务结论

废弃复用了归还接口，但在业务上属于**单独的危险化学品废弃出库流程**，强调原因记录与后续回收提醒。

---

## 5.7 查询模块

页面：

- `ui/inquiry/InquiryActivity.java`
- `ui/fragments/QueryOneFragment.kt`
- `ui/fragments/QueryTwoFragment.kt`
- `ui/inquiry/QueryDetailsActivity.kt`

### 核心流程

1. 进入查询页时可带登录态与预选柜门信息
2. 登录态下显示柜体/柜门列表
3. 左侧选柜，右侧选柜门
4. 切换查询 Fragment
5. 可通过扫描标签/RFID 查询详情
6. 某些情况下支持开柜门查看

关键代码：

- `InquiryActivity.java:139-181`
- `InquiryActivity.java:240-304`
- `InquiryActivity.java:306-362`
- `InquiryActivity.java:376-420`
- `InquiryActivity.java:505-598`

### 业务特点

- 查询分登录态与未登录态
- 未登录时扫码可查基础详情
- 登录时扫码可查更细库存详情
- 查询结果与柜门上下文绑定较深
- 查询页也允许权限人员执行开门操作

### 业务结论

查询并非纯浏览页面，而是**带柜门上下文的库存/标签/RFID 联动查询入口**。

---

## 5.8 电子台账模块

页面：

- `ui/discard/LedgerActivity.kt`
- `ui/fragments/UseLedgerFragment.kt`
- `ui/fragments/InventoryIedgerFragment.kt`

### 功能

电子台账分为两类：

- 使用台账
- 库存台账

切换方式：

- `LedgerActivity.kt:54-72`
- `LedgerActivity.kt:103-110`

对应后端能力：

- `useRecords`
- `stockLedger`
- `useReturnList`

见：

- `ApiService.java:254-261`
- `ApiRepository.kt:378-397`

---

## 5.9 预警事件模块

页面：

- `ui/uses/WarningEventsActivity.kt`
- `ui/uses/ProcessedActivity.kt`

### 功能

1. 获取预警总数
2. 分页查询预警列表
3. 支持按时间范围筛选
4. 支持按处理状态筛选
5. 进入详情页查看/处理
6. 提交处理说明

关键代码：

- `WarningEventsActivity.kt:50-60`
- `WarningEventsActivity.kt:81-145`
- `WarningEventsActivity.kt:210-240`
- `WarningEventsActivity.kt:563-576`

后端接口：

- `warningNoticeList`
- `warningNoticeDetail`
- `handleMessage`
- `warningNoticeCount`

见：

- `ApiService.java:220-230`

### 业务结论

预警模块是完整闭环，不是单纯看板，支持**统计、筛选、详情、处置**。

---

## 5.10 MSDS 模块

页面：

- `ui/still/MsdsActivity.kt`
- `ui/still/MsdsScreenActivity.kt`

### 功能

1. 查询 MSDS 列表
2. WebView 展示文档内容
3. 生成二维码用于分享/扫码查看
4. 全屏查看

关键代码：

- `MsdsActivity.kt:46-73`
- `MsdsActivity.kt:91-129`
- `MsdsActivity.kt:154-180`

后端接口：

- `getMsdsDetails`
- `msdsDetails`

### 技术特点

- 使用 X5 WebView
- 直接加载 HTML 内容
- 使用二维码地址 `type=1`

---

## 5.11 标签与 RFID 模块

页面：

- `ui/warehousing/ChemicalLabelingActivity.kt`

### 功能

1. 查询标签列表 `tagDetailsList`
2. 查看标签对应化学品详情
3. 补打标签
4. 更换 RFID
5. 打开柜门定位化学品
6. 对需要认证的标签执行双人认证后开门

关键代码：

- `ChemicalLabelingActivity.kt:70-107`
- `ChemicalLabelingActivity.kt:108-161`
- `ChemicalLabelingActivity.kt:165-219`
- `ChemicalLabelingActivity.kt:436-469`
- `ChemicalLabelingActivity.kt:492-513`

### 业务结论

该页面承担了**标签重打、RFID 维护、通过标签反查库存并定位开门**的现场维护职能。

---

## 6. 业务路径说明

## 6.1 启动到主页路径

`StartActivity` → 获取设备绑定实验室信息 → `MainActivity`

路径关键点：

- 自动授权
- 读取本地服务地址
- 调 `iot/aio/report`
- 写全局 `labInfo/subjectId/subjectName/subRoom`

源码：

- `StartActivity.java:100-150`

---

## 6.2 登录路径

### 刷卡登录

`MainActivity.basicConfLog()` → `SwipeActivity` → `cardNum` → `userCardValidation` → 登录成功 → 回主页

源码：

- `MainActivity.java:325-384`
- `SwipeActivity.kt:147-214`

### 人脸登录

`MainActivity.basicConfLog()` → `FaceLoginActivity` → `faceNewCompare` → 登录成功

### 扫码登录

`MainActivity.basicConfLog()` → `ScanLoginActivity` → `auth/scanCode` 或扫码验证相关接口 → 登录成功

---

## 6.3 新增入库路径

`MainActivity` → `PlanAddActivity` → `AddActivity` 手动录入/扫码录入 → 本地待入库列表 → `UnlockActivity`（如需要开门）→ `PlanAddActivityHelp.save()` → `SaveListActivity`

关键业务节点：

1. 选择柜层
2. 录入化学品信息
3. 归属人/课题组绑定
4. 打印标签
5. 蓝牙称重
6. 判断需要开哪些智能柜门
7. 提交入库

源码：

- `MainActivity.java:645-684`
- `PlanAddActivity.java:157-255`
- `AddActivityHelp.java:372-451`
- `PlanAddActivityHelp.java:317-391`

---

## 6.4 领用路径

`MainActivity` → `UseActivity` → 选柜/柜门 → 双人认证（如需）→ 开锁（如需）→ 扫标签/RFID → 称重/录入 → `addUseRecord`

源码：

- `MainActivity.java:504-513`
- `UseActivity.kt:178-321`
- `UseActivity.kt:323-585`
- `ApiService.java:165-176`

---

## 6.5 归还路径

`MainActivity` → `ChemicalsAlsoActivity` → 查询待归还记录或扫描 → 查看详情 → 双人认证（如需）→ 开锁（如需）→ 称重/录入 → `giveBack/returnGiveBack`

源码：

- `MainActivity.java:515-524`
- `ChemicalsAlsoActivity.kt:105-170`
- `ChemicalsAlsoActivity.kt:643-747`

---

## 6.6 废弃路径

`MainActivity` → `WasteChemicalsActivity` → 查询待废弃记录或扫描 → 双人认证（如需）→ 输入废弃原因 → `giveBack(useStatus=3)`

源码：

- `MainActivity.java:482-491`
- `WasteChemicalsActivity.kt:93-168`

---

## 6.7 查询路径

`MainActivity` → `InquiryActivity` → 选柜/柜门 → 查询 Fragment 切换 → 扫描标签/RFID → 查看详情 → 可选开柜

源码：

- `MainActivity.java:493-501`
- `InquiryActivity.java:240-304`
- `InquiryActivity.java:376-420`

---

## 6.8 台账路径

`MainActivity` → `LedgerActivity` → 使用台账 / 库存台账 Fragment 切换

源码：

- `MainActivity.java:526-535`
- `LedgerActivity.kt:54-72`

---

## 6.9 预警路径

`MainActivity` → `WarningEventsActivity` → 筛选列表 → `ProcessedActivity` → 查看/处理预警

源码：

- `MainActivity.java:548-557`
- `WarningEventsActivity.kt:61-72`

---

## 6.10 MSDS 路径

`MainActivity` → `MsdsActivity` → 搜索 MSDS → 查看 HTML 内容 → 全屏查看

源码：

- `MainActivity.java:559-564`
- `MsdsActivity.kt:46-129`

---

## 7. 业务规则与域模型

## 7.1 核心业务对象

### 化学品

模型：

- `ChemicalSearchBean.kt`
- `HxpChemicalVo.java`

关键字段：

- `chemicalId`
- `chemicalName`
- `casNum`
- `chemicalLevel`：1 管控，2 非管控
- `chemicalPurity`
- `chemicalCategory`
- `packNum`
- `specNum`
- `depositRequire`
- `msdsId`

见：

- `ChemicalSearchBean.kt:7-32`

### 柜体/柜门/柜锁

模型：

- `RuleBean.kt`
- `CabinetDoorVo.kt`
- `LockVoListBean.kt`

关键字段：

- `cabinetId`
- `cabinetName`
- `doorUniqueId`
- `cabinetDoorVoList`
- `lockNum`

见：

- `RuleBean.kt:3-28`

### 用户权限

模型：

- `UserValidationBean.kt`

决定：

- 是否能登录
- 是否能开门
- 是否可操作管控类/非管控类
- 是否可作为双人认证参与者

### 基础配置

模型：

- `ConfigBean.kt`

关键字段：

- `loginType` 登录方式
- `verifyType` 双人验证方式
- `operateTimeout`
- `timeoutHour`
- `useHour`
- `backTime`
- `signOutTime`
- `offTime`
- `vinVex` 称重容差率

见：

- `ConfigBean.kt:5-32`

## 7.2 角色权限策略

根据 `ChemicalApp` 与 `UserValidationBean`，系统至少存在两层权限模型：

### 全局业务角色

- 校级管理员
- 院级管理员
- 实验室负责人
- 安全负责人
- 柜锁管理员
- 归属人
- 课题组成员
- 白名单/准入人员

### 页面级快捷标识

`ChemicalApp` 中维护：

- `administrators`
- `responsibles`

注释说明：

- 管控类化学品：仅校级/院级管理员可操作
- 实验室负责人/安全责任人/柜门管理员：仅能操作非管控

见：

- `ChemicalApp.kt:56-59`

## 7.3 柜锁规则

代码中明确：

- `unlockingMethod == 2` 表示智能锁
- 只有智能锁才进入轮询开锁状态判断
- 柜门已开/无智能锁时直接进入后续操作

见：

- `InquiryActivity.java:95-103`
- `UseActivity.kt:209-214`
- `ChemicalsAlsoActivity.kt:154-159`
- `ChemicalLabelingActivity.kt:165-219`

## 7.4 超时与回退规则

由配置驱动：

- 自动返回：`backTime`
- 自动注销：`signOutTime`
- 弹窗关闭：`offTime`

同时，开锁后若未完成业务就返回，会调用：

- `outTimeWarn`

用于记录异常或超时操作。

---

## 8. 技术实现策略

## 8.1 UI 与架构策略

### 技术栈

- Java + Kotlin 混合
- 传统 Activity/Fragment 架构
- ViewBinding
- RecyclerView + 自定义 Dialog
- RxJava3 + Retrofit

见：

- `app/build.gradle:37-45`
- `app/build.gradle:85-105`

### 分层方式

- UI 页面：`xn.hxp.ui/**`
- 接口仓储：`ApiRepository.kt`
- Retrofit 包装：`ChemicalRetrofit.kt`
- 原始 HTTP 工具：`HttpTool.java`
- 全局状态：`ChemicalApp.kt`

特点：

- 业务页面直接通过 `ApiRepository.INSTANCE.xxx()` 调接口
- 某些老流程仍保留 `HttpTool + OkHttpUtils` 直连方式
- 属于“仓储层 + 历史工具共存”的过渡架构

## 8.2 网络层策略

### Retrofit 主通路

关键文件：

- `ApiService.java`
- `ChemicalRetrofit.kt`
- `ApiRepository.kt`
- `HttpClient.kt`

网络特征：

- `ApiService` 统一声明业务接口
- `ChemicalRetrofit` 做响应成功判断与请求体包装
- `ApiRepository` 统一调度线程：IO -> Main
- `HttpClient` 负责 OkHttp/Retrofit 创建

### 统一响应包装

后端返回统一结构：

- `code`
- `message`
- `data`

在 `ChemicalRetrofit.kt` 中统一判断 `isSuccess()`，失败抛 `NetException`。

### Token 策略

- 登录成功后将 token 写入 `HttpClient.token`
- `TokenHeaderInterceptor` 自动加 `authorization` 头
- 解析响应判断 token 是否过期并广播

见：

- `ChemicalRetrofit.kt:108-110`
- `ChemicalRetrofit.kt:855-856`
- `TokenHeaderInterceptor.kt:21-63`

### 旧接口补充通路

`HttpTool.java` 仍承担若干流程：

- 启动设备上报
- 获取柜体信息
- 直接入库提交
- 退出登录
- 心跳上报
- 某些旧版双人认证接口

说明项目存在一定历史接口兼容层。

## 8.3 本地数据策略

### SharedPreferences

用途：

- 服务端基础地址
- 图片地址
- 二维码地址
- 相机方向
- 管理员密码
- 双人认证缓存人员列表

见：

- `SharedPreferencesHelper.kt:19-39`
- `SharedPreferencesHelper.kt:42-70`

### Room 临时库

主要用于入库计划编排，不是全局核心数据库。

保存内容：

- 柜体
- 柜门
- 柜层选择
- 实验室负责人/安全员
- 待入库清单

见：

- `ui/plan/room/**`
- `PlanAddActivity.java:100-113`

## 8.4 权限与受控终端策略

Manifest 中声明了大量普通权限与高权限：

- 网络、存储、录音、摄像头、蓝牙、USB、定位
- `INSTALL_PACKAGES`
- `WRITE_SECURE_SETTINGS`
- `READ_PRIVILEGED_PHONE_STATE`
- `READ_LOGS`
- `MANAGE_USB`
- `USES_POLICY_FORCE_LOCK`

见：

- `AndroidManifest.xml:5-63`

这表明应用运行环境大概率是：

- 定制 ROM
- 系统签名应用
- 企业/工控专用设备

同时 `Tool.java` 直接调用：

- `suExec`
- `reboot`
- `force-stop`
- `pm set-home-activity`
- `settings put global bluetooth_on`

见：

- `Tool.java:24-99`

说明该 App 不只是普通应用，更像**设备侧受控终端软件**。

## 8.5 升级与设备监控策略

### 启动设备上报

- `iot/aio/report`
- 获取实验室绑定信息与版本相关信息

### 心跳

- 主页面每 20 秒调用 `terminal/machine/heartbeat`
- 上报设备号、版本、前台展示状态、IP 等信息

见：

- `MainActivity.java:194-217`
- `HttpTool.java:220-248`

### 安装升级

Manifest 申请了安装权限，并配置 `FileProvider`：

- `AndroidManifest.xml:249-262`

接口层也有：

- `onepcApkUpdate`

说明系统具备 APK 升级状态回传能力。

---

## 9. 硬件与外设接入策略

## 9.1 摄像头 / 人脸识别

### 方式

- Fotoapparat + FaceDetectorProcessor
- ML Kit face detection
- ArcSoft 相关 jar/aar 同时存在

依赖与文件：

- `app/build.gradle:73, 139`
- `app/libs/arcsoft_face.jar`
- `app/libs/facedetector-1.0.0.aar`
- `TwoVerificationActivity.kt:44-50`

### 用途

- 登录人脸识别
- 双人认证人脸校验

---

## 9.2 刷卡 / 串口扫码 / 键盘式输入

### 方式

- `PortScanHelper` 拦截按键流
- `UsbReceiver` 监听 USB 插拔
- `PortScanService` 设计为系统服务形式统一广播扫码结果

见：

- `SwipeActivity.kt:118-145`
- `InquiryActivity.java:117-137`
- `PortScanService.kt:9-67`

### 用途

- 刷卡登录
- 查询页扫码
- 领用/归还/废弃/标签页扫描标签或 RFID 码

---

## 9.3 蓝牙秤

### 实现方式

#### 主通路

- `SppTool.java` 使用 Feasycom SPP SDK
- 经典蓝牙串口协议
- 解析称重数据字符串

见：

- `SppTool.java:16-91`

#### 辅助旧实现

- `BluetoothHelper.kt`
- 使用 RFCOMM UUID `00001101-0000-1000-8000-00805F9B34FB`

见：

- `BluetoothHelper.kt:22-124`

### 用途

- 入库称重
- 领用称重
- 归还称重

### 配置方式

设置页支持：

- 扫描蓝牙设备
- 保存 `sppMac / sppName`

见：

- `SettingActivity.java:78-89`

## 9.4 柜门/锁控

### 方式

后端接口驱动为主：

- `getCabinetLock`
- `lockOperate`
- `getLocks`
- `outTimeWarn`

前端负责：

- 选定柜门
- 组装上下文（实验室、柜门、开锁人）
- 提交开锁请求
- 轮询锁状态
- 超时上报

见：

- `ApiService.java:209-248`
- `InquiryActivity.java:505-598`
- `UseActivity.kt:1140-1318`
- `ChemicalsAlsoActivity.kt:1488-1630`
- `WasteChemicalsActivity.kt:1237-1368`
- `ChemicalLabelingActivity.kt:904-1074`

## 9.5 标签打印 / RFID

### 已引入依赖

- `USBPrintSDK.jar`
- `autoreplyprint.aar`
- `whdrawlabel1.1.jar`
- `sdkapi.jar`

见：

- `app/libs/*`

### 业务动作

- 打印化学品标签
- 补打标签
- 更换 RFID
- RFID 补打/写入

页面：

- `ChemicalLabelingActivity.kt`
- `ChemicalsAlsoActivity.kt`
- 入库流程中的 `PrintLabelDialog`

## 9.6 WebView / 文档预览

- 使用腾讯 X5 内核
- 用于 MSDS HTML 展示与全屏浏览

见：

- `ChemicalApp.kt:142-160`
- `MsdsActivity.kt:91-117`

---

## 10. 关键后端接口能力边界

从 `ApiService.java` 可以明确后端提供的能力边界：

### 10.1 认证与身份

- `auth/cardNum`
- `chemical/aio/verify/userCardValidation`
- `chemical/aio/verify/useCardVerify`
- `chemical/aio/verify/aioScanLogin`
- `auth/faceByPic`
- `chemical/aio/verify/checkUserFaceByPic`
- `auth/logout`

### 10.2 实验室与柜体

- `laboratory/subRelInfo/getRelList`
- `chemical/aio/getCabinetList`
- `chemical/aio/getCabinetBySubId`
- `chemical/aio/getCabinetLock`
- `chemical/aio/lockOperate`
- `chemical/aio/getLockStatus`

### 10.3 化学品主数据

- `chemical/aio/searchChemica`
- `system/dict/item/option`
- `chemical/aio/searchProducer`
- `chemical/aio/searchSpec`
- `chemical/aio/controlConfig`

### 10.4 入库与库存

- `chemical/aio/addStock`
- `chemical/aio/addStockCheck`
- `chemical/aio/getStockWaitDetails`
- `chemical/aio/waitList`
- `chemical/aio/stockList`
- `chemical/aio/indexStockList`
- `chemical/aio/tagDetailsList`
- `chemical/aio/checkRfid`
- `chemical/aio/updateRfid`

### 10.5 领用与归还

- `chemical/aio/byRfid`
- `chemical/aio/indexDetailbyRfid`
- `chemical/aio/getStockDetailsByCode`
- `chemical/aio/addUserecord`
- `chemical/aio/useList`
- `chemical/aio/backDetail`
- `chemical/aio/giveBack`
- `chemical/aio/useReturnList`

### 10.6 废弃与处置

- `chemical/aio/discardDetail`
- `chemical/aio/stockDetailsList`

### 10.7 台账与预警

- `chemical/aio/useRecords`
- `chemical/aio/stockLedger`
- `system/aioUnify/warningNoticeList`
- `system/aioUnify/warningNoticeDetail`
- `system/warningNotice/handleMessage`
- `system/aioUnify/warningNoticeCount`
- `chemical/aio/outTimeWarn`

### 10.8 MSDS 与配置

- `chemical/aio/msds`
- `chemical/aio/msdsDetails`
- `chemical/aio/basicConfig`
- `system/logo/config/getConfInfo`

### 10.9 设备上报与升级

- `iot/aio/report`
- `iot/aio/monitor`
- `terminal/machine/heartbeat`
- `laboratory/apkfile/onepcApkUpdate/{id}/{state}`

---

## 11. 第三方依赖与本地 SDK 策略

## 11.1 Maven 依赖

主要依赖包括：

- Retrofit 2.11
- OkHttp 4.12
- RxJava3 / RxAndroid
- Gson
- Glide
- EventBus
- BRVAH
- XXPermissions
- DialogX
- CameraX
- ML Kit Face Detection
- FastBle
- Fotoapparat
- ZXing
- XPopup
- ANRWatchDog

见：

- `app/build.gradle:55-153`

## 11.2 本地 jar/aar/so

- `USBPrintSDK.jar`
- `arcsoft_face.jar`
- `arcsoft_image_util.jar`
- `autoreplyprint.aar`
- `facedetector-1.0.0.aar`
- `feasyblue.jar`
- `sdkapi.jar`
- `tbs_sdk_v4.3.0.165_20210628_103707.jar`
- `whdrawlabel1.1.jar`
- `libserial_port_wh.so`
- `libfacp.so`
- `libota.so`
- `libutil.so`

这些依赖说明系统同时整合了：

- 打印
- 人脸
- WebView 内核
- 蓝牙串口
- 本地串口
- OTA / 设备能力扩展

---

## 12. 当前源码体现出的设计特点

## 12.1 优点

1. 业务域边界比较清晰
   - 登录、认证、入库、领用、归还、废弃、查询、台账、MSDS、预警分包明确

2. 终端场景适配明显
   - 自动恢复、心跳、管理员入口、设备设置、蓝牙配置、系统权限操作完善

3. 安全流程完整
   - 登录权限、双人认证、智能锁、异常上报、预警处理形成闭环

4. 软硬件融合较深
   - 柜门、蓝牙秤、标签、扫码、刷卡、人脸不是外挂，而是业务主链路的一部分

## 12.2 需要注意的实现特征

1. 存在新旧接口栈并存
   - `ApiRepository/ChemicalRetrofit` 与 `HttpTool` 并存

2. 全局状态较多依赖 `ChemicalApp`
   - 业务推进依赖全局单例状态

3. 页面逻辑较重
   - 多个 Activity 承载了较多流程、硬件、弹窗和状态管理逻辑

4. 部分二维码地址为硬编码域名
   - 例如 `https://labcontrol.nwafu.edu.cn/api/...`
   - 与 `API_BASE_QC_URL` 并存

---

## 13. 总结

该仓库对应的是一个典型的**实验室化学品智能管理终端**，不是单纯的库存系统，而是一个把以下能力整合到统一设备端工作流里的应用：

- 实验室化学品主数据管理
- 智能柜门/智能锁控制
- 多方式登录与双人认证
- 入库、领用、归还、空瓶、废弃全生命周期管理
- RFID/标签/扫码联动
- 蓝牙称重复核
- 电子台账、MSDS、预警闭环
- 受控终端运维、心跳、升级、异常恢复

从实现角度看，系统采用了**传统 Android 业务页面 + Repository/Retrofit + 一体机设备控制 + 本地临时缓存**的混合架构，强调“现场操作闭环”和“安全合规可追溯”。

如果后续需要继续深入，建议优先沿以下三个方向细读：

1. **领用/归还/废弃页面**：最能体现主业务闭环
2. **双人认证页面**：最能体现安全策略
3. **PlanAdd + Room 临时库**：最能体现入库编排和智能柜协同

---

## 14. 源码导航版（适合开发接手）

本章节按“从哪里进、看哪些类、每个页面依赖哪些适配器/对话框/接口/模型”的方式整理，适合接手开发时快速建立代码地图。

## 14.1 启动与全局

### 1）应用全局入口

- `app/src/main/java/xn/hxp/app/ChemicalApp.kt:32`

建议先看：

- 全局状态字段：`userData / subjectId / confs / labInfo / administrators / responsibles`
- 初始化组件：`SppTool`、`BleManager`、`DialogX`、`QbSdk`
- ANR 恢复策略：`ANRWatchDog`

### 2）启动页

- `app/src/main/java/xn/hxp/ui/StartActivity.java:34`

建议重点看：

- `requestPermission()`：设备权限获取方式
- `unreasonableCode()`：本地地址/相机配置恢复
- `initView()`：设备校验与实验室绑定入口

关联类：

- `xn.hxp.ui.SettingActivity`
- `xn.hxp.utils.SharedPreferencesHelper`
- `com.rc.httpcore.client.HttpTool`

### 3）主页

- `app/src/main/java/xn/hxp/ui/MainActivity.java:87`

建议重点看：

- `basicConf()`：基础配置拉取
- `basicConfLog()`：登录方式分流
- `getCabinetIn()`：主页柜体轮播
- `getHxpStockWait()`：入库入口分流
- 自动登出 handler 与心跳 timer

关联适配器/弹窗：

- `ui/adapter/CabinetBannerAdapter.java`
- `weidith/PlanDialog.java`
- `weidith/CustomDialog.kt`

---

## 14.2 登录与认证导航

### 1）刷卡登录

- `app/src/main/java/xn/hxp/ui/login/SwipeActivity.kt:46`

建议先看：

- `handleScanEvent()`：刷卡登录
- `authenticationInfo()`：登录后权限校验

依赖：

- `receiver/PortScanHelper`
- `receiver/UsbReceiver`
- `ApiRepository.cardNum`
- `ApiRepository.userCardValidation`
- `weidith/AuthenticationDialog.kt`

### 2）扫码登录

- `app/src/main/java/xn/hxp/ui/login/ScanLoginActivity.kt`

用途：扫码方式登录或与其它登录方式组合切换。

### 3）人脸登录

- `app/src/main/java/xn/hxp/ui/login/FaceLoginActivity.java`
- `app/src/main/java/xn/hxp/ui/login/FacialCardActivity.kt`

用途：纯人脸登录、人脸+刷卡组合登录。

### 4）双人认证总控

- `app/src/main/java/xn/hxp/ui/verify/TwoVerificationActivity.kt:64`

这是接手时必须精读的页面，建议重点关注：

- `mTag`：当前认证服务于哪个业务场景
- `mVerTyps`：单认证方式
- `mCertificationType`：组合认证方式
- `mDoorId / mChemicalLevel`：认证上下文
- `SharedPreferencesHelper.saveList()`：认证通过后的双人缓存
- `when (mTag)`：不同业务场景的权限分支

当前可确认：

- `mTag = 0`：新增入库
- `mTag = 1`：归还/废弃/标签管理等
- `mTag = 2`：待入库
- `mTag = 3`：领用

关键代码点：

- `TwoVerificationActivity.kt:127-146`
- `TwoVerificationActivity.kt:464`
- `TwoVerificationActivity.kt:529-616`
- `TwoVerificationActivity.kt:1353-1467`
- `TwoVerificationActivity.kt:1658-1848`

关联类：

- `ui/DoubleDialogBean`
- `weidith/DoublePeopleDialog.kt`
- `receiver/PortScanHelper`
- `ApiRepository.useCardVerify`
- `ApiRepository.aioScanLogin`
- `ApiRepository.checkUserFaceByPic`

---

## 14.3 入库线源码导航

### 1）计划入库页

- `app/src/main/java/xn/hxp/ui/plan/PlanAddActivity.java:59`

建议阅读顺序：

1. `onInit()`：初始化 Room 临时表、页面事件
2. `subAdd` 点击逻辑：决定是否需要先开柜门
3. `intentActivityResultLauncher`：接收手动录入返回

关联 DAO：

- `ui/plan/room/dao/HxpCabinetDAO`
- `ui/plan/room/dao/HxpDoorDAO`
- `ui/plan/room/dao/HxpLayerDAO`
- `ui/plan/room/dao/HxpInventoryDAO`
- `ui/plan/room/dao/HxpLabDirectorDAO`
- `ui/plan/room/dao/HxpLabSafeDAO`

### 2）计划入库辅助类

- `app/src/main/java/xn/hxp/ui/plan/PlanAddActivityHelp.java:53`

建议重点看：

- `getLabInfo()`：实验室基础信息
- `getCabinetList()`：柜体/柜门落本地库
- `selectCabinetLayer()`：当前选中柜层
- `updateInventoryUi()`：待入库列表刷新
- `chemicalSearchByCode()`：扫码录入入口
- `startScanEventListener()`：扫码识别兼容逻辑
- `save()`：最终入库提交

该类是“计划入库编排中枢”。

### 3）手动录入页

- `app/src/main/java/xn/hxp/ui/plan/add/AddActivity.java:58`

建议重点看：

- 化学品搜索、CAS 搜索
- 归属人/课题组选择
- 规格、密度、净含量、数量
- 存储到本地待入库清单

### 4）手动录入辅助类

- `app/src/main/java/xn/hxp/ui/plan/add/AddActivityHelp.java:38`

建议重点看：

- `hxpSearch()`：化学品搜索
- `chemicalSearchResult()`：搜索结果回填
- `save(boolean isWeigh)`：录入校验与后续动作总控
- `startBluetoothWeigh()`：蓝牙称重入口
- `qrInit()`：扫码录入后的只读回填模式

### 5）入库开锁页

- `app/src/main/java/xn/hxp/ui/plan/unlock/UnlockActivity.java`
- `app/src/main/java/xn/hxp/ui/plan/unlock/UnlockActivityHelp.java`
- `app/src/main/java/xn/hxp/ui/plan/unlock/UnlockAdapter.java`

用途：

- 针对待入库清单需要开的智能柜门逐个开锁
- 管理上门/下门开锁状态
- 开锁完成后进入正式保存

### 6）入库完成页

- `app/src/main/java/xn/hxp/ui/plan/save_list/SaveListActivity.java`

用途：提交完成后的结果展示。

### 7）已申领未入库页

- `app/src/main/java/xn/hxp/ui/plan/already/AlreadyActivity.java`
- `app/src/main/java/xn/hxp/ui/plan/already/AlreadyAdapter.java`

用途：处理“已申领未入库”业务分支。

---

## 14.4 领用线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/uses/UseActivity.kt:58`

建议阅读顺序：

1. `onInit()`：列表、柜门、返回逻辑
2. `inAdapter()`：左柜/右门选择与认证分流
3. `verifyChecking()`：多认证方式组合
4. `usageLabelDialog()`：开门后的领用工作台
5. `getByRfid()`：按 RFID 查领用对象
6. `weighData()`：称重或录入重量
7. `getStockList()`：领用列表查询
8. `openLock()`：开锁请求
9. `outTimeWarnData()`：异常上报

关键依赖：

#### 适配器

- `ui/adapter/CabinetDoorAdapter.kt`
- `ui/adapter/CabinetDoorRighAdapter.kt`
- `ui/adapter/UseListAdapter.kt`
- `ui/adapter/UsageLabelDialogAdapter.java`

#### 对话框

- `weidith/UsageLabelDialog.java`
- `weidith/WeighDialog.kt`
- `weidith/CustomDialog.kt`
- `weidith/StorageDialog.kt`

#### 相关接口

- `ApiRepository.getStockList`
- `ApiRepository.getByRfid`
- `ApiRepository.addUseRecord`
- `ApiRepository.lockOperate`
- `ApiRepository.getLocks`
- `ApiRepository.outTimeWarn`

#### 关键模型

- `UseBean`
- `UsePostDataBean`
- `ChemistryBean`
- `LockVoListBean`
- `TimeWarBean`

---

## 14.5 归还/空瓶/废弃线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/still/ChemicalsAlsoActivity.kt:59`

建议阅读顺序：

1. `onInit()`：页面操作入口
2. `useList()`：待归还列表
3. `handleScanEvent()`：扫码进入详情
4. `verifyChecking()`：归还类双人认证
5. `weighData()`：归还称重
6. `cabinetOpen()` / `openLock()`：开门
7. `updateRfid()`：标签更换
8. `discardDialogShow()` / `emptiesDialogsShow()`：废弃/空瓶
9. `throwableView()`：页面统一异常处理

关键依赖：

#### 适配器

- `ui/adapter/ReturningChemicalsAdapter.kt`

#### 对话框

- `weidith/DiscardDialog.kt`
- `weidith/EmptiesDialog.kt`
- `weidith/AirBottleDialog.kt`
- `weidith/AirBottleNewDialog.kt`
- `weidith/CabinetOpenDialog.kt`
- `weidith/StorageDialog.kt`

#### 相关接口

- `ApiRepository.useList`
- `ApiRepository.backDetail`
- `ApiRepository.giveBack`
- `ApiRepository.returnGiveBack`
- `ApiRepository.updateRfid`
- `ApiRepository.lockOperate`
- `ApiRepository.getLocks`

#### 关键模型

- `ReturningChemicalsBean`
- `ReturnDetailsBean`
- `ReturnGiveBackBean`
- `GiveBackBean`

---

## 14.6 废弃线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/discard/WasteChemicalsActivity.kt:45`

建议阅读顺序：

1. `onInit()`：页面入口与分页
2. `stockDetailsList()`：废弃列表
3. `handleScanEvent()` / `codeDateIn()`：扫描后定位化学品
4. `verifyChecking()`：废弃认证
5. `discardDialogShow()`：废弃原因录入
6. `openLock()`：开门
7. `outTimeWarnData()`：异常退出上报

关键依赖：

- `ui/adapter/WasteChemicalsAdapter.kt`
- `weidith/DiscardDialog.kt`
- `weidith/StorageDialog.kt`
- `ApiRepository.stockDetailsList`
- `ApiRepository.discardDetail`
- `ApiRepository.giveBack`

---

## 14.7 查询线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/inquiry/InquiryActivity.java:69`

建议阅读顺序：

1. `initData()`：登录态/预选柜门处理
2. `fragmentInView()`：查询页签初始化
3. `inAdapter()`：左柜右门联动
4. `getCabinet()`：柜门初始化逻辑
5. `handleScanEvent()`：扫码查询详情
6. `openLock()` / `getLocks()`：查询场景开门

关键依赖：

#### Fragment

- `ui/fragments/QueryOneFragment.kt`
- `ui/fragments/QueryTwoFragment.kt`

#### 适配器

- `ui/adapter/CabinetDoorAdapter.kt`
- `ui/adapter/CabinetDoorRighAdapter.kt`

#### 对话框

- `weidith/PromptDialog.java`
- `weidith/ScanCodeDialog.kt`
- `weidith/CustomDialog.kt`

#### 接口

- `ApiRepository.getCabinetList`
- `ApiRepository.indexDetailbyRfid`
- `ApiRepository.getStockDetailsByCode`
- `ApiRepository.lockOperate`
- `ApiRepository.getLocks`

---

## 14.8 标签/RFID 维护线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/warehousing/ChemicalLabelingActivity.kt:43`

建议阅读顺序：

1. `onInit()`：列表、查询、补打、换标
2. `labelingData()`：标签列表查询
3. `getIdDate()` / `upView()`：点击记录加载详情
4. `verifyChecking()`：标签场景认证
5. `updateRfid()`：RFID 更换
6. `openLock()`：按标签定位开柜

关键依赖：

#### 适配器

- `ui/adapter/ChemicalLabelingAdapter.kt`
- `ui/adapter/CustomSpinnerTwoAdapter.kt`

#### 对话框

- `weidith/AirBottleDialog.kt`
- `weidith/AirBottleNewDialog.kt`
- `weidith/StorageDialog.kt`

#### 接口

- `ApiRepository.tagDetailsList`
- `ApiRepository.getDetailsById`
- `ApiRepository.updateRfid`
- `ApiRepository.lockOperate`

---

## 14.9 台账线源码导航

### 1）电子台账容器页

- `app/src/main/java/xn/hxp/ui/discard/LedgerActivity.kt:28`

职责：

- 切换使用台账和库存台账两个 Fragment

### 2）使用台账

- `app/src/main/java/xn/hxp/ui/fragments/UseLedgerFragment.kt:33`

建议重点看：

- 柜门过滤
n- 类别过滤
- 级别过滤
- 时间范围过滤
- `getLists()` -> `ApiRepository.useRecords`
- `butReturned` -> `ChecklistsActivity`

### 3）库存台账

- `app/src/main/java/xn/hxp/ui/fragments/InventoryIedgerFragment.kt:30`

建议重点看：

- 柜门过滤
- 类别过滤
- 级别过滤
- 出库方式过滤：在库/空瓶出库/废弃出库/整瓶领用
- `getLists()` -> `ApiRepository.stockLedger`

关联适配器：

- `ui/adapter/UseLedgerAdapter.kt`
- `ui/adapter/InventoryAdapter.kt`
- `ui/adapter/InventoryListAdapter.kt`

---

## 14.10 预警线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/uses/WarningEventsActivity.kt:33`
- `app/src/main/java/xn/hxp/ui/uses/ProcessedActivity.kt`

建议阅读顺序：

1. `warningNoticeCount()`：预警总数
2. `getLists()`：预警分页查询
3. 时间筛选、状态筛选
4. item child click -> `ProcessedActivity`

关键依赖：

- `ui/adapter/WarningEventsAdapter.kt`
- `ApiRepository.warningNoticeList`
- `ApiRepository.warningNoticeCount`
- `ApiRepository.warningNoticeDetail`
- `ApiRepository.handleMessage`

---

## 14.11 MSDS 线源码导航

### 核心页面

- `app/src/main/java/xn/hxp/ui/still/MsdsActivity.kt:32`
- `app/src/main/java/xn/hxp/ui/still/MsdsScreenActivity.kt`

建议重点看：

- `msdsDetails(searchValue)`：查询
- WebView 初始化与 HTML 渲染
- `screen` 按钮跳转全屏页
- MSDS 二维码生成

关联类：

- `ui/adapter/MsdsListAdapter.kt`
- `com.rc.core.util.WebViewHelper.kt`
- `com.rc.core.util.VideoFullScreenWebChromeClient.kt`

---

## 14.12 设置、设备与基础工具导航

### 1）设置页

- `app/src/main/java/xn/hxp/ui/SettingActivity.java:24`

建议重点看：

- 服务地址配置
- 管理员密码配置
- 蓝牙秤配置
- 相机前后置配置
- 系统设置/重启/文件浏览器入口

### 2）系统控制工具

- `app/src/main/java/xn/hxp/utils/Tool.java:16`

负责：

- su 命令执行
- 重启设备
- 重启 App
- 打开系统设置/文件浏览器
- 状态栏显示
- 获取设备序列号

### 3）蓝牙 SPP

- `app/src/main/java/xn/hxp/utils/bluetooth/SppTool.java:16`

负责：

- 蓝牙秤扫描、连接、收包、断连
- 将字符串称重值回调给业务页

### 4）称重弹窗

- `app/src/main/java/xn/hxp/weidith/ble/BluetoothWeighDialog.java:40`

建议重点看：

- 蓝牙连接建立
- 称重值解析
- 净含量与规格、称重值关系校验
- `HttpTool.addStockCheck()` 的称重校验提交

### 5）打印工具

- `app/src/main/java/xn/hxp/utils/PrintTool.java:16`

负责：

- 打开 USB 打印机
- 根据 `PrintBean` 生成标签图像
- 打印并切纸

### 6）扫码与 USB 接入

- `app/src/main/java/xn/hxp/receiver/PortScanService.kt:9`
- `app/src/main/java/xn/hxp/receiver/UsbReceiver.kt`
- `app/src/main/java/xn/hxp/receiver/PortScanHelper*`

负责：

- 键盘式扫码输入
- USB 设备接入监听
- 统一分发扫码内容

---

## 14.13 适配器与对话框总表

### 常用适配器

- 柜体/柜门：`CabinetDoorAdapter.kt`、`CabinetDoorRighAdapter.kt`、`CabinetBannerAdapter.java`
- 领用：`UseListAdapter.kt`、`UsageLabelDialogAdapter.java`
- 归还：`ReturningChemicalsAdapter.kt`
- 废弃：`WasteChemicalsAdapter.kt`
- 标签：`ChemicalLabelingAdapter.kt`
- 预警：`WarningEventsAdapter.kt`
- 台账：`UseLedgerAdapter.kt`、`InventoryAdapter.kt`
- MSDS：`MsdsListAdapter.kt`

### 常用对话框

- 通用提示：`CustomDialog.kt`
- 双人认证结果：`DoublePeopleDialog.kt`
- 领用工作台：`UsageLabelDialog.java`
- 称重：`WeighDialog.kt`、`BluetoothWeighDialog.java`
- 柜位选择：`StorageDialog.kt`
- 废弃：`DiscardDialog.kt`
- 空瓶：`EmptiesDialog.kt`
- 标签/RFID：`AirBottleDialog.kt`、`AirBottleNewDialog.kt`
- 标签打印确认：`PrintLabelDialog.java`
- 化学品选择：`SelectChemicalDialog.java`
- 归属人选择：`BelongingPersonDialog.kt`
- 课题组选择：`SelectTopicDialog.kt`
- 查询结果：`PromptDialog.java`、`ScanCodeDialog.kt`
- 蓝牙秤设备选择：`BleSelectorDialog.java`

---

## 14.14 接手开发建议阅读顺序

如果是第一次接手这个项目，建议按下面顺序看源码：

1. `ChemicalApp.kt`、`StartActivity.java`、`MainActivity.java`
2. `ConfigBean.kt`、`UserValidationBean.kt`、`RuleBean.kt`
3. `ApiService.java`、`ChemicalRetrofit.kt`、`ApiRepository.kt`
4. `TwoVerificationActivity.kt`
5. `UseActivity.kt`
6. `ChemicalsAlsoActivity.kt`
7. `WasteChemicalsActivity.kt`
8. `PlanAddActivity.java` + `PlanAddActivityHelp.java`
9. `AddActivity.java` + `AddActivityHelp.java`
10. `ChemicalLabelingActivity.kt`
11. `InquiryActivity.java`
12. `LedgerActivity.kt` + 两个台账 Fragment
13. `WarningEventsActivity.kt`、`MsdsActivity.kt`
14. `Tool.java`、`SppTool.java`、`BluetoothWeighDialog.java`、`PrintTool.java`

如果目的是修业务 Bug，优先看对应页面 + 认证页 + 开锁逻辑；
如果目的是重构，优先梳理 `ApiRepository / HttpTool / ChemicalApp` 三条主线。
