CLAUDE.md
本文件为 Claude Code (claude.ai/code) 在处理此仓库代码时提供指导。
开发命令
核心命令
-
pnpm dev:weapp- 启动微信小程序开发服务器 -
pnpm dev:h5- 启动 H5 开发服务器 -
pnpm build:weapp- 构建生产版本(微信小程序) -
pnpm lint- 运行 ESLint
其他平台构建
-
pnpm dev:alipay- 支付宝小程序开发 -
pnpm dev:swan- 百度小程序开发 -
pnpm dev:tt- 字节跳动小程序开发
项目概述
Manulife WeApp(臻奇智荟圈)是一个基于 Taro 4 + Vue 3 + NutUI 构建的财富管理微信小程序。
业务模块
应用目前包含以下主要功能:
-
产品展示 - 热门产品展示及详情页
- 首页显示热门产品,带"产品资料"按钮
- 产品详情页展示完整产品信息
-
资料库 - 培训材料和文档管理
- 培训材料和案例的知识库
- 资料列表页支持文档预览
- 家办 - 家族办公室服务
- 签单 - 签约流程
- 用户中心 - 个人资料、收藏、反馈、帮助中心
项目架构
这是一个基于 Taro 4 + Vue 3 + NutUI 的微信小程序,内置身份认证和可复用的导航组件。
技术栈
- 框架:Taro 4.1.9 + Vue 3.3.0 + Composition API
- UI 库:NutUI 4.3.13(京东推出的 Taro UI 库)
- 状态管理:Pinia 3.0.3 + taro-plugin-pinia
- HTTP 客户端:axios-miniprogram
- 样式:Less + TailwindCSS 3.x(双设计宽度系统)
- 构建工具:Webpack 5
- 导航:自定义 TabBar + 增强导航 hooks
双设计宽度系统
项目在 config/index.js:16-23 中配置了两种不同的设计宽度:
- NutUI 组件:375px 基准宽度
- 所有其他页面:750px 基准宽度
处理样式时:
- 使用 NutUI 组件 → 参考 375px 设计稿
- 自定义页面布局 → 参考 750px 设计稿
核心架构模式
1. 可复用的导航组件
TabBar 组件(src/components/TabBar.vue):
- 固定底部导航栏
- 自动适配安全区域(刘海屏/底部指示器)
- 支持图标 + 文字布局
- 激活状态高亮
- 使用于:首页、我的、家办、知识库、签单页面
NavHeader 组件(src/components/NavHeader.vue):
- 带返回按钮的自定义导航头
- 透明/背景变体
- 刘海屏设备的安全区域内边距
- 替代默认的 Taro 导航栏
IconFont 组件(src/components/IconFont.vue):
- 自定义图标的图标字体包装器
- 支持大小和颜色自定义
2. 身份认证流程(必需)
项目具有完善的身份认证系统,支持自动会话管理:
启动流程(src/app.js:26-214):
- 应用保存启动路径用于认证回调
- 检查网络状态并处理弱网络场景
- 如果未认证,尝试静默认证
- 认证成功后,启用离线功能
核心文件:
-
src/utils/authRedirect.js- 所有认证逻辑(静默刷新、导航、状态) -
src/utils/request.js- 带 401 自动刷新拦截器的 HTTP 客户端 -
src/pages/auth/index.vue- 认证页(必须保留) -
src/pages/login/index.vue- 登录页
401 自动刷新工作原理(src/utils/request.js:241-276):
- API 返回 401
- 拦截器保存当前页面路径
- 调用
refreshSession()通过微信登录获取新会话 - 使用新会话重试原始请求
- 如果刷新失败,跳转到认证页
重要:后端必须提供 /srv/?a=openid_wxapp 端点用于微信登录。
3. API 层架构
API 定义模式(src/api/index.js):
export const yourAPI = (params) => {
return buildApiUrl('your_action', params)
}
请求包装器(src/api/fn.js):
- 所有 API 调用都应通过此包装器
- 处理常见错误场景
- 提供一致的接口
URL 构建(src/utils/tools.js):
-
buildApiUrl(action, params)- 构建完整的 API URL - 自动合并来自
src/utils/config.js的默认参数
4. 增强导航系统
useGo Hook(src/hooks/useGo.js):
import { useGo } from '@/hooks/useGo'
const go = useGo()
go('/page-name') // 自动补全路径
go('/page', { id: 123 }) // 带查询参数
路由存储(src/stores/router.js):
- 维护已访问路由的栈
- 用于认证回调导航
- 由认证流程自动管理
页面结构
所有页面遵循以下目录结构:
src/pages/your-page/
├── index.vue # 页面组件(必须使用 <script setup>)
├── index.config.js # 页面配置(navigationBarTitleText 等)
└── assets/ # 页面特定资源(可选)
当前页面
核心页面:
-
pages/index/index- 首页(产品展示、搜索、网格导航)- 热门产品的"产品资料"按钮跳转到
product-detail页面,带产品 ID - 热门资料的"查看更多"跳转到
material-list页面 - 网格导航图标跳转到各个业务页面
- 热门产品的"产品资料"按钮跳转到
-
pages/auth/index- 认证页 -
pages/login/index- 登录页
业务页面:
-
pages/family-office/index- 家族办公室服务 -
pages/knowledge-base/index- 知识库(培训材料、案例) -
pages/signing/index- 签约 -
pages/plan/index- 业务计划管理 -
pages/favorites/index- 用户收藏 -
pages/feedback/index- 用户反馈 -
pages/avatar/index- 头像设置 -
pages/mine/index- 用户资料
产品与内容页面:
-
pages/product-detail/index- 产品详情页- 通过 Taro 的
useLoadhook 接收id参数 - 导航示例:
go('/pages/product-detail/index', { id: 1 }) - 参数可用于从 API 获取产品详情
- 通过 Taro 的
-
pages/material-list/index- 资料/文档列表页 -
pages/help-center/index- 帮助中心和常见问题页 -
pages/search/index- 产品和资料搜索页
工具页面:
-
pages/onboarding/index- 新用户引导 -
pages/webview/index- 外部 URL 的 WebView 包装器 -
pages/document-demo/index- 文档预览演示页 -
pages/document-preview/index- 文档预览页
组件库
可复用组件:
-
TabBar.vue- 底部导航栏 -
NavHeader.vue- 自定义导航头 -
IconFont.vue- 图标字体包装器
功能组件:
-
qrCode.vue- 二维码显示 -
qrCodeSearch.vue- 二维码扫描 -
PosterBuilder/- 海报生成 -
time-picker-data/- 时间选择器数据
路径别名
全部配置在 config/index.js:30-38:
@/utils → src/utils
@/components → src/components
@/images → src/assets/images
@/assets → src/assets
@/composables→ src/composables
@/api → src/api
@/stores → src/stores
@/hooks → src/hooks
配置管理
环境配置(src/utils/config.js):
⚠️ 使用前必须修改:
-
BASE_URL- 设置开发/生产域名 -
REQUEST_DEFAULT_PARAMS.f- 设置业务模块标识符 -
REQUEST_DEFAULT_PARAMS.client_name- 设置应用名称
构建配置(config/index.js):
- 路径别名
- 设计宽度规则
- NutUI 自动导入
- 平台特定设置
应用配置(src/app.config.js):
- 页面路由注册
- 窗口配置
- 标签栏配置(可选)
- 分包(如需要)
重要实现细节
会话管理
- 会话 ID 存储在
localStorage中,键名为sessionid - 微信登录成功后由
authRedirect.refreshSession()设置 - 由
request.js拦截器自动注入到请求头中 - 登出或显式手动操作时清除
Promise 单例模式
认证系统使用 Promise 单例防止并发登录尝试:
-
authRedirect.js中的auth_promise确保一次只刷新一个 - 所有并发的 401 共享同一个刷新 Promise
-
.finally()确保无论成功/失败都执行清理
请求超时处理
- 默认超时:5 秒(
src/utils/request.js:79) - 通过
is_timeout_error()辅助函数检测超时 - 通过
is_network_error()辅助函数检测网络错误 - 两者都会触发弱网络降级流程
NutUI 自动导入
NutUI 组件通过 unplugin-vue-components 自动导入(config/index.js:91-93)。
无需手动导入 - 直接在模板中使用组件即可。
TailwindCSS 集成
- 为小程序兼容性禁用了 Preflight
- 启用了
rem2rpx转换 - 内容路径配置在
tailwind.config.js中 - 使用 Tailwind 处理布局、间距、颜色
- 使用 Less 处理组件特定样式、动画、伪元素
样式指南
何时使用 TailwindCSS(80% 的情况):
<div class="flex items-center justify-between p-4 bg-white">
<h1 class="text-xl font-bold text-gray-900">标题</h1>
</div>
何时使用 Less(20% 的情况):
- 组件特定样式
- 深度选择器(
:deep()) - 动画和过渡
- 伪元素(
::before、::after) ```less .custom-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 16px;</li> </ul> <p>:deep(.nut-button) { background-color: rgba(255, 255, 255, 0.2); } }## 可选功能 如果不需要,可以移除以下功能: - **微信支付**:`src/utils/wechatPay.js`、`src/api/wx/pay.js` - **二维码**:`src/components/qrCode.vue`、`src/components/qrCodeSearch.vue` - **海报生成器**:`src/components/PosterBuilder/` - **时间选择器**:`src/components/time-picker-data/` - **离线缓存**:整个离线预约缓存系统(如果不使用) ## 开发工作流 ### 添加新页面 1. **创建页面目录**: ```bash src/pages/your-page/ ├── index.vue └── index.config.js-
配置页面(
index.config.js):export default { navigationBarTitleText: '您的页面标题', enablePullDownRefresh: true, backgroundColor: '#f5f5f5' } -
在
src/app.config.js中注册路由:pages: [ 'pages/your-page/index', // ... ] -
在
index.vue中使用 composition API:<script setup> import { ref } from 'vue' import { useLoad, useShow } from '@tarojs/taro'
const pageId = ref(null)
useLoad((options) => { console.log('页面加载,参数:', options) // 接收导航参数 if (options.id) { pageId.value = options.id // 根据 ID 获取数据 } })
useShow(() => { console.log('页面显示') })
// 您的组件逻辑
**带参数导航**: ```javascript // 从另一个页面 import { useGo } from '@/hooks/useGo' const go = useGo() // 带查询参数导航 go('/pages/product-detail/index', { id: 123, type: 'insurance' })-
添加导航(可选的 TabBar 集成):
- 导入并使用
TabBar组件 - 根据路由配置激活状态
- 导入并使用
添加 API 调用
-
在
src/api/index.js中定义 API:export const getProductListAPI = (params) => { return buildApiUrl('product_list', params) } -
在页面中使用:
import { getProductListAPI } from '@/api' import { fn } from '@/api/fn'
const fetchProducts = async () => { try { const res = await fn(getProductListAPI({ page: 1 })) if (res.code === 1) { products.value = res.data } } catch (err) { console.error('获取产品失败:', err) } }
### 使用导航 **推荐**:使用 `useGo` hook 进行增强导航: ```javascript import { useGo } from '@/hooks/useGo' const go = useGo() // 导航到页面 go('/pages/detail/index') // 带参数导航(例如产品 ID) go('/pages/product-detail/index', { id: 123 }) // 带多个参数导航 go('/pages/material-list/index', { category: 'insurance', page: 1 }) // 返回 go.back()在目标页面接收参数:
import { useLoad } from '@tarojs/taro' import { ref } from 'vue' const productId = ref(null) useLoad((options) => { // 访问导航参数 console.log('接收到的参数:', options) productId.value = options.id // 根据参数获取数据 fetchProductDetail(options.id) })替代方案:使用 Taro 内置导航:
import Taro from '@tarojs/taro' Taro.navigateTo({ url: '/pages/detail/index?id=123' })使用 Pinia 状态管理
创建 store(
src/stores/yourStore.js):import { defineStore } from 'pinia' import { ref } from 'vue' export const useYourStore = defineStore('yourStore', () => { const state = ref(null) function setState(newState) { state.value = newState } return { state, setState } })在组件中使用:
import { useYourStore } from '@/stores/yourStore' const store = useYourStore() store.setState('新值')关键文件总结
修改前必须理解
-
src/utils/authRedirect.js- 完整的认证流程逻辑 -
src/utils/request.js- 带拦截器的 HTTP 客户端 -
src/app.js- 应用启动序列和网络处理 -
src/utils/config.js- 服务器配置(需要修改)
核心业务逻辑
-
src/api/index.js- API 定义 -
src/api/fn.js- 请求包装器 -
src/stores/main.js- 主要状态管理 -
src/stores/router.js- 认证回调的路由状态
可复用组件
-
src/components/TabBar.vue- 底部导航栏 -
src/components/NavHeader.vue- 自定义导航头 -
src/components/IconFont.vue- 图标包装器
UI/UX 工具
-
src/utils/uiText.js- 集中式文案管理 -
src/utils/network.js- 网络状态工具 -
src/hooks/useGo.js- 增强导航 hook
调试技巧
调试问题时:
-
检查环境配置:
- 验证
src/utils/config.js中的BASE_URL - 检查业务模块标识符
f和client_name
- 验证
-
验证身份认证:
- 检查 localStorage 中的
sessionid - 在
src/utils/request.js拦截器中启用详细日志 - 测试 401 刷新流程
- 检查 localStorage 中的
-
网络问题:
- 使用 Taro 内置的网络状态监控
- 检查弱网络降级场景
- 验证离线缓存交互
-
样式问题:
- 确认设计宽度(375px vs 750px)
- 检查是 NutUI 组件还是自定义组件
- 验证 TailwindCSS 类是否已应用
-
导航问题:
- 检查路由是否在
src/app.config.js中注册 - 验证页面目录结构与路由匹配
- 使用
useGohook 进行一致的导航
- 检查路由是否在
最佳实践
组件开发
- 使用
<script setup>语法 - 使用 Composables 处理可复用逻辑
- Props 应该有类型定义
- 使用
emit进行子到父通信 - 优先使用 TailwindCSS 进行样式设计
API 集成
- 始终检查
res.code === 1判断成功 - 使用
try/catch进行错误处理 - 请求期间显示加载状态
- 优雅地处理网络错误
性能
- 使用页面懒加载(分包)
- 使用 CDN 参数优化图片
- 避免无分页的大数据集
- 在
onUnmounted中清理定时器和监听器
代码风格
- 遵循 Vue 3 Composition API 模式
- 使用描述性变量名
- 保持函数聚焦且简短(< 50 行)
- 为复杂函数添加 JSDoc 注释
- 提交前运行
pnpm lint
-