Browse Source

feat: 更新版本至 1.1.0,添加配置保存与加载功能

master
cles 3 weeks ago
parent
commit
3db26a408f
  1. 2
      package.json
  2. 80
      src/main/ipcRouter.js
  3. 6
      src/renderer/src/common/ipcEvents.js
  4. 156
      src/renderer/src/components/MeasurementPointSetting/MeasurementPointSetting.jsx

2
package.json

@ -1,6 +1,6 @@
{
"name": "FlexometerSetup",
"version": "1.0.9",
"version": "1.1.0",
"description": "An Electron application with React",
"main": "./out/main/index.js",
"author": "cles",

80
src/main/ipcRouter.js

@ -1,5 +1,5 @@
import { ipcMain } from 'electron'
import { dialog, shell } from 'electron'
import { dialog, shell, app } from 'electron'
import dgram from 'dgram'
import net from 'net'
import { appendFileSync, mkdirSync, existsSync } from 'fs'
@ -7,7 +7,9 @@ import { dirname } from 'path'
import { IPC_EVENT } from '../renderer/src/common/ipcEvents.js'
import log from 'electron-log'
import ReconnectManager from './reconnectManager.js'
import {getParametersFromDevice,setFirstParameter,disconnect} from './lib/adbClient.js'
import { getParametersFromDevice, setFirstParameter, disconnect } from './lib/adbClient.js'
import fs from 'fs/promises'
import path from 'path'
const TIMEOUT = 10000 // 10秒超时
const END_SEQUENCE = '\n\n' // 消息结束标志
// 全局保存所有TCP连接和相关信息
@ -202,6 +204,80 @@ export function registerIpRouter() {
// 曝光参数相关操作
ipcMain.handle(IPC_EVENT.EXPOSURE_GET, exposureGet)
ipcMain.handle(IPC_EVENT.EXPOSURE_SET, exposureSet)
// 配置保存与加载
ipcMain.handle(IPC_EVENT.SAVE_CONFIG, saveConfig)
ipcMain.handle(IPC_EVENT.LOAD_CONFIG, loadConfig)
}
// 导入配置文件
const loadConfig = async (event) => {
try {
// 打开文件选择对话框
const result = await dialog.showOpenDialog({
title: '导入传感器配置',
defaultPath: app.getPath('documents'),
filters: [
{ name: 'JSON 配置文件', extensions: ['json'] },
{ name: '所有文件', extensions: ['*'] }
],
properties: ['openFile']
})
if (result.canceled) {
return { success: false, canceled: true }
}
// 读取文件内容
const filePath = result.filePaths[0]
const fileContent = await fs.readFile(filePath, 'utf-8')
const configData = JSON.parse(fileContent)
// 验证配置文件格式
if (!configData.sensors || !Array.isArray(configData.sensors)) {
return {
success: false,
error: '配置文件格式不正确:缺少 sensors 数组'
}
}
return {
success: true,
data: configData,
filePath
}
} catch (error) {
console.error('导入配置文件失败:', error)
return {
success: false,
error: error.message || '文件读取或解析失败'
}
}
}
//配置保存
const saveConfig = async (event, { data, ip }) => {
try {
// 打开保存对话框
const result = await dialog.showSaveDialog({
title: '保存传感器配置',
defaultPath: path.join(app.getPath('documents'), `${ip}-测点列表.json`),
filters: [
{ name: 'JSON 配置文件', extensions: ['json'] },
{ name: '所有文件', extensions: ['*'] }
],
properties: ['createDirectory', 'showOverwriteConfirmation']
})
if (result.canceled) {
return { success: false, canceled: true }
}
// 写入文件
await fs.writeFile(result.filePath, JSON.stringify(data, null, 2), 'utf-8')
return { success: true, filePath: result.filePath }
} catch (error) {
console.error('保存配置文件失败:', error)
return { success: false, error: error.message }
}
}
// 获取设备的曝光参数
const exposureGet = async (event, { ip }) => {

6
src/renderer/src/common/ipcEvents.js

@ -56,5 +56,9 @@ export const IPC_EVENT = {
// 曝光参数相关操作
EXPOSURE_GET: 'exposure:get',
EXPOSURE_SET: 'exposure:set'
EXPOSURE_SET: 'exposure:set',
// 配置保存与加载
SAVE_CONFIG: 'save-config',
LOAD_CONFIG: 'load-config'
}

156
src/renderer/src/components/MeasurementPointSetting/MeasurementPointSetting.jsx

@ -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>

Loading…
Cancel
Save