|
|
@@ -5,6 +5,7 @@ import { PersonInfo } from '../entities/person-info.entity'
|
|
|
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 { PaginationResponse } from '../dto/common.dto'
|
|
|
import { FileService } from './file.service'
|
|
|
|
|
|
@@ -14,6 +15,7 @@ export class QrCodeService {
|
|
|
private petInfoRepository: Repository<PetInfo>
|
|
|
private goodsInfoRepository: Repository<GoodsInfo>
|
|
|
private linkInfoRepository: Repository<LinkInfo>
|
|
|
+ private userQrCodeRepository: Repository<UserQrCode>
|
|
|
private fileService: FileService
|
|
|
private app: FastifyInstance
|
|
|
|
|
|
@@ -23,6 +25,7 @@ export class QrCodeService {
|
|
|
this.petInfoRepository = app.dataSource.getRepository(PetInfo)
|
|
|
this.goodsInfoRepository = app.dataSource.getRepository(GoodsInfo)
|
|
|
this.linkInfoRepository = app.dataSource.getRepository(LinkInfo)
|
|
|
+ this.userQrCodeRepository = app.dataSource.getRepository(UserQrCode)
|
|
|
this.fileService = new FileService(app)
|
|
|
this.app = app
|
|
|
}
|
|
|
@@ -331,4 +334,152 @@ export class QrCodeService {
|
|
|
|
|
|
return newMaintenanceCode
|
|
|
}
|
|
|
+
|
|
|
+ async bindQrCode(userId: number, qrCodeId?: number, qrCode?: string, maintenanceCode?: string): Promise<UserQrCode> {
|
|
|
+ let targetQrCodeId: number
|
|
|
+ let targetQrCode: string
|
|
|
+
|
|
|
+ if (qrCodeId) {
|
|
|
+ const qrCodeEntity = await this.qrCodeRepository.findOne({ where: { id: qrCodeId } })
|
|
|
+ if (!qrCodeEntity) {
|
|
|
+ throw new Error('QR code not found')
|
|
|
+ }
|
|
|
+ targetQrCodeId = qrCodeId
|
|
|
+ targetQrCode = qrCodeEntity.qrCode
|
|
|
+ } else if (qrCode) {
|
|
|
+ const qrCodeEntity = await this.qrCodeRepository.findOne({ where: { qrCode } })
|
|
|
+ if (!qrCodeEntity) {
|
|
|
+ throw new Error('QR code not found')
|
|
|
+ }
|
|
|
+ targetQrCodeId = qrCodeEntity.id
|
|
|
+ targetQrCode = qrCode
|
|
|
+ } else {
|
|
|
+ throw new Error('Please provide qrCode')
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!maintenanceCode) {
|
|
|
+ throw new Error('Maintenance code cannot be empty')
|
|
|
+ }
|
|
|
+
|
|
|
+ const isValid = await this.verifyMaintenanceCode(targetQrCode, maintenanceCode)
|
|
|
+ if (!isValid) {
|
|
|
+ throw new Error('Maintenance code error')
|
|
|
+ }
|
|
|
+
|
|
|
+ const existing = await this.userQrCodeRepository.findOne({
|
|
|
+ where: { userId, qrCodeId: targetQrCodeId }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (existing) {
|
|
|
+ if (existing.isDeleted) {
|
|
|
+ existing.isDeleted = false
|
|
|
+ return await this.userQrCodeRepository.save(existing)
|
|
|
+ } else {
|
|
|
+ throw new Error('QR code already bound')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const userQrCode = this.userQrCodeRepository.create({
|
|
|
+ userId,
|
|
|
+ qrCodeId: targetQrCodeId,
|
|
|
+ isDeleted: false
|
|
|
+ })
|
|
|
+
|
|
|
+ return await this.userQrCodeRepository.save(userQrCode)
|
|
|
+ }
|
|
|
+
|
|
|
+ async unbindQrCode(userId: number, id?: number, qrCodeId?: number): Promise<void> {
|
|
|
+ let userQrCode: UserQrCode | null = null
|
|
|
+
|
|
|
+ if (id) {
|
|
|
+ userQrCode = await this.userQrCodeRepository.findOne({ where: { id, userId } })
|
|
|
+ } else if (qrCodeId) {
|
|
|
+ userQrCode = await this.userQrCodeRepository.findOne({ where: { qrCodeId, userId } })
|
|
|
+ } else {
|
|
|
+ throw new Error('Please provide qrCode')
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!userQrCode) {
|
|
|
+ throw new Error('Binding record not found')
|
|
|
+ }
|
|
|
+
|
|
|
+ if (userQrCode.isDeleted) {
|
|
|
+ throw new Error('Binding record already deleted')
|
|
|
+ }
|
|
|
+
|
|
|
+ userQrCode.isDeleted = true
|
|
|
+ await this.userQrCodeRepository.save(userQrCode)
|
|
|
+ }
|
|
|
+
|
|
|
+ async getUserQrCodes(userId: number, page: number = 0, pageSize: number = 20): Promise<PaginationResponse<any>> {
|
|
|
+ const [content, total] = await this.userQrCodeRepository
|
|
|
+ .createQueryBuilder('userQrCode')
|
|
|
+ .leftJoinAndSelect('userQrCode.qrCode', 'qrCode')
|
|
|
+ .leftJoinAndSelect('qrCode.personInfo', 'personInfo')
|
|
|
+ .leftJoinAndSelect('qrCode.petInfo', 'petInfo')
|
|
|
+ .leftJoinAndSelect('qrCode.goodsInfo', 'goodsInfo')
|
|
|
+ .leftJoinAndSelect('qrCode.linkInfo', 'linkInfo')
|
|
|
+ .where('userQrCode.userId = :userId', { userId })
|
|
|
+ .andWhere('userQrCode.isDeleted = :isDeleted', { isDeleted: false })
|
|
|
+ .skip(page * pageSize)
|
|
|
+ .take(pageSize)
|
|
|
+ .orderBy('userQrCode.createdAt', 'DESC')
|
|
|
+ .getManyAndCount()
|
|
|
+
|
|
|
+ const formattedContent = content.map(item => {
|
|
|
+ const qrCode = item.qrCode
|
|
|
+ const qrType = qrCode?.qrType
|
|
|
+
|
|
|
+ let info: any = null
|
|
|
+ let isVisible: boolean = true
|
|
|
+ let name: string | undefined = undefined
|
|
|
+ let jumpUrl: string | undefined = undefined
|
|
|
+
|
|
|
+ if (qrType === QrType.PERSON && qrCode?.personInfo) {
|
|
|
+ info = qrCode.personInfo
|
|
|
+ isVisible = info.isVisible ?? true
|
|
|
+ name = info.name
|
|
|
+ } else if (qrType === QrType.PET && qrCode?.petInfo) {
|
|
|
+ info = qrCode.petInfo
|
|
|
+ isVisible = info.isVisible ?? true
|
|
|
+ name = info.name
|
|
|
+ } else if (qrType === QrType.GOODS && qrCode?.goodsInfo) {
|
|
|
+ info = qrCode.goodsInfo
|
|
|
+ isVisible = info.isVisible ?? true
|
|
|
+ name = info.name
|
|
|
+ } else if (qrType === QrType.LINK && qrCode?.linkInfo) {
|
|
|
+ info = qrCode.linkInfo
|
|
|
+ isVisible = info.isVisible ?? true
|
|
|
+ jumpUrl = info.jumpUrl
|
|
|
+ }
|
|
|
+
|
|
|
+ const result: any = {
|
|
|
+ id: item.id,
|
|
|
+ qrCodeId: item.qrCodeId,
|
|
|
+ qrCode: qrCode?.qrCode,
|
|
|
+ qrType: qrType,
|
|
|
+ isActivated: qrCode?.isActivated,
|
|
|
+ lastScanAt: qrCode?.lastScanAt,
|
|
|
+ isVisible: isVisible
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据类型添加特定字段
|
|
|
+ if (qrType === QrType.LINK) {
|
|
|
+ result.jumpUrl = jumpUrl
|
|
|
+ } else if (qrType === QrType.PERSON || qrType === QrType.PET || qrType === QrType.GOODS) {
|
|
|
+ result.name = name
|
|
|
+ }
|
|
|
+
|
|
|
+ return result
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ content: formattedContent,
|
|
|
+ metadata: {
|
|
|
+ total: Number(total),
|
|
|
+ page: Number(page),
|
|
|
+ size: Number(pageSize)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|