# Design Document
## Overview
本设计文档描述了将「农小禹智慧农业系统」从 uni-app Vue2 (Options API) 迁移到 uni-app Vue3 (Composition API) 的技术方案。迁移的核心目标是支持 HarmonyOS 打包,同时确保在 Android、iOS 和 H5 平台上的功能和行为完全一致。
### 迁移原则
1. **零业务逻辑改动** - 所有业务逻辑、API 调用、数据处理保持不变
2. **零 UI 结构改动** - 所有模板结构、样式、布局保持不变
3. **语法层面迁移** - 仅进行 Vue2 到 Vue3 的语法和 API 转换
4. **跨平台一致性** - 确保所有平台行为一致
5. **HarmonyOS 兼容** - 移除浏览器特定 API,使用 uni-app 跨平台 API
6. **可维护性优先** - 遵循 Vue3 最佳实践,添加清晰的注释
### 项目现状分析
**当前技术栈:**
- Vue 2.6.14 + Options API
- Vuex 3.6.2
- uni-app 2.x
- uview-ui 2.0.38
- 第三方插件: Jessibuca (视频播放)、高德地图 SDK
**项目规模:**
- 约 40+ 页面组件
- 4 个公共组件
- 15+ API 服务模块
- 1 个 Vuex store
- 多个工具函数模块
## Architecture
### 迁移架构设计
```
┌─────────────────────────────────────────────────────────────┐
│ 迁移执行层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 组件迁移引擎 │ │ Store迁移引擎 │ │ 配置迁移引擎 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 转换规则层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 语法转换规则 │ │ API映射规则 │ │ 生命周期映射 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 验证层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 语法验证器 │ │ 功能测试器 │ │ 性能测试器 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 分层职责
**迁移执行层:**
- 组件迁移引擎: 负责 .vue 文件的转换
- Store 迁移引擎: 负责 Vuex store 的升级
- 配置迁移引擎: 负责 package.json、manifest.json 等配置文件的更新
**转换规则层:**
- 语法转换规则: Options API → Composition API 的转换规则
- API 映射规则: Vue2 API → Vue3 API 的映射关系
- 生命周期映射: Vue2 生命周期钩子 → Vue3 生命周期钩子的映射
**验证层:**
- 语法验证器: 验证转换后的代码符合 Vue3 规范
- 功能测试器: 验证业务逻辑和功能一致性
- 性能测试器: 验证性能指标不低于原版本
## Components and Interfaces
### 核心组件
#### 1. 组件迁移引擎 (ComponentMigrationEngine)
**职责:** 将 Vue2 单文件组件转换为 Vue3 Composition API 格式
**接口:**
```typescript
interface ComponentMigrationEngine {
// 迁移单个组件文件
migrateComponent(filePath: string): MigrationResult
// 批量迁移组件
migrateComponents(filePaths: string[]): MigrationResult[]
// 验证迁移结果
validateMigration(result: MigrationResult): ValidationResult
}
```
**转换流程:**
1. 解析 Vue2 组件的 script、template、style 部分
2. 转换 script 部分: Options API → Composition API
3. 更新 template 部分: 移除 Vue2 特有语法
4. 保持 style 部分不变
5. 生成 Vue3 组件文件
#### 2. Store 迁移引擎 (StoreMigrationEngine)
**职责:** 将 Vuex 3.x store 升级到 Vuex 4.x 或迁移到 Pinia
**接口:**
```typescript
interface StoreMigrationEngine {
// 迁移 store 文件
migrateStore(storePath: string, target: 'vuex4' | 'pinia'): MigrationResult
// 更新组件中的 store 使用
updateStoreUsage(componentPath: string): MigrationResult
}
```
**转换策略:**
- 选项 A: 升级到 Vuex 4.x (保持 API 相似性,迁移成本低)
- 选项 B: 迁移到 Pinia (更现代,更好的 TypeScript 支持)
- 推荐: Vuex 4.x (项目已有 Vuex 使用经验,迁移风险低)
#### 3. 配置迁移引擎 (ConfigMigrationEngine)
**职责:** 更新项目配置文件以支持 Vue3
**接口:**
```typescript
interface ConfigMigrationEngine {
// 更新 package.json 依赖
updateDependencies(): void
// 更新 manifest.json 配置
updateManifest(): void
// 更新 main.js 入口文件
updateMainEntry(): void
}
```
**需要更新的配置:**
- package.json: 升级 Vue、Vuex、uni-app 等依赖
- manifest.json: 更新 vueVersion 为 "3"
- main.js: 使用 createApp 替代 new Vue
### 转换规则定义
#### Options API → Composition API 转换规则
| Vue2 Options API | Vue3 Composition API | 说明 |
|-----------------|---------------------|------|
| `data()` | `ref()` / `reactive()` | 基本类型用 ref,对象用 reactive |
| `methods` | 函数定义 | 在 setup 中定义普通函数 |
| `computed` | `computed()` | 使用 computed 函数包装 |
| `watch` | `watch()` / `watchEffect()` | 使用 watch 函数 |
| `props` | `defineProps()` | 使用 defineProps 声明 |
| `$emit` | `defineEmits()` | 使用 defineEmits 声明 |
| `this.$refs` | `ref()` | 使用 ref 创建模板引用 |
| `this.$store` | `useStore()` | 使用 useStore 获取 store |
| `this.$route` | `useRoute()` | 使用 useRoute 获取路由 |
| `this.$router` | `useRouter()` | 使用 useRouter 获取路由器 |
#### 生命周期钩子映射
| Vue2 生命周期 | Vue3 生命周期 | 说明 |
|--------------|--------------|------|
| `beforeCreate` | `setup()` 顶层 | 逻辑移至 setup 顶层 |
| `created` | `setup()` 顶层 | 逻辑移至 setup 顶层 |
| `beforeMount` | `onBeforeMount()` | 导入并使用 |
| `mounted` | `onMounted()` | 导入并使用 |
| `beforeUpdate` | `onBeforeUpdate()` | 导入并使用 |
| `updated` | `onUpdated()` | 导入并使用 |
| `beforeDestroy` | `onBeforeUnmount()` | 名称变更 |
| `destroyed` | `onUnmounted()` | 名称变更 |
| `activated` | `onActivated()` | 导入并使用 |
| `deactivated` | `onDeactivated()` | 导入并使用 |
| `errorCaptured` | `onErrorCaptured()` | 导入并使用 |
| uni-app 生命周期 | 保持不变 | onLoad, onShow, onHide 等 |
#### 模板语法转换规则
| Vue2 语法 | Vue3 语法 | 说明 |
|----------|----------|------|
| `v-model` | `v-model` | 自定义组件需调整 |
| `.sync` | `v-model:propName` | .sync 修饰符已移除 |
| `$listeners` | 移除 | 已合并到 $attrs |
| `v-bind="$attrs"` | `v-bind="$attrs"` | 保持不变 |
| 自定义指令钩子 | 更新钩子名称 | bind→beforeMount 等 |
## Data Models
### 迁移结果数据模型
```typescript
interface MigrationResult {
// 文件路径
filePath: string
// 迁移状态
status: 'success' | 'partial' | 'failed'
// 转换后的代码
code: string
// 警告信息
warnings: Warning[]
// 错误信息
errors: Error[]
// TODO 项
todos: TodoItem[]
}
interface Warning {
line: number
column: number
message: string
rule: string
}
interface TodoItem {
line: number
message: string
reason: string
recommendation: string
}
interface ValidationResult {
isValid: boolean
errors: ValidationError[]
warnings: ValidationWarning[]
}
```
### 组件转换示例
**Vue2 组件 (Before):**
```vue
```
**Vue3 组件 (After):**
```vue
```
### Store 转换示例
**Vuex 3.x (Before):**
```javascript
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
export default store
```
**Vuex 4.x (After):**
```javascript
// store/index.js
import { createStore } from 'vuex'
const store = createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
export default store
```
**组件中使用 Store (Before):**
```vue
```
**组件中使用 Store (After):**
```vue
```
### 全局配置转换示例
**main.js (Before):**
```javascript
import Vue from 'vue'
import App from './App'
import store from './store'
import uView from 'uview-ui'
// 全局过滤器
Vue.filter('formatDate', (value) => {
// ...
})
// 全局属性
Vue.prototype.$api = api
Vue.use(store)
Vue.use(uView)
const app = new Vue({
store,
...App
})
app.$mount()
```
**main.js (After):**
```javascript
import { createSSRApp } from 'vue'
import App from './App.vue'
import store from './store'
import uView from 'uview-ui' // 需要 Vue3 兼容版本
// 全局方法 (替代过滤器)
import { formatDate } from './utils/filters'
export function createApp() {
const app = createSSRApp(App)
app.use(store)
app.use(uView)
// 全局属性
app.config.globalProperties.$api = api
app.config.globalProperties.$formatDate = formatDate
return {
app
}
}
```
## Correctness Properties
*属性 (Property) 是关于系统应该如何行为的形式化陈述,它应该在所有有效执行中保持为真。属性是人类可读规范和机器可验证正确性保证之间的桥梁。通过属性测试,我们可以验证代码在各种输入下的正确性。*
### Property 1: Options API 完整转换
*对于任意* Vue2 组件,如果它包含 data、methods、computed、watch 中的任意选项,转换后的 Vue3 组件应该使用对应的 Composition API (ref/reactive、函数定义、computed()、watch()),并且不包含 Options API 的选项对象。
**Validates: Requirements 1.1, 1.3**
### Property 2: 生命周期钩子正确映射
*对于任意* Vue2 组件,如果它包含生命周期钩子 (mounted、created、beforeDestroy、destroyed 等),转换后的 Vue3 组件应该使用对应的 Composition API 钩子 (onMounted、setup 顶层、onBeforeUnmount、onUnmounted 等),并且钩子内的业务逻辑保持不变。
**Validates: Requirements 1.2, 2.1, 2.2, 2.3, 2.4**
### Property 3: uni-app 生命周期保持不变
*对于任意* 包含 uni-app 特有生命周期 (onLoad、onShow、onHide、onPullDownRefresh 等) 的组件,转换后这些生命周期钩子的名称和用法应该保持完全不变。
**Validates: Requirements 2.5**
### Property 4: this 关键字完全移除
*对于任意* 转换后的 Vue3 组件,代码中不应该包含 `this.` 的引用 (除了在注释中),所有数据和方法访问应该使用 Composition API 的直接引用。
**Validates: Requirements 1.4**
### Property 5: script setup 语法使用
*对于任意* 转换后的 Vue3 组件,应该使用 `