Explorar el Código

📝 docs(file-relation): add documentation for generic CRUD file relation configuration
- 添加场景3:通用CRUD路由配置中relations字段的使用说明
- 补充注意事项5:关联查询的自动处理说明

♻️ refactor(advertisement): optimize file relation implementation
- 删除冗余的img字段及其相关定义
- 修复advertisementRoutes中缺失的relations配置
- 清理schema中重复的imageFileId定义

yourname hace 4 meses
padre
commit
ce65d9dc19

+ 23 - 0
.roo/commands/file-relation.md

@@ -126,12 +126,35 @@ avatarFile: z.object({
 ### 场景2: 多文件关联
 如需关联多个文件,请使用 ManyToMany 关联,参考广告实体的实现。
 
+### 场景3: 通用CRUD路由配置
+对于使用通用CRUD路由的实体,需要配置 `relations` 以自动关联查询文件信息:
+
+```typescript
+// 示例:广告实体的通用CRUD配置
+import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
+import { Advertisement } from '@/server/modules/advertisements/advertisement.entity';
+import { AdvertisementSchema, CreateAdvertisementDto, UpdateAdvertisementDto } from '@/server/modules/advertisements/advertisement.schema';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+const advertisementRoutes = createCrudRoutes({
+  entity: Advertisement,
+  createSchema: CreateAdvertisementDto,
+  updateSchema: UpdateAdvertisementDto,
+  getSchema: AdvertisementSchema,
+  listSchema: AdvertisementSchema,
+  searchFields: ['title', 'code'],
+  relations: ['imageFile'], // 关键配置:自动关联查询图片文件
+  middleware: [authMiddleware]
+});
+```
+
 ## 注意事项
 
 1. **空值处理**: 字段必须支持 `null`,允许无文件关联
 2. **级联操作**: 默认不级联,删除文件不会影响关联实体
 3. **文件验证**: 前端需先上传文件获取文件ID,再进行实体关联
 4. **类型安全**: 确保所有字段类型定义一致(number | null)
+5. **关联查询**: 配置 `relations` 后,通用CRUD会自动处理关联查询
 
 ## 扩展说明
 

+ 1 - 0
src/server/api/advertisements/index.ts

@@ -10,6 +10,7 @@ const advertisementRoutes = createCrudRoutes({
   getSchema: AdvertisementSchema,
   listSchema: AdvertisementSchema,
   searchFields: ['title', 'code'],
+  relations: ['imageFile'],
   middleware: [authMiddleware]
 });
 

+ 0 - 9
src/server/modules/advertisements/advertisement.entity.ts

@@ -41,15 +41,6 @@ export class Advertisement {
   })
   url!: string | null;
 
-  @Column({
-    name: 'img',
-    type: 'varchar',
-    length: 100,
-    nullable: true,
-    comment: '图片'
-  })
-  img!: string | null;
-
   @Column({
     name: 'image_file_id',
     type: 'int',

+ 3 - 15
src/server/modules/advertisements/advertisement.schema.ts

@@ -22,10 +22,6 @@ export const AdvertisementSchema = z.object({
     description: '跳转URL',
     example: 'https://example.com'
   }),
-  img: z.string().max(100).nullable().openapi({
-    description: '图片地址',
-    example: '/uploads/banner.jpg'
-  }),
   imageFileId: z.number().int().positive().nullable().openapi({
     description: '图片文件ID',
     example: 1
@@ -79,14 +75,6 @@ export const CreateAdvertisementDto = z.object({
     description: '跳转URL',
     example: 'https://example.com'
   }),
-  img: z.string().max(100).nullable().optional().openapi({
-    description: '图片地址',
-    example: '/uploads/banner.jpg'
-  }),
-  imageFileId: z.coerce.number().int().positive().optional().openapi({
-    description: '图片文件ID',
-    example: 1
-  }),
   imageFileId: z.coerce.number().int().positive().optional().openapi({
     description: '图片文件ID',
     example: 1
@@ -123,9 +111,9 @@ export const UpdateAdvertisementDto = z.object({
     description: '跳转URL',
     example: 'https://example.com'
   }),
-  img: z.string().max(100).nullable().optional().openapi({
-    description: '图片地址',
-    example: '/uploads/banner.jpg'
+  imageFileId: z.coerce.number().int().positive().optional().openapi({
+    description: '图片文件ID',
+    example: 1
   }),
   sort: z.coerce.number().int().optional().openapi({
     description: '排序值',