|
@@ -110,7 +110,7 @@ function _camerasToArmTypes(cameras) {
|
|
|
return result
|
|
return result
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function _makeIntersectionConfig(id, name, { fixedNsGreen } = {}) {
|
|
|
|
|
|
|
+function _makeIntersectionConfig(id, name, { fixedNsGreen, iconMode = 'default' } = {}) {
|
|
|
const phases = ['南北直行', '东西直行', '北单放', '东单放']
|
|
const phases = ['南北直行', '东西直行', '北单放', '东单放']
|
|
|
const nsGreen = fixedNsGreen !== undefined ? fixedNsGreen : false
|
|
const nsGreen = fixedNsGreen !== undefined ? fixedNsGreen : false
|
|
|
const countdown = 10 + Math.floor(Math.random() * 50)
|
|
const countdown = 10 + Math.floor(Math.random() * 50)
|
|
@@ -119,10 +119,21 @@ function _makeIntersectionConfig(id, name, { fixedNsGreen } = {}) {
|
|
|
const cameras = _makeCameras(id, name, seed)
|
|
const cameras = _makeCameras(id, name, seed)
|
|
|
const armCamTypes = _camerasToArmTypes(cameras)
|
|
const armCamTypes = _camerasToArmTypes(cameras)
|
|
|
|
|
|
|
|
- const lanePresets = [
|
|
|
|
|
- ['U', 'L', 'S', 'R'], ['U', 'L', 'S', 'R'],
|
|
|
|
|
- ['U', 'L', 'S', 'R'], ['U', 'L', 'S', 'R'],
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ const lanesPresetMap = {
|
|
|
|
|
+ default: {
|
|
|
|
|
+ N: ['U', 'L', 'S', 'R'],
|
|
|
|
|
+ S: ['U', 'L', 'S', 'R'],
|
|
|
|
|
+ E: ['U', 'L', 'S', 'R'],
|
|
|
|
|
+ W: ['U', 'L', 'S', 'R'],
|
|
|
|
|
+ },
|
|
|
|
|
+ simple: {
|
|
|
|
|
+ N: ['L', 'S', null, null], // 北:左转+直行
|
|
|
|
|
+ S: ['U', 'S', null, null], // 南:掉头+直行
|
|
|
|
|
+ E: ['L', 'S', null, null], // 东:掉头+直行
|
|
|
|
|
+ W: ['U', 'S', null, null], // 西:左转+直行
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+ const lanesPreset = lanesPresetMap[iconMode] || lanesPresetMap.default
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
status: _getDeviceStatus(id),
|
|
status: _getDeviceStatus(id),
|
|
@@ -131,10 +142,10 @@ function _makeIntersectionConfig(id, name, { fixedNsGreen } = {}) {
|
|
|
ew: { phaseName: phases[1], time: countdown, isGreen: !nsGreen },
|
|
ew: { phaseName: phases[1], time: countdown, isGreen: !nsGreen },
|
|
|
},
|
|
},
|
|
|
armsConfig: {
|
|
armsConfig: {
|
|
|
- N: { cameraType: armCamTypes.N, lanes: lanePresets[0] },
|
|
|
|
|
- S: { cameraType: armCamTypes.S, lanes: lanePresets[1] },
|
|
|
|
|
- E: { cameraType: armCamTypes.E, lanes: lanePresets[2] },
|
|
|
|
|
- W: { cameraType: armCamTypes.W, lanes: lanePresets[3] },
|
|
|
|
|
|
|
+ N: { cameraType: armCamTypes.N, lanes: lanesPreset.N },
|
|
|
|
|
+ S: { cameraType: armCamTypes.S, lanes: lanesPreset.S },
|
|
|
|
|
+ E: { cameraType: armCamTypes.E, lanes: lanesPreset.E },
|
|
|
|
|
+ W: { cameraType: armCamTypes.W, lanes: lanesPreset.W },
|
|
|
},
|
|
},
|
|
|
cameras,
|
|
cameras,
|
|
|
}
|
|
}
|
|
@@ -145,9 +156,9 @@ function _makeIntersectionConfig(id, name, { fixedNsGreen } = {}) {
|
|
|
* @param {number} cycleLength 周期总时长
|
|
* @param {number} cycleLength 周期总时长
|
|
|
* @param {boolean} isTwoRows 是否生成上下双排 8 相位 (默认 true)
|
|
* @param {boolean} isTwoRows 是否生成上下双排 8 相位 (默认 true)
|
|
|
*/
|
|
*/
|
|
|
-function _makePhaseData(cycleLength = 140, isTwoRows = true) {
|
|
|
|
|
|
|
+function _makePhaseData(cycleLength = 140, isTwoRows = true, iconMode = 'default') {
|
|
|
const n = 4; // 4个阶段 (S1-S4)
|
|
const n = 4; // 4个阶段 (S1-S4)
|
|
|
- const stageTime = Math.floor(cycleLength / n);
|
|
|
|
|
|
|
+ const stageTime = Math.floor(cycleLength / n);
|
|
|
const pd = [];
|
|
const pd = [];
|
|
|
|
|
|
|
|
// ==========================================
|
|
// ==========================================
|
|
@@ -155,12 +166,21 @@ function _makePhaseData(cycleLength = 140, isTwoRows = true) {
|
|
|
// 前端组件会按逗号切割并分别放到对角位置
|
|
// 前端组件会按逗号切割并分别放到对角位置
|
|
|
// ==========================================
|
|
// ==========================================
|
|
|
// 固定4个阶段的图标和方向:P1南北直行、P2南北左转、P3东西直行、P4东西左转
|
|
// 固定4个阶段的图标和方向:P1南北直行、P2南北左转、P3东西直行、P4东西左转
|
|
|
- const phaseConfig = [
|
|
|
|
|
- { icon: 'STRAIGHT_DOWN,STRAIGHT_UP', direction: 'ns' }, // P1: 南北直行
|
|
|
|
|
- { icon: 'TURN_DOWN_LEFT,TURN_UP_LEFT', direction: 'ns' }, // P2: 南北左转
|
|
|
|
|
- { icon: 'STRAIGHT_LEFT,STRAIGHT_RIGHT', direction: 'ew' }, // P3: 东西直行
|
|
|
|
|
- { icon: 'TURN_LEFT_DOWN,TURN_RIGHT_UP', direction: 'ew' }, // P4: 东西左转
|
|
|
|
|
- ];
|
|
|
|
|
|
|
+ const phaseConfigMap = {
|
|
|
|
|
+ default: [
|
|
|
|
|
+ { icon: 'STRAIGHT_DOWN,STRAIGHT_UP', direction: 'ns' }, // P1: 南北直行
|
|
|
|
|
+ { icon: 'TURN_DOWN_LEFT,TURN_UP_LEFT', direction: 'ns' }, // P2: 南北左转
|
|
|
|
|
+ { icon: 'STRAIGHT_LEFT,STRAIGHT_RIGHT', direction: 'ew' }, // P3: 东西直行
|
|
|
|
|
+ { icon: 'TURN_LEFT_DOWN,TURN_RIGHT_UP', direction: 'ew' }, // P4: 东西左转
|
|
|
|
|
+ ],
|
|
|
|
|
+ simple: [
|
|
|
|
|
+ { icon: 'STRAIGHT_DOWN,STRAIGHT_UP', direction: 'ns' }, // P1: 南北直行
|
|
|
|
|
+ { icon: 'TURN_DOWN_LEFT,TURN_UP_LEFT_UTURN', direction: 'ns' }, // P2: 北左转+南掉头
|
|
|
|
|
+ { icon: 'STRAIGHT_LEFT,STRAIGHT_RIGHT', direction: 'ew' }, // P3: 东西直行
|
|
|
|
|
+ { icon: 'TURN_LEFT_DOWN,TURN_RIGHT_UP_UTURN', direction: 'ew' }, // P4: 东左转+西掉头
|
|
|
|
|
+ ],
|
|
|
|
|
+ };
|
|
|
|
|
+ const phaseConfig = phaseConfigMap[iconMode] || phaseConfigMap.default;
|
|
|
|
|
|
|
|
let t = 0;
|
|
let t = 0;
|
|
|
for (let i = 0; i < n; i++) {
|
|
for (let i = 0; i < n; i++) {
|
|
@@ -786,7 +806,7 @@ export async function apiGetSpecialTaskMonitorData(id, { fixedNsGreen } = {}) {
|
|
|
export async function apiGetCrossingPanelData(id) {
|
|
export async function apiGetCrossingPanelData(id) {
|
|
|
await delay(300)
|
|
await delay(300)
|
|
|
const point = DB.points.find(p => p.id === id)
|
|
const point = DB.points.find(p => p.id === id)
|
|
|
- const config = DB.intersectionConfigs[id] || _makeIntersectionConfig(id, null, { fixedNsGreen: false })
|
|
|
|
|
|
|
+ const config = DB.intersectionConfigs[id] || _makeIntersectionConfig(id, null, { fixedNsGreen: false, iconMode: 'simple' })
|
|
|
const seed = id ? id.charCodeAt(id.length - 1) : 0
|
|
const seed = id ? id.charCodeAt(id.length - 1) : 0
|
|
|
// 确保 config 有 status
|
|
// 确保 config 有 status
|
|
|
if (!config.status) {
|
|
if (!config.status) {
|
|
@@ -795,7 +815,7 @@ export async function apiGetCrossingPanelData(id) {
|
|
|
|
|
|
|
|
const preset = DB.signalTimings[id]
|
|
const preset = DB.signalTimings[id]
|
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][Math.abs(seed) % 6]
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][Math.abs(seed) % 6]
|
|
|
- const phaseData = preset ? preset.data.phaseData : _makePhaseData(cycleLength, false)
|
|
|
|
|
|
|
+ const phaseData = preset ? preset.data.phaseData : _makePhaseData(cycleLength, false, 'simple')
|
|
|
const currentTime = Math.floor(Date.now() / 1000) % cycleLength
|
|
const currentTime = Math.floor(Date.now() / 1000) % cycleLength
|
|
|
|
|
|
|
|
return ok({
|
|
return ok({
|
|
@@ -814,10 +834,10 @@ export async function apiGetCrossingPanelData(id) {
|
|
|
/**
|
|
/**
|
|
|
* GET /api/crossing/detail/:id — CrossingDetailPanel 弹窗
|
|
* GET /api/crossing/detail/:id — CrossingDetailPanel 弹窗
|
|
|
*/
|
|
*/
|
|
|
-export async function apiGetCrossingDetailData(id) {
|
|
|
|
|
|
|
+export async function apiGetCrossingDetailData(id, { iconMode = 'default' } = {}) {
|
|
|
await delay(350)
|
|
await delay(350)
|
|
|
const point = DB.points.find(p => p.id === id)
|
|
const point = DB.points.find(p => p.id === id)
|
|
|
- const config = DB.intersectionConfigs[id] || _makeIntersectionConfig(id, null, { fixedNsGreen: false })
|
|
|
|
|
|
|
+ const config = DB.intersectionConfigs[id] || _makeIntersectionConfig(id, null, { fixedNsGreen: false, iconMode })
|
|
|
|
|
|
|
|
// 用 id 的全部字符生成稳定 seed(加权位置避免 charCode 总和碰撞)
|
|
// 用 id 的全部字符生成稳定 seed(加权位置避免 charCode 总和碰撞)
|
|
|
const seed = id ? Array.from(id).reduce((s, c, i) => s + c.charCodeAt(0) * (i + 1), 0) : 0
|
|
const seed = id ? Array.from(id).reduce((s, c, i) => s + c.charCodeAt(0) * (i + 1), 0) : 0
|
|
@@ -830,7 +850,7 @@ export async function apiGetCrossingDetailData(id) {
|
|
|
// 从真实阶段数据推导周期和相位
|
|
// 从真实阶段数据推导周期和相位
|
|
|
const preset = DB.signalTimings[id]
|
|
const preset = DB.signalTimings[id]
|
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][seed % 6]
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][seed % 6]
|
|
|
- const phaseData = preset ? preset.data.phaseData : _makePhaseData(cycleLength || 140, false)
|
|
|
|
|
|
|
+ const phaseData = preset ? preset.data.phaseData : _makePhaseData(cycleLength || 140, false, iconMode)
|
|
|
|
|
|
|
|
// 从相位数据中提取阶段列表(优先上轨道绿灯相位,单轨道时取 track 0,最多4个)
|
|
// 从相位数据中提取阶段列表(优先上轨道绿灯相位,单轨道时取 track 0,最多4个)
|
|
|
const hasTrack1 = phaseData.some(p => p[0] === 1)
|
|
const hasTrack1 = phaseData.some(p => p[0] === 1)
|