"use client"; import React, { useMemo, useState } from "react"; import { Alert, Box, Button, Collapse, TextField, Typography, } from "@mui/material"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { zhCN as pickerZhCN } from "@mui/x-date-pickers/locales"; import dayjs, { Dayjs } from "dayjs"; import "dayjs/locale/zh-cn"; import { useNotification } from "@refinedev/core"; import { api } from "@/lib/api"; import { NETWORK_NAME, config } from "@config/config"; import { LeakageResultDetail } from "./types"; import { FLOW_DISPLAY_UNIT, toM3s } from "@utils/units"; interface Props { onResult: (result: LeakageResultDetail) => void; } const AnalysisParameters: React.FC = ({ onResult }) => { const { open } = useNotification(); const [schemeName, setSchemeName] = useState(`DMA_Leak_${Date.now()}`); const [dmaCount, setDmaCount] = useState(5); const [startTime, setStartTime] = useState( dayjs().subtract(2, "hour"), ); const [endTime, setEndTime] = useState(dayjs()); const [popSize, setPopSize] = useState(10); const [maxGen, setMaxGen] = useState(50); const [qSum, setQSum] = useState(1440); const [advancedOpen, setAdvancedOpen] = useState(false); const [running, setRunning] = useState(false); const isValid = useMemo(() => { if (!schemeName.trim() || !startTime || !endTime) return false; return startTime.isBefore(endTime) && qSum >= 360; }, [schemeName, startTime, endTime, qSum]); const handleRun = async () => { if (!isValid || !startTime || !endTime) { open?.({ type: "error", message: "请完善参数并确认时间范围合法" }); return; } setRunning(true); open?.({ key: "dma-leak-analysis-progress", type: "progress", message: "方案提交分析中", undoableTimeout: 3, }); try { const response = await api.post( `${config.BACKEND_URL}/api/v1/leakage/identify/`, { network: NETWORK_NAME, scheme_name: schemeName.trim(), dma_count: dmaCount, scada_start: startTime.toISOString(), scada_end: endTime.toISOString(), pop_size: popSize, max_gen: maxGen, q_sum: toM3s(qSum, FLOW_DISPLAY_UNIT), q_sum_unit: "m3/s", output_flow_unit: FLOW_DISPLAY_UNIT, }, ); onResult(response.data as LeakageResultDetail); open?.({ key: "dma-leak-analysis-success", type: "success", message: "方案分析成功", description: "DMA 漏损识别完成,请在方案查询中查看结果。", }); } catch (error: any) { open?.({ key: "dma-leak-analysis-error", type: "error", message: "提交分析失败", description: error?.response?.data?.detail ?? "请求失败", }); } finally { setRunning(false); } }; return ( 漏损识别耗时较长(DMA 数量越多越慢),建议先用较小 DMA 数量试跑。 方案名称 setSchemeName(e.target.value)} placeholder="请输入方案名称" fullWidth size="small" /> DMA 数量 { const value = Number.parseInt(e.target.value, 10); // Limit between 3 and 10 if (Number.isNaN(value)) { setDmaCount(5); } else if (value > 10) { setDmaCount(10); } else { setDmaCount(Math.max(3, value)); } }} fullWidth size="small" inputProps={{ min: 3, max: 10, step: 1 }} helperText="DMA 数量限制为 3-10 个" /> SCADA 开始时间 SCADA 结束时间 总漏损流量 ({FLOW_DISPLAY_UNIT}) { const value = Number(e.target.value); setQSum(Number.isNaN(value) ? 1440 : Math.max(360, value)); }} inputProps={{ min: 360, step: 10 }} /> setAdvancedOpen((prev) => !prev)} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") setAdvancedOpen((prev) => !prev); }} sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", px: 1.25, py: 0.75, cursor: "pointer", backgroundColor: "transparent", "&:hover": { backgroundColor: "action.hover" }, }} > 高级选项 setPopSize(Number(e.target.value))} /> setMaxGen(Number(e.target.value))} /> ); }; export default AnalysisParameters;