修复: 版本更新与设置面板走查问题

- 更新链路: 检查记录远端SHA256,下载完成事件回传,安装时带哈希校验
- 续传: 服务器忽略Range返回200时截断重下防追加损坏,文件名去query
- 定时器: 自动检查可重入,配置变更免重启生效,关闭即停,下载加互斥
- 前端: 支持跳过此版本并按版本去重,手动检查不受门禁限制,启动未就绪延时重试
- 更新面板: 新增自动检查开关/间隔/地址配置与进度条状态映射
- 版本历史: cache参数强制刷新与加载超时重试兜底
- 配置: 侧边栏分区全链路持久化,保存请求复用api类型防字段丢失
- 侧边栏: 区块定位改显式类名,不再依赖排序位置
- 绑定: 重新生成并与镜像目录同步
This commit is contained in:
lxy
2026-10-03 10:18:27 +08:00
parent 81e245eade
commit c7978a5bfd
25 changed files with 589 additions and 286 deletions
+73 -16
View File
@@ -4,10 +4,15 @@ import { Message } from '@arco-design/web-vue'
import { formatBytes as formatFileSize } from '@/utils/fileUtils'
import { parseWailsEventData } from '@/utils/wailsEvent'
import {
CheckUpdate, GetUpdateConfig, DownloadUpdate, InstallUpdate
CheckUpdate, GetUpdateConfig, DownloadUpdate, InstallUpdate, InstallUpdateWithHash
} from '../wailsjs/v3-bindings/u-desk/app'
import { On, Off } from '@wailsio/events'
// 本次应用运行内已自动弹过的版本(升级后自动恢复提醒)
let sessionNotifiedVersion = ''
// 下载完成事件携带的远端声明哈希,安装时用于完整性校验
let lastExpectedSha256 = ''
/**
* 更新管理 Store
* 统一管理版本检查、下载、安装等更新相关逻辑
@@ -41,34 +46,65 @@ export const useUpdateStore = defineStore('update', () => {
}
// ==================== 核心方法 ====================
// 用户显式跳过的版本(localStorage):该版本不再自动弹窗,手动检查不受限
const SKIPPED_VERSION_KEY = 'udesk-update-skipped-version'
/**
* 展示更新弹窗。自动路径(静默检查/后端广播)按版本去重(用户已跳过或本次运行已弹过则不弹),手动检查强制弹
*/
const tryShowUpdate = (data: UpdateInfo, force = false) => {
const version = String(data?.latest_version || '')
if (!force && version) {
if (localStorage.getItem(SKIPPED_VERSION_KEY) === version) return
if (sessionNotifiedVersion === version) return
}
updateInfo.value = data
showUpdate.value = true
if (version) {
sessionNotifiedVersion = version
}
if (!force) {
// 自动发现时的系统通知
try {
window.runtime?.SendNotification?.({
title: 'U-Desk',
body: `发现新版本 ${version},点击查看`
})
} catch { /* 通知不可用时忽略 */ }
}
}
/**
* 稍后提醒:记录用户显式跳过的版本,该版本不再自动弹窗(手动检查仍强制弹)
*/
const skipVersion = (version: string) => {
if (version) {
localStorage.setItem(SKIPPED_VERSION_KEY, version)
}
showUpdate.value = false
}
/**
* 检查更新
* @param silent 是否静默模式(不显示消息)
* @param manual 是否手动触发(跳过 auto_check_enabled 门禁)
* @returns 检查是否实际完成(false=后端未就绪或网络失败,调用方可重试)
*/
const checkForUpdates = async (silent = false) => {
if (checking.value) return
const checkForUpdates = async (silent = false, manual = false): Promise<boolean> => {
if (checking.value) return true
checking.value = true
try {
const configResult = await GetUpdateConfig()
if (!configResult.success) return
if (!configResult.success) return false
const { auto_check_enabled } = configResult.data || {}
if (!auto_check_enabled) return
if (!manual && !auto_check_enabled) return true
const result = await CheckUpdate()
if (result.success && result.data?.has_update) {
updateInfo.value = result.data
showUpdate.value = true
// 系统通知:发现新版本
try {
window.runtime?.SendNotification?.({
title: 'U-Desk',
body: `发现新版本 ${result.data.latest_version},点击查看`
})
} catch { /* 通知不可用时忽略 */ }
tryShowUpdate(result.data, !silent)
if (!silent) {
Message.success('发现新版本!')
@@ -76,11 +112,13 @@ export const useUpdateStore = defineStore('update', () => {
} else if (!silent) {
Message.success('已是最新版本')
}
return result.success === true
} catch (error) {
if (!silent) {
console.error('检查更新失败:', error)
Message.error('检查更新失败:' + (error as Error).message)
}
return false
} finally {
checking.value = false
}
@@ -134,7 +172,10 @@ export const useUpdateStore = defineStore('update', () => {
installing.value = true
try {
const result = await InstallUpdate(filePath, true)
// 优先带哈希校验安装(期望哈希来自下载完成事件的远端声明)
const result = lastExpectedSha256
? await InstallUpdateWithHash(filePath, true, lastExpectedSha256, 'sha256')
: await InstallUpdate(filePath, true)
if (result.success) {
Message.success({
content: '安装成功!应用将在几秒后重启...',
@@ -200,6 +241,8 @@ export const useUpdateStore = defineStore('update', () => {
// 完成下载
downloadProgress.value = 100
downloadStatus.value = 'success'
// 记录远端声明的期望哈希,安装时用于校验
lastExpectedSha256 = String(data.expected_sha256 || '')
const fileSize = (data.file_size as number) || 0
@@ -227,12 +270,24 @@ export const useUpdateStore = defineStore('update', () => {
}, remainingTime)
}
/**
* 后端广播"发现新版本"处理(启动即查与周期检查命中时后端都会发)
*/
const onUpdateAvailable = (event: unknown) => {
const data = parseWailsEventData(event) as UpdateInfo
if (!data?.latest_version) {
return
}
tryShowUpdate(data)
}
/**
* 设置事件监听
*/
const setupEventListeners = () => {
On('download-progress', onDownloadProgress)
On('download-complete', onDownloadComplete)
On('update-available', onUpdateAvailable)
}
/**
@@ -241,6 +296,7 @@ export const useUpdateStore = defineStore('update', () => {
const removeEventListeners = () => {
Off('download-progress')
Off('download-complete')
Off('update-available')
}
// ==================== 返回 ====================
@@ -259,6 +315,7 @@ export const useUpdateStore = defineStore('update', () => {
checkForUpdates,
downloadUpdate,
installUpdate,
skipVersion,
setupEventListeners,
removeEventListeners,
formatFileSize,