Files
tashow-manager/CLAUDE.md
悠山 d5a795de77
All checks were successful
Auto Deploy / build-and-deploy (push) Successful in 32s
feat: 更新登录页面和项目文档
- 添加 CLAUDE.md 项目文档
- 添加自动部署脚本
- 修改登录页面"其他登录方式"文本

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 09:25:22 +08:00

7.6 KiB

CLAUDE.md

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

Project Overview

This is a multi-tenant service management platform ("百业到家") built with Ant Design Pro, React 19, TypeScript, and UmiJS Max framework. The application uses dynamic routing loaded from a backend API and implements a comprehensive permission system.

Development Commands

# Start development server (with mocks)
pnpm dev
# or
pnpm start

# Start development server (without mocks, connects to backend)
pnpm start:dev

# Build for production
pnpm build

# Lint (Biome + TypeScript check)
pnpm lint

# Run tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Type check only
pnpm tsc

Important: This project uses pnpm as the package manager, not npm or yarn.

Architecture

Dynamic Routing System

Routes are not statically defined in config/routes.ts (most routes are commented out). Instead, routes are dynamically loaded from the backend API:

  1. On app initialization, getInfo() fetches user permissions and menu structure
  2. patchClientRoutes() in src/app.tsx transforms backend menu data into UmiJS routes
  3. loopMenuItem() in src/utils/menuUtils.tsx recursively converts menu items to route objects
  4. Routes are lazy-loaded using React.lazy(() => import('@/pages/${component}'))

When adding new pages: Create the page component in src/pages/, then configure the route in the backend system (not in code).

Multi-Tenant Architecture

Every API request includes a tenant-id header. Tenant information is:

  • Stored in web-storage-cache with key CACHE_KEY.TenantId
  • Set during login via setTenantId()
  • Automatically added to all requests by the request interceptor in src/app.tsx

Authentication Flow

  1. User logs in with tenant name, username, and password (password is RSA encrypted via JSEncrypt)
  2. Backend returns accessToken and refreshToken
  3. Tokens stored in web-storage-cache (see src/utils/auth.ts)
  4. All requests include Authorization: Bearer ${accessToken} header
  5. On 401 response, automatically attempts token refresh using refreshToken
  6. If refresh fails, redirects to login page

Token refresh logic is in src/requestErrorConfig.ts with request queuing to prevent duplicate refresh attempts.

Request Interceptors

All API requests are automatically modified (see src/app.tsx):

  • API prefix: /admin-api is prepended to all URLs (unless already present)
  • Headers: Authorization, tenant-id, and Accept headers are added
  • Parameter serialization: Arrays are serialized specially:
    • createTime arrays become createTime[0] and createTime[1]
    • Other arrays become key[] format

Caching Strategy

Uses web-storage-cache library (see src/hooks/web/useCache.ts):

  • CACHE_KEY.USER: Current user info
  • CACHE_KEY.ROLE_ROUTERS: Dynamic menu/route data
  • CACHE_KEY.ACCESS_TOKEN / CACHE_KEY.REFRESH_TOKEN: Auth tokens
  • CACHE_KEY.DICT_CACHE: Dictionary/enum data loaded on app init
  • CACHE_KEY.LoginForm: Remember me functionality (password encrypted)

State Management

  • UmiJS Model Plugin: For global state (see src/app.tsx - initialState)
  • Custom Hooks: In src/hooks/stores/ (e.g., useDictStore for dictionary management)
  • Web Storage Cache: For persistent data across sessions

Project Structure

src/
├── pages/           # Feature pages organized by domain
│   ├── ai/         # AI model and sample management
│   ├── prod/       # Product and category management
│   ├── system/     # System admin (users, roles, menus, tenants, logs, messages)
│   ├── trade/      # Order and sales management
│   └── user/       # Login page
├── services/       # API service layer (mirrors page structure)
├── components/     # Reusable components
│   ├── Draggable/  # Drag-and-drop components using @dnd-kit
│   ├── Upload/     # File/image/video upload components
│   ├── GroupTag/   # Tag management components
│   └── Tinymce/    # Rich text editor wrapper
├── hooks/          # Custom React hooks
│   ├── antd/       # Ant Design related hooks
│   ├── stores/     # State management hooks
│   └── web/        # Web utilities (cache, etc.)
├── utils/          # Utility functions
│   ├── auth.ts     # Token and tenant management
│   ├── menuUtils.tsx  # Dynamic route conversion
│   ├── dict.ts     # Dictionary/enum utilities
│   └── tree.ts     # Tree data structure helpers
├── constants/      # Shared constants and enums
├── locales/        # i18n translations (zh-CN default)
└── app.tsx         # App initialization and runtime config

Environment Configuration

Multiple environment files:

  • .env.local - Local overrides (gitignored)
  • .env.dev - Development environment
  • .env.prod - Production environment

Proxy configuration in config/proxy.ts:

  • dev: Points to local backend (currently http://192.168.1.89:48080)
  • test: Points to test environment
  • pre: Points to pre-production environment

Switch environments using UMI_ENV:

cross-env UMI_ENV=dev pnpm start    # Development
cross-env UMI_ENV=test pnpm start   # Test
cross-env UMI_ENV=pre pnpm start    # Pre-production

Code Conventions

Linting

  • Uses Biome (not ESLint) for linting and formatting
  • Configured in biome.json
  • Pre-commit hook runs Biome via lint-staged

Commit Messages

  • Uses commitlint with conventional commits
  • Enforced via Husky pre-commit hook
  • Format: type(scope): subject (e.g., feat: add user management)

Component Patterns

  • ProTable: Use EnhancedProTable wrapper for common table functionality
  • Forms: Use DrawerForm or ModalForm from @ant-design/pro-components
  • File Uploads: Use custom UploadImages or UploadVideo components in src/components/Upload/
  • Rich Text: Use Tinymce component wrapper (TinyMCE is in public/tinymce/)

Service Layer

  • All API calls go through src/services/
  • Use UmiJS request from @umijs/max (configured in src/app.tsx)
  • Response format: { code: number, data: any, msg: string }
  • Success when code === 0

Common Patterns

Adding a New Page

  1. Create page component in src/pages/{domain}/{feature}/index.tsx
  2. Create corresponding service in src/services/{domain}/{feature}/index.ts
  3. Configure the menu/route in the backend system (not in code)
  4. The route will automatically appear after backend configuration

Working with Dictionaries/Enums

Dictionaries are loaded on app init and cached:

import { useDictStore } from '@/hooks/stores/dict';

const dictStore = useDictStore();
const dictData = dictStore.getDictByType('dict_type_key');

File Uploads

Media files are uploaded via src/services/infra/file/index.ts or src/services/infra/media/index.ts. Use the Upload components which handle the API integration.

Testing

  • Jest configured with jest.config.ts
  • Test files should be colocated with components or in __tests__ directories
  • Run single test: pnpm test -- path/to/test.spec.ts

Important Notes

  • Node version: Requires Node.js >= 20.0.0 (see package.json engines)
  • React 19: Uses React 19 with @ant-design/v5-patch-for-react-19 compatibility patch
  • Mako bundler: Uses UmiJS Mako for faster builds (configured in config/config.ts)
  • Mock data: Located in mock/ directory, enabled by default in dev mode
  • TinyMCE: Static files in public/tinymce/, Chinese language pack included