"use client"; import React, { useState } from "react"; import { Box, Button, Card, CardContent, Checkbox, Chip, Collapse, FormControlLabel, IconButton, Tooltip, Typography, } from "@mui/material"; import { InfoOutlined as InfoIcon } from "@mui/icons-material"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import dayjs, { Dayjs } from "dayjs"; import "dayjs/locale/zh-cn"; import { useNotification } from "@refinedev/core"; import { api } from "@/lib/api"; import { NETWORK_NAME } from "@config/config"; import { BurstDetectionResult, BurstDetectionSchemeDetail, BurstDetectionSchemeRecord, } from "./types"; interface Props { onViewResult: (result: BurstDetectionResult) => void; schemes?: BurstDetectionSchemeRecord[]; onSchemesChange?: (schemes: BurstDetectionSchemeRecord[]) => void; } const SchemeQuery: React.FC = ({ onViewResult, schemes: externalSchemes, onSchemesChange }) => { const { open } = useNotification(); const [queryAll, setQueryAll] = useState(true); const [queryDate, setQueryDate] = useState(dayjs()); const [internalSchemes, setInternalSchemes] = useState([]); const [loading, setLoading] = useState(false); const [expandedId, setExpandedId] = useState(null); const schemes = externalSchemes !== undefined ? externalSchemes : internalSchemes; const setSchemes = onSchemesChange || setInternalSchemes; const buildDisplayResult = ( scheme: Pick, detail?: BurstDetectionSchemeDetail, ): BurstDetectionResult | null => { const payload = detail?.result_payload; const summary = detail?.result_summary; const fallbackLatestDay = summary?.latest_day; if (!payload && !summary) return null; return { network: payload?.network ?? detail?.network ?? NETWORK_NAME, sensor_nodes: payload?.sensor_nodes ?? detail?.sensor_nodes ?? [], observed_source: payload?.observed_source ?? detail?.observed_source ?? "stored_scheme", sample_count: payload?.sample_count ?? 0, points_per_day: payload?.points_per_day ?? detail?.algorithm_params?.points_per_day ?? 1440, day_count: payload?.day_count ?? payload?.rows?.length ?? 0, rows: payload?.rows ?? (fallbackLatestDay ? [fallbackLatestDay] : []), summary: payload?.summary ?? (summary ? summary : { burst_detected: false, latest_day: fallbackLatestDay ?? { Day: 0, Score: 0, Prediction: 1, IsBurst: false }, most_anomalous_day: 0, anomaly_days: [], anomaly_day_count: 0, latest_sensor_rankings: [], }), scada_window: payload?.scada_window ?? detail?.scada_window, scheme_name: payload?.scheme_name ?? scheme.scheme_name, username: payload?.username ?? scheme.username, create_time: payload?.create_time ?? scheme.create_time, algorithm_params: payload?.algorithm_params ?? detail?.algorithm_params, }; }; const handleQuery = async () => { setLoading(true); try { const params: Record = { network: NETWORK_NAME }; if (!queryAll && queryDate) { params.query_date = queryDate.startOf("day").toISOString(); } const response = await api.get("/api/v1/burst-detection/schemes/", { params }); const nextSchemes = response.data as BurstDetectionSchemeRecord[]; setSchemes(nextSchemes); open?.({ type: "success", message: "查询成功", description: `共找到 ${nextSchemes.length} 条侦测记录。`, }); } catch (error: any) { open?.({ type: "error", message: "查询失败", description: error?.response?.data?.detail ?? "无法获取侦测方案列表", }); } finally { setLoading(false); } }; const handleViewSchemeResult = async (schemeName: string) => { try { const response = await api.get( `/api/v1/burst-detection/schemes/${encodeURIComponent(schemeName)}`, { params: { network: NETWORK_NAME } }, ); const schemeRecord = response.data as BurstDetectionSchemeRecord & { result_payload?: BurstDetectionResult; }; const normalizedResult = schemeRecord.result_payload ?? buildDisplayResult( { scheme_name: schemeRecord.scheme_name, username: schemeRecord.username, create_time: schemeRecord.create_time, }, schemeRecord.scheme_detail, ); if (!normalizedResult) { throw new Error("方案详情缺少侦测结果数据"); } onViewResult(normalizedResult); open?.({ type: "success", message: "方案加载成功", description: `已加载方案:${schemeName}`, }); } catch (error: any) { open?.({ type: "error", message: "查看详情失败", description: error?.response?.data?.detail ?? error?.message ?? "无法获取方案详情", }); } }; return ( setQueryAll(event.target.checked)} /> } label={查询全部} className="m-0" /> {schemes.length === 0 ? ( 暂无侦测方案 运行一次展示版侦测后,可在这里回看历史结果。 ) : ( 共 {schemes.length} 条记录 {schemes.map((scheme) => { const summary = scheme.scheme_detail?.result_summary; const payload = scheme.scheme_detail?.result_payload; const isBurst = payload?.summary?.burst_detected ?? summary?.burst_detected ?? false; const anomalyDayCount = payload?.summary?.anomaly_day_count ?? summary?.anomaly_day_count ?? 0; const mostAnomalousDay = payload?.summary?.most_anomalous_day ?? summary?.most_anomalous_day ?? "-"; const sensorCount = payload?.sensor_nodes?.length ?? scheme.scheme_detail?.sensor_nodes?.length ?? 0; return ( {scheme.scheme_name} 创建时间:{dayjs(scheme.create_time).format("YYYY-MM-DD HH:mm")} setExpandedId(expandedId === scheme.scheme_id ? null : scheme.scheme_id) } color="primary" className="p-1" > 异常天数 {anomalyDayCount} 最异常日 {isBurst ? typeof mostAnomalousDay === "number" ? `第 ${mostAnomalousDay} 天` : mostAnomalousDay : "无"} 测点数 {sensorCount} 数据来源: {(() => { const ds = payload?.data_source; const os = payload?.observed_source ?? scheme.scheme_detail?.observed_source; if (ds === "simulation") return "模拟数据"; if (ds === "monitoring") return "监测数据"; if (os === "simulation_scheme_timerange") return "模拟数据"; if (os === "backend_timerange") return "监测数据"; return os || "-"; })()} 时间窗口: {payload?.scada_window?.start ? `${dayjs(payload.scada_window.start).format("MM-DD HH:mm")} ~ ${dayjs( payload.scada_window.end, ).format("MM-DD HH:mm")}` : "-"} 算法参数: 频域截断系数:{scheme.scheme_detail?.algorithm_params?.mu ?? payload?.algorithm_params?.mu ?? "-"} ,每日采样点数: {scheme.scheme_detail?.algorithm_params?.points_per_day ?? payload?.algorithm_params?.points_per_day ?? "-"} ); })} )} ); }; export default SchemeQuery;