import React, { CSSProperties, useState, useEffect, useCallback, forwardRef, useRef, useMemo, } from 'react'; import classNames from '@pansy/classnames'; import { Button, Radio, message } from 'antd'; import { PlusOutlined } from '@ant-design/icons'; import Icon from '@sensoro/library/lib/components/icon-font'; import { Map, Controls, MapTheme } from '../map'; import { MouseTool, Markers } from '@sensoro/react-amap'; import { DeviceInfo } from './interface'; import Marker from './common/marker'; import Card from './common/card'; import styles from './index.less'; // 选择设备状态 // 1: 初始状态 2: 选择框选类型 3: 重新框选 type Status = 1 | 2 | 3; interface SelectDeviceProps { // 设备唯一标识集合 value?: string[]; style?: CSSProperties; simpleMode?: boolean; // 指定设备中唯一标识 默认为 cid deviceKey?: string; devices?: DeviceInfo[]; onChange?: (value: string[]) => void; onSelectDeviceClick?: () => void; readonly?: boolean; zoom?: number; center?: any; } let mouseTool: any = null; let overlayer: any = null; const SelectDevice = forwardRef((props: SelectDeviceProps, ref: any) => { const { style, devices = [], value = [], simpleMode, onSelectDeviceClick, onChange, deviceKey = 'cid', readonly, zoom, center, } = props; const [type, setType] = useState(''); const [status, setStatus] = useState(1); const [deviceList, setDeviceList] = useState([]); const [selectDevices, setSelectDevices] = useState([]); // 聚合实例 const markersInstance = useRef(null); // 地图实例 const mapInstance = useRef(null); const [mapIns, setMapIns] = useState(null); const lock = useRef(false); useEffect(() => { setTimeout(() => { if ( !lock.current && !simpleMode && mapInstance.current && markersInstance.current ) { mapInstance.current.setFitView(markersInstance.current); lock.current = true; } }, 200); }, [props.devices, props.simpleMode, markersInstance.current]); useEffect(() => { setDeviceList( devices.map(item => { return { ...item, position: { longitude: item.lng, latitude: item.lat, }, selected: value.includes(item[deviceKey]), }; }), ); setSelectDevices( value .map(sn => { return devices.find(item => item[deviceKey] === sn) as any; }) .filter(item => item), ); if (!simpleMode && value.length === 0) { if (mapInstance.current && overlayer) { setStatus(1); mapInstance.current.remove([overlayer]); } } }, [props.devices, props.value, props.simpleMode]); const setSelectDevicesCallback = useCallback( (nextValue: DeviceInfo[] = []) => { setSelectDevices(nextValue); onChange?.(nextValue.map(item => item[deviceKey])); }, [setSelectDevices], ); const toolEvents = { created: (tool: any) => { mouseTool = tool; }, draw({ obj }: any) { handleDrawEnd(obj); }, }; const markersEvents = { created: (markers: any) => { markersInstance.current = markers; }, }; const mapEvents = { created: (ins: any) => { setMapIns(ins); mapInstance.current = ins; }, }; /** * 绘制圆形 */ const handleDrawCircle = () => { if (mouseTool) { mouseTool.circle(); } }; /** * 绘制矩形 */ const handleDrawRectangle = () => { if (mouseTool) { mouseTool.rectangle(); } }; /** * 绘制多边形 */ const handleDrawPolygon = () => { if (mouseTool) { mouseTool.polygon(); } }; /** * 关闭绘图 */ const handleDrawClose = () => { if (mouseTool) { mouseTool.close(); } }; /** * 框选结束回调 * @param obj */ const handleDrawEnd = (obj: any) => { overlayer = obj; handleDrawClose(); const devices: DeviceInfo[] = []; const newDevices = [...selectDevices]; const ids: string[] = selectDevices.map(item => item[deviceKey]); let result = false; const newDeviceList = deviceList.map(item => { let selected = false; if (item.position && item.position.latitude && item.position.longitude) { if ( obj.contains( new window.AMap.LngLat( item.position.longitude, item.position.latitude, ), ) ) { devices.push(item); selected = true; result = true; } } if (ids.includes(item[deviceKey])) { selected = true; } return { ...item, selected, }; }); devices.forEach(item => { if (ids.indexOf(item[deviceKey]) === -1) { newDevices.push(item); } }); setSelectDevicesCallback(newDevices); setDeviceList(newDeviceList); if (!result) { message.warning('未框选到任何设备'); setStatus(2); setType(''); mapInstance.current.remove([overlayer]); } else { setStatus(3); } }; /** * 重新框选 */ const handleReframe = () => { setType(''); setStatus(2); if (mapInstance && overlayer) { mapInstance.current.remove([overlayer]); } overlayer = null; }; const handleReset = () => { const newDeviceList = deviceList.map(item => { return { ...item, selected: false, }; }); setDeviceList(newDeviceList); if (mapInstance.current && overlayer) { setStatus(1); mapInstance.current.remove([overlayer]); } setSelectDevicesCallback([]); }; const handleDrawTypeChange = (value: string) => { setType(value); if (value === 'circle') { handleDrawCircle(); } if (value === 'rectangle') { handleDrawRectangle(); } if (value === 'polygon') { handleDrawPolygon(); } }; const handleDeviceRemove = (id: string) => { const newDeviceList = deviceList.map(item => { if (item[deviceKey] === id) { return { ...item, selected: false, }; } return item; }); const newSelectDevices = selectDevices.filter( item => item[deviceKey] !== id, ); if (mapInstance.current && overlayer && newSelectDevices.length === 0) { setStatus(1); mapInstance.current.remove([overlayer]); } setDeviceList(newDeviceList); setSelectDevicesCallback(newSelectDevices); }; const [mapThemeStatus, setMapThemeStatus] = useState(false); const Theme = useMemo(() => { return ( ); }, [mapIns, mapThemeStatus]); const mapProps = !zoom ? {} : { zoom, center }; return (
{simpleMode && (
{Theme} {!readonly && ( 选择设备 )}
)} {!simpleMode && status === 2 && ( <>
{ setStatus(1); }} > 取消框选
{ handleDrawTypeChange('circle'); }} > 圆形 { handleDrawTypeChange('rectangle'); }} > 矩形 { handleDrawTypeChange('polygon'); }} > 多边形
)} {!simpleMode && (
{status === 1 && ( <> {Theme} { setStatus(2); }} > 框选设备 )} {status === 3 && ( <> {Theme} 重新框选 )}
)} {!simpleMode && ( )} { return ; }} events={markersEvents} useCluster={{ zoomOnClick: () => {}, renderCluserMarker: ({ count, marker, markers }: any) => { const list: DeviceInfo[] = markers .map((item: any) => { return item?.G?.extData; }) .filter((item: DeviceInfo) => item?.selected); if (list.length) { marker.setContent( `
${list.length}${count}
`, ); } else { marker.setContent( `
${count}
`, ); } }, }} />
); }); SelectDevice.defaultProps = { simpleMode: true, deviceKey: 'cid', value: [], devices: [], }; export default SelectDevice;