feat(ticket-order): 添加单线地铁图选中高亮金线及箭头动画,取消鼠标悬浮动画

This commit is contained in:
2026-07-14 01:43:24 +08:00
parent 63d710114d
commit 3311ee70ce
2 changed files with 46 additions and 8 deletions
+7
View File
@@ -3699,6 +3699,13 @@ body.jr-ticket-board-page .jr-board-card:last-child {
.jr-panel-headline { .jr-panel-headline {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
gap: 12px;
}
}
@keyframes tvmArrowMove {
0% { transform: translateX(-10px); }
100% { transform: translateX(10px); }
} }
.jr-query-stat, .jr-query-stat,
+39 -8
View File
@@ -131,7 +131,7 @@
gap: 6px; gap: 6px;
box-shadow: ${isActive ? '0 2px 4px rgba(0,0,0,0.1)' : 'none'}; box-shadow: ${isActive ? '0 2px 4px rgba(0,0,0,0.1)' : 'none'};
white-space: nowrap; white-space: nowrap;
" onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform='scale(1)'"> ">
<span style="width: 10px; height: 10px; border-radius: 50%; background: ${isActive ? 'var(--bg-color, #fff)' : color}; display: inline-block;"></span> <span style="width: 10px; height: 10px; border-radius: 50%; background: ${isActive ? 'var(--bg-color, #fff)' : color}; display: inline-block;"></span>
${line.name || line.线路名称 || '未知线路'} ${line.name || line.线路名称 || '未知线路'}
</button> </button>
@@ -148,12 +148,40 @@
stationsHtml += `<div style="display: flex; position: relative; min-width: max-content; align-items: flex-start;">`; stationsHtml += `<div style="display: flex; position: relative; min-width: max-content; align-items: flex-start;">`;
// The track line background
stationsHtml += `<div style="position: absolute; top: 14px; left: 35px; right: 35px; height: 8px; background-color: ${activeLine.color || '#94a3b8'}; border-radius: 4px; z-index: 1;"></div>`; stationsHtml += `<div style="position: absolute; top: 14px; left: 35px; right: 35px; height: 8px; background-color: ${activeLine.color || '#94a3b8'}; border-radius: 4px; z-index: 1;"></div>`;
// Draw highlighted route line if start and end are on the same line
let routeStartIndex = -1;
let routeEndIndex = -1;
if (selection[0] && selection[1] && Array.isArray(currentRoute) && currentRoute.length > 0) {
routeStartIndex = stops.indexOf(selection[0]);
routeEndIndex = stops.indexOf(selection[1]);
if (routeStartIndex !== -1 && routeEndIndex !== -1) {
const startPos = Math.min(routeStartIndex, routeEndIndex);
const endPos = Math.max(routeStartIndex, routeEndIndex);
const leftOffset = 35 + startPos * 70; // 70px is the width of each station node
const lineWidth = (endPos - startPos) * 70;
// Base yellow highlight line
stationsHtml += `<div style="position: absolute; top: 12px; left: ${leftOffset}px; width: ${lineWidth}px; height: 12px; background-color: var(--primary, #facc15); border-radius: 6px; z-index: 2; box-shadow: 0 0 8px rgba(250, 204, 21, 0.6);"></div>`;
// Animated arrows
const isForward = routeStartIndex < routeEndIndex;
const arrowCount = Math.max(1, Math.floor(lineWidth / 40));
stationsHtml += `<div style="position: absolute; top: 12px; left: ${leftOffset}px; width: ${lineWidth}px; height: 12px; z-index: 3; display: flex; align-items: center; justify-content: space-evenly; overflow: hidden; pointer-events: none;">`;
for (let i = 0; i < arrowCount; i++) {
stationsHtml += `<i class="fas fa-chevron-${isForward ? 'right' : 'left'}" style="color: #854d0e; font-size: 10px; animation: tvmArrowMove 1.5s infinite linear; opacity: 0.8;"></i>`;
}
stationsHtml += `</div>`;
}
}
let hasStations = false; let hasStations = false;
stops.forEach(code => { stops.forEach((code, index) => {
if (code === '-') return; // Skip breakpoints in this view if (code === '-') return;
hasStations = true; hasStations = true;
const name = stationNameByCode[code] || code; const name = stationNameByCode[code] || code;
@@ -181,24 +209,28 @@
let nodeSize = isTransfer ? '20px' : '14px'; let nodeSize = isTransfer ? '20px' : '14px';
let nodeBorder = isTransfer ? '4px' : '3px'; let nodeBorder = isTransfer ? '4px' : '3px';
let badgeHtml = ''; let badgeHtml = '';
let nodeZIndex = 4;
if (isSelectedFrom) { if (isSelectedFrom) {
nodeColor = 'var(--success, #16a34a)'; nodeColor = 'var(--success, #16a34a)';
nodeSize = '24px'; nodeSize = '24px';
nodeZIndex = 5;
badgeHtml = `<div style="position: absolute; top: -32px; background: var(--success, #16a34a); color: white; font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: bold; white-space: nowrap; box-shadow: 0 2px 4px rgba(0,0,0,0.2); z-index: 10;">起点</div>`; badgeHtml = `<div style="position: absolute; top: -32px; background: var(--success, #16a34a); color: white; font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: bold; white-space: nowrap; box-shadow: 0 2px 4px rgba(0,0,0,0.2); z-index: 10;">起点</div>`;
} else if (isSelectedTo) { } else if (isSelectedTo) {
nodeColor = 'var(--danger, #dc2626)'; nodeColor = 'var(--danger, #dc2626)';
nodeSize = '24px'; nodeSize = '24px';
nodeZIndex = 5;
badgeHtml = `<div style="position: absolute; top: -32px; background: var(--danger, #dc2626); color: white; font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: bold; white-space: nowrap; box-shadow: 0 2px 4px rgba(0,0,0,0.2); z-index: 10;">终点</div>`; badgeHtml = `<div style="position: absolute; top: -32px; background: var(--danger, #dc2626); color: white; font-size: 11px; padding: 2px 6px; border-radius: 4px; font-weight: bold; white-space: nowrap; box-shadow: 0 2px 4px rgba(0,0,0,0.2); z-index: 10;">终点</div>`;
} else if (inRoute) { } else if (inRoute) {
nodeColor = 'var(--primary, #facc15)'; nodeColor = 'var(--primary, #facc15)';
nodeZIndex = 5;
if (!isTransfer) nodeSize = '18px'; if (!isTransfer) nodeSize = '18px';
else nodeSize = '24px'; else nodeSize = '24px';
} }
let transferDotsHtml = ''; let transferDotsHtml = '';
if (isTransfer) { if (isTransfer) {
transferDotsHtml = `<div style="display: flex; gap: 3px; position: absolute; top: -14px;">`; transferDotsHtml = `<div style="display: flex; gap: 3px; position: absolute; top: -14px; z-index: 6;">`;
transferLines.slice(0, 3).forEach(l => { transferLines.slice(0, 3).forEach(l => {
transferDotsHtml += `<div title="可换乘 ${l.name}" style="width: 8px; height: 8px; border-radius: 50%; background: ${l.color || '#999'}; border: 1px solid #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.2);"></div>`; transferDotsHtml += `<div title="可换乘 ${l.name}" style="width: 8px; height: 8px; border-radius: 50%; background: ${l.color || '#999'}; border: 1px solid #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.2);"></div>`;
}); });
@@ -208,15 +240,14 @@
stationsHtml += ` stationsHtml += `
<div class="tvm-station-node" onclick="window.handleStationClick('${code}')" style=" <div class="tvm-station-node" onclick="window.handleStationClick('${code}')" style="
position: relative; position: relative;
z-index: 2; z-index: ${nodeZIndex};
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
width: 70px; width: 70px;
flex-shrink: 0; flex-shrink: 0;
cursor: pointer; cursor: pointer;
transition: transform 0.2s ease; ">
" onmouseover="this.style.transform='translateY(-4px)'" onmouseout="this.style.transform='translateY(0)'">
<!-- Fixed height container for vertical alignment of the track nodes --> <!-- Fixed height container for vertical alignment of the track nodes -->
<div style="height: 36px; display: flex; align-items: center; justify-content: center; position: relative; width: 100%;"> <div style="height: 36px; display: flex; align-items: center; justify-content: center; position: relative; width: 100%;">