99 lines
4.4 KiB
TypeScript
99 lines
4.4 KiB
TypeScript
import { createApp, type Component } from 'vue'
|
|
import { createPinia } from 'pinia'
|
|
import './style.css'
|
|
import 'vue-sonner/style.css'
|
|
|
|
import { createLogger } from './lib/logger'
|
|
const logger = createLogger('main')
|
|
|
|
// 禁用 WebView 默认右键菜单(桌面应用体验,主窗口与独立窗口共用)
|
|
document.addEventListener('contextmenu', (e) => e.preventDefault())
|
|
|
|
// 全局未捕获异常日志
|
|
window.addEventListener('error', (event) => {
|
|
logger.error(`全局JS错误: ${event.message} @ ${event.filename}:${event.lineno}`)
|
|
})
|
|
|
|
window.addEventListener('unhandledrejection', (event) => {
|
|
logger.error(`未处理的Promise拒绝: ${event.reason}`)
|
|
})
|
|
|
|
// ===== 独立窗口模式 =====
|
|
// 通过 URL hash 识别独立窗口:#osd-overlay / #clipboard-popup / #quick-panel / #tray-menu / #screenshot-overlay / #screenshot-editor
|
|
// 这些窗口是精简的独立 Vue 应用,不加载主应用的 store 和模块
|
|
// 新增独立窗口只需在此表登记一行(hash → 组件)
|
|
const standaloneWindowApps: Array<[hash: string, label: string, loader: () => Promise<{ default: Component }>]> = [
|
|
['#osd-overlay', 'OSD', () => import('./modules/monitor/OsdWindow.vue')],
|
|
['#clipboard-popup', '剪贴板弹窗', () => import('./modules/clipboard/ClipboardPopup.vue')],
|
|
['#quick-panel', '快速面板弹窗', () => import('./modules/quickpanel/QuickPanel.vue')],
|
|
['#tray-menu', '托盘菜单', () => import('./modules/tray/TrayMenu.vue')],
|
|
['#screenshot-overlay', '截图覆盖层', () => import('./modules/screenshot/ScreenshotOverlay.vue')],
|
|
['#screenshot-editor', '截图编辑器', () => import('./modules/screenshot/ScreenshotEditor.vue')],
|
|
['#screenshot-pin', '贴图窗口', () => import('./modules/screenshot/ScreenshotPin.vue')],
|
|
]
|
|
|
|
const winHash = window.location.hash
|
|
|
|
// #screenshot-overlay 带窗口号参数(多屏),按前缀匹配;其余精确匹配
|
|
const matched = standaloneWindowApps.find(([hash]) =>
|
|
hash === '#screenshot-overlay' ? winHash.startsWith(hash) : winHash === hash
|
|
)
|
|
|
|
if (matched) {
|
|
const [, label, loader] = matched
|
|
logger.info(`${label}窗口启动: ${winHash}`)
|
|
void loader().then(({ default: Comp }) => {
|
|
const app = createApp(Comp)
|
|
app.mount('#app')
|
|
})
|
|
} else {
|
|
// ===== 主应用模式 =====
|
|
void import('./App.vue').then(async ({ default: App }) => {
|
|
// 导入模块注册入口 —— 副作用导入,注册所有模块到 moduleRegistry
|
|
await import('./modules')
|
|
|
|
logger.info('Thing 应用启动')
|
|
|
|
const app = createApp(App)
|
|
const pinia = createPinia()
|
|
|
|
app.use(pinia)
|
|
|
|
app.mount('#app')
|
|
|
|
// 应用挂载后初始化搜索索引和进程监听(不阻塞首屏渲染)
|
|
void import('./stores/searchStore').then(({ useSearchStore }) => {
|
|
const searchStore = useSearchStore()
|
|
searchStore.initGlobalIndex()
|
|
|
|
// 移除已禁用模块的搜索项
|
|
void import('./stores/appStore').then(({ useAppStore }) => {
|
|
const appStore = useAppStore()
|
|
appStore.modules.forEach(m => {
|
|
if (!m.enabled) {
|
|
searchStore.unregisterModule(m.id)
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
void import('./stores/processStore').then(({ useProcessStore }) => {
|
|
useProcessStore().initListener().catch(e => console.error('Process listener init error:', e))
|
|
})
|
|
|
|
// 截图模块:加载设置 + 恢复持久化历史 + 预创建常驻覆盖层窗口 + 监听导出事件(历史/自动保存)+ 注册并监听全局快捷键(截图/贴图)
|
|
void import('./stores/screenshotStore').then(({ useScreenshotStore }) => {
|
|
const screenshotStore = useScreenshotStore()
|
|
screenshotStore.loadSettings()
|
|
screenshotStore.loadHistory()
|
|
screenshotStore.initOverlay().catch(e => console.error('Screenshot overlay init error:', e))
|
|
screenshotStore.initExportListener().catch(e => console.error('Screenshot export listener init error:', e))
|
|
screenshotStore.initShortcutListener().catch(e => console.error('Screenshot shortcut listener init error:', e))
|
|
screenshotStore.initShortcutRegistration().catch(e => console.error('Screenshot shortcut registration init error:', e))
|
|
screenshotStore.initPinShortcutListener().catch(e => console.error('Screenshot pin shortcut listener init error:', e))
|
|
screenshotStore.initPinShortcutRegistration().catch(e => console.error('Screenshot pin shortcut registration init error:', e))
|
|
})
|
|
})
|
|
}
|
|
|