Refactor Elesite sorting logic and introduce new utility functions

- Moved the Elesite sorting logic to a new module `elesiteTrainOrder.ts`.
- Created utility functions to infer heading direction and sort Elesite entries by train number.
- Updated `injectJavascriptData` to utilize the new sorting logic and handle station sequences.
- Refactored `useElesite` to use the new sorting utility for improved readability and maintainability.
This commit is contained in:
harukin-expo-dev-env
2026-05-15 17:21:18 +00:00
parent 26aa71866a
commit 8d7005170c
6 changed files with 242 additions and 32 deletions

View File

@@ -3,6 +3,15 @@ import { TRAIN_TYPE_CONFIG } from './webview/trainTypeConfig';
import { TRAIN_ICON_MAP, TRAIN_ICON_REGEX } from './webview/trainIconMap';
import { STATION_DATA } from './webview/stationData';
import { generateXhrInterceptorJs, MockApiConfig } from './mockApi/webviewXhrInterceptor';
import dosan from '@/assets/originData/dosan';
import dosan2 from '@/assets/originData/dosan2';
import koutoku from '@/assets/originData/koutoku';
import naruto from '@/assets/originData/naruto';
import seto from '@/assets/originData/seto';
import tokushima from '@/assets/originData/tokushima';
import uwajima from '@/assets/originData/uwajima';
import uwajima2 from '@/assets/originData/uwajima2';
import yosan from '@/assets/originData/yosan';
export interface InjectJavascriptOptions {
/** 地図スイッチ ("true" | "false") */
@@ -48,6 +57,17 @@ export const injectJavascriptData = ({
backendApiBaseUrl,
mockApiConfig,
}: InjectJavascriptOptions): string => {
const elesiteStationSequences = [
yosan,
uwajima,
uwajima2,
dosan,
dosan2,
koutoku,
tokushima,
naruto,
seto,
].map((stations) => stations.map((station) => station.Station_JP));
// 一番上のメニュー非表示 地図スイッチによって切り替え
const topMenu =
@@ -477,17 +497,68 @@ export const injectJavascriptData = ({
return null;
}
const results = [];
const elesiteStationSequences = ${JSON.stringify(elesiteStationSequences)};
const getElesiteRouteEndpoints = (targetTrainNumber) => {
const diagram = trainDiagramData2[targetTrainNumber] || trainTimeInfo[targetTrainNumber];
if (!diagram) return null;
const stations = diagram
.split('#')
.map((stop) => stop.split(',')[0] && stop.split(',')[0].trim())
.filter(Boolean);
if (stations.length < 2) return null;
return {
firstStation: stations[0],
lastStation: stations[stations.length - 1],
};
};
const getElesiteHeadingDirection = (entry, targetTrainNumber) => {
const matchedTrain = entry.trains && entry.trains.find((train) => train.train_number === targetTrainNumber);
const nav = matchedTrain && matchedTrain.nav;
if (!nav) return null;
if (nav.heading_to === 'left' || nav.heading_to === 'right') {
return nav.heading_to;
}
const route = getElesiteRouteEndpoints(targetTrainNumber);
const formationConfig = entry.formation_config;
if (!route || !formationConfig || !formationConfig.left_station || !formationConfig.right_station) {
return null;
}
const sequence = elesiteStationSequences.find((stations) =>
stations.includes(formationConfig.left_station) &&
stations.includes(formationConfig.right_station) &&
stations.includes(route.firstStation) &&
stations.includes(route.lastStation)
) || elesiteStationSequences.find((stations) =>
stations.includes(formationConfig.left_station) &&
stations.includes(formationConfig.right_station)
);
if (!sequence) return null;
const firstIndex = sequence.indexOf(route.firstStation);
const lastIndex = sequence.indexOf(route.lastStation);
const leftIndex = sequence.indexOf(formationConfig.left_station);
const rightIndex = sequence.indexOf(formationConfig.right_station);
if ([firstIndex, lastIndex, leftIndex, rightIndex].some((index) => index < 0)) {
return null;
}
const trainDelta = lastIndex - firstIndex;
const formationDelta = rightIndex - leftIndex;
if (trainDelta === 0 || formationDelta === 0) {
return null;
}
return Math.sign(trainDelta) === Math.sign(formationDelta) ? 'right' : 'left';
};
const getElesiteSortRank = (entry, targetTrainNumber) => {
const matchedTrain = entry.trains && entry.trains.find((train) => train.train_number === targetTrainNumber);
const nav = matchedTrain && matchedTrain.nav;
if (!nav) return 2;
const headingDirection = getElesiteHeadingDirection(entry, targetTrainNumber);
if (!headingDirection) return 2;
const isLeftSide = (headingDirection === 'left') === (nav.is_leading === true);
return isLeftSide ? 0 : 1;
};
// 高松(left_station)側のユニットを先に表示
// (heading_to === "left") === is_leading が true → 高松(left)端のユニット
const sortedElesiteData = elesiteData.slice().sort((a, b) => {
const aT = a.trains && a.trains.find(t => t.train_number === trainNumber);
const bT = b.trains && b.trains.find(t => t.train_number === trainNumber);
const aNav = aT && aT.nav;
const bNav = bT && bT.nav;
const aIsLeft = (aNav && aNav.heading_to === 'left') === (aNav && aNav.is_leading === true);
const bIsLeft = (bNav && bNav.heading_to === 'left') === (bNav && bNav.is_leading === true);
if (aIsLeft === bIsLeft) return 0;
return aIsLeft ? -1 : 1;
return getElesiteSortRank(a, trainNumber) - getElesiteSortRank(b, trainNumber);
});
for (const entry of sortedElesiteData) {
if (!entry.trains) continue;