import { z } from '@hono/zod-openapi'; import { GoodsCategorySchema } from './goods-category.schema'; import { SupplierSchema } from '@/server/modules/supplier/supplier.schema'; import { FileSchema } from '@/server/modules/files/file.schema'; export const GoodsSchema = z.object({ id: z.number().int().positive().openapi({ description: '商品ID' }), name: z.string().min(1, '商品名称不能为空').max(255, '商品名称最多255个字符').openapi({ description: '商品名称', example: 'iPhone 15' }), price: z.coerce.number().multipleOf(0.01, '价格最多保留两位小数').min(0, '价格不能为负数').default(0).openapi({ description: '售卖价', example: 5999.99 }), costPrice: z.coerce.number().multipleOf(0.01, '成本价最多保留两位小数').min(0, '成本价不能为负数').default(0).openapi({ description: '成本价', example: 4999.99 }), salesNum: z.coerce.number().int().nonnegative('销售数量必须为非负数').default(0).openapi({ description: '销售数量', example: 100 }), clickNum: z.coerce.number().int().nonnegative('点击次数必须为非负数').default(0).openapi({ description: '点击次数', example: 1000 }), categoryId1: z.number().int().nonnegative('一级类别ID必须为非负数').default(0).openapi({ description: '一级类别id', example: 1 }), categoryId2: z.number().int().nonnegative('二级类别ID必须为非负数').default(0).openapi({ description: '二级类别id', example: 2 }), categoryId3: z.number().int().nonnegative('三级类别ID必须为非负数').default(0).openapi({ description: '三级类别id', example: 3 }), goodsType: z.number().int().min(1).max(2).default(1).openapi({ description: '订单类型 1实物产品 2虚拟产品', example: 1 }), supplierId: z.number().int().positive().nullable().openapi({ description: '所属供应商id', example: 1 }), imageFileId: z.number().int().positive().nullable().openapi({ description: '商品主图文件ID', example: 1 }), slideImages: z.array(FileSchema).nullable().optional().openapi({ description: '商品轮播图文件列表', example: [{ id: 1, name: 'image1.jpg', fullUrl: 'https://example.com/image1.jpg', type: 'image/jpeg', size: 102400 }] }), detail: z.string().nullable().optional().openapi({ description: '商品详情', example: '这是商品详情内容' }), instructions: z.string().max(255, '简介最多255个字符').nullable().optional().openapi({ description: '简介', example: '高品质智能手机' }), sort: z.number().int().nonnegative('排序值必须为非负数').default(0).openapi({ description: '排序', example: 0 }), state: z.number().int().min(1).max(2).default(1).openapi({ description: '状态 1可用 2不可用', example: 1 }), stock: z.coerce.number().int().nonnegative('库存必须为非负数').default(0).openapi({ description: '库存', example: 100 }), spuId: z.number().int().nonnegative('主商品ID必须为非负数').default(0).openapi({ description: '主商品ID', example: 0 }), spuName: z.string().max(255, '主商品名称最多255个字符').nullable().optional().openapi({ description: '主商品名称', example: 'iPhone系列' }), lowestBuy: z.number().int().positive('最小起购量必须为正整数').default(1).openapi({ description: '最小起购量', example: 1 }), category1: GoodsCategorySchema.nullable().optional().openapi({ description: '一级分类信息' }), category2: GoodsCategorySchema.nullable().optional().openapi({ description: '二级分类信息' }), category3: GoodsCategorySchema.nullable().optional().openapi({ description: '三级分类信息' }), supplier: SupplierSchema.nullable().optional().openapi({ description: '供应商信息' }), imageFile: FileSchema.nullable().optional().openapi({ description: '商品主图信息' }), createdAt: z.coerce.date().openapi({ description: '创建时间', example: '2024-01-01T12:00:00Z' }), updatedAt: z.coerce.date().openapi({ description: '更新时间', example: '2024-01-01T12:00:00Z' }), createdBy: z.number().int().positive().nullable().openapi({ description: '创建用户ID', example: 1 }), updatedBy: z.number().int().positive().nullable().openapi({ description: '更新用户ID', example: 1 }), }); export const CreateGoodsDto = z.object({ name: z.string().min(1, '商品名称不能为空').max(255, '商品名称最多255个字符').openapi({ description: '商品名称', example: 'iPhone 15' }), price: z.coerce.number().multipleOf(0.01, '价格最多保留两位小数').min(0, '价格不能为负数').default(0).openapi({ description: '售卖价', example: 5999.99 }), costPrice: z.coerce.number().multipleOf(0.01, '成本价最多保留两位小数').min(0, '成本价不能为负数').default(0).openapi({ description: '成本价', example: 4999.99 }), categoryId1: z.number().int().nonnegative('一级类别ID必须为非负数').default(0).openapi({ description: '一级类别id', example: 1 }), categoryId2: z.number().int().nonnegative('二级类别ID必须为非负数').default(0).openapi({ description: '二级类别id', example: 2 }), categoryId3: z.number().int().nonnegative('三级类别ID必须为非负数').default(0).openapi({ description: '三级类别id', example: 3 }), goodsType: z.number().int().min(1).max(2).default(1).openapi({ description: '订单类型 1实物产品 2虚拟产品', example: 1 }), supplierId: z.number().int().positive().nullable().optional().openapi({ description: '所属供应商id', example: 1 }), imageFileId: z.number().int().positive().nullable().optional().openapi({ description: '商品主图文件ID', example: 1 }), slideImageIds: z.array(z.number().int().positive()).nullable().optional().openapi({ description: '商品轮播图文件ID数组', example: [1, 2, 3] }), detail: z.string().nullable().optional().openapi({ description: '商品详情', example: '这是商品详情内容' }), instructions: z.string().max(255, '简介最多255个字符').nullable().optional().openapi({ description: '简介', example: '高品质智能手机' }), sort: z.number().int().nonnegative('排序值必须为非负数').default(0).openapi({ description: '排序', example: 0 }), state: z.number().int().min(1).max(2).default(1).openapi({ description: '状态 1可用 2不可用', example: 1 }), stock: z.coerce.number().int().nonnegative('库存必须为非负数').default(0).openapi({ description: '库存', example: 100 }), spuId: z.number().int().nonnegative('主商品ID必须为非负数').default(0).openapi({ description: '主商品ID', example: 0 }), spuName: z.string().max(255, '主商品名称最多255个字符').nullable().optional().openapi({ description: '主商品名称', example: 'iPhone系列' }), lowestBuy: z.number().int().positive('最小起购量必须为正整数').default(1).openapi({ description: '最小起购量', example: 1 }) }); export const UpdateGoodsDto = z.object({ name: z.string().min(1, '商品名称不能为空').max(255, '商品名称最多255个字符').optional().openapi({ description: '商品名称', example: 'iPhone 15' }), price: z.coerce.number().multipleOf(0.01, '价格最多保留两位小数').min(0, '价格不能为负数').optional().openapi({ description: '售卖价', example: 5999.99 }), costPrice: z.coerce.number().multipleOf(0.01, '成本价最多保留两位小数').min(0, '成本价不能为负数').optional().openapi({ description: '成本价', example: 4999.99 }), categoryId1: z.number().int().nonnegative('一级类别ID必须为非负数').optional().openapi({ description: '一级类别id', example: 1 }), categoryId2: z.number().int().nonnegative('二级类别ID必须为非负数').optional().openapi({ description: '二级类别id', example: 2 }), categoryId3: z.number().int().nonnegative('三级类别ID必须为非负数').optional().openapi({ description: '三级类别id', example: 3 }), goodsType: z.number().int().min(1).max(2).optional().openapi({ description: '订单类型 1实物产品 2虚拟产品', example: 1 }), supplierId: z.number().int().positive().nullable().optional().openapi({ description: '所属供应商id', example: 1 }), imageFileId: z.number().int().positive().nullable().optional().openapi({ description: '商品主图文件ID', example: 1 }), slideImageIds: z.array(z.number().int().positive()).nullable().optional().openapi({ description: '商品轮播图文件ID数组', example: [1, 2, 3] }), detail: z.string().nullable().optional().openapi({ description: '商品详情', example: '这是商品详情内容' }), instructions: z.string().max(255, '简介最多255个字符').nullable().optional().openapi({ description: '简介', example: '高品质智能手机' }), sort: z.number().int().nonnegative('排序值必须为非负数').optional().openapi({ description: '排序', example: 0 }), state: z.number().int().min(1).max(2).optional().openapi({ description: '状态 1可用 2不可用', example: 1 }), stock: z.coerce.number().int().nonnegative('库存必须为非负数').optional().openapi({ description: '库存', example: 100 }), spuId: z.number().int().nonnegative('主商品ID必须为非负数').optional().openapi({ description: '主商品ID', example: 0 }), spuName: z.string().max(255, '主商品名称最多255个字符').nullable().optional().openapi({ description: '主商品名称', example: 'iPhone系列' }), lowestBuy: z.number().int().positive('最小起购量必须为正整数').optional().openapi({ description: '最小起购量', example: 1 }) });