Bläddra i källkod

添加管理员获取详细信息接口,支持通过二维码ID查询物品、人员和宠物信息,并更新相关服务和路由配置。

wuyi 1 månad sedan
förälder
incheckning
1af8750a6d

+ 21 - 0
src/controllers/goods-info.controller.ts

@@ -131,4 +131,25 @@ export class GoodsInfoController {
       return reply.code(500).send({ message })
     }
   }
+
+  async adminGetDetail(request: FastifyRequest<{ Querystring: { qrCodeId: string } }>, reply: FastifyReply) {
+    try {
+      const { qrCodeId } = request.query
+
+      if (!qrCodeId) {
+        return reply.code(400).send({ message: '请提供二维码ID' })
+      }
+
+      const goodsInfo = await this.goodsInfoService.adminGetDetail(Number(qrCodeId))
+
+      if (!goodsInfo) {
+        return reply.code(404).send({ message: '物品信息不存在' })
+      }
+
+      return reply.send(goodsInfo)
+    } catch (error) {
+      const message = error instanceof Error ? error.message : '获取失败'
+      return reply.code(500).send({ message })
+    }
+  }
 }

+ 21 - 0
src/controllers/person-info.controller.ts

@@ -123,4 +123,25 @@ export class PersonInfoController {
       return reply.code(500).send({ message })
     }
   }
+
+  async adminGetDetail(request: FastifyRequest<{ Querystring: { qrCodeId: string } }>, reply: FastifyReply) {
+    try {
+      const { qrCodeId } = request.query
+
+      if (!qrCodeId) {
+        return reply.code(400).send({ message: '请提供二维码ID' })
+      }
+
+      const personInfo = await this.personInfoService.adminGetDetail(Number(qrCodeId))
+
+      if (!personInfo) {
+        return reply.code(404).send({ message: '人员信息不存在' })
+      }
+
+      return reply.send(personInfo)
+    } catch (error) {
+      const message = error instanceof Error ? error.message : '获取失败'
+      return reply.code(500).send({ message })
+    }
+  }
 }

+ 21 - 0
src/controllers/pet-info.controller.ts

@@ -126,4 +126,25 @@ export class PetInfoController {
       return reply.code(500).send({ message })
     }
   }
+
+  async adminGetDetail(request: FastifyRequest<{ Querystring: { qrCodeId: string } }>, reply: FastifyReply) {
+    try {
+      const { qrCodeId } = request.query
+
+      if (!qrCodeId) {
+        return reply.code(400).send({ message: '请提供二维码ID' })
+      }
+
+      const petInfo = await this.petInfoService.adminGetDetail(Number(qrCodeId))
+
+      if (!petInfo) {
+        return reply.code(404).send({ message: '宠物/物品信息不存在' })
+      }
+
+      return reply.send(petInfo)
+    } catch (error) {
+      const message = error instanceof Error ? error.message : '获取失败'
+      return reply.code(500).send({ message })
+    }
+  }
 }

+ 9 - 6
src/controllers/qr-code.controller.ts

@@ -96,20 +96,23 @@ export class QrCodeController {
    */
   async getInfo(request: FastifyRequest<{ Querystring: GetQrCodeInfoDto }>, reply: FastifyReply) {
     try {
-      const { qrCode } = request.query
+      const { qrCode, id } = request.query
 
-      if (!qrCode) {
-        return reply.code(400).send({ message: '请提供二维码参数' })
+      if (!qrCode && !id) {
+        return reply.code(400).send({ message: '请提供参数' })
       }
 
       // 记录扫描
       const ipAddress = request.ip
       const userAgent = request.headers['user-agent']
 
-      await this.scanRecordService.create(qrCode, undefined, undefined, undefined, ipAddress, userAgent)
-
       // 获取二维码信息
-      const info = await this.qrCodeService.getQrCodeInfo(qrCode)
+      const info = await this.qrCodeService.getQrCodeInfo(qrCode, id)
+
+      // 如果通过 qrCode 查询,记录扫描
+      if (qrCode) {
+        await this.scanRecordService.create(qrCode, undefined, undefined, undefined, ipAddress, userAgent)
+      }
 
       return reply.send(info)
     } catch (error) {

+ 6 - 1
src/dto/qr-code.dto.ts

@@ -48,6 +48,11 @@ export class VerifyMaintenanceCodeDto {
 }
 
 export class GetQrCodeInfoDto {
+  @IsOptional()
   @IsString()
-  qrCode: string
+  qrCode?: string
+
+  @IsOptional()
+  @IsNumber()
+  id?: number
 }

+ 7 - 1
src/routes/goods-info.routes.ts

@@ -19,11 +19,17 @@ export default async function goodsInfoRoutes(fastify: FastifyInstance) {
   fastify.get<{ Querystring: { qrCode: string } }>('/get', goodsInfoController.get.bind(goodsInfoController))
 
   fastify.get<{ Querystring: QueryGoodsInfoDto }>(
-    '/list',
+    '/admin/list',
     { onRequest: [hasRole(UserRole.ADMIN)] },
     goodsInfoController.list.bind(goodsInfoController)
   )
 
+  fastify.get<{ Querystring: { qrCodeId: string } }>(
+    '/admin/detail',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    goodsInfoController.adminGetDetail.bind(goodsInfoController)
+  )
+
   fastify.post<{ Body: AdminUpdateGoodsInfoDto }>(
     '/admin/update',
     { onRequest: [hasRole(UserRole.ADMIN)] },

+ 7 - 1
src/routes/person-info.routes.ts

@@ -19,11 +19,17 @@ export default async function personInfoRoutes(fastify: FastifyInstance) {
   fastify.get<{ Querystring: { qrCode: string } }>('/get', personInfoController.get.bind(personInfoController))
 
   fastify.get<{ Querystring: QueryPersonInfoDto }>(
-    '/list',
+    '/admin/list',
     { onRequest: [hasRole(UserRole.ADMIN)] },
     personInfoController.list.bind(personInfoController)
   )
 
+  fastify.get<{ Querystring: { qrCodeId: string } }>(
+    '/admin/detail',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    personInfoController.adminGetDetail.bind(personInfoController)
+  )
+
   fastify.post<{ Body: AdminUpdatePersonInfoDto }>(
     '/admin/update',
     { onRequest: [hasRole(UserRole.ADMIN)] },

+ 7 - 1
src/routes/pet-info.routes.ts

@@ -14,11 +14,17 @@ export default async function petInfoRoutes(fastify: FastifyInstance) {
   fastify.get<{ Querystring: { qrCode: string } }>('/get', petInfoController.get.bind(petInfoController))
 
   fastify.get<{ Querystring: QueryPetInfoDto }>(
-    '/list',
+    '/admin/list',
     { onRequest: [hasRole(UserRole.ADMIN)] },
     petInfoController.list.bind(petInfoController)
   )
 
+  fastify.get<{ Querystring: { qrCodeId: string } }>(
+    '/admin/detail',
+    { onRequest: [hasRole(UserRole.ADMIN)] },
+    petInfoController.adminGetDetail.bind(petInfoController)
+  )
+
   fastify.post<{ Body: AdminUpdatePetInfoDto }>(
     '/admin/update',
     { onRequest: [hasRole(UserRole.ADMIN)] },

+ 26 - 0
src/services/goods-info.service.ts

@@ -5,14 +5,17 @@ import { QrCodeService } from './qr-code.service'
 import { QrType } from '../entities/qr-code.entity'
 import { PaginationResponse } from '../dto/common.dto'
 import { AdminUpdateGoodsInfoDto } from '../dto/goods-info.dto'
+import { FileService } from './file.service'
 
 export class GoodsInfoService {
   private goodsInfoRepository: Repository<GoodsInfo>
   private qrCodeService: QrCodeService
+  private fileService: FileService
 
   constructor(app: FastifyInstance) {
     this.goodsInfoRepository = app.dataSource.getRepository(GoodsInfo)
     this.qrCodeService = new QrCodeService(app)
+    this.fileService = new FileService(app)
   }
 
   async create(qrCode: string, data: Partial<GoodsInfo>): Promise<GoodsInfo> {
@@ -150,4 +153,27 @@ export class GoodsInfoService {
       }
     }
   }
+
+  async adminGetDetail(qrCodeId: number): Promise<GoodsInfo | null> {
+    const goodsInfo = await this.goodsInfoRepository.findOne({
+      where: { qrCodeId }
+    })
+
+    if (!goodsInfo) {
+      return null
+    }
+
+    // 如果有图片URL,生成带签名的URL
+    if (goodsInfo.photoUrl) {
+      try {
+        const signedUrl = await this.fileService.getSignedUrl(goodsInfo.photoUrl)
+        return { ...goodsInfo, photoUrl: signedUrl }
+      } catch (error) {
+        // 如果生成签名URL失败,返回原始数据
+        return goodsInfo
+      }
+    }
+
+    return goodsInfo
+  }
 }

+ 26 - 0
src/services/person-info.service.ts

@@ -5,14 +5,17 @@ import { QrCodeService } from './qr-code.service'
 import { QrType } from '../entities/qr-code.entity'
 import { PaginationResponse } from '../dto/common.dto'
 import { AdminUpdatePersonInfoDto } from '../dto/person-info.dto'
+import { FileService } from './file.service'
 
 export class PersonInfoService {
   private personInfoRepository: Repository<PersonInfo>
   private qrCodeService: QrCodeService
+  private fileService: FileService
 
   constructor(app: FastifyInstance) {
     this.personInfoRepository = app.dataSource.getRepository(PersonInfo)
     this.qrCodeService = new QrCodeService(app)
+    this.fileService = new FileService(app)
   }
 
   async create(qrCode: string, data: Partial<PersonInfo>): Promise<PersonInfo> {
@@ -150,4 +153,27 @@ export class PersonInfoService {
       }
     }
   }
+
+  async adminGetDetail(qrCodeId: number): Promise<PersonInfo | null> {
+    const personInfo = await this.personInfoRepository.findOne({
+      where: { qrCodeId }
+    })
+
+    if (!personInfo) {
+      return null
+    }
+
+    // 如果有图片URL,生成带签名的URL
+    if (personInfo.photoUrl) {
+      try {
+        const signedUrl = await this.fileService.getSignedUrl(personInfo.photoUrl)
+        return { ...personInfo, photoUrl: signedUrl }
+      } catch (error) {
+        // 如果生成签名URL失败,返回原始数据
+        return personInfo
+      }
+    }
+
+    return personInfo
+  }
 }

+ 26 - 0
src/services/pet-info.service.ts

@@ -5,14 +5,17 @@ import { QrCodeService } from './qr-code.service'
 import { QrType } from '../entities/qr-code.entity'
 import { PaginationResponse } from '../dto/common.dto'
 import { AdminUpdatePetInfoDto } from '../dto/pet-info.dto'
+import { FileService } from './file.service'
 
 export class PetInfoService {
   private petInfoRepository: Repository<PetInfo>
   private qrCodeService: QrCodeService
+  private fileService: FileService
 
   constructor(app: FastifyInstance) {
     this.petInfoRepository = app.dataSource.getRepository(PetInfo)
     this.qrCodeService = new QrCodeService(app)
+    this.fileService = new FileService(app)
   }
 
   async create(qrCode: string, data: Partial<PetInfo>): Promise<PetInfo> {
@@ -150,4 +153,27 @@ export class PetInfoService {
       }
     }
   }
+
+  async adminGetDetail(qrCodeId: number): Promise<PetInfo | null> {
+    const petInfo = await this.petInfoRepository.findOne({
+      where: { qrCodeId }
+    })
+
+    if (!petInfo) {
+      return null
+    }
+
+    // 如果有图片URL,生成带签名的URL
+    if (petInfo.photoUrl) {
+      try {
+        const signedUrl = await this.fileService.getSignedUrl(petInfo.photoUrl)
+        return { ...petInfo, photoUrl: signedUrl }
+      } catch (error) {
+        // 如果生成签名URL失败,返回原始数据
+        return petInfo
+      }
+    }
+
+    return petInfo
+  }
 }

+ 10 - 3
src/services/qr-code.service.ts

@@ -90,10 +90,17 @@ export class QrCodeService {
   }
 
   /**
-   * 根据二维码获取信息
+   * 根据二维码或ID获取信息
    */
-  async getQrCodeInfo(qrCode: string): Promise<any> {
-    const entity = await this.qrCodeRepository.findOne({ where: { qrCode } })
+  async getQrCodeInfo(qrCode?: string, id?: number): Promise<any> {
+    let entity: QrCode | null = null
+
+    if (qrCode) {
+      entity = await this.qrCodeRepository.findOne({ where: { qrCode } })
+    } else if (id) {
+      entity = await this.qrCodeRepository.findOne({ where: { id } })
+    }
+
     if (!entity) {
       throw new Error('二维码不存在')
     }