DATABASE DESIGN · V1.0

鑫潼智电系统 · PostgreSQL 数据库设计文档

基于《鑫潼智电系统需求分析报告 V1.0》数据说明,设计 37 张数据表 + 3 个分区管理函数 + 1 个物化视图,覆盖客户、项目、设备、派单、报警、报修、维保、报酬、用电采集等全部业务域。采用逻辑隔离 + 时序分区方案。

数据库:PostgreSQL 15+ 表数量:37 张 隔离方案:customer_id 逻辑隔离 时序分区:electricity_data 按月分区 自动分区:3 个管理函数 历史分析:1 个物化视图 字符集:UTF8
01

设计概述

设计原则与关键决策

设计原则

① 逻辑隔离:所有业务表携带 customer_id 字段实现行级数据隔离,不做物理分库。② 时序分区:用电采集数据(electricity_data)按月 RANGE 分区,解决数据量暴涨问题。③ 外键约束:核心关联表使用外键保证数据完整性。④ JSONB 灵活存储:照片路径列表、ICC 灵活字段使用 JSONB 类型。⑤ 全部表加 COMMENT:便于团队协作和 ORM 映射。

命名规范

表名:snake_case 小写下划线,业务表无前缀,系统表 sys_ 前缀。主键:统一 BIGSERIAL 自增。时间字段:统一 TIMESTAMPTZ 带时区。布尔状态:用 SMALLINT(0/1)。编码字段:如 customer_no、plan_no 等业务编号用 VARCHAR(64)。

02

业务域划分

14 个业务域 · 37 张表
D1

系统管理域

sys_user系统用户(业务员/管理员)
sys_role角色
sys_user_role用户角色关联
sys_menu菜单(RBAC 权限)
sys_role_menu角色菜单关联
sys_dict数据字典
sys_operation_log操作日志
D2

客户域

customer客户信息
customer_department客户部门
customer_visit客户拜访
customer_building客户建筑
customer_room客户房间
customer_equipment客户设备(配电间/井/箱)
customer_account客户访问账号
D3

智电设备域

smart_device智电设备型号(产品目录)
D4

项目方案与合同域

project_plan智电改造方案
project_plan_detail方案设备明细
contract项目合同
D5

线路与设备关联域

electric_line智电改造线路(ICC 同步)
line_room线路房间关联
D6

派单域

survey_order勘察派单
install_order安装派单
acceptance项目验收
visit_record客户回访
D7

报警域

fault_type报警故障类型
fault_type_detail故障类型明细
device_alarm设备报警(ICC 拉取)
alarm_dispatch报警派单
D8

报修域

repair_request报修单
repair_dispatch报修派单
D9

维保域

maintenance_order维保单
maintenance_detail维保明细
D10

共享电工域

worker共享电工信息
dispatch_price派单价格
worker_income派单收入(月度)
worker_income_detail派单收入明细
D11

用电采集域(分区)

electricity_data线路用电信息(按月分区)
D12

辅助域

icc_sync_logICC 同步日志
file_record文件存储记录
03

核心 ER 关系图

关键实体关联

以下展示客户域→项目域→线路域→报警/报修域的核心关联路径,省略系统管理域和辅助域。

erDiagram customer ||--o{ customer_department : "1对多" customer ||--o{ customer_building : "1对多" customer ||--o{ customer_equipment : "1对多" customer ||--o{ customer_room : "1对多" customer ||--o{ customer_visit : "1对多" customer ||--o{ customer_account : "1对多" customer ||--o{ project_plan : "1对多" customer ||--o{ contract : "1对多" customer ||--o{ survey_order : "1对多" customer ||--o{ install_order : "1对多" customer ||--o{ acceptance : "1对多" customer ||--o{ visit_record : "1对多" customer ||--o{ repair_request : "1对多" customer ||--o{ maintenance_order : "1对多" customer ||--o{ electricity_data : "1对多" customer_building ||--o{ customer_equipment : "建筑含设备" customer_building ||--o{ customer_room : "建筑含房间" customer_department ||--o{ customer_room : "部门含房间" project_plan ||--o{ project_plan_detail : "方案含明细" project_plan ||--o{ contract : "方案签合同" smart_device ||--o{ project_plan_detail : "设备型号" customer_equipment ||--o{ electric_line : "设备含线路" electric_line ||--o{ line_room : "线路关联房间" customer_room ||--o{ line_room : "房间关联线路" fault_type ||--o{ fault_type_detail : "类型含明细" fault_type ||--o{ alarm_dispatch : "故障派单" electric_line ||--o{ device_alarm : "线路报警" device_alarm ||--o{ alarm_dispatch : "报警派单" repair_request ||--|{ repair_dispatch : "报修派单" maintenance_order ||--|{ maintenance_detail : "维保明细" customer_equipment ||--o{ maintenance_detail : "维保设备" worker ||--o{ worker_income : "电工收入" worker_income ||--o{ worker_income_detail : "收入明细" dispatch_price ||--o{ worker_income_detail : "价格参考"
04

用电数据时序分区

electricity_data 按月 RANGE 分区

分区策略

electricity_data 表是数据量增量大头(每条线路按 ICC 采集频次持续写入)。采用 PostgreSQL 声明式 RANGE 分区,按 collect_time 字段按月切分。查询只扫描目标月份分区,性能稳定。历史分区可归档,不影响热数据查询。

2026_05

已归档

2026_06

已归档

2026_07

已归档

2026_08

当前活跃

2026_09

预创建

2026_10

预创建

2026_11

预创建

2026_12

预创建

2027_01

待创建

2027_02

待创建

2027_03

待创建

2027_04

待创建

分区自动管理

建议使用 pg_partman 扩展或编写定时任务(Midway.js cron)自动创建未来月份分区。每月初自动 CREATE 新分区,超过 N 个月的分区可 DETACH 后归档至冷存储。构建脚本已预创建 2026 年 8~12 月分区。

05

全部数据表字段说明

37 张表 · 按业务域分组
D1

系统管理域

7 张表 · 用户/角色/菜单/字典/日志
sys_user— 系统用户表(鑫潼内部人员)
字段类型键说明
idBIGSERIALPK自增主键
usernameVARCHAR(64)UNIQUE登录用户名
password_hashVARCHAR(256)密码哈希值
real_nameVARCHAR(64)真实姓名
phoneVARCHAR(20)手机号
emailVARCHAR(128)邮箱
statusSMALLINT状态:1启用 0禁用
last_login_atTIMESTAMPTZ最后登录时间
created_atTIMESTAMPTZ创建时间
updated_atTIMESTAMPTZ更新时间
sys_role— 角色表
字段类型键说明
idBIGSERIALPK自增主键
role_codeVARCHAR(32)UNIQUE角色编码
role_nameVARCHAR(64)角色名称
descriptionTEXT描述
sort_orderINT排序号
created_atTIMESTAMPTZ创建时间
sys_user_role— 用户角色关联表
字段类型键说明
user_idBIGINTPKFK用户 ID(→ sys_user)
role_idBIGINTPKFK角色 ID(→ sys_role)
sys_menu— 菜单表(RBAC 权限)
字段类型键说明
idBIGSERIALPK自增主键
parent_idBIGINTFK父菜单 ID(自关联)
menu_nameVARCHAR(64)菜单名称
menu_pathVARCHAR(256)路由路径
componentVARCHAR(256)前端组件路径
iconVARCHAR(64)图标
sort_orderINT排序号
menu_typeSMALLINT类型:1目录 2菜单 3按钮
permissionVARCHAR(128)权限标识,如 customer:list
visibleSMALLINT是否可见:1是 0否
created_atTIMESTAMPTZ创建时间
sys_role_menu— 角色菜单关联表
字段类型键说明
role_idBIGINTPKFK角色 ID(→ sys_role)
menu_idBIGINTPKFK菜单 ID(→ sys_menu)
sys_dict— 数据字典表
字段类型键说明
idBIGSERIALPK自增主键
dict_typeVARCHAR(64)IDX字典类型
dict_labelVARCHAR(128)字典标签
dict_valueVARCHAR(128)字典值
sort_orderINT排序号
statusSMALLINT状态:1启用 0禁用
created_atTIMESTAMPTZ创建时间
sys_operation_log— 操作日志表
字段类型键说明
idBIGSERIALPK自增主键
user_idBIGINTIDX操作用户 ID
moduleVARCHAR(64)操作模块
actionVARCHAR(64)操作动作
methodVARCHAR(256)请求方法
paramsTEXT请求参数
ipVARCHAR(64)操作 IP
created_atTIMESTAMPTZIDX操作时间
D2

客户域

7 张表 · 客户/部门/建筑/房间/设备/账号
customer— 客户信息表
字段类型键说明
idBIGSERIALPK自增主键
customer_nameVARCHAR(128)IDX客户名称
provinceVARCHAR(64)省
cityVARCHAR(64)市
districtVARCHAR(64)区/县
addressVARCHAR(256)地址
contact_personVARCHAR(64)联系人
contact_phoneVARCHAR(20)电话
postal_codeVARCHAR(10)邮编
faxVARCHAR(20)传真
customer_levelVARCHAR(32)客户级别(学校/医院等)
statusSMALLINT状态:1意向 2签约 3运维中 4终止
created_atTIMESTAMPTZ创建时间
updated_atTIMESTAMPTZ更新时间
customer_department— 客户部门信息表
字段类型键说明
idBIGSERIALPK自增主键
customer_idBIGINTFK客户 ID(→ customer)
dept_nameVARCHAR(128)部门名称
contact_personVARCHAR(64)联系人
contact_phoneVARCHAR(20)电话
function_descTEXT职能
created_atTIMESTAMPTZ创建时间
customer_visit— 客户拜访信息表
字段类型键说明
idBIGSERIALPK自增主键
visit_noVARCHAR(64)UNIQUE拜访单号
customer_idBIGINTFK客户 ID
visit_personVARCHAR(64)拜访人
visit_phoneVARCHAR(20)拜访人电话
visit_contentTEXT拜访内容
visit_timeDATE拜访时间
salesman_idBIGINTIDX业务员
will_planSMALLINT是否做方案:0不同意 1同意
created_atTIMESTAMPTZ创建时间
customer_building— 客户智电改造建筑信息表
字段类型键说明
idBIGSERIALPK自增主键
customer_idBIGINTFK客户 ID
building_nameVARCHAR(128)建筑名称
basic_infoTEXT基本情况
purposeVARCHAR(128)用途
floor_countINT层数
created_atTIMESTAMPTZ创建时间
customer_room— 客户建筑房间信息表
字段类型键说明
idBIGSERIALPK自增主键
room_codeVARCHAR(64)房间编码
customer_idBIGINTFK客户 ID
room_nameVARCHAR(128)房间名称
building_idBIGINTFK所属建筑 ID(→ customer_building)
floor_noVARCHAR(16)所在楼层
room_purposeVARCHAR(128)房间用途
dept_idBIGINTFK房间所属客户部门(→ customer_department)
created_atTIMESTAMPTZ创建时间
customer_equipment— 客户智电改造设备信息表(配电间/井/箱)
字段类型键说明
idBIGSERIALPK自增主键
equip_codeVARCHAR(64)UNIQUE客户设备编码
customer_idBIGINTFK客户 ID
equip_nameVARCHAR(128)客户设备名称
equip_typeVARCHAR(32)设备类型:配电间/配电井/配电箱
building_idBIGINTFK所属建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
descriptionTEXT设备描述
remarkTEXT备注
photo_urlVARCHAR(512)未改造前设备照片
created_atTIMESTAMPTZ创建时间
customer_account— 客户访问账号表(小程序登录)
字段类型键说明
idBIGSERIALPK自增主键
customer_idBIGINTFK客户 ID
phoneVARCHAR(20)UNIQUE登录电话
password_hashVARCHAR(256)密码哈希
wx_openidVARCHAR(128)微信 openid
statusSMALLINT状态:1启用 0禁用
last_login_atTIMESTAMPTZ最后登录时间
created_atTIMESTAMPTZ创建时间
D3

智电设备域

1 张表 · 产品目录
smart_device— 鑫潼智电设备信息表(产品目录)
字段类型键说明
idBIGSERIALPK自增主键
device_modelVARCHAR(64)智电设备型号
device_nameVARCHAR(128)智电设备名称
device_specVARCHAR(256)智电设备规格
device_typeVARCHAR(32)设备类型:网关/采集器/探测器等
device_functionTEXT智电设备功能
supplierVARCHAR(128)供应商
created_atTIMESTAMPTZ创建时间
D4

项目方案与合同域

3 张表 · 方案/明细/合同
project_plan— 智电改造方案信息表
字段类型键说明
idBIGSERIALPK自增主键
plan_noVARCHAR(64)UNIQUE方案单号
customer_idBIGINTFK客户 ID
registrarVARCHAR(64)方案登记人(业务员)
register_timeDATE方案登记时间
plan_descTEXT方案说明
plan_file_urlVARCHAR(512)方案最终文件
statusSMALLINT状态:0草稿 1已确认
created_atTIMESTAMPTZ创建时间
project_plan_detail— 项目方案智电设备明细表
字段类型键说明
idBIGSERIALPK自增主键
plan_idBIGINTFK方案 ID(→ project_plan)
customer_idBIGINTFK客户 ID
equip_idBIGINTFK客户设备 ID(→ customer_equipment)
smart_device_idBIGINTFK智电设备型号 ID(→ smart_device)
quantityNUMERIC(10,2)数量
remarkTEXT备注
created_atTIMESTAMPTZ创建时间
contract— 智电项目合同信息表
字段类型键说明
idBIGSERIALPK自增主键
contract_noVARCHAR(64)UNIQUE合同单号
xt_contract_noVARCHAR(64)IDX鑫潼合同号(XT+年份+序号)
customer_idBIGINTFK客户 ID
contract_amountNUMERIC(14,2)合同金额
pay_cycleVARCHAR(32)支付周期:按月/按年
salesman_idBIGINT业务员
sign_dateDATE签订日期
contract_descTEXT合同说明
start_dateDATE开始日期
end_dateDATE结束日期
plan_idBIGINTFK方案 ID(→ project_plan)
contract_file_urlVARCHAR(512)签字盖章电子合同
statusSMALLINT状态:1有效 0终止
created_atTIMESTAMPTZ创建时间
D5

线路与设备关联域

2 张表 · ICC 同步 + 房间关联
electric_line— 智电改造线路表(ICC 同步)
字段类型键说明
idBIGSERIALPK自增主键
line_codeVARCHAR(64)UNIQUE线路编码(唯一)
equip_idBIGINTFK客户设备 ID(→ customer_equipment)
icc_device_codeVARCHAR(128)IDXICC 智电设备编号
line_nameVARCHAR(128)线路名称(ICC 同步)
customer_idBIGINTFK客户 ID(逻辑隔离键)
building_idBIGINTFK所属建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
statusSMALLINT状态:1在线 0离线
synced_atTIMESTAMPTZICC 同步时间
created_atTIMESTAMPTZ创建时间
line_room— 线路所属房间关联表
字段类型键说明
idBIGSERIALPK自增主键
line_idBIGINTFK线路 ID(→ electric_line)
room_idBIGINTFK房间 ID(→ customer_room)
customer_idBIGINTFK客户 ID
created_atTIMESTAMPTZ创建时间
D6

派单域

4 张表 · 勘察/安装/验收/回访
survey_order— 客户勘察派单信息表
字段类型键说明
idBIGSERIALPK自增主键
survey_noVARCHAR(64)UNIQUE勘察单号
customer_idBIGINTFK客户 ID
surveyorVARCHAR(64)勘察人(共享电工)
worker_idBIGINT共享电工 ID
survey_timeTIMESTAMPTZ勘察时间
remarkTEXT备注
statusSMALLINT状态:0已派发 1已接单 2已完成
created_atTIMESTAMPTZ创建时间
install_order— 项目安装任务派单信息表
字段类型键说明
idBIGSERIALPK自增主键
install_noVARCHAR(64)UNIQUE安装单号
customer_idBIGINTFK客户 ID
installerVARCHAR(64)安装人(共享电工)
worker_idBIGINT共享电工 ID
dispatch_dateDATE派单日期
start_dateDATE开始日期
end_dateDATE结束日期
plan_idBIGINTFK方案 ID(→ project_plan)
remarkTEXT备注
statusSMALLINT状态:0已派发 1已完成
created_atTIMESTAMPTZ创建时间
acceptance— 项目验收信息表
字段类型键说明
idBIGSERIALPK自增主键
accept_noVARCHAR(64)UNIQUE验收单号
customer_idBIGINTFK客户 ID
acceptorVARCHAR(64)验收人
accept_opinionTEXT验收意见
accept_dateDATE验收日期
installerVARCHAR(64)安装人
accept_file_urlVARCHAR(512)验收文件电子版
contract_idBIGINTFK合同 ID(→ contract)
created_atTIMESTAMPTZ创建时间
visit_record— 客户回访信息表
字段类型键说明
idBIGSERIALPK自增主键
visit_noVARCHAR(64)UNIQUE回访单号
customer_idBIGINTFK客户 ID
contact_personVARCHAR(64)联系人
contact_phoneVARCHAR(20)电话
visitorVARCHAR(64)回访人
visit_timeDATE回访时间
customer_opinionTEXT客户意见
photosJSONB回访照片
created_atTIMESTAMPTZ创建时间
D7

报警域

4 张表 · 故障类型/设备报警/报警派单
fault_type— 报警故障类型信息表
字段类型键说明
idBIGSERIALPK自增主键
fault_type_codeVARCHAR(64)UNIQUE故障类型编码
fault_type_nameVARCHAR(128)故障类型名称
descriptionTEXT故障类型说明
remarkTEXT备注
created_atTIMESTAMPTZ创建时间
fault_type_detail— 报警故障类型明细表
字段类型键说明
idBIGSERIALPK自增主键
fault_type_idBIGINTFK故障类型 ID(→ fault_type)
detail_categoryVARCHAR(32)明细分类:故障原因/处理流程
detail_descTEXT明细说明
remarkTEXT备注
created_atTIMESTAMPTZ创建时间
device_alarm— 设备报警信息表(ICC 拉取)
字段类型键说明
idBIGSERIALPK自增主键
alarm_codeVARCHAR(128)UNIQUE报警编码
line_idBIGINTIDX线路 ID
equip_idBIGINT客户设备 ID
icc_device_codeVARCHAR(128)ICC 设备编号
line_nameVARCHAR(128)线路名称
customer_idBIGINTIDX客户 ID
building_idBIGINT所属建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
alarm_dateDATEIDX报警日期
fault_typeVARCHAR(128)ICC 预警类型
alarm_valueNUMERIC(14,2)报警数值
history_countINT历史出现次数
synced_atTIMESTAMPTZICC 同步时间
alarm_dispatch— 报警派单信息表
字段类型键说明
idBIGSERIALPK自增主键
dispatch_noVARCHAR(64)UNIQUE报警派单号
alarm_idBIGINTFK报警 ID(→ device_alarm)
line_idBIGINT线路 ID
equip_idBIGINT客户设备 ID
icc_device_codeVARCHAR(128)ICC 设备编号
line_nameVARCHAR(128)线路名称
customer_idBIGINTFK客户 ID
contact_personVARCHAR(64)联系人
contact_phoneVARCHAR(20)电话
building_idBIGINT建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
fault_type_idBIGINTFK故障类型 ID(→ fault_type)
fault_descTEXT故障事项(类型+数值)
dispatcherVARCHAR(64)派发人
fault_reasonTEXT故障原因(来自明细)
process_flowTEXT处理流程(来自明细)
worker_idBIGINTIDX共享电工 ID
statusSMALLINTIDX状态:0已派发 1已处理
process_photosJSONB报警处理照片(多张)
ratingSMALLINT派单处理评分
created_atTIMESTAMPTZ创建时间
completed_atTIMESTAMPTZ完成时间
D8

报修域

2 张表 · 报修单/报修派单
repair_request— 报修单信息表
字段类型键说明
idBIGSERIALPK自增主键
repair_noVARCHAR(64)UNIQUE报修单号
customer_idBIGINTFK客户 ID
requesterVARCHAR(64)报修人
requester_phoneVARCHAR(20)报修电话
request_timeTIMESTAMPTZ报修时间
building_idBIGINT所属建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
repair_contentTEXT报修内容
photosJSONB报修照片
statusSMALLINTIDX状态:0待处理 1已派单 2已完成
created_atTIMESTAMPTZ创建时间
repair_dispatch— 报修派单信息表
字段类型键说明
idBIGSERIALPK自增主键
dispatch_noVARCHAR(64)UNIQUE报修派单号
repair_idBIGINTFK报修单 ID(→ repair_request)
customer_idBIGINTFK客户 ID
requesterVARCHAR(64)报修人
requester_phoneVARCHAR(20)报修电话
request_timeTIMESTAMPTZ报修时间
building_idBIGINT建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
repair_contentTEXT报修内容
dispatcherVARCHAR(64)派发人
worker_idBIGINTIDX共享电工 ID
statusSMALLINT状态:0已派发 1已处理
process_photosJSONB处理完成照片
ratingSMALLINT报修派单处理评分(客户评)
created_atTIMESTAMPTZ创建时间
completed_atTIMESTAMPTZ完成时间
D9

维保域

2 张表 · 维保单/维保明细
maintenance_order— 维保单信息表
字段类型键说明
idBIGSERIALPK自增主键
maintenance_noVARCHAR(64)UNIQUE维保单号(录入,不自动生成)
customer_idBIGINTFK客户 ID
maintainerVARCHAR(64)维保人(共享电工)
worker_idBIGINT共享电工 ID
maintenance_dateDATE维保日期
remarkTEXT备注
statusSMALLINT状态:0已派发 1已完成
created_atTIMESTAMPTZ创建时间
maintenance_detail— 维保单明细表
字段类型键说明
idBIGSERIALPK自增主键
maintenance_idBIGINTFK维保单 ID(→ maintenance_order)
equip_idBIGINT客户设备 ID
customer_idBIGINTFK客户 ID
equip_nameVARCHAR(128)客户设备名称
equip_typeVARCHAR(32)设备类型:配电间/井/箱
building_idBIGINT建筑 ID
floor_noVARCHAR(16)所在楼层
locationVARCHAR(256)所在位置
panel_conditionTEXT配电间或电箱情况
circuit_conditionTEXT回路情况
terminal_conditionTEXT终端情况
maintenance_descTEXT维保情况说明
photosJSONB维保现场照片(水印)
created_atTIMESTAMPTZ创建时间
D10

共享电工域

4 张表 · 电工/价格/收入/明细
worker— 共享电工信息表
字段类型键说明
idBIGSERIALPK自增主键
worker_nameVARCHAR(64)电工姓名
phoneVARCHAR(20)IDX手机号
id_cardVARCHAR(18)身份证号
statusSMALLINT状态:1在岗 0离职
created_atTIMESTAMPTZ创建时间
updated_atTIMESTAMPTZ更新时间
dispatch_price— 共享电工派单价格信息表
字段类型键说明
idBIGSERIALPK自增主键
price_codeVARCHAR(64)UNIQUE派单价格编码
dispatch_typeVARCHAR(32)派单类型:勘察/安装/预警/维修/维保
price_typeVARCHAR(32)价格类型:单价/总价提成
unit_priceNUMERIC(10,2)服务单价
created_atTIMESTAMPTZ创建时间
worker_income— 共享电工派单收入信息表(月度汇总)
字段类型键说明
idBIGSERIALPK自增主键
income_codeVARCHAR(64)UNIQUE派单收入编码
worker_idBIGINTFK共享电工 ID(→ worker)
income_monthVARCHAR(7)IDX收入月份(YYYY-MM)
monthly_totalNUMERIC(14,2)月度收入合计
rating_summaryNUMERIC(5,2)评分综合统计
final_totalNUMERIC(14,2)月度最终收入合计
created_atTIMESTAMPTZ创建时间
worker_income_detail— 共享电工派单收入明细信息表
字段类型键说明
idBIGSERIALPK自增主键
income_idBIGINTFK收入 ID(→ worker_income)
worker_idBIGINTFK共享电工 ID
income_monthVARCHAR(7)收入月份
dispatch_typeVARCHAR(32)派单类型
dispatch_noVARCHAR(64)各类型派单单号
income_amountNUMERIC(10,2)本单收入
rating_levelVARCHAR(16)评价等级
final_incomeNUMERIC(10,2)本单最终收入合计
created_atTIMESTAMPTZ创建时间
D11

用电采集域(分区表)

1 张表 · 按月分区
electricity_data— 线路用电信息表(按月 RANGE 分区)
字段类型键说明
idBIGSERIALPK自增(复合主键含 collect_time)
line_idBIGINTFKIDX线路 ID(→ electric_line)
line_codeVARCHAR(64)线路编码(冗余,加速查询)
equip_idBIGINT客户设备 ID
icc_device_codeVARCHAR(128)ICC 设备编号
line_nameVARCHAR(128)线路名称
customer_idBIGINTIDX客户 ID(逻辑隔离键)
electricityNUMERIC(14,4)用电量
collect_timeTIMESTAMPTZPKIDX采集时间(分区键)

分区键:collect_time。主键为复合主键 (id, collect_time)。已预建分区:electricity_data_2026_08 ~ electricity_data_2026_12。组合索引:(customer_id, collect_time) 用于月报统计。

D12

辅助域

2 张表 · ICC 日志/文件记录
icc_sync_log— ICC 数据同步日志表
字段类型键说明
idBIGSERIALPK自增主键
sync_typeVARCHAR(32)IDX同步类型:客户/设备/用电/报警
start_timeTIMESTAMPTZ开始时间
end_timeTIMESTAMPTZ结束时间
record_countINT同步记录数
statusSMALLINT状态:1成功 0失败
error_messageTEXT错误信息
created_atTIMESTAMPTZIDX创建时间
file_record— 文件存储记录表
字段类型键说明
idBIGSERIALPK自增主键
file_nameVARCHAR(256)文件名
file_urlVARCHAR(512)文件 URL
file_typeVARCHAR(32)文件类型:取证/合同/验收/方案/月报
file_sizeBIGINT文件大小(字节)
business_typeVARCHAR(64)IDX关联业务类型
business_idBIGINT关联业务 ID
uploaded_byBIGINT上传人 ID
created_atTIMESTAMPTZ创建时间
06

索引策略

关键索引一览
表索引类型用途
customeridx_customer_nameB-Tree按客户名称搜索
customeridx_customer_regionB-Tree 组合按省市县区域查询
electric_lineidx_line_customerB-Tree按客户查线路(逻辑隔离)
electric_lineidx_line_iccB-TreeICC 设备码匹配同步
electricity_dataidx_ed_customer_timeB-Tree 组合按客户+时间查用电(月报核心查询)
device_alarmidx_alarm_dateB-Tree按报警日期查询
device_alarmidx_alarm_customerB-Tree按客户查报警
alarm_dispatchidx_alarm_disp_workerB-Tree电工查自己的派单(接口数据权限)
repair_dispatchidx_repair_disp_workerB-Tree电工查报修派单
sys_dictidx_sys_dict_typeB-Tree按字典类型查询
icc_sync_logidx_icc_sync_timeB-Tree按时间查同步日志

索引设计原则

① 所有 customer_id 外键字段建索引(逻辑隔离查询基础)。② 用电采集表建 (customer_id, collect_time) 组合索引(月报统计核心路径)。③ ICC 同步相关字段建索引(设备码匹配)。④ 共享电工查询字段建索引(接口数据权限过滤)。

07

初始数据

角色/菜单/字典
表初始数据说明
sys_role4 条运营管理员/业务员/共享电工/客户
sys_menu6 条客户管理/项目管理/运营派单/设备监控/统计报表/系统管理
sys_dict19 条客户状态/设备类型/派单状态/支付周期/派单类型等
08

自动分区管理

pg_cron 定时调度 · 数据库自治

设计背景

PostgreSQL 声明式分区不会自动创建子分区。若数据写入时对应月份的分区不存在,INSERT 会直接报错:no partition of relation found for row。因此需要一套自动化的分区管理机制,确保未来月份的分区始终提前就绪。

为什么不用触发器兜底?

PostgreSQL 分区表的 BEFORE INSERT 触发器在分区路由之后才执行——即数据库先判断数据该落入哪个子分区,如果子分区不存在直接报错,触发器根本没有机会执行。因此触发器无法在写入时动态创建分区,必须通过定时预创建 + 应用层调用来保证分区就绪。

管理函数一览

函数名参数返回用途
ensure_electricity_partition p_date DATE VOID 确保指定日期所在月的分区存在(不存在则创建)。应用层在写入数据前调用此函数兜底。
run_electricity_partition_maintenance p_premake INT(默认 3) TABLE(created_month, action) 批量预创建当前月 + 未来 N 个月的分区。Midway.js cron 每月调用一次,返回各分区状态(CREATED / EXISTS)。
refresh_electricity_monthly 无 VOID 刷新月度汇总物化视图。自动处理首次初始化(非并发),后续刷新用 CONCURRENTLY 不阻塞查询。

分区生命周期

flowchart LR subgraph P1 ["阶段一:预创建(pg_cron 自动执行)"] A1["pg_cron 定时调度
每月25号 03:00"] --> A2["run_electricity_partition_maintenance(3)"] A2 --> A3{"分区是否
已存在?"} A3 --"不存在"--> A4["CREATE TABLE ... PARTITION OF"] A3 --"已存在"--> A5["跳过"] end subgraph P2 ["阶段二:写入数据"] B1["ICC 数据拉取
服务写入数据"] --> B2["ensure_electricity_partition
(collect_time)"] B2 --> B3{"分区是否
已存在?"} B3 --"不存在"--> B4["自动创建分区"] B3 --"已存在"--> B5["直接写入"] B4 --> B5 end subgraph P3 ["阶段三:归档"] C1["超过 24 个月的
分区"] --> C2["DETACH PARTITION
从父表分离"] C2 --> C3["冷数据存档
或直接查询子表"] C3 --> C4["如需分析
ATTACH 临时挂回"] end P1 --> P2 P2 --> P3 style A4 fill:#e8f1ff,stroke:#1d6fff style A5 fill:#f0fdf4,stroke:#0d9488 style B4 fill:#e8f1ff,stroke:#1d6fff style B5 fill:#f0fdf4,stroke:#0d9488 style C2 fill:#fef3e8,stroke:#e0852b style C4 fill:#fef3e8,stroke:#e0852b

双重保障机制

保障层触发源调用函数频率角色
第一层:定时预创建 pg_cron(数据库自治) run_electricity_partition_maintenance(3) 每月 25 号 03:00 主动保障 — 提前创建未来 3 个月分区
第一层:物化视图刷新 pg_cron(数据库自治) refresh_electricity_monthly() 每月 1 号 02:00 月度汇总数据刷新
第二层:写入兜底 Midway.js(应用层) ensure_electricity_partition(collect_time) 每次 ICC 拉取批次 被动兜底 — 万一分区不存在时写入前自动创建

pg_cron 定时任务配置

两个定时任务已在 db_init.sql 中通过 cron.schedule() 自动注册,数据库重启后任务仍然有效:

-- 每月25号凌晨3点:预创建未来3个月分区
SELECT cron.schedule('electricity_partition_maintenance', '0 3 25 * *', 'SELECT run_electricity_partition_maintenance(3)');

-- 每月1号凌晨2点:刷新物化视图
SELECT cron.schedule('electricity_monthly_refresh', '0 2 1 * *', 'SELECT refresh_electricity_monthly()');

Midway.js 应用层兜底示例

pg_cron 负责定时预创建,后端无需配置 @Cron。但 ICC 数据拉取服务在写入前仍建议调用 ensure_electricity_partition() 做兜底:

// ICC 数据写入前兜底(在 ICC 同步服务中)
async saveElectricityData(items: ElectricityData[]) {
  for (const item of items) {
    // 写入前确保分区存在(99.9%的情况下什么都不做直接返回)
    await this.entityManager.query(
      'SELECT ensure_electricity_partition($1)',
      [item.collectTime]
    );
  }
  // 批量写入
  await this.electricityRepo.save(items);
}

月度汇总物化视图

物化视图 mv_electricity_monthly 按客户 + 线路 + 月份预聚合用电数据,用于历史数据分析和月报生成。每月初刷新一次,查询走预聚合数据,极快。

字段类型说明
customer_idBIGINT客户 ID(逻辑隔离键)
line_idBIGINT线路 ID
monthTEXT月份(YYYY-MM 格式)
total_usageNUMERIC月度总用电量
avg_usageNUMERIC平均用电量
peak_usageNUMERIC峰值用电量
min_usageNUMERIC最低用电量
record_countBIGINT采集记录数
first_collectTIMESTAMPTZ最早采集时间
last_collectTIMESTAMPTZ最晚采集时间

刷新策略

首次初始化:脚本执行时自动 REFRESH MATERIALIZED VIEW(非并发模式)。后续刷新:通过 refresh_electricity_monthly() 函数,使用 CONCURRENTLY 不阻塞查询,函数内部自动处理异常回退。

历史分区归档策略

分区年龄操作原因
0 ~ 12 个月保持在父表上热数据,查询频繁
12 ~ 24 个月保持在父表上温数据,偶尔查询
超过 24 个月DETACH PARTITION 分离冷数据,减少父表子分区数量,加速分区裁剪
需要分析冷数据直接查子表 或 ATTACH 临时挂回按需分析,分析完再 DETACH
确定不再需要DROP TABLE释放磁盘空间(需确认)