为 SCADA 设备列表实现虚拟列表,优化渲染性能
This commit is contained in:
@@ -12,7 +12,6 @@ import {
|
||||
Box,
|
||||
Paper,
|
||||
Typography,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
@@ -39,6 +38,7 @@ import {
|
||||
Clear,
|
||||
DeviceHub,
|
||||
} from "@mui/icons-material";
|
||||
import { FixedSizeList } from "react-window";
|
||||
|
||||
import { useMap } from "@app/OlMap/MapComponent";
|
||||
import { GeoJSON } from "ol/format";
|
||||
@@ -452,108 +452,122 @@ const SCADADeviceList: React.FC<SCADADeviceListProps> = ({
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<List dense sx={{ p: 0 }}>
|
||||
{filteredDevices.map((device, index) => (
|
||||
<React.Fragment key={device.id}>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
selected={activeSelection.includes(device.id)}
|
||||
onClick={(event) => handleDeviceClick(device, event)}
|
||||
sx={{
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: "primary.50",
|
||||
borderLeft: 3,
|
||||
borderColor: "primary.main",
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: "grey.50",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: `${getStatusColor(device.status)}.main`,
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{getStatusIcon(device.status)}
|
||||
</Typography>
|
||||
</ListItemIcon>
|
||||
|
||||
<ListItemText
|
||||
primary={
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={1}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ fontWeight: "medium" }}
|
||||
>
|
||||
{device.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={device.type}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ fontSize: "0.7rem", height: 20 }}
|
||||
/>
|
||||
</Stack>
|
||||
}
|
||||
secondary={
|
||||
<Stack spacing={0.5}>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
ID: {device.id}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
坐标: {device.coordinates[0].toFixed(6)},{" "}
|
||||
{device.coordinates[1].toFixed(6)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
}
|
||||
slotProps={{
|
||||
secondary: {
|
||||
component: "div", // 使其支持多行
|
||||
<FixedSizeList
|
||||
height={400}
|
||||
itemCount={filteredDevices.length}
|
||||
itemSize={80}
|
||||
width="100%"
|
||||
>
|
||||
{({
|
||||
index,
|
||||
style,
|
||||
}: {
|
||||
index: number;
|
||||
style: React.CSSProperties;
|
||||
}) => {
|
||||
const device = filteredDevices[index];
|
||||
return (
|
||||
<div style={style}>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
selected={activeSelection.includes(device.id)}
|
||||
onClick={(event) => handleDeviceClick(device, event)}
|
||||
sx={{
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: "primary.50",
|
||||
borderLeft: 3,
|
||||
borderColor: "primary.main",
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: "grey.50",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
color: `${getStatusColor(device.status)}.main`,
|
||||
fontWeight: "bold",
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{getStatusIcon(device.status)}
|
||||
</Typography>
|
||||
</ListItemIcon>
|
||||
|
||||
<Tooltip title="缩放到设备位置">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleZoomToDevice(device);
|
||||
}}
|
||||
sx={{
|
||||
ml: 1,
|
||||
color: "primary.main",
|
||||
"&:hover": {
|
||||
backgroundColor: "primary.50",
|
||||
<ListItemText
|
||||
primary={
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={1}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ fontWeight: "medium" }}
|
||||
>
|
||||
{device.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={device.type}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ fontSize: "0.7rem", height: 20 }}
|
||||
/>
|
||||
</Stack>
|
||||
}
|
||||
secondary={
|
||||
<Stack spacing={0.5}>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
ID: {device.id}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
>
|
||||
坐标: {device.coordinates[0].toFixed(6)},{" "}
|
||||
{device.coordinates[1].toFixed(6)}
|
||||
</Typography>
|
||||
</Stack>
|
||||
}
|
||||
slotProps={{
|
||||
secondary: {
|
||||
component: "div", // 使其支持多行
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MyLocation fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
{index < filteredDevices.length - 1 && (
|
||||
<Divider variant="inset" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</List>
|
||||
/>
|
||||
|
||||
<Tooltip title="缩放到设备位置">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
handleZoomToDevice(device);
|
||||
}}
|
||||
sx={{
|
||||
ml: 1,
|
||||
color: "primary.main",
|
||||
"&:hover": {
|
||||
backgroundColor: "primary.50",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MyLocation fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
{index < filteredDevices.length - 1 && (
|
||||
<Divider variant="inset" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</FixedSizeList>
|
||||
)}
|
||||
</Box>
|
||||
</Collapse>
|
||||
|
||||
Reference in New Issue
Block a user