14 KiB
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)
按顺序执行:
- 重复入住校验:
isExistCallDutyInfo(ryid, gyid),已有在寓记录直接失败。 - 房间校验:按
gyid + room_no精确查房,房间不存在/状态不可入住/床位已满则失败。 - 交路处理:
jllx='0'表示按交路入住。- 若传了
jlid(固定交路),从交路表取车次、机车号、起点、到达车次/时间,回填到入住记录。 - 若
cc包含“便乘/驻在”,jllx='1',不生成标准叫乘;否则调用populateJcXxByJlXx生成叫乘时间。
- 开车日期校验:有车次时必须传
kcrq,且格式为yyyy-MM-dd。 - 补助计算:
- 固定交路:
getTrainAllowanceInfo(cc, sfffcb, gyid, jlid)。 - 非固定交路:
getAllowanceInfo(gz, sfffcb, sjrysj, gyid)(按工种、是否发补助、入住时间规则)。 changeRemainder生成/更新余额与补助明细;节假日可能跳过余额与补助写入。
- 固定交路:
- 写入住记录:
insertJcxx,ryzt='0'、finish_ly='0'、sjrysj=入住时间,并记录房间号。 - 设备指令:
- 向签到机下发指令
5; - 向房间设备下发指令
1(刷新房间屏)。
- 向签到机下发指令
- 占用重算:
room_rydj→refreshRoomOccupancy,从有效在寓明细重算live_person、person_name,再按床位计算房态。 - 余额/补助落账:非节假日执行
updateRemainder+insert_allowance。 - 叫乘任务:固定交路且
sfjc='1'且非便乘/驻在时,事务提交后创建WakeUpJob,并置is_yaxx='1'。 - 推送: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 构造,不落库 |
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)
- 校验来源 IP 是否在
baseConfig.synJcXxIp白名单。 - 解析 JSON 快照,校验
id、workno、deptime必填,id唯一。 - 获取
CallDutyMatchLock.tryAcquireSync()(数据库协调行 + 租约),避免与抓取/匹配并发。 TRUNCATE GY_SYN_JCXX→ 批量插入 →GY_SYN_JCXX_STATUS='1'。- 事务提交后释放锁;返回
{code,message,result}。
3.2 主动抓取(ByxxResourceService.fetchJlXX)
- 获取同步锁。
- 加载
classpath:/wsdl/PbResource.wsdl,创建 SOAP 客户端。 - 清空
GY_SYN_JCXX。 - 调用运安
getDriverPlanByTimeStr(start, end),把司机 1–4 的计划分别写入快照。 - 更新同步状态为
1,记录日志。
mergeSynJcXx已停用:历史数据存在同一id对应多名司机,按idMERGE 会重复匹配。
3.3 匹配(/jcgl/synUnMatchJcXx → matchCallDutyUnderLock)
前置条件:GY_SYN_JCXX_STATUS='1'(同步完成),且配置了 baseConfig.gyid(匹配只处理该公寓)。
流程:
- 获取数据库行锁,串行匹配。
- 查询
jllx='0'的有效在寓记录,跳过人工锁定交路的记录;若配置不允许“叫乘完成后变更交路”,则跳过已完成叫乘且未离寓的人员。 - 以人员
card_id(工号)匹配GY_SYN_JCXX.workno。 - 命中且交路有变化:按开车时间 + 本地规则重算叫乘/复叫/报警/离寓时间,更新当前入住记录,取消并重建 3 个 Quartz 任务;事务提交后写“交路变更/首次自动匹配/重新匹配”事件日志并 TTS 提醒。
- 命中但交路未变:检查任务是否齐全,缺失则补建。
- 未命中且该人有开车时间:清空交路与时间、取消任务、TTS 通知本人。
- 汇总写同步日志,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 的关键点:
- 幂等:
deviceCode + deviceEventId已存在则直接返回“已经处理”;缺失事件号时只记录日志、不阻断(兼容旧设备)。 - 抓拍:Base64 只接受 JPEG;按
leaveSnapshot配置保存到本地目录,生成/yktgl/photo/leave-snapshots/...URL;未开启抓拍时按requiredForDevice决定是否报错。 - 服务评分:请求可带
kffwpf/jcfwpf/stfwpf,写入离寓记录。 - 事件证据:
recordLeaveEvent写GYGL_LY_EVENT(类型FACE,含deviceEventId、snapshotUrl、操作人、备注)。 - 提交离寓:
submit_ccly→ 更新GY_JCXX(finish_ly=1、sjlysj)→room_ccly释放房间 → 房间设备刷新 →remakeRemainder处理余额(如退补助)。 - 失败回滚:异常时删除已保存快照并回滚事务。
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)
- 校验新房间可入住;
- 校验人员当前房间未变化(防并发);
- 更新入住记录
fjh; - 重算旧房、新房占用;
- 向两个房间设备下发刷新指令。
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. 设备心跳与指令
- 设备按类型调用
/callingDevice/heartbeat、/checkInDevice/heartbeat、/roomDevice/heartbeat、/payDevice/heartbeat、/registDevice/heartbeat、/vendPayDevice/heartbeat。 - 心跳上报:
deviceCode、versionName、deviceType、ip、deviceUpdateState、lastUserUpdateTime、lastDeviceConfigUpdateTime、roomNumber等。 - 服务端返回:
devicePassword、apartmentName、serverTime、updateState、apkUrl、指令列表。 - 指令写入设备指令表,心跳时取走并置
deleted=1(一次性投递)。 - 叫乘/入住/离寓/充值/人员变更都会产生指令。
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 |