|
|
@@ -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'
|
|
|
|
|
|
@@ -203,7 +204,8 @@ export class QrCodeService {
|
|
|
createdAt: entity.createdAt,
|
|
|
updatedAt: entity.updatedAt,
|
|
|
activatedAt: entity.activatedAt,
|
|
|
- lastScanAt: entity.lastScanAt
|
|
|
+ lastScanAt: entity.lastScanAt,
|
|
|
+ remark: entity.remark
|
|
|
}),
|
|
|
isActivated: entity.isActivated,
|
|
|
isVisible,
|
|
|
@@ -247,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
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -293,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()
|
|
|
}
|
|
|
@@ -377,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 }
|
|
|
})
|
|
|
@@ -422,6 +475,27 @@ export class QrCodeService {
|
|
|
await this.userQrCodeRepository.save(userQrCode)
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 更新二维码信息
|
|
|
+ */
|
|
|
+ async updateQrCode(qrCode: string, maintenanceCode: string, data: { remark?: string }): Promise<QrCode> {
|
|
|
+ const isValid = await this.verifyMaintenanceCode(qrCode, maintenanceCode)
|
|
|
+ if (!isValid) {
|
|
|
+ throw new Error('维护码错误')
|
|
|
+ }
|
|
|
+
|
|
|
+ const entity = await this.qrCodeRepository.findOne({ where: { qrCode } })
|
|
|
+ if (!entity) {
|
|
|
+ throw new Error('二维码不存在')
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.remark !== undefined) {
|
|
|
+ entity.remark = data.remark
|
|
|
+ }
|
|
|
+
|
|
|
+ return await this.qrCodeRepository.save(entity)
|
|
|
+ }
|
|
|
+
|
|
|
async getUserQrCodes(userId: number, page: number = 0, pageSize: number = 20): Promise<PaginationResponse<any>> {
|
|
|
const [content, total] = await this.userQrCodeRepository
|
|
|
.createQueryBuilder('userQrCode')
|
|
|
@@ -471,10 +545,10 @@ export class QrCodeService {
|
|
|
qrType: qrType,
|
|
|
isActivated: qrCode?.isActivated,
|
|
|
lastScanAt: qrCode?.lastScanAt,
|
|
|
- isVisible: isVisible
|
|
|
+ isVisible: isVisible,
|
|
|
+ remark: qrCode?.remark
|
|
|
}
|
|
|
|
|
|
- // 根据类型添加特定字段
|
|
|
if (qrType === QrType.LINK) {
|
|
|
result.jumpUrl = jumpUrl
|
|
|
} else if (qrType === QrType.PERSON || qrType === QrType.PET || qrType === QrType.GOODS) {
|