From a5f19ebeda7b4a62d8223425fc0064a430d89aa1 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Thu, 7 May 2026 16:12:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=91=A8=E6=8A=A5=20metadata=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E5=88=B0=2016=20=E5=AD=97=E6=AE=B5=EF=BC=8C?= =?UTF-8?q?=E6=8A=BD=E5=8F=96=20buildWeeklyMetadata=20=E8=BE=85=E5=8A=A9?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/weekly-report.ts | 64 +++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/src/lib/weekly-report.ts b/src/lib/weekly-report.ts index 90fc34d..23baad8 100644 --- a/src/lib/weekly-report.ts +++ b/src/lib/weekly-report.ts @@ -88,6 +88,7 @@ export async function collectWeeklyReportData( currentStatus: t.current_status, isResolved, steps, + availability: t.availability, } }) @@ -166,6 +167,60 @@ export async function collectWeeklyReportData( } } +/** 从采集数据构建 metadata JSON */ +export function buildWeeklyMetadata(data: WeeklyReportData): string { + const faultTickets = [...data.gpuFaultTickets, ...data.storageFaultTickets] + const resolvedTickets = faultTickets.filter(t => t.isResolved) + + const resolvedCount = resolvedTickets.length + + const durations = resolvedTickets + .map(t => { + if (!t.closeTime) return 0 + const assign = new Date(t.assignTime).getTime() + const close = new Date(t.closeTime).getTime() + return Math.round((close - assign) / 60000) + }) + .filter(d => d > 0) + const avgDurationMinutes = durations.length > 0 + ? Math.round(durations.reduce((s, d) => s + d, 0) / durations.length) + : 0 + + const ongoingCount = data.pendingCount + + const faultTicketCount = data.totalFaultCount + + const affectedDeviceIps = new Set(faultTickets.map(t => t.deviceIp)) + const affectedDeviceCount = affectedDeviceIps.size + + const availabilities = faultTickets + .map(t => t.availability) + .filter((a): a is number => a !== null && a !== undefined) + const avgAvailability = availabilities.length > 0 + ? Math.round(availabilities.reduce((s, v) => s + v, 0) / availabilities.length * 10000) / 100 + : 100 + + const reportLabel = `图灵IT基础设施运营周报(${data.weekLabel})` + + return JSON.stringify({ + gpuCount: data.gpuTotal, + storageCount: data.storageTotal, + totalTickets: data.gpuFaultTickets.length + data.storageFaultTickets.length + data.otherTickets.length, + gpuFaultCount: data.gpuFaultTickets.length, + storageFaultCount: data.storageFaultTickets.length, + otherTicketCount: data.otherTickets.length, + avgAvailability, + resolvedCount, + avgDurationMinutes, + ongoingCount, + faultTicketCount, + affectedDeviceCount, + faultFreeDays: null, + availabilityDetails: null, + reportLabel, + }) +} + /** 异步生成周报 */ export async function generateWeeklyReport(reportId: number): Promise { const db = getDb() @@ -185,14 +240,7 @@ export async function generateWeeklyReport(reportId: number): Promise { const filePath = path.join(REPORTS_DIR, fileName) fs.writeFileSync(filePath, buffer) - const metadata = JSON.stringify({ - gpuCount: data.gpuTotal, - storageCount: data.storageTotal, - totalTickets: data.gpuFaultTickets.length + data.storageFaultTickets.length + data.otherTickets.length, - gpuFaultCount: data.gpuFaultTickets.length, - storageFaultCount: data.storageFaultTickets.length, - otherTicketCount: data.otherTickets.length, - }) + const metadata = buildWeeklyMetadata(data) db.prepare( "UPDATE reports SET status = 'completed', file_path = ?, file_name = ?, metadata = ? WHERE id = ?"