fix: 修复 HomeClient 和 ProductListItem 类型兼容性问题
This commit is contained in:
parent
8a88fcde10
commit
144a5fc944
@ -10,19 +10,53 @@ import { useDebounce } from '@/hooks/usePerformance'
|
||||
|
||||
type TabType = 'models' | 'hardware' | 'bom' | 'docs'
|
||||
|
||||
// 产品 SKU 类型(与 ProductListItem 兼容)
|
||||
interface ProductSku {
|
||||
id: string
|
||||
skuCode: string
|
||||
price: number
|
||||
stock: number
|
||||
isActive: boolean
|
||||
name?: string | null
|
||||
}
|
||||
|
||||
// 产品类型(与 ProductListItem 兼容)
|
||||
interface ProductWithSkus {
|
||||
id: string
|
||||
name: string
|
||||
modelNumber: string
|
||||
description?: string | null
|
||||
category: string | null
|
||||
modelUrl?: string | null
|
||||
thumbnailUrl?: string | null
|
||||
visibility?: 'TEAM' | 'DEPARTMENT' | 'PUBLIC'
|
||||
skus: ProductSku[]
|
||||
createdAt: Date | string
|
||||
updatedAt?: Date | string
|
||||
_count: {
|
||||
assemblySteps: number
|
||||
shareLinks: number
|
||||
skus: number
|
||||
}
|
||||
shareLinks: Array<{
|
||||
token: string
|
||||
viewCount: number
|
||||
}>
|
||||
}
|
||||
|
||||
interface HomeClientProps {
|
||||
products: any[]
|
||||
products: ProductWithSkus[]
|
||||
}
|
||||
|
||||
export default function HomeClient({ products: initialProducts }: HomeClientProps) {
|
||||
const [activeTab, setActiveTab] = useState<TabType>('models')
|
||||
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false)
|
||||
const [products, setProducts] = useState(initialProducts)
|
||||
const [products, setProducts] = useState<ProductWithSkus[]>(initialProducts)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
// 控制“新建型号”弹窗
|
||||
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false)
|
||||
// 控制“编辑产品”弹窗以及当前要编辑的产品
|
||||
const [editingProduct, setEditingProduct] = useState<any | null>(null)
|
||||
const [editingProduct, setEditingProduct] = useState<ProductWithSkus | null>(null)
|
||||
// 新建型号表单状态
|
||||
const [newModelNumber, setNewModelNumber] = useState('')
|
||||
const [newName, setNewName] = useState('')
|
||||
@ -77,12 +111,12 @@ export default function HomeClient({ products: initialProducts }: HomeClientProp
|
||||
|
||||
const query = raw.toLowerCase()
|
||||
|
||||
return products.filter((product: any) => {
|
||||
return products.filter((product) => {
|
||||
const inModelNumber = product.modelNumber?.toLowerCase().includes(query)
|
||||
const inName = product.name?.toLowerCase().includes(query)
|
||||
const inDescription = product.description?.toLowerCase().includes(query)
|
||||
const inSkuCodes = Array.isArray(product.skus)
|
||||
? product.skus.some((sku: any) =>
|
||||
? product.skus.some((sku) =>
|
||||
sku.skuCode?.toLowerCase().includes(query)
|
||||
)
|
||||
: false
|
||||
@ -174,7 +208,7 @@ export default function HomeClient({ products: initialProducts }: HomeClientProp
|
||||
}, [newModelNumber, newName, newCategory, newDescription, newVisibility, reloadProducts])
|
||||
|
||||
// 打开“编辑产品”弹窗,并根据当前产品初始化表单
|
||||
const handleOpenEditProduct = useCallback((product: any) => {
|
||||
const handleOpenEditProduct = useCallback((product: ProductWithSkus) => {
|
||||
setEditingProduct(product)
|
||||
setEditName(product.name || '')
|
||||
setEditCategory(product.category || '')
|
||||
@ -734,7 +768,7 @@ interface TabCardProps {
|
||||
id: TabType
|
||||
name: string
|
||||
description: string
|
||||
icon: any
|
||||
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>
|
||||
}
|
||||
isActive: boolean
|
||||
onClick: (tabId: TabType) => void
|
||||
|
||||
@ -68,6 +68,7 @@ export default async function HomePage() {
|
||||
// 手动计算 count 并转换 Decimal 类型
|
||||
const productsWithCount = products.map(product => ({
|
||||
...product,
|
||||
visibility: product.visibility as 'TEAM' | 'DEPARTMENT' | 'PUBLIC',
|
||||
skus: product.skus.map(sku => ({
|
||||
...sku,
|
||||
price: sku.price.toNumber() // 将 Prisma Decimal 转换为 number
|
||||
|
||||
@ -9,16 +9,15 @@
|
||||
* - 使用 useMemo 缓存计算结果
|
||||
*
|
||||
* @created 2025-12-12
|
||||
* @updated 2025-12-13 - 性能优化
|
||||
* @updated 2025-12-22 - 修复类型兼容性
|
||||
*/
|
||||
|
||||
'use client'
|
||||
|
||||
import React, { memo, useCallback, useMemo } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { ChevronDown, ChevronRight, Package, Eye, User } from 'lucide-react'
|
||||
import { ChevronDown, ChevronRight, Package, User } from 'lucide-react'
|
||||
import Badge from '@/components/ui/Badge'
|
||||
import Image from 'next/image'
|
||||
|
||||
// 产品列表项组件的入参类型
|
||||
interface ProductListItemProps {
|
||||
@ -27,7 +26,10 @@ interface ProductListItemProps {
|
||||
name: string
|
||||
modelNumber: string
|
||||
category: string | null
|
||||
createdAt: Date
|
||||
createdAt: Date | string
|
||||
updatedAt?: Date | string
|
||||
description?: string | null
|
||||
visibility?: 'TEAM' | 'DEPARTMENT' | 'PUBLIC'
|
||||
_count: {
|
||||
assemblySteps: number
|
||||
shareLinks: number
|
||||
@ -45,8 +47,9 @@ interface ProductListItemProps {
|
||||
isActive: boolean
|
||||
}>
|
||||
}
|
||||
// 当点击“编辑产品”按钮时触发,由父组件控制弹窗
|
||||
onEdit?: (product: ProductListItemProps['product']) => void
|
||||
// 当点击"编辑产品"按钮时触发,由父组件控制弹窗
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onEdit?: (product: any) => void
|
||||
}
|
||||
|
||||
const ProductListItem = memo(function ProductListItem({ product, onEdit }: ProductListItemProps) {
|
||||
@ -142,7 +145,6 @@ const ProductListItem = memo(function ProductListItem({ product, onEdit }: Produ
|
||||
color: 'var(--color-label-primary)',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
// 交给父组件决定如何编辑(弹窗形式)
|
||||
onClick={() => onEdit?.(product)}
|
||||
>
|
||||
编辑产品
|
||||
@ -205,7 +207,7 @@ const ProductListItem = memo(function ProductListItem({ product, onEdit }: Produ
|
||||
{sku.isActive ? '已上架' : '未上架'}
|
||||
</Badge>
|
||||
|
||||
{/* SKU 预览按钮 - 去掉图标 */}
|
||||
{/* SKU 预览按钮 */}
|
||||
{shareLink && (
|
||||
<Link href={`/share/${shareLink.token}?sku=${sku.id}`}>
|
||||
<button
|
||||
@ -222,7 +224,7 @@ const ProductListItem = memo(function ProductListItem({ product, onEdit }: Produ
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{/* SKU 编辑按钮 - 改名为编辑模型 */}
|
||||
{/* SKU 编辑按钮 */}
|
||||
<button
|
||||
className="px-4 py-2 rounded-apple-md transition-all text-sm font-medium"
|
||||
style={{
|
||||
|
||||
@ -57,6 +57,7 @@ describe('HomeClient 组件测试', () => {
|
||||
description: '这是测试产品1的描述',
|
||||
category: '家具',
|
||||
createdAt: new Date('2025-01-01'),
|
||||
updatedAt: new Date('2025-01-01'),
|
||||
_count: {
|
||||
assemblySteps: 5,
|
||||
shareLinks: 1,
|
||||
@ -75,6 +76,7 @@ describe('HomeClient 组件测试', () => {
|
||||
description: '这是测试产品2的描述',
|
||||
category: '家具',
|
||||
createdAt: new Date('2025-01-02'),
|
||||
updatedAt: new Date('2025-01-02'),
|
||||
_count: {
|
||||
assemblySteps: 3,
|
||||
shareLinks: 0,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user