1. 新增青色色系变量与对应的样式类 2. 调整图例顺序与文案,拆分运营相关端 3. 重构客户端层描述,从四端改为五端入口 4. 更新API路由分组,新增/ops路由 5. 补充对象存储为RustFS并更新说明 6. 新增运营管理APP模块与权限说明 7. 更新权限设计、权限流转与角色矩阵内容 8. 修正多处文案描述与功能细节
890 lines
61 KiB
HTML
890 lines
61 KiB
HTML
<!-- 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>鑫潼智电系统 · 完整架构设计</title>
|
||
<style>
|
||
@font-face { font-family:'InstrumentSans'; src:url('./_shared/fonts/InstrumentSans-Regular.ttf') format('truetype'); font-weight:400; font-display:swap; }
|
||
@font-face { font-family:'InstrumentSans'; src:url('./_shared/fonts/InstrumentSans-Bold.ttf') format('truetype'); font-weight:700; font-display:swap; }
|
||
@font-face { font-family:'JetBrainsMono'; src:url('./_shared/fonts/JetBrainsMono-Regular.ttf') format('truetype'); font-weight:400; font-display:swap; }
|
||
@font-face { font-family:'JetBrainsMono'; src:url('./_shared/fonts/JetBrainsMono-Bold.ttf') format('truetype'); font-weight:700; font-display:swap; }
|
||
|
||
: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;
|
||
/* block diagram palette */
|
||
--c-blue:#1d6fff; --c-blue-bg:#e8f1ff; --c-blue-d:#0c4dd1;
|
||
--c-green:#0d9488; --c-green-bg:#e6f7f5; --c-green-d:#0a7068;
|
||
--c-purple:#7c3aed; --c-purple-bg:#f0eaff; --c-purple-d:#5b21b6;
|
||
--c-teal:#0f766e; --c-teal-bg:#ccfbf1; --c-teal-d:#0d9488;
|
||
--c-amber:#e0852b; --c-amber-bg:#fef3e2; --c-amber-d:#b5681a;
|
||
--c-slate:#475569; --c-slate-bg:#f1f5f9; --c-slate-d:#334155;
|
||
--c-red:#dc2626; --c-red-bg:#fee2e2;
|
||
}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
html{scroll-behavior:smooth}
|
||
body{
|
||
font-family:'InstrumentSans','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%),
|
||
radial-gradient(700px 500px at 50% 100%,rgba(124,58,237,.05),transparent 60%);
|
||
}
|
||
.wrap{max-width:1200px;margin:0 auto;padding:0 24px}
|
||
|
||
/* ===== HERO ===== */
|
||
.hero{padding:56px 0 32px}
|
||
.hero .tag{display:inline-flex;align-items:center;gap:8px;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:16px}
|
||
.hero h1{font-size:36px;font-weight:700;letter-spacing:-.01em;line-height:1.2;margin-bottom:12px;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:740px}
|
||
.hero .meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:22px}
|
||
.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 ===== */
|
||
section{padding:40px 0}
|
||
.section-head{display:flex;align-items:baseline;gap:14px;margin-bottom:24px}
|
||
.section-num{font-family:'JetBrainsMono',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}
|
||
.section-head h2{font-size:23px;font-weight:700;letter-spacing:-.01em}
|
||
.section-head .desc{font-size:13px;color:var(--muted);margin-left:auto}
|
||
|
||
/* ===== DG: DIAGRAM BLOCK OVERVIEW ===== */
|
||
.dg-legend{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-bottom:20px}
|
||
.dg-legend .li{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);background:var(--bg2);border:1px solid var(--rule);padding:4px 11px;border-radius:8px}
|
||
.dg-legend .lc{width:11px;height:11px;border-radius:3px}
|
||
|
||
.dg-diagram{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow-lg);overflow-x:auto}
|
||
.dg-layer{margin-bottom:10px}
|
||
.dg-layer-label{display:flex;align-items:center;gap:8px;margin-bottom:8px}
|
||
.dg-ll-tag{font-size:11px;font-weight:700;color:#fff;padding:2px 9px;border-radius:5px;letter-spacing:.05em;flex-shrink:0}
|
||
.dg-ll-name{font-size:14px;font-weight:700}
|
||
.dg-ll-desc{font-size:12px;color:var(--muted);margin-left:auto}
|
||
|
||
.dg-conn{text-align:center;color:var(--rule);height:24px;display:flex;justify-content:center;align-items:center}
|
||
|
||
.dg-blocks{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
|
||
.dg-block{flex:1;min-width:145px;max-width:225px;border-radius:10px;padding:11px 13px;border:1.5px solid;transition:transform .12s}
|
||
.dg-block:hover{transform:translateY(-2px);box-shadow:var(--shadow-lg)}
|
||
.dg-block .dh{display:flex;align-items:center;gap:7px;margin-bottom:5px}
|
||
.dg-block .di{width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#fff;flex-shrink:0}
|
||
.dg-block .dt{font-size:13.5px;font-weight:700;line-height:1.2}
|
||
.dg-block .dx{font-size:11px;font-weight:600;margin-bottom:3px;opacity:.85}
|
||
.dg-block ul{list-style:none;font-size:11.5px;color:var(--muted);line-height:1.55}
|
||
.dg-block ul li::before{content:"·";font-weight:700;margin-right:4px}
|
||
|
||
.dg-blue{border-color:var(--c-blue);background:var(--c-blue-bg)} .dg-blue .di{background:var(--c-blue)} .dg-blue .dx{color:var(--c-blue-d)} .dg-blue .dt{color:var(--c-blue-d)}
|
||
.dg-purple{border-color:var(--c-purple);background:var(--c-purple-bg)} .dg-purple .di{background:var(--c-purple)} .dg-purple .dx{color:var(--c-purple-d)} .dg-purple .dt{color:var(--c-purple-d)}
|
||
.dg-teal{border-color:var(--c-teal);background:var(--c-teal-bg)} .dg-teal .di{background:var(--c-teal)} .dg-teal .dx{color:var(--c-teal-d)} .dg-teal .dt{color:var(--c-teal-d)}
|
||
.dg-green{border-color:var(--c-green);background:var(--c-green-bg)} .dg-green .di{background:var(--c-green)} .dg-green .dx{color:var(--c-green-d)} .dg-green .dt{color:var(--c-green-d)}
|
||
.dg-amber{border-color:var(--c-amber);background:var(--c-amber-bg)} .dg-amber .di{background:var(--c-amber)} .dg-amber .dx{color:var(--c-amber-d)} .dg-amber .dt{color:var(--c-amber-d)}
|
||
.dg-slate{border-color:var(--c-slate);background:var(--c-slate-bg)} .dg-slate .di{background:var(--c-slate)} .dg-slate .dx{color:var(--c-slate-d)} .dg-slate .dt{color:var(--c-slate-d)}
|
||
.dg-ext{border-style:dashed;border-width:2px}
|
||
|
||
.dg-gateway{display:flex;align-items:stretch;border-radius:10px;overflow:hidden;border:1.5px solid var(--c-purple)}
|
||
.dg-gateway .gi{flex:1;padding:9px 10px;text-align:center;background:var(--c-purple-bg);border-right:1px solid rgba(124,58,237,.15)}
|
||
.dg-gateway .gi:last-child{border:none}
|
||
.dg-gateway .gi h4{font-size:12.5px;font-weight:700;color:var(--c-purple-d);margin-bottom:1px}
|
||
.dg-gateway .gi p{font-size:10.5px;color:var(--muted);line-height:1.4}
|
||
|
||
.dg-backend{display:grid;grid-template-columns:repeat(5,1fr);gap:7px}
|
||
.dg-be{border-radius:8px;padding:9px 7px;text-align:center;border:1.5px solid var(--c-green);background:var(--c-green-bg);transition:transform .12s}
|
||
.dg-be:hover{transform:translateY(-2px)}
|
||
.dg-be .bi{font-size:17px;margin-bottom:3px}
|
||
.dg-be h4{font-size:11.5px;font-weight:700;line-height:1.2;margin-bottom:2px;color:var(--c-green-d)}
|
||
.dg-be p{font-size:10px;color:var(--muted);line-height:1.3}
|
||
|
||
.dg-data{display:grid;grid-template-columns:repeat(4,1fr);gap:9px}
|
||
.dg-db{border-radius:10px;padding:11px;border:1.5px solid;text-align:center}
|
||
.dg-db .dmi{font-size:20px;margin-bottom:3px}
|
||
.dg-db h4{font-size:12.5px;font-weight:700;margin-bottom:2px}
|
||
.dg-db p{font-size:10.5px;color:var(--muted);line-height:1.4}
|
||
.dg-db.d-amber{border-color:var(--c-amber);background:var(--c-amber-bg)} .dg-db.d-amber h4{color:var(--c-amber-d)}
|
||
.dg-db.d-red{border-color:var(--c-red);background:var(--c-red-bg)} .dg-db.d-red h4{color:var(--c-red)}
|
||
.dg-db.d-blue{border-color:var(--c-blue);background:var(--c-blue-bg)} .dg-db.d-blue h4{color:var(--c-blue-d)}
|
||
.dg-db.d-green{border-color:var(--c-green);background:var(--c-green-bg)} .dg-db.d-green h4{color:var(--c-green-d)}
|
||
|
||
.dg-perm{margin-top:18px;background:var(--c-red-bg);border:1.5px solid var(--c-red);border-radius:10px;padding:13px 16px}
|
||
.dg-perm h4{font-size:14px;font-weight:700;color:var(--c-red);margin-bottom:8px}
|
||
.dg-perm .pr{display:flex;gap:12px;flex-wrap:wrap}
|
||
.dg-perm .pi{flex:1;min-width:180px;background:var(--bg2);border-radius:8px;padding:9px 11px;border:1px solid rgba(220,38,38,.15)}
|
||
.dg-perm .pi .pt{font-size:12px;font-weight:700;color:var(--ink);margin-bottom:2px}
|
||
.dg-perm .pi .pd{font-size:11px;color:var(--muted)}
|
||
|
||
/* ===== DETAILED: LAYERED ARCH ===== */
|
||
.arch-stack{display:flex;flex-direction:column;gap:12px}
|
||
.alayer{position:relative;background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:16px 18px;box-shadow:var(--shadow)}
|
||
.alayer-head{display:flex;align-items:center;gap:12px;margin-bottom:12px}
|
||
.alayer-tag{font-family:'JetBrainsMono',monospace;font-size:11px;font-weight:700;color:#fff;padding:3px 9px;border-radius:5px;letter-spacing:.05em}
|
||
.alayer-name{font-size:15px;font-weight:700}
|
||
.alayer-note{font-size:12px;color:var(--muted);margin-left:auto}
|
||
.alayer-body{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
|
||
.anode{border:1px solid var(--rule);border-radius:10px;padding:11px 13px;background:linear-gradient(180deg,#fff,rgba(255,255,255,.6));transition:transform .15s,box-shadow .15s}
|
||
.anode:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.06)}
|
||
.anode h4{font-size:13.5px;font-weight:700;margin-bottom:3px;display:flex;align-items:center;gap:6px}
|
||
.anode h4 .dot{width:7px;height:7px;border-radius:50%;display:inline-block}
|
||
.anode p{font-size:12px;color:var(--muted);line-height:1.5}
|
||
.anode .tech{font-family:'JetBrainsMono',monospace;font-size:11px;color:var(--accent);margin-top:5px;display:block}
|
||
.alayer.client .alayer-tag{background:linear-gradient(135deg,#1d6fff,#3b82f6)} .alayer.client .anode h4 .dot{background:#1d6fff}
|
||
.alayer.gw .alayer-tag{background:linear-gradient(135deg,#7c3aed,#8b5cf6)} .alayer.gw .anode h4 .dot{background:#7c3aed}
|
||
.alayer.svc .alayer-tag{background:linear-gradient(135deg,#0d9488,#14b8a6)} .alayer.svc .anode h4 .dot{background:#0d9488}
|
||
.alayer.data .alayer-tag{background:linear-gradient(135deg,#e0852b,#f59e0b)} .alayer.data .anode h4 .dot{background:#e0852b}
|
||
.alayer.ext .alayer-tag{background:linear-gradient(135deg,#475569,#64748b)} .alayer.ext .anode h4 .dot{background:#64748b}
|
||
.flow-arrow{text-align:center;color:var(--muted);font-size:16px;line-height:1;margin:-3px 0}
|
||
|
||
/* ===== MODULE CARDS ===== */
|
||
.client-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
||
.client-card{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow)}
|
||
.client-card.full{grid-column:1/-1}
|
||
.cc-head{padding:14px 18px;color:#fff;display:flex;align-items:center;gap:12px}
|
||
.cc-head .icon{width:32px;height:32px;border-radius:8px;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:700}
|
||
.cc-head h3{font-size:16px;font-weight:700}
|
||
.cc-head .role{font-size:11.5px;opacity:.85;margin-left:auto;background:rgba(255,255,255,.15);padding:3px 10px;border-radius:999px}
|
||
.cc-blue .cc-head{background:linear-gradient(135deg,#1d6fff,#2563eb)}
|
||
.cc-green .cc-head{background:linear-gradient(135deg,#0d9488,#14b8a6)}
|
||
.cc-purple .cc-head{background:linear-gradient(135deg,#7c3aed,#8b5cf6)}
|
||
.cc-amber .cc-head{background:linear-gradient(135deg,#e0852b,#f59e0b)}
|
||
.cc-slate .cc-head{background:linear-gradient(135deg,#475569,#64748b)}
|
||
.cc-body{padding:7px 7px 11px}
|
||
.mod-list{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding:5px}
|
||
.mod{background:rgba(0,0,0,.02);border:1px solid var(--rule);border-radius:8px;padding:9px 11px}
|
||
.mod h4{font-size:12.5px;font-weight:700;margin-bottom:2px}
|
||
.mod p{font-size:11px;color:var(--muted);line-height:1.45}
|
||
|
||
/* ===== TABLE ===== */
|
||
.table-wrap{overflow-x:auto;max-height:560px;overflow-y:auto;border:1px solid var(--rule);border-radius:var(--radius);background:var(--bg2)}
|
||
table{width:100%;border-collapse:collapse;font-size:13px}
|
||
thead th{position:sticky;top:0;background:#f1f5fb;color:var(--ink);font-weight:700;text-align:left;padding:9px 13px;border-bottom:2px solid var(--rule);z-index:1}
|
||
tbody td{padding:8px 13px;border-bottom:1px solid var(--rule);vertical-align:top}
|
||
tbody tr:hover{background:rgba(29,111,255,.03)}
|
||
tbody td code{font-family:'JetBrainsMono',monospace;font-size:12px;color:var(--accent);background:rgba(29,111,255,.06);padding:1px 5px;border-radius:4px}
|
||
.pill{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:999px}
|
||
.pill-yes{background:rgba(13,148,136,.12);color:#0d9488}
|
||
.pill-no{background:rgba(239,68,68,.1);color:#dc2626}
|
||
|
||
/* ===== CALLOUT ===== */
|
||
.callout{background:var(--bg2);border:1px solid var(--rule);border-left:4px solid var(--accent);border-radius:0 var(--radius) var(--radius) 0;padding:15px 18px;margin:16px 0;box-shadow:var(--shadow)}
|
||
.callout.warn{border-left-color:var(--warn)}
|
||
.callout h4{font-size:14px;font-weight:700;margin-bottom:5px}
|
||
.callout p{font-size:13.5px;color:var(--muted)}
|
||
.callout p strong{color:var(--ink)}
|
||
|
||
/* ===== DB COMPARISON ===== */
|
||
.db-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:16px 0}
|
||
.db-card{background:var(--bg2);border:2px solid var(--rule);border-radius:var(--radius);padding:18px;box-shadow:var(--shadow);position:relative}
|
||
.db-card.rec{border-color:var(--accent2);background:linear-gradient(180deg,rgba(13,148,136,.04),#fff)}
|
||
.db-card .badge{position:absolute;top:-11px;right:14px;font-size:11px;font-weight:700;background:var(--accent2);color:#fff;padding:3px 10px;border-radius:999px}
|
||
.db-card h3{font-size:17px;font-weight:700;margin-bottom:3px}
|
||
.db-card .ver{font-family:'JetBrainsMono',monospace;font-size:12px;color:var(--muted);margin-bottom:10px}
|
||
.db-card ul{list-style:none;padding:0}
|
||
.db-card li{font-size:12.5px;padding:4px 0;border-bottom:1px dashed var(--rule);display:flex;gap:8px}
|
||
.db-card li:last-child{border:none}
|
||
.db-card li .ico{flex-shrink:0;font-weight:700}
|
||
.db-card.rec li .ico{color:var(--accent2)} .db-card.alt li .ico{color:var(--muted)}
|
||
|
||
/* ===== MERMAID ===== */
|
||
.mermaid{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:22px;text-align:center;margin:12px 0;box-shadow:var(--shadow)}
|
||
|
||
/* ===== PERMISSION FLOW ===== */
|
||
.perm-flow{display:flex;align-items:stretch;gap:0;margin:16px 0;flex-wrap:wrap}
|
||
.perm-step{flex:1;min-width:170px;background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:13px;margin:0 5px;box-shadow:var(--shadow)}
|
||
.perm-step .num{font-family:'JetBrainsMono',monospace;font-size:11px;font-weight:700;color:var(--accent);background:rgba(29,111,255,.08);padding:2px 7px;border-radius:5px;display:inline-block;margin-bottom:7px}
|
||
.perm-step h4{font-size:13.5px;font-weight:700;margin-bottom:3px}
|
||
.perm-step p{font-size:12px;color:var(--muted)}
|
||
.perm-arrow{display:flex;align-items:center;color:var(--accent);font-size:18px;font-weight:700;padding:0 2px}
|
||
|
||
/* ===== ISOLATION ===== */
|
||
.iso-vis{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:16px 0}
|
||
.iso-box{background:var(--bg2);border:1px solid var(--rule);border-radius:var(--radius);padding:16px;box-shadow:var(--shadow)}
|
||
.iso-box h4{font-size:14.5px;font-weight:700;margin-bottom:8px;display:flex;align-items:center;gap:8px}
|
||
.iso-box h4 .tg{font-size:11px;font-weight:700;padding:2px 7px;border-radius:5px}
|
||
.iso-box .rows{display:flex;flex-direction:column;gap:5px}
|
||
.iso-row{display:flex;align-items:center;gap:8px;font-family:'JetBrainsMono',monospace;font-size:11.5px;padding:6px 10px;border-radius:6px;background:rgba(0,0,0,.02);border:1px solid var(--rule)}
|
||
.iso-row .cid{font-weight:700;color:var(--accent)}
|
||
.iso-box.business .tg{background:rgba(29,111,255,.12);color:var(--accent)}
|
||
.iso-box.timeseries .tg{background:rgba(13,148,136,.12);color:var(--accent2)}
|
||
|
||
/* ===== FOOTER ===== */
|
||
footer{margin-top:36px;padding:24px 0 44px;border-top:1px solid var(--rule)}
|
||
footer .ft{font-size:13px;color:var(--muted);text-align:center}
|
||
|
||
/* ===== RESPONSIVE ===== */
|
||
@media(max-width:860px){
|
||
.alayer-body{grid-template-columns:1fr 1fr}
|
||
.client-grid,.db-grid,.iso-vis{grid-template-columns:1fr}
|
||
.perm-flow{flex-direction:column} .perm-arrow{transform:rotate(90deg);justify-content:center;padding:4px 0}
|
||
.dg-backend{grid-template-columns:repeat(3,1fr)} .dg-data{grid-template-columns:1fr 1fr}
|
||
.hero h1{font-size:27px}
|
||
}
|
||
@media(max-width:520px){
|
||
.alayer-body,.mod-list,.dg-backend,.dg-data{grid-template-columns:1fr}
|
||
.dg-block{max-width:none;flex:1 1 100%}
|
||
.dg-gateway{flex-direction:column}
|
||
.wrap{padding:0 14px}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<!-- ===== HERO ===== -->
|
||
<header class="hero">
|
||
<span class="tag">SYSTEM ARCHITECTURE · V1.0</span>
|
||
<h1>鑫潼智电系统 · 实现架构设计</h1>
|
||
<p class="sub">基于《鑫潼智电系统需求分析报告 V1.0》,按功能模块拆解为后端、前端、小程序、APP 的完整系统实现架构。覆盖 ICC 平台 API 对接、数据隔离、权限控制等关键设计决策。</p>
|
||
<div class="meta">
|
||
<span>运营主体:<b>鑫潼科技(单一运营方)</b></span>
|
||
<span>后端:<b>Midway.js + TypeORM</b></span>
|
||
<span>前端:<b>Vue3 + Ant Design Vue</b></span>
|
||
<span>APP/小程序:<b>uni-app</b></span>
|
||
<span>数据库:<b>PostgreSQL</b></span>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ===== 01. 架构总览框图 ===== -->
|
||
<section id="overview-diagram">
|
||
<div class="section-head">
|
||
<span class="section-num">01</span>
|
||
<h2>架构总览框图</h2>
|
||
<span class="desc">五层架构 · 一图全局</span>
|
||
</div>
|
||
|
||
<div class="dg-legend">
|
||
<div class="li"><span class="lc" style="background:var(--c-blue)"></span>运营管理平台 Web</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-purple)"></span>运营管理 APP(业务员)</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-green)"></span>共享电工 APP</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-amber)"></span>客户微信小程序</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-slate)"></span>大华 ICC 外部</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-teal, #0f766e)"></span>后端服务 Midway</div>
|
||
<div class="li"><span class="lc" style="background:var(--c-red)"></span>权限控制</div>
|
||
</div>
|
||
|
||
<div class="dg-diagram">
|
||
|
||
<!-- L1 Client -->
|
||
<div class="dg-layer">
|
||
<div class="dg-layer-label">
|
||
<span class="dg-ll-tag" style="background:var(--c-blue)">L1</span>
|
||
<span class="dg-ll-name">客户端层 — 五端入口</span>
|
||
<span class="dg-ll-desc">不同角色访问不同端,运营方双端(Web + APP)</span>
|
||
</div>
|
||
<div class="dg-blocks">
|
||
<div class="dg-block dg-blue">
|
||
<div class="dh"><div class="di">PC</div><div><div class="dt">运营管理平台</div><div class="dx">Vue3 + Ant Design Vue</div></div></div>
|
||
<ul><li>用户:运营管理员</li><li>审批/配置/报表/系统设置</li><li>全量数据查看与管理</li><li>RBAC 菜单级权限</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-purple">
|
||
<div class="dh"><div class="di">APP</div><div><div class="dt">运营管理 APP</div><div class="dx">uni-app → iOS / Android</div></div></div>
|
||
<ul><li>用户:业务员(运营方)</li><li>客户管理 / 项目跟进</li><li>勘察/回访/现场巡查</li><li>共享 sys_user 表 + 角色区分</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-teal">
|
||
<div class="dh"><div class="di">APP</div><div><div class="dt">共享电工 APP</div><div class="dx">uni-app → iOS / Android</div></div></div>
|
||
<ul><li>用户:共享电工</li><li>五类派单接单处理</li><li>现场水印拍照取证上传</li><li>领料管理 / 报酬查询</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-amber">
|
||
<div class="dh"><div class="di">WX</div><div><div class="dt">客户微信小程序</div><div class="dx">uni-app → 微信小程序</div></div></div>
|
||
<ul><li>用户:客户(学校/医院)</li><li>设备状态 / 用电统计查看</li><li>报警信息 / 月度报告下载</li><li>水电报修 / 服务评分</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-slate dg-ext">
|
||
<div class="dh"><div class="di">ICC</div><div><div class="dt">大华 ICC 平台</div><div class="dx">外部系统 · API 对接</div></div></div>
|
||
<ul><li>设备数据采集平台(厂家)</li><li>网关/探测器设备管理</li><li>设备运行状态 / 报警</li><li>用电采集数据</li></ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dg-conn">▼</div>
|
||
|
||
<!-- L2 Gateway -->
|
||
<div class="dg-layer">
|
||
<div class="dg-layer-label">
|
||
<span class="dg-ll-tag" style="background:var(--c-purple)">L2</span>
|
||
<span class="dg-ll-name">接入网关层 — 统一入口</span>
|
||
<span class="dg-ll-desc">认证 · 路由 · 限流 · 数据权限拦截</span>
|
||
</div>
|
||
<div class="dg-gateway">
|
||
<div class="gi"><h4>统一鉴权</h4><p>JWT 双 Token<br/>多端统一登录态</p></div>
|
||
<div class="gi"><h4>API 路由分发</h4><p>/admin · /ops · /worker<br/>/customer 分组路由</p></div>
|
||
<div class="gi"><h4>接口数据权限</h4><p>Interceptor 注入过滤<br/>给什么数据看什么</p></div>
|
||
<div class="gi"><h4>限流与日志</h4><p>rate-limiter<br/>操作审计 winston</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dg-conn">▼</div>
|
||
|
||
<!-- L3 Backend -->
|
||
<div class="dg-layer">
|
||
<div class="dg-layer-label">
|
||
<span class="dg-ll-tag" style="background:var(--c-green)">L3</span>
|
||
<span class="dg-ll-name">业务服务层 — Midway.js(Node.js + TypeScript + TypeORM)</span>
|
||
<span class="dg-ll-desc">10 个核心服务模块</span>
|
||
</div>
|
||
<div class="dg-backend">
|
||
<div class="dg-be"><div class="bi">👥</div><h4>客户管理</h4><p>客户/部门<br/>建筑/房间<br/>账号分配</p></div>
|
||
<div class="dg-be"><div class="bi">📋</div><h4>项目管理</h4><p>勘察/方案<br/>合同/安装<br/>验收/回访</p></div>
|
||
<div class="dg-be"><div class="bi">📡</div><h4>设备管理</h4><p>ICC 设备同步<br/>线路分配<br/>部门/房间映射</p></div>
|
||
<div class="dg-be"><div class="bi">📮</div><h4>派单管理</h4><p>勘察/安装<br/>报警/报修/维保<br/>全生命周期</p></div>
|
||
<div class="dg-be"><div class="bi">🔄</div><h4>ICC 数据采集</h4><p>定时拉取<br/>队列缓冲<br/>清洗映射</p></div>
|
||
<div class="dg-be"><div class="bi">📊</div><h4>统计报表</h4><p>多维用电统计<br/>月度报告生成<br/>报酬计算</p></div>
|
||
<div class="dg-be"><div class="bi">📸</div><h4>取证文件</h4><p>水印拍照取证<br/>合同/验收存档<br/>月报文件</p></div>
|
||
<div class="dg-be"><div class="bi">🔔</div><h4>消息通知</h4><p>APP 推送<br/>微信订阅消息<br/>短信(按需)</p></div>
|
||
<div class="dg-be"><div class="bi">⚙️</div><h4>系统管理</h4><p>用户/角色/菜单<br/>数据字典<br/>日志审计</p></div>
|
||
<div class="dg-be"><div class="bi">🔐</div><h4>认证授权</h4><p>JWT 签发校验<br/>微信 openid 登录<br/>RBAC 权限</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dg-conn">▼</div>
|
||
|
||
<!-- L4 Data -->
|
||
<div class="dg-layer">
|
||
<div class="dg-layer-label">
|
||
<span class="dg-ll-tag" style="background:var(--c-amber)">L4</span>
|
||
<span class="dg-ll-name">数据层 — 存储与缓存</span>
|
||
<span class="dg-ll-desc">逻辑隔离 + 时序分区 · 不做物理分库</span>
|
||
</div>
|
||
<div class="dg-data">
|
||
<div class="dg-db d-amber"><div class="dmi">🐘</div><h4>PostgreSQL 主库</h4><p>业务数据(customer_id 逻辑隔离)<br/>用电采集数据(按月分区)<br/>TypeORM + 声明式分区</p></div>
|
||
<div class="dg-db d-red"><div class="dmi">⚡</div><h4>Redis 缓存</h4><p>JWT 会话 Token<br/>数据字典/热点配置<br/>BullMQ 队列底层</p></div>
|
||
<div class="dg-db d-blue"><div class="dmi">📁</div><h4>对象存储 RustFS</h4><p>取证照片(水印)<br/>合同/验收/方案文件<br/>月度报告文档<br/>国产 · S3 兼容 · Apache 2.0</p></div>
|
||
<div class="dg-db d-green"><div class="dmi">📬</div><h4>BullMQ 消息队列</h4><p>ICC 拉取数据缓冲<br/>报警事件异步处理<br/>基于 Redis 轻量级</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dg-conn">▼</div>
|
||
|
||
<!-- L5 External -->
|
||
<div class="dg-layer">
|
||
<div class="dg-layer-label">
|
||
<span class="dg-ll-tag" style="background:var(--c-slate)">L5</span>
|
||
<span class="dg-ll-name">外部系统对接层</span>
|
||
<span class="dg-ll-desc">仅 API 对接 · 不直接操作硬件</span>
|
||
</div>
|
||
<div class="dg-blocks">
|
||
<div class="dg-block dg-slate dg-ext" style="max-width:380px;flex:2">
|
||
<div class="dh"><div class="di">ICC</div><div><div class="dt">大华 ICC OpenAPI</div><div class="dx">HTTP REST · 主动拉取</div></div></div>
|
||
<ul><li>客户信息接口 → 每小时/事件触发</li><li>设备信息接口(网关/探测器)→ 每小时</li><li>用电采集数据接口 → 5~15 分钟</li><li>设备报警数据接口 → 1 分钟</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-green dg-ext">
|
||
<div class="dh"><div class="di">WX</div><div><div class="dt">微信开放平台</div><div class="dx">小程序登录 + 订阅消息</div></div></div>
|
||
<ul><li>openid 登录授权</li><li>订阅消息推送</li><li>客户账号绑定</li></ul>
|
||
</div>
|
||
<div class="dg-block dg-amber dg-ext">
|
||
<div class="dh"><div class="di">SMS</div><div><div class="dt">短信服务</div><div class="dx">阿里云短信(可选)</div></div></div>
|
||
<ul><li>客户初始密码通知</li><li>报警短信提醒</li></ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- Permission overlay -->
|
||
<div class="dg-perm">
|
||
<h4>🔒 权限控制方案(贯穿 L1 → L3)</h4>
|
||
<div class="pr">
|
||
<div class="pi"><div class="pt">运营管理平台(Web)— RBAC 菜单级</div><div class="pd">运营管理员:审批/配置/报表/系统设置,全量数据,全部菜单</div></div>
|
||
<div class="pi"><div class="pt">运营管理 APP — 角色 + 数据权限</div><div class="pd">业务员:客户管理/项目跟进/勘察回访,按 salesman_id 过滤自己负责的数据</div></div>
|
||
<div class="pi"><div class="pt">共享电工 APP — 接口级数据权限</div><div class="pd">接口按 worker_id 过滤:仅自己接的派单、个人报酬明细,给什么看什么</div></div>
|
||
<div class="pi"><div class="pt">客户小程序 — 接口级数据权限</div><div class="pd">接口按 customer_id 过滤:仅本客户设备/用电/报警/月报/报修记录</div></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 02. 总体分层架构(详细) ===== -->
|
||
<section id="overview">
|
||
<div class="section-head">
|
||
<span class="section-num">02</span>
|
||
<h2>总体分层架构(详细)</h2>
|
||
<span class="desc">五层架构 · 自上而下数据流转</span>
|
||
</div>
|
||
|
||
<div class="arch-stack">
|
||
|
||
<div class="alayer client">
|
||
<div class="alayer-head"><span class="alayer-tag">CLIENT</span><span class="alayer-name">客户端层 · 五端入口</span><span class="alayer-note">运营方双端(Web+APP),统一鉴权</span></div>
|
||
<div class="alayer-body">
|
||
<div class="anode"><h4><span class="dot"></span>运营管理平台(Web)</h4><p>运营管理员使用:审批、配置、报表、系统设置</p><span class="tech">Vue3 + Ant Design Vue</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>运营管理 APP</h4><p>业务员移动办公:客户管理、项目跟进、现场勘察回访</p><span class="tech">uni-app (iOS / Android)</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>共享电工 APP</h4><p>共享电工接单、现场拍照取证、报酬查询</p><span class="tech">uni-app (iOS / Android)</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>客户微信小程序</h4><p>客户查看用电/报警/月报、报修申请、评分</p><span class="tech">uni-app → 微信小程序</span></div>
|
||
</div>
|
||
<div class="alayer-body" style="margin-top:10px;grid-template-columns:1fr">
|
||
<div class="anode" style="border-style:dashed"><h4><span class="dot" style="background:#64748b"></span>大华 ICC 管理平台</h4><p>设备数据采集平台(厂家后台,非自研)· API 对接</p><span class="tech">外部系统 · HTTP REST</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="flow-arrow">▼</div>
|
||
|
||
<div class="alayer gw">
|
||
<div class="alayer-head"><span class="alayer-tag">GATEWAY</span><span class="alayer-name">接入网关层 · 统一入口</span><span class="alayer-note">认证、路由、限流、日志</span></div>
|
||
<div class="alayer-body">
|
||
<div class="anode"><h4><span class="dot"></span>统一鉴权服务</h4><p>JWT Token 签发与校验,多端统一登录态</p><span class="tech">Midway Guard + JWT</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>API 路由分发</h4><p>按端区分路由前缀:/admin · /ops · /worker · /customer</p><span class="tech">Midway Controller 分组</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>接口级数据权限</h4><p>接口决定可见数据范围,APP/小程序给什么看什么</p><span class="tech">Guard + Interceptor</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>限流与日志</h4><p>常规 ERP 并发量,请求日志与操作审计</p><span class="tech">rate-limiter + winston</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="flow-arrow">▼</div>
|
||
|
||
<div class="alayer svc">
|
||
<div class="alayer-head"><span class="alayer-tag">SERVICE</span><span class="alayer-name">业务服务层 · Midway.js 核心模块</span><span class="alayer-note">按业务域划分,模块化服务</span></div>
|
||
<div class="alayer-body">
|
||
<div class="anode"><h4><span class="dot"></span>客户与项目模块</h4><p>客户/部门/建筑/房间、勘察/方案/合同/验收/回访</p><span class="tech">Customer · Project Service</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>运营派单模块</h4><p>报警派单、报修派单、维保派单、安装派单</p><span class="tech">Dispatch Service</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>设备与线路模块</h4><p>设备信息同步、线路分配、设备状态管理</p><span class="tech">Device · Line Service</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>统计与报表模块</h4><p>多维度用电统计、月度报告、共享电工报酬</p><span class="tech">Report Service</span></div>
|
||
</div>
|
||
<div class="alayer-body" style="margin-top:10px">
|
||
<div class="anode"><h4><span class="dot"></span>ICC 数据采集模块</h4><p>定时拉取设备/报警/用电数据,缓冲写入</p><span class="tech">ICC Sync Service + 定时任务</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>取证与文件模块</h4><p>现场拍照取证、合同/验收/方案文件存档</p><span class="tech">File Service + 对象存储</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>系统管理模块</h4><p>用户、角色、菜单权限(RBAC)、字典、日志</p><span class="tech">System Service</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>消息通知模块</h4><p>报警推送到 APP、派单提醒、微信消息</p><span class="tech">Notify Service</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="flow-arrow">▼</div>
|
||
|
||
<div class="alayer data">
|
||
<div class="alayer-head"><span class="alayer-tag">DATA</span><span class="alayer-name">数据层 · 存储与缓存</span><span class="alayer-note">逻辑隔离 + 时序分区,不做物理分库</span></div>
|
||
<div class="alayer-body">
|
||
<div class="anode"><h4><span class="dot"></span>PostgreSQL 主库</h4><p>业务数据(逻辑隔离)+ 用电采集数据(按月分区)</p><span class="tech">TypeORM + 声明式分区</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>Redis 缓存</h4><p>会话 Token、数据字典、热点配置、限流计数</p><span class="tech">ioredis</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>对象存储</h4><p>取证照片、合同/验收/方案电子文件、月度报告</p><span class="tech">RustFS(国产 · S3 兼容)</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>消息队列</h4><p>ICC 拉取数据缓冲、报警事件异步处理</p><span class="tech">BullMQ (Redis 队列)</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="flow-arrow">▼</div>
|
||
|
||
<div class="alayer ext">
|
||
<div class="alayer-head"><span class="alayer-tag">EXTERNAL</span><span class="alayer-name">外部系统对接层</span><span class="alayer-note">仅 API 对接,不直接操作硬件</span></div>
|
||
<div class="alayer-body">
|
||
<div class="anode"><h4><span class="dot"></span>大华 ICC OpenAPI</h4><p>设备信息、设备状态、报警数据、用电采集数据</p><span class="tech">HTTP REST · 主动拉取</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>微信开放平台</h4><p>小程序登录授权(openid)、消息订阅推送</p><span class="tech">微信登录 + 订阅消息</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>短信服务(可选)</h4><p>客户账号初始密码、报警短信通知(按需)</p><span class="tech">阿里云短信</span></div>
|
||
<div class="anode"><h4><span class="dot"></span>智电终端设备</h4><p>网关/探测器 → ICC 平台采集 → 鑫潼系统拉取</p><span class="tech">不直接对接</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<h4>架构设计要点</h4>
|
||
<p>① <strong>不直接对接硬件</strong>:所有设备数据通过大华 ICC 平台 API 拉取,鑫潼系统只做数据消费方。② <strong>五端共享一套后端</strong>:Midway.js 统一提供 /admin(Web管理台)、/ops(运营APP)、/worker(电工APP)、/customer(小程序)四组路由,避免重复开发。③ <strong>运营方双端同一套账号</strong>:运营管理平台(Web)和运营管理 APP(业务员)共用 sys_user 表,通过角色区分权限,共用 RBAC 体系。④ <strong>ICC 内部虽实时推送,但鑫潼侧采用主动拉取</strong>,通过定时任务按采集频次拉取,进入 BullMQ 队列缓冲后写入分区表。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 03. 技术栈选型 ===== -->
|
||
<section id="tech">
|
||
<div class="section-head">
|
||
<span class="section-num">03</span>
|
||
<h2>技术栈选型</h2>
|
||
<span class="desc">含数据库选型建议</span>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>层级</th><th>技术选型</th><th>版本/说明</th><th>选型理由</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>后端框架</td><td><code>Midway.js</code></td><td>Node.js · IoC + TypeORM</td><td>阿里出品,TypeScript 原生支持,装饰器风格,模块化清晰</td></tr>
|
||
<tr><td>前端框架</td><td><code>Vue 3 + Ant Design Vue</code></td><td>Composition API</td><td>AntDV 组件丰富,适合中后台 ERP 型管理系统</td></tr>
|
||
<tr><td>共享电工 APP</td><td><code>uni-app</code></td><td>跨 iOS / Android</td><td>一套代码多端发布,共享电工端仅需移动 App</td></tr>
|
||
<tr><td>运营管理 APP</td><td><code>uni-app</code></td><td>跨 iOS / Android</td><td>业务员移动办公,共用 sys_user 表,复用 uni-app 技术栈</td></tr>
|
||
<tr><td>小程序</td><td><code>uni-app → 微信小程序</code></td><td>客户端使用</td><td>复用 uni-app 技术栈,降低学习成本</td></tr>
|
||
<tr><td>数据库</td><td><code>PostgreSQL</code></td><td>15+</td><td>时序数据分区成熟、多维聚合分析强、JSONB 灵活(详见下方对比)</td></tr>
|
||
<tr><td>ORM</td><td><code>TypeORM</code></td><td>Midway 内置集成</td><td>与 Midway 深度集成,支持 PostgreSQL 分区表</td></tr>
|
||
<tr><td>缓存</td><td><code>Redis</code></td><td>7.x</td><td>会话、字典缓存、限流、BullMQ 队列底层</td></tr>
|
||
<tr><td>消息队列</td><td><code>BullMQ</code></td><td>基于 Redis</td><td>轻量级,无需额外引入 Kafka,满足常规 ERP 并发</td></tr>
|
||
<tr><td>对象存储</td><td><code>RustFS(国产)</code></td><td>S3 兼容 · Apache 2.0</td><td>取证照片、合同/验收文件、月度报告存档,替代 MinIO</td></tr>
|
||
<tr><td>鉴权</td><td><code>JWT</code></td><td>双 Token 刷新</td><td>多端统一,无状态易扩展</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<h3 style="margin:24px 0 6px;font-size:17px">数据库选型对比:PostgreSQL vs MySQL</h3>
|
||
<p style="color:var(--muted);font-size:13px;margin-bottom:12px">基于本系统的数据特征(时序用电数据 + 多维统计报表 + ICC 灵活设备数据)进行对比。</p>
|
||
|
||
<div class="db-grid">
|
||
<div class="db-card rec">
|
||
<span class="badge">推荐</span>
|
||
<h3>PostgreSQL</h3>
|
||
<div class="ver">v15+ · 开源 · 对象关系型</div>
|
||
<ul>
|
||
<li><span class="ico">✓</span>声明式分区成熟,用电采集数据按月分区查询性能优</li>
|
||
<li><span class="ico">✓</span>窗口函数/CTE/物化视图,多维统计(部门/楼栋/楼层/房间)能力强</li>
|
||
<li><span class="ico">✓</span>JSONB 类型存储 ICC 灵活设备数据,支持索引查询</li>
|
||
<li><span class="ico">✓</span>Midway + TypeORM 完整支持,迁移成本低</li>
|
||
<li><span class="ico">✓</span>行级安全(RLS)可选,未来可做更细数据隔离</li>
|
||
</ul>
|
||
</div>
|
||
<div class="db-card alt">
|
||
<h3>MySQL</h3>
|
||
<div class="ver">v8.x · 开源 · 关系型</div>
|
||
<ul>
|
||
<li><span class="ico">△</span>分区功能有但不如 PG 灵活,大表管理偏弱</li>
|
||
<li><span class="ico">△</span>聚合分析能力可用,但复杂多维统计不如 PG</li>
|
||
<li><span class="ico">△</span>JSON 类型有但查询和索引能力弱于 JSONB</li>
|
||
<li><span class="ico">✓</span>国内团队更熟悉,运维资源好找</li>
|
||
<li><span class="ico">△</span>月度报告按部门/楼栋统计时性能不如 PG</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<h4>结论:推荐 PostgreSQL</h4>
|
||
<p>本系统最核心的数据特征是<strong>用电采集数据持续增长(时序)</strong>和<strong>月度报告多维统计</strong>。PostgreSQL 的声明式分区能直接解决您担心的"数据量暴涨"问题——按月分区后,单表数据被切分为多个物理子表,查询只扫描相关分区,性能稳定。配合物化视图预聚合月度统计,即使客户和设备数量增长,报表查询依然高效。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 04. 四端功能模块拆解 ===== -->
|
||
<section id="modules">
|
||
<div class="section-head">
|
||
<span class="section-num">04</span>
|
||
<h2>五端功能模块拆解</h2>
|
||
<span class="desc">后端 · Web前端 · 运营APP · 电工APP · 小程序</span>
|
||
</div>
|
||
|
||
<div class="client-grid" style="margin-bottom:16px">
|
||
<div class="client-card full cc-green">
|
||
<div class="cc-head"><div class="icon">BE</div><h3>后端服务(Midway.js)</h3><span class="role">五端共享 · 统一 API</span></div>
|
||
<div class="cc-body"><div class="mod-list">
|
||
<div class="mod"><h4>客户管理服务</h4><p>客户信息(省市县分类)、客户部门、客户访问账号分配</p></div>
|
||
<div class="mod"><h4>项目管理服务</h4><p>建筑/房间、勘察派单、智电方案、合同、安装、验收、回访</p></div>
|
||
<div class="mod"><h4>设备管理服务</h4><p>ICC 设备信息同步、智电设备/网关/探测器、线路分配(部门/房间)</p></div>
|
||
<div class="mod"><h4>派单管理服务</h4><p>勘察/安装/报警/报修/维保五类派单全生命周期管理</p></div>
|
||
<div class="mod"><h4>ICC 数据采集服务</h4><p>定时拉取设备/报警/用电数据,队列缓冲,写入分区表</p></div>
|
||
<div class="mod"><h4>统计报表服务</h4><p>按部门/楼栋/楼层/房间维度用电统计,月度报告生成,报酬计算</p></div>
|
||
<div class="mod"><h4>取证文件服务</h4><p>现场拍照取证(水印)、合同/验收/方案/月报文件存档</p></div>
|
||
<div class="mod"><h4>消息通知服务</h4><p>APP 推送(报警/派单)、微信订阅消息、短信(按需)</p></div>
|
||
<div class="mod"><h4>系统管理服务</h4><p>用户/角色/菜单(RBAC)、数据字典、操作日志、定时任务</p></div>
|
||
<div class="mod"><h4>认证授权服务</h4><p>JWT 签发校验、微信 openid 登录、接口级数据权限拦截</p></div>
|
||
</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="client-grid">
|
||
<div class="client-card cc-blue">
|
||
<div class="cc-head"><div class="icon">PC</div><h3>运营管理平台(Web 前端)</h3><span class="role">运营管理员</span></div>
|
||
<div class="cc-body"><div class="mod-list">
|
||
<div class="mod"><h4>运营工作台</h4><p>全局数据概览、报警总览、派单总览、待办事项</p></div>
|
||
<div class="mod"><h4>审批与配置</h4><p>方案审批、合同审批、派单规则配置、数据字典</p></div>
|
||
<div class="mod"><h4>运营派单</h4><p>报警派单(从 ICC 拉取报警)、报修派单、维保派单、评分管理</p></div>
|
||
<div class="mod"><h4>设备监控</h4><p>设备列表、线路分配(部门/房间)、设备状态、报警查询</p></div>
|
||
<div class="mod"><h4>统计报表</h4><p>多维度用电统计、月度报告生成下载、共享电工报酬统计</p></div>
|
||
<div class="mod"><h4>系统管理</h4><p>用户/角色/菜单权限配置、员工管理、日志审计</p></div>
|
||
</div></div>
|
||
</div>
|
||
|
||
<div class="client-card cc-purple">
|
||
<div class="cc-head"><div class="icon">APP</div><h3>运营管理 APP(uni-app)</h3><span class="role">业务员(运营方)</span></div>
|
||
<div class="cc-body"><div class="mod-list">
|
||
<div class="mod"><h4>客户管理</h4><p>客户档案查看、联系人管理、客户项目列表(和后台功能一致,移动端适配)</p></div>
|
||
<div class="mod"><h4>项目管理</h4><p>项目跟进、勘察任务、方案查看、合同查看、验收与回访</p></div>
|
||
<div class="mod"><h4>派单查看</h4><p>负责客户的派单进度跟踪、报警处理进度、报修处理进度</p></div>
|
||
<div class="mod"><h4>现场巡查</h4><p>现场拍照记录、巡查日志提交、问题上报</p></div>
|
||
<div class="mod"><h4>消息通知</h4><p>派单提醒、报警推送、客户消息、系统通知</p></div>
|
||
<div class="mod"><h4>我的</h4><p>个人信息、修改密码、负责客户统计、业绩查看</p></div>
|
||
</div></div>
|
||
</div>
|
||
|
||
<div class="client-card cc-purple">
|
||
<div class="cc-head"><div class="icon">APP</div><h3>共享电工 APP(uni-app)</h3><span class="role">共享电工</span></div>
|
||
<div class="cc-body"><div class="mod-list">
|
||
<div class="mod"><h4>派单接收</h4><p>勘察/安装/报警/报修/维保五类派单推送与接单确认</p></div>
|
||
<div class="mod"><h4>领料管理</h4><p>安装派单自动生成设备/耗材领用单,领料确认</p></div>
|
||
<div class="mod"><h4>现场处理</h4><p>配电井/箱位置记录、按标准流程处置、水印拍照取证上传</p></div>
|
||
<div class="mod"><h4>任务提交</h4><p>处理完成后照片上传、提交派单、查看历史任务</p></div>
|
||
<div class="mod"><h4>报酬查询</h4><p>月度派单完成统计、单笔/月度收入明细查询</p></div>
|
||
<div class="mod"><h4>客户回访</h4><p>业务员回访记录上传(拍照+意见)</p></div>
|
||
</div></div>
|
||
</div>
|
||
|
||
<div class="client-card cc-amber">
|
||
<div class="cc-head"><div class="icon">WX</div><h3>客户微信小程序(uni-app)</h3><span class="role">客户(学校/医院等)</span></div>
|
||
<div class="cc-body"><div class="mod-list">
|
||
<div class="mod"><h4>设备状态查看</h4><p>所属设备在线状态、线路用电实时数据</p></div>
|
||
<div class="mod"><h4>报警信息</h4><p>设备报警记录查询、处理进度跟踪</p></div>
|
||
<div class="mod"><h4>用电统计</h4><p>按部门/楼栋/楼层/房间多维度用电查询、节电情况</p></div>
|
||
<div class="mod"><h4>月度报告</h4><p>当月用电统计查看、用电及改善报告文件下载</p></div>
|
||
<div class="mod"><h4>报修申请</h4><p>水电问题报修提交(描述+拍照)、报修进度查询</p></div>
|
||
<div class="mod"><h4>服务评分</h4><p>报修/维保派单完成后对共享电工评分</p></div>
|
||
</div></div>
|
||
</div>
|
||
|
||
<div class="client-card cc-slate" style="border-style:dashed">
|
||
<div class="cc-head"><div class="icon">ICC</div><h3>大华 ICC 平台(外部)</h3><span class="role">API 对接 · 非自研</span></div>
|
||
<div class="cc-body" style="padding:12px"><div class="mod-list">
|
||
<div class="mod"><h4>客户信息接口</h4><p>ICC 录入意向客户 → 推送到运营管理平台</p></div>
|
||
<div class="mod"><h4>设备信息接口</h4><p>网关/探测器设备数据同步到运营管理平台</p></div>
|
||
<div class="mod"><h4>设备数据采集接口</h4><p>用电实时数据按采集频次同步拉取</p></div>
|
||
<div class="mod"><h4>设备报警接口</h4><p>设备运行状态、预警类型、报警数值拉取</p></div>
|
||
</div></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 05. ICC 对接架构 ===== -->
|
||
<section id="icc">
|
||
<div class="section-head">
|
||
<span class="section-num">05</span>
|
||
<h2>ICC 平台对接架构</h2>
|
||
<span class="desc">主动拉取 · 队列缓冲 · 分区写入</span>
|
||
</div>
|
||
|
||
<div class="callout warn">
|
||
<h4>对接方式说明</h4>
|
||
<p>ICC 平台内部是实时推送机制,但<strong>鑫潼系统侧采用主动拉取</strong>(定时任务调 ICC OpenAPI)。ICC 接口文档待研究,当前按通用 REST API 模式设计,后续接入时按实际文档调整鉴权方式(AppKey/Token)和接口字段。</p>
|
||
</div>
|
||
|
||
<figure class="mermaid">
|
||
flowchart LR
|
||
subgraph ICC ["大华 ICC 平台(外部)"]
|
||
A1["客户信息"]
|
||
A2["设备信息<br/>网关/探测器"]
|
||
A3["用电采集数据<br/>(按频次)"]
|
||
A4["设备报警数据"]
|
||
end
|
||
subgraph SYNC ["鑫潼 ICC 采集服务"]
|
||
T1["定时任务调度<br/>不同频次拉取"]
|
||
Q1[("BullMQ 队列<br/>数据缓冲")]
|
||
P1["数据清洗与映射<br/>设备码 → 线路 → 客户"]
|
||
end
|
||
subgraph DB ["数据层"]
|
||
D1[("业务表<br/>设备/线路/客户")]
|
||
D2[("用电采集分区表<br/>按月分区")]
|
||
D3[("报警表")]
|
||
end
|
||
subgraph BIZ ["业务消费"]
|
||
B1["报警派单服务<br/>实时推送 APP"]
|
||
B2["统计报表服务<br/>多维聚合"]
|
||
B3["月度报告生成"]
|
||
end
|
||
A1 -->|"HTTP API 拉取"| T1
|
||
A2 -->|"HTTP API 拉取"| T1
|
||
A3 -->|"HTTP API 拉取<br/>高频(如5分钟)"| T1
|
||
A4 -->|"HTTP API 拉取<br/>中频(如1分钟)"| T1
|
||
T1 --> Q1
|
||
Q1 --> P1
|
||
P1 --> D1
|
||
P1 --> D2
|
||
P1 --> D3
|
||
D3 --> B1
|
||
D2 --> B2
|
||
D2 --> B3
|
||
style ICC fill:#f1f5f9,stroke:#475569,stroke-width:2px
|
||
style SYNC fill:#ecfdf5,stroke:#0d9488,stroke-width:2px
|
||
style DB fill:#fffbeb,stroke:#e0852b,stroke-width:2px
|
||
style BIZ fill:#eff6ff,stroke:#1d6fff,stroke-width:2px
|
||
</figure>
|
||
|
||
<div class="table-wrap" style="margin-top:16px">
|
||
<table>
|
||
<thead><tr><th>拉取数据</th><th>拉取频次(建议)</th><th>写入目标</th><th>消费方</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>客户信息</td><td>事件触发 / 每小时</td><td>业务表</td><td>客户管理模块</td></tr>
|
||
<tr><td>设备信息(网关/探测器)</td><td>每小时</td><td>设备表 + 线路表</td><td>设备管理模块</td></tr>
|
||
<tr><td>用电采集数据</td><td><code>5~15 分钟</code>(按 ICC 采集频次)</td><td>用电采集分区表(按月)</td><td>统计报表 / 月度报告</td></tr>
|
||
<tr><td>设备报警数据</td><td><code>1 分钟</code></td><td>报警表</td><td>报警派单服务 → APP 推送</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 06. 数据隔离方案 ===== -->
|
||
<section id="isolation">
|
||
<div class="section-head">
|
||
<span class="section-num">06</span>
|
||
<h2>数据隔离方案</h2>
|
||
<span class="desc">逻辑隔离 + 时序分区 · 不做物理分库</span>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<h4>核心决策:是否需要多租户 / 分库?</h4>
|
||
<p>鑫潼是<strong>唯一运营主体</strong>,客户(学校/医院)是平台上的数据主体而非独立租户,因此<strong>不需要严格多租户架构</strong>。采用<strong>逻辑隔离(customer_id 行级隔离)+ 时序数据按月分区</strong>的混合方案,兼顾性能与运维成本。</p>
|
||
</div>
|
||
|
||
<div class="iso-vis">
|
||
<div class="iso-box business">
|
||
<h4>业务数据 · 逻辑隔离 <span class="tg">customer_id</span></h4>
|
||
<p style="font-size:12px;color:var(--muted);margin-bottom:8px">客户、合同、派单、设备等业务表数据量有限,通过 customer_id 字段 + 索引隔离。</p>
|
||
<div class="rows">
|
||
<div class="iso-row"><span class="cid">C001</span> 客户A · 合同 · 派单 · 设备</div>
|
||
<div class="iso-row"><span class="cid">C002</span> 客户B · 合同 · 派单 · 设备</div>
|
||
<div class="iso-row"><span class="cid">C003</span> 客户C · 合同 · 派单 · 设备</div>
|
||
<div class="iso-row" style="opacity:.6"><span class="cid">...</span> 共享同一张表,行级隔离</div>
|
||
</div>
|
||
</div>
|
||
<div class="iso-box timeseries">
|
||
<h4>用电采集数据 · 按月分区 <span class="tg">RANGE BY 采集时间</span></h4>
|
||
<p style="font-size:12px;color:var(--muted);margin-bottom:8px">数据量增量大头。按采集时间分区,查询只扫描相关月份分区,性能稳定。</p>
|
||
<div class="rows">
|
||
<div class="iso-row">electricity_2026_05 · 分区子表</div>
|
||
<div class="iso-row">electricity_2026_06 · 分区子表</div>
|
||
<div class="iso-row">electricity_2026_07 · 分区子表</div>
|
||
<div class="iso-row">electricity_2026_08 · 分区子表(当前)</div>
|
||
<div class="iso-row" style="opacity:.6">历史分区可归档,不影响热数据查询</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>方案</th><th>是否采用</th><th>适用数据</th><th>理由</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>逻辑隔离(customer_id 行级)</td><td><span class="pill pill-yes">采用</span></td><td>业务数据(客户/合同/派单/设备)</td><td>数据量有限,索引隔离足够,支持跨客户运营统计</td></tr>
|
||
<tr><td>时序数据按月分区</td><td><span class="pill pill-yes">采用</span></td><td>用电采集数据</td><td>解决数据量暴涨问题,查询只扫相关分区</td></tr>
|
||
<tr><td>物理分库(每客户独立库)</td><td><span class="pill pill-no">不采用</span></td><td>—</td><td>运维成本高,跨客户统计困难,无合规强制要求</td></tr>
|
||
<tr><td>独立 Schema 隔离</td><td><span class="pill pill-no">不采用</span></td><td>—</td><td>增加复杂度但收益有限,逻辑隔离已满足</td></tr>
|
||
<tr><td>严格多租户(Tenant 模型)</td><td><span class="pill pill-no">不采用</span></td><td>—</td><td>鑫潼是单一运营方,客户非独立租户</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="callout warn">
|
||
<h4>关于"数据量暴涨影响性能"的回应</h4>
|
||
<p>数据增长的大头是<strong>用电采集数据</strong>(每条线路按采集频次持续写入),而非业务数据。业务数据(客户/合同/派单)即使客户增长到上千家,数据量仍在百万级以内,逻辑隔离 + 索引完全够用。用电采集数据通过<strong>按月分区 + 物化视图预聚合月度统计</strong>,即使积累数年数据,查询也只扫描目标月份分区,性能可控。<strong>不需要物理分库。</strong></p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 07. 权限控制方案 ===== -->
|
||
<section id="permission">
|
||
<div class="section-head">
|
||
<span class="section-num">07</span>
|
||
<h2>权限控制方案</h2>
|
||
<span class="desc">后台 RBAC 菜单级 · APP/小程序接口级</span>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<h4>权限设计原则</h4>
|
||
<p>现阶段权限粗放管理:<strong>运营方双端(Web + APP)共用 sys_user 表</strong>,采用 RBAC 菜单级权限(角色绑定菜单/按钮);<strong>共享电工 APP 和客户小程序的数据权限由接口定义</strong>——接口返回什么数据,端上就只能看到什么数据,不在端上做复杂权限判断。</p>
|
||
</div>
|
||
|
||
<h3 style="margin:18px 0 10px;font-size:16px">权限流转链路</h3>
|
||
<div class="perm-flow">
|
||
<div class="perm-step"><span class="num">STEP 1</span><h4>用户登录</h4><p>运营方双端:账号密码(sys_user)<br/>电工APP:账号密码(worker)<br/>小程序:微信 openid</p></div>
|
||
<div class="perm-arrow">→</div>
|
||
<div class="perm-step"><span class="num">STEP 2</span><h4>JWT 签发</h4><p>Token 携带:userId、user_type、role、customerId<br/>双 Token 刷新</p></div>
|
||
<div class="perm-arrow">→</div>
|
||
<div class="perm-step"><span class="num">STEP 3</span><h4>菜单/路由权限</h4><p>运营方双端:RBAC 角色 → 菜单<br/>电工APP/小程序:固定功能页</p></div>
|
||
<div class="perm-arrow">→</div>
|
||
<div class="perm-step"><span class="num">STEP 4</span><h4>接口数据权限</h4><p>接口根据 user_type + role 过滤数据<br/>给什么看什么</p></div>
|
||
</div>
|
||
|
||
<h3 style="margin:24px 0 10px;font-size:16px">角色与权限矩阵</h3>
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>角色</th><th>使用端</th><th>账号表</th><th>菜单权限(RBAC)</th><th>接口数据权限</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>运营管理员</td><td>运营管理平台(Web)</td><td>sys_user</td><td>全部菜单:工作台/审批/派单/设备/报表/系统管理</td><td>全量数据,所有客户和派单</td></tr>
|
||
<tr><td>业务员</td><td>运营管理平台(Web)+ 运营管理 APP</td><td>sys_user</td><td>客户/项目/派单查看/报表查看(按需配置)</td><td>仅自己负责的客户(salesman_id 过滤)</td></tr>
|
||
<tr><td>共享电工</td><td>共享电工 APP</td><td>worker</td><td>—(APP 固定功能页)</td><td>仅分配给自己的派单、个人报酬明细</td></tr>
|
||
<tr><td>客户</td><td>微信小程序</td><td>customer_account</td><td>—(小程序固定功能页)</td><td>仅本客户设备/用电/报警/月报/报修记录</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<h4>接口级数据权限实现要点</h4>
|
||
<p>① <strong>共享电工</strong>:查询派单接口自动按 <code>worker_id = 当前用户</code> 过滤;报酬接口只返回本人数据。② <strong>客户</strong>:查询设备/用电/报警接口自动按 <code>customer_id = 当前客户</code> 过滤;报修只能提交本客户的。③ <strong>业务员(运营管理 APP + Web)</strong>:查询客户/项目/派单接口按 <code>salesman_id = 当前用户</code> 过滤,只能看自己负责的客户数据(运营管理员不受限)。④ <strong>运营方双端共用一套 RBAC</strong>:Web 管理台和运营管理 APP 共用 sys_user 表 + 角色体系,菜单权限由后端统一返回,前端/APP 根据返回动态渲染。通过 Midway Interceptor 统一注入过滤条件,避免每个接口手动处理。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ===== 08. 关键业务数据流 ===== -->
|
||
<section id="dataflow">
|
||
<div class="section-head">
|
||
<span class="section-num">08</span>
|
||
<h2>关键业务数据流</h2>
|
||
<span class="desc">端到端数据流转</span>
|
||
</div>
|
||
|
||
<figure class="mermaid">
|
||
flowchart TB
|
||
subgraph PHASE1 ["项目阶段"]
|
||
P1["ICC 录入客户"] --> P2["运营平台配置建筑/房间"]
|
||
P2 --> P3["APP 勘察派单<br/>现场拍照"]
|
||
P3 --> P4["运营平台制定方案"]
|
||
P4 --> P5["签订合同"]
|
||
P5 --> P6["APP 安装派单<br/>设备配置指向 ICC"]
|
||
P6 --> P7["ICC 同步设备信息<br/>到运营平台"]
|
||
P7 --> P8["线路分配部门/房间"]
|
||
P8 --> P9["分配客户访问账号"]
|
||
P9 --> P10["项目验收"]
|
||
end
|
||
subgraph PHASE2 ["运营阶段"]
|
||
O1["ICC 报警数据"] -->|"定时拉取"| O2["运营平台生成报警派单"]
|
||
O2 --> O3["APP 推送接单"]
|
||
O3 --> O4["现场处置拍照"]
|
||
O4 --> O5["运营管理员评分"]
|
||
M1["客户小程序报修"] --> M2["运营平台生成报修派单"]
|
||
M2 --> M3["APP 接单处理"]
|
||
M3 --> M4["客户小程序评分"]
|
||
R1["ICC 用电数据"] -->|"定时拉取"| R2["分区表存储"]
|
||
R2 --> R3["多维统计聚合"]
|
||
R3 --> R4["月度报告生成"]
|
||
R4 --> R5["小程序下载查看"]
|
||
end
|
||
P10 --> O1
|
||
P10 --> M1
|
||
P10 --> R1
|
||
style PHASE1 fill:#eff6ff,stroke:#1d6fff,stroke-width:2px
|
||
style PHASE2 fill:#ecfdf5,stroke:#0d9488,stroke-width:2px
|
||
</figure>
|
||
</section>
|
||
|
||
<!-- ===== 09. 设计假设清单 ===== -->
|
||
<section id="assumptions">
|
||
<div class="section-head">
|
||
<span class="section-num">09</span>
|
||
<h2>设计假设清单</h2>
|
||
<span class="desc">已采用的假设 · 如需调整请告知</span>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>假设项</th><th>假设内容</th><th>来源</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>运营主体</td><td>鑫潼为唯一运营方,不做白标输出</td><td>用户确认</td></tr>
|
||
<tr><td>多租户</td><td>不需要严格多租户,采用逻辑隔离</td><td>用户确认 + 架构建议</td></tr>
|
||
<tr><td>分库</td><td>不做物理分库,用电数据按月分区</td><td>架构建议(解决数据量问题)</td></tr>
|
||
<tr><td>ICC 对接</td><td>主动拉取(定时任务),非 ICC 推送</td><td>用户确认</td></tr>
|
||
<tr><td>ICC 接口文档</td><td>待研究,按通用 REST API 模式预留</td><td>用户确认</td></tr>
|
||
<tr><td>后台权限</td><td>RBAC 菜单级,现阶段粗放管理</td><td>用户确认</td></tr>
|
||
<tr><td>APP/小程序数据权限</td><td>接口定义数据范围,给什么看什么</td><td>用户确认</td></tr>
|
||
<tr><td>共享电工 APP 技术栈</td><td>uni-app 跨 iOS/Android</td><td>用户确认</td></tr>
|
||
<tr><td>运营管理 APP</td><td>uni-app,业务员使用,功能与后台一致,共用 sys_user 表</td><td>用户确认</td></tr>
|
||
<tr><td>客户小程序</td><td>微信小程序,运营后台分配账号</td><td>用户确认</td></tr>
|
||
<tr><td>子账号</td><td>待定,当前按单账号预留扩展</td><td>用户确认(待定)</td></tr>
|
||
<tr><td>电子签章</td><td>不需要,但需取证拍照(水印)</td><td>用户确认</td></tr>
|
||
<tr><td>并发量</td><td>常规 ERP 级,无需特殊高并发架构</td><td>用户确认</td></tr>
|
||
<tr><td>数据库</td><td>PostgreSQL(架构建议,用户待定)</td><td>架构建议</td></tr>
|
||
<tr><td>消息队列</td><td>BullMQ(Redis 基础),不引入 Kafka</td><td>架构建议(匹配并发量)</td></tr>
|
||
<tr><td>后端框架</td><td>Midway.js + TypeORM</td><td>用户确认</td></tr>
|
||
<tr><td>前端框架</td><td>Vue3 + Ant Design Vue</td><td>用户确认</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<footer>
|
||
<p class="ft">鑫潼智电系统实现架构设计 · 基于《鑫潼智电系统需求分析报告 V1.0》 · 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',
|
||
flowchart: { htmlLabels: true, curve: 'basis', useMaxWidth: true },
|
||
themeVariables: {
|
||
primaryColor: '#ffffff', primaryTextColor: '#0f1e2e', primaryBorderColor: '#1d6fff',
|
||
lineColor: '#94a3b8', fontSize: '14px',
|
||
fontFamily: 'PingFang SC, Microsoft YaHei, sans-serif',
|
||
clusterBkg: '#f8fafc', clusterBorder: '#1d6fff'
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|