feat(web,server): 修复模板语法错误并新增多项体验优化

修复多处JS文件中的模板字符串转义错误,将错误的\\`替换为标准反引号
为IC卡搜索页面新增中文事件类型匹配,支持充值、进站、出站场景
重构票务订单页面的线路绘制逻辑,添加站点交替波浪偏移并使用贝塞尔曲线优化线路显示
优化SVG票价表格渲染,新增不可达站点的红色叉号提示,重构代码提升可读性
This commit is contained in:
2026-07-05 15:34:31 +08:00
parent bad74f819a
commit 06a89c678a
6 changed files with 70 additions and 52 deletions
+35 -29
View File
@@ -160,36 +160,42 @@ function generate(stations, lines, fares, nameByCode, transfers) {
if (i === j) {
svg += `<text x="${x0 + cellW / 2}" y="${y0 + 22}" font-size="12" fill="#6b7280" text-anchor="middle">-</text>`;
} 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 += `<rect x="${stripX}" y="${y0}" width="${stripW}" height="${cellH}" fill="${escapeHTML(c)}" fill-opacity="0.15" stroke="none"/>`;
}
const distVal = distAll[code][codes[j]];
if (distVal === Infinity || !Number.isFinite(distVal)) {
// Unreachable station
svg += `<text x="${x0 + cellW / 2}" y="${y0 + 22}" font-size="14" font-weight="800" fill="#ef4444" text-anchor="middle">×</text>`;
} else {
svg += `<rect x="${x0}" y="${y0}" width="${cellW}" height="${cellH}" fill="#000000" fill-opacity="0.03" stroke="none"/>`;
}
// Add cell border
svg += `<rect x="${x0}" y="${y0}" width="${cellW}" height="${cellH}" fill="none" stroke="#e5e7eb" stroke-width="0.5"/>`;
svg += `<text x="${x0 + cellW / 2}" y="${y0 + 22}" font-size="12" font-weight="800" fill="#000000" text-anchor="middle">${escapeHTML(String(val))}</text>`;
// 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 += `<circle cx="${cx}" cy="${cy}" r="3.5" fill="${escapeHTML(dotColor)}" stroke="white" stroke-width="1"/>`;
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 += `<rect x="${stripX}" y="${y0}" width="${stripW}" height="${cellH}" fill="${escapeHTML(c)}" fill-opacity="0.15" stroke="none"/>`;
}
} else {
svg += `<rect x="${x0}" y="${y0}" width="${cellW}" height="${cellH}" fill="#000000" fill-opacity="0.03" stroke="none"/>`;
}
// Add cell border
svg += `<rect x="${x0}" y="${y0}" width="${cellW}" height="${cellH}" fill="none" stroke="#e5e7eb" stroke-width="0.5"/>`;
svg += `<text x="${x0 + cellW / 2}" y="${y0 + 22}" font-size="12" font-weight="800" fill="#000000" text-anchor="middle">${escapeHTML(String(val))}</text>`;
// 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 += `<circle cx="${cx}" cy="${cy}" r="3.5" fill="${escapeHTML(dotColor)}" stroke="white" stroke-width="1"/>`;
}
}
}
}