-- ========================================================================= -- 公寓人脸门禁系统(智能门锁)业务表 —— MySQL v2.0 基线 -- -- 库名:iotlocks(与 application-druid.yml 中 master.url 保持一致) -- 前置:先执行同目录 ry_20260417.sql(若依基础表) -- 版本:v2.0 / 2026-10-30 -- 依据:doc/门锁系统架构设计.md §4.1 / §5.1 / §6 / §8.2 / §9.2 -- -- ⚠️ 本文件是【全新安装】的基线脚本,建表前会 drop 同名表。 -- 已在运行的 v1 库请勿直接执行,改用文末【附录 A:存量升级】。 -- -- 数据分域: -- 设备域 lock_group → lock_gateway ⇄ lock_device_gateway ⇄ lock_device -- (一锁可登记到多个网关,归属关系是多对多) -- 人员域 lock_person → lock_biometric(生物特征)/ lock_credential(凭证) -- 授权域 lock_grant = 凭证 × 门锁 × 有效期 × 下发状态 -- 编排域 lock_command -- 事件域 lock_access_log -- 运维域 lock_mqtt_log / lock_service_config / lock_protocol_profile -- -- 与 v1(sql/lock.sql,9 张表)的差异: -- 1) lock_face 拆为 lock_person + lock_biometric,基线不再创建 lock_face; -- lock_auth 拆为 lock_grant + lock_credential,基线不再创建 lock_auth。 -- 两张旧表在存量库中保留至数据迁移完成,本脚本不负责删除。 -- 2) lock_gateway.group_id 改为非空:网关必须先归入分区才能下发, -- 否则 topic 无法拼装(分区号是主题第 2 段)。 -- 3) lock_command 删除 target_code,改用 route_scope + route_code: -- 「投递到哪个主题」与「业务对象是谁」是两个概念,不能共用一个字段。 -- 状态码重排,新增「2 网关已接收」,与两段式应答对齐。 -- 4) lock_mqtt_log 删除 group_code / gateway_sn,改用 route_scope + route_code。 -- 5) 开锁方式、开门结果只保留设备码(2密码/3卡片/4指纹/5二维码/7人脸, -- 结果码 1-6),废弃自造编码 01-06;平台生成的远程开锁固定为 9。 -- 6) 新增 lock_device_gateway:一把锁可登记到多个网关,每个网关各自维护 -- locklist,两个网关按信号强度自行择优。lock_device.gateway_id 改为 -- primary_gateway_id(选路结果缓存,事实源是关联表); -- lock_device.group_id 冗余列删除,分区由选中的网关决定。 -- 7) 菜单未随 v2 调整(仍为人脸/授权口径),待人员域前后端改造时统一。 -- -- 规范(与 ry_20260417.sql 一致): -- 1) 主键统一 bigint(20) auto_increment;关联列统一 bigint(20),不建物理外键。 -- 2) 状态/标志位统一 char(1) 或 char(2);时间统一 datetime。 -- 3) 表与列注释使用 comment;索引统一 idx_ / uk_ 前缀。 -- 4) 脚本可重复执行:建表前 drop table if exists,种子数据先 delete 再 insert。 -- -- 表清单(13 张): -- 1. lock_group 分区 -- 2. lock_gateway 网关 -- 3. lock_device 门锁 -- 4. lock_device_gateway 门锁-网关归属(多对多) -- 5. lock_person 人员 -- 6. lock_biometric 生物特征 -- 7. lock_credential 凭证 -- 8. lock_grant 授权 -- 9. lock_access_log 通行记录 -- 10. lock_command 下行命令 -- 11. lock_mqtt_log MQTT 报文留痕 -- 12. lock_service_config 服务参数配置 -- 13. lock_protocol_profile 协议配置(多厂家/多信封) -- ========================================================================= set names utf8mb4; -- ========================================================================= -- 1、分区表 -- 业务含义:分区是三重身份的统一载体——组织维度(数据权限)、 -- 网络维度(LoRa 路由域,即 MQTT 主题第 2 段的 group_code)、 -- 下发维度(组播 topic 粒度)。三者必须由同一行数据承载。 -- ========================================================================= drop table if exists lock_group; create table lock_group ( group_id bigint(20) not null auto_increment comment '分区ID', group_code varchar(32) not null comment '分区编号(MQTT主题第2段,FFFA+4B,全局唯一,一经占用不再复用)', group_name varchar(64) not null comment '分区名称', parent_id bigint(20) default 0 comment '上级分区ID(0为顶级,支持 园区→楼栋→楼层 树形)', ancestors varchar(500) default '' comment '祖级列表(逗号分隔,如 0,100,101)', zone_type char(1) default '4' comment '分区类型(1园区 2楼栋 3楼层 4其他,字典 lock_zone_type)', dept_id bigint(20) default null comment '所属部门ID(用于数据权限)', manager varchar(64) default null comment '负责人', phone varchar(20) default null comment '联系电话', address varchar(255) default null comment '地址', config_id bigint(20) default null comment '关联MQTT服务器配置ID(lock_service_config.config_id,空表示用全局默认)', lock_capacity int(11) default 0 comment '设计门锁容量(容量规划与超限告警用,0表示不限)', status char(1) default '0' comment '状态(0正常 1停用)', order_num int(4) default 0 comment '显示顺序', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (group_id), unique key uk_lock_group_code (group_code), key idx_lock_group_parent (parent_id), key idx_lock_group_dept (dept_id), key idx_lock_group_status (status) ) engine=innodb comment = '分区表'; -- ========================================================================= -- 2、网关表 -- 业务含义:LoRa 汇聚节点,下挂 ≤16 台门锁;所属分区必填,决定网关级 -- 主题(ydlink/{gatewaySn}/thing/...)与组播主题(ydlink/{groupCode}/...)。 -- gateway_mac 用于 onoff_line 报文反查(该报文 devId 是 12 位 hex MAC)。 -- ========================================================================= drop table if exists lock_gateway; create table lock_gateway ( gateway_id bigint(20) not null auto_increment comment '网关ID', gateway_sn varchar(32) not null comment '网关SN(8位hex,MQTT主题第2段,全局唯一)', gateway_mac varchar(32) default null comment '网关MAC(12位hex,onoff_line 报文 devId,唯一)', gateway_name varchar(64) default null comment '网关名称', group_id bigint(20) not null comment '所属分区ID(lock_group.group_id,必填,决定下发主题)', gateway_ip varchar(64) default null comment '网关IP', subnet_mask varchar(64) default null comment '子网掩码', default_gateway varchar(64) default null comment '默认网关', gateway_password varchar(256) default null comment '网关密码(AES-GCM 密文,下发时解密为明文)', config_id bigint(20) default null comment '关联MQTT服务器配置ID', protocol_profile_id bigint(20) default null comment '协议配置ID(lock_protocol_profile.profile_id)', lora_config varchar(1024) default null comment 'LORA参数配置(JSON)', mqtt_config varchar(1024) default null comment '网关侧MQTT参数(JSON)', max_device int(11) default 16 comment '最大下挂门锁数(协议上限16)', device_count int(11) default 0 comment '关联门锁数(lock_device_gateway 计数,上限 max_device)', config_version int(11) default 0 comment '配置版本号(每次下发+1,用于比对网关侧是否已同步)', sync_status char(1) default '0' comment '配置同步状态(0未同步 1已同步 2同步失败)', online_status char(1) default '1' comment '在线状态(0在线 1离线 2未知,字典 lock_online_status)', last_online_time datetime comment '最后在线时间', last_sync_time datetime comment '最后配置同步时间', firmware_ver varchar(32) default null comment '网关固件版本', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (gateway_id), unique key uk_lock_gateway_sn (gateway_sn), unique key uk_lock_gateway_mac (gateway_mac), key idx_lock_gateway_group (group_id), key idx_lock_gateway_online (online_status), key idx_lock_gateway_sync (sync_status) ) engine=innodb comment = '网关表'; -- ========================================================================= -- 3、门锁表 -- 业务含义:门锁终端。归属关系是【多对多】:一把锁可以登记到多个网关, -- 每个网关各自维护自己的 locklist,两个网关按与锁之间的信号强度择优执行。 -- 归属的事实源在 lock_device_gateway;本表的 primary_gateway_id 只是 -- 选路结果缓存(决定下发主题),不是事实源。 -- 协议字段映射:device_sn -> devId,device_password -> devPsw, -- dev_type -> devType,dev_ver -> devVer。 -- device_mac 是 opencloselock 请求 params[4] 的必填值(12位hex), -- 缺它远程开锁组包不合法。 -- ========================================================================= drop table if exists lock_device; create table lock_device ( device_id bigint(20) not null auto_increment comment '门锁ID', device_sn varchar(32) not null comment '门锁SN(8位hex,对应协议devId,全局唯一)', device_mac varchar(32) default null comment '门锁MAC(12位hex,opencloselock params[4])', device_name varchar(64) default null comment '门锁名称', primary_gateway_id bigint(20) default null comment '当前主控网关ID(选路结果缓存,事实源为 lock_device_gateway,为空表示未登记到任何网关)', device_password varchar(256) default null comment '门锁密码(AES-GCM 密文,对应协议devPsw,下发时解密)', dev_type varchar(8) default null comment '设备类型(对应协议devType)', dev_ver varchar(16) default null comment '设备固件版本(对应协议devVer)', face_algo_version varchar(32) default null comment '人脸算法版本(特征提取 algorithm_version 入参,每把锁各自维护)', protocol_profile_id bigint(20) default null comment '协议配置ID(lock_protocol_profile.profile_id)', capacity_face int(11) default 0 comment '锁内人脸容量(0表示未知,不做校验)', capacity_pwd int(11) default 0 comment '锁内密码容量(0表示未知)', capacity_card int(11) default 0 comment '锁内卡片容量(0表示未知)', room_no varchar(64) default null comment '分配房间号', bind_time datetime comment '首次登记到网关的时间(明细见 lock_device_gateway.bind_time)', last_sync_time datetime comment '最后时间同步时间', signal_strength varchar(8) default null comment '信号强度RSSI(dBm,op=lockrssi 上报,如 -42)', battery_level int(11) default null comment '剩余电量(0-100,255表示常电/未知)', door_state char(1) default null comment '门状态(0关 1开 空未知,状态位bit1)', deadbolt_state char(1) default null comment '反锁/取电状态(0否 1是 空未知,状态位bit2)', door_sensor_state char(1) default null comment '门磁状态(0/1,状态位bit3,含义依现场定义)', raw_state varchar(64) default null comment '最近一次状态位原值(便于协议变更后回溯解析)', last_status_time datetime comment '最后状态上报时间', online_status char(1) default '1' comment '在线状态(0在线 1离线 2未知,字典 lock_online_status)', last_online_time datetime comment '最后在线时间', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (device_id), unique key uk_lock_device_sn (device_sn), key idx_lock_device_mac (device_mac), key idx_lock_device_primary_gw (primary_gateway_id), key idx_lock_device_room (room_no), key idx_lock_device_online (online_status) ) engine=innodb comment = '门锁表'; -- ========================================================================= -- 4、门锁-网关归属表(多对多) -- 业务含义:一把门锁登记到了哪些网关上,以及每个网关视角下该锁的信号与 -- 绑定状态。 -- -- 为什么需要独立成表:厂家协议里 locklist 是「网关的从设备清单」,绑定 -- 动作本身就是 per-gateway 的——locklist(add) 必须在每个期望为该锁服务的 -- 网关上各下发一次。同一把锁被两个网关覆盖时,两个网关依据与锁之间的 -- 信号强度自行择优执行,平台只做两件事:记录每条上报来自哪个网关、 -- 在需要平台选路时选出主控网关。 -- -- 选路规则(应用层实现,本表只提供数据): -- 1) 同分区多网关:LoRa 侧自行择优,平台不改路由,只按上报刷新 -- signal_strength / online_status / last_signal_time; -- 2) 跨分区多网关:按「在线优先 → 信号强度最大 → 上报时间最新」选一个, -- 回写 lock_device.primary_gateway_id,由该网关的分区决定下发主题; -- 3) 主控网关离线时降级到次优网关;全部离线则命令置 PENDING 等待上线。 -- -- 解除归属请用物理删除:本表可由网关的 locklist 回执重建,不存在需要保留的 -- 业务历史;若走 del_flag 逻辑删除,会被 uk_lock_device_gateway 挡住重新绑定。 -- ========================================================================= drop table if exists lock_device_gateway; create table lock_device_gateway ( rel_id bigint(20) not null auto_increment comment '归属关系ID', device_id bigint(20) not null comment '门锁ID(lock_device.device_id)', gateway_id bigint(20) not null comment '网关ID(lock_gateway.gateway_id)', signal_strength varchar(8) default null comment '该网关视角下的锁信号强度(dBm,如 -42,用于选路比较)', last_signal_time datetime comment '该网关最后一次上报本锁信号/状态的时间', online_status char(1) default '2' comment '该网关视角下的锁在线状态(0在线 1离线 2未知,字典 lock_online_status)', bind_status char(1) default '0' comment 'locklist 下发状态(0待下发 1已下发 2下发失败,字典 lock_bind_status)', bind_msg varchar(512) default null comment 'locklist 下发结果说明', bind_time datetime comment '首次登记到该网关的时间', last_sync_time datetime comment '最后一次 locklist 同步时间', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (rel_id), unique key uk_lock_device_gateway (device_id, gateway_id), key idx_lock_dg_gateway (gateway_id), key idx_lock_dg_device (device_id), key idx_lock_dg_route (gateway_id, online_status, last_signal_time), key idx_lock_dg_bind (bind_status) ) engine=innodb comment = '门锁-网关归属表'; -- ========================================================================= -- 5、人员表 -- 业务含义:人员主数据,「是谁」与「凭什么开门」解耦。 -- person_no 是协议中的人员/人脸 ID,8 位定长(如 AA000003), -- 一经下发到设备不可变更(设备侧用它索引特征与权限)。 -- ========================================================================= drop table if exists lock_person; create table lock_person ( person_id bigint(20) not null auto_increment comment '人员ID', person_no varchar(16) not null comment '人员编号(协议人脸/人员ID,8位定长,如 AA000003,全局唯一且不可变更)', person_name varchar(64) default null comment '姓名', person_type char(1) default '0' comment '人员类型(0住户 1员工 2访客 3其他,字典 lock_person_type)', dept_id bigint(20) default null comment '所属部门ID(数据权限)', sys_user_id bigint(20) default null comment '关联若依账号ID(员工自助场景,可为空)', id_card_no varchar(256) default null comment '证件号(AES-GCM 密文)', phone varchar(20) default null comment '联系电话', valid_from datetime comment '人员有效期起(早于凭证有效期时以人员为准)', valid_to datetime comment '人员有效期止(空表示永久)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (person_id), unique key uk_lock_person_no (person_no), key idx_lock_person_name (person_name), key idx_lock_person_dept (dept_id), key idx_lock_person_sys_user (sys_user_id) ) engine=innodb comment = '人员表'; -- ========================================================================= -- 6、生物特征表 -- 业务含义:一人 × 一种生物特征 × 一个算法版本 = 一份特征。 -- 协议要求特征值与门锁算法版本匹配;同一人员在算法版本不同的门锁上 -- 需要多份特征,故 algo_version 参与唯一键。 -- 存的是「未注入人员ID的原始特征」的 AES-GCM 密文;下发时才注入 person_no。 -- ========================================================================= drop table if exists lock_biometric; create table lock_biometric ( bio_id bigint(20) not null auto_increment comment '特征ID', person_id bigint(20) not null comment '人员ID(lock_person.person_id)', bio_type char(1) not null default '1' comment '特征类型(1人脸 2指纹,字典 lock_bio_type)', algo_version varchar(32) not null default '' comment '提取时使用的算法版本(来自 lock_device.face_algo_version)', photo_url varchar(512) default null comment '原图URL(仅人脸,对象存储/文件服务)', photo_md5 varchar(32) default null comment '原图指纹(去重与变更检测)', feature_data mediumtext comment '特征值(AES-GCM 密文,Base64密文)', feature_md5 varchar(32) default null comment '特征指纹(变更检测与幂等下发)', feature_size int(11) default 0 comment '特征字节数', quality_score int(11) default null comment '质量分(提取服务返回0-100)', extract_status char(1) default '0' comment '提取状态(0未提取 1成功 2失败,字典 lock_extract_status)', extract_time datetime comment '提取时间', extract_msg varchar(512) default null comment '提取失败原因', is_primary char(1) default '0' comment '是否主特征(0否 1是,一人多脸时取主)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (bio_id), unique key uk_lock_biometric_person_algo (person_id, bio_type, algo_version), key idx_lock_biometric_person (person_id), key idx_lock_biometric_extract (extract_status) ) engine=innodb comment = '生物特征表'; -- ========================================================================= -- 7、凭证表 -- 业务含义:「凭什么开门」——密码 / IC卡 / 指纹 / 人脸引用。 -- 密码必须可逆加密:协议要求明文下发,不能做 hash。 -- cred_fingerprint 为 HMAC-SHA256,只用于查重,不落明文。 -- ========================================================================= drop table if exists lock_credential; create table lock_credential ( cred_id bigint(20) not null auto_increment comment '凭证ID', person_id bigint(20) not null comment '人员ID(lock_person.person_id)', cred_type char(2) not null comment '凭证类型(01人脸 02密码 03指纹 04IC卡,字典 lock_cred_type)', cred_value_cipher mediumtext comment '凭证内容(AES-GCM 密文:密码/卡号/指纹模板/特征引用)', cred_fingerprint varchar(64) default null comment '凭证指纹(HMAC-SHA256,查重用,不落明文)', cred_seq varchar(64) default null comment '协议侧凭证编号(卡片ID/密码/绑定编号,需可读)', begin_time datetime comment '凭证有效期起(设备侧校验)', end_time datetime comment '凭证有效期止(空表示永久)', max_use int(11) default 0 comment '最大使用次数(0表示不限,对应 icardonce 一类限次卡)', used_count int(11) default 0 comment '已使用次数', freeze_flag char(1) default '0' comment '冻结标志(0正常 1冻结,对应 freeze 动作)', source char(1) default '0' comment '来源(0平台生成 1设备学习 2导入,字典 lock_cred_source)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (cred_id), unique key uk_lock_credential_fp (person_id, cred_type, cred_fingerprint), key idx_lock_credential_person (person_id), key idx_lock_credential_type (cred_type), key idx_lock_credential_seq (cred_seq) ) engine=innodb comment = '凭证表'; -- ========================================================================= -- 8、授权表 -- 业务含义:凭证 × 门锁 × 有效期,并跟踪下发到设备的同步状态。 -- 协议对应:ydlink/{groupCode}/thing/data/batch 的 params(add/delete)。 -- 唯一约束保证「同人同锁同类型凭证」只有一条授权。 -- ========================================================================= drop table if exists lock_grant; create table lock_grant ( grant_id bigint(20) not null auto_increment comment '授权ID', grant_no varchar(64) not null comment '授权编号(业务唯一,建议 GRANT+日期+序号)', person_id bigint(20) not null comment '人员ID', person_no varchar(16) default null comment '冗余人员编号(协议组包直接用)', cred_id bigint(20) not null comment '凭证ID(lock_credential.cred_id)', cred_type char(2) not null comment '冗余凭证类型(01人脸 02密码 03指纹 04IC卡)', device_id bigint(20) not null comment '目标门锁ID', device_sn varchar(32) default null comment '冗余门锁SN', gateway_id bigint(20) default null comment '冗余网关ID', group_id bigint(20) default null comment '冗余分区ID(决定下发主题)', grant_mode char(1) default '1' comment '授权方式(1常驻 2时段 3一次性,字典 lock_grant_mode)', begin_time datetime comment '授权生效窗口起(下发到设备)', end_time datetime comment '授权生效窗口止(空表示永久)', sync_status char(1) default '0' comment '下发状态(0待下发 1已下发 2成功 3失败 4已撤销 5已过期,字典 lock_sync_status)', sync_msg varchar(512) default null comment '下发结果说明', retry_count int(11) default 0 comment '下发重试次数', last_sync_time datetime comment '最后下发/响应时间', last_command_no varchar(64) default null comment '最近一次下发命令号(双向追溯用)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (grant_id), unique key uk_lock_grant_no (grant_no), unique key uk_lock_grant_person_device (person_id, device_id, cred_type), key idx_lock_grant_person (person_id), key idx_lock_grant_cred (cred_id), key idx_lock_grant_device (device_id), key idx_lock_grant_group (group_id), key idx_lock_grant_sync (sync_status), key idx_lock_grant_command (last_command_no) ) engine=innodb comment = '授权表'; -- ========================================================================= -- 9、通行记录表 -- 业务含义:设备通过 event/trigger(op=lockrecord)上报的开门记录。 -- 高频只追加表,无 del_flag / update_*。 -- -- 【幂等】设备上报的 seq 常为 "0" 或空,不能做唯一键; -- 去重靠业务键 (device_sn, open_time, open_type, 凭证) 先查后插 + -- Redis SETNX 抑制并发重复。 -- -- 【分区】当前不做分区(容量假设未经实测)。当单表超过千万行时按 -- open_time 月度 RANGE 分区,注意 MySQL 要求分区列必须包含在每个唯一键中, -- 届时主键需改为 (log_id, open_time)。 -- ========================================================================= drop table if exists lock_access_log; create table lock_access_log ( log_id bigint(20) not null auto_increment comment '日志ID', device_id bigint(20) default null comment '门锁ID(解析 device_sn 得到,未登记时为空)', device_sn varchar(32) not null comment '门锁SN', gateway_id bigint(20) default null comment '上报网关ID', gateway_sn varchar(32) default null comment '上报网关SN', group_id bigint(20) default null comment '所属分区ID', person_id bigint(20) default null comment '人员ID(凭证反查得到)', person_no varchar(16) default null comment '人员编号', person_name varchar(64) default null comment '冗余人员姓名', cred_id bigint(20) default null comment '凭证ID(凭证反查得到)', cred_type char(2) default null comment '凭证类型(01人脸 02密码 03指纹 04IC卡)', card_no varchar(32) default null comment '卡号(卡片开门时的脱敏凭证号)', open_type varchar(8) default null comment '开门方式(设备码:2密码 3卡片 4指纹 5二维码 7人脸,字典 lock_open_type)', open_result varchar(8) default null comment '开门结果(1成功 2通用错误 3密码错 4卡错 5传感器 6人脸错,字典 lock_open_result)', open_dir varchar(8) default null comment '开/关方向(V1为空;V2:1开 2关)', open_time datetime comment '开门时间(设备上报时间)', recv_time datetime comment '服务端接收时间', seq varchar(32) default null comment '报文序号(仅留痕,不用于唯一约束)', protocol_ver char(1) default '1' comment '记录协议版本(1或2,决定 params[4] 语义)', raw_params text comment '原始params数组(JSON,便于协议变更后重放解析)', create_time datetime comment '创建时间', remark varchar(500) default null comment '备注', primary key (log_id), key idx_lock_access_log_device (device_sn), key idx_lock_access_log_person (person_no), key idx_lock_access_log_time (open_time), key idx_lock_access_log_idem (device_sn, open_time, open_type), key idx_lock_access_log_group (group_id), key idx_lock_access_log_seq (seq) ) engine=innodb comment = '通行记录表'; -- ========================================================================= -- 10、下行命令表 -- 业务含义:所有平台→设备的指令留痕,支撑回执匹配、重试补偿、对账与审计。 -- -- 【路由与身份分离】route_scope/route_code 决定报文发到哪个主题; -- target_type/target_id 说明业务对象是谁。二者不可混用(v1 用 target_code -- 一个字段承担两种语义,导致按锁反查主题要绕三道推导)。 -- -- 【状态机】0待发送 → 1已发送 → 2网关已接收 → 3成功/4失败;5超时;6已取消。 -- 收到终态码(0/11/12)即置终态,不强制等到网关回执 10。 -- -- 【幂等】idempotency_key 不建唯一索引:同一业务在业务上允许合法重发 -- (如授权覆盖下发),唯一性由 Redis SETNX 在 5 秒窗口内保证, -- DB 索引仅用于排查重复下发。 -- ========================================================================= drop table if exists lock_command; create table lock_command ( command_id bigint(20) not null auto_increment comment '命令ID', command_no varchar(64) not null comment '命令编号(对应协议seq,全局唯一,分布式生成)', command_type char(4) not null comment '命令类型(字典 lock_command_type,0001-0020)', route_scope char(1) not null comment '路由范围(1分组 2网关,字典 lock_route_scope)', route_code varchar(32) not null comment '路由编号(分区号 group_code 或网关SN,决定下发主题)', target_type char(1) default null comment '业务目标类型(1网关 2门锁 3分组,字典 lock_target_type)', target_id bigint(20) default null comment '业务目标ID(网关ID/门锁ID/分区ID)', biz_type varchar(16) default null comment '业务类型(GRANT/DEVICE/GATEWAY/GROUP,解释 biz_id 的含义)', biz_id bigint(20) default null comment '业务ID(如授权下发时指向 lock_grant.grant_id)', topic varchar(255) default null comment '下发主题', payload mediumtext comment '下发报文(特征值等敏感字段需掩码)', req_time datetime comment '下发时间', resp_topic varchar(255) default null comment '响应主题', resp_payload mediumtext comment '响应报文(敏感字段需掩码)', resp_time datetime comment '响应时间', command_status char(1) default '0' comment '命令状态(0待发送 1已发送 2网关已接收 3成功 4失败 5超时 6已取消,字典 lock_command_status)', result_code varchar(8) default null comment '归一后的结果码(0成功 10网关已接收 11设备忙 12设备不存在)', gateway_ack char(1) default '0' comment '是否收到网关回执10(0否 1是)', device_ack char(1) default '0' comment '是否收到门锁终态(0否 1是)', device_result char(1) default null comment '门锁终态结果(0失败 1成功 空未知)', retry_count int(11) default 0 comment '已重试次数', max_retry int(11) default 3 comment '最大重试次数', next_retry_time datetime comment '下次重试时间(补偿任务扫描,必须早于 timeout_at)', timeout_at datetime comment '超时截止时间(按命令类型差异化)', idempotency_key varchar(64) default null comment '幂等键(hash(命令类型,目标,业务,报文指纹),5秒窗口内去重)', error_msg varchar(512) default null comment '失败原因', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (command_id), unique key uk_lock_command_no (command_no), key idx_lock_command_status (command_status), key idx_lock_command_timeout (command_status, timeout_at), key idx_lock_command_retry (command_status, next_retry_time), key idx_lock_command_route (route_scope, route_code), key idx_lock_command_biz (biz_type, biz_id), key idx_lock_command_idem (idempotency_key), key idx_lock_command_time (req_time) ) engine=innodb comment = '下行命令表'; -- ========================================================================= -- 11、MQTT 报文留痕表 -- 上下行原始报文留痕,用于协议联调、问题回溯与审计。 -- payload 入库前必须掩码(特征 Base64 / 密码 / 卡号一律替换为长度+MD5)。 -- route_scope/route_code 取代 v1 的 group_code/gateway_sn: -- 主题第 2 段既可能是分区号也可能是网关SN,一个字段无法表达。 -- ========================================================================= drop table if exists lock_mqtt_log; create table lock_mqtt_log ( log_id bigint(20) not null auto_increment comment '日志ID', direction char(1) not null comment '方向(1上行设备→平台 2下行平台→设备)', topic varchar(255) not null comment 'MQTT主题', route_scope char(1) default null comment '主题第2段类型(1分组 2网关)', route_code varchar(32) default null comment '主题第2段取值(分区号或网关SN)', device_sn varchar(32) default null comment '报文中的设备标识(devId,可能是锁SN/网关SN/网关MAC)', op varchar(32) default null comment '操作类型(协议op)', mode varchar(8) default null comment '方向标识(s2d服务端→设备 d2s设备→服务端)', ac varchar(8) default null comment '动作类型(协议ac:req请求 resp应答)', seq varchar(32) default null comment '报文序号(协议seq)', protocol_ver char(1) default null comment '业务协议版本(1或2,来自 protocalVer/devVer)', envelope_ver char(1) default null comment '信封形态(1完整V1 2精简V2 3无信封,字典 lock_envelope_ver)', qos smallint default 1 comment '服务质量', retained char(1) default '0' comment '是否保留消息(0否 1是)', payload mediumtext comment '报文原文(敏感字段掩码后)', chksum varchar(32) default null comment '报文校验和(协议未定义算法,仅留痕)', verify_status char(1) default '0' comment '校验结果(0未校验 1通过 2失败)', handle_status char(1) default '0' comment '处理状态(0待处理 1成功 2失败 3已忽略,字典 lock_handle_status)', handle_msg varchar(512) default null comment '处理结果说明', cost_time int(11) default 0 comment '处理耗时(毫秒)', recv_time datetime comment '接收/发送时间', create_time datetime comment '创建时间', primary key (log_id), key idx_lock_mqtt_log_topic (topic), key idx_lock_mqtt_log_device (device_sn), key idx_lock_mqtt_log_route (route_scope, route_code), key idx_lock_mqtt_log_time (recv_time), key idx_lock_mqtt_log_handle (handle_status), key idx_lock_mqtt_log_seq (seq), key idx_lock_mqtt_log_direct (direction) ) engine=innodb comment = 'MQTT报文留痕表'; -- ========================================================================= -- 12、服务参数配置表 -- 承载“系统参数”中的 MQTT 服务器配置、人脸特征提取服务配置、 -- 平台参数与协议策略。结构化分类字段 + JSON 值的折中方案, -- 新增配置项无需改表,前端按 config_type 渲染不同表单。 -- -- config_value JSON 约定: -- config_type=01(MQTT服务器) -- {"brokerUrl":"tcp://127.0.0.1:1883","clientId":"","username":"","password":"", -- "defaultQos":1,"cleanSession":true,"keepAlive":60,"connectionTimeout":30} -- config_type=02(人脸特征服务) -- POST multipart/form-data,表单字段 file 为图片文件 -- 返回 {"functionSuccess":true,"resultSuccess":true,"resultData":"特征base64","msg":"..."} -- {"endpoint":"http://192.168.1.202:8802/...","timeout":15000,"qualityThreshold":60} -- config_type=03(平台参数) -- {"accessLogKeepDays":180,"mqttLogLevel":"error","commandTimeout":10,"maxRetry":3} -- config_type=04(协议策略) -- {"protocolVer":"1","commandTimeout":10,"pushRatePerSecond":5, -- "retryBaseSeconds":30,"maskFields":["feature","password","cardNo"]} -- ========================================================================= drop table if exists lock_service_config; create table lock_service_config ( config_id bigint(20) not null auto_increment comment '配置ID', config_name varchar(100) not null comment '配置名称', config_type char(2) not null comment '配置类型(01MQTT服务器 02人脸特征服务 03平台参数 04协议策略,字典 lock_config_type)', config_value text comment '配置内容(JSON)', group_id bigint(20) default null comment '归属分区ID(为空表示全局默认)', is_default char(1) default '1' comment '是否默认(0是 1否)', enabled char(1) default '0' comment '是否启用(0启用 1停用)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (config_id), unique key uk_lock_service_config_name (config_name, config_type), key idx_lock_service_config_type (config_type) ) engine=innodb comment = '服务参数配置表'; -- ========================================================================= -- 13、协议配置表 -- 把「厂家差异」收敛成数据:主题前缀、资源段、信封版本、结果码映射、 -- 参数模板都由本表驱动,避免 ydlink/thing 之类的前缀散落在代码里。 -- param_templates 示例: -- {"password.add":{"requestSize":7,"resultIndex":2}, -- "password.delete":{"requestSize":5,"resultIndex":2}, -- "opencloselock":{"requestSize":-1,"resultIndex":5}} -- ========================================================================= drop table if exists lock_protocol_profile; create table lock_protocol_profile ( profile_id bigint(20) not null auto_increment comment '协议配置ID', profile_code varchar(32) not null comment '配置编码(如 ydlink-v1,全局唯一)', profile_name varchar(64) not null comment '配置名称', vendor varchar(32) not null comment '厂家标识(如 ydlink)', topic_prefix varchar(32) not null default 'ydlink' comment '主题前缀(第1段)', resource_segment varchar(32) not null default 'thing' comment '资源段(第3段)', envelope_ver char(1) default '1' comment '默认信封(1完整V1 2精简V2 3无信封,字典 lock_envelope_ver)', protocol_ver char(1) default '1' comment '默认业务协议版本(1或2)', result_code_map text comment '结果码映射(JSON:设备码→内部分类)', param_templates text comment '参数模板(JSON:op[.子命令]→长度/结果码下标/字段名)', enabled char(1) default '0' comment '是否启用(0启用 1停用)', status char(1) default '0' comment '状态(0正常 1停用)', del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', create_by varchar(64) default '' comment '创建者', create_time datetime comment '创建时间', update_by varchar(64) default '' comment '更新者', update_time datetime comment '更新时间', remark varchar(500) default null comment '备注', primary key (profile_id), unique key uk_lock_protocol_profile_code (profile_code), key idx_lock_protocol_profile_vendor (vendor) ) engine=innodb comment = '协议配置表'; -- ========================================================================= -- 14、字典初始化 -- 先按 dict_type 清理,保证脚本可重复执行。 -- 取值口径以 doc/门锁系统架构设计.md §9.4 为准。 -- ========================================================================= delete from sys_dict_data where dict_type in ('lock_online_status','lock_open_type','lock_open_result','lock_cred_type', 'lock_command_type','lock_command_status','lock_sync_status','lock_handle_status', 'lock_config_type','lock_extract_status','lock_person_type','lock_target_type', 'lock_zone_type','lock_bio_type','lock_grant_mode','lock_cred_source', 'lock_route_scope','lock_envelope_ver','lock_bind_status'); delete from sys_dict_type where dict_type in ('lock_online_status','lock_open_type','lock_open_result','lock_cred_type', 'lock_command_type','lock_command_status','lock_sync_status','lock_handle_status', 'lock_config_type','lock_extract_status','lock_person_type','lock_target_type', 'lock_zone_type','lock_bio_type','lock_grant_mode','lock_cred_source', 'lock_route_scope','lock_envelope_ver','lock_bind_status'); insert into sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) values (100, '门禁设备在线状态', 'lock_online_status', '0', 'admin', CURRENT_TIMESTAMP, '网关/门锁在线状态'), (101, '门禁开门方式', 'lock_open_type', '0', 'admin', CURRENT_TIMESTAMP, '只保留设备码,废弃自造编码'), (102, '门禁开门结果', 'lock_open_result', '0', 'admin', CURRENT_TIMESTAMP, '设备记录结果码 1-6'), (103, '门禁凭证类型', 'lock_cred_type', '0', 'admin', CURRENT_TIMESTAMP, '人脸/密码/指纹/IC卡'), (104, '门禁命令类型', 'lock_command_type', '0', 'admin', CURRENT_TIMESTAMP, '下行命令类型'), (105, '门禁命令状态', 'lock_command_status', '0', 'admin', CURRENT_TIMESTAMP, '与两段式应答对齐'), (106, '门禁授权同步状态', 'lock_sync_status', '0', 'admin', CURRENT_TIMESTAMP, '授权下发同步状态'), (107, '门禁报文处理状态', 'lock_handle_status', '0', 'admin', CURRENT_TIMESTAMP, 'MQTT报文处理状态'), (108, '门禁服务配置类型', 'lock_config_type', '0', 'admin', CURRENT_TIMESTAMP, '服务参数配置类型'), (109, '人脸特征提取状态', 'lock_extract_status', '0', 'admin', CURRENT_TIMESTAMP, '特征提取状态'), (110, '门禁人员类型', 'lock_person_type', '0', 'admin', CURRENT_TIMESTAMP, '人员类型'), (111, '门禁命令目标类型', 'lock_target_type', '0', 'admin', CURRENT_TIMESTAMP, '命令业务目标类型'), (112, '门禁分区类型', 'lock_zone_type', '0', 'admin', CURRENT_TIMESTAMP, '园区/楼栋/楼层'), (113, '生物特征类型', 'lock_bio_type', '0', 'admin', CURRENT_TIMESTAMP, '人脸/指纹'), (114, '授权方式', 'lock_grant_mode', '0', 'admin', CURRENT_TIMESTAMP, '常驻/时段/一次性'), (115, '凭证来源', 'lock_cred_source', '0', 'admin', CURRENT_TIMESTAMP, '平台生成/设备学习/导入'), (116, '命令路由范围', 'lock_route_scope', '0', 'admin', CURRENT_TIMESTAMP, '分组/网关'), (117, '协议信封形态', 'lock_envelope_ver', '0', 'admin', CURRENT_TIMESTAMP, '完整V1/精简V2/无信封'), (118, '门锁绑定状态', 'lock_bind_status', '0', 'admin', CURRENT_TIMESTAMP, 'locklist 下发状态'); insert into sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) values -- 在线状态 (100, 1, '在线', '0', 'lock_online_status', '', 'success', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (101, 2, '离线', '1', 'lock_online_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (102, 3, '未知', '2', 'lock_online_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 开门方式(设备记录 params[2] 原值) (110, 1, '密码', '2', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备码'), (111, 2, 'IC卡', '3', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备码'), (112, 3, '指纹', '4', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备码'), (113, 4, '二维码', '5', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备码'), (114, 5, '人脸', '7', 'lock_open_type', '', 'success', 'Y', '0', 'admin', CURRENT_TIMESTAMP, '设备码,实测值'), (115, 6, '远程开锁', '9', 'lock_open_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, '平台生成,非设备上报'), -- 开门结果(设备记录结果码) (120, 1, '成功', '1', 'lock_open_result', '', 'success', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (121, 2, '通用错误', '2', 'lock_open_result', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (122, 3, '密码错误', '3', 'lock_open_result', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (123, 4, '卡片错误', '4', 'lock_open_result', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (124, 5, '传感器事件','5','lock_open_result', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (125, 6, '人脸错误', '6', 'lock_open_result', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 凭证类型 (130, 1, '人脸', '01', 'lock_cred_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, 'op=facefeature'), (131, 2, '密码', '02', 'lock_cred_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'op=password'), (132, 3, '指纹', '03', 'lock_cred_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'op=finger'), (133, 4, 'IC卡', '04', 'lock_cred_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'op=iccard'), -- 命令类型(与架构设计 §5.5 一一对应) (140, 1, '绑定门锁', '0001', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'locklist(add) / property/set'), (141, 2, '解绑门锁', '0002', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'locklist(clear/add) / property/set'), (142, 3, '同步门锁时间', '0003', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(systime) / property/set'), (143, 4, '远程开锁', '0004', 'lock_command_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'opencloselock(1) / action/execute'), (144, 5, '远程关锁', '0005', 'lock_command_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'opencloselock(2) / action/execute'), (145, 6, '重启网关', '0006', 'lock_command_type', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(reset) / property/set'), (146, 7, '修改网络参数', '0007', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(server/bind) / property/set'), (147, 8, '修改LORA参数', '0008', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(lorainfo) / property/set'), (148, 9, '修改MQTT参数', '0009', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(server) / property/set'), (149, 10, '保存配置', '0010', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'locklist+config 组合,无独立 op'), (150, 11, '授权下发', '0011', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'facefeature/password/iccard/finger(add) / data/batch'), (151, 12, '清除授权', '0012', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '同上(delete) / data/batch'), (152, 13, '清除门锁', '0013', 'lock_command_type', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(reset) / property/set'), (153, 14, '恢复默认参数', '0014', 'lock_command_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(defaultpara) / property/set'), (154, 15, '配置断电延时', '0015', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'config(poweroffdelay) / property/set'), (155, 16, '远程语音播报', '0016', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'voice(play) / action/execute'), (156, 17, '查询从设备状态', '0017', 'lock_command_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'getslaveinfo / data/batch'), (157, 18, '读取开门记录', '0018', 'lock_command_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'getrecord(readrecord) / data/batch'), (158, 19, '读取权限列表', '0019', 'lock_command_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'getkey(readkey) / data/batch,对账用'), (159, 20, '读网关信息', '0020', 'lock_command_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'getgwinfo / property/set,发现用'), -- 命令状态 (160, 1, '待发送', '0', 'lock_command_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, 'PENDING'), (161, 2, '已发送', '1', 'lock_command_status', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'PUBLISHED'), (162, 3, '网关已接收', '2', 'lock_command_status', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'GATEWAY_ACK,结果码10,中间态'), (163, 4, '成功', '3', 'lock_command_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, '结果码0'), (164, 5, '失败', '4', 'lock_command_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, '结果码11/12'), (165, 6, '超时', '5', 'lock_command_status', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, '超过 timeout_at'), (166, 7, '已取消', '6', 'lock_command_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, '用户撤回/目标已解绑'), -- 授权同步状态 (170, 1, '待下发', '0', 'lock_sync_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (171, 2, '已下发', '1', 'lock_sync_status', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '命令已发出未终态'), (172, 3, '成功', '2', 'lock_sync_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (173, 4, '失败', '3', 'lock_sync_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (174, 5, '已撤销', '4', 'lock_sync_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备侧已删除'), (175, 6, '已过期', '5', 'lock_sync_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, '超过 end_time'), -- 报文处理状态 (180, 1, '待处理', '0', 'lock_handle_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (181, 2, '成功', '1', 'lock_handle_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (182, 3, '失败', '2', 'lock_handle_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, '含参数模板校验不通过'), (183, 4, '已忽略', '3', 'lock_handle_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 服务配置类型 (190, 1, 'MQTT服务器', '01', 'lock_config_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (191, 2, '人脸特征服务', '02', 'lock_config_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (192, 3, '平台参数', '03', 'lock_config_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (193, 4, '协议策略', '04', 'lock_config_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '重试/限流/掩码'), -- 特征提取状态 (200, 1, '未提取', '0', 'lock_extract_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (201, 2, '成功', '1', 'lock_extract_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (202, 3, '失败', '2', 'lock_extract_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 人员类型 (210, 1, '住户', '0', 'lock_person_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (211, 2, '员工', '1', 'lock_person_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (212, 3, '访客', '2', 'lock_person_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (213, 4, '其他', '3', 'lock_person_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 命令目标类型 (220, 1, '网关', '1', 'lock_target_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (221, 2, '门锁', '2', 'lock_target_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (222, 3, '分区', '3', 'lock_target_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 分区类型 (230, 1, '园区', '1', 'lock_zone_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (231, 2, '楼栋', '2', 'lock_zone_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (232, 3, '楼层', '3', 'lock_zone_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (233, 4, '其他', '4', 'lock_zone_type', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 生物特征类型 (240, 1, '人脸', '1', 'lock_bio_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (241, 2, '指纹', '2', 'lock_bio_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 授权方式 (250, 1, '常驻', '1', 'lock_grant_mode', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (251, 2, '时段', '2', 'lock_grant_mode', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), (252, 3, '一次性', '3', 'lock_grant_mode', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 凭证来源 (260, 1, '平台生成', '0', 'lock_cred_source', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (261, 2, '设备学习', '1', 'lock_cred_source', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'learn'), (262, 3, '导入', '2', 'lock_cred_source', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''), -- 命令路由范围 (270, 1, '分组', '1', 'lock_route_scope', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, '主题第2段为分区号'), (271, 2, '网关', '2', 'lock_route_scope', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '主题第2段为网关SN'), -- 协议信封形态 (280, 1, '完整信封V1', '1', 'lock_envelope_ver', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, '含 ac/mode/chksum'), (281, 2, '精简信封V2', '2', 'lock_envelope_ver', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '含 devVer/protocalVer'), (282, 3, '无信封', '3', 'lock_envelope_ver', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, '仅 devId/seq/op/params'), -- 门锁绑定状态(locklist 下发状态) (290, 1, '待下发', '0', 'lock_bind_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''), (291, 2, '已下发', '1', 'lock_bind_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, '网关已接收 locklist'), (292, 3, '下发失败', '2', 'lock_bind_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''); -- ========================================================================= -- 15、协议配置种子数据 -- 单厂家阶段只有 ydlink 一条;新增厂家时插一行即可,不新增配置项。 -- ========================================================================= delete from lock_protocol_profile where profile_code = 'ydlink-v1'; insert into lock_protocol_profile (profile_id, profile_code, profile_name, vendor, topic_prefix, resource_segment, envelope_ver, protocol_ver, result_code_map, param_templates, enabled, status, create_by, create_time, remark) values (1, 'ydlink-v1', 'ydlink 厂家协议(V1/V2 并存)', 'ydlink', 'ydlink', 'thing', '1', '1', '{"0":"SUCCESS","10":"GATEWAY_RECEIVED","11":"BUSY","12":"NOT_FOUND"}', '{"password.add":{"requestSize":7,"resultIndex":2},"password.delete":{"requestSize":5,"resultIndex":2},"iccard.add":{"requestSize":7,"resultIndex":2},"iccard.delete":{"requestSize":5,"resultIndex":2},"facefeature.add":{"requestSize":8,"resultIndex":2},"facefeature.delete":{"requestSize":4,"resultIndex":2},"locklist":{"requestSize":-1,"resultIndex":1},"config":{"requestSize":-1,"resultIndex":1},"opencloselock":{"requestSize":-1,"resultIndex":5}}', '0', '0', 'admin', CURRENT_TIMESTAMP, '参数模板随协议整理 §6 维护,改配置不改代码'); -- ========================================================================= -- 16、菜单初始化 -- 沿用 v1 菜单(人脸/授权口径),待人员域前后端改造时统一为 -- 人员/凭证/授权三模块。此处不改动,避免与现有控制器权限不一致。 -- ========================================================================= delete from sys_menu where perms like 'lock:%'; delete from sys_menu where menu_name = '门禁管理' and parent_id = 0; insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values (2000, '门禁管理', 0, 4, 'iot', null, '', '', 1, 0, 'M', '0', '0', '', 'lock', 'admin', CURRENT_TIMESTAMP, '公寓人脸门禁系统目录'); insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values (2010, '公寓分组', 2000, 1, 'group', 'iot/group/index', '', '', 1, 0, 'C', '0', '0', 'lock:group:list', 'tree', 'admin', CURRENT_TIMESTAMP, '公寓分组菜单'), (2020, '门锁网关', 2000, 2, 'gateway', 'iot/gateway/index', '', '', 1, 0, 'C', '0', '0', 'lock:gateway:list', 'server', 'admin', CURRENT_TIMESTAMP, '门锁网关菜单'), (2030, '智能门锁', 2000, 3, 'device', 'iot/device/index', '', '', 1, 0, 'C', '0', '0', 'lock:device:list', 'lock', 'admin', CURRENT_TIMESTAMP, '智能门锁菜单'), (2040, '人脸数据', 2000, 4, 'face', 'iot/face/index', '', '', 1, 0, 'C', '0', '0', 'lock:face:list', 'peoples', 'admin', CURRENT_TIMESTAMP, '人脸数据菜单'), (2050, '授权管理', 2000, 5, 'auth', 'iot/auth/index', '', '', 1, 0, 'C', '0', '0', 'lock:auth:list', 'lock', 'admin', CURRENT_TIMESTAMP, '授权管理菜单'), (2060, '通行记录', 2000, 6, 'accesslog', 'iot/accesslog/index','', '', 1, 0, 'C', '0', '0', 'lock:accesslog:list','list', 'admin', CURRENT_TIMESTAMP, '通行记录菜单'), (2070, '命令记录', 2000, 7, 'command', 'iot/command/index', '', '', 1, 0, 'C', '0', '0', 'lock:command:list', 'job', 'admin', CURRENT_TIMESTAMP, '命令记录菜单'), (2080, '报文日志', 2000, 8, 'mqttlog', 'iot/mqttlog/index', '', '', 1, 0, 'C', '0', '0', 'lock:mqttlog:list', 'log', 'admin', CURRENT_TIMESTAMP, '报文日志菜单'), (2090, '系统参数', 2000, 9, 'config', 'iot/config/index', '', '', 1, 0, 'C', '0', '0', 'lock:config:list', 'edit', 'admin', CURRENT_TIMESTAMP, '系统参数菜单'); insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values (2011, '分组查询', 2010, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2012, '分组新增', 2010, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:add', '#', 'admin', CURRENT_TIMESTAMP, ''), (2013, '分组修改', 2010, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:edit', '#', 'admin', CURRENT_TIMESTAMP, ''), (2014, '分组删除', 2010, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:remove', '#', 'admin', CURRENT_TIMESTAMP, ''), (2015, '分组导出', 2010, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2021, '网关查询', 2020, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2022, '网关新增', 2020, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:add', '#', 'admin', CURRENT_TIMESTAMP, ''), (2023, '网关修改', 2020, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:edit', '#', 'admin', CURRENT_TIMESTAMP, ''), (2024, '网关删除', 2020, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:remove', '#', 'admin', CURRENT_TIMESTAMP, ''), (2025, '网关导出', 2020, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2026, '网关配置下发', 2020, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:config', '#', 'admin', CURRENT_TIMESTAMP, '修改网络/LORA/MQTT参数与保存配置'), (2027, '网关重启', 2020, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:reboot', '#', 'admin', CURRENT_TIMESTAMP, ''), (2028, '网关绑定门锁', 2020, 8, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:bind', '#', 'admin', CURRENT_TIMESTAMP, '绑定/清除门锁'), (2031, '门锁查询', 2030, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2032, '门锁新增', 2030, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:add', '#', 'admin', CURRENT_TIMESTAMP, ''), (2033, '门锁修改', 2030, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:edit', '#', 'admin', CURRENT_TIMESTAMP, ''), (2034, '门锁删除', 2030, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:remove', '#', 'admin', CURRENT_TIMESTAMP, ''), (2035, '门锁导出', 2030, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2036, '绑定/解绑网关',2030, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:bind', '#', 'admin', CURRENT_TIMESTAMP, ''), (2037, '时间同步', 2030, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:sync', '#', 'admin', CURRENT_TIMESTAMP, ''), (2038, '远程开锁', 2030, 8, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:open', '#', 'admin', CURRENT_TIMESTAMP, ''), (2041, '人脸查询', 2040, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2042, '人脸新增', 2040, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:add', '#', 'admin', CURRENT_TIMESTAMP, ''), (2043, '人脸修改', 2040, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:edit', '#', 'admin', CURRENT_TIMESTAMP, ''), (2044, '人脸删除', 2040, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:remove', '#', 'admin', CURRENT_TIMESTAMP, ''), (2045, '人脸导出', 2040, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2046, '特征提取', 2040, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:extract', '#', 'admin', CURRENT_TIMESTAMP, '调用人脸特征提取服务'), (2051, '授权查询', 2050, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2052, '授权新增', 2050, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:add', '#', 'admin', CURRENT_TIMESTAMP, ''), (2053, '授权修改', 2050, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:edit', '#', 'admin', CURRENT_TIMESTAMP, ''), (2054, '授权删除', 2050, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:remove', '#', 'admin', CURRENT_TIMESTAMP, ''), (2055, '授权导出', 2050, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2056, '授权下发', 2050, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:push', '#', 'admin', CURRENT_TIMESTAMP, '向设备下发授权'), (2057, '清除授权', 2050, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:clear', '#', 'admin', CURRENT_TIMESTAMP, ''), (2061, '记录查询', 2060, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:accesslog:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2062, '记录导出', 2060, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:accesslog:export', '#', 'admin', CURRENT_TIMESTAMP, ''), (2071, '命令查询', 2070, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:command:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2072, '命令重发', 2070, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:command:retry', '#', 'admin', CURRENT_TIMESTAMP, ''), (2081, '报文查询', 2080, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:mqttlog:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2091, '参数查询', 2090, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:config:query', '#', 'admin', CURRENT_TIMESTAMP, ''), (2092, '参数修改', 2090, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:config:edit', '#', 'admin', CURRENT_TIMESTAMP, ''); -- ========================================================================= -- 脚本结束 -- ========================================================================= -- ========================================================================= -- 附录 A:存量升级(从 v1 的 9 张表到 v2 的 13 张表) -- -- ⚠️ 仅在已上线的 v1 库执行,且【不要】与上面的基线部分放在一起跑。 -- 使用方式:整段复制出来,逐节执行,每节之间核对行数。 -- 执行前务必:mysqldump -u root -p iotlocks > iotlocks_before_v2.sql -- -- 顺序:A1 补列 → A1.5 归属表(建表+回填)→ A2 其余新增表(复制基线 5/6/7/13 节) -- → A3 人员迁移 → A4 特征迁移 → A5 凭证迁移(需应用侧加密) -- → A6 授权迁移 → A7 命令/报文列迁移 → A8 旧表保留与最终下线 -- ========================================================================= -- A1 设备域补列(lock_group / lock_gateway / lock_device) -- alter table lock_group -- add column parent_id bigint(20) default 0 comment '上级分区ID(0为顶级)' after group_name, -- add column ancestors varchar(500) default '' comment '祖级列表' after parent_id, -- add column zone_type char(1) default '4' comment '分区类型(1园区 2楼栋 3楼层 4其他)' after ancestors, -- add column lock_capacity int(11) default 0 comment '设计门锁容量' after config_id; -- -- -- 先补齐空 group_id 再改非空,否则会失败;补不上的说明网关没入分区,需人工处理 -- -- select gateway_id, gateway_sn from lock_gateway where group_id is null; -- alter table lock_gateway -- add column gateway_mac varchar(32) default null comment '网关MAC(12位hex)' after gateway_sn, -- add column protocol_profile_id bigint(20) default null comment '协议配置ID' after config_id, -- add column max_device int(11) default 16 comment '最大下挂门锁数' after device_count, -- modify column group_id bigint(20) not null comment '所属分区ID(必填)', -- add unique key uk_lock_gateway_mac (gateway_mac); -- -- alter table lock_device -- add column device_mac varchar(32) default null comment '门锁MAC(12位hex)' after device_sn, -- add column protocol_profile_id bigint(20) default null comment '协议配置ID' after face_algo_version, -- add column capacity_face int(11) default 0 comment '人脸容量' after protocol_profile_id, -- add column capacity_pwd int(11) default 0 comment '密码容量' after capacity_face, -- add column capacity_card int(11) default 0 comment '卡片容量' after capacity_pwd, -- add column door_state char(1) default null comment '门状态' after battery_level, -- add column deadbolt_state char(1) default null comment '反锁/取电状态' after door_state, -- add column door_sensor_state char(1) default null comment '门磁状态' after deadbolt_state, -- add column raw_state varchar(64) default null comment '状态位原值' after door_sensor_state, -- add unique key uk_lock_device_mac (device_mac); -- -- -- 冗余列在 A1.5 关系表回填完成、代码切换到关系表之后再删(见 A8) -- -- alter table lock_device drop key idx_lock_device_group, drop column group_id; -- -- 密码列扩长(AES-GCM 密文比明文长) -- alter table lock_gateway modify column gateway_password varchar(256) default null comment '网关密码(密文)'; -- alter table lock_device modify column device_password varchar(256) default null comment '门锁密码(密文)'; -- A1.5 多网关归属:v1 的 lock_device.gateway_id 只能表达单一归属, -- 先建关联表并回填,再把 gateway_id 改名为 primary_gateway_id(选路缓存)。 -- 回填后每个锁只有一条关系;现场若已存在「一锁多网关」,由实施人员按实际 -- locklist 补录,不要依赖自动推导。 -- -- 建表:复制基线第 4 节 -- insert into lock_device_gateway -- (device_id, gateway_id, bind_status, bind_time, online_status, status, del_flag, -- create_by, create_time, remark) -- select d.device_id, d.gateway_id, '1', d.bind_time, '2', '0', '0', -- 'migrate', now(), 'v1 lock_device.gateway_id 迁移' -- from lock_device d -- where d.gateway_id is not null; -- -- 核对:两边行数应相等 -- -- select (select count(*) from lock_device where gateway_id is not null) as v1_cnt, -- -- (select count(*) from lock_device_gateway) as v2_cnt; -- alter table lock_device -- change column gateway_id primary_gateway_id bigint(20) default null -- comment '当前主控网关ID(选路缓存,事实源为 lock_device_gateway)'; -- alter table lock_device rename index idx_lock_device_gateway to idx_lock_device_primary_gw; -- -- 网关侧计数同步:device_count 由 lock_device_gateway 重算 -- update lock_gateway g -- set device_count = (select count(*) from lock_device_gateway r where r.gateway_id = g.gateway_id); -- A2 其余新增表:lock_person / lock_biometric / lock_credential / lock_protocol_profile -- 执行基线第 5、6、7、13 节的 create table 语句(这三节的 drop 只针对自身表名)。 -- A3 人员迁移:lock_face 中的人员维度按 person_no 去重 -- insert into lock_person (person_no, person_name, person_type, phone, status, del_flag, -- create_by, create_time, update_by, update_time, remark) -- select f.person_no, max(f.person_name), max(f.person_type), max(f.phone), -- max(f.status), max(f.del_flag), 'migrate', now(), 'migrate', now(), 'v1 lock_face 迁移' -- from lock_face f -- where f.person_no is not null and f.person_no <> '' -- group by f.person_no; -- -- 核对:应等于 lock_face 中不同的 person_no 数量 -- -- select count(distinct person_no) from lock_face; -- A4 特征迁移:一人一版本一份(同一 person_no 多行时按 feature_algo_version 取最新) -- feature_data 此时仍是明文 Base64,迁移后由应用侧批量重加密并改写该列。 -- insert into lock_biometric (person_id, bio_type, algo_version, photo_url, photo_md5, -- feature_data, feature_md5, feature_size, extract_status, -- extract_time, extract_msg, is_primary, status, del_flag, -- create_by, create_time, remark) -- select p.person_id, '1', ifnull(f.feature_algo_version, ''), f.photo_url, f.photo_md5, -- f.feature_data, f.feature_md5, ifnull(f.feature_size, 0), f.extract_status, -- f.extract_time, f.extract_msg, '1', f.status, f.del_flag, -- 'migrate', now(), 'v1 lock_face 迁移,待重加密' -- from lock_face f -- join lock_person p on p.person_no = f.person_no -- where f.face_id = (select max(x.face_id) from lock_face x where x.person_no = f.person_no); -- A5 凭证迁移(lock_auth.auth_value → lock_credential) -- 密码/卡号必须由应用侧加密后再写 cred_value_cipher,SQL 侧不做明文搬运。 -- 建议:先只迁人脸与指纹(值为特征引用),密码/卡走一次性迁移工具。 -- A6 授权迁移(lock_auth 关系部分 → lock_grant) -- insert into lock_grant (grant_no, person_id, person_no, cred_id, cred_type, -- device_id, device_sn, gateway_id, group_id, grant_mode, -- begin_time, end_time, sync_status, sync_msg, retry_count, -- last_sync_time, status, del_flag, create_by, create_time, remark) -- select a.auth_no, p.person_id, a.person_no, -- c.cred_id, a.auth_type, -- a.device_id, a.device_sn, a.gateway_id, a.group_id, '1', -- a.begin_time, a.end_time, a.sync_status, a.sync_msg, ifnull(a.retry_count, 0), -- a.sync_time, a.status, a.del_flag, 'migrate', now(), 'v1 lock_auth 迁移' -- from lock_auth a -- join lock_person p on p.person_no = a.person_no -- join lock_credential c on c.person_id = p.person_id and c.cred_type = a.auth_type -- where a.auth_type in ('01', '03'); -- -- 注意:sync_status 编码在 v2 有变化(4 由"已清除"改为"已撤销"、新增 5 已过期), -- -- 4 的历史数据按 4 保留即可,语义接近。 -- A7 命令与报文表改列 -- alter table lock_command -- add column route_scope char(1) default null comment '路由范围(1分组 2网关)' after command_type, -- add column route_code varchar(32) default null comment '路由编号(分区号/网关SN)' after route_scope, -- add column biz_type varchar(16) default null comment '业务类型' after target_id, -- add column result_code varchar(8) default null comment '归一结果码' after command_status, -- add column timeout_at datetime comment '超时截止时间' after next_retry_time, -- add column idempotency_key varchar(64) default null comment '幂等键' after timeout_at, -- add key idx_lock_command_timeout (command_status, timeout_at), -- add key idx_lock_command_route (route_scope, route_code), -- add key idx_lock_command_idem (idempotency_key); -- -- 回填路由:网关类命令取 target_code;门锁类命令按 lock_device → lock_gateway → lock_group 推导 -- update lock_command c -- set route_scope = if(c.target_type = '1', '2', '1'), -- route_code = if(c.target_type = '1', c.target_code, -- (select g.group_code from lock_device d -- join lock_gateway gw on gw.gateway_id = d.gateway_id -- join lock_group g on g.group_id = gw.group_id -- where d.device_id = c.target_id)) -- where c.route_code is null; -- -- 回填 biz_type:0011/0012 → GRANT,0001/0002/0013 → DEVICE,0006-0010 → GATEWAY -- -- 命令状态重排(2 成功→3、3 失败→4、4 超时→5、5 取消→6),必须从大到小改,避免撞值 -- update lock_command set command_status = '6' where command_status = '5'; -- update lock_command set command_status = '5' where command_status = '4'; -- update lock_command set command_status = '4' where command_status = '3'; -- update lock_command set command_status = '3' where command_status = '2'; -- -- alter table lock_mqtt_log -- add column route_scope char(1) default null comment '主题第2段类型(1分组 2网关)' after topic, -- add column route_code varchar(32) default null comment '主题第2段取值' after route_scope, -- add column protocol_ver char(1) default null comment '业务协议版本' after seq, -- add column envelope_ver char(1) default null comment '信封形态' after protocol_ver; -- update lock_mqtt_log set route_code = ifnull(group_code, gateway_sn), -- route_scope = if(group_code is not null, '1', '2') -- where route_code is null; -- -- 列删除放在代码切换之后,避免旧版本回滚时缺列 -- -- alter table lock_mqtt_log drop column group_code, drop column gateway_sn; -- A8 旧表下线(至少保留一个版本周期,确认迁移数据与线上一致后执行) -- rename table lock_face to lock_face_bak_20261030; -- rename table lock_auth to lock_auth_bak_20261030; -- -- 观察期结束后: -- -- drop table lock_face_bak_20261030; -- -- drop table lock_auth_bak_20261030;