CLAUDE.md 13.8 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Development Commands

Core Commands

  • pnpm dev:weapp - Start WeChat mini-program development server
  • pnpm dev:h5 - Start H5 development server
  • pnpm build:weapp - Build for production (WeChat mini-program)
  • pnpm lint - Run ESLint

Other Platform Builds

  • pnpm dev:alipay - Alipay mini-program development
  • pnpm dev:swan - Baidu mini-program development
  • pnpm dev:tt - ByteDance mini-program development

Project Overview

Manulife WeApp (臻奇智荟圈) is a wealth management WeChat mini-program built with Taro 4 + Vue 3 + NutUI.

Business Modules

The app currently includes the following main features:

  • Product Showcase - Hot products display and search
  • Family Office (家办) - Family office services
  • Knowledge Base (资料知识库) - Training materials and case studies
  • Contract Signing (签单) - Contract signing workflow
  • User Center - Personal profile, favorites, feedback

Project Architecture

This is a Taro 4 + Vue 3 + NutUI WeChat mini-program with built-in authentication and reusable navigation components.

Technology Stack

  • Framework: Taro 4.1.9 + Vue 3.3.0 + Composition API
  • UI Library: NutUI 4.3.13 (JD.com's UI library for Taro)
  • State Management: Pinia 3.0.3 + taro-plugin-pinia
  • HTTP Client: axios-miniprogram
  • Styling: Less + TailwindCSS 3.x (dual design width system)
  • Build Tool: Webpack 5
  • Navigation: Custom TabBar + enhanced navigation hooks

Dual Design Width System

The project uses two different design widths configured in config/index.js:16-23:

  • NutUI components: 375px base width
  • All other pages: 750px base width

When working with styles:

  • Check if you're using NutUI components → reference 375px designs
  • Custom page layouts → reference 750px designs

Key Architectural Patterns

1. Reusable Navigation Components

TabBar Component (src/components/TabBar.vue):

  • Fixed bottom navigation bar
  • Auto-adapts to safe areas (notch/home indicator)
  • Supports icon + text layout
  • Active state highlighting
  • Used across: Index, Mine, Family Office, Knowledge Base, Signing pages

NavHeader Component (src/components/NavHeader.vue):

  • Custom navigation header with back button
  • Transparent/background variants
  • Safe area padding for notch devices
  • Replaces default Taro navigation bar

IconFont Component (src/components/IconFont.vue):

  • Icon font wrapper for custom icons
  • Supports size and color customization

2. Authentication Flow (Required)

The project has a sophisticated authentication system with automatic session management:

Startup Flow (src/app.js:26-214):

  1. App saves launch path for auth callback
  2. Checks network status and handles weak network scenarios
  3. Attempts silent auth if not authenticated
  4. On auth success, enables offline features

Core Files:

  • src/utils/authRedirect.js - All auth logic (silent refresh, navigation, state)
  • src/utils/request.js - HTTP client with 401 auto-refresh interceptor
  • src/pages/auth/index.vue - Auth page (must be preserved)
  • src/pages/login/index.vue - Login page

How 401 Auto-Refresh Works (src/utils/request.js:241-276):

  1. API returns 401
  2. Interceptor saves current page path
  3. Calls refreshSession() to get new session via WeChat login
  4. Retries original request with new session
  5. If refresh fails, redirects to auth page

Important: The backend MUST provide /srv/?a=openid_wxapp endpoint for WeChat login.

3. API Layer Architecture

API Definition Pattern (src/api/index.js):

export const yourAPI = (params) => {
    return buildApiUrl('your_action', params)
}

Request Wrapper (src/api/fn.js):

  • All API calls should go through this wrapper
  • Handles common error scenarios
  • Provides consistent interface

URL Building (src/utils/tools.js):

  • buildApiUrl(action, params) - Constructs full API URL
  • Automatically merges default parameters from src/utils/config.js

4. Enhanced Navigation System

useGo Hook (src/hooks/useGo.js):

import { useGo } from '@/hooks/useGo'
const go = useGo()

go('/page-name')                    // Auto-completes path
go('/page', { id: 123 })           // With query params

Route Storage (src/stores/router.js):

  • Maintains stack of visited routes
  • Used for auth callback navigation
  • Automatically managed by auth flow

Page Structure

All pages follow this directory structure:

src/pages/your-page/
├── index.vue           # Page component (must use <script setup>)
├── index.config.js     # Page configuration (navigationBarTitleText, etc.)
└── assets/             # Page-specific assets (optional)

Current Pages

Core Pages:

  1. pages/index/index - Home page (product showcase, search, grid navigation)
  2. pages/auth/index - Authentication page
  3. pages/login/index - Login page

Business Pages:

  1. pages/family-office/index - Family office services
  2. pages/knowledge-base/index - Knowledge base (training materials, cases)
  3. pages/signing/index - Contract signing
  4. pages/plan/index - Business plan management
  5. pages/favorites/index - User favorites
  6. pages/feedback/index - User feedback
  7. pages/avatar/index - Avatar settings
  8. pages/mine/index - User profile

Auxiliary Pages:

  1. pages/onboarding/index - New user onboarding

Component Library

Reusable Components:

  • TabBar.vue - Bottom navigation bar
  • NavHeader.vue - Custom navigation header
  • IconFont.vue - Icon font wrapper

Feature Components:

  • qrCode.vue - QR code display
  • qrCodeSearch.vue - QR code scanner
  • PosterBuilder/ - Poster generation
  • time-picker-data/ - Time picker data

Path Aliases

All configured in 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

Configuration Management

Environment Config (src/utils/config.js): ⚠️ MUST BE MODIFIED before use:

  • BASE_URL - Set development/production domain
  • REQUEST_DEFAULT_PARAMS.f - Set business module identifier
  • REQUEST_DEFAULT_PARAMS.client_name - Set application name

Build Config (config/index.js):

  • Path aliases
  • Design width rules
  • NutUI auto-import
  • Platform-specific settings

App Config (src/app.config.js):

  • Page routes registration
  • Window configuration
  • Tab bar configuration (optional)
  • Subpackages (if needed)

Important Implementation Details

Session Management

  • Session ID stored in localStorage with key sessionid
  • Set by authRedirect.refreshSession() after successful WeChat login
  • Automatically injected into request headers by request.js interceptor
  • Cleared on logout or explicit manual intervention

Promise Single-Pattern

The auth system uses Promise singletons to prevent concurrent login attempts:

  • auth_promise in authRedirect.js ensures only one refresh at a time
  • All concurrent 401s share the same refresh Promise
  • .finally() ensures cleanup regardless of success/failure

Request Timeout Handling

  • Default timeout: 5 seconds (src/utils/request.js:79)
  • Timeout detection via is_timeout_error() helper
  • Network error detection via is_network_error() helper
  • Both trigger weak network fallback flow

NutUI Auto-Import

NutUI components are auto-imported via unplugin-vue-components (config/index.js:91-93). No manual imports needed - just use components directly in templates.

TailwindCSS Integration

  • Preflight disabled for mini-program compatibility
  • rem2rpx conversion enabled
  • Content paths configured in tailwind.config.js
  • Use Tailwind for layout, spacing, colors
  • Use Less for component-specific styles, animations, pseudo-elements

Styling Guidelines

When to use TailwindCSS (80% of cases):

<div class="flex items-center justify-between p-4 bg-white">
  <h1 class="text-xl font-bold text-gray-900">Title</h1>
</div>

When to use Less (20% of cases):

  • Component-specific styles
  • Deep selectors (:deep())
  • Animations and transitions
  • Pseudo-elements (::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); } }
    
    ## Optional Features
    
    These features can be removed if not needed:
    - **WeChat Pay**: `src/utils/wechatPay.js`, `src/api/wx/pay.js`
    - **QR Code**: `src/components/qrCode.vue`, `src/components/qrCodeSearch.vue`
    - **Poster Builder**: `src/components/PosterBuilder/`
    - **Time Picker**: `src/components/time-picker-data/`
    - **Offline Cache**: Entire offline booking cache system (if not used)
    
    ## Development Workflow
    
    ### Adding New Pages
    
    1. **Create page directory**:
       ```bash
       src/pages/your-page/
       ├── index.vue
       └── index.config.js
    
    1. Configure page (index.config.js):

      export default {
       navigationBarTitleText: 'Your Page Title',
       enablePullDownRefresh: true,
       backgroundColor: '#f5f5f5'
      }
      
    2. Register route in src/app.config.js:

      pages: [
       'pages/your-page/index',
       // ...
      ]
      
    3. Use composition API in index.vue:

      <script setup>
      import { ref, onMounted } from 'vue'
      import { useLoad, useShow } from '@tarojs/taro'
      

    useLoad((options) => { console.log('Page loaded with options:', options) })

    // Your component logic

    
    5. **Add navigation** (optional TabBar integration):
       - Import and use `TabBar` component
       - Configure active state based on route
    
    ### Adding API Calls
    
    1. **Define API** in `src/api/index.js`:
       ```javascript
       export const getProductListAPI = (params) => {
           return buildApiUrl('product_list', params)
       }
    
    1. Use in page: ```javascript 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('Failed to fetch products:', err) } }

    
    ### Using Navigation
    
    **Recommended**: Use `useGo` hook for enhanced navigation:
    ```javascript
    import { useGo } from '@/hooks/useGo'
    
    const go = useGo()
    
    // Navigate to page
    go('/pages/detail/index')
    
    // Navigate with params
    go('/pages/detail/index', { id: 123 })
    
    // Go back
    go.back()
    

    Alternative: Use Taro's built-in navigation:

    import Taro from '@tarojs/taro'
    
    Taro.navigateTo({
      url: '/pages/detail/index?id=123'
    })
    

    State Management with Pinia

    Create 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 }
    })
    

    Use in component:

    import { useYourStore } from '@/stores/yourStore'
    
    const store = useYourStore()
    store.setState('new value')
    

    Critical Files Summary

    Must Understand Before Modifying

    1. src/utils/authRedirect.js - Complete auth flow logic
    2. src/utils/request.js - HTTP client with interceptors
    3. src/app.js - App startup sequence and network handling
    4. src/utils/config.js - Server configuration (requires modification)

    Key Business Logic

    1. src/api/index.js - API definitions
    2. src/api/fn.js - Request wrapper
    3. src/stores/main.js - Primary state management
    4. src/stores/router.js - Route state for auth callbacks

    Reusable Components

    1. src/components/TabBar.vue - Bottom navigation bar
    2. src/components/NavHeader.vue - Custom navigation header
    3. src/components/IconFont.vue - Icon wrapper

    UI/UX Utilities

    1. src/utils/uiText.js - Centralized copy management
    2. src/utils/network.js - Network status utilities
    3. src/hooks/useGo.js - Enhanced navigation hook

    Debugging Tips

    When debugging issues:

    1. Check environment config:

      • Verify BASE_URL in src/utils/config.js
      • Check business module identifier f and client_name
    2. Verify authentication:

      • Check sessionid in localStorage
      • Enable verbose logging in src/utils/request.js interceptor
      • Test 401 refresh flow
    3. Network issues:

      • Use Taro's built-in network status monitoring
      • Check weak network fallback scenarios
      • Verify offline cache interactions
    4. Styling problems:

      • Confirm design width (375px vs 750px)
      • Check if NutUI component or custom component
      • Verify TailwindCSS classes are applied
    5. Navigation issues:

      • Check route is registered in src/app.config.js
      • Verify page directory structure matches route
      • Use useGo hook for consistent navigation

    Best Practices

    Component Development

    • Use <script setup> syntax
    • Composables for reusable logic
    • Props should have type definitions
    • Use emit for child-to-parent communication
    • Prefer TailwindCSS for styling

    API Integration

    • Always check res.code === 1 for success
    • Use try/catch for error handling
    • Show loading states during requests
    • Handle network errors gracefully

    Performance

    • Use page lazy loading (subpackages)
    • Optimize images with CDN parameters
    • Avoid large data sets without pagination
    • Clean up timers and listeners in onUnmounted

    Code Style

    • Follow Vue 3 Composition API patterns
    • Use descriptive variable names
    • Keep functions focused and small (< 50 lines)
    • Add JSDoc comments for complex functions
    • Run pnpm lint before committing