feat: 完善首页导航功能并更新项目文档
- 为首页网格导航添加跳转功能(计划书、入职相关、签单相关、家办相关、产品知识库) - 为产品卡片按钮添加跳转(产品资料→知识库、计划书→计划书页面) - 为"查看更多"链接添加跳转到知识库 - 工具箱暂时显示"功能开发中"提示 - 更新 CLAUDE.md 以反映当前项目架构和开发规范 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
2 changed files
with
377 additions
and
82 deletions
| ... | @@ -15,40 +15,76 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | ... | @@ -15,40 +15,76 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co |
| 15 | - `pnpm dev:swan` - Baidu mini-program development | 15 | - `pnpm dev:swan` - Baidu mini-program development |
| 16 | - `pnpm dev:tt` - ByteDance mini-program development | 16 | - `pnpm dev:tt` - ByteDance mini-program development |
| 17 | 17 | ||
| 18 | +## Project Overview | ||
| 19 | + | ||
| 20 | +**Manulife WeApp** (臻奇智荟圈) is a wealth management WeChat mini-program built with Taro 4 + Vue 3 + NutUI. | ||
| 21 | + | ||
| 22 | +### Business Modules | ||
| 23 | +The app currently includes the following main features: | ||
| 24 | +- **Product Showcase** - Hot products display and search | ||
| 25 | +- **Family Office** (家办) - Family office services | ||
| 26 | +- **Knowledge Base** (资料知识库) - Training materials and case studies | ||
| 27 | +- **Contract Signing** (签单) - Contract signing workflow | ||
| 28 | +- **User Center** - Personal profile, favorites, feedback | ||
| 29 | + | ||
| 18 | ## Project Architecture | 30 | ## Project Architecture |
| 19 | 31 | ||
| 20 | -This is a **Taro 4 + Vue 3 + NutUI** WeChat mini-program template with built-in authentication, offline support, and weak network handling. | 32 | +This is a **Taro 4 + Vue 3 + NutUI** WeChat mini-program with built-in authentication and reusable navigation components. |
| 21 | 33 | ||
| 22 | ### Technology Stack | 34 | ### Technology Stack |
| 23 | -- **Framework**: Taro 4.x (multi-platform mini-program framework) | 35 | +- **Framework**: Taro 4.1.9 + Vue 3.3.0 + Composition API |
| 24 | -- **UI**: Vue 3 + NutUI 4.x (JD.com's UI library) | 36 | +- **UI Library**: NutUI 4.3.13 (JD.com's UI library for Taro) |
| 25 | -- **State Management**: Pinia | 37 | +- **State Management**: Pinia 3.0.3 + taro-plugin-pinia |
| 26 | - **HTTP Client**: axios-miniprogram | 38 | - **HTTP Client**: axios-miniprogram |
| 27 | -- **Styling**: Less + TailwindCSS (dual design width system) | 39 | +- **Styling**: Less + TailwindCSS 3.x (dual design width system) |
| 28 | - **Build Tool**: Webpack 5 | 40 | - **Build Tool**: Webpack 5 |
| 41 | +- **Navigation**: Custom TabBar + enhanced navigation hooks | ||
| 29 | 42 | ||
| 30 | ### Dual Design Width System | 43 | ### Dual Design Width System |
| 31 | The project uses **two different design widths** configured in `config/index.js:16-23`: | 44 | The project uses **two different design widths** configured in `config/index.js:16-23`: |
| 32 | - **NutUI components**: 375px base width | 45 | - **NutUI components**: 375px base width |
| 33 | - **All other pages**: 750px base width | 46 | - **All other pages**: 750px base width |
| 34 | 47 | ||
| 35 | -When working with styles, always check if you're using NutUI components or custom components to determine which width to reference. | 48 | +When working with styles: |
| 49 | +- Check if you're using NutUI components → reference 375px designs | ||
| 50 | +- Custom page layouts → reference 750px designs | ||
| 36 | 51 | ||
| 37 | ### Key Architectural Patterns | 52 | ### Key Architectural Patterns |
| 38 | 53 | ||
| 39 | -#### 1. Authentication Flow (Required) | 54 | +#### 1. Reusable Navigation Components |
| 55 | + | ||
| 56 | +**TabBar Component** (`src/components/TabBar.vue`): | ||
| 57 | +- Fixed bottom navigation bar | ||
| 58 | +- Auto-adapts to safe areas (notch/home indicator) | ||
| 59 | +- Supports icon + text layout | ||
| 60 | +- Active state highlighting | ||
| 61 | +- Used across: Index, Mine, Family Office, Knowledge Base, Signing pages | ||
| 62 | + | ||
| 63 | +**NavHeader Component** (`src/components/NavHeader.vue`): | ||
| 64 | +- Custom navigation header with back button | ||
| 65 | +- Transparent/background variants | ||
| 66 | +- Safe area padding for notch devices | ||
| 67 | +- Replaces default Taro navigation bar | ||
| 68 | + | ||
| 69 | +**IconFont Component** (`src/components/IconFont.vue`): | ||
| 70 | +- Icon font wrapper for custom icons | ||
| 71 | +- Supports size and color customization | ||
| 72 | + | ||
| 73 | +#### 2. Authentication Flow (Required) | ||
| 74 | + | ||
| 40 | The project has a sophisticated authentication system with automatic session management: | 75 | The project has a sophisticated authentication system with automatic session management: |
| 41 | 76 | ||
| 42 | **Startup Flow** (`src/app.js:26-214`): | 77 | **Startup Flow** (`src/app.js:26-214`): |
| 43 | 1. App saves launch path for auth callback | 78 | 1. App saves launch path for auth callback |
| 44 | 2. Checks network status and handles weak network scenarios | 79 | 2. Checks network status and handles weak network scenarios |
| 45 | 3. Attempts silent auth if not authenticated | 80 | 3. Attempts silent auth if not authenticated |
| 46 | -4. On auth success, enables offline booking cache polling | 81 | +4. On auth success, enables offline features |
| 47 | 82 | ||
| 48 | **Core Files**: | 83 | **Core Files**: |
| 49 | - `src/utils/authRedirect.js` - All auth logic (silent refresh, navigation, state) | 84 | - `src/utils/authRedirect.js` - All auth logic (silent refresh, navigation, state) |
| 50 | - `src/utils/request.js` - HTTP client with 401 auto-refresh interceptor | 85 | - `src/utils/request.js` - HTTP client with 401 auto-refresh interceptor |
| 51 | - `src/pages/auth/index.vue` - Auth page (must be preserved) | 86 | - `src/pages/auth/index.vue` - Auth page (must be preserved) |
| 87 | +- `src/pages/login/index.vue` - Login page | ||
| 52 | 88 | ||
| 53 | **How 401 Auto-Refresh Works** (`src/utils/request.js:241-276`): | 89 | **How 401 Auto-Refresh Works** (`src/utils/request.js:241-276`): |
| 54 | 1. API returns 401 | 90 | 1. API returns 401 |
| ... | @@ -59,34 +95,6 @@ The project has a sophisticated authentication system with automatic session man | ... | @@ -59,34 +95,6 @@ The project has a sophisticated authentication system with automatic session man |
| 59 | 95 | ||
| 60 | **Important**: The backend MUST provide `/srv/?a=openid_wxapp` endpoint for WeChat login. | 96 | **Important**: The backend MUST provide `/srv/?a=openid_wxapp` endpoint for WeChat login. |
| 61 | 97 | ||
| 62 | -#### 2. Offline/Weak Network Support | ||
| 63 | -The app gracefully handles network issues through multiple mechanisms: | ||
| 64 | - | ||
| 65 | -**Network Detection** (`src/utils/network.js`): | ||
| 66 | -- Monitors network status changes | ||
| 67 | -- Detects weak network conditions | ||
| 68 | -- Provides offline caching capabilities | ||
| 69 | - | ||
| 70 | -**Offline Booking Cache** (`src/composables/useOfflineBookingCache.js`): | ||
| 71 | -- Caches booking data for offline access | ||
| 72 | -- Supports reading/writing cached data | ||
| 73 | -- Used when network is unavailable | ||
| 74 | - | ||
| 75 | -**Cache Polling** (`src/composables/useOfflineBookingCachePolling.js`): | ||
| 76 | -- Background polling to refresh cached data | ||
| 77 | -- Reference-counted enable/disable mechanism | ||
| 78 | -- Only runs when network is available | ||
| 79 | - | ||
| 80 | -**Weak Network UI** (`src/utils/uiText.js`): | ||
| 81 | -- Centralized copy management for weak network scenarios | ||
| 82 | -- Provides modal options for user interaction | ||
| 83 | - | ||
| 84 | -**Fallback Flow** (`src/utils/request.js:143-168`): | ||
| 85 | -1. Request times out or fails | ||
| 86 | -2. Checks if offline cache exists | ||
| 87 | -3. If yes, redirects to offline booking list | ||
| 88 | -4. If no, shows weak network modal | ||
| 89 | - | ||
| 90 | #### 3. API Layer Architecture | 98 | #### 3. API Layer Architecture |
| 91 | 99 | ||
| 92 | **API Definition Pattern** (`src/api/index.js`): | 100 | **API Definition Pattern** (`src/api/index.js`): |
| ... | @@ -97,7 +105,7 @@ export const yourAPI = (params) => { | ... | @@ -97,7 +105,7 @@ export const yourAPI = (params) => { |
| 97 | ``` | 105 | ``` |
| 98 | 106 | ||
| 99 | **Request Wrapper** (`src/api/fn.js`): | 107 | **Request Wrapper** (`src/api/fn.js`): |
| 100 | -- All API calls go through this wrapper | 108 | +- All API calls should go through this wrapper |
| 101 | - Handles common error scenarios | 109 | - Handles common error scenarios |
| 102 | - Provides consistent interface | 110 | - Provides consistent interface |
| 103 | 111 | ||
| ... | @@ -105,9 +113,9 @@ export const yourAPI = (params) => { | ... | @@ -105,9 +113,9 @@ export const yourAPI = (params) => { |
| 105 | - `buildApiUrl(action, params)` - Constructs full API URL | 113 | - `buildApiUrl(action, params)` - Constructs full API URL |
| 106 | - Automatically merges default parameters from `src/utils/config.js` | 114 | - Automatically merges default parameters from `src/utils/config.js` |
| 107 | 115 | ||
| 108 | -#### 4. Navigation System | 116 | +#### 4. Enhanced Navigation System |
| 109 | 117 | ||
| 110 | -**Enhanced Navigation Hook** (`src/hooks/useGo.js`): | 118 | +**useGo Hook** (`src/hooks/useGo.js`): |
| 111 | ```javascript | 119 | ```javascript |
| 112 | import { useGo } from '@/hooks/useGo' | 120 | import { useGo } from '@/hooks/useGo' |
| 113 | const go = useGo() | 121 | const go = useGo() |
| ... | @@ -121,6 +129,49 @@ go('/page', { id: 123 }) // With query params | ... | @@ -121,6 +129,49 @@ go('/page', { id: 123 }) // With query params |
| 121 | - Used for auth callback navigation | 129 | - Used for auth callback navigation |
| 122 | - Automatically managed by auth flow | 130 | - Automatically managed by auth flow |
| 123 | 131 | ||
| 132 | +### Page Structure | ||
| 133 | + | ||
| 134 | +All pages follow this directory structure: | ||
| 135 | +``` | ||
| 136 | +src/pages/your-page/ | ||
| 137 | +├── index.vue # Page component (must use <script setup>) | ||
| 138 | +├── index.config.js # Page configuration (navigationBarTitleText, etc.) | ||
| 139 | +└── assets/ # Page-specific assets (optional) | ||
| 140 | +``` | ||
| 141 | + | ||
| 142 | +### Current Pages | ||
| 143 | + | ||
| 144 | +**Core Pages**: | ||
| 145 | +1. `pages/index/index` - Home page (product showcase, search, grid navigation) | ||
| 146 | +2. `pages/auth/index` - Authentication page | ||
| 147 | +3. `pages/login/index` - Login page | ||
| 148 | + | ||
| 149 | +**Business Pages**: | ||
| 150 | +4. `pages/family-office/index` - Family office services | ||
| 151 | +5. `pages/knowledge-base/index` - Knowledge base (training materials, cases) | ||
| 152 | +6. `pages/signing/index` - Contract signing | ||
| 153 | +7. `pages/plan/index` - Business plan management | ||
| 154 | +8. `pages/favorites/index` - User favorites | ||
| 155 | +9. `pages/feedback/index` - User feedback | ||
| 156 | +10. `pages/avatar/index` - Avatar settings | ||
| 157 | +11. `pages/mine/index` - User profile | ||
| 158 | + | ||
| 159 | +**Auxiliary Pages**: | ||
| 160 | +12. `pages/onboarding/index` - New user onboarding | ||
| 161 | + | ||
| 162 | +### Component Library | ||
| 163 | + | ||
| 164 | +**Reusable Components**: | ||
| 165 | +- `TabBar.vue` - Bottom navigation bar | ||
| 166 | +- `NavHeader.vue` - Custom navigation header | ||
| 167 | +- `IconFont.vue` - Icon font wrapper | ||
| 168 | + | ||
| 169 | +**Feature Components**: | ||
| 170 | +- `qrCode.vue` - QR code display | ||
| 171 | +- `qrCodeSearch.vue` - QR code scanner | ||
| 172 | +- `PosterBuilder/` - Poster generation | ||
| 173 | +- `time-picker-data/` - Time picker data | ||
| 174 | + | ||
| 124 | ### Path Aliases | 175 | ### Path Aliases |
| 125 | All configured in `config/index.js:30-38`: | 176 | All configured in `config/index.js:30-38`: |
| 126 | ```javascript | 177 | ```javascript |
| ... | @@ -148,6 +199,12 @@ All configured in `config/index.js:30-38`: | ... | @@ -148,6 +199,12 @@ All configured in `config/index.js:30-38`: |
| 148 | - NutUI auto-import | 199 | - NutUI auto-import |
| 149 | - Platform-specific settings | 200 | - Platform-specific settings |
| 150 | 201 | ||
| 202 | +**App Config** (`src/app.config.js`): | ||
| 203 | +- Page routes registration | ||
| 204 | +- Window configuration | ||
| 205 | +- Tab bar configuration (optional) | ||
| 206 | +- Subpackages (if needed) | ||
| 207 | + | ||
| 151 | ## Important Implementation Details | 208 | ## Important Implementation Details |
| 152 | 209 | ||
| 153 | ### Session Management | 210 | ### Session Management |
| ... | @@ -169,20 +226,176 @@ The auth system uses Promise singletons to prevent concurrent login attempts: | ... | @@ -169,20 +226,176 @@ The auth system uses Promise singletons to prevent concurrent login attempts: |
| 169 | - Both trigger weak network fallback flow | 226 | - Both trigger weak network fallback flow |
| 170 | 227 | ||
| 171 | ### NutUI Auto-Import | 228 | ### NutUI Auto-Import |
| 172 | -NutUI components are auto-imported via unplugin-vue-components (`config/index.js:91-93`). No manual imports needed. | 229 | +NutUI components are auto-imported via unplugin-vue-components (`config/index.js:91-93`). |
| 230 | +**No manual imports needed** - just use components directly in templates. | ||
| 173 | 231 | ||
| 174 | ### TailwindCSS Integration | 232 | ### TailwindCSS Integration |
| 175 | - Preflight disabled for mini-program compatibility | 233 | - Preflight disabled for mini-program compatibility |
| 176 | - `rem2rpx` conversion enabled | 234 | - `rem2rpx` conversion enabled |
| 177 | - Content paths configured in `tailwind.config.js` | 235 | - Content paths configured in `tailwind.config.js` |
| 236 | +- Use Tailwind for layout, spacing, colors | ||
| 237 | +- Use Less for component-specific styles, animations, pseudo-elements | ||
| 238 | + | ||
| 239 | +### Styling Guidelines | ||
| 240 | + | ||
| 241 | +**When to use TailwindCSS** (80% of cases): | ||
| 242 | +```vue | ||
| 243 | +<div class="flex items-center justify-between p-4 bg-white"> | ||
| 244 | + <h1 class="text-xl font-bold text-gray-900">Title</h1> | ||
| 245 | +</div> | ||
| 246 | +``` | ||
| 247 | + | ||
| 248 | +**When to use Less** (20% of cases): | ||
| 249 | +- Component-specific styles | ||
| 250 | +- Deep selectors (`:deep()`) | ||
| 251 | +- Animations and transitions | ||
| 252 | +- Pseudo-elements (`::before`, `::after`) | ||
| 253 | +```less | ||
| 254 | +<style lang="less" scoped> | ||
| 255 | +.custom-card { | ||
| 256 | + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | ||
| 257 | + border-radius: 16px; | ||
| 258 | + | ||
| 259 | + :deep(.nut-button) { | ||
| 260 | + background-color: rgba(255, 255, 255, 0.2); | ||
| 261 | + } | ||
| 262 | +} | ||
| 263 | +</style> | ||
| 264 | +``` | ||
| 178 | 265 | ||
| 179 | ## Optional Features | 266 | ## Optional Features |
| 267 | + | ||
| 180 | These features can be removed if not needed: | 268 | These features can be removed if not needed: |
| 181 | -- **WeChat Pay**: `src/utils/wechatPay.js`, `src/api/wx/` | 269 | +- **WeChat Pay**: `src/utils/wechatPay.js`, `src/api/wx/pay.js` |
| 182 | - **QR Code**: `src/components/qrCode.vue`, `src/components/qrCodeSearch.vue` | 270 | - **QR Code**: `src/components/qrCode.vue`, `src/components/qrCodeSearch.vue` |
| 183 | - **Poster Builder**: `src/components/PosterBuilder/` | 271 | - **Poster Builder**: `src/components/PosterBuilder/` |
| 184 | - **Time Picker**: `src/components/time-picker-data/` | 272 | - **Time Picker**: `src/components/time-picker-data/` |
| 185 | -- **Offline Cache**: Entire offline booking cache system | 273 | +- **Offline Cache**: Entire offline booking cache system (if not used) |
| 274 | + | ||
| 275 | +## Development Workflow | ||
| 276 | + | ||
| 277 | +### Adding New Pages | ||
| 278 | + | ||
| 279 | +1. **Create page directory**: | ||
| 280 | + ```bash | ||
| 281 | + src/pages/your-page/ | ||
| 282 | + ├── index.vue | ||
| 283 | + └── index.config.js | ||
| 284 | + ``` | ||
| 285 | + | ||
| 286 | +2. **Configure page** (`index.config.js`): | ||
| 287 | + ```javascript | ||
| 288 | + export default { | ||
| 289 | + navigationBarTitleText: 'Your Page Title', | ||
| 290 | + enablePullDownRefresh: true, | ||
| 291 | + backgroundColor: '#f5f5f5' | ||
| 292 | + } | ||
| 293 | + ``` | ||
| 294 | + | ||
| 295 | +3. **Register route** in `src/app.config.js`: | ||
| 296 | + ```javascript | ||
| 297 | + pages: [ | ||
| 298 | + 'pages/your-page/index', | ||
| 299 | + // ... | ||
| 300 | + ] | ||
| 301 | + ``` | ||
| 302 | + | ||
| 303 | +4. **Use composition API** in `index.vue`: | ||
| 304 | + ```vue | ||
| 305 | + <script setup> | ||
| 306 | + import { ref, onMounted } from 'vue' | ||
| 307 | + import { useLoad, useShow } from '@tarojs/taro' | ||
| 308 | + | ||
| 309 | + useLoad((options) => { | ||
| 310 | + console.log('Page loaded with options:', options) | ||
| 311 | + }) | ||
| 312 | + | ||
| 313 | + // Your component logic | ||
| 314 | + </script> | ||
| 315 | + ``` | ||
| 316 | + | ||
| 317 | +5. **Add navigation** (optional TabBar integration): | ||
| 318 | + - Import and use `TabBar` component | ||
| 319 | + - Configure active state based on route | ||
| 320 | + | ||
| 321 | +### Adding API Calls | ||
| 322 | + | ||
| 323 | +1. **Define API** in `src/api/index.js`: | ||
| 324 | + ```javascript | ||
| 325 | + export const getProductListAPI = (params) => { | ||
| 326 | + return buildApiUrl('product_list', params) | ||
| 327 | + } | ||
| 328 | + ``` | ||
| 329 | + | ||
| 330 | +2. **Use in page**: | ||
| 331 | + ```javascript | ||
| 332 | + import { getProductListAPI } from '@/api' | ||
| 333 | + import { fn } from '@/api/fn' | ||
| 334 | + | ||
| 335 | + const fetchProducts = async () => { | ||
| 336 | + try { | ||
| 337 | + const res = await fn(getProductListAPI({ page: 1 })) | ||
| 338 | + if (res.code === 1) { | ||
| 339 | + products.value = res.data | ||
| 340 | + } | ||
| 341 | + } catch (err) { | ||
| 342 | + console.error('Failed to fetch products:', err) | ||
| 343 | + } | ||
| 344 | + } | ||
| 345 | + ``` | ||
| 346 | + | ||
| 347 | +### Using Navigation | ||
| 348 | + | ||
| 349 | +**Recommended**: Use `useGo` hook for enhanced navigation: | ||
| 350 | +```javascript | ||
| 351 | +import { useGo } from '@/hooks/useGo' | ||
| 352 | + | ||
| 353 | +const go = useGo() | ||
| 354 | + | ||
| 355 | +// Navigate to page | ||
| 356 | +go('/pages/detail/index') | ||
| 357 | + | ||
| 358 | +// Navigate with params | ||
| 359 | +go('/pages/detail/index', { id: 123 }) | ||
| 360 | + | ||
| 361 | +// Go back | ||
| 362 | +go.back() | ||
| 363 | +``` | ||
| 364 | + | ||
| 365 | +**Alternative**: Use Taro's built-in navigation: | ||
| 366 | +```javascript | ||
| 367 | +import Taro from '@tarojs/taro' | ||
| 368 | + | ||
| 369 | +Taro.navigateTo({ | ||
| 370 | + url: '/pages/detail/index?id=123' | ||
| 371 | +}) | ||
| 372 | +``` | ||
| 373 | + | ||
| 374 | +### State Management with Pinia | ||
| 375 | + | ||
| 376 | +**Create store** (`src/stores/yourStore.js`): | ||
| 377 | +```javascript | ||
| 378 | +import { defineStore } from 'pinia' | ||
| 379 | +import { ref } from 'vue' | ||
| 380 | + | ||
| 381 | +export const useYourStore = defineStore('yourStore', () => { | ||
| 382 | + const state = ref(null) | ||
| 383 | + | ||
| 384 | + function setState(newState) { | ||
| 385 | + state.value = newState | ||
| 386 | + } | ||
| 387 | + | ||
| 388 | + return { state, setState } | ||
| 389 | +}) | ||
| 390 | +``` | ||
| 391 | + | ||
| 392 | +**Use in component**: | ||
| 393 | +```javascript | ||
| 394 | +import { useYourStore } from '@/stores/yourStore' | ||
| 395 | + | ||
| 396 | +const store = useYourStore() | ||
| 397 | +store.setState('new value') | ||
| 398 | +``` | ||
| 186 | 399 | ||
| 187 | ## Critical Files Summary | 400 | ## Critical Files Summary |
| 188 | 401 | ||
| ... | @@ -198,29 +411,68 @@ These features can be removed if not needed: | ... | @@ -198,29 +411,68 @@ These features can be removed if not needed: |
| 198 | 3. **`src/stores/main.js`** - Primary state management | 411 | 3. **`src/stores/main.js`** - Primary state management |
| 199 | 4. **`src/stores/router.js`** - Route state for auth callbacks | 412 | 4. **`src/stores/router.js`** - Route state for auth callbacks |
| 200 | 413 | ||
| 201 | -### UI/UX | 414 | +### Reusable Components |
| 415 | +1. **`src/components/TabBar.vue`** - Bottom navigation bar | ||
| 416 | +2. **`src/components/NavHeader.vue`** - Custom navigation header | ||
| 417 | +3. **`src/components/IconFont.vue`** - Icon wrapper | ||
| 418 | + | ||
| 419 | +### UI/UX Utilities | ||
| 202 | 1. **`src/utils/uiText.js`** - Centralized copy management | 420 | 1. **`src/utils/uiText.js`** - Centralized copy management |
| 203 | 2. **`src/utils/network.js`** - Network status utilities | 421 | 2. **`src/utils/network.js`** - Network status utilities |
| 204 | -3. **`src/composables/`** - Reusable composition API hooks | 422 | +3. **`src/hooks/useGo.js`** - Enhanced navigation hook |
| 205 | - | 423 | + |
| 206 | -## Development Workflow | 424 | +## Debugging Tips |
| 207 | - | 425 | + |
| 208 | -When adding new features: | 426 | +When debugging issues: |
| 209 | -1. Define API in `src/api/index.js` using `buildApiUrl()` | 427 | + |
| 210 | -2. Create page in `src/pages/your-page/` | 428 | +1. **Check environment config**: |
| 211 | -3. Add route to `src/app.config.js` | 429 | + - Verify `BASE_URL` in `src/utils/config.js` |
| 212 | -4. Use `useGo()` hook for navigation | 430 | + - Check business module identifier `f` and `client_name` |
| 213 | -5. Leverage Pinia stores for state management | 431 | + |
| 214 | -6. Follow dual design width rules (375px for NutUI, 750px for custom) | 432 | +2. **Verify authentication**: |
| 215 | - | 433 | + - Check `sessionid` in localStorage |
| 216 | -When modifying auth/network behavior: | 434 | + - Enable verbose logging in `src/utils/request.js` interceptor |
| 217 | -- Always read both `authRedirect.js` and `request.js` together | 435 | + - Test 401 refresh flow |
| 218 | -- Test 401 refresh flow thoroughly | 436 | + |
| 219 | -- Verify weak network fallback scenarios | 437 | +3. **Network issues**: |
| 220 | -- Check offline cache interactions | 438 | + - Use Taro's built-in network status monitoring |
| 221 | - | 439 | + - Check weak network fallback scenarios |
| 222 | -When debugging: | 440 | + - Verify offline cache interactions |
| 223 | -- Check `src/utils/config.js` for correct BASE_URL | 441 | + |
| 224 | -- Verify sessionid in localStorage | 442 | +4. **Styling problems**: |
| 225 | -- Enable verbose logging in request interceptor | 443 | + - Confirm design width (375px vs 750px) |
| 226 | -- Use Taro's built-in network status monitoring | 444 | + - Check if NutUI component or custom component |
| 445 | + - Verify TailwindCSS classes are applied | ||
| 446 | + | ||
| 447 | +5. **Navigation issues**: | ||
| 448 | + - Check route is registered in `src/app.config.js` | ||
| 449 | + - Verify page directory structure matches route | ||
| 450 | + - Use `useGo` hook for consistent navigation | ||
| 451 | + | ||
| 452 | +## Best Practices | ||
| 453 | + | ||
| 454 | +### Component Development | ||
| 455 | +- Use `<script setup>` syntax | ||
| 456 | +- Composables for reusable logic | ||
| 457 | +- Props should have type definitions | ||
| 458 | +- Use `emit` for child-to-parent communication | ||
| 459 | +- Prefer TailwindCSS for styling | ||
| 460 | + | ||
| 461 | +### API Integration | ||
| 462 | +- Always check `res.code === 1` for success | ||
| 463 | +- Use `try/catch` for error handling | ||
| 464 | +- Show loading states during requests | ||
| 465 | +- Handle network errors gracefully | ||
| 466 | + | ||
| 467 | +### Performance | ||
| 468 | +- Use page lazy loading (subpackages) | ||
| 469 | +- Optimize images with CDN parameters | ||
| 470 | +- Avoid large data sets without pagination | ||
| 471 | +- Clean up timers and listeners in `onUnmounted` | ||
| 472 | + | ||
| 473 | +### Code Style | ||
| 474 | +- Follow Vue 3 Composition API patterns | ||
| 475 | +- Use descriptive variable names | ||
| 476 | +- Keep functions focused and small (< 50 lines) | ||
| 477 | +- Add JSDoc comments for complex functions | ||
| 478 | +- Run `pnpm lint` before committing | ... | ... |
| ... | @@ -22,7 +22,12 @@ | ... | @@ -22,7 +22,12 @@ |
| 22 | <!-- Grid Icons --> | 22 | <!-- Grid Icons --> |
| 23 | <view class="bg-white rounded-[32rpx] shadow-sm p-[40rpx] mb-[24rpx]"> | 23 | <view class="bg-white rounded-[32rpx] shadow-sm p-[40rpx] mb-[24rpx]"> |
| 24 | <view class="flex flex-wrap"> | 24 | <view class="flex flex-wrap"> |
| 25 | - <view class="flex flex-col items-center w-1/3 mb-[40rpx]" v-for="(item, index) in loopData0" :key="index"> | 25 | + <view |
| 26 | + class="flex flex-col items-center w-1/3 mb-[40rpx]" | ||
| 27 | + v-for="(item, index) in loopData0" | ||
| 28 | + :key="index" | ||
| 29 | + @tap="handleGridNav(item)" | ||
| 30 | + > | ||
| 26 | <view class="w-[88rpx] h-[88rpx] rounded-[24rpx] bg-blue-50 flex items-center justify-center mb-[16rpx]"> | 31 | <view class="w-[88rpx] h-[88rpx] rounded-[24rpx] bg-blue-50 flex items-center justify-center mb-[16rpx]"> |
| 27 | <IconFont :name="item.icon" class="text-blue-600" size="24" /> | 32 | <IconFont :name="item.icon" class="text-blue-600" size="24" /> |
| 28 | </view> | 33 | </view> |
| ... | @@ -35,7 +40,7 @@ | ... | @@ -35,7 +40,7 @@ |
| 35 | <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx] mb-[24rpx]"> | 40 | <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx] mb-[24rpx]"> |
| 36 | <view class="flex justify-between items-center mb-[24rpx]"> | 41 | <view class="flex justify-between items-center mb-[24rpx]"> |
| 37 | <text class="text-gray-900 text-[32rpx] font-bold">热卖产品:</text> | 42 | <text class="text-gray-900 text-[32rpx] font-bold">热卖产品:</text> |
| 38 | - <view class="flex items-center text-blue-600"> | 43 | + <view class="flex items-center text-blue-600" @tap="go('/pages/knowledge-base/index')"> |
| 39 | <text class="text-[26rpx] mr-[4rpx]">查看更多</text> | 44 | <text class="text-[26rpx] mr-[4rpx]">查看更多</text> |
| 40 | <IconFont name="RectRight" size="12" /> | 45 | <IconFont name="RectRight" size="12" /> |
| 41 | </view> | 46 | </view> |
| ... | @@ -56,9 +61,21 @@ | ... | @@ -56,9 +61,21 @@ |
| 56 | </view> | 61 | </view> |
| 57 | </view> | 62 | </view> |
| 58 | <view class="flex justify-between gap-[24rpx]"> | 63 | <view class="flex justify-between gap-[24rpx]"> |
| 59 | - <nut-button plain color="#2563EB" | 64 | + <nut-button |
| 60 | - class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0 !border-blue-600">产品资料</nut-button> | 65 | + plain |
| 61 | - <nut-button color="#2563EB" class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0">计划书</nut-button> | 66 | + color="#2563EB" |
| 67 | + class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0 !border-blue-600" | ||
| 68 | + @tap="go('/pages/knowledge-base/index')" | ||
| 69 | + > | ||
| 70 | + 产品资料 | ||
| 71 | + </nut-button> | ||
| 72 | + <nut-button | ||
| 73 | + color="#2563EB" | ||
| 74 | + class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" | ||
| 75 | + @tap="go('/pages/plan/index')" | ||
| 76 | + > | ||
| 77 | + 计划书 | ||
| 78 | + </nut-button> | ||
| 62 | </view> | 79 | </view> |
| 63 | </view> | 80 | </view> |
| 64 | 81 | ||
| ... | @@ -77,9 +94,21 @@ | ... | @@ -77,9 +94,21 @@ |
| 77 | </view> | 94 | </view> |
| 78 | </view> | 95 | </view> |
| 79 | <view class="flex justify-between gap-[24rpx]"> | 96 | <view class="flex justify-between gap-[24rpx]"> |
| 80 | - <nut-button plain color="#2563EB" | 97 | + <nut-button |
| 81 | - class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0 !border-blue-600">产品资料</nut-button> | 98 | + plain |
| 82 | - <nut-button color="#2563EB" class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0">计划书</nut-button> | 99 | + color="#2563EB" |
| 100 | + class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0 !border-blue-600" | ||
| 101 | + @tap="go('/pages/knowledge-base/index')" | ||
| 102 | + > | ||
| 103 | + 产品资料 | ||
| 104 | + </nut-button> | ||
| 105 | + <nut-button | ||
| 106 | + color="#2563EB" | ||
| 107 | + class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0" | ||
| 108 | + @tap="go('/pages/plan/index')" | ||
| 109 | + > | ||
| 110 | + 计划书 | ||
| 111 | + </nut-button> | ||
| 83 | </view> | 112 | </view> |
| 84 | </view> | 113 | </view> |
| 85 | </view> | 114 | </view> |
| ... | @@ -88,7 +117,7 @@ | ... | @@ -88,7 +117,7 @@ |
| 88 | <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx]"> | 117 | <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx]"> |
| 89 | <view class="flex justify-between items-center mb-[24rpx]"> | 118 | <view class="flex justify-between items-center mb-[24rpx]"> |
| 90 | <text class="text-gray-900 text-[32rpx] font-bold">本周热门资料</text> | 119 | <text class="text-gray-900 text-[32rpx] font-bold">本周热门资料</text> |
| 91 | - <view class="flex items-center text-blue-600"> | 120 | + <view class="flex items-center text-blue-600" @tap="go('/pages/knowledge-base/index')"> |
| 92 | <text class="text-[26rpx] mr-[4rpx]">查看更多</text> | 121 | <text class="text-[26rpx] mr-[4rpx]">查看更多</text> |
| 93 | <IconFont name="RectRight" size="12" /> | 122 | <IconFont name="RectRight" size="12" /> |
| 94 | </view> | 123 | </view> |
| ... | @@ -150,19 +179,33 @@ import { useGo } from '@/hooks/useGo'; | ... | @@ -150,19 +179,33 @@ import { useGo } from '@/hooks/useGo'; |
| 150 | import TabBar from '@/components/TabBar.vue'; | 179 | import TabBar from '@/components/TabBar.vue'; |
| 151 | import IconFont from '@/components/IconFont.vue'; | 180 | import IconFont from '@/components/IconFont.vue'; |
| 152 | 181 | ||
| 153 | -// Data | 182 | +// Grid navigation data with routes |
| 154 | const loopData0 = shallowRef([ | 183 | const loopData0 = shallowRef([ |
| 155 | - { icon: 'Order', lanhutext0: '计划书' }, | 184 | + { icon: 'Order', lanhutext0: '计划书', route: '/pages/plan/index' }, |
| 156 | - { icon: 'My', lanhutext0: '入职相关' }, | 185 | + { icon: 'My', lanhutext0: '入职相关', route: '/pages/onboarding/index' }, |
| 157 | - { icon: 'Cart', lanhutext0: '签单相关' }, | 186 | + { icon: 'Cart', lanhutext0: '签单相关', route: '/pages/signing/index' }, |
| 158 | - { icon: 'Home', lanhutext0: '家办相关' }, | 187 | + { icon: 'Home', lanhutext0: '家办相关', route: '/pages/family-office/index' }, |
| 159 | - { icon: 'Category', lanhutext0: '产品知识库' }, | 188 | + { icon: 'Category', lanhutext0: '产品知识库', route: '/pages/knowledge-base/index' }, |
| 160 | - { icon: 'Star', lanhutext0: '工具箱' }, | 189 | + { icon: 'Star', lanhutext0: '工具箱', route: null }, // 待开发 |
| 161 | ]); | 190 | ]); |
| 162 | 191 | ||
| 163 | // Navigation | 192 | // Navigation |
| 164 | const go = useGo(); | 193 | const go = useGo(); |
| 165 | 194 | ||
| 195 | +// Handle grid navigation click | ||
| 196 | +const handleGridNav = (item) => { | ||
| 197 | + if (!item.route) { | ||
| 198 | + Taro.showToast({ | ||
| 199 | + title: '功能开发中', | ||
| 200 | + icon: 'none', | ||
| 201 | + duration: 2000 | ||
| 202 | + }); | ||
| 203 | + return; | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + go(item.route); | ||
| 207 | +}; | ||
| 208 | + | ||
| 166 | useShareAppMessage(() => { | 209 | useShareAppMessage(() => { |
| 167 | return { | 210 | return { |
| 168 | title: '臻奇智荟圈', | 211 | title: '臻奇智荟圈', | ... | ... |
-
Please register or login to post a comment