import { createApp } from 'vue' import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import './styles/index.css' import 'stk-table-vue/lib/style.css' import { registerFeature, useAreaSelection } from 'stk-table-vue' import App from './App.vue' import router from './router' import { initThemeSync } from './stores/app' // stk-table 按需特性注册:单元格区域选择(FmsTable 的行编辑依赖 area-selection 事件) registerFeature(useAreaSelection) const pinia = createPinia() pinia.use(piniaPluginPersistedstate) const app = createApp(App) app.use(pinia) app.use(router) // mount 前初始化主题同步(恢复持久化状态并写入 DOM,避免首屏闪烁) initThemeSync(pinia) function showBootstrapError(error) { console.error('Application bootstrap failed', error) const boot = document.querySelector('#app-boot') const message = document.querySelector('#app-boot-message') const retry = document.querySelector('#app-boot-retry') if (!boot || !message || !retry) return boot.classList.add('app-boot--error') boot.setAttribute('aria-busy', 'false') boot.setAttribute('aria-label', '应用加载失败') message.textContent = '应用加载失败,请检查网络后重试' message.hidden = false retry.hidden = false retry.addEventListener('click', () => window.location.reload(), { once: true }) } async function bootstrap() { try { await router.isReady() // 权限数据由路由守卫(beforeEach)统一加载:首屏 beforeEach 在 mount 前 await 完成, // 菜单一次性到位、不会“跳出”(对齐 cool-admin:菜单加载放在 mount 之前) // 先把 boot 屏移出 #app,避免被 mount 整体替换而瞬间消失(那样没有过渡且会卡顿) const boot = document.querySelector('#app-boot') if (boot) document.body.appendChild(boot) // 数据已就绪,挂载路由首屏(布局含完整菜单将一次性渲染出来) app.mount('#app') // 下一帧启动 boot 屏的 opacity 淡出(合成属性,由 compositor 驱动,不被下方渲染阻塞)。 // 此时菜单已在布局中就位,淡出过程中直接露出完整页面,不会“跳出”。 requestAnimationFrame(() => { if (boot) boot.classList.add('app-boot--hide') }) if (boot) { // 移除 boot 屏并清理加载屏的临时主题类(主题由 applyDarkMode 的 .dark 统一管理) const cleanupBoot = () => { boot.remove() document.documentElement.classList.remove('boot-dark') } boot.addEventListener('transitionend', cleanupBoot, { once: true }) // 兜底:防止 transitionend 未触发导致节点残留 setTimeout(() => { if (boot.isConnected) cleanupBoot() }, 600) } } catch (error) { showBootstrapError(error) } } void bootstrap()