78 lines
2.8 KiB
JavaScript
78 lines
2.8 KiB
JavaScript
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()
|