fix(analysis): 统一方案名与接口错误提示
This commit is contained in:
@@ -21,7 +21,15 @@ import { api } from "@/lib/api";
|
||||
import { NETWORK_NAME } from "@config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import { BurstDetectionResult } from "./types";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
interface Props {
|
||||
onResult: (result: BurstDetectionResult) => void;
|
||||
@@ -49,7 +57,7 @@ const currentQuarterHour = () => {
|
||||
|
||||
export const createBurstDetectionAnalysisParametersState =
|
||||
(): BurstDetectionAnalysisParametersState => ({
|
||||
schemeName: `Burst_Detection_${Date.now()}`,
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.burstDetection),
|
||||
detectionMode: "latest",
|
||||
targetTime: currentQuarterHour(),
|
||||
samplingIntervalMinutes: 15,
|
||||
@@ -94,7 +102,7 @@ export const resolvePressureSamplingInterval = (items: ScadaInfoItem[]) => {
|
||||
export const buildBurstDetectionRequest = (
|
||||
parameters: BurstDetectionAnalysisParametersState,
|
||||
) => ({
|
||||
scheme_name: parameters.schemeName.trim(),
|
||||
scheme_name: normalizeSchemeName(parameters.schemeName),
|
||||
sampling_interval_minutes: parameters.samplingIntervalMinutes,
|
||||
...(parameters.detectionMode === "historical" && parameters.targetTime
|
||||
? { target_time: parameters.targetTime.toISOString() }
|
||||
@@ -164,7 +172,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
|
||||
const isValid = useMemo(
|
||||
() =>
|
||||
schemeName.trim().length > 0 &&
|
||||
isSchemeNameValid(schemeName) &&
|
||||
samplingIntervalValid &&
|
||||
(detectionMode === "latest" || Boolean(targetTime?.isValid())),
|
||||
[detectionMode, samplingIntervalValid, schemeName, targetTime],
|
||||
@@ -203,12 +211,12 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
? "目标时刻存在异常信号,请优先复核相关测点。"
|
||||
: "目标时刻未发现爆管异常。",
|
||||
});
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
open?.({
|
||||
key: "burst-detection-analysis-error",
|
||||
type: "error",
|
||||
message: "侦测失败",
|
||||
description: error?.response?.data?.detail ?? error?.message ?? "请求失败",
|
||||
description: getApiErrorMessage(error, "爆管侦测请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setRunning(false);
|
||||
@@ -226,6 +234,13 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
value={schemeName}
|
||||
onChange={(event) => setFormField("schemeName", event.target.value)}
|
||||
placeholder="请输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
fullWidth
|
||||
size="small"
|
||||
/>
|
||||
|
||||
@@ -27,9 +27,17 @@ import { api } from "@/lib/api";
|
||||
import { NETWORK_NAME, config } from "@config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import { FLOW_DISPLAY_UNIT, toM3s } from "@utils/units";
|
||||
import { BurstLocationResult } from "./types";
|
||||
import { getBurstLocationErrorNotice } from "./burstLocationError";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
interface Props {
|
||||
onResult: (result: BurstLocationResult) => void;
|
||||
@@ -67,7 +75,7 @@ export interface BurstLocationAnalysisParametersState {
|
||||
|
||||
export const createBurstLocationAnalysisParametersState =
|
||||
(): BurstLocationAnalysisParametersState => ({
|
||||
schemeName: `Burst_Locate_${Date.now()}`,
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.burstLocation),
|
||||
dataSource: "monitoring",
|
||||
schemes: [],
|
||||
selectedSchemeId: "",
|
||||
@@ -163,12 +171,14 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
description: `当前可选爆管分析方案 ${burstSchemes.length} 个`,
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
open?.({
|
||||
type: "error",
|
||||
message: "刷新方案失败",
|
||||
description:
|
||||
error?.response?.data?.detail ?? error?.message ?? "无法获取爆管分析方案列表",
|
||||
description: getApiErrorMessage(
|
||||
error,
|
||||
"无法获取爆管分析方案列表",
|
||||
),
|
||||
});
|
||||
} finally {
|
||||
setSchemeLoading(false);
|
||||
@@ -193,6 +203,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
};
|
||||
|
||||
const isValid = useMemo(() => {
|
||||
if (!isSchemeNameValid(schemeName)) return false;
|
||||
if (!Number.isFinite(burstLeakage) || burstLeakage <= 0) return false;
|
||||
if (!burstStartTime || !burstEndTime) {
|
||||
return false;
|
||||
@@ -204,6 +215,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
return burstStartTime.isBefore(burstEndTime);
|
||||
}, [
|
||||
burstLeakage,
|
||||
schemeName,
|
||||
burstStartTime,
|
||||
burstEndTime,
|
||||
dataSource,
|
||||
@@ -234,7 +246,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
`${config.BACKEND_URL}/api/v1/burst-locations`,
|
||||
{
|
||||
data_source: dataSource,
|
||||
scheme_name: schemeName.trim() || undefined,
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
burst_leakage: toM3s(burstLeakage, FLOW_DISPLAY_UNIT),
|
||||
min_dpressure: minDpressure,
|
||||
basic_pressure: basicPressure,
|
||||
@@ -270,7 +282,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
message: "爆管定位成功",
|
||||
description: `定位到管段: ${(response.data as BurstLocationResult).located_pipe}`,
|
||||
});
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
const notice = getBurstLocationErrorNotice(error);
|
||||
open?.({
|
||||
key: "burst-location-analysis-error",
|
||||
@@ -294,6 +306,13 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setFormField("schemeName", e.target.value)}
|
||||
placeholder="请输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
fullWidth
|
||||
size="small"
|
||||
/>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
|
||||
export interface BurstLocationErrorNotice {
|
||||
message: string;
|
||||
description: string;
|
||||
@@ -6,26 +8,10 @@ export interface BurstLocationErrorNotice {
|
||||
const DATA_GAP_PATTERN =
|
||||
/^(爆管压力数据|正常压力数据|爆管流量数据|正常流量数据) 在时间窗内无有效模拟数据: (.+)$/;
|
||||
|
||||
const extractErrorDetail = (error: unknown): string => {
|
||||
const candidate = error as {
|
||||
message?: string;
|
||||
response?: { data?: { detail?: unknown } };
|
||||
};
|
||||
const detail = candidate?.response?.data?.detail;
|
||||
|
||||
if (typeof detail === "string" && detail.trim()) {
|
||||
return detail.trim();
|
||||
}
|
||||
if (typeof candidate?.message === "string" && candidate.message.trim()) {
|
||||
return candidate.message.trim();
|
||||
}
|
||||
return "请求失败";
|
||||
};
|
||||
|
||||
export const getBurstLocationErrorNotice = (
|
||||
error: unknown,
|
||||
): BurstLocationErrorNotice => {
|
||||
const detail = extractErrorDetail(error);
|
||||
const detail = getApiErrorMessage(error);
|
||||
const match = detail.match(DATA_GAP_PATTERN);
|
||||
|
||||
if (!match) {
|
||||
|
||||
@@ -30,9 +30,17 @@ import { api } from "@/lib/api";
|
||||
import { config, NETWORK_NAME } from "@/config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import { along, lineString, length, toMercator } from "@turf/turf";
|
||||
import { Point } from "ol/geom";
|
||||
import { toLonLat } from "ol/proj";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
export interface PipePoint {
|
||||
id: string;
|
||||
@@ -52,7 +60,7 @@ export const createBurstAnalysisParametersState = (): BurstAnalysisParametersSta
|
||||
pipePoints: [],
|
||||
startTime: dayjs(new Date()),
|
||||
duration: 3600,
|
||||
schemeName: "FANGAN" + new Date().getTime(),
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.burstAnalysis),
|
||||
network: NETWORK_NAME,
|
||||
});
|
||||
|
||||
@@ -104,7 +112,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
pipePoints.length > 0 &&
|
||||
startTime !== null &&
|
||||
duration > 0 &&
|
||||
schemeName.trim() !== "";
|
||||
isSchemeNameValid(schemeName);
|
||||
|
||||
// 地图点击选择要素事件处理函数
|
||||
const handleMapClickSelectFeatures = useCallback(
|
||||
@@ -333,7 +341,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
burst_id: burst_ID,
|
||||
burst_size: burst_size,
|
||||
modify_total_duration: modify_total_duration,
|
||||
scheme_name: schemeName,
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -358,8 +366,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
key: "burst-analysis",
|
||||
type: "error",
|
||||
message: "提交分析失败",
|
||||
description:
|
||||
error instanceof Error ? error.message : "请检查网络连接或稍后重试",
|
||||
description: getApiErrorMessage(error, "爆管模拟请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setAnalyzing(false);
|
||||
@@ -525,6 +532,13 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setParameterField("schemeName", e.target.value)}
|
||||
placeholder="输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -30,6 +30,14 @@ import {
|
||||
} from "@/utils/mapQueryService";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
export interface ContaminantAnalysisParametersState {
|
||||
schemeName: string;
|
||||
@@ -42,7 +50,7 @@ export interface ContaminantAnalysisParametersState {
|
||||
|
||||
export const createContaminantAnalysisParametersState =
|
||||
(): ContaminantAnalysisParametersState => ({
|
||||
schemeName: "WQ_" + new Date().getTime(),
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.contaminantAnalysis),
|
||||
startTime: dayjs(new Date()),
|
||||
sourceNode: "",
|
||||
concentration: 100,
|
||||
@@ -98,7 +106,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
Boolean(sourceNode) &&
|
||||
concentration > 0 &&
|
||||
duration > 0 &&
|
||||
schemeName.trim() !== ""
|
||||
isSchemeNameValid(schemeName)
|
||||
);
|
||||
}, [network, startTime, sourceNode, concentration, duration, schemeName]);
|
||||
|
||||
@@ -240,7 +248,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
concentration,
|
||||
duration,
|
||||
pattern: pattern || undefined,
|
||||
scheme_name: schemeName,
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
};
|
||||
|
||||
await api.post(`${config.BACKEND_URL}/api/v1/contaminant-simulations`, undefined, {
|
||||
@@ -259,8 +267,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
key: "contaminant-analysis",
|
||||
type: "error",
|
||||
message: "提交分析失败",
|
||||
description:
|
||||
error instanceof Error ? error.message : "请检查网络连接或稍后重试",
|
||||
description: getApiErrorMessage(error, "污染物模拟请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
@@ -391,6 +398,13 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setFormField("schemeName", e.target.value)}
|
||||
placeholder="输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -21,8 +21,16 @@ import { api } from "@/lib/api";
|
||||
import { config } from "@config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import { LeakageResultDetail } from "./types";
|
||||
import { FLOW_DISPLAY_UNIT, toM3s } from "@utils/units";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
interface Props {
|
||||
onResult: (result: LeakageResultDetail) => void;
|
||||
@@ -43,7 +51,7 @@ export interface DMALeakAnalysisParametersState {
|
||||
|
||||
export const createDMALeakAnalysisParametersState =
|
||||
(): DMALeakAnalysisParametersState => ({
|
||||
schemeName: `DMA_Leak_${Date.now()}`,
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.dmaLeakIdentification),
|
||||
dmaCount: 5,
|
||||
startTime: dayjs().subtract(2, "hour"),
|
||||
endTime: dayjs(),
|
||||
@@ -93,7 +101,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
qSumInput.trim() !== "" && Number.isFinite(parsedQSum) && parsedQSum >= 0;
|
||||
|
||||
const isValid = useMemo(() => {
|
||||
if (!schemeName.trim() || !startTime || !endTime) return false;
|
||||
if (!isSchemeNameValid(schemeName) || !startTime || !endTime) return false;
|
||||
return startTime.isBefore(endTime) && qSumIsValid;
|
||||
}, [schemeName, startTime, endTime, qSumIsValid]);
|
||||
|
||||
@@ -118,7 +126,7 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
const response = await api.post(
|
||||
`${config.BACKEND_URL}/api/v1/leakage-identifications`,
|
||||
{
|
||||
scheme_name: schemeName.trim(),
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
dma_count: dmaCount,
|
||||
scada_start: startTime.toISOString(),
|
||||
scada_end: endTime.toISOString(),
|
||||
@@ -136,12 +144,12 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
message: "方案分析成功",
|
||||
description: "DMA 漏损识别完成,请在方案查询中查看结果。",
|
||||
});
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
open?.({
|
||||
key: "dma-leak-analysis-error",
|
||||
type: "error",
|
||||
message: "提交分析失败",
|
||||
description: error?.response?.data?.detail ?? "请求失败",
|
||||
description: getApiErrorMessage(error, "DMA 漏损识别请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setRunning(false);
|
||||
@@ -163,6 +171,13 @@ const AnalysisParameters: React.FC<Props> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setFormField("schemeName", e.target.value)}
|
||||
placeholder="请输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
fullWidth
|
||||
size="small"
|
||||
/>
|
||||
|
||||
@@ -36,7 +36,15 @@ import { api } from "@/lib/api";
|
||||
import { config } from "@/config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { useSessionRecoveryDraft } from "@/lib/sessionRecoveryDraft";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import PanelEmptyState from "@components/olmap/common/PanelEmptyState";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
import {
|
||||
type LinkStatus,
|
||||
getValveSettingHelperText,
|
||||
@@ -65,7 +73,7 @@ export interface FlushingAnalysisParametersState {
|
||||
|
||||
export const createFlushingAnalysisParametersState =
|
||||
(): FlushingAnalysisParametersState => ({
|
||||
schemeName: "Flushing_" + new Date().getTime(),
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.flushingAnalysis),
|
||||
valves: [],
|
||||
drainageNode: null,
|
||||
startTime: dayjs(new Date()),
|
||||
@@ -334,6 +342,22 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
open?.({
|
||||
type: "error",
|
||||
message: `阀门 ${valve.id} 的部分属性读取失败`,
|
||||
description: [
|
||||
propertiesResult.status === "rejected"
|
||||
? `阀门属性:${getApiErrorMessage(
|
||||
propertiesResult.reason,
|
||||
"读取失败",
|
||||
)}`
|
||||
: null,
|
||||
statusResult.status === "rejected"
|
||||
? `开关状态:${getApiErrorMessage(
|
||||
statusResult.reason,
|
||||
"读取失败",
|
||||
)}`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(";"),
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -400,7 +424,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
};
|
||||
|
||||
const handleAnalyze = async () => {
|
||||
if (!startTime || !drainageNode || !schemeName.trim()) {
|
||||
if (!startTime || !drainageNode || !isSchemeNameValid(schemeName)) {
|
||||
open?.({
|
||||
type: "error",
|
||||
message: "请填写完整参数",
|
||||
@@ -442,7 +466,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
const formattedTime = startTime.format("YYYY-MM-DDTHH:mm:00Z"); // ISO format with seconds set to 00
|
||||
|
||||
const params = {
|
||||
scheme_name: schemeName,
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
start_time: formattedTime,
|
||||
...(valves.length > 0 && {
|
||||
valves: valves.map(v => v.id),
|
||||
@@ -480,7 +504,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
open?.({
|
||||
type: "error",
|
||||
message: "提交分析失败",
|
||||
description: error instanceof Error ? error.message : "未知错误",
|
||||
description: getApiErrorMessage(error, "管道冲洗分析请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setAnalyzing(false);
|
||||
@@ -668,6 +692,13 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setFormField("schemeName", e.target.value)}
|
||||
placeholder="请输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -710,7 +741,7 @@ const AnalysisParameters: React.FC<AnalysisParametersProps> = ({
|
||||
onClick={handleAnalyze}
|
||||
disabled={
|
||||
analyzing ||
|
||||
!schemeName.trim() ||
|
||||
!isSchemeNameValid(schemeName) ||
|
||||
!drainageNode ||
|
||||
!startTime ||
|
||||
// !flushFlow ||
|
||||
|
||||
@@ -12,8 +12,16 @@ import { PlayArrow as PlayArrowIcon } from "@mui/icons-material";
|
||||
import { useNotification } from "@refinedev/core";
|
||||
import { NETWORK_NAME } from "@/config/config";
|
||||
import { useControllableObjectState } from "@components/olmap/core/useControllableState";
|
||||
import { getApiErrorMessage } from "@/lib/apiError";
|
||||
import { optimizeSensorPlacement } from "./schemeApi";
|
||||
import type { SensorPlacementScheme } from "./types";
|
||||
import {
|
||||
createSchemeName,
|
||||
isSchemeNameValid,
|
||||
normalizeSchemeName,
|
||||
SCHEME_NAME_MAX_LENGTH,
|
||||
SCHEME_NAME_PREFIXES,
|
||||
} from "@utils/schemeName";
|
||||
|
||||
export interface OptimizationParametersState {
|
||||
method: string;
|
||||
@@ -27,7 +35,7 @@ export const createOptimizationParametersState =
|
||||
method: "kmeans",
|
||||
sensorCount: 5,
|
||||
minDiameter: 5,
|
||||
schemeName: "Fangan" + new Date().getTime(),
|
||||
schemeName: createSchemeName(SCHEME_NAME_PREFIXES.sensorPlacement),
|
||||
});
|
||||
|
||||
interface OptimizationParametersProps {
|
||||
@@ -62,7 +70,7 @@ const OptimizationParameters: React.FC<OptimizationParametersProps> = ({
|
||||
// 创建方案
|
||||
const handleCreateScheme = async () => {
|
||||
// 验证输入
|
||||
if (!schemeName.trim()) {
|
||||
if (!isSchemeNameValid(schemeName)) {
|
||||
open?.({
|
||||
type: "error",
|
||||
message: "请输入方案名称",
|
||||
@@ -90,7 +98,7 @@ const OptimizationParameters: React.FC<OptimizationParametersProps> = ({
|
||||
|
||||
try {
|
||||
const created = await optimizeSensorPlacement({
|
||||
scheme_name: schemeName,
|
||||
scheme_name: normalizeSchemeName(schemeName),
|
||||
sensor_type: "pressure",
|
||||
method: method as "sensitivity" | "kmeans",
|
||||
sensor_count: sensorCount,
|
||||
@@ -102,14 +110,16 @@ const OptimizationParameters: React.FC<OptimizationParametersProps> = ({
|
||||
description: `方案 "${schemeName}" 已完成优化分析`,
|
||||
});
|
||||
onSchemeCreated?.(created);
|
||||
setFormField("schemeName", "Fangan" + new Date().getTime());
|
||||
} catch (error: any) {
|
||||
setFormField(
|
||||
"schemeName",
|
||||
createSchemeName(SCHEME_NAME_PREFIXES.sensorPlacement),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("创建方案失败:", error);
|
||||
open?.({
|
||||
type: "error",
|
||||
message: "创建方案失败",
|
||||
description:
|
||||
error.response?.data?.message || error.message || "未知错误",
|
||||
description: getApiErrorMessage(error, "监测点优化请求失败"),
|
||||
});
|
||||
} finally {
|
||||
setAnalyzing(false);
|
||||
@@ -255,6 +265,13 @@ const OptimizationParameters: React.FC<OptimizationParametersProps> = ({
|
||||
value={schemeName}
|
||||
onChange={(e) => setFormField("schemeName", e.target.value)}
|
||||
placeholder="请输入方案名称"
|
||||
error={schemeName.trim().length > SCHEME_NAME_MAX_LENGTH}
|
||||
helperText={
|
||||
schemeName.trim().length > SCHEME_NAME_MAX_LENGTH
|
||||
? `方案名称不能超过 ${SCHEME_NAME_MAX_LENGTH} 个字符`
|
||||
: undefined
|
||||
}
|
||||
inputProps={{ maxLength: SCHEME_NAME_MAX_LENGTH }}
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"&:hover fieldset": {
|
||||
|
||||
Reference in New Issue
Block a user