feat: 技术支持工单/企微权限/开发版本管理/消息推送等迭代
This commit is contained in:
@@ -1,113 +0,0 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Observable, catchError, tap, throwError } from 'rxjs';
|
||||
import type { AuthUser } from '../guards/jwt-auth.guard';
|
||||
import type { RequestWithId } from '../logging/request-id.middleware';
|
||||
import { HQ_OPERATION_KEY, type HqOperationMeta } from './hq-operation.decorator';
|
||||
import { HqOperationLogService } from './hq-operation-log.service';
|
||||
|
||||
function pickRefId(value: unknown): bigint | null {
|
||||
if (value == null || value === '') return null;
|
||||
try {
|
||||
return BigInt(String(value));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeBody(body: unknown): unknown {
|
||||
if (!body || typeof body !== 'object') return body;
|
||||
const copy = { ...(body as Record<string, unknown>) };
|
||||
for (const key of Object.keys(copy)) {
|
||||
if (/password|secret|token/i.test(key)) {
|
||||
copy[key] = '***';
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
function summarizeResponse(data: unknown): unknown {
|
||||
if (data == null) return null;
|
||||
if (typeof data !== 'object') return data;
|
||||
const obj = data as Record<string, unknown>;
|
||||
const summary: Record<string, unknown> = {};
|
||||
for (const key of ['id', 'ok', 'deleted', 'orderNo', 'userNo', 'redeemNo', 'message', 'status']) {
|
||||
if (obj[key] !== undefined) summary[key] = obj[key];
|
||||
}
|
||||
if (Array.isArray(obj.items)) {
|
||||
summary.itemCount = obj.items.length;
|
||||
}
|
||||
if (Array.isArray(obj.orderNos)) {
|
||||
summary.orderNos = obj.orderNos;
|
||||
}
|
||||
return Object.keys(summary).length ? summary : obj;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class HqOperationInterceptor implements NestInterceptor {
|
||||
constructor(
|
||||
private readonly reflector: Reflector,
|
||||
private readonly logService: HqOperationLogService,
|
||||
) {}
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
const meta = this.reflector.get<HqOperationMeta | undefined>(
|
||||
HQ_OPERATION_KEY,
|
||||
context.getHandler(),
|
||||
);
|
||||
if (!meta) return next.handle();
|
||||
|
||||
const req = context.switchToHttp().getRequest<RequestWithId & { user?: AuthUser }>();
|
||||
const user = req.user as AuthUser | undefined;
|
||||
if (!user || user.actorType !== 'HQ') {
|
||||
return next.handle();
|
||||
}
|
||||
|
||||
const writeLog = (status: 'SUCCESS' | 'FAILED', data?: unknown, errorMessage?: string) => {
|
||||
const refId = meta.batch
|
||||
? 0n
|
||||
: pickRefId(meta.refIdParam ? req.params?.[meta.refIdParam] : null)
|
||||
?? pickRefId(
|
||||
meta.refIdField
|
||||
? (data as Record<string, unknown> | null)?.[meta.refIdField]
|
||||
: (data as Record<string, unknown> | null)?.id,
|
||||
)
|
||||
?? 0n;
|
||||
|
||||
const detail: Record<string, unknown> = {
|
||||
method: req.method,
|
||||
path: req.originalUrl ?? req.url,
|
||||
requestId: req.requestId,
|
||||
};
|
||||
if (meta.includeBody && req.body) {
|
||||
detail.requestBody = sanitizeBody(req.body);
|
||||
}
|
||||
if (status === 'SUCCESS' && meta.includeResponse !== false && data != null) {
|
||||
detail.response = summarizeResponse(data);
|
||||
}
|
||||
if (errorMessage) detail.error = errorMessage;
|
||||
|
||||
this.logService.logSafe({
|
||||
hqAccountId: user.actorId,
|
||||
action: meta.action,
|
||||
refType: meta.refType,
|
||||
refId,
|
||||
status,
|
||||
detail,
|
||||
});
|
||||
};
|
||||
|
||||
return next.handle().pipe(
|
||||
tap((data) => writeLog('SUCCESS', data)),
|
||||
catchError((err: { message?: string }) => {
|
||||
writeLog('FAILED', undefined, err?.message ?? '操作失败');
|
||||
return throwError(() => err);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user