From ec31c12130070b151e5e74476b04e3a674d4e8bb Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Fri, 17 Jul 2026 03:17:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B9=E9=80=A0=E7=BA=BF=E8=B7=AF?= =?UTF-8?q?=E5=9B=BE=E4=B8=8A=E4=BC=A0=E5=90=8E=E5=8F=B0=E5=B9=B6=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E8=B4=AD=E7=A5=A8=E9=A1=B5=E6=80=BB=E8=A7=88=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/index.html | 97 +++++++++++++++------------------------------ web/index.js | 3 -- web/ticket-order.js | 28 ++++++++++--- 3 files changed, 56 insertions(+), 72 deletions(-) diff --git a/web/index.html b/web/index.html index e8b7f6d..0fcf9a6 100644 --- a/web/index.html +++ b/web/index.html @@ -74,7 +74,7 @@ IC卡管理 -
-
+
+
-
-

线路拓扑图布局编辑器

- 拖拽站点以自定义位置 +
+

线路图上传

+
上传后会用于首页展示,也会在购票页未选择线路时显示为总览图。
-
- -
-
-
- - - - - - - - - - - - - -
- -
-
-
-
- -
- {{ node.name }} -
+
+
+
上传说明
+
+
支持格式:PNG、JPG、WEBP、SVG
+
建议上传横向长图,便于首页和购票页展示。
+
再次上传会自动替换旧文件。
+
+
+
当前文件: {{ assetsManifest.routeMap || '未上传' }}
+
更新时间: {{ assetsManifest.updatedAt ? formatTime(assetsManifest.updatedAt) : '暂无' }}
+
+
+ +
+ +
+ 暂无线路图,请先上传一张线路图。
@@ -994,5 +965,3 @@ - - diff --git a/web/index.js b/web/index.js index ecf7b5f..bed3532 100644 --- a/web/index.js +++ b/web/index.js @@ -1843,9 +1843,6 @@ createApp({ } else { stopIcCardSync(); } - if (v === 'assets') { - setTimeout(initTopologyLayout, 300); - } ensureViewData(v).catch(console.error); const sp = new URLSearchParams(location.search); if (v === 'dashboard') sp.delete('view'); diff --git a/web/ticket-order.js b/web/ticket-order.js index bed4822..1024c72 100644 --- a/web/ticket-order.js +++ b/web/ticket-order.js @@ -41,7 +41,8 @@ let lineColors = []; let linesByStation = new Map(); let lineIdxsByCanonical = {}; - let activeLineIdx = 0; + let activeLineIdx = -1; + let routeMapUrl = ''; const piePath = (cx, cy, r, a0, a1) => { const x0 = cx + r * Math.cos(a0); @@ -77,6 +78,12 @@ return (yiq >= 140) ? '#0f172a' : '#ffffff'; }; + const buildAssetUrl = (name, updatedAt) => { + if (!name) return ''; + const version = updatedAt ? String(updatedAt) : String(Date.now()); + return `/assets/${encodeURIComponent(name)}?v=${encodeURIComponent(version)}`; + }; + function renderStationNode(x, y, code, i, forceColor = null) { const canonical = stationCanonicalByCode[code] || code; const codes = stationCodesByCanonical[canonical] || [canonical]; @@ -165,7 +172,7 @@ } window.selectTvmLine = (idx) => { - activeLineIdx = idx; + activeLineIdx = (activeLineIdx === idx) ? -1 : idx; renderTvmLines(); renderTvmSingleLine(); }; @@ -175,7 +182,11 @@ if (!container) return; const li = lineStops[activeLineIdx]; if (!li) { - container.innerHTML = ''; + if (routeMapUrl) { + container.innerHTML = `
线路图总览
`; + } else { + container.innerHTML = '
暂未选择线路,且暂无已上传线路图。
'; + } return; } @@ -313,9 +324,10 @@ async function renderSystemMap() { mapContainer.innerHTML = '
加载线路数据...
'; try { - const [linesData, stationsData] = await Promise.all([ + const [linesData, stationsData, assetsData] = await Promise.all([ fetch('/api/public/lines').then(r=>r.json()), - fetch('/api/public/stations').then(r=>r.json()) + fetch('/api/public/stations').then(r=>r.json()), + fetch('/api/assets/manifest', { cache: 'no-store' }).then(r => r.json()).catch(() => null) ]); window.cachedStationsData = stationsData; @@ -374,6 +386,8 @@ const uniq = Array.from(new Set(arr)); if (uniq.length >= 2) stationTransfer.add(c); } + + routeMapUrl = (assetsData && assetsData.routeMap) ? buildAssetUrl(assetsData.routeMap, assetsData.updatedAt) : ''; const fadeStyle = `