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) {