基类化

This commit is contained in:
龟男日记\www 2026-02-20 22:01:23 +08:00
parent 35928a6144
commit dae1b2704f
7 changed files with 533 additions and 368 deletions

View File

@ -126,14 +126,14 @@ export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const medusaId = searchParams.get('medusaId')
const payloadId = searchParams.get('payloadId')
const collection = searchParams.get('collection')
const collection = searchParams.get('collection') as 'products' | 'preorder-products' | null
const forceUpdate = searchParams.get('forceUpdate') === 'true'
const payload = await getPayload({ config })
// 同步单个商品(通过 Medusa ID
if (medusaId) {
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate)
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate, collection || undefined)
return NextResponse.json(result)
}
@ -166,13 +166,22 @@ export async function GET(request: Request) {
/**
* Medusa ID
*/
async function syncSingleProductByMedusaId(payload: any, medusaId: string, forceUpdate: boolean) {
async function syncSingleProductByMedusaId(
payload: any,
medusaId: string,
forceUpdate: boolean,
preferredCollection?: 'products' | 'preorder-products'
) {
console.log(`[Sync API] 🔄 开始同步产品: ${medusaId}`)
console.log(`[Sync API] ⚙️ forceUpdate: ${forceUpdate}, preferredCollection: ${preferredCollection || 'auto'}`)
try {
// 从 Medusa 获取商品数据
const medusaProducts = await getAllMedusaProducts()
const medusaProduct = medusaProducts.find((p) => p.id === medusaId)
if (!medusaProduct) {
console.error(`[Sync API] ❌ Medusa 中未找到商品: ${medusaId}`)
return {
success: false,
action: 'not_found',
@ -180,20 +189,27 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
}
}
// 确定应该同步到哪个 collection
const targetCollection = getProductCollection(medusaProduct)
console.log(`[Sync API] ✅ 找到 Medusa 产品: ${medusaProduct.title}`)
// 确定应该同步到哪个 collection优先使用传入的 collection否则自动判断
const targetCollection = preferredCollection || getProductCollection(medusaProduct)
console.log(`[Sync API] 🎯 目标 collection: ${targetCollection}${preferredCollection ? ' (指定)' : ' (自动判断)'}`)
const otherCollection =
targetCollection === 'preorder-products' ? 'products' : 'preorder-products'
// 转换数据
const productData = transformMedusaProductToPayload(medusaProduct)
const seedId = productData.seedId
console.log(`[Sync API] 📦 产品数据: title=${productData.title}, seedId=${seedId}`)
// 使用新的查找函数(优先 seedId
const found = await findProductBySeedIdOrMedusaId(payload, seedId, medusaId)
// 如果在另一个 collection 中找到,需要移动
if (found && found.collection !== targetCollection) {
console.log(`[Sync API] 🚚 需要移动: ${found.collection} -> ${targetCollection}`)
await payload.delete({
collection: found.collection,
id: found.product.id,
@ -204,6 +220,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
data: productData,
})
console.log(`[Sync API] ✅ 移动成功, 新 ID: ${created.id}`)
return {
success: true,
action: 'moved',
@ -215,16 +232,19 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
// 如果在目标 collection 中找到
if (found) {
console.log(`[Sync API] 🔎 在 ${found.collection} 中找到现有产品, ID: ${found.product.id}`)
const existingProduct = found.product
// 如果存在且不强制更新,只更新空字段
if (!forceUpdate) {
// 合并数据(只更新空字段)
console.log(`[Sync API] 🔄 模式: 只填充空字段`)
// 合并数据(只曹新空字段)
const mergedData = mergeProductData(existingProduct, productData, false)
// 如果没有需要更新的字段,跳过
if (Object.keys(mergedData).length <= 2) {
// 只有 lastSyncedAt 和 medusaId
console.log(`[Sync API] ⏭️ 跳过: 所有字段都有值`)
return {
success: true,
action: 'skipped',
@ -234,6 +254,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
}
}
console.log(`[Sync API] 📝 更新字段: ${Object.keys(mergedData).join(', ')}`)
// 更新(只更新空字段)
const updated = await payload.update({
collection: targetCollection,
@ -241,6 +262,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
data: mergedData,
})
console.log(`[Sync API] ✅ 部分更新成功`)
return {
success: true,
action: 'updated_partial',
@ -250,6 +272,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
}
}
console.log(`[Sync API] ⚡ 模式: 强制更新所有字段`)
// 强制更新所有字段
const updated = await payload.update({
collection: targetCollection,
@ -257,6 +280,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
data: productData,
})
console.log(`[Sync API] ✅ 强制更新成功`)
return {
success: true,
action: 'updated',
@ -266,12 +290,14 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
}
}
console.log(`[Sync API] ✨ 创建新产品`)
// 不存在,创建新商品
const created = await payload.create({
collection: targetCollection,
data: productData,
})
console.log(`[Sync API] ✅ 创建成功, ID: ${created.id}`)
return {
success: true,
action: 'created',
@ -280,7 +306,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
collection: targetCollection,
}
} catch (error) {
console.error(`Error syncing product ${medusaId}:`, error)
console.error(`[Sync API] ❌ 同步失败:`, error)
return {
success: false,
action: 'error',
@ -344,8 +370,8 @@ async function syncSingleProductByPayloadId(
}
}
// 使用 medusaId 同步
return await syncSingleProductByMedusaId(payload, product.medusaId, forceUpdate)
// 使用 medusaId 同步(保持在当前 collection
return await syncSingleProductByMedusaId(payload, product.medusaId, forceUpdate, foundCollection as 'products' | 'preorder-products')
} catch (error) {
console.error(`Error syncing product by Payload ID ${payloadId}:`, error)
return {
@ -545,7 +571,7 @@ export async function POST(request: Request) {
const { medusaId, payloadId, collection = '', forceUpdate = true } = body
if (medusaId) {
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate)
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate, collection || undefined)
return NextResponse.json(result)
}

View File

@ -1,6 +1,7 @@
import type { CollectionConfig } from 'payload'
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
import { ProductBaseFields, RelatedProductsField, TaobaoLinksField, MedusaAttributesTab } from './base/ProductBase'
import {
AlignFeature,
BlocksFeature,
@ -53,78 +54,7 @@ export const PreorderProducts: CollectionConfig = {
{
label: ' 基本信息',
fields: [
{
type: 'row',
fields: [
{
name: 'medusaId',
type: 'text',
required: true,
unique: true,
index: true,
admin: {
description: 'Medusa 商品 ID',
readOnly: true,
width: '60%',
},
},
{
name: 'status',
type: 'select',
required: true,
defaultValue: 'draft',
options: [
{ label: '草稿', value: 'draft' },
{ label: '已发布', value: 'published' },
],
admin: {
description: '商品详情状态',
width: '40%',
},
},
],
},
{
name: 'seedId',
type: 'text',
unique: true,
index: true,
admin: {
description: 'Seed ID (从 Medusa 同步,用于数据绑定)',
readOnly: true,
},
},
{
name: 'title',
type: 'text',
required: true,
admin: {
description: '商品标题(从 Medusa 同步)',
readOnly: true,
},
},
{
name: 'thumbnail',
type: 'text',
admin: {
description: '商品封面 URL支持上传或输入 URL',
components: {
Cell: '/components/cells/ThumbnailCell#ThumbnailCell',
Field: '/components/fields/ThumbnailField#ThumbnailField',
},
},
},
{
name: 'lastSyncedAt',
type: 'date',
admin: {
description: '上次同步时间',
readOnly: true,
date: {
displayFormat: 'yyyy-MM-dd HH:mm:ss',
},
},
},
...ProductBaseFields,
{
name: 'progress',
type: 'ui',
@ -170,14 +100,31 @@ export const PreorderProducts: CollectionConfig = {
],
},
{
name: 'preorderEndDate',
type: 'date',
admin: {
description: '预购结束日期(可选)',
date: {
displayFormat: 'yyyy-MM-dd HH:mm',
type: 'row',
fields: [
{
name: 'preorderStartDate',
type: 'date',
admin: {
description: '预购开始日期(可选)',
width: '50%',
date: {
displayFormat: 'yyyy-MM-dd HH:mm',
},
},
},
},
{
name: 'preorderEndDate',
type: 'date',
admin: {
description: '预购结束日期(可选)',
width: '50%',
date: {
displayFormat: 'yyyy-MM-dd HH:mm',
},
},
},
],
},
{
type: 'ui',
@ -276,31 +223,7 @@ export const PreorderProducts: CollectionConfig = {
},
{
label: '🔗 相关商品',
fields: [
{
name: 'relatedProducts',
type: 'relationship',
relationTo: ['preorder-products', 'products'],
hasMany: true,
admin: {
description: '推荐的相关商品',
components: {
Field: '/components/fields/RelatedProductsField#RelatedProductsField',
},
},
filterOptions: ({ relationTo, data }) => {
// 过滤掉当前商品本身,避免自引用
if (data?.id) {
return {
id: {
not_equals: data.id,
},
}
}
return true
},
},
],
fields: [RelatedProductsField],
},
{
label: '📦 订单信息',
@ -316,69 +239,10 @@ export const PreorderProducts: CollectionConfig = {
},
],
},
MedusaAttributesTab,
{
label: '🛒 淘宝链接',
fields: [
{
name: 'taobaoLinks',
type: 'array',
label: '淘宝采购链接列表',
admin: {
description: '💡 管理淘宝采购链接(仅后台显示,不通过 API 暴露)',
initCollapsed: false,
},
access: {
read: ({ req: { user } }) => !!user,
update: ({ req: { user } }) => !!user,
},
fields: [
{
name: 'url',
type: 'text',
label: '🔗 淘宝链接',
required: true,
admin: {
placeholder: 'https://item.taobao.com/...',
},
},
{
name: 'title',
type: 'text',
label: '📝 标题',
admin: {
placeholder: '链接标题或商品名称',
},
},
{
name: 'thumbnail',
type: 'text',
label: '🖼️ 缩略图 URL',
admin: {
placeholder: 'https://...',
description: '淘宝商品图片地址',
},
},
{
name: 'note',
type: 'textarea',
label: '📄 备注',
admin: {
placeholder: '其他备注信息...',
rows: 3,
},
},
{
type: 'ui',
name: 'linkPreview',
admin: {
components: {
Field: '/components/fields/TaobaoLinkPreview#TaobaoLinkPreview',
},
},
},
],
},
],
fields: [TaobaoLinksField],
},
],
},

View File

@ -1,26 +1,15 @@
import type { CollectionConfig } from 'payload'
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
import { ProductBaseFields, RelatedProductsField, TaobaoLinksField, MedusaAttributesTab } from './base/ProductBase'
import {
AlignFeature,
BlocksFeature,
BoldFeature,
ChecklistFeature,
HeadingFeature,
IndentFeature,
InlineCodeFeature,
ItalicFeature,
lexicalEditor,
LinkFeature,
OrderedListFeature,
ParagraphFeature,
RelationshipFeature,
UnorderedListFeature,
UploadFeature,
FixedToolbarFeature,
InlineToolbarFeature,
HorizontalRuleFeature,
BlockquoteFeature,
} from '@payloadcms/richtext-lexical'
export const Products: CollectionConfig = {
@ -49,86 +38,7 @@ export const Products: CollectionConfig = {
tabs: [
{
label: ' 基本信息',
fields: [
{
type: 'row',
fields: [
{
name: 'medusaId',
type: 'text',
required: true,
unique: true,
index: true,
admin: {
description: 'Medusa 商品 ID',
readOnly: true,
width: '60%',
},
},
{
name: 'status',
type: 'select',
required: true,
defaultValue: 'draft',
options: [
{
label: '草稿',
value: 'draft',
},
{
label: '已发布',
value: 'published',
},
],
admin: {
description: '商品详情状态',
width: '40%',
},
},
],
},
{
name: 'seedId',
type: 'text',
unique: true,
index: true,
admin: {
description: 'Seed ID (恥从 Medusa 同步,用于数据绑定)',
readOnly: true,
},
},
{
name: 'title',
type: 'text',
required: true,
admin: {
description: '商品标题(从 Medusa 同步)',
readOnly: true,
},
},
{
name: 'thumbnail',
type: 'text',
admin: {
description: '商品封面 URL支持上传或输入 URL',
components: {
Cell: '/components/cells/ThumbnailCell#ThumbnailCell',
Field: '/components/fields/ThumbnailField#ThumbnailField',
},
},
},
{
name: 'lastSyncedAt',
type: 'date',
admin: {
description: '最后同步时间',
readOnly: true,
date: {
displayFormat: 'yyyy-MM-dd HH:mm:ss',
},
},
},
],
fields: ProductBaseFields,
},
{
label: '📄 商品详情',
@ -184,95 +94,12 @@ export const Products: CollectionConfig = {
},
{
label: '🔗 关联信息',
fields: [
{
name: 'relatedProducts',
type: 'relationship',
relationTo: ['products', 'preorder-products'],
hasMany: true,
admin: {
description: '相关商品,支持搜索联想',
components: {
Field: '/components/fields/RelatedProductsField#RelatedProductsField',
},
},
filterOptions: ({ relationTo, data }) => {
// 过滤掉当前商品本身,避免自引用
if (data?.id) {
return {
id: {
not_equals: data.id,
},
}
}
return true
},
},
],
fields: [RelatedProductsField],
},
MedusaAttributesTab,
{
label: '🛒 淘宝链接',
fields: [
{
name: 'taobaoLinks',
type: 'array',
label: '淘宝采购链接列表',
admin: {
description: '💡 管理淘宝采购链接(仅后台显示,不通过 API 暴露)',
initCollapsed: false,
},
access: {
read: ({ req: { user } }) => !!user,
update: ({ req: { user } }) => !!user,
},
fields: [
{
name: 'url',
type: 'text',
label: '🔗 淘宝链接',
required: true,
admin: {
placeholder: 'https://item.taobao.com/...',
},
},
{
name: 'title',
type: 'text',
label: '📝 标题',
admin: {
placeholder: '链接标题或商品名称',
},
},
{
name: 'thumbnail',
type: 'text',
label: '🖼️ 缩略图 URL',
admin: {
placeholder: 'https://...',
description: '淘宝商品图片地址',
},
},
{
name: 'note',
type: 'textarea',
label: '📄 备注',
admin: {
placeholder: '其他备注信息...',
rows: 3,
},
},
{
type: 'ui',
name: 'linkPreview',
admin: {
components: {
Field: '/components/fields/TaobaoLinkPreview#TaobaoLinkPreview',
},
},
},
],
},
],
fields: [TaobaoLinksField],
},
],
},

View File

@ -0,0 +1,311 @@
import type { Field, Tab } from 'payload'
import {
HeadingFeature,
lexicalEditor,
LinkFeature,
UploadFeature,
FixedToolbarFeature,
InlineToolbarFeature,
HorizontalRuleFeature,
} from '@payloadcms/richtext-lexical'
/**
*
* Products PreorderProducts
*/
export const ProductBaseFields: Field[] = [
// ========== 基本信息字段 ==========
{
type: 'row',
fields: [
{
name: 'medusaId',
type: 'text',
required: true,
unique: true,
index: true,
admin: {
description: 'Medusa 商品 ID',
readOnly: true,
width: '60%',
},
},
{
name: 'status',
type: 'select',
required: true,
defaultValue: 'draft',
options: [
{ label: '草稿', value: 'draft' },
{ label: '已发布', value: 'published' },
],
admin: {
description: '商品详情状态',
width: '40%',
},
},
],
},
{
name: 'seedId',
type: 'text',
unique: true,
index: true,
admin: {
description: 'Seed ID (从 Medusa 同步,用于数据绑定)',
readOnly: true,
},
},
{
name: 'title',
type: 'text',
required: true,
admin: {
description: '商品标题(从 Medusa 同步)',
readOnly: true,
},
},
{
name: 'thumbnail',
type: 'text',
admin: {
description: '商品封面 URL支持上传或输入 URL',
components: {
Cell: '/components/cells/ThumbnailCell#ThumbnailCell',
Field: '/components/fields/ThumbnailField#ThumbnailField',
},
},
},
{
name: 'lastSyncedAt',
type: 'date',
admin: {
description: '最后同步时间',
readOnly: true,
date: {
displayFormat: 'yyyy-MM-dd HH:mm:ss',
},
},
},
]
/**
* Medusa
* Medusa
*/
export const MedusaAttributesFields: Field[] = [
{
name: 'tags',
type: 'text',
admin: {
description: '产品标签(逗号分隔)',
placeholder: '例如: 热门, 新品, 限量',
},
},
{
name: 'type',
type: 'text',
admin: {
description: '产品类型',
placeholder: '例如: 外壳, PCB, 工具',
},
},
{
name: 'collection',
type: 'text',
admin: {
description: '产品系列',
placeholder: '例如: Shell, Cartridge',
},
},
{
name: 'category',
type: 'text',
admin: {
description: '产品分类',
placeholder: '例如: GBA, GBC, GB',
},
},
{
type: 'collapsible',
label: '物理属性',
fields: [
{
type: 'row',
fields: [
{
name: 'height',
type: 'number',
admin: {
description: '高度 (cm)',
width: '25%',
},
},
{
name: 'width',
type: 'number',
admin: {
description: '宽度 (cm)',
width: '25%',
},
},
{
name: 'length',
type: 'number',
admin: {
description: '长度 (cm)',
width: '25%',
},
},
{
name: 'weight',
type: 'number',
admin: {
description: '重量 (g)',
width: '25%',
},
},
],
},
],
},
{
type: 'collapsible',
label: '海关与物流',
fields: [
{
type: 'row',
fields: [
{
name: 'midCode',
type: 'text',
admin: {
description: 'MID 代码(制造商识别码)',
placeholder: '例如: 1234567890',
width: '33%',
},
},
{
name: 'hsCode',
type: 'text',
admin: {
description: 'HS 代码(海关编码)',
placeholder: '例如: 8523.49.00',
width: '33%',
},
},
{
name: 'countryOfOrigin',
type: 'text',
admin: {
description: '原产国',
placeholder: '例如: CN, US, JP',
width: '34%',
},
},
],
},
],
},
]
/**
* Medusa Tab
* Medusa
*/
export const MedusaAttributesTab: Tab = {
label: '🏷️ 属性',
fields: MedusaAttributesFields,
}
/**
*
* (products preorder-products)
*/
export const RelatedProductsField: Field = {
name: 'relatedProducts',
type: 'relationship',
relationTo: ['products', 'preorder-products'],
hasMany: true,
admin: {
description: '相关商品,支持搜索联想',
components: {
Field: '/components/fields/RelatedProductsField#RelatedProductsField',
},
},
filterOptions: ({ relationTo, data }) => {
// 过滤掉当前商品本身,避免自引用
if (data?.id) {
return {
id: {
not_equals: data.id,
},
}
}
return true
},
}
/**
*
* API
*/
export const TaobaoLinksField: Field = {
name: 'taobaoLinks',
type: 'array',
label: '淘宝采购链接列表',
admin: {
description: '💡 管理淘宝采购链接(仅后台显示,不通过 API 暴露)',
initCollapsed: false,
},
access: {
read: ({ req: { user } }) => !!user,
update: ({ req: { user } }) => !!user,
},
fields: [
{
name: 'url',
type: 'text',
label: '🔗 淘宝链接',
required: true,
admin: {
placeholder: 'https://item.taobao.com/...',
},
},
{
name: 'title',
type: 'text',
label: '📝 标题',
admin: {
placeholder: '链接标题或商品名称',
},
},
{
name: 'thumbnail',
type: 'text',
label: '🖼️ 缩略图 URL',
admin: {
placeholder: 'https://...',
description: '淘宝商品图片地址',
},
},
{
name: 'note',
type: 'textarea',
label: '📄 备注',
admin: {
placeholder: '其他备注信息...',
rows: 3,
},
},
{
type: 'ui',
name: 'linkPreview',
admin: {
components: {
Field: '/components/fields/TaobaoLinkPreview#TaobaoLinkPreview',
},
},
},
],
}

View File

@ -1,19 +1,21 @@
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
export const ThumbnailCell = (props: any) => {
const pathname = usePathname()
// 从 URL 路径中提取 collection slug
const collectionSlug = pathname?.includes('/preorder-products')
? 'preorder-products'
: 'products'
// 尝试从不同的 props 路径获取值
const value = props.value || props.cellData || props.data
const rowData = props.rowData || props.row
// 优先从 props 中获取 collection 信息Payload Cell API
let collectionSlug = props.collectionConfig?.slug || props.field?.relationTo || props.collection
// 如果没有从 props 获取到,通过检查预购特有字段自动判断
if (!collectionSlug) {
// PreorderProducts 有 orderCount, preorderType 等特有字段
const isPreorder = rowData?.orderCount !== undefined || rowData?.preorderType !== undefined
collectionSlug = isPreorder ? 'preorder-products' : 'products'
}
const isImage = typeof value === 'string' && value.match(/^https?:\/\/.+/)
const editUrl = `/admin/collections/${collectionSlug}/${rowData?.id || ''}`

View File

@ -211,6 +211,9 @@ export function transformMedusaProductToPayload(product: MedusaProduct) {
thumbnailUrl = product.images[0].url
}
// 提取 tags逗号分隔
const tags = product.tags?.map(tag => tag.value).join(', ') || null
return {
medusaId: product.id,
seedId: product.metadata?.seed_id || null,
@ -219,6 +222,23 @@ export function transformMedusaProductToPayload(product: MedusaProduct) {
thumbnail: thumbnailUrl || null,
status: 'draft',
lastSyncedAt: new Date().toISOString(),
// Medusa 默认属性
tags: tags,
type: product.type_id || null,
collection: product.collection_id || null,
category: product.metadata?.category || null,
// 物理属性(从 metadata 中提取)
height: product.metadata?.height ? Number(product.metadata.height) : null,
width: product.metadata?.width ? Number(product.metadata.width) : null,
length: product.metadata?.length ? Number(product.metadata.length) : null,
weight: product.metadata?.weight ? Number(product.metadata.weight) : null,
// 海关与物流
midCode: product.metadata?.mid_code || product.metadata?.midCode || null,
hsCode: product.metadata?.hs_code || product.metadata?.hsCode || null,
countryOfOrigin: product.metadata?.country_of_origin || product.metadata?.countryOfOrigin || null,
}
}

View File

@ -206,7 +206,7 @@ export interface Product {
*/
status: 'draft' | 'published';
/**
* Seed ID Medusa
* Seed ID Medusa
*/
seedId?: string | null;
/**
@ -254,6 +254,50 @@ export interface Product {
}
)[]
| null;
/**
*
*/
tags?: string | null;
/**
*
*/
type?: string | null;
/**
*
*/
collection?: string | null;
/**
*
*/
category?: string | null;
/**
* (cm)
*/
height?: number | null;
/**
* (cm)
*/
width?: number | null;
/**
* (cm)
*/
length?: number | null;
/**
* (g)
*/
weight?: number | null;
/**
* MID
*/
midCode?: string | null;
/**
* HS
*/
hsCode?: string | null;
/**
*
*/
countryOfOrigin?: string | null;
/**
* 💡 API
*/
@ -301,7 +345,7 @@ export interface PreorderProduct {
*/
thumbnail?: string | null;
/**
*
*
*/
lastSyncedAt?: string | null;
/**
@ -312,6 +356,10 @@ export interface PreorderProduct {
* 0 max_orders
*/
fundingGoal: number;
/**
*
*/
preorderStartDate?: string | null;
/**
*
*/
@ -343,20 +391,64 @@ export interface PreorderProduct {
[k: string]: unknown;
} | null;
/**
*
*
*/
relatedProducts?:
| (
| {
relationTo: 'preorder-products';
value: number | PreorderProduct;
}
| {
relationTo: 'products';
value: number | Product;
}
| {
relationTo: 'preorder-products';
value: number | PreorderProduct;
}
)[]
| null;
/**
*
*/
tags?: string | null;
/**
*
*/
type?: string | null;
/**
*
*/
collection?: string | null;
/**
*
*/
category?: string | null;
/**
* (cm)
*/
height?: number | null;
/**
* (cm)
*/
width?: number | null;
/**
* (cm)
*/
length?: number | null;
/**
* (g)
*/
weight?: number | null;
/**
* MID
*/
midCode?: string | null;
/**
* HS
*/
hsCode?: string | null;
/**
*
*/
countryOfOrigin?: string | null;
/**
* 💡 API
*/
@ -821,6 +913,17 @@ export interface ProductsSelect<T extends boolean = true> {
lastSyncedAt?: T;
content?: T;
relatedProducts?: T;
tags?: T;
type?: T;
collection?: T;
category?: T;
height?: T;
width?: T;
length?: T;
weight?: T;
midCode?: T;
hsCode?: T;
countryOfOrigin?: T;
taobaoLinks?:
| T
| {
@ -846,11 +949,23 @@ export interface PreorderProductsSelect<T extends boolean = true> {
lastSyncedAt?: T;
preorderType?: T;
fundingGoal?: T;
preorderStartDate?: T;
preorderEndDate?: T;
orderCount?: T;
fakeOrderCount?: T;
description?: T;
relatedProducts?: T;
tags?: T;
type?: T;
collection?: T;
category?: T;
height?: T;
width?: T;
length?: T;
weight?: T;
midCode?: T;
hsCode?: T;
countryOfOrigin?: T;
taobaoLinks?:
| T
| {