有源标靶上位机
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

188 lines
6.3 KiB

import { useState, useEffect } from 'react'
import styles from './SiderHeader.module.css'
import { Flex, Select, Button, Input, Spin, message } from 'antd'
import { IPC_EVENT } from '../../common/ipcEvents.js'
import useDeviceStore from '../../stores/deviceStore'
import {
VideoCameraFilled,
GoldFilled,
ApiFilled,
SecurityScanFilled,
SlidersFilled
} from '@ant-design/icons'
import SystemSettings from '../SystemSettings/SystemSettings'
import MeasurementPointSetting from '../MeasurementPointSetting/MeasurementPointSetting'
import PropTypes from 'prop-types'
function SiderHeader({ showSystemSettings = true }) {
const [searching, setSearching] = useState(false)
const [deviceList, setDeviceList] = useState([])
const [selectedDevice, setSelectedDevice] = useState(undefined)
const [devicePort, setDevicePort] = useState('2230')
const [connected, setConnected] = useState(null) // 保存已连接设备IP
// 使用设备store
const setConnectedDevice = useDeviceStore((state) => state.setConnectedDevice)
const clearConnectedDevice = useDeviceStore((state) => state.clearConnectedDevice)
const setDeviceList_store = useDeviceStore((state) => state.setDeviceList)
// 监听设备搜索结果
useEffect(() => {
const handler = (event, results) => {
setSearching(false)
if (Array.isArray(results) && results.length > 0) {
const ips = results.map((item) => item.from)
const devices = ips.map((ip) => ({ value: ip, label: ip }))
setDeviceList(devices)
// 同时更新到store中
setDeviceList_store(ips.map((ip) => ({ ip, name: ip })))
message.success(`发现${ips.length}台设备`)
} else {
setDeviceList([])
setDeviceList_store([])
message.warning('未发现设备')
}
}
window.electron.ipcRenderer.on(IPC_EVENT.DEVICE_SEARCH_REPLY, handler)
return () => {
window.electron.ipcRenderer.removeListener(IPC_EVENT.DEVICE_SEARCH_REPLY, handler)
}
}, [setDeviceList_store])
// 监听设备连接/断开结果
useEffect(() => {
const connectHandler = (event, result) => {
if (result.success) {
setConnected(result.ip)
// 更新到store中
setConnectedDevice({
ip: result.ip,
port: devicePort,
connectedAt: new Date().toISOString()
})
message.success('设备连接成功')
} else {
setConnected(null)
clearConnectedDevice()
message.error('设备连接失败: ' + (result.error || '未知错误'))
}
}
const disconnectHandler = (event, result) => {
setConnected(null)
// 清除store中的连接信息
clearConnectedDevice()
if (result.success) {
message.success('设备已断开')
} else {
message.error('断开失败: ' + (result.error || '未知错误'))
}
}
window.electron.ipcRenderer.on(IPC_EVENT.DEVICE_CONNECT_REPLY, connectHandler)
window.electron.ipcRenderer.on(IPC_EVENT.DEVICE_DISCONNECT_REPLY, disconnectHandler)
return () => {
window.electron.ipcRenderer.removeListener(IPC_EVENT.DEVICE_CONNECT_REPLY, connectHandler)
window.electron.ipcRenderer.removeListener(
IPC_EVENT.DEVICE_DISCONNECT_REPLY,
disconnectHandler
)
}
}, [devicePort, setConnectedDevice, clearConnectedDevice])
// 搜索设备
const handleSearchDevice = () => {
setSearching(true)
setDeviceList([])
setSelectedDevice(undefined)
window.electron.ipcRenderer.send(IPC_EVENT.DEVICE_SEARCH)
}
// 连接/断开设备
const handleConnectOrDisconnect = () => {
if (connected) {
// 已连接,断开
window.electron.ipcRenderer.send(IPC_EVENT.DEVICE_DISCONNECT, { ip: connected })
} else {
// 未连接,连接
if (!selectedDevice || !devicePort) {
message.error('请选择设备并填写端口')
return
}
window.electron.ipcRenderer.send(IPC_EVENT.DEVICE_CONNECT, {
ip: selectedDevice,
port: devicePort
})
}
}
// 除断开连接按钮外,其他UI是否禁用
const uiDisabled = !!connected
// 调试信息
console.log('connected:', connected, 'uiDisabled:', uiDisabled)
return (
<Flex vertical>
<Flex className={styles.header}>
<div className={styles.titlePanel}>
挠度仪控制面板
<SlidersFilled />
</div>
<Flex vertical gap={8} className={styles.contentPanel}>
<Flex align="center">
<VideoCameraFilled className={styles.icon} />
<span className={styles.label}>设备列表:</span>
<Select
className={styles.deviceSelect}
placeholder="请选择设备"
loading={searching}
value={selectedDevice}
options={deviceList}
onChange={setSelectedDevice}
style={{ minWidth: 120, flex: 1 }}
notFoundContent={searching ? <Spin size="small" /> : '无设备'}
disabled={searching || uiDisabled}
/>
</Flex>
<Flex align="center">
<span className={styles.label}>设备端口:</span>
<GoldFilled className={styles.icon} />
<Input
className={styles.deviceInput}
value={devicePort}
onChange={(e) => setDevicePort(e.target.value)}
disabled={uiDisabled}
/>
</Flex>
<Flex gap={8}>
<Button
className={styles.actionButton}
type="primary"
icon={<SecurityScanFilled />}
loading={searching}
onClick={handleSearchDevice}
disabled={searching || uiDisabled}
>
{searching ? '正在搜索...' : '搜索设备'}
</Button>
<Button
className={styles.actionButton}
icon={<ApiFilled />}
danger={!!connected}
type={connected ? 'primary' : 'default'}
onClick={handleConnectOrDisconnect}
>
{connected ? '断开连接' : '连接设备'}
</Button>
</Flex>
</Flex>
</Flex>
{showSystemSettings ? <SystemSettings /> : <MeasurementPointSetting />}
</Flex>
)
}
SiderHeader.propTypes = {
showSystemSettings: PropTypes.bool
}
export default SiderHeader