# 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 组件,应该使用 `