diff --git a/.trae/rules/git.md b/.trae/rules/git.md index a379908..246112c 100644 --- a/.trae/rules/git.md +++ b/.trae/rules/git.md @@ -1,2 +1,2 @@ 1. 完成功能制作后自行编辑git commit并推送 -2. \ No newline at end of file +2. 提交时请添加功能描述 \ No newline at end of file diff --git a/web/map-preview.html b/web/map-preview.html deleted file mode 100644 index 0f5c8c0..0000000 --- a/web/map-preview.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - 全网线路图预览 - FSE铁路运输票务系统 - - - - -
-

全网线路图预览 (正交布线)

-
- 返回后台 - -
-
-
-
正在计算布局,请稍候...
-
- - - diff --git a/web/ticket-order.js b/web/ticket-order.js index 90ab193..7ce8333 100644 --- a/web/ticket-order.js +++ b/web/ticket-order.js @@ -1,3 +1,11 @@ +/* + * @Author: HenryDu8133 813367384@qq.com + * @Date: 2025-12-06 23:59:11 + * @LastEditors: HenryDu8133 813367384@qq.com + * @LastEditTime: 2026-07-15 23:25:36 + * @FilePath: \TicketMachine\web\ticket-order.js + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ (() => { const $ = (sel) => document.querySelector(sel); const fromEl = $('#from'); @@ -56,13 +64,101 @@ }; const buildTransitPath = (points, radius = 12) => { - if (!points || points.length === 0) return ''; - if (points.length === 1) return `M ${points[0].x} ${points[0].y}`; + const src = Array.isArray(points) ? points.filter(Boolean) : []; + if (src.length === 0) return ''; + if (src.length === 1) return `M ${src[0].x} ${src[0].y}`; - let d = `M ${points[0].x} ${points[0].y}`; - for (let i = 1; i < points.length; i++) { - d += ` L ${points[i].x} ${points[i].y}`; + const fmt = (n) => { + const v = Number(n); + if (!Number.isFinite(v)) return '0'; + return String(Math.round(v * 10) / 10); + }; + const eq = (a, b) => Math.abs(a.x - b.x) < 0.01 && Math.abs(a.y - b.y) < 0.01; + const push = (arr, p) => { + const x = Number(p?.x); + const y = Number(p?.y); + if (!Number.isFinite(x) || !Number.isFinite(y)) return; + const item = { x, y, code: p?.code ? String(p.code).trim() : '' }; + if (arr.length && eq(arr[arr.length - 1], item)) return; + arr.push(item); + }; + const isTransfer = (p) => { + const code = String(p?.code || '').trim(); + return !!code && stationTransfer && stationTransfer.has(code); + }; + const simplify = (arr) => { + const out = []; + for (const p of arr) push(out, p); + let changed = true; + while (changed) { + changed = false; + for (let i = 1; i < out.length - 1; i++) { + const a = out[i - 1]; + const b = out[i]; + const c = out[i + 1]; + if ((a.x === b.x && b.x === c.x) || (a.y === b.y && b.y === c.y)) { + out.splice(i, 1); + changed = true; + break; + } + } + } + return out; + }; + const orth = []; + push(orth, src[0]); + for (let i = 1; i < src.length; i++) { + const prev = orth[orth.length - 1]; + const next = src[i]; + const x2 = Number(next?.x); + const y2 = Number(next?.y); + if (!Number.isFinite(x2) || !Number.isFinite(y2)) continue; + + if (prev.x === x2 || prev.y === y2) { + push(orth, next); + continue; + } + + const aT = isTransfer(prev); + const bT = isTransfer(next); + if (bT && !aT) { + push(orth, { x: x2, y: prev.y, code: next?.code }); + } else if (aT && !bT) { + push(orth, { x: prev.x, y: y2, code: prev?.code }); + } else { + push(orth, { x: x2, y: prev.y, code: next?.code }); + } + push(orth, next); } + + const pts = simplify(orth); + if (pts.length === 0) return ''; + if (pts.length === 1) return `M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`; + if (radius <= 0 || pts.length === 2) { + let d = `M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`; + for (let i = 1; i < pts.length; i++) d += ` L ${fmt(pts[i].x)} ${fmt(pts[i].y)}`; + return d; + } + + const rBase = Math.max(0, Number(radius) || 0); + let d = `M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`; + for (let i = 1; i < pts.length - 1; i++) { + const a = pts[i - 1]; + const b = pts[i]; + const c = pts[i + 1]; + const v1x = b.x - a.x; + const v1y = b.y - a.y; + const v2x = c.x - b.x; + const v2y = c.y - b.y; + const len1 = Math.hypot(v1x, v1y); + const len2 = Math.hypot(v2x, v2y); + if (!len1 || !len2) continue; + const r = Math.min(rBase, len1 / 2, len2 / 2); + const p1 = { x: b.x - (v1x / len1) * r, y: b.y - (v1y / len1) * r }; + const p2 = { x: b.x + (v2x / len2) * r, y: b.y + (v2y / len2) * r }; + d += ` L ${fmt(p1.x)} ${fmt(p1.y)} Q ${fmt(b.x)} ${fmt(b.y)} ${fmt(p2.x)} ${fmt(p2.y)}`; + } + d += ` L ${fmt(pts[pts.length - 1].x)} ${fmt(pts[pts.length - 1].y)}`; return d; }; @@ -194,8 +290,17 @@ const legendW = 10; const startX = 140; const baseY = 80; - const lineGapY = 80; - const minGapX = 80; + const totalLines = currentLineIdx; + const maxStops = Math.max(2, ...lineStops.map(li => Array.isArray(li.stops) ? li.stops.length : 2)); + let lineGapY = 80; + if (totalLines >= 14) lineGapY = 66; + else if (totalLines >= 10) lineGapY = 72; + lineGapY = Math.max(60, Math.min(84, lineGapY)); + let minGapX = 80; + if (maxStops >= 24) minGapX = 64; + else if (maxStops >= 18) minGapX = 72; + minGapX = Math.max(56, Math.min(96, minGapX)); + const labelStackGap = Math.max(30, Math.round(lineGapY * 0.55)); const occurrences = {}; for (const li of lineStops) { @@ -272,7 +377,7 @@ const hasEn = !!enName; const nameLen = Math.max(name.length * 13 + 16, hasEn ? enName.length * 6.5 + 16 : 0); const h = hasEn ? 36 : 24; - const yOffset = count * 42 - (h / 2); + const yOffset = count * labelStackGap - (h / 2); let lx, textX; if (isStart) { @@ -301,7 +406,8 @@ const canonical = stationCanonicalByCode[code] || code; return { x: stationXByCanonical[canonical] || 0, - y: stationYByCanonical[code] ?? (baseY + li.idx * lineGapY) + y: stationYByCanonical[code] ?? (baseY + li.idx * lineGapY), + code }; }); @@ -311,8 +417,9 @@ // Add line name labels at ends const pStart = pts[0]; const pEnd = pts[pts.length - 1]; - svgContent += placeLabel(pStart.x, pStart.y, true, li.name, li.enName, li.color); - svgContent += placeLabel(pEnd.x, pEnd.y, false, li.name, li.enName, li.color); + const yLabel = baseY + li.idx * lineGapY; + svgContent += placeLabel(pStart.x, yLabel, true, li.name, li.enName, li.color); + svgContent += placeLabel(pEnd.x, yLabel, false, li.name, li.enName, li.color); } } @@ -355,10 +462,10 @@ const codeW = primaryCode.length * 6 + 10; if (preferTop) { - const bottomY = y - 14; + const bottomY = y - 22; const enY = bottomY; const nameY = showEn ? bottomY - 12 : bottomY; - const codeY = nameY - 16; + const codeY = nameY - 18; textContent += ``; textContent += `${primaryCode}`; @@ -369,9 +476,9 @@ textContent += `${enName}`; } } else { - const topY = y + 24; + const topY = y + 34; const codeY = topY; - const nameY = topY + 16; + const nameY = topY + 18; const enY = nameY + 12; textContent += ``; @@ -537,7 +644,7 @@ const x = stationXByCanonical[canonical]; const y = stationYByCanonical[normalized]; if (!Number.isFinite(x) || !Number.isFinite(y)) return null; - return { x, y }; + return { x, y, code: normalized }; } function getMapStationEl(code) {