# uni-app-x 页面修复指南 ## 📋 文档概述 本文档总结了 uni-app-x 项目中页面配置和编译错误的完整修复流程,旨在为后续开发提供标准化的解决方案和最佳实践。 ## 🔍 问题根源分析 ### 1. 初始错误现象 ``` [plugin:uni:h5-pages-json] 页面"minimal"不存在,请确保填写的页面路径不包含文件后缀,且必须与真实的文件路径大小写保持一致。 ``` ``` SyntaxError: The requested module '.../vue.runtime.esm.js' does not provide an export named 'onLoad' ``` ### 2. 根本原因总结 #### **原因一:pages.json 路径配置错误** - **错误格式**: `"path": "pages/minimal"` (主页面缺少完整路径) - **错误格式**: `"path": "pages/mall/admin/index"` (主页面错误包含完整路径) - **错误格式**: 子包路径配置不完整 #### **原因二:AdminLayout 组件语法错误** - **重复闭合标签**: ` 标签 --> ``` #### **步骤 2.2:修复生命周期导入** ```javascript // ❌ 错误:从 Vue 导入 uni-app 生命周期 import { ref, computed, onLoad } from "vue"; // ✅ 正确:uni-app-x 生命周期全局可用 import { ref, computed } from "vue"; // 在组件中直接使用 onLoad(() => { activeMenu.value = props.currentPage; }); ``` #### **步骤 2.3:验证组件结构** ```vue ``` ### **阶段三:页面配置恢复** #### **步骤 3.1:恢复主页面配置** ```json { "pages": [ { "path": "pages/minimal", "style": { "navigationBarTitleText": "最小测试" } }, { "path": "pages/mall/admin/index", "style": { "navigationBarTitleText": "管理后台", "navigationStyle": "custom" } } ] } ``` #### **步骤 3.2:恢复子包配置** ```json { "subPackages": [ { "root": "pages/mall", "pages": [ { "path": "admin/user-management", "style": { "navigationBarTitleText": "用户管理", "navigationStyle": "custom" } } // ... 其他页面 ] } ] } ``` #### **步骤 3.3:验证完整配置** ```json { "pages": [ { "path": "pages/minimal", "style": { "navigationBarTitleText": "最小测试" } }, { "path": "pages/mall/admin/index", "style": { "navigationBarTitleText": "管理后台", "navigationStyle": "custom" } } ], "subPackages": [ { "root": "pages/mall", "pages": [ { "path": "admin/user-management", "style": { "navigationBarTitleText": "用户管理", "navigationStyle": "custom" } }, { "path": "admin/product-management", "style": { "navigationBarTitleText": "商品管理", "navigationStyle": "custom" } }, { "path": "admin/order-management", "style": { "navigationBarTitleText": "订单管理", "navigationStyle": "custom" } }, { "path": "admin/finance-management", "style": { "navigationBarTitleText": "财务管理", "navigationStyle": "custom" } }, { "path": "admin/system-settings", "style": { "navigationBarTitleText": "系统设置", "navigationStyle": "custom" } } ] } ], "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "mall", "navigationBarBackgroundColor": "#FFFFFF", "backgroundColor": "#F8F8F8" } } ``` ### **阶段四:路径格式统一** ### **阶段五:特殊字符处理** #### **步骤 5.1:移除问题 Emoji 字符** ```vue ``` **常见问题 Emoji 及替代方案**: ```javascript // 统计图标 '👥' → '👤' // 用户数量 '✅' → '✓' // 成功/活跃 '🚫' → '✗' // 禁用/下架 '📦' → '□' // 商品/包裹 '⏳' → '○' // 等待/处理中 '🚚' → '→' // 配送中 '⚠️' → '!' // 警告/库存不足 // 财务图标 '💰' → '$' // 收入 '📈' → '↑' // 增长 '📊' → '≡' // 图表 '💳' → '■' // 账户 ``` #### **步骤 5.2:检查文件编码** ```bash # 检查文件编码和特殊字符 file pages/mall/admin/*.uvue # 确保文件编码为 UTF-8 无 BOM # 移除任何不可见字符 ``` #### **步骤 5.3:验证模板语法完整性** ```vue ``` #### **步骤 5.4:最终验证** ### **阶段六:缩进一致性检查** #### **步骤 6.1:统一缩进方式** ```vue ``` #### **步骤 6.2:检查缩进工具** ```bash # 检查文件中是否存在制表符 grep -P '\t' pages/mall/admin/*.uvue # 将制表符转换为空格(2个空格) sed -i 's/\t/ /g' pages/mall/admin/*.uvue ``` #### **步骤 6.3:验证标签闭合** ```javascript // 检查所有开始标签都有对应结束标签 // 检查缩进一致性 // 确保没有多余的闭合标签 ``` #### **步骤 6.4:最终验证** ### **阶段七:方法调用检查** #### **步骤 7.1:检查方法引用** ```javascript // ❌ 错误:方法名已更改但模板未更新 // ✅ 正确:更新方法引用 ``` #### **步骤 7.2:验证方法定义** ```javascript // 确保所有模板中引用的方法都已定义 const newMethodName = () => { // 方法实现 }; ``` #### **步骤 7.3:检查参数匹配** ```javascript // 确保方法调用时的参数与定义一致 const handleClick = (param: string) => { console.log(param) } // 模板调用 ``` #### **步骤 7.4:最终验证** ### **阶段八:自闭合标签检查** #### **步骤 8.1:检查自闭合标签格式** ```vue ``` #### **步骤 8.2:自动修复工具** ```bash # 使用 sed 批量修复(注意备份文件) sed -i 's/><\/image>/ \/>/g' pages/mall/admin/*.uvue sed -i 's/><\/checkbox>/ \/>/g' pages/mall/admin/*.uvue ``` #### **步骤 8.3:验证标签完整性** ```javascript // 检查所有自闭合标签都正确结束 // 确保没有多余的结束标签 ``` ### **阶段九:模态框位置优化** #### **步骤 9.1:识别模态框位置问题** ```vue ``` #### **步骤 9.2:重构模态框位置** ```vue ``` #### **步骤 9.3:验证模态框行为** ```javascript // 确保模态框在所有页面模式下都能正常显示 // 测试不同条件下的模态框显示 ``` #### **步骤 9.4:最终验证** ### **阶段十:.uvue文件特殊处理** #### **步骤 10.1:简化复杂模板** ```vue ``` #### **步骤 10.2:移除问题Unicode字符** ```vue Y N * ``` #### **步骤 10.3:UTS编译器兼容性检查** ```javascript // 检查UTS特定的语法要求 // 确保所有导入和类型定义正确 // 验证组件Props和事件处理 ``` #### **步骤 10.4:渐进式开发策略** ```javascript // 1. 从最小可用模板开始 const minimalTemplate = ` `; // 2. 逐步添加功能,每次只添加一个特性 // 3. 每次修改后立即编译测试 // 4. 出现问题时立即回滚到上一个稳定版本 ``` #### **步骤 10.5:最终验证** ### **阶段十一:批量.uvue文件修复** ### **阶段十二:AdminLayout双侧边栏布局** #### **步骤 11.1:识别问题文件** ```bash # 检查所有.uvue文件是否正常编译 # 记录出现"Invalid end tag"错误的文件 # 按优先级排序修复顺序 ``` #### **步骤 11.2:批量简化模板** ```javascript // 为每个问题文件创建最小可用模板 const minimalTemplates = { "user-management.uvue": ` `, "product-management.uvue": ` `, // 为其他页面创建类似的模板 }; ``` #### **步骤 11.3:统一字符替换** ```bash # 批量替换所有.uvue文件中的问题字符 find pages/mall/admin -name "*.uvue" -exec sed -i \ -e 's/👤/U/g' \ -e 's/✓/Y/g' \ -e 's/✗/N/g' \ -e 's/★/*/g' \ -e 's/📦/□/g' \ -e 's/⏳/○/g' \ -e 's/🚚/→/g' \ {} \; ``` #### **步骤 11.4:验证批量修复** ```javascript // 检查所有文件是否正常编译 // 确认没有"Invalid end tag"错误 // 测试基本页面导航功能 ``` #### **步骤 11.5:最终验证** #### **步骤 12.1:设计双侧边栏布局** ```vue ``` #### **步骤 12.2:实现菜单数据结构** ```javascript const menuList = ref([ { id: "user", title: "用户管理", icon: "icon-user", path: "/pages/mall/admin/user-management", subMenus: [ { id: "user-list", title: "用户列表", path: "/pages/mall/admin/user-management", }, { id: "user-add", title: "添加用户", path: "/pages/mall/admin/user-management?action=add", }, ], }, { id: "product", title: "商品管理", icon: "icon-product", path: "/pages/mall/admin/product-management", subMenus: [ { id: "product-list", title: "商品列表", path: "/pages/mall/admin/product-management", }, { id: "category", title: "商品分类", path: "/pages/mall/admin/product-management?tab=category", }, ], }, // 没有子菜单的页面 { id: "statistics", title: "用户统计", icon: "icon-statistics", path: "/pages/mall/admin/user-statistics", }, ]); ``` #### **步骤 12.3:计算属性实现** ```javascript // 计算当前菜单的子菜单 const activeSubMenus = computed(() => { const menu = menuList.value.find((m) => m.id === activeMenu.value); return menu ? menu.subMenus || [] : []; }); // 判断是否有子菜单 const hasSubMenus = computed(() => { return activeSubMenus.value.length > 0; }); ``` #### **步骤 12.4:菜单点击处理** ```javascript const handleMenuClick = (menu: any) => { activeMenu.value = menu.id // 设置默认子菜单(如果有的话) activeSubMenu.value = menu.subMenus && menu.subMenus.length > 0 ? menu.subMenus[0].id : '' // 导航到菜单路径 uni.navigateTo({ url: menu.path }) } const handleSubMenuClick = (subMenu: any) => { activeSubMenu.value = subMenu.id // 导航到子菜单路径(可能包含查询参数) uni.navigateTo({ url: subMenu.path }) } ``` #### **步骤 12.5:样式实现** ```scss /* 主侧边栏 */ .admin-sider { width: 200px; background-color: #001529; position: fixed; left: 0; top: 0; bottom: 0; z-index: 1000; } /* 主内容区 */ .admin-main { margin-left: 200px; display: flex; min-height: 100vh; } /* 内容侧边栏 */ .content-sider { width: 180px; background-color: #ffffff; border-right: 1px solid #e8e8e8; box-shadow: 2px 0 8px rgba(0, 0, 0, 0.06); } .content-sub-menu-item { height: 36px; padding: 0 16px; cursor: pointer; transition: all 0.2s; &.active { background-color: #e6f7ff; color: #1890ff; border-right: 2px solid #1890ff; } } /* 内容区域 */ .content-area { flex: 1; background-color: #f0f2f5; } ``` #### **步骤 12.6:响应式设计** ```scss @media (max-width: 768px) { .admin-sider { width: 160px; } .admin-main { margin-left: 160px; } .content-sider { width: 140px; } } ``` #### **步骤 12.7:最终验证** ### **阶段十三:AdminLayout代码清理** #### **步骤 13.1:移除遗留变量引用** ```javascript // ❌ 错误:引用已删除的变量 const handleMenuClick = (menu: any) => { activeMenu.value = menu.id // 引用不存在的 tabs 变量 const existingTab = tabs.value.find(tab => tab.id === menu.id) // ... } // ✅ 修复:移除所有遗留引用 const handleMenuClick = (menu: any) => { activeMenu.value = menu.id activeSubMenu.value = menu.subMenus?.[0]?.id || '' uni.navigateTo({ url: menu.path }) } ``` #### **步骤 13.2:检查计算属性完整性** ```javascript // 确保所有模板中使用的属性都已定义 const activeSubMenuTitle = computed(() => { const subMenu = activeSubMenus.value.find(sm => sm.id === activeSubMenu.value) return subMenu ? subMenu.title : '' }) // 模板中使用 {{ activeSubMenuTitle }} ``` #### **步骤 13.3:验证模板依赖** ```vue ``` #### **步骤 13.4:最终验证** ### **阶段十二:AdminLayout组件解析修复** #### **步骤 12.1:检查组件导入路径** ```javascript // ❌ 错误:缺少文件扩展名 import AdminLayout from "@/layouts/admin/index"; // ❌ 错误:路径不存在 import AdminLayout from "@/layout/admin/index.uvue"; // ✅ 正确:完整路径包含扩展名 import AdminLayout from "@/layouts/admin/index.uvue"; ``` #### **步骤 12.2:简化组件结构** ```vue ``` #### **步骤 12.3:验证组件可用性** ```javascript // 在页面中正确使用组件 ``` #### **步骤 12.4:UTS编译器兼容性** ```javascript // 确保组件语法符合UTS要求 // 使用 ``` ### **原理五:错误排查方法** #### **逐步验证策略**: 1. **最小化配置**: 从最简单的配置开始 2. **逐步添加**: 每次只添加一个功能 3. **错误定位**: 根据错误信息快速定位问题 4. **备份恢复**: 修改前备份,失败时快速回滚 #### **常见错误检查清单**: - ✅ pages.json 路径格式是否正确 - ✅ 页面文件是否存在 - ✅ 组件语法是否正确 - ✅ 导入语句是否正确 - ✅ 生命周期钩子使用是否正确 - ✅ 响应式数据使用是否正确 - ✅ 特殊字符和 emoji 是否安全 - ✅ 缩进是否一致(避免混用制表符和空格) - ✅ 方法调用是否正确(方法名和参数匹配) - ✅ 自闭合标签格式是否正确(使用 `/>` 而非 `>`) - ✅ 模态框位置是否正确(避免条件嵌套) - ✅ .uvue文件复杂度是否适中(避免过度复杂的模板结构) - ✅ 批量文件修复是否完整(所有.uvue文件都已简化处理) - ✅ AdminLayout组件是否正确导入和解析 - ✅ AdminLayout代码清理是否完整(无遗留变量引用) ## 🚀 最佳实践指南 ### **开发规范** #### **1. 文件命名规范** - 页面文件: `kebab-case.uvue` - 组件文件: `PascalCase.uvue` - 工具文件: `camelCase.uts` #### **2. 路径配置规范** - 主页面: `pages/page-name` - 子包页面: `root: "pages/module"`, `path: "sub-page"` - 组件导入: `@/layouts/...`, `@/components/...` #### **3. 代码组织规范** ```vue ``` ### **调试技巧** #### **1. 编译错误排查** - 查看控制台错误信息 - 检查文件语法 - 验证导入路径 - 确认类型定义 #### **2. 运行时错误排查** - 检查页面配置 - 验证组件 Props - 确认事件处理 - 测试页面跳转 #### **3. 性能优化** - 合理使用响应式数据 - 避免不必要的计算属性 - 优化组件渲染 - 使用合适的生命周期 #### **4. .uvue文件特殊处理** - 保持模板结构简单,避免过度复杂 - 使用UTS编译器兼容的字符集 - 定期检查文件编码和特殊字符 - 采用渐进式开发策略,从简单到复杂 - 出现编译错误时优先简化模板结构 #### **5. AdminLayout组件维护** - 保持组件结构简单,避免过度复杂的功能 - 使用正确的文件扩展名(.uvue)在导入路径中 - 定期验证组件的导出和解析 - 出现解析错误时优先简化组件结构 - 确保组件语法符合UTS编译器要求 #### **6. 双侧边栏布局设计** - 主侧边栏只显示一级菜单图标,保持简洁 - 内容侧边栏显示二级菜单,位于内容区左侧 - 合理分配侧边栏宽度,确保移动端兼容性 - 使用计算属性动态控制侧边栏显示 - 确保路由同步和高亮状态正确 ## 📚 参考资源 ### **官方文档** - [uni-app-x 官方文档](https://doc.dcloud.net.cn/uni-app-x/) - [Vue 3 组合式 API](https://cn.vuejs.org/guide/extras/composition-api-faq.html) - [TypeScript 指南](https://www.typescriptlang.org/docs/) ### **最佳实践** - 遵循项目现有的代码风格 - 保持配置的一致性 - 定期检查和更新依赖 - 编写清晰的注释 --- ## 🎯 总结 通过本次修复,我们建立了完整的 uni-app-x 项目开发和调试方法论: 1. **问题定位**: 快速识别配置和语法错误 2. **逐步修复**: 从简单到复杂,逐步解决问题 3. **规范建立**: 统一的代码和配置规范 4. **最佳实践**: 可复用的开发模式 ### **新增问题类型** #### **特殊字符兼容性问题** - **现象**: `[plugin:uts] Invalid end tag` 错误 - **原因**: emoji 字符或特殊 Unicode 符号导致模板解析失败 - **解决方案**: 替换为标准 ASCII 字符或安全 Unicode 符号 - **预防**: 在模板中使用经过验证的安全字符集 --- #### **原因十四:AdminLayout代码清理不完整** - **遗留变量引用**: 移除功能后仍引用已删除的变量 - **计算属性缺失**: 重构时遗漏必要的计算属性 - **模板依赖问题**: 模板中使用未定义的响应式属性 --- ## 🎯 阶段十五: CRMEB 路由体系 1:1 复刻 ### **背景与目标** 本阶段实现了 CRMEB v5 标准版管理端前端的路由体系和侧边栏布局的完整复刻,采用"内部路由/状态驱动渲染"模式,在 uni-app-x 项目中实现单页应用(SPA)体验。 ### **核心架构设计** #### **1. 内部路由系统** 不同于传统的 `uni.navigateTo` 页面栈模式,采用状态驱动的内部路由: ``` 点击菜单 → 更新 activeRouteId → 切换组件渲染 → 不打开新页面 ``` **优势**: - ✅ 避免页面栈堆积 - ✅ 保持布局和侧边栏状态 - ✅ 实现 CRMEB 风格的标签页系统 - ✅ 更快的页面切换速度 #### **2. 文件结构** ``` layouts/admin/ ├── router/ │ ├── adminRoutes.uts # 路由配置(映射CRMEB routes) │ └── adminComponentMap.uts # 组件映射表(静态导入) ├── store/ │ └── adminNavStore.uts # 导航状态管理 ├── components/ │ ├── AdminAside.uvue # 主侧边栏(一级菜单) │ ├── AdminSubSider.uvue # 二级侧边栏(分组+菜单项) │ ├── AdminHeader.uvue # 顶部栏 │ ├── AdminTagsView.uvue # 标签页 │ └── PlaceholderPage.uvue # 占位组件 └── AdminLayout.uvue # 布局容器(渲染组件) ``` #### **3. 路由数据结构** **一级菜单 (TopMenu)**: ```typescript { id: 'user', title: '用户', icon: 'user', path: '/pages/mall/admin/user/list', // 默认路径 order: 2, groups: [...] // 分组列表 } ``` **路由记录 (RouteRecord)**: ```typescript { id: 'user_list', title: '用户管理', path: '/pages/mall/admin/user/list', componentKey: 'UserList', // 映射到组件 parentId: 'user', groupId: 'user-manage', auth: ['admin-user-user-index'] } ``` ### **实施步骤总结** #### **步骤 1: 抽取 CRMEB 路由结构** 从 CRMEB 源码 `router/modules/*` 抽取: - 9 个一级模块: home, user, product, order, marketing, cms, finance, statistic, setting - 30+ 二级路由: 用户管理、商品列表、订单管理等 - 分组信息: 用户管理、会员管理、营销工具等 #### **步骤 2: 创建路由配置文件** **文件**: `layouts/admin/router/adminRoutes.uts` 包含: - `topMenus`: 一级菜单配置 - `routes`: 完整路由表 - 工具函数: `getTopMenus()`, `findRouteById()`, `getBreadcrumb()` 等 #### **步骤 3: 创建状态管理** **文件**: `layouts/admin/store/adminNavStore.uts` 状态: - `activeTopMenuId`: 当前选中的一级菜单 - `activeRouteId`: 当前激活的路由 - `tabs`: 标签页列表 - `isMainAsideCollapsed`: 主侧边栏折叠状态 方法: - `openRoute(routeId)`: 打开路由(核心方法) - `closeTab(tabId)`: 关闭标签页 - `initNavState()`: 初始化导航状态 #### **步骤 4: 创建组件映射表** **文件**: `layouts/admin/router/adminComponentMap.uts` **关键点**: - ✅ 所有组件**必须静态导入**(确保打包可分析) - ✅ 使用 `@` 别名(禁止相对路径) - ✅ 占位组件统一使用 `PlaceholderPage` ```typescript import UserList from '@/pages/mall/admin/user/list.uvue' import ProductList from '@/pages/mall/admin/product/list.uvue' export const componentMap: Map = new Map([ ['UserList', UserList], ['ProductList', ProductList], ... ]) ``` #### **步骤 5: 重构 AdminLayout** **核心变化**: ```vue ``` **计算属性**: ```typescript const currentComponent = computed(() => { const route = findRouteById(activeRouteId.value); return getComponent(route.componentKey); }); ``` #### **步骤 6: 重构侧边栏组件** **AdminAside (主侧边栏)**: - 仅显示一级菜单图标+文本 - 宽度: 96px (CRMEB: 64px) - 点击切换 `activeTopMenuId` **AdminSubSider (二级侧边栏)**: - 显示当前一级菜单的分组和子项 - 宽度: 180px (CRMEB: 200px) - 位于内容区左侧(独立层级) #### **步骤 7: 批量创建占位页面** 使用 Python 脚本创建 26 个占位页面: ```bash python create_placeholder_pages.py ``` 每个页面包含: - 标题和组件Key显示 - 统一的占位样式 - TODO 注释 #### **步骤 8: 修改首页模式** **旧模式**: ```vue ``` **新模式**: ```vue ``` ### **关键技术点** #### **1. 组件动态渲染** **问题**: uni-app-x 不支持动态 `import()` **解决方案**: 使用 Map + 静态导入 ```typescript // ❌ 不可用 const component = () => import(`@/pages/${path}.uvue`); // ✅ 正确方式 const component = componentMap.get(componentKey); ``` #### **2. 路由同步** 状态驱动而非URL驱动: ```typescript // 点击菜单 onRouteClick(routeId) → activeRouteId.value = routeId → currentComponent 重新计算 → 渲染新组件 ``` #### **3. 标签页管理** 模仿 CRMEB 的标签页行为: - 固定标签 (`isAffix`): 首页等,不可关闭 - 普通标签: 可关闭、关闭其他、关闭全部 - 关闭当前标签时自动切换到相邻标签 #### **4. 面包屑导航** 自动生成面包屑: ```typescript getBreadcrumb('user_list') → [{ id: 'user', title: '用户' }, { id: 'user_list', title: '用户管理' }] ``` ### **与 CRMEB 的对照表** | CRMEB 特性 | uni-app-x 实现 | 备注 | | ------------- | ---------------- | --------------------------- | | Vue Router | 状态驱动内部路由 | 无 router 实例 | | router.push() | openRoute() | 更新状态而非跳转 | | keep-alive | 未实现 | 后续可通过组件缓存实现 | | 菜单配置 | menu.uts | 已废弃,改用 adminRoutes.uts | | Vuex store | UTS 响应式变量 | ref/computed 代替 | | 动态导入 | 静态映射表 | 打包限制 | ### **常见问题与解决方案** #### **问题 1: 组件未找到** **现象**: `getComponent` 返回 `PlaceholderPage` **原因**: - componentMap 中缺少对应的 key - 导入路径错误 **解决**: ```typescript // 检查 adminComponentMap.uts import UserList from "@/pages/mall/admin/user/list.uvue"; componentMap.set("UserList", UserList); ``` #### **问题 2: 标签页不显示** **现象**: 点击菜单后标签页为空 **原因**: `tabs` 数组未正确更新 **解决**: ```typescript // 确保在 openRoute 中添加标签 if (addTab) { addTabItem(route); } ``` #### **问题 3: 二级侧边栏不显示** **现象**: 点击一级菜单后二级侧边栏空白 **原因**: 一级菜单的 `groups` 为空数组 **解决**: ```typescript // 检查 adminRoutes.uts 中的 topMenus 配置 { id: 'user', groups: [ { id: 'user-manage', title: '用户管理' } // ✅ 必须有 ] } ``` #### **问题 4: 模板编译错误** **现象**: `Invalid end tag` 或 `Illegal '/' in tags` **原因**: - 组件模板中有乱码 - 标签未正确闭合 **解决**: - 检查文件编码为 UTF-8 - 移除特殊 emoji 字符 - 确保所有标签正确闭合 ### **性能优化建议** 1. **懒加载路由**: 只在需要时加载组件 2. **虚拟滚动**: 标签页数量过多时使用虚拟列表 3. **状态持久化**: 将 `activeRouteId` 等状态存入 localStorage 4. **权限控制**: 在 `openRoute` 中增加权限校验逻辑 ### **扩展开发指南** #### **添加新路由** 1. 在 `adminRoutes.uts` 中添加路由记录: ```typescript { id: 'custom_feature', title: '自定义功能', path: '/pages/mall/admin/custom/feature', componentKey: 'CustomFeature', parentId: 'setting', groupId: 'setting-system' } ``` 2. 创建页面文件: ```bash pages/mall/admin/custom/feature.uvue ``` 3. 在 `adminComponentMap.uts` 中添加映射: ```typescript import CustomFeature from "@/pages/mall/admin/custom/feature.uvue"; componentMap.set("CustomFeature", CustomFeature); ``` #### **添加新的一级菜单** 1. 在 `topMenus` 中添加: ```typescript { id: 'reports', title: '报表', icon: 'report', path: '/pages/mall/admin/reports/index', order: 10, groups: [...] } ``` 2. 更新侧边栏图标映射 (`AdminAside.uvue`): ```typescript const iconMap: Record = { ... 'reports': 'R' } ``` ### **验收标准** - ✅ 主侧边栏显示所有一级菜单 - ✅ 点击一级菜单,二级侧边栏正确显示分组和子项 - ✅ 点击子项,内容区渲染对应组件 - ✅ 标签页正确添加、切换、关闭 - ✅ 无页面栈堆积 - ✅ 无模板编译错误 - ✅ 无乱码 - ✅ 所有 import 使用 `@` 别名 ### **文档更新** 本次重构新增以下文件和概念: - **内部路由模式**: 状态驱动渲染,替代页面跳转 - **组件映射表**: 静态导入 + Map 查找,替代动态导入 - **CRMEB 路由映射**: 1:1 复刻 CRMEB 的路由和菜单结构 - **双侧边栏布局**: 主侧边栏(一级) + 二级侧边栏(分组) --- 这个指南现在涵盖了 uni-app-x 项目开发中最常见的 15 类问题(新增 CRMEB 路由体系复刻),为后续开发提供了完整的故障排除和最佳实践指导。 🚀