chenpei 0ce59be34e 备份:组织架构设计方案讨论前的代码快照
- 包含所有当前修改和新功能
- 准备开始组织架构优化实施方案
2025-12-30 13:20:26 +08:00

10 KiB
Raw Blame History

Design Document: 代码拆分重构

Overview

本设计文档描述如何将三个大型代码文件拆分为更小、更可维护的模块。采用 React 自定义 Hooks 和组件拆分的方式,遵循单一职责原则。

Architecture

components/
├── upload/                    # 上传相关组件(已有部分)
│   ├── UploadModal.tsx       # 主组件(重构后)
│   ├── UploadForm.tsx        # 新增:表单字段组件
│   ├── SpecialBatchUploadUI.tsx  # 新增:特殊批量上传UI
│   └── ... (已有文件保持不变)
├── admin/                     # 新增:管理后台组件
│   ├── UserManagement.tsx
│   ├── MaterialManagement.tsx
│   ├── CategoryManagement.tsx
│   ├── SystemSettings.tsx
│   └── AdminStats.tsx
└── home/                      # 新增:首页组件
    ├── FilterPanel.tsx
    ├── MaterialGrid.tsx
    ├── MaterialDetailModal.tsx
    ├── SearchBar.tsx
    └── Pagination.tsx

hooks/
├── useUploadState.ts         # 新增:上传状态管理
├── useCategoryData.ts        # 新增:分类数据获取
├── useBatchUpload.ts         # 新增:批量上传逻辑
├── useDragHandlers.ts        # 新增:拖拽处理
├── useAdminState.ts          # 新增:管理后台状态
├── useHomeState.ts           # 新增:首页状态
└── useMaterials.ts           # 新增:素材数据获取

Components and Interfaces

1. UploadModal 拆分

useUploadState Hook

// hooks/useUploadState.ts
interface UploadState {
  // 文件状态
  previewImages: File[]
  previewUrls: string[]
  displayImage: File | null
  displayImageUrl: string
  modelImages: File[]
  modelImageUrls: string[]
  zipFile: File | null
  
  // 表单状态
  productModel: string
  categoryName: string
  sceneName: string
  platformName: string
  productCategoryName: string
  materialType: string
  renderer: string
  
  // 上传状态
  uploading: boolean
  uploadProgress: number
  uploadSpeed: number
  isProcessing: boolean
  error: string
  
  // 批量上传状态
  batchFiles: BatchFileItem[]
  isBatchMode: boolean
  batchUploadStatus: BatchUploadStatus | null
}

export function useUploadState(): {
  state: UploadState
  actions: UploadStateActions
}

useCategoryData Hook

// hooks/useCategoryData.ts
interface CategoryData {
  categories: Array<{ id: string; name: string }>
  scenes: Array<{ id: string; name: string }>
  platforms: Array<{ id: string; name: string }>
  productCategories: Array<{ id: string; name: string }>
}

export function useCategoryData(): {
  data: CategoryData
  loading: boolean
  refresh: () => Promise<void>
}

useBatchUpload Hook

// hooks/useBatchUpload.ts
export function useBatchUpload(materialType: string): {
  // 特殊类型批量文件
  batchMusicFiles: Array<{ file: File; productModel: string }>
  batchVideoFiles: Array<{ file: File; productModel: string }>
  batch3DFiles: Array<{ file: File; productModel: string; previewImage?: File }>
  batchBrandVIFiles: Array<{ file: File; productModel: string }>
  batchBuyerShowFiles: Array<{ productModel: string; images: File[] }>
  batchXiaohongshuFiles: Array<{ productModel: string; images: File[] }>
  
  // 操作函数
  handleBatchFileSelect: (e: React.ChangeEvent<HTMLInputElement>) => void
  handleBatchMusicUpload: () => Promise<void>
  handleCancelBatchUpload: () => Promise<void>
  // ... 其他批量上传函数
}

useDragHandlers Hook

// hooks/useDragHandlers.ts
export function useDragHandlers(): {
  isDragging: boolean
  isPreviewDragging: boolean
  isDisplayImageDragging: boolean
  
  handleDragEnter: (e: React.DragEvent) => void
  handleDragLeave: (e: React.DragEvent) => void
  handleDragOver: (e: React.DragEvent) => void
  handleDrop: (e: React.DragEvent) => void
  handlePreviewDrop: (e: React.DragEvent) => void
  handleDisplayImageDrop: (e: React.DragEvent) => void
}

UploadForm Component

// components/upload/UploadForm.tsx
interface UploadFormProps {
  materialType: string
  productModel: string
  categoryName: string
  sceneName: string
  platformName: string
  productCategoryName: string
  renderer: string
  categories: Array<{ id: string; name: string }>
  scenes: Array<{ id: string; name: string }>
  platforms: Array<{ id: string; name: string }>
  productCategories: Array<{ id: string; name: string }>
  onProductModelChange: (value: string) => void
  onCategoryChange: (value: string) => void
  onSceneChange: (value: string) => void
  onPlatformChange: (value: string) => void
  onProductCategoryChange: (value: string) => void
  onRendererChange: (value: string) => void
  onAddCategory: (name: string) => Promise<void>
  onAddScene: (name: string) => Promise<void>
}

2. AdminPage 拆分

useAdminState Hook

// hooks/useAdminState.ts
interface AdminState {
  activeTab: 'materials' | 'users' | 'categories' | 'departments' | 'permissions' | 'superAdmins'
  materials: Material[]
  users: User[]
  categories: Category[]
  scenes: Scene[]
  platforms: Platform[]
  productCategories: ProductCategory[]
  loading: boolean
  // ... 其他状态
}

export function useAdminState(): {
  state: AdminState
  actions: AdminStateActions
}

Admin Components

// components/admin/UserManagement.tsx
interface UserManagementProps {
  users: User[]
  departments: Department[]
  onUpdateUser: (userId: string, data: Partial<User>) => Promise<void>
  onDeleteUser: (userId: string) => Promise<void>
}

// components/admin/MaterialManagement.tsx
interface MaterialManagementProps {
  materials: Material[]
  showRecycleBin: boolean
  onDelete: (ids: string[]) => Promise<void>
  onRestore: (ids: string[]) => Promise<void>
  onSearch: (keyword: string) => void
}

// components/admin/CategoryManagement.tsx
interface CategoryManagementProps {
  categories: Category[]
  scenes: Scene[]
  platforms: Platform[]
  productCategories: ProductCategory[]
  onAdd: (type: string, name: string) => Promise<void>
  onEdit: (type: string, id: string, name: string) => Promise<void>
  onDelete: (type: string, id: string) => Promise<void>
}

3. HomePage 拆分

useHomeState Hook

// hooks/useHomeState.ts
interface HomeState {
  searchKeyword: string
  selectedCategory: string
  selectedScene: string
  selectedMaterialType: string
  selectedPlatform: string
  selectedProductCategory: string
  selectedMonth: string
  sortBy: string
  sortOrder: 'asc' | 'desc'
  isFilterCollapsed: boolean
}

export function useHomeState(): {
  state: HomeState
  actions: HomeStateActions
}

useMaterials Hook

// hooks/useMaterials.ts
interface UseMaterialsOptions {
  searchKeyword: string
  selectedCategory: string
  selectedScene: string
  selectedMaterialType: string
  selectedPlatform: string
  selectedProductCategory: string
  selectedMonth: string
  sortBy: string
  sortOrder: 'asc' | 'desc'
}

export function useMaterials(options: UseMaterialsOptions): {
  materials: Material[]
  loading: boolean
  hasMore: boolean
  totalCount: number
  loadMore: () => Promise<void>
  refresh: () => Promise<void>
}

Home Components

// components/home/FilterPanel.tsx
interface FilterPanelProps {
  categories: Category[]
  scenes: Scene[]
  platforms: Platform[]
  productCategories: ProductCategory[]
  materialTypes: MaterialType[]
  months: Month[]
  selectedCategory: string
  selectedScene: string
  selectedMaterialType: string
  selectedPlatform: string
  selectedProductCategory: string
  selectedMonth: string
  sortBy: string
  sortOrder: 'asc' | 'desc'
  isCollapsed: boolean
  onCategoryChange: (value: string) => void
  onSceneChange: (value: string) => void
  onMaterialTypeChange: (value: string) => void
  onPlatformChange: (value: string) => void
  onProductCategoryChange: (value: string) => void
  onMonthChange: (value: string) => void
  onSortByChange: (value: string) => void
  onSortOrderChange: (value: 'asc' | 'desc') => void
  onToggleCollapse: () => void
}

// components/home/MaterialGrid.tsx
interface MaterialGridProps {
  materials: Material[]
  loading: boolean
  onMaterialClick: (material: Material) => void
  onDownload: (material: Material) => void
  onLike: (material: Material) => void
  onFavorite: (material: Material) => void
  onShare: (material: Material) => void
}

// components/home/SearchBar.tsx
interface SearchBarProps {
  value: string
  onChange: (value: string) => void
  placeholder?: string
}

// components/home/Pagination.tsx
interface PaginationProps {
  hasMore: boolean
  isLoading: boolean
  onLoadMore: () => void
}

Data Models

数据模型保持不变,继续使用现有的 Prisma 模型和 TypeScript 接口。

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

由于本次重构主要是代码组织优化,不涉及业务逻辑变更,因此主要通过以下方式验证正确性:

  1. 构建验证: 重构后代码能够成功通过 TypeScript 编译和 Next.js 构建
  2. 行数验证: 主文件行数符合目标要求
  3. 功能验证: 通过手动测试确保所有功能正常工作

Error Handling

  • 拆分后的 Hooks 和组件应保持原有的错误处理逻辑
  • 新增的 Hooks 应提供统一的错误状态和错误处理回调
  • 组件间通过 props 传递错误信息,保持错误边界清晰

Testing Strategy

验证方式

  1. TypeScript 类型检查: 运行 npx tsc --noEmit 确保无类型错误
  2. ESLint 检查: 运行 npm run lint 确保代码风格一致
  3. 构建测试: 运行 npm run build 确保能够成功构建
  4. 手动功能测试:
    • 测试上传弹窗的所有上传类型
    • 测试管理后台的所有功能标签页
    • 测试首页的筛选、搜索、分页功能

回归测试清单

  • 单个文件上传(各种素材类型)
  • 批量文件上传(音乐、视频、3D场景等)
  • 拖拽上传
  • 分类/场景/平台筛选
  • 搜索功能
  • 分页加载
  • 用户管理
  • 素材管理(删除、恢复)
  • 分类管理(增删改)