feat(admin-portal): 完整实现 admin-portal 管理端微前端

包含 src 全部实现、Dockerfile、配置文件等
This commit is contained in:
SpecialX
2026-07-10 19:09:12 +08:00
parent 02d09c47fa
commit b3511910d1
69 changed files with 11955 additions and 693 deletions

View File

@@ -0,0 +1,89 @@
/**
* 审计日志 Hooks
*
* contract §2.4auditLogs
* 仲裁 ARB-005经 teacher-bff GraphQL 消费(不直连 Kafka
*/
import { useCallback, useState } from "react";
import { useGraphQuery } from "./use-graphql";
import { AUDIT_LOGS_QUERY } from "@/lib/graphql-client";
import type {
AuditLogViewModel,
PaginatedResult,
ListFilter,
} from "@/types/view-models";
interface AuditLogsResponse {
auditLogs: PaginatedResult<AuditLogViewModel>;
}
interface AuditLogFilter extends Partial<ListFilter> {
action?: string;
actorUserId?: string;
startDate?: number;
endDate?: number;
}
export function useAuditLogs(filter: AuditLogFilter) {
const result = useGraphQuery<AuditLogsResponse>(AUDIT_LOGS_QUERY, { filter });
return {
...result,
data: result.data?.auditLogs ?? null,
};
}
export function useAuditLogFilter(initial?: Partial<AuditLogFilter>) {
const [filter, setFilter] = useState<AuditLogFilter>({
page: 1,
pageSize: 20,
...initial,
});
const setPage = useCallback(
(page: number) => setFilter((f) => ({ ...f, page })),
[],
);
const setSearch = useCallback(
(search: string) => setFilter((f) => ({ ...f, search, page: 1 })),
[],
);
const setAction = useCallback(
(action: string) =>
setFilter((f) => ({ ...f, action: action || undefined, page: 1 })),
[],
);
return { filter, setFilter, setPage, setSearch, setAction };
}
/** 审计日志导出 CSV */
export function exportAuditLogsCsv(logs: AuditLogViewModel[]): void {
const headers = [
"时间",
"操作人",
"操作",
"资源类型",
"资源ID",
"IP",
"追踪ID",
];
const rows = logs.map((l) => [
new Date(l.occurredAt).toLocaleString("zh-CN"),
l.actorName,
l.action,
l.resourceType,
l.resourceId,
l.ip,
l.traceId ?? "",
]);
const csv = [headers, ...rows]
.map((row) =>
row.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(","),
)
.join("\n");
const blob = new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8;" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `audit-logs-${new Date().toISOString().slice(0, 10)}.csv`;
link.click();
URL.revokeObjectURL(url);
}