diff --git a/old-ticket-order.js b/old-ticket-order.js new file mode 100644 index 0000000..4986de3 Binary files /dev/null and b/old-ticket-order.js differ diff --git a/server/services/svg-generator.js b/server/services/svg-generator.js index b896f35..71f9a8b 100644 --- a/server/services/svg-generator.js +++ b/server/services/svg-generator.js @@ -160,36 +160,42 @@ function generate(stations, lines, fares, nameByCode, transfers) { if (i === j) { svg += `-`; } else { - const val = Math.round(Number(distAll[code][codes[j]] || 0)); - const intensity = maxFare > 0 ? Math.min(1, val / maxFare) : 0; - - // Get route colors - const routeColors = colorsForRoute(code, codes[j]); - - // Draw background strips for multiple lines - if (routeColors.length > 0) { - const stripW = cellW / routeColors.length; - for (let k = 0; k < routeColors.length; k++) { - const c = routeColors[k] || '#93a2b7'; - const stripX = x0 + k * stripW; - // Use fill-opacity for robustness against any color format - svg += ``; - } + const distVal = distAll[code][codes[j]]; + if (distVal === Infinity || !Number.isFinite(distVal)) { + // Unreachable station + svg += `×`; } else { - svg += ``; - } - - // Add cell border - svg += ``; - - svg += `${escapeHTML(String(val))}`; - - // Show small color indicators at top left - const dots = routeColors.slice(0, 4); - for (let k = 0; k < dots.length; k++) { - const cx = x0 + 8 + k * 10; const cy = y0 + 10; - const dotColor = dots[k] || '#93a2b7'; - svg += ``; + const val = Math.round(Number(distVal || 0)); + const intensity = maxFare > 0 ? Math.min(1, val / maxFare) : 0; + + // Get route colors + const routeColors = colorsForRoute(code, codes[j]); + + // Draw background strips for multiple lines + if (routeColors.length > 0) { + const stripW = cellW / routeColors.length; + for (let k = 0; k < routeColors.length; k++) { + const c = routeColors[k] || '#93a2b7'; + const stripX = x0 + k * stripW; + // Use fill-opacity for robustness against any color format + svg += ``; + } + } else { + svg += ``; + } + + // Add cell border + svg += ``; + + svg += `${escapeHTML(String(val))}`; + + // Show small color indicators at top left + const dots = routeColors.slice(0, 4); + for (let k = 0; k < dots.length; k++) { + const cx = x0 + 8 + k * 10; const cy = y0 + 10; + const dotColor = dots[k] || '#93a2b7'; + svg += ``; + } } } } diff --git a/web/ic-card-search.js b/web/ic-card-search.js index dc32056..bcd29c8 100644 --- a/web/ic-card-search.js +++ b/web/ic-card-search.js @@ -96,25 +96,25 @@ if (type === 'create' || type === 'order_created' || type === 'activated') { const cardType = ev?.detail?.card_type || ev?.card_type || ev?.["类型"] || '储值卡'; - return \`[${cardType}];余额: \${balance};时间: \${timeStr}\`; + return `[${cardType}];余额: ${balance};时间: ${timeStr}`; } - if (type === 'topup' || type === 'refill' || action === 'topup') { + if (type === 'topup' || type === 'refill' || action === 'topup' || type === '充值') { const amount = ev?.amount ?? ev?.["充值数额"] ?? 0; - return \`机器ID: \${deviceId};充值数额: \${amount};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};充值数额: ${amount};余额: ${balance};时间: ${timeStr}`; } - if (action === 'entry' || type === 'entry') { + if (action === 'entry' || type === 'entry' || type === '进站') { const code = ev?.station_code || ev?.["站点编号"] || '---'; const name = ev?.station_name || ev?.["站点中文"] || ev?.["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};余额: ${balance};时间: ${timeStr}`; } - if (action === 'exit' || type === 'exit') { + if (action === 'exit' || type === 'exit' || type === '出站') { const code = ev?.station_code || ev?.["站点编号"] || '---'; const name = ev?.station_name || ev?.["站点中文"] || ev?.["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};余额: ${balance};时间: ${timeStr}`; } // fallback - return \`时间: \${timeStr};\${typeof ev?.detail === 'string' ? ev.detail : JSON.stringify(ev?.detail || {}, null, 2)}\`; + return `时间: ${timeStr};${typeof ev?.detail === 'string' ? ev.detail : JSON.stringify(ev?.detail || {}, null, 2)}`; }; const buildEventsHtml = (events) => { diff --git a/web/index.js b/web/index.js index 7826ec7..a4e1fb0 100644 --- a/web/index.js +++ b/web/index.js @@ -457,25 +457,25 @@ createApp({ if (type === 'create' || type === 'order_created' || type === 'activated') { const cardType = ev?.detail?.card_type || ev?.card_type || ev?.["类型"] || '储值卡'; - return \`[${cardType}];余额: \${balance};时间: \${timeStr}\`; + return `[${cardType}];余额: ${balance};时间: ${timeStr}`; } if (type === 'topup' || type === 'refill' || action === 'topup') { const amount = ev?.amount ?? ev?.["充值数额"] ?? 0; - return \`机器ID: \${deviceId};充值数额: \${amount};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};充值数额: ${amount};余额: ${balance};时间: ${timeStr}`; } if (action === 'entry' || type === 'entry') { const code = ev?.station_code || ev?.["站点编号"] || '---'; const name = ev?.station_name || ev?.["站点中文"] || ev?.["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};余额: ${balance};时间: ${timeStr}`; } if (action === 'exit' || type === 'exit') { const code = ev?.station_code || ev?.["站点编号"] || '---'; const name = ev?.station_name || ev?.["站点中文"] || ev?.["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};余额: \${balance};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};余额: ${balance};时间: ${timeStr}`; } // fallback - return \`时间: \${timeStr};\${typeof ev?.detail === 'string' ? ev.detail : JSON.stringify(ev?.detail || {}, null, 2)}\`; + return `时间: ${timeStr};${typeof ev?.detail === 'string' ? ev.detail : JSON.stringify(ev?.detail || {}, null, 2)}`; }; const getStationName = (code) => { diff --git a/web/ticket-order.js b/web/ticket-order.js index a2a7b72..e140f25 100644 --- a/web/ticket-order.js +++ b/web/ticket-order.js @@ -190,10 +190,13 @@ } stationYByCanonical = {}; + let stationIndex = 0; for (const c of Object.keys(primaryLineByStation)) { const li = primaryLineByStation[c]; if (li == null) continue; - stationYByCanonical[c] = baseY + li * lineGapY; + const waveOffset = (stationIndex % 2 === 0) ? -12 : 12; + stationYByCanonical[c] = baseY + li * lineGapY + waveOffset; + stationIndex++; } const allStations = Object.keys(primaryLineByStation); @@ -219,11 +222,20 @@ svgContent += `${li.name}`; if (li.stops.length >= 2) { - const firstX = stationXByCanonical[stationCanonicalByCode[li.stops[0]] || li.stops[0]]; - let d = `M ${firstX} ${yLine}`; - for (let i = 1; i < li.stops.length; i++) { - const x = stationXByCanonical[stationCanonicalByCode[li.stops[i]] || li.stops[i]]; - d += ` L ${x} ${yLine}`; + const pts = li.stops.map(code => { + const canonical = stationCanonicalByCode[code] || code; + return { + x: stationXByCanonical[canonical] || 0, + y: stationYByCanonical[code] ?? yLine + }; + }); + + let d = `M ${pts[0].x} ${pts[0].y}`; + for (let i = 1; i < pts.length; i++) { + const prev = pts[i-1]; + const curr = pts[i]; + const midX = (prev.x + curr.x) / 2; + d += ` C ${midX} ${prev.y}, ${midX} ${curr.y}, ${curr.x} ${curr.y}`; } svgContent += ``; } diff --git a/web/ticket-search.js b/web/ticket-search.js index 11f8eff..cf041e8 100644 --- a/web/ticket-search.js +++ b/web/ticket-search.js @@ -115,23 +115,23 @@ if (type === 'sale' || type === '售票') { const cost = ev.cost ?? ev.price ?? ev.amount ?? ev["票价"] ?? ev["售票额"] ?? '0'; - return \`机器ID: \${deviceId};票价: \${cost};时间: \${timeStr}\`; + return `机器ID: ${deviceId};票价: ${cost};时间: ${timeStr}`; } if (type === 'entry' || action === 'entry') { const code = ev.station_code || ev["站点编号"] || '---'; const name = ev.station_name || ev["站点中文"] || ev["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};时间: ${timeStr}`; } if (type === 'exit' || action === 'exit') { const code = ev.station_code || ev["站点编号"] || '---'; const name = ev.station_name || ev["站点中文"] || ev["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};时间: ${timeStr}`; } // fallback const code = ev.station_code || ev["站点编号"] || '---'; const name = ev.station_name || ev["站点中文"] || ev["发生站"] || '---'; - return \`机器ID: \${deviceId};站点编号: \${code};站点中文: \${name};时间: \${timeStr}\`; + return `机器ID: ${deviceId};站点编号: ${code};站点中文: ${name};时间: ${timeStr}`; }; function renderList(items) {