Selaa lähdekoodia

新增消息功能,包括消息控制器、服务、路由和数据传输对象(DTO),支持创建、更新、删除和查询消息,增强了消息管理的灵活性和完整性。

wuyi 2 kuukautta sitten
vanhempi
commit
47c8cdfae1

+ 2 - 0
src/app.ts

@@ -13,6 +13,7 @@ import recordsRoutes from './routes/records.routes'
 import fileRoutes from './routes/file.routes'
 import fishRoutes from './routes/fish.routes'
 import fishFriendsRoutes from './routes/fish-friends.routes'
+import messagesRoutes from './routes/messages.routes'
 
 const options: FastifyEnvOptions = {
   schema: schema,
@@ -82,6 +83,7 @@ export const createApp = async () => {
   app.register(fileRoutes, { prefix: '/api/files' })
   app.register(fishRoutes, { prefix: '/api/fish' })
   app.register(fishFriendsRoutes, { prefix: '/api/fish-friends' })
+  app.register(messagesRoutes, { prefix: '/api/messages' })
 
   const dataSource = createDataSource(app)
   await dataSource.initialize()

+ 194 - 0
src/controllers/messages.controller.ts

@@ -0,0 +1,194 @@
+import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify'
+import { MessagesService } from '../services/messages.service'
+import { CreateMessageBody, CreateMessagesBody, ListMessagesQuery, UpdateMessageBody } from '../dto/messages.dto'
+
+export class MessagesController {
+  private messagesService: MessagesService
+
+  constructor(app: FastifyInstance) {
+    this.messagesService = new MessagesService(app)
+  }
+
+  async create(request: FastifyRequest<{ Body: CreateMessageBody }>, reply: FastifyReply) {
+    try {
+      const { userId, fishId, targetId, message } = request.body
+
+      if (!userId || !fishId || !targetId || !message) {
+        return reply.code(400).send({ message: '用户ID、鱼类ID、目标ID和消息内容不能为空' })
+      }
+
+      if (message.trim().length === 0) {
+        return reply.code(400).send({ message: '消息内容不能为空' })
+      }
+
+      await this.messagesService.create(userId, fishId, targetId, message)
+
+      return reply.code(201).send({
+        message: '消息创建成功'
+      })
+    } catch (error) {
+      return reply.code(500).send({ message: '创建消息失败', error: (error as Error).message })
+    }
+  }
+
+  async createBatch(request: FastifyRequest<{ Body: CreateMessagesBody }>, reply: FastifyReply) {
+    try {
+      const { messages } = request.body
+
+      if (!messages || !Array.isArray(messages) || messages.length === 0) {
+        return reply.code(400).send({ message: '消息列表不能为空' })
+      }
+
+      // 验证每个消息的必填字段
+      for (const msg of messages) {
+        if (!msg.userId || !msg.fishId || !msg.targetId || !msg.message) {
+          return reply.code(400).send({ message: '每个消息必须包含用户ID、鱼类ID、目标ID和消息内容' })
+        }
+        if (msg.message.trim().length === 0) {
+          return reply.code(400).send({ message: '消息内容不能为空' })
+        }
+      }
+
+      const messageEntities = await this.messagesService.createBatch(messages)
+
+      return reply.code(201).send({
+        message: `成功创建 ${messageEntities.length} 条消息`
+      })
+    } catch (error) {
+      return reply.code(500).send({ message: '批量创建消息失败', error: (error as Error).message })
+    }
+  }
+
+  async list(request: FastifyRequest<{ Querystring: ListMessagesQuery }>, reply: FastifyReply) {
+    try {
+      const { page = 0, size = 20, userId, fishId, targetId } = request.query
+
+      const result = await this.messagesService.list(page, size, userId, fishId, targetId)
+
+      return reply.send({
+        message: '获取消息列表成功',
+        data: result
+      })
+    } catch (error) {
+      return reply.code(500).send({ message: '获取消息列表失败', error: (error as Error).message })
+    }
+  }
+
+  async getById(request: FastifyRequest<{ Params: { id: number } }>, reply: FastifyReply) {
+    try {
+      const { id } = request.params
+
+      const message = await this.messagesService.findById(id)
+
+      return reply.send({
+        message: '获取消息详情成功',
+        data: {
+          id: message.id,
+          userId: message.userId,
+          fishId: message.fishId,
+          targetId: message.targetId,
+          message: message.message,
+          createdAt: message.createdAt,
+          updatedAt: message.updatedAt
+        }
+      })
+    } catch (error) {
+      if ((error as Error).name === 'EntityNotFoundError') {
+        return reply.code(404).send({ message: '消息不存在' })
+      }
+      return reply.code(500).send({ message: '获取消息详情失败', error: (error as Error).message })
+    }
+  }
+
+  async update(request: FastifyRequest<{ Body: UpdateMessageBody }>, reply: FastifyReply) {
+    try {
+      const { id, message } = request.body
+
+      if (!id) {
+        return reply.code(400).send({ message: '消息ID不能为空' })
+      }
+
+      if (!message || message.trim().length === 0) {
+        return reply.code(400).send({ message: '消息内容不能为空' })
+      }
+
+      const updatedMessage = await this.messagesService.update(id, message)
+
+      return reply.send({
+        message: '消息更新成功',
+        data: {
+          id: updatedMessage.id,
+          userId: updatedMessage.userId,
+          fishId: updatedMessage.fishId,
+          targetId: updatedMessage.targetId,
+          message: updatedMessage.message,
+          createdAt: updatedMessage.createdAt,
+          updatedAt: updatedMessage.updatedAt
+        }
+      })
+    } catch (error) {
+      if ((error as Error).name === 'EntityNotFoundError') {
+        return reply.code(404).send({ message: '消息不存在' })
+      }
+      return reply.code(500).send({ message: '更新消息失败', error: (error as Error).message })
+    }
+  }
+
+  async delete(request: FastifyRequest<{ Params: { id: number } }>, reply: FastifyReply) {
+    try {
+      const { id } = request.params
+
+      // 先检查消息是否存在
+      await this.messagesService.findById(id)
+
+      await this.messagesService.delete(id)
+
+      return reply.send({
+        message: '消息删除成功'
+      })
+    } catch (error) {
+      if ((error as Error).name === 'EntityNotFoundError') {
+        return reply.code(404).send({ message: '消息不存在' })
+      }
+      return reply.code(500).send({ message: '删除消息失败', error: (error as Error).message })
+    }
+  }
+
+  async getByUserId(request: FastifyRequest<{ Params: { userId: number } }>, reply: FastifyReply) {
+    try {
+      const { userId } = request.params
+
+      const messages = await this.messagesService.findByUserId(userId)
+
+      return reply.send({
+        message: '获取用户消息成功',
+        data: messages
+      })
+    } catch (error) {
+      return reply.code(500).send({ message: '获取用户消息失败', error: (error as Error).message })
+    }
+  }
+
+  async getByFishId(request: FastifyRequest<{ Params: { fishId: number } }>, reply: FastifyReply) {
+    try {
+      const { fishId } = request.params
+    } catch (error) {
+      return reply.code(500).send({ message: '获取鱼类消息失败', error: (error as Error).message })
+    }
+  }
+
+  async getByTargetId(request: FastifyRequest<{ Params: { targetId: number } }>, reply: FastifyReply) {
+    try {
+      const { targetId } = request.params
+
+      const messages = await this.messagesService.findByTargetId(targetId)
+
+      return reply.send({
+        message: '获取目标消息成功',
+        data: messages
+      })
+    } catch (error) {
+      return reply.code(500).send({ message: '获取目标消息失败', error: (error as Error).message })
+    }
+  }
+}

+ 24 - 0
src/dto/messages.dto.ts

@@ -0,0 +1,24 @@
+import { FastifyRequest } from 'fastify'
+import { Pagination } from './common.dto'
+
+export interface CreateMessageBody {
+  userId: number
+  fishId: number
+  targetId: number
+  message: string
+}
+
+export interface CreateMessagesBody {
+  messages: CreateMessageBody[]
+}
+
+export interface ListMessagesQuery extends Pagination {
+  userId?: number
+  fishId?: number
+  targetId?: number
+}
+
+export interface UpdateMessageBody {
+  id: number
+  message?: string
+}

+ 25 - 0
src/entities/messages.entity.ts

@@ -0,0 +1,25 @@
+import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'
+
+@Entity()
+export class Messages {
+  @PrimaryGeneratedColumn()
+  id: number
+
+  @Column({ nullable: false, default: 0 })
+  userId: number
+
+  @Column({ type: 'bigint', nullable: false, default: 0 })
+  fishId: number
+
+  @Column({ type: 'bigint', nullable: false, default: 0 })
+  targetId: number
+
+  @Column({ type: 'text' })
+  message: string
+
+  @CreateDateColumn()
+  createdAt: Date
+
+  @UpdateDateColumn()
+  updatedAt: Date
+}

+ 64 - 0
src/routes/messages.routes.ts

@@ -0,0 +1,64 @@
+import { FastifyInstance } from 'fastify'
+import { MessagesController } from '../controllers/messages.controller'
+import { hasRole } from '../middlewares/auth.middleware'
+import { CreateMessageBody, CreateMessagesBody, ListMessagesQuery, UpdateMessageBody } from '../dto/messages.dto'
+import { UserRole } from '../entities/user.entity'
+
+export default async function messagesRoutes(fastify: FastifyInstance) {
+  const messagesController = new MessagesController(fastify)
+
+  // 创建单条消息
+  fastify.post<{ Body: CreateMessageBody }>('/', messagesController.create.bind(messagesController))
+
+  // 批量创建消息
+  fastify.post<{ Body: CreateMessagesBody }>('/batch', messagesController.createBatch.bind(messagesController))
+
+  // 获取消息列表(支持分页和筛选)
+  fastify.get<{ Querystring: ListMessagesQuery }>(
+    '/',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.list.bind(messagesController)
+  )
+
+  // 根据ID获取消息详情
+  fastify.get<{ Params: { id: number } }>(
+    '/:id',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.getById.bind(messagesController)
+  )
+
+  // 更新消息
+  fastify.put<{ Body: UpdateMessageBody }>(
+    '/',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.update.bind(messagesController)
+  )
+
+  // 删除消息
+  fastify.delete<{ Params: { id: number } }>(
+    '/:id',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.delete.bind(messagesController)
+  )
+
+  // 根据用户ID获取消息
+  fastify.get<{ Params: { userId: number } }>(
+    '/user/:userId',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.getByUserId.bind(messagesController)
+  )
+
+  // 根据鱼类ID获取消息
+  fastify.get<{ Params: { fishId: number } }>(
+    '/fish/:fishId',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.getByFishId.bind(messagesController)
+  )
+
+  // 根据目标ID获取消息
+  fastify.get<{ Params: { targetId: number } }>(
+    '/target/:targetId',
+    { onRequest: hasRole(UserRole.ADMIN) },
+    messagesController.getByTargetId.bind(messagesController)
+  )
+}

+ 88 - 0
src/services/messages.service.ts

@@ -0,0 +1,88 @@
+import { Repository } from 'typeorm'
+import { FastifyInstance } from 'fastify'
+import { Messages } from '../entities/messages.entity'
+import { PaginationResponse } from '../dto/common.dto'
+import { CreateMessageBody } from '../dto/messages.dto'
+
+export class MessagesService {
+  private messagesRepository: Repository<Messages>
+
+  constructor(app: FastifyInstance) {
+    this.messagesRepository = app.dataSource.getRepository(Messages)
+  }
+
+  async create(userId: number, fishId: number, targetId: number, message: string): Promise<Messages> {
+    console.log('userId', userId)
+    console.log('fishId', fishId)
+    console.log('targetId', targetId)
+    console.log('message', message)
+    const messageEntity = this.messagesRepository.create({
+      userId,
+      fishId,
+      targetId,
+      message
+    })
+    return this.messagesRepository.save(messageEntity)
+  }
+
+  async createBatch(messages: CreateMessageBody[]): Promise<Messages[]> {
+    const messageEntities = this.messagesRepository.create(messages)
+    return this.messagesRepository.save(messageEntities)
+  }
+
+  async findById(id: number): Promise<Messages> {
+    return this.messagesRepository.findOneOrFail({ where: { id } })
+  }
+
+  async list(
+    page: number, 
+    size: number, 
+    userId?: number, 
+    fishId?: number,
+    targetId?: number
+  ): Promise<PaginationResponse<Messages>> {
+    const where: any = {}
+    if (userId) where.userId = userId
+    if (fishId) where.fishId = fishId
+    if (targetId) where.targetId = targetId
+
+    const [messages, total] = await this.messagesRepository.findAndCount({
+      skip: (Number(page) || 0) * (Number(size) || 20),
+      take: Number(size) || 20,
+      where,
+      order: { createdAt: 'DESC' }
+    })
+
+    return {
+      content: messages,
+      metadata: {
+        total: Number(total),
+        page: Number(page),
+        size: Number(size)
+      }
+    }
+  }
+
+  async update(id: number, message: string): Promise<Messages> {
+    await this.messagesRepository.update(id, { message })
+    return this.findById(id)
+  }
+
+  async delete(id: number): Promise<void> {
+    await this.messagesRepository.delete(id)
+  }
+
+  async findByUserId(userId: number): Promise<Messages[]> {
+    return this.messagesRepository.find({
+      where: { userId },
+      order: { createdAt: 'DESC' }
+    })
+  }
+
+  async findByTargetId(targetId: number): Promise<Messages[]> {
+    return this.messagesRepository.find({
+      where: { targetId },
+      order: { createdAt: 'DESC' }
+    })
+  }
+}