|
|
@@ -438,6 +438,23 @@ export async function apiGetTrunkLineMenuTree() {
|
|
|
* GET /api/devices/status/summary
|
|
|
* 在线数每次请求轻微波动
|
|
|
*/
|
|
|
+// ── 信号机故障数缓存:同一秒内多次调用返回同一份数据,保证在线离线与故障同步 ──
|
|
|
+let _smFaultCache = { ts: 0, total: 0, faultTotal: 0 }
|
|
|
+function _getSmFaultSnapshot() {
|
|
|
+ const now = Math.floor(Date.now() / 1000)
|
|
|
+ if (_smFaultCache.ts === now) return _smFaultCache
|
|
|
+ const sm = DB.deviceStatus.signalMachine
|
|
|
+ const total = sm.chartData[0].value + sm.chartData[1].value
|
|
|
+ const yellowFlashMode = DB.homeData.controlModes.find(m => m.name === '黄闪控制')
|
|
|
+ const yellowFlash = yellowFlashMode ? yellowFlashMode.value : 0
|
|
|
+ const ctrlBoard = Math.max(0, _fluctuate(5, 3))
|
|
|
+ const phaseBoard = Math.max(0, _fluctuate(4, 2))
|
|
|
+ const detBoard = Math.max(0, _fluctuate(3, 2))
|
|
|
+ const faultTotal = ctrlBoard + phaseBoard + detBoard + yellowFlash
|
|
|
+ _smFaultCache = { ts: now, total, faultTotal, ctrlBoard, phaseBoard, detBoard, yellowFlash }
|
|
|
+ return _smFaultCache
|
|
|
+}
|
|
|
+
|
|
|
export async function apiGetDeviceStatus(type) {
|
|
|
await delay(200)
|
|
|
function fluctuateStats(base) {
|
|
|
@@ -455,9 +472,24 @@ export async function apiGetDeviceStatus(type) {
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
+ // 信号机:离线数 = 故障总数(与设备状态同步)
|
|
|
+ function smStats() {
|
|
|
+ const snap = _getSmFaultSnapshot()
|
|
|
+ const online = snap.total - snap.faultTotal
|
|
|
+ const rate = Math.round(online / snap.total * 100)
|
|
|
+ return {
|
|
|
+ centerTitle: rate + '%',
|
|
|
+ centerSubTitle: `${online}/${snap.total}`,
|
|
|
+ chartData: [
|
|
|
+ { name: '在线', value: online, color: '#32F6F8' },
|
|
|
+ { name: '离线', value: snap.faultTotal, color: '#E4D552' },
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type === 'signalMachine') return ok(smStats())
|
|
|
if (type && DB.deviceStatus[type]) return ok(fluctuateStats(DB.deviceStatus[type]))
|
|
|
return ok({
|
|
|
- signalMachine: fluctuateStats(DB.deviceStatus.signalMachine),
|
|
|
+ signalMachine: smStats(),
|
|
|
detector: fluctuateStats(DB.deviceStatus.detector),
|
|
|
camera: fluctuateStats(DB.deviceStatus.camera),
|
|
|
})
|
|
|
@@ -488,12 +520,20 @@ export async function apiGetHomeSnapshot() {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-/** GET /api/home/control-mode-stats — 控制模式分布(轻微波动) */
|
|
|
+/** GET /api/home/control-mode-stats — 控制模式分布(总数与信号机总数同步,内部重分配) */
|
|
|
export async function apiGetControlModeStats() {
|
|
|
await delay(150)
|
|
|
- return ok(DB.homeData.controlModes.map(m => ({
|
|
|
- ...m, value: _fluctuate(m.value, Math.ceil(m.value * 0.05)),
|
|
|
- })))
|
|
|
+ const sm = DB.deviceStatus.signalMachine
|
|
|
+ const total = sm.chartData[0].value + sm.chartData[1].value
|
|
|
+ const modes = DB.homeData.controlModes
|
|
|
+ // 各项按基准值波动
|
|
|
+ const fluctuated = modes.map(m => ({
|
|
|
+ ...m, value: Math.max(0, _fluctuate(m.value, Math.ceil(m.value * 0.05))),
|
|
|
+ }))
|
|
|
+ // 修正总数:将差值补到第一项(定周期控制),保证总数 = 信号机总数
|
|
|
+ const currentSum = fluctuated.reduce((s, m) => s + m.value, 0)
|
|
|
+ fluctuated[0].value = Math.max(0, fluctuated[0].value + (total - currentSum))
|
|
|
+ return ok(fluctuated)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1029,41 +1069,51 @@ export async function apiGetMapLegendConfig() {
|
|
|
*/
|
|
|
export async function apiGetDeviceFaultStatus() {
|
|
|
await delay(200)
|
|
|
- const sm = DB.deviceStatus.signalMachine
|
|
|
const dt = DB.deviceStatus.detector
|
|
|
const cam = DB.deviceStatus.camera
|
|
|
|
|
|
- // 从在线数据推算故障数,每次波动
|
|
|
- const smTotal = sm.chartData[0].value + sm.chartData[1].value
|
|
|
- const smFault = 0 // 信号机无故障,用于测试无故障状态
|
|
|
+ // ── 信号机故障:从共享缓存获取,确保与在线状态的离线数一致 ──
|
|
|
+ const snap = _getSmFaultSnapshot()
|
|
|
+ const smTotal = snap.total
|
|
|
+ const smFaultTotal = snap.faultTotal
|
|
|
+ const smFaultList = [
|
|
|
+ { name: '正常', value: Math.max(0, smTotal - smFaultTotal), color: '#A0E551' },
|
|
|
+ { name: '控制板报警', value: snap.ctrlBoard, color: '#FF4545' },
|
|
|
+ { name: '相位板报警', value: snap.phaseBoard, color: '#D42A2A' },
|
|
|
+ { name: '检测板报警', value: snap.detBoard, color: '#9B1B1B' },
|
|
|
+ { name: '黄闪报警', value: snap.yellowFlash, color: '#5C0E0E' },
|
|
|
+ ]
|
|
|
+
|
|
|
+ // ── 检测器故障 ──
|
|
|
const dtTotal = dt.chartData[0].value + dt.chartData[1].value
|
|
|
- const dtFault = _fluctuate(dt.chartData[1].value, 5)
|
|
|
+ const dtFault = Math.max(0, _fluctuate(dt.chartData[1].value, 5))
|
|
|
+ const dtCommFault = Math.max(0, Math.floor(dtFault * 0.6))
|
|
|
+
|
|
|
+ // ── 红绿灯故障 ──
|
|
|
const camTotal = cam.chartData[0].value + cam.chartData[1].value
|
|
|
- const camFault = _fluctuate(cam.chartData[1].value, 2)
|
|
|
+ const camFault = Math.max(0, _fluctuate(cam.chartData[1].value, 2))
|
|
|
+ const camConflict = Math.max(0, Math.floor(camFault * 0.5))
|
|
|
|
|
|
return ok({
|
|
|
signalMachineStatus: {
|
|
|
- centerTitle: Math.max(0, smFault) + '',
|
|
|
- centerSubTitle: `${Math.max(0, smFault)}/${smTotal}`,
|
|
|
- chartData: [
|
|
|
- { name: '正常', value: Math.max(0, smTotal - smFault), color: '#A0E551' },
|
|
|
- { name: '故障', value: Math.max(0, smFault), color: '#D03030' },
|
|
|
- ]
|
|
|
+ centerTitle: smFaultTotal + '',
|
|
|
+ centerSubTitle: `${smFaultTotal}/${smTotal}`,
|
|
|
+ chartData: smFaultList,
|
|
|
},
|
|
|
detectorStatus: {
|
|
|
- centerTitle: Math.max(0, dtFault) + '',
|
|
|
- centerSubTitle: `${Math.max(0, dtFault)}/${dtTotal}`,
|
|
|
+ centerTitle: dtFault + '',
|
|
|
+ centerSubTitle: `${dtFault}/${dtTotal}`,
|
|
|
chartData: [
|
|
|
- { name: '通信故障', value: Math.max(0, Math.floor(dtFault * 0.6)), color: '#C6302B' },
|
|
|
- { name: '数据异常', value: Math.max(0, dtFault - Math.floor(dtFault * 0.6)), color: '#faad14' },
|
|
|
+ { name: '通信故障', value: dtCommFault, color: '#C6302B' },
|
|
|
+ { name: '数据异常', value: Math.max(0, dtFault - dtCommFault), color: '#faad14' },
|
|
|
]
|
|
|
},
|
|
|
trafficLightStatus: {
|
|
|
- centerTitle: Math.max(0, camFault) + '',
|
|
|
- centerSubTitle: `${Math.max(0, camFault)}/${camTotal}`,
|
|
|
+ centerTitle: camFault + '',
|
|
|
+ centerSubTitle: `${camFault}/${camTotal}`,
|
|
|
chartData: [
|
|
|
- { name: '红绿冲突', value: Math.max(0, Math.floor(camFault * 0.5)), color: '#C6302B' },
|
|
|
- { name: '红灯故障', value: Math.max(0, camFault - Math.floor(camFault * 0.5)), color: '#8F1E1E' },
|
|
|
+ { name: '红绿冲突', value: camConflict, color: '#C6302B' },
|
|
|
+ { name: '红灯故障', value: Math.max(0, camFault - camConflict), color: '#8F1E1E' },
|
|
|
]
|
|
|
},
|
|
|
})
|