CLAUDE.md 14.9 KB

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):

  1. 应用保存启动路径用于认证回调
  2. 检查网络状态并处理弱网络场景
  3. 如果未认证,尝试静默认证
  4. 认证成功后,启用离线功能

核心文件

  • 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):

  1. API 返回 401
  2. 拦截器保存当前页面路径
  3. 调用 refreshSession() 通过微信登录获取新会话
  4. 使用新会话重试原始请求
  5. 如果刷新失败,跳转到认证页

重要:后端必须提供 /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 Hooksrc/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/             # 页面特定资源(可选)

当前页面

核心页面

  1. pages/index/index - 首页(产品展示、搜索、网格导航)
    • 热门产品的"产品资料"按钮跳转到 product-detail 页面,带产品 ID
    • 热门资料的"查看更多"跳转到 material-list 页面
    • 网格导航图标跳转到各个业务页面
  2. pages/auth/index - 认证页
  3. pages/login/index - 登录页

业务页面

  1. pages/family-office/index - 家族办公室服务
  2. pages/knowledge-base/index - 知识库(培训材料、案例)
  3. pages/signing/index - 签约
  4. pages/plan/index - 业务计划管理
  5. pages/favorites/index - 用户收藏
  6. pages/feedback/index - 用户反馈
  7. pages/avatar/index - 头像设置
  8. pages/mine/index - 用户资料

产品与内容页面

  1. pages/product-detail/index - 产品详情页
    • 通过 Taro 的 useLoad hook 接收 id 参数
    • 导航示例:go('/pages/product-detail/index', { id: 1 })
    • 参数可用于从 API 获取产品详情
  2. pages/material-list/index - 资料/文档列表页
  3. pages/help-center/index - 帮助中心和常见问题页
  4. pages/search/index - 产品和资料搜索页

工具页面

  1. pages/onboarding/index - 新用户引导
  2. pages/webview/index - 外部 URL 的 WebView 包装器
  3. pages/document-demo/index - 文档预览演示页
  4. 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
    
    1. 配置页面index.config.js):

      export default {
       navigationBarTitleText: '您的页面标题',
       enablePullDownRefresh: true,
       backgroundColor: '#f5f5f5'
      }
      
    2. src/app.config.js 中注册路由

      pages: [
       'pages/your-page/index',
       // ...
      ]
      
    3. 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' })
    
    1. 添加导航(可选的 TabBar 集成):
      • 导入并使用 TabBar 组件
      • 根据路由配置激活状态

    添加 API 调用

    1. src/api/index.js 中定义 API

      export const getProductListAPI = (params) => {
         return buildApiUrl('product_list', params)
      }
      
    2. 在页面中使用

      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 状态管理

    创建 storesrc/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('新值')
    

    关键文件总结

    修改前必须理解

    1. src/utils/authRedirect.js - 完整的认证流程逻辑
    2. src/utils/request.js - 带拦截器的 HTTP 客户端
    3. src/app.js - 应用启动序列和网络处理
    4. src/utils/config.js - 服务器配置(需要修改)

    核心业务逻辑

    1. src/api/index.js - API 定义
    2. src/api/fn.js - 请求包装器
    3. src/stores/main.js - 主要状态管理
    4. src/stores/router.js - 认证回调的路由状态

    可复用组件

    1. src/components/TabBar.vue - 底部导航栏
    2. src/components/NavHeader.vue - 自定义导航头
    3. src/components/IconFont.vue - 图标包装器

    UI/UX 工具

    1. src/utils/uiText.js - 集中式文案管理
    2. src/utils/network.js - 网络状态工具
    3. src/hooks/useGo.js - 增强导航 hook

    调试技巧

    调试问题时:

    1. 检查环境配置

      • 验证 src/utils/config.js 中的 BASE_URL
      • 检查业务模块标识符 fclient_name
    2. 验证身份认证

      • 检查 localStorage 中的 sessionid
      • src/utils/request.js 拦截器中启用详细日志
      • 测试 401 刷新流程
    3. 网络问题

      • 使用 Taro 内置的网络状态监控
      • 检查弱网络降级场景
      • 验证离线缓存交互
    4. 样式问题

      • 确认设计宽度(375px vs 750px)
      • 检查是 NutUI 组件还是自定义组件
      • 验证 TailwindCSS 类是否已应用
    5. 导航问题

      • 检查路由是否在 src/app.config.js 中注册
      • 验证页面目录结构与路由匹配
      • 使用 useGo hook 进行一致的导航

    最佳实践

    组件开发

    • 使用 <script setup> 语法
    • 使用 Composables 处理可复用逻辑
    • Props 应该有类型定义
    • 使用 emit 进行子到父通信
    • 优先使用 TailwindCSS 进行样式设计

    API 集成

    • 始终检查 res.code === 1 判断成功
    • 使用 try/catch 进行错误处理
    • 请求期间显示加载状态
    • 优雅地处理网络错误

    性能

    • 使用页面懒加载(分包)
    • 使用 CDN 参数优化图片
    • 避免无分页的大数据集
    • onUnmounted 中清理定时器和监听器

    代码风格

    • 遵循 Vue 3 Composition API 模式
    • 使用描述性变量名
    • 保持函数聚焦且简短(< 50 行)
    • 为复杂函数添加 JSDoc 注释
    • 提交前运行 pnpm lint