- 新增 admin/CLAUDE.md - 管理后台开发指导文档 - 修正技术栈为 React + TypeScript + shadcn/ui - 提供完整的管理后台架构设计 - 包含照片管理、分类管理、日志管理等核心功能 - 详细的开发环境配置和部署指南 - 新增 backend/CLAUDE.md - 后端开发指导文档 - 基于 Golang + Gin + GORM 技术栈 - 完整的 API 接口设计和数据库架构 - 包含认证、权限、文件存储等核心功能 - 详细的部署和监控配置 - 新增 ui/CLAUDE.md - UI 备份模块管理文档 - 支持组件备份和 A/B 测试功能 - 详细的同步策略和实验环境配置 - 完整的版本管理和协作流程 - 更新 CLAUDE.md 根目录文档 - 完善模块选择指南和协调机制 - 新增模块间通信和依赖关系说明 - 优化文档维护和使用建议 - 建立完整的模块化开发规范 通过模块化设计最大限度减少 AI 幻觉,提高开发效率。
690 lines
18 KiB
Markdown
690 lines
18 KiB
Markdown
# 管理后台模块 - CLAUDE.md
|
|
|
|
此文件为 Claude Code 在管理后台模块工作时提供指导。
|
|
|
|
## 🎯 模块概览
|
|
|
|
管理后台是摄影作品集项目的管理界面,用于内容管理、用户管理和系统配置。
|
|
|
|
### 功能特性
|
|
- 📸 照片管理:上传、编辑、删除照片
|
|
- 🏷️ 分类管理:相册分类、标签管理
|
|
- 👥 用户管理:用户权限、访问控制
|
|
- 📊 数据统计:访问统计、照片数据
|
|
- ⚙️ 系统配置:站点设置、主题配置
|
|
|
|
### 技术栈
|
|
- **前端**: React + TypeScript + Vite
|
|
- **组件**: shadcn/ui + Radix UI
|
|
- **状态管理**: Zustand / React Query
|
|
- **路由**: React Router
|
|
- **认证**: JWT Token
|
|
- **构建**: Vite + TypeScript
|
|
|
|
## 📁 目录结构
|
|
|
|
```
|
|
admin/
|
|
├── CLAUDE.md # 🔍 当前文件 - 管理后台指导
|
|
├── src/ # 源代码目录
|
|
│ ├── components/ # 组件目录
|
|
│ │ ├── ui/ # shadcn/ui 基础组件
|
|
│ │ ├── layout/ # 布局组件
|
|
│ │ ├── photo/ # 照片管理组件
|
|
│ │ ├── category/ # 分类管理组件
|
|
│ │ ├── logs/ # 日志管理组件
|
|
│ │ └── common/ # 通用组件
|
|
│ ├── pages/ # 页面组件
|
|
│ │ ├── dashboard/ # 仪表板
|
|
│ │ ├── photos/ # 照片管理
|
|
│ │ ├── categories/ # 分类管理
|
|
│ │ ├── logs/ # 日志管理
|
|
│ │ └── settings/ # 系统设置
|
|
│ ├── hooks/ # 自定义 Hooks
|
|
│ ├── services/ # API 服务
|
|
│ ├── store/ # 状态管理
|
|
│ ├── utils/ # 工具函数
|
|
│ └── types/ # TypeScript 类型定义
|
|
├── public/ # 静态资源
|
|
├── package.json # 项目配置
|
|
├── vite.config.ts # Vite 配置
|
|
├── tsconfig.json # TypeScript 配置
|
|
├── tailwind.config.js # Tailwind 配置
|
|
└── README.md # 模块说明
|
|
```
|
|
|
|
## 🚀 开发环境配置
|
|
|
|
### 环境要求
|
|
- **Node.js**: 18+
|
|
- **包管理器**: npm/yarn/pnpm
|
|
- **编辑器**: VS Code (推荐)
|
|
- **后端依赖**: Golang 后端 API 服务
|
|
|
|
### 初始化项目
|
|
```bash
|
|
# 进入管理后台目录
|
|
cd admin/
|
|
|
|
# 安装依赖
|
|
npm install
|
|
|
|
# 启动开发服务器
|
|
npm run dev
|
|
|
|
# 构建生产版本
|
|
npm run build
|
|
```
|
|
|
|
### 环境变量配置
|
|
```bash
|
|
# .env.development
|
|
VITE_APP_TITLE=摄影作品集管理后台
|
|
VITE_API_BASE_URL=http://localhost:8080/api
|
|
VITE_UPLOAD_URL=http://localhost:8080/api/upload
|
|
|
|
# .env.production
|
|
VITE_APP_TITLE=摄影作品集管理后台
|
|
VITE_API_BASE_URL=https://api.photography.iriver.top
|
|
VITE_UPLOAD_URL=https://api.photography.iriver.top/upload
|
|
```
|
|
|
|
## 🏗️ 项目架构
|
|
|
|
### 目录结构详解
|
|
|
|
#### 🧩 组件架构
|
|
```
|
|
src/components/
|
|
├── ui/ # shadcn/ui 基础组件
|
|
│ ├── button.tsx # 按钮组件
|
|
│ ├── input.tsx # 输入框组件
|
|
│ ├── table.tsx # 表格组件
|
|
│ ├── modal.tsx # 弹窗组件
|
|
│ ├── card.tsx # 卡片组件
|
|
│ └── form.tsx # 表单组件
|
|
├── layout/ # 布局组件
|
|
│ ├── header.tsx # 顶部导航
|
|
│ ├── sidebar.tsx # 侧边栏
|
|
│ └── main-layout.tsx # 主布局
|
|
├── photo/ # 照片管理组件
|
|
│ ├── photo-list.tsx # 照片列表
|
|
│ ├── photo-form.tsx # 照片表单
|
|
│ ├── photo-upload.tsx # 照片上传
|
|
│ └── photo-detail.tsx # 照片详情
|
|
├── category/ # 分类管理组件
|
|
│ ├── category-tree.tsx # 分类树
|
|
│ ├── category-form.tsx # 分类表单
|
|
│ └── category-stats.tsx # 分类统计
|
|
├── logs/ # 日志管理组件
|
|
│ ├── log-viewer.tsx # 日志查看器
|
|
│ ├── log-filter.tsx # 日志过滤器
|
|
│ └── log-detail.tsx # 日志详情
|
|
└── common/ # 通用组件
|
|
├── loading.tsx # 加载组件
|
|
├── error-boundary.tsx # 错误边界
|
|
└── confirmation.tsx # 确认对话框
|
|
```
|
|
|
|
#### 📱 页面结构
|
|
```
|
|
src/pages/
|
|
├── dashboard/ # 仪表板
|
|
│ └── index.tsx # 首页
|
|
├── photos/ # 照片管理
|
|
│ ├── index.tsx # 照片列表
|
|
│ ├── edit.tsx # 照片编辑
|
|
│ └── upload.tsx # 照片上传
|
|
├── categories/ # 分类管理
|
|
│ └── index.tsx # 分类管理
|
|
├── tags/ # 标签管理
|
|
│ └── index.tsx # 标签管理
|
|
├── logs/ # 日志管理
|
|
│ ├── index.tsx # 日志列表
|
|
│ └── detail.tsx # 日志详情
|
|
└── settings/ # 系统设置
|
|
└── index.tsx # 系统设置
|
|
```
|
|
|
|
#### 🔄 状态管理
|
|
```
|
|
src/store/
|
|
├── auth.ts # 认证状态 (Zustand)
|
|
├── photo.ts # 照片状态
|
|
├── logs.ts # 日志状态
|
|
└── ui.ts # UI 状态
|
|
|
|
src/hooks/
|
|
├── useAuth.ts # 认证 Hook
|
|
├── usePhotos.ts # 照片数据 (React Query)
|
|
├── useCategories.ts # 分类数据
|
|
├── useLogs.ts # 日志数据
|
|
└── useUpload.ts # 上传功能
|
|
```
|
|
|
|
## 🔌 API 集成
|
|
|
|
### API 接口规范
|
|
```typescript
|
|
// src/services/photo.ts
|
|
interface PhotoAPI {
|
|
// 获取照片列表
|
|
getPhotos(params: PhotoListParams): Promise<PhotoListResponse>
|
|
|
|
// 上传照片
|
|
uploadPhoto(file: File, metadata: PhotoMetadata): Promise<Photo>
|
|
|
|
// 更新照片信息
|
|
updatePhoto(id: string, data: PhotoUpdateData): Promise<Photo>
|
|
|
|
// 删除照片
|
|
deletePhoto(id: string): Promise<void>
|
|
|
|
// 批量操作
|
|
batchUpdatePhotos(ids: string[], data: Partial<Photo>): Promise<void>
|
|
}
|
|
|
|
// src/services/category.ts
|
|
interface CategoryAPI {
|
|
getCategories(): Promise<Category[]>
|
|
getCategoryTree(): Promise<CategoryTree[]>
|
|
createCategory(data: CategoryCreateData): Promise<Category>
|
|
updateCategory(id: string, data: CategoryUpdateData): Promise<Category>
|
|
deleteCategory(id: string): Promise<void>
|
|
}
|
|
|
|
// src/services/logs.ts
|
|
interface LogsAPI {
|
|
getLogs(params: LogListParams): Promise<LogListResponse>
|
|
getLogDetail(traceId: string): Promise<LogDetail>
|
|
getLogStats(): Promise<LogStats>
|
|
}
|
|
```
|
|
|
|
### 数据类型定义
|
|
```typescript
|
|
// src/types/photo.ts
|
|
interface Photo {
|
|
id: string
|
|
title: string
|
|
description: string
|
|
originalFilename: string
|
|
fileSize: number
|
|
status: 'processing' | 'published' | 'draft' | 'archived'
|
|
categories: Category[]
|
|
tags: Tag[]
|
|
formats: PhotoFormat[]
|
|
camera?: string
|
|
lens?: string
|
|
iso?: number
|
|
aperture?: string
|
|
shutterSpeed?: string
|
|
focalLength?: string
|
|
takenAt?: string
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
// src/types/category.ts
|
|
interface Category {
|
|
id: string
|
|
name: string
|
|
slug: string
|
|
description: string
|
|
parentId?: string
|
|
sortOrder: number
|
|
isActive: boolean
|
|
photoCount: number
|
|
createdAt: string
|
|
updatedAt: string
|
|
}
|
|
|
|
// src/types/logs.ts
|
|
interface LogEntry {
|
|
id: string
|
|
timestamp: string
|
|
level: 'error' | 'warn' | 'info' | 'debug'
|
|
message: string
|
|
traceId: string
|
|
userId?: string
|
|
action?: string
|
|
details?: Record<string, any>
|
|
}
|
|
```
|
|
|
|
## 🎨 UI 设计规范
|
|
|
|
### 设计原则
|
|
- **一致性**: 保持界面元素的一致性
|
|
- **易用性**: 简洁直观的操作流程
|
|
- **响应式**: 适配不同屏幕尺寸
|
|
- **可访问性**: 支持键盘导航和屏幕阅读器
|
|
|
|
### 主题配置
|
|
```typescript
|
|
// tailwind.config.js
|
|
module.exports = {
|
|
content: ['./src/**/*.{ts,tsx}'],
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: {
|
|
DEFAULT: '#d4af37',
|
|
50: '#fefce8',
|
|
500: '#d4af37',
|
|
900: '#713f12'
|
|
},
|
|
border: 'hsl(var(--border))',
|
|
background: 'hsl(var(--background))',
|
|
foreground: 'hsl(var(--foreground))',
|
|
muted: 'hsl(var(--muted))',
|
|
'muted-foreground': 'hsl(var(--muted-foreground))'
|
|
},
|
|
fontFamily: {
|
|
sans: ['Inter', 'system-ui', 'sans-serif']
|
|
}
|
|
}
|
|
},
|
|
plugins: [require('tailwindcss-animate')]
|
|
}
|
|
|
|
// src/lib/utils.ts
|
|
import { clsx, type ClassValue } from 'clsx'
|
|
import { twMerge } from 'tailwind-merge'
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs))
|
|
}
|
|
```
|
|
|
|
## 🔐 权限管理
|
|
|
|
### 角色权限设计
|
|
```typescript
|
|
// src/types/permission.ts
|
|
interface Permission {
|
|
id: string
|
|
name: string
|
|
code: string
|
|
description: string
|
|
}
|
|
|
|
interface Role {
|
|
id: string
|
|
name: string
|
|
permissions: Permission[]
|
|
}
|
|
|
|
interface User {
|
|
id: string
|
|
username: string
|
|
email: string
|
|
role: Role
|
|
isActive: boolean
|
|
}
|
|
```
|
|
|
|
### 路由保护
|
|
```typescript
|
|
// src/components/auth/ProtectedRoute.tsx
|
|
import { useAuth } from '@/hooks/useAuth'
|
|
import { Navigate, useLocation } from 'react-router-dom'
|
|
|
|
interface ProtectedRouteProps {
|
|
children: React.ReactNode
|
|
requiredRole?: string
|
|
}
|
|
|
|
export function ProtectedRoute({ children, requiredRole }: ProtectedRouteProps) {
|
|
const { user, isLoading } = useAuth()
|
|
const location = useLocation()
|
|
|
|
if (isLoading) {
|
|
return <div>Loading...</div>
|
|
}
|
|
|
|
if (!user) {
|
|
return <Navigate to="/login" state={{ from: location }} replace />
|
|
}
|
|
|
|
if (requiredRole && user.role !== requiredRole) {
|
|
return <Navigate to="/403" replace />
|
|
}
|
|
|
|
return <>{children}</>
|
|
}
|
|
|
|
// src/hooks/useAuth.ts
|
|
import { create } from 'zustand'
|
|
import { persist } from 'zustand/middleware'
|
|
|
|
interface AuthState {
|
|
user: User | null
|
|
token: string | null
|
|
login: (token: string, user: User) => void
|
|
logout: () => void
|
|
isLoggedIn: boolean
|
|
}
|
|
|
|
export const useAuthStore = create<AuthState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
user: null,
|
|
token: null,
|
|
isLoggedIn: false,
|
|
login: (token, user) => set({ token, user, isLoggedIn: true }),
|
|
logout: () => set({ token: null, user: null, isLoggedIn: false })
|
|
}),
|
|
{ name: 'auth-storage' }
|
|
)
|
|
)
|
|
```
|
|
|
|
## 🚀 构建和部署
|
|
|
|
### 开发命令
|
|
```bash
|
|
# 安装依赖
|
|
npm install
|
|
|
|
# 启动开发服务器
|
|
npm run dev
|
|
|
|
# 类型检查
|
|
npm run type-check
|
|
|
|
# 代码检查
|
|
npm run lint
|
|
|
|
# 代码格式化
|
|
npm run format
|
|
|
|
# 构建生产版本
|
|
npm run build
|
|
|
|
# 预览构建结果
|
|
npm run preview
|
|
```
|
|
|
|
### 部署配置
|
|
```typescript
|
|
// vite.config.ts
|
|
import { defineConfig } from 'vite'
|
|
import react from '@vitejs/plugin-react'
|
|
import path from 'path'
|
|
|
|
export default defineConfig({
|
|
plugins: [react()],
|
|
resolve: {
|
|
alias: {
|
|
'@': path.resolve(__dirname, './src')
|
|
}
|
|
},
|
|
base: '/admin/', // 部署路径
|
|
build: {
|
|
outDir: 'dist',
|
|
assetsDir: 'static',
|
|
rollupOptions: {
|
|
output: {
|
|
manualChunks: {
|
|
'react-vendor': ['react', 'react-dom', 'react-router-dom'],
|
|
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-select'],
|
|
'utils-vendor': ['clsx', 'tailwind-merge', 'date-fns']
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
```
|
|
|
|
## 🔧 开发指南
|
|
|
|
### 代码规范
|
|
- 使用 TypeScript 进行类型约束
|
|
- 遵循 React Hooks 最佳实践
|
|
- 组件命名采用 PascalCase
|
|
- 文件命名采用 kebab-case
|
|
- 使用 ESLint + Prettier 进行代码格式化
|
|
|
|
### 组件开发
|
|
```tsx
|
|
// src/components/photo/photo-list.tsx
|
|
import { useState } from 'react'
|
|
import { usePhotos } from '@/hooks/usePhotos'
|
|
import { Button } from '@/components/ui/button'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { Badge } from '@/components/ui/badge'
|
|
|
|
interface PhotoListProps {
|
|
onPhotoSelect?: (photo: Photo) => void
|
|
}
|
|
|
|
export function PhotoList({ onPhotoSelect }: PhotoListProps) {
|
|
const [search, setSearch] = useState('')
|
|
const [page, setPage] = useState(1)
|
|
|
|
const { data: photosData, isLoading, error } = usePhotos({
|
|
search,
|
|
page,
|
|
limit: 20
|
|
})
|
|
|
|
if (isLoading) return <div>Loading...</div>
|
|
if (error) return <div>Error loading photos</div>
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{/* 搜索栏 */}
|
|
<div className="flex gap-4">
|
|
<Input
|
|
placeholder="搜索照片..."
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
className="max-w-sm"
|
|
/>
|
|
<Button>+ 上传照片</Button>
|
|
</div>
|
|
|
|
{/* 照片网格 */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{photosData?.photos.map((photo) => (
|
|
<Card
|
|
key={photo.id}
|
|
className="cursor-pointer hover:shadow-lg transition-shadow"
|
|
onClick={() => onPhotoSelect?.(photo)}
|
|
>
|
|
<CardHeader className="p-0">
|
|
<div className="aspect-square bg-gray-100 rounded-t-lg" />
|
|
</CardHeader>
|
|
<CardContent className="p-4">
|
|
<CardTitle className="text-sm truncate">{photo.title}</CardTitle>
|
|
<div className="flex gap-1 mt-2">
|
|
<Badge variant={photo.status === 'published' ? 'default' : 'secondary'}>
|
|
{photo.status}
|
|
</Badge>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### API 请求封装
|
|
```typescript
|
|
// src/services/api.ts
|
|
import axios from 'axios'
|
|
import { useAuthStore } from '@/store/auth'
|
|
import { toast } from 'sonner'
|
|
|
|
const api = axios.create({
|
|
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
timeout: 10000
|
|
})
|
|
|
|
// 请求拦截器
|
|
api.interceptors.request.use(
|
|
(config) => {
|
|
const { token } = useAuthStore.getState()
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`
|
|
}
|
|
return config
|
|
},
|
|
(error) => Promise.reject(error)
|
|
)
|
|
|
|
// 响应拦截器
|
|
api.interceptors.response.use(
|
|
(response) => response.data,
|
|
(error) => {
|
|
const message = error.response?.data?.message || '请求失败'
|
|
toast.error(message)
|
|
|
|
// 401 错误自动跳转登录
|
|
if (error.response?.status === 401) {
|
|
useAuthStore.getState().logout()
|
|
window.location.href = '/login'
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
}
|
|
)
|
|
|
|
export default api
|
|
|
|
// src/hooks/usePhotos.ts
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { photoService } from '@/services/photo'
|
|
|
|
export function usePhotos(params: PhotoListParams) {
|
|
return useQuery({
|
|
queryKey: ['photos', params],
|
|
queryFn: () => photoService.getPhotos(params)
|
|
})
|
|
}
|
|
|
|
export function useCreatePhoto() {
|
|
const queryClient = useQueryClient()
|
|
|
|
return useMutation({
|
|
mutationFn: photoService.createPhoto,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['photos'] })
|
|
toast.success('照片创建成功')
|
|
}
|
|
})
|
|
}
|
|
```
|
|
|
|
## 🔄 与其他模块的集成
|
|
|
|
### 与前端展示的关系
|
|
- 管理后台修改的数据通过 API 影响前端展示
|
|
- 照片和相册的增删改查直接影响用户访问体验
|
|
- 主题设置和配置修改需要前端重新获取
|
|
|
|
### 与后端 API 的关系
|
|
- 依赖后端提供的 REST API 接口
|
|
- 需要后端提供认证和权限控制
|
|
- 文件上传需要后端存储支持
|
|
|
|
### 与部署模块的关系
|
|
- 构建产物需要部署到 Web 服务器
|
|
- 需要配置反向代理到管理后台路径
|
|
- 与前端项目共享域名和 SSL 证书
|
|
|
|
## 🐛 问题排查
|
|
|
|
### 常见问题
|
|
1. **登录失败**: 检查 API 地址和 Token 存储
|
|
2. **图片上传失败**: 检查文件大小和格式限制
|
|
3. **权限错误**: 检查用户角色和权限配置
|
|
4. **页面空白**: 检查路由配置和组件导入
|
|
|
|
### 调试技巧
|
|
```bash
|
|
# 查看开发环境变量
|
|
npm run dev --debug
|
|
|
|
# 查看构建详情
|
|
npm run build --debug
|
|
|
|
# 分析构建产物
|
|
npm run analyze
|
|
```
|
|
|
|
## 📈 性能优化
|
|
|
|
### 代码分割
|
|
```typescript
|
|
// 路由懒加载
|
|
const PhotoList = () => import('@/views/photos/PhotoList.vue')
|
|
const AlbumList = () => import('@/views/albums/AlbumList.vue')
|
|
|
|
// 组件懒加载
|
|
const LazyComponent = defineAsyncComponent(() => import('./Component.vue'))
|
|
```
|
|
|
|
### 缓存策略
|
|
```typescript
|
|
// src/lib/query-client.ts
|
|
import { QueryClient } from '@tanstack/react-query'
|
|
|
|
export const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 5 * 60 * 1000, // 5分钟缓存
|
|
cacheTime: 10 * 60 * 1000, // 10分钟
|
|
refetchOnWindowFocus: false,
|
|
retry: (failureCount, error: any) => {
|
|
if (error?.response?.status === 404) return false
|
|
return failureCount < 3
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
// 使用示例
|
|
export function usePhotos(params: PhotoListParams) {
|
|
return useQuery({
|
|
queryKey: ['photos', params],
|
|
queryFn: () => photoService.getPhotos(params),
|
|
staleTime: 5 * 60 * 1000 // 5分钟缓存
|
|
})
|
|
}
|
|
```
|
|
|
|
## 🔮 未来规划
|
|
|
|
### 功能扩展
|
|
- 📊 高级数据分析和报表
|
|
- 🔄 批量操作和导入导出
|
|
- 📱 移动端管理应用
|
|
- 🎨 可视化主题编辑器
|
|
- 🔌 插件系统支持
|
|
|
|
### 技术升级
|
|
- 升级到 React 19 最新特性
|
|
- 引入 React Server Components
|
|
- 支持 PWA 离线访问
|
|
- 集成 AI 辅助功能
|
|
- 支持 Micro Frontend 架构
|
|
|
|
## 📚 参考资料
|
|
|
|
- [React 官方文档](https://react.dev/)
|
|
- [shadcn/ui 文档](https://ui.shadcn.com/)
|
|
- [Radix UI 文档](https://radix-ui.com/)
|
|
- [Tailwind CSS 文档](https://tailwindcss.com/)
|
|
- [React Query 文档](https://tanstack.com/query/)
|
|
- [Zustand 文档](https://zustand-demo.pmnd.rs/)
|
|
- [Vite 配置指南](https://vitejs.dev/)
|
|
- [TypeScript 最佳实践](https://www.typescriptlang.org/)
|
|
|
|
---
|
|
|
|
💡 **开发提示**: 在开始开发前,请确保已经阅读根目录的 CLAUDE.md 文件,了解项目整体架构和模块间的关系。开发过程中遇到问题,可以参考对应模块的 CLAUDE.md 文件寻找解决方案。 |