forked from yoone/API
446 lines
13 KiB
TypeScript
446 lines
13 KiB
TypeScript
import { ApiProperty } from '@midwayjs/swagger';
|
|
import { Rule, RuleType } from '@midwayjs/validate';
|
|
import { UnifiedSearchParamsDTO } from './api.dto';
|
|
|
|
/**
|
|
* 属性输入DTO
|
|
*/
|
|
export class AttributeInputDTO {
|
|
@ApiProperty({ description: '属性字典标识', example: 'brand' })
|
|
@Rule(RuleType.string())
|
|
dictName?: string;
|
|
|
|
@ApiProperty({ description: '属性值', example: 'ZYN' })
|
|
@Rule(RuleType.string())
|
|
value?: string;
|
|
|
|
@ApiProperty({ description: '属性ID', example: 1 })
|
|
@Rule(RuleType.number())
|
|
id?: number;
|
|
|
|
@ApiProperty({ description: '属性名称', example: 'ZYN' })
|
|
@Rule(RuleType.string())
|
|
name?: string;
|
|
|
|
@ApiProperty({ description: '属性显示名称', example: 'ZYN' })
|
|
@Rule(RuleType.string())
|
|
title?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO 用于创建产品
|
|
*/
|
|
export class CreateProductDTO {
|
|
@ApiProperty({
|
|
example: 'ZYN 6MG WINTERGREEN',
|
|
description: '产品名称',
|
|
required: true,
|
|
})
|
|
@Rule(RuleType.string().required().empty({ message: '产品名称不能为空' }))
|
|
name: string;
|
|
|
|
@ApiProperty({ description: '产品中文名称', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
nameCn?: string;
|
|
|
|
@ApiProperty({ example: '产品描述', description: '产品描述' })
|
|
@Rule(RuleType.string())
|
|
description: string;
|
|
|
|
@ApiProperty({ example: '产品简短描述', description: '产品简短描述' })
|
|
@Rule(RuleType.string().optional())
|
|
shortDescription?: string;
|
|
|
|
@ApiProperty({ description: '产品 SKU', required: false })
|
|
@Rule(RuleType.string())
|
|
sku?: string;
|
|
|
|
@ApiProperty({ description: '分类ID (DictItem ID)', required: false })
|
|
@Rule(RuleType.number())
|
|
categoryId?: number;
|
|
|
|
@ApiProperty({ description: '分类名称', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
categoryName?: string;
|
|
|
|
@ApiProperty({ description: '站点 SKU 列表', type: 'array', required: false })
|
|
@Rule(RuleType.array().items(RuleType.string()).optional())
|
|
siteSkus?: string[];
|
|
|
|
// 通用属性输入(通过 attributes 统一提交品牌/口味/强度/尺寸/干湿等)
|
|
// 当 type 为 'single' 时必填,当 type 为 'bundle' 时可选
|
|
@ApiProperty({ description: '属性列表', type: 'array', required: false })
|
|
@Rule(
|
|
RuleType.array()
|
|
.when('type', {
|
|
is: 'single',
|
|
then: RuleType.array().required(),
|
|
otherwise: RuleType.array().optional()
|
|
})
|
|
)
|
|
attributes?: AttributeInputDTO[];
|
|
|
|
// 商品价格
|
|
@ApiProperty({ description: '价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number())
|
|
price?: number;
|
|
|
|
// 促销价格
|
|
@ApiProperty({ description: '促销价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number())
|
|
promotionPrice?: number;
|
|
|
|
// 产品图片URL
|
|
@ApiProperty({ description: '产品图片URL', example: 'https://example.com/image.jpg', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
image?: string;
|
|
|
|
// 商品类型(默认 single; bundle 需手动设置组成)
|
|
@ApiProperty({ description: '商品类型', enum: ['single', 'bundle'], default: 'single', required: false })
|
|
@Rule(RuleType.string().valid('single', 'bundle').default('single'))
|
|
type?: string;
|
|
|
|
// 仅当 type 为 'bundle' 时,才需要提供 components
|
|
@ApiProperty({ description: '产品组成', type: 'array', required: false })
|
|
@Rule(
|
|
RuleType.array()
|
|
.items(
|
|
RuleType.object({
|
|
sku: RuleType.string().required(),
|
|
quantity: RuleType.number().required(),
|
|
})
|
|
)
|
|
.when('type', {
|
|
is: 'bundle',
|
|
then: RuleType.array().required(),
|
|
})
|
|
)
|
|
components?: { sku: string; quantity: number }[];
|
|
}
|
|
|
|
/**
|
|
* DTO 用于更新产品
|
|
*/
|
|
export class UpdateProductDTO {
|
|
@ApiProperty({ example: 'ZYN 6MG WINTERGREEN', description: '产品名称' })
|
|
@Rule(RuleType.string())
|
|
name?: string;
|
|
|
|
@ApiProperty({ description: '产品中文名称', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
nameCn?: string;
|
|
|
|
@ApiProperty({ example: '产品描述', description: '产品描述' })
|
|
@Rule(RuleType.string())
|
|
description?: string;
|
|
|
|
@ApiProperty({ example: '产品简短描述', description: '产品简短描述' })
|
|
@Rule(RuleType.string().optional())
|
|
shortDescription?: string;
|
|
|
|
@ApiProperty({ description: '产品 SKU', required: false })
|
|
@Rule(RuleType.string())
|
|
sku?: string;
|
|
|
|
@ApiProperty({ description: '分类ID (DictItem ID)', required: false })
|
|
@Rule(RuleType.number())
|
|
categoryId?: number;
|
|
|
|
@ApiProperty({ description: '分类名称', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
categoryName?: string;
|
|
|
|
@ApiProperty({ description: '站点 SKU 列表', type: 'array', required: false })
|
|
@Rule(RuleType.array().items(RuleType.string()).optional())
|
|
siteSkus?: string[];
|
|
|
|
// 商品价格
|
|
@ApiProperty({ description: '价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number())
|
|
price?: number;
|
|
|
|
// 促销价格
|
|
@ApiProperty({ description: '促销价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number())
|
|
promotionPrice?: number;
|
|
|
|
// 产品图片URL
|
|
@ApiProperty({ description: '产品图片URL', example: 'https://example.com/image.jpg', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
image?: string;
|
|
|
|
// 属性更新(可选, 支持增量替换指定字典的属性项)
|
|
@ApiProperty({ description: '属性列表', type: 'array', required: false })
|
|
@Rule(RuleType.array())
|
|
attributes?: AttributeInputDTO[];
|
|
|
|
// 商品类型(single 或 bundle)
|
|
@ApiProperty({ description: '商品类型', enum: ['single', 'bundle'], required: false })
|
|
@Rule(RuleType.string().valid('single', 'bundle'))
|
|
type?: string;
|
|
|
|
// 仅当 type 为 'bundle' 时,才需要提供 components
|
|
@ApiProperty({ description: '产品组成', type: 'array', required: false })
|
|
@Rule(
|
|
RuleType.array()
|
|
.items(
|
|
RuleType.object({
|
|
sku: RuleType.string().required(),
|
|
quantity: RuleType.number().required(),
|
|
})
|
|
)
|
|
.when('type', {
|
|
is: 'bundle',
|
|
then: RuleType.array().optional(),
|
|
})
|
|
)
|
|
components?: { sku: string; quantity: number }[];
|
|
}
|
|
|
|
|
|
/**
|
|
* DTO 用于批量更新产品属性
|
|
*/
|
|
export class BatchUpdateProductDTO {
|
|
@ApiProperty({ description: '产品ID列表', type: 'array', required: true })
|
|
@Rule(RuleType.array().items(RuleType.number()).required().min(1))
|
|
ids: number[];
|
|
|
|
@ApiProperty({ example: 'ZYN 6MG WINTERGREEN', description: '产品名称', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
name?: string;
|
|
|
|
@ApiProperty({ description: '产品中文名称', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
nameCn?: string;
|
|
|
|
@ApiProperty({ example: '产品描述', description: '产品描述', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
description?: string;
|
|
|
|
@ApiProperty({ example: '产品简短描述', description: '产品简短描述', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
shortDescription?: string;
|
|
|
|
@ApiProperty({ description: '产品 SKU', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
sku?: string;
|
|
|
|
@ApiProperty({ description: '分类ID (DictItem ID)', required: false })
|
|
@Rule(RuleType.number().optional())
|
|
categoryId?: number;
|
|
|
|
@ApiProperty({ description: '站点 SKU 列表', type: 'array', required: false })
|
|
@Rule(RuleType.array().items(RuleType.string()).optional())
|
|
siteSkus?: string[];
|
|
|
|
@ApiProperty({ description: '价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number().optional())
|
|
price?: number;
|
|
|
|
@ApiProperty({ description: '促销价格', example: 99.99, required: false })
|
|
@Rule(RuleType.number().optional())
|
|
promotionPrice?: number;
|
|
|
|
@ApiProperty({ description: '产品图片URL', example: 'https://example.com/image.jpg', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
image?: string;
|
|
|
|
@ApiProperty({ description: '属性列表', type: 'array', required: false })
|
|
@Rule(RuleType.array().optional())
|
|
attributes?: AttributeInputDTO[];
|
|
|
|
@ApiProperty({ description: '商品类型', enum: ['single', 'bundle'], required: false })
|
|
@Rule(RuleType.string().valid('single', 'bundle').optional())
|
|
type?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO 用于批量删除产品
|
|
*/
|
|
export class BatchDeleteProductDTO {
|
|
@ApiProperty({ description: '产品ID列表', type: 'array', required: true })
|
|
@Rule(RuleType.array().items(RuleType.number()).required().min(1))
|
|
ids: number[];
|
|
}
|
|
|
|
/**
|
|
* DTO 用于创建分类属性绑定
|
|
*/
|
|
export class CreateCategoryAttributeDTO {
|
|
@ApiProperty({ description: '分类字典项ID', example: 1 })
|
|
@Rule(RuleType.number().required())
|
|
categoryItemId: number;
|
|
|
|
@ApiProperty({ description: '属性字典ID列表', example: [2, 3] })
|
|
@Rule(RuleType.array().items(RuleType.number()).required())
|
|
attributeDictIds: number[];
|
|
}
|
|
|
|
/**
|
|
* 产品查询过滤条件接口
|
|
*/
|
|
export interface ProductWhereFilter {
|
|
// 产品ID
|
|
id?: number;
|
|
// 产品ID列表
|
|
ids?: number[];
|
|
// SKU
|
|
sku?: string;
|
|
// SKU列表
|
|
skus?: string[];
|
|
// 产品名称
|
|
name?: string;
|
|
// 产品中文名称
|
|
nameCn?: string;
|
|
// 分类ID
|
|
categoryId?: number;
|
|
// 分类ID列表
|
|
categoryIds?: number[];
|
|
// 品牌ID
|
|
brandId?: number;
|
|
// 品牌ID列表
|
|
brandIds?: number[];
|
|
// 产品类型
|
|
type?: string;
|
|
// 价格最小值
|
|
minPrice?: number;
|
|
// 价格最大值
|
|
maxPrice?: number;
|
|
// 促销价格最小值
|
|
minPromotionPrice?: number;
|
|
// 促销价格最大值
|
|
maxPromotionPrice?: number;
|
|
// 创建时间范围开始
|
|
createdAtStart?: string;
|
|
// 创建时间范围结束
|
|
createdAtEnd?: string;
|
|
// 更新时间范围开始
|
|
updatedAtStart?: string;
|
|
// 更新时间范围结束
|
|
updatedAtEnd?: string;
|
|
// TODO 使用 attributes 过滤
|
|
attributes?: Record<string, string>;
|
|
}
|
|
|
|
/**
|
|
* 产品查询过滤条件DTO
|
|
*/
|
|
export class ProductWhereFilterDTO {
|
|
@ApiProperty({ description: '产品ID', example: 1 })
|
|
id?: number;
|
|
|
|
@ApiProperty({ description: '产品ID列表', example: [1, 2, 3] })
|
|
ids?: number[];
|
|
|
|
@ApiProperty({ description: 'SKU', example: 'ZYN-6MG-WINTERGREEN' })
|
|
sku?: string;
|
|
|
|
@ApiProperty({ description: 'SKU列表', example: ['ZYN-6MG-WINTERGREEN', 'ZYN-3MG-WINTERGREEN'] })
|
|
skus?: string[];
|
|
|
|
@ApiProperty({ description: '产品名称', example: 'ZYN 6MG WINTERGREEN' })
|
|
name?: string;
|
|
|
|
@ApiProperty({ description: '产品中文名称', example: 'ZYN 6毫克 冬清味' })
|
|
nameCn?: string;
|
|
|
|
@ApiProperty({ description: '分类ID', example: 1 })
|
|
categoryId?: number;
|
|
|
|
@ApiProperty({ description: '分类ID列表', example: [1, 2, 3] })
|
|
categoryIds?: number[];
|
|
|
|
@ApiProperty({ description: '品牌ID', example: 1 })
|
|
brandId?: number;
|
|
|
|
@ApiProperty({ description: '品牌ID列表', example: [1, 2, 3] })
|
|
brandIds?: number[];
|
|
|
|
@ApiProperty({ description: '产品类型', example: 'single', enum: ['single', 'bundle'] })
|
|
type?: string;
|
|
|
|
@ApiProperty({ description: '价格最小值', example: 99.99 })
|
|
minPrice?: number;
|
|
|
|
@ApiProperty({ description: '价格最大值', example: 199.99 })
|
|
maxPrice?: number;
|
|
|
|
@ApiProperty({ description: '促销价格最小值', example: 89.99 })
|
|
minPromotionPrice?: number;
|
|
|
|
@ApiProperty({ description: '促销价格最大值', example: 179.99 })
|
|
maxPromotionPrice?: number;
|
|
|
|
@ApiProperty({ description: '创建时间范围开始', example: '2023-01-01 00:00:00' })
|
|
createdAtStart?: string;
|
|
|
|
@ApiProperty({ description: '创建时间范围结束', example: '2023-12-31 23:59:59' })
|
|
createdAtEnd?: string;
|
|
|
|
@ApiProperty({ description: '更新时间范围开始', example: '2023-01-01 00:00:00' })
|
|
updatedAtStart?: string;
|
|
|
|
@ApiProperty({ description: '更新时间范围结束', example: '2023-12-31 23:59:59' })
|
|
updatedAtEnd?: string;
|
|
}
|
|
|
|
/**
|
|
* DTO 用于分页查询产品
|
|
* 支持灵活的where条件、分页和排序
|
|
*/
|
|
export class QueryProductDTO extends UnifiedSearchParamsDTO<ProductWhereFilter> {
|
|
|
|
}
|
|
|
|
/**
|
|
* DTO 用于创建分类
|
|
*/
|
|
export class CreateCategoryDTO {
|
|
@ApiProperty({ description: '分类显示名称', required: true })
|
|
@Rule(RuleType.string().required())
|
|
title: string;
|
|
|
|
@ApiProperty({ description: '分类中文名称', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
titleCN?: string;
|
|
|
|
@ApiProperty({ description: '分类唯一标识', required: true })
|
|
@Rule(RuleType.string().required())
|
|
name: string;
|
|
|
|
@ApiProperty({ description: '分类短名称,用于生成SKU', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
shortName?: string;
|
|
|
|
@ApiProperty({ description: '排序', required: false })
|
|
@Rule(RuleType.number().optional())
|
|
sort?: number;
|
|
}
|
|
|
|
/**
|
|
* DTO 用于更新分类
|
|
*/
|
|
export class UpdateCategoryDTO {
|
|
@ApiProperty({ description: '分类显示名称', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
title?: string;
|
|
|
|
@ApiProperty({ description: '分类中文名称', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
titleCN?: string;
|
|
|
|
@ApiProperty({ description: '分类唯一标识', required: false })
|
|
@Rule(RuleType.string().optional())
|
|
name?: string;
|
|
|
|
@ApiProperty({ description: '分类短名称,用于生成SKU', required: false })
|
|
@Rule(RuleType.string().allow('').optional())
|
|
shortName?: string;
|
|
|
|
@ApiProperty({ description: '排序', required: false })
|
|
@Rule(RuleType.number().optional())
|
|
sort?: number;
|
|
}
|
|
|