包含 RuoYi-Vue 后端(ruoyi-iot 门禁模块)、RuoYi-Vue2 前端、设计文档与升级脚本。 忽略构建产物(target/node_modules/dist)、IDE 配置、运行日志与数据库转储。
163 lines
8.9 KiB
SQL
163 lines
8.9 KiB
SQL
-- =========================================================================
|
||
-- 存量升级:D20 对外房间门禁服务接口 P1(v1 库)
|
||
--
|
||
-- 背景:向外部业务系统(PMS/访客/园区平台)开放入住、退房、续住能力。
|
||
-- 对外接口复用住宿模块(lock_room / lock_stay)与授权下发(lock_auth),
|
||
-- 本期只补三处数据结构:
|
||
-- 1) lock_stay 增加业务系统归属字段,用于幂等与数据隔离;
|
||
-- 2) lock_person_ref 把外部人员标识映射到平台 person_no(按应用隔离);
|
||
-- 3) lock_room_device_history 记录房间-门锁绑定历史,支撑后续
|
||
-- 「开锁记录查询包含历史门锁」(P3)。
|
||
--
|
||
-- 本文档对应设计:doc/对外开放房间门禁服务接口设计.md §9
|
||
--
|
||
-- 执行前置:
|
||
-- 1) 备份 lock_stay / lock_room / lock_device;
|
||
-- 2) 与 D20 代码同批次发布:新代码写 biz_no/biz_system/source 三列,
|
||
-- 缺列会导致接口入住直接失败(平台页面入住不受影响);
|
||
-- 3) 低峰期执行;alter 段锁表时间取决于 lock_stay 行数。
|
||
--
|
||
-- 可重复执行说明:建表用 if not exists、回填用 not exists 保护;
|
||
-- MySQL 不支持 add column / add index if not exists,第 1 节重复执行会报
|
||
-- "Duplicate column name 'biz_no'" 或 "Duplicate key name",忽略即可继续。
|
||
--
|
||
-- 未包含:lock_callback_task(结果回调与重试,P2 交付时再建)。
|
||
-- =========================================================================
|
||
|
||
set names utf8mb4;
|
||
|
||
|
||
-- =========================================================================
|
||
-- 1、lock_stay 增加业务系统字段
|
||
-- biz_system + biz_no 为对外幂等键:业务号只在应用内唯一,平台手工单
|
||
-- 两者均为 NULL(MySQL 唯一索引允许多行 NULL,不会互相冲突)。
|
||
-- source 区分单据来源,便于页面与对账区分「平台办理」和「接口办理」。
|
||
-- =========================================================================
|
||
alter table lock_stay
|
||
add column biz_no varchar(64) default null comment '业务系统单号(应用内唯一,平台手工单为空)' after stay_no,
|
||
add column biz_system varchar(32) default null comment '业务系统编码(iot.openapi.apps[].app-code,平台手工单为空)' after biz_no,
|
||
add column source char(1) default '1' comment '单据来源(1平台 2接口)' after biz_system;
|
||
|
||
alter table lock_stay
|
||
add unique key uk_lock_stay_biz (biz_system, biz_no);
|
||
|
||
|
||
-- =========================================================================
|
||
-- 2、外部人员标识映射表
|
||
-- 业务系统的人员标识格式不受 person_no(2 字母 + 6 数字)约束,因此单独
|
||
-- 建映射;(app_code, external_id) 唯一,同一自然人在不同应用各自建档。
|
||
-- =========================================================================
|
||
create table if not exists lock_person_ref (
|
||
ref_id bigint(20) not null auto_increment comment '映射ID',
|
||
person_id bigint(20) not null comment '人员ID(lock_person.person_id)',
|
||
person_no varchar(32) not null comment '人员编号(冗余协议键)',
|
||
app_code varchar(32) not null comment '接入应用编码(iot.openapi.apps[].app-code)',
|
||
external_id varchar(64) not null comment '业务系统人员标识(假定稳定不变)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (ref_id),
|
||
unique key uk_lock_person_ref (app_code, external_id),
|
||
key idx_lock_person_ref_person (person_no)
|
||
) engine=innodb comment = '外部人员标识映射表';
|
||
|
||
|
||
-- =========================================================================
|
||
-- 3、房间-门锁绑定历史表
|
||
-- 只增不改(解绑时回填 unbind_time):房间换锁后,历史时段内的开锁记录
|
||
-- 仍要能按房间查出来,因此需要保留「哪段时间绑的是哪把锁」。
|
||
-- =========================================================================
|
||
create table if not exists lock_room_device_history (
|
||
history_id bigint(20) not null auto_increment comment '历史ID',
|
||
room_id bigint(20) not null comment '房间ID(lock_room.room_id)',
|
||
device_id bigint(20) not null comment '门锁ID(lock_device.device_id)',
|
||
device_sn varchar(32) default null comment '门锁SN(冗余快照)',
|
||
bind_time datetime not null comment '绑定生效时间',
|
||
unbind_time datetime default null comment '解绑时间(为空表示当前仍在绑)',
|
||
create_by varchar(64) default '' comment '创建者',
|
||
create_time datetime comment '创建时间',
|
||
remark varchar(500) default null comment '备注',
|
||
primary key (history_id),
|
||
key idx_lock_room_device_history (room_id, bind_time, unbind_time),
|
||
key idx_lock_room_device_history_device (device_id)
|
||
) engine=innodb comment = '房间门锁绑定历史表';
|
||
|
||
|
||
-- =========================================================================
|
||
-- 4、存量回填:把房间当前绑定登记为一条未解绑的历史
|
||
-- bind_time 取房间的 update_time(最近一次绑定/换锁),缺失时退到
|
||
-- create_time,再缺失取当前时间。
|
||
-- =========================================================================
|
||
insert into lock_room_device_history (room_id, device_id, device_sn, bind_time, create_by, create_time, remark)
|
||
select r.room_id, r.device_id, d.device_sn,
|
||
ifnull(r.update_time, ifnull(r.create_time, now())), 'migrate', now(),
|
||
'D20 存量回填:当前绑定视为历史起点'
|
||
from lock_room r
|
||
join lock_device d on d.device_id = r.device_id
|
||
where r.del_flag = '0'
|
||
and r.device_id is not null
|
||
and not exists (
|
||
select 1 from lock_room_device_history h
|
||
where h.room_id = r.room_id and h.device_id = r.device_id and h.unbind_time is null
|
||
);
|
||
|
||
|
||
-- =========================================================================
|
||
-- 5、执行后核对(只读,按需执行)
|
||
-- =========================================================================
|
||
-- 5.1 新增列与唯一键是否到位
|
||
-- select column_name, column_type, column_default, column_comment
|
||
-- from information_schema.columns
|
||
-- where table_schema = database() and table_name = 'lock_stay'
|
||
-- and column_name in ('biz_no', 'biz_system', 'source');
|
||
--
|
||
-- select index_name, column_name from information_schema.statistics
|
||
-- where table_schema = database() and table_name = 'lock_stay'
|
||
-- and index_name = 'uk_lock_stay_biz';
|
||
--
|
||
-- 5.2 回填的历史行数应等于当前已绑锁的房间数
|
||
-- select (select count(1) from lock_room_device_history where unbind_time is null) as open_history_cnt,
|
||
-- (select count(1) from lock_room where del_flag = '0' and device_id is not null) as bound_room_cnt;
|
||
--
|
||
-- 5.3 存量入住单的 source 应全部为 1(平台),biz_no/biz_system 应为空
|
||
-- select source, count(1) from lock_stay group by source;
|
||
--
|
||
-- 5.4 业务号重复检查(应为空)
|
||
-- select biz_system, biz_no, count(1) from lock_stay
|
||
-- where biz_no is not null group by biz_system, biz_no having count(1) > 1;
|
||
|
||
|
||
-- =========================================================================
|
||
-- 5.5 修复:平台手工单被写成空串的 biz_no / biz_system(2026-11-01)
|
||
-- 现象:入住管理第二次办理入住报
|
||
-- Duplicate entry '' for key 'lock_stay.uk_lock_stay_biz'
|
||
-- 原因:唯一键只允许多行 NULL,平台单落的却是空串。
|
||
-- 代码已修正为空 → NULL;存量空串按下面语句归一,可重复执行。
|
||
-- 接口单的业务号必非空,这里的空串只可能来自平台手工单,不会误伤接口单据。
|
||
-- =========================================================================
|
||
update lock_stay
|
||
set biz_no = null
|
||
where biz_no = ''
|
||
and (biz_system is null or biz_system = '');
|
||
|
||
update lock_stay
|
||
set biz_system = null
|
||
where biz_system = ''
|
||
and biz_no is null;
|
||
|
||
-- 核对:结果应为 0
|
||
-- select count(1) from lock_stay where biz_no = '' or biz_system = '';
|
||
|
||
|
||
-- =========================================================================
|
||
-- 6、回滚(仅在确认没有接口单据后执行)
|
||
-- =========================================================================
|
||
-- 6.1 删除新增表
|
||
-- drop table if exists lock_room_device_history;
|
||
-- drop table if exists lock_person_ref;
|
||
--
|
||
-- 6.2 回退 lock_stay 字段(会丢失接口单据的业务号归属,执行前先确认)
|
||
-- select count(1) from lock_stay where biz_no is not null;
|
||
-- alter table lock_stay drop index uk_lock_stay_biz;
|
||
-- alter table lock_stay drop column source, drop column biz_system, drop column biz_no;
|