Jelajahi Sumber

新增批量创建鱼友记录接口,更新相关 DTO 和服务逻辑,确保支持鱼友 ID 的处理。同时,调整记录创建和查询接口,增强参数验证。

wuyi 4 bulan lalu
induk
melakukan
880ada5133

+ 21 - 0
src/controllers/fish-friends.controller.ts

@@ -3,6 +3,7 @@ import { FishFriendsService } from '../services/fish-friends.service'
 import {
   ListFishFriendsQuery,
   CreateFishFriendsBody,
+  BatchCreateFishFriendsBody,
   UpdateFishFriendsBody,
   DeleteFishFriendsBody
 } from '../dto/fish-friends.dto'
@@ -49,6 +50,26 @@ export class FishFriendsController {
     }
   }
 
+  async batchUpsert(request: FastifyRequest<{ Body: BatchCreateFishFriendsBody }>, reply: FastifyReply) {
+    try {
+      const { fishFriends } = request.body
+
+      if (!fishFriends || !Array.isArray(fishFriends) || fishFriends.length === 0) {
+        return reply.code(400).send({ message: '请提供有效的朋友列表' })
+      }
+
+      // 使用批量 upsert 操作
+      await this.fishFriendsService.batchUpsert(fishFriends)
+
+      return reply.code(201).send({
+        message: `批量操作完成`
+      })
+    } catch (error) {
+      console.error('批量创建记录失败:', error)
+      return reply.code(500).send({ message: '批量失败' })
+    }
+  }
+
   async getById(request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) {
     try {
       const { id } = request.params

+ 20 - 11
src/controllers/records.controller.ts

@@ -31,23 +31,29 @@ export class RecordsController {
       const filename = data.filename
       const mimeType = data.mimetype
       
-      // 从表单字段中获取描述
+      // 从表单字段中获取描述和 fishId
       const description = (data.fields?.description as any)?.value || ''
+      const fishId = (data.fields?.fishId as any)?.value || ''
+
+      if (!fishId) {
+        return reply.code(400).send({ message: 'FishId 不能为空' })
+      }
 
       // 上传文件到OSS
       const uploadResult = await this.fileService.uploadFile(buffer, filename, mimeType, {
         folder: 'tweb',
-        maxSize: 50 * 1024 * 1024 // 50MB
+        maxSize: 500 * 1024 * 1024 // 500MB
       })
 
       // 创建记录
-      const record = await this.recordsService.create(uploadResult.url, description)
+      const record = await this.recordsService.create(fishId, uploadResult.url, description)
 
       return reply.code(201).send({
         message: '文件上传并创建记录成功',
         data: {
           record: {
             id: record.id,
+            fishId: record.fishId,
             url: record.url,
             description: record.description,
             createdAt: record.createdAt,
@@ -74,17 +80,18 @@ export class RecordsController {
 
   async create(request: FastifyRequest<{ Body: CreateRecordsBody }>, reply: FastifyReply) {
     try {
-      const { url, description } = request.body
+      const { fishId, url, description } = request.body
 
-      if (!url || !description) {
-        return reply.code(400).send({ message: 'URL和描述不能为空' })
+      if (!fishId || !url || !description) {
+        return reply.code(400).send({ message: 'FishId、URL和描述不能为空' })
       }
 
-      const record = await this.recordsService.create(url, description)
+      const record = await this.recordsService.create(fishId, url, description)
 
       return reply.code(201).send({
         record: {
           id: record.id,
+          fishId: record.fishId,
           url: record.url,
           description: record.description,
           createdAt: record.createdAt,
@@ -98,9 +105,9 @@ export class RecordsController {
 
   async list(request: FastifyRequest<{ Querystring: ListRecordsQuery }>, reply: FastifyReply) {
     try {
-      const { page, size, url, description } = request.query
+      const { page, size, fishId, url, description } = request.query
 
-      const result = await this.recordsService.findAll(page, size, url, description)
+      const result = await this.recordsService.findAll(page, size, fishId, url, description)
 
       return reply.send(result)
     } catch (error) {
@@ -121,6 +128,7 @@ export class RecordsController {
       return reply.send({
         record: {
           id: record.id,
+          fishId: record.fishId,
           url: record.url,
           description: record.description,
           createdAt: record.createdAt,
@@ -137,7 +145,7 @@ export class RecordsController {
 
   async update(request: FastifyRequest<{ Body: UpdateRecordsBody }>, reply: FastifyReply) {
     try {
-      const { id, url, description } = request.body
+      const { id, fishId, url, description } = request.body
 
       if (!id) {
         return reply.code(400).send({ message: 'ID不能为空' })
@@ -149,11 +157,12 @@ export class RecordsController {
         return reply.code(404).send({ message: '记录不存在' })
       }
 
-      const updatedRecord = await this.recordsService.updateRecord(id, { url, description })
+      const updatedRecord = await this.recordsService.updateRecord(id, { fishId, url, description })
 
       return reply.send({
         record: {
           id: updatedRecord.id,
+          fishId: updatedRecord.fishId,
           url: updatedRecord.url,
           description: updatedRecord.description,
           createdAt: updatedRecord.createdAt,

+ 4 - 0
src/dto/fish-friends.dto.ts

@@ -23,6 +23,10 @@ export interface CreateFishFriendsBody {
   remark?: string
 }
 
+export interface BatchCreateFishFriendsBody {
+  fishFriends: CreateFishFriendsBody[]
+}
+
 export interface UpdateFishFriendsBody {
   id: string
   fishId?: string

+ 3 - 0
src/dto/records.dto.ts

@@ -1,17 +1,20 @@
 import { Pagination } from './common.dto'
 
 export interface CreateRecordsBody {
+  fishId: string
   url: string
   description: string
 }
 
 export interface UpdateRecordsBody {
   id: number
+  fishId?: string
   url?: string
   description?: string
 }
 
 export interface ListRecordsQuery extends Pagination {
+  fishId?: string
   url?: string
   description?: string
 } 

+ 3 - 0
src/entities/records.entity.ts

@@ -5,6 +5,9 @@ export class Records {
   @PrimaryGeneratedColumn()
   id: number
 
+  @Column()
+  fishId: string
+
   @Column({ length: 1024 })
   url: string
 

+ 7 - 1
src/routes/fish-friends.routes.ts

@@ -1,7 +1,7 @@
 import { FastifyInstance } from 'fastify'
 import { FishFriendsController } from '../controllers/fish-friends.controller'
 import { authenticate } from '../middlewares/auth.middleware'
-import { ListFishFriendsQuery, CreateFishFriendsBody, UpdateFishFriendsBody, DeleteFishFriendsBody } from '../dto/fish-friends.dto'
+import { ListFishFriendsQuery, CreateFishFriendsBody, BatchCreateFishFriendsBody, UpdateFishFriendsBody, DeleteFishFriendsBody } from '../dto/fish-friends.dto'
 
 export default async function fishFriendsRoutes(fastify: FastifyInstance) {
   const fishFriendsController = new FishFriendsController(fastify)
@@ -12,6 +12,12 @@ export default async function fishFriendsRoutes(fastify: FastifyInstance) {
     fishFriendsController.create.bind(fishFriendsController)
   )
 
+  // 批量创建记录
+  fastify.post<{ Body: BatchCreateFishFriendsBody }>(
+    '/batch',
+    fishFriendsController.batchUpsert.bind(fishFriendsController)
+  )
+
   // 根据ID获取记录
   fastify.get<{ Params: { id: string } }>(
     '/:id',

+ 4 - 0
src/services/fish-friends.service.ts

@@ -102,6 +102,10 @@ export class FishFriendsService {
     await this.fishFriendsRepository.delete({ id: In(ids) })
   }
 
+  async batchUpsert(dataList: Partial<FishFriends>[]): Promise<void> {
+    await this.fishFriendsRepository.upsert(dataList, ['id'])
+  }
+
   async countByFishId(fishId: string): Promise<number> {
     return this.fishFriendsRepository.count({ where: { fishId } })
   }

+ 6 - 2
src/services/records.service.ts

@@ -10,8 +10,9 @@ export class RecordsService {
     this.recordsRepository = app.dataSource.getRepository(Records)
   }
 
-  async create(url: string, description: string): Promise<Records> {
+  async create(fishId: string, url: string, description: string): Promise<Records> {
     const record = this.recordsRepository.create({
+      fishId,
       url,
       description
     })
@@ -22,9 +23,12 @@ export class RecordsService {
     return this.recordsRepository.findOneOrFail({ where: { id } })
   }
 
-  async findAll(page: number = 0, size: number = 20, url?: string, description?: string): Promise<PaginationResponse<Records>> {
+  async findAll(page: number = 0, size: number = 20, fishId?: string, url?: string, description?: string): Promise<PaginationResponse<Records>> {
     const where: any = {}
     
+    if (fishId) {
+      where.fishId = fishId
+    }
     if (url) {
       where.url = Like(`%${url}%`)
     }