Private
Public Access
1
0
Files
u-desk/docs/05-代码审查/分析报告/version-update-comparison.md

7.0 KiB
Raw Blame History

版本更新代码对比分析

📋 代码差异对比

原始版本cc50de0- 正常显示进度

状态定义

// ✅ 所有状态都是组件内的 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
})

下载函数

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
  }
}

事件监听

// ✅ 在组件内监听事件
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- 不显示进度

状态定义

// ✅ 使用 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
// })

下载函数

const handleDownload = async () => {
  // ❌ 不再直接设置状态,而是调用 store 方法
  updateStore.downloadUpdate()
}

Store 中的下载函数

// 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
  }
}

事件监听

// ❌ 在 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 中:

const progressInfo = reactive({
  speed: 0,
  downloaded: 0,
  total: 0
})

使用 storeToRefs 解构后:

const { progressInfo } = storeToRefs(updateStore)
// progressInfo 现在是一个 Ref<Reactive<...>>

但是Object.assign(progressInfo, { ... }) 修改 reactive 对象时,可能不会触发 Vue 的响应式更新!

响应性链路断裂

原始版本:
后端事件 → onDownloadProgress → progressInfo.value = {...}  → ✅ 触发更新

当前版本:
后端事件 → store.onDownloadProgress → Object.assign(progressInfo, {...}) → ❌ 不触发更新

解决方案

方案 1保持 progressInfo 为 ref推荐

修改 store 定义:

// 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

// stores/update.ts
const progressInfoState = reactive({
  speed: 0,
  downloaded: 0,
  total: 0
})
const progressInfo = ref(progressInfoState)

// 更新时:
Object.assign(progressInfoState, { ... })

方案 3不使用 storeToRefs直接访问 store

// UpdatePanel.vue
const updateStore = useUpdateStore()

// 模板中直接使用
updateStore.progressInfo.speed
updateStore.progressInfo.downloaded

🎯 推荐修复

采用方案 1:将 progressInfo 改为 ref

修改 stores/update.ts

// ❌ 修改前
const progressInfo = reactive({
  speed: 0,
  downloaded: 0,
  total: 0
})

// ✅ 修改后
const progressInfo = ref({
  speed: 0,
  downloaded: 0,
  total: 0
})

修改 onDownloadProgress

// ❌ 修改前
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

// ❌ 修改前
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 架构的同时,恢复响应性。