Ver Fonte

优化二维码服务,调整查询逻辑以支持日期范围过滤,并确保二维码只能绑定一个用户,更新相关DTO和服务逻辑以提升功能完整性。

wuyi há 3 dias atrás
pai
commit
90907fe536

+ 1 - 1
src/controllers/qr-code.controller.ts

@@ -254,7 +254,7 @@ export class QrCodeController {
       const userId = request.user.id
       const { qrCodeId, qrCode, maintenanceCode } = request.body
 
-      const userQrCode = await this.qrCodeService.bindQrCode(userId, qrCodeId, qrCode, maintenanceCode)
+      await this.qrCodeService.bindQrCode(userId, qrCodeId, qrCode, maintenanceCode)
 
       return reply.code(201).send({
         message: 'Bound successfully'

+ 1 - 1
src/entities/user-qr-code.entity.ts

@@ -13,7 +13,7 @@ import { QrCode } from './qr-code.entity'
 
 @Entity()
 @Index(['userId', 'isDeleted'])
-@Index(['qrCodeId', 'isDeleted'])
+@Index(['qrCodeId', 'isDeleted', 'id'])
 @Index(['userId', 'qrCodeId'])
 export class UserQrCode {
   @PrimaryGeneratedColumn()

+ 66 - 15
src/services/qr-code.service.ts

@@ -6,6 +6,7 @@ import { PetInfo } from '../entities/pet-info.entity'
 import { GoodsInfo } from '../entities/goods-info.entity'
 import { LinkInfo } from '../entities/link-info.entity'
 import { UserQrCode } from '../entities/user-qr-code.entity'
+import { User } from '../entities/user.entity'
 import { PaginationResponse } from '../dto/common.dto'
 import { FileService } from './file.service'
 
@@ -248,44 +249,82 @@ export class QrCodeService {
     endDate?: string,
     page: number = 0,
     pageSize: number = 20
-  ): Promise<PaginationResponse<QrCode>> {
-    const queryBuilder = this.qrCodeRepository.createQueryBuilder('qrCode')
+  ): Promise<PaginationResponse<any>> {
+    const baseQueryBuilder = this.qrCodeRepository.createQueryBuilder('qrCode')
 
     if (qrCode) {
-      queryBuilder.andWhere('qrCode.qrCode = :qrCode', { qrCode })
+      baseQueryBuilder.andWhere('qrCode.qrCode = :qrCode', { qrCode })
     }
 
     if (qrType) {
-      queryBuilder.andWhere('qrCode.qrType = :qrType', { qrType })
+      baseQueryBuilder.andWhere('qrCode.qrType = :qrType', { qrType })
     }
 
     if (isActivated !== undefined) {
       const isActivatedBool =
         typeof isActivated === 'string' ? isActivated === 'true' || isActivated === '1' : Boolean(isActivated)
-      queryBuilder.andWhere('qrCode.isActivated = :isActivated', { isActivated: isActivatedBool })
+      baseQueryBuilder.andWhere('qrCode.isActivated = :isActivated', { isActivated: isActivatedBool })
     }
 
     if (startDate && endDate) {
-      queryBuilder.andWhere('DATE(qrCode.createdAt) BETWEEN :startDate AND :endDate', { startDate, endDate })
+      const start = `${startDate} 00:00:00`
+      const end = `${endDate} 23:59:59`
+      baseQueryBuilder.andWhere('qrCode.createdAt BETWEEN :start AND :end', { start, end })
     } else if (startDate) {
-      queryBuilder.andWhere('DATE(qrCode.createdAt) >= :startDate', { startDate })
+      const start = `${startDate} 00:00:00`
+      baseQueryBuilder.andWhere('qrCode.createdAt >= :start', { start })
     } else if (endDate) {
-      queryBuilder.andWhere('DATE(qrCode.createdAt) <= :endDate', { endDate })
+      const end = `${endDate} 23:59:59`
+      baseQueryBuilder.andWhere('qrCode.createdAt <= :end', { end })
     }
 
-    const [content, total] = await queryBuilder
-      .select()
+    const [qrCodes, total] = await baseQueryBuilder
+      .clone()
       .skip(page * pageSize)
       .take(pageSize)
       .orderBy('qrCode.createdAt', 'DESC')
       .getManyAndCount()
 
+    const qrCodeIds = qrCodes.map(item => item.id).filter(Boolean)
+
+    const ownerByQrCodeId = new Map<number, { ownerId: number; ownerName: string }>()
+
+    if (qrCodeIds.length > 0) {
+      const rows = await this.userQrCodeRepository
+        .createQueryBuilder('uq')
+        .leftJoin(User, 'owner', 'owner.id = uq.userId')
+        .select('uq.qrCodeId', 'qrCodeId')
+        .addSelect('owner.id', 'ownerId')
+        .addSelect('owner.name', 'ownerName')
+        .where('uq.isDeleted = :isDeleted', { isDeleted: false })
+        .andWhere('uq.qrCodeId IN (:...qrCodeIds)', { qrCodeIds })
+        .orderBy('uq.qrCodeId', 'ASC')
+        .addOrderBy('uq.id', 'DESC')
+        .getRawMany<{ qrCodeId: number; ownerId: number; ownerName: string }>()
+
+      for (const row of rows) {
+        const id = Number((row as any).qrCodeId)
+        if (!ownerByQrCodeId.has(id) && (row as any).ownerId != null) {
+          ownerByQrCodeId.set(id, { ownerId: Number((row as any).ownerId), ownerName: (row as any).ownerName })
+        }
+      }
+    }
+
+    const content = qrCodes.map(entity => {
+      const owner = ownerByQrCodeId.get(entity.id)
+      return {
+        ...entity,
+        ownerId: owner?.ownerId ?? null,
+        ownerName: owner?.ownerName ?? null
+      }
+    })
+
     return {
       content,
       metadata: {
-        total: Number(total),
-        page: Number(page),
-        size: Number(pageSize)
+        total: total,
+        page: page,
+        size: pageSize
       }
     }
   }
@@ -294,9 +333,11 @@ export class QrCodeService {
    * 根据日期获取二维码列表(用于下载)
    */
   async getQrCodesByDate(date: string): Promise<QrCode[]> {
+    const start = `${date} 00:00:00`
+    const end = `${date} 23:59:59`
     return this.qrCodeRepository
       .createQueryBuilder('qrCode')
-      .where('DATE(qrCode.createdAt) = :date', { date })
+      .where('qrCode.createdAt BETWEEN :start AND :end', { start, end })
       .orderBy('qrCode.createdAt', 'ASC')
       .getMany()
   }
@@ -378,6 +419,17 @@ export class QrCodeService {
       throw new Error('Maintenance code error')
     }
 
+    // 一个二维码只能绑定一个用户
+    const activeBind = await this.userQrCodeRepository.findOne({
+      where: { qrCodeId: targetQrCodeId, isDeleted: false }
+    })
+    if (activeBind) {
+      if (activeBind.userId !== userId) {
+        throw new Error('QR code already bound')
+      }
+      return activeBind
+    }
+
     const existing = await this.userQrCodeRepository.findOne({
       where: { userId, qrCodeId: targetQrCodeId }
     })
@@ -497,7 +549,6 @@ export class QrCodeService {
         remark: qrCode?.remark
       }
 
-      // 根据类型添加特定字段
       if (qrType === QrType.LINK) {
         result.jumpUrl = jumpUrl
       } else if (qrType === QrType.PERSON || qrType === QrType.PET || qrType === QrType.GOODS) {