import { readFileSync } from 'node:fs' import { registerHooks } from 'node:module' import { parse, compileScript, compileTemplate } from '@vue/compiler-sfc' const SRC = '../../../../../src/modules/cockpit/' const ENV_STUB = 'const import_meta_env = { BASE_URL: "/", MODE: "development", DEV: true, PROD: false, SSR: false };' registerHooks({ load(url, context, nextLoad) { if (url.endsWith('.json')) return { format: 'module', shortCircuit: true, source: 'export default ' + readFileSync(new URL(url), 'utf8') } if (url.endsWith('.css')) return { format: 'module', shortCircuit: true, source: 'export default {}' } if (url.endsWith('.js') && url.includes('/src/')) { const raw = readFileSync(new URL(url), 'utf8') if (raw.includes('import.meta.env')) return { format: 'module', shortCircuit: true, source: ENV_STUB + raw.replace(/import\.meta\.env/g, 'import_meta_env') } } if (url.endsWith('.vue')) { const source = readFileSync(new URL(url), 'utf8') const { descriptor } = parse(source, { filename: url }) const script = compileScript(descriptor, { id: 'replay', genDefaultAs: '__sfc__' }) const template = compileTemplate({ source: descriptor.template.content, filename: url, id: 'replay', ssr: true, compilerOptions: { bindingMetadata: script.bindings } }) const body = script.content.replace(/import\.meta\.env/g, 'import_meta_env') return { format: 'module', shortCircuit: true, source: ENV_STUB + '\n' + body + '\n' + template.code + '\n__sfc__.ssrRender = ssrRender; export default __sfc__;' } } return nextLoad(url, context) }, }) // 最小 DOM/window stub(启动计划里只有 WS/字体/计时器需要它们) const noop = () => {} globalThis.window = globalThis.window || { addEventListener: noop, removeEventListener: noop, setTimeout, clearTimeout, setInterval, clearInterval, requestAnimationFrame: (cb) => setTimeout(() => cb(Date.now()), 16), cancelAnimationFrame: noop, devicePixelRatio: 1, innerWidth: 1680, innerHeight: 950, location: { href: 'http://127.0.0.1:8000/#/cockpit', search: '', hash: '#/cockpit', origin: 'http://127.0.0.1:8000' }, matchMedia: () => ({ matches: false, addEventListener: noop, removeEventListener: noop }), getComputedStyle: () => ({ getPropertyValue: () => '' }), ResizeObserver: class { observe() {} unobserve() {} disconnect() {} }, } globalThis.document = globalThis.document || { activeElement: null, visibilityState: 'visible', hidden: false, createElement: () => ({ style: {}, setAttribute: noop, appendChild: noop, addEventListener: noop, classList: { add: noop, remove: noop } }), createElementNS: () => ({ style: {}, setAttribute: noop, appendChild: noop, addEventListener: noop }), createTextNode: () => ({}), createComment: () => ({}), querySelector: () => null, querySelectorAll: () => [], getElementById: () => null, head: { appendChild: noop, children: [] }, body: { appendChild: noop, children: [] }, addEventListener: noop, removeEventListener: noop, } if (!globalThis.navigator) Object.defineProperty(globalThis, 'navigator', { value: { userAgent: 'node' }, configurable: true }) for (const k of ['ResizeObserver', 'matchMedia', 'getComputedStyle']) if (globalThis[k] === undefined) globalThis[k] = globalThis.window[k] const { createPinia, setActivePinia } = await import('pinia') setActivePinia(createPinia()) const { loadCockpitConfig } = await import(SRC + 'services/cockpitConfig.js') const { planCockpitStartup } = await import(SRC + 'domain/startupPlan.js') const { STARTUP_ACTION } = await import(SRC + 'domain/startupPlan.js') const { registerMockTransport, resetMockTransportsForTest } = await import(SRC + 'services/cockpitApi.js') const { registerCockpitMocks } = await import(SRC + 'mocks/contractMocks.js') const { useMapStore } = await import(SRC + 'stores/mapStore.js') const { useDetailStore } = await import(SRC + 'stores/detailStore.js') const { usePipeNetworkStore } = await import(SRC + 'stores/pipeNetworkStore.js') const { useInfrastructureStore } = await import(SRC + 'stores/infrastructureStore.js') const { useMonitoringStore } = await import(SRC + 'stores/monitoringStore.js') const { useEventStore } = await import(SRC + 'stores/eventStore.js') const { useOverviewStore } = await import(SRC + 'stores/overviewStore.js') const { useRuntimeStore } = await import(SRC + 'stores/runtimeStore.js') const { useFilterStore } = await import(SRC + 'stores/filterStore.js') const requests = [] resetMockTransportsForTest() registerCockpitMocks({ scenario: 'success', handlers: { registerMockTransport: (path, handler) => registerMockTransport(path, (req) => { requests.push(typeof req === 'string' ? req : JSON.stringify(req).slice(0, 120)); return handler(req) }), resetMockTransportsForTest, }, }) const result = await loadCockpitConfig() const plan = planCockpitStartup(result.config) console.log('config state =', result.state, 'dataSource =', result.config.dataSource) console.log('plan.actions =', plan.actions.join(', ')) const filterStore = useFilterStore() const mapStore = useMapStore() const detailStore = useDetailStore() const pipeNetworkStore = usePipeNetworkStore() const infrastructureStore = useInfrastructureStore() const monitoringStore = useMonitoringStore() const eventStore = useEventStore() const overviewStore = useOverviewStore() const runtimeStore = useRuntimeStore() const scope = { value: filterStore.scope } let failedAt = null for (const action of plan.actions) { try { if (action === STARTUP_ACTION.REGISTER_MOCKS) continue if (action === STARTUP_ACTION.LOAD_MAP_SUMMARY) { mapStore.setup({ config: result.config, industry: 'all', scope: 'all', deviceType: '', pointStatus: [] }); continue } if (action === STARTUP_ACTION.LOAD_SHARED_SECTIONS) { detailStore.loadSharedSections({ config: result.config }); pipeNetworkStore.load({ industry: 'all', scope: 'all', config: result.config }); continue } if (action === STARTUP_ACTION.LOAD_INFRASTRUCTURE_PANELS) { infrastructureStore.configure({ config: result.config }); infrastructureStore.loadPanels({ industry: 'all', scope: 'all' }); continue } if (action === STARTUP_ACTION.LOAD_MONITORING_PANELS) { monitoringStore.configure({ config: result.config }); monitoringStore.loadPanels({ industry: 'all', deviceType: '', pointStatus: [], scope: 'all' }); continue } if (action === STARTUP_ACTION.LOAD_EVENT_PANELS) { eventStore.configure({ config: result.config }); eventStore.loadPanels({ mode: 'WARNING', range: '7d', industry: 'all' }); continue } if (action === STARTUP_ACTION.LOAD_OVERVIEW_PANELS) { overviewStore.configure({ config: result.config }); overviewStore.loadPanels(); continue } if (action === STARTUP_ACTION.START_WEBSOCKET) { runtimeStore.startWithConfig(result.config, { scenario: 'success' }); continue } if (action === STARTUP_ACTION.START_FRESHNESS) { continue } } catch (error) { failedAt = action + ' → ' + (error && error.stack ? error.stack.split('\n').slice(0, 4).join(' | ') : error) break } } console.log('启动计划同步执行:', failedAt || '全部动作未抛错') await new Promise((r) => setTimeout(r, 300)) console.log('请求数 =', requests.length) console.log('mapStore.filters =', JSON.stringify(mapStore.filters)) console.log('mapStore.summary.phase =', mapStore.summary.phase) console.log('infrastructure 分区 loaded =', Object.entries(infrastructureStore.sections).map(([k, v]) => k + ':' + v.state + '/' + v.loaded).join(' ')) process.exit(0)