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 = ?"