feat(admin): 优化换乘设置与坐标绑定逻辑,自动识别同名换乘站
This commit is contained in:
+63
-11
@@ -1143,6 +1143,29 @@ createApp({
|
||||
const mapBindingStation = ref('');
|
||||
const mapImageRef = ref(null);
|
||||
|
||||
const unboundStationsGrouped = computed(() => {
|
||||
const groups = {};
|
||||
stations.value.forEach(s => {
|
||||
const name = String(s.name || s.cn_name || '').trim();
|
||||
if (!groups[name]) groups[name] = [];
|
||||
groups[name].push(s);
|
||||
});
|
||||
const out = [];
|
||||
for (const [name, list] of Object.entries(groups)) {
|
||||
out.push({
|
||||
name,
|
||||
isTransfer: list.length > 1,
|
||||
stations: list,
|
||||
isBound: list.every(s => s.svg_x != null && s.svg_y != null)
|
||||
});
|
||||
}
|
||||
return out.sort((a, b) => {
|
||||
if (a.isBound !== b.isBound) return a.isBound ? 1 : -1;
|
||||
if (a.isTransfer !== b.isTransfer) return a.isTransfer ? -1 : 1;
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
|
||||
const onMapImageClick = async (e) => {
|
||||
if (!mapBindingMode.value || !mapBindingStation.value) return;
|
||||
const img = mapImageRef.value;
|
||||
@@ -1157,16 +1180,30 @@ createApp({
|
||||
const station = stations.value.find(s => s.code === mapBindingStation.value);
|
||||
if (!station) return;
|
||||
|
||||
station.svg_x = Number(percentX.toFixed(2));
|
||||
station.svg_y = Number(percentY.toFixed(2));
|
||||
const pctX = Number(percentX.toFixed(2));
|
||||
const pctY = Number(percentY.toFixed(2));
|
||||
|
||||
const targetName = String(station.name || station.cn_name || '').trim().toLowerCase();
|
||||
|
||||
// Auto-bind all stations with the same name (transfers)
|
||||
const stationsToUpdate = stations.value.filter(s => {
|
||||
if (s.code === mapBindingStation.value) return true;
|
||||
const sName = String(s.name || s.cn_name || '').trim().toLowerCase();
|
||||
return targetName && sName === targetName;
|
||||
});
|
||||
|
||||
try {
|
||||
await requestJson(`/api/stations/${encodeURIComponent(station.code)}`, {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(station)
|
||||
}, { expectOk: true });
|
||||
// Optional: find the next station without coordinates and select it
|
||||
for (const s of stationsToUpdate) {
|
||||
s.svg_x = pctX;
|
||||
s.svg_y = pctY;
|
||||
await requestJson(`/api/stations/${encodeURIComponent(s.code)}`, {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(s)
|
||||
}, { expectOk: true });
|
||||
}
|
||||
|
||||
// Find the next station without coordinates and select it
|
||||
const nextStation = stations.value.find(s => s.svg_x == null && s.svg_y == null);
|
||||
if (nextStation) {
|
||||
mapBindingStation.value = nextStation.code;
|
||||
@@ -1342,9 +1379,24 @@ createApp({
|
||||
|
||||
const transferTargets = computed(() => {
|
||||
const fromCode = stationForm.code;
|
||||
return stations.value
|
||||
.filter(s => s && s.code && s.code !== fromCode)
|
||||
.map(s => ({ code: s.code, name: s.name || s.cn_name || s.code, en_name: s.en_name || s.enName || '' }));
|
||||
const fromName = String(stationForm.name || '').trim().toLowerCase();
|
||||
|
||||
const sameName = [];
|
||||
const others = [];
|
||||
|
||||
stations.value.forEach(s => {
|
||||
if (!s || !s.code || s.code === fromCode) return;
|
||||
const targetName = String(s.name || s.cn_name || s.code).trim().toLowerCase();
|
||||
const opt = { code: s.code, name: s.name || s.cn_name || s.code, en_name: s.en_name || s.enName || '' };
|
||||
|
||||
if (fromName && targetName === fromName) {
|
||||
sameName.push(opt);
|
||||
} else {
|
||||
others.push(opt);
|
||||
}
|
||||
});
|
||||
|
||||
return { sameName, others };
|
||||
});
|
||||
|
||||
const openLineModal = () => {
|
||||
|
||||
Reference in New Issue
Block a user