|
|
@ -6,7 +6,12 @@ import { |
|
|
ControlFilled, |
|
|
ControlFilled, |
|
|
FolderFilled, |
|
|
FolderFilled, |
|
|
EyeOutlined, |
|
|
EyeOutlined, |
|
|
EditOutlined |
|
|
EditOutlined, |
|
|
|
|
|
DownOutlined, |
|
|
|
|
|
RightOutlined, |
|
|
|
|
|
DeleteOutlined, |
|
|
|
|
|
PlusOutlined, |
|
|
|
|
|
CheckCircleFilled |
|
|
} from '@ant-design/icons' |
|
|
} from '@ant-design/icons' |
|
|
import { useState, useEffect, useCallback, useRef } from 'react' |
|
|
import { useState, useEffect, useCallback, useRef } from 'react' |
|
|
import { IPC_EVENT } from '../../common/ipcEvents' |
|
|
import { IPC_EVENT } from '../../common/ipcEvents' |
|
|
@ -14,9 +19,14 @@ import useDeviceStore from '../../stores/deviceStore' |
|
|
import AlgorithmSettings from '../AlgorithmSettings/AlgorithmSettings' |
|
|
import AlgorithmSettings from '../AlgorithmSettings/AlgorithmSettings' |
|
|
import { |
|
|
import { |
|
|
applyCorrectionToSensor, |
|
|
applyCorrectionToSensor, |
|
|
DEFAULT_CORRECTION_FACTORS, |
|
|
createDefaultCorrectionConfig, |
|
|
|
|
|
createDefaultCorrectionProfile, |
|
|
|
|
|
DEFAULT_CORRECTION_DISTANCE, |
|
|
DEFLECTION_CORRECTION_STORAGE_KEY, |
|
|
DEFLECTION_CORRECTION_STORAGE_KEY, |
|
|
sanitizeCorrectionFactors |
|
|
getActiveCorrectionFactors, |
|
|
|
|
|
removeCorrectionProfileWithFallback, |
|
|
|
|
|
sanitizeCorrectionConfig, |
|
|
|
|
|
sanitizeCorrectionProfiles |
|
|
} from '../../utils/deflectionCorrection' |
|
|
} from '../../utils/deflectionCorrection' |
|
|
|
|
|
|
|
|
function SystemSettings() { |
|
|
function SystemSettings() { |
|
|
@ -35,6 +45,7 @@ function SystemSettings() { |
|
|
|
|
|
|
|
|
// 算法设置 Modal 状态 |
|
|
// 算法设置 Modal 状态 |
|
|
const [algorithmModalVisible, setAlgorithmModalVisible] = useState(false) |
|
|
const [algorithmModalVisible, setAlgorithmModalVisible] = useState(false) |
|
|
|
|
|
const [correctionPanelExpanded, setCorrectionPanelExpanded] = useState(false) |
|
|
|
|
|
|
|
|
// 获取设备连接状态和重连配置 |
|
|
// 获取设备连接状态和重连配置 |
|
|
const connectedDevice = useDeviceStore((state) => state.connectedDevice) |
|
|
const connectedDevice = useDeviceStore((state) => state.connectedDevice) |
|
|
@ -44,12 +55,17 @@ function SystemSettings() { |
|
|
const alarmEnabled = useDeviceStore((state) => state.alarmEnabled) |
|
|
const alarmEnabled = useDeviceStore((state) => state.alarmEnabled) |
|
|
const alarmLimits = useDeviceStore((state) => state.alarmLimits) |
|
|
const alarmLimits = useDeviceStore((state) => state.alarmLimits) |
|
|
const correctionFactors = useDeviceStore((state) => state.correctionFactors) |
|
|
const correctionFactors = useDeviceStore((state) => state.correctionFactors) |
|
|
|
|
|
const correctionProfiles = useDeviceStore((state) => state.correctionProfiles) |
|
|
|
|
|
const activeCorrectionDistance = useDeviceStore((state) => state.activeCorrectionDistance) |
|
|
const setReconnectEnabled = useDeviceStore((state) => state.setReconnectEnabled) |
|
|
const setReconnectEnabled = useDeviceStore((state) => state.setReconnectEnabled) |
|
|
const setReconnectInterval = useDeviceStore((state) => state.setReconnectInterval) |
|
|
const setReconnectInterval = useDeviceStore((state) => state.setReconnectInterval) |
|
|
const setReconnecting = useDeviceStore((state) => state.setReconnecting) |
|
|
const setReconnecting = useDeviceStore((state) => state.setReconnecting) |
|
|
const setAlarmEnabled = useDeviceStore((state) => state.setAlarmEnabled) |
|
|
const setAlarmEnabled = useDeviceStore((state) => state.setAlarmEnabled) |
|
|
const setAlarmLimits = useDeviceStore((state) => state.setAlarmLimits) |
|
|
const setAlarmLimits = useDeviceStore((state) => state.setAlarmLimits) |
|
|
const setCorrectionFactors = useDeviceStore((state) => state.setCorrectionFactors) |
|
|
const setCorrectionFactors = useDeviceStore((state) => state.setCorrectionFactors) |
|
|
|
|
|
const setCorrectionProfiles = useDeviceStore((state) => state.setCorrectionProfiles) |
|
|
|
|
|
const setActiveCorrectionDistance = useDeviceStore((state) => state.setActiveCorrectionDistance) |
|
|
|
|
|
const setActiveCorrectionByDistance = useDeviceStore((state) => state.setActiveCorrectionByDistance) |
|
|
|
|
|
|
|
|
// 使用ref来存储最新的状态值,避免闭包问题 |
|
|
// 使用ref来存储最新的状态值,避免闭包问题 |
|
|
const realtimeDataEnabledRef = useRef(realtimeDataEnabled) |
|
|
const realtimeDataEnabledRef = useRef(realtimeDataEnabled) |
|
|
@ -136,18 +152,31 @@ function SystemSettings() { |
|
|
const savedFactors = localStorage.getItem(DEFLECTION_CORRECTION_STORAGE_KEY) |
|
|
const savedFactors = localStorage.getItem(DEFLECTION_CORRECTION_STORAGE_KEY) |
|
|
|
|
|
|
|
|
if (!savedFactors) { |
|
|
if (!savedFactors) { |
|
|
setCorrectionFactors(DEFAULT_CORRECTION_FACTORS) |
|
|
const defaultConfig = createDefaultCorrectionConfig() |
|
|
|
|
|
setCorrectionProfiles(defaultConfig.profiles) |
|
|
|
|
|
setActiveCorrectionDistance(defaultConfig.activeDistance) |
|
|
|
|
|
setCorrectionFactors(getActiveCorrectionFactors(defaultConfig)) |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
const parsedFactors = JSON.parse(savedFactors) |
|
|
const parsedFactors = JSON.parse(savedFactors) |
|
|
setCorrectionFactors(sanitizeCorrectionFactors(parsedFactors)) |
|
|
const normalizedConfig = sanitizeCorrectionConfig(parsedFactors) |
|
|
|
|
|
setCorrectionProfiles(normalizedConfig.profiles) |
|
|
|
|
|
setActiveCorrectionDistance(normalizedConfig.activeDistance) |
|
|
|
|
|
setCorrectionFactors(getActiveCorrectionFactors(normalizedConfig)) |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('读取数据修正系数失败:', error) |
|
|
console.error('读取数据修正系数失败:', error) |
|
|
setCorrectionFactors(DEFAULT_CORRECTION_FACTORS) |
|
|
const defaultConfig = createDefaultCorrectionConfig() |
|
|
|
|
|
setCorrectionProfiles(defaultConfig.profiles) |
|
|
|
|
|
setActiveCorrectionDistance(defaultConfig.activeDistance) |
|
|
|
|
|
setCorrectionFactors(getActiveCorrectionFactors(defaultConfig)) |
|
|
} |
|
|
} |
|
|
}, [setCorrectionFactors]) |
|
|
}, [ |
|
|
|
|
|
setCorrectionFactors, |
|
|
|
|
|
setCorrectionProfiles, |
|
|
|
|
|
setActiveCorrectionDistance |
|
|
|
|
|
]) |
|
|
|
|
|
|
|
|
// 新增:写入实时数据到CSV文件 |
|
|
// 新增:写入实时数据到CSV文件 |
|
|
const writeRealtimeDataToCSV = useCallback( |
|
|
const writeRealtimeDataToCSV = useCallback( |
|
|
@ -677,21 +706,110 @@ function SystemSettings() { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const handleCorrectionFactorChange = (field, value) => { |
|
|
const persistCorrectionConfig = (profiles, activeDistance) => { |
|
|
|
|
|
const normalizedProfiles = sanitizeCorrectionProfiles(profiles) |
|
|
|
|
|
const nextConfig = sanitizeCorrectionConfig({ |
|
|
|
|
|
profiles: normalizedProfiles, |
|
|
|
|
|
activeDistance |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
setCorrectionProfiles(nextConfig.profiles) |
|
|
|
|
|
setActiveCorrectionDistance(nextConfig.activeDistance) |
|
|
|
|
|
setCorrectionFactors(getActiveCorrectionFactors(nextConfig)) |
|
|
|
|
|
localStorage.setItem(DEFLECTION_CORRECTION_STORAGE_KEY, JSON.stringify(nextConfig)) |
|
|
|
|
|
|
|
|
|
|
|
return nextConfig |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleAddCorrectionProfile = () => { |
|
|
|
|
|
const existingDistanceSet = new Set(correctionProfiles.map((profile) => profile.distance)) |
|
|
|
|
|
let nextDistance = DEFAULT_CORRECTION_DISTANCE |
|
|
|
|
|
|
|
|
|
|
|
while (existingDistanceSet.has(nextDistance)) { |
|
|
|
|
|
nextDistance += 1 |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const nextProfiles = sanitizeCorrectionProfiles([ |
|
|
|
|
|
...correctionProfiles, |
|
|
|
|
|
createDefaultCorrectionProfile(nextDistance) |
|
|
|
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
persistCorrectionConfig(nextProfiles, activeCorrectionDistance) |
|
|
|
|
|
message.success(`已新增 ${nextDistance} 米修正系数`) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleCorrectionProfileChange = (distance, field, value) => { |
|
|
|
|
|
if (field === 'distance') { |
|
|
|
|
|
const normalizedDistance = Number(value) |
|
|
|
|
|
if (!Number.isInteger(normalizedDistance) || normalizedDistance <= 0) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const duplicateDistance = correctionProfiles.some( |
|
|
|
|
|
(profile) => profile.distance === normalizedDistance && profile.distance !== distance |
|
|
|
|
|
) |
|
|
|
|
|
if (duplicateDistance) { |
|
|
|
|
|
message.error(`已存在 ${normalizedDistance} 米配置,请使用其他距离`) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const nextProfiles = correctionProfiles.map((profile) => |
|
|
|
|
|
profile.distance === distance ? { ...profile, distance: normalizedDistance } : profile |
|
|
|
|
|
) |
|
|
|
|
|
const nextActiveDistance = |
|
|
|
|
|
activeCorrectionDistance === distance ? normalizedDistance : activeCorrectionDistance |
|
|
|
|
|
|
|
|
|
|
|
persistCorrectionConfig(nextProfiles, nextActiveDistance) |
|
|
|
|
|
message.success(`已更新 ${normalizedDistance} 米距离配置`) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (value === null || value === undefined || !Number.isFinite(Number(value))) { |
|
|
if (value === null || value === undefined || !Number.isFinite(Number(value))) { |
|
|
return |
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const nextFactors = { |
|
|
const nextProfiles = correctionProfiles.map((profile) => |
|
|
...correctionFactors, |
|
|
profile.distance === distance ? { ...profile, [field]: Number(value) } : profile |
|
|
[field]: Number(value) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
const nextConfig = persistCorrectionConfig(nextProfiles, activeCorrectionDistance) |
|
|
|
|
|
|
|
|
|
|
|
if (nextConfig.activeDistance === distance) { |
|
|
|
|
|
setActiveCorrectionByDistance(distance) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setCorrectionFactors(nextFactors) |
|
|
|
|
|
localStorage.setItem(DEFLECTION_CORRECTION_STORAGE_KEY, JSON.stringify(nextFactors)) |
|
|
|
|
|
message.success(`修正系数 ${field} 已更新`) |
|
|
message.success(`修正系数 ${field} 已更新`) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleActivateCorrectionProfile = (distance) => { |
|
|
|
|
|
const hasProfile = correctionProfiles.some((profile) => profile.distance === distance) |
|
|
|
|
|
if (!hasProfile) { |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const nextConfig = persistCorrectionConfig(correctionProfiles, distance) |
|
|
|
|
|
setActiveCorrectionByDistance(nextConfig.activeDistance) |
|
|
|
|
|
message.success(`已应用 ${distance} 米修正系数`) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const handleDeleteCorrectionProfile = (distance) => { |
|
|
|
|
|
const nextConfig = removeCorrectionProfileWithFallback( |
|
|
|
|
|
correctionProfiles, |
|
|
|
|
|
activeCorrectionDistance, |
|
|
|
|
|
distance |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
persistCorrectionConfig(nextConfig.profiles, nextConfig.activeDistance) |
|
|
|
|
|
setActiveCorrectionByDistance(nextConfig.activeDistance) |
|
|
|
|
|
|
|
|
|
|
|
if (nextConfig.activeDistance === DEFAULT_CORRECTION_DISTANCE && distance === activeCorrectionDistance) { |
|
|
|
|
|
message.success(`已删除 ${distance} 米配置,当前已切换到 ${DEFAULT_CORRECTION_DISTANCE} 米`) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
message.success(`已删除 ${distance} 米修正系数`) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
<Flex vertical gap={4} className={styles.container}> |
|
|
<Flex vertical gap={4} className={styles.container}> |
|
|
<div className={styles.header}> |
|
|
<div className={styles.header}> |
|
|
@ -881,42 +999,6 @@ function SystemSettings() { |
|
|
</Flex> |
|
|
</Flex> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div className={styles.subSection}> |
|
|
|
|
|
<div className={styles.subSectionTitle}>数据修正系数</div> |
|
|
|
|
|
<Flex gap="middle" className={styles.correctionInputs} vertical> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
addonBefore={'X轴 K'} |
|
|
|
|
|
className={styles.inputNumber} |
|
|
|
|
|
value={correctionFactors.xK} |
|
|
|
|
|
onChange={(value) => handleCorrectionFactorChange('xK', value)} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
addonBefore={'X轴 B'} |
|
|
|
|
|
className={styles.inputNumber} |
|
|
|
|
|
value={correctionFactors.xB} |
|
|
|
|
|
onChange={(value) => handleCorrectionFactorChange('xB', value)} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
addonBefore={'Y轴 K'} |
|
|
|
|
|
className={styles.inputNumber} |
|
|
|
|
|
value={correctionFactors.yK} |
|
|
|
|
|
onChange={(value) => handleCorrectionFactorChange('yK', value)} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
addonBefore={'Y轴 B'} |
|
|
|
|
|
className={styles.inputNumberLast} |
|
|
|
|
|
value={correctionFactors.yB} |
|
|
|
|
|
onChange={(value) => handleCorrectionFactorChange('yB', value)} |
|
|
|
|
|
/> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
{/* 存储设置 */} |
|
|
{/* 存储设置 */} |
|
|
@ -982,6 +1064,132 @@ function SystemSettings() { |
|
|
</Flex> |
|
|
</Flex> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className={styles.subSection}> |
|
|
|
|
|
<Button |
|
|
|
|
|
type="text" |
|
|
|
|
|
className={styles.correctionPanelToggle} |
|
|
|
|
|
onClick={() => setCorrectionPanelExpanded((prev) => !prev)} |
|
|
|
|
|
> |
|
|
|
|
|
{correctionPanelExpanded ? <DownOutlined /> : <RightOutlined />} |
|
|
|
|
|
数据修正系数 |
|
|
|
|
|
</Button> |
|
|
|
|
|
|
|
|
|
|
|
{correctionPanelExpanded ? ( |
|
|
|
|
|
<Flex vertical gap={8} className={styles.correctionPanelContent}> |
|
|
|
|
|
<div className={styles.correctionPanelHint}> |
|
|
|
|
|
当前应用距离:{activeCorrectionDistance} 米 |
|
|
|
|
|
</div> |
|
|
|
|
|
<Flex justify="flex-end"> |
|
|
|
|
|
<Button icon={<PlusOutlined />} type="primary" onClick={handleAddCorrectionProfile}> |
|
|
|
|
|
新增距离配置 |
|
|
|
|
|
</Button> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
<div className={styles.correctionCardList}> |
|
|
|
|
|
{correctionProfiles.map((profile) => { |
|
|
|
|
|
const isActive = profile.distance === activeCorrectionDistance |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
<div |
|
|
|
|
|
key={profile.distance} |
|
|
|
|
|
className={`${styles.correctionCard} ${isActive ? styles.correctionCardActive : ''}`} |
|
|
|
|
|
> |
|
|
|
|
|
<div className={styles.correctionCardHeader}> |
|
|
|
|
|
<div className={styles.correctionCardTitleRow}> |
|
|
|
|
|
<span className={styles.correctionCardTitle}>距离配置</span> |
|
|
|
|
|
{isActive ? ( |
|
|
|
|
|
<span className={styles.correctionCardBadge}> |
|
|
|
|
|
<CheckCircleFilled /> |
|
|
|
|
|
当前应用 |
|
|
|
|
|
</span> |
|
|
|
|
|
) : null} |
|
|
|
|
|
</div> |
|
|
|
|
|
<div className={styles.correctionCardActions}> |
|
|
|
|
|
<Button |
|
|
|
|
|
type={isActive ? 'default' : 'primary'} |
|
|
|
|
|
size="small" |
|
|
|
|
|
onClick={() => handleActivateCorrectionProfile(profile.distance)} |
|
|
|
|
|
> |
|
|
|
|
|
{isActive ? '已应用' : '应用'} |
|
|
|
|
|
</Button> |
|
|
|
|
|
<Button |
|
|
|
|
|
danger |
|
|
|
|
|
type="text" |
|
|
|
|
|
size="small" |
|
|
|
|
|
icon={<DeleteOutlined />} |
|
|
|
|
|
onClick={() => handleDeleteCorrectionProfile(profile.distance)} |
|
|
|
|
|
> |
|
|
|
|
|
删除 |
|
|
|
|
|
</Button> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className={styles.correctionDistanceRow}> |
|
|
|
|
|
<span className={styles.correctionFieldLabel}>距离(米)</span> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
min={1} |
|
|
|
|
|
precision={0} |
|
|
|
|
|
value={profile.distance} |
|
|
|
|
|
onChange={(nextValue) => |
|
|
|
|
|
handleCorrectionProfileChange(profile.distance, 'distance', nextValue) |
|
|
|
|
|
} |
|
|
|
|
|
className={styles.correctionDistanceInput} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className={styles.correctionFactorGrid}> |
|
|
|
|
|
<div className={styles.correctionField}> |
|
|
|
|
|
<span className={styles.correctionFieldLabel}>xK</span> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
value={profile.xK} |
|
|
|
|
|
onChange={(nextValue) => |
|
|
|
|
|
handleCorrectionProfileChange(profile.distance, 'xK', nextValue) |
|
|
|
|
|
} |
|
|
|
|
|
className={styles.correctionFieldInput} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div className={styles.correctionField}> |
|
|
|
|
|
<span className={styles.correctionFieldLabel}>xB</span> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
value={profile.xB} |
|
|
|
|
|
onChange={(nextValue) => |
|
|
|
|
|
handleCorrectionProfileChange(profile.distance, 'xB', nextValue) |
|
|
|
|
|
} |
|
|
|
|
|
className={styles.correctionFieldInput} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div className={styles.correctionField}> |
|
|
|
|
|
<span className={styles.correctionFieldLabel}>yK</span> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
value={profile.yK} |
|
|
|
|
|
onChange={(nextValue) => |
|
|
|
|
|
handleCorrectionProfileChange(profile.distance, 'yK', nextValue) |
|
|
|
|
|
} |
|
|
|
|
|
className={styles.correctionFieldInput} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div className={styles.correctionField}> |
|
|
|
|
|
<span className={styles.correctionFieldLabel}>yB</span> |
|
|
|
|
|
<InputNumber |
|
|
|
|
|
precision={6} |
|
|
|
|
|
value={profile.yB} |
|
|
|
|
|
onChange={(nextValue) => |
|
|
|
|
|
handleCorrectionProfileChange(profile.distance, 'yB', nextValue) |
|
|
|
|
|
} |
|
|
|
|
|
className={styles.correctionFieldInput} |
|
|
|
|
|
/> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
) |
|
|
|
|
|
})} |
|
|
|
|
|
</div> |
|
|
|
|
|
</Flex> |
|
|
|
|
|
) : null} |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
{/* 算法设置 Modal */} |
|
|
{/* 算法设置 Modal */} |
|
|
<AlgorithmSettings |
|
|
<AlgorithmSettings |
|
|
visible={algorithmModalVisible} |
|
|
visible={algorithmModalVisible} |
|
|
|