gongxiangp2/hooks/useHomeState.ts

338 lines
10 KiB
TypeScript

/**
* 首页状态管理 Hook
* 提取自 app/page.tsx 的状态管理逻辑
*/
import { useState, useCallback, useRef, useEffect } from 'react'
// 素材类型定义
export interface Material {
id: string
userId: string
previewUrl: string
productModel: string
categoryName: string
sceneName: string
platformName?: string
productCategoryName?: string
materialType: string
renderer: string
authorName: string
zipFileName: string
zipFileSize: string | number
downloadCount: number
likeCount: number
isLiked: boolean
isFavorited: boolean
createdAt: string
displayImages?: string[]
videoSourceUrl?: string | null
videoPreview540Url?: string | null
videoPreviewClipUrl?: string | null
videoCoverUrl?: string | null
videoProcessingStatus?: string | null
videoDuration?: number | null
transcodeLastError?: string | null
transcodeAttempts?: number | null
transcodeProgress?: number | null
transcodeStage?: string | null
transcodeQueueWaitingIndex?: number | null
transcodeQueueWaitingTotal?: number | null
transcodeQueueProcessingIds?: string[]
transcodeQueueMaxConcurrent?: number | null
user: {
username: string
avatar?: string | null
}
}
// 分类项类型
export interface CategoryItem {
id: string
name: string
count: number
}
// 月份项类型
export interface MonthItem {
value: string
label: string
count: number
}
// 默认素材类型列表(已分类排序)
export const DEFAULT_MATERIAL_TYPES = [
// 3D相关
'3D场景',
'材质',
'标准模型',
'标准饰品',
// 图片相关
'详情模板',
'模特',
'实拍图片',
'买家秀图片',
// 视频相关
'主图视频',
'安装视频',
'种草视频',
// 模板和种草
'主图模版',
'SKU模版',
'小红书种草',
// 其他
'音乐',
'品牌VI灵感',
// 任务相关
'任务-详情',
'任务-3D原图',
'任务-AI原图',
'任务-实拍原图',
]
export interface UseHomeStateReturn {
// 素材数据
materials: Material[]
setMaterials: React.Dispatch<React.SetStateAction<Material[]>>
loading: boolean
setLoading: React.Dispatch<React.SetStateAction<boolean>>
isTransitionLoading: boolean
setIsTransitionLoading: React.Dispatch<React.SetStateAction<boolean>>
// 筛选状态
searchKeyword: string
setSearchKeyword: React.Dispatch<React.SetStateAction<string>>
selectedCategory: string
setSelectedCategory: React.Dispatch<React.SetStateAction<string>>
selectedScene: string
setSelectedScene: React.Dispatch<React.SetStateAction<string>>
selectedMaterialType: string
setSelectedMaterialType: React.Dispatch<React.SetStateAction<string>>
selectedPlatform: string
setSelectedPlatform: React.Dispatch<React.SetStateAction<string>>
selectedProductCategory: string
setSelectedProductCategory: React.Dispatch<React.SetStateAction<string>>
selectedMonth: string
setSelectedMonth: React.Dispatch<React.SetStateAction<string>>
// 排序状态
sortBy: string
setSortBy: React.Dispatch<React.SetStateAction<string>>
sortOrder: 'desc' | 'asc'
setSortOrder: React.Dispatch<React.SetStateAction<'desc' | 'asc'>>
// 分类数据
categories: CategoryItem[]
setCategories: React.Dispatch<React.SetStateAction<CategoryItem[]>>
scenes: CategoryItem[]
setScenes: React.Dispatch<React.SetStateAction<CategoryItem[]>>
platforms: CategoryItem[]
setPlatforms: React.Dispatch<React.SetStateAction<CategoryItem[]>>
productCategories: CategoryItem[]
setProductCategories: React.Dispatch<React.SetStateAction<CategoryItem[]>>
materialTypes: { value: string; label: string }[]
setMaterialTypes: React.Dispatch<React.SetStateAction<{ value: string; label: string }[]>>
months: MonthItem[]
setMonths: React.Dispatch<React.SetStateAction<MonthItem[]>>
// 分页状态
displayedCount: number
setDisplayedCount: React.Dispatch<React.SetStateAction<number>>
currentPage: number
setCurrentPage: React.Dispatch<React.SetStateAction<number>>
hasMore: boolean
setHasMore: React.Dispatch<React.SetStateAction<boolean>>
isLoadingMore: boolean
setIsLoadingMore: React.Dispatch<React.SetStateAction<boolean>>
totalMaterialsCount: number
setTotalMaterialsCount: React.Dispatch<React.SetStateAction<number>>
pageSize: number
// UI状态
isFilterCollapsed: boolean
setIsFilterCollapsed: React.Dispatch<React.SetStateAction<boolean>>
showUploadModal: boolean
setShowUploadModal: React.Dispatch<React.SetStateAction<boolean>>
themeColor: string
setThemeColor: React.Dispatch<React.SetStateAction<string>>
// 搜索防抖处理
handleSearchChange: (value: string) => void
searchDebounceRef: React.MutableRefObject<NodeJS.Timeout | null>
}
export function useHomeState(): UseHomeStateReturn {
// 素材数据
const [materials, setMaterials] = useState<Material[]>([])
const [loading, setLoading] = useState(true)
const [isTransitionLoading, setIsTransitionLoading] = useState(false)
// 筛选状态
const [searchKeyword, setSearchKeyword] = useState('')
const [selectedCategory, setSelectedCategory] = useState('')
const [selectedScene, setSelectedScene] = useState('')
const [selectedMaterialType, setSelectedMaterialType] = useState('3D场景')
const [selectedPlatform, setSelectedPlatform] = useState('')
const [selectedProductCategory, setSelectedProductCategory] = useState('')
const [selectedMonth, setSelectedMonth] = useState('')
// 排序状态
const [sortBy, setSortBy] = useState('createdAt')
const [sortOrder, setSortOrder] = useState<'desc' | 'asc'>('desc')
// 分类数据
const [categories, setCategories] = useState<CategoryItem[]>([])
const [scenes, setScenes] = useState<CategoryItem[]>([])
const [platforms, setPlatforms] = useState<CategoryItem[]>([])
const [productCategories, setProductCategories] = useState<CategoryItem[]>([])
const [materialTypes, setMaterialTypes] = useState<{ value: string; label: string }[]>([])
const [months, setMonths] = useState<MonthItem[]>([])
// 分页状态
const [displayedCount, setDisplayedCount] = useState(24)
const [currentPage, setCurrentPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
const [isLoadingMore, setIsLoadingMore] = useState(false)
const [totalMaterialsCount, setTotalMaterialsCount] = useState(0)
const pageSize = 20
// UI状态
const [isFilterCollapsed, setIsFilterCollapsed] = useState(true)
const [showUploadModal, setShowUploadModal] = useState(false)
const [themeColor, setThemeColor] = useState('#1f2937')
// 搜索防抖
const searchDebounceRef = useRef<NodeJS.Timeout | null>(null)
const fetchMaterialsRef = useRef<((page?: number, append?: boolean) => Promise<number>) | null>(null)
// 搜索防抖处理函数
const handleSearchChange = useCallback((value: string) => {
setSearchKeyword(value)
if (searchDebounceRef.current) {
clearTimeout(searchDebounceRef.current)
}
searchDebounceRef.current = setTimeout(() => {
console.log('[搜索防抖] 触发搜索:', value)
setCurrentPage(1)
setDisplayedCount(24)
setHasMore(true)
// 触发重新获取数据(通过依赖变化)
}, 500)
}, [])
// 从URL参数恢复筛选状态
useEffect(() => {
if (typeof window === 'undefined') return
const params = new URLSearchParams(window.location.search)
const materialType = params.get('materialType')
const category = params.get('category')
const scene = params.get('scene')
const platform = params.get('platform')
const productCategory = params.get('productCategory')
const month = params.get('month')
const sort = params.get('sortBy')
const sortOrderParam = params.get('sortOrder')
if (materialType) setSelectedMaterialType(materialType)
if (category) setSelectedCategory(category)
if (scene) setSelectedScene(scene)
if (platform) setSelectedPlatform(platform)
if (productCategory) setSelectedProductCategory(productCategory)
if (month) setSelectedMonth(month)
if (sort) setSortBy(sort)
if (sortOrderParam === 'asc' || sortOrderParam === 'desc') setSortOrder(sortOrderParam)
}, [])
// 同步筛选状态到URL参数
useEffect(() => {
if (typeof window === 'undefined') return
const params = new URLSearchParams()
if (selectedMaterialType && selectedMaterialType !== '3D场景') params.set('materialType', selectedMaterialType)
if (selectedCategory) params.set('category', selectedCategory)
if (selectedScene) params.set('scene', selectedScene)
if (selectedPlatform) params.set('platform', selectedPlatform)
if (selectedProductCategory) params.set('productCategory', selectedProductCategory)
if (selectedMonth) params.set('month', selectedMonth)
if (sortBy && sortBy !== 'createdAt') params.set('sortBy', sortBy)
if (sortOrder && sortOrder !== 'desc') params.set('sortOrder', sortOrder)
const newUrl = params.toString() ? `${window.location.pathname}?${params.toString()}` : window.location.pathname
window.history.replaceState({}, '', newUrl)
}, [selectedMaterialType, selectedCategory, selectedScene, selectedPlatform, selectedProductCategory, selectedMonth, sortBy, sortOrder])
return {
// 素材数据
materials,
setMaterials,
loading,
setLoading,
isTransitionLoading,
setIsTransitionLoading,
// 筛选状态
searchKeyword,
setSearchKeyword,
selectedCategory,
setSelectedCategory,
selectedScene,
setSelectedScene,
selectedMaterialType,
setSelectedMaterialType,
selectedPlatform,
setSelectedPlatform,
selectedProductCategory,
setSelectedProductCategory,
selectedMonth,
setSelectedMonth,
// 排序状态
sortBy,
setSortBy,
sortOrder,
setSortOrder,
// 分类数据
categories,
setCategories,
scenes,
setScenes,
platforms,
setPlatforms,
productCategories,
setProductCategories,
materialTypes,
setMaterialTypes,
months,
setMonths,
// 分页状态
displayedCount,
setDisplayedCount,
currentPage,
setCurrentPage,
hasMore,
setHasMore,
isLoadingMore,
setIsLoadingMore,
totalMaterialsCount,
setTotalMaterialsCount,
pageSize,
// UI状态
isFilterCollapsed,
setIsFilterCollapsed,
showUploadModal,
setShowUploadModal,
themeColor,
setThemeColor,
// 搜索防抖处理
handleSearchChange,
searchDebounceRef,
}
}