From 88836590cd26b40627713711c5626be6be6958a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E5=85=AE?= Date: Thu, 11 Jun 2026 23:06:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B1=95=E7=A4=BA=E7=9C=9F=E5=AE=9E?= =?UTF-8?q?=E8=BF=90=E7=BB=B4=E5=AE=A1=E8=AE=A1=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/devopsApi.ts | 41 ++++++++++++++++++++++ src/stores/platform.ts | 17 ++++++++- src/types/devops.ts | 16 +++++++++ src/views/SettingsView.vue | 72 ++++++++++++++++++++++++++++++++++++++ vite.config.ts | 10 ++++++ 5 files changed, 155 insertions(+), 1 deletion(-) diff --git a/src/services/devopsApi.ts b/src/services/devopsApi.ts index 6716a7e..62e4c00 100644 --- a/src/services/devopsApi.ts +++ b/src/services/devopsApi.ts @@ -4,6 +4,7 @@ import type { AgentCard, AgentInvocation, + AuditLogEntry, CreateAgentInvocationPayload, CreateDeployRunPayload, DashboardSummary, @@ -267,6 +268,12 @@ export const devopsApi = { return toJenkinsSyncSummary(data, projectList) }, + async getAuditLogs(): Promise { + const { data } = await http.get('/audit-logs') + lastDataSource = 'backend' + return Array.isArray(data) ? data.map(sanitizeAuditLogEntry) : [] + }, + async getAgentCards(): Promise { return agentCards }, @@ -416,6 +423,22 @@ function sanitizeIntegrationNote(note?: string): string | undefined { .replace(/key=[^&\s]+/g, 'key=[已隐藏]') } +function safeText(value: unknown, fallback: string): string { + return typeof value === 'string' && value.trim() ? value : fallback +} + +function optionalSafeText(value: unknown): string | undefined { + return typeof value === 'string' && value.trim() ? value : undefined +} + +function safeRecord(value: unknown): Record | undefined { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + return undefined + } + + return value as Record +} + function toProjectConfigs(backendProjects: BackendProject[]): ProjectConfig[] { return backendProjects.map((project) => { const repo = parseRepository(project.repositoryUrl, project.key) @@ -498,6 +521,24 @@ function toJenkinsSyncSummary( } } +function sanitizeAuditLogEntry(record: AuditLogEntry): AuditLogEntry { + return { + id: safeText(record.id, 'audit-unknown'), + action: safeText(record.action, 'UNKNOWN_ACTION'), + resourceType: safeText(record.resourceType, 'unknown'), + resourceId: optionalSafeText(record.resourceId), + actorId: optionalSafeText(record.actorId), + actorName: optionalSafeText(record.actorName), + requestId: optionalSafeText(record.requestId), + sourceIp: optionalSafeText(record.sourceIp), + userAgent: optionalSafeText(record.userAgent), + before: safeRecord(record.before), + after: safeRecord(record.after), + parameterDigest: safeRecord(record.parameterDigest), + createdAt: safeText(record.createdAt, ''), + } +} + function toPipelineStep(step: BackendDeployRunStep): PipelineStep { const bpmnNodeId = step.bpmnNodeId || step.id || 'unknown-step' const name = step.name || bpmnNodeId diff --git a/src/stores/platform.ts b/src/stores/platform.ts index eecc00d..7a64479 100644 --- a/src/stores/platform.ts +++ b/src/stores/platform.ts @@ -3,6 +3,7 @@ import { defineStore } from 'pinia' import { devopsApi } from '../services/devopsApi' import type { AgentCard, + AuditLogEntry, CreateDeployRunPayload, IntegrationStatus, IntegrationConfigStatus, @@ -24,6 +25,7 @@ export const usePlatformStore = defineStore('platform', () => { const integrations = ref([]) const agentCards = ref([]) const settings = ref([]) + const auditLogs = ref([]) const integrationConfig = ref({ checkedAt: '', integrations: [], @@ -46,7 +48,12 @@ export const usePlatformStore = defineStore('platform', () => { agentCards.value = summary.agentCards settings.value = summary.settings integrationConfig.value = summary.integrationConfig - releaseProcessXml.value = await devopsApi.getReleaseProcessXml() + const [processXml, recentAuditLogs] = await Promise.all([ + devopsApi.getReleaseProcessXml(), + devopsApi.getAuditLogs(), + ]) + releaseProcessXml.value = processXml + auditLogs.value = recentAuditLogs dataSource.value = devopsApi.getLastDataSource() } finally { loading.value = false @@ -98,6 +105,12 @@ export const usePlatformStore = defineStore('platform', () => { return refs } + async function loadAuditLogs() { + auditLogs.value = await devopsApi.getAuditLogs() + dataSource.value = devopsApi.getLastDataSource() + return auditLogs.value + } + function upsertRun(run: ReleaseRun) { runs.value = [run, ...runs.value.filter((item) => item.id !== run.id)] } @@ -110,6 +123,7 @@ export const usePlatformStore = defineStore('platform', () => { integrations, agentCards, settings, + auditLogs, integrationConfig, releaseProcessXml, projectRefs, @@ -122,5 +136,6 @@ export const usePlatformStore = defineStore('platform', () => { syncJenkinsRun, syncJenkinsRuns, loadProjectRefs, + loadAuditLogs, } }) diff --git a/src/types/devops.ts b/src/types/devops.ts index 04e4e8c..bee58ec 100644 --- a/src/types/devops.ts +++ b/src/types/devops.ts @@ -165,6 +165,22 @@ export interface JenkinsSyncSummary { failedRuns: JenkinsSyncError[] } +export interface AuditLogEntry { + id: string + action: string + resourceType: string + resourceId?: string + actorId?: string + actorName?: string + requestId?: string + sourceIp?: string + userAgent?: string + before?: Record + after?: Record + parameterDigest?: Record + createdAt: string +} + export interface AgentCard { mode: AgentMode title: string diff --git a/src/views/SettingsView.vue b/src/views/SettingsView.vue index a80afb9..18b1c33 100644 --- a/src/views/SettingsView.vue +++ b/src/views/SettingsView.vue @@ -1,6 +1,8 @@