const DEFAULT_API_BASE_URL = "http://localhost:8080"; export const D4_METRICS_PATH = "/api/d4/metrics"; export type D4EventName = | "D4_COLLAB_CONFLICT_CREATED" | "D4_COLLAB_CONFLICT_RESOLVED" | "D4_COLLAB_EFFECTIVE" | "D4_COMM_MESSAGE_RESPONSE" | "D4_COMM_MESSAGE_SENT" | "D4_TASK_ASSIGNED" | "D4_TASK_COMPLETED"; export interface D4MetricsQuery { from?: string; to?: string; projectId?: number | string; taskType?: string; userId?: number | string; slaMs?: number | string; } export interface D4MetricsResponse { from: string; to: string; filter: { projectId: number | null; taskType: string | null; userId: number | null; slaMs: number | null; }; taskCompletion: { assignedCount: number; completedCount: number; completionRate: number | null; onTimeCompletedCount: number | null; onTimeCompletionRate: number | null; }; communication: { sentMessageCount: number; respondedMessageCount: number; averageResponseMs: number | null; }; collaboration: { effectiveCollaborationCount: number; }; conflict: { createdCount: number; resolvedCount: number; resolutionRate: number | null; }; eventCounts: Record; scan: { indexPattern: string; scannedEvents: number; maxEventsToScan: number; truncated: boolean; }; } export const D4_EVENT_LABELS: Record = { D4_COLLAB_CONFLICT_CREATED: "协作冲突创建", D4_COLLAB_CONFLICT_RESOLVED: "协作冲突解决", D4_COLLAB_EFFECTIVE: "有效协作", D4_COMM_MESSAGE_RESPONSE: "沟通响应", D4_COMM_MESSAGE_SENT: "沟通发送", D4_TASK_ASSIGNED: "任务分配", D4_TASK_COMPLETED: "任务完成", }; export function getApiBaseUrl() { return (process.env.NEXT_PUBLIC_SEEC_ANALYSIS_API_BASE_URL || DEFAULT_API_BASE_URL).replace(/\/$/, ""); } export function toD4UserId(userId: string | null | undefined) { if (!userId) { return undefined; } const parsed = Number(userId); return Number.isSafeInteger(parsed) ? parsed : undefined; } export function buildD4MetricsUrl(query: D4MetricsQuery = {}) { const url = new URL(`${getApiBaseUrl()}${D4_METRICS_PATH}`); Object.entries(query).forEach(([key, value]) => { if (value !== undefined && value !== null && `${value}`.trim() !== "") { url.searchParams.set(key, `${value}`); } }); return url.toString(); } export async function fetchD4Metrics(query: D4MetricsQuery = {}, signal?: AbortSignal) { const response = await fetch(buildD4MetricsUrl(query), { method: "GET", headers: { Accept: "application/json", }, signal, }); if (!response.ok) { let message = `D4 指标请求失败 (${response.status})`; try { const body = (await response.json()) as { message?: string; error?: string }; message = body.message || body.error || message; } catch { // Keep the status based message when the response body is not JSON. } throw new Error(message); } return (await response.json()) as D4MetricsResponse; }