|
|
|
@ -6,6 +6,8 @@ import { |
|
|
|
DeleteOutlined, |
|
|
|
ReloadOutlined, |
|
|
|
SendOutlined, |
|
|
|
ExportOutlined, |
|
|
|
ImportOutlined, |
|
|
|
BoxPlotFilled |
|
|
|
} from '@ant-design/icons' |
|
|
|
import useRectangleStore from '../../stores/rectangleStore' |
|
|
|
@ -143,7 +145,7 @@ function MeasurementPointSetting() { |
|
|
|
|
|
|
|
// 只更新当前选中的传感器的坐标 |
|
|
|
if (sensorKey === selectedSensorKey) { |
|
|
|
const coordMap = { '1': 'x', '2': 'y', '3': 'width', '4': 'height' } |
|
|
|
const coordMap = { 1: 'x', 2: 'y', 3: 'width', 4: 'height' } |
|
|
|
const coordName = coordMap[coordIndex] |
|
|
|
|
|
|
|
if (coordName && rectangleData) { |
|
|
|
@ -282,7 +284,7 @@ function MeasurementPointSetting() { |
|
|
|
return ( |
|
|
|
<Input |
|
|
|
size="small" |
|
|
|
onFocus={() =>onInputFocus(record)} |
|
|
|
onFocus={() => onInputFocus(record)} |
|
|
|
value={value} |
|
|
|
onChange={(e) => handleCellValueChange(record.key, e.target.value)} |
|
|
|
style={{ fontSize }} |
|
|
|
@ -501,6 +503,138 @@ function MeasurementPointSetting() { |
|
|
|
setRectangleData(null) |
|
|
|
} |
|
|
|
} |
|
|
|
const handleSaveConfig = async () => { |
|
|
|
try { |
|
|
|
// 检查是否有传感器数据 |
|
|
|
if (!sensorList || sensorList.length === 0) { |
|
|
|
message.warning('没有可保存的传感器数据!') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 收集传感器数据并转换为指定格式(与handleSet相同的格式) |
|
|
|
const configData = sensorList.map((sensor) => { |
|
|
|
const children = sensor.children || [] |
|
|
|
|
|
|
|
const positionItem = children.find((item) => item.name === '测点位置') |
|
|
|
const descriptionItem = children.find((item) => item.name === '测点描述') |
|
|
|
const coefficientItem = children.find((item) => item.name === '计算系数') |
|
|
|
const targetItem = children.find((item) => item.name === '基准标靶') |
|
|
|
|
|
|
|
const targetChildren = targetItem?.children || [] |
|
|
|
const xItem = targetChildren.find((item) => item.name === 'x') |
|
|
|
const yItem = targetChildren.find((item) => item.name === 'y') |
|
|
|
const wItem = targetChildren.find((item) => item.name === 'w') |
|
|
|
const hItem = targetChildren.find((item) => item.name === 'h') |
|
|
|
|
|
|
|
return { |
|
|
|
arg: String(coefficientItem?.value), |
|
|
|
des: String(descriptionItem?.value), |
|
|
|
pos: String(positionItem?.value), |
|
|
|
tar: String(targetItem?.value), |
|
|
|
w: String(wItem?.value), |
|
|
|
h: String(hItem?.value), |
|
|
|
x: String(xItem?.value), |
|
|
|
y: String(yItem?.value) |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
// 准备保存的完整配置数据 |
|
|
|
const fullConfig = { |
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
sensors: configData, |
|
|
|
metadata: { |
|
|
|
lensDistance, |
|
|
|
measureDistance, |
|
|
|
calculatedCoefficient |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 调用主进程保存文件 |
|
|
|
const result = await window.electron.ipcRenderer.invoke(IPC_EVENT.SAVE_CONFIG, { |
|
|
|
data: fullConfig, |
|
|
|
ip: connectedDevice?.ip || '' |
|
|
|
}) |
|
|
|
|
|
|
|
if (result.success) { |
|
|
|
message.success(`配置已保存到:${result.filePath}`) |
|
|
|
} else if (result.canceled) { |
|
|
|
message.info('已取消保存') |
|
|
|
} else { |
|
|
|
message.error(`保存失败:${result.error}`) |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('保存配置失败:', error) |
|
|
|
message.error(`保存配置失败:${error.message}`) |
|
|
|
} |
|
|
|
} |
|
|
|
const handleImportConfig = async () => { |
|
|
|
try { |
|
|
|
// 如果当前有传感器数据,先确认是否覆盖 |
|
|
|
if (sensorList.length > 0) { |
|
|
|
const confirmed = await new Promise((resolve) => { |
|
|
|
Modal.confirm({ |
|
|
|
title: '导入确认', |
|
|
|
content: '导入配置将覆盖当前的传感器列表,是否继续?', |
|
|
|
okText: '继续导入', |
|
|
|
cancelText: '取消', |
|
|
|
centered: true, |
|
|
|
onOk: () => resolve(true), |
|
|
|
onCancel: () => resolve(false) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
if (!confirmed) { |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 调用主进程打开文件选择对话框 |
|
|
|
const result = await window.electron.ipcRenderer.invoke(IPC_EVENT.LOAD_CONFIG) |
|
|
|
|
|
|
|
if (result.canceled) { |
|
|
|
message.info('已取消导入') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if (!result.success) { |
|
|
|
message.error(`导入失败:${result.error}`) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
const configData = result.data |
|
|
|
|
|
|
|
// 验证配置数据 |
|
|
|
if (!configData.sensors || !Array.isArray(configData.sensors)) { |
|
|
|
message.error('配置文件格式不正确') |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 转换导入的数据为内部格式 |
|
|
|
const convertedData = convertSensorDataToInternalFormat(configData.sensors) |
|
|
|
|
|
|
|
// 更新传感器列表 |
|
|
|
setSensorList(convertedData) |
|
|
|
|
|
|
|
// 清除选中状态 |
|
|
|
setSelectedSensorKey(null) |
|
|
|
setRectangleData(null) |
|
|
|
|
|
|
|
// 如果配置中包含元数据,恢复镜头焦距和测点距离 |
|
|
|
if (configData.metadata) { |
|
|
|
if (configData.metadata.lensDistance !== undefined) { |
|
|
|
setLensDistance(configData.metadata.lensDistance) |
|
|
|
} |
|
|
|
if (configData.metadata.measureDistance !== undefined) { |
|
|
|
setMeasureDistance(configData.metadata.measureDistance) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
message.success(`配置已成功导入!共 ${convertedData.length} 个传感器`) |
|
|
|
} catch (error) { |
|
|
|
console.error('导入配置失败:', error) |
|
|
|
message.error(`导入配置失败:${error.message}`) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return ( |
|
|
|
<Flex vertical className={styles.container}> |
|
|
|
@ -744,6 +878,24 @@ function MeasurementPointSetting() { |
|
|
|
disabled={!connectedDevice || loadingSensors || settingSensors} |
|
|
|
/> |
|
|
|
</Tooltip> |
|
|
|
<Tooltip title="保存当前配置"> |
|
|
|
<Button |
|
|
|
icon={<ExportOutlined />} |
|
|
|
shape="circle" |
|
|
|
onClick={handleSaveConfig} |
|
|
|
loading={settingSensors} |
|
|
|
disabled={!connectedDevice || loadingSensors || settingSensors} |
|
|
|
/> |
|
|
|
</Tooltip> |
|
|
|
<Tooltip title="导入配置文件"> |
|
|
|
<Button |
|
|
|
icon={<ImportOutlined />} |
|
|
|
shape="circle" |
|
|
|
onClick={handleImportConfig} |
|
|
|
loading={settingSensors} |
|
|
|
disabled={!connectedDevice || loadingSensors || settingSensors} |
|
|
|
/> |
|
|
|
</Tooltip> |
|
|
|
</Flex> |
|
|
|
</div> |
|
|
|
</Flex> |
|
|
|
|