56 KiB
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. 现状评估
- 2. 目标架构
- 3. 端职责边界
- 4. 领域与模块划分
- 5. 数据架构
- 6. 接口与集成
- 7. 设备接入方案
- 8. 部署与运行
- 9. 迁移与实施路径
- 10. 风险与决策点
- 11. 结论与优先级
- 附录 A 术语表
- 附录 B 图表清单
- 附录 C 代码证据索引
- 附录 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') |
|
| 值班能力集中在单页 | 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 与目标架构不一致的核心点
- “平台—公寓”未分层,只靠
centerServerUrl字符串互调。注册、交路两条链路都是“同一套 Controller 既当设备接口又当中心接口”,无版本、无契约、无重试与幂等。 - 公寓身份靠 IP 推断且多公寓共享库。这是“一实例多公寓”的妥协设计,直接阻碍“公寓本地数据本地存”。
- 叫乘执行、设备接入、平台接入三者同进程。平台不可达会拖累叫乘主链路,叫乘高峰也会挤占同步线程(
AsyncConfig核心 10 / 最大 200 / 队列 10,队列极小)。 - 账务散落。余额在公寓库被直接更新,餐饮、售货机、充值三条链路各自改余额,缺少统一流水与对账口径。
- 设备通道不可靠。一次性投递 + 全局口令 + 无 ACK,是弱网现场最典型故障源。
- 状态机与视图耦合。
ryzt由设备上报、Quartz、AMI 事件、人工操作共同写入,缺少单一写入口;应用端与公寓端同库后风险被放大。
2. 目标架构
2.1 逻辑架构
图 2-1 目标逻辑架构
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 部署拓扑
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
拓扑要点
- 平台端不进公寓内网:所有跨端流量由公寓端主动出站发起,规避现场 NAT/防火墙,并让平台与设备链路彻底解耦。
- 公寓端 = 部署单元 = 公寓隔离单元:一公寓一实例一库(或独立 schema),
gyid由部署参数固定。 - 应用端不新增进程与库:值班员访问
http://<公寓服务器>/duty,与公寓端同 JVM、同库、同 Nginx。 - 平台端可多实例;公寓端的 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 |
公寓隔离方式
- 部署期固定
apartment.gyId,服务启动即校验;gyid不再从请求 IP 推断,getGyIdByIp降级为旧设备兼容兜底并打告警。 - 库级隔离:一公寓一 schema/库 + 独立连接账号,账号仅对本库有 DML 权限,对平台库无任何权限。
- 请求级隔离:值班员登录后
gyid写入会话与令牌声明,服务层用拦截器强制注入,业务 SQL 一律带gyid条件。 - 设备级隔离:设备注册时绑定
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 同库边界防混乱
- 表归属清单(Ownership Matrix):每张表标注
owner=platform|apartment|duty、允许的写入模块、是否为上报源;越权写入纳入 Code Review 检查项。 - 命名分区:执行域沿用
GY_*(避免大规模迁移),应用域新增DUTY_*(操作审计、人工干预、审核、交接班);报表/只读视图统一V_*,禁止跨域直写。 - 模块依赖单向:
module-duty → module-apartment → module-platform-client,禁止反向依赖;用 Maven 模块或架构约束测试固定。 - 禁止跨端 SQL 关联:不在公寓库写“需要平台数据才能算”的统计 SQL,一律先落到本地快照。
gyid强制注入:拦截器统一注入并校验,任何 SQL 缺gyid视为缺陷;新代码统一走上下文,不再逐处解析 IP。- 状态字段单写入口:
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 上报协议
信封结构(所有上行接口统一)
{
"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": {}
}
]
}
协议要点:
occurredAt(现场发生时间)、receivedAt(公寓端入库时间)、serverReceivedAt(平台接收时间)三时间戳并存,用于处理时钟差异与迟到数据。idempotencyKey = hash(gyId + bizType + bizId + bizVersion):同一业务对象同一版本只生效一次;版本递增用于“更正上报”。watermark:公寓端本地自增序号,平台据此判断漏报/乱序并作为对账水位;现状GY_SYN_JCXX_STATUS(0/1)可作为该思路的历史参照。- 批量上限建议单批 ≤ 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 接入形态
- 统一网关入口
/apt/dev/{deviceType}/register|heartbeat|event|command/ack,把现有 6 个*Device包的重复协议收敛为“网关 + 类型插件”(叫乘屏、签到机、房间屏、消费机、注册机、售货机)。 - 设备只连本公寓服务器,内网优先;公寓端不暴露公网入口。
- 协议保持现有 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 告警处理
- 判定在公寓端:叫乘未应答、复叫未应答、叫乘结束未应答、超时未离寓、设备离线、AMI 不可用、串口异常、上报积压。
- 两级输出:本地即时告警(应用端弹窗/声响/TTS,走本地 WebSocket)与平台摘要上报(数量、类型、最近发生时间,不逐条上报)。
- 现有
GYGL_JGXX与is_jcbj/is_lybj语义保留,作为本地告警事实表。
7.5 本地数据缓存
- 主数据缓存:人员(含照片)、交路、时间规则、节假日、房间属性,带
version + validUntil,过期只提示不阻断。 - 指令缓存:可靠队列(本地库表 + 状态机)。
- 事件缓存:设备事件先落本地(
deviceCode + deviceEventId幂等,沿用GYGL_LY_EVENT设计),再异步上报。 - 媒体缓存:离寓抓拍、录音本地保存 + 生命周期清理(沿用
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 思路 |
— |
隔离与网络:
- 一公寓一实例一库,Nginx 按公寓内网域名/端口区分;平台端不配置到公寓的路由。
- 跨端仅允许公寓 → 平台出站 HTTPS;平台侧以
gyId+ 客户端证书/令牌双向认证。 - 反向代理必须透传真实 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 实施路径
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 总体结论
- 拆分方向可行,且现状已有雏形。
centerServerUrl的双向调用、getApartmentPersonData*/synFinanceData、GY_SYN_JCXX_STATUS状态位,本质是“平台—公寓”关系未完成的形态;本次重构是把隐式关系显式化,而非推倒重建。 - 最大障碍不是技术选型,而是三件事:公寓身份(IP 推断 → 部署绑定)、数据归属(共享库 → 库隔离)、状态写入口分散(多写 → 单一状态机)。
- 公寓端用 RuoYi 新建是合理的。设备网关、执行引擎、上报器、值班 API 天然属于“管理后台 + 本地接入”形态,可复用 RBAC、定时任务、代码生成;但必须约定“RuoYi 管本地账号、平台管全局账号”,否则权限体系会打架。
- 应用端不独立是正确的。值班员的全部操作都必须落在公寓本地事实库上,独立服务只会带来跨服务事务与延迟;同代码同库 + 模块边界 + 状态机单入口足以支撑。
- 必须先做阶段零。
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、4、5 章为模板,产出《表归属矩阵》与《接口归属清单》两份工作底稿。
- 以第 6 章为蓝本,先冻结 v1 契约(含错误码与幂等语义),再进入任何编码。
- 以第 3.3 节为基础,明确“值班员可写字段白名单”,作为 Code Review 检查项。
- 本文落盘后,在
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 文档维护约定
- 本文为设计方案,实施过程中若与代码现状出现偏差,以代码为准并同步更新本文,不得反向以文档为借口修改既有约定。
- 新增/调整端职责、模块划分、跨端接口时,同步更新第 3、4、6 章与附录 B 的图表清单。
- 每个迁移阶段结束,在第 9 章对应阶段表下追加“实际完成情况”与偏差说明。
- 决策点在 10.2 定稿后,从“待决策”移入正文对应章节,并保留决策时间与决策人。