Files
admin-web/src/main.ts
T

90 lines
3.5 KiB
TypeScript
Raw Normal View History

2026-09-15 09:58:15 +08:00
import '@/styles/adminDensity.css'
2026-08-06 19:03:13 +08:00
import { computed, createApp } from 'vue'
2026-08-25 22:08:59 +08:00
import 'dayjs/locale/zh-cn'
2026-07-30 17:59:43 +08:00
import { createPinia } from 'pinia'
2026-08-25 19:56:37 +08:00
import { ElMessage, ElMessageBox } from 'element-plus'
2026-07-30 17:59:43 +08:00
import 'element-plus/es/components/message/style/css'
import 'element-plus/es/components/message-box/style/css'
import App from './App.vue'
2026-08-03 18:49:18 +08:00
import router from '@/app/router'
import { sanitizeInternalPath } from '@/core/routing/accessDecision'
2026-09-19 17:02:17 +08:00
import { createNavigationRecoveryHandler, installAssetRecoveryListeners, isStaleRouteAssetError, reloadNavigationTarget } from '@/core/routing/navigationRecovery'
2026-08-03 18:49:18 +08:00
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { useUnsavedWorkStore } from '@/core/unsaved-work/unsavedWork'
2026-08-05 15:54:59 +08:00
import { useWorkspaceTabsStore } from '@/core/workspace-tabs/workspaceTabs'
2026-08-03 18:49:18 +08:00
import { useAuthStore } from '@/core/auth/auth'
import { registerAuthSessionExpiredHandler } from '@/shared/api/http'
2026-08-06 19:03:13 +08:00
import { UI_PREFERENCE_SCOPE } from '@/shared/utils/uiLayoutPreference'
2026-07-30 17:59:43 +08:00
import './styles/index.css'
2026-07-31 13:43:16 +08:00
const pinia = createPinia()
const auth = useAuthStore(pinia)
2026-08-05 15:54:59 +08:00
const unsaved = useUnsavedWorkStore(pinia)
const workspace = useWorkspaceTabsStore(pinia)
2026-07-30 22:38:28 +08:00
2026-07-31 13:43:16 +08:00
registerAuthSessionExpiredHandler(async () => {
const currentRoute = router.currentRoute.value
if (currentRoute.name === 'login') return
useAccessPreviewStore(pinia).reset()
2026-08-05 15:54:59 +08:00
unsaved.clear()
workspace.reset(true)
2026-07-31 13:43:16 +08:00
const redirect = sanitizeInternalPath(currentRoute.fullPath)
ElMessage.warning('登录状态已过期,请重新登录')
await router.replace({
name: 'login',
query: redirect === '/' ? undefined : { redirect },
})
})
2026-09-19 17:02:17 +08:00
const recoverAssetError = createNavigationRecoveryHandler({
storage: {
getItem: (key) => window.sessionStorage.getItem(key),
setItem: (key, value) => window.sessionStorage.setItem(key, value),
},
now: Date.now,
hasUnsavedWork: () => unsaved.entries.some((entry) => entry.dirty),
confirmDiscard: async () => {
try {
await ElMessageBox.confirm(
'页面资源加载失败,可能已发布新版本,需要重新加载页面。继续后将放弃当前未保存内容。',
'重新加载页面?',
{ confirmButtonText: '重新加载', cancelButtonText: '继续编辑', type: 'warning', customClass: 'admin-density-confirm' },
)
return true
} catch {
return false
}
},
discardUnsavedWork: () => unsaved.clear(),
navigate: (target) => reloadNavigationTarget(window, target),
showError: (message) => ElMessage.error(message),
})
let pendingRoute: string | undefined
const recoveryTarget = () => pendingRoute
?? `${window.location.pathname}${window.location.search}${window.location.hash}`
router.beforeEach((to) => { pendingRoute = to.fullPath })
2026-08-25 19:56:37 +08:00
router.onError((error, to) => {
2026-09-19 17:02:17 +08:00
void recoverAssetError(error, to.fullPath)
if (pendingRoute === to.fullPath) pendingRoute = undefined
2026-08-25 19:56:37 +08:00
})
2026-09-19 17:02:17 +08:00
router.afterEach((to) => {
if (pendingRoute === to.fullPath) pendingRoute = undefined
2026-08-25 19:56:37 +08:00
})
2026-09-19 17:02:17 +08:00
installAssetRecoveryListeners(window, recoveryTarget, recoverAssetError)
2026-08-25 19:56:37 +08:00
2026-08-05 15:54:59 +08:00
window.addEventListener('beforeunload', (event) => {
if (!unsaved.entries.some((entry) => entry.dirty)) return
event.preventDefault()
event.returnValue = ''
})
2026-08-06 19:03:13 +08:00
const app = createApp(App)
2026-09-19 17:02:17 +08:00
app.config.errorHandler = (error) => {
if (isStaleRouteAssetError(error)) void recoverAssetError(error, recoveryTarget())
else console.error(error)
}
2026-08-06 19:03:13 +08:00
app.provide(UI_PREFERENCE_SCOPE, computed(() => auth.user?.id || 'anonymous'))
2026-09-19 17:02:17 +08:00
await auth.restoreSession()
2026-08-06 19:03:13 +08:00
app.use(pinia).use(router).mount('#app')