import { Repository, Between, LessThanOrEqual, MoreThanOrEqual } from 'typeorm' import { FastifyInstance } from 'fastify' import { QrCode, QrType } from '../entities/qr-code.entity' import { PersonInfo } from '../entities/person-info.entity' import { PetInfo } from '../entities/pet-info.entity' import { PaginationResponse } from '../dto/common.dto' import bcrypt from 'bcryptjs' import { randomBytes } from 'crypto' export class QrCodeService { private qrCodeRepository: Repository private personInfoRepository: Repository private petInfoRepository: Repository constructor(app: FastifyInstance) { this.qrCodeRepository = app.dataSource.getRepository(QrCode) this.personInfoRepository = app.dataSource.getRepository(PersonInfo) this.petInfoRepository = app.dataSource.getRepository(PetInfo) } /** * 生成唯一的二维码编号 */ private generateQrCode(): string { const timestamp = Date.now().toString(36) const random = randomBytes(8).toString('hex') return `QR${timestamp}${random}`.toUpperCase() } /** * 生成维护码 */ private generateMaintenanceCode(): string { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' let code = '' for (let i = 0; i < 8; i++) { code += chars.charAt(Math.floor(Math.random() * chars.length)) } return code } /** * 生成二维码 */ async generateQrCodes( qrType: QrType, quantity: number = 1 ): Promise> { const result = [] for (let i = 0; i < quantity; i++) { const qrCode = this.generateQrCode() const maintenanceCode = this.generateMaintenanceCode() const hashedMaintenanceCode = await bcrypt.hash(maintenanceCode, 10) const entity = this.qrCodeRepository.create({ qrCode, maintenanceCode: hashedMaintenanceCode, qrType, isActivated: false, scanCount: 0 }) await this.qrCodeRepository.save(entity) result.push({ qrCode, maintenanceCode }) } return result } /** * 验证维护码 */ async verifyMaintenanceCode(qrCode: string, maintenanceCode: string): Promise { const entity = await this.qrCodeRepository.findOne({ where: { qrCode } }) if (!entity) { return false } return bcrypt.compare(maintenanceCode, entity.maintenanceCode) } /** * 根据二维码获取信息 */ async getQrCodeInfo(qrCode: string): Promise { const entity = await this.qrCodeRepository.findOne({ where: { qrCode } }) if (!entity) { throw new Error('二维码不存在') } let info = null if (entity.qrType === QrType.PERSON) { info = await this.personInfoRepository.findOne({ where: { qrCodeId: entity.id } }) } else if (entity.qrType === QrType.PET) { info = await this.petInfoRepository.findOne({ where: { qrCodeId: entity.id } }) } return { id: entity.id, qrCode: entity.qrCode, qrType: entity.qrType, isActivated: entity.isActivated, scanCount: entity.scanCount, info } } /** * 增加扫描次数 */ async incrementScanCount(qrCodeId: number): Promise { await this.qrCodeRepository.increment({ id: qrCodeId }, 'scanCount', 1) } /** * 激活二维码 */ async activateQrCode(qrCodeId: number): Promise { await this.qrCodeRepository.update(qrCodeId, { isActivated: true }) } /** * 查询二维码列表 */ async queryQrCodes( qrType?: QrType, isActivated?: boolean, startDate?: string, endDate?: string, page: number = 0, pageSize: number = 20 ): Promise> { const queryBuilder = this.qrCodeRepository.createQueryBuilder('qrCode') if (qrType) { queryBuilder.andWhere('qrCode.qrType = :qrType', { qrType }) } if (isActivated !== undefined) { queryBuilder.andWhere('qrCode.isActivated = :isActivated', { isActivated }) } if (startDate && endDate) { queryBuilder.andWhere('DATE(qrCode.createdAt) BETWEEN :startDate AND :endDate', { startDate, endDate }) } else if (startDate) { queryBuilder.andWhere('DATE(qrCode.createdAt) >= :startDate', { startDate }) } else if (endDate) { queryBuilder.andWhere('DATE(qrCode.createdAt) <= :endDate', { endDate }) } const [content, total] = await queryBuilder .select([ 'qrCode.id', 'qrCode.qrCode', 'qrCode.qrType', 'qrCode.isActivated', 'qrCode.scanCount', 'qrCode.createdAt', 'qrCode.updatedAt' ]) .skip(page * pageSize) .take(pageSize) .orderBy('qrCode.createdAt', 'DESC') .getManyAndCount() return { content, metadata: { total: Number(total), page: Number(page), size: Number(pageSize) } } } /** * 根据日期获取二维码列表(用于下载) */ async getQrCodesByDate(date: string): Promise { return this.qrCodeRepository .createQueryBuilder('qrCode') .where('DATE(qrCode.createdAt) = :date', { date }) .orderBy('qrCode.createdAt', 'ASC') .getMany() } /** * 根据ID获取二维码 */ async findById(id: number): Promise { return this.qrCodeRepository.findOne({ where: { id } }) } /** * 根据qrCode获取实体 */ async findByQrCode(qrCode: string): Promise { return this.qrCodeRepository.findOne({ where: { qrCode } }) } }