新增:文档体系重构+CHANGELOG补充+发布产物清理
This commit is contained in:
313
docs/05-代码审查/分析报告/version-update-comparison.md
Normal file
313
docs/05-代码审查/分析报告/version-update-comparison.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 版本更新代码对比分析
|
||||
|
||||
## 📋 代码差异对比
|
||||
|
||||
### 原始版本(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 架构的同时,恢复响应性。
|
||||
Reference in New Issue
Block a user