hookehuyr

docs(readme): 重构项目文档结构

- 优化 CLAUDE.md 文档,添加设计原则说明
- 新增 CHANGELOG.md 版本更新日志
- 新增最佳实践指南
- 新增调试指南
- 新增 API 集成、导航、页面开发指南
- 新增参考文档目录

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 +# 变更日志
2 +
3 +记录项目开发过程中的重要变更和完成任务。
4 +
5 +## 2026-02-24
6 +
7 +### 23:59:18 - 完成任务
8 +
9 +**影响文件**:
10 +- `.husky/README.md`
11 +- `.husky/post-commit`
12 +- `docs/CHANGELOG.md`
13 +- `scripts/changelog/README.md`
14 +- `scripts/changelog/update-changelog.sh`
15 +
16 +**变更摘要**:
17 +- 无详细描述
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
2 2
3 本文件为 Claude Code (claude.ai/code) 在处理此仓库代码时提供指导。 3 本文件为 Claude Code (claude.ai/code) 在处理此仓库代码时提供指导。
4 4
5 +**设计原则**:这是一个轻量级索引文档,只保留必须立即知道的信息。详细内容通过链接访问。
6 +
7 +---
8 +
5 ## 📚 项目文档索引 9 ## 📚 项目文档索引
6 10
7 - **[经验教训总结](docs/lessons-learned.md)** - Taro 项目开发经验、最佳实践和常见陷阱 11 - **[经验教训总结](docs/lessons-learned.md)** - Taro 项目开发经验、最佳实践和常见陷阱
...@@ -9,6 +13,8 @@ ...@@ -9,6 +13,8 @@
9 - **[变更日志](docs/CHANGELOG.md)** - 项目版本更新历史 13 - **[变更日志](docs/CHANGELOG.md)** - 项目版本更新历史
10 - **[项目 README](README.md)** - 项目概述和快速开始指南 14 - **[项目 README](README.md)** - 项目概述和快速开始指南
11 15
16 +---
17 +
12 ## 🚀 开发命令 18 ## 🚀 开发命令
13 19
14 ### 核心命令 20 ### 核心命令
...@@ -53,26 +59,10 @@ git branch -d feature/功能名称 ...@@ -53,26 +59,10 @@ git branch -d feature/功能名称
53 - `docs/style/refactor/test/chore` - 不更新 59 - `docs/style/refactor/test/chore` - 不更新
54 60
55 **实现方式** 61 **实现方式**
56 --`commit-msg` hook �用 `scripts/update-version.sh` 自动更新 62 +-使用 `standard-version` 自动更新版本
57 --更新后的 `package.json` 自动加入暂存区 63 +-配置 conventional commits 规范
58 - ✅ 支持 `feat(version):` 格式跳过版本更新 64 - ✅ 支持 `feat(version):` 格式跳过版本更新
59 65
60 -**使用示例**
61 -```bash
62 -# 在当前功能分支开发
63 -git checkout -b feature/new-page
64 -# ... 开发代码 ...
65 -git add .
66 -git commit -m "feat(page): 添加新页面"
67 -
68 -# 合并回 develop
69 -git checkout develop
70 -git merge feature/new-page
71 -
72 -# 删除分支(可选)
73 -git branch -d feature/new-page
74 -```
75 -
76 ### 其他平台构建 66 ### 其他平台构建
77 ```bash 67 ```bash
78 pnpm dev:alipay # 支付宝小程序开发 68 pnpm dev:alipay # 支付宝小程序开发
...@@ -80,106 +70,22 @@ pnpm dev:swan # 百度小程序开发 ...@@ -80,106 +70,22 @@ pnpm dev:swan # 百度小程序开发
80 pnpm dev:tt # 字节跳动小程序开发 70 pnpm dev:tt # 字节跳动小程序开发
81 ``` 71 ```
82 72
73 +---
74 +
83 ## 📋 快速参考 75 ## 📋 快速参考
84 76
85 ### 🆕 最新更新(2026-02-15) 77 ### 🆕 最新更新(2026-02-15)
86 78
87 -**配置清理** 79 +**详细更新记录**
88 -- ✅ 禁用 Mock 数据(`USE_MOCK_DATA: false` 80 +- **[变更日志](docs/CHANGELOG.md)** - 完整版本更新历史
89 -- ✅ 移除测试计划书模板(测试计划书-智享未来2、长宁終身壽險計劃3) 81 +- **[接口联调日志](docs/api-integration-log.md)** - API 集成状态
90 - 82 +
91 -**合并选项控制功能** 83 +**最新亮点**
92 -- ✅ 合并选项控制功能到 develop 分支 84 +- 🎯 文档解析重大升级(多产品支持、智能字段提取)
93 -- ✅ 添加字段条件显示系统扩展功能 85 +- 🎯 计划书模块重构(Schema 化、模板字段映射)
94 -- ✅ 重组脚本目录结构 86 +- 🎯 消息功能全面优化(布局、交互、红点)
95 - 87 +- 🎯 选项控制功能合并
96 -**文档解析重大升级** 88 +- 🎯 Git 工作流优化(standard-version)
97 -- ✅ 支持多产品文档解析(自动识别和分割多个保险产品)
98 -- ✅ 实现智能字段提取器 smartExtractList()
99 -- ✅ 新增产品边界检测模块(支持产品代码和命名模式识别)
100 -- ✅ 完善 MCP 解析切换功能和审核流程
101 -- ✅ 待审核文件按原始文档名分目录生成
102 -
103 -**计划书模块重构**
104 -- ✅ 计划书表单字段 Schema 化(人寿/重疾模板)
105 -- ✅ 优化字段配置管理,提取订单状态常量
106 -- ✅ 重构表单提交逻辑,使用模板字段映射
107 -- ✅ 完善表单交互和字段验证
108 -
109 -**消息功能全面优化**
110 -- ✅ 优化消息列表卡片布局,提升信息可读性
111 -- ✅ 简化消息列表逻辑,移除冗余代码
112 -- ✅ 优化消息详情页布局和样式
113 -- ✅ 统一消息页面交互体验
114 -
115 -**Git 工作流与版本管理**
116 -- ✅ 使用 standard-version 替代自定义版本更新脚本
117 -- ✅ 配置 conventional commits 规范
118 -- ✅ 完善版本发布流程文档
119 -- ✅ 移除旧的版本自动更新脚本
120 -
121 -**Mock 数据优化**
122 -- ✅ 优化产品列表 Mock 数据结构
123 -- ✅ 添加测试商品到列表首位
124 -- ✅ 修正搜索测试 Mock 开关
125 -
126 -**计划书功能优化(历史更新)**
127 -- ✅ 添加计划书卡片状态标记("生成中"/"已完成",黄色/绿色背景)
128 -- ✅ 修复嵌套弹窗层级冲突(使用 provide/inject 模式)
129 -- ✅ 优化页面滚动加载并清理调试代码
130 -- ✅ 修复搜索栏清空按钮点击无效
131 -- ✅ 修改提交结果页按钮为"返回上一页"
132 -- ✅ 预览成功后才调用查看接口,避免预览失败也翻状态
133 -- ✅ 优化计划书提交跳转体验:关闭弹框时清理已选产品
134 -- ✅ 提取计划书提交回调逻辑为 composable
135 -
136 -**认证与权限优化**
137 -- ✅ 为所有制作计划书按钮添加登录权限检查
138 -- ✅ 修复退出登录时红点状态未重置的问题
139 -- ✅ 修复登录页返回按钮:清空 router store 并跳转到首页
140 -- ✅ 修复 401 重定向死循环和返回报错问题
141 -
142 -**消息功能优化**
143 -- ✅ 配置 TabBar 红点功能使用新的 unread_msg_count 字段
144 -- ✅ 修复 TabBar 未读红点显示问题
145 -- ✅ 优化消息列表卡片布局,提升信息可读性
146 -- ✅ 增加未读消息红点提示
147 -- ✅ 优化消息详情页布局,避免内容重复显示
148 -- ✅ 添加消息列表 API 错误提示
149 -
150 -**样式改进**
151 -- ✅ 增强资料卡片边框可见性(border-gray-200)
152 -- ✅ 增大产品中心和详情页的字体与图标尺寸
153 -- ✅ 添加全局背景色
154 -- ✅ 增大全局字体和图标尺寸以提升可读性
155 -- ✅ 优化首页网格导航视觉体验
156 -- ✅ 重构"我的"页面为专业高端风格
157 -- ✅ 优化 ProductCard 组件视觉样式
158 -- ✅ 统一视觉柔和度和整体设计一致性
159 -- ✅ 优化首页头图 CDN 加载
160 -
161 -**计划书字段优化**
162 -- ✅ 优化提取金额字段并新增每年提取字段
163 -- ✅ 隐藏产品详情页附件下载提示
164 -- ✅ 优化输入框间距
165 -
166 -**代码质量**
167 -- ✅ 从版本控制中移除本地配置文件 settings.local.json
168 -- ✅ 禁用消息列表 Mock 数据,使用真实接口
169 -- ✅ 清理调试日志
170 -
171 -**API 集成进度**
172 -- ✅ 总接口数:29,已完成:26 (89.7%)
173 -- ✅ 计划书模块接口联调完成(submitPlanAPI、listAPI)
174 -
175 -**新增功能**
176 -- ✅ 消息列表和消息详情页
177 -- ✅ 产品中心页
178 -- ✅ 周热门资料页
179 -- ✅ 分类列表页
180 -- ✅ PlanFields 表单字段组件集
181 -- ✅ useCollectOperation composable
182 -- ✅ usePlanPermission composable
183 89
184 --- 90 ---
185 91
...@@ -192,10 +98,11 @@ pnpm dev:tt # 字节跳动小程序开发 ...@@ -192,10 +98,11 @@ pnpm dev:tt # 字节跳动小程序开发
192 | SVG 图标加载失败(500 错误) | 使用 `import` 导入 | [经验教训](docs/lessons-learned.md#静态资源加载问题) | 98 | SVG 图标加载失败(500 错误) | 使用 `import` 导入 | [经验教训](docs/lessons-learned.md#静态资源加载问题) |
193 | 代码重复 3 次 | 抽取为 Composable | [经验教训](docs/lessons-learned.md#组件抽取与复用) | 99 | 代码重复 3 次 | 抽取为 Composable | [经验教训](docs/lessons-learned.md#组件抽取与复用) |
194 | 组件对象响应式警告 | 使用 `shallowRef` + `markRaw` | [经验教训](docs/lessons-learned.md#性能优化) | 100 | 组件对象响应式警告 | 使用 `shallowRef` + `markRaw` | [经验教训](docs/lessons-learned.md#性能优化) |
195 -| 业务状态标记显示 | 使用条件类名 + 语义化颜色 | [经验教训](docs/lessons-learned.md#案例-4-状态标记组件模式) |
196 | 嵌套弹窗层级冲突 | 使用 provide/inject 模式 | 最近提交记录(3357bed) | 101 | 嵌套弹窗层级冲突 | 使用 provide/inject 模式 | 最近提交记录(3357bed) |
197 | 401 重定向死循环 | 检查重定向拦截器逻辑 | 最近提交记录(6d2a4ec) | 102 | 401 重定向死循环 | 检查重定向拦截器逻辑 | 最近提交记录(6d2a4ec) |
198 103
104 +---
105 +
199 ### 🎯 核心架构模式 106 ### 🎯 核心架构模式
200 107
201 1. **认证流程** - 静默认证 + 401 自动刷新 108 1. **认证流程** - 静默认证 + 401 自动刷新
...@@ -203,6 +110,8 @@ pnpm dev:tt # 字节跳动小程序开发 ...@@ -203,6 +110,8 @@ pnpm dev:tt # 字节跳动小程序开发
203 3. **样式策略** - TailwindCSS(80%) + Less(20%) 110 3. **样式策略** - TailwindCSS(80%) + Less(20%)
204 4. **组件抽取** - "第 3 次出现原则" 111 4. **组件抽取** - "第 3 次出现原则"
205 112
113 +---
114 +
206 ### 📦 技术栈 115 ### 📦 技术栈
207 116
208 - **框架**: Taro 4.1.9 + Vue 3.3.0 + Composition API 117 - **框架**: Taro 4.1.9 + Vue 3.3.0 + Composition API
...@@ -225,26 +134,11 @@ pnpm dev:tt # 字节跳动小程序开发 ...@@ -225,26 +134,11 @@ pnpm dev:tt # 字节跳动小程序开发
225 - **签单** - 签约流程 134 - **签单** - 签约流程
226 - **用户中心** - 个人资料、收藏、反馈、帮助中心 135 - **用户中心** - 个人资料、收藏、反馈、帮助中心
227 136
228 -## 🏗️ 核心架构 137 +---
229 -
230 -### 1. 可复用的导航组件
231 -
232 -**TabBar 组件**`src/components/TabBar.vue`
233 -- 固定底部导航栏,自动适配安全区域
234 -- 支持图标 + 文字布局,激活状态高亮
235 -- 使用于:首页、我的、家办、知识库、签单页面
236 -
237 -**NavHeader 组件**`src/components/NavHeader.vue`
238 -- 带返回按钮的自定义导航头
239 -- 透明/背景变体,刘海屏设备的安全区域内边距
240 -
241 -**IconFont 组件**`src/components/IconFont.vue`
242 -- 自定义图标的图标字体包装器
243 -- ⚠️ **动态切换时需添加 `:key="name"`** [详见经验教训](docs/lessons-learned.md#坑-2-iconfont-动态切换不响应)
244 138
245 -### 2. 身份认证流程(必需) 139 +## 🏗️ 核心架构
246 140
247 -项目具有完善的身份认证系统,支持静默认证和会话管理。 141 +### 1. 身份认证流程(必需)
248 142
249 **核心文件** 143 **核心文件**
250 - `src/utils/openid.js` - 微信授权和会话管理 144 - `src/utils/openid.js` - 微信授权和会话管理
...@@ -256,24 +150,16 @@ pnpm dev:tt # 字节跳动小程序开发 ...@@ -256,24 +150,16 @@ pnpm dev:tt # 字节跳动小程序开发
256 - 调用 `wx.login()` 获取 code 150 - 调用 `wx.login()` 获取 code
257 - 调用后端 `/srv/?a=openid` 接口换取 sessionid 151 - 调用后端 `/srv/?a=openid` 接口换取 sessionid
258 - 自动将 sessionid 写入 localStorage 152 - 自动将 sessionid 写入 localStorage
259 - - 尝试调用 `loginStatusAPI` 获取用户信息(如已登录)
260 153
261 2. **401 自动刷新** 154 2. **401 自动刷新**
262 - API 返回 401 时触发 155 - API 返回 401 时触发
263 - 拦截器保存当前页面路径 156 - 拦截器保存当前页面路径
264 - 调用 `miniProgramAuth()` 重新获取会话 157 - 调用 `miniProgramAuth()` 重新获取会话
265 - 使用新会话重试原始请求 158 - 使用新会话重试原始请求
266 - - 如果刷新失败,跳转到登录页
267 -
268 -**重要**
269 -- 后端必须提供 `/srv/?a=openid` 端点用于微信登录
270 -- 后端必须提供 `loginStatusAPI` 接口用于检查登录状态
271 -- sessionid 存储在 `localStorage.sessionid`
272 -- sessionid 由请求拦截器自动注入到请求头的 `cookie` 字段
273 159
274 -### 3. API 层架构 160 +### 2. API 层架构
275 161
276 -**API 定义模式**`src/api/index.js`): 162 +**API 定义**`src/api/index.js`):
277 ```javascript 163 ```javascript
278 export const yourAPI = (params) => { 164 export const yourAPI = (params) => {
279 return buildApiUrl('your_action', params) 165 return buildApiUrl('your_action', params)
...@@ -285,7 +171,7 @@ export const yourAPI = (params) => { ...@@ -285,7 +171,7 @@ export const yourAPI = (params) => {
285 - 处理常见错误场景 171 - 处理常见错误场景
286 - **始终检查 `res.code === 1` 判断成功** 172 - **始终检查 `res.code === 1` 判断成功**
287 173
288 -### 4. 增强导航系统 174 +### 3. 增强导航系统
289 175
290 **useGo Hook**`src/hooks/useGo.js`): 176 **useGo Hook**`src/hooks/useGo.js`):
291 ```javascript 177 ```javascript
...@@ -297,496 +183,53 @@ go('/pages/product-detail/index', { id: 123 }) // 带查询参数 ...@@ -297,496 +183,53 @@ go('/pages/product-detail/index', { id: 123 }) // 带查询参数
297 go.back() // 返回上一页 183 go.back() // 返回上一页
298 ``` 184 ```
299 185
300 -**路由存储**`src/stores/router.js`): 186 +### 4. 样式处理策略
301 -- 维护已访问路由的栈
302 -- 用于认证回调导航
303 -
304 -### 5. 可复用 Composables
305 -
306 -**项目中的 Composables**
307 -
308 -| Composable | 用途 | 文档 |
309 -|-----------|------|------|
310 -| `useSectionList` | 分组列表管理 | [经验教训](docs/lessons-learned.md#案例-1-usesectionlist-composable) |
311 -| `useFileOperation` | 文件下载、预览、打开 | [经验教训](docs/lessons-learned.md#案例-2-usefileoperation-composable) |
312 -| `useListItemClick` | 统一的列表点击处理 | [经验教训](docs/lessons-learned.md#案例-3-uselistitemclick-composable) |
313 -| `useCollectOperation` | 收藏操作(新增) | 处理收藏/取消收藏逻辑 |
314 -
315 -**抽取原则**:"第 3 次出现原则" - 当相同代码模式出现 3 次时,**必须**抽取为 Composable。
316 -
317 -**组件自包含原则**(新增):
318 -- 对于重复的UI结构,抽取为可复用组件(如 MaterialCard、ProductCard)
319 -- 组件应该自包含业务逻辑(查看、收藏等),通过事件与父组件通信
320 -- 避免在父组件中重复编写相同的逻辑代码
321 -
322 -### 6. 样式处理策略
323 187
324 **TailwindCSS vs Less 使用指南** 188 **TailwindCSS vs Less 使用指南**
325 189
326 | 场景 | 使用 | 比例 | 190 | 场景 | 使用 | 比例 |
327 |------|------|------| 191 |------|------|------|
328 -| 布局(flex、grid、absolute) | TailwindCSS | 80% | 192 +| 布局、间距、排版、颜色 | TailwindCSS | 80% |
329 -| 间距(padding、margin、gap) | TailwindCSS | | 193 +| 组件特定样式、深度选择器 | Less | 20% |
330 -| 排版(font-size、text-align) | TailwindCSS | |
331 -| 颜色(bg-*、text-*、border-*) | TailwindCSS | |
332 -| 响应式设计(sm:、md:、lg:) | TailwindCSS | |
333 -| 组件特定样式(需要 scoped) | Less | 20% |
334 -| 深度选择器(`:deep()`) | Less | |
335 -| 动画和过渡 | Less | |
336 -| 伪元素(`::before``::after`) | Less | |
337 194
338 -[详见样式处理策略](docs/lessons-learned.md#✅-tailwindcss-vs-less-使用指南) 195 +### 5. 响应式优化
339 -
340 -### 7. 响应式优化
341 196
342 **处理组件对象响应式** 197 **处理组件对象响应式**
343 198
344 ```javascript 199 ```javascript
345 // ❌ BAD - 深度响应式导致性能问题 200 // ❌ BAD - 深度响应式导致性能问题
346 const menuItems = ref([ 201 const menuItems = ref([
347 - { icon: IconFont, name: 'heart' } // Vue 会深度代理组件对象 202 + { icon: IconFont, name: 'heart' }
348 ]) 203 ])
349 204
350 // ✅ GOOD - 使用 shallowRef + markRaw 205 // ✅ GOOD - 使用 shallowRef + markRaw
351 import { shallowRef, markRaw } from 'vue' 206 import { shallowRef, markRaw } from 'vue'
352 -
353 const menuItems = shallowRef([ 207 const menuItems = shallowRef([
354 - { icon: markRaw(IconFont), name: 'heart' } // 避免深度代理 208 + { icon: markRaw(IconFont), name: 'heart' }
355 ]) 209 ])
356 ``` 210 ```
357 211
358 -[详见性能优化](docs/lessons-learned.md#✅-1-响应式数据优化) 212 +---
359 -
360 -### 页面结构
361 -
362 -所有页面遵循以下目录结构:
363 -```
364 -src/pages/your-page/
365 -├── index.vue # 页面组件(必须使用 <script setup>)
366 -├── index.config.js # 页面配置(navigationBarTitleText 等)
367 -└── assets/ # 页面特定资源(可选)
368 -```
369 -
370 -### 当前页面
371 -
372 -所有页面按 `src/app.config.js` 注册顺序排列:
373 -
374 -**核心页面**
375 -1. `pages/index/index` - 首页(产品展示、搜索、网格导航)
376 - - 热门产品的"产品资料"按钮跳转到 `product-detail` 页面,带产品 ID
377 - - 热门资料的"查看更多"跳转到 `material-list` 页面
378 - - 网格导航图标跳转到各个业务页面
379 - - 使用可复用组件(MaterialCard、ProductCard)
380 -2. `pages/search/index` - 产品和资料搜索页
381 - - 支持实时搜索(输入关键字自动调用 searchAPI)
382 - - 双Tab切换(产品、资料)
383 - - 支持分页加载和触底加载更多
384 - - 使用可复用组件(MaterialCard、ProductCard)
385 -3. `pages/webview/index` - 外部 URL 的 WebView 包装器
386 -4. `pages/document-preview/index` - 文档预览页
387 -5. `pages/document-demo/index` - 文档预览演示页
388 -6. `pages/onboarding/index` - 新用户引导
389 -
390 -**业务页面**
391 -7. `pages/family-office/index` - 家族办公室服务
392 -8. `pages/product-center/index` - 产品中心页
393 -9. `pages/category-list/index` - 分类列表页
394 -10. `pages/product-detail/index` - 产品详情页
395 - - 通过 Taro 的 `useLoad` hook 接收 `id` 参数
396 - - 导航示例:`go('/pages/product-detail/index', { id: 1 })`
397 - - 参数可用于从 API 获取产品详情
398 -11. `pages/material-list/index` - 资料/文档列表页
399 -12. `pages/week-hot-material/index` - 周热门资料页
400 - - 使用 MaterialCard 组件展示热门资料
401 - - 支持分页加载和触底加载更多
402 -13. `pages/signing/index` - 签约
403 -14. `pages/mine/index` - 用户资料
404 -15. `pages/plan/index` - 业务计划管理
405 - - 使用 PlanSchemes 和 PlanPopup 组件
406 - - 支持嵌套弹窗交互(provide/inject 模式)
407 - - 支持滚动加载和分页
408 -16. `pages/plan-submit-result/index` - 计划提交结果页
409 - - 导航按钮:返回上一页(非首页)
410 -
411 -**用户相关页面**
412 -17. `pages/favorites/index` - 用户收藏
413 -18. `pages/avatar/index` - 头像设置
414 -19. `pages/message/index` - 消息列表页
415 -20. `pages/message-detail/index` - 消息详情页
416 -21. `pages/feedback-list/index` - 反馈列表
417 -22. `pages/feedback/index` - 用户反馈
418 -23. `pages/login/index` - 登录页
419 -24. `pages/help-center/index` - 帮助中心和常见问题页
420 -
421 -**开发测试页面**(仅开发环境):
422 -- `pages/test-tabs/index` - 标签页测试
423 -
424 -### 组件库
425 -
426 -**导航与布局组件**
427 -- `TabBar.vue` - 底部导航栏
428 -- `NavHeader.vue` - 自定义导航头
429 -- `indexNav.vue` - 首页网格导航
430 -
431 -**图标与媒体组件**
432 -- `IconFont.vue` - 图标字体包装器
433 -- `qrCode.vue` - 二维码显示
434 -- `qrCodeSearch.vue` - 二维码扫描
435 -
436 -**列表与展示组件**
437 -- `SectionCard.vue` - 分组卡片组件
438 -- `SectionItem.vue` - 分组列表项组件
439 -- `ListItemActions/` - 列表项操作按钮
440 -- `MaterialCard.vue` - 资料卡片组件(可复用)
441 - - 自包含业务逻辑:查看、收藏
442 - - 支持动态标签、文件大小格式化、学习人数显示
443 - - 支持图片文件预览(使用 Taro.previewImage)
444 - - 使用页面:首页、搜索页、周热门资料页
445 - - 使用 composable:useCollectOperation、useListItemClick
446 -- `ProductCard.vue` - 产品卡片组件(可复用)
447 - - 自定义样式:动态标签、封面图
448 - - 支持产品详情查看和计划书功能
449 - - 使用页面:首页、搜索页、产品中心页
450 -
451 -**表单与输入组件**
452 -- `FilterTabs.vue` - 过滤标签组件
453 -- `SearchBar.vue` - 搜索栏组件
454 -
455 -**文档预览组件**
456 -- `DocumentPreview/` - 文档预览组件
457 -- `PdfPreview.vue` - PDF 预览组件
458 -- `OfficeViewer.vue` - Office 文档查看器
459 -
460 -**业务组件**
461 -- `PlanSchemes/` - 计划方案组件(SchemeA, SchemeB)
462 -- `PlanPopup/` - 计划弹窗组件
463 - - 使用 provide/inject 模式实现父子弹窗通信
464 - - 子弹窗打开时自动隐藏父级 footer
465 - - 支持 AgePicker、DatePicker、SelectPicker 等字段组件
466 -- `PlanFields/` - 计划书表单字段组件
467 - - `AgePicker.vue` - 年龄选择器
468 - - `AmountInput.vue` - 金额输入框
469 - - `DatePicker.vue` - 日期选择器
470 - - `SelectPicker.vue` - 下拉选择器
471 - - `RadioGroup.vue` - 单选按钮组
472 -- `PlanTemplates/` - 计划模板组件
473 -
474 -**工具组件**
475 -- `PosterBuilder/` - 海报生成器
476 -- `time-picker-data/` - 时间选择器数据
477 -
478 -### 路径别名
479 -全部配置在 `config/index.js:30-38`
480 -```javascript
481 -@/utils src/utils
482 -@/components src/components
483 -@/images src/assets/images
484 -@/assets src/assets
485 -@/composables src/composables
486 -@/api src/api
487 -@/stores src/stores
488 -@/hooks src/hooks
489 -```
490 -
491 -### 配置管理
492 -
493 -**环境配置**`src/utils/config.js`):
494 -**⚠️ 使用前必须修改**
495 -- `BASE_URL` - 设置开发/生产域名
496 -- `REQUEST_DEFAULT_PARAMS.f` - 设置业务模块标识符
497 -- `REQUEST_DEFAULT_PARAMS.client_name` - 设置应用名称
498 -
499 -**构建配置**`config/index.js`):
500 -- 路径别名
501 -- 设计宽度规则
502 -- NutUI 自动导入
503 -- 平台特定设置
504 -
505 -**应用配置**`src/app.config.js`):
506 -- 页面路由注册
507 -- 窗口配置
508 -- 标签栏配置(可选)
509 -- 分包(如需要)
510 -
511 -## 🔧 重要实现细节
512 -
513 -### 会话管理
514 -- **会话 ID 存储**`localStorage.sessionid`
515 -- **静默登录**`openid.js``miniProgramAuth()` 函数
516 - - 调用 `wx.login()` 获取 code
517 - - 调用 `/srv/?a=openid` 接口换取 sessionid
518 - - 自动写入 localStorage
519 -- **请求注入**`request.js` 拦截器自动读取并注入到请求头的 `cookie` 字段
520 -- **会话清除**:登出或 401 失败时清除
521 -- **401 刷新**:拦截器捕获 401 → 调用 `miniProgramAuth()` → 重试原始请求
522 -
523 -### 请求超时处理
524 -- 默认超时:5 秒(`src/utils/request.js:79`
525 -- 通过 `is_timeout_error()` 辅助函数检测超时
526 -- 通过 `is_network_error()` 辅助函数检测网络错误
527 -- 两者都会触发弱网络降级流程
528 -
529 -### NutUI 自动导入
530 -NutUI 组件通过 unplugin-vue-components 自动导入(`config/index.js:91-93`)。
531 -**无需手动导入** - 直接在模板中使用组件即可。
532 -
533 -### TailwindCSS 集成
534 -- 为小程序兼容性禁用了 Preflight
535 -- 启用了 `rem2rpx` 转换
536 -- 内容路径配置在 `tailwind.config.js`
537 -- [详见样式处理策略](docs/lessons-learned.md#✅-tailwindcss-vs-less-使用指南)
538 -
539 -## 📦 可选功能
540 -
541 -如果不需要,可以移除以下功能:
542 -- **微信支付**`src/utils/wechatPay.js``src/api/wx/pay.js`
543 -- **二维码**`src/components/qrCode.vue``src/components/qrCodeSearch.vue`
544 -- **海报生成器**`src/components/PosterBuilder/`
545 -- **时间选择器**`src/components/time-picker-data/`
546 -
547 -## 开发工作流
548 -
549 -### 添加新页面
550 -
551 -1. **创建页面目录**
552 - ```bash
553 - src/pages/your-page/
554 - ├── index.vue
555 - └── index.config.js
556 - ```
557 -
558 -2. **配置页面**`index.config.js`):
559 - ```javascript
560 - export default {
561 - navigationBarTitleText: '您的页面标题',
562 - enablePullDownRefresh: true,
563 - backgroundColor: '#f5f5f5'
564 - }
565 - ```
566 -
567 -3. **`src/app.config.js` 中注册路由**
568 - ```javascript
569 - pages: [
570 - 'pages/your-page/index',
571 - // ...
572 - ]
573 - ```
574 -
575 -4. **`index.vue` 中使用 composition API**
576 - ```vue
577 - <script setup>
578 - import { ref } from 'vue'
579 - import { useLoad, useShow } from '@tarojs/taro'
580 -
581 - const pageId = ref(null)
582 -
583 - useLoad((options) => {
584 - console.log('页面加载,参数:', options)
585 - // 接收导航参数
586 - if (options.id) {
587 - pageId.value = options.id
588 - // 根据 ID 获取数据
589 - }
590 - })
591 -
592 - useShow(() => {
593 - console.log('页面显示')
594 - })
595 -
596 - // 您的组件逻辑
597 - </script>
598 - ```
599 -
600 - **带参数导航**
601 - ```javascript
602 - // 从另一个页面
603 - import { useGo } from '@/hooks/useGo'
604 - const go = useGo()
605 -
606 - // 带查询参数导航
607 - go('/pages/product-detail/index', { id: 123, type: 'insurance' })
608 - ```
609 -
610 -5. **添加导航**(可选的 TabBar 集成):
611 - - 导入并使用 `TabBar` 组件
612 - - 根据路由配置激活状态
613 -
614 -### 添加 API 调用
615 -
616 -1. **`src/api/index.js` 中定义 API**
617 - ```javascript
618 - export const getProductListAPI = (params) => {
619 - return buildApiUrl('product_list', params)
620 - }
621 - ```
622 -
623 -2. **在页面中使用**
624 - ```javascript
625 - import { getProductListAPI } from '@/api'
626 - import { fn } from '@/api/fn'
627 -
628 - const fetchProducts = async () => {
629 - try {
630 - const res = await fn(getProductListAPI({ page: 1 }))
631 - if (res.code === 1) {
632 - products.value = res.data
633 - }
634 - } catch (err) {
635 - console.error('获取产品失败:', err)
636 - }
637 - }
638 - ```
639 -
640 -### 使用导航
641 -
642 -**推荐**:使用 `useGo` hook 进行增强导航:
643 -```javascript
644 -import { useGo } from '@/hooks/useGo'
645 -
646 -const go = useGo()
647 -
648 -// 导航到页面
649 -go('/pages/detail/index')
650 -
651 -// 带参数导航(例如产品 ID)
652 -go('/pages/product-detail/index', { id: 123 })
653 -
654 -// 带多个参数导航
655 -go('/pages/material-list/index', { category: 'insurance', page: 1 })
656 -
657 -// 返回
658 -go.back()
659 -```
660 -
661 -**在目标页面接收参数**:
662 -```javascript
663 -import { useLoad } from '@tarojs/taro'
664 -import { ref } from 'vue'
665 -
666 -const productId = ref(null)
667 -
668 -useLoad((options) => {
669 - // 访问导航参数
670 - console.log('接收到的参数:', options)
671 - productId.value = options.id
672 -
673 - // 根据参数获取数据
674 - fetchProductDetail(options.id)
675 -})
676 -```
677 -
678 -**替代方案**:使用 Taro 内置导航:
679 -```javascript
680 -import Taro from '@tarojs/taro'
681 -
682 -Taro.navigateTo({
683 - url: '/pages/detail/index?id=123'
684 -})
685 -```
686 -
687 -### 使用 Pinia 状态管理
688 -
689 -**创建 store**(`src/stores/yourStore.js`):
690 -```javascript
691 -import { defineStore } from 'pinia'
692 -import { ref } from 'vue'
693 -
694 -export const useYourStore = defineStore('yourStore', () => {
695 - const state = ref(null)
696 -
697 - function setState(newState) {
698 - state.value = newState
699 - }
700 -
701 - return { state, setState }
702 -})
703 -```
704 -
705 -**在组件中使用**:
706 -```javascript
707 -import { useYourStore } from '@/stores/yourStore'
708 -
709 -const store = useYourStore()
710 -store.setState('新值')
711 -```
712 -
713 -### 使用 Mock 数据工具
714 -
715 -项目提供了统一的 Mock 数据工具(`src/utils/mockData.js`),用于开发阶段测试分页加载等功能。
716 -
717 -**支持的 Mock API**:
718 -
719 -| API 名称 | 功能说明 | 使用页面 |
720 -|---------|---------|---------|
721 -| `mockWeekHotAPI` | 周热门资料 | 周热门资料页 |
722 -| `mockFileListAPI` | 资料列表 | 资料列表页 |
723 -| `mockProductListAPI` | 产品列表 | 产品中心页 |
724 -| `mockSearchAPI` | 搜索(产品+资料) | 搜索页 |
725 -| `mockMessageListAPI` | 消息列表 | 消息列表页 |
726 -| `mockFavoriteListAPI` | 收藏列表 | 收藏页 |
727 -| `mockFeedbackListAPI` | 意见反馈列表 | 意见反馈页 |
728 -
729 -**使用方式**:
730 -
731 -1. **在页面中导入 Mock 函数**:
732 -```javascript
733 -import { mockWeekHotAPI } from '@/utils/mockData'
734 -```
735 -
736 -2. **设置 Mock 开关**:
737 -```javascript
738 -// 开发环境使用 Mock,生产环境使用真实 API
739 -const USE_MOCK_DATA = process.env.NODE_ENV === 'development'
740 -```
741 -
742 -3. **在数据获取函数中使用**:
743 -```javascript
744 -const fetchWeekHot = async (page = 0) => {
745 - loading.value = true
746 -
747 - try {
748 - // 根据 USE_MOCK_DATA 开关决定使用 Mock 数据还是真实 API
749 - const res = USE_MOCK_DATA
750 - ? await mockWeekHotAPI({ page, limit: 20 })
751 - : await fn(weekHotAPI({ page, limit: 20 }))
752 -
753 - if (res.code === 1) {
754 - weekHotList.value.push(...res.data.list)
755 - hasMore.value = res.data.list.length >= 20
756 - }
757 - } catch (err) {
758 - console.error('获取周热门资料失败:', err)
759 - } finally {
760 - loading.value = false
761 - }
762 -}
763 -```
764 -
765 -**Mock 数据特性**:
766 213
767 -- ✅ **模拟网络延迟**:100-300ms 随机延迟 214 +## 📁 详细文档
768 -- ✅ **支持分页加载**:可配置 `page` 和 `limit` 参数
769 -- ✅ **随机数据生成**:文件大小、学习人数、收藏状态等
770 -- ✅ **支持关键词搜索**:搜索 API 会根据关键词过滤数据
771 -- ✅ **真实数据结构**:返回的数据结构与真实 API 一致
772 -- ✅ **控制台日志**:每次请求都会打印 `[Mock]` 日志便于调试
773 215
774 -**统一调用器**(可选): 216 +### 开发指南
217 +- **[页面开发指南](docs/guides/page-development.md)** - 如何添加新页面
218 +- **[API 集成指南](docs/guides/api-integration.md)** - API 调用详解
219 +- **[导航系统指南](docs/guides/navigation.md)** - 导航和参数传递
775 220
776 -也可以使用 `mockAPI()` 统一调用器: 221 +### 参考文档
777 -```javascript 222 +- **[页面参考](docs/reference/pages.md)** - 所有页面详细说明
778 -import { mockAPI } from '@/utils/mockData' 223 +- **[组件参考](docs/reference/components.md)** - 组件库文档
224 +- **[Composables 参考](docs/reference/composables.md)** - 可复用逻辑
779 225
780 -// 调用指定的 Mock API 226 +### 最佳实践
781 -const res = await mockAPI('weekHotAPI', { page: 0, limit: 20 }) 227 +- **[最佳实践](docs/best-practices.md)** - 组件开发、API 集成、性能优化
782 -``` 228 +- **[调试指南](docs/debugging.md)** - 调试技巧和工具
783 229
784 -**注意事项** 230 +---
785 -- ⚠️ **生产环境关闭**:部署时确保 `USE_MOCK_DATA = false`
786 -- ⚠️ **数据结构对齐**:Mock 数据结构必须与真实 API 保持一致
787 -- ⚠️ **分页逻辑**:Mock API 返回的 `list` 为空时表示没有更多数据
788 231
789 -## 关键文件总结 232 +## 🔧 关键文件
790 233
791 ### 修改前必须理解 234 ### 修改前必须理解
792 1. **`src/utils/openid.js`** - 微信授权和会话管理逻辑 235 1. **`src/utils/openid.js`** - 微信授权和会话管理逻辑
...@@ -801,105 +244,53 @@ const res = await mockAPI('weekHotAPI', { page: 0, limit: 20 }) ...@@ -801,105 +244,53 @@ const res = await mockAPI('weekHotAPI', { page: 0, limit: 20 })
801 4. **`src/stores/user.js`** - 用户状态管理 244 4. **`src/stores/user.js`** - 用户状态管理
802 5. **`src/stores/router.js`** - 路由状态管理 245 5. **`src/stores/router.js`** - 路由状态管理
803 246
804 -### 认证与会话
805 -1. **`src/utils/openid.js`** - `miniProgramAuth()` 静默登录
806 -2. **`src/utils/request.js`** - 401 拦截器和 sessionid 管理
807 -3. **`src/pages/login/index.vue`** - 登录页
808 -
809 ### 可复用组件 247 ### 可复用组件
810 1. **`src/components/TabBar.vue`** - 底部导航栏 248 1. **`src/components/TabBar.vue`** - 底部导航栏
811 2. **`src/components/NavHeader.vue`** - 自定义导航头 249 2. **`src/components/NavHeader.vue`** - 自定义导航头
812 -3. **`src/components/SectionCard.vue`** - 分组卡片 250 +3. **`src/components/MaterialCard.vue`** - 资料卡片(可复用)
813 -4. **`src/components/DocumentPreview/`** - 文档预览 251 +4. **`src/components/ProductCard.vue`** - 产品卡片(可复用)
814 -5. **`src/components/MaterialCard.vue`** - 资料卡片(可复用)
815 - - 自包含业务逻辑:查看、收藏
816 - - 支持动态标签、文件大小格式化、学习人数显示
817 - - 使用页面:首页、搜索页、周热门资料页
818 -6. **`src/components/ProductCard.vue`** - 产品卡片(可复用)
819 - - 自定义样式:动态标签、封面图
820 - - 支持产品详情查看和计划书功能
821 - - 使用页面:首页、搜索页
822 252
823 ### Composables 253 ### Composables
824 1. **`src/composables/useSectionList.js`** - 分组列表管理 254 1. **`src/composables/useSectionList.js`** - 分组列表管理
825 2. **`src/composables/useFileOperation.js`** - 文件操作 255 2. **`src/composables/useFileOperation.js`** - 文件操作
826 3. **`src/composables/useListItemClick.js`** - 列表点击处理 256 3. **`src/composables/useListItemClick.js`** - 列表点击处理
827 257
828 -### 工具函数 258 +---
829 -1. **`src/utils/mockData.js`** - Mock 数据生成工具(开发测试用) 259 +
830 - - 支持多个 API 的 Mock:周热门资料、资料列表、产品列表、搜索、消息列表、收藏列表、意见反馈 260 +## ⚠️ 重要配置
831 - - 统一调用器:`mockAPI(apiName, params)` 261 +
832 - - 支持分页加载、模拟网络延迟、随机数据生成 262 +**环境配置**`src/utils/config.js`):
833 -2. **`src/utils/documentIcons.js`** - 文档类型图标识别 263 +- `BASE_URL` - 设置开发/生产域名
834 -3. **`src/utils/tools.js`** - 通用工具函数集合 264 +- `REQUEST_DEFAULT_PARAMS.f` - 设置业务模块标识符
835 -4. **`src/utils/network.js`** - 网络状态工具 265 +- `REQUEST_DEFAULT_PARAMS.client_name` - 设置应用名称
836 -5. **`src/hooks/useGo.js`** - 增强导航 hook 266 +
837 - 267 +---
838 -## 调试技巧 268 +
839 - 269 +## 🚀 快速开始
840 -调试问题时: 270 +
841 - 271 +### 1. 安装依赖
842 -1. **检查环境配置** 272 +```bash
843 - - 验证 `src/utils/config.js` 中的 `BASE_URL` 273 +pnpm install
844 - - 检查业务模块标识符 `f``client_name` 274 +```
845 - 275 +
846 -2. **验证身份认证** 276 +### 2. 配置环境
847 - - 检查 localStorage 中的 `sessionid` 277 +编辑 `src/utils/config.js`,设置 `BASE_URL` 和业务参数。
848 - -`src/utils/request.js` 拦截器中启用详细日志 278 +
849 - - 测试 401 刷新流程 279 +### 3. 启动开发服务器
850 - 280 +```bash
851 -3. **网络问题** 281 +pnpm dev:weapp
852 - - 使用 Taro 内置的网络状态监控 282 +```
853 - - 检查弱网络降级场景 283 +
854 - - 验证离线缓存交互 284 +### 4. 打开微信开发者工具
855 - 285 +导入项目目录:`dist/`
856 -4. **样式问题** 286 +
857 - - 确认设计宽度(375px vs 750px) 287 +---
858 - - 检查是 NutUI 组件还是自定义组件 288 +
859 - - 验证 TailwindCSS 类是否已应用 289 +## 📖 更多文档
860 - 290 +
861 -5. **导航问题** 291 +- **[页面参考](docs/reference/pages.md)** - 查看所有页面
862 - - 检查路由是否在 `src/app.config.js` 中注册 292 +- **[组件参考](docs/reference/components.md)** - 查看所有组件
863 - - 验证页面目录结构与路由匹配 293 +- **[Composables 参考](docs/reference/composables.md)** - 查看所有 Composables
864 - - 使用 `useGo` hook 进行一致的导航 294 +- **[最佳实践](docs/best-practices.md)** - 代码质量和性能优化
865 - 295 +- **[调试指南](docs/debugging.md)** - 调试技巧
866 -## ✨ 最佳实践 296 +- **[经验教训总结](docs/lessons-learned.md)** - 常见陷阱和解决方案
867 -
868 -### 组件开发
869 -- ✅ 使用 `<script setup>` 语法
870 -- ✅ 使用 Composables 处理可复用逻辑
871 -- ✅ Props 应该有类型定义
872 -- ✅ 使用 `emit` 进行子到父通信
873 -- ✅ 优先使用 TailwindCSS 进行样式设计
874 -
875 -### API 集成
876 -- ✅ 始终检查 `res.code === 1` 判断成功
877 -- ✅ 使用 `try/catch` 进行错误处理
878 -- ✅ 请求期间显示加载状态
879 -- ✅ 优雅地处理网络错误
880 -
881 -### 性能
882 -- ✅ 使用页面懒加载(分包)
883 -- ✅ 使用 CDN 参数优化图片
884 -- ✅ 避免无分页的大数据集
885 -- ✅ 在 `onUnmounted` 中清理定时器和监听器
886 -- ✅ 使用 `shallowRef` + `markRaw` 处理组件对象
887 -
888 -### 代码质量
889 -- ✅ 遵循 Vue 3 Composition API 模式
890 -- ✅ 使用描述性变量名
891 -- ✅ 保持函数聚焦且简短(< 50 行)
892 --**所有函数必须有 JSDoc 注释** [详见代码注释规范](~/.claude/rules/code-commenting.md)
893 -- ✅ 提交前运行 `pnpm lint`
894 -
895 -### 代码复用
896 -- ✅ 遵循"第 3 次出现原则" - 代码重复 3 次时必须抽取
897 -- ✅ 优先使用 Composables 而非 Mixins
898 -- ✅ 组件职责单一,避免过度复杂
899 --**组件自包含业务逻辑** - 当UI结构重复出现时,抽取为可复用组件(如 MaterialCard、ProductCard)
900 - - 组件内部处理业务逻辑(查看、收藏等)
901 - - 通过事件与父组件通信
902 - - 减少父组件的重复代码
903 - - 示例:MaterialCard 组件在首页、搜索页、周热门资料页复用
904 -
905 -[更多最佳实践详见经验教训总结](docs/lessons-learned.md)
......
1 +# 最佳实践
2 +
3 +本文档列出项目开发中的最佳实践。
4 +
5 +## 组件开发
6 +
7 +### ✅ 推荐做法
8 +
9 +```vue
10 +<script setup>
11 +// 1. 使用 <script setup> 语法
12 +import { ref, computed } from 'vue'
13 +
14 +// 2. Props 应该有类型定义
15 +const props = defineProps({
16 + title: {
17 + type: String,
18 + required: true
19 + },
20 + count: {
21 + type: Number,
22 + default: 0
23 + }
24 +})
25 +
26 +// 3. 使用 emit 进行子到父通信
27 +const emit = defineEmits(['update', 'delete'])
28 +
29 +// 4. 使用 Composables 处理可复用逻辑
30 +const { data, loading } = use fetchData()
31 +</script>
32 +```
33 +
34 +### ❌ 避免做法
35 +
36 +```vue
37 +<script>
38 +// ❌ 不要使用 Options API
39 +export default {
40 + data() {
41 + return { }
42 + }
43 +}
44 +</script>
45 +
46 +<script setup>
47 +// ❌ 不要省略 Props 类型
48 +const props = defineProps(['title'])
49 +
50 +// ❌ 不要直接修改 props
51 +props.title = 'new title'
52 +</script>
53 +```
54 +
55 +---
56 +
57 +## 样式开发
58 +
59 +### TailwindCSS vs Less
60 +
61 +| 场景 | 使用 | 比例 |
62 +|------|------|------|
63 +| 布局(flex、grid、absolute) | TailwindCSS | 80% |
64 +| 间距(padding、margin、gap) | TailwindCSS | |
65 +| 排版(font-size、text-align) | TailwindCSS | |
66 +| 颜色(bg-*、text-*、border-*) | TailwindCSS | |
67 +| 响应式设计(sm:、md:、lg:) | TailwindCSS | |
68 +| 组件特定样式(需要 scoped) | Less | 20% |
69 +| 深度选择器(`:deep()`) | Less | |
70 +| 动画和过渡 | Less | |
71 +| 伪元素(`::before``::after`) | Less | |
72 +
73 +### ✅ 优先使用 TailwindCSS
74 +
75 +```vue
76 +<template>
77 + <!-- ✅ 使用 TailwindCSS -->
78 + <view class="flex items-center gap-4 p-4 bg-white rounded-lg">
79 + <text class="text-lg font-semibold">标题</text>
80 + </view>
81 +</template>
82 +```
83 +
84 +### ❌ 避免过度使用 Less
85 +
86 +```vue
87 +<style lang="less" scoped>
88 +// ❌ 能用 TailwindCSS 的就不要用 Less
89 +.custom-container {
90 + display: flex;
91 + align-items: center;
92 + padding: 16px;
93 +}
94 +</style>
95 +```
96 +
97 +---
98 +
99 +## API 集成
100 +
101 +### ✅ 推荐做法
102 +
103 +```javascript
104 +// 1. 始终检查 res.code === 1
105 +const res = await fn(yourAPI(params))
106 +if (res.code === 1) {
107 + // 成功处理
108 +}
109 +
110 +// 2. 使用 try/catch 进行错误处理
111 +try {
112 + const res = await fn(yourAPI(params))
113 +} catch (err) {
114 + console.error('API 错误:', err)
115 +}
116 +
117 +// 3. 请求期间显示加载状态
118 +loading.value = true
119 +await fn(yourAPI(params))
120 +loading.value = false
121 +
122 +// 4. 优雅地处理网络错误
123 +try {
124 + await fn(yourAPI(params))
125 +} catch (err) {
126 + if (is_network_error(err)) {
127 + Taro.showToast({ title: '网络错误,请重试', icon: 'none' })
128 + }
129 +}
130 +```
131 +
132 +### ❌ 避免做法
133 +
134 +```javascript
135 +// ❌ 不要只检查 res.code
136 +if (res.code) { }
137 +
138 +// ❌ 不要忽略错误处理
139 +await fn(yourAPI(params))
140 +
141 +// ❌ 不要不显示加载状态
142 +await fn(yourAPI(params)) // 用户不知道发生了什么
143 +```
144 +
145 +---
146 +
147 +## 性能优化
148 +
149 +### ✅ 推荐做法
150 +
151 +```javascript
152 +// 1. 使用页面懒加载(分包)
153 +// 在 app.config.js 中配置分包
154 +subPackages: [
155 + {
156 + root: 'pages/business',
157 + pages: ['/*']
158 + }
159 +]
160 +
161 +// 2. 使用 CDN 参数优化图片
162 +const imageUrl = 'https://cdn.example.com/image.jpg?w=750&q=80'
163 +
164 +// 3. 避免无分页的大数据集
165 +const res = await fn(getListAPI({ page: 1, limit: 20 }))
166 +
167 +// 4. 在 onUnmounted 中清理
168 +onUnmounted(() => {
169 + timer && clearInterval(timer)
170 +})
171 +
172 +// 5. 使用 shallowRef + markRaw 处理组件对象
173 +import { shallowRef, markRaw } from 'vue'
174 +
175 +const menuItems = shallowRef([
176 + { icon: markRaw(IconFont), name: 'heart' }
177 +])
178 +```
179 +
180 +### ❌ 避免做法
181 +
182 +```javascript
183 +// ❌ 不要一次性加载所有数据
184 +const allData = await fn(getAllDataAPI())
185 +
186 +// ❌ 不要忘记清理定时器
187 +const timer = setInterval(() => { }, 1000)
188 +// 没有清理
189 +
190 +// ❌ 不要深度代理组件对象
191 +const menuItems = ref([
192 + { icon: IconFont, name: 'heart' } // Vue 会深度代理
193 +])
194 +```
195 +
196 +---
197 +
198 +## 代码质量
199 +
200 +### ✅ 推荐做法
201 +
202 +```javascript
203 +// 1. 遵循 Vue 3 Composition API 模式
204 +<script setup>
205 +// ...
206 +</script>
207 +
208 +// 2. 使用描述性变量名
209 +const isLoadingUserFavorites = ref(false)
210 +
211 +// 3. 保持函数聚焦且简短(< 50 行)
212 +const fetchUserData = async () => {
213 + // 单一职责
214 +}
215 +
216 +// 4. 所有函数必须有 JSDoc 注释
217 +/**
218 + * 获取用户数据
219 + * @param {number} userId - 用户 ID
220 + * @returns {Promise<User>} 用户数据
221 + */
222 +async function getUserData(userId) { }
223 +
224 +// 5. 提交前运行 pnpm lint
225 +```
226 +
227 +### ❌ 避免做法
228 +
229 +```javascript
230 +// ❌ 不要使用无意义的变量名
231 +const a = ref(false)
232 +const temp = ref(null)
233 +
234 +// ❌ 不要写超长函数(> 50 行)
235 +const doEverything = async () => {
236 + // 100+ 行代码
237 +}
238 +
239 +// ❌ 不要省略函数注释
240 +function process(data) { }
241 +```
242 +
243 +---
244 +
245 +## 代码复用
246 +
247 +### 第 3 次出现原则
248 +
249 +当相同代码模式出现 3 次时,**必须**抽取为 Composable 或组件。
250 +
251 +### ✅ 推荐做法
252 +
253 +```javascript
254 +// 抽取为 Composable
255 +// src/composables/useUserData.js
256 +export function useUserData() {
257 + const user = ref(null)
258 + const loading = ref(false)
259 +
260 + const fetchUser = async () => {
261 + loading.value = true
262 + // ...
263 + }
264 +
265 + return { user, loading, fetchUser }
266 +}
267 +
268 +// 在组件中使用
269 +const { user, loading, fetchUser } = useUserData()
270 +```
271 +
272 +### 组件自包含原则
273 +
274 +对于重复的UI结构,抽取为可复用组件:
275 +
276 +```vue
277 +<!-- MaterialCard.vue - 自包含业务逻辑 -->
278 +<script setup>
279 +const props = defineProps(['item'])
280 +const emit = defineEmits(['view', 'collect'])
281 +
282 +// 组件内部处理业务逻辑
283 +const handleView = () => {
284 + emit('view', props.item.id)
285 +}
286 +</script>
287 +
288 +<!-- 父组件只需要传递数据 -->
289 +<MaterialCard :item="material" @view="handleView" />
290 +```
291 +
292 +---
293 +
294 +## 安全性
295 +
296 +### ✅ 推荐做法
297 +
298 +```javascript
299 +// 1. 用户输入验证
300 +const validateInput = (input) => {
301 + if (!input || input.length > 100) {
302 + return false
303 + }
304 + return true
305 +}
306 +
307 +// 2. XSS 防护(使用 v-html 时净化)
308 +import DOMPurify from 'dompurify'
309 +const sanitizedHtml = DOMPurify.sanitize(rawHtml)
310 +
311 +// 3. 敏感数据不存储在 localStorage
312 +// ❌ 不要存储
313 +localStorage.setItem('password', password)
314 +
315 +// ✅ 使用 Pinia(内存存储)
316 +const authStore = useAuthStore()
317 +authStore.setToken(token)
318 +```
319 +
320 +---
321 +
322 +## 相关文档
323 +
324 +- **[经验教训总结](lessons-learned.md)** - 常见陷阱和解决方案
325 +- **[调试指南](debugging.md)** - 调试技巧
1 +# 调试指南
2 +
3 +本文档介绍项目调试的常用技巧和工具。
4 +
5 +## 检查环境配置
6 +
7 +### 验证 BASE_URL
8 +
9 +```bash
10 +# 查看 src/utils/config.js 中的 BASE_URL 配置
11 +cat src/utils/config.js | grep BASE_URL
12 +```
13 +
14 +确保:
15 +- 开发环境指向测试服务器
16 +- 生产环境指向正式服务器
17 +
18 +### 检查业务参数
19 +
20 +```javascript
21 +// src/utils/config.js
22 +REQUEST_DEFAULT_PARAMS: {
23 + f: 'your_module', // 业务模块标识符
24 + client_name: 'your_app' // 应用名称
25 +}
26 +```
27 +
28 +---
29 +
30 +## 验证身份认证
31 +
32 +### 检查 sessionid
33 +
34 +```javascript
35 +// 在浏览器控制台或微信开发者工具中执行
36 +console.log(localStorage.sessionid)
37 +```
38 +
39 +### 启用详细日志
40 +
41 +`src/utils/request.js` 拦截器中启用详细日志:
42 +
43 +```javascript
44 +// 请求拦截器
45 +config.headers = {
46 + 'cookie': `sessionid=${localStorage.sessionid}`,
47 + // 添加调试日志
48 + 'X-Debug': 'true'
49 +}
50 +
51 +console.log('[Request]', config.url, config.data)
52 +```
53 +
54 +### 测试 401 刷新流程
55 +
56 +```javascript
57 +// 1. 清除 sessionid 模拟过期
58 +localStorage.removeItem('sessionid')
59 +
60 +// 2. 发送请求触发 401
61 +await fn(someAPI())
62 +
63 +// 3. 观察是否自动刷新并重试
64 +```
65 +
66 +---
67 +
68 +## 网络问题调试
69 +
70 +### 检查网络状态
71 +
72 +```javascript
73 +import Taro from '@tarojs/taro'
74 +
75 +// 获取网络类型
76 +Taro.getNetworkType({
77 + success: (res) => {
78 + console.log('网络类型:', res.networkType)
79 + // wifi, 4g, 5g, none
80 + }
81 +})
82 +
83 +// 监听网络变化
84 +Taro.onNetworkStatusChange((result) => {
85 + console.log('网络状态变化:', result)
86 +})
87 +```
88 +
89 +### 检查弱网络场景
90 +
91 +项目支持弱网络降级,通过以下方式检测:
92 +
93 +```javascript
94 +// src/utils/request.js
95 +import { is_timeout_error, is_network_error } from '@/utils/network'
96 +
97 +try {
98 + const res = await fn(yourAPI())
99 +} catch (err) {
100 + if (is_timeout_error(err)) {
101 + console.log('请求超时')
102 + } else if (is_network_error(err)) {
103 + console.log('网络错误')
104 + }
105 +}
106 +```
107 +
108 +---
109 +
110 +## 样式问题调试
111 +
112 +### 确认设计宽度
113 +
114 +项目中使用双设计宽度系统:
115 +- **NutUI 组件**:375px
116 +- **其他组件**:750px
117 +
118 +```javascript
119 +// config/index.js
120 +designWidth: 750, // 默认
121 +
122 +// NutUI 特殊配置
123 +nutui: {
124 + designWidth: 375
125 +}
126 +```
127 +
128 +### 检查样式应用
129 +
130 +```vue
131 +<template>
132 + <!-- 添加调试类名 -->
133 + <view class="debug-component">
134 + 内容
135 + </view>
136 +</template>
137 +
138 +<style lang="less" scoped>
139 +.debug-component {
140 + /* 调试边框 */
141 + border: 1px solid red;
142 +}
143 +</style>
144 +```
145 +
146 +### 验证 TailwindCSS 类
147 +
148 +```bash
149 +# 检查 TailwindCSS 配置
150 +cat tailwind.config.js
151 +
152 +# 检查类是否生效
153 +# 在微信开发者工具中查看元素的 computed styles
154 +```
155 +
156 +---
157 +
158 +## 导航问题调试
159 +
160 +### 检查路由注册
161 +
162 +```javascript
163 +// src/app.config.js
164 +export default {
165 + pages: [
166 + 'pages/your-page/index', // 确认已注册
167 + ]
168 +}
169 +```
170 +
171 +### 验证页面目录结构
172 +
173 +```bash
174 +# 确认页面文件存在
175 +ls -la src/pages/your-page/
176 +
177 +# 应该包含:
178 +# - index.vue
179 +# - index.config.js
180 +```
181 +
182 +### 调试导航参数
183 +
184 +```javascript
185 +// 发送页面
186 +go('/pages/detail/index', { id: 123 })
187 +
188 +// 接收页面
189 +useLoad((options) => {
190 + console.log('接收到的参数:', options)
191 + console.log('ID:', options.id) // 应该输出 123
192 +})
193 +```
194 +
195 +---
196 +
197 +## API 问题调试
198 +
199 +### 查看 API 请求
200 +
201 +```javascript
202 +// src/utils/request.js
203 +// 在拦截器中添加日志
204 +interceptors.request.use((config) => {
205 + console.log('[API Request]', {
206 + url: config.url,
207 + method: config.method,
208 + data: config.data,
209 + headers: config.headers
210 + })
211 + return config
212 +})
213 +
214 +interceptors.response.use((response) => {
215 + console.log('[API Response]', {
216 + status: response.status,
217 + data: response.data
218 + })
219 + return response
220 +})
221 +```
222 +
223 +### 测试 API 调用
224 +
225 +```javascript
226 +// 独立测试 API
227 +import { yourAPI } from '@/api'
228 +import { fn } from '@/api/fn'
229 +
230 +async function testAPI() {
231 + try {
232 + const url = yourAPI({ id: 123 })
233 + console.log('API URL:', url)
234 +
235 + const res = await fn(url)
236 + console.log('API Response:', res)
237 +
238 + if (res.code === 1) {
239 + console.log('API 调用成功')
240 + } else {
241 + console.log('API 业务错误:', res.msg)
242 + }
243 + } catch (err) {
244 + console.error('API 网络错误:', err)
245 + }
246 +}
247 +
248 +testAPI()
249 +```
250 +
251 +---
252 +
253 +## 常见问题
254 +
255 +### Q: NutUI 组件样式不生效
256 +
257 +A: 检查设计宽度配置,NutUI 使用 375px 设计宽度:
258 +
259 +```javascript
260 +// config/index.js
261 +nutui: {
262 + designWidth: 375 // 确认配置正确
263 +}
264 +```
265 +
266 +### Q: 页面参数接收不到
267 +
268 +A: 检查以下几点:
269 +
270 +1. 确认使用 `useLoad` 接收参数
271 +2. 确认参数名称正确
272 +3. 确认参数类型(数字 vs 字符串)
273 +
274 +```javascript
275 +useLoad((options) => {
276 + console.log(options) // 先打印看看有什么
277 +})
278 +```
279 +
280 +### Q: API 请求不发送
281 +
282 +A: 检查以下几点:
283 +
284 +1. 确认 BASE_URL 配置正确
285 +2. 确认网络权限
286 +3. 查看控制台是否有错误
287 +4. 检查 request.js 拦截器
288 +
289 +### Q: 组件不更新
290 +
291 +A: 可能的原因:
292 +
293 +1. 响应式数据未正确声明
294 +2. 使用了深度嵌套的对象
295 +3. Key 值未正确设置
296 +
297 +```javascript
298 +// 确保使用 ref 或 reactive
299 +const data = ref(null) // ✅
300 +const data = null // ❌
301 +
302 +// 列表使用 key
303 +<view v-for="item in list" :key="item.id"> // ✅
304 +<view v-for="item in list"> // ❌
305 +```
306 +
307 +---
308 +
309 +## 调试工具
310 +
311 +### 微信开发者工具
312 +
313 +- **Console** - 查看日志输出
314 +- **Network** - 查看网络请求
315 +- **AppData** - 查看 AppData 数据
316 +- **Storage** - 查看 localStorage
317 +- **Wxml** - 查看 DOM 结构
318 +
319 +### Vue DevTools
320 +
321 +Taro 支持 Vue DevTools,可以:
322 +- 查看组件树
323 +- 查看 Vuex/Pinia 状态
324 +- 查看事件监听器
325 +
326 +---
327 +
328 +## 相关文档
329 +
330 +- **[API 集成指南](guides/api-integration.md)** - API 调用详解
331 +- **[最佳实践](best-practices.md)** - 代码质量建议
1 +# API 集成指南
2 +
3 +本文档介绍如何在项目中添加和调用 API。
4 +
5 +## API 定义模式
6 +
7 +### 步骤 1:在 src/api/index.js 中定义 API
8 +
9 +```javascript
10 +export const getProductListAPI = (params) => {
11 + return buildApiUrl('product_list', params)
12 +}
13 +
14 +export const getProductDetailAPI = (params) => {
15 + return buildApiUrl('product_detail', params)
16 +}
17 +```
18 +
19 +### 步骤 2:在页面中使用
20 +
21 +```javascript
22 +import { getProductListAPI } from '@/api'
23 +import { fn } from '@/api/fn'
24 +
25 +const fetchProducts = async () => {
26 + try {
27 + const res = await fn(getProductListAPI({ page: 1 }))
28 + if (res.code === 1) {
29 + products.value = res.data
30 + }
31 + } catch (err) {
32 + console.error('获取产品失败:', err)
33 + }
34 +}
35 +```
36 +
37 +## 请求包装器(fn.js)
38 +
39 +所有 API 调用都应通过 `src/api/fn.js` 的包装器:
40 +
41 +- ✅ 处理常见错误场景
42 +- ✅ 统一错误提示
43 +-**始终检查 `res.code === 1` 判断成功**
44 +
45 +## 完整示例
46 +
47 +### 带加载状态的 API 调用
48 +
49 +```javascript
50 +import { ref } from 'vue'
51 +import { getProductListAPI } from '@/api'
52 +import { fn } from '@/api/fn'
53 +
54 +const products = ref([])
55 +const loading = ref(false)
56 +const error = ref(null)
57 +
58 +const fetchProducts = async (page = 1) => {
59 + loading.value = true
60 + error.value = null
61 +
62 + try {
63 + const res = await fn(getProductListAPI({ page, limit: 20 }))
64 +
65 + if (res.code === 1) {
66 + products.value = res.data.list
67 + } else {
68 + error.value = res.msg || '获取失败'
69 + }
70 + } catch (err) {
71 + console.error('API 错误:', err)
72 + error.value = '网络错误,请重试'
73 + } finally {
74 + loading.value = false
75 + }
76 +}
77 +```
78 +
79 +### 带分页的 API 调用
80 +
81 +```javascript
82 +const page = ref(0)
83 +const hasMore = ref(true)
84 +const loading = ref(false)
85 +
86 +const loadMore = async () => {
87 + if (loading.value || !hasMore.value) return
88 +
89 + loading.value = true
90 + try {
91 + const res = await fn(getProductListAPI({ page: page.value, limit: 20 }))
92 +
93 + if (res.code === 1) {
94 + products.value.push(...res.data.list)
95 + page.value++
96 + hasMore.value = res.data.list.length >= 20
97 + }
98 + } catch (err) {
99 + console.error('加载更多失败:', err)
100 + } finally {
101 + loading.value = false
102 + }
103 +}
104 +```
105 +
106 +## 错误处理
107 +
108 +### 网络错误
109 +
110 +```javascript
111 +try {
112 + const res = await fn(yourAPI(params))
113 + // ...
114 +} catch (err) {
115 + if (is_network_error(err)) {
116 + // 网络错误
117 + Taro.showToast({ title: '网络错误', icon: 'none' })
118 + } else if (is_timeout_error(err)) {
119 + // 超时
120 + Taro.showToast({ title: '请求超时', icon: 'none' })
121 + } else {
122 + // 其他错误
123 + Taro.showToast({ title: '请求失败', icon: 'none' })
124 + }
125 +}
126 +```
127 +
128 +### 业务错误
129 +
130 +```javascript
131 +const res = await fn(yourAPI(params))
132 +
133 +if (res.code === 1) {
134 + // 成功
135 +} else if (res.code === 401) {
136 + // 未登录(通常会被拦截器自动处理)
137 +} else {
138 + // 业务错误
139 + Taro.showToast({ title: res.msg || '操作失败', icon: 'none' })
140 +}
141 +```
142 +
143 +## API 规范
144 +
145 +### 请求格式
146 +
147 +```javascript
148 +// 查询列表
149 +yourAPI({ page: 1, limit: 20, keyword: '搜索词' })
150 +
151 +// 获取详情
152 +detailAPI({ id: 123 })
153 +
154 +// 提交表单
155 +submitAPI({ field1: 'value1', field2: 'value2' })
156 +```
157 +
158 +### 响应格式
159 +
160 +```javascript
161 +// 成功
162 +{
163 + code: 1,
164 + msg: 'success',
165 + data: { /* 业务数据 */ }
166 +}
167 +
168 +// 失败
169 +{
170 + code: 0, // 或其他错误码
171 + msg: '错误信息',
172 + data: null
173 +}
174 +```
175 +
176 +## 最佳实践
177 +
178 +### ✅ 推荐做法
179 +
180 +```javascript
181 +// 1. 使用 async/await
182 +const res = await fn(yourAPI(params))
183 +
184 +// 2. 检查 res.code === 1
185 +if (res.code === 1) {
186 + // 成功处理
187 +}
188 +
189 +// 3. 使用 try/catch
190 +try {
191 + const res = await fn(yourAPI(params))
192 +} catch (err) {
193 + // 错误处理
194 +}
195 +
196 +// 4. 显示加载状态
197 +loading.value = true
198 +// ... API 调用
199 +loading.value = false
200 +```
201 +
202 +### ❌ 避免做法
203 +
204 +```javascript
205 +// 1. 不要只检查 res.code
206 +if (res.code) { } // ❌
207 +
208 +// 2. 不要忽略错误
209 +const res = await fn(yourAPI(params)) // ❌ 无 try/catch
210 +
211 +// 3. 不要硬编码 API URL
212 +fetch('/srv/?a=your_action') // ❌
213 +```
214 +
215 +## 参考文档
216 +
217 +- **[API 接口文档](docs/api-specs/)** - 完整的 API 接口规范
218 +- **[接口联调日志](docs/api-integration-log.md)** - API 集成状态
1 +# 导航系统指南
2 +
3 +本文档介绍项目中的导航系统使用方法。
4 +
5 +## useGo Hook(推荐)
6 +
7 +`useGo` 是增强的导航 Hook,提供自动路径补全和便捷方法。
8 +
9 +### 基础用法
10 +
11 +```javascript
12 +import { useGo } from '@/hooks/useGo'
13 +
14 +const go = useGo()
15 +
16 +// 导航到页面
17 +go('/pages/detail/index')
18 +
19 +// 带参数导航(例如产品 ID)
20 +go('/pages/product-detail/index', { id: 123 })
21 +
22 +// 带多个参数导航
23 +go('/pages/material-list/index', { category: 'insurance', page: 1 })
24 +
25 +// 返回上一页
26 +go.back()
27 +```
28 +
29 +### 路径自动补全
30 +
31 +`useGo` 会自动补全相对路径为绝对路径:
32 +
33 +```javascript
34 +go('detail') // → /pages/detail/index
35 +go('product-detail') // → /pages/product-detail/index
36 +```
37 +
38 +### 返回导航
39 +
40 +```javascript
41 +// 返回上一页
42 +go.back()
43 +
44 +// 返回多页
45 +go.back(2)
46 +
47 +// 返回首页
48 +go('/pages/index/index')
49 +```
50 +
51 +## 在目标页面接收参数
52 +
53 +```javascript
54 +import { useLoad } from '@tarojs/taro'
55 +import { ref } from 'vue'
56 +
57 +const productId = ref(null)
58 +
59 +useLoad((options) => {
60 + // 访问导航参数
61 + console.log('接收到的参数:', options)
62 + productId.value = options.id
63 +
64 + // 根据参数获取数据
65 + fetchProductDetail(options.id)
66 +})
67 +```
68 +
69 +## Taro 内置导航(备选方案)
70 +
71 +如果需要更底层的控制,可以直接使用 Taro 导航 API:
72 +
73 +### navigateTo - 保留当前页
74 +
75 +```javascript
76 +import Taro from '@tarojs/taro'
77 +
78 +Taro.navigateTo({
79 + url: '/pages/detail/index?id=123'
80 +})
81 +```
82 +
83 +### redirectTo - 不保留当前页
84 +
85 +```javascript
86 +Taro.redirectTo({
87 + url: '/pages/login/index'
88 +})
89 +```
90 +
91 +### switchTab - 切换 Tab
92 +
93 +```javascript
94 +Taro.switchTab({
95 + url: '/pages/index/index'
96 +})
97 +```
98 +
99 +### reLaunch - 重启应用
100 +
101 +```javascript
102 +Taro.reLaunch({
103 + url: '/pages/index/index'
104 +})
105 +```
106 +
107 +### navigateBack - 返回
108 +
109 +```javascript
110 +// 返回上一页
111 +Taro.navigateBack()
112 +
113 +// 返回多页
114 +Taro.navigateBack({ delta: 2 })
115 +```
116 +
117 +## 路由状态管理
118 +
119 +### router Store
120 +
121 +项目使用 `src/stores/router.js` 维护已访问路由的栈,主要用于认证回调导航。
122 +
123 +```javascript
124 +import { useRouterStore } from '@/stores/router'
125 +
126 +const routerStore = useRouterStore()
127 +
128 +// 获取上一页路径
129 +const previousPage = routerStore.previousRoute
130 +```
131 +
132 +### 导航钩子
133 +
134 +```javascript
135 +import { useLoad, useShow, useHide, useUnload } from '@tarojs/taro'
136 +
137 +// 页面加载时(只执行一次)
138 +useLoad((options) => {
139 + console.log('页面加载', options)
140 +})
141 +
142 +// 页面显示时(每次返回都会执行)
143 +useShow(() => {
144 + console.log('页面显示')
145 +})
146 +
147 +// 页面隐藏时
148 +useHide(() => {
149 + console.log('页面隐藏')
150 +})
151 +
152 +// 页面卸载时
153 +useUnload(() => {
154 + console.log('页面卸载')
155 +})
156 +```
157 +
158 +## 认证场景导航
159 +
160 +### 登录后返回原页面
161 +
162 +```javascript
163 +import { useGo } from '@/hooks/useGo'
164 +import { useRouterStore } from '@/stores/router'
165 +
166 +const go = useGo()
167 +const routerStore = useRouterStore()
168 +
169 +// 1. 保存当前路径
170 +routerStore.setRedirect('/pages/some-page/index')
171 +
172 +// 2. 跳转登录页
173 +go('/pages/login/index')
174 +
175 +// 3. 登录成功后返回
176 +const redirectUrl = routerStore.redirect
177 +if (redirectUrl) {
178 + go(redirectUrl)
179 + routerStore.setRedirect(null)
180 +}
181 +```
182 +
183 +## 常见问题
184 +
185 +### Q: 导航后页面不刷新?
186 +
187 +A: 使用 `useShow` 钩子,每次页面显示时都会执行:
188 +
189 +```javascript
190 +useShow(() => {
191 + // 重新加载数据
192 + fetchData()
193 +})
194 +```
195 +
196 +### Q: 参数传递丢失?
197 +
198 +A: 确保参数类型正确:
199 +
200 +```javascript
201 +// ❌ 错误:对象作为参数
202 +go('/pages/detail/index', { data: { id: 1 } })
203 +
204 +// ✅ 正确:扁平参数
205 +go('/pages/detail/index', { id: 1, type: 'insurance' })
206 +```
207 +
208 +### Q: 如何清除页面栈?
209 +
210 +A: 使用 `redirectTo``reLaunch`
211 +
212 +```javascript
213 +// 不保留当前页
214 +Taro.redirectTo({ url: '/pages/login/index' })
215 +
216 +// 清空所有页面栈
217 +Taro.reLaunch({ url: '/pages/index/index' })
218 +```
219 +
220 +## 参考文档
221 +
222 +- **[Taro 导航文档](https://docs.taro.zone/docs/vue-navigation)** - 官方文档
223 +- **[页面开发指南](guides/page-development.md)** - 页面创建和路由注册
1 +# 页面开发指南
2 +
3 +本文档介绍如何在项目中添加新页面。
4 +
5 +## 目录结构
6 +
7 +所有页面遵循以下目录结构:
8 +```
9 +src/pages/your-page/
10 +├── index.vue # 页面组件(必须使用 <script setup>)
11 +├── index.config.js # 页面配置(navigationBarTitleText 等)
12 +└── assets/ # 页面特定资源(可选)
13 +```
14 +
15 +## 步骤 1:创建页面目录和文件
16 +
17 +```bash
18 +mkdir -p src/pages/your-page
19 +touch src/pages/your-page/index.vue
20 +touch src/pages/your-page/index.config.js
21 +```
22 +
23 +## 步骤 2:配置页面
24 +
25 +**`index.config.js`**
26 +```javascript
27 +export default {
28 + navigationBarTitleText: '您的页面标题',
29 + enablePullDownRefresh: true,
30 + backgroundColor: '#f5f5f5'
31 +}
32 +```
33 +
34 +## 步骤 3:编写页面组件
35 +
36 +**`index.vue`**
37 +```vue
38 +<script setup>
39 +import { ref } from 'vue'
40 +import { useLoad, useShow } from '@tarojs/taro'
41 +
42 +const pageId = ref(null)
43 +
44 +useLoad((options) => {
45 + console.log('页面加载,参数:', options)
46 + // 接收导航参数
47 + if (options.id) {
48 + pageId.value = options.id
49 + // 根据 ID 获取数据
50 + }
51 +})
52 +
53 +useShow(() => {
54 + console.log('页面显示')
55 +})
56 +
57 +// 您的组件逻辑
58 +</script>
59 +
60 +<template>
61 + <view class="page">
62 + <!-- 页面内容 -->
63 + </view>
64 +</template>
65 +
66 +<style lang="less" scoped>
67 +.page {
68 + padding: 20px;
69 +}
70 +</style>
71 +```
72 +
73 +## 步骤 4:注册路由
74 +
75 +**`src/app.config.js`** 中注册路由:
76 +
77 +```javascript
78 +export default {
79 + pages: [
80 + 'pages/your-page/index',
81 + // ... 其他页面
82 + ],
83 + // ...
84 +}
85 +```
86 +
87 +## 步骤 5:添加导航(可选)
88 +
89 +### 使用 useGo Hook(推荐)
90 +
91 +```javascript
92 +import { useGo } from '@/hooks/useGo'
93 +const go = useGo()
94 +
95 +// 带查询参数导航
96 +go('/pages/your-page/index', { id: 123, type: 'insurance' })
97 +```
98 +
99 +### 使用 Taro 内置导航
100 +
101 +```javascript
102 +import Taro from '@tarojs/taro'
103 +
104 +Taro.navigateTo({
105 + url: '/pages/your-page/index?id=123'
106 +})
107 +```
108 +
109 +## 接收导航参数
110 +
111 +在目标页面的 `useLoad` 中接收参数:
112 +
113 +```javascript
114 +useLoad((options) => {
115 + console.log('接收到的参数:', options)
116 + const { id, type } = options
117 +
118 + // 根据参数获取数据
119 + fetchData(id, type)
120 +})
121 +```
122 +
123 +## TabBar 集成(可选)
124 +
125 +如果页面需要底部导航栏:
126 +
127 +1. 导入 `TabBar` 组件
128 +2. 根据路由配置激活状态
129 +
130 +```vue
131 +<script setup>
132 +import TabBar from '@/components/TabBar.vue'
133 +</script>
134 +
135 +<template>
136 + <view class="page">
137 + <!-- 页面内容 -->
138 + <TabBar />
139 + </view>
140 +</template>
141 +```
142 +
143 +## 常见问题
144 +
145 +### Q: 页面注册后还是 404?
146 +
147 +A: 检查以下几点:
148 +1. 路由路径是否正确(`pages/your-page/index`
149 +2. 是否重启了开发服务器
150 +3. `index.config.js` 是否存在
151 +
152 +### Q: 如何隐藏原生导航栏?
153 +
154 +A: 在 `index.config.js` 中设置:
155 +```javascript
156 +export default {
157 + navigationStyle: 'custom'
158 +}
159 +```
160 +
161 +### Q: 页面参数丢失?
162 +
163 +A: 检查参数是否正确编码:
164 +```javascript
165 +// ❌ 错误
166 +go('/pages/detail/index', { id: '123' })
167 +
168 +// ✅ 正确
169 +go('/pages/detail/index', { id: 123 }) // 数字类型
170 +// 或
171 +go('/pages/detail/index?id=123') // 字符串类型
172 +```
1 +# 组件库参考文档
2 +
3 +本文档列出项目中所有组件的详细说明。
4 +
5 +## 导航与布局组件
6 +
7 +### TabBar.vue - 底部导航栏
8 +
9 +**位置**`src/components/TabBar.vue`
10 +
11 +**功能**:固定底部导航栏,自动适配安全区域
12 +
13 +**关键特性**
14 +- 支持图标 + 文字布局
15 +- 激活状态高亮
16 +
17 +**使用页面**:首页、我的、家办、知识库、签单页面
18 +
19 +---
20 +
21 +### NavHeader.vue - 自定义导航头
22 +
23 +**位置**`src/components/NavHeader.vue`
24 +
25 +**功能**:带返回按钮的自定义导航头
26 +
27 +**关键特性**
28 +- 透明/背景变体
29 +- 刘海屏设备的安全区域内边距
30 +
31 +---
32 +
33 +### indexNav.vue - 首页网格导航
34 +
35 +**位置**`src/components/indexNav.vue`
36 +
37 +**功能**:首页网格导航
38 +
39 +---
40 +
41 +## 图标与媒体组件
42 +
43 +### IconFont.vue - 图标字体包装器
44 +
45 +**位置**`src/components/IconFont.vue`
46 +
47 +**功能**:自定义图标的图标字体包装器
48 +
49 +**⚠️ 注意**:动态切换时需添加 `:key="name"`
50 +
51 +```vue
52 +<IconFont :name="iconName" :key="iconName" />
53 +```
54 +
55 +---
56 +
57 +### qrCode.vue - 二维码显示
58 +
59 +**位置**`src/components/qrCode.vue`
60 +
61 +**功能**:二维码显示
62 +
63 +---
64 +
65 +### qrCodeSearch.vue - 二维码扫描
66 +
67 +**位置**`src/components/qrCodeSearch.vue`
68 +
69 +**功能**:二维码扫描
70 +
71 +---
72 +
73 +## 列表与展示组件
74 +
75 +### SectionCard.vue - 分组卡片
76 +
77 +**位置**`src/components/SectionCard.vue`
78 +
79 +**功能**:分组卡片组件
80 +
81 +---
82 +
83 +### SectionItem.vue - 分组列表项
84 +
85 +**位置**`src/components/SectionItem.vue`
86 +
87 +**功能**:分组列表项组件
88 +
89 +---
90 +
91 +### ListItemActions/ - 列表项操作按钮
92 +
93 +**位置**`src/components/list/ListItemActions/`
94 +
95 +**功能**:列表项操作按钮组
96 +
97 +**关键特性**
98 +- 权限检查
99 +- 自动埋点上报
100 +- 查看按钮、收藏按钮等
101 +
102 +---
103 +
104 +### MaterialCard.vue - 资料卡片(可复用)
105 +
106 +**位置**`src/components/MaterialCard.vue`
107 +
108 +**功能**:资料展示卡片
109 +
110 +**关键特性**
111 +- 自包含业务逻辑:查看、收藏
112 +- 支持动态标签
113 +- 文件大小格式化
114 +- 学习人数显示
115 +- 支持图片文件预览(使用 Taro.previewImage)
116 +
117 +**使用页面**:首页、搜索页、周热门资料页
118 +
119 +**使用的 Composable**
120 +- useCollectOperation
121 +- useListItemClick
122 +
123 +---
124 +
125 +### ProductCard.vue - 产品卡片(可复用)
126 +
127 +**位置**`src/components/ProductCard.vue`
128 +
129 +**功能**:产品展示卡片
130 +
131 +**关键特性**
132 +- 自定义样式:动态标签、封面图
133 +- 支持产品详情查看
134 +- 支持计划书功能
135 +
136 +**使用页面**:首页、搜索页、产品中心页
137 +
138 +---
139 +
140 +## 表单与输入组件
141 +
142 +### FilterTabs.vue - 过滤标签
143 +
144 +**位置**`src/components/FilterTabs.vue`
145 +
146 +**功能**:过滤标签组件
147 +
148 +---
149 +
150 +### SearchBar.vue - 搜索栏
151 +
152 +**位置**`src/components/SearchBar.vue`
153 +
154 +**功能**:搜索栏组件
155 +
156 +---
157 +
158 +## 文档预览组件
159 +
160 +### DocumentPreview/ - 文档预览
161 +
162 +**位置**`src/components/DocumentPreview/`
163 +
164 +**功能**:文档预览组件
165 +
166 +---
167 +
168 +### PdfPreview.vue - PDF 预览
169 +
170 +**位置**`src/components/PdfPreview.vue`
171 +
172 +**功能**:PDF 文件预览
173 +
174 +---
175 +
176 +### OfficeViewer.vue - Office 文档查看器
177 +
178 +**位置**`src/components/OfficeViewer.vue`
179 +
180 +**功能**:Office 文档查看
181 +
182 +---
183 +
184 +## 业务组件
185 +
186 +### PlanSchemes/ - 计划方案
187 +
188 +**位置**`src/components/plan/PlanSchemes/`
189 +
190 +**功能**:计划方案组件(SchemeA, SchemeB)
191 +
192 +---
193 +
194 +### PlanPopup/ - 计划弹窗
195 +
196 +**位置**`src/components/plan/PlanPopup/`
197 +
198 +**功能**:计划弹窗组件
199 +
200 +**关键特性**
201 +- 使用 provide/inject 模式实现父子弹窗通信
202 +- 子弹窗打开时自动隐藏父级 footer
203 +- 支持 AgePicker、DatePicker、SelectPicker 等字段组件
204 +
205 +---
206 +
207 +### PlanFields/ - 计划书表单字段
208 +
209 +**位置**`src/components/plan/PlanFields/`
210 +
211 +**功能**:计划书表单字段组件集
212 +
213 +**子组件**
214 +- `AgePicker.vue` - 年龄选择器
215 +- `AmountInput.vue` - 金额输入框
216 +- `DatePicker.vue` - 日期选择器
217 +- `SelectPicker.vue` - 下拉选择器
218 +- `RadioGroup.vue` - 单选按钮组
219 +
220 +---
221 +
222 +### PlanTemplates/ - 计划模板
223 +
224 +**位置**`src/components/plan/PlanTemplates/`
225 +
226 +**功能**:计划模板组件
227 +
228 +---
229 +
230 +## 工具组件
231 +
232 +### PosterBuilder/ - 海报生成器
233 +
234 +**位置**`src/components/PosterBuilder/`
235 +
236 +**功能**:海报生成
237 +
238 +---
239 +
240 +### time-picker-data/ - 时间选择器数据
241 +
242 +**位置**`src/components/time-picker-data/`
243 +
244 +**功能**:时间选择器数据配置
245 +
246 +---
247 +
248 +## 可选功能组件
249 +
250 +以下组件如果不需要,可以移除:
251 +
252 +- **微信支付**`src/utils/wechatPay.js``src/api/wx/pay.js`
253 +- **二维码**`src/components/qrCode.vue``src/components/qrCodeSearch.vue`
254 +- **海报生成器**`src/components/PosterBuilder/`
255 +- **时间选择器**`src/components/time-picker-data/`
256 +
257 +---
258 +
259 +## 组件使用原则
260 +
261 +### 第 3 次出现原则
262 +
263 +当相同代码模式出现 3 次时,**必须**抽取为组件。
264 +
265 +### 组件自包含原则
266 +
267 +对于重复的UI结构,抽取为可复用组件(如 MaterialCard、ProductCard):
268 +- 组件应该自包含业务逻辑(查看、收藏等)
269 +- 通过事件与父组件通信
270 +- 避免在父组件中重复编写相同的逻辑代码
271 +
272 +## 相关文档
273 +
274 +- **[Composables 参考](composables.md)** - 可复用逻辑
1 +# Composables 参考文档
2 +
3 +本文档列出项目中所有 Composables 的详细说明。
4 +
5 +## 项目中的 Composables
6 +
7 +| Composable | 用途 | 文档 |
8 +|-----------|------|------|
9 +| `useSectionList` | 分组列表管理 | [详情](#usesectionlist) |
10 +| `useFileOperation` | 文件下载、预览、打开 | [详情](#usefileoperation) |
11 +| `useListItemClick` | 统一的列表点击处理 | [详情](#uselistitemclick) |
12 +| `useCollectOperation` | 收藏操作 | [详情](#usecollectoperation) |
13 +| `useEventTracking` | 事件埋点 | [详情](#useeventtracking) |
14 +| `useGo` | 增强导航 | [详情](#usego) |
15 +| `usePlanPermission` | 计划书权限检查 | [详情](#useplanpermission) |
16 +
17 +---
18 +
19 +## useSectionList
20 +
21 +**位置**`src/composables/useSectionList.js`
22 +
23 +**功能**:分组列表管理
24 +
25 +**用途**:处理分组数据的展开/收起、过滤等逻辑
26 +
27 +**示例**
28 +```javascript
29 +import { useSectionList } from '@/composables/useSectionList'
30 +
31 +const { sections, toggleSection, isExpanded } = useSectionList(data)
32 +```
33 +
34 +---
35 +
36 +## useFileOperation
37 +
38 +**位置**`src/composables/useFileOperation.js`
39 +
40 +**功能**:文件操作(下载、预览、打开)
41 +
42 +**用途**:统一的文件操作逻辑,支持多种文件类型
43 +
44 +**示例**
45 +```javascript
46 +import { useFileOperation } from '@/composables/useFileOperation'
47 +
48 +const { downloadFile, previewFile, openFile } = useFileOperation()
49 +
50 +// 下载文件
51 +await downloadFile(file)
52 +
53 +// 预览文件
54 +await previewFile(file)
55 +```
56 +
57 +---
58 +
59 +## useListItemClick
60 +
61 +**位置**`src/composables/useListItemClick.js`
62 +
63 +**功能**:统一的列表点击处理
64 +
65 +**用途**:处理列表项的点击事件,包含权限检查和埋点
66 +
67 +**示例**
68 +```javascript
69 +import { useListItemClick } from '@/composables/useListItemClick'
70 +
71 +const { handleItemClick } = useListItemClick()
72 +
73 +// 处理点击
74 +await handleItemClick(item, () => {
75 + // 点击后的操作
76 +})
77 +```
78 +
79 +---
80 +
81 +## useCollectOperation
82 +
83 +**位置**`src/composables/useCollectOperation.js`
84 +
85 +**功能**:收藏/取消收藏操作
86 +
87 +**用途**:处理收藏状态切换和 API 调用
88 +
89 +**示例**
90 +```javascript
91 +import { useCollectOperation } from '@/composables/useCollectOperation'
92 +
93 +const { isCollected, toggleCollect } = useCollectOperation(metaId)
94 +
95 +// 切换收藏状态
96 +await toggleCollect()
97 +```
98 +
99 +---
100 +
101 +## useEventTracking
102 +
103 +**位置**`src/composables/useEventTracking.js`
104 +
105 +**功能**:事件埋点
106 +
107 +**用途**:统一的事件埋点功能,支持多种埋点类型
108 +
109 +**事件类型**
110 +- `READ_FILE` - 阅读素材
111 +
112 +**示例**
113 +```javascript
114 +import { useEventTracking } from '@/composables/useEventTracking'
115 +
116 +const { trackEvent, trackFileRead } = useEventTracking()
117 +
118 +// 追踪阅读事件
119 +await trackFileRead('file-id-123')
120 +
121 +// 追踪自定义事件
122 +await trackEvent('CUSTOM_EVENT', 'object-id', {
123 + title: '文档标题',
124 + category: '分类'
125 +})
126 +```
127 +
128 +---
129 +
130 +## useGo
131 +
132 +**位置**`src/hooks/useGo.js`
133 +
134 +**功能**:增强导航
135 +
136 +**用途**:自动路径补全和便捷导航方法
137 +
138 +**示例**
139 +```javascript
140 +import { useGo } from '@/hooks/useGo'
141 +
142 +const go = useGo()
143 +
144 +// 导航到页面
145 +go('/pages/detail/index')
146 +
147 +// 带参数导航
148 +go('/pages/product-detail/index', { id: 123 })
149 +
150 +// 返回
151 +go.back()
152 +```
153 +
154 +---
155 +
156 +## usePlanPermission
157 +
158 +**位置**`src/composables/usePlanPermission.js`
159 +
160 +**功能**:计划书权限检查
161 +
162 +**用途**:检查用户是否有权限操作计划书
163 +
164 +**示例**
165 +```javascript
166 +import { usePlanPermission } from '@/composables/usePlanPermission'
167 +
168 +const { checkPlanPermission } = usePlanPermission()
169 +
170 +// 检查权限后执行操作
171 +await checkPlanPermission(() => {
172 + // 有权限后的操作
173 +})
174 +```
175 +
176 +---
177 +
178 +## 抽取原则
179 +
180 +**第 3 次出现原则**
181 +
182 +当相同代码模式出现 3 次时,**必须**抽取为 Composable。
183 +
184 +**示例**
185 +
186 +```javascript
187 +// ❌ BAD - 在多个组件中重复
188 +const handleClick = async () => {
189 + if (!isLoggedIn()) {
190 + Taro.showToast({ title: '请先登录', icon: 'none' })
191 + return
192 + }
193 + // ... 业务逻辑
194 +}
195 +
196 +// ✅ GOOD - 抽取为 Composable
197 +const { requireLogin } = usePermission()
198 +await requireLogin(() => {
199 + // ... 业务逻辑
200 +})
201 +```
202 +
203 +---
204 +
205 +## 创建新的 Composable
206 +
207 +### 命名规范
208 +
209 +- 使用 `use` 前缀
210 +- 使用驼峰命名
211 +- 名称应描述功能
212 +
213 +**示例**
214 +-`useUserData`
215 +-`useFormValidation`
216 +-`userData`
217 +-`validation`
218 +
219 +### 基本结构
220 +
221 +```javascript
222 +/**
223 + * 使用 XXX 功能
224 + *
225 + * @description 功能描述
226 + * @returns {Object} 返回值描述
227 + */
228 +export function useXxx() {
229 + // 响应式状态
230 + const state = ref(null)
231 +
232 + // 方法
233 + const method = () => {
234 + // ...
235 + }
236 +
237 + // 返回公共 API
238 + return {
239 + state,
240 + method
241 + }
242 +}
243 +```
244 +
245 +### 使用示例
246 +
247 +```javascript
248 +// 在组件中使用
249 +import { useXxx } from '@/composables/useXxx'
250 +
251 +const { state, method } = useXxx()
252 +```
253 +
254 +---
255 +
256 +## 相关文档
257 +
258 +- **[组件参考](components.md)** - 可复用组件
259 +- **[最佳实践](../best-practices.md)** - 代码复用原则
1 +# 页面参考文档
2 +
3 +本文档列出项目中所有页面的详细说明。
4 +
5 +## 核心页面
6 +
7 +### 1. pages/index/index - 首页
8 +
9 +**功能**:产品展示、搜索、网格导航
10 +
11 +**关键特性**
12 +- 热门产品的"产品资料"按钮跳转到 `product-detail` 页面,带产品 ID
13 +- 热门资料的"查看更多"跳转到 `material-list` 页面
14 +- 网格导航图标跳转到各个业务页面
15 +
16 +**使用的组件**
17 +- MaterialCard - 资料卡片
18 +- ProductCard - 产品卡片
19 +
20 +---
21 +
22 +### 2. pages/search/index - 搜索页
23 +
24 +**功能**:产品和资料搜索
25 +
26 +**关键特性**
27 +- 支持实时搜索(输入关键字自动调用 searchAPI)
28 +- 双Tab切换(产品、资料)
29 +- 支持分页加载和触底加载更多
30 +
31 +**使用的组件**
32 +- MaterialCard
33 +- ProductCard
34 +
35 +---
36 +
37 +### 3. pages/webview/index - WebView 包装器
38 +
39 +**功能**:外部 URL 的 WebView 包装器
40 +
41 +---
42 +
43 +### 4. pages/document-preview/index - 文档预览页
44 +
45 +**功能**:文档预览
46 +
47 +---
48 +
49 +### 5. pages/document-demo/index - 文档预览演示页
50 +
51 +**功能**:文档预览演示
52 +
53 +---
54 +
55 +### 6. pages/onboarding/index - 新用户引导
56 +
57 +**功能**:新用户引导流程
58 +
59 +---
60 +
61 +## 业务页面
62 +
63 +### 7. pages/family-office/index - 家族办公室
64 +
65 +**功能**:家族办公室服务
66 +
67 +---
68 +
69 +### 8. pages/product-center/index - 产品中心
70 +
71 +**功能**:产品列表展示
72 +
73 +**关键特性**
74 +- 分类筛选
75 +- 分页加载
76 +
77 +---
78 +
79 +### 9. pages/category-list/index - 分类列表
80 +
81 +**功能**:分类列表展示
82 +
83 +---
84 +
85 +### 10. pages/product-detail/index - 产品详情
86 +
87 +**功能**:产品详情展示
88 +
89 +**关键特性**
90 +- 通过 Taro 的 `useLoad` hook 接收 `id` 参数
91 +- 导航示例:`go('/pages/product-detail/index', { id: 1 })`
92 +- 参数可用于从 API 获取产品详情
93 +
94 +---
95 +
96 +### 11. pages/material-list/index - 资料列表
97 +
98 +**功能**:资料/文档列表展示
99 +
100 +**关键特性**
101 +- 分类筛选
102 +- 分页加载
103 +- 触底加载更多
104 +
105 +---
106 +
107 +### 12. pages/week-hot-material/index - 周热门资料
108 +
109 +**功能**:热门资料展示
110 +
111 +**关键特性**
112 +- 使用 MaterialCard 组件展示热门资料
113 +- 支持分页加载和触底加载更多
114 +
115 +---
116 +
117 +### 13. pages/signing/index - 签约
118 +
119 +**功能**:签约流程
120 +
121 +---
122 +
123 +### 14. pages/mine/index - 我的
124 +
125 +**功能**:用户资料页面
126 +
127 +**关键特性**
128 +- 用户信息展示
129 +- 设置入口
130 +
131 +---
132 +
133 +### 15. pages/plan/index - 计划书管理
134 +
135 +**功能**:业务计划管理
136 +
137 +**关键特性**
138 +- 使用 PlanSchemes 和 PlanPopup 组件
139 +- 支持嵌套弹窗交互(provide/inject 模式)
140 +- 支持滚动加载和分页
141 +
142 +---
143 +
144 +### 16. pages/plan-submit-result/index - 计划提交结果
145 +
146 +**功能**:计划提交结果展示
147 +
148 +**关键特性**
149 +- 导航按钮:返回上一页(非首页)
150 +
151 +---
152 +
153 +## 用户相关页面
154 +
155 +### 17. pages/favorites/index - 收藏
156 +
157 +**功能**:用户收藏列表
158 +
159 +---
160 +
161 +### 18. pages/avatar/index - 头像设置
162 +
163 +**功能**:用户头像上传和设置
164 +
165 +---
166 +
167 +### 19. pages/message/index - 消息列表
168 +
169 +**功能**:消息列表展示
170 +
171 +**关键特性**
172 +- 未读消息红点
173 +- 消息分类
174 +
175 +---
176 +
177 +### 20. pages/message-detail/index - 消息详情
178 +
179 +**功能**:消息详情展示
180 +
181 +---
182 +
183 +### 21. pages/feedback-list/index - 反馈列表
184 +
185 +**功能**:意见反馈列表
186 +
187 +---
188 +
189 +### 22. pages/feedback/index - 用户反馈
190 +
191 +**功能**:提交用户反馈
192 +
193 +---
194 +
195 +### 23. pages/login/index - 登录
196 +
197 +**功能**:用户登录
198 +
199 +**关键特性**
200 +- 微信授权登录
201 +- 登录状态检查
202 +
203 +---
204 +
205 +### 24. pages/help-center/index - 帮助中心
206 +
207 +**功能**:帮助中心和常见问题
208 +
209 +---
210 +
211 +## 开发测试页面
212 +
213 +### 25. pages/test-tabs/index - 标签页测试
214 +
215 +**功能**:仅开发环境,用于测试标签页组件
216 +
217 +---
218 +
219 +## 页面注册
220 +
221 +所有页面在 `src/app.config.js` 中注册:
222 +
223 +```javascript
224 +export default {
225 + pages: [
226 + 'pages/index/index',
227 + 'pages/search/index',
228 + // ... 其他页面
229 + ]
230 +}
231 +```
232 +
233 +## 相关文档
234 +
235 +- **[页面开发指南](guides/page-development.md)** - 如何添加新页面
236 +- **[导航系统指南](guides/navigation.md)** - 导航和参数传递