75 lines
2.7 KiB
TypeScript
75 lines
2.7 KiB
TypeScript
import { computed, createApp } from 'vue'
|
|
import { createPinia } from 'pinia'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import 'element-plus/es/components/message/style/css'
|
|
import 'element-plus/es/components/message-box/style/css'
|
|
import App from './App.vue'
|
|
import router from '@/app/router'
|
|
import { sanitizeInternalPath } from '@/core/routing/accessDecision'
|
|
import { clearNavigationRecoveryAttempt, recoverNavigationError } from '@/core/routing/navigationRecovery'
|
|
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
|
import { useUnsavedWorkStore } from '@/core/unsaved-work/unsavedWork'
|
|
import { useWorkspaceTabsStore } from '@/core/workspace-tabs/workspaceTabs'
|
|
import { useAuthStore } from '@/core/auth/auth'
|
|
import { registerAuthSessionExpiredHandler } from '@/shared/api/http'
|
|
import { UI_PREFERENCE_SCOPE } from '@/shared/utils/uiLayoutPreference'
|
|
import './styles/index.css'
|
|
|
|
const pinia = createPinia()
|
|
const auth = useAuthStore(pinia)
|
|
const unsaved = useUnsavedWorkStore(pinia)
|
|
const workspace = useWorkspaceTabsStore(pinia)
|
|
|
|
await auth.restoreSession()
|
|
|
|
registerAuthSessionExpiredHandler(async () => {
|
|
const currentRoute = router.currentRoute.value
|
|
if (currentRoute.name === 'login') return
|
|
|
|
useAccessPreviewStore(pinia).reset()
|
|
unsaved.clear()
|
|
workspace.reset(true)
|
|
const redirect = sanitizeInternalPath(currentRoute.fullPath)
|
|
ElMessage.warning('登录状态已过期,请重新登录')
|
|
await router.replace({
|
|
name: 'login',
|
|
query: redirect === '/' ? undefined : { redirect },
|
|
})
|
|
})
|
|
|
|
router.onError((error, to) => {
|
|
void recoverNavigationError(error, to.fullPath, {
|
|
storage: sessionStorage,
|
|
now: Date.now,
|
|
hasUnsavedWork: () => unsaved.entries.some((entry) => entry.dirty),
|
|
confirmDiscard: async () => {
|
|
try {
|
|
await ElMessageBox.confirm(
|
|
'检测到后台已发布新版本,需要重新加载页面。继续后将放弃当前未保存内容。',
|
|
'重新加载页面?',
|
|
{ confirmButtonText: '重新加载', cancelButtonText: '继续编辑', type: 'warning' },
|
|
)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
discardUnsavedWork: () => unsaved.clear(),
|
|
navigate: (target) => window.location.assign(target),
|
|
showError: (message) => ElMessage.error(message),
|
|
})
|
|
})
|
|
router.afterEach((_to, _from, failure) => {
|
|
if (!failure) clearNavigationRecoveryAttempt(sessionStorage)
|
|
})
|
|
|
|
window.addEventListener('beforeunload', (event) => {
|
|
if (!unsaved.entries.some((entry) => entry.dirty)) return
|
|
event.preventDefault()
|
|
event.returnValue = ''
|
|
})
|
|
|
|
const app = createApp(App)
|
|
app.provide(UI_PREFERENCE_SCOPE, computed(() => auth.user?.id || 'anonymous'))
|
|
app.use(pinia).use(router).mount('#app')
|