feat(admin): 完善审计访问上下文与后台布局

This commit is contained in:
Cheng Zhou
2026-07-09 17:10:42 +08:00
parent 1dc10f569d
commit 0bbc125806
20 changed files with 776 additions and 112 deletions
+80 -1
View File
@@ -7,6 +7,7 @@ export interface AuditEvent {
eventLabel: string;
actorId: string;
actorName: string;
actorAccount?: string;
actorRole: string;
actorRoleLabel: string;
targetType: string;
@@ -21,6 +22,19 @@ export interface AuditEvent {
result: "SUCCESS" | "FAIL";
resultLabel: string;
timestamp: string;
clientIp?: string;
ipLocation?: string;
ipCountry?: string;
ipProvince?: string;
ipCity?: string;
ipIsp?: string;
clientType?: string;
clientVersion?: string;
clientPlatform?: string;
buildChannel?: string;
buildCommit?: string;
userAgent?: string;
clientSourceLabel?: string;
}
const entityTypeLabelMap: Record<string, string> = {
@@ -619,6 +633,57 @@ const buildDiffText = (
return lines;
};
const fallbackIpLocation = (ip: string | null | undefined): string => {
if (!ip) return "";
if (ip === "127.0.0.1" || ip === "::1") return "本机访问";
if (/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(ip)) return "内网地址";
return "";
};
export const formatAuditIpLocation = (raw: {
ip_country?: string | null;
ip_province?: string | null;
ip_city?: string | null;
ip_isp?: string | null;
ip_location?: string | null;
client_ip?: string | null;
clientIp?: string | null;
}): string => {
const parts = [
raw.ip_country && raw.ip_country !== "中国" ? raw.ip_country : "",
raw.ip_province,
raw.ip_city,
raw.ip_isp,
].filter(Boolean);
if (parts.length) return parts.join(" / ");
return raw.ip_location || fallbackIpLocation(raw.client_ip || raw.clientIp) || "";
};
const isAutomationUserAgent = (userAgent = ""): boolean =>
/curl|wget|python-requests|httpie|go-http-client|node-fetch|axios|postman|insomnia|okhttp|java|powershell|libwww/i.test(userAgent);
const isBrowserUserAgent = (userAgent = ""): boolean =>
/mozilla|chrome|safari|firefox|edg\//i.test(userAgent);
export const resolveAuditClientSourceLabel = (raw: {
client_type?: string | null;
client_platform?: string | null;
user_agent?: string | null;
clientType?: string | null;
clientPlatform?: string | null;
userAgent?: string | null;
}): string => {
const clientType = String(raw.client_type || raw.clientType || "").trim().toLowerCase();
const platform = String(raw.client_platform || raw.clientPlatform || "").trim();
const userAgent = String(raw.user_agent || raw.userAgent || "").trim();
if (clientType === "web") return "网页端";
if (clientType === "desktop") return platform ? `桌面端 / ${platform}` : "桌面端";
if (clientType) return `未知客户端 / ${clientType}`;
if (isAutomationUserAgent(userAgent)) return "脚本/命令行";
if (isBrowserUserAgent(userAgent)) return "浏览器(未标识)";
return "未知来源";
};
export const normalizeAuditEvent = (raw: any, userMap: Record<string, string>): AuditEvent => {
const dict = auditDict[raw.action] || buildReadableAuditDict(raw.action, raw.entity_type);
let detailObj: any = {};
@@ -668,7 +733,8 @@ export const normalizeAuditEvent = (raw: any, userMap: Record<string, string>):
eventType: raw.action,
eventLabel: dict.label,
actorId: raw.operator_id,
actorName: userMap[raw.operator_id] || raw.operator_id,
actorName: raw.operator_name || userMap[raw.operator_id] || raw.operator_id,
actorAccount: raw.operator_email || raw.operator_id,
actorRole: raw.operator_role,
actorRoleLabel: getDictLabel(roleDict, raw.operator_role),
targetType: raw.entity_type || "",
@@ -683,6 +749,19 @@ export const normalizeAuditEvent = (raw: any, userMap: Record<string, string>):
result: detailObj.result || "SUCCESS",
resultLabel: detailObj.result === "FAIL" ? TEXT.audit.resultFail : TEXT.audit.resultSuccess,
timestamp: raw.created_at,
clientIp: raw.client_ip || "",
ipLocation: formatAuditIpLocation(raw),
ipCountry: raw.ip_country || "",
ipProvince: raw.ip_province || "",
ipCity: raw.ip_city || "",
ipIsp: raw.ip_isp || "",
clientType: raw.client_type || "",
clientVersion: raw.client_version || "",
clientPlatform: raw.client_platform || "",
buildChannel: raw.build_channel || "",
buildCommit: raw.build_commit || "",
userAgent: raw.user_agent || "",
clientSourceLabel: resolveAuditClientSourceLabel(raw),
};
};