基类化
This commit is contained in:
parent
35928a6144
commit
dae1b2704f
|
|
@ -126,14 +126,14 @@ export async function GET(request: Request) {
|
||||||
const { searchParams } = new URL(request.url)
|
const { searchParams } = new URL(request.url)
|
||||||
const medusaId = searchParams.get('medusaId')
|
const medusaId = searchParams.get('medusaId')
|
||||||
const payloadId = searchParams.get('payloadId')
|
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 forceUpdate = searchParams.get('forceUpdate') === 'true'
|
||||||
|
|
||||||
const payload = await getPayload({ config })
|
const payload = await getPayload({ config })
|
||||||
|
|
||||||
// 同步单个商品(通过 Medusa ID)
|
// 同步单个商品(通过 Medusa ID)
|
||||||
if (medusaId) {
|
if (medusaId) {
|
||||||
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate)
|
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate, collection || undefined)
|
||||||
return NextResponse.json(result)
|
return NextResponse.json(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,13 +166,22 @@ export async function GET(request: Request) {
|
||||||
/**
|
/**
|
||||||
* 通过 Medusa ID 同步单个商品
|
* 通过 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 {
|
try {
|
||||||
// 从 Medusa 获取商品数据
|
// 从 Medusa 获取商品数据
|
||||||
const medusaProducts = await getAllMedusaProducts()
|
const medusaProducts = await getAllMedusaProducts()
|
||||||
const medusaProduct = medusaProducts.find((p) => p.id === medusaId)
|
const medusaProduct = medusaProducts.find((p) => p.id === medusaId)
|
||||||
|
|
||||||
if (!medusaProduct) {
|
if (!medusaProduct) {
|
||||||
|
console.error(`[Sync API] ❌ Medusa 中未找到商品: ${medusaId}`)
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
action: 'not_found',
|
action: 'not_found',
|
||||||
|
|
@ -180,20 +189,27 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确定应该同步到哪个 collection
|
console.log(`[Sync API] ✅ 找到 Medusa 产品: ${medusaProduct.title}`)
|
||||||
const targetCollection = getProductCollection(medusaProduct)
|
|
||||||
|
// 确定应该同步到哪个 collection(优先使用传入的 collection,否则自动判断)
|
||||||
|
const targetCollection = preferredCollection || getProductCollection(medusaProduct)
|
||||||
|
console.log(`[Sync API] 🎯 目标 collection: ${targetCollection}${preferredCollection ? ' (指定)' : ' (自动判断)'}`)
|
||||||
|
|
||||||
const otherCollection =
|
const otherCollection =
|
||||||
targetCollection === 'preorder-products' ? 'products' : 'preorder-products'
|
targetCollection === 'preorder-products' ? 'products' : 'preorder-products'
|
||||||
|
|
||||||
// 转换数据
|
// 转换数据
|
||||||
const productData = transformMedusaProductToPayload(medusaProduct)
|
const productData = transformMedusaProductToPayload(medusaProduct)
|
||||||
const seedId = productData.seedId
|
const seedId = productData.seedId
|
||||||
|
console.log(`[Sync API] 📦 产品数据: title=${productData.title}, seedId=${seedId}`)
|
||||||
|
|
||||||
// 使用新的查找函数(优先 seedId)
|
// 使用新的查找函数(优先 seedId)
|
||||||
const found = await findProductBySeedIdOrMedusaId(payload, seedId, medusaId)
|
const found = await findProductBySeedIdOrMedusaId(payload, seedId, medusaId)
|
||||||
|
|
||||||
// 如果在另一个 collection 中找到,需要移动
|
// 如果在另一个 collection 中找到,需要移动
|
||||||
if (found && found.collection !== targetCollection) {
|
if (found && found.collection !== targetCollection) {
|
||||||
|
console.log(`[Sync API] 🚚 需要移动: ${found.collection} -> ${targetCollection}`)
|
||||||
|
|
||||||
await payload.delete({
|
await payload.delete({
|
||||||
collection: found.collection,
|
collection: found.collection,
|
||||||
id: found.product.id,
|
id: found.product.id,
|
||||||
|
|
@ -204,6 +220,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
data: productData,
|
data: productData,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(`[Sync API] ✅ 移动成功, 新 ID: ${created.id}`)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
action: 'moved',
|
action: 'moved',
|
||||||
|
|
@ -215,16 +232,19 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
|
|
||||||
// 如果在目标 collection 中找到
|
// 如果在目标 collection 中找到
|
||||||
if (found) {
|
if (found) {
|
||||||
|
console.log(`[Sync API] 🔎 在 ${found.collection} 中找到现有产品, ID: ${found.product.id}`)
|
||||||
const existingProduct = found.product
|
const existingProduct = found.product
|
||||||
|
|
||||||
// 如果存在且不强制更新,只更新空字段
|
// 如果存在且不强制更新,只更新空字段
|
||||||
if (!forceUpdate) {
|
if (!forceUpdate) {
|
||||||
// 合并数据(只更新空字段)
|
console.log(`[Sync API] 🔄 模式: 只填充空字段`)
|
||||||
|
// 合并数据(只曹新空字段)
|
||||||
const mergedData = mergeProductData(existingProduct, productData, false)
|
const mergedData = mergeProductData(existingProduct, productData, false)
|
||||||
|
|
||||||
// 如果没有需要更新的字段,跳过
|
// 如果没有需要更新的字段,跳过
|
||||||
if (Object.keys(mergedData).length <= 2) {
|
if (Object.keys(mergedData).length <= 2) {
|
||||||
// 只有 lastSyncedAt 和 medusaId
|
// 只有 lastSyncedAt 和 medusaId
|
||||||
|
console.log(`[Sync API] ⏭️ 跳过: 所有字段都有值`)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
action: 'skipped',
|
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({
|
const updated = await payload.update({
|
||||||
collection: targetCollection,
|
collection: targetCollection,
|
||||||
|
|
@ -241,6 +262,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
data: mergedData,
|
data: mergedData,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(`[Sync API] ✅ 部分更新成功`)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
action: 'updated_partial',
|
action: 'updated_partial',
|
||||||
|
|
@ -250,6 +272,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[Sync API] ⚡ 模式: 强制更新所有字段`)
|
||||||
// 强制更新所有字段
|
// 强制更新所有字段
|
||||||
const updated = await payload.update({
|
const updated = await payload.update({
|
||||||
collection: targetCollection,
|
collection: targetCollection,
|
||||||
|
|
@ -257,6 +280,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
data: productData,
|
data: productData,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(`[Sync API] ✅ 强制更新成功`)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
action: 'updated',
|
action: 'updated',
|
||||||
|
|
@ -266,12 +290,14 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`[Sync API] ✨ 创建新产品`)
|
||||||
// 不存在,创建新商品
|
// 不存在,创建新商品
|
||||||
const created = await payload.create({
|
const created = await payload.create({
|
||||||
collection: targetCollection,
|
collection: targetCollection,
|
||||||
data: productData,
|
data: productData,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log(`[Sync API] ✅ 创建成功, ID: ${created.id}`)
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
action: 'created',
|
action: 'created',
|
||||||
|
|
@ -280,7 +306,7 @@ async function syncSingleProductByMedusaId(payload: any, medusaId: string, force
|
||||||
collection: targetCollection,
|
collection: targetCollection,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error syncing product ${medusaId}:`, error)
|
console.error(`[Sync API] ❌ 同步失败:`, error)
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
action: 'error',
|
action: 'error',
|
||||||
|
|
@ -344,8 +370,8 @@ async function syncSingleProductByPayloadId(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 medusaId 同步
|
// 使用 medusaId 同步(保持在当前 collection)
|
||||||
return await syncSingleProductByMedusaId(payload, product.medusaId, forceUpdate)
|
return await syncSingleProductByMedusaId(payload, product.medusaId, forceUpdate, foundCollection as 'products' | 'preorder-products')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error syncing product by Payload ID ${payloadId}:`, error)
|
console.error(`Error syncing product by Payload ID ${payloadId}:`, error)
|
||||||
return {
|
return {
|
||||||
|
|
@ -545,7 +571,7 @@ export async function POST(request: Request) {
|
||||||
const { medusaId, payloadId, collection = '', forceUpdate = true } = body
|
const { medusaId, payloadId, collection = '', forceUpdate = true } = body
|
||||||
|
|
||||||
if (medusaId) {
|
if (medusaId) {
|
||||||
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate)
|
const result = await syncSingleProductByMedusaId(payload, medusaId, forceUpdate, collection || undefined)
|
||||||
return NextResponse.json(result)
|
return NextResponse.json(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import type { CollectionConfig } from 'payload'
|
import type { CollectionConfig } from 'payload'
|
||||||
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
|
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
|
||||||
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
|
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
|
||||||
|
import { ProductBaseFields, RelatedProductsField, TaobaoLinksField, MedusaAttributesTab } from './base/ProductBase'
|
||||||
import {
|
import {
|
||||||
AlignFeature,
|
AlignFeature,
|
||||||
BlocksFeature,
|
BlocksFeature,
|
||||||
|
|
@ -53,78 +54,7 @@ export const PreorderProducts: CollectionConfig = {
|
||||||
{
|
{
|
||||||
label: 'ℹ️ 基本信息',
|
label: 'ℹ️ 基本信息',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
...ProductBaseFields,
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'progress',
|
name: 'progress',
|
||||||
type: 'ui',
|
type: 'ui',
|
||||||
|
|
@ -170,14 +100,31 @@ export const PreorderProducts: CollectionConfig = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'preorderEndDate',
|
type: 'row',
|
||||||
type: 'date',
|
fields: [
|
||||||
admin: {
|
{
|
||||||
description: '预购结束日期(可选)',
|
name: 'preorderStartDate',
|
||||||
date: {
|
type: 'date',
|
||||||
displayFormat: 'yyyy-MM-dd HH:mm',
|
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',
|
type: 'ui',
|
||||||
|
|
@ -276,31 +223,7 @@ export const PreorderProducts: CollectionConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '🔗 相关商品',
|
label: '🔗 相关商品',
|
||||||
fields: [
|
fields: [RelatedProductsField],
|
||||||
{
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '📦 订单信息',
|
label: '📦 订单信息',
|
||||||
|
|
@ -316,69 +239,10 @@ export const PreorderProducts: CollectionConfig = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
MedusaAttributesTab,
|
||||||
{
|
{
|
||||||
label: '🛒 淘宝链接',
|
label: '🛒 淘宝链接',
|
||||||
fields: [
|
fields: [TaobaoLinksField],
|
||||||
{
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,15 @@
|
||||||
import type { CollectionConfig } from 'payload'
|
import type { CollectionConfig } from 'payload'
|
||||||
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
|
import { logAfterChange, logAfterDelete } from '../hooks/logAction'
|
||||||
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
|
import { cacheAfterChange, cacheAfterDelete } from '../hooks/cacheInvalidation'
|
||||||
|
import { ProductBaseFields, RelatedProductsField, TaobaoLinksField, MedusaAttributesTab } from './base/ProductBase'
|
||||||
import {
|
import {
|
||||||
AlignFeature,
|
|
||||||
BlocksFeature,
|
|
||||||
BoldFeature,
|
|
||||||
ChecklistFeature,
|
|
||||||
HeadingFeature,
|
HeadingFeature,
|
||||||
IndentFeature,
|
|
||||||
InlineCodeFeature,
|
|
||||||
ItalicFeature,
|
|
||||||
lexicalEditor,
|
lexicalEditor,
|
||||||
LinkFeature,
|
LinkFeature,
|
||||||
OrderedListFeature,
|
|
||||||
ParagraphFeature,
|
|
||||||
RelationshipFeature,
|
|
||||||
UnorderedListFeature,
|
|
||||||
UploadFeature,
|
UploadFeature,
|
||||||
FixedToolbarFeature,
|
FixedToolbarFeature,
|
||||||
InlineToolbarFeature,
|
InlineToolbarFeature,
|
||||||
HorizontalRuleFeature,
|
HorizontalRuleFeature,
|
||||||
BlockquoteFeature,
|
|
||||||
} from '@payloadcms/richtext-lexical'
|
} from '@payloadcms/richtext-lexical'
|
||||||
|
|
||||||
export const Products: CollectionConfig = {
|
export const Products: CollectionConfig = {
|
||||||
|
|
@ -49,86 +38,7 @@ export const Products: CollectionConfig = {
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
label: 'ℹ️ 基本信息',
|
label: 'ℹ️ 基本信息',
|
||||||
fields: [
|
fields: ProductBaseFields,
|
||||||
{
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '📄 商品详情',
|
label: '📄 商品详情',
|
||||||
|
|
@ -184,95 +94,12 @@ export const Products: CollectionConfig = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '🔗 关联信息',
|
label: '🔗 关联信息',
|
||||||
fields: [
|
fields: [RelatedProductsField],
|
||||||
{
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
MedusaAttributesTab,
|
||||||
{
|
{
|
||||||
label: '🛒 淘宝链接',
|
label: '🛒 淘宝链接',
|
||||||
fields: [
|
fields: [TaobaoLinksField],
|
||||||
{
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
'use client'
|
'use client'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { usePathname } from 'next/navigation'
|
|
||||||
|
|
||||||
export const ThumbnailCell = (props: any) => {
|
export const ThumbnailCell = (props: any) => {
|
||||||
const pathname = usePathname()
|
|
||||||
|
|
||||||
// 从 URL 路径中提取 collection slug
|
|
||||||
const collectionSlug = pathname?.includes('/preorder-products')
|
|
||||||
? 'preorder-products'
|
|
||||||
: 'products'
|
|
||||||
|
|
||||||
// 尝试从不同的 props 路径获取值
|
// 尝试从不同的 props 路径获取值
|
||||||
const value = props.value || props.cellData || props.data
|
const value = props.value || props.cellData || props.data
|
||||||
const rowData = props.rowData || props.row
|
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 isImage = typeof value === 'string' && value.match(/^https?:\/\/.+/)
|
||||||
const editUrl = `/admin/collections/${collectionSlug}/${rowData?.id || ''}`
|
const editUrl = `/admin/collections/${collectionSlug}/${rowData?.id || ''}`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,9 @@ export function transformMedusaProductToPayload(product: MedusaProduct) {
|
||||||
thumbnailUrl = product.images[0].url
|
thumbnailUrl = product.images[0].url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提取 tags(逗号分隔)
|
||||||
|
const tags = product.tags?.map(tag => tag.value).join(', ') || null
|
||||||
|
|
||||||
return {
|
return {
|
||||||
medusaId: product.id,
|
medusaId: product.id,
|
||||||
seedId: product.metadata?.seed_id || null,
|
seedId: product.metadata?.seed_id || null,
|
||||||
|
|
@ -219,6 +222,23 @@ export function transformMedusaProductToPayload(product: MedusaProduct) {
|
||||||
thumbnail: thumbnailUrl || null,
|
thumbnail: thumbnailUrl || null,
|
||||||
status: 'draft',
|
status: 'draft',
|
||||||
lastSyncedAt: new Date().toISOString(),
|
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ export interface Product {
|
||||||
*/
|
*/
|
||||||
status: 'draft' | 'published';
|
status: 'draft' | 'published';
|
||||||
/**
|
/**
|
||||||
* Seed ID (恥从 Medusa 同步,用于数据绑定)
|
* Seed ID (从 Medusa 同步,用于数据绑定)
|
||||||
*/
|
*/
|
||||||
seedId?: string | null;
|
seedId?: string | null;
|
||||||
/**
|
/**
|
||||||
|
|
@ -254,6 +254,50 @@ export interface Product {
|
||||||
}
|
}
|
||||||
)[]
|
)[]
|
||||||
| null;
|
| 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 暴露)
|
* 💡 管理淘宝采购链接(仅后台显示,不通过 API 暴露)
|
||||||
*/
|
*/
|
||||||
|
|
@ -301,7 +345,7 @@ export interface PreorderProduct {
|
||||||
*/
|
*/
|
||||||
thumbnail?: string | null;
|
thumbnail?: string | null;
|
||||||
/**
|
/**
|
||||||
* 上次同步时间
|
* 最后同步时间
|
||||||
*/
|
*/
|
||||||
lastSyncedAt?: string | null;
|
lastSyncedAt?: string | null;
|
||||||
/**
|
/**
|
||||||
|
|
@ -312,6 +356,10 @@ export interface PreorderProduct {
|
||||||
* 众筹目标数量(0 表示以变体 max_orders 总和为准)
|
* 众筹目标数量(0 表示以变体 max_orders 总和为准)
|
||||||
*/
|
*/
|
||||||
fundingGoal: number;
|
fundingGoal: number;
|
||||||
|
/**
|
||||||
|
* 预购开始日期(可选)
|
||||||
|
*/
|
||||||
|
preorderStartDate?: string | null;
|
||||||
/**
|
/**
|
||||||
* 预购结束日期(可选)
|
* 预购结束日期(可选)
|
||||||
*/
|
*/
|
||||||
|
|
@ -343,20 +391,64 @@ export interface PreorderProduct {
|
||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
} | null;
|
} | null;
|
||||||
/**
|
/**
|
||||||
* 推荐的相关商品
|
* 相关商品,支持搜索联想
|
||||||
*/
|
*/
|
||||||
relatedProducts?:
|
relatedProducts?:
|
||||||
| (
|
| (
|
||||||
| {
|
|
||||||
relationTo: 'preorder-products';
|
|
||||||
value: number | PreorderProduct;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
relationTo: 'products';
|
relationTo: 'products';
|
||||||
value: number | Product;
|
value: number | Product;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
relationTo: 'preorder-products';
|
||||||
|
value: number | PreorderProduct;
|
||||||
|
}
|
||||||
)[]
|
)[]
|
||||||
| null;
|
| 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 暴露)
|
* 💡 管理淘宝采购链接(仅后台显示,不通过 API 暴露)
|
||||||
*/
|
*/
|
||||||
|
|
@ -821,6 +913,17 @@ export interface ProductsSelect<T extends boolean = true> {
|
||||||
lastSyncedAt?: T;
|
lastSyncedAt?: T;
|
||||||
content?: T;
|
content?: T;
|
||||||
relatedProducts?: 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?:
|
taobaoLinks?:
|
||||||
| T
|
| T
|
||||||
| {
|
| {
|
||||||
|
|
@ -846,11 +949,23 @@ export interface PreorderProductsSelect<T extends boolean = true> {
|
||||||
lastSyncedAt?: T;
|
lastSyncedAt?: T;
|
||||||
preorderType?: T;
|
preorderType?: T;
|
||||||
fundingGoal?: T;
|
fundingGoal?: T;
|
||||||
|
preorderStartDate?: T;
|
||||||
preorderEndDate?: T;
|
preorderEndDate?: T;
|
||||||
orderCount?: T;
|
orderCount?: T;
|
||||||
fakeOrderCount?: T;
|
fakeOrderCount?: T;
|
||||||
description?: T;
|
description?: T;
|
||||||
relatedProducts?: 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?:
|
taobaoLinks?:
|
||||||
| T
|
| T
|
||||||
| {
|
| {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue