|
@@ -33,6 +33,8 @@ import { LOCATE_RESULT, locateFailureText, planLocate } from '../domain/mapLocat
|
|
|
import { TERRAIN_LOCATE_REASON } from '../domain/pointLocate.js'
|
|
import { TERRAIN_LOCATE_REASON } from '../domain/pointLocate.js'
|
|
|
import {
|
|
import {
|
|
|
fetchMonitoringDistribution,
|
|
fetchMonitoringDistribution,
|
|
|
|
|
+ fetchMonitoringDistributionBatch,
|
|
|
|
|
+ monitoringDistributionInputs,
|
|
|
fetchMonitoringOverview,
|
|
fetchMonitoringOverview,
|
|
|
fetchMonitoringSituation,
|
|
fetchMonitoringSituation,
|
|
|
} from '../services/monitoringApi.js'
|
|
} from '../services/monitoringApi.js'
|
|
@@ -40,6 +42,7 @@ import { fetchMonitoringPointDetail } from '../services/detailApi.js'
|
|
|
import { getCameraState, locateMonitoringPoint } from '../services/mapService.js'
|
|
import { getCameraState, locateMonitoringPoint } from '../services/mapService.js'
|
|
|
import { useDetailStore } from './detailStore.js'
|
|
import { useDetailStore } from './detailStore.js'
|
|
|
import { useMapStore } from './mapStore.js'
|
|
import { useMapStore } from './mapStore.js'
|
|
|
|
|
+import { sameInputs } from '../domain/panelViewCache.js'
|
|
|
// 票 41:监测点选择的统一入口(与地图点选共用同一个函数)。
|
|
// 票 41:监测点选择的统一入口(与地图点选共用同一个函数)。
|
|
|
import { selectMonitoringPoint } from '../pointSelection.js'
|
|
import { selectMonitoringPoint } from '../pointSelection.js'
|
|
|
|
|
|
|
@@ -51,7 +54,7 @@ function pending() {
|
|
|
/** 该把哪个 panelId 喂给哪个取数函数 —— 台账**不在**这里(它与分布共用一次取数)。 */
|
|
/** 该把哪个 panelId 喂给哪个取数函数 —— 台账**不在**这里(它与分布共用一次取数)。 */
|
|
|
const FETCHERS = {
|
|
const FETCHERS = {
|
|
|
monitoringOverview: fetchMonitoringOverview,
|
|
monitoringOverview: fetchMonitoringOverview,
|
|
|
- monitoringDistribution: fetchMonitoringDistribution,
|
|
|
|
|
|
|
+ monitoringDistribution: fetchMonitoringDistributionBatch,
|
|
|
operationOverview: fetchMonitoringSituation,
|
|
operationOverview: fetchMonitoringSituation,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -123,6 +126,8 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
|
|
|
|
|
/** 台账装载器(幂等;`setup` 时按当前条件建一次)。 */
|
|
/** 台账装载器(幂等;`setup` 时按当前条件建一次)。 */
|
|
|
let ledgerLoader = null
|
|
let ledgerLoader = null
|
|
|
|
|
+ /** loader内部集合所属的有效请求输入;新轮/漂移时清空,reuse不能复活旧页。 */
|
|
|
|
|
+ let ledgerInputs = null
|
|
|
|
|
|
|
|
/** 自动链两批之间的间隔(票 62:给渲染与交互留一口气,不一次打满请求)。 */
|
|
/** 自动链两批之间的间隔(票 62:给渲染与交互留一口气,不一次打满请求)。 */
|
|
|
const LEDGER_AUTO_BATCH_GAP_MS = 16
|
|
const LEDGER_AUTO_BATCH_GAP_MS = 16
|
|
@@ -180,6 +185,11 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const active = activeOptions()
|
|
const active = activeOptions()
|
|
|
|
|
+ const firstPageInputs = monitoringDistributionInputs(active)
|
|
|
|
|
+ // 新一轮开始就作废旧台账写入/下一页;不能等三块面板返回后才换纪元。
|
|
|
|
|
+ const initialLedgerEpoch = ++ledgerEpoch
|
|
|
|
|
+ ledgerInputs = null
|
|
|
|
|
+ let firstPage
|
|
|
const window = rangeWindow(trendRange.value)
|
|
const window = rangeWindow(trendRange.value)
|
|
|
|
|
|
|
|
token += 1
|
|
token += 1
|
|
@@ -189,7 +199,12 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
const results = await Promise.all(
|
|
const results = await Promise.all(
|
|
|
INDEPENDENT_PANELS.map(async (panelId) => {
|
|
INDEPENDENT_PANELS.map(async (panelId) => {
|
|
|
try {
|
|
try {
|
|
|
- return [panelId, await FETCHERS[panelId]({ ...active, ...(panelId === 'operationOverview' ? window : {}) })]
|
|
|
|
|
|
|
+ const result = await FETCHERS[panelId]({ ...active, ...(panelId === 'operationOverview' ? window : {}) })
|
|
|
|
|
+ if (panelId === 'monitoringDistribution') {
|
|
|
|
|
+ firstPage = result.firstPage
|
|
|
|
|
+ return [panelId, result.section]
|
|
|
|
|
+ }
|
|
|
|
|
+ return [panelId, result]
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
// 与票 11/17 同款兜底:适配层不抛,但转换层万一抛了要收成一条失败分区,
|
|
// 与票 11/17 同款兜底:适配层不抛,但转换层万一抛了要收成一条失败分区,
|
|
|
// 不能把面板卡在「加载中」(用户还得能看见其它块)。
|
|
// 不能把面板卡在「加载中」(用户还得能看见其它块)。
|
|
@@ -211,9 +226,10 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
sections.value = next
|
|
sections.value = next
|
|
|
loading.value = false
|
|
loading.value = false
|
|
|
|
|
|
|
|
- // 票 62:台账不再读分布的这一次响应(分布只回第 1 页切片、也不保证装载完整),
|
|
|
|
|
- // 改由**自己的自动装载链**取全(下方 `loadLedgerChain`)。两者并发:台账慢不拖住其它三块。
|
|
|
|
|
- const chain = loadLedgerChain('refresh')
|
|
|
|
|
|
|
+ // 台账仍有独立自动链;同轮成功首批可复用,后续页仍按其快照token装载到完整。
|
|
|
|
|
+ const sameRequest = initialLedgerEpoch === ledgerEpoch &&
|
|
|
|
|
+ sameInputs(firstPageInputs, monitoringDistributionInputs({ ...activeOptions(), page: 1 }))
|
|
|
|
|
+ const chain = loadLedgerChain('refresh', sameRequest ? firstPage : undefined)
|
|
|
await chain
|
|
await chain
|
|
|
return sections.value
|
|
return sections.value
|
|
|
}
|
|
}
|
|
@@ -275,19 +291,29 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
* @param {'refresh'|'reuse'} kind `refresh`=换新快照并自动连翻到 settled;
|
|
* @param {'refresh'|'reuse'} kind `refresh`=换新快照并自动连翻到 settled;
|
|
|
* `reuse`=还在同一快照有效期内,**只补没取完的部分**(定时刷新走这条,不重放全链)
|
|
* `reuse`=还在同一快照有效期内,**只补没取完的部分**(定时刷新走这条,不重放全链)
|
|
|
*/
|
|
*/
|
|
|
- async function loadLedgerChain(kind = 'refresh') {
|
|
|
|
|
|
|
+ async function loadLedgerChain(kind = 'refresh', firstPage) {
|
|
|
const loader = ensureLedgerLoader()
|
|
const loader = ensureLedgerLoader()
|
|
|
|
|
+ const inputs = monitoringDistributionInputs({ ...activeOptions(), page: 1 })
|
|
|
|
|
+ const reuse = kind === 'reuse' && sameInputs(ledgerInputs, inputs)
|
|
|
const mine = ++ledgerEpoch
|
|
const mine = ++ledgerEpoch
|
|
|
- const started = kind === 'refresh' ? await loader.refresh() : loader.getState()
|
|
|
|
|
- if (mine !== ledgerEpoch) return sections.value.monitoringPointLedger
|
|
|
|
|
|
|
+ if (!reuse) ledgerInputs = null
|
|
|
|
|
+ const stillCurrent = () => {
|
|
|
|
|
+ if (mine !== ledgerEpoch) return false
|
|
|
|
|
+ if (sameInputs(inputs, monitoringDistributionInputs({ ...activeOptions(), page: 1 }))) return true
|
|
|
|
|
+ ledgerInputs = null
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ const started = reuse ? loader.getState() : await loader.refresh(firstPage)
|
|
|
|
|
+ if (!stillCurrent()) return sections.value.monitoringPointLedger
|
|
|
|
|
+ ledgerInputs = inputs
|
|
|
syncLedgerSection(started)
|
|
syncLedgerSection(started)
|
|
|
|
|
|
|
|
let state = started
|
|
let state = started
|
|
|
- while (mine === ledgerEpoch && !ledgerSettledForAuto(state)) {
|
|
|
|
|
|
|
+ while (stillCurrent() && !ledgerSettledForAuto(state)) {
|
|
|
await new Promise((resolve) => setTimeout(resolve, LEDGER_AUTO_BATCH_GAP_MS))
|
|
await new Promise((resolve) => setTimeout(resolve, LEDGER_AUTO_BATCH_GAP_MS))
|
|
|
- if (mine !== ledgerEpoch) break
|
|
|
|
|
|
|
+ if (!stillCurrent()) break
|
|
|
state = await loader.loadNext()
|
|
state = await loader.loadNext()
|
|
|
- if (mine !== ledgerEpoch) break
|
|
|
|
|
|
|
+ if (!stillCurrent()) break
|
|
|
syncLedgerSection(state)
|
|
syncLedgerSection(state)
|
|
|
// 失败/过期不自动重试(决策 04):停链,等新鲜度周期或手动入口。
|
|
// 失败/过期不自动重试(决策 04):停链,等新鲜度周期或手动入口。
|
|
|
if (state.phase === 'failed' || state.phase === 'expired') break
|
|
if (state.phase === 'failed' || state.phase === 'expired') break
|
|
@@ -308,6 +334,7 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
* 已 settled 的台账**一个请求都不发**。
|
|
* 已 settled 的台账**一个请求都不发**。
|
|
|
*/
|
|
*/
|
|
|
async function reuseLedgerSnapshot() {
|
|
async function reuseLedgerSnapshot() {
|
|
|
|
|
+ if (!sameInputs(ledgerInputs, monitoringDistributionInputs({ ...activeOptions(), page: 1 }))) return loadLedgerChain('refresh')
|
|
|
const state = ledger.state
|
|
const state = ledger.state
|
|
|
if (!state) return loadLedgerChain('refresh')
|
|
if (!state) return loadLedgerChain('refresh')
|
|
|
if (ledgerSettledForAuto(state)) return sections.value.monitoringPointLedger
|
|
if (ledgerSettledForAuto(state)) return sections.value.monitoringPointLedger
|
|
@@ -321,7 +348,9 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
*/
|
|
*/
|
|
|
async function loadMoreLedger() {
|
|
async function loadMoreLedger() {
|
|
|
const state = ledger.state
|
|
const state = ledger.state
|
|
|
- if (!state || ledgerSettledForAuto(state)) return sections.value.monitoringPointLedger
|
|
|
|
|
|
|
+ if (!state) return sections.value.monitoringPointLedger
|
|
|
|
|
+ if (!sameInputs(ledgerInputs, monitoringDistributionInputs({ ...activeOptions(), page: 1 }))) return loadLedgerChain('refresh')
|
|
|
|
|
+ if (ledgerSettledForAuto(state)) return sections.value.monitoringPointLedger
|
|
|
return loadLedgerChain('reuse')
|
|
return loadLedgerChain('reuse')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -426,6 +455,7 @@ export const useMonitoringStore = defineStore('monitoringStore', () => {
|
|
|
token += 1
|
|
token += 1
|
|
|
ledgerEpoch += 1
|
|
ledgerEpoch += 1
|
|
|
ledgerLoader = null
|
|
ledgerLoader = null
|
|
|
|
|
+ ledgerInputs = null
|
|
|
ledger.state = null
|
|
ledger.state = null
|
|
|
sections.value = Object.fromEntries(MONITORING_PANEL_IDS.map((panelId) => [panelId, pending()]))
|
|
sections.value = Object.fromEntries(MONITORING_PANEL_IDS.map((panelId) => [panelId, pending()]))
|
|
|
badges.value = {}
|
|
badges.value = {}
|