Files
smart_grid_iot/系统设计/db_design.html
T
andyesfly 6b00f61550 feat: 新增现场勘察派单全流程业务能力
1.  新增共享电工管理模块:包含实体、DTO、控制器、服务以及前后端API
2.  重构勘察工单实体与查询逻辑,完善工单全状态流程与字段
3.  新增勘察SOP模板与工单回执业务体系
4.  更新数据库字典与初始化脚本,补充业务数据
5.  新增勘察派单增删改查、指派、复核、催办等全流程接口
6.  修复用户服务角色关联SQL生成问题
7.  新增勘察派单前后端完整交互链路
2026-09-15 08:50:55 +08:00

1181 lines
90 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- Generated by Trae Work -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鑫潼智电系统 · PostgreSQL 数据库设计文档</title>
<style>
:root{
--bg:#eef3f8; --bg2:#fff; --ink:#0f1e2e; --muted:#5b6b7e; --rule:#dbe4ee;
--accent:#1d6fff; --accent2:#0d9488; --accent3:#7c3aed; --warn:#e0852b; --red:#dc2626;
--shadow:0 4px 14px rgba(0,0,0,.07); --shadow-lg:0 8px 28px rgba(0,0,0,.1); --radius:12px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:'PingFang SC','Microsoft YaHei','Hiragino Sans GB',sans-serif;background:var(--bg);color:var(--ink);line-height:1.7;font-size:15px;-webkit-font-smoothing:antialiased}
body::before{content:"";position:fixed;inset:0;z-index:-1;background:radial-gradient(900px 600px at 8% 0%,rgba(29,111,255,.07),transparent 60%),radial-gradient(800px 600px at 92% 6%,rgba(13,148,136,.07),transparent 60%)}
.wrap{max-width:1180px;margin:0 auto;padding:0 24px}
.hero{padding:56px 0 32px}
.hero .tag{display:inline-block;font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);background:rgba(29,111,255,.08);padding:6px 14px;border-radius:999px;margin-bottom:14px}
.hero h1{font-size:34px;font-weight:700;letter-spacing:-.01em;margin-bottom:10px;background:linear-gradient(135deg,var(--ink),var(--accent));-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.hero .sub{font-size:16px;color:var(--muted);max-width:720px}
.hero .meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:20px}
.hero .meta span{font-size:12.5px;color:var(--muted);background:var(--bg2);border:1px solid var(--rule);padding:5px 11px;border-radius:8px}
.hero .meta b{color:var(--ink);font-weight:600}
section{padding:36px 0}
.sh{display:flex;align-items:baseline;gap:14px;margin-bottom:22px}
.sn{font-family:'JetBrains Mono','Consolas',monospace;font-size:13px;font-weight:700;color:var(--accent);background:rgba(29,111,255,.08);padding:4px 10px;border-radius:6px;flex-shrink:0}
.sh h2{font-size:22px;font-weight:700;letter-spacing:-.01em}
.sh .d{font-size:13px;color:var(--muted);margin-left:auto}
.callout{background:var(--bg2);border:1px solid var(--rule);border-left:4px solid var(--accent);border-radius:0 var(--radius) var(--radius) 0;padding:14px 18px;margin:14px 0;box-shadow:var(--shadow)}
.callout.warn{border-left-color:var(--warn)}
.callout h4{font-size:14px;font-weight:700;margin-bottom:4px}
.callout p{font-size:13.5px;color:var(--muted)} .callout p strong{color:var(--ink)}
/* Domain cards */
.domains{display:grid;grid-template-columns:repeat(2,1fr);gap:14px}
.dom{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow)}
.dom-head{padding:10px 14px;color:#fff;display:flex;align-items:center;gap:8px}
.dom-head .dn{font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:700;opacity:.7}
.dom-head h3{font-size:14px;font-weight:700}
.dom-body{padding:6px 8px 10px}
.tbl{padding:8px 10px;border-radius:6px;margin:3px}
.tbl:hover{background:rgba(29,111,255,.03)}
.tbl .tn{font-family:'JetBrains Mono',monospace;font-size:12.5px;font-weight:700;color:var(--accent)}
.tbl .tc{font-size:12px;color:var(--muted);margin-left:6px}
.dom-blue .dom-head{background:linear-gradient(135deg,#1d6fff,#3b82f6)} .dom-blue .tbl .tn{color:#1d6fff}
.dom-green .dom-head{background:linear-gradient(135deg,#0d9488,#14b8a6)} .dom-green .tbl .tn{color:#0d9488}
.dom-purple .dom-head{background:linear-gradient(135deg,#7c3aed,#8b5cf6)} .dom-purple .tbl .tn{color:#7c3aed}
.dom-amber .dom-head{background:linear-gradient(135deg,#e0852b,#f59e0b)} .dom-amber .tbl .tn{color:#e0852b}
.dom-slate .dom-head{background:linear-gradient(135deg,#475569,#64748b)} .dom-slate .tbl .tn{color:#475569}
.dom-red .dom-head{background:linear-gradient(135deg,#dc2626,#ef4444)} .dom-red .tbl .tn{color:#dc2626}
/* ER diagram */
.mermaid{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:20px;text-align:center;margin:14px 0;box-shadow:var(--shadow);overflow-x:auto}
/* Table detail */
table{width:100%;border-collapse:collapse;font-size:12.5px}
thead th{background:#f1f5fb;color:var(--ink);font-weight:700;text-align:left;padding:8px 12px;border-bottom:2px solid var(--rule);position:sticky;top:0}
tbody td{padding:7px 12px;border-bottom:1px solid var(--rule);vertical-align:top}
tbody tr:hover{background:rgba(29,111,255,.03)}
code{font-family:'JetBrains Mono',monospace;font-size:11.5px;color:var(--accent);background:rgba(29,111,255,.06);padding:1px 5px;border-radius:4px}
.pill{display:inline-block;font-size:10px;font-weight:700;padding:1px 7px;border-radius:999px}
.p-pk{background:rgba(29,111,255,.12);color:#1d6fff}
.p-fk{background:rgba(124,58,237,.12);color:#7c3aed}
.p-pi{background:rgba(13,148,136,.12);color:#0d9488}
.table-wrap{border:1px solid var(--rule);border-radius:var(--radius);overflow:auto;max-height:480px;background:var(--bg2);margin:8px 0}
.dom-div{display:flex;align-items:center;gap:10px;margin:28px 0 10px;padding:8px 14px;border-radius:8px;background:var(--bg2);border:1px solid var(--rule);border-left:4px solid var(--accent)}
.dom-div .dn{font-family:'JetBrains Mono',monospace;font-size:11px;font-weight:700;color:#fff;background:var(--accent);padding:2px 8px;border-radius:4px}
.dom-div h3{font-size:15px;font-weight:700}
.dom-div .dc{font-size:12px;color:var(--muted);margin-left:auto}
.tbl-title{font-size:14px;font-weight:700;margin:12px 0 4px;display:flex;align-items:center;gap:8px}
.tbl-title code{font-size:13px}
.tbl-title .td{font-size:12px;color:var(--muted);font-weight:400}
/* Partition vis */
.part-vis{display:grid;grid-template-columns:repeat(6,1fr);gap:6px;margin:14px 0}
.part{border-radius:8px;padding:10px 6px;text-align:center;border:1.5px solid;font-size:11px}
.part h4{font-family:'JetBrains Mono',monospace;font-size:10.5px;font-weight:700;margin-bottom:2px}
.part p{font-size:10px;color:var(--muted)}
.part.active{border-color:var(--accent2);background:rgba(13,148,136,.08)} .part.active h4{color:#0d9488}
.part.future{border-color:var(--rule);background:rgba(0,0,0,.02)} .part.future h4{color:var(--muted)}
.part.archive{border-style:dashed;border-color:var(--rule)} .part.archive h4{color:var(--muted)} .part.archive p{color:#94a3b8}
footer{margin-top:36px;padding:24px 0 44px;border-top:1px solid var(--rule)}
footer p{text-align:center;font-size:13px;color:var(--muted)}
@media(max-width:860px){.domains{grid-template-columns:1fr}.part-vis{grid-template-columns:repeat(3,1fr)} .hero h1{font-size:26px}}
@media(max-width:520px){.part-vis{grid-template-columns:repeat(2,1fr)} .wrap{padding:0 14px}}
</style>
</head>
<body>
<div class="wrap">
<header class="hero">
<span class="tag">DATABASE DESIGN · V1.0</span>
<h1>鑫潼智电系统 · PostgreSQL 数据库设计文档</h1>
<p class="sub">基于《鑫潼智电系统需求分析报告 V1.0》数据说明,设计 37 张数据表 + 3 个分区管理函数 + 1 个物化视图,覆盖客户、项目、设备、派单、报警、报修、维保、报酬、用电采集等全部业务域。采用逻辑隔离 + 时序分区方案。</p>
<div class="meta">
<span>数据库:<b>PostgreSQL 15+</b></span>
<span>表数量:<b>39 张</b></span>
<span>隔离方案:<b>customer_id 逻辑隔离</b></span>
<span>时序分区:<b>electricity_data 按月分区</b></span>
<span>自动分区:<b>3 个管理函数</b></span>
<span>历史分析:<b>1 个物化视图</b></span>
<span>字符集:<b>UTF8</b></span>
</div>
</header>
<!-- 01 设计概述 -->
<section id="overview">
<div class="sh"><span class="sn">01</span><h2>设计概述</h2><span class="d">设计原则与关键决策</span></div>
<div class="callout">
<h4>设计原则</h4>
<p>① <strong>逻辑隔离</strong>:所有业务表携带 <code>customer_id</code> 字段实现行级数据隔离,不做物理分库。② <strong>时序分区</strong>:用电采集数据(<code>electricity_data</code>)按月 RANGE 分区,解决数据量暴涨问题。③ <strong>外键约束</strong>:核心关联表使用外键保证数据完整性。④ <strong>JSONB 灵活存储</strong>:照片路径列表、ICC 灵活字段使用 JSONB 类型。⑤ <strong>全部表加 COMMENT</strong>:便于团队协作和 ORM 映射。</p>
</div>
<div class="callout warn">
<h4>命名规范</h4>
<p>表名:<code>snake_case</code> 小写下划线,业务表无前缀,系统表 <code>sys_</code> 前缀。主键:统一 <code>BIGSERIAL</code> 自增。时间字段:统一 <code>TIMESTAMPTZ</code> 带时区。布尔状态:用 <code>SMALLINT</code>(0/1)。编码字段:如 <code>customer_no</code>、<code>plan_no</code> 等业务编号用 <code>VARCHAR(64)</code>。</p>
</div>
</section>
<!-- 02 业务域划分 -->
<section id="domains">
<div class="sh"><span class="sn">02</span><h2>业务域划分</h2><span class="d">14 个业务域 · 39 张表</span></div>
<div class="domains">
<div class="dom dom-blue">
<div class="dom-head"><span class="dn">D1</span><h3>系统管理域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">sys_user</span><span class="tc">系统用户(业务员/管理员)</span></div>
<div class="tbl"><span class="tn">sys_role</span><span class="tc">角色</span></div>
<div class="tbl"><span class="tn">sys_user_role</span><span class="tc">用户角色关联</span></div>
<div class="tbl"><span class="tn">sys_menu</span><span class="tc">菜单(RBAC 权限)</span></div>
<div class="tbl"><span class="tn">sys_role_menu</span><span class="tc">角色菜单关联</span></div>
<div class="tbl"><span class="tn">sys_dict</span><span class="tc">数据字典</span></div>
<div class="tbl"><span class="tn">sys_operation_log</span><span class="tc">操作日志</span></div>
</div>
</div>
<div class="dom dom-green">
<div class="dom-head"><span class="dn">D2</span><h3>客户域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">customer</span><span class="tc">客户信息</span></div>
<div class="tbl"><span class="tn">customer_department</span><span class="tc">客户部门</span></div>
<div class="tbl"><span class="tn">customer_visit</span><span class="tc">客户拜访</span></div>
<div class="tbl"><span class="tn">customer_building</span><span class="tc">客户建筑</span></div>
<div class="tbl"><span class="tn">customer_room</span><span class="tc">客户房间</span></div>
<div class="tbl"><span class="tn">customer_equipment</span><span class="tc">客户设备(配电间/井/箱)</span></div>
<div class="tbl"><span class="tn">customer_account</span><span class="tc">客户访问账号</span></div>
</div>
</div>
<div class="dom dom-purple">
<div class="dom-head"><span class="dn">D3</span><h3>智电设备域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">smart_device</span><span class="tc">智电设备型号(产品目录)</span></div>
</div>
</div>
<div class="dom dom-amber">
<div class="dom-head"><span class="dn">D4</span><h3>项目方案与合同域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">project_plan</span><span class="tc">智电改造方案</span></div>
<div class="tbl"><span class="tn">project_plan_detail</span><span class="tc">方案设备明细</span></div>
<div class="tbl"><span class="tn">contract</span><span class="tc">项目合同</span></div>
</div>
</div>
<div class="dom dom-slate">
<div class="dom-head"><span class="dn">D5</span><h3>线路与设备关联域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">electric_line</span><span class="tc">智电改造线路(ICC 同步)</span></div>
<div class="tbl"><span class="tn">line_room</span><span class="tc">线路房间关联</span></div>
</div>
</div>
<div class="dom dom-blue">
<div class="dom-head"><span class="dn">D6</span><h3>派单域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">survey_order</span><span class="tc">勘察派单</span></div>
<div class="tbl"><span class="tn">survey_sop_item</span><span class="tc">勘察SOP模板检查项</span></div>
<div class="tbl"><span class="tn">survey_sop_result</span><span class="tc">勘察SOP工单回执</span></div>
<div class="tbl"><span class="tn">install_order</span><span class="tc">安装派单</span></div>
<div class="tbl"><span class="tn">acceptance</span><span class="tc">项目验收</span></div>
<div class="tbl"><span class="tn">visit_record</span><span class="tc">客户回访</span></div>
</div>
</div>
<div class="dom dom-red">
<div class="dom-head"><span class="dn">D7</span><h3>报警域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">fault_type</span><span class="tc">报警故障类型</span></div>
<div class="tbl"><span class="tn">fault_type_detail</span><span class="tc">故障类型明细</span></div>
<div class="tbl"><span class="tn">device_alarm</span><span class="tc">设备报警(ICC 拉取)</span></div>
<div class="tbl"><span class="tn">alarm_dispatch</span><span class="tc">报警派单</span></div>
</div>
</div>
<div class="dom dom-amber">
<div class="dom-head"><span class="dn">D8</span><h3>报修域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">repair_request</span><span class="tc">报修单</span></div>
<div class="tbl"><span class="tn">repair_dispatch</span><span class="tc">报修派单</span></div>
</div>
</div>
<div class="dom dom-green">
<div class="dom-head"><span class="dn">D9</span><h3>维保域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">maintenance_order</span><span class="tc">维保单</span></div>
<div class="tbl"><span class="tn">maintenance_detail</span><span class="tc">维保明细</span></div>
</div>
</div>
<div class="dom dom-purple">
<div class="dom-head"><span class="dn">D10</span><h3>共享电工域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">worker</span><span class="tc">共享电工信息</span></div>
<div class="tbl"><span class="tn">dispatch_price</span><span class="tc">派单价格</span></div>
<div class="tbl"><span class="tn">worker_income</span><span class="tc">派单收入(月度)</span></div>
<div class="tbl"><span class="tn">worker_income_detail</span><span class="tc">派单收入明细</span></div>
</div>
</div>
<div class="dom dom-amber">
<div class="dom-head"><span class="dn">D11</span><h3>用电采集域(分区)</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">electricity_data</span><span class="tc">线路用电信息(按月分区)</span></div>
</div>
</div>
<div class="dom dom-slate">
<div class="dom-head"><span class="dn">D12</span><h3>辅助域</h3></div>
<div class="dom-body">
<div class="tbl"><span class="tn">icc_sync_log</span><span class="tc">ICC 同步日志</span></div>
<div class="tbl"><span class="tn">file_record</span><span class="tc">文件存储记录</span></div>
</div>
</div>
</div>
</section>
<!-- 03 ER 图 -->
<section id="er">
<div class="sh"><span class="sn">03</span><h2>核心 ER 关系图</h2><span class="d">关键实体关联</span></div>
<div class="callout"><p>以下展示客户域→项目域→线路域→报警/报修域的核心关联路径,省略系统管理域和辅助域。</p></div>
<figure class="mermaid">
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 : "价格参考"
survey_order ||--o{ survey_sop_result : "工单回执"
survey_sop_item ||--o{ survey_sop_result : "模板检查项"
</figure>
</section>
<!-- 04 时序分区 -->
<section id="partition">
<div class="sh"><span class="sn">04</span><h2>用电数据时序分区</h2><span class="d">electricity_data 按月 RANGE 分区</span></div>
<div class="callout">
<h4>分区策略</h4>
<p><code>electricity_data</code> 表是数据量增量大头(每条线路按 ICC 采集频次持续写入)。采用 PostgreSQL 声明式 RANGE 分区,按 <code>collect_time</code> 字段按月切分。查询只扫描目标月份分区,性能稳定。历史分区可归档,不影响热数据查询。</p>
</div>
<div class="part-vis">
<div class="part archive"><h4>2026_05</h4><p>已归档</p></div>
<div class="part archive"><h4>2026_06</h4><p>已归档</p></div>
<div class="part archive"><h4>2026_07</h4><p>已归档</p></div>
<div class="part active"><h4>2026_08</h4><p>当前活跃</p></div>
<div class="part future"><h4>2026_09</h4><p>预创建</p></div>
<div class="part future"><h4>2026_10</h4><p>预创建</p></div>
<div class="part future"><h4>2026_11</h4><p>预创建</p></div>
<div class="part future"><h4>2026_12</h4><p>预创建</p></div>
<div class="part future"><h4>2027_01</h4><p>待创建</p></div>
<div class="part future"><h4>2027_02</h4><p>待创建</p></div>
<div class="part future"><h4>2027_03</h4><p>待创建</p></div>
<div class="part future"><h4>2027_04</h4><p>待创建</p></div>
</div>
<div class="callout warn">
<h4>分区自动管理</h4>
<p>建议使用 <code>pg_partman</code> 扩展或编写定时任务(Midway.js cron)自动创建未来月份分区。每月初自动 CREATE 新分区,超过 N 个月的分区可 DETACH 后归档至冷存储。构建脚本已预创建 2026 年 8~12 月分区。</p>
</div>
</section>
<!-- 05 全部表字段说明 -->
<section id="tables">
<div class="sh"><span class="sn">05</span><h2>全部数据表字段说明</h2><span class="d">39 张表 · 按业务域分组</span></div>
<!-- D1 系统管理域 -->
<div class="dom-div"><span class="dn">D1</span><h3>系统管理域</h3><span class="dc">7 张表 · 用户/角色/菜单/字典/日志</span></div>
<div class="tbl-title"><code>sys_user</code><span class="td">— 系统用户表(鑫潼内部人员)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>username</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>登录用户名</td></tr>
<tr><td><code>password_hash</code></td><td>VARCHAR(256)</td><td></td><td>密码哈希值</td></tr>
<tr><td><code>real_name</code></td><td>VARCHAR(64)</td><td></td><td>真实姓名</td></tr>
<tr><td><code>phone</code></td><td>VARCHAR(20)</td><td></td><td>手机号</td></tr>
<tr><td><code>email</code></td><td>VARCHAR(128)</td><td></td><td>邮箱</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1启用 0禁用</td></tr>
<tr><td><code>last_login_at</code></td><td>TIMESTAMPTZ</td><td></td><td>最后登录时间</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>updated_at</code></td><td>TIMESTAMPTZ</td><td></td><td>更新时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_role</code><span class="td">— 角色表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>role_code</code></td><td>VARCHAR(32)</td><td>UNIQUE</td><td>角色编码</td></tr>
<tr><td><code>role_name</code></td><td>VARCHAR(64)</td><td></td><td>角色名称</td></tr>
<tr><td><code>description</code></td><td>TEXT</td><td></td><td>描述</td></tr>
<tr><td><code>sort_order</code></td><td>INT</td><td></td><td>排序号</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_user_role</code><span class="td">— 用户角色关联表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>user_id</code></td><td>BIGINT</td><td><span class="pill p-pk">PK</span><span class="pill p-fk">FK</span></td><td>用户 ID(→ sys_user)</td></tr>
<tr><td><code>role_id</code></td><td>BIGINT</td><td><span class="pill p-pk">PK</span><span class="pill p-fk">FK</span></td><td>角色 ID(→ sys_role)</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_menu</code><span class="td">— 菜单表(RBAC 权限)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>parent_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>父菜单 ID(自关联)</td></tr>
<tr><td><code>menu_name</code></td><td>VARCHAR(64)</td><td></td><td>菜单名称</td></tr>
<tr><td><code>menu_path</code></td><td>VARCHAR(256)</td><td></td><td>路由路径</td></tr>
<tr><td><code>component</code></td><td>VARCHAR(256)</td><td></td><td>前端组件路径</td></tr>
<tr><td><code>icon</code></td><td>VARCHAR(64)</td><td></td><td>图标</td></tr>
<tr><td><code>sort_order</code></td><td>INT</td><td></td><td>排序号</td></tr>
<tr><td><code>menu_type</code></td><td>SMALLINT</td><td></td><td>类型:1目录 2菜单 3按钮</td></tr>
<tr><td><code>permission</code></td><td>VARCHAR(128)</td><td></td><td>权限标识,如 customer:list</td></tr>
<tr><td><code>visible</code></td><td>SMALLINT</td><td></td><td>是否可见:1是 0否</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_role_menu</code><span class="td">— 角色菜单关联表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>role_id</code></td><td>BIGINT</td><td><span class="pill p-pk">PK</span><span class="pill p-fk">FK</span></td><td>角色 ID(→ sys_role)</td></tr>
<tr><td><code>menu_id</code></td><td>BIGINT</td><td><span class="pill p-pk">PK</span><span class="pill p-fk">FK</span></td><td>菜单 ID(→ sys_menu)</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_dict</code><span class="td">— 数据字典表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>dict_type</code></td><td>VARCHAR(64)</td><td><span class="pill p-pi">IDX</span></td><td>字典类型</td></tr>
<tr><td><code>dict_label</code></td><td>VARCHAR(128)</td><td></td><td>字典标签</td></tr>
<tr><td><code>dict_value</code></td><td>VARCHAR(128)</td><td></td><td>字典值</td></tr>
<tr><td><code>sort_order</code></td><td>INT</td><td></td><td>排序号</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1启用 0禁用</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>sys_operation_log</code><span class="td">— 操作日志表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>user_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>操作用户 ID</td></tr>
<tr><td><code>module</code></td><td>VARCHAR(64)</td><td></td><td>操作模块</td></tr>
<tr><td><code>action</code></td><td>VARCHAR(64)</td><td></td><td>操作动作</td></tr>
<tr><td><code>method</code></td><td>VARCHAR(256)</td><td></td><td>请求方法</td></tr>
<tr><td><code>params</code></td><td>TEXT</td><td></td><td>请求参数</td></tr>
<tr><td><code>ip</code></td><td>VARCHAR(64)</td><td></td><td>操作 IP</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td><span class="pill p-pi">IDX</span></td><td>操作时间</td></tr>
</tbody></table></div>
<!-- D2 客户域 -->
<div class="dom-div"><span class="dn">D2</span><h3>客户域</h3><span class="dc">7 张表 · 客户/部门/建筑/房间/设备/账号</span></div>
<div class="tbl-title"><code>customer</code><span class="td">— 客户信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>customer_name</code></td><td>VARCHAR(128)</td><td><span class="pill p-pi">IDX</span></td><td>客户名称</td></tr>
<tr><td><code>province</code></td><td>VARCHAR(64)</td><td></td><td>省</td></tr>
<tr><td><code>city</code></td><td>VARCHAR(64)</td><td></td><td>市</td></tr>
<tr><td><code>district</code></td><td>VARCHAR(64)</td><td></td><td>区/县</td></tr>
<tr><td><code>address</code></td><td>VARCHAR(256)</td><td></td><td>地址</td></tr>
<tr><td><code>contact_person</code></td><td>VARCHAR(64)</td><td></td><td>联系人</td></tr>
<tr><td><code>contact_phone</code></td><td>VARCHAR(20)</td><td></td><td>电话</td></tr>
<tr><td><code>postal_code</code></td><td>VARCHAR(10)</td><td></td><td>邮编</td></tr>
<tr><td><code>fax</code></td><td>VARCHAR(20)</td><td></td><td>传真</td></tr>
<tr><td><code>customer_level</code></td><td>VARCHAR(32)</td><td></td><td>客户级别(学校/医院等)</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1意向 2签约 3运维中 4终止</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>updated_at</code></td><td>TIMESTAMPTZ</td><td></td><td>更新时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_department</code><span class="td">— 客户部门信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID(→ customer)</td></tr>
<tr><td><code>dept_name</code></td><td>VARCHAR(128)</td><td></td><td>部门名称</td></tr>
<tr><td><code>contact_person</code></td><td>VARCHAR(64)</td><td></td><td>联系人</td></tr>
<tr><td><code>contact_phone</code></td><td>VARCHAR(20)</td><td></td><td>电话</td></tr>
<tr><td><code>function_desc</code></td><td>TEXT</td><td></td><td>职能</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_visit</code><span class="td">— 客户拜访信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>visit_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>拜访单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>visit_person</code></td><td>VARCHAR(64)</td><td></td><td>拜访人</td></tr>
<tr><td><code>visit_phone</code></td><td>VARCHAR(20)</td><td></td><td>拜访人电话</td></tr>
<tr><td><code>visit_content</code></td><td>TEXT</td><td></td><td>拜访内容</td></tr>
<tr><td><code>visit_time</code></td><td>DATE</td><td></td><td>拜访时间</td></tr>
<tr><td><code>salesman_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>业务员</td></tr>
<tr><td><code>will_plan</code></td><td>SMALLINT</td><td></td><td>是否做方案:0不同意 1同意</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_building</code><span class="td">— 客户智电改造建筑信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>building_name</code></td><td>VARCHAR(128)</td><td></td><td>建筑名称</td></tr>
<tr><td><code>basic_info</code></td><td>TEXT</td><td></td><td>基本情况</td></tr>
<tr><td><code>purpose</code></td><td>VARCHAR(128)</td><td></td><td>用途</td></tr>
<tr><td><code>floor_count</code></td><td>INT</td><td></td><td>层数</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_room</code><span class="td">— 客户建筑房间信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>room_code</code></td><td>VARCHAR(64)</td><td></td><td>房间编码</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>room_name</code></td><td>VARCHAR(128)</td><td></td><td>房间名称</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>所属建筑 ID(→ customer_building)</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>room_purpose</code></td><td>VARCHAR(128)</td><td></td><td>房间用途</td></tr>
<tr><td><code>dept_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>房间所属客户部门(→ customer_department)</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_equipment</code><span class="td">— 客户智电改造设备信息表(配电间/井/箱)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>equip_code</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>客户设备编码</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>equip_name</code></td><td>VARCHAR(128)</td><td></td><td>客户设备名称</td></tr>
<tr><td><code>equip_type</code></td><td>VARCHAR(32)</td><td></td><td>设备类型:配电间/配电井/配电箱</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>所属建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>description</code></td><td>TEXT</td><td></td><td>设备描述</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>photo_url</code></td><td>VARCHAR(512)</td><td></td><td>未改造前设备照片</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>customer_account</code><span class="td">— 客户访问账号表(小程序登录)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>phone</code></td><td>VARCHAR(20)</td><td>UNIQUE</td><td>登录电话</td></tr>
<tr><td><code>password_hash</code></td><td>VARCHAR(256)</td><td></td><td>密码哈希</td></tr>
<tr><td><code>wx_openid</code></td><td>VARCHAR(128)</td><td></td><td>微信 openid</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1启用 0禁用</td></tr>
<tr><td><code>last_login_at</code></td><td>TIMESTAMPTZ</td><td></td><td>最后登录时间</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D3 智电设备域 -->
<div class="dom-div"><span class="dn">D3</span><h3>智电设备域</h3><span class="dc">1 张表 · 产品目录</span></div>
<div class="tbl-title"><code>smart_device</code><span class="td">— 鑫潼智电设备信息表(产品目录)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>device_model</code></td><td>VARCHAR(64)</td><td></td><td>智电设备型号</td></tr>
<tr><td><code>device_name</code></td><td>VARCHAR(128)</td><td></td><td>智电设备名称</td></tr>
<tr><td><code>device_spec</code></td><td>VARCHAR(256)</td><td></td><td>智电设备规格</td></tr>
<tr><td><code>device_type</code></td><td>VARCHAR(32)</td><td></td><td>设备类型:网关/采集器/探测器等</td></tr>
<tr><td><code>device_function</code></td><td>TEXT</td><td></td><td>智电设备功能</td></tr>
<tr><td><code>supplier</code></td><td>VARCHAR(128)</td><td></td><td>供应商</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D4 项目方案与合同域 -->
<div class="dom-div"><span class="dn">D4</span><h3>项目方案与合同域</h3><span class="dc">3 张表 · 方案/明细/合同</span></div>
<div class="tbl-title"><code>project_plan</code><span class="td">— 智电改造方案信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>plan_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>方案单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>registrar</code></td><td>VARCHAR(64)</td><td></td><td>方案登记人(业务员)</td></tr>
<tr><td><code>register_time</code></td><td>DATE</td><td></td><td>方案登记时间</td></tr>
<tr><td><code>plan_desc</code></td><td>TEXT</td><td></td><td>方案说明</td></tr>
<tr><td><code>plan_file_url</code></td><td>VARCHAR(512)</td><td></td><td>方案最终文件</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:0草稿 1已确认</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>project_plan_detail</code><span class="td">— 项目方案智电设备明细表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>plan_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>方案 ID(→ project_plan)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户设备 ID(→ customer_equipment)</td></tr>
<tr><td><code>smart_device_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>智电设备型号 ID(→ smart_device)</td></tr>
<tr><td><code>quantity</code></td><td>NUMERIC(10,2)</td><td></td><td>数量</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>contract</code><span class="td">— 智电项目合同信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>contract_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>合同单号</td></tr>
<tr><td><code>xt_contract_no</code></td><td>VARCHAR(64)</td><td><span class="pill p-pi">IDX</span></td><td>鑫潼合同号(XT+年份+序号)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>contract_amount</code></td><td>NUMERIC(14,2)</td><td></td><td>合同金额</td></tr>
<tr><td><code>pay_cycle</code></td><td>VARCHAR(32)</td><td></td><td>支付周期:按月/按年</td></tr>
<tr><td><code>salesman_id</code></td><td>BIGINT</td><td></td><td>业务员</td></tr>
<tr><td><code>sign_date</code></td><td>DATE</td><td></td><td>签订日期</td></tr>
<tr><td><code>contract_desc</code></td><td>TEXT</td><td></td><td>合同说明</td></tr>
<tr><td><code>start_date</code></td><td>DATE</td><td></td><td>开始日期</td></tr>
<tr><td><code>end_date</code></td><td>DATE</td><td></td><td>结束日期</td></tr>
<tr><td><code>plan_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>方案 ID(→ project_plan)</td></tr>
<tr><td><code>contract_file_url</code></td><td>VARCHAR(512)</td><td></td><td>签字盖章电子合同</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1有效 0终止</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D5 线路与设备关联域 -->
<div class="dom-div"><span class="dn">D5</span><h3>线路与设备关联域</h3><span class="dc">2 张表 · ICC 同步 + 房间关联</span></div>
<div class="tbl-title"><code>electric_line</code><span class="td">— 智电改造线路表(ICC 同步)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>line_code</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>线路编码(唯一)</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户设备 ID(→ customer_equipment)</td></tr>
<tr><td><code>icc_device_code</code></td><td>VARCHAR(128)</td><td><span class="pill p-pi">IDX</span></td><td>ICC 智电设备编号</td></tr>
<tr><td><code>line_name</code></td><td>VARCHAR(128)</td><td></td><td>线路名称(ICC 同步)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID(逻辑隔离键)</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>所属建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1在线 0离线</td></tr>
<tr><td><code>synced_at</code></td><td>TIMESTAMPTZ</td><td></td><td>ICC 同步时间</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>line_room</code><span class="td">— 线路所属房间关联表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>line_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>线路 ID(→ electric_line)</td></tr>
<tr><td><code>room_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>房间 ID(→ customer_room)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D6 派单域 -->
<div class="dom-div"><span class="dn">D6</span><h3>派单域</h3><span class="dc">6 张表 · 勘察/勘察SOP/安装/验收/回访</span></div>
<div class="tbl-title"><code>survey_order</code><span class="td">— 客户勘察派单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>survey_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>勘察单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>surveyor</code></td><td>VARCHAR(64)</td><td></td><td>勘察人(共享电工)</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td></td><td>共享电工 ID</td></tr>
<tr><td><code>survey_time</code></td><td>TIMESTAMPTZ</td><td></td><td>勘察时间</td></tr>
<tr><td><code>priority</code></td><td>SMALLINT</td><td><span class="pill p-pi">IDX</span></td><td>优先级:1特急P1 2加急P2 3常规P3</td></tr>
<tr><td><code>task_title</code></td><td>VARCHAR(128)</td><td></td><td>勘察任务标题</td></tr>
<tr><td><code>site_location</code></td><td>VARCHAR(255)</td><td></td><td>具体勘察物理区域</td></tr>
<tr><td><code>source</code></td><td>VARCHAR(32)</td><td></td><td>工单来源:ledger台账派工 visit拜访转勘察 customer客户发起</td></tr>
<tr><td><code>loop_spec</code></td><td>VARCHAR(128)</td><td></td><td>主进线规约与断路器容量</td></tr>
<tr><td><code>loop_count</code></td><td>INTEGER</td><td></td><td>预估分支测绘回路数</td></tr>
<tr><td><code>progress_done</code></td><td>INTEGER</td><td></td><td>已完成测绘回路数</td></tr>
<tr><td><code>progress_total</code></td><td>INTEGER</td><td></td><td>应测绘回路总数</td></tr>
<tr><td><code>drawing_count</code></td><td>INTEGER</td><td></td><td>待技术复核图纸数</td></tr>
<tr><td><code>salesman_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>责任业务员 ID(→ sys_user,数据隔离)</td></tr>
<tr><td><code>tech_contact</code></td><td>VARCHAR(128)</td><td></td><td>现场技术联系人</td></tr>
<tr><td><code>plan_start</code></td><td>TIMESTAMPTZ</td><td><span class="pill p-pi">IDX</span></td><td>计划到场窗口开始</td></tr>
<tr><td><code>plan_end</code></td><td>TIMESTAMPTZ</td><td></td><td>计划到场窗口结束</td></tr>
<tr><td><code>expect_minutes</code></td><td>INTEGER</td><td></td><td>要求接单后到场时限(分钟)</td></tr>
<tr><td><code>expect_arrival_at</code></td><td>TIMESTAMPTZ</td><td></td><td>期望到场时限(指派时按 expect_minutes 推算)</td></tr>
<tr><td><code>sla_level</code></td><td>VARCHAR(32)</td><td></td><td>履约质保要求</td></tr>
<tr><td><code>urge_count</code></td><td>INTEGER</td><td></td><td>催办次数</td></tr>
<tr><td><code>last_urged_at</code></td><td>TIMESTAMPTZ</td><td></td><td>最近催办时间</td></tr>
<tr><td><code>is_draft</code></td><td>SMALLINT</td><td></td><td>是否草稿:0正式工单 1草稿</td></tr>
<tr><td><code>estimated_fee</code></td><td>NUMERIC(10,2)</td><td></td><td>预估劳务费(基础出场费+回路补贴)</td></tr>
<tr><td><code>actual_fee</code></td><td>NUMERIC(10,2)</td><td></td><td>实际结算劳务费</td></tr>
<tr><td><code>photos</code></td><td>VARCHAR(1024)</td><td></td><td>现场取证照片对象key(JSON数组字符串)</td></tr>
<tr><td><code>review_remark</code></td><td>TEXT</td><td></td><td>技术复核意见</td></tr>
<tr><td><code>reviewed_at</code></td><td>TIMESTAMPTZ</td><td></td><td>技术复核时间</td></tr>
<tr><td><code>cancel_reason</code></td><td>VARCHAR(255)</td><td></td><td>取消原因</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td><span class="pill p-pi">IDX</span></td><td>状态:0待指派 1现场勘察中 2待技术复核 3已归档 4预留 5已取消</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>updated_at</code></td><td>TIMESTAMPTZ</td><td></td><td>更新时间(触发器自动维护)</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>survey_sop_item</code><span class="td">— 勘察 SOP 模板检查项表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>template_code</code></td><td>VARCHAR(64)</td><td><span class="pill p-uk">UNIQUE</span></td><td>SOP模板编码:standard_dist 标准配电改造模板(与 sort_order 联合唯一)</td></tr>
<tr><td><code>sort_order</code></td><td>INTEGER</td><td></td><td>检查项序号</td></tr>
<tr><td><code>item_name</code></td><td>VARCHAR(128)</td><td></td><td>检查项名称</td></tr>
<tr><td><code>item_desc</code></td><td>VARCHAR(255)</td><td></td><td>检查项说明</td></tr>
<tr><td><code>receipt_type</code></td><td>VARCHAR(16)</td><td></td><td>回执形式:photo现场照片 form清单表单 meter测仪截图</td></tr>
<tr><td><code>receipt_require</code></td><td>VARCHAR(64)</td><td></td><td>回执指标要求,如「照片 ≥ 2 张」</td></tr>
<tr><td><code>required</code></td><td>BOOLEAN</td><td></td><td>是否必填</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>survey_sop_result</code><span class="td">— 勘察 SOP 工单回执表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>survey_order_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>勘察工单 ID(→ survey_order,级联删除)</td></tr>
<tr><td><code>sop_item_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>SOP 检查项 ID(→ survey_sop_item)</td></tr>
<tr><td><code>checked</code></td><td>BOOLEAN</td><td></td><td>是否已完成回执</td></tr>
<tr><td><code>receipt_value</code></td><td>VARCHAR(1024)</td><td></td><td>回执内容(照片对象key数组/表单值/截图key)</td></tr>
<tr><td><code>remark</code></td><td>VARCHAR(255)</td><td></td><td>回执备注</td></tr>
<tr><td><code>checked_at</code></td><td>TIMESTAMPTZ</td><td></td><td>回执时间</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>updated_at</code></td><td>TIMESTAMPTZ</td><td></td><td>更新时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>install_order</code><span class="td">— 项目安装任务派单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>install_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>安装单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>installer</code></td><td>VARCHAR(64)</td><td></td><td>安装人(共享电工)</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td></td><td>共享电工 ID</td></tr>
<tr><td><code>dispatch_date</code></td><td>DATE</td><td></td><td>派单日期</td></tr>
<tr><td><code>start_date</code></td><td>DATE</td><td></td><td>开始日期</td></tr>
<tr><td><code>end_date</code></td><td>DATE</td><td></td><td>结束日期</td></tr>
<tr><td><code>plan_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>方案 ID(→ project_plan)</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:0已派发 1已完成</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>acceptance</code><span class="td">— 项目验收信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>accept_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>验收单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>acceptor</code></td><td>VARCHAR(64)</td><td></td><td>验收人</td></tr>
<tr><td><code>accept_opinion</code></td><td>TEXT</td><td></td><td>验收意见</td></tr>
<tr><td><code>accept_date</code></td><td>DATE</td><td></td><td>验收日期</td></tr>
<tr><td><code>installer</code></td><td>VARCHAR(64)</td><td></td><td>安装人</td></tr>
<tr><td><code>accept_file_url</code></td><td>VARCHAR(512)</td><td></td><td>验收文件电子版</td></tr>
<tr><td><code>contract_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>合同 ID(→ contract)</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>visit_record</code><span class="td">— 客户回访信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>visit_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>回访单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>contact_person</code></td><td>VARCHAR(64)</td><td></td><td>联系人</td></tr>
<tr><td><code>contact_phone</code></td><td>VARCHAR(20)</td><td></td><td>电话</td></tr>
<tr><td><code>visitor</code></td><td>VARCHAR(64)</td><td></td><td>回访人</td></tr>
<tr><td><code>visit_time</code></td><td>DATE</td><td></td><td>回访时间</td></tr>
<tr><td><code>customer_opinion</code></td><td>TEXT</td><td></td><td>客户意见</td></tr>
<tr><td><code>photos</code></td><td>JSONB</td><td></td><td>回访照片</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D7 报警域 -->
<div class="dom-div"><span class="dn">D7</span><h3>报警域</h3><span class="dc">4 张表 · 故障类型/设备报警/报警派单</span></div>
<div class="tbl-title"><code>fault_type</code><span class="td">— 报警故障类型信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>fault_type_code</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>故障类型编码</td></tr>
<tr><td><code>fault_type_name</code></td><td>VARCHAR(128)</td><td></td><td>故障类型名称</td></tr>
<tr><td><code>description</code></td><td>TEXT</td><td></td><td>故障类型说明</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>fault_type_detail</code><span class="td">— 报警故障类型明细表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>fault_type_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>故障类型 ID(→ fault_type)</td></tr>
<tr><td><code>detail_category</code></td><td>VARCHAR(32)</td><td></td><td>明细分类:故障原因/处理流程</td></tr>
<tr><td><code>detail_desc</code></td><td>TEXT</td><td></td><td>明细说明</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>device_alarm</code><span class="td">— 设备报警信息表(ICC 拉取)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>alarm_code</code></td><td>VARCHAR(128)</td><td>UNIQUE</td><td>报警编码</td></tr>
<tr><td><code>line_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>线路 ID</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td></td><td>客户设备 ID</td></tr>
<tr><td><code>icc_device_code</code></td><td>VARCHAR(128)</td><td></td><td>ICC 设备编号</td></tr>
<tr><td><code>line_name</code></td><td>VARCHAR(128)</td><td></td><td>线路名称</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>客户 ID</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td></td><td>所属建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>alarm_date</code></td><td>DATE</td><td><span class="pill p-pi">IDX</span></td><td>报警日期</td></tr>
<tr><td><code>fault_type</code></td><td>VARCHAR(128)</td><td></td><td>ICC 预警类型</td></tr>
<tr><td><code>alarm_value</code></td><td>NUMERIC(14,2)</td><td></td><td>报警数值</td></tr>
<tr><td><code>history_count</code></td><td>INT</td><td></td><td>历史出现次数</td></tr>
<tr><td><code>synced_at</code></td><td>TIMESTAMPTZ</td><td></td><td>ICC 同步时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>alarm_dispatch</code><span class="td">— 报警派单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>dispatch_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>报警派单号</td></tr>
<tr><td><code>alarm_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>报警 ID(→ device_alarm)</td></tr>
<tr><td><code>line_id</code></td><td>BIGINT</td><td></td><td>线路 ID</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td></td><td>客户设备 ID</td></tr>
<tr><td><code>icc_device_code</code></td><td>VARCHAR(128)</td><td></td><td>ICC 设备编号</td></tr>
<tr><td><code>line_name</code></td><td>VARCHAR(128)</td><td></td><td>线路名称</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>contact_person</code></td><td>VARCHAR(64)</td><td></td><td>联系人</td></tr>
<tr><td><code>contact_phone</code></td><td>VARCHAR(20)</td><td></td><td>电话</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td></td><td>建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>fault_type_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>故障类型 ID(→ fault_type)</td></tr>
<tr><td><code>fault_desc</code></td><td>TEXT</td><td></td><td>故障事项(类型+数值)</td></tr>
<tr><td><code>dispatcher</code></td><td>VARCHAR(64)</td><td></td><td>派发人</td></tr>
<tr><td><code>fault_reason</code></td><td>TEXT</td><td></td><td>故障原因(来自明细)</td></tr>
<tr><td><code>process_flow</code></td><td>TEXT</td><td></td><td>处理流程(来自明细)</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>共享电工 ID</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td><span class="pill p-pi">IDX</span></td><td>状态:0已派发 1已处理</td></tr>
<tr><td><code>process_photos</code></td><td>JSONB</td><td></td><td>报警处理照片(多张)</td></tr>
<tr><td><code>rating</code></td><td>SMALLINT</td><td></td><td>派单处理评分</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>completed_at</code></td><td>TIMESTAMPTZ</td><td></td><td>完成时间</td></tr>
</tbody></table></div>
<!-- D8 报修域 -->
<div class="dom-div"><span class="dn">D8</span><h3>报修域</h3><span class="dc">2 张表 · 报修单/报修派单</span></div>
<div class="tbl-title"><code>repair_request</code><span class="td">— 报修单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>repair_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>报修单号</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>requester</code></td><td>VARCHAR(64)</td><td></td><td>报修人</td></tr>
<tr><td><code>requester_phone</code></td><td>VARCHAR(20)</td><td></td><td>报修电话</td></tr>
<tr><td><code>request_time</code></td><td>TIMESTAMPTZ</td><td></td><td>报修时间</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td></td><td>所属建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>repair_content</code></td><td>TEXT</td><td></td><td>报修内容</td></tr>
<tr><td><code>photos</code></td><td>JSONB</td><td></td><td>报修照片</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td><span class="pill p-pi">IDX</span></td><td>状态:0待处理 1已派单 2已完成</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>repair_dispatch</code><span class="td">— 报修派单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>dispatch_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>报修派单号</td></tr>
<tr><td><code>repair_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>报修单 ID(→ repair_request)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>requester</code></td><td>VARCHAR(64)</td><td></td><td>报修人</td></tr>
<tr><td><code>requester_phone</code></td><td>VARCHAR(20)</td><td></td><td>报修电话</td></tr>
<tr><td><code>request_time</code></td><td>TIMESTAMPTZ</td><td></td><td>报修时间</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td></td><td>建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>repair_content</code></td><td>TEXT</td><td></td><td>报修内容</td></tr>
<tr><td><code>dispatcher</code></td><td>VARCHAR(64)</td><td></td><td>派发人</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>共享电工 ID</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:0已派发 1已处理</td></tr>
<tr><td><code>process_photos</code></td><td>JSONB</td><td></td><td>处理完成照片</td></tr>
<tr><td><code>rating</code></td><td>SMALLINT</td><td></td><td>报修派单处理评分(客户评)</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>completed_at</code></td><td>TIMESTAMPTZ</td><td></td><td>完成时间</td></tr>
</tbody></table></div>
<!-- D9 维保域 -->
<div class="dom-div"><span class="dn">D9</span><h3>维保域</h3><span class="dc">2 张表 · 维保单/维保明细</span></div>
<div class="tbl-title"><code>maintenance_order</code><span class="td">— 维保单信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>maintenance_no</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>维保单号(录入,不自动生成)</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>maintainer</code></td><td>VARCHAR(64)</td><td></td><td>维保人(共享电工)</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td></td><td>共享电工 ID</td></tr>
<tr><td><code>maintenance_date</code></td><td>DATE</td><td></td><td>维保日期</td></tr>
<tr><td><code>remark</code></td><td>TEXT</td><td></td><td>备注</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:0已派发 1已完成</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>maintenance_detail</code><span class="td">— 维保单明细表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>maintenance_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>维保单 ID(→ maintenance_order)</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td></td><td>客户设备 ID</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>客户 ID</td></tr>
<tr><td><code>equip_name</code></td><td>VARCHAR(128)</td><td></td><td>客户设备名称</td></tr>
<tr><td><code>equip_type</code></td><td>VARCHAR(32)</td><td></td><td>设备类型:配电间/井/箱</td></tr>
<tr><td><code>building_id</code></td><td>BIGINT</td><td></td><td>建筑 ID</td></tr>
<tr><td><code>floor_no</code></td><td>VARCHAR(16)</td><td></td><td>所在楼层</td></tr>
<tr><td><code>location</code></td><td>VARCHAR(256)</td><td></td><td>所在位置</td></tr>
<tr><td><code>panel_condition</code></td><td>TEXT</td><td></td><td>配电间或电箱情况</td></tr>
<tr><td><code>circuit_condition</code></td><td>TEXT</td><td></td><td>回路情况</td></tr>
<tr><td><code>terminal_condition</code></td><td>TEXT</td><td></td><td>终端情况</td></tr>
<tr><td><code>maintenance_desc</code></td><td>TEXT</td><td></td><td>维保情况说明</td></tr>
<tr><td><code>photos</code></td><td>JSONB</td><td></td><td>维保现场照片(水印)</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D10 共享电工域 -->
<div class="dom-div"><span class="dn">D10</span><h3>共享电工域</h3><span class="dc">4 张表 · 电工/价格/收入/明细</span></div>
<div class="tbl-title"><code>worker</code><span class="td">— 共享电工信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>worker_name</code></td><td>VARCHAR(64)</td><td></td><td>电工姓名</td></tr>
<tr><td><code>phone</code></td><td>VARCHAR(20)</td><td><span class="pill p-uk">UNIQUE</span></td><td>手机号(登录帐号)</td></tr>
<tr><td><code>password_hash</code></td><td>VARCHAR(255)</td><td></td><td>密码哈希(BCrypt)</td></tr>
<tr><td><code>id_card</code></td><td>VARCHAR(18)</td><td></td><td>身份证号</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1在岗 0离职</td></tr>
<tr><td><code>worker_title</code></td><td>VARCHAR(32)</td><td></td><td>职衔:电工/资深班组长/特种高压电工</td></tr>
<tr><td><code>rating</code></td><td>NUMERIC(3,2)</td><td></td><td>服务评分(0-5,推荐算法权重 0.5)</td></tr>
<tr><td><code>cert_info</code></td><td>VARCHAR(128)</td><td></td><td>持证资质</td></tr>
<tr><td><code>cert_verified</code></td><td>BOOLEAN</td><td></td><td>资质是否已核验(推荐算法权重 0.3)</td></tr>
<tr><td><code>completed_count</code></td><td>INTEGER</td><td></td><td>历史累计勘察场次(推荐算法权重 0.2)</td></tr>
<tr><td><code>last_login_at</code></td><td>TIMESTAMPTZ</td><td></td><td>最后登录时间</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
<tr><td><code>updated_at</code></td><td>TIMESTAMPTZ</td><td></td><td>更新时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>dispatch_price</code><span class="td">— 共享电工派单价格信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>price_code</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>派单价格编码</td></tr>
<tr><td><code>dispatch_type</code></td><td>VARCHAR(32)</td><td></td><td>派单类型:勘察/安装/预警/维修/维保</td></tr>
<tr><td><code>price_type</code></td><td>VARCHAR(32)</td><td></td><td>价格类型:单价/总价提成</td></tr>
<tr><td><code>unit_price</code></td><td>NUMERIC(10,2)</td><td></td><td>服务单价</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>worker_income</code><span class="td">— 共享电工派单收入信息表(月度汇总)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>income_code</code></td><td>VARCHAR(64)</td><td>UNIQUE</td><td>派单收入编码</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>共享电工 ID(→ worker)</td></tr>
<tr><td><code>income_month</code></td><td>VARCHAR(7)</td><td><span class="pill p-pi">IDX</span></td><td>收入月份(YYYY-MM)</td></tr>
<tr><td><code>monthly_total</code></td><td>NUMERIC(14,2)</td><td></td><td>月度收入合计</td></tr>
<tr><td><code>rating_summary</code></td><td>NUMERIC(5,2)</td><td></td><td>评分综合统计</td></tr>
<tr><td><code>final_total</code></td><td>NUMERIC(14,2)</td><td></td><td>月度最终收入合计</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>worker_income_detail</code><span class="td">— 共享电工派单收入明细信息表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>income_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>收入 ID(→ worker_income)</td></tr>
<tr><td><code>worker_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span></td><td>共享电工 ID</td></tr>
<tr><td><code>income_month</code></td><td>VARCHAR(7)</td><td></td><td>收入月份</td></tr>
<tr><td><code>dispatch_type</code></td><td>VARCHAR(32)</td><td></td><td>派单类型</td></tr>
<tr><td><code>dispatch_no</code></td><td>VARCHAR(64)</td><td></td><td>各类型派单单号</td></tr>
<tr><td><code>income_amount</code></td><td>NUMERIC(10,2)</td><td></td><td>本单收入</td></tr>
<tr><td><code>rating_level</code></td><td>VARCHAR(16)</td><td></td><td>评价等级</td></tr>
<tr><td><code>final_income</code></td><td>NUMERIC(10,2)</td><td></td><td>本单最终收入合计</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
<!-- D11 用电采集域 -->
<div class="dom-div"><span class="dn">D11</span><h3>用电采集域(分区表)</h3><span class="dc">1 张表 · 按月分区</span></div>
<div class="tbl-title"><code>electricity_data</code><span class="td">— 线路用电信息表(按月 RANGE 分区)</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增(复合主键含 collect_time)</td></tr>
<tr><td><code>line_id</code></td><td>BIGINT</td><td><span class="pill p-fk">FK</span><span class="pill p-pi">IDX</span></td><td>线路 ID(→ electric_line)</td></tr>
<tr><td><code>line_code</code></td><td>VARCHAR(64)</td><td></td><td>线路编码(冗余,加速查询)</td></tr>
<tr><td><code>equip_id</code></td><td>BIGINT</td><td></td><td>客户设备 ID</td></tr>
<tr><td><code>icc_device_code</code></td><td>VARCHAR(128)</td><td></td><td>ICC 设备编号</td></tr>
<tr><td><code>line_name</code></td><td>VARCHAR(128)</td><td></td><td>线路名称</td></tr>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td><span class="pill p-pi">IDX</span></td><td>客户 ID(逻辑隔离键)</td></tr>
<tr><td><code>electricity</code></td><td>NUMERIC(14,4)</td><td></td><td>用电量</td></tr>
<tr><td><code>collect_time</code></td><td>TIMESTAMPTZ</td><td><span class="pill p-pk">PK</span><span class="pill p-pi">IDX</span></td><td>采集时间(分区键)</td></tr>
</tbody></table></div>
<div class="callout"><p><strong>分区键</strong>:<code>collect_time</code>。主键为复合主键 <code>(id, collect_time)</code>。已预建分区:<code>electricity_data_2026_08</code> ~ <code>electricity_data_2026_12</code>。组合索引:<code>(customer_id, collect_time)</code> 用于月报统计。</p></div>
<!-- D12 辅助域 -->
<div class="dom-div"><span class="dn">D12</span><h3>辅助域</h3><span class="dc">2 张表 · ICC 日志/文件记录</span></div>
<div class="tbl-title"><code>icc_sync_log</code><span class="td">— ICC 数据同步日志表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>sync_type</code></td><td>VARCHAR(32)</td><td><span class="pill p-pi">IDX</span></td><td>同步类型:客户/设备/用电/报警</td></tr>
<tr><td><code>start_time</code></td><td>TIMESTAMPTZ</td><td></td><td>开始时间</td></tr>
<tr><td><code>end_time</code></td><td>TIMESTAMPTZ</td><td></td><td>结束时间</td></tr>
<tr><td><code>record_count</code></td><td>INT</td><td></td><td>同步记录数</td></tr>
<tr><td><code>status</code></td><td>SMALLINT</td><td></td><td>状态:1成功 0失败</td></tr>
<tr><td><code>error_message</code></td><td>TEXT</td><td></td><td>错误信息</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td><span class="pill p-pi">IDX</span></td><td>创建时间</td></tr>
</tbody></table></div>
<div class="tbl-title"><code>file_record</code><span class="td">— 文件存储记录表</span></div>
<div class="table-wrap"><table><thead><tr><th>字段</th><th>类型</th><th>键</th><th>说明</th></tr></thead><tbody>
<tr><td><code>id</code></td><td>BIGSERIAL</td><td><span class="pill p-pk">PK</span></td><td>自增主键</td></tr>
<tr><td><code>file_name</code></td><td>VARCHAR(256)</td><td></td><td>文件名</td></tr>
<tr><td><code>file_url</code></td><td>VARCHAR(512)</td><td></td><td>文件 URL</td></tr>
<tr><td><code>file_type</code></td><td>VARCHAR(32)</td><td></td><td>文件类型:取证/合同/验收/方案/月报</td></tr>
<tr><td><code>file_size</code></td><td>BIGINT</td><td></td><td>文件大小(字节)</td></tr>
<tr><td><code>business_type</code></td><td>VARCHAR(64)</td><td><span class="pill p-pi">IDX</span></td><td>关联业务类型</td></tr>
<tr><td><code>business_id</code></td><td>BIGINT</td><td></td><td>关联业务 ID</td></tr>
<tr><td><code>uploaded_by</code></td><td>BIGINT</td><td></td><td>上传人 ID</td></tr>
<tr><td><code>created_at</code></td><td>TIMESTAMPTZ</td><td></td><td>创建时间</td></tr>
</tbody></table></div>
</section>
<!-- 06 索引策略 -->
<section id="index">
<div class="sh"><span class="sn">06</span><h2>索引策略</h2><span class="d">关键索引一览</span></div>
<div class="table-wrap"><table>
<thead><tr><th>表</th><th>索引</th><th>类型</th><th>用途</th></tr></thead>
<tbody>
<tr><td>customer</td><td><code>idx_customer_name</code></td><td>B-Tree</td><td>按客户名称搜索</td></tr>
<tr><td>customer</td><td><code>idx_customer_region</code></td><td>B-Tree 组合</td><td>按省市县区域查询</td></tr>
<tr><td>electric_line</td><td><code>idx_line_customer</code></td><td>B-Tree</td><td>按客户查线路(逻辑隔离)</td></tr>
<tr><td>electric_line</td><td><code>idx_line_icc</code></td><td>B-Tree</td><td>ICC 设备码匹配同步</td></tr>
<tr><td>electricity_data</td><td><code>idx_ed_customer_time</code></td><td>B-Tree 组合</td><td>按客户+时间查用电(月报核心查询)</td></tr>
<tr><td>device_alarm</td><td><code>idx_alarm_date</code></td><td>B-Tree</td><td>按报警日期查询</td></tr>
<tr><td>device_alarm</td><td><code>idx_alarm_customer</code></td><td>B-Tree</td><td>按客户查报警</td></tr>
<tr><td>alarm_dispatch</td><td><code>idx_alarm_disp_worker</code></td><td>B-Tree</td><td>电工查自己的派单(接口数据权限)</td></tr>
<tr><td>repair_dispatch</td><td><code>idx_repair_disp_worker</code></td><td>B-Tree</td><td>电工查报修派单</td></tr>
<tr><td>sys_dict</td><td><code>idx_sys_dict_type</code></td><td>B-Tree</td><td>按字典类型查询</td></tr>
<tr><td>icc_sync_log</td><td><code>idx_icc_sync_time</code></td><td>B-Tree</td><td>按时间查同步日志</td></tr>
</tbody>
</table></div>
<div class="callout">
<h4>索引设计原则</h4>
<p>① 所有 <code>customer_id</code> 外键字段建索引(逻辑隔离查询基础)。② 用电采集表建 <code>(customer_id, collect_time)</code> 组合索引(月报统计核心路径)。③ ICC 同步相关字段建索引(设备码匹配)。④ 共享电工查询字段建索引(接口数据权限过滤)。</p>
</div>
</section>
<!-- 07 初始数据 -->
<section id="init">
<div class="sh"><span class="sn">07</span><h2>初始数据</h2><span class="d">角色/菜单/字典</span></div>
<div class="table-wrap"><table>
<thead><tr><th>表</th><th>初始数据</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>sys_role</code></td><td>4 条</td><td>运营管理员/业务员/共享电工/客户</td></tr>
<tr><td><code>sys_menu</code></td><td>6 条</td><td>客户管理/项目管理/运营派单/设备监控/统计报表/系统管理</td></tr>
<tr><td><code>sys_dict</code></td><td>19 条</td><td>客户状态/设备类型/派单状态/支付周期/派单类型等</td></tr>
</tbody>
</table></div>
</section>
<!-- 08 自动分区管理 -->
<section id="autopartition">
<div class="sh"><span class="sn">08</span><h2>自动分区管理</h2><span class="d">pg_cron 定时调度 · 数据库自治</span></div>
<div class="callout">
<h4>设计背景</h4>
<p>PostgreSQL 声明式分区<strong>不会自动创建子分区</strong>。若数据写入时对应月份的分区不存在,INSERT 会直接报错:<code>no partition of relation found for row</code>。因此需要一套自动化的分区管理机制,确保未来月份的分区始终提前就绪。</p>
</div>
<div class="callout warn">
<h4>为什么不用触发器兜底?</h4>
<p>PostgreSQL 分区表的 <code>BEFORE INSERT</code> 触发器在<strong>分区路由之后</strong>才执行——即数据库先判断数据该落入哪个子分区,如果子分区不存在直接报错,触发器根本没有机会执行。因此触发器无法在写入时动态创建分区,必须通过<strong>定时预创建</strong> + <strong>应用层调用</strong>来保证分区就绪。</p>
</div>
<h3 style="margin:24px 0 12px;font-size:16px">管理函数一览</h3>
<div class="table-wrap" style="max-height:none"><table>
<thead><tr><th>函数名</th><th>参数</th><th>返回</th><th>用途</th></tr></thead>
<tbody>
<tr>
<td><code>ensure_electricity_partition</code></td>
<td><code>p_date DATE</code></td>
<td><code>VOID</code></td>
<td>确保指定日期所在月的分区存在(不存在则创建)。应用层在写入数据前调用此函数兜底。</td>
</tr>
<tr>
<td><code>run_electricity_partition_maintenance</code></td>
<td><code>p_premake INT</code>(默认 3)</td>
<td><code>TABLE(created_month, action)</code></td>
<td>批量预创建当前月 + 未来 N 个月的分区。Midway.js cron 每月调用一次,返回各分区状态(CREATED / EXISTS)。</td>
</tr>
<tr>
<td><code>refresh_electricity_monthly</code></td>
<td>无</td>
<td><code>VOID</code></td>
<td>刷新月度汇总物化视图。自动处理首次初始化(非并发),后续刷新用 <code>CONCURRENTLY</code> 不阻塞查询。</td>
</tr>
</tbody>
</table></div>
<h3 style="margin:24px 0 12px;font-size:16px">分区生命周期</h3>
<div class="mermaid">
flowchart LR
subgraph P1 ["阶段一:预创建(pg_cron 自动执行)"]
A1["pg_cron 定时调度<br/>每月25号 03:00"] --> A2["run_electricity_partition_maintenance(3)"]
A2 --> A3{"分区是否<br/>已存在?"}
A3 --"不存在"--> A4["CREATE TABLE ... PARTITION OF"]
A3 --"已存在"--> A5["跳过"]
end
subgraph P2 ["阶段二:写入数据"]
B1["ICC 数据拉取<br/>服务写入数据"] --> B2["ensure_electricity_partition<br/>(collect_time)"]
B2 --> B3{"分区是否<br/>已存在?"}
B3 --"不存在"--> B4["自动创建分区"]
B3 --"已存在"--> B5["直接写入"]
B4 --> B5
end
subgraph P3 ["阶段三:归档"]
C1["超过 24 个月的<br/>分区"] --> C2["DETACH PARTITION<br/>从父表分离"]
C2 --> C3["冷数据存档<br/>或直接查询子表"]
C3 --> C4["如需分析<br/>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
</div>
<h3 style="margin:24px 0 12px;font-size:16px">双重保障机制</h3>
<div class="table-wrap" style="max-height:none"><table>
<thead><tr><th>保障层</th><th>触发源</th><th>调用函数</th><th>频率</th><th>角色</th></tr></thead>
<tbody>
<tr>
<td>第一层:定时预创建</td>
<td><strong>pg_cron</strong>(数据库自治)</td>
<td><code>run_electricity_partition_maintenance(3)</code></td>
<td>每月 25 号 03:00</td>
<td>主动保障 — 提前创建未来 3 个月分区</td>
</tr>
<tr>
<td>第一层:物化视图刷新</td>
<td><strong>pg_cron</strong>(数据库自治)</td>
<td><code>refresh_electricity_monthly()</code></td>
<td>每月 1 号 02:00</td>
<td>月度汇总数据刷新</td>
</tr>
<tr>
<td>第二层:写入兜底</td>
<td>Midway.js(应用层)</td>
<td><code>ensure_electricity_partition(collect_time)</code></td>
<td>每次 ICC 拉取批次</td>
<td>被动兜底 — 万一分区不存在时写入前自动创建</td>
</tr>
</tbody>
</table></div>
<div class="callout">
<h4>pg_cron 定时任务配置</h4>
<p>两个定时任务已在 <code>db_init.sql</code> 中通过 <code>cron.schedule()</code> 自动注册,数据库重启后任务仍然有效:</p>
<p><code>-- 每月25号凌晨3点:预创建未来3个月分区</code><br>
<code>SELECT cron.schedule('electricity_partition_maintenance', '0 3 25 * *', 'SELECT run_electricity_partition_maintenance(3)');</code><br><br>
<code>-- 每月1号凌晨2点:刷新物化视图</code><br>
<code>SELECT cron.schedule('electricity_monthly_refresh', '0 2 1 * *', 'SELECT refresh_electricity_monthly()');</code></p>
</div>
<h3 style="margin:24px 0 12px;font-size:16px">Midway.js 应用层兜底示例</h3>
<p style="font-size:13.5px;color:var(--muted);margin-bottom:12px">pg_cron 负责定时预创建,后端无需配置 @Cron。但 ICC 数据拉取服务在写入前仍建议调用 <code>ensure_electricity_partition()</code> 做兜底:</p>
<pre style="background:#1e293b;color:#e2e8f0;border-radius:12px;padding:20px;overflow-x:auto;font-size:13px;line-height:1.6;margin:14px 0"><code><span style="color:#94a3b8">// ICC 数据写入前兜底(在 ICC 同步服务中)</span>
<span style="color:#7dd3fc">async</span> <span style="color:#fbbf24">saveElectricityData</span>(items: ElectricityData[]) {
<span style="color:#7dd3fc">for</span> (<span style="color:#7dd3fc">const</span> item <span style="color:#7dd3fc">of</span> items) {
<span style="color:#94a3b8">// 写入前确保分区存在(99.9%的情况下什么都不做直接返回)</span>
<span style="color:#7dd3fc">await</span> <span style="color:#7dd3fc">this</span>.entityManager.query(
<span style="color:#86efac">'SELECT ensure_electricity_partition($1)'</span>,
[item.collectTime]
);
}
<span style="color:#94a3b8">// 批量写入</span>
<span style="color:#7dd3fc">await</span> <span style="color:#7dd3fc">this</span>.electricityRepo.save(items);
}</code></pre>
<h3 style="margin:24px 0 12px;font-size:16px">月度汇总物化视图</h3>
<p style="font-size:13.5px;color:var(--muted);margin-bottom:12px">物化视图 <code>mv_electricity_monthly</code> 按客户 + 线路 + 月份预聚合用电数据,用于历史数据分析和月报生成。每月初刷新一次,查询走预聚合数据,极快。</p>
<div class="table-wrap" style="max-height:none"><table>
<thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead>
<tbody>
<tr><td><code>customer_id</code></td><td>BIGINT</td><td>客户 ID(逻辑隔离键)</td></tr>
<tr><td><code>line_id</code></td><td>BIGINT</td><td>线路 ID</td></tr>
<tr><td><code>month</code></td><td>TEXT</td><td>月份(YYYY-MM 格式)</td></tr>
<tr><td><code>total_usage</code></td><td>NUMERIC</td><td>月度总用电量</td></tr>
<tr><td><code>avg_usage</code></td><td>NUMERIC</td><td>平均用电量</td></tr>
<tr><td><code>peak_usage</code></td><td>NUMERIC</td><td>峰值用电量</td></tr>
<tr><td><code>min_usage</code></td><td>NUMERIC</td><td>最低用电量</td></tr>
<tr><td><code>record_count</code></td><td>BIGINT</td><td>采集记录数</td></tr>
<tr><td><code>first_collect</code></td><td>TIMESTAMPTZ</td><td>最早采集时间</td></tr>
<tr><td><code>last_collect</code></td><td>TIMESTAMPTZ</td><td>最晚采集时间</td></tr>
</tbody>
</table></div>
<div class="callout">
<h4>刷新策略</h4>
<p><strong>首次初始化</strong>:脚本执行时自动 <code>REFRESH MATERIALIZED VIEW</code>(非并发模式)。<strong>后续刷新</strong>:通过 <code>refresh_electricity_monthly()</code> 函数,使用 <code>CONCURRENTLY</code> 不阻塞查询,函数内部自动处理异常回退。</p>
</div>
<h3 style="margin:24px 0 12px;font-size:16px">历史分区归档策略</h3>
<div class="table-wrap" style="max-height:none"><table>
<thead><tr><th>分区年龄</th><th>操作</th><th>原因</th></tr></thead>
<tbody>
<tr><td>0 ~ 12 个月</td><td>保持在父表上</td><td>热数据,查询频繁</td></tr>
<tr><td>12 ~ 24 个月</td><td>保持在父表上</td><td>温数据,偶尔查询</td></tr>
<tr><td>超过 24 个月</td><td><code>DETACH PARTITION</code> 分离</td><td>冷数据,减少父表子分区数量,加速分区裁剪</td></tr>
<tr><td>需要分析冷数据</td><td>直接查子表 或 <code>ATTACH</code> 临时挂回</td><td>按需分析,分析完再 DETACH</td></tr>
<tr><td>确定不再需要</td><td><code>DROP TABLE</code></td><td>释放磁盘空间(需确认)</td></tr>
</tbody>
</table></div>
</section>
<footer>
<p>鑫潼智电系统 PostgreSQL 数据库设计文档 · 基于《需求分析报告 V1.0》 · 39 张表 · 3 个分区管理函数 · 1 个物化视图 · pg_cron 自动调度 · 2026-08</p>
</footer>
</div>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true, theme: 'default', securityLevel: 'loose',
themeVariables: {
primaryColor: '#e8f1ff', primaryTextColor: '#0f1e2e', primaryBorderColor: '#1d6fff',
lineColor: '#94a3b8', fontSize: '13px',
fontFamily: 'PingFang SC, Microsoft YaHei, sans-serif'
},
er: { useMaxWidth: true }
});
</script>
</body>
</html>