| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>基础设施 / 基础档案</title>
- <style>
- :root { --ink:#172033; --muted:#667085; --line:#d9dee7; --panel:#fff; --page:#f3f5f8; }
- * { box-sizing:border-box; }
- body { margin:0; min-height:100vh; color:var(--ink); font-family:"Microsoft YaHei",Arial,sans-serif; background:var(--page); }
- header { display:flex; flex-wrap:wrap; gap:12px; justify-content:space-between; align-items:center; padding:18px 24px; background:var(--panel); border-bottom:1px solid var(--line); }
- h1 { margin:0; font-size:20px; }
- .state { color:var(--muted); font-size:13px; }
- .state strong { color:#067647; }
- main { display:grid; grid-template-columns:minmax(330px,430px) minmax(0,1fr); min-height:calc(100vh - 61px); }
- aside { padding:18px; background:var(--panel); border-right:1px solid var(--line); }
- section { display:grid; grid-template-rows:auto minmax(0,1fr); }
- .toolbar { display:flex; justify-content:space-between; gap:12px; padding:14px 20px; background:var(--panel); border-bottom:1px solid var(--line); }
- button { min-width:74px; height:32px; border:1px solid #d0d5dd; border-radius:4px; background:#fff; color:var(--ink); cursor:pointer; }
- button:hover { border-color:#1570ef; color:#175cd3; }
- h2 { margin:16px 0 8px; font-size:15px; }
- .chart { display:grid; gap:6px; }
- .bar { display:grid; grid-template-columns:96px minmax(0,1fr) 34px; gap:8px; align-items:center; font-size:12px; }
- .track { height:8px; background:#eef1f5; }
- .fill { height:100%; width:0; background:#1570ef; }
- .item { cursor:pointer; }
- .item.active .fill { background:#067647; }
- .map { position:relative; overflow:hidden; background:linear-gradient(90deg,rgba(255,255,255,.4) 1px,transparent 1px),linear-gradient(0deg,rgba(255,255,255,.4) 1px,transparent 1px),#dfe5ec; background-size:70px 70px; }
- .point { position:absolute; width:13px; height:13px; border-radius:50%; background:#1570ef; border:2px solid #fff; box-shadow:0 1px 4px rgba(16,24,40,.25); }
- .point.pipeline { border-radius:2px; transform:rotate(45deg); }
- .point.hidden { display:none; }
- .label { position:absolute; font-size:11px; color:#344054; background:rgba(255,255,255,.88); padding:1px 4px; border-radius:3px; white-space:nowrap; }
- .legend { position:absolute; left:14px; bottom:14px; padding:7px 10px; border-radius:4px; background:rgba(255,255,255,.9); font-size:12px; color:var(--muted); }
- @media (max-width:900px) { main { grid-template-columns:1fr; } .map { min-height:420px; } aside { border-right:0; border-bottom:1px solid var(--line); } }
- </style>
- </head>
- <body>
- <header>
- <h1>基础设施 / 基础档案</h1>
- <div class="state">更新时间 <strong id="updatedAt">--</strong> · 新鲜度 <strong id="freshness">CURRENT</strong> · 设施 <strong id="total">0</strong></div>
- </header>
- <main>
- <aside>
- <h2>规模</h2>
- <div class="chart" id="scaleChart"></div>
- <h2>年龄</h2>
- <div class="chart" id="ageChart"></div>
- <h2>类型</h2>
- <div class="chart" id="typeChart"></div>
- <h2>行业</h2>
- <div class="chart" id="industryChart"></div>
- <h2>区域</h2>
- <div class="chart" id="regionChart"></div>
- </aside>
- <section>
- <div class="toolbar">
- <strong id="mapTitle">全部基础档案</strong>
- <button id="refresh" type="button">手动刷新</button>
- </div>
- <div class="map" id="map">
- <div class="legend">点击左侧分布项联动筛选</div>
- </div>
- </section>
- </main>
- <script>
- const records = [
- { name:"第一水厂", industry:"GAS", type:"WATER_PLANT", scale:"medium", age:"UNDER_5_YEARS", region:"CN", x:52, y:42 },
- { name:"2号泵站", industry:"WATER_SUPPLY", type:"PUMP_STATION", scale:"small", age:"5_TO_10_YEARS", region:"CN", x:65, y:57 },
- { name:"燃气管线 A", industry:"GAS", type:"GAS_PIPE", scale:null, age:"20_YEARS_OR_OVER", region:"CB", x:22, y:34 },
- { name:"供水管线 B", industry:"WATER_SUPPLY", type:"WATER_PIPE", scale:null, age:"10_TO_20_YEARS", region:"CN", x:75, y:35 },
- { name:"排水管线 C", industry:"DRAINAGE", type:"DRAINAGE_PIPE", scale:null, age:"20_YEARS_OR_OVER", region:"UNKNOWN", x:36, y:72 }
- ];
- const dimensions = {
- scale: ["medium","small"],
- age: ["UNDER_5_YEARS","5_TO_10_YEARS","10_TO_20_YEARS","20_YEARS_OR_OVER"],
- type: ["WATER_PLANT","PUMP_STATION","GAS_PIPE","WATER_PIPE","DRAINAGE_PIPE"],
- industry: ["GAS","WATER_SUPPLY","DRAINAGE"],
- region: ["CN","CB","UNKNOWN"]
- };
- let selected = {};
- function count(dimension, value) {
- return records.filter(item => String(item[dimension]) === value).length;
- }
- function matches(item) {
- return Object.entries(selected).every(([key, value]) => !value || String(item[key]) === value);
- }
- function renderCharts() {
- Object.entries(dimensions).forEach(([dimension, values]) => {
- const max = Math.max(...values.map(value => count(dimension, value)), 1);
- document.getElementById(dimension + "Chart").innerHTML = values.map(value => {
- const selectedCount = records.filter(item => matches(item) && String(item[dimension]) === value).length;
- const active = selected[dimension] === value ? " active" : "";
- return `<div class="bar item${active}" data-dimension="${dimension}" data-value="${value}">
- <span>${value}</span><div class="track"><div class="fill" style="width:${selectedCount / max * 100}%"></div></div><span>${selectedCount}</span>
- </div>`;
- }).join("");
- });
- }
- function renderMap() {
- const visible = records.filter(matches);
- const map = document.getElementById("map");
- map.querySelectorAll(".point,.label").forEach(node => node.remove());
- const title = Object.values(selected).filter(Boolean).join(" / ") || "全部基础档案";
- document.getElementById("mapTitle").textContent = title;
- visible.forEach(item => {
- const point = document.createElement("div");
- point.className = "point" + (item.type.includes("PIPE") ? " pipeline" : "");
- point.style.left = item.x + "%";
- point.style.top = item.y + "%";
- map.appendChild(point);
- const label = document.createElement("div");
- label.className = "label";
- label.style.left = `calc(${item.x}% + 10px)`;
- label.style.top = `calc(${item.y}% - 7px)`;
- label.textContent = item.name;
- map.appendChild(label);
- });
- }
- function render() {
- const visible = records.filter(matches);
- document.getElementById("total").textContent = visible.length;
- document.getElementById("updatedAt").textContent = "2026-09-02T10:00:00+08:00";
- renderCharts();
- renderMap();
- }
- document.addEventListener("click", event => {
- const item = event.target.closest(".item");
- if (!item) return;
- const {dimension, value} = item.dataset;
- selected[dimension] = selected[dimension] === value ? null : value;
- render();
- });
- document.getElementById("refresh").addEventListener("click", () => {
- selected = {};
- render();
- });
- render();
- </script>
- </body>
- </html>
|