| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- 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<QrCode>
- private personInfoRepository: Repository<PersonInfo>
- private petInfoRepository: Repository<PetInfo>
- 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<Array<{ qrCode: string; maintenanceCode: string }>> {
- 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<boolean> {
- const entity = await this.qrCodeRepository.findOne({ where: { qrCode } })
- if (!entity) {
- return false
- }
- return bcrypt.compare(maintenanceCode, entity.maintenanceCode)
- }
- /**
- * 根据二维码获取信息
- */
- async getQrCodeInfo(qrCode: string): Promise<any> {
- 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<void> {
- await this.qrCodeRepository.increment({ id: qrCodeId }, 'scanCount', 1)
- }
- /**
- * 激活二维码
- */
- async activateQrCode(qrCodeId: number): Promise<void> {
- await this.qrCodeRepository.update(qrCodeId, { isActivated: true })
- }
- /**
- * 查询二维码列表
- */
- async queryQrCodes(
- qrType?: QrType,
- isActivated?: boolean,
- startDate?: string,
- endDate?: string,
- page: number = 0,
- pageSize: number = 20
- ): Promise<PaginationResponse<QrCode>> {
- 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<QrCode[]> {
- return this.qrCodeRepository
- .createQueryBuilder('qrCode')
- .where('DATE(qrCode.createdAt) = :date', { date })
- .orderBy('qrCode.createdAt', 'ASC')
- .getMany()
- }
- /**
- * 根据ID获取二维码
- */
- async findById(id: number): Promise<QrCode | null> {
- return this.qrCodeRepository.findOne({ where: { id } })
- }
- /**
- * 根据qrCode获取实体
- */
- async findByQrCode(qrCode: string): Promise<QrCode | null> {
- return this.qrCodeRepository.findOne({ where: { qrCode } })
- }
- }
|