新增:文件系统导航面包屑
功能: - 新增 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:
@@ -79,10 +79,22 @@
|
||||
</div>
|
||||
</a-alert>
|
||||
|
||||
<!-- 调试信息(始终显示) -->
|
||||
<div style="font-size: 12px; color: #999; padding: 8px; background: var(--color-fill-2); margin-top: 16px; border-radius: 4px;">
|
||||
<strong>调试信息:</strong>
|
||||
<br>downloading = {{ downloading }}
|
||||
<br>downloadProgress = {{ downloadProgress }}
|
||||
<br>downloadStatus = {{ downloadStatus }}
|
||||
<br>progressInfo = {{ progressInfo }}
|
||||
</div>
|
||||
|
||||
<!-- 下载进度 -->
|
||||
<div v-if="downloadProgress > 0 || downloading" class="download-progress">
|
||||
<div style="font-size: 11px; color: #999; margin-bottom: 8px;">
|
||||
进度条已显示:downloadProgress={{ downloadProgress }}, downloading={{ downloading }}
|
||||
</div>
|
||||
<a-progress
|
||||
:percent="downloadProgress / 100"
|
||||
:percent="downloadProgress"
|
||||
:status="downloadStatus"
|
||||
/>
|
||||
<div class="progress-info">
|
||||
@@ -109,66 +121,37 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { Message, Modal } from '@arco-design/web-vue'
|
||||
import { IconCheck, IconClose } from '@arco-design/web-vue/es/icon'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useUpdateStore } from '../stores/update'
|
||||
|
||||
// 工具函数:解析事件数据
|
||||
const parseEventData = (event) => {
|
||||
try {
|
||||
return typeof event === 'string' ? JSON.parse(event) : event
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
// 使用更新管理 store
|
||||
const updateStore = useUpdateStore()
|
||||
|
||||
// 状态
|
||||
// 使用 storeToRefs 解构以保持响应性
|
||||
const { checking, downloading, installing, downloadProgress, downloadStatus, progressInfo, updateInfo } = storeToRefs(updateStore)
|
||||
|
||||
// 本地状态
|
||||
const currentVersion = ref('-')
|
||||
const lastCheckTime = ref('-')
|
||||
const checking = ref(false)
|
||||
const downloading = ref(false)
|
||||
const installing = ref(false)
|
||||
const saving = ref(false)
|
||||
const updateInfo = ref(null)
|
||||
const downloadedFile = ref(null)
|
||||
const installResult = ref(null)
|
||||
const downloadProgress = ref(0)
|
||||
const downloadStatus = ref('active')
|
||||
const downloadedFile = ref(null)
|
||||
|
||||
// 配置
|
||||
const config = ref({
|
||||
auto_check_enabled: true,
|
||||
check_interval_minutes: 60,
|
||||
check_url: ''
|
||||
})
|
||||
|
||||
// 下载进度信息
|
||||
const progressInfo = ref({
|
||||
progress: 0,
|
||||
speed: 0,
|
||||
downloaded: 0,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 格式化文件大小
|
||||
// 工具函数
|
||||
const formatFileSize = (bytes) => {
|
||||
if (!bytes || bytes < 0) return '0 B'
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
|
||||
return updateStore.formatFileSize(bytes)
|
||||
}
|
||||
|
||||
// 格式化速度
|
||||
const formatSpeed = (bytesPerSecond) => {
|
||||
return formatFileSize(bytesPerSecond) + '/s'
|
||||
return updateStore.formatSpeed(bytesPerSecond)
|
||||
}
|
||||
|
||||
// 加载当前版本
|
||||
const loadCurrentVersion = async () => {
|
||||
try {
|
||||
const result = await window.go.main.App.GetCurrentVersion()
|
||||
if (result.success) {
|
||||
currentVersion.value = result.data?.version || '-'
|
||||
}
|
||||
if (!result.success) return
|
||||
|
||||
currentVersion.value = result.data?.version || '-'
|
||||
} catch (error) {
|
||||
console.error('获取版本失败:', error)
|
||||
}
|
||||
@@ -178,114 +161,30 @@ const loadCurrentVersion = async () => {
|
||||
const loadConfig = async () => {
|
||||
try {
|
||||
const result = await window.go.main.App.GetUpdateConfig()
|
||||
if (result.success) {
|
||||
config.value = {
|
||||
auto_check_enabled: result.data.auto_check_enabled || false,
|
||||
check_interval_minutes: result.data.check_interval_minutes || 60,
|
||||
check_url: result.data.check_url || ''
|
||||
}
|
||||
lastCheckTime.value = result.data.last_check_time || '-'
|
||||
}
|
||||
if (!result.success) return
|
||||
|
||||
const { last_check_time = '-' } = result.data || {}
|
||||
lastCheckTime.value = last_check_time
|
||||
} catch (error) {
|
||||
console.error('加载配置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 配置变化时自动保存(防抖)
|
||||
let saveTimer = null
|
||||
const handleConfigChange = () => {
|
||||
// 清除之前的定时器
|
||||
if (saveTimer) {
|
||||
clearTimeout(saveTimer)
|
||||
}
|
||||
|
||||
// 设置新的定时器,1秒后保存
|
||||
saveTimer = setTimeout(async () => {
|
||||
await saveConfig()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
const saveConfig = async () => {
|
||||
saving.value = true
|
||||
|
||||
try {
|
||||
const result = await window.go.main.App.SetUpdateConfig(
|
||||
config.value.auto_check_enabled,
|
||||
config.value.check_interval_minutes,
|
||||
config.value.check_url
|
||||
)
|
||||
|
||||
if (result.success) {
|
||||
Message.success('配置已自动保存')
|
||||
await loadConfig()
|
||||
} else {
|
||||
Message.error(result.message || '保存配置失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存配置失败:', error)
|
||||
Message.error('保存配置失败:' + (error.message || error))
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 检查更新
|
||||
const handleCheckUpdate = async () => {
|
||||
checking.value = true
|
||||
updateInfo.value = null
|
||||
installResult.value = null
|
||||
|
||||
try {
|
||||
const result = await window.go.main.App.CheckUpdate()
|
||||
if (result.success) {
|
||||
updateInfo.value = result.data
|
||||
if (result.data.has_update) {
|
||||
Message.success('发现新版本!')
|
||||
} else {
|
||||
Message.success('已是最新版本')
|
||||
}
|
||||
} else {
|
||||
Message.error(result.message || '检查更新失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('检查更新失败:', error)
|
||||
Message.error('检查更新失败:' + (error.message || error))
|
||||
} finally {
|
||||
checking.value = false
|
||||
// 刷新最后检查时间
|
||||
await loadConfig()
|
||||
}
|
||||
// 使用 store 的检查方法(非静默模式,显示消息)
|
||||
await updateStore.checkForUpdates(false)
|
||||
|
||||
// 刷新最后检查时间
|
||||
await loadConfig()
|
||||
}
|
||||
|
||||
// 下载更新
|
||||
const handleDownload = async () => {
|
||||
if (!updateInfo.value?.download_url) {
|
||||
Message.warning('下载地址不存在')
|
||||
return
|
||||
}
|
||||
|
||||
downloading.value = true
|
||||
downloadProgress.value = 0
|
||||
downloadStatus.value = 'active'
|
||||
progressInfo.value = { progress: 0, speed: 0, downloaded: 0, total: 0 }
|
||||
installResult.value = null
|
||||
|
||||
try {
|
||||
const result = await window.go.main.App.DownloadUpdate(updateInfo.value.download_url)
|
||||
if (result.success) {
|
||||
Message.success('下载请求已发送')
|
||||
} else {
|
||||
downloadStatus.value = 'exception'
|
||||
Message.error(result.message || '下载启动失败')
|
||||
downloading.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
downloadStatus.value = 'exception'
|
||||
Message.error('下载失败:' + (error.message || error))
|
||||
downloading.value = false
|
||||
}
|
||||
// 使用 store 的下载方法,会自动管理状态和事件监听
|
||||
await updateStore.downloadUpdate()
|
||||
}
|
||||
|
||||
// 安装更新
|
||||
@@ -295,7 +194,6 @@ const handleInstall = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 确认对话框
|
||||
Modal.confirm({
|
||||
title: '确认安装',
|
||||
content: '安装更新后应用将自动重启,是否继续?',
|
||||
@@ -304,27 +202,24 @@ const handleInstall = async () => {
|
||||
installResult.value = null
|
||||
|
||||
try {
|
||||
const result = await window.go.main.App.InstallUpdate(
|
||||
downloadedFile.value,
|
||||
true // 自动重启
|
||||
)
|
||||
const result = await window.go.main.App.InstallUpdate(downloadedFile.value, true)
|
||||
installResult.value = result.data || result
|
||||
|
||||
if (result.success || result.data?.success) {
|
||||
Message.success({
|
||||
content: '安装成功!应用将在几秒后重启...',
|
||||
duration: 3000
|
||||
})
|
||||
} else {
|
||||
const success = result.success || result.data?.success
|
||||
if (!success) {
|
||||
Message.error(result.message || '安装失败')
|
||||
return
|
||||
}
|
||||
|
||||
Message.success({
|
||||
content: '安装成功!应用将在几秒后重启...',
|
||||
duration: 3000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('安装失败:', error)
|
||||
installResult.value = {
|
||||
success: false,
|
||||
message: '安装失败:' + (error.message || error)
|
||||
}
|
||||
Message.error('安装失败:' + (error.message || error))
|
||||
const errorMsg = '安装失败:' + (error.message || error)
|
||||
installResult.value = { success: false, message: errorMsg }
|
||||
Message.error(errorMsg)
|
||||
} finally {
|
||||
installing.value = false
|
||||
}
|
||||
@@ -332,34 +227,12 @@ const handleInstall = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 监听下载进度事件
|
||||
const onDownloadProgress = (event) => {
|
||||
const data = parseEventData(event)
|
||||
progressInfo.value = {
|
||||
progress: data.progress || 0,
|
||||
speed: data.speed || 0,
|
||||
downloaded: data.downloaded || 0,
|
||||
total: data.total || 0
|
||||
}
|
||||
// 确保进度值在 0-100 之间
|
||||
const rawProgress = data.progress || 0
|
||||
downloadProgress.value = Math.min(100, Math.max(0, Math.round(rawProgress)))
|
||||
console.log('[下载进度] 原始值:', rawProgress, '处理后:', downloadProgress.value)
|
||||
}
|
||||
|
||||
// 监听下载完成事件
|
||||
// 监听下载完成事件(本地覆盖:记录下载文件路径)
|
||||
const onDownloadComplete = (event) => {
|
||||
downloading.value = false
|
||||
const data = parseEventData(event)
|
||||
const data = typeof event === 'string' ? JSON.parse(event) : event
|
||||
|
||||
if (data.error) {
|
||||
downloadStatus.value = 'exception'
|
||||
Message.error('下载失败:' + data.error)
|
||||
} else if (data.success) {
|
||||
downloadStatus.value = 'success'
|
||||
downloadProgress.value = 100
|
||||
if (data.success && data.file_path) {
|
||||
downloadedFile.value = data.file_path
|
||||
Message.success('下载完成!文件已保存到:' + data.file_path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,9 +240,8 @@ onMounted(async () => {
|
||||
await loadCurrentVersion()
|
||||
await loadConfig()
|
||||
|
||||
// 监听下载进度事件
|
||||
// 监听下载完成事件(仅用于记录文件路径)
|
||||
if (window.runtime?.EventsOn) {
|
||||
window.runtime.EventsOn('download-progress', onDownloadProgress)
|
||||
window.runtime.EventsOn('download-complete', onDownloadComplete)
|
||||
}
|
||||
})
|
||||
@@ -377,14 +249,8 @@ onMounted(async () => {
|
||||
onUnmounted(() => {
|
||||
// 取消事件监听
|
||||
if (window.runtime?.EventsOff) {
|
||||
window.runtime.EventsOff('download-progress')
|
||||
window.runtime.EventsOff('download-complete')
|
||||
}
|
||||
|
||||
// 清除定时器
|
||||
if (saveTimer) {
|
||||
clearTimeout(saveTimer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user