This commit is contained in:
parent
3ad86524d4
commit
cccbe20aa0
|
|
@ -1,3 +1,5 @@
|
|||
import { ThumbnailCell as ThumbnailCell_a0b2acb813359aec894b6644d7c3bfd2 } from '../../../components/products/ThumbnailCell'
|
||||
import { ThumbnailAndStatusField as ThumbnailAndStatusField_8fa95ec6265982d11b99fbeb81e24c1c } from '../../../components/products/ThumbnailAndStatusField'
|
||||
import { SyncMedusaButton as SyncMedusaButton_8c90663551920f0510ea531726668adc } from '../../../components/products/SyncMedusaButton'
|
||||
import { default as default_3fd1353246fc8a459244c8dc11f58470 } from '../../../components/products/ProductGridStyler'
|
||||
import { ForceSyncButton as ForceSyncButton_86f9d5df4f20495427521354d06db618 } from '../../../components/products/ForceSyncButton'
|
||||
|
|
@ -5,6 +7,8 @@ import { S3ClientUploadHandler as S3ClientUploadHandler_f97aa6c64367fa259c5bc056
|
|||
import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from '@payloadcms/next/rsc'
|
||||
|
||||
export const importMap = {
|
||||
"/components/products/ThumbnailCell#ThumbnailCell": ThumbnailCell_a0b2acb813359aec894b6644d7c3bfd2,
|
||||
"/components/products/ThumbnailAndStatusField#ThumbnailAndStatusField": ThumbnailAndStatusField_8fa95ec6265982d11b99fbeb81e24c1c,
|
||||
"/components/products/SyncMedusaButton#SyncMedusaButton": SyncMedusaButton_8c90663551920f0510ea531726668adc,
|
||||
"/components/products/ProductGridStyler#default": default_3fd1353246fc8a459244c8dc11f58470,
|
||||
"/components/products/ForceSyncButton#ForceSyncButton": ForceSyncButton_86f9d5df4f20495427521354d06db618,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export const Products: CollectionConfig = {
|
|||
description: '管理 Medusa 商品的详细内容和描述',
|
||||
listSearchableFields: ['title', 'medusaId', 'handle'],
|
||||
pagination: {
|
||||
defaultLimit: 48,
|
||||
defaultLimit: 25,
|
||||
},
|
||||
components: {
|
||||
edit: {
|
||||
|
|
@ -57,6 +57,10 @@ export const Products: CollectionConfig = {
|
|||
admin: {
|
||||
description: '商品缩略图 URL(从 Medusa 同步)',
|
||||
readOnly: true,
|
||||
components: {
|
||||
Cell: '/components/products/ThumbnailCell#ThumbnailCell',
|
||||
Field: '/components/products/ThumbnailAndStatusField#ThumbnailAndStatusField',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
'use client'
|
||||
import type { SelectFieldClientComponent } from 'payload'
|
||||
|
||||
// 隐藏字段(因为在ThumbnailAndStatusField中已经显示和编辑)
|
||||
export const HiddenField: SelectFieldClientComponent = () => {
|
||||
return null
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
'use client'
|
||||
import { useFormFields, useField } from '@payloadcms/ui'
|
||||
import type { TextFieldClientComponent } from 'payload'
|
||||
|
||||
// 并排显示缩略图和状态(带状态选择器)
|
||||
export const ThumbnailAndStatusField: TextFieldClientComponent = ({ path }) => {
|
||||
// 获取thumbnail值
|
||||
const fields = useFormFields(([fields]) => fields)
|
||||
const thumbnail = fields.thumbnail?.value
|
||||
|
||||
// 获取status字段的值和setter
|
||||
const { value: status, setValue: setStatus } = useField({ path: 'status' })
|
||||
|
||||
const isImage = typeof thumbnail === 'string' && thumbnail.match(/^https?:\/\/.+/)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label style={{ display: 'block', marginBottom: 8, fontWeight: 500 }}>商品缩略图和状态</label>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 16 }}>
|
||||
<div
|
||||
style={{
|
||||
width: 100,
|
||||
height: 100,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 8,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{isImage ? (
|
||||
<img
|
||||
src={thumbnail}
|
||||
alt="商品缩略图"
|
||||
style={{ maxWidth: '100%', maxHeight: '100%', borderRadius: 6 }}
|
||||
/>
|
||||
) : (
|
||||
<span style={{ color: '#bbb' }}>无图片</span>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<label style={{ display: 'block', marginBottom: 4, fontSize: 14 }}>状态</label>
|
||||
<select
|
||||
value={(status as string) || 'draft'}
|
||||
onChange={(e) => setStatus(e.target.value)}
|
||||
style={{
|
||||
padding: '8px 12px',
|
||||
borderRadius: 4,
|
||||
fontSize: 14,
|
||||
minWidth: 120,
|
||||
}}
|
||||
>
|
||||
<option value="draft">草稿</option>
|
||||
<option value="published">已发布</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
'use client'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const ThumbnailCell = (props: any) => {
|
||||
console.log('=== ThumbnailCell All Props ===', props)
|
||||
console.log('Props keys:', Object.keys(props))
|
||||
|
||||
// 尝试从不同的 props 路径获取值
|
||||
const value = props.value || props.cellData || props.data
|
||||
const rowData = props.rowData || props.row
|
||||
|
||||
console.log('Extracted value:', value)
|
||||
console.log('Extracted rowData:', rowData)
|
||||
|
||||
const isImage = typeof value === 'string' && value.match(/^https?:\/\/.+/)
|
||||
const editUrl = `/admin/collections/products/${rowData?.id || ''}`
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={editUrl}
|
||||
style={{ display: 'block', width: '100%', height: '200px', textDecoration: 'none' }}
|
||||
>
|
||||
{isImage ? (
|
||||
<img src={value} alt="商品缩略图" className="thumbnail-img" />
|
||||
) : (
|
||||
<div className="no-image">{value || '无图片'}</div>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
|
@ -27,11 +27,14 @@
|
|||
transition: all 0.2s ease-in-out !important;
|
||||
height: 100% !important;
|
||||
min-height: 320px;
|
||||
cursor: pointer;
|
||||
text-decoration: none !important;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.1);
|
||||
border-color: var(--theme-elevation-300) !important;
|
||||
background: var(--theme-elevation-100) !important;
|
||||
}
|
||||
|
||||
td {
|
||||
|
|
@ -59,8 +62,6 @@
|
|||
}
|
||||
|
||||
// 2. Thumbnail (First content column)
|
||||
// We depend on 'thumbnail' being the first custom column in Products.ts
|
||||
// Note: td:nth-child(2) because checkbox is #1
|
||||
&:nth-child(2) {
|
||||
padding: 0 !important;
|
||||
height: 200px !important;
|
||||
|
|
@ -69,27 +70,23 @@
|
|||
background: var(--theme-elevation-100) !important;
|
||||
order: -1 !important; // Force to top
|
||||
flex-grow: 0 !important;
|
||||
|
||||
// Support for Payload's file cell or specific image structures
|
||||
.file-cell, .thumbnail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
object-fit: cover !important;
|
||||
display: block !important;
|
||||
background: var(--theme-elevation-100);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback purely text content in that cell
|
||||
span {
|
||||
.no-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
color: var(--theme-elevation-400);
|
||||
font-size: 0.8rem;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue