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

314 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 版本更新代码对比分析
## 📋 代码差异对比
### 原始版本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<Reactive<...>>
```
**但是**`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 架构的同时,恢复响应性。