|
|
@@ -37,6 +37,13 @@ function delay(base = 200) { return sleep(base + Math.floor(Math.random() * 200)
|
|
|
function ok(data) { return { code: 200, message: 'success', data } }
|
|
|
function fail(msg, code = 400) { return { code, message: msg, data: null } }
|
|
|
|
|
|
+/** 根据路口ID生成稳定的设备状态(所有API共用,确保一致) */
|
|
|
+function _getDeviceStatus(id) {
|
|
|
+ const seed = id ? Array.from(id).reduce((s, c, i) => s + c.charCodeAt(0) * (i + 1), 0) : 0
|
|
|
+ const statusList = ['在线', '在线', '在线', '在线', '在线', '在线', '在线', '离线']
|
|
|
+ return statusList[seed % statusList.length]
|
|
|
+}
|
|
|
+
|
|
|
/** 基于当前秒数产生稳定随机(同一秒内多次调用返回相同值) */
|
|
|
function seededRand(seed) {
|
|
|
const x = Math.sin(seed) * 10000
|
|
|
@@ -118,6 +125,7 @@ function _makeIntersectionConfig(id, name, { fixedNsGreen } = {}) {
|
|
|
]
|
|
|
|
|
|
return {
|
|
|
+ status: _getDeviceStatus(id),
|
|
|
signals: {
|
|
|
ns: { phaseName: phases[0], time: countdown, isGreen: nsGreen },
|
|
|
ew: { phaseName: phases[1], time: countdown, isGreen: !nsGreen },
|
|
|
@@ -330,6 +338,7 @@ export async function apiGetIntersectionData(id, { fixedNsGreen } = {}) {
|
|
|
const nsGreen = nsGreenVal
|
|
|
|
|
|
const config = base ? {
|
|
|
+ status: base.status || _getDeviceStatus(id),
|
|
|
signals: {
|
|
|
ns: { ...base.signals.ns, time: Math.max(1, cycle - elapsed), isGreen: nsGreen },
|
|
|
ew: { ...base.signals.ew, time: elapsed || 1, isGreen: !nsGreen },
|
|
|
@@ -606,7 +615,7 @@ export async function apiGetCrossingList(params = {}) {
|
|
|
const phaseData = _makePhaseData(cycleLength, false)
|
|
|
return {
|
|
|
...r,
|
|
|
- status: statuses[Math.floor(seededRand(i + 42) * statuses.length)],
|
|
|
+ status: _getDeviceStatus(r.id),
|
|
|
cycle: cycleLength,
|
|
|
phaseData,
|
|
|
currentTime: Math.floor(seededRand(i * 31 + page * 97) * cycleLength),
|
|
|
@@ -788,6 +797,10 @@ export async function apiGetCrossingPanelData(id) {
|
|
|
const point = DB.points.find(p => p.id === id)
|
|
|
const config = DB.intersectionConfigs[id] || _makeIntersectionConfig(id, null, { fixedNsGreen: false })
|
|
|
const seed = id ? id.charCodeAt(id.length - 1) : 0
|
|
|
+ // 确保 config 有 status
|
|
|
+ if (!config.status) {
|
|
|
+ config.status = _getDeviceStatus(id)
|
|
|
+ }
|
|
|
|
|
|
const preset = DB.signalTimings[id]
|
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][Math.abs(seed) % 6]
|
|
|
@@ -818,6 +831,11 @@ export async function apiGetCrossingDetailData(id) {
|
|
|
// 用 id 的全部字符生成稳定 seed(加权位置避免 charCode 总和碰撞)
|
|
|
const seed = id ? Array.from(id).reduce((s, c, i) => s + c.charCodeAt(0) * (i + 1), 0) : 0
|
|
|
|
|
|
+ // 确保 config 有 status 字段(预存配置可能缺失)
|
|
|
+ if (!config.status) {
|
|
|
+ config.status = _getDeviceStatus(id)
|
|
|
+ }
|
|
|
+
|
|
|
// 从真实阶段数据推导周期和相位
|
|
|
const preset = DB.signalTimings[id]
|
|
|
const cycleLength = preset ? preset.data.cycleLength : [100, 120, 130, 140, 150, 160][seed % 6]
|