|
@@ -80,6 +80,8 @@ updatedAt!: Date;
|
|
|
|
|
|
|
|
## 7. Zod Schema 规范
|
|
## 7. Zod Schema 规范
|
|
|
|
|
|
|
|
|
|
+### 7.1 基础类型规范
|
|
|
|
|
+
|
|
|
```typescript
|
|
```typescript
|
|
|
export const EntitySchema = z.object({
|
|
export const EntitySchema = z.object({
|
|
|
id: z.number().int().positive().openapi({ description: 'ID说明' }),
|
|
id: z.number().int().positive().openapi({ description: 'ID说明' }),
|
|
@@ -87,11 +89,11 @@ export const EntitySchema = z.object({
|
|
|
fieldName: z.string()
|
|
fieldName: z.string()
|
|
|
.max(255)
|
|
.max(255)
|
|
|
.nullable()
|
|
.nullable()
|
|
|
- .openapi({
|
|
|
|
|
|
|
+ .openapi({
|
|
|
description: '字段说明',
|
|
description: '字段说明',
|
|
|
example: '示例值'
|
|
example: '示例值'
|
|
|
}),
|
|
}),
|
|
|
- // 数字字段
|
|
|
|
|
|
|
+ // 数字字段
|
|
|
numberField: z.number()
|
|
numberField: z.number()
|
|
|
.default(默认值)
|
|
.default(默认值)
|
|
|
.openapi({...}),
|
|
.openapi({...}),
|
|
@@ -100,6 +102,133 @@ export const EntitySchema = z.object({
|
|
|
});
|
|
});
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+### 7.2 数据类型转换规范
|
|
|
|
|
+
|
|
|
|
|
+#### 7.2.1 数字类型转换
|
|
|
|
|
+
|
|
|
|
|
+对于URL参数或表单数据中的数字类型,必须使用`z.coerce.number()`进行类型转换,以确保字符串到数字的正确转换:
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 整数类型
|
|
|
|
|
+z.coerce.number().int().positive().openapi({
|
|
|
|
|
+ description: '正整数ID',
|
|
|
|
|
+ example: 1
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 小数类型
|
|
|
|
|
+z.coerce.number().multipleOf(0.01).openapi({
|
|
|
|
|
+ description: '金额,保留两位小数',
|
|
|
|
|
+ example: 19.99
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 状态类型(0/1)
|
|
|
|
|
+z.coerce.number().int().min(0).max(1).openapi({
|
|
|
|
|
+ description: '状态(0-禁用,1-启用)',
|
|
|
|
|
+ example: 1
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 7.2.2 日期类型转换
|
|
|
|
|
+
|
|
|
|
|
+对于日期时间类型,必须使用`z.coerce.date()`进行类型转换:
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 日期时间类型
|
|
|
|
|
+z.coerce.date().openapi({
|
|
|
|
|
+ description: '创建时间',
|
|
|
|
|
+ example: '2023-10-01T12:00:00Z'
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// 日期范围查询
|
|
|
|
|
+const DateRangeSchema = z.object({
|
|
|
|
|
+ startDate: z.coerce.date().openapi({
|
|
|
|
|
+ description: '开始日期',
|
|
|
|
|
+ example: '2023-10-01T00:00:00Z'
|
|
|
|
|
+ }),
|
|
|
|
|
+ endDate: z.coerce.date().openapi({
|
|
|
|
|
+ description: '结束日期',
|
|
|
|
|
+ example: '2023-10-31T23:59:59Z'
|
|
|
|
|
+ })
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 7.2.3 布尔类型转换
|
|
|
|
|
+
|
|
|
|
|
+对于布尔类型参数,必须使用`z.coerce.boolean()`进行类型转换:
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 布尔类型
|
|
|
|
|
+z.coerce.boolean().openapi({
|
|
|
|
|
+ description: '是否启用',
|
|
|
|
|
+ example: true
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7.3 创建/更新Schema特殊规范
|
|
|
|
|
+
|
|
|
|
|
+创建(Create)和更新(Update)Schema必须遵循以下额外规范:
|
|
|
|
|
+
|
|
|
|
|
+1. **创建Schema**:
|
|
|
|
|
+ - 不包含`id`字段(由数据库自动生成)
|
|
|
|
|
+ - 所有必填字段必须显式定义,不得为`optional()`
|
|
|
|
|
+ - 必须使用适当的coerce方法处理非字符串类型
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+export const CreateEntityDto = z.object({
|
|
|
|
|
+ name: z.string().max(255).openapi({
|
|
|
|
|
+ description: '名称',
|
|
|
|
|
+ example: '示例名称'
|
|
|
|
|
+ }),
|
|
|
|
|
+ quantity: z.coerce.number().int().min(1).openapi({
|
|
|
|
|
+ description: '数量',
|
|
|
|
|
+ example: 10
|
|
|
|
|
+ }),
|
|
|
|
|
+ price: z.coerce.number().multipleOf(0.01).openapi({
|
|
|
|
|
+ description: '价格',
|
|
|
|
|
+ example: 99.99
|
|
|
|
|
+ }),
|
|
|
|
|
+ isActive: z.coerce.boolean().default(true).openapi({
|
|
|
|
|
+ description: '是否激活',
|
|
|
|
|
+ example: true
|
|
|
|
|
+ }),
|
|
|
|
|
+ expireDate: z.coerce.date().openapi({
|
|
|
|
|
+ description: '过期日期',
|
|
|
|
|
+ example: '2024-12-31T23:59:59Z'
|
|
|
|
|
+ })
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. **更新Schema**:
|
|
|
|
|
+ - 不包含`id`字段(通过URL参数传递)
|
|
|
|
|
+ - 所有字段必须为`optional()`
|
|
|
|
|
+ - 必须使用适当的coerce方法处理非字符串类型
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+export const UpdateEntityDto = z.object({
|
|
|
|
|
+ name: z.string().max(255).optional().openapi({
|
|
|
|
|
+ description: '名称',
|
|
|
|
|
+ example: '更新后的名称'
|
|
|
|
|
+ }),
|
|
|
|
|
+ quantity: z.coerce.number().int().min(1).optional().openapi({
|
|
|
|
|
+ description: '数量',
|
|
|
|
|
+ example: 20
|
|
|
|
|
+ }),
|
|
|
|
|
+ price: z.coerce.number().multipleOf(0.01).optional().openapi({
|
|
|
|
|
+ description: '价格',
|
|
|
|
|
+ example: 89.99
|
|
|
|
|
+ }),
|
|
|
|
|
+ isActive: z.coerce.boolean().optional().openapi({
|
|
|
|
|
+ description: '是否激活',
|
|
|
|
|
+ example: false
|
|
|
|
|
+ }),
|
|
|
|
|
+ expireDate: z.coerce.date().optional().openapi({
|
|
|
|
|
+ description: '过期日期',
|
|
|
|
|
+ example: '2025-12-31T23:59:59Z'
|
|
|
|
|
+ })
|
|
|
|
|
+});
|
|
|
|
|
+```
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
## 8. 命名规范
|
|
## 8. 命名规范
|
|
|
|
|
|
|
|
- 实体类名:PascalCase (如 RackInfo)
|
|
- 实体类名:PascalCase (如 RackInfo)
|