新增:文件系统导航面包屑
功能: - 新增 PathBreadcrumb 组件,支持路径快速跳转 - 新增 DropdownItem 通用下拉菜单组件 优化: - 版本升级流程优化(Pinia 状态管理、进度节流、完整下载验证) - 模块延迟初始化(数据库、文件系统按需启动) - API 数据格式统一(蛇形转驼峰) - CodeMirror 语言包按需动态加载 - Markdown 渲染增强(支持锚点跳转) 重构: - 迁移到 Pinia 状态管理(stores/config.ts、stores/theme.ts、stores/update.ts) - 简化 UpdatePanel、UpdateNotification、ThemeToggle 逻辑 - 优化表结构加载逻辑 清理: - 删除测试组件 index-simple.vue - 删除旧的 useTheme.ts
This commit is contained in:
242
web/src/App.vue
242
web/src/App.vue
@@ -58,29 +58,30 @@
|
||||
<!-- 设置抽屉 -->
|
||||
<SettingsPanel
|
||||
v-model="showSettings"
|
||||
:config="appConfig"
|
||||
:config="configStore.appConfig"
|
||||
@save="handleSaveConfig"
|
||||
/>
|
||||
|
||||
<!-- 升级提示弹窗 -->
|
||||
<UpdateNotification
|
||||
v-model="showUpdateNotification"
|
||||
:update-info="updateInfo"
|
||||
@install="handleUpdateInstall"
|
||||
@skip="handleUpdateSkip"
|
||||
v-model="updateStore.showUpdate"
|
||||
:update-info="updateStore.updateInfo"
|
||||
@install="updateStore.installUpdate"
|
||||
/>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, onMounted, ref, watch} from 'vue'
|
||||
import {IconSettings} from '@arco-design/web-vue/es/icon'
|
||||
import {Message} from '@arco-design/web-vue'
|
||||
import { computed, watch, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { IconSettings } from '@arco-design/web-vue/es/icon'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import DbCli from './views/db-cli/index.vue'
|
||||
import ThemeToggle from './components/ThemeToggle.vue'
|
||||
import FileSystem from './components/FileSystem/index.vue'
|
||||
import SettingsPanel from './components/SettingsPanel.vue'
|
||||
import UpdateNotification from './components/UpdateNotification.vue'
|
||||
import { useUpdateStore } from './stores/update'
|
||||
import { useConfigStore } from './stores/config'
|
||||
|
||||
// 存储键
|
||||
const ACTIVE_TAB_STORAGE_KEY = 'app-active-tab'
|
||||
@@ -91,124 +92,39 @@ const activeTab = ref((savedTab === 'user' ? 'file-system' : savedTab) || 'file-
|
||||
const showSettings = ref(false)
|
||||
const isMaximized = ref(false)
|
||||
|
||||
// 更新相关状态
|
||||
const showUpdateNotification = ref(false)
|
||||
const updateInfo = ref(null)
|
||||
const checkedUpdate = ref(false)
|
||||
// 使用 stores
|
||||
const updateStore = useUpdateStore()
|
||||
const configStore = useConfigStore()
|
||||
|
||||
// 应用配置
|
||||
const appConfig = ref({
|
||||
tabs: [],
|
||||
visibleTabs: [],
|
||||
defaultTab: 'file-system'
|
||||
})
|
||||
// 应用配置(从 store 获取)
|
||||
const appConfig = computed(() => configStore.appConfig)
|
||||
|
||||
// 可见 Tabs(根据配置动态生成)
|
||||
const visibleTabs = computed(() => {
|
||||
if (!appConfig.value.tabs || appConfig.value.tabs.length === 0) {
|
||||
// 默认配置
|
||||
return [
|
||||
{key: 'file-system', title: '文件管理'},
|
||||
{key: 'db-cli', title: '数据库'}
|
||||
]
|
||||
}
|
||||
|
||||
return appConfig.value.tabs
|
||||
.filter(tab => tab.visible)
|
||||
.sort((a, b) => {
|
||||
const aIndex = appConfig.value.visibleTabs.indexOf(a.key)
|
||||
const bIndex = appConfig.value.visibleTabs.indexOf(b.key)
|
||||
return aIndex - bIndex
|
||||
})
|
||||
})
|
||||
|
||||
// 加载配置
|
||||
const loadConfig = async () => {
|
||||
try {
|
||||
// 检查 Wails 绑定是否准备好
|
||||
if (!window.go || !window.go.main || !window.go.main.App) {
|
||||
console.warn('Wails 绑定未准备好,等待重试...')
|
||||
setTimeout(() => loadConfig(), 100)
|
||||
return
|
||||
}
|
||||
|
||||
const result = await window.go.main.App.GetAppConfig()
|
||||
if (result.success) {
|
||||
const tabs = result.data.tabs || []
|
||||
const visibleTabs = result.data.visibleTabs || []
|
||||
|
||||
// 确保 tabs 数组中的 visible 属性与 visibleTabs 同步
|
||||
const syncedTabs = tabs.map(tab => ({
|
||||
...tab,
|
||||
visible: visibleTabs.includes(tab.key)
|
||||
}))
|
||||
|
||||
appConfig.value = {
|
||||
tabs: syncedTabs,
|
||||
visibleTabs: visibleTabs,
|
||||
defaultTab: result.data.defaultTab || 'file-system'
|
||||
}
|
||||
|
||||
// 设置默认 Tab
|
||||
activeTab.value = appConfig.value.defaultTab
|
||||
} else {
|
||||
console.error('加载配置失败:', result.message)
|
||||
// 使用默认配置
|
||||
useDefaultConfig()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载配置失败:', error)
|
||||
// 使用默认配置
|
||||
useDefaultConfig()
|
||||
}
|
||||
}
|
||||
|
||||
// 使用默认配置
|
||||
const useDefaultConfig = () => {
|
||||
appConfig.value = {
|
||||
tabs: [
|
||||
{key: 'file-system', title: '文件管理', visible: true, enabled: true},
|
||||
{key: 'db-cli', title: '数据库', visible: true, enabled: true}
|
||||
],
|
||||
visibleTabs: ['file-system', 'db-cli'],
|
||||
defaultTab: 'file-system'
|
||||
}
|
||||
}
|
||||
// 可见 Tabs(从 store 获取)
|
||||
const visibleTabs = computed(() => configStore.visibleTabs)
|
||||
|
||||
// 保存配置
|
||||
const handleSaveConfig = async (config) => {
|
||||
try {
|
||||
const result = await window.go.main.App.SaveAppConfig({
|
||||
tabs: config.tabs,
|
||||
visibleTabs: config.visibleTabs,
|
||||
defaultTab: config.defaultTab
|
||||
})
|
||||
await configStore.saveConfig(config)
|
||||
showSettings.value = false
|
||||
|
||||
if (result.success) {
|
||||
// 更新本地配置
|
||||
appConfig.value = {
|
||||
tabs: [...config.tabs],
|
||||
visibleTabs: [...config.visibleTabs],
|
||||
defaultTab: config.defaultTab
|
||||
}
|
||||
|
||||
// 如果当前激活的 Tab 被隐藏,切换到默认 Tab
|
||||
if (!config.visibleTabs.includes(activeTab.value)) {
|
||||
activeTab.value = config.defaultTab
|
||||
}
|
||||
|
||||
Message.success('配置保存成功')
|
||||
showSettings.value = false
|
||||
} else {
|
||||
Message.error(result.message || '保存配置失败')
|
||||
throw new Error(result.message)
|
||||
// 如果当前激活的 Tab 被隐藏,切换到默认 Tab
|
||||
if (!config.visibleTabs.includes(activeTab.value)) {
|
||||
activeTab.value = config.defaultTab
|
||||
}
|
||||
} catch (error) {
|
||||
// 错误已在 store 中处理
|
||||
console.error('保存配置失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 加载配置(调用 store 方法)
|
||||
const loadConfig = async () => {
|
||||
await configStore.loadConfig()
|
||||
// 设置默认 Tab
|
||||
activeTab.value = configStore.defaultTab
|
||||
}
|
||||
|
||||
// 获取组件
|
||||
const getComponent = (key) => {
|
||||
const components = {
|
||||
@@ -218,75 +134,22 @@ const getComponent = (key) => {
|
||||
return components[key] || null
|
||||
}
|
||||
|
||||
// 检查更新
|
||||
const checkForUpdates = async () => {
|
||||
try {
|
||||
// 等待 Wails 绑定准备好
|
||||
if (!window.go || !window.go.main || !window.go.main.App) {
|
||||
console.warn('Wails 绑定未准备好,延迟检查更新...')
|
||||
setTimeout(() => checkForUpdates(), 1000)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取更新配置
|
||||
const configResult = await window.go.main.App.GetUpdateConfig()
|
||||
if (!configResult.success) {
|
||||
console.error('获取更新配置失败:', configResult.message)
|
||||
return
|
||||
}
|
||||
|
||||
const config = configResult.data
|
||||
const shouldCheck = config.auto_check_enabled
|
||||
|
||||
if (!shouldCheck) {
|
||||
console.log('自动更新检查已关闭')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[自动检查] 开始检查更新...')
|
||||
|
||||
// 检查更新
|
||||
const result = await window.go.main.App.CheckUpdate()
|
||||
if (result.success && result.data) {
|
||||
checkedUpdate.value = true
|
||||
|
||||
// 检查是否已跳过此版本
|
||||
const skippedVersion = localStorage.getItem('skipped_version')
|
||||
if (result.data.has_update) {
|
||||
// 如果是强制更新,或者未跳过此版本,则显示提示
|
||||
if (result.data.force_update || skippedVersion !== result.data.latest_version) {
|
||||
console.log('[自动检查] 发现新版本:', result.data.latest_version)
|
||||
updateInfo.value = result.data
|
||||
// 延迟显示,让用户先看到应用界面
|
||||
setTimeout(() => {
|
||||
showUpdateNotification.value = true
|
||||
}, 2000)
|
||||
} else {
|
||||
console.log('[自动检查] 此版本已跳过')
|
||||
}
|
||||
} else {
|
||||
console.log('[自动检查] 已是最新版本')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载时加载配置和检查更新
|
||||
// 组件挂载时加载配置
|
||||
onMounted(() => {
|
||||
loadConfig()
|
||||
// 延迟检查更新,避免阻塞应用启动
|
||||
|
||||
// 设置更新事件监听
|
||||
updateStore.setupEventListeners()
|
||||
|
||||
// 延迟检查更新(启动后 3 秒,静默模式)
|
||||
setTimeout(() => {
|
||||
if (!checkedUpdate.value) {
|
||||
checkForUpdates()
|
||||
}
|
||||
updateStore.checkForUpdates(true)
|
||||
}, 3000)
|
||||
})
|
||||
|
||||
// 监听 activeTab 变化,自动保存到 localStorage
|
||||
watch(activeTab, (newTab) => {
|
||||
localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, newTab)
|
||||
// 组件卸载时清理事件监听
|
||||
onUnmounted(() => {
|
||||
updateStore.removeEventListeners()
|
||||
})
|
||||
|
||||
// 窗口控制方法
|
||||
@@ -321,29 +184,6 @@ const handleClose = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 升级提示事件处理
|
||||
const handleUpdateInstall = async (filePath) => {
|
||||
try {
|
||||
const result = await window.go.main.App.InstallUpdate(filePath, true)
|
||||
if (result.success) {
|
||||
Message.success({
|
||||
content: '安装成功!应用将在几秒后重启...',
|
||||
duration: 3000
|
||||
})
|
||||
} else {
|
||||
Message.error(result.message || '安装失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('安装失败:', error)
|
||||
Message.error('安装失败:' + (error.message || error))
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateSkip = () => {
|
||||
// 清除跳过的版本记录(如果用户选择"稍后提醒")
|
||||
// 版本记录在组件内部处理
|
||||
}
|
||||
|
||||
// 监听 activeTab 变化,如果当前 Tab 不在可见列表中,切换到默认 Tab
|
||||
watch(activeTab, (newTab) => {
|
||||
// 保存到 localStorage
|
||||
@@ -351,8 +191,8 @@ watch(activeTab, (newTab) => {
|
||||
|
||||
// 检查 Tab 是否在可见列表中
|
||||
const isVisible = appConfig.value.visibleTabs.includes(newTab)
|
||||
if (!isVisible && appConfig.value.visibleTabs.length > 0) {
|
||||
// 切换到默认 Tab
|
||||
if (!isVisible && appConfig.value.visibleTabs.length > 0 && newTab !== appConfig.value.defaultTab) {
|
||||
// 切换到默认 Tab(避免重复触发)
|
||||
activeTab.value = appConfig.value.defaultTab
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user