/** * GYXX 工作台面板 —— 极简外部存储(避免向客户端包引入额外依赖)。 * React 18 的 useSyncExternalStore 直接订阅。 */ const listeners = new Set() let state = { open: false, loading: false, error: null, generatedAt: null, summary: null, workflows: [], selectedId: null, detail: null, detailLoading: false, runs: [], diagnosis: null, diagnosisLoading: false, question: '', businessDate: defaultBusinessDate(), alerts: [], seenAlertIds: {}, toasts: [], } export function defaultBusinessDate() { const now = new Date() now.setDate(now.getDate() - 1) const pad = (value) => String(value).padStart(2, '0') return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}` } export function getState() { return state } export function update(patch) { state = { ...state, ...patch } for (const listener of listeners) listener() } export function subscribe(listener) { listeners.add(listener) return () => listeners.delete(listener) } export function pushToast(toast) { const id = `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}` update({ toasts: [...state.toasts, { id, ...toast }] }) return id } export function dismissToast(id) { update({ toasts: state.toasts.filter((toast) => toast.id !== id) }) }