对既有代码进行架构分析,整理架构调整方案。
This commit is contained in:
1 parent
135a1925ac
commit
2bc30f18d7
21 files changed
+4708
No files matched your search
+110
@@ -0,0 +1,110 @@
|
|||||||
|
# 01 系统总览
|
||||||
|
|
||||||
|
## 1. 业务定位
|
||||||
|
|
||||||
|
`yktgl` 是铁路行车公寓的**叫乘(叫班)管理系统**。公寓为值乘机车的乘务员提供住宿,系统负责把“入住—叫乘—出乘—离寓”串起来,并对接机务运安系统的乘务计划,确保乘务员按时出乘。
|
||||||
|
|
||||||
|
核心业务闭环:
|
||||||
|
|
||||||
|
1. 乘务员到寓,在设备或值班端完成**入寓登记**,分配房间与床位,读取/生成叫乘计划(开车时间、叫乘时间、复叫时间、叫乘结束时间)。
|
||||||
|
2. 到点自动**叫乘**:通过电话/广播(Asterisk 会议桥 + TTS)呼叫房间和值班台;未应答触发**复叫**,仍未应答触发**报警**。
|
||||||
|
3. 乘务员**应答**后记录应答时间,结束本次叫乘。
|
||||||
|
4. 乘务员**离寓**(刷卡/人脸/值班端操作),释放房间床位,写离寓时间与归档标记。
|
||||||
|
5. 卡务侧完成**补助发放、余额、消费、现金充值**;管理端提供房间、人员、交路、统计报表、设备心跳与指令。
|
||||||
|
|
||||||
|
## 2. 使用角色
|
||||||
|
|
||||||
|
| 角色 | 使用入口 | 主要动作 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 公寓值班员 | Web 管理端(`YktVue`) | 入寓/离寓登记、叫乘监控与人工干预、换房、房间状态、充值审核 |
|
||||||
|
| 公寓管理员 | Web 管理端 | 人员、交路、房间、设备、报表、用户权限 |
|
||||||
|
| 乘务员 | 公寓设备(叫乘屏/签到机/房间屏/消费机/售货机) | 自助登记、查询、应答、消费、充值 |
|
||||||
|
| 保洁人员 | 房间设备/管理端 | 开始/结束保洁 |
|
||||||
|
| 运安系统 | SOAP / HTTP | 下发乘务计划、人员资料 |
|
||||||
|
| 中心服务器 | HTTP | 汇总公寓人员、财务数据 |
|
||||||
|
|
||||||
|
## 3. 运行形态
|
||||||
|
|
||||||
|
系统同时支持两种部署语义,但代码是同一套:
|
||||||
|
|
||||||
|
- **公寓端**:每套公寓一套服务(或同一服务按 IP 区分公寓),连接本地 Asterisk、串口控制台、各类设备。
|
||||||
|
- **中心/汇总端**:通过 `/synData/*`、`/excel/*` 提供人员与财务数据汇总;部分环境由中心下发交路。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph 公寓现场
|
||||||
|
DEV[叫乘屏/签到机/房间屏/消费机/售货机]
|
||||||
|
WEB[值班员浏览器 YktVue]
|
||||||
|
PHONE[电话/广播终端]
|
||||||
|
CONSOLE[串口控制台]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 应用服务器
|
||||||
|
APP[Spring Boot yktgl<br/>context /yktgl :8081]
|
||||||
|
WS[WebSocket 服务]
|
||||||
|
QZ[Quartz / @Scheduled]
|
||||||
|
REDIS[(Redis Session)]
|
||||||
|
DB[(KingbaseES gygl)]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph 外部系统
|
||||||
|
AST[Asterisk AMI / Conf-01]
|
||||||
|
BYXX[机务运安 SOAP]
|
||||||
|
CENTER[中心服务器 HTTP]
|
||||||
|
end
|
||||||
|
|
||||||
|
DEV -->|HTTP 心跳/业务| APP
|
||||||
|
WEB -->|HTTP + WebSocket| APP
|
||||||
|
APP --- WS
|
||||||
|
APP --- QZ
|
||||||
|
APP --- REDIS
|
||||||
|
APP --- DB
|
||||||
|
QZ -->|呼叫| AST
|
||||||
|
AST --> PHONE
|
||||||
|
AST --> CONSOLE
|
||||||
|
APP -->|WSDL PbResource| BYXX
|
||||||
|
APP <-->|人员/财务| CENTER
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 技术栈
|
||||||
|
|
||||||
|
| 层次 | 选型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 运行时 | Java 8、Spring Boot 2.6.13 | 继承 `spring-boot-starter-parent`;`pom.xml` 未声明 packaging(默认 jar),入口继承 `SpringBootServletInitializer`,也可改为 WAR 部署到外部 Tomcat |
|
||||||
|
| Web | Spring MVC、Spring WebSocket | `@ServerEndpoint` + `ServerEndpointExporter` |
|
||||||
|
| 持久化 | MyBatis-Plus 3.1.0、PageHelper 1.4.1 | Mapper XML 位于 `classpath:mapper/**/*.xml` |
|
||||||
|
| 数据库 | KingbaseES 8(`kingbase8` 8.6.0) | URL 形如 `jdbc:kingbase8://host:54321/gygl?currentSchema=gygl`;SQL 大量使用 Oracle 兼容写法(`TO_DATE`、`NVL`、`ROWNUM`、`MERGE`、`LISTAGG`、`sysdate`) |
|
||||||
|
| 缓存/会话 | Redis + Spring Session | `@EnableRedisHttpSession`,默认 30 分钟 |
|
||||||
|
| 调度 | Quartz(内存模式)+ Spring `@Scheduled` | 叫乘任务用 Quartz,补偿/清理用 `@Scheduled` |
|
||||||
|
| 电话 | asterisk-java `3.38.0-zfjia` + jSerialComm | AMI 控制会议桥,串口控制广播/话机 |
|
||||||
|
| 文档 | Springfox Swagger 2.9.2 | 仅扫描 `jlgl.controller` |
|
||||||
|
| 报表 | Apache POI 4.1.2 | `/excel/*` 导出 |
|
||||||
|
| 其他 | fastjson2、Guava、Reflections、JNA | JSON、工具、类扫描、本地库调用 |
|
||||||
|
|
||||||
|
> 注意:`pom.xml` 中 `spring-boot-starter-web` 显式写了 `3.5.4`、`spring-boot-starter-data-redis` 写了 `3.3.1`,与 Boot 2.6.13 / Java 8 不匹配。见 [09-迭代指引与风险清单.md](./09-迭代指引与风险清单.md)。
|
||||||
|
|
||||||
|
## 5. 多公寓识别(重要约束)
|
||||||
|
|
||||||
|
同一套后端服务多个公寓时,公寓身份由请求来源 IP 决定:
|
||||||
|
|
||||||
|
- 入口:`ZdwhService.getUniqueGyByIp(request)` / `getGyIdByIp(request)`。
|
||||||
|
- 解析顺序:设备表(`GY_SB`)中的 IP → 公寓字典 `GY_GYZD.ip`。
|
||||||
|
- 若同一 IP 命中多个公寓,直接拒绝,避免写错公寓数据。
|
||||||
|
- 业务代码中 `gyid` 不能信任前端传入;入住、房间、充值等写操作均由服务端重新解析或校验。
|
||||||
|
|
||||||
|
相关配置:`baseConfig.gyid`、`baseConfig.gymc` 作为单公寓/默认值兜底;各 Profile 不同。
|
||||||
|
|
||||||
|
## 6. 关键设计约束(迭代时不要破坏)
|
||||||
|
|
||||||
|
1. **房间占用以有效在寓明细为准**:`live_person`、`person_name` 由 `GY_JCXX` 中 `finish_ly='0' AND sjlysj IS NULL` 的记录实时重算,不能仅做 ±1 计数。
|
||||||
|
2. **交路快照与匹配分离**:运安计划先整表落到 `GY_SYN_JCXX`(快照),再由匹配流程写入 `GY_JCXX`;匹配有全局锁和状态位,避免抓取/推送并发写坏数据。
|
||||||
|
3. **叫乘任务可恢复**:Quartz 任务按 `ryid + 类型` 建键,应用重启后由 `WakeupJobRecoveryRunner` 从库中恢复未来任务。
|
||||||
|
4. **设备指令一次性投递**:指令写入设备指令表,心跳时下发,下发后置 `deleted=1`。
|
||||||
|
5. **事务内不做外部副作用**:WebSocket 推送、创建 Quartz 任务等放在事务提交后(`afterCurrentTransactionCommits`)。
|
||||||
|
6. **离寓有证据链**:人脸离寓会保存抓拍快照、写 `GYGL_LY_EVENT`,并以 `deviceEventId` 做幂等。
|
||||||
|
|
||||||
|
## 7. 与前端/设备的关系
|
||||||
|
|
||||||
|
- Web 管理端 `YktVue` 通过 `/yktgl/*` 接口与 WebSocket 交互;后端也会把旧构建产物放在 `src/main/resources/static` 下(历史遗留,见风险清单)。
|
||||||
|
- 设备通过各自的心跳接口注册,通过业务接口上报事件;服务端通过 WebSocket 向值班端推送刷新与人员信息。
|
||||||
|
- 叫乘执行不经过设备,而是直接走 Asterisk 电话/广播链路。
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
# 02 工程结构与分层
|
||||||
|
|
||||||
|
## 1. 目录结构
|
||||||
|
|
||||||
|
仓库根目录:
|
||||||
|
|
||||||
|
```
|
||||||
|
jcgl/
|
||||||
|
├── yktgl/ # 后端(Spring Boot / Maven)
|
||||||
|
│ ├── pom.xml
|
||||||
|
│ └── src/
|
||||||
|
│ ├── main/
|
||||||
|
│ │ ├── java/org/example/yktgl/...
|
||||||
|
│ │ └── resources/
|
||||||
|
│ │ ├── application.yml / application-*.yml
|
||||||
|
│ │ ├── mapper/**/*.xml
|
||||||
|
│ │ ├── wsdl/PbResource.wsdl
|
||||||
|
│ │ ├── db/ # 手工升级脚本
|
||||||
|
│ │ └── static/ # 历史前端构建产物
|
||||||
|
│ └── test/java/...
|
||||||
|
├── YktVue/ # Vue 前端
|
||||||
|
└── docs/ # 本文档目录
|
||||||
|
```
|
||||||
|
|
||||||
|
后端 Java 包(`org.example.yktgl`):
|
||||||
|
|
||||||
|
| 包 | 职责 |
|
||||||
|
| --- | --- |
|
||||||
|
| `jcgl` | 叫乘核心:入寓/离寓、叫乘执行、房间、交路匹配、补助、卡余额、统计联动 |
|
||||||
|
| `jlgl` | 交路维护:交路 CRUD、叫乘时刻、上传、跨公寓同步、车次查询 |
|
||||||
|
| `regist` | 人员资料与注册:注册查询、照片、人员增删改 |
|
||||||
|
| `recharge` | 现金充值:设备发起、值班端处理、余额变动、补助入账 |
|
||||||
|
| `pay` | 消费:设备余额查询与扣款、消费明细 |
|
||||||
|
| `MealsOrdering` | 食堂/餐食订单与消费 |
|
||||||
|
| `kcgl` | 库存/出入库/物料/成品/文件(扩展业务) |
|
||||||
|
| `display` | 登录、用户、角色、权限、菜单、部门、日志 |
|
||||||
|
| `excel` | 各类报表导出(POI) |
|
||||||
|
| `xxtj` | 信息统计:日报、进出情况、月报、补助统计 |
|
||||||
|
| `zdwh` | 字典/基础资料:公寓、房间、工种、节假日、餐补标准;IP→公寓解析 |
|
||||||
|
| `syndata` | 运安/中心数据同步、同步日志、人员同步服务 |
|
||||||
|
| `heartBeat` | 设备心跳、设备指令、设备信息 |
|
||||||
|
| `callingDevice` / `checkInDevice` / `roomDevice` / `payDevice` / `registDevice` / `vendPayDevice` | 各类设备的接入层(心跳 + 业务) |
|
||||||
|
| `clean` | 房间保洁 |
|
||||||
|
| `jgxxgl` | 叫乘报警/警示信息查询 |
|
||||||
|
| `quartz` | Quartz 工具、任务管理、叫乘任务 `WakeUpJob` |
|
||||||
|
| `schedule` | `@Scheduled` 补偿任务与启动恢复 |
|
||||||
|
| `websockets` | 各类 WebSocket 端点 |
|
||||||
|
| `common` | 通用返回体、验证码、工具、Session/WebSocket 配置 |
|
||||||
|
| `config` | 异步线程池、RestTemplate、Swagger |
|
||||||
|
| `util` | 日期、字符串工具 |
|
||||||
|
| `test` | 测试/演示接口(生产应限制) |
|
||||||
|
|
||||||
|
## 2. 分层约定与调用链
|
||||||
|
|
||||||
|
典型调用链:
|
||||||
|
|
||||||
|
```
|
||||||
|
Controller(参数/鉴权/协议编解码)
|
||||||
|
→ Service(业务编排、事务、状态机)
|
||||||
|
→ Mapper 接口(MyBatis)
|
||||||
|
→ mapper/**/*.xml(SQL)
|
||||||
|
→ KingbaseES
|
||||||
|
```
|
||||||
|
|
||||||
|
实际代码中的偏差:
|
||||||
|
|
||||||
|
- 部分 Controller 直接调用 Mapper(如设备心跳、字典查询)。
|
||||||
|
- 设备接入层通常只有一个 Service,同时承担协议解析与业务调用。
|
||||||
|
- `JcglService` 体量过大,承担了叫乘、房间、人员、补助、同步、归档等多类职责;迭代时应优先“新增小服务 + 复用其中方法”,避免继续膨胀。
|
||||||
|
|
||||||
|
### 请求与返回
|
||||||
|
|
||||||
|
- 统一返回 `common/entity/Result` 或 `ResultData`,包含成功标志、消息、数据。
|
||||||
|
- 设备接口多返回 `ResultData`;Web 接口多返回 `Result`。
|
||||||
|
- 部分统计接口直接返回 `JSONObject`(如 `/synData/synPersonData`)。
|
||||||
|
|
||||||
|
### 事务与异常
|
||||||
|
|
||||||
|
- 写操作使用 `@Transactional`;捕获异常后调用 `TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()` 再返回失败。
|
||||||
|
- 叫乘任务创建、WebSocket 推送等副作用通过 `afterCurrentTransactionCommits(...)` 延迟到提交后,避免“事务回滚但消息已发/任务已建”。
|
||||||
|
- 大量 `try/catch` 将异常转成 `Result.failure(message)`,同时写业务日志;排查时需同时看 `GY_LOGS` / 同步日志 / `System.out`。
|
||||||
|
|
||||||
|
## 3. 启动流程
|
||||||
|
|
||||||
|
入口:`YktglApplication`
|
||||||
|
|
||||||
|
```java
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableScheduling
|
||||||
|
public class YktglApplication extends SpringBootServletInitializer
|
||||||
|
```
|
||||||
|
|
||||||
|
启动关键动作:
|
||||||
|
|
||||||
|
1. Spring 容器初始化,激活 `spring.profiles.active`(默认 `local`)。
|
||||||
|
2. `SessionConfig` 开启 Redis HttpSession。
|
||||||
|
3. `WebSocketConfig` 注册 `ServerEndpointExporter`,扫描 `@ServerEndpoint`(`websockets/*`)。
|
||||||
|
4. `ServerStartupListener` 在启动时做初始化(端口/环境相关)。
|
||||||
|
5. `WakeupJobRecoveryRunner` 监听 `ApplicationReadyEvent`,从 `GY_JCXX` 恢复未来叫乘任务。
|
||||||
|
6. `@Scheduled` 任务开始运行(见 07)。
|
||||||
|
|
||||||
|
## 4. 配置与 Profile
|
||||||
|
|
||||||
|
- 主配置:`application.yml`,只保留通用项与 `active: local`。
|
||||||
|
- 环境配置:`application-{byq,cc,dev,dl,local,pj,prod,sjt,tl}.yml`,各自定义端口、数据源、Redis、公寓、AMI、串口等。
|
||||||
|
- 自定义前缀:`baseConfig.*`(公寓、中心地址、同步白名单、设备密码、服务器 OS)、`callcontrol.*`(AMI、录音、串口)。
|
||||||
|
|
||||||
|
详细字段见 [08-部署与配置.md](./08-部署与配置.md)。
|
||||||
|
|
||||||
|
## 5. 公共组件速查
|
||||||
|
|
||||||
|
| 组件 | 位置 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `Result` / `ResultData` | `common/entity` | 统一返回体 |
|
||||||
|
| `CaptchaUtil` / `CaptchaResult` | `common` | 登录验证码 |
|
||||||
|
| `IpUtil` | `common/utils` | 取真实客户端 IP |
|
||||||
|
| `HttpRequest` | `common/utils` | 内部 HTTP 调用(运安人员接口等) |
|
||||||
|
| `MD5Util` / `PasswordEncoder` | `common/utils` | 口令处理 |
|
||||||
|
| `MyBatisUtils` | `common/utils` | MyBatis 辅助 |
|
||||||
|
| `SpringUtils` | `common/utils` | 静态获取 Bean |
|
||||||
|
| `AsyncConfig` | `config` | 异步线程池(核心 10、最大 200、队列 10) |
|
||||||
|
| `RestTemplateConfig` | `config` | HTTP 客户端 |
|
||||||
|
| `SwaggerConfig` | `config` | 仅扫描 `jlgl.controller` |
|
||||||
|
| `QuartzUtils` / `SchedulerManager` | `quartz` | 任务创建/取消/重建 |
|
||||||
|
| `CallDutyMatchLock` | `jcgl/service` | 交路抓取与匹配的互斥锁(DB 行锁 + 租约) |
|
||||||
|
| `AsteriskCallUtil` | `jcgl/service` | AMI 呼叫、会议桥、录音、挂断 |
|
||||||
|
| `JcWebsocket` 等 | `websockets` | 按公寓/房间推送 |
|
||||||
|
|
||||||
|
## 6. 测试现状
|
||||||
|
|
||||||
|
`src/test/java` 下已有部分单元/切片测试(录音控制器、当前在寓交路 SQL、最近同步时间、人员同步等),但工程 `target/` 为空,未见完整构建/测试产物。迭代前建议先补齐可重复的构建与测试基线。
|
||||||
|
|
||||||
|
## 7. 关键文件索引
|
||||||
|
|
||||||
|
> 行号为当前版本近似位置,改动后请以方法名检索。
|
||||||
|
|
||||||
|
| 文件 | 关注内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| `jcgl/service/JcglService.java` | 叫乘/入住/离寓/房间/补助/同步/归档主逻辑(约 4192 行) |
|
||||||
|
| ├─ 559–1010 | 房间列表、推荐、房态修改、入住提交、离寓提交 |
|
||||||
|
| ├─ 1320–1450 | `processCallDuty` / `processTempCallDuty` 状态上报 |
|
||||||
|
| ├─ 1700–2150 | 远程同步、交路匹配、提醒补偿 |
|
||||||
|
| ├─ 2400–2510 | `ryzt` 状态更新与校验 |
|
||||||
|
| ├─ 2640–2800 | 按开车时间与时间规则计算叫乘时刻 |
|
||||||
|
| ├─ 3065–3175 | 刷脸离寓 |
|
||||||
|
| ├─ 3600–3700 | 房间校验、时间线校验 |
|
||||||
|
| └─ 3880–4192 | 停止叫乘、录音、归档 |
|
||||||
|
| `jcgl/controller/JcglController.java` | `/jcgl` 全部 Web/设备接口入口 |
|
||||||
|
| `jcgl/service/AsteriskCallUtil.java` | AMI 连接、呼叫、会议桥、TTS、录音、挂断 |
|
||||||
|
| `jcgl/service/CallDutyMatchLock.java` | 同步/匹配互斥锁 |
|
||||||
|
| `jcgl/service/ByxxResourceService.java` | 运安 WSDL 调用与快照写入 |
|
||||||
|
| `quartz/SchedulerManager.java` | 叫乘任务创建/取消/重建 |
|
||||||
|
| `quartz/WakeUpJob.java` | 单个叫乘任务执行 |
|
||||||
|
| `quartz/QuartzUtils.java` | Quartz 基础设施 |
|
||||||
|
| `schedule/JcSchedule.java` | 漏叫提醒、超时离寓、归档 |
|
||||||
|
| `schedule/SynDataSchedule.java` | 运安抓取/人员同步 |
|
||||||
|
| `schedule/WakeupJobRecoveryRunner.java` | 启动恢复任务 |
|
||||||
|
| `mapper/jcgl/JcglMapper.xml` | 叫乘核心 SQL(表结构事实来源之一) |
|
||||||
|
| `mapper/jcgl/JcglRoomMapper.xml` | 房间 SQL 与推荐逻辑 |
|
||||||
|
| `mapper/jcgl/LeaveEventMapper.xml` | 离寓事件 |
|
||||||
|
| `mapper/heartBeat/HeartBeatMapper.xml` | 设备、心跳、指令 |
|
||||||
|
| `mapper/recharge/RechargeMapper.xml` | 充值申请/余额/补助 |
|
||||||
|
| `heartBeat/service/HeartBeatService.java` | 指令写入与设备维护 |
|
||||||
|
| `zdwh/service/ZdwhService.java` | IP→公寓、字典 |
|
||||||
|
| `websockets/JcWebsocket.java` | 叫乘实时推送 |
|
||||||
|
| `application.yml` / `application-*.yml` | 运行配置 |
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# 03 业务模块地图
|
||||||
|
|
||||||
|
## 1. 模块总表
|
||||||
|
|
||||||
|
| 模块(包) | 入口 | 核心服务 | 一句话职责 | 主要数据表 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `jcgl` | `JcglController` `/jcgl`、`RecordingController` | `JcglService`(4192 行)、`AsteriskCallUtil`、`ByxxResourceService`、`CallDutyMatchLock` | 叫乘主流程、入寓/离寓、房间、补助、交路匹配、归档 | `GY_JCXX`、`GY_JCXX_HIS`、`GY_ROOMS`、`GY_SYN_JCXX`、`GY_YKT_*`、`GYGL_LY_EVENT` |
|
||||||
|
| `jlgl` | `JlGlController` `/jlgl` | `JlGlService` | 交路模板维护、叫乘时刻、上传/同步、车次查询 | `GYGL_JLXX`、`GYGL_JLXX_TY`、`GYGL_JLXX_LOGS`、`GY_GYZD` |
|
||||||
|
| `regist` | `RegistController` `/regist` | `RegistService` | 人员注册信息、照片、人员资料增删改 | `GY_YKT_RY`、人员照片表 |
|
||||||
|
| `recharge` | `RechargeController` `/recharge` | `RechargeService` | 现金充值申请/处理、余额与补助入账 | `GY_YKT_CASH_REQUEST`、`GY_YKT_REMAINDER`、`GY_YKT_XJCZJL`、`GY_YKT_ALLOWANCE` |
|
||||||
|
| `pay` | `PayController` `/pay` | `PayService` | 消费扣款、消费明细与统计 | `GY_YKT_CONSUME`、`GY_YKT_REMAINDER` |
|
||||||
|
| `MealsOrdering` | `MealsController` `/Meals` | `MealsService` | 餐食/订单、房间送餐、消费 | 餐食/订单相关表 |
|
||||||
|
| `kcgl` | `kcglController` `/kcgl` | `kcglService` | 库存、出入库、物料、成品、PDF 文件 | 库存/出入库相关表 |
|
||||||
|
| `display` | `/auth`、`/user`、`/role`、`/permission`、`/menu`、`/dept` | `SysUserService` 等 | 登录、会话、RBAC、菜单、部门、日志 | `GL_YH`、`GL_JS`、`GL_QX`、`GL_CD`、`GL_YH_JS`、`GL_JS_QX`、`GY_LOGS` |
|
||||||
|
| `excel` | `ExcelExportController` `/excel` | 直接查询/POI | 叫乘、日报、补助、充值、消费等 Excel 导出 | 只读多表 |
|
||||||
|
| `xxtj` | `xxtjController` `/xxtj` | `XxTjService` | 报警次数、进出情况、日报、月报、补助统计 | 只读多表 |
|
||||||
|
| `zdwh` | `ZdwhController` `/Zdwh` | `ZdwhService` | 公寓/房间/工种/节假日/餐补字典;IP→公寓 | `GY_GYZD`、`GY_ROOMS`、`GY_GZZD`、`GY_JRB`、`GY_JBXX` |
|
||||||
|
| `syndata` | `/synData`、`/jwDataLog` | `SynDataService`、`DriverPersonSyncService`、`JwDataLogService` | 运安人员、公寓人员、财务数据;同步日志 | `GY_YKT_RY`、`GY_JCXX`、`GY_YKT_REMAINDER`、同步日志表 |
|
||||||
|
| `heartBeat` | `HeartBeatController` `/heartBeat` | `HeartBeatService` | 设备注册、心跳、指令下发、版本/配置 | `GY_SB`、`GY_SB_XT`、设备指令表 |
|
||||||
|
| `callingDevice` | `/callingDevice` | `CallingDeviceService` | 叫乘屏心跳/业务 | `GY_SB` |
|
||||||
|
| `checkInDevice` | `/checkInDevice` | `CheckInDeviceService` | 签到机心跳/业务 | `GY_SB` |
|
||||||
|
| `roomDevice` | `/roomDevice` | `RoomDeviceService` | 房间屏心跳/应答/保洁 | `GY_SB` |
|
||||||
|
| `payDevice` | `/payDevice` | `PayDeviceService` | 消费机心跳/消费 | `GY_SB` |
|
||||||
|
| `registDevice` | `/registDevice` | `RegistDeviceHeartBeatService` | 注册机心跳 | `GY_SB` |
|
||||||
|
| `vendPayDevice` | `/vendPayDevice` | `VendPayDeviceService` | 售货机支付/退款 | 订单、余额 |
|
||||||
|
| `clean` | `CleanController` `/clean` | `CleanService` | 开始/结束保洁、保洁记录 | `GY_ROOMS`、保洁记录 |
|
||||||
|
| `jgxxgl` | `JgXxGlController` `/jgxxgl` | `JgXxGlService` | 报警/警示信息查询 | `GYGL_JGXX` |
|
||||||
|
| `quartz` | — | `SchedulerManager`、`WakeUpJob` | 叫乘/复叫/叫乘结束任务 | Quartz 内存 JobStore |
|
||||||
|
| `schedule` | — | 各 `@Scheduled` | 漏叫补偿、超时离寓、归档、运安同步、快照清理 | 多表 |
|
||||||
|
| `websockets` | `/websocket/*` | — | 值班端/房间端实时推送 | — |
|
||||||
|
|
||||||
|
## 2. 模块依赖关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
DEV[设备接入层<br/>calling/checkIn/room/pay/regist/vend] --> CORE[jcgl 核心服务]
|
||||||
|
WEB[Web 控制器<br/>jcgl/jlgl/regist/recharge/pay/xxtj/excel] --> CORE
|
||||||
|
CORE --> JL[jlgl 交路]
|
||||||
|
CORE --> ZD[zdwh 字典/IP→公寓]
|
||||||
|
CORE --> HB[heartBeat 设备指令]
|
||||||
|
CORE --> WS[websockets 推送]
|
||||||
|
CORE --> QZ[quartz 叫乘任务]
|
||||||
|
QZ --> AST[AsteriskCallUtil]
|
||||||
|
SYNC[syndata / ByxxResourceService] --> CORE
|
||||||
|
CORE --> CARD[卡务: recharge/pay/Meals]
|
||||||
|
ALL[全部模块] --> DISP[display 登录/RBAC/日志]
|
||||||
|
```
|
||||||
|
|
||||||
|
关键耦合点:
|
||||||
|
|
||||||
|
- **`jcgl` 是事实上的“领域服务层”**,其他模块大量直接调用 `JcglService`(如 `pay` 调 `checkRemainder`/`isHoliday`,`regist` 调 `processPersonDeviceInstructions`,`recharge` 调余额与补助)。
|
||||||
|
- **`zdwh` 提供公寓上下文**,几乎所有写操作都依赖 `getGyIdByIp` / `getUniqueGyByIp`。
|
||||||
|
- **`heartBeat` 提供设备指令通道**,叫乘、入住、充值、人员变更都会写入指令。
|
||||||
|
- **`websockets` 只负责推送**,业务状态不以其为准。
|
||||||
|
|
||||||
|
## 3. 按业务视角分组
|
||||||
|
|
||||||
|
### 3.1 叫乘与住宿(核心)
|
||||||
|
|
||||||
|
- 入寓登记:`submit_rydj` / `processCheckInRegistration`
|
||||||
|
- 叫乘执行:`processCallDuty`、`processTempCallDuty`、`WakeUpJob`、`AsteriskCallUtil`
|
||||||
|
- 房间:`getRoomList`、`getRoomRecommendations`、`modifyRoomStatus`、`exchangeRoom`
|
||||||
|
- 离寓:`processCheckOutRegistration`、`handleCheckOut`、`submit_ccly`
|
||||||
|
- 交路匹配:`synCallDutyInfo`、`synUnMatchJcXx`、`matchCallDutyUnderLock`
|
||||||
|
- 归档:`syncJcXxData`
|
||||||
|
|
||||||
|
### 3.2 卡务与消费
|
||||||
|
|
||||||
|
- 补助:`getAllowanceInfo`、`getTrainAllowanceInfo`、`changeRemainder`、`insert_allowance`
|
||||||
|
- 余额:`checkRemainder`、`remakeRemainder`
|
||||||
|
- 消费:`PayService`、`VendPayDeviceService`、`MealsService.updateMoney`
|
||||||
|
- 充值:`RechargeService`(设备申请 + 值班端确认)
|
||||||
|
|
||||||
|
### 3.3 基础资料与管理
|
||||||
|
|
||||||
|
- 人员:`regist` + `syndata`(运安/中心)
|
||||||
|
- 交路:`jlgl`
|
||||||
|
- 公寓/房间/工种/节假日:`zdwh`
|
||||||
|
- 用户/角色/权限/菜单:`display`
|
||||||
|
|
||||||
|
### 3.4 统计与导出
|
||||||
|
|
||||||
|
- 页面统计:`xxtj`(日报、月报、补助统计)
|
||||||
|
- Excel:`excel`(叫乘明细、日报、补助、充值、消费及汇总)
|
||||||
|
|
||||||
|
## 4. 模块边界与迭代建议
|
||||||
|
|
||||||
|
| 场景 | 建议落点 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 叫乘规则(时间/次数/优先级) | `JcglService` + `quartz` | 先改状态机与任务生成,再改执行器 |
|
||||||
|
| 新的设备类型 | 新建 `xxxDevice` 包 | 复用 `heartBeat` 指令与 `GY_SB` |
|
||||||
|
| 新报表 | `xxtj` 或 `excel` | 统计 SQL 放对应 Mapper XML |
|
||||||
|
| 新的卡务规则 | `recharge` / `pay` | 余额变动必须与明细同事务 |
|
||||||
|
| 交路来源新增 | `syndata` + `jlgl` | 统一落到快照表再匹配 |
|
||||||
|
| 管理端新功能 | `display` + 对应业务模块 | 权限走 RBAC 表 |
|
||||||
|
|
||||||
|
> `kcgl`(库存)与叫乘主线关系较弱,更像同工程内的扩展业务;迭代叫乘时通常无需改动。
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
# 04 核心业务流程
|
||||||
|
|
||||||
|
本文按“人”和“房间”两条主线梳理:人从入寓到离寓,房间从占用到释放;同时说明叫乘任务如何被创建、执行和补偿。
|
||||||
|
|
||||||
|
## 1. 入寓登记
|
||||||
|
|
||||||
|
入口有两类:
|
||||||
|
|
||||||
|
- 设备端:`POST /jcgl/processCheckInRegistration`(签到机)
|
||||||
|
- 值班端:`POST /jcgl/submitAll` → `JcglService.submit_rydj`
|
||||||
|
|
||||||
|
### 1.1 设备端查询/建档(`processCheckInRegistration`)
|
||||||
|
|
||||||
|
| code | 行为 |
|
||||||
|
| --- | --- |
|
||||||
|
| 1 | 按 `ryid` 查询当前在寓记录、离寓快照、人员资料,返回给设备;用于设备判断“是否已入住/是否可入住” |
|
||||||
|
| 2 | 由人员资料 + 选择的交路(`jlid`)或班次构造入住信息,通过 WebSocket `{"lx":"ry","content":...}` 推送值班端确认;房间号仅作为协议字段,不在此步写库 |
|
||||||
|
| 3 | 按 `id` 查询指定记录 |
|
||||||
|
|
||||||
|
> 设备端只负责“采集 + 推送”,真正的写入统一走值班端确认后的 `submit_rydj`。
|
||||||
|
|
||||||
|
### 1.2 值班端提交(`submit_rydj`,`@Transactional`)
|
||||||
|
|
||||||
|
按顺序执行:
|
||||||
|
|
||||||
|
1. **重复入住校验**:`isExistCallDutyInfo(ryid, gyid)`,已有在寓记录直接失败。
|
||||||
|
2. **房间校验**:按 `gyid + room_no` 精确查房,房间不存在/状态不可入住/床位已满则失败。
|
||||||
|
3. **交路处理**:
|
||||||
|
- `jllx='0'` 表示按交路入住。
|
||||||
|
- 若传了 `jlid`(固定交路),从交路表取车次、机车号、起点、到达车次/时间,回填到入住记录。
|
||||||
|
- 若 `cc` 包含“便乘/驻在”,`jllx='1'`,不生成标准叫乘;否则调用 `populateJcXxByJlXx` 生成叫乘时间。
|
||||||
|
4. **开车日期校验**:有车次时必须传 `kcrq`,且格式为 `yyyy-MM-dd`。
|
||||||
|
5. **补助计算**:
|
||||||
|
- 固定交路:`getTrainAllowanceInfo(cc, sfffcb, gyid, jlid)`。
|
||||||
|
- 非固定交路:`getAllowanceInfo(gz, sfffcb, sjrysj, gyid)`(按工种、是否发补助、入住时间规则)。
|
||||||
|
- `changeRemainder` 生成/更新余额与补助明细;节假日可能跳过余额与补助写入。
|
||||||
|
6. **写入住记录**:`insertJcxx`,`ryzt='0'`、`finish_ly='0'`、`sjrysj=入住时间`,并记录房间号。
|
||||||
|
7. **设备指令**:
|
||||||
|
- 向签到机下发指令 `5`;
|
||||||
|
- 向房间设备下发指令 `1`(刷新房间屏)。
|
||||||
|
8. **占用重算**:`room_rydj` → `refreshRoomOccupancy`,从有效在寓明细重算 `live_person`、`person_name`,再按床位计算房态。
|
||||||
|
9. **余额/补助落账**:非节假日执行 `updateRemainder` + `insert_allowance`。
|
||||||
|
10. **叫乘任务**:固定交路且 `sfjc='1'` 且非便乘/驻在时,事务提交后创建 `WakeUpJob`,并置 `is_yaxx='1'`。
|
||||||
|
11. **推送**:WebSocket `{"lx":"refresh"}`。
|
||||||
|
|
||||||
|
失败时统一回滚并写业务日志。
|
||||||
|
|
||||||
|
### 1.3 房间推荐(`getRoomRecommendations`)
|
||||||
|
|
||||||
|
- 仅对“可入住”的房间给出推荐顺序;
|
||||||
|
- 排序依据:**同行房间**(同车次/同批人)→ **历史房间**(该人员曾住过);
|
||||||
|
- 推荐结果不作为最终校验,提交时仍由房间状态与床位兜底。
|
||||||
|
|
||||||
|
## 2. 叫乘状态机
|
||||||
|
|
||||||
|
### 2.1 人员状态 `ryzt`
|
||||||
|
|
||||||
|
| 值 | 含义 | 进入方式 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `0` | 待叫乘/未叫乘 | 入住初始化、重置交路、任务取消 |
|
||||||
|
| `1` | 叫乘中(已叫/复叫) | 任务执行、设备上报 status=1/2 |
|
||||||
|
| `2` | 叫乘报警(未应答) | 报警任务、设备上报 status=3 |
|
||||||
|
| `3` | 已应答,待离寓 | 应答(status=5)或通话结束 |
|
||||||
|
| `4` | 离寓报警(超时未离寓) | 超时检查、设备上报 status=4 |
|
||||||
|
| `5` | 正在通话 | Asterisk 接通后临时状态 |
|
||||||
|
| `-1` | 查询用合成状态(未匹配/特殊行) | SQL 构造,不落库 |
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
state "0 待叫乘" as S0
|
||||||
|
state "1 叫乘中" as S1
|
||||||
|
state "2 叫乘报警" as S2
|
||||||
|
state "3 已应答待离寓" as S3
|
||||||
|
state "4 离寓报警" as S4
|
||||||
|
state "5 通话中" as S5
|
||||||
|
|
||||||
|
[*] --> S0
|
||||||
|
S0 --> S1: JC 任务 / 设备 status=1
|
||||||
|
S1 --> S1: FJ 复叫 / status=2
|
||||||
|
S1 --> S5: 电话接通
|
||||||
|
S5 --> S3: 挂断 / 应答
|
||||||
|
S1 --> S2: 未应答 / status=3
|
||||||
|
S2 --> S3: 人工应答 / status=5
|
||||||
|
S3 --> S4: 超时未离寓
|
||||||
|
S3 --> [*]: 办理离寓
|
||||||
|
S4 --> [*]: 办理离寓
|
||||||
|
```
|
||||||
|
|
||||||
|
配套字段:
|
||||||
|
|
||||||
|
- `jcsj_s` / `fjsj_s` / `jcbjsj_s`:实际叫乘/复叫/报警时间。
|
||||||
|
- `hjxysj`:呼叫应答时间。
|
||||||
|
- `finish_jc`:叫乘是否结束(`1` 结束)。
|
||||||
|
- `finish_ly`:是否离寓(`1` 离寓)。
|
||||||
|
- `stoped`:是否人工停止叫乘。
|
||||||
|
- `is_jcbj` / `is_lybj`:叫乘报警/离寓报警标记。
|
||||||
|
|
||||||
|
### 2.2 设备上报(`processCallDuty`)
|
||||||
|
|
||||||
|
设备 POST `/jcgl/processCallDuty`,`status` 语义:
|
||||||
|
|
||||||
|
| status | 动作 |
|
||||||
|
| --- | --- |
|
||||||
|
| 1 | 开始叫乘:`ryzt=1`、记录 `jcsj_s` |
|
||||||
|
| 2 | 开始复叫:记录 `fjsj_s`(状态保持叫乘中) |
|
||||||
|
| 3 | 叫乘报警:若原状态 < 2 则 `ryzt=2`,`is_jcbj=1`,记录 `jcbjsj_s`,写报警记录 |
|
||||||
|
| 4 | 离寓报警:`triggerLeaveAlarm`(条件更新,防重复),写报警记录 |
|
||||||
|
| 5 | 呼叫应答:`ryzt=3`、`hjxysj`、`finish_jc=1`、`stoped=0` |
|
||||||
|
|
||||||
|
临时叫乘走 `/jcgl/processTempCallDuty`,语义相同,但会额外刷新对应房间设备。
|
||||||
|
|
||||||
|
### 2.3 自动叫乘(Quartz)
|
||||||
|
|
||||||
|
入住/修改交路时为一个人创建 **3 个一次性任务**:
|
||||||
|
|
||||||
|
| 任务 | 触发时间 | 行为 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `JC` | `jcsj` | 开始叫乘:状态置 1,TTS 呼叫值班台 + 房间;未接通则按规则转报警 |
|
||||||
|
| `FJ` | `fjsj`(叫乘 +10 分钟) | 复叫:再次呼叫;仍未接通转报警 |
|
||||||
|
| `JCJS` | `jcbjsj`(叫乘 +15 分钟) | 叫乘结束:挂断会议桥、状态置 2、写报警记录 |
|
||||||
|
|
||||||
|
任务键:`ryid + "JC"/"FJ"/"JCJS"`,组:`gyid + fjh`;同一房间/车次会合并为一个执行组,组长优先呼叫。任务执行前会校验 `jcid/fjh/时间` 是否仍与库中一致,避免过期任务误叫。
|
||||||
|
|
||||||
|
补偿:
|
||||||
|
|
||||||
|
- `SchedulerManager` 统一创建/取消/重建;
|
||||||
|
- `WakeupJobRecoveryRunner` 在应用启动后恢复未来任务;
|
||||||
|
- 会议桥忙时延迟 60 秒再试;
|
||||||
|
- 人工“停止叫乘”会取消任务、挂断通话、置 `stoped=1`。
|
||||||
|
|
||||||
|
### 2.4 叫乘时间规则
|
||||||
|
|
||||||
|
叫乘时间统一由**开车时间 + 本地时间规则**计算(运安下发的 `jcsj` 仅保留读取,不作为最终依据):
|
||||||
|
|
||||||
|
- 规则来自 `GY_SJGZ`(按 `gyid + 单位`):
|
||||||
|
- `zjjcsjgz`:站接叫乘提前分钟数;
|
||||||
|
- `kjjcsjgz`:库出叫乘提前分钟数;
|
||||||
|
- `lysjgz`:离寓时间规则。
|
||||||
|
- `站接`:`jcsj = kcsj - zjjcsjgz`;`库出`:`jcsj = kcsj - kjjcsjgz`。
|
||||||
|
- `fjsj = jcsj + 10 分钟`;`jcbjsj = jcsj + 15 分钟`;`ylysj = jcsj + lysjgz`。
|
||||||
|
- 若计算出的叫乘时间已过期:只发 TTS 提醒,不生成报警记录(`adjustPastCallDutyTimes`)。
|
||||||
|
|
||||||
|
## 3. 运安交路同步与匹配
|
||||||
|
|
||||||
|
### 3.1 推送式同步(`POST /jcgl/synCallDutyInfo`)
|
||||||
|
|
||||||
|
1. 校验来源 IP 是否在 `baseConfig.synJcXxIp` 白名单。
|
||||||
|
2. 解析 JSON 快照,校验 `id`、`workno`、`deptime` 必填,`id` 唯一。
|
||||||
|
3. 获取 `CallDutyMatchLock.tryAcquireSync()`(数据库协调行 + 租约),避免与抓取/匹配并发。
|
||||||
|
4. `TRUNCATE GY_SYN_JCXX` → 批量插入 → `GY_SYN_JCXX_STATUS='1'`。
|
||||||
|
5. 事务提交后释放锁;返回 `{code,message,result}`。
|
||||||
|
|
||||||
|
### 3.2 主动抓取(`ByxxResourceService.fetchJlXX`)
|
||||||
|
|
||||||
|
1. 获取同步锁。
|
||||||
|
2. 加载 `classpath:/wsdl/PbResource.wsdl`,创建 SOAP 客户端。
|
||||||
|
3. 清空 `GY_SYN_JCXX`。
|
||||||
|
4. 调用运安 `getDriverPlanByTimeStr(start, end)`,把司机 1–4 的计划分别写入快照。
|
||||||
|
5. 更新同步状态为 `1`,记录日志。
|
||||||
|
|
||||||
|
> `mergeSynJcXx` 已停用:历史数据存在同一 `id` 对应多名司机,按 `id` MERGE 会重复匹配。
|
||||||
|
|
||||||
|
### 3.3 匹配(`/jcgl/synUnMatchJcXx` → `matchCallDutyUnderLock`)
|
||||||
|
|
||||||
|
前置条件:`GY_SYN_JCXX_STATUS='1'`(同步完成),且配置了 `baseConfig.gyid`(匹配只处理该公寓)。
|
||||||
|
|
||||||
|
流程:
|
||||||
|
|
||||||
|
1. 获取数据库行锁,串行匹配。
|
||||||
|
2. 查询 `jllx='0'` 的有效在寓记录,跳过人工锁定交路的记录;若配置不允许“叫乘完成后变更交路”,则跳过已完成叫乘且未离寓的人员。
|
||||||
|
3. 以人员 `card_id`(工号)匹配 `GY_SYN_JCXX.workno`。
|
||||||
|
4. 命中且交路有变化:按开车时间 + 本地规则重算叫乘/复叫/报警/离寓时间,更新当前入住记录,取消并重建 3 个 Quartz 任务;事务提交后写“交路变更/首次自动匹配/重新匹配”事件日志并 TTS 提醒。
|
||||||
|
5. 命中但交路未变:检查任务是否齐全,缺失则补建。
|
||||||
|
6. 未命中且该人有开车时间:清空交路与时间、取消任务、TTS 通知本人。
|
||||||
|
7. 汇总写同步日志,WebSocket `"all"` 刷新。
|
||||||
|
|
||||||
|
### 3.4 归档
|
||||||
|
|
||||||
|
`POST /jcgl/syncJcXxData`:
|
||||||
|
|
||||||
|
- 条件:`finish_ly='1' AND sjlysj <= sysdate - 7`,且属于当前公寓。
|
||||||
|
- 分批 500 条:复制到 `GY_JCXX_HIS` → 从 `GY_JCXX` 删除。
|
||||||
|
- 统计冲突/无效条数并写日志。
|
||||||
|
- 每日 00:00 也有自动归档任务。
|
||||||
|
|
||||||
|
## 4. 离寓
|
||||||
|
|
||||||
|
### 4.1 刷脸离寓(`processCheckOutRegistration`)
|
||||||
|
|
||||||
|
| code | 行为 |
|
||||||
|
| --- | --- |
|
||||||
|
| 1 | 按 `ryid + gyid` 查询在寓记录与人员资料,返回离寓页面数据 |
|
||||||
|
| 2 | 刷脸离寓:校验事件幂等 → 保存抓拍 → 更新离寓字段 → 写离寓事件 → 更新房间 → 推送刷新 |
|
||||||
|
|
||||||
|
code=2 的关键点:
|
||||||
|
|
||||||
|
1. **幂等**:`deviceCode + deviceEventId` 已存在则直接返回“已经处理”;缺失事件号时只记录日志、不阻断(兼容旧设备)。
|
||||||
|
2. **抓拍**:Base64 只接受 JPEG;按 `leaveSnapshot` 配置保存到本地目录,生成 `/yktgl/photo/leave-snapshots/...` URL;未开启抓拍时按 `requiredForDevice` 决定是否报错。
|
||||||
|
3. **服务评分**:请求可带 `kffwpf/jcfwpf/stfwpf`,写入离寓记录。
|
||||||
|
4. **事件证据**:`recordLeaveEvent` 写 `GYGL_LY_EVENT`(类型 `FACE`,含 `deviceEventId`、`snapshotUrl`、操作人、备注)。
|
||||||
|
5. **提交离寓**:`submit_ccly` → 更新 `GY_JCXX`(`finish_ly=1`、`sjlysj`)→ `room_ccly` 释放房间 → 房间设备刷新 → `remakeRemainder` 处理余额(如退补助)。
|
||||||
|
6. **失败回滚**:异常时删除已保存快照并回滚事务。
|
||||||
|
|
||||||
|
### 4.2 值班端离寓
|
||||||
|
|
||||||
|
`POST /jcgl/handleCheckOut` 走同一套 `submit_ccly`,离寓类型记为 `MANUAL`,无设备事件号与抓拍。
|
||||||
|
|
||||||
|
### 4.3 超时未离寓
|
||||||
|
|
||||||
|
`JcSchedule` 每 15 秒检查:`finish_jc='1'`、`ryzt='3'`、`ylysj <= now`、未触发过的记录 → `triggerLeaveAlarm`(条件更新 `ryzt=4`、`lybjsj`、`is_lybj=1`)→ 写报警记录。
|
||||||
|
|
||||||
|
## 5. 房间与保洁
|
||||||
|
|
||||||
|
### 5.1 房态
|
||||||
|
|
||||||
|
| `room_status` | 含义 | 计算/设置 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `1` | 空闲 | 结束保洁、恢复可入住 |
|
||||||
|
| `2` | 住满 | `live_person >= bed_numbers` |
|
||||||
|
| `3` | 待清扫 | 空房(`live_person=0`),退房后的默认状态 |
|
||||||
|
| `4` | 不能入住 | 人工设置(要求房间无人) |
|
||||||
|
| `5` | 未满 | `0 < live_person < bed_numbers` |
|
||||||
|
| `6` | 保洁中 | 保洁开始;结束后回到 `1` |
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- 房间占用始终由 `GY_JCXX` 有效在寓明细重算,不直接 ±1。
|
||||||
|
- 入住校验会重新计算房态,拒绝 `4`(不能入住)、`6`(保洁中)、满员房间。
|
||||||
|
- 保洁中不允许直接改房态;需先结束保洁。
|
||||||
|
|
||||||
|
### 5.2 换房(`/jcgl/exchangeRoom`)
|
||||||
|
|
||||||
|
1. 校验新房间可入住;
|
||||||
|
2. 校验人员当前房间未变化(防并发);
|
||||||
|
3. 更新入住记录 `fjh`;
|
||||||
|
4. 重算旧房、新房占用;
|
||||||
|
5. 向两个房间设备下发刷新指令。
|
||||||
|
|
||||||
|
## 6. 卡务:补助、充值、消费
|
||||||
|
|
||||||
|
### 6.1 补助
|
||||||
|
|
||||||
|
- 入住时按规则计算补助,写 `GY_YKT_ALLOWANCE` 并更新 `GY_YKT_REMAINDER` 的补助余额。
|
||||||
|
- 固定交路按车次查固定补助;非固定交路按工种/时间规则。
|
||||||
|
- 节假日策略:`isHoliday()` 命中时不发补助、不入账。
|
||||||
|
|
||||||
|
### 6.2 现金充值(`RechargeService`)
|
||||||
|
|
||||||
|
设备协议 `code`:
|
||||||
|
|
||||||
|
| code | 行为 |
|
||||||
|
| --- | --- |
|
||||||
|
| 1 | 查询余额 |
|
||||||
|
| 2 | 创建充值申请(`GY_YKT_CASH_REQUEST`,状态 `PENDING`),WebSocket `"cz"` 通知值班端 |
|
||||||
|
| 3 | 查询申请状态 |
|
||||||
|
| 4 | 取消申请(`CANCELLED`) |
|
||||||
|
|
||||||
|
值班端处理 `/recharge/handleRecharge`:
|
||||||
|
|
||||||
|
- 金额必须 `> 0` 且 `< 100`,最多 2 位小数;
|
||||||
|
- 通过条件更新把申请从 `PENDING` 置为 `COMPLETED`(与取消互斥);
|
||||||
|
- 更新余额、写充值记录、向设备下发指令 `6`。
|
||||||
|
|
||||||
|
### 6.3 消费
|
||||||
|
|
||||||
|
- 消费机:`PayService`,code 1 查余额,code 2 扣款;节假日金额按 0 处理;“内部人员”可透支。
|
||||||
|
- 售货机:`VendPayDeviceService`,code 1 查余额,code 2 下单扣款,code 3 查询结果/退款;退款时恢复余额并标记 `refunded=1`。
|
||||||
|
- 所有扣款都写 `GY_YKT_CONSUME`,并与余额更新同事务。
|
||||||
|
|
||||||
|
## 7. 设备心跳与指令
|
||||||
|
|
||||||
|
1. 设备按类型调用 `/callingDevice/heartbeat`、`/checkInDevice/heartbeat`、`/roomDevice/heartbeat`、`/payDevice/heartbeat`、`/registDevice/heartbeat`、`/vendPayDevice/heartbeat`。
|
||||||
|
2. 心跳上报:`deviceCode`、`versionName`、`deviceType`、`ip`、`deviceUpdateState`、`lastUserUpdateTime`、`lastDeviceConfigUpdateTime`、`roomNumber` 等。
|
||||||
|
3. 服务端返回:`devicePassword`、`apartmentName`、`serverTime`、`updateState`、`apkUrl`、指令列表。
|
||||||
|
4. 指令写入设备指令表,心跳时取走并置 `deleted=1`(一次性投递)。
|
||||||
|
5. 叫乘/入住/离寓/充值/人员变更都会产生指令。
|
||||||
|
|
||||||
|
## 8. 流程与代码位置对照
|
||||||
|
|
||||||
|
| 流程 | 主要方法 |
|
||||||
|
| --- | --- |
|
||||||
|
| 入住提交 | `JcglService.submit_rydj` |
|
||||||
|
| 设备入住 | `JcglService.processCheckInRegistration` |
|
||||||
|
| 叫乘上报 | `JcglService.processCallDuty` / `processTempCallDuty` |
|
||||||
|
| 叫乘执行 | `quartz/WakeUpJob`、`quartz/SchedulerManager` |
|
||||||
|
| 电话/会议桥 | `jcgl/service/AsteriskCallUtil` |
|
||||||
|
| 离寓 | `JcglService.processCheckOutRegistration` / `submit_ccly` |
|
||||||
|
| 交路推送 | `JcglService.synCallDutyInfo` |
|
||||||
|
| 交路匹配 | `JcglService.matchCallDutyUnderLock` |
|
||||||
|
| 运安抓取 | `ByxxResourceService.fetchJlXX` |
|
||||||
|
| 归档 | `JcglService.syncJcXxData` |
|
||||||
|
| 房间 | `JcglService.getRoomRecommendations` / `modifyRoomStatus` / `exchangeRoom` |
|
||||||
|
| 充值 | `RechargeService` |
|
||||||
|
| 消费 | `PayService` / `VendPayDeviceService` |
|
||||||
+241
@@ -0,0 +1,241 @@
|
|||||||
|
# 05 数据模型
|
||||||
|
|
||||||
|
> 数据库为 KingbaseES 8,默认 schema `gygl`。表名大小写混用(`GY_JCXX`、`gy_rooms`、`GYGL_JLXX`),SQL 中需按现有写法保持一致。
|
||||||
|
> 本文只列核心表与关键字段;完整字段以 `src/main/resources/mapper/**/*.xml` 为准。
|
||||||
|
|
||||||
|
## 1. 核心关系图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
GY_YKT_RY ||--o{ GY_JCXX : "ryid/card_id"
|
||||||
|
GY_JCXX }o--|| GY_ROOMS : "gyid + fjh"
|
||||||
|
GY_JCXX ||--o{ GYGL_LY_EVENT : "jcid"
|
||||||
|
GY_JCXX }o--o| GYGL_JLXX : "jlid"
|
||||||
|
GY_JCXX ||--o| GY_JCXX_HIS : "归档"
|
||||||
|
GY_YKT_RY ||--o| GY_YKT_REMAINDER : "ryid"
|
||||||
|
GY_YKT_REMAINDER ||--o{ GY_YKT_ALLOWANCE : "补助"
|
||||||
|
GY_YKT_REMAINDER ||--o{ GY_YKT_CONSUME : "消费"
|
||||||
|
GY_YKT_REMAINDER ||--o{ GY_YKT_XJCZJL : "现金充值"
|
||||||
|
GY_YKT_CASH_REQUEST ||--o| GY_YKT_XJCZJL : "完成充值"
|
||||||
|
GY_SYN_JCXX }o--|| GY_SYN_JCXX_STATUS : "同步状态"
|
||||||
|
GY_GYZD ||--o{ GY_ROOMS : "gyid"
|
||||||
|
GY_GYZD ||--o{ GY_SB : "gyid"
|
||||||
|
GY_SB ||--o| GY_SB_XT : "devicecode"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 住宿与叫乘
|
||||||
|
|
||||||
|
### 2.1 `GY_JCXX`(当前在寓/叫乘记录,核心表)
|
||||||
|
|
||||||
|
| 分组 | 字段 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 主键 | `jcid` | 入住记录 ID |
|
||||||
|
| 人员 | `ryid`、`card_id`、`rymc`、`rydw`、`gzzh`、`depotid` | 人员工号/卡号/姓名/单位/工资账号 |
|
||||||
|
| 公寓 | `gyid`、`gymc` | 公寓 |
|
||||||
|
| 房间 | `fjh` | 房间号(与 `GY_ROOMS.room_no` 对应) |
|
||||||
|
| 交路 | `jlid`、`cc`、`jch`、`cclx`、`qd`、`ddcc`、`ddsj` | 交路 ID、车次、机车号、接车方式、起点、到达车次/时间 |
|
||||||
|
| 时间 | `kcsj`、`jcsj`、`fjsj`、`jcbjsj` | 开车、叫乘、复叫、叫乘结束(计划) |
|
||||||
|
| 实际时间 | `jcsj_s`、`fjsj_s`、`jcbjsj_s`、`hjxysj`、`lybjsj` | 实际叫乘/复叫/报警/应答/离寓报警 |
|
||||||
|
| 入住离寓 | `yrysj`、`sjrysj`、`ylysj`、`sjlysj` | 预定/实际入住、预定/实际离寓 |
|
||||||
|
| 状态 | `ryzt`、`finish_jc`、`finish_ly`、`stoped`、`jllx` | 见状态字典 |
|
||||||
|
| 报警 | `is_jcbj`、`is_lybj`、`alarm_event_key` | 叫乘/离寓报警标记、报警事件键 |
|
||||||
|
| 通知去重 | `route_notice_key`、`call_timeout_notice_key`、`missed_call_notice_key` | 防止重复提醒 |
|
||||||
|
| 离寓证据 | `leave_type`、`leave_event_id`、`leave_remark`、`leave_snapshot_url` | 冗余自 `GYGL_LY_EVENT`,便于查询 |
|
||||||
|
| 其他 | `is_yaxx`、`yappsj`、`is_tempCall`、`recordfile`、`cblx`、`cbje`、`sfffcb` | 运安匹配标记、临时叫乘、录音文件、补助标识 |
|
||||||
|
|
||||||
|
有效在寓判定:`finish_ly='0' AND sjlysj IS NULL`。
|
||||||
|
|
||||||
|
### 2.2 `GY_JCXX_HIS`
|
||||||
|
|
||||||
|
与 `GY_JCXX` 同构的历史归档表;另有 `ly_event_id` 等证据字段。归档条件:已离寓且 `sjlysj <= sysdate - 7`。
|
||||||
|
|
||||||
|
### 2.3 `GY_ROOMS`
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `gyid`、`room_no` | 公寓 + 房间号(联合定位) |
|
||||||
|
| `room_floor`、`room_dir`、`room_face`、`is_edge`、`is_next_floor`、`next_floor` | 楼层/朝向/相邻关系(用于推荐与排序) |
|
||||||
|
| `room_status` | 房态,见下表 |
|
||||||
|
| `bed_numbers` | 床位数 |
|
||||||
|
| `room_type`、`room_dept`、`room_order` | 房型/所属部门/排序 |
|
||||||
|
| `live_person`、`person_name` | 当前人数/姓名串(实时重算) |
|
||||||
|
| `sip_account` | 房间 SIP 账号(叫乘呼叫用) |
|
||||||
|
| `bjkssj` | 保洁开始时间 |
|
||||||
|
|
||||||
|
| `room_status` | 含义 |
|
||||||
|
| --- | --- |
|
||||||
|
| `1` | 空闲 |
|
||||||
|
| `2` | 住满 |
|
||||||
|
| `3` | 待清扫 |
|
||||||
|
| `4` | 不能入住 |
|
||||||
|
| `5` | 未满 |
|
||||||
|
| `6` | 保洁中 |
|
||||||
|
|
||||||
|
### 2.4 `GYGL_LY_EVENT`(离寓事件证据)
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `id` | 事件 ID |
|
||||||
|
| `jcid`、`gyid`、`ryid`、`fjh` | 关联入住记录 |
|
||||||
|
| `leave_type` | `FACE` / `MANUAL` 等 |
|
||||||
|
| `device_code`、`device_event_id` | 设备与事件号(`device_code + device_event_id` 幂等) |
|
||||||
|
| `snapshot_url`、`remark`、`operator_id`、`operator_name` | 抓拍、备注、操作人 |
|
||||||
|
| `occurred_at`、`received_at` | 发生/接收时间 |
|
||||||
|
|
||||||
|
### 2.5 `GYGL_JLXX`(交路模板)
|
||||||
|
|
||||||
|
`id`、`jch`、`cc`、`qd`、`kcsj`、`jcsj`、`cclx`、`ddcc`、`ddsj`、`rysj`、`lysj`、`sfpc`、`bz`、`qr_fcd`、`qr_gy`、`lrsj`、`gyid`、`gymc`、`flag_send`、`bzje`。
|
||||||
|
|
||||||
|
关联:
|
||||||
|
|
||||||
|
- `GYGL_JLXX_TY`:交路停运/调整时间段(`gyid`、`cc`、`kssj`、`jssj`)。
|
||||||
|
- `GYGL_JLXX_LOGS`:交路操作日志。
|
||||||
|
- 交路叫乘时刻不单独建表:`getJlXxJcsjList` 由 `GYGL_JLXX` 的 `kcsj`(开车时刻)、`jcsj`(叫乘时刻)、`lysj`(离寓时刻)结合传入的开车日期 `kcrq` 计算得出,`fjsj = jcsj + 10 分钟`、`jcbjsj = jcsj + 15 分钟`。
|
||||||
|
|
||||||
|
## 3. 运安同步
|
||||||
|
|
||||||
|
### 3.1 `GY_SYN_JCXX`(运安计划快照)
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `id` | 计划 ID(`jobid|taskdicid`) |
|
||||||
|
| `ryid`、`ryxm`、`sfzh`、`sjh` | 司机工号/姓名/身份证/手机 |
|
||||||
|
| `jch`、`cx`、`cc` | 机车号、车型、车次 |
|
||||||
|
| `kcsj` | 开车时间(匹配后据此本地计算叫乘时间) |
|
||||||
|
| `jhxl`、`jhcqdd`、`jcfs` | 计划线路、机车缺勤地点、接车方式 |
|
||||||
|
| `h1` | 派班室/公寓辅助字段 |
|
||||||
|
| `write_time` | 写入时间 |
|
||||||
|
|
||||||
|
### 3.2 `GY_SYN_JCXX_STATUS`
|
||||||
|
|
||||||
|
单行/少量行状态表,表示快照是否可用于匹配:`0` 未同步/同步中,`1` 同步完成。
|
||||||
|
|
||||||
|
### 3.3 `GY_SYN_JCXX_HIS`
|
||||||
|
|
||||||
|
同步快照历史(按需保留/排查用)。
|
||||||
|
|
||||||
|
### 3.4 `GY_CALL_DUTY_MATCH_LOCK`
|
||||||
|
|
||||||
|
交路抓取/推送/匹配的协调锁表。使用固定协调行(如 `__SYNC_JCXX__`)持有租约,避免多实例/多线程同时 TRUNCATE 与匹配。
|
||||||
|
|
||||||
|
### 3.5 `JWDATA_SYNC_LOG` / 同步日志
|
||||||
|
|
||||||
|
记录运安抓取、推送、匹配结果与异常,页面 `/jwDataLog/*` 查询。
|
||||||
|
|
||||||
|
## 4. 人员与卡务
|
||||||
|
|
||||||
|
### 4.1 `GY_YKT_RY`(人员)
|
||||||
|
|
||||||
|
`ryid`、`card_id`、`gzzh`、`xm`、`dw`、`depotid`、`gwmc`、`gzmcnew`、`sjh`、`sfzh`、`xb`、`mz`、`zm`、`deleted`、`gxsj`、`photoUrl`。
|
||||||
|
|
||||||
|
- `deleted='1'` 为逻辑删除,查询普遍带 `nvl(deleted,'0') != '1'`。
|
||||||
|
- `gzmcnew` 是岗位归类,用于补助规则与“内部人员”判断。
|
||||||
|
|
||||||
|
### 4.2 `GY_YKT_RY_ZP`
|
||||||
|
|
||||||
|
人员照片(`ryid` + `photoBase64` BLOB)。
|
||||||
|
|
||||||
|
### 4.3 `GY_YKT_REMAINDER`(卡余额)
|
||||||
|
|
||||||
|
`ryid`、`xm`、`xjye`(现金余额)、`knye`(卡内余额/可用余额)、`xfze`(消费总额)、`bzze`(补助总额)、`xfxjje`(现金消费额)、`xfbzje`(补助消费额)。
|
||||||
|
|
||||||
|
### 4.4 `GY_YKT_ALLOWANCE`(补助明细)
|
||||||
|
|
||||||
|
`ryid`、`gyid`、`cblx`(补助类型)、`cbje`(金额)、`sfffcb`、`ryzt`、`fjh`、`jlid`、`yrysj`、`sjrysj`、`ylysj` 等。
|
||||||
|
|
||||||
|
### 4.5 `GY_YKT_CONSUME`(消费明细)
|
||||||
|
|
||||||
|
`tid`(交易号)、`ryid`、`xm`、`xfje`、`xfsj`、`gyid`、`knye`、`xjye`、`xfze`、`bzze`、`xfxjje`、`xfbzje`、`deviceCode`、`xfly`(消费来源)、`is_jrxf`(节假日消费)。
|
||||||
|
|
||||||
|
### 4.6 `GY_YKT_XJCZJL`(现金充值记录)
|
||||||
|
|
||||||
|
充值流水,关联现金充值申请。
|
||||||
|
|
||||||
|
### 4.7 `GY_YKT_CASH_REQUEST`(现金充值申请)
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `id` | 申请 ID |
|
||||||
|
| `ryid`、`gyid`、`device_code` | 人员/公寓/设备 |
|
||||||
|
| `request_state` | `PENDING` / `CANCELLED` / `COMPLETED` |
|
||||||
|
| `created_at`、`updated_at` | 创建/更新时间 |
|
||||||
|
|
||||||
|
> 申请表本身不存金额;金额由设备/值班端在处理时传入,校验后写入充值流水与余额。
|
||||||
|
|
||||||
|
状态流转:`PENDING → COMPLETED`(值班端处理)或 `PENDING → CANCELLED`(设备取消),两者通过条件更新互斥。
|
||||||
|
|
||||||
|
### 4.8 `GY_YKT_BTJS` / `GY_YKT_BTBJ`
|
||||||
|
|
||||||
|
补助结算/补助报警相关表,配合补助统计与异常检查。
|
||||||
|
|
||||||
|
## 5. 设备
|
||||||
|
|
||||||
|
### 5.1 `GY_SB`(设备)
|
||||||
|
|
||||||
|
`DEVICECODE`、`GYID`、`LX`(类型)、`jrsj`、`gxsj`、`ip`、`fjh`(房间号)。
|
||||||
|
|
||||||
|
### 5.2 `GY_SB_XT`(设备心跳/系统信息)
|
||||||
|
|
||||||
|
`devicecode`、版本、`deviceType`、`ip`、`deviceUpdateState`、`lastUserUpdateTime`、`lastDeviceConfigUpdateTime`、心跳时间等。
|
||||||
|
|
||||||
|
### 5.3 `GY_SB_ZL`(设备指令/版本)
|
||||||
|
|
||||||
|
`id`、`devicecode`、`updateState`、`generatedTime`、`apkurl`、`deleted`。
|
||||||
|
|
||||||
|
- 业务代码写入指令后,设备心跳时按 `devicecode + deleted='0'` 取**最新一条**返回,并置 `deleted='1'`。
|
||||||
|
- 因此一次心跳只消费一条指令;多条指令会随多次心跳依次下发。
|
||||||
|
|
||||||
|
## 6. 基础资料与统计
|
||||||
|
|
||||||
|
| 表 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `GY_GYZD` | 公寓字典(`gyid`、`gymc`、`ip` 等) |
|
||||||
|
| `GY_GZZD` | 工种字典 |
|
||||||
|
| `GY_JRB` | 节假日日历 |
|
||||||
|
| `GY_JBXX` | 基本/班次信息 |
|
||||||
|
| `GY_SJGZ` | 时间规则:`lysjgz`、`zjjcsjgz`、`kjjcsjgz`(按公寓 + 单位) |
|
||||||
|
| `GY_BJCSTJ`、`GY_BJXX` | 报警次数/报警信息 |
|
||||||
|
| `GYGL_JGXX` | 叫乘/离寓警示记录(`gyid`、`fssj`、`xx_cc`、`xx_sj`、`xx_ryid`、`xx_ry`、`xxlx`、`xxms`) |
|
||||||
|
| `GY_JDQKHZ` | 进出情况汇总 |
|
||||||
|
| `GY_RTJB`、`GY_YTJB` | 日报/月报 |
|
||||||
|
| `GY_LOGS`、`GL_LOGS` | 业务/登录日志 |
|
||||||
|
| `GY_ZBY` | 值班员信息 |
|
||||||
|
|
||||||
|
## 7. 权限与用户
|
||||||
|
|
||||||
|
`GL_YH`(用户)、`GL_JS`(角色)、`GL_QX`(权限)、`GL_CD`(菜单)、`GL_YH_JS`(用户-角色)、`GL_JS_QX`(角色-权限);另有 `SYS_USER`、`SYS_USER_ROLE`(历史/兼容)。
|
||||||
|
|
||||||
|
## 8. 库存扩展(kcgl)
|
||||||
|
|
||||||
|
`GYGL_KCGL_*`:仓库、供应商、物料、成品、入库单/出库单、盘点单、领料单、价格系数等;与叫乘主线弱相关。
|
||||||
|
|
||||||
|
## 9. 状态字典汇总
|
||||||
|
|
||||||
|
| 字段 | 取值 |
|
||||||
|
| --- | --- |
|
||||||
|
| `GY_JCXX.ryzt` | 0 待叫乘;1 叫乘中;2 叫乘报警;3 已应答待离寓;4 离寓报警;5 通话中;-1 查询合成 |
|
||||||
|
| `GY_JCXX.finish_jc` | 0 未结束;1 已结束 |
|
||||||
|
| `GY_JCXX.finish_ly` | 0 在寓;1 已离寓 |
|
||||||
|
| `GY_JCXX.jllx` | 0 按交路;1 非标准/便乘/驻在/人工修改 |
|
||||||
|
| `GY_ROOMS.room_status` | 1 空闲;2 住满;3 待清扫;4 不能入住;5 未满;6 保洁中 |
|
||||||
|
| `GY_YKT_CASH_REQUEST.request_state` | PENDING / CANCELLED / COMPLETED |
|
||||||
|
| `GY_JCXX.leave_type` | FACE / MANUAL 等 |
|
||||||
|
| 同步状态 | 0 未完成;1 完成 |
|
||||||
|
|
||||||
|
## 10. 升级脚本
|
||||||
|
|
||||||
|
`yktgl/src/main/resources/db/manual/` 下为手工执行的 Kingbase 脚本,按文件名日期顺序执行:
|
||||||
|
|
||||||
|
| 脚本 | 作用 |
|
||||||
|
| --- | --- |
|
||||||
|
| `V20260921_01__leave_snapshot_evidence_kingbase.sql` | 离寓抓拍证据字段/表 |
|
||||||
|
| `V20260922_01__call_duty_notice_dedup_kingbase.sql` | 叫乘提醒去重键 |
|
||||||
|
| `V20261008_01__syn_jcxx_write_time_kingbase.sql` | 快照写入时间 |
|
||||||
|
| `V20261008_02__call_duty_match_lock_kingbase.sql` | 匹配锁表与协调行 |
|
||||||
|
| `V20261009_01__jcxx_history_archive_kingbase.sql` | 历史归档字段/索引 |
|
||||||
|
| `V20261023_01__cash_request_state_kingbase.sql` | 现金充值申请状态 |
|
||||||
|
| `V20261029_01__reconcile_tlxc_room_occupancy.sql` | 通辽公寓房间占用校对(含 preview 版本) |
|
||||||
|
|
||||||
|
另有 `db/GY_SYN_JCXX_STATUS.sql` 初始化同步状态表。
|
||||||
|
|
||||||
|
> 这些脚本不在应用启动时自动执行,升级需人工按序执行并校验。执行前务必备份。
|
||||||
+227
@@ -0,0 +1,227 @@
|
|||||||
|
# 06 接口清单
|
||||||
|
|
||||||
|
## 1. 通用约定
|
||||||
|
|
||||||
|
- 基础路径:`http://host:8081/yktgl`(`server.servlet.context-path`)。
|
||||||
|
- 返回体:
|
||||||
|
- `Result`:`{code/flag, message, data}`(Web 接口常用)
|
||||||
|
- `ResultData`:设备接口常用
|
||||||
|
- 少数接口直接返回 `JSONObject` 或字符串。
|
||||||
|
- 公寓上下文:绝大多数写接口通过客户端 IP 解析 `gyid`;少数接口显式接收 `gyid`,但服务端仍会校验。
|
||||||
|
- **方法约束宽松**:大量接口用 `@RequestMapping`,GET/POST 都可访问,部分写操作也能用 GET 触发。新增接口建议明确 `@GetMapping`/`@PostMapping`。
|
||||||
|
- 字符集:JSON 为 UTF-8;设备请求体常为单行 JSON。
|
||||||
|
|
||||||
|
## 2. 叫乘核心 `/jcgl`
|
||||||
|
|
||||||
|
| 方法 | 路径 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| ALL | `/getJcxxByRyid` | 按人员/记录查叫乘信息 |
|
||||||
|
| ALL | `/getEmployeeArriveInfo` | 按单位查人员到达信息 |
|
||||||
|
| POST | `/getJcXx` | 条件查询在寓/叫乘列表 |
|
||||||
|
| POST | `/resetJllx` | 重置交路类型 |
|
||||||
|
| GET | `/getLatestSyncTime` | 当前公寓最近同步时间 |
|
||||||
|
| GET | `/getSjgz` | 时间规则(叫乘/离寓提前量) |
|
||||||
|
| ALL | `/getJlxxList` | 按车次/机车号查交路 |
|
||||||
|
| ALL | `/getRoomList` | 房间列表 |
|
||||||
|
| GET | `/getRoomRecommendations` | 入住房间推荐 |
|
||||||
|
| ALL | `/modifyRoomStatus` | 设置不能入住/恢复可入住 |
|
||||||
|
| ALL | `/submitAll` | 提交入寓登记(`submit_rydj`) |
|
||||||
|
| ALL | `/updateMeal3` | 更新第三餐补助 |
|
||||||
|
| ALL | `/getBtje_info` | 按入住时间查补助金额 |
|
||||||
|
| ALL | `/getBtje_infoMeal3` | 第三餐补助信息 |
|
||||||
|
| ALL | `/getRyxx` | 按人员查资料 |
|
||||||
|
| ALL | `/getRyxxByRyId` | 按人员查资料(含公寓上下文) |
|
||||||
|
| ALL | `/remakeRemainder` | 重算余额/补助 |
|
||||||
|
| ALL | `/modifyJcXx` | 修改叫乘信息并重建任务 |
|
||||||
|
| POST | `/getJcXxFromGy` | 从公寓端获取叫乘信息 |
|
||||||
|
| ALL | `/getZbyList` | 值班员列表 |
|
||||||
|
| ALL | `/getGzList` | 工种列表 |
|
||||||
|
| POST | `/modifyRyXx` | 修改人员资料 |
|
||||||
|
| POST | `/deleteRyXx` | 删除人员 |
|
||||||
|
| ALL | `/isHoliday` | 是否节假日 |
|
||||||
|
| ALL | `/getGyOptions` | 按单位取公寓选项 |
|
||||||
|
| POST | `/synCallDutyInfo` | 运安计划推送(整表快照) |
|
||||||
|
| POST | `/processCheckInRegistration` | 设备入寓登记(code 1/2/3) |
|
||||||
|
| POST | `/processCheckOutRegistration` | 设备离寓(code 1/2) |
|
||||||
|
| POST | `/processCallDuty` | 叫乘设备状态上报(status 1–5) |
|
||||||
|
| POST | `/processTempCallDuty` | 临时叫乘状态上报 |
|
||||||
|
| ALL | `/getCcJcXx` | 按车次聚合叫乘信息 |
|
||||||
|
| ALL | `/getCcJcXx_Ls` | 历史车次叫乘信息 |
|
||||||
|
| ALL | `/getCallDutyInfoByDeviceCode` | 叫乘屏按设备码取人员 |
|
||||||
|
| ALL | `/getTempCallDutyInfoByDeviceCode` | 临时叫乘屏取人员 |
|
||||||
|
| ALL | `/getSynJcXx` | 分页查运安快照 |
|
||||||
|
| ALL | `/getRzXx` | 入住信息 |
|
||||||
|
| ALL | `/getRemoteSynJcXx` | 远程同步(当前为桩实现,返回空成功) |
|
||||||
|
| ALL | `/synUnMatchJcXx` | 触发交路匹配 |
|
||||||
|
| POST | `/syncJcXxData` | 手工归档 7 天前已离寓记录 |
|
||||||
|
| ALL | `/handleTempCalling` | 临时叫乘(人工) |
|
||||||
|
| ALL | `/handleRoomCall2` / `/handleRoomCallEnd2` | 房间呼叫/结束(新版) |
|
||||||
|
| ALL | `/handleRoomCall` / `/handleRoomCallEnd` | 房间呼叫/结束(旧版) |
|
||||||
|
| ALL | `/handleMultiRoomCall` / `/handleMultiRoomCallEnd` | 多房间呼叫/结束 |
|
||||||
|
| ALL | `/handleCheckOut` | 值班端办理离寓 |
|
||||||
|
| ALL | `/cancelTrainAssignment` | 取消交路并清理任务 |
|
||||||
|
| ALL | `/getWslRyXx` | 未匹配人员信息 |
|
||||||
|
| ALL | `/getRyFjXx` | 人员房间信息 |
|
||||||
|
| ALL | `/exchangeRoom` | 换房 |
|
||||||
|
| ALL | `/handleStopCalling` | 停止叫乘(需报警事件键) |
|
||||||
|
| ALL | `/yatest` | 运安 SOAP 连通性测试 |
|
||||||
|
| ALL | `/ya/list` | 触发运安计划抓取 |
|
||||||
|
| ALL | `/driver/{driverId}` | 查询运安司机信息 |
|
||||||
|
| GET | `/getRecordingConfig` | 录音回放配置(RecordingController) |
|
||||||
|
|
||||||
|
## 3. 交路 `/jlgl`
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/addJlXx` | 新增交路 |
|
||||||
|
| `/modifyJlXx` | 修改交路 |
|
||||||
|
| `/getJlXxList` | 交路列表 |
|
||||||
|
| `/getJlXxJcsjList` | 交路及叫乘时刻 |
|
||||||
|
| `/delJlXx`、`/deleteJlXx` | 删除交路 |
|
||||||
|
| `/uploadJlXx` | Excel 上传交路 |
|
||||||
|
| `/getMessageFromGy`、`/getMessageFromFcd` | 从公寓/发车点获取信息 |
|
||||||
|
| `/getGyXxList`、`/getTyXxList` | 公寓/停运信息 |
|
||||||
|
| `/addTySjList` | 新增停运时间 |
|
||||||
|
| `/confirmJlXx` | 交路确认 |
|
||||||
|
| `/getTrainNumberInfo` | 车次信息 |
|
||||||
|
|
||||||
|
## 4. 人员与注册 `/regist`
|
||||||
|
|
||||||
|
| 方法 | 路径 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| POST | `/registPersonInfo` | 设备注册协议(code 1 拍照、2 查/更新照片、3 按 ID 查、4 批量增量) |
|
||||||
|
| POST | `/addPersonInfo` | 新增人员(写真 + 照片表) |
|
||||||
|
| ALL | `/getPersonelInfo` | 按手机号/姓名查人员 |
|
||||||
|
| POST | `/updatePersonelInfo` | 修改人员并下发设备指令 |
|
||||||
|
| ALL | `/deletePersonelInfo` | 逻辑删除人员并清理照片 |
|
||||||
|
|
||||||
|
## 5. 充值 `/recharge`
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/processCashRecharge` | 设备充值协议(code 1–4) |
|
||||||
|
| `/handleRecharge` | 值班端处理充值 |
|
||||||
|
| `/autoRecharge` | 自动补助入账(对应定时器已停用) |
|
||||||
|
| `/getAllowance` | 补助查询 |
|
||||||
|
| `/getRechargeInfo` | 充值记录 |
|
||||||
|
| `/getRechargeStatisInfo` | 充值统计 |
|
||||||
|
| `/getAllowanceStatis` | 补助统计 |
|
||||||
|
|
||||||
|
## 6. 消费 `/pay`
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/processPayment` | 设备消费协议(code 1 查余额、2 扣款) |
|
||||||
|
| `/getConsumDetailInfo` | 消费明细 |
|
||||||
|
| `/getCashConsumeStatisInfo` | 现金消费统计 |
|
||||||
|
| `/getAllowanceConsumeStatisInfo` | 补助消费统计 |
|
||||||
|
| `/getConsumeStatis` | 消费汇总 |
|
||||||
|
|
||||||
|
## 7. 设备接入
|
||||||
|
|
||||||
|
| 基础路径 | 接口 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `/callingDevice` | `POST /heartbeat` | 叫乘屏心跳 |
|
||||||
|
| `/checkInDevice` | `POST /heartbeat` | 签到机心跳 |
|
||||||
|
| `/roomDevice` | `POST /heartbeat` | 房间屏心跳 |
|
||||||
|
| `/payDevice` | `POST /heartbeat` | 消费机心跳 |
|
||||||
|
| `/registDevice` | `POST /heartbeat` | 注册机心跳 |
|
||||||
|
| `/vendPayDevice` | `POST /heartbeat`、`POST /processPayment` | 售货机心跳/支付 |
|
||||||
|
| `/heartBeat` | `/getDeviceInfo`、`/getDeviceStatusInfo`、`/modifyDeviceInfo`、`/modifyApkVersion` | 管理端设备查询/维护 |
|
||||||
|
|
||||||
|
### 7.1 心跳请求字段(常见)
|
||||||
|
|
||||||
|
`deviceCode`、`versionName`、`deviceType`、`ip`、`deviceUpdateState`、`lastUserUpdateTime`、`lastDeviceConfigUpdateTime`、`roomNumber`。
|
||||||
|
|
||||||
|
### 7.2 心跳响应字段
|
||||||
|
|
||||||
|
`devicePassword`、`apartmentName`、`serverTime`、`updateState`、`apkUrl`、指令列表。
|
||||||
|
|
||||||
|
### 7.3 设备业务协议
|
||||||
|
|
||||||
|
| 场景 | code/status | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 入寓登记 | code 1/2/3 | 查询/提交/按 ID 查询 |
|
||||||
|
| 离寓 | code 1/2 | 查询/刷脸离寓 |
|
||||||
|
| 叫乘 | status 1–5 | 开始/复叫/叫乘报警/离寓报警/应答 |
|
||||||
|
| 临时叫乘 | status 1–5 | 同上,另刷新房间设备 |
|
||||||
|
| 充值 | code 1–4 | 查余额/申请/查状态/取消 |
|
||||||
|
| 消费 | code 1/2 | 查余额/扣款 |
|
||||||
|
| 售货机 | code 1/2/3 | 查余额/下单/结果或退款 |
|
||||||
|
| 注册 | code 1–4 | 拍照/查询/按 ID/批量增量 |
|
||||||
|
| 保洁 | — | 开始/结束保洁(`/clean`) |
|
||||||
|
|
||||||
|
## 8. 管理后台
|
||||||
|
|
||||||
|
### 8.1 登录与权限
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/auth/getCaptcha`、`/auth/captchaImage` | 验证码 |
|
||||||
|
| `/auth/login` | 登录 |
|
||||||
|
| `/auth/logon` | 注册/开通 |
|
||||||
|
| `/auth/logout` | 退出 |
|
||||||
|
| `/auth/getInfo` | 当前用户信息 |
|
||||||
|
| `/auth/getMenuInfo` | 用户菜单 |
|
||||||
|
| `/user/*` | 用户增删改查、改密、启停 |
|
||||||
|
| `/role/*` | 角色与角色权限 |
|
||||||
|
| `/permission/*` | 权限树与权限维护 |
|
||||||
|
| `/menu/*` | 菜单维护 |
|
||||||
|
| `/dept/*` | 部门树、公寓部门树 |
|
||||||
|
|
||||||
|
### 8.2 基础资料 `/Zdwh`
|
||||||
|
|
||||||
|
时间规则、公寓、房间、节假日、餐补标准的新增/修改/删除/查询;公寓与房间资料是入住与推荐的基础。
|
||||||
|
|
||||||
|
### 8.3 统计与导出
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/xxtj/getBjcs` | 报警次数 |
|
||||||
|
| `/xxtj/getJdqk` | 进出情况 |
|
||||||
|
| `/xxtj/getRtjb` | 日报 |
|
||||||
|
| `/xxtj/getYtjb` | 月报 |
|
||||||
|
| `/xxtj/getDailyApartmentReport`、`/getDailyApartmentReportFull` | 公寓日报 |
|
||||||
|
| `/xxtj/getApartmentAllowanceStatis` | 补助统计 |
|
||||||
|
| `/excel/exportJcXxExcell` | 叫乘明细 |
|
||||||
|
| `/excel/exportDailyApartmentReport` | 日报 |
|
||||||
|
| `/excel/exportJcXxExcellOld` | 旧版叫乘明细 |
|
||||||
|
| `/excel/exportAllowanceExcell` | 补助明细 |
|
||||||
|
| `/excel/exportRechargeExcell` | 充值明细 |
|
||||||
|
| `/excel/exportConsumeExcell` | 消费明细 |
|
||||||
|
| `/excel/exportRechargeStatisExcell` | 充值统计 |
|
||||||
|
| `/excel/exportAllowanceStatisExcell` | 补助统计 |
|
||||||
|
| `/excel/exportCashConsumeStatisExcell` | 现金消费统计 |
|
||||||
|
| `/excel/exportAllowanceConsumeStatisExcell` | 补助消费统计 |
|
||||||
|
|
||||||
|
### 8.4 其他
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/clean/startCleaning`、`/endCleaning`、`/getRoomCleanInfo` | 保洁 |
|
||||||
|
| `/jgxxgl/getJgXx` | 报警/警示查询 |
|
||||||
|
| `/Meals/*` | 餐食、订单、房间、餐次列表 |
|
||||||
|
| `/kcgl/*` | 库存/出入库/物料/成品/文件 |
|
||||||
|
| `/synData/*` | 运安/公寓人员、财务数据 |
|
||||||
|
| `/jwDataLog/getSynJcXxIsOffline` | 同步状态/是否离线 |
|
||||||
|
| `/websocket/{username}`、`/jcwebsocket/{username}`、`/jlwebsocket/{username}`、`/rlywebsocket/{username}`、`/MealsWebsocket/{username}` | WebSocket 端点 |
|
||||||
|
|
||||||
|
## 9. WebSocket 消息
|
||||||
|
|
||||||
|
| 消息 | 含义 |
|
||||||
|
| --- | --- |
|
||||||
|
| `{"lx":"refresh"}` | 叫乘/房间/人员数据刷新 |
|
||||||
|
| `{"lx":"ry","content":...}` | 入寓人员信息推送值班端 |
|
||||||
|
| `{"lx":"zcxx","photoBase64":...,"deviceCode":...,"zcid":...}` | 注册拍照 |
|
||||||
|
| `{"lx":"xgxx","content":...,"newPhotoBase64":...}` | 人员资料/照片更新 |
|
||||||
|
| `{"lx":"cz"}` | 充值申请提醒 |
|
||||||
|
|
||||||
|
`JcWebsocket.sendMessage(message, gyid)` 会按公寓路由;`gyid="all"` 表示广播。
|
||||||
|
|
||||||
|
## 10. 接口扩展建议
|
||||||
|
|
||||||
|
1. 新接口明确 HTTP 方法,避免用 `@RequestMapping` 触发写操作。
|
||||||
|
2. 统一返回体,不在 Controller 里拼 `JSONObject`。
|
||||||
|
3. 前端传入的 `gyid` 只能作为提示,服务端必须重新解析/校验。
|
||||||
|
4. 设备协议新增字段时保持向后兼容:旧字段可缺省,新增字段给默认值。
|
||||||
|
5. 接口文档以本清单为基线,最终以 `JcglController` 等源码为准;Swagger 目前只扫描 `jlgl.controller`,覆盖不全。
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
# 07 外部集成与定时任务
|
||||||
|
|
||||||
|
## 1. Asterisk 电话/广播链路
|
||||||
|
|
||||||
|
### 1.1 角色
|
||||||
|
|
||||||
|
- 叫乘执行者:`AsteriskCallUtil`。
|
||||||
|
- 连接方式:Asterisk Manager Interface(AMI),使用定制版 `asterisk-java 3.38.0-zfjia`。
|
||||||
|
- 会议桥:`Conf-01`。
|
||||||
|
- 呼叫对象:
|
||||||
|
- 值班台:`Local/1701@from-internal`(`callcontrol.ami.console`,默认 1009/1010)。
|
||||||
|
- 房间:房间 `sip_account`(`GY_ROOMS.sip_account`)经 `Local/1901@from-internal` 呼入。
|
||||||
|
- 串口:`callcontrol.console.*`(默认 `COM1`、9600),用于广播/话机控制。
|
||||||
|
|
||||||
|
### 1.2 配置项
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
callcontrol:
|
||||||
|
ami:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 7058
|
||||||
|
user: ${AMI_USER}
|
||||||
|
pwd: ${AMI_PASSWORD}
|
||||||
|
console: 1010
|
||||||
|
callduration: 180
|
||||||
|
console:
|
||||||
|
port: COM1
|
||||||
|
baudrate: 9600
|
||||||
|
recording:
|
||||||
|
base-url: ... # 录音回放地址
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 一次叫乘的时序
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Q as Quartz WakeUpJob
|
||||||
|
participant S as JcglService
|
||||||
|
participant A as AsteriskCallUtil
|
||||||
|
participant AMI as Asterisk AMI
|
||||||
|
participant C as 值班台
|
||||||
|
participant R as 房间话机
|
||||||
|
|
||||||
|
Q->>S: 触发 JC/FJ/JCJS
|
||||||
|
S->>A: makeWakeup(人员, 房间SIP)
|
||||||
|
A->>A: 组装 TTS 文本
|
||||||
|
A->>AMI: 呼叫 1701(值班台)
|
||||||
|
A->>AMI: 呼叫 1901 + 房间 SIP
|
||||||
|
AMI->>C: 接通
|
||||||
|
AMI->>R: 接通并加入 Conf-01
|
||||||
|
A->>AMI: 播放 TTS
|
||||||
|
R-->>A: ConfbridgeJoin / Answered
|
||||||
|
A->>S: ryzt=5(通话中)→ 挂断后 ryzt=3(待离寓)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.4 TTS 文案
|
||||||
|
|
||||||
|
> 尊敬的{姓名},{公寓名称}提醒您,您值乘的{车次}次,接车方式是{接车方式},开车时间{开车时间},现在时间{当前时间},请您携带好随身物品,准备出乘。
|
||||||
|
|
||||||
|
车次、接车方式、时间会做口语化格式化(`formatTrainCodeForSpeech` / `formatPickupModeForSpeech` / `formatTrainTimeForSpeech`)。
|
||||||
|
|
||||||
|
### 1.5 超时与挂断
|
||||||
|
|
||||||
|
| 常量 | 值 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `CALL_TIMEOUT_MS` | 30 秒 | 呼叫无应答超时 |
|
||||||
|
| `WAKEUP_ANSWERED_AUTO_HANGUP_SECONDS` | 40 秒 | 叫乘接通后自动挂断 |
|
||||||
|
| `SHOUT_CALL_ANSWERED_AUTO_HANGUP_SECONDS` | 30 秒 | 广播/喊话接通后自动挂断 |
|
||||||
|
|
||||||
|
事件监听:
|
||||||
|
|
||||||
|
- `ConfbridgeJoinEvent`:入会,记录通道与接通。
|
||||||
|
- `ConfbridgeLeaveEvent`:离会,清理跟踪。
|
||||||
|
- `NewCallerIdEvent`:回填通道/主叫。
|
||||||
|
- `HangupEvent`:挂断,若已接通且需跟踪则置 `ryzt=3`;未接通则进入未应答处理(转报警/复叫)。
|
||||||
|
|
||||||
|
录音:接通后记录录音文件名,追加到 `GY_JCXX.recordfile`;`/jcgl/getRecordingConfig` 返回回放地址。
|
||||||
|
|
||||||
|
### 1.6 停止/挂断
|
||||||
|
|
||||||
|
- `stopWakeupCall` / `stopWakeupCallAsync`:挂断该人员所有跟踪通道、值班台/房间通道、`Conf-01`。
|
||||||
|
- `hangupTrackedCallsByRyid`:只挂断跟踪到的通道。
|
||||||
|
- `isConferenceBusy`:会议桥占用时任务延迟 60 秒。
|
||||||
|
|
||||||
|
## 2. 机务运安(BYXX)SOAP
|
||||||
|
|
||||||
|
### 2.1 接入方式
|
||||||
|
|
||||||
|
- WSDL:`classpath:/wsdl/PbResource.wsdl`。
|
||||||
|
- 生成客户端:`byxx.resource.PbResource_Service` / `PbResource`。
|
||||||
|
- 服务实现:`ByxxResourceService`。
|
||||||
|
|
||||||
|
### 2.2 主要操作
|
||||||
|
|
||||||
|
| 操作 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `getLocoHomeList` | 机务段列表 |
|
||||||
|
| `getDriverInfoBySectionCode` | 按段获取司机资料 |
|
||||||
|
| `getDriverInfoByWorkNo` | 按工号获取司机 |
|
||||||
|
| `getDriverPlanByTimeStr` | 按时间段获取乘务计划(叫乘快照来源) |
|
||||||
|
|
||||||
|
### 2.3 计划字段映射
|
||||||
|
|
||||||
|
| 运安字段 | 快照字段 |
|
||||||
|
| --- | --- |
|
||||||
|
| `jobid + taskdicid` | `id` |
|
||||||
|
| `driver1..driver4` | `ryid`(一条计划拆成最多 4 条人员记录) |
|
||||||
|
| `plantrainnum` | `cc` |
|
||||||
|
| `model + loco` | `jch` |
|
||||||
|
| `dispmancode` | `h1` |
|
||||||
|
| `plandeptime` | `kcsj` |
|
||||||
|
| `plancalltime` | `jcsj`(仅保留,最终叫乘时间按本地规则重算) |
|
||||||
|
| `plandepstation` | `jhcqdd` |
|
||||||
|
| `jobType`(0 库出,其他站接) | `jcfs` |
|
||||||
|
|
||||||
|
### 2.4 调度
|
||||||
|
|
||||||
|
- 每 5 分钟抓取一次(`SynDataSchedule.getSynDataJob`),窗口约 4 小时。
|
||||||
|
- 每 5 天同步一次人员(`SyncPersonData`,仅 `T` 开头机务段)。
|
||||||
|
- 抓取/匹配共用 `CallDutyMatchLock`,防止并发清表。
|
||||||
|
- **匹配只处理 `baseConfig.gyid` 配置的公寓**;一实例多公寓部署时,其他公寓不会自动匹配,需改造或拆实例。
|
||||||
|
|
||||||
|
### 2.5 已知限制
|
||||||
|
|
||||||
|
- `mergeSynJcXx` 已停用(同 `id` 多司机导致 MERGE 重复)。
|
||||||
|
- `getRemoteSynJcXx` 为桩实现,未恢复远程 HTTP 同步。
|
||||||
|
- WSDL 地址与派班室/公寓编码硬编码(“通辽南公寓”“通辽南派班室”),多公寓部署需参数化。
|
||||||
|
|
||||||
|
## 3. 中心服务器 HTTP
|
||||||
|
|
||||||
|
| 场景 | 地址/配置 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 人员资料拉取 | `http://10.32.112.153:52411/api/users?pagenum=N` | `SynDataService.personData`,分页拉取机务人员 |
|
||||||
|
| 人员变更推送 | `/synData/modifyPersonData` | 运安推送人员增量 |
|
||||||
|
| 公寓人员查询 | `/synData/getApartmentPersonData*` | 按公寓/工号/时间查询在寓人员 |
|
||||||
|
| 财务数据 | `/synData/synFinanceData` | 按 IP 解析公寓后返回余额数据 |
|
||||||
|
| 照片/静态资源 | `baseConfig.centerServerUrl` / `serverUrl` | 人员照片 URL 前缀 |
|
||||||
|
|
||||||
|
中心同步使用 `HttpRequest`(内部封装),未见超时/重试统一配置,排障时需关注网络与超时。
|
||||||
|
|
||||||
|
## 4. WebSocket
|
||||||
|
|
||||||
|
| 端点 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/websocket/{username}` | 通用推送(历史) |
|
||||||
|
| `/jcwebsocket/{username}` | 叫乘主界面刷新/人员信息 |
|
||||||
|
| `/jlwebsocket/{username}` | 交路界面 |
|
||||||
|
| `/rlywebsocket/{username}` | 人员/入住相关 |
|
||||||
|
| `/MealsWebsocket/{username}` | 餐食订单 |
|
||||||
|
|
||||||
|
关键消息见 [06-接口清单.md](./06-接口清单.md) 第 9 节。服务端推送按 `gyid` 路由,`"all"` 广播。
|
||||||
|
|
||||||
|
## 5. Quartz 叫乘任务
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| Job 类 | `quartz/WakeUpJob` |
|
||||||
|
| 调度管理 | `quartz/SchedulerManager` |
|
||||||
|
| JobKey | `ryid + "JC"` / `"FJ"` / `"JCJS"` |
|
||||||
|
| TriggerGroup | `gyid + fjh` |
|
||||||
|
| 触发方式 | 一次性 cron,精确到秒 |
|
||||||
|
| 优先级 | JC=1、FJ=2、JCJS=3 |
|
||||||
|
| 并发控制 | `@DisallowConcurrentExecution` |
|
||||||
|
| 参数 | `JobParas`(人员、房间、车次、时间、jcid 等) |
|
||||||
|
| 执行前校验 | `jcid/fjh/叫乘时间` 与库中一致才执行,否则跳过 |
|
||||||
|
| 合并执行 | 同房间/同车次合并为一个执行组,组长先叫 |
|
||||||
|
| 会议桥忙 | 延迟 60 秒 |
|
||||||
|
| 恢复 | `WakeupJobRecoveryRunner` 在 `ApplicationReadyEvent` 后恢复未来任务 |
|
||||||
|
|
||||||
|
失败处理:
|
||||||
|
|
||||||
|
- 任务内部异常写业务日志,不抛到 Quartz。
|
||||||
|
- `JCJS` 挂断会议桥、置 `ryzt=2`、写报警记录。
|
||||||
|
- 人工停止叫乘会取消该人员全部任务。
|
||||||
|
|
||||||
|
## 6. Spring `@Scheduled` 清单
|
||||||
|
|
||||||
|
| 类.方法 | Cron | 作用 | 状态 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `JcSchedule.notifyMissedCallWarnings` | `5 * * * * ?`(每分钟第 5 秒) | 超时未叫乘分级提醒(第 1/10/15 分钟) | 启用 |
|
||||||
|
| `JcSchedule.triggerOverdueLeaveAlarms` | `15 * * * * ?`(每分钟第 15 秒) | 已应答但超时未离寓报警 | 启用 |
|
||||||
|
| `JcSchedule.syncJcXxData` | `0 0 0 * * ?`(Asia/Shanghai) | 归档已离寓满 7 天记录 | 启用 |
|
||||||
|
| `SynDataSchedule.getSynDataJob` | `0 */5 * * * ?` | 运安抓取 + 记录同步时间 + 触发匹配 | 启用 |
|
||||||
|
| `SynDataSchedule.synPersonDataJob` | `30 0 0 */5 * ?` | 每 5 天同步运安人员 | 启用 |
|
||||||
|
| `LeaveSnapshotCleanupSchedule.cleanupExpiredLeaveSnapshots` | `${leaveSnapshot.cleanupCron:0 30 2 * * ?}` | 清理过期离寓抓拍 | 启用 |
|
||||||
|
| `RechargeSchedule.*` | — | 自动补助/充值 | 全部注释停用 |
|
||||||
|
| `JlSchedule.*` | — | 交路定时同步 | 注释停用 |
|
||||||
|
| `LogSchedule.*` | — | 日志清理 | 注释停用 |
|
||||||
|
|
||||||
|
## 7. 并发控制与幂等
|
||||||
|
|
||||||
|
| 机制 | 位置 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 交路同步锁 | `CallDutyMatchLock` + `GY_CALL_DUTY_MATCH_LOCK` | 抓取/推送/匹配互斥,事务提交后释放 |
|
||||||
|
| 同步状态位 | `GY_SYN_JCXX_STATUS` | 只有 `1` 才能匹配 |
|
||||||
|
| 设备事件幂等 | `GYGL_LY_EVENT(device_code, device_event_id)` | 刷脸离寓重复请求直接返回已处理 |
|
||||||
|
| 报警去重 | `triggerLeaveAlarmIfPending` 条件更新 | 同一次入住只触发一次离寓报警 |
|
||||||
|
| 提醒去重 | `route_notice_key` / `call_timeout_notice_key` / `missed_call_notice_key` | 同一节点只提醒一次 |
|
||||||
|
| 充值互斥 | `GY_YKT_CASH_REQUEST` 条件更新 | 完成与取消只能成功一个 |
|
||||||
|
| 房间占用 | `refreshRoomOccupancy` + 有效在寓明细 | 防止计数漂移 |
|
||||||
|
| 任务过期校验 | `WakeUpJob` 执行前比对库中数据 | 防止旧任务误叫 |
|
||||||
|
|
||||||
|
## 8. 排障入口
|
||||||
|
|
||||||
|
1. **叫乘没响**:看 Quartz 任务是否存在(`SchedulerManager` 日志)→ AMI 连接 → 会议桥是否忙 → 房间 `sip_account` 是否为空 → 任务时间是否已过期被跳过。
|
||||||
|
2. **叫乘响了但状态不变**:看 AMI 事件(Join/Hangup)是否被正确匹配通道 → `GY_JCXX.ryzt` / `recordfile`。
|
||||||
|
3. **运安计划没进来**:看 5 分钟任务日志、`GY_SYN_JCXX_STATUS`、`JWDATA_SYNC_LOG`、WSDL 可达性。
|
||||||
|
4. **匹配不上**:核对 `GY_YKT_RY.card_id` 与 `GY_SYN_JCXX.workno`,以及人员是否在有效在寓状态、`jllx` 是否被人工锁定。
|
||||||
|
5. **离寓报错**:看抓拍配置 `leaveSnapshot.*`、事件幂等记录、`GYGL_LY_EVENT`。
|
||||||
|
6. **设备指令不下发**:看 `GY_SB` 是否有该设备、心跳是否带 `deviceCode`、指令是否已被置 `deleted=1`。
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
# 08 部署与配置
|
||||||
|
|
||||||
|
## 1. 构建与运行
|
||||||
|
|
||||||
|
### 1.1 环境要求
|
||||||
|
|
||||||
|
| 组件 | 要求 |
|
||||||
|
| --- | --- |
|
||||||
|
| JDK | 8 |
|
||||||
|
| Maven | 3.6+ |
|
||||||
|
| 数据库 | KingbaseES 8(部分 Profile 仍接 Oracle) |
|
||||||
|
| 缓存 | Redis(Session) |
|
||||||
|
| 电话 | Asterisk + AMI 账号 + 会议桥 `Conf-01` |
|
||||||
|
| 串口 | 广播/话机控制串口(默认 `COM1`,Linux 下为 `/dev/ttyS0` 等) |
|
||||||
|
| 文件 | 照片、离寓抓拍、录音的可读写目录 |
|
||||||
|
|
||||||
|
### 1.2 构建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd yktgl
|
||||||
|
mvn clean package -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
- `pom.xml` 未声明 `<packaging>`,默认生成 jar。
|
||||||
|
- 入口继承 `SpringBootServletInitializer`,如需部署到外部 Tomcat,可改为 `<packaging>war</packaging>` 并排除内嵌容器。
|
||||||
|
- 构建前注意 `pom.xml` 中 Boot 3.x 依赖版本与 Boot 2.6.13 的兼容问题(见 09)。
|
||||||
|
|
||||||
|
### 1.3 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar yktgl-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
|
||||||
|
```
|
||||||
|
|
||||||
|
或:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -Dspring.profiles.active=prod -jar yktgl-0.0.1-SNAPSHOT.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
默认端口 `8081`,上下文路径 `/yktgl`。
|
||||||
|
|
||||||
|
## 2. Profile 对照
|
||||||
|
|
||||||
|
| Profile | 公寓 `gyid` / `gymc` | 数据源 | 备注 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `local` | `TMXC` 图们行车公寓 | Kingbase `127.0.0.1:54321/gygl` | 本机调试,Redis/AMI/串口均本机 |
|
||||||
|
| `dev` | 未启用(注释为 `TLXC`) | Kingbase `10.32.209.76:54321/gygl` | 开发环境 |
|
||||||
|
| `prod` | `TLNXC` 通辽南行车公寓 | Kingbase `10.33.165.41:54321/gygl` | 生产 |
|
||||||
|
| `tl` | `TLXC` 通辽行车公寓 | Kingbase `10.32.209.76:54321/gygl` | 通辽 |
|
||||||
|
| `sjt` | `SJTXC` 苏家屯行车公寓 | Kingbase `10.32.209.76:54321/gygl` | 苏家屯 |
|
||||||
|
| `byq` | `BYQXC` 鲅鱼圈行车公寓 | Oracle `10.32.116.45/db3` | 仍在 Oracle |
|
||||||
|
| `cc` | `SJTXC` 苏家屯行车公寓 | Oracle `10.32.5.175/rlxt` | 仍在 Oracle,注意与 `sjt` 同名不同库 |
|
||||||
|
| `dl` | `DLXC` 大连行车公寓 | Oracle `10.32.116.45/db3` | 仍在 Oracle |
|
||||||
|
| `pj` | `PJXC` 盘锦行车公寓 | Oracle `10.32.116.45/db3` | 仍在 Oracle |
|
||||||
|
|
||||||
|
> 所有 Profile 中的数据库口令、AMI 口令、`devicePassword` 目前均为明文,且已提交到仓库。生产使用前应改为环境变量/配置中心,并轮换口令。
|
||||||
|
|
||||||
|
## 3. 关键配置项
|
||||||
|
|
||||||
|
### 3.1 服务
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `server.port` | 默认 8081 |
|
||||||
|
| `server.servlet.context-path` | `/yktgl` |
|
||||||
|
| `spring.profiles.active` | 默认 `local` |
|
||||||
|
| `spring.mvc.pathmatch.matching-strategy` | `ant_path_matcher`(兼容 Springfox) |
|
||||||
|
|
||||||
|
### 3.2 数据源与连接池
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `spring.datasource.url` | Kingbase 需带 `currentSchema=gygl` |
|
||||||
|
| `spring.datasource.driver-class-name` | `com.kingbase8.Driver` |
|
||||||
|
| `spring.datasource.hikari.*` | 最小空闲 5、最大 15、连接超时 60s、最大生命周期 600s |
|
||||||
|
|
||||||
|
### 3.3 Redis / Session
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `spring.redis.host/port` | Redis 地址 |
|
||||||
|
| `spring.session.store-type` | `redis` |
|
||||||
|
| `spring.session.timeout` | 默认 30m |
|
||||||
|
|
||||||
|
### 3.4 公寓与业务开关 `baseConfig`
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `gyid` / `gymc` | 当前公寓(单公寓/默认兜底) |
|
||||||
|
| `centerServerUrl` | 中心服务器地址(照片前缀等) |
|
||||||
|
| `serverUrl` | 服务自身地址 |
|
||||||
|
| `synJcXxIp` | 运安推送来源 IP 白名单(逗号分隔) |
|
||||||
|
| `devicePassword` | 设备心跳返回的设备密码 |
|
||||||
|
| `centralPhoneIp` | 中心电话 IP |
|
||||||
|
| `serverOS` | `windows` / `linux`,影响照片与抓拍路径 |
|
||||||
|
| `modifyyasj` | 是否允许调整运安叫乘时间 |
|
||||||
|
| `allowRouteChangeAfterCompletedCall` | 默认 `true`;叫乘完成后是否允许运安匹配继续变更交路 |
|
||||||
|
| `syncMatchWaitSeconds` | 默认 900;抓取/匹配等待同步锁的最长秒数 |
|
||||||
|
| `fjgydbs` | 分公寓/终端所属公寓段的交互标识(按需配置) |
|
||||||
|
|
||||||
|
### 3.5 电话与录音 `callcontrol`
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `callcontrol.ami.host/port` | AMI 地址 |
|
||||||
|
| `callcontrol.ami.user/pwd` | AMI 账号 |
|
||||||
|
| `callcontrol.ami.console` | 值班台分机/控制台号 |
|
||||||
|
| `callcontrol.ami.callduration` | 呼叫时长上限(秒) |
|
||||||
|
| `callcontrol.console.port/baudrate/...` | 串口参数 |
|
||||||
|
| `callcontrol.recording.base-url` | 录音回放根地址;为空时默认 `http://<ami.host>/conf/` |
|
||||||
|
| `RECORDING_BASE_URL` | 环境变量覆盖录音地址 |
|
||||||
|
|
||||||
|
### 3.6 离寓抓拍 `leaveSnapshot`
|
||||||
|
|
||||||
|
| 配置 | 默认 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `enabled` | `true` | 是否保存抓拍 |
|
||||||
|
| `requiredForDevice` | `false` | 设备未传抓拍是否失败(兼容旧设备) |
|
||||||
|
| `retentionDays` | `7` | 保留天数 |
|
||||||
|
| `cleanupCron` | `0 30 2 * * ?` | 每日清理 |
|
||||||
|
| `rootDirectory` | 见 Profile | 抓拍保存目录 |
|
||||||
|
| `urlPrefix` | `/yktgl/photo/leave-snapshots` | 访问前缀 |
|
||||||
|
|
||||||
|
### 3.7 静态资源与文件
|
||||||
|
|
||||||
|
| 配置 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `spring.web.resources.static-locations` | `classpath:/static/` + 文件目录(Linux 常见 `/home/gygl/resouce/`) |
|
||||||
|
| 人员照片 | `.../resouce/photo/{ryid}.png`(代码中写死,Windows 为 `C:\project_doc\resouce\photo\`) |
|
||||||
|
| 离寓抓拍 | `.../resouce/photo/leave-snapshots/{gyid}/{eventId}.jpg` |
|
||||||
|
|
||||||
|
> 照片路径在 `RegistService` 中按 `serverOS` 硬编码,迁移环境时需同步修改代码或改为配置项。
|
||||||
|
|
||||||
|
## 4. 数据库升级
|
||||||
|
|
||||||
|
手工脚本位于 `yktgl/src/main/resources/db/`,按日期顺序执行:
|
||||||
|
|
||||||
|
1. `GY_SYN_JCXX_STATUS.sql`(首次部署)
|
||||||
|
2. `manual/V20260921_01__leave_snapshot_evidence_kingbase.sql`
|
||||||
|
3. `manual/V20260922_01__call_duty_notice_dedup_kingbase.sql`
|
||||||
|
4. `manual/V20261008_01__syn_jcxx_write_time_kingbase.sql`
|
||||||
|
5. `manual/V20261008_02__call_duty_match_lock_kingbase.sql`
|
||||||
|
6. `manual/V20261009_01__jcxx_history_archive_kingbase.sql`
|
||||||
|
7. `manual/V20261023_01__cash_request_state_kingbase.sql`
|
||||||
|
8. `manual/V20261029_01__reconcile_tlxc_room_occupancy_preview.sql`(先预览)
|
||||||
|
9. `manual/V20261029_01__reconcile_tlxc_room_occupancy.sql`(确认后执行)
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- 脚本不会随应用启动自动执行。
|
||||||
|
- 执行前备份;先跑 preview 核对影响行数。
|
||||||
|
- 若数据库仍为 Oracle,需确认脚本语法是否兼容(现有 manual 脚本以 Kingbase 为主)。
|
||||||
|
|
||||||
|
## 5. 多公寓部署
|
||||||
|
|
||||||
|
两种方式:
|
||||||
|
|
||||||
|
1. **一套服务一个公寓**:通过 `baseConfig.gyid/gymc` 指定;设备 IP 仍参与解析。
|
||||||
|
2. **一套服务多个公寓**:依赖 `GY_SB.ip` / `GY_GYZD.ip` 做 IP→公寓映射;同一 IP 命中多个公寓会直接拒绝。
|
||||||
|
|
||||||
|
部署检查:
|
||||||
|
|
||||||
|
- 每个公寓的设备 IP 必须唯一归属。
|
||||||
|
- 反向代理必须透传真实客户端 IP(`X-Forwarded-For`),否则所有请求会被识别为代理 IP。
|
||||||
|
- WebSocket 需允许 `Upgrade`/`Connection` 头,并适当延长超时。
|
||||||
|
|
||||||
|
## 6. 上线检查清单
|
||||||
|
|
||||||
|
- [ ] JDK 8、时区 `Asia/Shanghai`、服务器时间与 NTP 同步(叫乘精确到秒)。
|
||||||
|
- [ ] Kingbase 可连,schema `gygl` 正确,升级脚本已执行。
|
||||||
|
- [ ] Redis 可连,Session 能写入。
|
||||||
|
- [ ] `baseConfig.gyid/gymc` 与当前公寓一致。
|
||||||
|
- [ ] `synJcXxIp` 包含运安推送源 IP。
|
||||||
|
- [ ] `devicePassword` 与设备端一致。
|
||||||
|
- [ ] Asterisk AMI 可连,`Conf-01` 存在,值班台/房间分机可呼通。
|
||||||
|
- [ ] 串口设备可打开(Linux 检查权限与设备名)。
|
||||||
|
- [ ] 照片/抓拍目录存在且可写,静态资源映射正确。
|
||||||
|
- [ ] 反向代理透传真实 IP,WebSocket 可升级。
|
||||||
|
- [ ] 启动日志无 Mapper/Bean 初始化错误;`WakeupJobRecoveryRunner` 已恢复任务。
|
||||||
|
- [ ] 用一个测试人员走通:入住 → 叫乘 → 应答 → 离寓 → 归档。
|
||||||
|
|
||||||
|
## 7. 运行期维护
|
||||||
|
|
||||||
|
| 事项 | 建议 |
|
||||||
|
| --- | --- |
|
||||||
|
| 日志 | 现有 `System.out` 与业务日志混杂,建议接入统一日志文件与轮转 |
|
||||||
|
| 归档 | 每日 00:00 自动归档 7 天前离寓记录;数据量大时关注执行耗时 |
|
||||||
|
| 抓拍清理 | 每日 02:30 清理过期抓拍;确认磁盘余量 |
|
||||||
|
| 同步 | 运安每 5 分钟抓取;观察 `JWDATA_SYNC_LOG` 与同步状态 |
|
||||||
|
| 备份 | 数据库 + 照片/抓拍目录 + 录音目录 |
|
||||||
|
| 口令 | 尽快外置并轮换数据库/AMI/设备口令 |
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# 09 迭代指引与风险清单
|
||||||
|
|
||||||
|
## 1. 技术债与风险
|
||||||
|
|
||||||
|
### P0:会直接影响构建/上线
|
||||||
|
|
||||||
|
| 项 | 现状 | 影响 | 建议 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Spring Boot 依赖版本错配 | `pom.xml` 在 Boot 2.6.13 父工程下显式声明 `spring-boot-starter-web:3.5.4`、`spring-boot-starter-data-redis:3.3.1` | 可能拉入 Spring 6 / Jakarta 依赖,与 `javax.servlet` 代码不兼容,导致编译/运行失败 | 删除显式版本,交给父工程管理;或统一升到 Boot 3 + Jakarta(大改造)。先跑一次 `mvn clean test` 确认基线 |
|
||||||
|
| 明文口令与内部地址入库 | 各 `application-*.yml` 含数据库口令、AMI 口令、`devicePassword`、内网 IP | 已推送到远端,存在泄露风险 | 轮换口令;改用环境变量/配置中心;生产库最小权限 |
|
||||||
|
| 无根级 `.gitignore` | 仓库根目录没有 `.gitignore`,仅有 `YktVue/.gitignore` | 易误提交构建产物、日志、数据转储 | 在仓库根补充 `.gitignore`(target、logs、*.log、node_modules、dist、本地配置) |
|
||||||
|
| 构建/测试基线不明 | `target/` 为空,测试未运行,无 CI 配置 | 无法判断改动是否破坏现有功能 | 建立 CI:编译 + 单测 + 关键 SQL 校验 |
|
||||||
|
|
||||||
|
### P1:影响正确性与可维护性
|
||||||
|
|
||||||
|
| 项 | 现状 | 影响 | 建议 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `JcglService` 过大 | 约 4192 行,混合叫乘、房间、补助、交路、归档、设备指令 | 改动风险高、冲突多、难测试 | 按“叫乘执行 / 房间 / 卡务 / 交路匹配 / 归档”拆服务,先抽只读逻辑与纯函数 |
|
||||||
|
| 交路 MERGE 停用 | `mergeSynJcXx` 因同 `id` 多司机被注释 | 快照与历史数据可能长期不一致 | 改为 `id + ryid` 唯一键后恢复,并加数据清理脚本 |
|
||||||
|
| 远程同步为桩 | `/jcgl/getRemoteSynJcXx` 直接返回成功 | 调用方误以为已同步 | 恢复实现或明确返回“未启用” |
|
||||||
|
| 部分定时任务停用 | `RechargeSchedule`、`JlSchedule`、`LogSchedule` 全部注释 | 自动补助、交路同步、日志清理不生效 | 明确替代方案;若不再需要则删除代码 |
|
||||||
|
| 写接口用 `@RequestMapping` | 大量写操作接受 GET | 易被误触发、难做权限/审计 | 新接口强制 POST;存量逐步收敛 |
|
||||||
|
| 异常被吞 | 大量 `catch` 返回 `Result.failure`,仅写日志 | 故障定位困难、事务边界不清 | 统一异常处理与错误码;关键路径保留堆栈 |
|
||||||
|
| 日志不规范 | `System.out.println` 与业务日志混用 | 无法集中检索/轮转 | 统一 SLF4J + 文件轮转;敏感信息脱敏 |
|
||||||
|
| 硬编码 | 公寓名“通辽南公寓/通辽南派班室”、照片路径、内网 IP、中心地址 | 多公寓/迁移环境需改代码 | 抽到配置或字典表 |
|
||||||
|
| 交路匹配只覆盖单公寓 | `matchCallDutyUnderLock` 只处理 `baseConfig.gyid` 配置的公寓 | 一实例多公寓时,其他公寓不会自动匹配交路 | 明确部署形态;如需一实例多公寓,把 `gyid` 改为循环/列表并逐公寓加锁 |
|
||||||
|
| 房态语义不一致 | `selectRoomRecommendations` 与前端允许 `3`(待清扫)、`6`(保洁中);`validateRoomForCheckIn` 也允许 `6` | 保洁中的房间可能被入住 | 确认业务规则;若不允许,收紧 SQL 与校验 |
|
||||||
|
| 备份文件/旧构建 | `RoomLook copy.vue`、`JcXx.vue.bak_mojibake`、`resources/static` 下旧前端与 `.gz` | 干扰阅读、增大仓库 | 清理或移入 `legacy/` |
|
||||||
|
|
||||||
|
### P2:体验与稳健性
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `processCallDuty` 空值判断顺序 | `ryid.equals("") || ryid == null` 在 `ryid=null` 时会先 NPE;应改为 `StringUtils.isBlank` |
|
||||||
|
| `h1.concat(...)` 结果未赋值 | `ByxxResourceService` 中拼接公寓编码无效,`h1` 实际未追加 `housecode` |
|
||||||
|
| `syncJlXX` 返回 `null` | `/jcgl/ya/list` 永远返回空数据,容易误判 |
|
||||||
|
| `personData` 空数组 | `jsonArray.getJSONObject(0)` 未判空,上游无数据时异常 |
|
||||||
|
| 时间字符串 | 全链路用字符串 + `TO_DATE`,格式/时区问题只能在运行期暴露 |
|
||||||
|
| IP→公寓 | 依赖真实客户端 IP;反向代理未透传时会识别错误 |
|
||||||
|
| 设备照片/抓拍 | Base64 体积大,需关注请求体大小、内存与磁盘 |
|
||||||
|
| 测试接口暴露 | `/test/*`、`/jcgl/yatest`、`/jcgl/driver/{id}` 可访问外部系统,生产应限制 |
|
||||||
|
|
||||||
|
## 2. 改动落点速查
|
||||||
|
|
||||||
|
| 需求 | 先看 | 可能要改 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 调整叫乘/复叫/报警时间 | `GY_SJGZ`、`modifyJcXxBySynJcXx`、`populateJcXxByJlXx` | `JcglService`、`WakeUpJob`、`SchedulerManager` |
|
||||||
|
| 改叫乘提醒节点 | `JcglService.notifyMissedCallWarnings`、`selectMissedCallWarnings` | `JcSchedule`、SQL |
|
||||||
|
| 改叫乘语音内容 | `AsteriskCallUtil.makeWakeup` | TTS 文案、格式化函数 |
|
||||||
|
| 改房间状态规则 | `getRoomStatus`、`validateRoomForCheckIn`、`modifyRoomStatus` | `JcglRoomMapper.xml`、前端 `Room.vue` |
|
||||||
|
| 改房间推荐 | `selectRoomRecommendations` | 推荐 SQL、`getRoomRecommendations` |
|
||||||
|
| 新增设备类型 | `heartBeat`、`GY_SB`、`GY_SB_XT` | 新建 `xxxDevice` 包、心跳控制器 |
|
||||||
|
| 改设备指令 | `HeartBeatService.addDeviceInstructionInfo*` | 各业务调用点 |
|
||||||
|
| 改入住补助 | `getAllowanceInfo`、`getTrainAllowanceInfo`、`changeRemainder` | `GY_YKT_*` 表、节假日规则 |
|
||||||
|
| 改充值/消费 | `RechargeService`、`PayService`、`VendPayDeviceService` | 余额与明细同事务 |
|
||||||
|
| 改交路维护 | `JlGlService`、`GYGL_JLXX` | 上传模板、同步接口 |
|
||||||
|
| 改运安同步 | `ByxxResourceService`、`SynDataSchedule` | WSDL、字段映射、锁 |
|
||||||
|
| 改匹配规则 | `matchCallDutyUnderLock` | 工号匹配、时间重算、任务重建 |
|
||||||
|
| 改离寓/抓拍 | `processCheckOutRegistration`、`leaveSnapshot.*` | `GYGL_LY_EVENT`、文件目录 |
|
||||||
|
| 新增报表 | `xxtj` / `excel` | 对应 Mapper XML |
|
||||||
|
| 改权限/菜单 | `display`、`GL_*` | 登录、RBAC、菜单 |
|
||||||
|
| 改公寓识别 | `ZdwhService.getUniqueGyByIp` | `GY_SB`、`GY_GYZD`、代理配置 |
|
||||||
|
|
||||||
|
## 3. 建议的迭代顺序
|
||||||
|
|
||||||
|
1. **建立基线**:修复 pom 版本错配,确保能编译;跑通现有测试;加 CI。
|
||||||
|
2. **安全整改**:口令外置与轮换;生产关闭测试接口;补根 `.gitignore`;清理备份文件。
|
||||||
|
3. **稳定性**:统一日志与异常;关键路径加监控(叫乘任务创建数、AMI 连接、同步状态、快照积压)。
|
||||||
|
4. **结构治理**:拆分 `JcglService`;把硬编码公寓/路径/地址配置化;收敛写接口 HTTP 方法。
|
||||||
|
5. **业务增强**:恢复并测试 `mergeSynJcXx`、远程同步;完善多公寓参数化;补叫乘/入住/离寓的集成测试。
|
||||||
|
6. **数据治理**:归档与索引优化;房间占用对账;历史数据清理。
|
||||||
|
|
||||||
|
## 4. 待确认问题
|
||||||
|
|
||||||
|
建议与业务/现场逐条确认,确认后回写本文档:
|
||||||
|
|
||||||
|
1. **保洁中(`room_status=6`)房间是否允许入住?** 当前推荐 SQL、入住校验、前端都允许,但 `modifyRoomStatus` 又禁止修改保洁中房间。
|
||||||
|
2. **待清扫(`3`)房间是否应出现在推荐列表?** 当前会出现,可能影响值班员选房效率。
|
||||||
|
3. **便乘/驻在是否完全不叫乘?** 当前 `jllx=1` 且跳过任务;是否符合现场?
|
||||||
|
4. **运安下发的 `jcsj` 是否彻底弃用?** 当前仅保留读取,最终按本地规则重算。
|
||||||
|
5. **远程同步是否还需要?** `getRemoteSynJcXx` 目前是桩。
|
||||||
|
6. **多公寓部署形态**:一公寓一实例,还是一实例多公寓?影响 IP 映射、同步任务与锁。
|
||||||
|
7. **刷脸抓拍是否强制?** `requiredForDevice=false` 目前兼容旧设备,何时切为 `true`?
|
||||||
|
8. **Oracle Profile(byq/cc/dl/pj)是否继续维护?** 若迁移 Kingbase,需要同步 SQL 兼容性。
|
||||||
|
9. **叫乘任务恢复范围**:应用重启后恢复未来任务,是否也要补偿“重启期间已错过”的任务?当前只恢复未来任务,错过由提醒任务兜底。
|
||||||
|
10. **归档保留策略**:`GY_JCXX_HIS` 保留多久?是否需要冷备/清理?
|
||||||
|
|
||||||
|
## 5. 文档维护约定
|
||||||
|
|
||||||
|
- 本文档以代码为准;接口、表、状态码变更时同步更新对应章节。
|
||||||
|
- 新增模块时,在 [03-业务模块地图.md](./03-业务模块地图.md) 增加一行,并在 [06-接口清单.md](./06-接口清单.md) 补接口。
|
||||||
|
- 新增表/字段时,在 [05-数据模型.md](./05-数据模型.md) 补字段与状态字典。
|
||||||
|
- 新增外部依赖/定时任务时,在 [07-外部集成与定时任务.md](./07-外部集成与定时任务.md) 补时序与排障点。
|
||||||
|
- 每次迭代结束,把已解决的风险从本清单移除,并在提交说明中引用相关文档章节。
|
||||||
@@ -0,0 +1,818 @@
|
|||||||
|
# 10 架构优化方案:平台端 / 公寓端 / 应用端三端拆分
|
||||||
|
|
||||||
|
> 文档性质:架构设计方案(Design Only)。本文不含代码补丁、不含数据库变更脚本、不含配置修改,仅作为后续重构设计、评审与实施的输入。
|
||||||
|
|
||||||
|
## 0. 文档说明
|
||||||
|
|
||||||
|
表 0-1 文档信息
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 文档编号 | docs/10 |
|
||||||
|
| 文档名称 | 架构优化方案:平台端 / 公寓端 / 应用端三端拆分 |
|
||||||
|
| 适用范围 | 铁路行车公寓叫乘系统(`YktVue` 前端、`yktgl` 后端、`docs` 文档) |
|
||||||
|
| 关联文档 | `01-系统总览`、`02-工程结构与分层`、`03-业务模块地图`、`04-核心业务流程`、`05-数据模型`、`06-接口清单`、`07-外部集成与定时任务`、`08-部署与配置`、`09-迭代指引与风险清单`、`frontend/*` |
|
||||||
|
| 约束条件 | 1)不改变“平台做核心业务与基础数据服务、公寓端做本地设备与任务执行、应用端做值班员操作界面”的总体定位;2)应用端与公寓端复用同一套代码与同一个数据库,不构成第三套服务或独立库;3)平台端不承担现场设备实时接入与控制;4)公寓端与应用端技术基线锁定为 RuoYi-Vue + Vue + MySQL(见 2.4),本基线不再讨论替代方案;5)公寓端直连本地 Asterisk,语音链路不经平台端中转 |
|
||||||
|
| 交付对象 | 架构评审、重构详细设计、试点实施与验收 |
|
||||||
|
|
||||||
|
表 0-2 修订记录
|
||||||
|
|
||||||
|
| 版本 | 日期 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| v1.0 | 2026-11-07 | 首次形成:现状评估、目标架构、职责边界、模块划分、数据架构、接口契约方向、设备接入、部署运行、迁移路径、风险与优先级 |
|
||||||
|
| v1.1 | 2026-11-07 | 细化公寓端:锁定 RuoYi-Vue + Vue + MySQL 技术基线;补齐应用端与公寓端的复用实现(2.5);新增语音模块清单与依赖方向(4.4);新增语音域数据设计(5.4)与分机配置一致性(5.5);新增数据库选型迁移分析(5.6);新增语音域接口清单(6.4);新增 Asterisk 链路设计(7.7–7.11);新增 Asterisk 部署运行(8.3);新增专项风险与决策点 D11–D16 |
|
||||||
|
|
||||||
|
表 0-3 本次修订(v1.1)涉及的小节与表号
|
||||||
|
|
||||||
|
| 类型 | 编号 | 内容 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 修订 | 表 0-1 | 约束条件补入技术基线与语音链路前提(第 4、5 条) |
|
||||||
|
| 修订 | 表 1-1 | 追加 3 条与 AMI、会议桥、分机台账相关的现状事实 |
|
||||||
|
| 新增 | 2.4 / 表 2-2 | 三端技术基线(确定前提) |
|
||||||
|
| 新增 | 2.5 / 图 2-3 / 表 2-3 | 应用端与公寓端的复用实现(工程结构、路由、权限、部署) |
|
||||||
|
| 修订 | 3.2 | 公寓端“负责/不负责”补入语音、分机、事件三条职责 |
|
||||||
|
| 新增 | 3.4 / 表 3-2 | 语音链路上的三端分工 |
|
||||||
|
| 修订 | 表 4-3 | 公寓端模块清单追加 4 个语音模块 |
|
||||||
|
| 新增 | 4.4 / 图 4-1 / 表 4-4 | 语音相关模块与依赖方向 |
|
||||||
|
| 新增 | 5.4 / 表 5-3、5-4 | 语音域数据设计(含 MySQL 适配) |
|
||||||
|
| 新增 | 5.5 / 表 5-5 | 分机配置在本地库与 Asterisk 之间的一致性机制 |
|
||||||
|
| 新增 | 5.6 / 表 5-6 ~ 5-9 | 数据库选型:KingbaseES → MySQL 的影响、迁移、双跑与平台端取舍 |
|
||||||
|
| 新增 | 6.4 / 表 6-3 | 公寓端语音域接口清单 |
|
||||||
|
| 新增 | 7.7 ~ 7.11 / 图 7-1 / 表 7-4 ~ 7-7 | Asterisk 语音链路:拓扑、资源生命周期、事件跟踪、闭环边界、自检巡检 |
|
||||||
|
| 新增 | 8.3 / 表 8-3 ~ 8-5 | Asterisk 与公寓端同机部署、端口防火墙、录音存储与清理 |
|
||||||
|
| 新增 | 10.3 / 表 10-3 | 语音与数据库专项风险 |
|
||||||
|
| 修订 | 表 10-2 | 追加待决策点 D11–D16 |
|
||||||
|
| 修订 | 表 11-1、11.3 | 落地顺序补入语音域治理与数据库切换两项 |
|
||||||
|
| 修订 | 附录 A/B/C/D | 术语、图表索引、代码证据、维护约定同步更新 |
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [1. 现状评估](#1-现状评估)
|
||||||
|
- [2. 目标架构](#2-目标架构)
|
||||||
|
- [3. 端职责边界](#3-端职责边界)
|
||||||
|
- [4. 领域与模块划分](#4-领域与模块划分)
|
||||||
|
- [5. 数据架构](#5-数据架构)
|
||||||
|
- [6. 接口与集成](#6-接口与集成)
|
||||||
|
- [7. 设备接入方案](#7-设备接入方案)
|
||||||
|
- [8. 部署与运行](#8-部署与运行)
|
||||||
|
- [9. 迁移与实施路径](#9-迁移与实施路径)
|
||||||
|
- [10. 风险与决策点](#10-风险与决策点)
|
||||||
|
- [11. 结论与优先级](#11-结论与优先级)
|
||||||
|
- [附录 A 术语表](#附录-a-术语表)
|
||||||
|
- [附录 B 图表清单](#附录-b-图表清单)
|
||||||
|
- [附录 C 代码证据索引](#附录-c-代码证据索引)
|
||||||
|
- [附录 D 文档维护约定](#附录-d-文档维护约定)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 现状评估
|
||||||
|
|
||||||
|
本章只做定位与改造建议,不修改代码。表 1-1 是拆分设计所依据的代码与配置事实,表 1-2 是模块级归属判断。
|
||||||
|
|
||||||
|
### 1.1 现状事实基线
|
||||||
|
|
||||||
|
表 1-1 现状事实与拆分影响
|
||||||
|
|
||||||
|
| 事实 | 代码/配置证据 | 对拆分的影响 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 一套 jar 同时扮演“公寓端”和“中心端” | `JcglService` 注册人员时转发 `centerServerUrl + /yktgl/regist/addPersonInfo`;`JlGlService` 从 `centerServerUrl + /yktgl/jlgl/getMessageFromGy` 拉交路 | 平台与公寓的边界已存在,但靠同一套接口“自调自”,必须先切出接口契约 |
|
||||||
|
| 公寓身份靠请求 IP 推断 | `ZdwhService.getGyIdByIp` / `getUniqueGyByIp`,在 `JcglController`、6 个设备包、`ExcelExportController`、`LoginController` 等 25 处以上调用 | 目标架构下公寓身份应来自部署配置与认证上下文,IP 识别只作为兼容层 |
|
||||||
|
| 多公寓共用一套库 | `tl` / `sjt` / `dev` 共用 `10.32.209.76:54321/gygl`,仅 `prod` 独立 | 与“公寓本地数据本地存”直接冲突,是数据归属改造重点 |
|
||||||
|
| 交路匹配只处理一个公寓 | `matchCallDutyUnderLock` 仅处理 `baseConfig.gyid` | 一实例多公寓时其他公寓永不自动匹配,本身说明“计划与匹配应上收平台” |
|
||||||
|
| 叫乘执行与运安强绑定在同一进程 | `SynDataSchedule`(每 5 分钟抓取 → 写 `GY_SYN_JCXX` → 触发匹配)与 `WakeUpJob` 同进程 | 目标是平台下发计划、公寓只执行、结果上报 |
|
||||||
|
| 设备认证是全局共享口令 | `baseConfig.devicePassword` 在 6 个设备服务中被注入并原样下发心跳响应 | 公寓本地化后必须升级为一机一密/签名 |
|
||||||
|
| 设备指令一次性投递、无 ACK | `GY_SB_ZL` 取最新一条后置 `deleted=1`(`HeartBeatService`) | 弱网必丢指令,属公寓端必须解决的核心问题 |
|
||||||
|
| 餐饮直接改卡务余额 | `MealsService.updateMoney` → `JcglService.changeRemainder` + `JcglMapper.updateRemainder` | 餐饮归平台、账务在主账,二者必须走“记账接口”而非直接改余额 |
|
||||||
|
| WebSocket 是进程内实现 | `JcWebsocket` 用静态 `Map<sessionId, endpoint>`,`sendMessage(message, gyid)` 按 `username` 当 `gyid` 匹配 | 应用端与公寓端同进程可复用;但不能横向扩容,除非补广播 |
|
||||||
|
| 前端按部署硬编码公寓 | `public/config.js`:`apiRoot = window.location.host`、`gyid = localStorage.getItem('gyid') || 'TLXC'`,并注释各公寓 IP/端口 | 正好对应“一公寓一部署”,可演进为公寓端/应用端同源前端 |
|
||||||
|
| 值班能力集中在单页 | `views/JcXx.vue`(约 5294 行)承载盯控、入寓、换房、充值、人员、交路、设备状态、告警音、TTS | 应用端应以此页为骨架做角色化拆分,而非另起一套 |
|
||||||
|
| 构建基线不稳 | `pom.xml` 在 Boot 2.6.13 父工程下显式声明 `spring-boot-starter-web:3.5.4`、`spring-boot-starter-data-redis:3.3.1` | 拆分前必须先修复,否则新工程无法验证 |
|
||||||
|
| AMI 连接是单例且不重连 | `AsteriskAmiConfig` 在 `@Bean` 内 `login()`,失败仅打印;`AsteriskCallUtil.makeCall` 仅在 `IllegalStateException` 时补登一次 | 语音链路必须在公寓端闭环并具备连接自愈,不能靠重启容器恢复 |
|
||||||
|
| 会议桥硬编码单实例 | `"Conf-01"` 在 `AsteriskCallUtil`、`JcglController`、`WakeUpJob` 中硬编码 20 处以上;`isConferenceBusy` 以内存 `recordlist` + `core show channels concise` 判断 | 单会议桥是容量与串音约束,必须在设计层明确会议粒度 |
|
||||||
|
| 分机没有独立台账 | 分机只以 `GY_ROOMS.sip_account` 单列存在(`RoomEntity.sip_account`、`JcglRoomMapper` 可写),无注册状态、无中继、无绑定实体,`sip_status` 从未被写入 | 分机资源需独立建模,才具备增删改停用与状态跟踪能力 |
|
||||||
|
|
||||||
|
### 1.2 模块定位与目标归属
|
||||||
|
|
||||||
|
表 1-2 主要模块定位与目标归属
|
||||||
|
|
||||||
|
| 现状模块(包) | 实际职责 | 目标归属 | 主要问题 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `jcgl`(`JcglService`,约 4193 行) | 入寓/离寓、叫乘状态机、房间推荐与房态、补助计算、交路匹配、归档、设备指令、WebSocket 推送 | 拆三份:任务执行与状态机 → 公寓端;补助规则与账务 → 平台端;盯控与人工干预 → 应用端 | 上帝类,跨 6 个领域,任一改动影响全链路 |
|
||||||
|
| `jlgl` | 交路模板 CRUD、叫乘时刻、Excel 上传、从中心拉取 | 平台端(交路主数据)+ 公寓端只读快照 | 与 `centerServerUrl` 双向调用语义不清,真源不明确 |
|
||||||
|
| `regist` | 人员资料、照片、增删改 | 平台端(人员主数据)+ 公寓端缓存 | 注册链路绕过本地直写“中心”,失败会整体回滚用户操作 |
|
||||||
|
| `recharge` / `pay` / `vendPayDevice` | 现金充值、消费扣款、余额变动 | 账务主账 → 平台端;公寓端保留本地流水与离线可用缓存 | 余额以“改字段”方式落在公寓库,无流水约束、无对账 |
|
||||||
|
| `MealsOrdering` | 菜品、订单、后厨、送餐、结算 | 平台端(餐饮业务) | 直接调 `JcglService.changeRemainder` 改余额,跨端耦合最重 |
|
||||||
|
| `zdwh` | 公寓、房间、工种、节假日、餐补、IP→公寓 | 平台端(主数据)+ 公寓端本地缓存 | 房间是公寓资产却与平台主数据同库;IP 解析扩散全工程 |
|
||||||
|
| `syndata` / `ByxxResourceService` | 运安 SOAP 抓取、人员同步、财务汇总(`getApartmentPersonDataByGyCode/ByWorkNo/ByTime`、`synFinanceData`) | 平台端(运安接入 + 分发 + 汇总接收) | 部署在公寓实例内,每个公寓各自连运安并各自清空快照表 |
|
||||||
|
| `heartBeat` + 6 个 `*Device` 包 | 设备心跳、指令下发、设备档案 | 公寓端(设备网关) | 全局共享口令、指令一次性投递、无 ACK、无离线队列 |
|
||||||
|
| `quartz`(`WakeUpJob` / `SchedulerManager`)+ `AsteriskCallUtil` | 叫乘调度、AMI 会议桥、TTS、串口广播 | 公寓端 | 未配置持久化 JobStore(默认内存模式),重启只恢复未来任务;AMI/串口为本地资源,不能上收 |
|
||||||
|
| `schedule` | `JcSchedule`(漏叫提醒、超时离寓、归档)、`SynDataSchedule`(运安)、`LeaveSnapshotCleanupSchedule` | 混合:提醒/归档/清理 → 公寓端;运安抓取 → 平台端 | 一个包内混着“本地执行”与“平台接入”两类任务 |
|
||||||
|
| `websockets` | 5 个端点,按 `gyid` 推送刷新/人员/充值/订单 | 公寓端 + 应用端共用 | 进程内状态,无订阅者身份校验 |
|
||||||
|
| `display` | 登录、RBAC、菜单、日志 | 平台端(全局账号与审计基线)+ 公寓端用 RuoYi 自有 RBAC | 两套账号体系若不约定会出现“平台账号进不了公寓端、公寓账号看不到平台菜单” |
|
||||||
|
| `xxtj` / `excel` | 日报、月报、补助/充值/消费统计与导出 | 平台端(跨公寓报表);公寓端保留本公寓运行报表 | 当前跨表统计在公寓库内执行,数据分散后无法汇总 |
|
||||||
|
| `kcgl` | 库存、出入库、物料 | 独立边界(可留平台或独立系统) | 与叫乘主线弱相关,不应进入公寓端 |
|
||||||
|
| `test`、`/jcgl/yatest`、`/jcgl/driver/{id}` | 测试/演示入口 | 全部下线 | 生产暴露外部系统调用入口 |
|
||||||
|
|
||||||
|
### 1.3 与目标架构不一致的核心点
|
||||||
|
|
||||||
|
1. **“平台—公寓”未分层,只靠 `centerServerUrl` 字符串互调**。注册、交路两条链路都是“同一套 Controller 既当设备接口又当中心接口”,无版本、无契约、无重试与幂等。
|
||||||
|
2. **公寓身份靠 IP 推断且多公寓共享库**。这是“一实例多公寓”的妥协设计,直接阻碍“公寓本地数据本地存”。
|
||||||
|
3. **叫乘执行、设备接入、平台接入三者同进程**。平台不可达会拖累叫乘主链路,叫乘高峰也会挤占同步线程(`AsyncConfig` 核心 10 / 最大 200 / 队列 10,队列极小)。
|
||||||
|
4. **账务散落**。余额在公寓库被直接更新,餐饮、售货机、充值三条链路各自改余额,缺少统一流水与对账口径。
|
||||||
|
5. **设备通道不可靠**。一次性投递 + 全局口令 + 无 ACK,是弱网现场最典型故障源。
|
||||||
|
6. **状态机与视图耦合**。`ryzt` 由设备上报、Quartz、AMI 事件、人工操作共同写入,缺少单一写入口;应用端与公寓端同库后风险被放大。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 目标架构
|
||||||
|
|
||||||
|
### 2.1 逻辑架构
|
||||||
|
|
||||||
|
图 2-1 目标逻辑架构
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph PLAT["平台端(现有 yktgl 收敛演进)"]
|
||||||
|
P1["主数据服务:公寓/房间基线/人员/交路/时间规则/节假日/餐补"]
|
||||||
|
P2["计划服务:运安 SOAP 接入 + 乘务计划 + 任务生成"]
|
||||||
|
P3["账务服务:补助规则/余额主账/流水归集/对账"]
|
||||||
|
P4["餐饮服务:菜品/订单/后厨/结算"]
|
||||||
|
P5["权限与审计:账号/RBAC/操作审计/接口审计"]
|
||||||
|
P6["报表与监控:跨公寓统计/设备在线率/执行质量"]
|
||||||
|
P7["上报接收与对账中心:结果/流水/告警/水位"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph APT["公寓端(RuoYi 新建,一公寓一实例)"]
|
||||||
|
A1["设备网关:注册/心跳/指令/事件/离线队列"]
|
||||||
|
A2["叫乘执行引擎:Quartz + AMI + 串口广播 + TTS"]
|
||||||
|
A3["本地主数据缓存:人员/交路/房间/规则快照"]
|
||||||
|
A4["在寓与房态事实:入住/离寓/换房/保洁"]
|
||||||
|
A5["本地账务缓存 + 消费受理"]
|
||||||
|
A6["上报器:outbox + 幂等键 + 重试"]
|
||||||
|
A7["值班 API + WebSocket 推送"]
|
||||||
|
A8["本地运维:自检/日志/版本"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph DUTY["应用端(与公寓端同代码同库,同进程部署)"]
|
||||||
|
D1["叫乘盯控台:任务/报警/应答/临叫/停止"]
|
||||||
|
D2["房态与房间管理:选房/换房/停用/保洁"]
|
||||||
|
D3["人工干预与审核:充值确认/资料修正/备注"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph EXT["外部"]
|
||||||
|
E1["运安 SOAP"]
|
||||||
|
E2["现场设备"]
|
||||||
|
E3["Asterisk / 串口 / 话机"]
|
||||||
|
E4["中心汇总/财务"]
|
||||||
|
end
|
||||||
|
|
||||||
|
DUTY -->|同进程领域调用| APT
|
||||||
|
A2 --> E3
|
||||||
|
A1 --> E2
|
||||||
|
APT -->|下行拉取:主数据/计划/规则| PLAT
|
||||||
|
APT -->|上行推送:结果/流水/告警/水位| PLAT
|
||||||
|
PLAT --> E1
|
||||||
|
PLAT --> E4
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 部署拓扑
|
||||||
|
|
||||||
|
图 2-2 部署拓扑
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph Center["中心机房"]
|
||||||
|
LB["Nginx / 网关(TLS)"]
|
||||||
|
PF1["平台端实例 A"]
|
||||||
|
PF2["平台端实例 B"]
|
||||||
|
PDB[("平台主库")]
|
||||||
|
PRD[("Redis")]
|
||||||
|
POS[("对象存储:照片/抓拍/录音")]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Apt1["公寓 A 现场"]
|
||||||
|
N1["Nginx(公寓内网)"]
|
||||||
|
S1["公寓端+应用端同进程实例"]
|
||||||
|
DB1[("公寓本地库")]
|
||||||
|
RD1[("本地 Redis")]
|
||||||
|
AST1["Asterisk + 串口"]
|
||||||
|
DEV1["叫乘屏/签到机/房间屏/消费机/售货机"]
|
||||||
|
DUTY1["值班员浏览器"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Apt2["公寓 B 现场(同构)"]
|
||||||
|
S2["公寓端+应用端同进程实例"]
|
||||||
|
DB2[("公寓本地库")]
|
||||||
|
end
|
||||||
|
|
||||||
|
LB --- PF1
|
||||||
|
LB --- PF2
|
||||||
|
PF1 --- PDB
|
||||||
|
PF2 --- PDB
|
||||||
|
PF1 --- PRD
|
||||||
|
PF2 --- PRD
|
||||||
|
PF1 --- POS
|
||||||
|
|
||||||
|
N1 --- S1
|
||||||
|
S1 --- DB1
|
||||||
|
S1 --- RD1
|
||||||
|
S1 --- AST1
|
||||||
|
DEV1 --> N1
|
||||||
|
DUTY1 --> N1
|
||||||
|
S2 --- DB2
|
||||||
|
|
||||||
|
S1 -->|出站 HTTPS 443| LB
|
||||||
|
S2 -->|出站 HTTPS 443| LB
|
||||||
|
```
|
||||||
|
|
||||||
|
**拓扑要点**
|
||||||
|
|
||||||
|
1. 平台端不进公寓内网:所有跨端流量由公寓端主动出站发起,规避现场 NAT/防火墙,并让平台与设备链路彻底解耦。
|
||||||
|
2. 公寓端 = 部署单元 = 公寓隔离单元:一公寓一实例一库(或独立 schema),`gyid` 由部署参数固定。
|
||||||
|
3. 应用端不新增进程与库:值班员访问 `http://<公寓服务器>/duty`,与公寓端同 JVM、同库、同 Nginx。
|
||||||
|
4. 平台端可多实例;公寓端的 WebSocket 为进程内实现,因此公寓端须保持单实例(或先完成广播改造再扩容)。
|
||||||
|
|
||||||
|
### 2.3 三端调用关系与数据流
|
||||||
|
|
||||||
|
表 2-1 三端调用关系与数据流
|
||||||
|
|
||||||
|
| 调用方向 | 协议 | 触发方式 | 典型数据 |
|
||||||
|
| --- | --- | --- |-----------------------------|
|
||||||
|
| 应用端 → 公寓端 | 进程内 Service 调用 | 同步 | 人工干预、房态修改、审核动作 |
|
||||||
|
| 公寓端 → 平台端 | HTTPS 主动拉取 | 定时(如 5 分钟)+ 变更通知 | 主数据增量、乘务计划、规则版本 |
|
||||||
|
| 公寓端 → 平台端 | HTTPS 主动推送 | 近实时批量 + 重试 | 执行结果、账务流水、告警摘要、设备摘要、g'y'g水位 |
|
||||||
|
| 设备 → 公寓端 | 内网 HTTP(后续可评估 MQTT) | 心跳 + 事件 | 指令取走、业务上报 |
|
||||||
|
| 平台端 → 运安 | SOAP | 定时 | 乘务计划 |
|
||||||
|
| 平台端 → 中心/财务 | HTTPS | 定时/按需 | 财务汇总、跨公寓人员查询 |
|
||||||
|
| 平台端 → 公寓端 | 不允许直连 | — | 仅落“待下发配置版本”,由公寓端拉取 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 端职责边界
|
||||||
|
|
||||||
|
### 3.1 平台端
|
||||||
|
|
||||||
|
**负责**
|
||||||
|
|
||||||
|
- 公寓档案、房间基线(`gyid + room_no + 床位数`)、人员主数据与照片、交路模板与叫乘时刻、时间规则、节假日、餐补/补助标准。
|
||||||
|
- 运安计划的唯一入口(替代现状各公寓分别抓取),并将计划转换为叫乘任务/计划快照下发对应公寓。
|
||||||
|
- 账务主账:补助发放规则、余额主账、消费/充值/补助流水归集、跨端对账。
|
||||||
|
- 餐饮业务(菜品、订单、后厨、结算规则),但结算扣款必须经账务接口,不直接改公寓库余额。
|
||||||
|
- 账号、角色、权限、操作审计、跨公寓报表、设备在线率与执行质量监控、告警汇总。
|
||||||
|
- 接收各公寓执行结果与异常补偿请求,维护每公寓水位与对账结果。
|
||||||
|
|
||||||
|
**不负责**
|
||||||
|
|
||||||
|
- 不接入现场设备、不下发设备指令、不持有设备心跳流水。
|
||||||
|
- 不执行叫乘(不连 AMI、不控串口、不播 TTS)。
|
||||||
|
- 不直连公寓本地库,不做跨库 JOIN。
|
||||||
|
- 不承担房间实时房态(仅保留基线,实时占用以公寓端为准)。
|
||||||
|
|
||||||
|
### 3.2 公寓端
|
||||||
|
|
||||||
|
**负责**
|
||||||
|
|
||||||
|
- 本公寓设备接入:注册、认证、心跳、指令队列、事件受理、离线缓存。
|
||||||
|
- 本公寓叫乘执行全链路:任务创建、Quartz 调度、AMI 会议桥、TTS、串口广播、复叫/报警/停止、重启恢复与漏叫补偿。
|
||||||
|
- 在寓事实与房态(`GY_JCXX` 语义)、换房、退房、保洁、超时离寓报警。
|
||||||
|
- 本地主数据缓存与规则快照(人员照片、交路、时间规则、节假日),保证断网可叫乘。
|
||||||
|
- 本地账务流水与离线消费受理(缓存余额),向平台归集。
|
||||||
|
- 结果上报:执行结果、流水、告警摘要、设备摘要、归档摘要、水位。
|
||||||
|
|
||||||
|
**不负责**
|
||||||
|
|
||||||
|
- 不直连运安(运安仅由平台接入),不维护跨公寓人员全集。
|
||||||
|
- 不决定补助标准,不做跨公寓统计,不维护平台账号体系。
|
||||||
|
- 不制定园区级设备策略(策略由平台配置,执行在公寓)。
|
||||||
|
|
||||||
|
### 3.3 应用端(与公寓端同代码同库)
|
||||||
|
|
||||||
|
**负责**
|
||||||
|
|
||||||
|
- 叫乘盯控:任务列表、报警、应答确认、临时叫乘、房间/多房间喊话、停止叫乘、录音回放入口。
|
||||||
|
- 房间与房态:选房、换房、停用/恢复、保洁开始/结束、在寓人员查看。
|
||||||
|
- 人工干预与审核:充值确认、人员资料修正、交路人工指定与重置、备注与操作留痕。
|
||||||
|
|
||||||
|
**不负责**
|
||||||
|
|
||||||
|
- 不直接改设备指令表、不直接改叫乘任务表(必须经公寓端领域服务)。
|
||||||
|
- 不持有独立数据库,不引入第三套服务,不做独立鉴权中心。
|
||||||
|
- 不承担跨公寓查询(跨公寓看平台端)。
|
||||||
|
|
||||||
|
表 3-1 应用端与公寓端的逻辑分工
|
||||||
|
|
||||||
|
| 维度 | 公寓端(执行域) | 应用端(操作域) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 表归属 | 现有 `GY_JCXX`、`GY_SB*`、`GY_SYN_JCXX` 等执行与设备表(可加 `apt_*` 前缀新表) | 新增 `DUTY_*`:操作审计、人工干预记录、审核动作、备注、班次交接 |
|
||||||
|
| 写权限 | 仅执行引擎/设备网关写状态字段(`ryzt`、`jcsj_s`、`finish_jc` 等) | 仅通过状态机服务写,禁止直连 Mapper 修改状态字段 |
|
||||||
|
| 部署形态 | 同一 JVM 内的 `module-apartment` | 同一 JVM 内的 `module-duty`,依赖公寓端领域接口,禁止反向依赖 |
|
||||||
|
| 前端形态 | 同一前端工程的 `apt` 入口(设备/终端页) | 同一前端工程的 `duty` 入口(值班员页),按角色裁剪路由与菜单 |
|
||||||
|
| 鉴权 | 设备用设备凭据;值班员用本地 RuoYi 账号 | 复用公寓端 RuoYi 账号 + 数据范围锁定 `gyid` |
|
||||||
|
|
||||||
|
**公寓隔离方式**
|
||||||
|
|
||||||
|
1. 部署期固定 `apartment.gyId`,服务启动即校验;`gyid` 不再从请求 IP 推断,`getGyIdByIp` 降级为旧设备兼容兜底并打告警。
|
||||||
|
2. 库级隔离:一公寓一 schema/库 + 独立连接账号,账号仅对本库有 DML 权限,对平台库无任何权限。
|
||||||
|
3. 请求级隔离:值班员登录后 `gyid` 写入会话与令牌声明,服务层用拦截器强制注入,业务 SQL 一律带 `gyid` 条件。
|
||||||
|
4. 设备级隔离:设备注册时绑定 `gyid + deviceCode`,跨公寓 `deviceCode` 直接拒绝。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 领域与模块划分
|
||||||
|
|
||||||
|
### 4.1 能力归属
|
||||||
|
|
||||||
|
表 4-1 能力归属决策表(● 主责 ○ 参与/缓存 — 不参与)
|
||||||
|
|
||||||
|
| 能力 | 平台端 | 公寓端 | 应用端 | 协同说明 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 公寓/房间基线 | ● | ○ 缓存 | — | 房间物理属性(楼层/朝向/SIP/床位数)由公寓维护后上报,平台存基线 |
|
||||||
|
| 人员主数据/照片 | ● | ○ 缓存 | — | 平台是全量真源,公寓增量缓存 + 照片版本 |
|
||||||
|
| 交路模板/叫乘时刻 | ● | ○ 快照 | — | 公寓可上报“现场临时交路”,平台确认后版本化 |
|
||||||
|
| 时间规则/节假日/餐补 | ● | ○ 快照 | — | 按 `gyid` 差异化,必须版本化下发 |
|
||||||
|
| 运安计划接入 | ● | — | — | 公寓端不再持有 WSDL |
|
||||||
|
| 任务生成(计划→叫乘时刻) | ● | ○ 复算校验 | — | 平台给“计划 + 规则版本”,公寓端本地复算并回执 |
|
||||||
|
| 叫乘任务执行 | — | ● | — | Quartz/AMI/串口/TTS 全在公寓端 |
|
||||||
|
| 叫乘状态机 | — | ● | ○ 触发 | 唯一写入口在公寓端,应用端只发命令 |
|
||||||
|
| 入寓/离寓/换房/房态 | — | ● | ○ 操作 | 应用端发起,公寓端校验与落库 |
|
||||||
|
| 设备接入/指令/心跳 | — | ● | ○ 查看 | 应用端仅查询与触发“刷新”类指令 |
|
||||||
|
| 补助规则与发放 | ● | ○ 试用缓存 | — | 规则在平台,入住时由公寓端触发发放并上报 |
|
||||||
|
| 余额主账 | ● | ○ 缓存 | — | 公寓端本地记账 + 平台归集,日对账 |
|
||||||
|
| 消费受理(消费机/售货机) | — | ● | — | 现场必须离线可用 |
|
||||||
|
| 餐饮订单/后厨 | ● | ○ 代理 | ○ 视图 | 公寓端只做终端接入与转发,业务在平台 |
|
||||||
|
| 报警与告警 | ○ 汇总 | ● 判定 | ● 展示 | 判定阈值在公寓端,摘要上报平台 |
|
||||||
|
| 归档 | — | ● | — | 公寓本地归档 + 归档摘要上报 |
|
||||||
|
| 统计报表 | ○ 跨公寓 | ● 本公寓 | ● 查看 | 公寓端出运行报表,平台出跨公寓报表 |
|
||||||
|
| 账号/RBAC/审计 | ● 平台侧 | ● 本地侧 | ● 复用公寓侧 | 两套 RBAC 通过“人员—账号映射”打通,不合并表 |
|
||||||
|
| 库存 `kcgl` | 独立 | — | — | 不进入公寓端,避免污染现场部署 |
|
||||||
|
|
||||||
|
### 4.2 平台端模块清单
|
||||||
|
|
||||||
|
表 4-2 平台端模块清单
|
||||||
|
|
||||||
|
| 模块 | 职责 | 现状来源 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `platform.master` | 公寓、房间基线、工种、时间规则、节假日、餐补标准 | `zdwh` |
|
||||||
|
| `platform.person` | 人员主数据、照片、增量分发 | `regist` + `syndata` 人员部分 |
|
||||||
|
| `platform.route` | 交路模板、叫乘时刻、停运调整、Excel 上传 | `jlgl` |
|
||||||
|
| `platform.plan` | 运安 SOAP 接入、计划快照、任务生成与下发 | `ByxxResourceService` + `SynDataSchedule` |
|
||||||
|
| `platform.ledger` | 补助规则、余额主账、流水归集、对账 | `recharge` / `pay` 账务部分 |
|
||||||
|
| `platform.catering` | 菜品、订单、后厨、结算 | `MealsOrdering` |
|
||||||
|
| `platform.report` | 跨公寓报表、导出、执行质量 | `xxtj` + `excel` |
|
||||||
|
| `platform.ingest` | 上报接收、幂等、水位、重放、对账(新增) | 新增 |
|
||||||
|
| `platform.iam` | 账号、角色、权限、审计 | `display` |
|
||||||
|
| `platform.ops` | 公寓注册、版本、健康度、配置下发版本(新增) | 新增 |
|
||||||
|
|
||||||
|
### 4.3 公寓端模块清单
|
||||||
|
|
||||||
|
表 4-3 公寓端模块清单
|
||||||
|
|
||||||
|
| 模块 | 职责 | 现状来源 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `apt.device.gateway` | 统一设备入口:注册/认证/心跳/指令/事件 | 收敛 6 个 `*Device` 包 |
|
||||||
|
| `apt.device.command` | 指令队列:下发—ACK—重投—过期 | 替代 `GY_SB_ZL` 一次性投递 |
|
||||||
|
| `apt.device.catalog` | 设备档案、在线率、版本 | `heartBeat` |
|
||||||
|
| `apt.duty.engine` | 叫乘执行:Quartz、AMI、TTS、串口、复叫/报警/停止 | `quartz` + `AsteriskCallUtil` |
|
||||||
|
| `apt.duty.state` | 状态机唯一写入口(`ryzt`/`finish_jc`/`finish_ly`/`stoped`) | 从 `JcglService` 抽取 |
|
||||||
|
| `apt.stay` | 入住、离寓、换房、在寓事实、房态重算 | 从 `JcglService` 抽取 |
|
||||||
|
| `apt.room` | 房间本地属性、推荐、停用、保洁 | `zdwh` 房间部分 + `clean` |
|
||||||
|
| `apt.ledger.local` | 本地余额缓存、离线消费、流水生成 | `pay` / `recharge` 本地部分 |
|
||||||
|
| `apt.report.outbox` | 上报 outbox、幂等键、重试、水位(新增) | 新增 |
|
||||||
|
| `apt.master.cache` | 主数据快照与版本校验 | `zdwh` 缓存部分 |
|
||||||
|
| `apt.duty.view` | 应用端后端 API、WebSocket 推送、人工干预命令 | 从 `JcglController` 拆出 |
|
||||||
|
| `apt.ops` | 自检、时钟偏差、磁盘(抓拍/录音)、日志、版本 | 新增 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 数据架构
|
||||||
|
|
||||||
|
### 5.1 数据分层与归属
|
||||||
|
|
||||||
|
表 5-1 数据分层、归属与同步方向
|
||||||
|
|
||||||
|
| 数据层 | 典型数据 | 归属 | 存储位置 | 同步方向 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 平台主数据 | 公寓、房间基线、人员、照片、交路、时间规则、节假日、餐补标准 | 平台 | 平台主库 + 对象存储 | 下行:平台 → 公寓(版本化增量) |
|
||||||
|
| 平台计划数据 | 运安计划快照、生成的叫乘任务/时刻、变更与取消 | 平台 | 平台主库 | 下行:平台 → 公寓 |
|
||||||
|
| 公寓执行数据 | `GY_JCXX`(在寓/叫乘事实)、`GYGL_LY_EVENT`、房态、保洁、报警 | 公寓 | 公寓本地库 | 本地强一致;摘要上行 |
|
||||||
|
| 设备数据 | `GY_SB`、`GY_SB_XT`、指令队列、心跳 | 公寓 | 公寓本地库 | 仅上行摘要(在线率/版本/故障) |
|
||||||
|
| 账务数据 | 补助明细、消费/充值流水、余额 | 主账平台 / 流水双记 | 平台主库 + 公寓本地缓存 | 流水上行;对账后余额快照下行 |
|
||||||
|
| 归档数据 | `GY_JCXX_HIS`、离寓事件历史 | 公寓 | 公寓本地库 | 上行归档摘要 |
|
||||||
|
| 账号与审计 | 账号、角色、权限、操作审计 | 平台(平台侧)/ 公寓(本地侧) | 各自库 | 人员—账号映射下行 |
|
||||||
|
| 汇总与报表 | 跨公寓统计、财务汇总 | 平台 | 平台主库/数仓 | 由上行数据加工 |
|
||||||
|
|
||||||
|
### 5.2 一致性策略
|
||||||
|
|
||||||
|
表 5-2 各场景一致性策略
|
||||||
|
|
||||||
|
| 场景 | 策略 |
|
||||||
|
| --- | --- |
|
||||||
|
| 公寓内业务(入住、离寓、房态、叫乘状态) | 强一致:单库本地事务 + 状态机唯一入口 |
|
||||||
|
| 主数据/规则下发 | 最终一致 + 版本号:公寓端保存 `masterVersion`,版本不一致时拒绝接收任务并触发全量重拉 |
|
||||||
|
| 执行结果上报 | 最终一致 + 至少一次 + 幂等:outbox 表 + `idempotencyKey`,平台按 `(gyid, bizType, bizId, bizVersion)` 去重 |
|
||||||
|
| 账务 | 本地记账为准的最终一致:本地先落流水(离线可用),平台归集后按日对账,差异进入人工处理队列 |
|
||||||
|
| 余额 | 平台主账权威;公寓端缓存带“版本 + 最后对账日期”,超期未对账时限制高额操作(如大额充值与退款) |
|
||||||
|
| 任务下发与执行 | 平台下发“计划 + 规则版本”,公寓端复算并回执 `taskAck`;不一致以平台为准并告警 |
|
||||||
|
|
||||||
|
### 5.3 同库边界防混乱
|
||||||
|
|
||||||
|
1. **表归属清单(Ownership Matrix)**:每张表标注 `owner=platform|apartment|duty`、允许的写入模块、是否为上报源;越权写入纳入 Code Review 检查项。
|
||||||
|
2. **命名分区**:执行域沿用 `GY_*`(避免大规模迁移),应用域新增 `DUTY_*`(操作审计、人工干预、审核、交接班);报表/只读视图统一 `V_*`,禁止跨域直写。
|
||||||
|
3. **模块依赖单向**:`module-duty → module-apartment → module-platform-client`,禁止反向依赖;用 Maven 模块或架构约束测试固定。
|
||||||
|
4. **禁止跨端 SQL 关联**:不在公寓库写“需要平台数据才能算”的统计 SQL,一律先落到本地快照。
|
||||||
|
5. **`gyid` 强制注入**:拦截器统一注入并校验,任何 SQL 缺 `gyid` 视为缺陷;新代码统一走上下文,不再逐处解析 IP。
|
||||||
|
6. **状态字段单写入口**:`ryzt`、`finish_jc`、`finish_ly`、`stoped` 仅允许 `apt.duty.state` 写入,设备上报、Quartz、AMI 事件、人工操作统一转为状态机命令。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 接口与集成
|
||||||
|
|
||||||
|
### 6.1 跨端接口清单
|
||||||
|
|
||||||
|
表 6-1 平台端与公寓端关键接口
|
||||||
|
|
||||||
|
| # | 方向 | 接口 | 用途 | 关键字段 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | 下行 | `GET /platform/v1/master/apartments/{gyId}` | 公寓档案与能力开关 | `gyId`、`name`、`features[]`、`version` |
|
||||||
|
| 2 | 下行 | `GET /platform/v1/master/persons?gyId&cursor&version` | 人员增量(含照片版本) | `ryid`、`cardId`、`deptId`、`photoVersion`、`deleted` |
|
||||||
|
| 3 | 下行 | `GET /platform/v1/master/routes?gyId&from&to` | 交路模板与叫乘时刻 | `jlid`、`cc`、`kcsj`、`jcsj`、`lysj` |
|
||||||
|
| 4 | 下行 | `GET /platform/v1/master/rules?gyId` | 时间规则/节假日/餐补标准 | `zjjcsjgz`、`kjjcsjgz`、`lysjgz`、`holidays[]` |
|
||||||
|
| 5 | 下行 | `GET /platform/v1/master/rooms?gyId&version` | 房间基线(取决于决策点 D3) | `roomNo`、`bedNumbers` |
|
||||||
|
| 6 | 下行 | `GET /platform/v1/plans/duty?gyId&from&to` | 乘务计划(替代本地抓运安) | `planId`、`workno`、`trainNo`、`depTime`、`pickupMode` |
|
||||||
|
| 7 | 下行 | `GET /platform/v1/tasks/changes?gyId&cursor` | 任务变更/取消增量 | `taskId`、`op=UPSERT/CANCEL`、`version` |
|
||||||
|
| 8 | 上行 | `POST /platform/v1/ack/tasks` | 任务接收回执(含复算结果) | `taskId`、`accepted`、`computedCallTime`、`ruleVersion` |
|
||||||
|
| 9 | 上行 | `POST /platform/v1/report/duty-results` | 叫乘/入寓/离寓执行结果(批量) | `events[]`:`eventId`、`type`、`jcid`、`ryid`、`occurredAt`、`status` |
|
||||||
|
| 10 | 上行 | `POST /platform/v1/report/ledger` | 账务流水(消费/充值/补助) | `flowId`、`type`、`ryid`、`amount`、`balanceAfter`、`deviceCode` |
|
||||||
|
| 11 | 上行 | `POST /platform/v1/report/device-status` | 设备在线率/版本/故障摘要 | `onlineCount`、`offlineList[]`、`versions{}` |
|
||||||
|
| 12 | 上行 | `POST /platform/v1/report/alarms` | 叫乘/离寓报警摘要 | `alarmId`、`type`、`jcid`、`level` |
|
||||||
|
| 13 | 上行 | `POST /platform/v1/report/archive` | 归档摘要与数据量 | `period`、`archivedCount`、`from`、`to` |
|
||||||
|
| 14 | 上行 | `POST /platform/v1/heartbeat` | 公寓端存活、版本、水位、时钟偏差 | `gyId`、`appVersion`、`outboxWatermark`、`clockSkewMs` |
|
||||||
|
| 15 | 查询 | `GET /platform/v1/status/{gyId}` | 平台侧查看公寓健康度与积压 | `lastReportAt`、`pending`、`failed` |
|
||||||
|
| 16 | 补偿 | `POST /platform/v1/reconcile/run?gyId&date` | 触发日对账 | 返回差异清单 |
|
||||||
|
| 17 | 补偿 | `POST /platform/v1/replay` | 指定幂等键/区间重放 | `gyId`、`bizType`、`from`、`to` |
|
||||||
|
|
||||||
|
现状对应关系:`getApartmentPersonDataByGyCode` / `ByWorkNo` / `ByTime`、`synFinanceData` 是“中心被查询”的雏形;`/yktgl/regist/addPersonInfo`、`/yktgl/jlgl/getMessageFromGy` 是“中心被调用”的雏形。新接口应保留旧路径的兼容适配层,不直接改旧签名。
|
||||||
|
|
||||||
|
### 6.2 上报协议
|
||||||
|
|
||||||
|
**信封结构(所有上行接口统一)**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"gyId": "TLXC",
|
||||||
|
"appVersion": "1.0.0",
|
||||||
|
"batchId": "uuid",
|
||||||
|
"sentAt": "2026-11-07T10:00:00+08:00",
|
||||||
|
"watermark": 102345,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"idempotencyKey": "hash(gyId+bizType+bizId+bizVersion)",
|
||||||
|
"bizType": "DUTY_RESULT",
|
||||||
|
"bizId": "JC20261107001",
|
||||||
|
"bizVersion": 3,
|
||||||
|
"occurredAt": "2026-11-07T09:58:12+08:00",
|
||||||
|
"receivedAt": "2026-11-07T09:58:13+08:00",
|
||||||
|
"payload": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
协议要点:
|
||||||
|
|
||||||
|
1. `occurredAt`(现场发生时间)、`receivedAt`(公寓端入库时间)、`serverReceivedAt`(平台接收时间)三时间戳并存,用于处理时钟差异与迟到数据。
|
||||||
|
2. `idempotencyKey = hash(gyId + bizType + bizId + bizVersion)`:同一业务对象同一版本只生效一次;版本递增用于“更正上报”。
|
||||||
|
3. `watermark`:公寓端本地自增序号,平台据此判断漏报/乱序并作为对账水位;现状 `GY_SYN_JCXX_STATUS`(0/1)可作为该思路的历史参照。
|
||||||
|
4. 批量上限建议单批 ≤ 500 条、≤ 1MB,失败按条回报,避免整批重传。
|
||||||
|
|
||||||
|
### 6.3 幂等、重试、对账与失败处理
|
||||||
|
|
||||||
|
表 6-2 跨端可靠性机制
|
||||||
|
|
||||||
|
| 机制 | 设计 |
|
||||||
|
| --- | --- |
|
||||||
|
| 幂等 | 平台侧 `(gyid, biz_type, biz_id, biz_version)` 唯一约束;重复请求返回“已处理 + 原结果” |
|
||||||
|
| 重试 | 指数退避(1s / 5s / 30s / 2min / 10min,上限 1 小时)+ 抖动;连续失败进入死信队列并触发公寓端告警 |
|
||||||
|
| 顺序 | 同一 `bizId` 按 `bizVersion` 单调;乱序到达丢弃旧版本并记录 |
|
||||||
|
| 对账 | 按日比对 `count`、`sum(amount)`、`max(watermark)` 三维;差异输出至“待人工处理”并可触发重放 |
|
||||||
|
| 补偿 | 平台支持“按区间重放”,公寓端支持“按 outbox 序号重发”,双侧均可主动发起 |
|
||||||
|
| 断网 | outbox 落本地库(非内存),断网期间持续累积,恢复后按水位续传 |
|
||||||
|
| 平台不可用 | 不影响叫乘:下行使用本地快照(带版本与有效期),过期后仅降级“新计划不生效”并告警 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 设备接入方案
|
||||||
|
|
||||||
|
### 7.1 接入形态
|
||||||
|
|
||||||
|
1. 统一网关入口 `/apt/dev/{deviceType}/register|heartbeat|event|command/ack`,把现有 6 个 `*Device` 包的重复协议收敛为“网关 + 类型插件”(叫乘屏、签到机、房间屏、消费机、注册机、售货机)。
|
||||||
|
2. 设备只连本公寓服务器,内网优先;公寓端不暴露公网入口。
|
||||||
|
3. 协议保持现有 JSON 字段以兼容存量固件;新增字段一律可选并给默认值。
|
||||||
|
|
||||||
|
### 7.2 设备认证
|
||||||
|
|
||||||
|
表 7-1 设备认证阶段设计
|
||||||
|
|
||||||
|
| 阶段 | 机制 |
|
||||||
|
| --- | --- |
|
||||||
|
| 注册 | `deviceCode + 公寓激活码` 首次绑定 `gyid`,生成一机一密(替换现状全局 `baseConfig.devicePassword`) |
|
||||||
|
| 心跳 | `deviceCode + 时间戳 + nonce + HMAC(secret, body)`;校验时间窗(±5 分钟)与 nonce 去重,防重放 |
|
||||||
|
| 越权 | `deviceCode` 与 `gyid`/房间不匹配直接拒绝并告警(现状仅校验存在性) |
|
||||||
|
| 轮换 | 密钥支持在线轮换,旧密钥保留一个过渡期 |
|
||||||
|
| 过渡 | 存量设备保留“口令模式”开关,按公寓逐步切换为签名模式 |
|
||||||
|
|
||||||
|
### 7.3 心跳、指令与状态采集
|
||||||
|
|
||||||
|
表 7-2 心跳、指令与状态采集
|
||||||
|
|
||||||
|
| 能力 | 设计 |
|
||||||
|
| --- | --- |
|
||||||
|
| 心跳 | 设备上报版本、IP、房间号、配置版本;服务端返回 `serverTime`(校时)、`apartmentName`、`configVersion`、待执行指令列表 |
|
||||||
|
| 指令 | 下发—确认—重投:指令带 `commandId + seq + expireAt`,取走后置 `DELIVERED`,设备 ACK 后置 `DONE`;超时未 ACK 自动重投(上限 N 次),过期作废并告警(替代 `deleted=1` 一次性投递) |
|
||||||
|
| 状态采集 | 设备上报在线/离线、软件版本、故障码、当前展示状态;公寓端按小时聚合,仅上报摘要 |
|
||||||
|
| 优先级 | `P0` 叫乘相关(重投 5 次、不过期)、`P1` 房态刷新、`P2` 版本升级(可延后) |
|
||||||
|
| 离线 | 设备离线超阈值产生“设备离线”告警,进入应用端盯控列表 |
|
||||||
|
|
||||||
|
### 7.4 告警处理
|
||||||
|
|
||||||
|
1. 判定在公寓端:叫乘未应答、复叫未应答、叫乘结束未应答、超时未离寓、设备离线、AMI 不可用、串口异常、上报积压。
|
||||||
|
2. 两级输出:本地即时告警(应用端弹窗/声响/TTS,走本地 WebSocket)与平台摘要上报(数量、类型、最近发生时间,不逐条上报)。
|
||||||
|
3. 现有 `GYGL_JGXX` 与 `is_jcbj` / `is_lybj` 语义保留,作为本地告警事实表。
|
||||||
|
|
||||||
|
### 7.5 本地数据缓存
|
||||||
|
|
||||||
|
1. 主数据缓存:人员(含照片)、交路、时间规则、节假日、房间属性,带 `version + validUntil`,过期只提示不阻断。
|
||||||
|
2. 指令缓存:可靠队列(本地库表 + 状态机)。
|
||||||
|
3. 事件缓存:设备事件先落本地(`deviceCode + deviceEventId` 幂等,沿用 `GYGL_LY_EVENT` 设计),再异步上报。
|
||||||
|
4. 媒体缓存:离寓抓拍、录音本地保存 + 生命周期清理(沿用 `leaveSnapshot.retentionDays` / `cleanupCron`),平台只存索引并按需回捞。
|
||||||
|
|
||||||
|
### 7.6 上报边界
|
||||||
|
|
||||||
|
表 7-3 设备域数据上报与不上报
|
||||||
|
|
||||||
|
| 上报平台 | 不上报平台 |
|
||||||
|
| --- | --- |
|
||||||
|
| 设备清单与在线率摘要、版本分布、故障事件 | 原始心跳流水、每次指令明细 |
|
||||||
|
| 叫乘/复叫/应答/离寓执行结果(业务事件) | AMI 通道事件、TTS 文本、串口字节流 |
|
||||||
|
| 报警摘要(类型、数量、时间) | 每条报警的完整现场上下文 |
|
||||||
|
| 账务流水 | 余额中间态、实时读余额请求 |
|
||||||
|
| 归档摘要与对账水位 | 全量历史明细(按需回捞) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 部署与运行
|
||||||
|
|
||||||
|
### 8.1 部署建议
|
||||||
|
|
||||||
|
表 8-1 三端部署形态
|
||||||
|
|
||||||
|
| 端 | 形态 | 规模建议 | 关键依赖 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 平台端 | 无状态双实例 + Nginx + 平台主库(Kingbase/Oracle)+ Redis + 对象存储 | 2 实例起步;对外仅暴露 443 | 运安 WSDL、中心/财务系统 |
|
||||||
|
| 公寓端 + 应用端 | 单实例同进程,Nginx 前置,本地库 + 本地 Redis + Asterisk + 串口 | 1 公寓 1 实例;不允许水平扩容(WebSocket 进程内) | 本地设备、AMI、串口、磁盘 |
|
||||||
|
| 前端 | 同一工程双入口:`/apt`(终端)、`/duty`(值班) | 与公寓端同域部署,沿用 `config.js` 的 `apiRoot = host` 思路 | — |
|
||||||
|
|
||||||
|
隔离与网络:
|
||||||
|
|
||||||
|
1. 一公寓一实例一库,Nginx 按公寓内网域名/端口区分;平台端不配置到公寓的路由。
|
||||||
|
2. 跨端仅允许公寓 → 平台出站 HTTPS;平台侧以 `gyId` + 客户端证书/令牌双向认证。
|
||||||
|
3. 反向代理必须透传真实 IP(兼容层仍需),并提前把 `gyid` 落到会话,逐步降低对 IP 的依赖。
|
||||||
|
|
||||||
|
### 8.2 非功能要求
|
||||||
|
|
||||||
|
表 8-2 非功能要求与实现要点
|
||||||
|
|
||||||
|
| 项 | 要求与做法 |
|
||||||
|
| --- | --- |
|
||||||
|
| 多公寓隔离 | 部署单元隔离 + 库隔离 + 设备绑定隔离 + 会话 `gyid` 强制注入;平台侧查询强制 `gyId` 参数并做权限校验 |
|
||||||
|
| 网络中断/弱网 | 叫乘主链路 100% 本地闭环(任务、AMI、设备、房态);下行快照带有效期;上行走 outbox 断点续传;补齐统一超时与熔断(现状 `HttpRequest` 无统一超时) |
|
||||||
|
| 重复上报 | 幂等键 + 版本号 + 平台唯一约束;重复请求返回原结果,不产生二次账务 |
|
||||||
|
| 时钟差异 | 全端 NTP;心跳下发 `serverTime`;三时间戳并存;账务日切以平台时间为准;偏差 > 5s 在应用端显式告警 |
|
||||||
|
| 安全认证 | 设备一机一密 + HMAC;值班员走本地 RuoYi 会话 + 权限点;平台—公寓 mTLS 或双向令牌;数据库/AMI/设备口令外置到环境变量或配置中心并轮换 |
|
||||||
|
| 审计日志 | 三类审计:值班员操作审计(`DUTY_*`)、设备指令审计(下发/确认/重投/过期)、跨端接口审计(请求/响应摘要 + 幂等键 + 结果);保留期与查询入口在应用端可查 |
|
||||||
|
| 可观测性 | 指标:叫乘任务创建数与执行成功率、AMI 连接状态、会议桥占用、设备在线率、指令积压、outbox 积压、上报失败率、对账差异数、平台接口 P99;日志统一 SLF4J 并以 `traceId` / `gyId` 贯穿;健康检查区分“可叫乘”与“可上报”两个探针 |
|
||||||
|
| 容量与降级 | 归档与抓拍清理置于低峰;平台不可用时公寓端进入“离线模式”并横幅提示;上报积压超阈值时降级为仅上报 `P0` 事件 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 迁移与实施路径
|
||||||
|
|
||||||
|
图 9-1 实施路径
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
S0["阶段零 基线修复"] --> S1["阶段一 现状梳理与边界确认"]
|
||||||
|
S1 --> S2["阶段二 接口契约与数据模型设计"]
|
||||||
|
S2 --> S3["阶段三 公寓端试点"]
|
||||||
|
S3 --> S4["阶段四 多公寓推广"]
|
||||||
|
S4 --> S5["阶段五 平台端收敛与旧逻辑下线"]
|
||||||
|
S3 -.并行.-> S0
|
||||||
|
```
|
||||||
|
|
||||||
|
表 9-1 阶段零:基线修复(前置)
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 建立可信的编译、测试、安全基线,使后续拆分可验证 |
|
||||||
|
| 主要产出 | 修复 `pom.xml` 依赖版本错配;CI(编译 + 单测 + 关键 SQL 校验);口令与内网地址外置并轮换;关闭测试接口;补仓库根 `.gitignore` |
|
||||||
|
| 验收标准 | 主干可稳定编译;测试可重复执行;仓库无明文口令 |
|
||||||
|
| 风险 | 版本修复可能暴露存量编译问题 → 单独分支验证,不与业务改动混提 |
|
||||||
|
|
||||||
|
表 9-2 阶段一:现状梳理与边界确认
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 锁定边界,不改业务逻辑 |
|
||||||
|
| 主要产出 | 表归属清单(每张 `GY_*` 表标注 owner 与写入模块);接口现状清单(`jcgl`/`jlgl`/`regist`/`syndata`/`heartBeat` 全量,标注设备用/值班用/中心用);`JcglService` 方法级职责地图(叫乘、房间、卡务、交路、归档五组);`gyid` 依赖点清单;待决策问题清单(见 10.2) |
|
||||||
|
| 验收标准 | 任一表能回答“谁写、谁读、跨不跨端”;任一接口能回答目标归属;无悬空模块 |
|
||||||
|
| 风险 | 业务方对“房间属谁、余额属谁”认知不一致 → 安排两轮评审并签字定稿 |
|
||||||
|
|
||||||
|
表 9-3 阶段二:接口契约与数据模型设计
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 把第 5、6 章固化为可评审契约 |
|
||||||
|
| 主要产出 | 17 个跨端接口契约(含错误码、幂等语义、限流);上报信封与 outbox 表设计;主数据版本与快照表设计;任务下发/回执模型;平台主账与公寓流水模型;旧接口兼容适配层方案 |
|
||||||
|
| 验收标准 | 契约评审通过;Mock 服务完成“下行 → 复算 → 上报 → 对账”全链路联调;幂等与重试用例通过(重复投递、乱序、断网续传三类) |
|
||||||
|
| 风险 | 契约反复变更 → 冻结版本号,变更走 v2 并保留 v1 至少两个公寓周期 |
|
||||||
|
|
||||||
|
表 9-4 阶段三:公寓端试点(1 个公寓)
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 单公寓端到端跑通,平台端仅提供主数据与计划 |
|
||||||
|
| 主要产出 | RuoYi 公寓端骨架 + 设备网关 + 叫乘执行引擎 + 状态机 + outbox;应用端盯控台(从 `JcXx.vue` 抽取核心能力,先做“看 + 干预”);本地库 schema 与数据迁移脚本(机场只读双跑) |
|
||||||
|
| 验收标准 | 断网 2 小时仍完成“入住 → 叫乘 → 复叫 → 报警 → 应答 → 离寓 → 归档”;恢复后 10 分钟内上报追平且对账零差异;叫乘准点率不低于现网;值班员操作步骤增加不超过 10% 且有记录 |
|
||||||
|
| 风险 | RuoYi 与现有前端体验差异大 → 试点期保留旧值班台只读并行对照;固件不支持 ACK → 网关做“尽力确认”降级 |
|
||||||
|
|
||||||
|
表 9-5 阶段四:多公寓推广
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 复制到 3–5 个公寓,验证隔离能力与运维成本 |
|
||||||
|
| 主要产出 | 标准化部署包与一键初始化脚本(库/schema/配置/证书);公寓注册与版本管理;监控大盘(在线率、上报积压、对账差异);运维手册与故障预案 |
|
||||||
|
| 验收标准 | 单公寓部署 ≤ 4 小时;公寓间零串数据(跨 `gyid` 越权用例 100% 拦截);平台端可查看各公寓健康度与差异清单 |
|
||||||
|
| 风险 | Oracle 存量公寓(`byq`/`cc`/`dl`/`pj`)SQL 兼容 → 试点避开或先做兼容层;网络质量差异 → 按公寓配置批量与重试参数 |
|
||||||
|
|
||||||
|
表 9-6 阶段五:平台端收敛与旧逻辑下线
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 目标 | 平台端成为唯一业务与主数据入口,公寓端剥离平台职责 |
|
||||||
|
| 主要产出 | `syndata` / `ByxxResourceService` / `SynDataSchedule` 从公寓端下线;`regist` 转发中心改为“本地写 + 上报”;`jlgl` 从中心拉取改为标准下行接口;`xxtj` / `excel` 跨公寓统计迁平台;`getGyIdByIp` 兼容层按公寓逐个关闭;`kcgl`、`test`、`yatest`、`driver/{id}` 明确处置 |
|
||||||
|
| 验收标准 | 公寓端不再连接运安与中心;平台端可独立出具跨公寓报表;旧接口调用量归零(按网关日志统计);回滚演练通过 |
|
||||||
|
| 风险 | 旧报表/旧终端仍依赖旧接口 → 提前一个周期盘点调用量,保留灰度通道 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 风险与决策点
|
||||||
|
|
||||||
|
### 10.1 风险清单
|
||||||
|
|
||||||
|
表 10-1 风险与应对
|
||||||
|
|
||||||
|
| 风险 | 表现 | 应对建议 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 职责边界不清 | 房间归属、余额归属、餐饮是否碰余额反复讨论 | 阶段一产出归属矩阵并签字;争议项默认“业务在平台、事实在公寓” |
|
||||||
|
| 数据不一致 | 平台余额与公寓缓存长期漂移;计划与任务时间不一致 | 日对账 + 水位 + 差异工单;规则版本化 + 公寓端复算回执 |
|
||||||
|
| 设备兼容 | 存量固件不支持签名/ACK;不同厂家协议差异 | 网关做协议适配层 + 能力协商(`capabilities`);保留口令模式开关;固件升级与网关改造解耦 |
|
||||||
|
| 双写/重复上报 | 迁移期新旧通道同时写;重试导致重复账务 | 迁移期用“影子上报”(只写不生效);幂等键 + 唯一约束兜底;账务类接口强制幂等 |
|
||||||
|
| 旧系统兼容 | 旧值班台、旧报表、旧终端依赖旧接口 | 网关级兼容层 + 调用量盘点 + 按公寓灰度下线 |
|
||||||
|
| 迁移回滚 | 新端上线后叫乘异常,需快速回退 | 数据只读双跑 → 按公寓粒度的切换开关 → 保留旧实例一个周期;回滚脚本与演练纳入验收 |
|
||||||
|
| 状态机多写 | 应用端与设备同时修改 `ryzt` 引发脏写 | 状态机唯一入口 + 条件更新(沿用 `triggerLeaveAlarmIfPending` 思路并推广) |
|
||||||
|
| 时钟/时区 | 叫乘精确到秒,偏差导致误叫/漏叫 | NTP 强约束 + `serverTime` 下发 + 偏差告警 + 三时间戳 |
|
||||||
|
| 单实例约束被忽视 | 公寓端为高可用随手扩容,导致 WebSocket/Quartz 重复执行 | 部署规范明确“公寓端单实例”;若必须扩容,先做推送广播 + Quartz 持久化 + 任务抢占 |
|
||||||
|
| 权限体系冲突 | 平台 `GL_*` 与 RuoYi `sys_*` 并存导致账号混乱 | 两套 RBAC 各自管理,用“人员—账号映射表”打通;值班员登录只走公寓端 |
|
||||||
|
| 构建基线不稳 | `pom.xml` 版本错配导致新工程无法编译验证 | 阶段零修复依赖并建立 CI,先于一切拆分动作 |
|
||||||
|
| 安全暴露 | 测试接口、明文口令、全局设备口令 | 生产关闭 `/test`、`/jcgl/yatest`、`/jcgl/driver/*`;口令外置轮换;设备改一机一密 |
|
||||||
|
|
||||||
|
### 10.2 待决策点
|
||||||
|
|
||||||
|
表 10-2 待决策点与建议
|
||||||
|
|
||||||
|
| # | 决策点 | 建议 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| D1 | 餐饮归属 | 业务平台化;扣款走账务接口,禁止公寓端直接改余额(当前 `MealsService` 直改余额必须改) |
|
||||||
|
| D2 | 余额主账位置 | 平台主账 + 公寓缓存;离线消费允许本地记账并上报 |
|
||||||
|
| D3 | 房间主数据归属 | 平台存基线(`gyid + roomNo + 床位数`),物理属性(楼层/朝向/SIP)公寓维护并上报 |
|
||||||
|
| D4 | 运安接入位置 | 只在平台端接入;公寓端不再持有 WSDL(同时解除“通辽南”硬编码的多公寓障碍) |
|
||||||
|
| D5 | 是否保留“一实例多公寓” | 目标架构下取消;存量多公寓共享库(`tl`/`sjt` 共用库)在阶段四拆分 |
|
||||||
|
| D6 | 应用端是否独立前端工程 | 与公寓端同一工程双入口,按角色裁剪路由与菜单 |
|
||||||
|
| D7 | 交路人工维护落点 | 平台维护模板,公寓可“应急新增”并上报确认 |
|
||||||
|
| D8 | 叫乘时间以谁为准 | 平台下发“计划 + 规则版本”,公寓端复算执行,不一致告警 |
|
||||||
|
| D9 | Oracle 存量公寓 | 明确保留期与迁移批次,避免新端并行维护两套 SQL |
|
||||||
|
| D10 | `kcgl` 库存边界 | 独立处置,不进入公寓端 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 结论与优先级
|
||||||
|
|
||||||
|
### 11.1 总体结论
|
||||||
|
|
||||||
|
1. 拆分方向可行,且现状已有雏形。`centerServerUrl` 的双向调用、`getApartmentPersonData*` / `synFinanceData`、`GY_SYN_JCXX_STATUS` 状态位,本质是“平台—公寓”关系未完成的形态;本次重构是把隐式关系显式化,而非推倒重建。
|
||||||
|
2. 最大障碍不是技术选型,而是三件事:公寓身份(IP 推断 → 部署绑定)、数据归属(共享库 → 库隔离)、状态写入口分散(多写 → 单一状态机)。
|
||||||
|
3. 公寓端用 RuoYi 新建是合理的。设备网关、执行引擎、上报器、值班 API 天然属于“管理后台 + 本地接入”形态,可复用 RBAC、定时任务、代码生成;但必须约定“RuoYi 管本地账号、平台管全局账号”,否则权限体系会打架。
|
||||||
|
4. 应用端不独立是正确的。值班员的全部操作都必须落在公寓本地事实库上,独立服务只会带来跨服务事务与延迟;同代码同库 + 模块边界 + 状态机单入口足以支撑。
|
||||||
|
5. 必须先做阶段零。`pom.xml` 依赖错配会让任何新工程无法建立可信基线,明文口令入库是安全红线;这两项不解决,拆分过程无法验收。
|
||||||
|
|
||||||
|
### 11.2 推荐落地顺序
|
||||||
|
|
||||||
|
表 11-1 优先级与落地顺序
|
||||||
|
|
||||||
|
| 优先级 | 事项 | 理由 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| P0-1 | 修复 `pom.xml` 版本错配;建立编译/单测/CI 基线 | 没有基线就没有“拆分正确性” |
|
||||||
|
| P0-2 | 口令与内网地址外置、轮换;关闭测试接口 | 安全红线,改造成本低 |
|
||||||
|
| P0-3 | 产出表归属矩阵 + 接口归属清单 + `JcglService` 职责地图 | 后续所有设计的输入 |
|
||||||
|
| P1-1 | 17 个跨端接口契约 + 上报信封 + outbox 模型 | 决定拆分能否落地 |
|
||||||
|
| P1-2 | 公寓端设备网关(一机一密 + 指令 ACK + 离线队列) | 现场稳定性收益最直接 |
|
||||||
|
| P1-3 | 叫乘状态机单一入口 + 应用端盯控台(基于 `JcXx.vue` 抽取) | 降低同库后脏写风险 |
|
||||||
|
| P2-1 | 账务:平台主账 + 公寓流水 + 日对账;餐饮改走账务接口 | 数据一致性风险最高的一环 |
|
||||||
|
| P2-2 | 运安接入上收平台,公寓端仅消费计划 | 解除多公寓匹配限制 |
|
||||||
|
| P2-3 | 单公寓试点 → 多公寓推广 → 旧逻辑下线与回滚演练 | 控制现场风险 |
|
||||||
|
|
||||||
|
### 11.3 后续动作
|
||||||
|
|
||||||
|
1. 以第 1、4、5 章为模板,产出《表归属矩阵》与《接口归属清单》两份工作底稿。
|
||||||
|
2. 以第 6 章为蓝本,先冻结 v1 契约(含错误码与幂等语义),再进入任何编码。
|
||||||
|
3. 以第 3.3 节为基础,明确“值班员可写字段白名单”,作为 Code Review 检查项。
|
||||||
|
4. 本文落盘后,在 `docs/README.md` 与 `docs/09-迭代指引与风险清单.md` 中建立索引。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附录 A 术语表
|
||||||
|
|
||||||
|
表 A-1 术语表
|
||||||
|
|
||||||
|
| 术语 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 平台端 | 提供主数据、运安计划、账务主账、餐饮、跨公寓报表与审计的中心服务 |
|
||||||
|
| 公寓端 | 部署在某公寓现场、负责设备接入与叫乘执行的本地服务(基于 RuoYi 新建) |
|
||||||
|
| 应用端 | 与公寓端同代码同库、面向值班员的盯控与操作界面,不是独立服务或独立库 |
|
||||||
|
| 执行域 / 操作域 | 同一库内的两类数据与模块:执行域由执行引擎与设备网关写;操作域记录人工干预与审核 |
|
||||||
|
| 水位(watermark) | 公寓端上报序号,用于判断漏报、乱序与对账进度 |
|
||||||
|
| 幂等键 | 同一业务对象同一版本仅生效一次的去重标识 |
|
||||||
|
| 快照版本 | 下行主数据/规则的版本号,公寓端据此判断是否过期 |
|
||||||
|
| 影子上报 | 迁移期只上报不生效的写入通道,用于验证新链路而不改变业务结果 |
|
||||||
|
|
||||||
|
## 附录 B 图表清单
|
||||||
|
|
||||||
|
表 B-1 图表索引
|
||||||
|
|
||||||
|
| 编号 | 名称 | 位置 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 表 0-1 | 文档信息 | 0 章 |
|
||||||
|
| 表 0-2 | 修订记录 | 0 章 |
|
||||||
|
| 表 1-1 | 现状事实与拆分影响 | 1.1 |
|
||||||
|
| 表 1-2 | 主要模块定位与目标归属 | 1.2 |
|
||||||
|
| 图 2-1 | 目标逻辑架构 | 2.1 |
|
||||||
|
| 图 2-2 | 部署拓扑 | 2.2 |
|
||||||
|
| 表 2-1 | 三端调用关系与数据流 | 2.3 |
|
||||||
|
| 表 3-1 | 应用端与公寓端的逻辑分工 | 3.3 |
|
||||||
|
| 表 4-1 | 能力归属决策表 | 4.1 |
|
||||||
|
| 表 4-2 | 平台端模块清单 | 4.2 |
|
||||||
|
| 表 4-3 | 公寓端模块清单 | 4.3 |
|
||||||
|
| 表 5-1 | 数据分层、归属与同步方向 | 5.1 |
|
||||||
|
| 表 5-2 | 各场景一致性策略 | 5.2 |
|
||||||
|
| 表 6-1 | 平台端与公寓端关键接口 | 6.1 |
|
||||||
|
| 表 6-2 | 跨端可靠性机制 | 6.3 |
|
||||||
|
| 表 7-1 | 设备认证阶段设计 | 7.2 |
|
||||||
|
| 表 7-2 | 心跳、指令与状态采集 | 7.3 |
|
||||||
|
| 表 7-3 | 设备域数据上报与不上报 | 7.6 |
|
||||||
|
| 表 8-1 | 三端部署形态 | 8.1 |
|
||||||
|
| 表 8-2 | 非功能要求与实现要点 | 8.2 |
|
||||||
|
| 图 9-1 | 实施路径 | 9 章 |
|
||||||
|
| 表 9-1 ~ 9-6 | 各阶段目标/产出/验收/风险 | 9 章 |
|
||||||
|
| 表 10-1 | 风险与应对 | 10.1 |
|
||||||
|
| 表 10-2 | 待决策点与建议 | 10.2 |
|
||||||
|
| 表 11-1 | 优先级与落地顺序 | 11.2 |
|
||||||
|
|
||||||
|
## 附录 C 代码证据索引
|
||||||
|
|
||||||
|
表 C-1 本文引用证据的代码位置
|
||||||
|
|
||||||
|
| 证据 | 位置 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 注册转发中心 | `jcgl/service/JcglService.java`(`centerServerUrl + /yktgl/regist/addPersonInfo`) | 证明平台/公寓同源、需切接口契约 |
|
||||||
|
| 交路从中心拉取 | `jlgl/service/JlGlService.java`(`getMessageFromGy`) | 证明已有下行雏形 |
|
||||||
|
| IP→公寓解析 | `zdwh/service/ZdwhService.java`(`getGyIdByIp` / `getUniqueGyByIp`) | 公寓身份改造对象 |
|
||||||
|
| 设备指令一次性投递 | `heartBeat/service/HeartBeatService.java` | 指令可靠性与 ACK 改造依据 |
|
||||||
|
| 设备全局口令 | 6 个 `*Device` 服务中的 `baseConfig.devicePassword` | 一机一密改造依据 |
|
||||||
|
| 叫乘调度 | `quartz/SchedulerManager.java`、`quartz/WakeUpJob.java`、`schedule/WakeupJobRecoveryRunner.java` | 公寓端执行引擎范围 |
|
||||||
|
| 定时任务混合 | `schedule/JcSchedule.java`、`schedule/SynDataSchedule.java` | 任务上收/下沉划分依据 |
|
||||||
|
| WebSocket 进程内实现 | `websockets/JcWebsocket.java` | 单实例约束与推送改造依据 |
|
||||||
|
| 餐饮改余额 | `MealsOrdering/service/MealsService.java`(`updateMoney`) | 餐饮与账务解耦依据 |
|
||||||
|
| 中心侧汇总接口 | `syndata/controller/SynPersonDataController.java`(`getApartmentPersonDataByGyCode` / `ByWorkNo` / `ByTime`、`synFinanceData`) | 平台化接口的现状参照 |
|
||||||
|
| 设备业务协议 | `callingDevice` / `checkInDevice` / `roomDevice` / `payDevice` / `registDevice` / `vendPayDevice` | 网关收敛范围 |
|
||||||
|
| 前端部署硬编码 | `YktVue/public/config.js`、`YktVue/vue.config.js` | 双入口前端与公寓绑定的依据 |
|
||||||
|
| 值班主页面 | `YktVue/src/views/JcXx.vue` | 应用端拆分骨架 |
|
||||||
|
| 构建依赖错配 | `yktgl/pom.xml` | 阶段零修复项 |
|
||||||
|
| 多公寓部署差异 | `yktgl/src/main/resources/application-*.yml` | 库隔离与 Profile 收敛依据 |
|
||||||
|
|
||||||
|
## 附录 D 文档维护约定
|
||||||
|
|
||||||
|
1. 本文为设计方案,实施过程中若与代码现状出现偏差,以代码为准并同步更新本文,不得反向以文档为借口修改既有约定。
|
||||||
|
2. 新增/调整端职责、模块划分、跨端接口时,同步更新第 3、4、6 章与附录 B 的图表清单。
|
||||||
|
3. 每个迁移阶段结束,在第 9 章对应阶段表下追加“实际完成情况”与偏差说明。
|
||||||
|
4. 决策点在 10.2 定稿后,从“待决策”移入正文对应章节,并保留决策时间与决策人。
|
||||||
|
|
||||||
@@ -0,0 +1,451 @@
|
|||||||
|
# 11 既有数据库结构分析(KingbaseES)
|
||||||
|
|
||||||
|
> 文档性质:现状实证分析(Analysis Only)。本文所有结论来自对 `db/gygl.sql` 的结构解析与对已导入实例的只读查询(全部为 `SELECT`),**不含**数据库变更、DDL 执行、配置修改。改造建议仅为设计输入,需评审后另行排期。
|
||||||
|
|
||||||
|
## 0. 文档说明
|
||||||
|
|
||||||
|
表 0-1 采集信息
|
||||||
|
|
||||||
|
| 项 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 数据来源 | `db/gygl.sql`(Navicat 导出,源库 `10.33.165.41:54321/gygl`,导出时间 2026-11-07 14:34) |
|
||||||
|
| 校验实例 | 本机 KingbaseES 导入库,`jdbc:kingbase8://127.0.0.1:54321/gygl` |
|
||||||
|
| 采集方式 | JDBC 只读查询(information_schema / pg_catalog / pg_stat_user_tables)+ dump 文本解析 |
|
||||||
|
| 库与 schema | 数据库 `gygl`,业务 schema `gygl`,表 owner 均为 `system` |
|
||||||
|
| 规模 | 40 张表、524 个字段、schema 总容量 117 MB、495,772 行数据 |
|
||||||
|
| 关联文档 | `05-数据模型.md`(表语义与状态码)、`09-迭代指引与风险清单.md`(技术债)、`10-架构优化方案-三端拆分.md`(目标归属) |
|
||||||
|
|
||||||
|
> 样本口径提醒:本机实例的数据是导出快照,业务数据只覆盖 2 个公寓(见 3.9)。行数、分布用于判断**结构缺陷**,不作为生产容量基线;容量测算需在生产库重跑附录 A 的 SQL。
|
||||||
|
|
||||||
|
## 1. 实例与库级特征
|
||||||
|
|
||||||
|
表 1-1 库级参数(实测)
|
||||||
|
|
||||||
|
| 参数 | 实测值 | 结构影响 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 版本 | `KingbaseES V009R001C010`(`server_version` 报 12.1) | 兼容 PG 12 协议;JDBC 9.0.0 驱动可直连 |
|
||||||
|
| 兼容模式 | `database_mode = oracle` | 出现 `sys.date`、`sys_guid()`、`sysdate()`、`dual` 表等 Oracle 兼容对象 |
|
||||||
|
| 空串语义 | `ora_input_emptystr_isnull = on` | **写入 `""` 存成 `NULL`**,读取恒为 `NULL`;见 3.4 |
|
||||||
|
| 字符集 | `UTF8` | 中文数据无乱码风险 |
|
||||||
|
| MAC 扩展 | schema `sysmac`(8 张表,248 kB) | 金仓安全版强制访问控制扩展;上线前需确认是否启用策略 |
|
||||||
|
| 对象种类 | 视图 0、触发器 0、函数 0、分区表 0 | **业务逻辑全部在 Java 侧**,库内无任何约束性逻辑 |
|
||||||
|
|
||||||
|
表 1-2 schema 分布
|
||||||
|
|
||||||
|
| schema | 表数 | 容量 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `gygl` | 40 | 117 MB | 全部业务表 |
|
||||||
|
| `sysmac` | 8 | 248 kB | 金仓安全版 MAC 元数据(空表) |
|
||||||
|
| `sys_hm` | 3 | 128 kB | 金仓自带 |
|
||||||
|
| `sys` | 1 | 40 kB | 金仓自带 |
|
||||||
|
|
||||||
|
结论:**这是一个"纯存储库"**——没有主键、没有索引、没有外键、没有触发器、没有存储过程。数据完整性、唯一性、顺序性、并发控制全部由应用代码承担,这也是下一章几乎所有缺陷的共同根因。
|
||||||
|
|
||||||
|
## 2. 表清单与规模
|
||||||
|
|
||||||
|
图 2-1 数据域与表簇
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[公寓主数据<br/>gy_jbxx / gy_gyzd / gy_sjgz / gy_jcsj / gy_jrb] --> B[房间<br/>gy_rooms]
|
||||||
|
B --> C[叫乘执行<br/>gy_jcxx / gy_jcxx_his<br/>gy_bjxx / gy_bjcstj]
|
||||||
|
D[交路同步<br/>gy_syn_jcxx / _his / _status] --> C
|
||||||
|
E[人员与卡<br/>gy_ykt_ry / gy_ykt_ry_zp] --> C
|
||||||
|
F[账务<br/>gy_ykt_remainder / _allowance / _consume / _btbj / _btjs] --> E
|
||||||
|
G[设备<br/>gy_sb / gy_device / gy_sb_xt / gy_sb_zl / _his] --> C
|
||||||
|
H[权限<br/>gl_yh / gl_js / gl_qx / gl_cd / gl_yh_js / gl_js_qx]
|
||||||
|
I[日志<br/>gy_logs / gy_operation_log]
|
||||||
|
```
|
||||||
|
|
||||||
|
表 2-1 业务表清单(按数据域)
|
||||||
|
|
||||||
|
| 表 | 行数 | 大小 | 列数 | 含 gyid | 现职责 |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| `gy_jbxx` | 9 | 16 kB | 26 | ✔ | 公寓基础信息(面积、床位、负责人、热水/燃气方式) |
|
||||||
|
| `gy_gyzd` | 37 | 16 kB | 8 | ✔ | 公寓字典(网关地址、机器号、IP) |
|
||||||
|
| `gy_gzzd` | 17 | 16 kB | 3 | — | 工种字典 + 客货类型 |
|
||||||
|
| `gy_sjgz` | 17 | 16 kB | 10 | ✔ | 时间规则(入住/离寓/叫乘基准) |
|
||||||
|
| `gy_jcsj` | 7 | 16 kB | 3 | — | 叫乘时刻表(`cb/kssj/jssj`,均为字符) |
|
||||||
|
| `gy_jrb` | 2 | 16 kB | 6 | — | 节假日 |
|
||||||
|
| `gy_rooms` | 197 | 64 kB | 22 | ✔ | 房间基线 + 房态 + 分机 + 报警起点(三类语义混装) |
|
||||||
|
| `gy_jcxx` | 3,541 | 1.5 MB | **70** | ✔ | 叫乘执行主表(上帝表,见 3.5) |
|
||||||
|
| `gy_jcxx_his` | 32,505 | 12 MB | **70** | ✔ | 叫乘归档表 |
|
||||||
|
| `gy_bjxx` | 2,490 | 304 kB | 7 | ✔ | 报警记录(开始/结束时间) |
|
||||||
|
| `gy_bjcstj` | 0 | 8 kB | 12 | — | 补叫统计(**未使用**) |
|
||||||
|
| `gy_jdqkhz` | 1 | 16 kB | 9 | ✔ | 房间年度/月度汇总(近似废表) |
|
||||||
|
| `gy_rtjb` | 0 | 8 kB | 7 | ✔ | 日报(**未使用**) |
|
||||||
|
| `gy_call_duty_match_lock` | 38 | 8 kB | 1 | ✔ | 单列行锁表,用 `gyid` 做悲观锁 |
|
||||||
|
| `gy_syn_jcxx` | 1,139 | 384 kB | 15 | — | 运安交路快照 |
|
||||||
|
| `gy_syn_jcxx_his` | 2,291 | 376 kB | 12 | — | 交路归档 |
|
||||||
|
| `gy_syn_jcxx_status` | 1 | 8 kB | 2 | — | 同步状态/水位(单行开关) |
|
||||||
|
| `gy_ykt_ry` | 1,349 | 336 kB | 27 | — | 人员与卡主数据 |
|
||||||
|
| `gy_ykt_ry_zp` | 100 | **27 MB** | 2 | — | 照片(BLOB 存库) |
|
||||||
|
| `gy_ykt_remainder` | 1,253 | 224 kB | 12 | — | 余额(补助/现金/消费/补助总额) |
|
||||||
|
| `gy_ykt_allowance` | 34,182 | 4.2 MB | 11 | ✔ | 补助发放流水 |
|
||||||
|
| `gy_ykt_consume` | 35 | 16 kB | 19 | ✔ | 消费流水 |
|
||||||
|
| `gy_ykt_btbj` | 5 | 16 kB | 8 | ✔ | 补助标准(早/正/节假日) |
|
||||||
|
| `gy_ykt_btjs` | 5 | 16 kB | 7 | — | 补助计算规则 |
|
||||||
|
| `gy_sb` | 148 | 48 kB | 8 | ✔ | 设备台账 v1(`devicecode/lx`) |
|
||||||
|
| `gy_device` | 92 | 48 kB | 18 | ✔ | 设备台账 v2(`device_code/device_type`,RuoYi 风格) |
|
||||||
|
| `gy_sb_xt` | 246 | 64 kB | 9 | ✔ | 设备心跳与版本状态 |
|
||||||
|
| `gy_sb_zl` | **129,665** | 11 MB | 6 | — | 设备指令队列(**与历史同表**) |
|
||||||
|
| `gy_sb_zl_his` | 0 | 8 kB | 6 | — | 指令历史(**从未使用**) |
|
||||||
|
| `gy_logs` | **285,914** | **56 MB** | 7 | ✔ | 运行日志(无清理策略) |
|
||||||
|
| `gy_operation_log` | 0 | 8 kB | 6 | — | 操作审计(**从未写入**) |
|
||||||
|
| `gy_file` | 1 | 16 kB | 6 | — | 文件登记 |
|
||||||
|
|
||||||
|
表 2-2 支撑表清单
|
||||||
|
|
||||||
|
| 表 | 行数 | 列数 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `gl_yh` / `gl_js` / `gl_qx` / `gl_cd` / `gl_yh_js` / `gl_js_qx` | 17 / 4 / 48 / 45 / 16 / 58 | 18 / 6 / 9 / 9 / 2 / 2 | 自研 RBAC(用户/角色/权限/菜单及关联) |
|
||||||
|
| `gen_table` / `gen_table_column` | 18 / 279 | 21 / 22 | **RuoYi 代码生成器元数据残留** |
|
||||||
|
|
||||||
|
容量结构:`gy_logs` 占 48%、`gy_ykt_ry_zp` 占 23%、`gy_jcxx_his` 占 10%、`gy_sb_zl` 占 9%——四张表吃掉全库 90%。其中两张(日志、指令)是纯追加、无清理的表。
|
||||||
|
|
||||||
|
## 3. 结构缺陷诊断
|
||||||
|
|
||||||
|
表 3-1 约束与索引现状(全库实测)
|
||||||
|
|
||||||
|
| 指标 | 数量 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 主键 | **0** | 40 张表无一有主键 |
|
||||||
|
| 唯一约束 | **0** | 唯一性完全依赖应用层判断 |
|
||||||
|
| 外键 | **0** | 关联完整性靠代码,无 DB 兜底 |
|
||||||
|
| 索引 | **0** | 含隐式主键索引在内,`pg_indexes` 计数为 0 |
|
||||||
|
| 序列 | 64 | 仅 4 个被列默认值引用,其余 60 个为**孤儿序列** |
|
||||||
|
| 表注释 | 3/40 | 仅 `gen_table`、`gen_table_column`、`gy_device` 有 |
|
||||||
|
| 列注释 | 60/524 | 其中仅 5 条属于业务表(`gy_jcxx` 3 条、`gy_syn_jcxx` 1 条、`gy_gzzd` 1 条) |
|
||||||
|
| 非空约束 | 5 处 | 仅 `gy_ykt_ry.ryid`、`gy_call_duty_match_lock.gyid`、`gy_syn_jcxx_status.id/sync_status`、`gy_device.device_code` |
|
||||||
|
|
||||||
|
### 3.1 无主键、无索引的连锁后果
|
||||||
|
|
||||||
|
1. **每次按 `devicecode` / `ryid` / `jcid` 查询都是全表扫描**。`gy_sb_zl` 12.9 万行、`gy_logs` 28.6 万行,心跳与指令链路是高频路径,随运行时间线性劣化。
|
||||||
|
2. **重复数据无法阻断**。实测 `gy_jcxx` 3,541 行中 `jcid` 只有 3,540 个不同值——已存在 1 组重复 `jcid`,且没有任何机制能阻止再次发生。
|
||||||
|
3. **更新语义不可靠**。`update ... where jcid=?` 命中多行时,MyBatis 返回的影响行数与业务预期不符,容易被误判为"成功"。
|
||||||
|
4. **分页与排序无稳定基准**。无主键导致同一秒内多行顺序不确定,翻页可能重复或漏行。
|
||||||
|
5. **归档与对账无法定位单行**。`gy_jcxx` → `gy_jcxx_his` 的搬迁只能按业务键或不带条件批量搬,出错后难以精确回滚。
|
||||||
|
|
||||||
|
### 3.2 类型体系混乱
|
||||||
|
|
||||||
|
表 3-2 字段类型分布(524 列)
|
||||||
|
|
||||||
|
| 类型 | 列数 | 占比 | 风险 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `varcharbyte`(金仓特有) | **276** | 53% | **全部未指定长度**(`character_maximum_length` 为 NULL),任何超长/脏数据都能写入 |
|
||||||
|
| `numeric` | 82 | 16% | 未指定精度标度,金额列与计数列同型,无精度约束 |
|
||||||
|
| `varchar` | 78 | 15% | 有长度,但风格与 `varcharbyte` 混用 |
|
||||||
|
| `timestamp` | 68 | 13% | 含 `Oracle DATE`(`sys.date`)映射,秒级精度 |
|
||||||
|
| `bpchar` | 11 | 2% | 定长字符(`'0'/'1'` 标记) |
|
||||||
|
| `text` / `int8` / `int4` / `bytea` | 9 | 2% | LOB(`nclob`/`blob`)、自增主键 |
|
||||||
|
|
||||||
|
**同一字段名在不同表里类型不一致,共 12 组**:
|
||||||
|
|
||||||
|
| 字段 | 类型变体 | 涉及表数 | 直接后果 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `id` | `numeric` / `varchar` / `varcharbyte` | 14 | 跨表 `join`、`union` 需隐式转换;索引即便补上也难生效 |
|
||||||
|
| `deleted` | `numeric` / `varcharbyte` | 4 | 逻辑删除写法不统一(`=0` 与 `='0'` 混用) |
|
||||||
|
| `gyid` | `varchar(64)` / `varcharbyte` | 17 | 长度与比较语义不一致,`gyid='TLXC'` 在不同表可能命中/不命中 |
|
||||||
|
| `kssj` / `jssj` | `timestamp` / `varcharbyte` | 3 / 3 | 同一含义的时间一半能比较、一半是字符串 |
|
||||||
|
| `sort` | `int4` / `numeric` | 4 | — |
|
||||||
|
| `lx` / `cb` / `name` / `dwmc` / `room_no` / `table_id` | 各 2 种 | — | — |
|
||||||
|
|
||||||
|
### 3.3 时间字段三种存法并存
|
||||||
|
|
||||||
|
| 存法 | 示例 | 问题 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `timestamp`(含 `sys.date`) | `kcsj`、`jcsj`、`fjsj`、`sjrysj`、`scbzsj` | 正常,但秒级精度、无时区字段 |
|
||||||
|
| **字符串** `varcharbyte` | `gy_jcxx.yrysj`(预期入住时间)、`gy_jcxx.ddsj`、`gy_jcsj.kssj/jssj`、`gy_jbxx.zrsj/sjsj` | 无法做范围比较、无法排序、格式靠约定;共 13 处 |
|
||||||
|
| 冗余列并存 | `jcsj` 与 `jcsj_s`、`fjsj` 与 `fjsj_s`、`jcbjsj` 与 `jcbjsj_s` | 同一时刻两列,靠代码保证同步,无约束 |
|
||||||
|
|
||||||
|
### 3.4 Oracle 空串语义(高危)
|
||||||
|
|
||||||
|
实例参数 `ora_input_emptystr_isnull = on`,实测验证:
|
||||||
|
|
||||||
|
- `select count(*) from gy_jcxx where bz = ''` → **0**
|
||||||
|
- `select count(*) from gy_jcxx where bz is null` → **3541**(全表)
|
||||||
|
|
||||||
|
含义:业务代码写 `""` 入库后变成 `NULL`;反过来读出的 `NULL` 在 Java 侧可能是 `null` 也可能是 `""`,取决于取值方式。表现为:前端显示`undefined`、`StringUtils.isBlank` 与 `!= null` 判断在不同层得到不同结论、`where col <> ''` 恒不命中。三端拆分后跨库/跨端传输时这个语义差异会被放大。
|
||||||
|
|
||||||
|
### 3.5 `gy_jcxx` 上帝表
|
||||||
|
|
||||||
|
单表 **70 列**,同时承载 7 类语义:
|
||||||
|
|
||||||
|
| 语义组 | 代表列 |
|
||||||
|
| --- | --- |
|
||||||
|
| 车次与交路 | `jch`、`cc`、`cdw`、`kcsj`、`jlid`、`cclx`、`qd`、`ddcc`、`depotid` |
|
||||||
|
| 叫乘状态机 | `ryzt`、`jcsj`、`fjsj`、`jcbjsj`、`sjrysj`、`lybjsj`、`scbzsj` |
|
||||||
|
| 入住/离寓 | `yrysj`、`sjrysj`、`ylysj`、`sjlysj`、`flag_send`、`tbsj_gytofcd`、`tbsj_fcdtogy` |
|
||||||
|
| 补助与餐饮 | `cblx`、`cbje`、`sfffcb`、`dayallowance`、`is_meal3`、`isoverday` |
|
||||||
|
| 服务评分 | `kffwpf`、`stfwpf`、`jcfwpf`、`zm` |
|
||||||
|
| 报警与提醒去重 | `is_yaxx`、`is_jcbj`、`is_lybj`、`route_notice_key`、`call_timeout_notice_key`、`missed_call_notice_key` |
|
||||||
|
| 设备与录音 | `finish_sb`、`recordfile`、`hjxysj`、`fjhold` |
|
||||||
|
|
||||||
|
后 8 列(`business_id`、`ly_type`、`ly_event_id`、`ly_remark`、`ly_snapshot_url`、`route_notice_key`、`call_timeout_notice_key`、`missed_call_notice_key`)明显是后期追加,且 `ly_*` 属于"离寓事件"子域、`*_notice_key` 属于"通知去重"子域——表已演化为多子域的物理合并点。`gy_jcxx_his` 同步复制了这 70 列(但 `yappsj` 类型从 `sys.date` 漂移为 `timestamp`),归档表与主表已出现结构漂移。
|
||||||
|
|
||||||
|
### 3.6 设备台账双轨
|
||||||
|
|
||||||
|
表 3-4 两套设备表
|
||||||
|
|
||||||
|
| 项 | `gy_sb`(v1) | `gy_device`(v2) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 行数 | 148 | 92 |
|
||||||
|
| 命名风格 | 全小写无下划线:`devicecode`/`lx`/`fjh` | 下划线 + RuoYi 审计列:`device_code`/`device_type`/`create_by` |
|
||||||
|
| 类型编码 | `lx`:3=134、1=4、5=3、6=3、2=2、空=2 | `device_type`:3=80、1=3、5=3、6=3、99=2、2=1 |
|
||||||
|
| 附加字段 | `gxsj`、`gymc` | `online_status`、`last_heartbeat`、`firmware_version`、`del_flag` |
|
||||||
|
| 关系 | — | `device_code` 与 `gy_sb.devicecode` **交集 92 行 = 完全子集** |
|
||||||
|
|
||||||
|
即:v2 的 92 个 `device_code` **全部能在 v1 中找到**(交集恰为 92),而 v1 仍有 148 行未被 v2 覆盖。两张表**同时在线、同时被读**,无外键、无同步机制。设备在线率、版本、故障统计存在两个数据源,"当前是否在线"取决于读哪张表。
|
||||||
|
|
||||||
|
### 3.7 指令队列与历史同表,且积压
|
||||||
|
|
||||||
|
表 3-5 `gy_sb_zl` 实测分布
|
||||||
|
|
||||||
|
| `deleted` | 行数 | 涉及设备数 | 时间范围 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `0`(未消费/未删除) | 72,088 | 96 | 2025-08-26 ~ 2026-11-07 |
|
||||||
|
| `1`(已消费) | 57,577 | 172 | 2025-08-26 ~ 2026-11-07 |
|
||||||
|
|
||||||
|
其中 **`deleted='0'` 且生成时间超过 1 天的记录有 71,723 条**——占未消费量的 99.5%。这说明:"取最新一条 → 置 `deleted=1`"的消费方式(见 `HeartBeatService`/设备服务)在多数情况下没有闭环:要么设备从未取走,要么取了没回写成功。同时该表 12.9 万行、零索引,每次取指令都是全表扫描 + 排序。
|
||||||
|
|
||||||
|
### 3.8 日志表无清理
|
||||||
|
|
||||||
|
`gy_logs` 28.6 万行 / 56 MB,`eventtime` 跨度 2025-05 ~ 2026-11。按 `lx` 分布:
|
||||||
|
|
||||||
|
| `lx` | 行数 |
|
||||||
|
| --- | --- |
|
||||||
|
| 运安叫乘同步汇总 | 238,386 |
|
||||||
|
| 刷脸离寓事件号缺失 / 请求 / 完成 / 抓拍缺失 | 7,655 / 7,655 / 7,649 / 7,649 |
|
||||||
|
| 运安叫乘同步跳过 | 4,472 |
|
||||||
|
| 运安定时抓取完成 | 3,470 |
|
||||||
|
| 自动叫乘任务未创建 | 2,369 |
|
||||||
|
| 叫乘时间延后 | 2,258 |
|
||||||
|
| 注册机心跳异常 | 1,797 |
|
||||||
|
| 超时未叫乘提醒 | 857 |
|
||||||
|
| 其余(匹配异常、登录、启动恢复等) | ~1,400 |
|
||||||
|
|
||||||
|
按月看,"运安叫乘同步汇总"稳定在 **每月约 4.4 万条**(2026-05 ~ 09 均在 40,980 ~ 44,640 之间)。这是"每 5 分钟 × 每公寓写一条汇总日志"的直接结果——**一条业务无异常的流水日志,占了全库 87% 的日志行数**。该表无归档、无分区、无索引,年增约 53 万行。
|
||||||
|
|
||||||
|
### 3.9 主数据与租户键(`gyid`)不一致
|
||||||
|
|
||||||
|
17 张表带 `gyid`,但各表的取值域互不匹配:
|
||||||
|
|
||||||
|
| 观测点 | 实测值 |
|
||||||
|
| --- | --- |
|
||||||
|
| `gy_jbxx`(公寓基础信息) | **9** 个:SYXC、SYNDC、SJTXC、SYXXC、DDXC、DSQXC、BYQXC、DLXC、DLBDC |
|
||||||
|
| `gy_call_duty_match_lock`(行锁表) | **37** 个业务 gyid + 1 个伪 gyid `__SYNC_JCXX__` |
|
||||||
|
| `gy_rooms`(房间) | **6** 个:TLXC 102、THXC 56、PJXC 35、TLNXC 2、CCXDC 1、**空 1** |
|
||||||
|
| `gy_jcxx`(叫乘) | **2** 个:THXC 2,110、TLXC 1,431 |
|
||||||
|
| `gy_sb.lx` 为空 / `gy_rooms.gyid` 为空 | 各存在 1~2 行 |
|
||||||
|
|
||||||
|
三个结论:
|
||||||
|
1. **主数据严重缺失**:系统实际服务的 gyid 至少 37 个,但只有 9 个在 `gy_jbxx` 有基础信息,31 个公寓缺面积/床位/负责人/时间规则来源。
|
||||||
|
2. **租户键可空**:`gy_rooms` 有 1 行 `gyid` 为 `NULL`(很可能是代码写入 `""` 后被 Oracle 空串语义转成 `NULL`),这类行在按租户过滤时会被全局漏掉或全局命中。
|
||||||
|
3. **行锁表用 `gyid` 当锁键**并塞入 `__SYNC_JCXX__` 这种伪租户,说明"公寓"与"同步任务"两个概念共用了一张锁表——三端拆分后必须把锁的粒度从"字符串键"改为"业务对象 + 版本"。
|
||||||
|
|
||||||
|
> 样本库只覆盖 THXC / TLXC 两个公寓的叫乘数据,属于导出时的数据裁剪(或该公寓数据被迁移过),不代表生产分布;但 `gyid` 的**取值域不一致**是结构性问题,与数据量无关。
|
||||||
|
|
||||||
|
### 3.10 RuoYi 残留与孤儿序列
|
||||||
|
|
||||||
|
- `gen_table`(18 行)、`gen_table_column`(279 行)是 RuoYi 代码生成器的元数据表,业务上完全不用,却占据 40 张表中的 2 张。
|
||||||
|
- 64 个序列中只有 4 个被列默认值引用:`gen_table_table_id_seq`、`gen_table_column_column_id_seq`、`gy_device_device_id_seq`、`seq_gy_allowance`。其余 60 个指向**已不存在的表**:`sys_user_*`、`sys_role_*`、`sys_menu_*`、`sys_dept_*`、`sys_job_*`、`t_oa_*`、`t_role_*`、`ykt_account_id_seq`、`ykt_consume_flow_id_seq`、`gygl_consumer_terminal_device_id_seq` 等。
|
||||||
|
|
||||||
|
这组序列是"库曾经跑过一版 RuoYi/其他业务系统、后来表被删但序列没删"的直接证据。对三端拆分的意义:**新公寓端选 RuoYi 并不是引入新范式,而是回到这条被中断过的路线上**,因此必须明确"沿用还是重建"权限表(现状 `gl_*` 是自研 RBAC,与 RuoYi `sys_*` 完全不同构)。
|
||||||
|
|
||||||
|
### 3.11 照片以 BLOB 入库
|
||||||
|
|
||||||
|
`gy_ykt_ry_zp`:100 行 / 27 MB / 平均 281.3 KB / 最大 547,778 字节,列类型 `blob`(`bytea`)。同时 `gy_ykt_ry.photourl` 又存了一份路径,代码里还有按 `serverOS` 硬编码的文件目录(`C:\project_doc\resouce\photo\` 与 `/home/gygl/resouce/photo/`)。**同一张照片有"库内 BLOB + 本地磁盘路径"两条真相**,且备份策略完全不同(逻辑备份含 BLOB,磁盘目录不在备份范围)。
|
||||||
|
|
||||||
|
### 3.12 审计与统计表空置
|
||||||
|
|
||||||
|
`gy_operation_log`(操作审计)0 行、`gy_bjcstj`(补叫统计)0 行、`gy_rtjb`(日报)0 行、`gy_sb_zl_his`(指令历史)0 行。四张表有结构无数据——**设计了但没有接线**。其中操作审计的缺失,与"值班员可改叫乘状态但无留痕"的风险直接相关。
|
||||||
|
|
||||||
|
## 4. 数据质量实证
|
||||||
|
|
||||||
|
表 4-1 抽样核对结果
|
||||||
|
|
||||||
|
| 检查项 | 结果 | 判读 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gy_jcxx` 主键候选 `jcid` | 3,541 行 / 3,540 个不同值 | 存在 1 组重复,无约束可阻断 |
|
||||||
|
| `gy_jcxx.kcsj` 为空 | 367 / 3,541(10.4%) | 开车时间缺失仍可入库,下游按时间排序/提醒会漏 |
|
||||||
|
| `gy_jcxx.ryzt` 分布 | 3=2,373、0=582、5=225、4=171、2=134、1=56 | `-1` 未出现;状态分布偏向"已完成/在寓",缺失败态样本 |
|
||||||
|
| `gy_jcxx.jllx` 分布 | 1=2,224、0=1,317 | 两值区分,但字段无注释、无字典表 |
|
||||||
|
| `gy_ykt_remainder` | 1,253 行 / 1,253 个 `ryid`,无重复 | 当前无重复,但无唯一约束保障 |
|
||||||
|
| `gy_rooms` 房态分布 | 3=68、1=58、4=32、2=32、5=7 | `room_status=6` 从未出现(字典有 6 值,实际只用 5 值) |
|
||||||
|
| `gy_sb_xt` 心跳 | 246 行,`updatestate` 全为 0 | 更新状态位从未被置位,与 3.7 的指令积压互相印证 |
|
||||||
|
| `gy_sb_zl.id` / `gy_logs.id` | 12.9 万 / 28.6 万,全部唯一 | 应用层 UUID 生成正确,纯靠代码保证 |
|
||||||
|
|
||||||
|
账务三表口径无法自洽(实测合计):
|
||||||
|
|
||||||
|
| 表 | 口径 | 合计 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gy_ykt_allowance` | 补助发放流水 | 552,295.00 元 |
|
||||||
|
| `gy_ykt_consume` | 消费流水 | 265.10 元 |
|
||||||
|
| `gy_ykt_remainder` | 当前余额(补助/现金/消费/补助总额) | 补助余额 1,228.00 元,现金余额 0.00 元 |
|
||||||
|
|
||||||
|
补助累计 55.2 万元的规模,与仅 265 元的消费流水、1,228 元的当前余额之间,**缺少任何可对账的中间口径**(无期初、无结转、无冲正、无对账批次)。这不能简单判定为"数据错误",但可以确定:**当前结构下无法证明账是对的**。
|
||||||
|
|
||||||
|
## 5. 表归属矩阵(对接文档 10 第 5 章)
|
||||||
|
|
||||||
|
表 5-1 40 张表的目标归属与改造动作
|
||||||
|
|
||||||
|
| 表 | 行数 | 目标端 | 改造动作 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `gy_jbxx` | 9 | 平台 | 升为公寓主数据,补全 37 个 gyid,版本化下发 |
|
||||||
|
| `gy_gyzd` | 37 | 平台 | 主数据(网关/机器号/IP),下发只读 |
|
||||||
|
| `gy_gzzd` | 17 | 平台 | 主数据(工种/客货类型) |
|
||||||
|
| `gy_sjgz` | 17 | 平台 | 时间规则收敛为平台唯一口径,下发 |
|
||||||
|
| `gy_jcsj` | 7 | 平台 | 计划数据 |
|
||||||
|
| `gy_jrb` | 2 | 平台 | 主数据 |
|
||||||
|
| `gy_rooms` | 197 | 平台 + 公寓 + 值班 | **拆三份**:房间基线(平台)/ 房态(公寓)/ 分机与报警起点(公寓) |
|
||||||
|
| `gy_jcxx` | 3,541 | 公寓 | **拆表**:叫乘任务 / 入住离寓 / 通知去重键,见 6.4 |
|
||||||
|
| `gy_jcxx_his` | 32,505 | 公寓 + 归档 | 按月分区;修正与主表的类型漂移 |
|
||||||
|
| `gy_bjxx` | 2,490 | 公寓 | 保留,补主键与 `gyid+时间` 索引 |
|
||||||
|
| `gy_bjcstj` | 0 | — | 退役(无数据无代码写入) |
|
||||||
|
| `gy_jdqkhz` | 1 | 平台 | 转报表视图或退役 |
|
||||||
|
| `gy_rtjb` | 0 | — | 退役 |
|
||||||
|
| `gy_call_duty_match_lock` | 38 | 公寓 | 换为行级锁表(含 `locked_at`/`owner`)或 DB advisory lock |
|
||||||
|
| `gy_syn_jcxx` | 1,139 | 平台 | 运安抓取上收平台,公寓只收下行计划 |
|
||||||
|
| `gy_syn_jcxx_his` | 2,291 | 平台 | 归档分区 |
|
||||||
|
| `gy_syn_jcxx_status` | 1 | 平台 | 改为 watermark 表(含 `last_success_at`/`cursor`) |
|
||||||
|
| `gy_ykt_ry` | 1,349 | 平台 | 人员/卡主数据,公寓本地缓存 |
|
||||||
|
| `gy_ykt_ry_zp` | 100 | 平台 | 迁对象存储,表只留 URL 与校验和 |
|
||||||
|
| `gy_ykt_remainder` | 1,253 | 平台主账 + 公寓缓存 | 双记:本地流水 + 平台主账,日对账 |
|
||||||
|
| `gy_ykt_allowance` | 34,182 | 平台 | 补助流水归平台,公寓不上报原始流水 |
|
||||||
|
| `gy_ykt_consume` | 35 | 平台(餐饮)/ 公寓(其他) | 按消费来源拆分归属 |
|
||||||
|
| `gy_ykt_btbj` | 5 | 平台 | 补助标准主数据 |
|
||||||
|
| `gy_ykt_btjs` | 5 | 平台 | 补助规则主数据 |
|
||||||
|
| `gy_sb` | 148 | 公寓 | **合并到 `gy_device`**,命名归一 |
|
||||||
|
| `gy_device` | 92 | 公寓 | 保留为唯一设备台账,补 `(gyid, device_code)` 唯一 |
|
||||||
|
| `gy_sb_xt` | 246 | 公寓 | 保留;心跳改 upsert,加 `last_heartbeat` 索引 |
|
||||||
|
| `gy_sb_zl` | 129,665 | 公寓 | **拆队列 / 历史**,见 6.4 |
|
||||||
|
| `gy_sb_zl_his` | 0 | 公寓 | 改分区表承接指令历史 |
|
||||||
|
| `gy_logs` | 285,914 | 公寓 | 按月分区 + 保留期;"同步汇总"降为采样 |
|
||||||
|
| `gy_operation_log` | 0 | 公寓 + 值班 | 启用,按端打标 |
|
||||||
|
| `gy_file` | 1 | 平台 | 对象存储索引 |
|
||||||
|
| `gl_*`(6 张) | 17/4/48/45/16/58 | 平台 | 统一账号与权限;公寓端沿用 RuoYi `sys_*` 或适配 `gl_*`,二者只能留一套 |
|
||||||
|
| `gen_table` / `gen_table_column` | 18 / 279 | — | 退役,目标库不携带 |
|
||||||
|
|
||||||
|
## 6. 目标结构建议(设计输入,未执行)
|
||||||
|
|
||||||
|
### 6.1 命名与边界
|
||||||
|
|
||||||
|
1. 保留 schema `gygl`,用**表名前缀**表达归属:`PLT_`(平台主数据/计划)、`APT_`(公寓执行事实)、`DUTY_`(值班操作)、`ARC_`(归档)。
|
||||||
|
2. 现有 `gy_*` 表在迁移期保留原名,新增列/新表用新前缀,避免一次性重命名带来的全量改代码。
|
||||||
|
3. 权限表二选一:若公寓端采用 RuoYi,则 `gl_*` 只作为平台端兼容视图存在,不再有第二份可写副本。
|
||||||
|
|
||||||
|
### 6.2 主键与索引基线
|
||||||
|
|
||||||
|
表 6-1 必补约束与索引(按优先级)
|
||||||
|
|
||||||
|
| 表 | 建议主键 / 唯一 | 建议索引 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gy_jcxx` / `gy_jcxx_his` | `jcid` | `(gyid, kcsj)`、`(gyid, ryzt)` |
|
||||||
|
| `gy_rooms` | `(gyid, room_no)` | `(gyid, room_status)` |
|
||||||
|
| `gy_ykt_ry` | `ryid` | `(card_id)`、`(gzzh)` |
|
||||||
|
| `gy_ykt_remainder` | `ryid` | `(cardid)` |
|
||||||
|
| `gy_ykt_allowance` | `tid` | `(gyid, czsj)`、`(ryid, czsj)` |
|
||||||
|
| `gy_ykt_consume` | `tid` | `(gyid, xfsj)`、`(orderid)` |
|
||||||
|
| `gy_device` | `(gyid, device_code)` | `(ip_addr)`、`(last_heartbeat)` |
|
||||||
|
| `gy_sb_xt` | `devicecode` | `(gyid, heartbeattime)` |
|
||||||
|
| `gy_sb_zl` | `id` | `(devicecode, deleted, generatedtime)` —— 取指令的主路径 |
|
||||||
|
| `gy_logs` | `id` | `(eventtime)` + 按月分区 |
|
||||||
|
| `gy_bjxx` | `id` | `(gyid, kssj)` |
|
||||||
|
| `gy_syn_jcxx` | `id` | `(kcsj)`、`(jch, cc)` |
|
||||||
|
| `gy_jbxx` / `gy_gyzd` / `gy_sjgz` | `gyid` | — |
|
||||||
|
| `gl_yh` / `gl_js` / `gl_qx` / `gl_cd` | 各自首列 | 关联表 `(user_id)/(role_id)` |
|
||||||
|
| `gy_call_duty_match_lock` | `gyid` | — |
|
||||||
|
|
||||||
|
### 6.3 类型归一规则
|
||||||
|
|
||||||
|
表 6-2 类型目标
|
||||||
|
|
||||||
|
| 现类型 | 目标 | 规则 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `varcharbyte`(无长度) | `varchar(n)` | 按实测最大长度 + 30% 余量定 n;标识类统一 `varchar(32/64)` |
|
||||||
|
| 业务时间(`kssj`/`jssj`/`ddsj`/`yrysj`…) | `timestamp(3)` | 禁止再新增字符串时间;迁移时按 `YYYY-MM-DD HH24:MI:SS` 解析,解析失败行单独落错误表 |
|
||||||
|
| `sys.date` | `timestamp(0)` | 保持秒精度,避免与 `timestamp(6)` 混比 |
|
||||||
|
| 金额(`bzje`/`xfje`/`knye`/`xjye`/`xfze`/`bzze`) | `numeric(12,2)` | 统一两位小数,禁止 `numeric` 裸用 |
|
||||||
|
| 布尔标记(`deleted`/`sfjc`/`finish_*`/`is_*`/`stoped`) | `char(1)` + `CHECK IN ('0','1')` | 或 `boolean`;**同一字段名全库只允许一种表示** |
|
||||||
|
| `id`(`numeric` vs `varchar`) | `varchar(32)` 或 `bigint` | 每张表内自洽即可,但跨表引用必须同型 |
|
||||||
|
| `blob` 照片 | 移出库 | 表内只留 `photo_url` + `sha256` + `size` |
|
||||||
|
|
||||||
|
### 6.4 拆表与归档
|
||||||
|
|
||||||
|
1. **`gy_jcxx` 三分**:
|
||||||
|
- `APT_JC_TASK`:任务与状态机(`jcid/ryid/jch/cc/kcsj/jcsj/fjsj/jcbjsj/ryzt`)
|
||||||
|
- `APT_JC_STAY`:入住离寓(`yrysj/sjrysj/ylysj/sjlysj/ly_*`/`flag_send`)
|
||||||
|
- `APT_JC_NOTICE`:通知去重键(`route_notice_key/call_timeout_notice_key/missed_call_notice_key`)→ 或并入通用 `NOTICE_KEY` 表
|
||||||
|
- 物理上不再是 70 列宽表,写入口从"多处 update 同一行"变为"三个子域各自写自己的表",`JcglService` 的 4193 行才有可能拆开。
|
||||||
|
2. **`gy_sb_zl` 拆队列/历史**:`APT_DEV_CMD`(只保留未消费,带 `status/attempt/expire_at`)+ `ARC_DEV_CMD`(消费即搬走),队列表行数应稳定在"在线设备数 × 个位数"量级,当前 7.1 万条积压即为异常基线。
|
||||||
|
3. **`gy_logs` 分区**:按月 `RANGE` 分区,保留 3 个月热数据;"运安叫乘同步汇总"改为只记异常与抽样,预计日志量下降 90%。
|
||||||
|
4. **`gy_jcxx_his` / `gy_syn_jcxx_his` / `gy_sb_zl_his`** 统一进 `ARC_` 分区族,保留期与合规要求对齐。
|
||||||
|
|
||||||
|
### 6.5 迁移时的兼容陷阱
|
||||||
|
|
||||||
|
1. `varcharbyte` 无长度 → 转 `varchar(n)` 前必须先跑 `select max(length(col))` 全量核对,否则截断报错会中断迁移。
|
||||||
|
2. `ora_input_emptystr_isnull=on` → 迁移前后同一份数据 `''` 与 `NULL` 的判断结果不同;迁移脚本与校验 SQL 都要用 `coalesce(col,'')` 口径。
|
||||||
|
3. `gen_table_column` 里记录的 `is_pk` 全为 RuoYi 生成器推断值,**不能当作主键依据**——实测全库主键为 0,该字段不代表真实约束。
|
||||||
|
4. 60 个孤儿序列不要随库迁移,目标库从 0 重建,否则序列起始值会带来 ID 跳号与冲突排查成本。
|
||||||
|
5. Oracle 兼容模式与金仓安全版 MAC 策略需在目标环境确认(`database_mode`、`sysmac` 是否启用),二者会改变 SQL 行为与权限模型。
|
||||||
|
|
||||||
|
## 7. 与三端拆分方案的衔接
|
||||||
|
|
||||||
|
表 7-1 结构缺陷 → 方案措施
|
||||||
|
|
||||||
|
| 本次实测缺陷 | 对应章节 | 方案措施 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 零主键零索引零外键(3.1) | 阶段零 基线修复 | 先补 `(gyid, 业务键)` 唯一约束与查询索引,再谈拆分 |
|
||||||
|
| 同名不同型 12 组(3.2) | 5 数据架构 / 6 接口契约 | 契约层强制类型规范;`gyid` 统一 `varchar(64)` |
|
||||||
|
| 空串即 NULL(3.4) | 6 接口契约 | 上报信封中 `null` 与 `""` 语义显式化,服务端统一 `coalesce` |
|
||||||
|
| `gy_jcxx` 70 列(3.5) | 4 领域与模块划分 | 拆三子域,状态机唯一写入口 |
|
||||||
|
| 双设备台账(3.6) | 7 设备接入 | 设备主数据唯一化,`gy_device` 为准,`gy_sb` 合并 |
|
||||||
|
| 指令积压 7.1 万(3.7) | 7.4 指令下发-ACK-重投 | 队列化 + ACK + 过期作废 + 优先级 |
|
||||||
|
| 日志月增 4.4 万(3.8) | 8 部署与运行 | 分区 + 保留期 + 异常化 |
|
||||||
|
| `gyid` 取值域不一致(3.9) | 3 端职责边界 | 公寓主数据上收,租户键非空 + 外键校验 |
|
||||||
|
| RuoYi 残留与孤儿序列(3.10) | 阶段一 新公寓端脚手架 | 明确权限表归属,目标库不携带 `gen_*` 与孤儿序列 |
|
||||||
|
| 照片双真相(3.11) | 5.3 数据归属 | 统一对象存储 + 校验和 |
|
||||||
|
| 审计表空置(3.12) | 10 风险 | 值班操作留痕纳入验收项 |
|
||||||
|
| 账务不可对账(4 节) | 5.2 一致性策略 | 主账在平台 + 本地流水 + 日对账 |
|
||||||
|
|
||||||
|
## 8. 待现场确认
|
||||||
|
|
||||||
|
1. **生产库是否真的没有索引**:本机导入库与 dump 均为 0,但需要在生产 DBA 侧执行 `\d+ gygl.gy_jcxx` 复核(导出工具理论上会带索引,需排除导出裁剪)。
|
||||||
|
2. **37 个 gyid 与 9 个 `gy_jbxx` 的差集**:是"未登记"还是"已停用"?决定主数据补录范围。
|
||||||
|
3. **样本库只有 2 个公寓的叫乘数据**:确认是导出裁剪、数据迁移,还是这两个公寓曾单独部署。
|
||||||
|
4. **`gy_sb_zl` 积压 7.1 万条的成因**:设备端未取、网关未转发,还是消费后回写失败?需查 2026-10 之后的设备侧日志。
|
||||||
|
5. **Oracle 存量公寓**:`ojdbc8` 依赖存在,确认是否存在仍直连 Oracle 的部署环境。
|
||||||
|
6. **金仓安全版 MAC 是否启用**:`sysmac` schema 为空表,若启用策略会影响后续新增表的授权模型。
|
||||||
|
|
||||||
|
## 附录 A 采集 SQL(可复现)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 库级
|
||||||
|
select version(), current_setting('server_encoding');
|
||||||
|
select name, setting from pg_settings where name in ('database_mode','ora_input_emptystr_isnull');
|
||||||
|
select nspname, count(*) from pg_class c join pg_namespace n on n.oid=c.relnamespace
|
||||||
|
where c.relkind='r' group by 1;
|
||||||
|
|
||||||
|
-- 约束与索引
|
||||||
|
select count(*) from pg_indexes where schemaname='gygl';
|
||||||
|
select constraint_type, count(*) from information_schema.table_constraints
|
||||||
|
where table_schema='gygl' group by 1;
|
||||||
|
select count(*) from pg_class c join pg_namespace n on n.oid=c.relnamespace
|
||||||
|
where c.relkind='S' and n.nspname='gygl';
|
||||||
|
|
||||||
|
-- 类型与注释
|
||||||
|
select udt_name, count(*), sum(case when character_maximum_length is null then 1 else 0 end)
|
||||||
|
from information_schema.columns where table_schema='gygl' group by 1 order by 2 desc;
|
||||||
|
select column_name, count(distinct udt_name) from information_schema.columns
|
||||||
|
where table_schema='gygl' group by 1 having count(distinct udt_name)>1;
|
||||||
|
|
||||||
|
-- 规模与分布
|
||||||
|
select relname, n_live_tup, pg_size_pretty(pg_total_relation_size(relid))
|
||||||
|
from pg_stat_user_tables order by pg_total_relation_size(relid) desc;
|
||||||
|
select count(*), count(distinct jcid), count(distinct gyid), min(kcsj), max(kcsj) from gygl.gy_jcxx;
|
||||||
|
select deleted, count(*), min(generatedtime), max(generatedtime) from gygl.gy_sb_zl group by 1;
|
||||||
|
select count(*) from gygl.gy_sb_zl where deleted='0' and generatedtime < now() - interval '1 day';
|
||||||
|
select to_char(eventtime,'YYYY-MM'), count(*) from gygl.gy_logs group by 1 order by 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
> 本轮对实例的全部操作均为 `SELECT`,未执行任何 DDL/DML;分析用临时脚本仅存在于本机临时目录。
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# 叫乘管理系统 梳理文档
|
||||||
|
|
||||||
|
本目录是对既有代码的结构化梳理,目的是为后续迭代提供统一的“地图”:知道每个业务落在哪个包/页面、数据怎么流转、接口和外部系统怎么对接、改动时应该看哪些文件。
|
||||||
|
|
||||||
|
> 后端:`yktgl/`;前端:`YktVue/`,见 [frontend/](./frontend/README.md)。
|
||||||
|
> 梳理基准:`main` 分支提交 `135a192`(2026-11-07)。
|
||||||
|
|
||||||
|
## 文档索引
|
||||||
|
|
||||||
|
| 文档 | 内容 | 适用场景 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [01-系统总览.md](./01-系统总览.md) | 业务定位、角色、运行形态、技术栈、关键设计约束 | 新人入门、方案评审 |
|
||||||
|
| [02-工程结构与分层.md](./02-工程结构与分层.md) | 目录/包结构、分层约定、启动流程、公共组件 | 找代码、定落点 |
|
||||||
|
| [03-业务模块地图.md](./03-业务模块地图.md) | 各业务模块职责、控制器、服务、依赖关系 | 评估改动影响面 |
|
||||||
|
| [04-核心业务流程.md](./04-核心业务流程.md) | 入住、叫乘、复叫、报警、应答、离寓、房间、交路同步、卡务 | 改业务逻辑前必读 |
|
||||||
|
| [05-数据模型.md](./05-数据模型.md) | 核心表、字段语义、状态码、归档与锁 | 写 SQL / 改表 / 排查数据 |
|
||||||
|
| [06-接口清单.md](./06-接口清单.md) | Web 接口与设备接口清单、协议枚举 | 联调、接口扩展 |
|
||||||
|
| [07-外部集成与定时任务.md](./07-外部集成与定时任务.md) | Asterisk AMI、运安 SOAP、中心 HTTP、WebSocket、Quartz/@Scheduled | 排障、集成改造 |
|
||||||
|
| [08-部署与配置.md](./08-部署与配置.md) | Profile、数据库/Redis、资源目录、升级脚本 | 部署、环境切换 |
|
||||||
|
| [09-迭代指引与风险清单.md](./09-迭代指引与风险清单.md) | 技术债、改动落点速查、待确认问题、迭代建议 | 排期、评审 |
|
||||||
|
| [10-架构优化方案-三端拆分.md](./10-架构优化方案-三端拆分.md) | 平台端/公寓端/应用端拆分:现状评估、目标架构、职责边界、模块与数据归属、接口契约、设备接入、部署与迁移路径 | 架构评审、重构设计 |
|
||||||
|
| [11-既有数据库结构分析.md](./11-既有数据库结构分析.md) | 实测库级参数、40 表清单与规模、零主键零索引等结构缺陷、数据质量实证、表归属矩阵、类型归一与拆表建议 | 库设计评审、迁移改造 |
|
||||||
|
|
||||||
|
## 前端文档
|
||||||
|
|
||||||
|
前端梳理独立成册,入口见 [frontend/README.md](./frontend/README.md):
|
||||||
|
|
||||||
|
| 文档 | 内容 |
|
||||||
|
| --- | --- |
|
||||||
|
| [frontend/01-前端总览与技术栈.md](./frontend/01-前端总览与技术栈.md) | 四类界面、运行拓扑、技术栈、全局变量 |
|
||||||
|
| [frontend/02-工程结构与请求链路.md](./frontend/02-工程结构与请求链路.md) | 启动装配、登录守卫、axios、API 与后端映射 |
|
||||||
|
| [frontend/03-路由与页面职责.md](./frontend/03-路由与页面职责.md) | 13 条路由、入口关系、遗留页面 |
|
||||||
|
| [frontend/04-核心页面拆解-JcXx.md](./frontend/04-核心页面拆解-JcXx.md) | 值班台布局、状态、操作、时间规则、轮询 |
|
||||||
|
| [frontend/05-实时通信与语音告警.md](./frontend/05-实时通信与语音告警.md) | WebSocket/SIP、消息协议、告警与 TTS 队列 |
|
||||||
|
| [frontend/06-食堂与自助终端模块.md](./frontend/06-食堂与自助终端模块.md) | 自助登记、点餐/结算/后厨/保洁、选房与房间维护 |
|
||||||
|
| [frontend/07-构建部署与风险清单.md](./frontend/07-构建部署与风险清单.md) | 构建、环境、部署要点、测试基线、P0/P1/P2 风险 |
|
||||||
|
|
||||||
|
## 建议阅读路径
|
||||||
|
|
||||||
|
- **第一次接触项目**:01 → 02 → 03 → 04;再看前端 01 → 02 → 04。
|
||||||
|
- **要接一个需求**:03 定位模块 → 04 看流程 → 09 查落点与风险 → 06/05 查接口和表;涉及页面时读前端 04/05。
|
||||||
|
- **线上排障**:07(外部依赖/定时任务)→ 04(状态机)→ 05(数据与状态码)→ 08(配置);前端问题读前端 05/07。
|
||||||
|
- **准备重构**:02(分层)→ 09(技术债与建议)→ 10(三端拆分方案)→ 11(既有库结构分析);前端读前端 02/04/07。
|
||||||
|
|
||||||
|
## 快速事实
|
||||||
|
|
||||||
|
- 后端:Spring Boot 2.6.13 + Java 8,默认 jar 打包(可改 WAR),上下文路径 `/yktgl`,默认端口 `8081`。
|
||||||
|
- 数据库:KingbaseES 8(兼容 Oracle 语法),Redis 存 Session。
|
||||||
|
- 多公寓:同一套代码通过“客户端 IP → 公寓”解析 `gyid`,不依赖前端传参。
|
||||||
|
- 核心链路:设备/网页入寓登记 → 生成叫乘计划(Quartz 三个任务)→ 叫乘/复叫/报警/应答 → 离寓归档。
|
||||||
|
- 最大单体:后端 `jcgl/service/JcglService.java`(约 4192 行);前端 `src/views/JcXx.vue`(5294 行)。
|
||||||
|
- 前端:Vue 2.6 + Element UI,生产静态与接口同域 `/yktgl`;登录无真实 token,公寓 `gyid` 由后端按客户端 IP 解析。
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# 01 前端总览与技术栈
|
||||||
|
|
||||||
|
## 1. 系统定位
|
||||||
|
|
||||||
|
前端是“叫乘 / 公寓管理”系统的操作层,服务四类现场角色,共用一个 Vue 工程、一套构建产物:
|
||||||
|
|
||||||
|
| 界面 | 主要使用者 | 典型设备 | 入口路由 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 叫乘值班控制台 | 公寓值班员 | 值班室大屏 / 双屏 PC | `/jcxx`(登录后默认页) |
|
||||||
|
| 入寓自助终端 | 乘务员本人 | 触摸屏一体机(带摄像头、读卡器) | `/ykt_main` |
|
||||||
|
| 食堂终端 | 乘务员、厨师、保洁 | 点餐屏 / 后厨屏 / 保洁屏 | `/MealsOrdering`、`/paymentPlatform`、`/chefOrders`、`/roomService` |
|
||||||
|
| 房间维护与同步查询 | 值班员、管理员 | PC | 值班台弹窗 + `/synJcXx` |
|
||||||
|
|
||||||
|
前端不承担鉴权与公寓归属判断:**公寓 `gyid` 最终以后端按客户端 IP 解析的结果为准**。前端登录时把用户名写入 `localStorage.gyid`,主要用于 WebSocket 的 `{username}` 路径段和部分页面查询参数;两者不一致是本系统最常见的联调问题来源,详见 [02](./02-工程结构与请求链路.md) 与 [07](./07-构建部署与风险清单.md)。
|
||||||
|
|
||||||
|
## 2. 运行拓扑
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph Browser["浏览器(现场终端)"]
|
||||||
|
Duty["值班控制台 JcXx.vue"]
|
||||||
|
Self["自助终端 shijinpeng/main.vue"]
|
||||||
|
Meal["食堂终端 zhengchuang/*"]
|
||||||
|
RoomUI["房间选择/维护 Room.vue / RoomLook.vue"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph SameOrigin["同域静态资源"]
|
||||||
|
Static["/yktgl/ 前端 dist"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Backend["后端 yktgl(8081,context /yktgl)"]
|
||||||
|
API["REST /jcgl /jlgl /Meals /clean /recharge /heartBeat /excel /jwDataLog"]
|
||||||
|
WS["WebSocket /jcwebsocket /jlwebsocket /rlywebsocket /MealsWebsocket"]
|
||||||
|
SIPGW["SIP 客户端网关 :9004 /sipclient"]
|
||||||
|
end
|
||||||
|
|
||||||
|
PBX["Asterisk / AMI / 广播设备"]
|
||||||
|
|
||||||
|
Duty --> Static
|
||||||
|
Self --> Static
|
||||||
|
Meal --> Static
|
||||||
|
RoomUI --> Static
|
||||||
|
Duty -->|"axios baseURL /yktgl(生产)或 /dev-api→/yktgl(开发)"| API
|
||||||
|
Self -->|"axios 同源 /yktgl"| API
|
||||||
|
Meal -->|"axios 同源 /yktgl"| API
|
||||||
|
RoomUI -->|"axios 同源 /yktgl"| API
|
||||||
|
Duty -->|"ws://host/yktgl/jcwebsocket/{gyid}"| WS
|
||||||
|
Duty -->|"ws://host/yktgl/jlwebsocket/{gyid}"| WS
|
||||||
|
Self -->|"ws://host/yktgl/rlywebsocket/test33"| WS
|
||||||
|
Meal -->|"ws://host/yktgl/MealsWebsocket/test33"| WS
|
||||||
|
Duty -->|"ws://127.0.0.1:9004/sipclient/{gyid}"| SIPGW
|
||||||
|
SIPGW --> PBX
|
||||||
|
Backend --> PBX
|
||||||
|
```
|
||||||
|
|
||||||
|
要点:
|
||||||
|
|
||||||
|
- **静态资源与接口同域**。生产 `vue.config.js` 的 `publicPath` 是 `/yktgl/`([vue.config.js:21](../../YktVue/vue.config.js#L21)),axios 生产 `baseURL` 也是 `/yktgl`([request.js:17](../../YktVue/src/utils/request.js#L17)),依赖反向代理把 `/yktgl/*` 转到后端。
|
||||||
|
- **WebSocket 地址是硬编码相对当前主机**,没有走 `public/config.js` 里的 `getWebSocketUrl()`;协议固定 `ws://`,HTTPS 部署会失败。
|
||||||
|
- **SIP 地址固定本机 `127.0.0.1:9004`**,意味着值班台必须与 SIP 网关同机部署。
|
||||||
|
- 浏览器不直连 Asterisk,语音呼叫由后端/SIP 网关完成;前端只发“呼叫/停止”指令。
|
||||||
|
|
||||||
|
## 3. 技术栈
|
||||||
|
|
||||||
|
| 层次 | 选型 | 版本 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 框架 | Vue | 2.6.12 | Options API,无 Composition API |
|
||||||
|
| 路由 | vue-router | 3.4.9 | hash 默认模式,守卫只判断本地登录痕迹 |
|
||||||
|
| 状态 | Vuex | 3.6.0 | 依赖已声明,但工程没有 `src/store`,实际未使用 |
|
||||||
|
| UI | Element UI | 2.15.13 | 大量内联样式覆盖主题 |
|
||||||
|
| 请求 | axios | 0.24.0 | 统一拦截器 + 两套实例(`request.js` / `fileRequest.js`) |
|
||||||
|
| 图表 | ECharts | 5.4.0 | 依赖已声明,业务页面基本未使用 |
|
||||||
|
| 构建 | Vue CLI / webpack | 4.4.6 / 4 | `--openssl-legacy-provider` 兼容新 Node |
|
||||||
|
| 样式 | Sass | 1.32.13 | `lang="scss"`,含全局大屏样式 |
|
||||||
|
| 工具 | js-cookie、file-saver、jsencrypt、quill、vuedraggable、vue-cropper | 见 package.json | 多数为 RuoYi 模板遗留 |
|
||||||
|
|
||||||
|
工程来源是 RuoYi-Vue 模板(`package.json` 的 repository 仍指向 RuoYi),但业务页面已大幅改造,模板的权限、字典、布局、Vuex 体系基本被剥离或未接线。
|
||||||
|
|
||||||
|
## 4. 四类界面与页面清单
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
Login["/login 登录"] --> Duty["/jcxx 值班控制台"]
|
||||||
|
Duty -->|弹窗| Room["Room.vue 选房"]
|
||||||
|
Duty -->|弹窗| RoomLook["RoomLook.vue 房间维护"]
|
||||||
|
Duty -->|弹窗| History["历史叫乘 / 交路 / 人员 / 充值"]
|
||||||
|
Login --> Self["/ykt_main 自助终端"]
|
||||||
|
Login --> MealOrder["/MealsOrdering 点餐"]
|
||||||
|
Login --> Pay["/paymentPlatform 结算"]
|
||||||
|
Login --> Chef["/chefOrders 后厨"]
|
||||||
|
Login --> Clean["/roomService 保洁"]
|
||||||
|
Login --> Syn["/synJcXx 运安同步查询"]
|
||||||
|
```
|
||||||
|
|
||||||
|
页面规模与职责:
|
||||||
|
|
||||||
|
| 文件 | 行数 | 职责 | 详细说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| [`src/views/JcXx.vue`](../../YktVue/src/views/JcXx.vue) | 5294 | 值班主界面:叫乘列表、全部操作、实时告警、SIP、历史、导出 | [04](./04-核心页面拆解-JcXx.md) |
|
||||||
|
| [`src/shijinpeng/main.vue`](../../YktVue/src/shijinpeng/main.vue) | 943 | 自助入寓/离寓登记、刷脸、餐补查询、录像 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/zhengchuang/views/MealsOrdering.vue`](../../YktVue/src/zhengchuang/views/MealsOrdering.vue) | 988 | 乘务员自助点餐、刷脸支付、购物车 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/zhengchuang/views/paymentPlatform.vue`](../../YktVue/src/zhengchuang/views/paymentPlatform.vue) | 570 | 自助结算金额录入 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/zhengchuang/views/chefOrders.vue`](../../YktVue/src/zhengchuang/views/chefOrders.vue) | 532 | 后厨订单队列、完成订单、新单提示 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/zhengchuang/views/roomService.vue`](../../YktVue/src/zhengchuang/views/roomService.vue) | 339 | 保洁房间卡片、清扫计时 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/components/Room.vue`](../../YktVue/src/components/Room.vue) | 332 | 房间选择器,按楼层分组、推荐房、状态过滤 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/components/RoomLook.vue`](../../YktVue/src/components/RoomLook.vue) | 618 | 房间维护:多选同状态房间、开始/结束保洁、停用/恢复 | [06](./06-食堂与自助终端模块.md) |
|
||||||
|
| [`src/views/SynJcXx.vue`](../../YktVue/src/views/SynJcXx.vue) | 101 | 运安同步叫乘数据只读查询 | [03](./03-路由与页面职责.md) |
|
||||||
|
| [`src/views/Login.vue`](../../YktVue/src/views/Login.vue) | 206 | 公寓账号登录 | [02](./02-工程结构与请求链路.md) |
|
||||||
|
|
||||||
|
## 5. 全局变量与页面差异
|
||||||
|
|
||||||
|
`public/config.js` 在 `index.html` 中以脚本方式先于应用加载,向 `window` 注入:
|
||||||
|
|
||||||
|
| 变量 | 值 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `apiRoot` | `window.location.host` | 拼接 WebSocket 地址;注意不含协议 |
|
||||||
|
| `gyid` | `localStorage.getItem('gyid') \|\| 'TLXC'` | 全局公寓标识兜底值 |
|
||||||
|
|
||||||
|
不同页面对这两个变量的使用并不一致:
|
||||||
|
|
||||||
|
| 页面 | WebSocket 地址 | 公寓标识 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `JcXx.vue` | `ws://{apiRoot}/yktgl/{jc,jl}websocket/{this.gyid}` | `this.gyid = localStorage.gyid \|\| 全局 gyid`([JcXx.vue:1728](../../YktVue/src/views/JcXx.vue#L1728)) |
|
||||||
|
| `shijinpeng/main.vue` | `ws://{apiRoot}/yktgl/rlywebsocket/test33` | 页面内硬编码 `gyid: "SYBXC"`、`gymc: "沈阳站公寓"`([main.vue:291](../../YktVue/src/shijinpeng/main.vue#L291)) |
|
||||||
|
| `MealsOrdering.vue` / `paymentPlatform.vue` | `ws://{apiRoot}/yktgl/MealsWebsocket/test33` | 无 |
|
||||||
|
| `roomService.vue` | 无 | 硬编码 `gyid: "SYBXC"`([roomService.vue:190](../../YktVue/src/zhengchuang/views/roomService.vue#L190)) |
|
||||||
|
| `public/config.js` 注释 | — | 保留 PJXC / SJTXC / BYQXC 等多公寓 IP/gyid 手工切换示例 |
|
||||||
|
|
||||||
|
结论:**这个工程原本按“一套代码、多个公寓分别部署”的方式维护**,多公寓配置靠改 `config.js` 注释或改页面常量,而不是运行时配置中心。
|
||||||
|
|
||||||
|
## 6. 关键设计约束
|
||||||
|
|
||||||
|
1. **同域部署**:静态资源 `/yktgl/`、接口 `/yktgl/*`、WebSocket `/yktgl/*websocket` 必须由同一反向代理暴露。
|
||||||
|
2. **后端按 IP 识别公寓**:`/jcgl/*` 的大量接口不接收前端 `gyid`,后端用 `zdwhService.getGyIdByIp(request)` 解析(见 [后端 03](../03-业务模块地图.md))。前端传的 `gyid` 主要用于推送寻址。
|
||||||
|
3. **WebSocket username 必须等于公寓 gyid**:`JcWebsocket` 只向 `username == gyid` 或 `all` 的会话发送(见 [后端 07](../07-外部集成与定时任务.md))。因此值班员登录名通常就是公寓代码。
|
||||||
|
4. **无全局状态**:所有页面状态各自维护,跨页面协作靠 `localStorage`、`BroadcastChannel` 和 `location.reload()`。
|
||||||
|
5. **单机终端假设**:SIP、自助终端、食堂终端都存在本机地址或固定 `test33`/`SYBXC` 的硬编码,跨机部署需要先改代码。
|
||||||
|
|
||||||
|
## 7. 下一步
|
||||||
|
|
||||||
|
- 想看一次请求从点击到后端:读 [02-工程结构与请求链路](./02-工程结构与请求链路.md)。
|
||||||
|
- 想改叫乘主界面:直接读 [04-核心页面拆解-JcXx](./04-核心页面拆解-JcXx.md)。
|
||||||
|
- 想改实时告警:读 [05-实时通信与语音告警](./05-实时通信与语音告警.md)。
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
# 02 工程结构与请求链路
|
||||||
|
|
||||||
|
## 1. 目录结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
YktVue/
|
||||||
|
├── public/
|
||||||
|
│ ├── index.html # 先加载 config.js,再加载应用
|
||||||
|
│ ├── config.js # 全局 apiRoot / gyid / getWebSocketUrl
|
||||||
|
│ └── favicon.ico
|
||||||
|
├── src/
|
||||||
|
│ ├── main.js # 仅装配 ElementUI + router
|
||||||
|
│ ├── App.vue # 仅 <router-view>
|
||||||
|
│ ├── router/index.js # 13 条路由 + 登录守卫
|
||||||
|
│ ├── api/
|
||||||
|
│ │ ├── login.js # /auth/captchaImage、/auth/logon
|
||||||
|
│ │ ├── jcgl/jcgl.js # 叫乘主业务接口(35 个)
|
||||||
|
│ │ ├── jlgl/jlgl.js # 交路管理接口(7 个)
|
||||||
|
│ │ └── zhengchuang/mealsOrdering.js # 食堂接口(9 个)
|
||||||
|
│ ├── utils/
|
||||||
|
│ │ ├── request.js # axios 主实例 + 拦截器 + download
|
||||||
|
│ │ ├── fileRequest.js # 导出专用 axios 实例
|
||||||
|
│ │ ├── auth.js # Cookie token + 清理登录信息
|
||||||
|
│ │ ├── ruoyi.js # tansParams / blobValidate 等模板工具
|
||||||
|
│ │ └── permission.js # 依赖不存在的 @/store,死代码
|
||||||
|
│ ├── plugins/ # RuoYi 插件(cache/download/modal/...),未安装
|
||||||
|
│ ├── components/
|
||||||
|
│ │ ├── Room.vue # 选房器
|
||||||
|
│ │ ├── RoomLook.vue # 房间维护
|
||||||
|
│ │ └── RoomLook copy.vue, media.vue # 遗留
|
||||||
|
│ ├── views/
|
||||||
|
│ │ ├── Login.vue
|
||||||
|
│ │ ├── JcXx.vue # 值班主界面(5294 行)
|
||||||
|
│ │ ├── SynJcXx.vue
|
||||||
|
│ │ ├── Home.vue / About.vue # 模板遗留
|
||||||
|
│ │ └── JcXx.vue.bak_mojibake # 遗留备份
|
||||||
|
│ ├── shijinpeng/main.vue # 自助登记终端
|
||||||
|
│ └── zhengchuang/
|
||||||
|
│ ├── views/ # 点餐、结算、后厨、保洁
|
||||||
|
│ ├── components/ # audioPlay / textSpeak
|
||||||
|
│ └── css/ # MealCss.css 等
|
||||||
|
├── tests/ # 两个纯 Node 测试脚本
|
||||||
|
├── vue.config.js
|
||||||
|
├── package.json
|
||||||
|
└── .env.development / .env.production / .env.staging
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. 启动装配
|
||||||
|
|
||||||
|
[`src/main.js`](../../YktVue/src/main.js) 只有 14 行:
|
||||||
|
|
||||||
|
```js
|
||||||
|
Vue.use(ElementUI)
|
||||||
|
Vue.prototype.$axios = axios
|
||||||
|
new Vue({ router, render: h => h(App) }).$mount('#app')
|
||||||
|
```
|
||||||
|
|
||||||
|
因此:
|
||||||
|
|
||||||
|
- **没有安装 Vuex**,也没有 `store` 目录;`package.json` 中的 `vuex` 只是模板残留。
|
||||||
|
- **没有安装 `src/plugins/index.js`**,所以 `this.$modal`、`this.$download`、`this.$tab` 等 RuoYi 原型方法不存在;`JcXx.vue` 的 `handleDelete` 仍调用了 `this.$modal.confirm`,该分支是死路径。
|
||||||
|
- **没有全局路由守卫之外的权限体系**;`utils/permission.js` 因为 import `@/store` 会失败,且没有被引用。
|
||||||
|
- `public/index.html:9` 先加载 `config.js`,所以页面里可以直接使用 `apiRoot`、`gyid` 这两个隐式全局变量。
|
||||||
|
|
||||||
|
## 3. 登录与路由守卫
|
||||||
|
|
||||||
|
### 3.1 登录时序
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as 用户
|
||||||
|
participant L as Login.vue
|
||||||
|
participant R as request.js
|
||||||
|
participant B as 后端 /auth/logon
|
||||||
|
participant LS as localStorage/Cookie
|
||||||
|
|
||||||
|
U->>L: 输入用户名/密码
|
||||||
|
L->>R: GET /auth/logon?username&password
|
||||||
|
R->>B: baseURL + /auth/logon
|
||||||
|
B->>B: 按用户名查 DictData_gy,校验请求 IP 是否在该公寓 ip 列表
|
||||||
|
alt 校验通过
|
||||||
|
B-->>R: Result.success(LogEntity)
|
||||||
|
R-->>L: { code:'00000', data: LogEntity }
|
||||||
|
L->>LS: setToken('fake-token-<ts>')(响应无 token)
|
||||||
|
L->>LS: gyid=username, loginAccount=username
|
||||||
|
L->>L: $router.push('/jcxx')
|
||||||
|
else 用户/IP 不匹配
|
||||||
|
B-->>R: Result.failure(msg)
|
||||||
|
R-->>L: Promise.reject + Message.error
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
关键代码:
|
||||||
|
|
||||||
|
- 登录请求:`api/login.js` 的 `login()` 使用 GET `/auth/logon`([login.js:16](../../YktVue/src/api/login.js#L16))。
|
||||||
|
- 成功处理:`Login.vue` 判断 `response.code === '00000'`,没有 `response.token` 就写入 `fake-token-时间戳`,并把 **用户名当成 gyid**([Login.vue:83](../../YktVue/src/views/Login.vue#L83))。
|
||||||
|
- 后端契约:`/auth/logon` 只校验 `DictData_gy` 与 IP,写入 Session 的 `gyid`/`ip`,返回 `LogEntity`,不签发 token(见 [后端 06](../06-接口清单.md))。
|
||||||
|
|
||||||
|
### 3.2 守卫逻辑
|
||||||
|
|
||||||
|
[`src/router/index.js:80`](../../YktVue/src/router/index.js#L80):
|
||||||
|
|
||||||
|
```js
|
||||||
|
const isLoggedIn = token || loginAccount
|
||||||
|
if (to.path === '/login') {
|
||||||
|
isLoggedIn ? next('/jcxx') : next()
|
||||||
|
} else {
|
||||||
|
isLoggedIn ? next() : next('/login')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
含义与风险:
|
||||||
|
|
||||||
|
- 登录态 = Cookie `Admin-Token` 或 `localStorage.loginAccount` 任一存在,**不校验 token 有效性**,也不校验后端 Session 是否过期。
|
||||||
|
- 退出登录只清本地信息(`clearLoginInfo()`),没有调用后端 `/auth/logout`。
|
||||||
|
- 只要用户手工写入 `loginAccount`,就能进入所有页面;真正的权限控制完全依赖后端接口和 IP 校验。
|
||||||
|
- 登录页在已登录时会强制跳 `/jcxx`,无法回到登录页切换账号,除非先清 localStorage/Cookie。
|
||||||
|
|
||||||
|
## 4. axios 请求链路
|
||||||
|
|
||||||
|
### 4.1 主实例
|
||||||
|
|
||||||
|
[`src/utils/request.js:14`](../../YktVue/src/utils/request.js#L14) 创建实例:
|
||||||
|
|
||||||
|
| 配置 | 值 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `baseURL` | 开发 `/dev-api`,其他 `/yktgl` | 硬编码,**不读取 `VUE_APP_BASE_API`**([request.js:17](../../YktVue/src/utils/request.js#L17)) |
|
||||||
|
| `timeout` | 10000 ms | 导出走 `fileRequest` 的 50 s |
|
||||||
|
| `Content-Type` | `application/json;charset=utf-8` | GET 参数由拦截器拼到 URL |
|
||||||
|
|
||||||
|
请求拦截器([request.js:24](../../YktVue/src/utils/request.js#L24)):
|
||||||
|
|
||||||
|
1. 若存在 Cookie token 且未显式 `isToken: false`,加 `Authorization: Bearer <token>`;由于 token 是假的,后端并不校验。
|
||||||
|
2. GET 请求用 `tansParams` 把 `params` 序列化到 URL,然后清空 `params`。
|
||||||
|
3. POST/PUT 的防重复提交逻辑只写不校验:`sessionObj` 写入后,真正比较的 `else` 分支被整段注释([request.js:54](../../YktVue/src/utils/request.js#L54))。
|
||||||
|
|
||||||
|
响应拦截器([request.js:75](../../YktVue/src/utils/request.js#L75)):
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { code, msg } = response.data
|
||||||
|
if (code === '00000' || code === '11111' || code === 1) return response.data
|
||||||
|
if (response.data instanceof ArrayBuffer) return response
|
||||||
|
Message({ message: msg || '系统出错', type: 'error' })
|
||||||
|
return Promise.reject(new Error(msg || 'Error'))
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- **`11111` 被当成成功返回**。业务层需要自己判断 `res.code === '11111'` 并提示错误(例如 `handleRechargeConfirm`、`handleUpdateJcXxConfirm`)。这与后端“`00000` 成功、`11111` 业务失败”的约定不一致,容易漏判。
|
||||||
|
- 二进制判断在成功码判断之后,且 axios 默认不会把 blob 转成 `ArrayBuffer`,所以 blob 分支实际很少命中;导出另走 `fileRequest`。
|
||||||
|
- 网络错误分支整体被块注释([request.js:94](../../YktVue/src/utils/request.js#L94)),**请求失败时不会弹全局错误提示**,多数页面 `.catch()` 为空或只 `console.log`,表现为“点了没反应”。
|
||||||
|
|
||||||
|
### 4.2 导出实例
|
||||||
|
|
||||||
|
[`src/utils/fileRequest.js:6`](../../YktVue/src/utils/fileRequest.js#L6) 固定 `baseURL: '/yktgl'`、`timeout: 50000`。开发环境没有 `/yktgl` 代理(只有 `/dev-api`),**本地导出会 404**;生产同域部署才可用。
|
||||||
|
|
||||||
|
### 4.3 环境变量现状
|
||||||
|
|
||||||
|
| 文件 | `VUE_APP_BASE_API` | 是否生效 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `.env.development` | `/yktgl` | 否,`request.js` 写死 `/dev-api` |
|
||||||
|
| `.env.production` | `/prod-api` | 否,写死 `/yktgl` |
|
||||||
|
| `.env.staging` | `/stage-api` | 否,`build:stage` 也走写死值 |
|
||||||
|
|
||||||
|
改环境时不要只改 `.env`,必须同步改 `request.js`(以及需要时的 `fileRequest.js` 和 `vue.config.js` 代理)。
|
||||||
|
|
||||||
|
## 5. API 封装与后端映射
|
||||||
|
|
||||||
|
### 5.1 模块划分
|
||||||
|
|
||||||
|
| 模块 | 文件 | 接口数 | 用途 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 登录 | `src/api/login.js` | 2 | 验证码(未使用)、登录 |
|
||||||
|
| 叫乘主业务 | `src/api/jcgl/jcgl.js` | 35 | 列表、叫乘、房间、人员、导出、同步、时间规则 |
|
||||||
|
| 交路 | `src/api/jlgl/jlgl.js` | 7 | 交路增删改查、导入、确认 |
|
||||||
|
| 食堂 | `src/api/zhengchuang/mealsOrdering.js` | 9 | 菜品、订单、房间、消费、餐次 |
|
||||||
|
|
||||||
|
### 5.2 叫乘主业务接口映射
|
||||||
|
|
||||||
|
`src/api/jcgl/jcgl.js` 的函数与后端控制器对应关系(后端细节见 [06-接口清单](../06-接口清单.md)):
|
||||||
|
|
||||||
|
| 前端函数 | 方法 | URL | 典型调用方 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `getJcXxList` | POST | `/jcgl/getCcJcXx` | 值班主列表、轮询 |
|
||||||
|
| `getJcXxList_Ls` | POST | `/jcgl/getCcJcXx_Ls` | 历史叫乘(分页/滚动加载) |
|
||||||
|
| `modifyJcXx` | POST | `/jcgl/modifyJcXx` | 修改叫乘信息 |
|
||||||
|
| `cancelTrainAssignment` | POST | `/jcgl/cancelTrainAssignment` | 取消叫乘 |
|
||||||
|
| `handleCheckOut` | POST | `/jcgl/handleCheckOut` | 出乘 |
|
||||||
|
| `handleStopCalling` | POST | `/jcgl/handleStopCalling` | 停止报警/暂停报警 |
|
||||||
|
| `handleTempCalling` | POST | `/jcgl/handleTempCalling` | 语音临叫(广播式) |
|
||||||
|
| `handleRoomCall` | POST | `/jcgl/handleRoomCall`(method=1 语音,=2 喊话) | 单房间临叫 |
|
||||||
|
| `handleRoomCallEnd` | POST | `/jcgl/handleRoomCallEnd` / `...End2` | 停止单房间呼叫 |
|
||||||
|
| `handleMultiRoomCall` | POST | `/jcgl/handleMultiRoomCall` | 多房间喊话 |
|
||||||
|
| `handleMultiRoomCallEnd` | POST | `/jcgl/handleMultiRoomCallEnd` | 停止多房间喊话 |
|
||||||
|
| `getRoomList` | GET | `/jcgl/getRoomList` | 选房、房间维护、终端 |
|
||||||
|
| `getRoomRecommendations` | GET | `/jcgl/getRoomRecommendations` | 选房推荐 |
|
||||||
|
| `modifyRoomStatus` | GET | `/jcgl/modifyRoomStatus` | 停用/恢复房间 |
|
||||||
|
| `startRoomCleaning` | POST | `/clean/startCleaning` | 开始保洁(`deviceCode` 固定 `"123123"`) |
|
||||||
|
| `endRoomCleaning` | POST | `/clean/endCleaning` | 结束保洁 |
|
||||||
|
| `getRyXxByRyId` | POST | `/jcgl/getRyxxByRyId` | 人员查询/维护 |
|
||||||
|
| `modifyRyXx` | POST | `/jcgl/modifyRyXx` | 人员维护保存 |
|
||||||
|
| `deleteRyXx` | POST | `/jcgl/deleteRyXx` | 删除人员 |
|
||||||
|
| `getWslRyXx` | POST | `/jcgl/getWslRyXx` | 未刷脸人员 |
|
||||||
|
| `getRyFjXx` | POST | `/jcgl/getRyFjXx` | 换房前查询同房间人员 |
|
||||||
|
| `exchangeRoom` | POST | `/jcgl/exchangeRoom` | 确认换房 |
|
||||||
|
| `getJlxxList` | GET | `/jcgl/getJlxxList` | 交路列表 |
|
||||||
|
| `getJlXxJcsjList` | POST | `/jlgl/getJlXxJcsjList` | 按开车日期取车次 |
|
||||||
|
| `addJlXx` / `modifyJlXx` / `delJlXx` / `deleteJlXx` / `confirmJlXx` | POST | `/jlgl/*` | 交路维护 |
|
||||||
|
| `getZbyList` / `getGzList` | GET | `/jcgl/getZbyList`、`/jcgl/getGzList` | 值班员/工种字典 |
|
||||||
|
| `getSjgz` | GET | `/jcgl/getSjgz` | 时间规则(150/120/30 分钟) |
|
||||||
|
| `isHoliday` | GET | `/jcgl/isHoliday` | 食堂节假日判断 |
|
||||||
|
| `getSynJcXx` | GET | `/jcgl/getSynJcXx` | 运安同步数据查询 |
|
||||||
|
| `getSynJcXxIsOffline` | POST | `/jwDataLog/getSynJcXxIsOffline` | 运安离线检测 |
|
||||||
|
| `getLatestSyncTime` | GET | `/jcgl/getLatestSyncTime` | 最近同步时间 |
|
||||||
|
| `getDeviceStatusInfo` | POST | `/heartBeat/getDeviceStatusInfo` | 设备心跳/在线状态 |
|
||||||
|
| `getRecordingConfig` | GET | `/jcgl/getRecordingConfig` | 录音回放配置 |
|
||||||
|
| `handleRecharge` | GET | `/recharge/handleRecharge` | 现金充值办理 |
|
||||||
|
| `exportJcXxExcell` | GET(blob) | `/excel/exportJcXxExcell` | 定时/手工导出 |
|
||||||
|
| `getBtje_info` / `getBtje_infoMeal3` / `updateMeal3` | GET/POST | `/jcgl/getBtje_info*`、`/jcgl/updateMeal3` | 餐补余额 |
|
||||||
|
| `submitAll` | GET | `/jcgl/submitAll` | 自助终端/值班台提交入寓登记 |
|
||||||
|
| `getJcxxByRyid` | POST | `/jcgl/getJcxxByRyid` | 按人员查叫乘 |
|
||||||
|
| `jcAlarm` | POST | `/jcgl/jcAlarm` | 设备报警 |
|
||||||
|
| `login` | GET | `/auth/login` | **未被页面使用**,登录走 `api/login.js` |
|
||||||
|
|
||||||
|
### 5.3 食堂接口映射
|
||||||
|
|
||||||
|
| 前端函数 | 方法 | URL |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `getMeals` | GET | `/Meals/getMeals` |
|
||||||
|
| `createOrder` | POST | `/Meals/createOrder` |
|
||||||
|
| `addOrders_MX` | POST | `/Meals/addOrders_MX` |
|
||||||
|
| `OrdersSearch` | GET | `/Meals/OrdersSearch` |
|
||||||
|
| `OrderMX_search` | GET | `/Meals/OrderMX_search` |
|
||||||
|
| `updateStatus` | POST | `/Meals/updateStatus` |
|
||||||
|
| `getRooms` | GET | `/Meals/getRooms` |
|
||||||
|
| `consume` | POST | `/Meals/consume` |
|
||||||
|
| `getCsLb` | GET | `/Meals/getCsLb` |
|
||||||
|
|
||||||
|
## 6. 响应契约与业务判断
|
||||||
|
|
||||||
|
后端统一返回 `Result`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": "00000", "msg": "...", "data": ..., "count": 123 }
|
||||||
|
```
|
||||||
|
|
||||||
|
前端使用约定:
|
||||||
|
|
||||||
|
- `code === '00000'`:成功,`data` 为业务数据,`count` 为分页总数。
|
||||||
|
- `code === '11111'`:业务失败;拦截器仍返回该对象,调用方必须自己处理。
|
||||||
|
- 其他:拦截器弹 `Message.error` 并 reject。
|
||||||
|
- 导出接口返回 blob,不经过统一响应判断。
|
||||||
|
|
||||||
|
## 7. 工程遗留与陷阱
|
||||||
|
|
||||||
|
| 现象 | 位置 | 影响 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `JcXx.vue` 导入不存在的 `auditJlXx` | [JcXx.vue:1392](../../YktVue/src/views/JcXx.vue#L1392) | 构建告警;若将来使用会运行时报错 |
|
||||||
|
| `shijinpeng/main.vue` 导入不存在的 `getRyxx` | [main.vue:280](../../YktVue/src/shijinpeng/main.vue#L280) | 刷脸登记调用时 `TypeError: getRyxx is not a function` |
|
||||||
|
| `utils/permission.js` 依赖不存在的 `@/store` | `src/utils/permission.js` | 死代码,若被引入立即失败 |
|
||||||
|
| `App.vue` 结尾多一个字面量 `3` | [App.vue:32](../../YktVue/src/App.vue#L32) | 无效语句,构建噪音 |
|
||||||
|
| `Home.vue` 使用未注册的 `<test1>` | [Home.vue:6](../../YktVue/src/views/Home.vue#L6) | 访问 `/home` 时渲染告警 |
|
||||||
|
| `README.md` 命令写成 `npm run serve/build` | `YktVue/README.md` | 与 `package.json` 的 `dev/build:prod` 不符 |
|
||||||
|
| 防重复提交只写不判 | [request.js:51](../../YktVue/src/utils/request.js#L51) | 双击可能重复提交 |
|
||||||
|
| 请求失败无全局提示 | [request.js:94](../../YktVue/src/utils/request.js#L94) | 用户无感知,排障困难 |
|
||||||
|
| `build:stage` 没有对应接口前缀 | `.env.staging` | 构建产物仍请求 `/yktgl` |
|
||||||
|
|
||||||
|
## 8. 修改落点速查
|
||||||
|
|
||||||
|
| 需求 | 先看 |
|
||||||
|
| --- | --- |
|
||||||
|
| 新增一个后端接口 | `src/api/jcgl/jcgl.js` 增加封装 → 页面调用 |
|
||||||
|
| 改登录/切换账号 | `Login.vue`、`utils/auth.js`、`router/index.js` |
|
||||||
|
| 改请求超时/前缀/错误提示 | `utils/request.js`、`fileRequest.js`、`vue.config.js` |
|
||||||
|
| 改开发代理指向 | `vue.config.js` 的 `devServer.proxy` |
|
||||||
|
| 新增页面 | `router/index.js` + `src/views/` |
|
||||||
|
| 清理模板遗留 | `plugins/`、`utils/permission.js`、`views/Home.vue`、`About.vue`、`RoomLook copy.vue`、`JcXx.vue.bak_mojibake` |
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# 03 路由与页面职责
|
||||||
|
|
||||||
|
## 1. 路由总表
|
||||||
|
|
||||||
|
路由定义在 [`src/router/index.js`](../../YktVue/src/router/index.js),全部为静态路由,无动态权限路由、无嵌套路由。
|
||||||
|
|
||||||
|
| # | 路径 | 名称 | 组件 | 状态 | 职责 |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| 1 | `/` | — | 重定向 `/login` | 可用 | 默认入口 |
|
||||||
|
| 2 | `/login` | `Login` | `views/Login.vue` | 可用 | 公寓账号 + 密码登录 |
|
||||||
|
| 3 | `/home` | `Home` | `views/Home.vue` | **模板遗留** | 展示 HelloWorld,含未注册组件 |
|
||||||
|
| 4 | `/MealsOrdering` | `MealsOrdering` | `zhengchuang/views/MealsOrdering.vue` | 可用(有缺陷) | 乘务员自助点餐 |
|
||||||
|
| 5 | `/paymentPlatform` | `paymentPlatform` | `zhengchuang/views/paymentPlatform.vue` | **半可用** | 自助结算金额录入,刷脸链路被注释 |
|
||||||
|
| 6 | `/chefOrders` | `chefOrders` | `zhengchuang/views/chefOrders.vue` | 可用 | 后厨订单队列 |
|
||||||
|
| 7 | `/roomService` | `roomService` | `zhengchuang/views/roomService.vue` | **半可用** | 保洁房间卡片与计时,完成不回写后端 |
|
||||||
|
| 8 | `/jcxx` | `JcXx` | `views/JcXx.vue` | 可用 | 值班控制台(主业务) |
|
||||||
|
| 9 | `/JcXx` | — | 重定向 `/jcxx` | 可用 | 大小写兼容 |
|
||||||
|
| 10 | `/about` | `About` | `views/About.vue` | 模板遗留 | 空壳页 |
|
||||||
|
| 11 | `/ykt_main` | `ykt_main` | `shijinpeng/main.vue` | 可用(有缺陷) | 自助入寓/离寓登记终端 |
|
||||||
|
| 12 | `/room` | `room` | `components/Room.vue` | 独立可访问 | 选房组件;正常由值班台弹窗内嵌 |
|
||||||
|
| 13 | `/synJcXx` | `synJcXx` | `views/SynJcXx.vue` | 可用 | 运安同步叫乘数据查询 |
|
||||||
|
|
||||||
|
## 2. 页面分组
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph DutySide["值班侧"]
|
||||||
|
J["/jcxx 主控制台"]
|
||||||
|
S["/synJcXx 同步查询"]
|
||||||
|
end
|
||||||
|
subgraph CrewSide["乘务员自助"]
|
||||||
|
Y["/ykt_main 入寓登记"]
|
||||||
|
M["/MealsOrdering 点餐"]
|
||||||
|
P["/paymentPlatform 结算"]
|
||||||
|
end
|
||||||
|
subgraph CanteenSide["食堂/保洁"]
|
||||||
|
C["/chefOrders 后厨"]
|
||||||
|
R["/roomService 保洁"]
|
||||||
|
end
|
||||||
|
subgraph LegacySide["模板遗留"]
|
||||||
|
H["/home"]
|
||||||
|
A["/about"]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
四组页面之间**没有前端共享状态**,协作方式只有三种:
|
||||||
|
|
||||||
|
1. 后端轮询 / WebSocket 推送;
|
||||||
|
2. `localStorage`(`gyid`、`loginAccount`、`Admin-Token`);
|
||||||
|
3. `BroadcastChannel`(同浏览器多标签页,见 [06](./06-食堂与自助终端模块.md))。
|
||||||
|
|
||||||
|
## 3. 页面职责与关键行为
|
||||||
|
|
||||||
|
### 3.1 `/login` 登录页
|
||||||
|
|
||||||
|
- 表单只有用户名、密码,没有验证码;`getCodeImg()` 虽已封装但未使用。
|
||||||
|
- 成功后写假 token、`gyid`、`loginAccount`,跳 `/jcxx`。
|
||||||
|
- 已登录用户访问 `/login` 会被守卫重定向回 `/jcxx`,无法直接切换账号。
|
||||||
|
- 详见 [02-登录与路由守卫](./02-工程结构与请求链路.md#3-登录与路由守卫)。
|
||||||
|
|
||||||
|
### 3.2 `/jcxx` 值班控制台
|
||||||
|
|
||||||
|
系统的核心页面,承担:
|
||||||
|
|
||||||
|
- 叫乘任务列表(机务/客运、其他人员两个 Tab,但 Tab 仅切换选中态,不改变查询);
|
||||||
|
- 入寓登记、修改叫乘、取消叫乘、出乘、换房、暂停报警、临叫、停止呼叫;
|
||||||
|
- 交路信息查看/确认/维护;
|
||||||
|
- 人员维护、现金充值、历史叫乘、设备状态;
|
||||||
|
- 实时告警音、运安离线报警、同步提醒弹窗与 TTS;
|
||||||
|
- 定时刷新列表、定时导出 Excel。
|
||||||
|
|
||||||
|
完整拆解见 [04-核心页面拆解-JcXx](./04-核心页面拆解-JcXx.md)。
|
||||||
|
|
||||||
|
### 3.3 `/ykt_main` 自助登记终端
|
||||||
|
|
||||||
|
- 无登录态输入,靠 `rlywebsocket/test33` 接收“有人靠近/刷脸”事件后弹出登记窗口。
|
||||||
|
- 页面内固定 `gyid: "SYBXC"`、`gymc: "沈阳站公寓"`,部署到其他公寓必须改代码。
|
||||||
|
- 依赖的 `getRyxx` 在 `api/jcgl/jcgl.js` 中不存在(实际函数名是 `getRyXxByRyId`),刷脸确认时会抛异常;即使修复,入寓分支也只广播、不调用 `/jcgl/submitAll`。
|
||||||
|
- 详见 [06](./06-食堂与自助终端模块.md)。
|
||||||
|
|
||||||
|
### 3.4 食堂四页
|
||||||
|
|
||||||
|
| 页面 | 正常业务闭环 | 当前状态 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 点餐 `MealsOrdering` | 选餐 → 确认 → 刷脸 → `consume` 扣款 → `createOrder` + 明细 → 广播后厨 | 刷卡回调存在;餐次判断与定时器有缺陷 |
|
||||||
|
| 结算 `paymentPlatform` | 录入金额 → 刷脸 → 扣款 → 生成订单 | `initWebSocket()` 被注释,刷脸回调不会触发 |
|
||||||
|
| 后厨 `chefOrders` | 拉取待处理订单 → 查看明细 → 完成订单;收到 `2603` 广播刷新并响铃 | 可用 |
|
||||||
|
| 保洁 `roomService` | 房间卡片 → 开始保洁计时 → 完成 | “完成”只弹提示,不调用后端 |
|
||||||
|
|
||||||
|
详见 [06](./06-食堂与自助终端模块.md)。
|
||||||
|
|
||||||
|
### 3.5 `/synJcXx` 同步查询
|
||||||
|
|
||||||
|
- 只读列表:车次、机车号、开车时间、计划出勤地点、司机姓名、接车方式。
|
||||||
|
- 输入即查询(`@input`),带分页 `[5,10,15,20,30,40,50]`。
|
||||||
|
- 数据来源 `/jcgl/getSynJcXx`,是运安计划同步结果的查询视图,不参与叫乘状态流转。
|
||||||
|
|
||||||
|
### 3.6 `/room` 与房间维护
|
||||||
|
|
||||||
|
- `/room` 可直接访问 `Room.vue`,但正常使用方式是值班台弹窗:`JcXx.vue` 通过 `<Room>` 内嵌,选房后 `$emit('childByValue', room)` 回传。
|
||||||
|
- `RoomLook.vue` 没有独立路由,只作为值班台“房间信息”弹窗使用。
|
||||||
|
- 两者都属于“房间状态”操作面,详见 [06](./06-食堂与自助终端模块.md)。
|
||||||
|
|
||||||
|
## 4. 入口关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Login["/login"] -->|成功| Jcxx["/jcxx"]
|
||||||
|
Jcxx -->|房间信息| RoomLook["RoomLook 弹窗"]
|
||||||
|
Jcxx -->|入寓登记选房| Room["Room 弹窗"]
|
||||||
|
Jcxx -->|历史数据| History["历史叫乘弹窗"]
|
||||||
|
Jcxx -->|交路管理| Jl["交路弹窗"]
|
||||||
|
Jcxx -->|人员维护| Ry["人员维护弹窗"]
|
||||||
|
Jcxx -->|退出| Login
|
||||||
|
Login -.手工访问.-> Terminal["/ykt_main · /MealsOrdering · /paymentPlatform · /chefOrders · /roomService · /synJcXx"]
|
||||||
|
```
|
||||||
|
|
||||||
|
除 `/jcxx` 外,其余业务页面**没有导航菜单**,需要现场终端在浏览器书签/快捷方式中直接配置 URL。这是“终端型系统”的常见做法,但也意味着改路由会直接影响现场快捷方式。
|
||||||
|
|
||||||
|
## 5. 路由层面的注意事项
|
||||||
|
|
||||||
|
| 问题 | 影响 | 位置 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 守卫只判断本地痕迹 | 可绕过;后端 Session 过期后页面仍可进入,接口才报错 | [router/index.js:85](../../YktVue/src/router/index.js#L85) |
|
||||||
|
| 没有 404 路由 | 未知路径会渲染空白 | `router/index.js` |
|
||||||
|
| 没有路由级 code-splitting 之外的懒加载策略 | 首屏仍会加载 Element UI 全量 | `main.js` |
|
||||||
|
| `/home`、`/about` 仍在路由表 | 可被访问,产生无意义页面/告警 | `router/index.js:19`、`:53` |
|
||||||
|
| 终端页面无登录页跳转保护 | 未登录访问会被送到 `/login`,终端无法自动恢复 | 守卫全局生效 |
|
||||||
|
|
||||||
|
## 6. 遗留文件清单
|
||||||
|
|
||||||
|
以下文件不被路由或组件引用,属于历史备份/模板残留,重构时可直接评估删除:
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `src/views/JcXx.vue.bak_mojibake` | 主页面乱码备份 |
|
||||||
|
| `src/components/RoomLook copy.vue` | 房间维护旧版 |
|
||||||
|
| `src/components/media.vue` | 媒体示例组件 |
|
||||||
|
| `src/components/HelloWorld.vue` | Vue CLI 模板组件(仅 `/home` 使用) |
|
||||||
|
| `src/views/Home.vue`、`src/views/About.vue` | Vue CLI 模板页面 |
|
||||||
|
| `src/plugins/*` | RuoYi 插件,未安装 |
|
||||||
|
| `src/utils/permission.js` | 依赖不存在的 `@/store` |
|
||||||
|
| `src/utils/jsencrypt.js`、`src/utils/validate.js` | 模板工具,当前业务未使用 |
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
# 04 核心页面拆解:JcXx 值班控制台
|
||||||
|
|
||||||
|
`src/views/JcXx.vue` 5294 行,模板 1–1389,脚本 1390–4532,样式 4533 之后。它是整个系统的操作中枢,下面按“布局 → 状态 → 列表 → 操作 → 时间规则 → 轮询 → 历史 → 陷阱”拆解。
|
||||||
|
|
||||||
|
## 1. 页面布局
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 跑马灯(当前告警/呼叫提示) │ 大时钟 │ 房间信息 设备信息 人员维护 │
|
||||||
|
│ 机车号 车次 房间号 姓名 [查询][重置] │ │ 交路管理 历史数据 退出 │
|
||||||
|
│ │ │ 语音临叫 喊话临叫 停止呼叫 停止报警 │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Tab:机务人员和客运人员 / 其他人员 │
|
||||||
|
│ 叫乘列表(状态、到寓时间、单位、机车号、姓名、房间号、车次、开车/叫乘/ │
|
||||||
|
│ 复叫/应离寓时间、接车方式、暂停报警) │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ 底部:在寓汇总 / 值班信息 │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
弹窗:历史叫乘、离寓抓拍、设备信息、未刷脸、换房、交路、待确认交路、
|
||||||
|
新增/修改交路、修改叫乘、入寓登记、人员维护、现金充值、交接班、
|
||||||
|
房间选择、房间维护、多房间喊话、出乘确认、广播确认、临叫确认、
|
||||||
|
停止呼叫确认、运安离线告警、交路及叫乘提醒
|
||||||
|
```
|
||||||
|
|
||||||
|
| 区域 | 行号 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 顶部卡片 | 4–176 | 左:跑马灯 + 4 个查询框;中:每秒刷新的大时钟;右:功能按钮 |
|
||||||
|
| 列表卡片 | 178–241 | 两个 Tab(仅视觉)、主表格 |
|
||||||
|
| 主表格 | 183–240 | `height=600`、`row-style=setRowStyle`、单选高亮 |
|
||||||
|
| 底部栏 | 1178–1191 | 在寓人数汇总、值班信息 |
|
||||||
|
| 业务弹窗 | 244–1378 | 见第 7 节 |
|
||||||
|
|
||||||
|
主表格列:序号、状态、到寓时间、单位、机车号、姓名、房间号、出发车次、开车时间、叫乘时间、复叫时间、叫乘日期、应离寓时间、接车方式、操作(暂停报警)。
|
||||||
|
|
||||||
|
## 2. 页面状态
|
||||||
|
|
||||||
|
`data()` 从 1406 行开始,核心字段:
|
||||||
|
|
||||||
|
| 字段 | 行号 | 用途 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gyid` | 1453 | 当前公寓;`created()` 中取 `localStorage.gyid` 或全局 `gyid` |
|
||||||
|
| `apiRoot` | 1459 | WebSocket 主机名 |
|
||||||
|
| `jcxxList` | 1542 | 主列表数据 |
|
||||||
|
| `selectedRow` | 1470 | 当前选中行,所有行操作的入参 |
|
||||||
|
| `JcXxQueryParams` | 1546 | 查询条件:`gyid/jch/cc/fjh/rymc/begindt/enddt` |
|
||||||
|
| `LsJcXxQueryParams` | 1555 | 历史查询:增加 `historyTimeType/pageNum/pageSize` |
|
||||||
|
| `sjgzConfig` | 1631 | 时间规则 `{kjjcsjgz,zjjcsjgz,lysjgz}` |
|
||||||
|
| `dismissedAlarmEvents` | 1430 | 已处理告警事件 key 集合,防止重复响铃 |
|
||||||
|
| `alarmVoiceActive` | 1428 | 报警音是否正在播放 |
|
||||||
|
| `syncSpeechQueue` / `syncSpeechCurrent` | 1627 起 | TTS 播报队列 |
|
||||||
|
| `activeTempCalls` | 1644 | 本页面发起的临叫房间及类型(voice/speech) |
|
||||||
|
| `callListRequestVersion` | 1429 | 列表请求版本号,防止旧响应覆盖新数据 |
|
||||||
|
|
||||||
|
`created()`([JcXx.vue:1726](../../YktVue/src/views/JcXx.vue#L1726))设置 `gyid` 与查询参数,加载交路列表与当前时间;`mounted()`([:1784](../../YktVue/src/views/JcXx.vue#L1784))启动 WebSocket、SIP、字典、列表、时间规则和 4 个定时器。
|
||||||
|
|
||||||
|
## 3. 列表与状态
|
||||||
|
|
||||||
|
### 3.1 状态码映射
|
||||||
|
|
||||||
|
表格“状态”列([JcXx.vue:194](../../YktVue/src/views/JcXx.vue#L194)):
|
||||||
|
|
||||||
|
| `ryzt` | 显示 | 含义 | 行颜色 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `0` | 待叫乘 | 尚未到叫乘时间 | 黄色 `#FFF200` |
|
||||||
|
| `1` | 正在呼叫 | 正在叫乘/通话建立中 | 绿色 `#00FF00` |
|
||||||
|
| `2` | 叫乘报警 | 叫乘未应答 | 红色 `#F56C6C` |
|
||||||
|
| `3` | 待离寓 | 已叫乘完成,等待离寓 | 浅绿 `#B3E19D` |
|
||||||
|
| `4` | 离寓报警 | 超时应离寓 | 红色 `#F56C6C` |
|
||||||
|
| `5` | 正在通话 | 语音通道已建立 | 绿色 `#00FF00` |
|
||||||
|
| 其他 | 已入寓 | 正常在寓 | 默认 |
|
||||||
|
|
||||||
|
### 3.2 行样式与跑马灯
|
||||||
|
|
||||||
|
`setRowStyle(row)`([JcXx.vue:3723](../../YktVue/src/views/JcXx.vue#L3723))按以下优先级返回样式,并**在渲染函数里直接修改 `this.message`**:
|
||||||
|
|
||||||
|
1. `ryzt=0` 且 `missedCallTaskWarning=1`:黄色 + 闪烁动画,提示“叫乘时间已过”;
|
||||||
|
2. `ryzt=1/5`:绿色;
|
||||||
|
3. `ryzt=2/4`:红色;
|
||||||
|
4. 本页发起的临叫:绿色,提示“正在喊话/语音临叫”;
|
||||||
|
5. `jllx=1`:浅蓝 `#d9ecff`;
|
||||||
|
6. `ryzt=3`:浅绿;
|
||||||
|
7. `ryzt=0`:黄色;
|
||||||
|
8. 其他:默认。
|
||||||
|
|
||||||
|
问题:`setRowStyle` 是纯函数位,却在渲染期间写 `this.message`,会触发额外的渲染与响应式更新;表格行数多时可能造成卡顿或“跑马灯内容错行”。修改行样式逻辑时建议把消息计算移出渲染函数。
|
||||||
|
|
||||||
|
### 3.3 接车方式显示
|
||||||
|
|
||||||
|
`cclx` 为“站接”显示站接;“库接/库出”统一显示“库出”;其他为空。
|
||||||
|
|
||||||
|
## 4. 操作矩阵
|
||||||
|
|
||||||
|
所有行级操作都要求先选中行(`selectedRow`),点击行时还会向 SIP 发送一次注册状态([JcXx.vue:3231](../../YktVue/src/views/JcXx.vue#L3231))。
|
||||||
|
|
||||||
|
| 操作 | 入口 | 处理方法 | 后端接口 | 说明 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 查询/重置 | 顶部 | `getJcXxList` / `resetForm` | `/jcgl/getCcJcXx` | 输入即查询;重置只清 4 个文本条件 |
|
||||||
|
| 取消叫乘 | 顶部 | `openCancelTrainAssignment` | `/jcgl/cancelTrainAssignment` | 二次确认;成功后停报警、刷新列表 |
|
||||||
|
| 修改叫乘 | 行/弹窗 | `handleModifyJcXx` → `handleUpdateJcXxConfirm` | `/jcgl/modifyJcXx` | 编辑表单与表格行分离,避免后端拒绝时已改表格 |
|
||||||
|
| 出乘 | 弹窗 | `handleCheckOut` → `handleCheckOutConfirm` | `/jcgl/handleCheckOut` | 确认后不可修改 |
|
||||||
|
| 暂停报警 | 行内按钮 | `handleStopCalling` | `/jcgl/handleStopCalling` | 仅 `ryzt=2/4` 有效;成功后把事件 key 加入已忽略集合 |
|
||||||
|
| 停止报警 | 顶部 | `stopCurrentAlarm` | 同上 | 先校验选中行必须是 `2/4` |
|
||||||
|
| 语音临叫 | 顶部 | `handleCalling` → `handleRoomCallConfirm` | SIP + `/jcgl/handleRoomCall` | 需 SIP 已连接;`callmethod=1` |
|
||||||
|
| 喊话临叫(单房间) | 顶部 | `handleCallingOld` → `handleRoomCallConfirm` | SIP + `/jcgl/handleRoomCall2` | 选中行时 `callmethod=2` |
|
||||||
|
| 喊话临叫(多房间) | 顶部 | `confirmMultiCall` | `/jcgl/handleMultiRoomCall` | 未选中行时弹出多选房间;记录 `lastCalledRooms` |
|
||||||
|
| 停止呼叫 | 顶部 | `handleRoomCallEnd` | `/jcgl/handleMultiRoomCallEnd` 或 `/jcgl/handleRoomCallEnd(2)` | 优先停止多房间,否则停止当前行 |
|
||||||
|
| 换房间 | 弹窗 | `handleChangeRoom` → `exchangeRoomConfirm` | `/jcgl/getRyFjXx`、`/jcgl/exchangeRoom` | 先列出同房间人员,再逐人设置新房间 |
|
||||||
|
| 入寓登记 | 弹窗 | `finalCheck` | `/jcgl/submitAll` | 校验房间/开车日期后提交;成功后关弹窗刷新 |
|
||||||
|
| 人员维护 | 顶部 | `handleUpdateRyXx` | `/jcgl/getRyxxByRyId`、`/jcgl/modifyRyXx`、`/jcgl/deleteRyXx` | 支持刷脸照片上传/替换 |
|
||||||
|
| 现金充值 | WebSocket 触发 | `handleRechargeConfirm` | `/recharge/handleRecharge` | 收到 `cz` 消息弹窗;`cz_cancel` 可按 id 关闭 |
|
||||||
|
| 交路管理 | 顶部 | `handleJlGlClick` | `/jcgl/getJlxxList` | 打开交路列表,可新增/修改/删除/导入 |
|
||||||
|
| 待确认交路 | 交路弹窗 | `handdleDqrButton` → `handleConfirmJlXxClick` | `/jlgl/confirmJlXx` | 按勾选 id 批量确认 |
|
||||||
|
| 历史数据 | 顶部 | `handleLsSjClick` → `loadLsJcXx` | `/jcgl/getCcJcXx_Ls` | 分页 + 滚动加载;可回放录音 |
|
||||||
|
| 设备信息 | 顶部 | `handleDeviceStatus` | `/heartBeat/getDeviceStatusInfo` | 离线设备整行标红 |
|
||||||
|
| 导出 Excel | 定时 | `exportJcXxExcell` | `/excel/exportJcXxExcell` | 每 10 分钟自动下载一次 |
|
||||||
|
| 退出 | 顶部 | `handleLogout` | — | 关 WS、清定时器、清本地登录信息 |
|
||||||
|
|
||||||
|
### 4.1 临叫的 SIP 前置动作
|
||||||
|
|
||||||
|
`handleRoomCallConfirm`([JcXx.vue:4263](../../YktVue/src/views/JcXx.vue#L4263))在调用后端前先向 SIP 发送:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"reqAct": {
|
||||||
|
"type": "call_make",
|
||||||
|
"actId": "actid_12121212",
|
||||||
|
"params": ["sip:1001@10.32.100.166"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 目标 SIP 地址、`actId` 都是硬编码;
|
||||||
|
- `语音临叫` 按钮在 `sipclient.connected == 0` 时禁用,但喊话临叫没有同样保护;
|
||||||
|
- SIP 发送失败不会阻断后端调用,前后端状态可能不一致。
|
||||||
|
|
||||||
|
## 5. 时间规则与校验
|
||||||
|
|
||||||
|
### 5.1 规则来源
|
||||||
|
|
||||||
|
`getSjgzConfig()`([JcXx.vue:3782](../../YktVue/src/views/JcXx.vue#L3782))调用 `/jcgl/getSjgz`,取第一条:
|
||||||
|
|
||||||
|
| 字段 | 默认 | 含义 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `kjjcsjgz` | 150 | 库出/库接提前叫乘分钟数 |
|
||||||
|
| `zjjcsjgz` | 120 | 站接提前叫乘分钟数 |
|
||||||
|
| `lysjgz` | 30 | 叫乘后到应离寓的分钟数 |
|
||||||
|
|
||||||
|
接口失败时页面回退到同一组默认值并提示。
|
||||||
|
|
||||||
|
### 5.2 计算关系
|
||||||
|
|
||||||
|
`test()`(修改叫乘,[JcXx.vue:3901](../../YktVue/src/views/JcXx.vue#L3901))与 `calculateJlxxTime()`(交路新增,[:3998](../../YktVue/src/views/JcXx.vue#L3998)):
|
||||||
|
|
||||||
|
```text
|
||||||
|
叫乘时间 jcsj = 开车时间 kcsj − 规则分钟(站接 zjjcsjgz,库出/库接/未选 kjjcsjgz)
|
||||||
|
复叫时间 fjsj = jcsj + 10 分钟
|
||||||
|
报警时间 jcbjsj = fjsj + 5 分钟
|
||||||
|
应离寓 ylysj = jcsj + lysjgz(默认 30 分钟)
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:交路新增表单里的字段叫 `lysj`,修改叫乘表单里叫 `ylysj`,两者复用同一套计算,但字段名不同。
|
||||||
|
|
||||||
|
### 5.3 合法性校验
|
||||||
|
|
||||||
|
`validateCallDutyTimeline`([JcXx.vue:3852](../../YktVue/src/views/JcXx.vue#L3852))要求:
|
||||||
|
|
||||||
|
1. 五个时间全部存在且格式正确(`yyyy-MM-dd HH:mm[:ss]`);
|
||||||
|
2. 严格满足 `kcsj > ylysj > jcbjsj > fjsj > jcsj`;
|
||||||
|
3. `kcsj − jcsj < 24 小时`。
|
||||||
|
|
||||||
|
`handleJcsjChange`([:3870](../../YktVue/src/views/JcXx.vue#L3870))在手工修改叫乘时间时重算后三个时间,并要求当前开车时间仍然合法。
|
||||||
|
|
||||||
|
### 5.4 修改叫乘的提交
|
||||||
|
|
||||||
|
`handleUpdateJcXxConfirm`([JcXx.vue:3335](../../YktVue/src/views/JcXx.vue#L3335))先规范化 5 个时间字段、再校验时间线,最后提交;`00000` 关闭弹窗刷新列表,`11111` 只弹错误不关闭。
|
||||||
|
|
||||||
|
## 6. 轮询与自动行为
|
||||||
|
|
||||||
|
`mounted()` 注册的定时器:
|
||||||
|
|
||||||
|
| 定时器 | 周期 | 动作 | 副作用 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `latestSyncTimeTimer` | 30 s | `loadLatestSyncTime` → `/jcgl/getLatestSyncTime` | 更新底部“最近同步时间” |
|
||||||
|
| `minuteTimer` | 10 min | `getJcXxList` | 刷新列表并触发告警音/TTS 调度 |
|
||||||
|
| `fiveMinuteTimer` | 10 min | `exportJcXxExcell` | **自动下载 Excel 到浏览器** |
|
||||||
|
| `threeMinuteTimer` | 10 min | `getSynJcXxIsOffline` | 运安离线时弹窗并播放离线报警音 |
|
||||||
|
| `currentDateTimer` | 1 s | 更新 `currentDate` | 大时钟 |
|
||||||
|
|
||||||
|
`getJcXxList`([JcXx.vue:2262](../../YktVue/src/views/JcXx.vue#L2262))用 `callListRequestVersion` 防止旧响应覆盖:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const requestVersion = ++this.callListRequestVersion
|
||||||
|
getJcXxList(params).then(res => {
|
||||||
|
if (requestVersion !== this.callListRequestVersion) return
|
||||||
|
this.jcxxList = res.data
|
||||||
|
this.syncAlarmVoice(this.jcxxList)
|
||||||
|
...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
`handleStopCalling` 成功后主动 `++callListRequestVersion`,使所有在途响应失效,避免“刚停掉的报警又被旧数据拉响”。
|
||||||
|
|
||||||
|
退出/离开页面时 `destroyed`([JcXx.vue:1740](../../YktVue/src/views/JcXx.vue#L1740))清理全部定时器、队列和语音;但 `jlwebsocketclose()` / `jcwebsocketclose()` 被直接调用,而这两个方法内部会执行 `location.reload()`,因此**路由离开本页会触发整页刷新**(详见 05、07)。
|
||||||
|
|
||||||
|
## 7. 弹窗清单
|
||||||
|
|
||||||
|
| 弹窗 | 行号 | 绑定 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 历史叫乘信息 | 244–413 | `visible_jcxx_ls` | 查询、分页、录音回放、离寓抓拍 |
|
||||||
|
| 刷脸离寓抓拍 | 415–426 | `visible_leaveSnapshot` | 图片预览 |
|
||||||
|
| 设备信息 | 428–484 | `visible_sbxx` | 离线设备标红 |
|
||||||
|
| 未刷脸人员 | 486–496 | `visible_wslRy` | 入口按钮当前被注释 |
|
||||||
|
| 换房间 | 498–518 | `visible_hfj` | 逐人选择新房间 |
|
||||||
|
| 交路信息 | 521–584 | `visible_jlxx` | 列表、增删改、导入、确认 |
|
||||||
|
| 待确认交路信息 | 595–642 | `visible_jlqrxx` | 批量确认 |
|
||||||
|
| 新增/修改交路 | 644–779 | `visible_jlxx_add` | 时间自动计算 |
|
||||||
|
| 修改叫乘信息 | 781–898 | `visible_jcxx` | 5 个时间 + 车次选择 |
|
||||||
|
| 入寓登记信息 | 900–988 | `visible_rydj` | 刷脸照片、房间选择 |
|
||||||
|
| 人员维护 | 990–1118 | `visible_ryxxwh` | 查询、编辑、照片 |
|
||||||
|
| 现金充值 | 1120–1176 | `visible_xjcz` | 金额 0–100,WebSocket 触发 |
|
||||||
|
| 交接班 | 1192–1205 | `visible_login` | 登录表单(当前值班台不使用) |
|
||||||
|
| 房间选择 | 1207–1210 | `visible_room` | 内嵌 `Room.vue` |
|
||||||
|
| 房间维护 | 1212–1215 | `visible_roomLook` | 内嵌 `RoomLook.vue` |
|
||||||
|
| 多房间喊话 | 1222–1258 | `dialogMultiCallVisible` | 房间多选 |
|
||||||
|
| 出乘确认 | 1260–1282 | `dialog1Visible` | 不可撤销提示 |
|
||||||
|
| 广播确认 | 1284–1301 | `dialog2Visible` | 所有公共区域呼叫 |
|
||||||
|
| 临叫确认 | 1303–1317 | `dialogCallVisible` | 语音/喊话文案动态 |
|
||||||
|
| 停止呼叫确认 | 1319–1333 | `dialogCallEndVisible` | — |
|
||||||
|
| 运安离线报警 | 1335–1344 | `visible_synJcXxIsOffline` | 同步异常提示 |
|
||||||
|
| 交路及叫乘提醒 | 1347–1378 | `syncDialogVisible` | 分组提醒、10 秒自动关闭、TTS |
|
||||||
|
|
||||||
|
## 8. 历史数据与录音
|
||||||
|
|
||||||
|
- `handleLsSjClick`([JcXx.vue:4312](../../YktVue/src/views/JcXx.vue#L4312))打开弹窗后 `getLsJcXx`。
|
||||||
|
- `loadLsJcXx(reset)`([:4326](../../YktVue/src/views/JcXx.vue#L4326))每次取 100 条,`lsJcxxList.length < count` 时允许继续加载;滚动到底部触发下一页。
|
||||||
|
- 历史查询支持按“入寓时间/离寓时间”切换,日期输入兼容 `8`、`815`、`0815`、`081530` 等简写(2300 行附近)。
|
||||||
|
- 录音:`getRecordingConfig()` 获取基地址,`splitRecordFiles` / `getRecordAudioUrl` / `playRecordVoice` 处理 `recordfile` 逗号分隔的多段录音。
|
||||||
|
- 离寓抓拍:`leaveSnapshotPreviewUrl` 显示照片,加载失败时显示占位。
|
||||||
|
|
||||||
|
## 9. 代码级陷阱
|
||||||
|
|
||||||
|
| 陷阱 | 位置 | 影响 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `setRowStyle` 内改 `this.message` | :3723 | 渲染期副作用,列表大时卡顿/提示错乱 |
|
||||||
|
| `formatTime` 定义两次 | :2276、:3153 | 后者覆盖前者,易误用 |
|
||||||
|
| `destroyed` 调用 `*websocketclose()` | :1743–1744 | 方法内 `location.reload()`,离开页面即刷新 |
|
||||||
|
| WebSocket `onclose` 无条件 `location.reload()` | :2086、:2198 | 后端重启/网络抖动会导致页面反复刷新 |
|
||||||
|
| 自动导出每 10 分钟 | :1792 | 值班机持续产生下载文件,可能占满磁盘 |
|
||||||
|
| 临叫 SIP 目标硬编码 | :4272 | 换 SIP 账号/网段必须改代码 |
|
||||||
|
| 语音临叫依赖 SIP 连接,喊话不依赖 | :153、:157 | 两条路径的前置条件不一致 |
|
||||||
|
| `handleUpdateJcXxConfirm` 只处理 `00000/11111` | :3353 | 其他错误码无提示 |
|
||||||
|
| `handleTabClick` 空实现 | :3779 | 两个 Tab 不改变数据,仅是视觉分组 |
|
||||||
|
| `handleDelete` 使用未安装的 `$modal` | :3034 | 该删除入口不可用 |
|
||||||
|
|
||||||
|
## 10. 修改落点速查
|
||||||
|
|
||||||
|
| 需求 | 修改位置 |
|
||||||
|
| --- | --- |
|
||||||
|
| 增加列表列/状态 | 模板 183–240;状态映射 :194 |
|
||||||
|
| 改行颜色/闪烁规则 | `setRowStyle` :3723 |
|
||||||
|
| 增加行操作按钮 | 模板 234–239 + 新方法 |
|
||||||
|
| 改查询条件 | `JcXxQueryParams` :1546、顶部模板 21–46 |
|
||||||
|
| 改时间计算 | `test` :3901、`calculateJlxxTime` :3998、`buildFollowUpTimes` :3808 |
|
||||||
|
| 改临叫/停止逻辑 | `handleCalling*`、`handleRoomCall*` :4194–4310 |
|
||||||
|
| 改告警/TTS | `syncAlarmVoice` :2742、`enqueueSyncNotice` :2765、`playNextSyncSpeech` :2917 |
|
||||||
|
| 改轮询周期 | `mounted` :1790–1793 |
|
||||||
|
| 改历史查询 | `loadLsJcXx` :4326、历史弹窗 244–413 |
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
# 05 实时通信与语音告警
|
||||||
|
|
||||||
|
前端有 5 条长连接:4 条业务 WebSocket + 1 条本机 SIP WebSocket。它们都不走 axios,地址在代码里硬编码,连接生命周期与页面绑定。
|
||||||
|
|
||||||
|
## 1. 连接清单
|
||||||
|
|
||||||
|
| 连接 | 地址 | 页面 | 用途 | 断线行为 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 叫乘推送 | `ws://{apiRoot}/yktgl/jcwebsocket/{gyid}` | `JcXx.vue` | 叫乘状态、入寓人员、充值、同步提醒 | `location.reload()` |
|
||||||
|
| 交路推送 | `ws://{apiRoot}/yktgl/jlwebsocket/{gyid}` | `JcXx.vue` | 交路更新提醒 | `location.reload()` |
|
||||||
|
| 人员/入住推送 | `ws://{apiRoot}/yktgl/rlywebsocket/test33` | `shijinpeng/main.vue` | 触发自助登记 | `location.reload()` |
|
||||||
|
| 食堂推送 | `ws://{apiRoot}/yktgl/MealsWebsocket/test33` | `MealsOrdering.vue`、`paymentPlatform.vue` | 刷脸/刷卡回调 | `location.reload()` |
|
||||||
|
| SIP 客户端 | `ws://127.0.0.1:9004/sipclient/{gyid}` | `JcXx.vue` | 注册、呼叫指令 | 仅日志,不重连 |
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- `apiRoot = window.location.host`,由 `public/config.js` 注入;地址里再拼 `/yktgl` 上下文。
|
||||||
|
- **协议固定 `ws://`**,没有使用 `config.js` 的 `getWebSocketUrl()`(该函数支持 wss 但无人调用)。
|
||||||
|
- 业务 WebSocket 没有心跳、没有指数退避重连,关闭即整页刷新。
|
||||||
|
- `shijinpeng` 与食堂页面把 username 固定为 `test33`,多终端同时连接时后端广播会给所有 `test33` 会话,无法区分终端。
|
||||||
|
- 后端路由规则见 [后端 07](../07-外部集成与定时任务.md#4-websocket):`jcwebsocket` 只投递给 `username == gyid` 或 `all` 的会话;`jlwebsocket`、`rlywebsocket`、`MealsWebsocket` 为广播。
|
||||||
|
|
||||||
|
## 2. 叫乘推送协议(jcwebsocket)
|
||||||
|
|
||||||
|
消息体是 JSON 字符串,至少包含 `lx`(类型);`JcXx.vue:2097` 的 `switch` 分发:
|
||||||
|
|
||||||
|
| `lx` | 附带的字段 | 前端行为 | 当前状态 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `ry` | `content` | 打开“入寓登记信息”弹窗并填充 | 启用 |
|
||||||
|
| `cz` | `content`、`id`、`deviceCode` | 打开“现金充值”弹窗,记录申请 id | 启用 |
|
||||||
|
| `cz_cancel` | `id` | 仅当 id 与当前弹窗一致时关闭,并提示“乘务员已取消” | 启用 |
|
||||||
|
| `zcxx` | `photoBase64`、`deviceCode`、`zcid` | 打开“注册人员信息”,进入新增人员流程 | 启用 |
|
||||||
|
| `xgxx` | `content`、`newPhotoBase64` | 打开“修改人员信息”,带原照片/新照片 | 启用 |
|
||||||
|
| `refresh` | — | 重新拉取叫乘列表 | 启用 |
|
||||||
|
| `autoCallFailed` | `content`、`roomNo` | 入同步提醒队列(标题“超时未叫乘提醒”)+ 刷新列表 | 启用 |
|
||||||
|
| `missedCallWarning` | `content`、`roomNo` | 入同步提醒队列 | 启用 |
|
||||||
|
| `routeChangeWarning` | `content`、`routeStatus` | 原为交路变更提醒 | **已注释禁用** |
|
||||||
|
| `routeExpiredWarning` | `content`、`roomNo` | 原为运安交路超时提醒 | **已注释禁用** |
|
||||||
|
| `callTimeResetWarning` | `content`、`roomNo` | 原为叫乘时间重置提醒 | **已注释禁用** |
|
||||||
|
| 其他 | — | 忽略 | — |
|
||||||
|
|
||||||
|
后端文档 [06-接口清单](../06-接口清单.md#9-websocket-消息) 目前只列了前 5 类,`cz_cancel`、`autoCallFailed`、`missedCallWarning` 是前端实际已在处理、文档需补齐的消息。
|
||||||
|
|
||||||
|
### 2.1 人员登记链路
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant D as 自助终端/设备
|
||||||
|
participant B as 后端
|
||||||
|
participant W as JcXx 值班台
|
||||||
|
D->>B: 刷脸/读卡事件
|
||||||
|
B->>W: {"lx":"zcxx", photoBase64, zcid, deviceCode}
|
||||||
|
W->>W: 打开注册人员弹窗,设置 ryxx_code='0'
|
||||||
|
W->>B: GET /jcgl/getRyxxByRyId?ryid=...
|
||||||
|
B-->>W: 人员信息(可能不存在)
|
||||||
|
W->>B: POST /jcgl/modifyRyXx?code=0
|
||||||
|
B-->>W: 保存结果
|
||||||
|
```
|
||||||
|
|
||||||
|
`xgxx` 走同一弹窗但 `ryxx_code='1'`,提交时 `code=1`。
|
||||||
|
|
||||||
|
## 3. 交路推送(jlwebsocket)
|
||||||
|
|
||||||
|
`jlwebsocketonmessage`([JcXx.vue:2081](../../YktVue/src/views/JcXx.vue#L2081))不解析消息内容,只做两件事:
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.visible_jlxxtx = true
|
||||||
|
this.playVoice() // 播放 orderCompleteTip.mp3
|
||||||
|
```
|
||||||
|
|
||||||
|
页面右下角出现“交路信息已更新”的浮动提示(`bottom-right-div`),点击后打开交路弹窗。消息内容、变更类型完全依赖用户再查询。
|
||||||
|
|
||||||
|
## 4. 告警链路
|
||||||
|
|
||||||
|
### 4.1 报警音状态机
|
||||||
|
|
||||||
|
相关字段:
|
||||||
|
|
||||||
|
- `alarmVoiceActive`:是否正在播放报警音;
|
||||||
|
- `dismissedAlarmEvents`:已人工处理的事件 key 集合;
|
||||||
|
- `audioPlayerAlarm`:`<audio loop>`,`loop` 绑定 `alarmVoiceActive`。
|
||||||
|
|
||||||
|
`syncAlarmVoice(rows)`([JcXx.vue:2742](../../YktVue/src/views/JcXx.vue#L2742))每次列表刷新后执行:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A["收到 jcxxList"] --> B{"存在 ryzt=2/4 的行?"}
|
||||||
|
B -- 否 --> C{"alarmVoiceActive?"}
|
||||||
|
C -- 是 --> D["stopAlarmVoice()"]
|
||||||
|
C -- 否 --> E["保持静音"]
|
||||||
|
B -- 是 --> F{"该行有 alarmEventKey?"}
|
||||||
|
F -- 是 --> G{"任一 key 未被 dismissed?"}
|
||||||
|
F -- 否 --> H{"stoped != '1'?"}
|
||||||
|
G -- 是 --> I["开始播放报警音"]
|
||||||
|
H -- 是 --> I
|
||||||
|
G -- 否 --> E
|
||||||
|
H -- 否 --> E
|
||||||
|
```
|
||||||
|
|
||||||
|
事件 key 来自后端字段 `alarmEventKey`,可能是逗号分隔的多个 key(`getAlarmEventKeys`)。人工停止报警成功后:
|
||||||
|
|
||||||
|
1. 调用 `/jcgl/handleStopCalling`;
|
||||||
|
2. 把该行所有 key 写入 `dismissedAlarmEvents`;
|
||||||
|
3. `++callListRequestVersion` 使在途列表响应失效;
|
||||||
|
4. 立即 `syncAlarmVoice(this.jcxxList)` 停音;
|
||||||
|
5. 再刷新列表。
|
||||||
|
|
||||||
|
这样即使后端状态尚未落库、旧列表又返回,也不会重新响铃。对应测试见 `tests/alarm-state.test.cjs`。
|
||||||
|
|
||||||
|
### 4.2 停止报警的入口
|
||||||
|
|
||||||
|
| 入口 | 方法 | 条件 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 顶部“停止报警” | `stopCurrentAlarm` | 选中行必须是 `ryzt=2/4` |
|
||||||
|
| 行内“暂停报警” | `handleStopCalling(row)` | 同上 |
|
||||||
|
|
||||||
|
非报警状态点击“暂停报警”只提示“当前状态停止报警无效”。
|
||||||
|
|
||||||
|
## 5. 同步提醒:弹窗队列 + TTS 队列
|
||||||
|
|
||||||
|
`autoCallFailed`、`missedCallWarning` 等消息不直接弹窗,而是走两级队列。
|
||||||
|
|
||||||
|
### 5.1 入队与合并
|
||||||
|
|
||||||
|
`enqueueSyncNotice(title, content)`([JcXx.vue:2765](../../YktVue/src/views/JcXx.vue#L2765)):
|
||||||
|
|
||||||
|
1. 以 `title|content` 为 key 去重;
|
||||||
|
2. 已人工关闭过的 key(`syncDismissedNoticeKeys`)直接丢弃;
|
||||||
|
3. 800 ms 内的多条提醒合并到一次 `flushSyncNotices()`。
|
||||||
|
|
||||||
|
`flushSyncNotices`([:2782](../../YktVue/src/views/JcXx.vue#L2782)):
|
||||||
|
|
||||||
|
- 按 `title` 分组,生成 `sections: [{title, contents[]}]`;
|
||||||
|
- 每个分组进入 TTS 队列;
|
||||||
|
- 若当前已有提醒弹窗,则把新 section 合并进当前弹窗并重置 10 秒关闭计时;
|
||||||
|
- 否则入 `syncDialogQueue`,由 `showNextSyncDialog` 依次展示;
|
||||||
|
- 每次刷新都会调用 `getJcXxList()`。
|
||||||
|
|
||||||
|
### 5.2 弹窗行为
|
||||||
|
|
||||||
|
- 标题固定“交路及叫乘提醒”,展示所有 section;
|
||||||
|
- 10 秒无操作自动关闭(`startSyncDialogCloseTimer`);
|
||||||
|
- 用户手动关闭时,`handleSyncDialogBeforeClose` 把当前所有 section 的 key 写入 `syncDismissedNoticeKeys`;
|
||||||
|
- `@closed` 后展示队列中的下一条;
|
||||||
|
- 关闭后同一内容不会再打扰,直到页面刷新(集合只在 `destroyed` 清空)。
|
||||||
|
|
||||||
|
### 5.3 TTS 播报
|
||||||
|
|
||||||
|
`enqueueSyncSpeech` 把同一 title 下的 contents 用“;”拼成一段文本。播放调度 `playNextSyncSpeech`([JcXx.vue:2917](../../YktVue/src/views/JcXx.vue#L2917)):
|
||||||
|
|
||||||
|
- 使用浏览器 `SpeechSynthesisUtterance`,`lang=zh-CN`、`rate=0.9`;
|
||||||
|
- 单条播完 500 ms 后播下一条;
|
||||||
|
- 若 `isBusinessVoiceBusy()` 为真,则 2 秒后重试;
|
||||||
|
- 业务语音(叫乘/通话/临叫/页面音频/其他 TTS)优先:`getJcXxList` 发现忙时调用 `interruptSyncSpeechForBusinessVoice()`,把当前播报退回队首并 `cancel()`,等业务语音结束再播。
|
||||||
|
|
||||||
|
`isBusinessVoiceBusy`([:2896](../../YktVue/src/views/JcXx.vue#L2896))判定任意一条成立即忙:
|
||||||
|
|
||||||
|
- 列表存在 `ryzt=1/5`;
|
||||||
|
- `activeTempCalls` 非空(本页发起的临叫);
|
||||||
|
- 4 个 `<audio>` 中任意一个正在播放;
|
||||||
|
- 浏览器正在播其他 TTS 且不是同步提醒自己。
|
||||||
|
|
||||||
|
### 5.4 队列字段总览
|
||||||
|
|
||||||
|
| 字段 | 作用 |
|
||||||
|
| --- | --- |
|
||||||
|
| `syncNoticeQueue` / `syncNoticeTimer` | 800 ms 合并窗口 |
|
||||||
|
| `syncDialogQueue` / `syncCurrentDialog` / `syncDialogVisible` | 弹窗队列 |
|
||||||
|
| `syncDialogActive` / `syncDialogCloseTimer` | 弹窗互斥与 10 秒自动关闭 |
|
||||||
|
| `syncDismissedNoticeKeys` | 已关闭提醒去重 |
|
||||||
|
| `syncSpeechQueue` / `syncSpeechCurrent` / `syncSpeechRetryTimer` | TTS 队列与重试 |
|
||||||
|
|
||||||
|
## 6. 运安离线报警
|
||||||
|
|
||||||
|
`getSynJcXxIsOffline` 每 10 分钟调用 `/jwDataLog/getSynJcXxIsOffline`([JcXx.vue:4522](../../YktVue/src/views/JcXx.vue#L4522)):
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (res.data == '1') {
|
||||||
|
this.visible_synJcXxIsOffline = true
|
||||||
|
this.playOfflineAlarmVoice()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 离线弹窗标题“报警”,内容“运安计划数据同步异常,请联系技术人员处理!”;
|
||||||
|
- 离线报警音复用 `alarm.mp3`,但不循环、不参与 `alarmVoiceActive` 状态机;
|
||||||
|
- 只提示一次,不做持续告警,也不会自动关闭(需人工点关闭);
|
||||||
|
- 未做去重,10 分钟一次会重复播放,直到后端恢复。
|
||||||
|
|
||||||
|
## 7. SIP 语音通道
|
||||||
|
|
||||||
|
`initClientSocket`([JcXx.vue:2019](../../YktVue/src/views/JcXx.vue#L2019))连接 `ws://127.0.0.1:9004/sipclient/{gyid}`,连接成功后设置 `sipclient.connected = 1`。
|
||||||
|
|
||||||
|
前端只发送两类报文:
|
||||||
|
|
||||||
|
### 7.1 选中行时注册状态
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"regSta": {
|
||||||
|
"acc_no": 1,
|
||||||
|
"reg_act": 0,
|
||||||
|
"sta": 2,
|
||||||
|
"code": 200,
|
||||||
|
"expire": 180
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `handleRowClick` 中发送([JcXx.vue:3241](../../YktVue/src/views/JcXx.vue#L3241)),目的疑似让 SIP 客户端切换/刷新注册账号。
|
||||||
|
|
||||||
|
### 7.2 发起呼叫
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"reqAct": {
|
||||||
|
"type": "call_make",
|
||||||
|
"actId": "actid_12121212",
|
||||||
|
"params": ["sip:1001@10.32.100.166"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `handleRoomCallConfirm` 中发送([:4268](../../YktVue/src/views/JcXx.vue#L4268)),随后才调用后端 `/jcgl/handleRoomCall(2)`。
|
||||||
|
|
||||||
|
问题:
|
||||||
|
|
||||||
|
- 目标 `sip:1001@10.32.100.166` 与 `actId` 都是硬编码,换环境必须改代码;
|
||||||
|
- SIP 发送与后端调用没有事务关系,任一方失败都会造成“界面显示已呼叫/实际未呼叫”或相反;
|
||||||
|
- 停止呼叫只调后端,没有对应的 SIP `call_end` 报文;
|
||||||
|
- `sipclient.connected` 只在首次 `onopen` 设置,断线后不清零,按钮仍可点。
|
||||||
|
|
||||||
|
## 8. 食堂与自助终端的推送
|
||||||
|
|
||||||
|
| 页面 | 消息处理 | 结果 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `MealsOrdering.vue` | `messageObj.code === '5' && icTag === 1` | 调用 `/Meals/consume` 扣款,成功后 `handleSuccess` 建单;失败提示“卡内余额不足” |
|
||||||
|
| `paymentPlatform.vue` | 同样的回调 | `initWebSocket()` 在 `mounted` 被注释,回调不会触发 |
|
||||||
|
| `shijinpeng/main.vue` | 任意消息 | 重置人员信息、显示“入寓登记,请刷脸!”、开始录像 |
|
||||||
|
| `chefOrders.vue` | 不连 WebSocket | 监听 `BroadcastChannel("myChannel")` 的 `"2603"` 消息刷新订单并响铃 |
|
||||||
|
|
||||||
|
详见 [06-食堂与自助终端模块](./06-食堂与自助终端模块.md)。
|
||||||
|
|
||||||
|
## 9. 连接生命周期与风险
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant P as JcXx.vue
|
||||||
|
participant WS as 业务 WebSocket
|
||||||
|
P->>WS: mounted 建立连接
|
||||||
|
WS-->>P: onopen(仅日志)
|
||||||
|
WS-->>P: onmessage(业务消息)
|
||||||
|
alt 网络抖动/后端重启
|
||||||
|
WS-->>P: onclose
|
||||||
|
P->>P: location.reload()
|
||||||
|
P->>WS: 重新加载页面后重连
|
||||||
|
end
|
||||||
|
alt 退出登录/路由离开
|
||||||
|
P->>WS: close()
|
||||||
|
WS-->>P: onclose
|
||||||
|
P->>P: location.reload()(与方法内清理竞争)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
| 风险 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| 刷新风暴 | 后端重启时所有值班台同时 `reload`,重连后若仍失败会继续刷新 |
|
||||||
|
| 无重连退避 | 没有 `setTimeout` 重连、没有最大重试次数 |
|
||||||
|
| 退出竞争 | `handleLogout` 先 `close()` 再清登录信息,`onclose` 的 `reload` 可能在不同时序触发 |
|
||||||
|
| 路由离开刷新 | `destroyed` 直接调用 `jlwebsocketclose()`/`jcwebsocketclose()`,方法内 `reload()` |
|
||||||
|
| wss 不支持 | HTTPS 部署时 `ws://` 被浏览器拦截 |
|
||||||
|
| 固定 username | 多终端共用 `test33`,消息无法定向 |
|
||||||
|
| 无消息校验 | `JSON.parse(e.data)` 无 try/catch,非法消息会中断回调 |
|
||||||
|
|
||||||
|
## 10. 修改落点
|
||||||
|
|
||||||
|
| 需求 | 位置 |
|
||||||
|
| --- | --- |
|
||||||
|
| 新增叫乘消息类型 | `jcwebsocketonmessage` :2097 |
|
||||||
|
| 改告警判定 | `syncAlarmVoice` :2742、`getAlarmEventKeys` :2739 |
|
||||||
|
| 改提醒弹窗样式/时长 | 模板 1347–1378、`startSyncDialogCloseTimer` :2859 |
|
||||||
|
| 改 TTS 语速/优先级 | `playNextSyncSpeech` :2917、`isBusinessVoiceBusy` :2896 |
|
||||||
|
| 改 WebSocket 地址/重连 | `initWebSocket` :2005、`initClientSocket` :2019 |
|
||||||
|
| 改 SIP 报文 | `handleRowClick` :3241、`handleRoomCallConfirm` :4263 |
|
||||||
|
| 改离线报警 | `getSynJcXxIsOffline` :4522 |
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
# 06 食堂与自助终端模块
|
||||||
|
|
||||||
|
本模块包含 6 个“终端型”界面:自助登记、点餐、结算、后厨、保洁,以及值班台复用的选房/房间维护组件。它们共同的特点是:**无导航、固定 URL、部分公寓/终端标识硬编码、状态靠整页刷新或广播同步**。
|
||||||
|
|
||||||
|
## 1. 自助登记终端 `/ykt_main`
|
||||||
|
|
||||||
|
文件:[`src/shijinpeng/main.vue`](../../YktVue/src/shijinpeng/main.vue)(943 行)。
|
||||||
|
|
||||||
|
### 1.1 定位与配置
|
||||||
|
|
||||||
|
- 面向乘务员本人,部署在公寓大厅触摸屏一体机。
|
||||||
|
- 页面内固定:
|
||||||
|
|
||||||
|
```js
|
||||||
|
gyid: "SYBXC"
|
||||||
|
gymc: "沈阳站公寓"
|
||||||
|
```
|
||||||
|
|
||||||
|
([main.vue:291](../../YktVue/src/shijinpeng/main.vue#L291))
|
||||||
|
|
||||||
|
- 后端查询房间时也使用该 `gyid`,换公寓必须改代码或改成运行时可配。
|
||||||
|
- 连接 `ws://{apiRoot}/yktgl/rlywebsocket/test33`([main.vue:379](../../YktVue/src/shijinpeng/main.vue#L379)),任何消息都会触发“入寓登记,请刷脸!”。
|
||||||
|
|
||||||
|
### 1.2 业务模式
|
||||||
|
|
||||||
|
| 模式 | 入口方法 | `ryzt` | 流程 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 入寓登记 | `rydj()` | `1` | 弹窗 → 刷脸 → `getRyxx(ryid)` 取人员 → `getBtje_info` 取餐补 → `finalCheck` **只广播 `channel_rly_jc` 并整页刷新,不调用后端** |
|
||||||
|
| 出乘离寓 | `ccly()` | `3` | 刷脸 → `getJcxxByRyid(ryid)` 取叫乘记录 → 合并房间信息 → `finalCheck` 调 `/jcgl/submitAll` → 成功广播并整页刷新 |
|
||||||
|
| 就餐补助 | `jcbz()` | `5` | 刷脸 → `getBtje_infoMeal3` → `updateMeal3` 领取第三餐补 |
|
||||||
|
|
||||||
|
入寓登记的关键代码在 `rydj_submit()`([main.vue:426](../../YktVue/src/shijinpeng/main.vue#L426)),但这行:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ..., getRyxx, ... } from "@/api/jcgl/jcgl"
|
||||||
|
```
|
||||||
|
|
||||||
|
`jcgl.js` 并没有导出 `getRyxx`,实际函数名是 `getRyXxByRyId`。**刷脸确认时会抛 `TypeError: getRyxx is not a function`,入寓登记链路目前是断的。**
|
||||||
|
|
||||||
|
### 1.3 录像与刷脸
|
||||||
|
|
||||||
|
- 使用 `navigator.mediaDevices.getDisplayMedia` 录屏(`invokeGetDisplayMedia` / `captureScreen` / `startRecording`,[main.vue:751](../../YktVue/src/shijinpeng/main.vue#L751) 起)。
|
||||||
|
- 一体机需要允许屏幕捕获权限;普通浏览器会弹权限框,不适合无人值守。
|
||||||
|
- 录像在提交后未显式上传,`stopRecording` 的结果处理需结合后端设备协议确认。
|
||||||
|
|
||||||
|
### 1.4 房间选择
|
||||||
|
|
||||||
|
- 页面自行拉取 `getRoomList`,按 `row_sort` 分组,状态统计使用 `zd_roomStatus_groupName`。
|
||||||
|
- 可选房间规则与 `Room.vue` 类似:状态 `1/3/5/6`。
|
||||||
|
- 选择后 `select_room(item)` 把房间字段合并进 `jcxx`,`finalCheck` 时一并提交。
|
||||||
|
|
||||||
|
### 1.5 跨页广播
|
||||||
|
|
||||||
|
`finalCheck` 通过 `BroadcastChannel("channel_rly_jc")` 发送 JSON 字符串([main.vue:676](../../YktVue/src/shijinpeng/main.vue#L676)、[:685](../../YktVue/src/shijinpeng/main.vue#L685))。**仓库内没有任何监听 `channel_rly_jc` 的代码**,这条广播目前是空写;如果要让值班台实时感知,需要在 `JcXx.vue` 增加监听或改用 WebSocket。
|
||||||
|
|
||||||
|
更关键的是 `finalCheck` 的分支([main.vue:675](../../YktVue/src/shijinpeng/main.vue#L675)):
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (this.jcxx.ryzt == '1') { // 入寓登记
|
||||||
|
channelObj.postMessage(...)
|
||||||
|
this.$router.go(0) // 没有 submitAll
|
||||||
|
}
|
||||||
|
if (this.jcxx.ryzt == '3') { // 出乘离寓
|
||||||
|
submitAll(this.jcxx)...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
也就是说,**自助终端的入寓登记即使修好 `getRyxx`,也不会把登记写回后端**,只广播给一个不存在的监听者后刷新页面。这是比导入错误更根本的断链。
|
||||||
|
|
||||||
|
## 2. 点餐终端 `/MealsOrdering`
|
||||||
|
|
||||||
|
文件:[`src/zhengchuang/views/MealsOrdering.vue`](../../YktVue/src/zhengchuang/views/MealsOrdering.vue)(988 行)。
|
||||||
|
|
||||||
|
### 2.1 点餐流程
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as 乘务员
|
||||||
|
participant P as MealsOrdering
|
||||||
|
participant B as 后端 /Meals
|
||||||
|
participant K as 后厨 chefOrders
|
||||||
|
|
||||||
|
U->>P: 选择主食/副食/小菜,加入购物车
|
||||||
|
U->>P: 点击确定
|
||||||
|
P->>P: 显示等待刷脸,30 秒倒计时
|
||||||
|
B-->>P: WS 推送 {code:'5', icName}
|
||||||
|
P->>B: POST /Meals/consume?ryid&xfje
|
||||||
|
alt 扣款成功
|
||||||
|
P->>B: POST /Meals/createOrder
|
||||||
|
loop 每个购物车项
|
||||||
|
P->>B: POST /Meals/addOrders_MX
|
||||||
|
end
|
||||||
|
opt 偏餐 mcb=3
|
||||||
|
P->>K: BroadcastChannel("myChannel").postMessage("2603")
|
||||||
|
end
|
||||||
|
P->>P: 显示成功,3 秒后关闭弹窗
|
||||||
|
else 余额不足
|
||||||
|
P->>U: MessageBox 提示“卡内余额不足”
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
关键点:
|
||||||
|
|
||||||
|
- 人脸/刷卡结果来自 `ws://{apiRoot}/yktgl/MealsWebsocket/test33`([MealsOrdering.vue:392](../../YktVue/src/zhengchuang/views/MealsOrdering.vue#L392))。
|
||||||
|
- **先扣款、后建单**,且建单与明细没有事务:`consume` 成功但 `createOrder` 失败时,钱已扣、订单不存在;`addOrders_MX` 失败被空 `catch` 吞掉,会出现订单少明细。
|
||||||
|
- 成功后 3 秒自动关闭弹窗(`timeCount3`),等待刷脸 30 秒超时则 `window.location.reload()`。
|
||||||
|
|
||||||
|
### 2.2 已知缺陷
|
||||||
|
|
||||||
|
| 缺陷 | 位置 | 影响 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `isMealsClass()` 使用未定义的 `this.hours` | :262、:269 | 条件永远为 false,餐次永远是“偏餐”,`mcb` 恒为 3 |
|
||||||
|
| `setInterval(this.getMealsInfo, ...)`,但方法不存在 | :257 | 30 分钟后定时器报错;菜单不会自动刷新 |
|
||||||
|
| `queryParams` 中 `mcb` 重复声明 | :229、:235 | 后者覆盖前者,当前值 `null` |
|
||||||
|
| `consume()` 方法内调用未定义的 `updateMoney()` | :436 | 若走该路径会报错(实际扣款走 API 的 `consume`) |
|
||||||
|
| `destroyed` 调用 `websocketclose()` | :450 | 方法内 `location.reload()`,离开页面即刷新 |
|
||||||
|
| WebSocket 断开即刷新 | :440 附近 | 网络抖动导致点餐页反复重载 |
|
||||||
|
|
||||||
|
## 3. 结算终端 `/paymentPlatform`
|
||||||
|
|
||||||
|
文件:[`src/zhengchuang/views/paymentPlatform.vue`](../../YktVue/src/zhengchuang/views/paymentPlatform.vue)(570 行)。
|
||||||
|
|
||||||
|
- 复用点餐的菜品/订单 API,页面职责是“录入金额 + 刷脸结算”。
|
||||||
|
- `mounted()` 中 `this.initWebSocket()` 被注释([paymentPlatform.vue:212](../../YktVue/src/zhengchuang/views/paymentPlatform.vue#L212)),**刷脸回调不会触发**;`initWebSocket` 方法本身仍在(:376)。
|
||||||
|
- `isHoliday()`(:224)在节假日把金额锁定:早餐 10 元、正餐 20 元,否则允许手工输入。
|
||||||
|
- `handleConfirm` → 30 秒倒计时等待刷脸 → `handleSuccess` → `createOrder` + 明细。
|
||||||
|
- 该页只导入了 `getMeals/createOrder/addOrders_MX/getCsLb`,**完全没有调用 `/Meals/consume`**;即使恢复 WebSocket,也只是建单、不扣款。
|
||||||
|
- 结论:**当前结算页只能录入金额和生成订单,不能完成真实扣款闭环**,上线前必须确认是否启用。
|
||||||
|
|
||||||
|
## 4. 后厨终端 `/chefOrders`
|
||||||
|
|
||||||
|
文件:[`src/zhengchuang/views/chefOrders.vue`](../../YktVue/src/zhengchuang/views/chefOrders.vue)(532 行)。
|
||||||
|
|
||||||
|
- 拉取待处理订单:`OrdersSearch`(:341),查看明细:`OrderMX_search`(:349)。
|
||||||
|
- 完成订单:`updateStatus(order_id)`(:359),成功后 1 秒关闭弹窗并刷新。
|
||||||
|
- 新单提示:监听 `BroadcastChannel("myChannel")`,收到 `"2603"` 时刷新并播放 `newOrderTip.mp3`(:394–:406)。
|
||||||
|
- 缺陷:`beforeDestroy` 里新建了另一个 `BroadcastChannel` 实例再 `removeEventListener`(:412–:413),**监听器不会被移除**;在单页应用内多次进入会重复响应。
|
||||||
|
|
||||||
|
## 5. 保洁终端 `/roomService`
|
||||||
|
|
||||||
|
文件:[`src/zhengchuang/views/roomService.vue`](../../YktVue/src/zhengchuang/views/roomService.vue)(339 行)。
|
||||||
|
|
||||||
|
- 固定 `gyid: "SYBXC"`、`room_floor: "1"`([roomService.vue:190](../../YktVue/src/zhengchuang/views/roomService.vue#L190))。
|
||||||
|
- `northRoomSearch` / `southRoomSearch` 分别按 `room_face` 拉取南北两侧房间,生成房间卡片。
|
||||||
|
- 点击房间 → `roomClick` → `cleanStart` 打开弹窗并启动秒表。
|
||||||
|
- `cleanComplete()`(:260)**只弹“已完成清扫”并重置计时,不调用 `/clean/endCleaning`**,房间状态不会变化。
|
||||||
|
- 弹窗里的布草/备品/报修区域没有对应接口,属于未接线界面。
|
||||||
|
|
||||||
|
## 6. 选房与房间维护
|
||||||
|
|
||||||
|
### 6.1 `Room.vue` 选房器
|
||||||
|
|
||||||
|
- 数据:`getRoomList()`,按 `room_floor` 分组,统计各状态数量。
|
||||||
|
- 状态颜色:
|
||||||
|
|
||||||
|
| `room_status` | 含义 | 按钮类型 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `1` | 空闲 | success |
|
||||||
|
| `2` | 住满 | info |
|
||||||
|
| `3` | 待清扫 | warning |
|
||||||
|
| `4` | 不能入住 | danger |
|
||||||
|
| `5` | 未满 | primary |
|
||||||
|
| `6` | 正在保洁 | 默认(紫色样式) |
|
||||||
|
|
||||||
|
- `select_room`([Room.vue:209](../../YktVue/src/components/Room.vue#L209))只允许 `1/3/5/6`;其他状态提示“仅状态为 1、3、5、6 的房间可选择入住”。
|
||||||
|
- 推荐房来自父组件传入的 `recommendations`,点击后按 `room_no` 回查真实房间再选中;推荐理由直接显示 `recommend_reason`。
|
||||||
|
- 确认时 `$emit('childByValue', room)`;父组件 `JcXx.vue` 的 `childByValue` 根据当前弹窗把房间合并进入寓表单或换房列表。
|
||||||
|
- 缺陷:状态 `6` 可以选择,但 `zd_roomStatus_statusName` 没有 `6` 分支,确认框会显示“房屋状态:undefined”。
|
||||||
|
|
||||||
|
### 6.2 `RoomLook.vue` 房间维护
|
||||||
|
|
||||||
|
- 数据:`getRoomList()`,状态统计包含 `6`。
|
||||||
|
- 支持**多选相同状态**的房间(`select_room`,[RoomLook.vue:279](../../YktVue/src/components/RoomLook.vue#L279)),混合状态会拒绝。
|
||||||
|
- 批量操作:
|
||||||
|
|
||||||
|
| 操作 | 方法 | 接口 | 前置条件 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 开始保洁 | `startCleanSelected` | `/clean/startCleaning` | 选中状态 `3`(待清扫) |
|
||||||
|
| 结束保洁 | `endCleanSelected` | `/clean/endCleaning` | 选中状态 `6`(正在保洁) |
|
||||||
|
| 设为不能入住 | `setSelectedRoomsUnavailable` | `/jcgl/modifyRoomStatus?zt=4` | 状态 `1/2/3/5` 且房间无人 |
|
||||||
|
| 恢复可入住 | `restoreSelectedRoomsAvailable` | `/jcgl/modifyRoomStatus?zt=1` | 选中状态 `4` |
|
||||||
|
|
||||||
|
- `batchRun` 用 `Promise.all` 并发调用,任一失败会整体 reject,但已成功的房间不会回滚;界面只显示成功提示(失败被 `catch` 吞掉)。
|
||||||
|
- 保洁时长由 `bjkssj` 计算,仅用于展示。
|
||||||
|
|
||||||
|
## 7. 跨页面广播矩阵
|
||||||
|
|
||||||
|
| 通道 | 写入方 | 读取方 | 消息 | 状态 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `myChannel` | `MealsOrdering`(偏餐下单)、`paymentPlatform` | `chefOrders` | `"2603"` | 可用(后厨监听器移除有 bug) |
|
||||||
|
| `channel_rly_jc` | `shijinpeng/main.vue` | 无 | JSON 登记数据 | **空写,无人监听** |
|
||||||
|
| `localStorage.gyid` / `loginAccount` | `Login.vue` | 所有页面/路由守卫 | 登录痕迹 | 可用,但可被手工篡改 |
|
||||||
|
| `location.reload()` / `$router.go(0)` | 各终端 | — | 整页刷新 | 事实上的“状态同步”手段 |
|
||||||
|
|
||||||
|
## 8. 终端模块风险汇总
|
||||||
|
|
||||||
|
| 级别 | 问题 | 位置 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| P0 | 自助终端 `getRyxx` 未导出,且入寓分支不调 `submitAll`,登记链路双重断裂 | `shijinpeng/main.vue:280`、`:428`、`:675` |
|
||||||
|
| P0 | 结算页刷脸链接被注释,且未调用扣款接口,结算闭环不成立 | `paymentPlatform.vue:212`、`:314` |
|
||||||
|
| P1 | 点餐餐次判断恒为偏餐 | `MealsOrdering.vue:262` |
|
||||||
|
| P1 | 点餐 30 分钟定时器调用不存在的方法 | `MealsOrdering.vue:257` |
|
||||||
|
| P1 | 扣款与建单无事务,可能钱扣了没订单 | `MealsOrdering.vue:334` 起 |
|
||||||
|
| P1 | 保洁完成不回写后端 | `roomService.vue:260` |
|
||||||
|
| P1 | 公寓/终端标识硬编码(`SYBXC`、`test33`) | `main.vue:291`、`roomService.vue:190`、各 WS URL |
|
||||||
|
| P2 | 后厨广播监听器泄漏 | `chefOrders.vue:412` |
|
||||||
|
| P2 | `channel_rly_jc` 无人监听 | `main.vue:285` |
|
||||||
|
| P2 | 状态 6 选房确认文案 undefined | `Room.vue:229` |
|
||||||
|
| P2 | 批量操作无失败回滚/提示 | `RoomLook.vue:313` |
|
||||||
|
|
||||||
|
## 9. 修改落点
|
||||||
|
|
||||||
|
| 需求 | 位置 |
|
||||||
|
| --- | --- |
|
||||||
|
| 自助终端支持多公寓 | `main.vue` 的 `gyid`/`gymc`、WS 路径、`roomService.vue` 的 `queryParams.gyid` |
|
||||||
|
| 修复入寓登记 | `main.vue:280` 改导入 `getRyXxByRyId`,同步改 `:428` 调用 |
|
||||||
|
| 启用结算刷脸 | `paymentPlatform.vue:212` 取消注释,并补齐扣款调用 |
|
||||||
|
| 改点餐餐次 | `MealsOrdering.vue`/`paymentPlatform.vue` 的 `isMealsClass`,用 `minute` 计算而非 `hours` |
|
||||||
|
| 改后厨提示 | `chefOrders.vue:394` 的 `handleReceivedMessage` |
|
||||||
|
| 改保洁闭环 | `roomService.vue:260` 接 `/clean/endCleaning` |
|
||||||
|
| 改选房规则 | `Room.vue:210`、`RoomLook.vue:287`、`:318` 起 |
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
# 07 构建部署与风险清单
|
||||||
|
|
||||||
|
## 1. 构建脚本
|
||||||
|
|
||||||
|
[`package.json`](../../YktVue/package.json) 实际脚本:
|
||||||
|
|
||||||
|
| 命令 | 作用 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `npm run dev` | 开发服务器 | 端口 `8080`,`host 0.0.0.0`,启动后自动开浏览器 |
|
||||||
|
| `npm run build:prod` | 生产构建 | 输出 `dist/`,`publicPath=/yktgl/` |
|
||||||
|
| `npm run build:stage` | staging 构建 | 仍请求 `/yktgl`(环境变量未生效) |
|
||||||
|
| `npm run preview` | 预览 | 依赖 `build/index.js`,仓库中不存在该文件 |
|
||||||
|
| `npm run lint` | ESLint | `eslint --ext .js,.vue src` |
|
||||||
|
|
||||||
|
环境要求:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"engines": { "node": ">=16 <19", "npm": ">=8 <11" }
|
||||||
|
```
|
||||||
|
|
||||||
|
实际脚本使用 `node --openssl-legacy-provider`(Vue CLI 4 / webpack 4 在新 OpenSSL 下的兼容做法)。Node 16 使用的是 OpenSSL 1.1.1,可能不识别该参数;建议统一到 Node 18 LTS,并锁定 npm 版本。
|
||||||
|
|
||||||
|
`YktVue/README.md` 仍写 `npm run serve` / `npm run build`,与 `package.json` 不一致,按上表为准。
|
||||||
|
|
||||||
|
## 2. 环境与地址矩阵
|
||||||
|
|
||||||
|
| 环境 | 启动方式 | 页面地址 | 接口 baseURL | WebSocket |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 开发 | `npm run dev` | `http://localhost:8080` | `/dev-api` → 代理到 `http://127.0.0.1:8081/yktgl` | `ws://localhost:8080/yktgl/...` → 开发服务器是否代理 WS 未配置 |
|
||||||
|
| 生产 | `npm run build:prod` | `http://host/yktgl/` | `/yktgl` | `ws://host/yktgl/...` |
|
||||||
|
| staging | `npm run build:stage` | 同生产 | `/yktgl` | 同生产 |
|
||||||
|
|
||||||
|
开发代理配置在 [`vue.config.js`](../../YktVue/vue.config.js):
|
||||||
|
|
||||||
|
```js
|
||||||
|
'/dev-api': {
|
||||||
|
target: 'http://127.0.0.1:8081/yktgl',
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: { '^/dev-api': '' }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- 开发代理只配了 HTTP,没有 `ws: true`;**本地 WebSocket 实际连的是前端 dev server 的 `8080`,不会自动转到 8081**,需要浏览器插件/反向代理或直接改代码。
|
||||||
|
- `.env.*` 的 `VUE_APP_BASE_API` 全部未生效;`request.js` 写死 `/dev-api` 与 `/yktgl`。
|
||||||
|
- `fileRequest.js` 写死 `/yktgl`,开发环境导出 404。
|
||||||
|
|
||||||
|
## 3. 部署要点
|
||||||
|
|
||||||
|
仓库内没有 nginx、Dockerfile、部署脚本,部署依赖现场约定。按代码推断的最小拓扑:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# 前端静态资源
|
||||||
|
location /yktgl/ {
|
||||||
|
root /opt/app; # /opt/app/yktgl/index.html
|
||||||
|
try_files $uri $uri/ /yktgl/index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 后端接口与 WebSocket
|
||||||
|
location /yktgl/ {
|
||||||
|
proxy_pass http://127.0.0.1:8081/yktgl/;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的两段 `location /yktgl/` 会冲突,实际部署需要按路径拆分(例如静态资源用 `/yktgl/static/`、`/yktgl/index.html`,接口用 `/yktgl/jcgl/` 等),或让后端同时托管静态资源。**上线前必须拿到现场真实 nginx 配置**,不要照抄本示例。
|
||||||
|
|
||||||
|
关键约束:
|
||||||
|
|
||||||
|
1. **静态与接口同源**:`publicPath`、`baseURL`、WebSocket 路径都假定 `/yktgl` 由同一个 host 提供。
|
||||||
|
2. **SIP 网关必须在本机 9004**:值班台写死 `ws://127.0.0.1:9004`。
|
||||||
|
3. **HTTPS 不可用**:所有 WebSocket 都是 `ws://`,页面一旦上 HTTPS 会被浏览器按混合内容拦截。
|
||||||
|
4. **浏览器权限**:自助终端使用 `getDisplayMedia` 录屏,需要现场授权;无人值守场景要配置 kiosk 模式与自动授权。
|
||||||
|
5. **多公寓**:当前产物只能通过改 `public/config.js`、`shijinpeng/main.vue`、`roomService.vue` 的常量来切换,不能一套包多公寓运行。
|
||||||
|
|
||||||
|
## 4. 测试基线
|
||||||
|
|
||||||
|
仓库没有 jest/vitest,也没有 `npm test`。现有两个纯 Node 脚本,直接在 `YktVue/` 下运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node tests/alarm-state.test.cjs
|
||||||
|
node tests/recharge-cancellation.cjs
|
||||||
|
```
|
||||||
|
|
||||||
|
| 脚本 | 覆盖内容 | 当前结果(2026-11-07) |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `tests/alarm-state.test.cjs` | 告警事件去重、新事件响铃、分组行、列表响应乱序、停止报警使在途响应失效 | 5 个场景通过 |
|
||||||
|
| `tests/recharge-cancellation.cjs` | 充值弹窗按 id 匹配取消、无关取消、后端拒绝、旧成功响应、网络失败 | 5 个场景通过 |
|
||||||
|
|
||||||
|
两个脚本通过正则截取 `JcXx.vue` 的方法源码再 `new Function` 执行,**重构方法名/缩进会导致测试失效**,改 `JcXx.vue` 后要同步检查。
|
||||||
|
|
||||||
|
建议补充的测试优先级:
|
||||||
|
|
||||||
|
1. 时间规则计算与 24 小时校验(`buildFollowUpTimes`、`validateCallDutyTimeline`);
|
||||||
|
2. 时间输入规范化(`8`、`815`、`0815`、`081530`);
|
||||||
|
3. 房间可选状态过滤(`Room.vue` 的 `1/3/5/6`);
|
||||||
|
4. 请求响应码分支(`11111` 的业务处理);
|
||||||
|
5. 食堂下单失败/部分明细失败的回滚策略(需要先重构)。
|
||||||
|
|
||||||
|
## 5. 风险清单
|
||||||
|
|
||||||
|
### P0:上线/运行阻断
|
||||||
|
|
||||||
|
| # | 风险 | 证据 | 影响 | 建议 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| P0-1 | 登录态是本地假 token,守卫可绕过 | [Login.vue:83](../../YktVue/src/views/Login.vue#L83)、[router/index.js:85](../../YktVue/src/router/index.js#L85) | 任何人写 `localStorage.loginAccount` 即可进入;后端 Session 过期后页面仍可操作,接口才失败 | 后端签发 token/Session 标识,前端守卫校验并处理 401;退出调用后端 |
|
||||||
|
| P0-2 | WebSocket 断开即整页刷新,且 `destroyed` 主动触发 | [JcXx.vue:1743](../../YktVue/src/views/JcXx.vue#L1743)、[:2086](../../YktVue/src/views/JcXx.vue#L2086)、[:2198](../../YktVue/src/views/JcXx.vue#L2198) | 后端重启/网络抖动导致值班台反复重载,告警期间可能丢失操作 | 改为退避重连;`destroyed` 只关闭连接,不调用含 `reload` 的方法 |
|
||||||
|
| P0-3 | 自助终端导入不存在的 `getRyxx`,且入寓分支不提交后端 | [main.vue:280](../../YktVue/src/shijinpeng/main.vue#L280)、[:428](../../YktVue/src/shijinpeng/main.vue#L428)、[:675](../../YktVue/src/shijinpeng/main.vue#L675) | 入寓登记刷脸必抛异常;即使修复,也只广播不落库,终端主功能不可用 | 改为 `getRyXxByRyId`,并在 `ryzt=1` 分支调用 `/jcgl/submitAll` 后联调 |
|
||||||
|
| P0-4 | 结算页刷脸链路被注释且不扣款 | [paymentPlatform.vue:212](../../YktVue/src/zhengchuang/views/paymentPlatform.vue#L212)、[:314](../../YktVue/src/zhengchuang/views/paymentPlatform.vue#L314) | 结算闭环不成立,可能“下单不扣钱” | 确认该页是否在用;启用 WS 并调用 `/Meals/consume` |
|
||||||
|
| P0-5 | 生产强依赖 `ws://` 与本机 SIP | [JcXx.vue:2007](../../YktVue/src/views/JcXx.vue#L2007)、[:2020](../../YktVue/src/views/JcXx.vue#L2020) | HTTPS 部署失败;值班台与 SIP 网关必须同机 | 统一用 `getWebSocketUrl()`;SIP 地址配置化 |
|
||||||
|
| P0-6 | 多公寓/多终端标识硬编码 | `shijinpeng/main.vue:291`、`roomService.vue:190`、各 WS 的 `test33` | 换公寓/多终端需要改代码重打包;消息无法定向 | 改为登录/URL 参数/后端下发 |
|
||||||
|
|
||||||
|
### P1:功能错误或明显数据风险
|
||||||
|
|
||||||
|
| # | 风险 | 证据 | 影响 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| P1-1 | `11111` 被拦截器当成功返回 | [request.js:79](../../YktVue/src/utils/request.js#L79) | 调用方漏判时会把业务失败当成功;各页面处理不一致 |
|
||||||
|
| P1-2 | 网络错误无全局提示,`.catch()` 多为空 | [request.js:94](../../YktVue/src/utils/request.js#L94) | 用户点按钮无反应,排障困难 |
|
||||||
|
| P1-3 | 环境变量不生效、两套 baseURL | `request.js:17`、`fileRequest.js:6` | 切环境/切域名必须改代码;开发导出失败 |
|
||||||
|
| P1-4 | 自动导出每 10 分钟 | [JcXx.vue:1792](../../YktVue/src/views/JcXx.vue#L1792) | 值班机持续下载,占磁盘、干扰浏览器 |
|
||||||
|
| P1-5 | 点餐餐次判断恒为偏餐 | [MealsOrdering.vue:262](../../YktVue/src/zhengchuang/views/MealsOrdering.vue#L262) | 早餐/正餐菜单和价格取错 |
|
||||||
|
| P1-6 | 点餐定时器调用不存在的方法 | [MealsOrdering.vue:257](../../YktVue/src/zhengchuang/views/MealsOrdering.vue#L257) | 30 分钟后报错,菜单不刷新 |
|
||||||
|
| P1-7 | 扣款与建单非原子 | [MealsOrdering.vue:334](../../YktVue/src/zhengchuang/views/MealsOrdering.vue#L334) | 钱扣了没订单,或订单缺明细 |
|
||||||
|
| P1-8 | 保洁完成不回写 | [roomService.vue:260](../../YktVue/src/zhengchuang/views/roomService.vue#L260) | 房间状态永远停在“正在保洁/待清扫” |
|
||||||
|
| P1-9 | `JcXx.vue` 5294 行单体 | `src/views/JcXx.vue` | 修改风险高、测试只能截取方法、多人协作冲突 |
|
||||||
|
| P1-10 | 防重复提交只写不判 | [request.js:51](../../YktVue/src/utils/request.js#L51) | 双击/弱网重试可能重复充值、重复叫乘 |
|
||||||
|
| P1-11 | 前端 gyid 与后端 IP 解析 gyid 双源 | `JcXx.vue:1728`、后端 `getGyIdByIp` | 登录名不是公寓代码时,推送收不到/查询与推送范围不一致 |
|
||||||
|
|
||||||
|
### P2:代码质量与遗留
|
||||||
|
|
||||||
|
| # | 风险 | 证据 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| P2-1 | `setRowStyle` 渲染期修改 `this.message` | `JcXx.vue:3723` |
|
||||||
|
| P2-2 | `formatTime` 重复定义 | `JcXx.vue:2276`、`:3153` |
|
||||||
|
| P2-3 | `JcXx.vue` 导入不存在的 `auditJlXx` | `JcXx.vue:1392` |
|
||||||
|
| P2-4 | `handleDelete` 使用未安装的 `$modal` | `JcXx.vue:3034` |
|
||||||
|
| P2-5 | `plugins/*` 未安装、`utils/permission.js` 依赖不存在的 store | `src/plugins/`、`src/utils/permission.js` |
|
||||||
|
| P2-6 | `App.vue` 结尾多字面量 `3` | `App.vue:32` |
|
||||||
|
| P2-7 | `Home.vue` 使用未注册的 `<test1>` | `Home.vue:6` |
|
||||||
|
| P2-8 | 遗留文件:`JcXx.vue.bak_mojibake`、`RoomLook copy.vue`、`media.vue` | `src/views/`、`src/components/` |
|
||||||
|
| P2-9 | 后厨 `BroadcastChannel` 监听器泄漏 | `chefOrders.vue:412` |
|
||||||
|
| P2-10 | `channel_rly_jc` 无人监听 | `main.vue:285` |
|
||||||
|
| P2-11 | 状态 6 选房确认文案 undefined | `Room.vue:229` |
|
||||||
|
| P2-12 | 批量房间操作无失败回滚/提示 | `RoomLook.vue:313` |
|
||||||
|
| P2-13 | 无 404 路由 | `router/index.js` |
|
||||||
|
| P2-14 | README 命令与实际脚本不一致 | `YktVue/README.md` |
|
||||||
|
|
||||||
|
## 6. 改动落点速查
|
||||||
|
|
||||||
|
| 需求类型 | 首选落点 | 需要同步 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 新增业务接口 | `src/api/jcgl/jcgl.js` | 页面调用、后端文档 06 |
|
||||||
|
| 改登录/鉴权 | `Login.vue`、`utils/auth.js`、`router/index.js`、`request.js` | 后端 `/auth/*`、部署 Session |
|
||||||
|
| 改 WebSocket/告警 | `JcXx.vue` 的 `initWebSocket`、`jcwebsocketonmessage`、`syncAlarmVoice` | 后端 `Jcwebsocket`、文档 05 |
|
||||||
|
| 改叫乘操作 | `JcXx.vue` 对应 `handle*` 方法 | 后端 `JcglController/Service`、文档 04 |
|
||||||
|
| 改房间状态 | `Room.vue`、`RoomLook.vue` | `/jcgl/getRoomList`、`/clean/*`、状态码表 |
|
||||||
|
| 改自助终端 | `shijinpeng/main.vue` | `rlywebsocket`、`/jcgl/submitAll`、设备录像协议 |
|
||||||
|
| 改食堂 | `zhengchuang/views/*`、`api/zhengchuang/mealsOrdering.js` | `/Meals/*`、`MealsWebsocket`、广播协议 |
|
||||||
|
| 改构建/代理 | `vue.config.js`、`request.js`、`fileRequest.js` | nginx、`.env.*`、部署文档 |
|
||||||
|
|
||||||
|
## 7. 待确认问题
|
||||||
|
|
||||||
|
以下问题无法仅从代码判断,需要业务/现场确认:
|
||||||
|
|
||||||
|
1. `paymentPlatform` 是否仍在用?如果不用,是否下线路由和页面?
|
||||||
|
2. `shijinpeng/main.vue` 的入寓登记是否还有现场依赖?`getRyxx` 是改名遗漏还是有意停用?
|
||||||
|
3. 现场是否有 HTTPS/域名计划?如果有,WebSocket 必须改 `wss`,SIP 也要确认是否支持 TLS。
|
||||||
|
4. 自动导出 Excel 是业务要求还是调试遗留?如果是要求,应改为后端定时任务或手工导出。
|
||||||
|
5. 多公寓是否仍靠“一套代码改常量分别打包”?是否有统一配置中心计划?
|
||||||
|
6. 值班台是否会在同一浏览器打开多个页面?`location.reload()` 和 `BroadcastChannel` 的假设都基于单页/单终端。
|
||||||
|
7. 后端 `jcwebsocket` 的 `cz_cancel`、`autoCallFailed`、`missedCallWarning` 消息是否已稳定?后端文档需要同步补齐。
|
||||||
|
|
||||||
|
## 8. 建议的迭代顺序
|
||||||
|
|
||||||
|
1. **先修 P0 阻断**:自助终端导入、结算闭环确认、WebSocket 重连、鉴权方案。
|
||||||
|
2. **再修 P1 数据风险**:扣款/建单一致性、自动导出、餐次判断、时间规则测试。
|
||||||
|
3. **然后做结构治理**:拆分 `JcXx.vue`(布局 / 列表 / 告警 / 操作 / 历史),统一请求层与环境配置。
|
||||||
|
4. **最后清遗留**:删除模板页面/插件/备份文件,补 404、补测试、更新 README。
|
||||||
|
|
||||||
|
## 9. 文档维护
|
||||||
|
|
||||||
|
- 本目录与后端文档同基准提交;改接口、改路由、改 WebSocket 消息时同步更新对应章节。
|
||||||
|
- 行号会随重构漂移,检索时优先用方法名/文件名。
|
||||||
|
- 新增前端文档时在 [README](./README.md) 索引中登记,并保持与 [后端文档索引](../README.md) 的交叉链接。
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# 叫乘管理系统 前端梳理文档
|
||||||
|
|
||||||
|
本目录是对 `YktVue/` 前端工程的结构化梳理,与后端文档 `../README.md` 配套使用。目标同样是给后续迭代一张“地图”:页面在哪里、数据从哪来、实时消息怎么走、改动会落到哪些文件。
|
||||||
|
|
||||||
|
> 适用范围:`YktVue/`(Vue 2 + Element UI)。
|
||||||
|
> 梳理基准:`main` 分支提交 `135a192`(2026-11-07),前端有效源码约 1.39 万行(不含备份/模板遗留)。
|
||||||
|
> 后端契约以 `yktgl/` 同提交为准,详见 [后端文档索引](../README.md)。
|
||||||
|
|
||||||
|
## 文档索引
|
||||||
|
|
||||||
|
| 文档 | 内容 | 适用场景 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [01-前端总览与技术栈.md](./01-前端总览与技术栈.md) | 系统定位、使用角色、运行拓扑、技术栈、四类界面 | 新人入门、方案评审 |
|
||||||
|
| [02-工程结构与请求链路.md](./02-工程结构与请求链路.md) | 目录结构、启动装配、登录与路由守卫、axios 链路、API 封装与后端映射 | 找代码、改接口、排网络问题 |
|
||||||
|
| [03-路由与页面职责.md](./03-路由与页面职责.md) | 13 条路由、页面分组、入口关系、遗留页面 | 评估页面改动影响面 |
|
||||||
|
| [04-核心页面拆解-JcXx.md](./04-核心页面拆解-JcXx.md) | 值班主界面布局、状态与配色、全部操作、时间规则、轮询、历史数据 | 改叫乘业务前必读 |
|
||||||
|
| [05-实时通信与语音告警.md](./05-实时通信与语音告警.md) | 4 路 WebSocket + SIP、消息协议、告警状态机、弹窗队列、TTS 队列 | 改推送/告警/语音 |
|
||||||
|
| [06-食堂与自助终端模块.md](./06-食堂与自助终端模块.md) | 自助登记终端、点餐/结算/厨师/保洁终端、房间选择与房间维护 | 改终端类需求 |
|
||||||
|
| [07-构建部署与风险清单.md](./07-构建部署与风险清单.md) | 构建脚本、环境变量、部署要点、测试基线、P0/P1/P2 风险 | 排期、上线、评审 |
|
||||||
|
|
||||||
|
## 建议阅读路径
|
||||||
|
|
||||||
|
- **第一次接触前端**:01 → 02 → 03 → 04。
|
||||||
|
- **接一个叫乘需求**:04 看页面与操作 → 05 看消息 → 02 查接口 → 07 查风险。
|
||||||
|
- **接一个终端/食堂需求**:06 → 02(API 封装)→ 07(构建与遗留问题)。
|
||||||
|
- **线上排障**:05(WebSocket/告警)→ 02(请求 baseURL/响应码)→ 07(已知缺陷)。
|
||||||
|
- **准备重构**:02(工程结构)→ 04(单体页面)→ 07(风险与落点)。
|
||||||
|
|
||||||
|
## 快速事实
|
||||||
|
|
||||||
|
- 技术栈:Vue 2.6.12 + Vue Router 3.4.9 + Element UI 2.15.13 + axios 0.24.0 + ECharts 5.4.0,Vue CLI 4.4.6 / webpack 4。
|
||||||
|
- 启动脚本是 `npm run dev`(不是 README 里写的 `npm run serve`),开发端口 `8080`,代理 `/dev-api` → `http://127.0.0.1:8081/yktgl`。
|
||||||
|
- 生产 `publicPath` 为 `/yktgl/`,接口 `baseURL` 固定 `/yktgl`,按“前后端同域反向代理”部署设计。
|
||||||
|
- 登录走后端 `/auth/logon`:只校验公寓账号与来源 IP,**后端不返回 token**,前端落一个 `fake-token-*`,并把用户名同时写入 `gyid` 与 `loginAccount`。
|
||||||
|
- 主界面 `src/views/JcXx.vue` 5294 行,是绝对的单体页面:布局、状态、告警、TTS、SIP、历史、导出全在一个文件里。
|
||||||
|
- 实时通道有 4 类业务 WebSocket(叫乘/交路/人员/食堂)外加 1 路本机 SIP WebSocket(`ws://127.0.0.1:9004/sipclient/{gyid}`)。
|
||||||
|
- 前端没有 Vuex store、没有安装 `src/plugins/*`;`utils/permission.js` 与部分 RuoYi 模板代码是死代码。
|
||||||
|
- 已有两个纯 Node 测试脚本:`tests/alarm-state.test.cjs`、`tests/recharge-cancellation.cjs`,无 jest/npm test。
|
||||||
|
|
||||||
|
## 约定与说明
|
||||||
|
|
||||||
|
- 文档中的“行号”以本提交源码为准,重构后会漂移,优先按方法名/文件名检索。
|
||||||
|
- 前端很多页面依赖全局变量 `apiRoot`、`gyid`(由 `public/config.js` 注入),不是模块导入;搜索时直接搜变量名。
|
||||||
|
- 标注“已禁用/未接线”的代码表示界面上仍存在,但当前不会触发后端动作,改动前需确认是否要恢复。
|
||||||
|
- 本目录只做梳理,不对既有代码做修正;发现的问题统一收敛在 07 的风险清单。
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="web" name="Web">
|
||||||
|
<configuration>
|
||||||
|
<webroots />
|
||||||
|
<sourceRoots>
|
||||||
|
<root url="file://$MODULE_DIR$/src/main/java" />
|
||||||
|
<root url="file://$MODULE_DIR$/src/main/resources" />
|
||||||
|
</sourceRoots>
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
<facet type="Spring" name="Spring">
|
||||||
|
<configuration />
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||||
|
<output url="file://$MODULE_DIR$/target/classes" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.18" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.32" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-websocket:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-messaging:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-websocket:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-quartz:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.29" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.quartz-scheduler:quartz:2.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.mchange:mchange-commons-java:0.2.15" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.20" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.20" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.13.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.2.0.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:3.5.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.13.4.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.13.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.68" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.68" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.68" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:3.3.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.10.RELEASE" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.84.Final" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.24" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.6.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.6.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.6.9" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.session:spring-session-data-redis:2.6.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.session:spring-session-core:2.6.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-boot-starter:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-extension:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-core:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-annotation:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: cn.com.kingbase:kingbase8:8.6.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="RUNTIME" name="Maven: com.mysql:mysql-connector-j:8.0.31" level="project" />
|
||||||
|
<orderEntry type="library" scope="RUNTIME" name="Maven: com.oracle.database.jdbc:ojdbc8:21.3.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.oracle.ojdbc:orai18n:19.3.0.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.6.13" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.6.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:json-smart:2.4.8" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.minidev:accessors-smart:2.4.8" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.ow2.asm:asm:9.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: jakarta.xml.bind:jakarta.xml.bind-api:2.3.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: jakarta.activation:jakarta.activation-api:1.2.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.21.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest:2.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.8.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:4.0.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: net.bytebuddy:byte-buddy:1.11.22" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.11.22" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:3.2" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-junit-jupiter:4.0.0" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.3.23" level="project" />
|
||||||
|
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.8.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.sun.xml.bind:jaxb-impl:2.3.3" level="project" />
|
||||||
|
<orderEntry type="library" scope="RUNTIME" name="Maven: com.sun.activation:jakarta.activation:1.2.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.sun.activation:javax.activation:1.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.jws:javax.jws-api:1.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.xml.ws:jaxws-api:2.3.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.xml.soap:javax.xml.soap-api:1.4.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:4.1.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.7" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.6" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.4.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.32" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.fazecast:jSerialComm:2.9.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.asteriskjava:asterisk-java:3.38.0-zfjia" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.reflections:reflections:0.10.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.javassist:javassist:3.28.0-GA" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.guava:guava:31.1-jre" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:3.12.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.11.0" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
|
||||||
|
<orderEntry type="library" name="Maven: net.java.dev.jna:jna:5.13.0" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Reference in new issue
Block a user