Files
jcgl-dev/docs/10-架构优化方案-三端拆分.md
zfjia 329e27b515 初始提交:三端设计文档与 dev 代码基线
docs/:系统梳理、架构优化方案、CR-02 三端功能设计修订(含 §15 三端一致性同步与平台统计分析)、公寓端/应用端/平台端分册、公寓统计分析与排名报表、公寓端小步迭代开发计划(IT-0~IT-8)

dev/:RuoYi-Vue-master(后端)与 RuoYi-Vue2-master(前端)官方上游基线,未改动
2026-11-10 13:43:05 +08:00

128 KiB
Raw Permalink Blame History

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
v1.2 2026-11-07 回填公寓端设计的差异确认结果:表 2-2(不引入代码生成模块)、表 2-3(前端静态路由实现落点)、2.5 末段(操作域表名)、表 5-3(补归档表)、表 5-4(排序规则例外与隔离级别口径)、表 5-5(备份恢复行不再写非法枚举值)、表 5-6(隔离级别改部署待办、排序规则指向例外)、表 5-9(第 1、7 项口径)、表 7-4(增「落库载体」列)
v1.3 2026-11-09 同步 docs/backend/10 v1.3(CR-01「本地建单与本地调整」)口径:本地建单、apt_local_task、要素 / 时刻受控命令、D8' 时刻归属;按附录 D 核对第 3、4、6 章
v1.4 2026-11-09 落实 docs/公寓端/00 对公寓端功能的重新规划:三端覆盖范围、交互协议与交互数据、模块与数据表设计、关键流程变更以 docs/设计变更/03-三端功能设计修订(CR-02).md 为权威增量(§3 端职责、§4 模块划分、§6 接口契约同步改判,详见 CR-02 §8 施工单);跨端接口仍为 20 个编号、不新增不重排,附录 B 图表索引不变;公寓本地库业务表口径统一为 58 张
v1.5 2026-11-09 落实 docs/公寓端/00 v1.1 的 Asterisk 配置数据管理模块(分机表 / 呼叫记录表 / 录音文件表 / 注册在线状态表的字段、CRUD、权限)与 SIP 分机离线告警规则;补遗见 docs/设计变更/03 §10(CR-C15CR-C19、F-I、T-17、R-68R-76、Q-26~Q-28);新增 apt_sip_reg_status,公寓本地库业务表口径 58 → 59 张;§5.4 表 5-3 的 APT_SIP_ENDPOINT.register_status 枚举补充为 ONLINE/OFFLINE/UNREACHABLE/UNKNOWN,表 7-4 的 sync_state 四值状态机与附录 B 图表索引不变
v1.6 2026-11-09 明确叫乘功能的两类实现方式及其业务流程:SIP 语音叫乘(Asterisk 主动呼叫、房间 SIP 终端接听入会后播放提示语音、状态依 AMI 事件经状态机上报)与平板叫乘(平板拉取任务、按 jcsj 本地定时播放、刷脸签到结束叫乘、结果上报公寓服务),含触发条件、交互流程、状态上报机制与结果反馈路径;流程权威表述为 docs/公寓端/05 §9,裁决与施工单见 docs/设计变更/03 §11(CR-C20CR-C23、R-77R-84、Q-29);§7.7 / §7.9 表 7-5、表 7-6 与附录 B 图表索引不变,未新增跨端接口编号或数据表
v1.7 2026-11-09 新增 docs/公寓端/10「人脸数据下发管理」模块(AF-01AF-06:注册与平台同步、平台下载入库、签到设备下发、消费 / 叫乘按设备范围隔离、离寓自动擦除、长期驻留保留);注册链路按 CR-C25 改判为「签到终端发起注册申请并上传人脸 → 值班员在值班台完成人员注册 → 注册成功后人脸进入公寓服务系统 → 分别上传平台与下发公寓内设备」,两条路径解耦并行、互不阻塞,平台 personRegVerdicts[] 降级为主档同步回执;人员主数据照片与特征值按 CR-C24 允许平台 ↔ 公寓双向同步,业务抓拍、录音与签到现场图仍不出公寓。裁决 / 流程 / 施工单见 docs/设计变更/03 §12(CR-C24CR-C25、F-J、R-85R-93、Q-30Q-35、验收 15~17)。不新增业务表、不新增跨端编号,公寓本地库仍 59 张、契约 v2-draft、平台零回调;§7.7 / §7.9 表 7-5、表 7-6 与附录 B 图表索引不变
v1.8 2026-11-10 新增 docs/公寓端/11「人员入住作业流程」(CI-01CI-05):注册与签到、入住申请(房间 / 交路)、值班员审核与房间调整、#9 CHECKIN 提报与平台运安匹配(#6 / #8 / #7)、#7 任务查询进入叫乘;含三条状态链、apt_local_task 补列结构、端内接口 N-38N-47 与跨端请求 / 响应字段。"已入住"按 CR-C26 为流程态 + 业务事实双重表达,不新增 gy_jcxx 状态字段、不新增业务表(公寓本地库仍 59 张);jcsj 仍恒由公寓按规则快照复算、apt.duty.state 仍是状态字段单写入口,match_state 沿用正式五值。裁决 / 流程 / 施工单见 docs/设计变更/03 §13(CR-C26CR-C30、F-K、R-95R-103、Q-36Q-40、验收 1820)。跨端仍 20 个编号、契约 v2-draft、平台零回调;§7.7 / §7.9 表 7-5、表 7-6 与附录 B 图表索引不变
v1.9 2026-11-10 新增 docs/公寓端/12「消费、充值与菜品管理」(CF-01CF-03):人员消费(选餐加菜显示金额 → 查补贴 / 现金额度 → 补贴优先扣款、不足现金补足 → 上报公寓端 → 同步平台并落入人员账户)、人员线下充值(仅线下现金、扫码只识别公寓、系统只记账,管理员核对后计入现金额度并同步平台)、公寓菜品管理(阶段性食谱发布 → 消费终端查看菜品并加入选择菜单 → 远程点菜仅预留入口);含四条状态链、双额度 CAS 扣减与"一笔消费只一条流水"、gy_ykt_* / apt_ledger_offline / YKT_MEALS 补列、端内接口 N-48N-58 与 #1 / #4 / #10 / #16 payload 扩展。裁决 / 流程 / 施工单见 docs/设计变更/03 §14(CR-C31CR-C35、F-L / F-M / F-N、R-104R-113、Q-41Q-45、验收 2123)。不新增业务表、不新增状态字段、不新增跨端编号与 bizType,公寓本地库仍 59 张;apt.ledger.local / platform-ledger 各自单写入口不变,平台零回调、契约 v2-draft;§7.7 / §7.9 表 7-5、表 7-6 与附录 B 图表索引不变
v2.0 2026-11-10 三端一致性同步 + 平台统计分析(CR-02 §15):把公寓端已完成的平板叫乘(§11)、人脸签到(§12)、消费与菜品管理(§14)在应用端 / 平台端同步落地,统一业务规则、交互流程、权限控制与异常处理;三端状态映射与数据同步机制以 CR-02 §15 表 3-66 为唯一权威。新增 docs/平台端/10「公寓统计分析与排名报表」:以 gyid 为单位分类统计接待能力(入住人数 / 叫乘人数 / 评价情况 / 报警情况)、补贴发放、补贴消费、现金充值(计为收入)、房间利用周转,按月 / 季 / 年生成报表并对各公寓做分类 + 综合排名。新增裁决 CR-C36CR-C42、流程 F-O / F-P / F-Q、管理端接口 S-01S-07、错误码 PF-7003PF-7005、决策点 Q-46Q-50、验收 2426、施工单 R-114R-125;变更点与影响范围见 CR-02 §15 表 3-63。跨端仍 20 个编号、契约 v2-draft、平台零回调、公寓本地库仍 59 张、不新增 bizType / 公寓业务表 / 对象存储桶;平台库新增 pl_apt_stat_period / pl_apt_stat_rank 2 张(累计 5 张,另计),统计结果不回写任何业务状态,apt.duty.state / platform-ledger / platform-report 三个单写入口不变;§7.7 / §7.9 表 7-5、表 7-6 与附录 B 图表索引不变

表 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-1、4-3 能力归属表补入“语音资源”与“语音事件/录音”两条;公寓端模块清单追加 4 个语音模块
新增 4.4 / 图 4-1 / 表 4-4 语音相关模块与依赖方向
新增/修订 5.4 / 表 5-1、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 术语、图表索引、代码证据、维护约定同步更新

v1.2 回填说明(2026-11-07)

本次回填的唯一依据是 docs/公寓端/08-待决策与风险.md §4 表 8-8 与 §5 的确认结果,评审口径为:表 8-8 的 8 处差异全部采纳(其中差-1 保留库默认 utf8mb4_general_ci、差-3 不引入代码生成模块、差-7 采用前端静态路由);docs/公寓端 表 3-16 的 G-01(房间楼栋列)、G-02(人员本地启停列)、G-03(交路停用原因列)三项字段缺口,本期一律走“不改库兜底”、暂不新增字段,因此本文不新增任何字段级口径。

本次只改以下 9 处表述,其余内容(尤其第 3、4、6 章结论与表 10-2 中 D1–D16 的待决状态)不动:

  1. 表 2-2「后端框架」行(差-3):模块清单去掉 ruoyi-generator,明确不引入代码生成模块。
  2. 表 2-2「定时任务」行(差-3):Quartz 依托公寓端执行引擎模块落地,不单独建框架子模块;JobStore 仍持久化到 sys_job。
  3. 表 2-3「前端路由」行(差-7):补“实现落点”——entry-duty 用 sys_menu 驱动的动态路由,entry-apt 用前端静态路由表、sys_menu 仅作权限点载体。
  4. 2.5 末段(差-4):操作域表名 DUTY_OPERATION 更正为 duty_operation_log(同族 duty_manual_action、duty_shift_handover)。
  5. 表 5-3(差-5):补归档表 APT_CALL_EVENT_HIS 一行,语音域由 10 张补为 11 张。
  6. 表 5-4「字符集与排序」行 + 表 5-6「大小写」「字符集」两行(差-1):统一追加排序规则例外说明(库默认 utf8mb4_general_ci),覆盖表 5-9 第 7 项的逐列要求。
  7. 表 5-6「事务与锁」行 + 表 5-4「事务隔离」行(差-2):READ-COMMITTED 由“实例级固定/显式设”改为“部署待办”,应用侧不以隔离级别为正确性前提。
  8. 表 5-9 第 1、7 项 + 表 7-4(差-6 / 差-1 / 差-8):第 1 项口径改为 44 张业务表 + 30 张若依表;第 7 项改为库默认统一 + 例外清单;表 7-4 增加“落库载体”列,7 态映射为 sync_state 4 值 + enabled + deleted。
  9. 表 5-5「备份恢复/版本升级」行(差-8 连带):sync_state 全量置 UNKNOWN 改为置 PENDING 并清 applied_version,避免写入 CHECK 之外的值被拒。

以上改动均不新增图/表编号,附录 B 图表索引无需变更;逐条差异的原始依据与影响面仍以 docs/公寓端/08 表 8-8 为准。

目录


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 目标逻辑架构

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

拓扑要点

  1. 平台端不进公寓内网:所有跨端流量由公寓端主动出站发起,规避现场 NAT/防火墙,并让平台与设备链路彻底解耦。
  2. 公寓端 = 部署单元 = 公寓隔离单元:一公寓一实例一库(或独立 schema),gyid 由部署参数固定。
  3. 应用端不新增进程与库:值班员访问 http://<公寓服务器>/duty,与公寓端同 JVM、同库、同 Nginx。
  4. 平台端可多实例;公寓端的 WebSocket 为进程内实现,因此公寓端须保持单实例(或先完成广播改造再扩容)。

2.3 三端调用关系与数据流

表 2-1 三端调用关系与数据流

调用方向 协议 触发方式 典型数据
应用端 → 公寓端 进程内 Service 调用 同步 人工干预、房态修改、审核动作
公寓端 → 平台端 HTTPS 主动拉取 定时(如 5 分钟)+ 变更通知 主数据增量、乘务计划、规则版本
公寓端 → 平台端 HTTPS 主动推送 近实时批量 + 重试 执行结果、账务流水、告警摘要、设备摘要、水位
设备 → 公寓端 内网 HTTP(后续可评估 MQTT) 心跳 + 事件 指令取走、业务上报
平台端 → 运安 SOAP 定时 乘务计划
平台端 → 中心/财务 HTTPS 定时/按需 财务汇总、跨公寓人员查询
平台端 → 公寓端 不允许直连 — 仅落“待下发配置版本”,由公寓端拉取

2.4 技术基线(确定前提)

本节把公寓端与应用端的技术选型固定为约束条件,后续章节不再讨论替代方案;与基线冲突的现有实现按第 9 章处理。

表 2-2 公寓端与应用端技术基线

项 基线选择 约束说明 与现状的关系
后端框架 RuoYi-Vue 前后端分离版(Spring Boot 多模块:ruoyi-admin / ruoyi-framework / ruoyi-system / ruoyi-common / ruoyi-quartz) 只在 ruoyi-* 之上增加业务模块,不修改框架自身的认证、权限机制;不引入代码生成模块 ruoyi-generator(表结构已定稿,生成代码风格与手写不一致,维护成本高于收益) 现有 yktgl 为单模块 Spring Boot 2.6.13;阶段零先修 pom.xml 版本错配,使两侧依赖可对齐
前端框架 Vue 2 + Element UI(RuoYi-Vue 默认栈),沿用 Vuex + Vue Router 一个前端工程两个入口,不引入第二套 UI 库 YktVue 的 src/utils/{request,permission,ruoyi}.js、src/plugins/* 已是 RuoYi 前端骨架,请求与权限层可直接复用
数据库 MySQL 8.0,字符集 utf8mb4,引擎 InnoDB 一公寓一库;不允许与其他公寓共库 现网为 KingbaseES(Oracle 兼容模式),切换影响见 5.6
持久层 RuoYi 默认 MyBatis + mapper/*.xml;存量 MyBatis-Plus 代码允许暂留 新模块统一 MyBatis XML;MyBatis-Plus 仅作过渡,不新增用法 现有 yktgl 用 MyBatis-Plus 3.1.0,需在阶段零把 DbType 与分页方言切到 MySQL
定时任务 Quartz + sys_job(ruoyi-quartz 的任务定义与调度能力) 任务定义入库、支持暂停/恢复/立即执行;公寓端单实例运行;Quartz 依赖落在公寓端执行引擎模块,不单独建框架子模块,JobStore 仍持久化到 sys_job 现有 quartz/WakeUpJob + SchedulerManager 为内存 JobStore,重启只恢复未来任务,须一并改造
权限 RuoYi RBAC(sys_user / sys_role / sys_menu / sys_dept) 公寓端本地账号体系;平台账号不进公寓端 替代现有 display + gl_* 自研 RBAC;两套体系通过“人员—账号映射”打通
缓存与会话 本地 Redis 会话、令牌、设备 nonce、指令去重 现有 spring-session-data-redis;与 Boot 3.x starter 的版本错配需在阶段零修复
语音 asterisk-java(现有定制版 3.38.0-zfjia)+ AMI + Conf-01 会议桥 只在公寓端使用,平台端不依赖 现有 AsteriskAmiConfig / AsteriskCallUtil 直接演进,不重写协议层
媒体 Asterisk 本地录音 + 本地 HTTP 目录;TTS 走 Playback(tts) 不引入独立媒体服务器或流媒体服务 现有 callcontrol.recording.base-url 已指向 http://<ami.host>/conf/
部署 单 jar + Nginx + 本地库 + Asterisk 同机 不引入注册中心、消息中间件、独立网关 与现有“一公寓一套部署”一致

基线带来的三条硬约束:

  1. 框架不魔改:ruoyi-framework 的鉴权链、异常处理、分页插件不改,业务差异集中在 apt-* 模块,升级 RuoYi 时不必逐处合并。
  2. 一套代码两个入口:应用端不是独立工程,任何“只给值班员用”的能力必须落在同一 jar 内的 apt-duty 模块与前端 duty 入口,不允许起第二个服务。
  3. 语音只在公寓内闭环:平台端不得成为媒体或 AMI 的中转节点,跨端只有“配置版本下行”与“质量摘要上行”两类流量。

2.5 应用端与公寓端的复用实现

复用不是“两个入口指向同一个地址”,需要在工程结构、路由与权限、部署形态三层各有明确落点。

图 2-3 复用形态

flowchart TB
    subgraph REPO["单仓库 / 单 Maven 多模块"]
        ADM["apt-admin(唯一可执行 jar,启动类与配置)"]
        DUTY["apt-duty(值班操作 API、人工干预命令)"]
        DISP["apt-dispatch(叫乘执行引擎、Quartz、状态机)"]
        VOICE["apt-voice(AMI、分机、事件、录音媒体)"]
        DEV["apt-device(设备网关、指令队列)"]
        STAY["apt-stay(入住/离寓/房态)"]
        SYS["apt-system(RuoYi RBAC、账号、菜单、日志)"]
        FND["apt-framework / apt-common(拦截器、gyid 注入、错误码)"]
        REP["apt-report(outbox 上报)"]
        MC["apt-master-client(平台下行)"]
        OPS["apt-ops(自检、健康检查)"]
    end

    subgraph FE["单前端工程,双入口"]
        EA["entry-apt:设备 / 终端 / 运维页"]
        ED["entry-duty:值班员盯控与操作页"]
        SH["shared:api / store / components / dict"]
    end

    ADM --> SYS
    ADM --> DUTY
    ADM --> DEV
    ADM --> OPS
    DUTY --> DISP
    DUTY --> STAY
    DISP --> VOICE
    DISP --> STAY
    DEV --> DISP
    DISP --> REP
    REP --> MC
    EA --> SH
    ED --> SH

表 2-3 复用维度与实现落点

维度 复用方式 具体落点 负面清单(不允许)
代码库 单 Git 仓库、单 Maven 多模块、单可执行 jar apt-admin 是唯一打包入口;应用端 = apt-duty 模块 + 前端 duty 入口 不允许为应用端再建一个启动模块或第二套 jar
数据库 同一公寓库、同一 DataSource、同一事务管理器 执行域表(GY_*)与操作域表(DUTY_*)同库不同前缀,可处于同一本地事务 不允许为应用端建第二数据源、第二库或读写分离副本
模块依赖 单向依赖:apt-duty → apt-dispatch / apt-stay → apt-voice 应用端只发“命令”与“查询”,状态由 apt.duty.state 唯一写入 不允许 apt-dispatch / apt-voice 反向依赖 apt-duty;不允许应用端绕过状态机直写 ryzt 等字段
后端路由 按前缀分区:/apt/**(管理/终端/运维)、/duty/**(值班员)、/system/**(RuoYi 框架)、/open/**(跨端与设备,独立鉴权) 各前缀独立拦截器链:/duty/** 走会话 + 权限点 + gyid 数据域;/open/** 走设备签名或 mTLS 不允许 /duty/** 出现在设备可达的接口清单里;不允许 /open/** 复用会话鉴权
前端路由 同一工程、同一次构建,两个 entry,路由按角色过滤 实现落点:① entry-duty 的路由由 sys_menu 驱动的动态路由生成(菜单即路由);② entry-apt 使用前端静态路由表(在 entries/apt/router 内按功能域声明),sys_menu 对 apt 入口仅作权限点载体,不参与路由生成;③ 两个入口共用 shared 的路由守卫与异常页,路由表各自维护;④ 按钮级一律 v-hasPermi 校验权限点,前端隐藏不等于后端放行 不允许两个 entry 互相 import 页面;共用只走 shared;不允许为了让 apt 入口“能显示菜单”而伪造 sys_menu 记录
菜单与权限点 RuoYi 菜单树 + 权限点(如 duty:call:stop、duty:room:swap) 值班菜单挂 duty 目录,运维菜单挂 apt 目录;按钮级复用 v-hasPermi 不允许以“前端隐藏”代替后端校验;不允许只有前端判断角色
鉴权与身份 值班员用本地 RuoYi 账号;gyid 作为登录用户扩展属性写入令牌 RuoYi LoginUser 扩展 gyId;数据范围扩展为“按 gyid 过滤”;服务层拦截器强制注入 不允许再出现“从请求 IP 推断公寓”;getGyIdByIp 只作旧设备兜底并打告警
部署形态 单进程、单 Nginx、单端口对外 Nginx location /duty 与 /apt 指向同一 SPA,/prod-api 反代同一后端;/ws/duty 与 /ws/device 两个 WebSocket 端点 不允许为应用端单独扩容(推送为进程内状态、Quartz 单实例);扩容前先完成推送广播与任务抢占改造
发布节奏 一次发布同时生效 应用端与公寓端同版本号、同发布窗口;接口变更至少向前兼容一个版本 不允许跨越破坏性变更只发前端不发后端

同库边界如何避免互相踩:apt-duty 只能通过领域服务写执行域,事务边界由 apt-dispatch 提供;值班员的每次操作落操作域 duty_operation_log(同族表:duty_manual_action 人工干预、duty_shift_handover 交接班),记录“谁在什么时间对哪个对象下了什么命令”,并通过 commandId 与执行域的状态变更关联。这样即使两侧同库,也能从审计上区分“人下的命令”与“系统产生的状态”。


3. 端职责边界

CR-02 指针(v1.4,2026-11-09):依据 docs/公寓端/00 的公寓端功能重新规划,第 3 章(端职责边界)、第 4 章(领域与模块划分)、第 6 章(接口与集成)的增量与口径改判以 docs/设计变更/03-三端功能设计修订(CR-02).md 为权威,逐处施工单见 CR-02 §8。要点:① 入住 / 换房 / 离寓与账务本地流水由"后续 / P2"调整为本期;② 平板叫乘、换乘、保洁、排班考核、上报历史续报纳入三端覆盖范围;③ 跨端仍为 20 个接口编号、不新增不重排,新数据走 payload + bizType 扩展(契约 v2-draft);④ jcsj 恒由公寓复算(R-C9 / R-C10);⑤ 公寓本地库业务表口径 v1.4 为 58 张、v1.5 补遗后为 59 张(见 docs/公寓端/00 §3、CR-02 §10)。本章及以下原有结论中与上述要点冲突处,以 CR-02 表 3-4 为准;⑥ v1.7 人脸数据下发模块(CR-02 §12)不新增业务表与跨端编号,人员主数据人脸按 CR-C24 允许跨端、注册链路按 CR-C25 改判为「签到终端申请 → 值班员注册 → 入公寓服务系统 → 分别上传平台 / 下发公寓内设备」,59 张表口径与契约 v2-draft 不变;⑦ v1.8 人员入住作业流程(CR-02 §13)不新增业务表、不新增 gy_jcxx 状态字段与跨端编号,"已入住"为流程态 + 业务事实双重表达,jcsj 公寓复算与 apt.duty.state 单写入口不变;⑧ v1.9 消费 / 充值 / 菜品管理(CR-02 §14)三项流程不新增业务表、不新增状态字段、不新增跨端编号与 bizType,复用 gy_ykt_* / apt_ledger_offline 与平台库 YKT_MEALS 补列,apt.ledger.local / platform-ledger 各自单写入口不变,仅线下充值不接支付渠道、远程点菜仅预留入口,权威表述见 docs/公寓端/12;⑨ v2.0 三端一致性同步与平台统计分析(CR-02 §15)不改变公寓端四项能力的权威表述,只在应用端 / 平台端同步业务规则、交互流程、权限控制与异常处理,三端状态映射与数据同步机制以 CR-02 §15 表 3-66 为唯一权威;#13 摘要按 payload 扩展评价 / 房间周转分组计数,不新增 bizType 与上报接口;新增 docs/平台端/10 以 gyid 为单位的五类分类统计、月 / 季 / 年报表与公寓排名,平台库新增 2 张另计(累计 5 张)、公寓本地库仍 59 张,统计结果不回写任何业务状态,apt.duty.state / platform-ledger / platform-report 三个单写入口不变,变更点与影响范围见 CR-02 §15 表 3-63;附录 B 图表索引不变。

3.1 平台端

负责

  • 公寓档案、房间基线(gyid + room_no + 床位数)、人员主数据与照片、交路模板与叫乘时刻、时间规则、节假日、餐补/补助标准。
  • 运安计划的唯一入口(替代现状各公寓分别抓取),并将计划转换为叫乘任务/计划快照下发对应公寓。
  • 账务主账:补助发放规则、余额主账、消费/充值/补助流水归集、跨端对账。
  • 餐饮业务(菜品、订单、后厨、结算规则),但结算扣款必须经账务接口,不直接改公寓库余额。
  • 账号、角色、权限、操作审计、跨公寓报表、设备在线率与执行质量监控、告警汇总。
  • 接收各公寓执行结果与异常补偿请求,维护每公寓水位与对账结果。

不负责

  • 不接入现场设备、不下发设备指令、不持有设备心跳流水。
  • 不执行叫乘(不连 AMI、不控串口、不播 TTS)。
  • 不直连公寓本地库,不做跨库 JOIN。
  • 不承担房间实时房态(仅保留基线,实时占用以公寓端为准)。

3.2 公寓端

负责

  • 本公寓设备接入:注册、认证、心跳、指令队列、事件受理、离线缓存。
  • 本公寓叫乘执行全链路:任务创建、Quartz 调度、AMI 会议桥、TTS、串口广播、复叫/报警/停止、重启恢复与漏叫补偿。
  • Asterisk 资源全生命周期:SIP 分机与中继的新增、修改、停用、删除;分机注册状态与在线判定;分机与房间、值班台、广播终端的绑定关系;分机台账与 Asterisk 实际配置的收敛与对账。
  • Asterisk 事件闭环:AMI 连接建立与断线自愈、事件订阅与解析、通话与会议状态跟踪(呼入/接通/入会/离会/挂断/异常)、呼叫失败与超时识别、录音与 TTS 的触发时机与结果回写。
  • 会议桥与媒体:会议桥粒度与占用判定、TTS 文本排队与播放结果、录音落盘与索引、录音留存与清理。
  • 在寓事实与房态(GY_JCXX 语义)、换房、退房、保洁、超时离寓报警。
  • 本地主数据缓存与规则快照(人员照片、交路、时间规则、节假日),保证断网可叫乘。
  • 本地账务流水与离线消费受理(缓存余额),向平台归集。
  • 结果上报:执行结果、流水、告警摘要、设备摘要、归档摘要、水位。

不负责

  • 不直连运安(运安仅由平台接入),不维护跨公寓人员全集。
  • 不决定补助标准,不做跨公寓统计,不维护平台账号体系。
  • 不制定园区级设备策略(策略由平台配置,执行在公寓)。
  • 不制定跨公寓的号段规划、中继路由策略与录音合规策略(平台给规则,公寓落地执行)。
  • 不经平台中转运维语音媒体流;外线呼入业务规则由本地 Asterisk 拨号计划定义,公寓端只做事件观测与关联。
  • 不评估录音内容合规性,只执行留存期与访问控制策略。

3.3 应用端(与公寓端同代码同库)

负责

  • 叫乘盯控:任务列表、报警、应答确认、临时叫乘、房间/多房间喊话、停止叫乘、录音回放入口。
  • 房间与房态:选房、换房、停用/恢复、保洁开始/结束、在寓人员查看。
  • 人工干预与审核:充值确认、人员资料修正、交路人工指定与重置、备注与操作留痕。

不负责

  • 不直接改设备指令表、不直接改叫乘任务表(必须经公寓端领域服务)。
  • 不持有独立数据库,不引入第三套服务,不做独立鉴权中心。
  • 不承担跨公寓查询(跨公寓看平台端)。

表 3-1 应用端与公寓端的逻辑分工

维度 公寓端(执行域) 应用端(操作域)
表归属 现有 GY_JCXX、GY_SB*、GY_SYN_JCXX 等执行与设备表(可加 apt_* 前缀新表) 新增 DUTY_*:操作审计、人工干预记录、审核动作、备注、班次交接
写权限 仅执行引擎/设备网关写状态字段(ryzt、jcsj_s、finish_jc 等) 仅通过状态机服务写,禁止直连 Mapper 修改状态字段
部署形态 同一 JVM 内的 apt-dispatch(叫乘引擎)+ apt-voice(语音域) 同一 JVM 内的 apt-duty,依赖公寓端领域接口,禁止反向依赖
前端形态 同一前端工程的 apt 入口(设备/终端页) 同一前端工程的 duty 入口(值班员页),按角色裁剪路由与菜单
鉴权 设备用设备凭据;值班员用本地 RuoYi 账号 复用公寓端 RuoYi 账号 + 数据范围锁定 gyid

公寓隔离方式

  1. 部署期固定 apartment.gyId,服务启动即校验;gyid 不再从请求 IP 推断,getGyIdByIp 降级为旧设备兼容兜底并打告警。
  2. 库级隔离:一公寓一 schema/库 + 独立连接账号,账号仅对本库有 DML 权限,对平台库无任何权限。
  3. 请求级隔离:值班员登录后 gyid 写入会话与令牌声明,服务层用拦截器强制注入,业务 SQL 一律带 gyid 条件。
  4. 设备级隔离:设备注册时绑定 gyid + deviceCode,跨公寓 deviceCode 直接拒绝。

3.4 语音链路上的三端分工

表 3-2 语音/分机/事件的三端分工(● 主责 ○ 参与 — 不参与)

环节 平台端 公寓端 应用端 说明
号段与编号规则 ● ○ 取规则快照 — 平台定“房间号 ↔ 分机号”映射规则,公寓端按规则生成并校验
中继与路由策略 ● 定策略 ● 落地配置 — 外线呼入/呼出的业务规则由公寓本地拨号计划承载
分机资源增删改停 — ● ○ 界面发起 应用端只发命令,apt.voice.endpoint 落库并收敛到 Asterisk
分机与房间/值班台/广播绑定 — ● ○ 界面发起 换房、改值班台、调整广播区改绑定,不改分机号
注册状态与在线判定 ○ 汇总 ● 采集 ● 展示 平台只收“注册率/离线清单”摘要
叫乘发起与会议桥 — ● ○ 人工触发 语音链路不经平台中转
TTS 文本生成 — ● ○ 单次改写 模板可由平台配置,生成与播放在公寓端
录音落盘与索引 — ● ○ 回放 平台只收索引摘要与缺失数
录音留存与访问控制 ● 定策略 ● 执行 ○ 申请导出 合规口径见待决策 D15
语音质量与故障 ○ 汇总 ● 判定 ● 展示 注册率、呼叫成功率、录音缺失、AMI 断连次数
外线呼入业务 — ● 观测/关联 ○ 查看 呼入由 Asterisk 拨号计划处理,公寓端只跟踪会话与关联房间

一句话边界:平台管“号码规则与合规策略”,公寓管“资源、事件与媒体”,应用端管“人看与人工干预”。


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 自检、时钟偏差、磁盘(抓拍/录音)、日志、版本 新增
apt.voice.ami AMI 连接建立与守护、重连退避、命令发送与超时、事件分类分发 AsteriskAmiConfig + AsteriskCallUtil 连接部分
apt.voice.endpoint 分机与中继台账、绑定关系、期望态→实际态收敛、对账与漂移 GY_ROOMS.sip_account 单列、sip_status 从未写入
apt.voice.event 会话与会议状态机、失败/超时识别、录音与 TTS 触发、结果回写 AsteriskCallUtil 事件回调 + 内存 recordlist
apt.voice.media 录音索引与清理、TTS 文本队列与模板、播放结果回写 GY_JCXX.recordfile 逗号拼接 + conftts 单槽位

4.4 语音相关模块与依赖方向

图 4-1 语音模块依赖方向

flowchart LR
    subgraph CALL["叫乘执行"]
        M1["apt.duty.engine<br/>任务/调度/复叫"]
        M2["apt.duty.state<br/>状态机唯一写入口"]
    end
    subgraph VOICE["语音域"]
        V1["apt.voice.event<br/>会话状态机/失败识别"]
        V2["apt.voice.ami<br/>连接/事件分发"]
        V3["apt.voice.endpoint<br/>分机中继台账/收敛对账"]
        V4["apt.voice.media<br/>录音索引/TTS 队列"]
    end
    subgraph SIDE["相邻域"]
        D1["apt.device.gateway<br/>设备网关"]
        D2["apt.master.cache<br/>平台配置快照"]
        D3["apt.report.outbox<br/>上报"]
        D4["apt.duty.view<br/>值班 API"]
    end
    AST["Asterisk(AMI + 会议桥 + 录音目录)"]
    SPK["串口广播"]

    M1 --> V1
    M1 --> D1
    M1 --> SPK
    M1 --> M2
    V1 --> V2
    V1 --> V4
    V1 --> M2
    V3 --> V2
    V2 --> AST
    V4 --> AST
    D2 --> V3
    D4 --> V1
    D4 --> V3
    V1 --> D3

表 4-4 语音模块职责与依赖约束

模块 核心职责 允许依赖 禁止依赖 现状来源
apt.voice.ami 连接建立与守护、重连退避、命令发送与超时、事件按类型分发 apt.common、配置 任何业务模块(不得反向调用叫乘/设备/值班) AsteriskAmiConfig(Bean 内单次 login(),失败仅打印)
apt.voice.endpoint 分机/中继台账、绑定、期望态→实际态收敛、对账与漂移 apt.voice.ami、apt.master.cache apt.voice.event、apt.duty.* GY_ROOMS.sip_account 可写但无台账、无状态
apt.voice.event 会话与会议状态机、失败/超时识别、录音与 TTS 触发、结果回写状态机 apt.voice.ami、apt.voice.media、apt.duty.state apt.device.*、apt.report.*、apt.duty.view AsteriskCallUtil 的 recordlist 内存跟踪
apt.voice.media 录音索引与清理、TTS 文本队列与模板、播放结果回写 存储、apt.common apt.duty.* GY_JCXX.recordfile 逗号拼接、conftts 单槽位
apt.duty.engine 任务领取、Quartz 调度、复叫/报警/停止 apt.voice.event、apt.device.command、串口 直连 AMI(必须经 apt.voice.*) WakeUpJob、SchedulerManager
apt.duty.state 状态机唯一写入口 apt.common 全部语音/设备模块(只能被调用) JcglService.updateJcxxRyzt 被多处直接调用
apt.duty.view 值班 API、WebSocket、人工干预命令 apt.voice.endpoint、apt.voice.event、apt.duty.state 直接写状态字段 JcglController

依赖方向的三条硬规则:

  1. 事件单向下行:apt.duty.engine → apt.voice.event,语音层不得回调叫乘层;需要通知执行层时,以“状态机命令”形式交给 apt.duty.state,避免双向依赖。
  2. AMI 只在最底层:只有 apt.voice.ami 持有 ManagerConnection,其他模块不得自行建连(现状 AsteriskCallUtil 既是连接持有者又是业务逻辑,必须先拆)。
  3. 设备与语音互不感知:广播终端、房间屏走设备网关,话机走语音域;两者只在“同房间、同任务”这一业务层通过 task_id 关联。

5. 数据架构

5.1 数据分层与归属

表 5-1 数据分层、归属与同步方向

数据层 典型数据 归属 存储位置 同步方向
平台主数据 公寓、房间基线、人员、照片、交路、时间规则、节假日、餐补标准 平台 平台主库 + 对象存储 下行:平台 → 公寓(版本化增量)
平台计划数据 运安计划快照、生成的叫乘任务/时刻、变更与取消 平台 平台主库 下行:平台 → 公寓
公寓执行数据 GY_JCXX(在寓/叫乘事实)、GYGL_LY_EVENT、房态、保洁、报警 公寓 公寓本地库 本地强一致;摘要上行
设备数据 GY_SB、GY_SB_XT、指令队列、心跳 公寓 公寓本地库 仅上行摘要(在线率/版本/故障)
账务数据 补助明细、消费/充值流水、余额 主账平台 / 流水双记 平台主库 + 公寓本地缓存 流水上行;对账后余额快照下行
归档数据 GY_JCXX_HIS、离寓事件历史 公寓 公寓本地库 上行归档摘要
账号与审计 账号、角色、权限、操作审计 平台(平台侧)/ 公寓(本地侧) 各自库 人员—账号映射下行
语音与媒体数据 分机与中继台账、会话与事件、录音索引、TTS 单元、配置版本与漂移 公寓 公寓本地库 + 本地磁盘 本地强一致;仅上行质量与应用摘要
汇总与报表 跨公寓统计、财务汇总 平台 平台主库/数仓 由上行数据加工

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 事件、人工操作统一转为状态机命令。

5.4 语音域数据设计

语音域数据全部落在公寓本地库,与执行域同库;归属标注为 owner=apartment,写入口在 apt.voice.*。表名沿用公寓端新增前缀 APT_,与操作域 DUTY_ 区分。

表 5-3 语音域表清单、主键与关键约束

表 用途 主键 关键唯一约束与索引 关键字段 写入口
APT_SIP_ENDPOINT 分机台账(房间分机、值班台、广播终端话机) endpoint_id(bigint) UK (gyid, extension);IDX (gyid, endpoint_type, enabled)、(room_no) extension、endpoint_type(ROOM/CONSOLE/BROADCAST/TRUNK_SIDE)、room_no、enabled、register_status、last_reg_at、last_seen_ip、sync_state(PENDING/SYNCED/FAILED/DRIFT)、applied_version、config_version、remark、deleted apt.voice.endpoint
APT_SIP_BINDING 分机与房间/值班台/广播区/设备的绑定 bind_id UK (endpoint_id, bind_type, bind_target, eff_from);IDX (bind_type, bind_target, eff_to) bind_type(ROOM/CONSOLE/BROADCAST_ZONE/DEVICE)、bind_target(房间号/台号/区号/device_code)、is_primary、eff_from、eff_to apt.voice.endpoint
APT_TRUNK 中继台账 trunk_id UK (gyid, trunk_name) trunk_name、trunk_type(REGISTER/PEER)、peer_host、peer_port、auth_user、register_status、last_reg_at、enabled、sync_state apt.voice.endpoint
APT_CALL_SESSION 一次呼叫/入会会话(业务视角) session_id UK (gyid, linked_id);IDX (task_id)、(ryid, originate_at)、(state, originate_at) linked_id(Asterisk linkedid)、unique_id、conf_no、task_id、ryid、room_no、peer_extension、console_extension、attempt_no、state(CALLING/RINGING/ANSWERED/JOINED_CONF/LEFT/HANGUP/FAILED/TIMEOUT/UNKNOWN)、originate_at/ring_at/answer_at/join_at/leave_at/hangup_at、hangup_cause、duration_ms、recording_id、source(AUTO/MANUAL/TEST) apt.voice.event
APT_CALL_EVENT 原始 AMI 事件流水(只追加) event_seq(bigint 自增) UK (gyid, session_id, event_type, channel, event_at_ms);IDX (event_at_ms) session_id、event_type、channel、conference、caller_id、cause、event_at_ms、received_at、payload(JSON,原始事件快照) apt.voice.ami
APT_CALL_EVENT_HIS AMI 事件归档(按月归档,结构与在线表同口径) event_seq(bigint 自增) PK (event_seq);IDX (event_at_ms)、(session_id, event_at_ms) session_id、event_type、channel、conference、caller_id、cause、event_at_ms、received_at、payload(JSON)、create_time(原记录创建时间)、archived_at(归档时间) apt.voice.ami(归档任务,只写)
APT_RECORDING 录音索引(与会话一对多) recording_id UK (gyid, file_key);IDX (task_id)、(ryid, started_at)、(state, started_at) session_id、task_id、ryid、file_key(Asterisk recordfile)、storage_kind(LOCAL/NFS/HTTP)、storage_path、url、bytes、duration_ms、codec、started_at、state(RECORDING/AVAILABLE/MISSING/PURGED)、retention_days、purged_at、checksum apt.voice.media
APT_TTS_UTTERANCE TTS 播报单元(会话内排队) utterance_id IDX (session_id, seq)、(state, created_at) session_id、task_id、conf_no、seq、template_code、text、state(PENDING/PLAYING/DONE/FAILED)、started_at、finished_at、fail_reason apt.voice.media
APT_AST_CONFIG_VERSION 配置版本(本地意图版本 + 平台下发版本) version_id UK (gyid, config_type, source, version_no) config_type(SIP/TRUNK/CONF/DIALPLAN/TTS/RETENTION)、source(LOCAL/PLATFORM)、version_no、checksum、applied_at、applied_by、apply_result apt.voice.endpoint
APT_AST_DRIFT 对账差异 drift_id UK (gyid, config_type, object_key, detected_at);IDX (resolved_at) config_type、object_key(分机号/中继名/会议桥)、drift_type(MISSING_IN_AST/EXTRA_IN_AST/ATTR_MISMATCH)、expected_value、actual_value、detected_at、resolved_at、resolve_action apt.voice.endpoint
APT_AST_AMI_SESSION AMI 连接健康与断连记录 ami_session_id IDX (connected_at)、(node, connected_at) node、connected_at、disconnected_at、disconnect_reason、reconnect_count、last_event_at、event_lag_ms apt.voice.ami

与既有表的处理关系:

  1. GY_ROOMS.sip_account:迁入 APT_SIP_ENDPOINT 后降级为只读冗余(一期内保留,供旧报表与旧接口兼容),不再作为写入口;从未被写入的 sip_status 直接废弃。
  2. GY_JCXX.recordfile:现状是逗号拼接的多条录音文件名(updateJcxxRyzt 内部合并),改为 APT_RECORDING 一对多;旧列保留只读一期,新会话只写 APT_RECORDING。
  3. GY_JCXX.ryzt:语音事件不再直接 UPDATE,统一提交 apt.duty.state 的状态机命令,由状态机条件更新(保留“已结束叫乘不回写”的现有保护语义)。
  4. 设备档案 GY_SB 与分机台账是两套对象:前者是“终端”,后者是“号码/账号”,用 APT_SIP_BINDING 的 DEVICE 类型关联,不合表。
  5. 归档:APT_CALL_EVENT 按天分区或按月归档到 APT_CALL_EVENT_HIS,在线保留 90 天;APT_RECORDING 索引长期保留(仅状态变 PURGED)。

表 5-4 语音域字段级 MySQL 适配要点

关注点 现状(KingbaseES) MySQL 8.0 落法 说明
主键 现库 0 主键,业务靠 id 列(numeric/varchar 混用) 每表单列 bigint 主键;业务键另建 UK InnoDB 按主键聚簇,无主键会退化为隐藏 rowid,写入与复制代价上升
分机号/房间号 varcharbyte 无长度 varchar(32);extension 建议 char(8) 定长 + CHECK 数字 定长便于索引与比对;utf8mb4 下宽度按字符计,长度要克制
枚举状态 varchar 存 0/1/2 数字 varchar(16) + CHECK 约束(8.0.16 起真实生效) 不用 MySQL ENUM:新增值需 DDL,跨端契约变更成本高
时间 timestamp/timestamp(6)/sys.date 混用 统一 datetime(3) 不用 timestamp:受会话 time_zone 影响;毫秒精度对 30s 级叫乘判定足够
三时间戳 现状只有单列时间 event_at_ms、received_at、created_at 分列 与 6.2 三时间戳约定对齐;event_at_ms 用 bigint 存毫秒,避开解析歧义
原始事件载荷 无(事件只在内存) payload json JSON 列不能有默认值、不能直接建索引;需检索的字段用生成列 + 索引
录音路径 varchar 存文件名 storage_path varchar(512)、url varchar(1024)(或 text) 长 URL 用 text,只在 file_key 上建 UK
空串语义 ora_input_emptystr_isnull=on,空串入库即 NULL 需在应用层把 "" 归一为 NULL(或反之,但必须全端统一) 迁移后 = '' 与 IS NULL 结果会变,是“假差异”的主要来源
唯一约束长度 现库无唯一约束 组合 UK 总长 < 3072 字节(utf8mb4 约 768 字符) (gyid, extension) 这类短键无风险;带长路径的组合键改用哈希列
字符集与排序 库级 UTF8,Oracle 模式比较区分大小写 库/表/连接统一 utf8mb4;排序规则以库默认 utf8mb4_general_ci 统一,不逐列改 utf8mb4_0900_ai_ci / _as_cs 例外说明(覆盖表 5-9 第 7 项的逐列要求,也约束表 5-6「大小写」「字符集」两行):与若依 sys_* 表 JOIN 时混排规则会报 Illegal mix of collations,故全库统一 general_ci;大小写归一改在应用层(分机号、房间号入库统一大写),不依赖数据库排序规则折叠
自增与序列 sys_guid();64 个序列仅 4 个被引用 bigint AUTO_INCREMENT(单库内)+ 业务 biz_id 用 ULID/UUID 跨端幂等键不能用自增;biz_id 必须独立且全局唯一
长文本 text / nclob 混用 text(64 KB)/ mediumtext 录音只存索引不存二进制;照片仍走对象存储或本地磁盘
事务隔离 Oracle 兼容模式(读已提交) 实例级 transaction_isolation=READ-COMMITTED(部署待办,口径见 表 5-6) MySQL 默认 REPEATABLE-READ 有间隙锁与幻读差异,会改变状态机条件更新语义

本节只给字段与约束口径,建表语句在详细设计阶段产出,本文不提供 DDL。

5.5 分机配置在“本地库”与“Asterisk 实际配置”之间的一致性

一致性模型采用 期望态(desired)在库、实际态(actual)在 Asterisk、协调器单向收敛,不做双向双写。

表 5-5 分机配置一致性机制

场景 机制 失败处理 可见性
新增分机 本地库事务写 APT_SIP_ENDPOINT(sync_state=PENDING,config_version+1)→ 提交后投递收敛任务 → 通过 AMI/配置文件下发 → 回写 SYNCED 与 applied_version 下发失败置 FAILED + 错误码 + 退避重试;连续失败 N 次告警并禁止该分机参与叫乘 列表显示“同步中/同步失败”,值班员可见但不可选
修改属性(值班台号、房间绑定) 只改绑定与属性,不换号码;绑定表按生效区间新增一条,旧记录写 eff_to 绑定写入失败不产生半状态;Asterisk 侧属性变更失败保留旧值并告警 换房历史可追溯
修改号码 不允许原地改号:停用旧分机 + 新建新分机,旧号保留 N 天(默认 7 天) 旧号停用即不再参与叫乘;物理删除延迟执行 审计留痕“哪个任务改的号”
停用 本地先置 enabled=0,叫乘前过滤;再下发 Asterisk 停用(不注册) Asterisk 不可达时本地已停用,功能上已生效(安全侧优先) 状态“已停用/待同步”
删除 逻辑删除 + 解绑 → 延迟物理删除;Asterisk 侧先停用后删对象 物理删除前二次对账,确认无活动会话 仅管理员可见
启动自检 见 7.11:AMI 连通、会议桥、拨号计划、分机数量与属性比对 关键项失败进入 DEGRADED,叫乘前二次校验并走值班台兜底 首页横幅 + 健康探针
运行期对账 每 30 分钟(可配)拉取 pjsip show endpoints / pjsip show registrations,与台账比对 差异写 APT_AST_DRIFT;默认“只报告不自动修”,自动修复需显式开关 漂移清单页 + 差异数量指标
现场手工改 Asterisk 视为漂移来源之一;对账发现后由运维选择“库为准”或“Asterisk 为准” 选择后回写台账并记 resolve_action 漂移处理记录可审计
备份恢复/版本升级 升级窗口内把 sync_state 全量置 PENDING 并清 applied_version(不写 CHECK 之外的值),升级后全量比对一次 比对期间叫乘使用“最后已知可用”快照 升级后跑完全量对账才算成功

三条原则:

  1. 写顺序固定:先库后 Asterisk。库是意图,Asterisk 是派生物;库成功、Asterisk 失败可以重试,反过来会出现“设备在响、系统不知道”。
  2. 失败不回滚库:Asterisk 失败不回滚本地库,而是保留失败态并阻断该分机的叫乘参与,避免“回滚后库里没、Asterisk 里多一个孤儿号”这种更难修的状态。
  3. 叫乘前二次校验:sync_state=SYNCED 且注册在线才允许发起;否则直接走“值班台人工兜底 + 告警”,而不是像现状 makeWakeup 失败只打印日志那样静默失败。

5.6 数据库选型:KingbaseES → MySQL 的影响与迁移

现行生产库为 KingbaseES(实测 V009R001C010,server_version 报 12.1,database_mode=oracle,ora_input_emptystr_isnull=on);公寓端基线库改为 MySQL 8.0。这不是换一个 JDBC 驱动,而是类型、语义、约束、排序规则四类同时改变。

5.6.1 影响面

表 5-6 数据库差异与影响

差异类别 现状事实(实测,见 docs/11) MySQL 后的变化 应对
字符类型 524 列中 varcharbyte 276 列,全部未指定长度;varchar 78 列 varchar 必须给长度;utf8mb4 行上限 65535 字节、单索引键 3072 字节 逐列定长:编码类 32、名称类 64~128、备注 512、长文本 text
空串语义 ora_input_emptystr_isnull=on:写 '' 实际存 NULL(实测 bz='' 命中 0 行、bz IS NULL 命中 3,541 行) MySQL 原样保留空串 全端统一“空串归一为 NULL”并在拦截器/实体层实现;迁移必须做空串专项比对,否则会出现大量假差异
时间类型 timestamp 68 列、sys.date(Oracle DATE 语义)、gy_jcxx_his.yappsj 漂移为 timestamp(6) datetime 不随时区变,timestamp 随会话时区变;毫秒精度需显式 (3) 统一 datetime(3);禁止用 timestamp;纯日期列用 date
数值与金额 numeric 82 列,金额未统一精度(实测三表合计 552,295.00 / 265.10 / 1,228.00 无法对账) decimal(p,s) 需显式精度 金额统一 decimal(12,2),比率 decimal(6,4),计数 bigint
自增/序列 64 个序列,仅 4 个被引用(gen_table*、gy_device、seq_gy_allowance);大量主键是应用层 UUID MySQL 无序列;自增列只能一个且与业务语义无关 主键 bigint AUTO_INCREMENT,业务标识另设 biz_id + UK;跨端幂等键必须用 biz_id
JSON 现库无 JSON 列,事件类数据靠 text 拼接 MySQL 原生 json,不能有默认值、不能直接建索引 只在 payload 类字段用 json;需检索字段用“生成列 + 索引”
大小写 Oracle 模式下标识符折叠为大写(表名 GY_JCXX、列名 JCID);比较区分大小写 Linux 下 lower_case_table_names=0 表名区分大小写;默认排序规则 _ci 不区分大小写 表名列名统一小写;业务键入库统一大写;排序规则以库默认统一,不逐列指定(例外见 表 5-4)
字符集 库级 UTF8 utf8mb4 + 库默认 utf8mb4_general_ci(与若依 sys_* 一致,例外见 表 5-4) 连接串固定 characterEncoding=UTF-8 与 connectionCollation;禁止 utf8mb3
索引与约束 索引 0、主键 0、唯一 0、外键 0(40 表全量) InnoDB 必须主键;二级索引带来写放大 按表 5-3 口径补 PK/UK/IDX;外键默认不建(跨端与分库场景),用应用层约束 + 对账兜底
注释 表注释 3/40,列注释 60/524(业务表仅 5 条) 表/列注释均支持,上限 2048 字符 迁移时补齐中文注释,作为 DDL 评审项
事务与锁 Oracle 兼容模式(读已提交) 默认 REPEATABLE-READ,有间隙锁与幻读差异 部署待办(实例级参数,不入应用配置):my.cnf 设 transaction_isolation=READ-COMMITTED,随切换一并整改并纳入上线检查;应用侧不以隔离级别为正确性前提,状态机一律条件更新(WHERE state=?)而非先查后改
SQL 方言 sysdate()、dual、sys_guid()、Oracle 风格分页 NOW(3)、LIMIT、UUID() 阶段一产出方言点清单;MyBatis-Plus DbType 与分页插件同步切换

5.6.2 迁移与双跑验证

表 5-7 迁移步骤与退出条件

步骤 内容 退出条件(可验收)
S0 元数据盘点 以实测 information_schema 为唯一来源(不依赖 dump),产出列级清单:类型、长度、可空、注释、实际最大值 524 列全部有目标类型与长度,无“待定”列
S1 目标结构 按 5.4 与 docs/11 第 6 章口径产出 MySQL 结构草案(PK/UK/IDX/NOT NULL/默认值/注释) 结构评审通过;每表有主键;金额精度统一
S2 全量迁移 按表迁移,字符集转换显式指定;大表分批(gy_logs 285,914 行、gy_sb_zl 129,665 行) 行数一致;sum() 类指标一致;抽样 1,000 行字段级 diff 为零
S3 空串/NULL 专项 对现状 '' 与 NULL 语义差异做专项比对 差异清单可解释,每条都归属到一条归一规则
S4 只读双跑 新库只读,页面与报表并行对照 2 周 差异条目收敛到 0,或全部判定为非缺陷
S5 影子上报 新链路只写不生效(见 6.3),验证上报与对账 对账零差异连续 3 天
S6 灰度切换 按公寓逐个切换,旧库保留只读一个周期 单公寓连续 7 天无 P0/P1 缺陷
S7 回滚演练 保留旧实例与旧库只读副本,演练回退 回退时间 < 2 小时且数据可追平

双跑必须固定的三条口径:

  1. 校验维度:count、关键金额 sum、max(updated_at)、max(watermark)、抽样字段级 diff。少一维都可能“看起来对”。
  2. 差异分类:真实缺陷 / 空串与 NULL 语义 / 排序与大小写 / 时间精度截断 / 历史脏数据。后四类必须在双跑手册里预置判定规则,否则争议无法收敛。
  3. 双跑时长:至少覆盖 2 个完整结算周期(含一次月度补助结算),账务类表尤其不能缩短。

5.6.3 平台端是否一并改为 MySQL

表 5-8 平台端数据库选项对比

选项 做法 优点 风险 适用判断
A 平台保持现库 公寓端 MySQL,平台端继续 KingbaseES(Oracle 存量公寓继续 Oracle) 平台零迁移风险;公寓端可先行;跨端只有 HTTP,无跨库 JOIN 需求 两套方言、两套 SQL 审查与测试矩阵;团队要同时维护 推荐作为第一阶段:先把公寓端跑通
B 平台一并改 MySQL 平台主库迁 MySQL,Oracle 存量公寓按期退役 全栈统一,工具链与运维口径一致,人力最省 平台库更大、耦合更多;现库 0 主键 0 索引,迁移等于“结构重构 + 数据迁移”叠加;运维与 DBA 熟悉度需确认 中期评估,不建议与公寓端试点同期进行
C 平台 MySQL + 存量公寓 Oracle 平台迁 MySQL,未退役公寓保持 Oracle 只读过渡 兼顾统一与存量 三套方言并存,过渡期最长 仅在 Oracle 存量公寓有明确退役时间表时采用

不替用户拍板的三个前置条件(满足再议 B/C):

  1. Oracle 存量公寓(byq/cc/dl/pj 等 profile)的退役时间表是否已定(对应 D9)。
  2. 平台端是否已有跨 schema 的强耦合 SQL(如 gy_* 与 gl_* 混查、gen_table* 依赖),改造量能否估清。
  3. 运维团队对 MySQL 高可用(主从/组复制)与备份恢复的能力是否覆盖平台端 SLA。

表 5-9 切换前必查清单(评审用)

# 检查项 判定标准
1 每表有主键 44 张业务表(APT_* 23 + GY_*/gygl_* 18 + duty_* 3)+ 30 张若依 sys_* 表,全部 100% 有单列主键
2 字符列有长度 无“无长度 varchar”;长文本用 text
3 非空与默认值 业务必填列 NOT NULL;状态列有默认值
4 时间列统一 全部 datetime(3),无 timestamp
5 金额精度 decimal(12,2),无 float/double
6 空串归一 有统一实现点(拦截器/实体转换),有单测覆盖
7 排序规则 库/表/连接统一库默认 utf8mb4_general_ci,例外清单见 表 5-4「字符集与排序」行;不逐列指定 _ai_ci / _as_cs
8 唯一键长度 组合 UK 总字节数 < 3072
9 保留字冲突 列名不与 MySQL 保留字冲突(如 key、rank、groups)
10 分页与方言 全量 SQL 清点完成,DbType 已切换并有回归用例
11 标识符大小写 全小写;部署机 lower_case_table_names 已确认
12 权限模型 一公寓一 database + 独立账号;账号无平台库权限

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": {}
    }
  ]
}

协议要点:

  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 落本地库(非内存),断网期间持续累积,恢复后按水位续传
平台不可用 不影响叫乘:下行使用本地快照(带版本与有效期),过期后仅降级“新计划不生效”并告警

6.4 语音域接口清单

语音域接口分三组:管理/值班侧(/apt/voice/**,会话鉴权 + 权限点)、健康与运维(/apt/voice/ast/**)、跨端(/open/**,mTLS 或双向令牌)。下表只给清单级描述,字段级契约在阶段二冻结。

表 6-3 公寓端语音域接口清单

# 方向/分组 接口 用途 关键字段
1 管理 GET /apt/voice/endpoints 分机列表(分页) extension、endpointType、roomNo、enabled、registerStatus、syncState
2 管理 POST /apt/voice/endpoints 新增分机(只落库,异步下发) extension、endpointType、roomNo、bindings[]
3 管理 PUT /apt/voice/endpoints/{id} 修改分机属性(不含号码) roomNo、remark、enabled
4 管理 POST /apt/voice/endpoints/{id}/enable、/disable 启用/停用 id、reason
5 管理 DELETE /apt/voice/endpoints/{id} 逻辑删除(延迟物理删除) id、reason
6 管理 POST /apt/voice/endpoints/{id}/bindings 绑定房间/值班台/广播区/设备 bindType、bindTarget、effFrom
7 管理 DELETE /apt/voice/endpoints/{id}/bindings/{bindId} 解绑(写 eff_to) bindId、effTo
8 管理 POST /apt/voice/endpoints/{id}/resync 手工触发收敛 id、force
9 管理 GET /apt/voice/trunks、POST/PUT/DELETE /apt/voice/trunks 中继台账与维护 trunkName、trunkType、peerHost、registerStatus
10 管理 GET /apt/voice/registrations 注册与在线状态 extension、registered、userAgent、lastRegAt
11 查询 GET /apt/voice/calls 会话列表(按任务/人员/时间/状态) taskId、ryid、state、from、to
12 查询 GET /apt/voice/calls/{sessionId} 单次会话详情 全量时间戳、hangupCause、attemptNo
13 查询 GET /apt/voice/calls/{sessionId}/events 原始事件时间线 eventType、eventAt、channel
14 干预 POST /apt/voice/calls/{sessionId}/hangup 人工挂断 reason、operator
15 录音 GET /apt/voice/recordings 录音索引查询 taskId、ryid、state、from、to
16 录音 GET /apt/voice/recordings/{id}/url 取带签名的临时播放地址 url、expireAt
17 录音 POST /apt/voice/recordings/{id}/purge 提前清理(需审计) reason、operator
18 TTS POST /apt/voice/tts/test 试听(不代表叫乘,标 TEST) confNo、text
19 健康 GET /apt/voice/ast/health Asterisk 与 AMI 健康度 amiState、astVersion、confReady、onlineCount、recDiskFree
20 运维 POST /apt/voice/ast/reconcile 触发对账 configType、dryRun
21 运维 GET /apt/voice/ast/drifts 漂移清单 driftType、objectKey、detectedAt
22 运维 GET /apt/voice/config/versions 配置版本与生效情况 configType、source、versionNo、appliedAt
23 跨端下行 GET /open/v1/voice/config?gyId&configType 平台下发语音配置(号段规则、TTS 模板、留存策略) versionNo、checksum、payload
24 跨端上行 POST /open/v1/voice/summary 上报语音质量摘要 regRate、callSuccessRate、recordingMissing、amiReconnects
25 跨端查询 GET /platform/v1/voice/endpoints?gyId 平台侧汇总查看(只读) gyId、total、online、driftCount

接口设计要点:

  1. 增删改停一律异步收敛:接口返回“已受理 + 当前 syncState”,不阻塞等待 Asterisk;前端轮询或订阅 WebSocket 获取最终结果。
  2. 号码不可改:接口层直接拒绝改号请求(返回专用错误码),引导“停旧建新”,避免历史会话与录音索引失去归属。
  3. 录音不外直链:播放必须经 recordings/{id}/url 换取短期签名地址,不暴露物理路径与目录结构。
  4. 健康探针分两个:/apt/voice/ast/health 面向人看(字段全),另设 /apt/ops/health/call-ready 面向监控(只返回“可叫乘/不可叫乘”),避免内部状态导致误判。
  5. 跨端不带媒体:/open/** 只有配置与摘要,不上传录音、不代理 AMI。

不对外暴露的“回调”:AMI 是公寓端主动连接 Asterisk 的客户端,不存在 Asterisk 反向回调 HTTP 的场景;会议与通话状态通过本地领域事件 + /ws/duty 推给前端,不设计公网回调接口。

与表 6-1 的关系:#23~#25 属于新增的跨端语音接口,冻结 v1 契约时并入同一版本号管理(跨端接口总数由 17 变 20),不另立 v2。


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 文本、串口字节流
报警摘要(类型、数量、时间) 每条报警的完整现场上下文
账务流水 余额中间态、实时读余额请求
归档摘要与对账水位 全量历史明细(按需回捞)

7.7 语音链路拓扑

图 7-1 公寓内语音链路

flowchart TB
    subgraph APTHOST["公寓服务器(单机)"]
        UI["值班员浏览器(duty 入口)"]
        APP["公寓端进程<br/>apt-duty.view / apt.duty.engine<br/>apt.voice.*"]
        AST["Asterisk<br/>PJSIP + ConfBridge(Conf-01) + Playback(tts)"]
        REC["录音目录<br/>/data/asterisk/monitor/..."]
        WEB["Nginx<br/>静态页 + 录音 HTTP"]
        DB[("本地 MySQL")]
        SER["串口广播<br/>COM1 9600 8N1"]
    end
    PHONE["房间话机<br/>PJSIP 分机"]
    CONSOLE["值班台话机<br/>固定分机 1009/1010"]
    SPK["广播终端"]
    PLAT["平台端"]

    UI --> WEB
    WEB --> APP
    APP -->|AMI 7058 命令| AST
    AST -->|AMI 事件| APP
    PHONE <-->|SIP 5060 / RTP| AST
    CONSOLE <-->|SIP / RTP| AST
    AST -->|写录音| REC
    REC -->|HTTP 目录| WEB
    APP --> SER --> SPK
    APP --> DB
    APP -->|HTTPS 443 出站| PLAT

链路要点(对应现状实现,作为改造基线):

  1. 叫乘发起固定为两条 Originate:一条打值班台(PJSIP/<console>,扩展 1701@from-internal),一条打房间(PJSIP/<sip_account>,扩展 1901@from-internal);房间侧带 Call-Info: answer-after=5 自动接听。
  2. 接通判定依赖 ConfbridgeJoinEvent(会议号 Conf-01、通道含 PJSIP/ 且非值班台),不是 Answer 事件。
  3. TTS 由 Local/1701@from-internal 发起 Playback(<文本>,tts),文本现经进程内 conftts 单槽位传递。
  4. 录音由 Asterisk 侧产出,公寓端只从事件取文件名并索引;播放走 callcontrol.recording.base-url。
  5. 串口广播与语音是两条独立通道,同一任务可同时触发,互不阻塞。

7.8 分机与中继资源的生命周期

表 7-4 分机资源状态机

状态 含义 进入条件 允许动作 出错处理 落库载体(APT_SIP_ENDPOINT)
DRAFT 台账已建,未下发 新增保存 编辑、下发、删除 — sync_state='PENDING' + enabled=0(与 PENDING 合并,落库即待下发)
PENDING 已提交下发,等待 Asterisk 结果 提交收敛任务 重试、撤回(删除) 超时转 FAILED sync_state='PENDING'
SYNCED 库与 Asterisk 一致 下发成功或对账确认 停用、改绑定、改号(停旧建新) 对账发现差异转 DRIFT sync_state='SYNCED'
FAILED 下发失败 下发报错/超时 重试、修正后重发 连续失败 N 次告警并禁止叫乘 sync_state='FAILED'
DISABLED 停用,不参与叫乘 停用操作 启用(回 PENDING)、删除 — enabled=0(sync_state 不改值)
DELETED 逻辑删除,等待物理清理 删除操作 恢复(仅未物理删除前) 物理删除前二次对账 deleted=1(sync_state 不改值)
DRIFT 库与 Asterisk 不一致 对账发现 按库修复 / 按 Asterisk 回写 未解决前禁止叫乘 sync_state='DRIFT' + APT_AST_DRIFT 一行

落库载体说明:上表 7 个状态不落成 7 个枚举值,而以“sync_state(CHECK 限定 PENDING / SYNCED / FAILED / DRIFT 四值)+ enabled + deleted”三个载体表达,DRAFT 与 PENDING 合并。不这么拆会出现“把 DISABLED 写进 sync_state 直接被 CHECK 拒绝”的故障;语义等价、可查询性更好,迁移到多会议桥或多中继时也不需要改状态机。

配套规则:

  1. 分机号是业务键,不允许原地改号:改号 = 停旧 + 建新,旧号保留 N 天(默认 7 天)以防话机仍注册。
  2. 中继(APT_TRUNK)只有启用/停用两态,注册状态由 pjsip show registrations 观测,不写入资源状态。
  3. 分机与房间是“绑定”而非“字段”:一个房间可临时绑定广播区、一个广播区可含多个分机,绑定按生效区间版本化。
  4. 所有资源变更必须留 APT_AST_CONFIG_VERSION 版本记录与操作审计,支持“回到某一版本”。

7.9 事件跟踪:从 AMI 事件到业务状态

表 7-5 关键事件与处理动作

AMI 事件 触发时机 处理动作 业务状态迁移 落表
OriginateResponse 发起后立即 判 Success/Failure,失败记录原因 CALLING → FAILED APT_CALL_SESSION
Newstate(Ringing/Dialing) 振铃 记录振铃时间 CALLING → RINGING APT_CALL_SESSION
ConfbridgeJoin 入会 匹配任务与人员,回写应答 RINGING → ANSWERED/JOINED_CONF APT_CALL_SESSION + 状态机命令
ConfbridgeLeave 离会 记录离会,启动挂断计时 JOINED_CONF → LEFT APT_CALL_SESSION
Hangup 挂断 按 cause 分类,计算时长 任意 → HANGUP APT_CALL_SESSION
AMI Disconnect 连接断开 在途会话标 UNKNOWN,启动补偿巡检 不变(待补偿判定) APT_AST_AMI_SESSION
本地超时(无事件) 发起后 30s 无应答 判超时,触发复叫策略 CALLING/RINGING → TIMEOUT APT_CALL_SESSION
无 recordfile 字段 入会但事件无录音字段 按文件名约定反查录音目录 不变 APT_RECORDING(缺失态)

失败与超时的识别口径(对齐现状 CALL_TIMEOUT_MS=30000、复叫判定 35s、接听后自动挂断 40s/喊话 30s):

  1. 发起失败:OriginateResponse.Failure,或 AMI 调用抛异常且重连后仍失败。
  2. 无应答超时:30s 内无 ConfbridgeJoin 且通道不存在。
  3. 接通即断:ConfbridgeJoin 后 < 3s Hangup,判“异常中断”,触发复叫并告警。
  4. 会议桥满/不可用:ConfBridge 应用不存在或入会失败,判“语音链路不可用”,直接转值班台兜底。
  5. 挂断原因映射:cause=16 正常、17 忙、18 无应答、19 不可达、21 拒绝;其余归“未知”并保留原始值。

录音与 TTS 的触发时机与回写:

能力 触发时机 成功判定 失败回写
录音 会议桥内房间侧通道入会即开始(Asterisk 侧策略) 事件带 recordfile 或目录存在对应文件 索引置 MISSING + 告警,不影响叫乘结论
TTS 房间侧入会后、播放前生成 APT_TTS_UTTERANCE Playback 返回成功且状态 PLAYING→DONE 置 FAILED + 原因,可人工重播(重播记 source=TEST)
复叫 TTS 复叫任务入会后 同上,seq 递增 同上

7.10 本地闭环与平台依赖边界

表 7-6 能力闭环矩阵

能力 断网是否可用 是否依赖平台 说明
叫乘发起、会议桥、TTS、录音 可用 不依赖 全部本地,平台不可达不影响
分机/中继增删改停 可用 不依赖(号段规则取本地快照) 平台只定规则,落地在本地
注册状态与在线判定 可用 不依赖 AMI/注册事件本地可得
换房后重新绑定分机 可用 不依赖 绑定在本地版本化
语音配置版本(TTS 模板、会议桥参数、录音留存) 可用(用最后版本) 依赖平台下发 断网使用最后已知版本 + 有效期,过期仅告警不阻断
号段规划与中继路由策略 — 依赖平台 变更频率低,随主数据版本下发
语音质量摘要上报 可用(本地累积) 依赖平台接收 进 outbox,恢复后续传
录音合规策略 可用(按最后策略执行) 依赖平台定策略 策略过期时按“更保守”的本地默认执行
跨公寓号码冲突检查 — 依赖平台 新增分机时本地校验规则快照,平台侧做最终冲突检测

7.11 启动自检与运行期巡检

表 7-7 自检项与失败处理

# 检查项 判定方式 失败级别 恢复动作
1 AMI 可达与登录 TCP 连接 + login() 成功 BLOCKED 指数退避重连,告警
2 Asterisk 版本与能力 core show version,比对 asterisk-java 兼容矩阵 DEGRADED 记录并禁止高级能力(如录音)
3 会议桥存在 Conf-01 在 confbridge.conf 且应用可用 BLOCKED 告警;叫乘转值班台
4 拨号计划上下文 from-internal 存在且含 1901/1701 BLOCKED 告警,禁止叫乘
5 值班台分机在册且注册 台账 CONSOLE 类型 + 注册状态 DEGRADED 告警;房间侧仍可叫乘
6 分机台账与 Asterisk 一致 pjsip show endpoints 与台账数量/属性比对 DEGRADED 生成漂移清单
7 录音目录可写、空间充足 试写文件 + 剩余空间 > 阈值 DEGRADED 停止录音、保留叫乘
8 录音播放地址可达 请求 recording.base-url 返回 200 DEGRADED 告警,回放降级为下载
9 TTS 通道可用 试播一条 TEST 文本 DEGRADED 关闭 TTS,仅播放提示音
10 串口可打开 按 console.port 打开(COM1 9600 8N1) DEGRADED 广播改用语音通道
11 时钟偏差 NTP 偏差 < 1s DEGRADED 告警,三时间戳仍可判序
12 AMI 事件滞后 last_event_at 与当前时间差 DEGRADED 触发补偿巡检

运行期巡检(不依赖事件,用于兜住“事件丢了”):每 5 分钟执行一次 core show channels concise 与在途会话比对,发现“库里有会话、Asterisk 无通道”则判 HANGUP(UNKNOWN) 并记补偿;发现“Asterisk 有通道、库里无会话”则记孤儿通道并告警。


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 事件

8.3 Asterisk 与公寓端同机部署

表 8-3 单机资源与容量

项 建议值 依据
CPU 2 核(4 核更稳) 会议桥混音 + 转码 + JVM + MySQL 同机
内存 8 GB(JVM 3 GB / Asterisk 1 GB / MySQL 2 GB / 系统 2 GB) 并发叫乘时会议桥与 TTS 是内存与 CPU 双峰
磁盘 200 GB SSD:系统 60、库 30、录音 80、余量 30 录音按 197 房间量级估算,见下
网卡 千兆内网 RTP 与终端同网段
操作系统 Linux(推荐统信/麒麟或 Rocky);若保留 Windows 需验证串口与录音路径 现状配置含 serverOS: windows、串口 COM1
数据库 本地 MySQL 8.0,独立数据目录 与 Asterisk 抢 IO 时优先保证库
时钟 NTP 客户端指向公寓内网源 叫乘精确到秒,录音与事件时间戳需对齐

录音容量估算(用于定保留天数):8 kHz/16 bit 单声道 WAV 约 0.94 MB/分钟;单次叫乘(含 TTS 与应答)按 2 分钟计约 1.9 MB;197 房间、日均 60 通 ≈ 114 MB/日;保留 90 天 ≈ 10 GB。抓拍与照片另计,不与录音共用卷。

表 8-4 端口与防火墙

端口/协议 用途 监听地址 放通范围
7058/tcp AMI(现状配置值,非默认 5038) 127.0.0.1 仅本机;不建议对公寓内网开放
5060/udp、5060/tcp SIP 信令(PJSIP) 公寓服务器内网地址 公寓内网话机与广播终端
10000-20000/udp RTP 媒体 同上 同上;端口段固定便于策略收敛
80/443/tcp Nginx:值班台、终端页、录音 HTTP 内网地址 公寓内网
22/tcp 运维 SSH 内网地址 仅运维网段
出站 443/tcp 公寓 → 平台 HTTPS — 单向出站,平台侧不回调

防火墙三条硬约束:

  1. AMI 不出本机:现状 AMI 口令(manager01)属于弱边界,同机部署没有理由对外开放 7058。
  2. SIP/RTP 不出公寓内网:话机与广播终端必须与 Asterisk 同网段或经内网 VPN,避免 NAT 导致单向语音。
  3. 录音 HTTP 只对内网:录音含个人信息,不通过公网直链;外发须走申请与审计(见 D15)。

表 8-5 录音存储与清理

项 设计
目录结构 /data/asterisk/monitor/<gyid>/<yyyy>/<MM>/<dd>/,文件名为 Asterisk 回传的 recordfile 名
索引与文件的关系 先落盘、后写 APT_RECORDING;索引缺失时置 MISSING,由巡检补齐或标记丢失
保留期 叫乘录音默认 90 天;TEST 试听 7 天;可按平台策略调为 180/365
清理 每日低峰执行(沿用 cleanupCron 思路 0 30 2 * * ?),先置状态 PURGED 再删文件,失败重试并告警
容量保护 磁盘 > 85% 触发“最旧优先”清理;< 5 GB 停止录音并告警,叫乘不受影响
一致性校验 每日抽样 10 条录音做“索引↔文件↔可播放”三向校验
备份 默认不集中备份;如需归档,按公寓打包上传对象存储,不作为叫乘前置条件

单点故障与高可用取舍:

  1. 不做双活:会议桥状态、SIP 注册与 RTP 无法无状态化,双活会带来注册漂移与串音,收益低于复杂度。
  2. 推荐冷备:同型号备机 + 配置与录音目录定时同步,恢复目标 15 分钟(含 Asterisk 起服与自检)。
  3. 降级路径:Asterisk 不可用时,叫乘退化为“串口广播 + 终端提示 + 值班台人工”,不允许静默失败。
  4. 必须写出 SLA:叫乘可用性目标、恢复时间、降级期间责任人,作为验收条款(对应 D16)。

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 章固化为可评审契约
主要产出 跨端接口契约(表 6-1 的 17 个 + 表 6-3 的语音域 3 个,含错误码、幂等语义、限流);上报信封与 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 库存边界 独立处置,不进入公寓端
D11 会议桥粒度 现状单 Conf-01 是串音与容量的硬约束;建议“每任务一个会议桥 + 保留 Conf-01 作为兼容与广播”,需先评估 Asterisk 资源与拨号计划改造量;未定则分机表与事件表的 conf_no 只能先做“多值预留”
D12 号段与分机编号规则归属 建议平台定规则、公寓端落地;需明确跨公寓是否要求分机号唯一(影响平台侧冲突检测与历史录音检索)
D13 平台端是否一并改 MySQL 短期选 A(平台不动),中期满足表 5-8 三个前置条件后再议 B/C;不建议与公寓端试点同期切换
D14 公寓端操作系统 建议统一 Linux(串口、录音、监控、系统服务均更可控);若必须兼容 Windows,需为串口库、路径、服务化各留一套验证用例
D15 录音合规 需明确:留存期、告知方式、可访问角色、是否允许导出与对外提供;未定前按“90 天 + 仅内网 + 导出必审计”执行
D16 Asterisk 高可用方式 建议单机 + 冷备(RTO 15 分钟)+ 降级广播;双机主备需解决 SIP 注册漂移、录音共享与会议桥状态,不建议首期引入

10.3 语音与数据库专项风险

表 10-3 语音域与数据库迁移专项风险

风险 表现 应对
Asterisk 单点 整个公寓叫乘停摆 冷备 + 自检 + 降级广播 + 明确 RTO;不承诺双活
AMI 事件丢失 连接瞬断丢事件,会话永久停在“呼叫中” 事件 + 超时 + 周期巡检三路判定;巡检发现无通道即判 HANGUP(UNKNOWN) 并补偿
分机配置漂移 现场手工改 Asterisk,库与实际不一致 定时对账 + 漂移表 + 默认只报告;叫乘前二次校验
会议桥串音/串台 多房间同时叫乘互相听到 会议粒度定稿(D11);未定前限制“同瞬间仅一个房间会话”并告警
TTS 文本槽位覆盖 conftts 按会议号单值,并发时后写覆盖前写 消息化 TTS(APT_TTS_UTTERANCE 队列 + 任务绑定),不依赖内存槽位
录音合规 录音含个人信息,留存与导出无约束 定稿 D15;索引层记录访问与导出操作;默认仅内网可访问
录音缺失 recordfile 字段依赖 asterisk-java 版本,现状靠反射容错 文件名约定兜底 + 每日三向校验 + 缺失告警,不阻断叫乘
注册状态不可靠 无 qualify 时分机“假在线” 开启 qualify + 注册事件 + 定时探测;在线判定以“事件 + 探测”双源为准
MySQL 迁移语义变化 空串变 NULL、大小写、无长度 varchar、无主键被放大 表 5-9 清单前置检查 + 只读双跑 + 差异分类手册
双库方言 平台 Kingbase + 公寓 MySQL,同一段 SQL 两边跑 方言测试矩阵;禁止跨库 SQL;SQL 审查纳入 CI
号码规划冲突 多公寓号段重叠,历史录音无法定位 号段规则平台化(D12);分机号全局唯一键含 gyid
时钟偏差 录音、事件、上报时间错位 NTP + 三时间戳 + 偏差告警;账务日切以平台时间为准

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 职责地图 后续所有设计的输入
P0-4 语音域基线修复:AMI 连接自愈、会议桥粒度定稿(D11)、分机台账建立 语音是叫乘主链路,现状无台账、无重连、会议桥硬编码
P1-1 跨端接口契约(17 + 3 个)+ 上报信封 + outbox 模型 决定拆分能否落地
P1-2 公寓端设备网关(一机一密 + 指令 ACK + 离线队列) 现场稳定性收益最直接
P1-3 叫乘状态机单一入口 + 应用端盯控台(基于 JcXx.vue 抽取) 降低同库后脏写风险
P1-4 语音域模型与接口(5.4 / 6.4)+ 配置收敛与对账(5.5) 决定分机能否日常运维,也是录音可追溯的前提
P2-1 账务:平台主账 + 公寓流水 + 日对账;餐饮改走账务接口 数据一致性风险最高的一环
P2-2 运安接入上收平台,公寓端仅消费计划 解除多公寓匹配限制
P2-3 单公寓试点 → 多公寓推广 → 旧逻辑下线与回滚演练 控制现场风险
P2-4 公寓端 KingbaseES → MySQL 切换与双跑(5.6) 影响全库,必须与试点同步,不能拖到推广后

11.3 后续动作

  1. 以第 1、4、5 章为模板,产出《表归属矩阵》与《接口归属清单》两份工作底稿。
  2. 以第 6 章为蓝本,先冻结 v1 契约(含错误码与幂等语义),再进入任何编码。
  3. 以第 3.3 节为基础,明确“值班员可写字段白名单”,作为 Code Review 检查项。
  4. 本文落盘后,在 docs/README.md 与 docs/09-迭代指引与风险清单.md 中建立索引。
  5. 语音域专项(会议桥粒度 D11、号段规则 D12、录音合规 D15)需在阶段二冻结契约前定稿,否则分机表与语音接口会返工;这三项不依赖开发进度,宜先推。

附录 A 术语表

表 A-1 术语表

术语 说明
平台端 提供主数据、运安计划、账务主账、餐饮、跨公寓报表与审计的中心服务
公寓端 部署在某公寓现场、负责设备接入与叫乘执行的本地服务(基于 RuoYi 新建)
应用端 与公寓端同代码同库、面向值班员的盯控与操作界面,不是独立服务或独立库
执行域 / 操作域 同一库内的两类数据与模块:执行域由执行引擎与设备网关写;操作域记录人工干预与审核
水位(watermark) 公寓端上报序号,用于判断漏报、乱序与对账进度
幂等键 同一业务对象同一版本仅生效一次的去重标识
快照版本 下行主数据/规则的版本号,公寓端据此判断是否过期
影子上报 迁移期只上报不生效的写入通道,用于验证新链路而不改变业务结果
分机(endpoint) Asterisk 侧的一个 SIP/PJSIP 终端对象,对应一个号码;与“房间”是多对多绑定关系
中继(trunk) Asterisk 与外部语音系统/运营商对接的通道,不直接绑定房间
AMI Asterisk Manager Interface,公寓端向 Asterisk 发命令并接收事件的通道
会议桥(conference bridge) Asterisk ConfBridge 应用中的一个会议实例;现状固定为 Conf-01
期望态 / 实际态 期望态在本地库(分机台账),实际态在 Asterisk 配置;两者以对账收敛
收敛(reconcile) 将本地台账变更应用到 Asterisk 并回写结果的过程
漂移(drift) 本地台账与 Asterisk 实际配置的差异,记入 APT_AST_DRIFT

附录 B 图表清单

表 B-1 图表索引

编号 名称 位置
表 0-1 文档信息 0 章
表 0-2 修订记录 0 章
表 0-3 本次修订涉及的小节与表号 0 章
表 1-1 现状事实与拆分影响 1.1
表 1-2 主要模块定位与目标归属 1.2
图 2-1 目标逻辑架构 2.1
图 2-2 部署拓扑 2.2
表 2-1 三端调用关系与数据流 2.3
表 2-2 公寓端与应用端技术基线 2.4
图 2-3 应用端与公寓端复用形态 2.5
表 2-3 复用维度与实现落点 2.5
表 3-1 应用端与公寓端的逻辑分工 3.3
表 3-2 语音/分机/事件的三端分工 3.4
表 4-1 能力归属决策表 4.1
表 4-2 平台端模块清单 4.2
表 4-3 公寓端模块清单 4.3
图 4-1 语音模块依赖方向 4.4
表 4-4 语音模块职责与依赖约束 4.4
表 5-1 数据分层、归属与同步方向 5.1
表 5-2 各场景一致性策略 5.2
表 5-3 语音域表清单、主键与关键约束 5.4
表 5-4 语音域字段级 MySQL 适配要点 5.4
表 5-5 分机配置一致性机制 5.5
表 5-6 数据库差异与影响 5.6.1
表 5-7 迁移步骤与退出条件 5.6.2
表 5-8 平台端数据库选项对比 5.6.3
表 5-9 切换前必查清单 5.6.3
表 6-1 平台端与公寓端关键接口 6.1
表 6-2 跨端可靠性机制 6.3
表 6-3 公寓端语音域接口清单 6.4
表 7-1 设备认证阶段设计 7.2
表 7-2 心跳、指令与状态采集 7.3
表 7-3 设备域数据上报与不上报 7.6
图 7-1 公寓内语音链路 7.7
表 7-4 分机资源状态机 7.8
表 7-5 关键事件与处理动作 7.9
表 7-6 能力闭环矩阵 7.10
表 7-7 自检项与失败处理 7.11
表 8-1 三端部署形态 8.1
表 8-2 非功能要求与实现要点 8.2
表 8-3 单机资源与容量 8.3
表 8-4 端口与防火墙 8.3
表 8-5 录音存储与清理 8.3
图 9-1 实施路径 9 章
表 9-1 ~ 9-6 各阶段目标/产出/验收/风险 9 章
表 10-1 风险与应对 10.1
表 10-2 待决策点与建议 10.2
表 10-3 语音域与数据库迁移专项风险 10.3
表 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 阶段零修复项
AMI 连接单例 jcgl/service/AsteriskAmiConfig.java(@Bean 内 login(),失败仅打印) 语音域连接自愈改造依据
会议桥与事件跟踪 jcgl/service/AsteriskCallUtil.java(Conf-01 硬编码、recordlist 内存跟踪、conftts 单槽位、CALL_TIMEOUT_MS=30000、接听后自动挂断 40s/喊话 30s) 7.7–7.11 与 5.4 的设计输入
叫乘发起拨号计划 同上:PJSIP/<console> → 1701@from-internal、PJSIP/<sip_account> → 1901@from-internal、Call-Info: answer-after=5 拨号计划自检项与分机参数基线
录音结果回写 jcgl/service/JcglService.java(updateJcxxRyzt → appendRecordFile 逗号拼接)、mapper/jcgl/JcglMapper.xml(recordfile 列) 录音索引拆表依据(5.4)
分机无台账 mapper/jcgl/JcglRoomMapper.xml、RoomEntity.sip_account APT_SIP_ENDPOINT 拆分依据
语音配置与串口 application.yml / application-{local,prod}.yml(callcontrol.ami.*:host/port 7058/user/pwd/console、callcontrol.console.*:COM1 9600 8N1、callcontrol.recording.base-url) 8.3 部署与 8.4 端口依据
MySQL 驱动已就位 yktgl/pom.xml(mysql-connector-j、kingbase8、ojdbc8 同时存在) 5.6 数据库切换的可行性依据
多公寓部署差异 yktgl/src/main/resources/application-*.yml 库隔离与 Profile 收敛依据

附录 D 文档维护约定

  1. 本文为设计方案,实施过程中若与代码现状出现偏差,以代码为准并同步更新本文,不得反向以文档为借口修改既有约定。
  2. 新增/调整端职责、模块划分、跨端接口时,同步更新第 3、4、6 章与附录 B 的图表清单。
  3. 每个迁移阶段结束,在第 9 章对应阶段表下追加“实际完成情况”与偏差说明。
  4. 决策点在 10.2 定稿后,从“待决策”移入正文对应章节,并保留决策时间与决策人。
  5. 语音域任何变更(新增事件类型、改变会议桥粒度、调整录音路径或留存期)必须同步更新 5.4、5.5、7.7–7.11 与表 8-5,并在表 C-1 补充对应代码位置;不得只改代码不改本文。