74 lines
4.4 KiB
TypeScript
74 lines
4.4 KiB
TypeScript
import { BadRequestException, ConflictException, Injectable, NotFoundException } from '@nestjs/common';
|
|
import { Prisma } from '@prisma/client';
|
|
import ExcelJS from 'exceljs';
|
|
import { createHash, randomUUID } from 'node:crypto';
|
|
import { extname } from 'node:path';
|
|
import { FilesService } from '../files/files.service';
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
import { SmsConfigService } from '../sms-config/sms-config.service';
|
|
import type { AnalyzeImportOptions, CreateImportProfileDto, CreateReportBatchDto, EmbeddedImage, ImportCommitDto, ImportMapping, PagedQuery, ReportBatchInspection, ReportBatchTarget, ReviewImportItemsDto } from './report-materials.contracts';
|
|
import { profileData, validateProfile, loadWorkbook, assertSafeWorkbook, safeSpreadsheetText, readEmbeddedImages, suggestMappings, remapProfileColumns, signatureCoreMapping, drainageCoreMapping, normalizeHeader, normalizeFieldCode, clamp, normalizePage, normalizePageSize, dateRange, cellText, transformValue, mappedCoreValue, dynamicValues, jsonRecord, hasValue, isFileRef, resolveExportValue, applyExportTransform, styleHeader, normalizeImageExtension, imageContentType, safeFileName, normalizeBatchIdempotencyKey, jsonStringArray, jsonSafe } from './report-materials.helpers';
|
|
|
|
|
|
/** R4 report-materials domain service composed behind ReportMaterialsService. */
|
|
export class ReportPendingQueryService {
|
|
constructor(private readonly prisma: PrismaService, private readonly files: FilesService, private readonly smsConfig: SmsConfigService) {}
|
|
|
|
async listPending(query: { reportType?: 'signature' | 'drainage'; tenantId?: string; applicationId?: string } & PagedQuery) {
|
|
const items = await this.findPendingItems(query);
|
|
const page = normalizePage(query.page);
|
|
const pageSize = normalizePageSize(query.pageSize);
|
|
return {
|
|
items: items.slice((page - 1) * pageSize, page * pageSize),
|
|
total: items.length,
|
|
page,
|
|
pageSize,
|
|
};
|
|
}
|
|
|
|
async findPendingItems(query: { reportType?: 'signature' | 'drainage'; tenantId?: string; applicationId?: string } & PagedQuery) {
|
|
const changedAt = dateRange(query.startAt, query.endAt);
|
|
const keyword = query.keyword?.trim();
|
|
const [signatures, drainageInfos] = await Promise.all([
|
|
query.reportType === 'drainage' ? Promise.resolve([]) : this.prisma.smsSignature.findMany({
|
|
where: {
|
|
pendingReport: true,
|
|
auditStatus: 'approved',
|
|
tenantId: query.tenantId,
|
|
applicationId: query.applicationId,
|
|
reportChangedAt: changedAt,
|
|
OR: keyword ? [
|
|
{ name: { contains: keyword } },
|
|
{ tenant: { name: { contains: keyword } } },
|
|
{ application: { name: { contains: keyword } } },
|
|
] : undefined,
|
|
},
|
|
include: { tenant: true, application: true },
|
|
orderBy: { reportChangedAt: 'desc' },
|
|
}),
|
|
query.reportType === 'signature' ? Promise.resolve([]) : this.prisma.smsDrainageInfo.findMany({
|
|
where: {
|
|
pendingReport: true,
|
|
auditStatus: 'approved',
|
|
tenantId: query.tenantId,
|
|
applicationId: query.applicationId,
|
|
reportChangedAt: changedAt,
|
|
OR: keyword ? [
|
|
{ siteName: { contains: keyword } },
|
|
{ url: { contains: keyword } },
|
|
{ signature: { name: { contains: keyword } } },
|
|
{ tenant: { name: { contains: keyword } } },
|
|
{ application: { name: { contains: keyword } } },
|
|
] : undefined,
|
|
},
|
|
include: { tenant: true, application: true, signature: true },
|
|
orderBy: { reportChangedAt: 'desc' },
|
|
}),
|
|
]);
|
|
return [
|
|
...signatures.map((item) => ({ id: `signature:${item.id}`, reportType: 'signature', signatureId: item.id, drainageItemId: null, materialVersion: item.materialVersion, changedAt: item.reportChangedAt, name: item.name, detail: item.purpose, tenant: item.tenant, application: item.application })),
|
|
...drainageInfos.map((item) => ({ id: `drainage:${item.id}`, reportType: 'drainage', signatureId: item.signatureId, drainageItemId: item.id, materialVersion: item.materialVersion, changedAt: item.reportChangedAt, name: item.siteName, detail: item.url, signatureName: item.signature.name, tenant: item.tenant, application: item.application })),
|
|
].sort((left, right) => new Date(right.changedAt).getTime() - new Date(left.changedAt).getTime());
|
|
}
|
|
}
|