# 版本更新代码对比分析 ## 📋 代码差异对比 ### 原始版本(cc50de0)- ✅ 正常显示进度 #### 状态定义 ```typescript // ✅ 所有状态都是组件内的 ref const downloading = ref(false) const installing = ref(false) const downloadProgress = ref(0) const downloadStatus = ref('active') // ✅ progressInfo 是 ref,包含嵌套对象 const progressInfo = ref({ progress: 0, speed: 0, downloaded: 0, total: 0 }) ``` #### 下载函数 ```typescript 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('下载请求已发送') } } catch (error) { console.error('下载失败:', error) downloadStatus.value = 'exception' downloading.value = false } } ``` #### 事件监听 ```typescript // ✅ 在组件内监听事件 const onDownloadProgress = (event) => { const data = parseEventData(event) progressInfo.value = { // ✅ 直接修改 ref progress: data.progress || 0, speed: data.speed || 0, downloaded: data.downloaded || 0, total: data.total || 0 } downloadProgress.value = Math.round(data.progress || 0) } onMounted(async () => { await loadCurrentVersion() await loadConfig() // ✅ 直接监听事件 window.EventsOn('download-progress', onDownloadProgress) window.EventsOn('download-complete', onDownloadComplete) }) ``` --- ### 当前版本(HEAD)- ❌ 不显示进度 #### 状态定义 ```typescript // ✅ 使用 storeToRefs 从 store 解构 import { storeToRefs } from 'pinia' import { useUpdateStore } from '../stores/update' const updateStore = useUpdateStore() const { checking, downloading, installing, downloadProgress, downloadStatus, progressInfo, updateInfo } = storeToRefs(updateStore) // ❌ 问题:progressInfo 在 store 中是 reactive,不是 ref // store.ts 定义: // const progressInfo = reactive({ // speed: 0, // downloaded: 0, // total: 0 // }) ``` #### 下载函数 ```typescript const handleDownload = async () => { // ❌ 不再直接设置状态,而是调用 store 方法 updateStore.downloadUpdate() } ``` #### Store 中的下载函数 ```typescript // stores/update.ts const downloadUpdate = async () => { const url = updateInfo.value?.download_url if (!url) { Message.warning('下载地址不存在') return } // ✅ 设置 store 状态 downloading.value = true downloadProgress.value = 0 downloadStatus.value = 'active' Object.assign(progressInfo, { speed: 0, downloaded: 0, total: 0 }) // ❌ Object.assign 对 reactive 对象的修改 try { const result = await window.go.main.App.DownloadUpdate(url) if (result.success) { Message.success('下载请求已发送') } } catch (error) { downloadStatus.value = 'exception' downloading.value = false } } ``` #### 事件监听 ```typescript // ❌ 在 App.vue 中注册事件(store 的方法) // App.vue onMounted: updateStore.setupEventListeners() // stores/update.ts: const setupEventListeners = () => { window.runtime.EventsOn('download-progress', onDownloadProgress) window.runtime.EventsOn('download-complete', onDownloadComplete) } // ❌ UpdatePanel 不再监听 download-progress(只监听 download-complete) ``` --- ## 🔍 问题根因分析 ### 核心问题 **storeToRefs 解构 reactive 对象的响应性问题** 在 Pinia store 中: ```typescript const progressInfo = reactive({ speed: 0, downloaded: 0, total: 0 }) ``` 使用 `storeToRefs` 解构后: ```typescript const { progressInfo } = storeToRefs(updateStore) // progressInfo 现在是一个 Ref> ``` **但是**:`Object.assign(progressInfo, { ... })` 修改 reactive 对象时,可能不会触发 Vue 的响应式更新! ### 响应性链路断裂 ``` 原始版本: 后端事件 → onDownloadProgress → progressInfo.value = {...} → ✅ 触发更新 当前版本: 后端事件 → store.onDownloadProgress → Object.assign(progressInfo, {...}) → ❌ 不触发更新 ``` --- ## ✅ 解决方案 ### 方案 1:保持 progressInfo 为 ref(推荐) 修改 store 定义: ```typescript // stores/update.ts const progressInfo = ref({ speed: 0, downloaded: 0, total: 0 }) // 更新时: const onDownloadProgress = (event: unknown) => { const data = parseEventData(event) progressInfo.value = { // ✅ 直接替换整个对象 speed: data.speed || 0, downloaded: data.downloaded || 0, total: data.total || 0 } } ``` ### 方案 2:使用 ref 包装 reactive ```typescript // stores/update.ts const progressInfoState = reactive({ speed: 0, downloaded: 0, total: 0 }) const progressInfo = ref(progressInfoState) // 更新时: Object.assign(progressInfoState, { ... }) ``` ### 方案 3:不使用 storeToRefs,直接访问 store ```typescript // UpdatePanel.vue const updateStore = useUpdateStore() // 模板中直接使用 updateStore.progressInfo.speed updateStore.progressInfo.downloaded ``` --- ## 🎯 推荐修复 **采用方案 1**:将 progressInfo 改为 ref ### 修改 stores/update.ts ```typescript // ❌ 修改前 const progressInfo = reactive({ speed: 0, downloaded: 0, total: 0 }) // ✅ 修改后 const progressInfo = ref({ speed: 0, downloaded: 0, total: 0 }) ``` ### 修改 onDownloadProgress ```typescript // ❌ 修改前 Object.assign(progressInfo, { speed: (data.speed as number) || 0, downloaded: (data.downloaded as number) || 0, total: (data.total as number) || 0 }) // ✅ 修改后 progressInfo.value = { speed: (data.speed as number) || 0, downloaded: (data.downloaded as number) || 0, total: (data.total as number) || 0 } ``` ### 修改 onDownloadComplete ```typescript // ❌ 修改前 downloadProgress.value = 100 progressInfo.downloaded = (data.file_size as number) || 0 progressInfo.total = (data.file_size as number) || 0 // ✅ 修改后 downloadProgress.value = 100 progressInfo.value = { speed: 0, downloaded: (data.file_size as number) || 0, total: (data.file_size as number) || 0 } ``` --- ## 📊 对比总结 | 项目 | 原始版本 | 当前版本 | 推荐方案 | |------|---------|---------|---------| | progressInfo 类型 | `ref({...})` | `reactive({...})` | `ref({...})` | | 更新方式 | `progressInfo.value = {...}` | `Object.assign(progressInfo, {...})` | `progressInfo.value = {...}` | | 事件监听 | 组件内监听 | store 监听 | store 监听 | | 响应性 | ✅ 正常 | ❌ 断裂 | ✅ 正常 | --- ## 🔧 立即修复 需要修改 3 个地方: 1. **stores/update.ts** - progressInfo 改为 ref 2. **stores/update.ts** - 更新 onDownloadProgress 3. **stores/update.ts** - 更新 onDownloadComplete 这样可以保持 store 架构的同时,恢复响应性。