feat: harden platform workflows and UI governance
This commit is contained in:
@@ -729,7 +729,13 @@ export class SmsConfigService {
|
||||
const timeoutMs = getPositiveIntegerEnv('CMPP_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS', DEFAULT_DOWNSTREAM_HEARTBEAT_TIMEOUT_MS);
|
||||
const cutoff = new Date(now.getTime() - timeoutMs);
|
||||
return this.prisma.cmppDownstreamConnection.deleteMany({
|
||||
where: { status: 'connected', lastHeartbeatAt: { lt: cutoff } },
|
||||
where: {
|
||||
status: 'connected',
|
||||
OR: [
|
||||
{ lastHeartbeatAt: { lt: cutoff } },
|
||||
{ lastHeartbeatAt: null, connectedAt: { lt: cutoff } },
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1005,14 +1011,19 @@ export class SmsConfigService {
|
||||
const drainageInfo = data.drainageInfo
|
||||
? await this.withReportRequirementSnapshot(applicationId, data.drainageInfo)
|
||||
: undefined;
|
||||
const materialChanged = (data.applicationId !== undefined && data.applicationId !== signature.applicationId)
|
||||
|| (data.name !== undefined && normalizeSmsSignature(data.name) !== normalizeSmsSignature(signature.name))
|
||||
|| (data.purpose !== undefined && data.purpose !== signature.purpose)
|
||||
|| (data.drainageInfo !== undefined && JSON.stringify(data.drainageInfo) !== JSON.stringify(signature.drainageInfo ?? null));
|
||||
const auditStatus = materialChanged && signature.auditStatus === 'approved' ? 'pending' : data.auditStatus;
|
||||
const updated = await this.prisma.smsSignature.update({
|
||||
where: { id: signatureId },
|
||||
data: {
|
||||
applicationId: data.applicationId,
|
||||
name: data.name,
|
||||
purpose: data.purpose,
|
||||
auditStatus: data.auditStatus,
|
||||
rejectReason: data.auditStatus === 'pending' ? null : undefined,
|
||||
auditStatus,
|
||||
rejectReason: auditStatus === 'pending' ? null : undefined,
|
||||
drainageInfo: drainageInfo as Prisma.InputJsonValue | undefined,
|
||||
materialVersion: { increment: 1 },
|
||||
pendingReport: true,
|
||||
@@ -1376,6 +1387,12 @@ export class SmsConfigService {
|
||||
const variables = data.content !== undefined || data.variables !== undefined
|
||||
? validateAndNormalizeTemplateVariables(data.content ?? template.content, data.variables)
|
||||
: undefined;
|
||||
const materialChanged = (data.applicationId !== undefined && data.applicationId !== template.applicationId)
|
||||
|| (data.signatureId !== undefined && data.signatureId !== template.signatureId)
|
||||
|| (data.content !== undefined && data.content !== template.content)
|
||||
|| (data.category !== undefined && data.category !== template.category)
|
||||
|| data.variables !== undefined;
|
||||
const auditStatus = materialChanged && template.auditStatus === 'approved' ? 'pending' : data.auditStatus;
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
if (variables) {
|
||||
await tx.templateVariable.deleteMany({ where: { templateId } });
|
||||
@@ -1388,7 +1405,8 @@ export class SmsConfigService {
|
||||
name: data.name,
|
||||
content: data.content,
|
||||
category: data.category,
|
||||
auditStatus: data.auditStatus,
|
||||
auditStatus,
|
||||
rejectReason: auditStatus === 'pending' ? null : undefined,
|
||||
billingUnits: data.content ? estimateBillingUnits(data.content) : undefined,
|
||||
variables: variables ? {
|
||||
create: variables.map((variable) => ({
|
||||
@@ -1403,6 +1421,24 @@ export class SmsConfigService {
|
||||
});
|
||||
}
|
||||
|
||||
async updateClientTemplate(templateId: string, data: UpdateSmsTemplateDto, tenantId?: string) {
|
||||
const current = await this.prisma.smsTemplate.findUnique({ where: { id: templateId } });
|
||||
if (!current || (tenantId && current.tenantId !== tenantId)) throw new NotFoundException('Template not found');
|
||||
if (!['draft', 'rejected', 'approved'].includes(current.auditStatus)) {
|
||||
throw new BadRequestException('当前审核状态不允许修改模板');
|
||||
}
|
||||
const updated = await this.updateTemplate(templateId, { ...data, auditStatus: 'pending' }, tenantId);
|
||||
await this.createAuditRecord({
|
||||
tenantId: current.tenantId,
|
||||
targetType: 'sms_template',
|
||||
targetId: templateId,
|
||||
action: 'client_update_submit',
|
||||
statusBefore: current.auditStatus,
|
||||
statusAfter: 'pending',
|
||||
});
|
||||
return updated;
|
||||
}
|
||||
|
||||
async submitTemplate(templateId: string, tenantId?: string) {
|
||||
const template = await this.prisma.smsTemplate.findUnique({ where: { id: templateId } });
|
||||
if (!template || (tenantId && template.tenantId !== tenantId)) {
|
||||
|
||||
Reference in New Issue
Block a user