修复: 版本更新与设置面板走查问题
- 更新链路: 检查记录远端SHA256,下载完成事件回传,安装时带哈希校验 - 续传: 服务器忽略Range返回200时截断重下防追加损坏,文件名去query - 定时器: 自动检查可重入,配置变更免重启生效,关闭即停,下载加互斥 - 前端: 支持跳过此版本并按版本去重,手动检查不受门禁限制,启动未就绪延时重试 - 更新面板: 新增自动检查开关/间隔/地址配置与进度条状态映射 - 版本历史: cache参数强制刷新与加载超时重试兜底 - 配置: 侧边栏分区全链路持久化,保存请求复用api类型防字段丢失 - 侧边栏: 区块定位改显式类名,不再依赖排序位置 - 绑定: 重新生成并与镜像目录同步
This commit is contained in:
@@ -3,14 +3,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, watch, onMounted, onUnmounted, h, nextTick } from 'vue'
|
||||
import { Modal, Message, Progress } from '@arco-design/web-vue'
|
||||
import { computed, ref, watch, onMounted, onUnmounted, h, nextTick } from 'vue'
|
||||
import { Modal, Message, Progress, Button } from '@arco-design/web-vue'
|
||||
import { useUpdateStore } from '../stores/update'
|
||||
import { parseMarkdown, isMarkedReady, preloadMarked } from '../utils/markedExtensions'
|
||||
import { sanitizeHtml } from '@/utils/fileUtils'
|
||||
import { parseWailsEventData } from '@/utils/wailsEvent'
|
||||
import { DownloadUpdate } from '../wailsjs/v3-bindings/u-desk/app'
|
||||
import { On, Off } from '@wailsio/events'
|
||||
import { GetCurrentVersion } from '../wailsjs/v3-bindings/u-desk/app'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -33,7 +31,9 @@ let confirmModalInstance = null
|
||||
let progressModalInstance = null
|
||||
|
||||
// Computed
|
||||
const currentVersion = computed(() => props.updateInfo?.current_version || '0.1.0')
|
||||
// 更新信息未带 current_version 时从后端兜底获取
|
||||
const backendVersion = ref('')
|
||||
const currentVersion = computed(() => props.updateInfo?.current_version || backendVersion.value)
|
||||
const latestVersion = computed(() => props.updateInfo?.latest_version || '')
|
||||
const changelog = computed(() => props.updateInfo?.changelog || '')
|
||||
const forceUpdate = computed(() => props.updateInfo?.force_update || false)
|
||||
@@ -133,6 +133,15 @@ const showUpdateModal = () => {
|
||||
)
|
||||
}
|
||||
|
||||
// 跳过此版本(强制更新不可跳过)
|
||||
if (!forceUpdate.value) {
|
||||
elements.push(
|
||||
h('div', { style: { marginTop: '8px', textAlign: 'right' } }, [
|
||||
h(Button, { size: 'small', type: 'text', onClick: handleSkipVersion }, () => '跳过此版本')
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
return elements
|
||||
},
|
||||
okText: '立即更新',
|
||||
@@ -187,22 +196,12 @@ const getProgressModalContent = () => {
|
||||
]
|
||||
}
|
||||
|
||||
// 安装中状态
|
||||
if (updateStore.installing) {
|
||||
return [
|
||||
h('div', { style: { marginBottom: '16px' } }, [
|
||||
h('div', { style: { marginBottom: '8px', fontSize: '14px', color: 'var(--color-text-2)' } }, '正在安装更新...')
|
||||
]),
|
||||
h('div', { style: { fontSize: '12px', color: 'var(--color-text-3)' } }, '请稍候,应用将在安装完成后自动重启...')
|
||||
]
|
||||
}
|
||||
|
||||
// 完成状态
|
||||
// 安装中状态:下载完成后进入安装阶段,弹窗保持打开直到进程重启
|
||||
return [
|
||||
h('div', { style: { marginBottom: '16px', textAlign: 'center' } }, [
|
||||
h('div', { style: { fontSize: '16px', color: 'rgb(var(--success-6))', marginBottom: '8px' } }, '✓ 更新完成')
|
||||
h('div', { style: { marginBottom: '16px' } }, [
|
||||
h('div', { style: { marginBottom: '8px', fontSize: '14px', color: 'var(--color-text-2)' } }, '正在安装更新...')
|
||||
]),
|
||||
h('div', { style: { fontSize: '14px', color: 'var(--color-text-2)' } }, '应用将在几秒后自动重启...')
|
||||
h('div', { style: { fontSize: '12px', color: 'var(--color-text-3)' } }, '请稍候,应用将在安装完成后自动重启...')
|
||||
]
|
||||
}
|
||||
|
||||
@@ -274,16 +273,23 @@ const closeModals = () => {
|
||||
closeProgressModal()
|
||||
}
|
||||
|
||||
// 下载更新
|
||||
// 跳过此版本
|
||||
const handleSkipVersion = async () => {
|
||||
try {
|
||||
await updateStore.skipVersion(props.updateInfo.latest_version)
|
||||
} catch (error) {
|
||||
console.error('跳过版本失败:', error)
|
||||
}
|
||||
closeModals()
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
// 下载更新(进度与完成事件由 store 统一处理)
|
||||
const handleDownload = async () => {
|
||||
await showProgressModal()
|
||||
|
||||
try {
|
||||
const result = await DownloadUpdate(props.updateInfo.download_url)
|
||||
if (result.success) return
|
||||
|
||||
closeProgressModal()
|
||||
Message.error(result.message || '下载启动失败')
|
||||
await updateStore.downloadUpdate()
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
closeProgressModal()
|
||||
@@ -291,35 +297,34 @@ const handleDownload = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 下载完成处理(本地覆盖:关闭弹窗)
|
||||
const onDownloadComplete = async (event) => {
|
||||
const data = parseWailsEventData(event)
|
||||
|
||||
if (data.error) {
|
||||
closeProgressModal()
|
||||
Message.error('下载失败:' + data.error)
|
||||
return
|
||||
// 下载/安装状态收尾:下载失败收起进度弹窗;安装流程结束(重启前或失败)关闭弹窗
|
||||
watch(
|
||||
() => [updateStore.installing, updateStore.downloadStatus],
|
||||
([installing, status], [prevInstalling]) => {
|
||||
if (status === 'exception') {
|
||||
closeProgressModal()
|
||||
return
|
||||
}
|
||||
if (prevInstalling && !installing) {
|
||||
closeProgressModal()
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!data.success || !data.file_path) {
|
||||
closeProgressModal()
|
||||
Message.error('下载完成但数据不完整')
|
||||
return
|
||||
}
|
||||
|
||||
// 等待安装完成
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
closeProgressModal()
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
)
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
On('download-complete', onDownloadComplete)
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const result = await GetCurrentVersion()
|
||||
if (result.success) {
|
||||
backendVersion.value = result.data?.version || ''
|
||||
}
|
||||
} catch {
|
||||
// 后端未就绪时忽略,留空兜底
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
Off('download-complete')
|
||||
closeModals()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user