2025-09-28 17:45:29 +08:00
|
|
|
|
import React, { Fragment, useRef, useMemo, useEffect, useState } from 'react';
|
2024-09-20 15:02:50 +08:00
|
|
|
|
import BasicCrudModal from '../../../../components/crud/BasicCrudModal';
|
2025-09-28 17:45:29 +08:00
|
|
|
|
import { Table, Card, Modal, Form, Input, Button, Row, Col, Timeline, message, Tabs, Image, Tag } from 'antd';
|
|
|
|
|
|
import { FileWordOutlined, FilePdfOutlined, FileZipOutlined, FileExcelOutlined } from '@ant-design/icons';
|
|
|
|
|
|
import { useSelector, useDispatch } from 'react-redux';
|
2024-09-20 15:02:50 +08:00
|
|
|
|
import ToolBar from './toolbar';
|
|
|
|
|
|
import ModalForm from './form';
|
|
|
|
|
|
import apiurl from '../../../../service/apiurl';
|
|
|
|
|
|
import usePageTable from '../../../../components/crud/usePageTable2';
|
|
|
|
|
|
import { createCrudService } from '../../../../components/crud/_';
|
2025-09-28 17:45:29 +08:00
|
|
|
|
import { httppost2, httpget2 } from '../../../../utils/request';
|
|
|
|
|
|
import { CrudOpRender_text } from '../../../../components/crud/CrudOpRender';
|
|
|
|
|
|
import PointHistory from './pointHistory';
|
2025-09-29 17:57:17 +08:00
|
|
|
|
import PrecessForm from './precessForm'
|
2025-03-21 17:36:23 +08:00
|
|
|
|
import './index.less';
|
2025-09-19 17:14:29 +08:00
|
|
|
|
import moment from 'moment';
|
2025-09-28 17:45:29 +08:00
|
|
|
|
// 引入OpenLayers相关依赖
|
|
|
|
|
|
import Map from 'ol/Map';
|
|
|
|
|
|
import View from 'ol/View';
|
|
|
|
|
|
import TileLayer from 'ol/layer/Tile';
|
|
|
|
|
|
import XYZSource from 'ol/source/XYZ';
|
|
|
|
|
|
import * as proj from 'ol/proj';
|
|
|
|
|
|
import Feature from 'ol/Feature';
|
|
|
|
|
|
import Point from 'ol/geom/Point';
|
|
|
|
|
|
import { Vector as VectorLayer } from 'ol/layer';
|
|
|
|
|
|
import { Vector as VectorSource } from 'ol/source';
|
|
|
|
|
|
import { Circle as CircleStyle, Fill, Stroke, Style, Text } from 'ol/style';
|
|
|
|
|
|
import Overlay from 'ol/Overlay';
|
2025-04-07 09:16:20 +08:00
|
|
|
|
const url = "http://223.75.53.141:9100/gs-tsg"
|
2024-09-20 15:02:50 +08:00
|
|
|
|
const Page = () => {
|
|
|
|
|
|
const role = useSelector(state => state.auth.role);
|
2024-09-23 13:49:58 +08:00
|
|
|
|
const editBtn = role?.rule?.find(item => item.menuName == "编辑") || true;
|
2025-09-28 17:45:29 +08:00
|
|
|
|
const viewBtn = role?.rule?.find(item => item.menuName == "查看") || true;
|
2025-03-21 17:36:23 +08:00
|
|
|
|
const delBtn = role?.rule?.find(item => item.menuName == "删除") || true;
|
2025-09-19 17:14:29 +08:00
|
|
|
|
const initData = {
|
|
|
|
|
|
obDate: moment().format('YYYY-MM-DD')
|
|
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
// 添加地图相关的状态和引用
|
|
|
|
|
|
const mapContainerRef = useRef(null);
|
|
|
|
|
|
const [map, setMap] = useState(null);
|
|
|
|
|
|
const [vectorLayer, setVectorLayer] = useState(null);
|
|
|
|
|
|
const [selectedFeature, setSelectedFeature] = useState(null);
|
|
|
|
|
|
const [popupOverlay, setPopupOverlay] = useState(null);
|
|
|
|
|
|
const popupRef = useRef(null);
|
|
|
|
|
|
// 在组件顶部的状态声明中添加一个新的状态
|
|
|
|
|
|
const [highlightLayer, setHighlightLayer] = useState(null);
|
|
|
|
|
|
// 点位弹框
|
|
|
|
|
|
const [modalVisible, setModalVisible] = useState(false)
|
|
|
|
|
|
const [detailPoint, setDetailPoint] = useState({})
|
2025-09-29 17:57:17 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 白蚁处理弹框
|
|
|
|
|
|
const [precessVisible, setPrecessVisible] = useState(false)
|
|
|
|
|
|
const [mode, setMode] = useState('save')
|
|
|
|
|
|
|
2025-09-28 17:45:29 +08:00
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-09-20 15:02:50 +08:00
|
|
|
|
const refModal = useRef();
|
2025-09-28 17:45:29 +08:00
|
|
|
|
const [searchVal, setSearchVal] = useState({ ...initData })
|
2025-03-27 14:37:31 +08:00
|
|
|
|
const [count, setCount] = useState({})
|
2025-09-28 17:45:29 +08:00
|
|
|
|
const [allCdList, setAllCdList] = useState([])
|
2025-03-21 17:36:23 +08:00
|
|
|
|
// const columns = [
|
|
|
|
|
|
// { title: '序号', key: 'inx', dataIndex: 'inx', width: 60, align: "center" },
|
|
|
|
|
|
// {title: '填报日期', key: 'reportDate', dataIndex: 'reportDate', width: 140,},
|
|
|
|
|
|
// {
|
|
|
|
|
|
// title: '普查类型', key: 'surveyType', dataIndex: 'surveyType', width: 200,
|
|
|
|
|
|
// render: (value) => <span>{value ? surveyType[value] : ''}</span>
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// title: '普查方式', key: 'surveyWay', dataIndex: 'surveyWay', width: 200,
|
|
|
|
|
|
// render: (value) => <span>{value ? surveyWay[value] : ''}</span>
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
2025-03-21 17:36:23 +08:00
|
|
|
|
// },
|
|
|
|
|
|
// {
|
|
|
|
|
|
// title: '危害情况', key: 'isHarm', dataIndex: 'isHarm', width: 200,
|
|
|
|
|
|
// render: (value, row) =>(
|
|
|
|
|
|
// <span style={row.harmNum > 0 ? { color: "red" } : {}}>{isHarm[row.harmNum > 0 ? 1 : 0]}</span>)
|
|
|
|
|
|
// },
|
|
|
|
|
|
// {title: '白蚁危害处数', key: 'harmNum', dataIndex: 'harmNum', width: 100},
|
|
|
|
|
|
// {title: '已处置处数', key: 'handleNum', dataIndex: 'handleNum', width: 100},
|
|
|
|
|
|
// {title: '上报人', key: 'reportUserName', dataIndex: 'reportUserName', width: 100},
|
|
|
|
|
|
// {
|
|
|
|
|
|
// title: '操作', key: 'operation', width: 200, fixed: 'right',align: 'center',
|
|
|
|
|
|
// render: (value, row, index) => (
|
|
|
|
|
|
// <CrudOpRender_text
|
|
|
|
|
|
// edit={editBtn ? true : false}
|
|
|
|
|
|
// del={delBtn ? true : false}
|
|
|
|
|
|
// view={viewBtn ? true : false}
|
|
|
|
|
|
// command={(cmd) => () => command(cmd)(row)} />)
|
|
|
|
|
|
// },
|
|
|
|
|
|
// ];
|
|
|
|
|
|
|
2024-09-20 15:02:50 +08:00
|
|
|
|
const columns = [
|
|
|
|
|
|
{
|
2025-03-21 17:36:23 +08:00
|
|
|
|
title: '监测时间',
|
2025-09-01 17:55:23 +08:00
|
|
|
|
dataIndex: 'obDate',
|
|
|
|
|
|
key: 'obDate',
|
2025-03-27 14:37:31 +08:00
|
|
|
|
width: 180,
|
2025-09-28 17:45:29 +08:00
|
|
|
|
align: 'center'
|
2024-09-20 15:02:50 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
2025-03-21 17:36:23 +08:00
|
|
|
|
title: '测点编号',
|
2025-09-02 17:27:53 +08:00
|
|
|
|
dataIndex: 'order',
|
|
|
|
|
|
key: 'order',
|
2025-03-27 14:37:31 +08:00
|
|
|
|
width: 120,
|
2025-09-28 17:45:29 +08:00
|
|
|
|
align: 'center'
|
2024-09-20 15:02:50 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
2025-03-21 17:36:23 +08:00
|
|
|
|
title: '有无白蚁',
|
2025-09-01 17:55:23 +08:00
|
|
|
|
dataIndex: 'status',
|
2025-09-28 17:45:29 +08:00
|
|
|
|
align: 'center',
|
2025-09-01 17:55:23 +08:00
|
|
|
|
key: 'status',
|
2025-03-21 17:36:23 +08:00
|
|
|
|
width: 100,
|
2025-09-28 17:45:29 +08:00
|
|
|
|
render: (text, record) => {
|
2025-03-27 14:37:31 +08:00
|
|
|
|
// 如果 isHarm 为 null 或 undefined,显示无
|
|
|
|
|
|
if (text == null) {
|
2025-09-28 17:45:29 +08:00
|
|
|
|
return <Tag color="#04d919" style={{ borderRadius: '50%', padding: '4px 8px' }}>无</Tag>;
|
2025-03-27 14:37:31 +08:00
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
2025-03-27 14:37:31 +08:00
|
|
|
|
// 如果 isHandle 为 null 或 undefined,当作 false 处理
|
|
|
|
|
|
const isHandle = record.isHandle ?? false;
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
2025-03-27 14:37:31 +08:00
|
|
|
|
return (
|
2025-09-28 17:45:29 +08:00
|
|
|
|
<Tag
|
|
|
|
|
|
color={!text ? '#04d919' : '#d9001b'}
|
|
|
|
|
|
style={{ borderRadius: '50%', padding: '4px 8px' }}
|
2025-03-27 14:37:31 +08:00
|
|
|
|
>
|
2025-09-01 17:55:23 +08:00
|
|
|
|
{!text ? '无' : '有'}
|
2025-03-27 14:37:31 +08:00
|
|
|
|
</Tag>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-09-29 17:57:17 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
|
|
|
|
|
dataIndex: 'opreate',
|
|
|
|
|
|
key: 'opreate',
|
|
|
|
|
|
width: 120,
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
render: (v, r) => {
|
|
|
|
|
|
let renderTag;
|
|
|
|
|
|
if (!r.isProcess && r.status == 1) {
|
|
|
|
|
|
renderTag = <Button style={{ marginRight: 4 }} type="link" size="small" onClick={()=> handlerPrecess(r,'save')} title="处理">处理</Button>;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (r.hasInspectTask && r.jcskByRProcessVo) {
|
|
|
|
|
|
renderTag = <Button style={{ marginRight: 4 }} type="link" size="small" onClick={()=> handlerPrecess(r,'view')} title="工单详情">工单详情</Button>;
|
|
|
|
|
|
}
|
|
|
|
|
|
return (<>
|
|
|
|
|
|
{renderTag}
|
|
|
|
|
|
<Button style={{ marginRight: 4 }} type="link" size="small" title="查看" onClick={()=> viewDetail(r)}>查看</Button>
|
|
|
|
|
|
</>)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2024-09-20 15:02:50 +08:00
|
|
|
|
];
|
|
|
|
|
|
const width = useMemo(() => columns.reduce((total, cur) => total + (cur.width), 0), [columns]);
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
2024-09-20 15:02:50 +08:00
|
|
|
|
const command = (type) => (params) => {
|
|
|
|
|
|
if (type === 'save') {
|
|
|
|
|
|
refModal.current.showSave();
|
|
|
|
|
|
} else if (type === 'edit') {
|
|
|
|
|
|
refModal.current.showEdit({ ...params });
|
|
|
|
|
|
} else if (type === 'view') {
|
|
|
|
|
|
refModal.current.showView(params);
|
|
|
|
|
|
} else if (type === 'del') {
|
|
|
|
|
|
refModal.current.onDeleteGet(apiurl.rcgl.byfz.bypc.delete + `/${params.id}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-09-20 15:02:50 +08:00
|
|
|
|
|
|
|
|
|
|
const { tableProps, search, refresh } = usePageTable(createCrudService(apiurl.rcgl.byfz.bypc.page).find_noCode);
|
|
|
|
|
|
|
2025-09-28 17:45:29 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @description 处理成功的回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
const successCallback = () => {
|
|
|
|
|
|
refresh()
|
2025-03-27 14:37:31 +08:00
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
2025-09-29 17:57:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 表格操作栏 查看按钮回调
|
|
|
|
|
|
const viewDetail = (r) => {
|
|
|
|
|
|
setDetailPoint(r);
|
|
|
|
|
|
setModalVisible(true)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 表格操作栏 处理按钮回调
|
|
|
|
|
|
const handlerPrecess = (r,type) => {
|
|
|
|
|
|
setDetailPoint(r);
|
|
|
|
|
|
setPrecessVisible(true)
|
|
|
|
|
|
setMode(type)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 14:37:31 +08:00
|
|
|
|
// 获取白蚁统计数量
|
|
|
|
|
|
const getCount = async () => {
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
pageSo: {
|
|
|
|
|
|
pageNumber: 1,
|
|
|
|
|
|
pageSize: 99999,
|
2025-03-28 17:33:56 +08:00
|
|
|
|
},
|
2025-09-18 15:26:22 +08:00
|
|
|
|
...searchVal
|
2025-03-27 14:37:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await httppost2(apiurl.rcgl.byfz.bypc.count, params);
|
|
|
|
|
|
setCount(res.data);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log(error);
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取白蚁所有测点
|
2025-09-30 15:49:30 +08:00
|
|
|
|
const getCdList = async (params) => {
|
|
|
|
|
|
|
2025-09-28 17:45:29 +08:00
|
|
|
|
try {
|
2025-09-30 15:49:30 +08:00
|
|
|
|
const res = await httppost2(apiurl.rcgl.byfz.bypc.allCd,params);
|
2025-09-28 17:45:29 +08:00
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
|
setAllCdList(res.data);
|
|
|
|
|
|
// 添加标记点到地图
|
|
|
|
|
|
if (map && res.data && res.data.length > 0) {
|
|
|
|
|
|
addMarkersToMap(res.data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log(error);
|
|
|
|
|
|
|
2025-03-27 14:37:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加标记点到地图
|
|
|
|
|
|
const addMarkersToMap = (points) => {
|
|
|
|
|
|
if (!map) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果已存在矢量图层,先移除
|
|
|
|
|
|
if (vectorLayer) {
|
|
|
|
|
|
map.removeLayer(vectorLayer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建矢量数据源
|
|
|
|
|
|
const vectorSource = new VectorSource();
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历所有点位数据
|
|
|
|
|
|
points.forEach(point => {
|
|
|
|
|
|
// 确保点位有经纬度
|
|
|
|
|
|
if (point.lgtd && point.lttd) {
|
|
|
|
|
|
// 创建要素
|
|
|
|
|
|
const feature = new Feature({
|
|
|
|
|
|
geometry: new Point(proj.fromLonLat([point.lgtd, point.lttd])),
|
|
|
|
|
|
properties: point // 保存点位的所有属性
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 根据status设置样式
|
2025-09-30 15:49:30 +08:00
|
|
|
|
const color = point.status === 1 ? '#d9001b' :
|
|
|
|
|
|
point.status === 0 ? '#04d919':'#8c8c8c'
|
|
|
|
|
|
; // 1为红色,0为绿色 null 为灰色
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
|
|
|
|
|
feature.setStyle(new Style({
|
|
|
|
|
|
image: new CircleStyle({
|
|
|
|
|
|
radius: 4,
|
|
|
|
|
|
fill: new Fill({ color: color }),
|
|
|
|
|
|
stroke: new Stroke({ color: '#ffffff', width: 1 })
|
|
|
|
|
|
})
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// 添加要素到数据源
|
|
|
|
|
|
vectorSource.addFeature(feature);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 创建矢量图层
|
|
|
|
|
|
const newVectorLayer = new VectorLayer({
|
|
|
|
|
|
source: vectorSource,
|
|
|
|
|
|
zIndex: 10 // 确保点位在地图上层显示
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加图层到地图
|
|
|
|
|
|
map.addLayer(newVectorLayer);
|
|
|
|
|
|
|
|
|
|
|
|
// 保存矢量图层引用
|
|
|
|
|
|
setVectorLayer(newVectorLayer);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加点击事件处理
|
|
|
|
|
|
// map.on('click', (event) => {
|
|
|
|
|
|
// const feature = map.forEachFeatureAtPixel(event.pixel, function(feature) {
|
|
|
|
|
|
// return feature;
|
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
|
|
// if (feature) {
|
|
|
|
|
|
// const properties = feature.get('properties');
|
|
|
|
|
|
// if (properties) {
|
|
|
|
|
|
// // 可以在这里处理点击事件,比如显示详情等
|
|
|
|
|
|
// console.log('点击了标记点:', properties);
|
|
|
|
|
|
// // 可以添加弹窗或其他交互
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 修改高亮显示选中的测点函数
|
|
|
|
|
|
const highlightFeature = (feature) => {
|
|
|
|
|
|
if (!feature || !highlightLayer) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 清除之前的高亮
|
|
|
|
|
|
highlightLayer.getSource().clear();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取要素属性
|
|
|
|
|
|
const properties = feature.get('properties');
|
|
|
|
|
|
const color = properties.status === 1 ? '#d9001b' : '#04d919';
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个新的要素用于高亮显示
|
|
|
|
|
|
const highlightFeature = new Feature({
|
|
|
|
|
|
geometry: feature.getGeometry().clone(),
|
|
|
|
|
|
properties: properties
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 设置高亮样式
|
|
|
|
|
|
highlightFeature.setStyle(new Style({
|
|
|
|
|
|
image: new CircleStyle({
|
|
|
|
|
|
radius: 10, // 放大图标
|
|
|
|
|
|
fill: new Fill({ color: color }),
|
|
|
|
|
|
stroke: new Stroke({ color: '#ffffff', width: 3 })
|
|
|
|
|
|
}),
|
|
|
|
|
|
text: new Text({
|
|
|
|
|
|
text: properties.order || '未命名测点',
|
|
|
|
|
|
offsetY: -20,
|
|
|
|
|
|
font: 'bold 14px Arial',
|
|
|
|
|
|
fill: new Fill({ color: '#333' }),
|
|
|
|
|
|
stroke: new Stroke({ color: '#fff', width: 3 })
|
|
|
|
|
|
})
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到高亮图层
|
|
|
|
|
|
highlightLayer.getSource().addFeature(highlightFeature);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新选中的要素引用
|
|
|
|
|
|
setSelectedFeature(feature);
|
|
|
|
|
|
|
|
|
|
|
|
// 平移地图到选中的要素位置
|
|
|
|
|
|
const geometry = feature.getGeometry();
|
|
|
|
|
|
const coordinate = geometry.getCoordinates();
|
|
|
|
|
|
map.getView().animate({
|
|
|
|
|
|
center: coordinate,
|
|
|
|
|
|
duration: 500,
|
|
|
|
|
|
zoom: map.getView().getZoom() < 18 ? 18 : map.getView().getZoom()
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 根据测点ID查找对应的要素
|
|
|
|
|
|
const findFeatureByDeviceId = (deviceId) => {
|
|
|
|
|
|
if (!vectorLayer) return null;
|
|
|
|
|
|
|
|
|
|
|
|
let targetFeature = null;
|
|
|
|
|
|
vectorLayer.getSource().forEachFeature((feature) => {
|
|
|
|
|
|
const properties = feature.get('properties');
|
|
|
|
|
|
if (properties && properties.order === deviceId) {
|
|
|
|
|
|
targetFeature = feature;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return targetFeature;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理表格行点击事件
|
2025-09-29 17:57:17 +08:00
|
|
|
|
const handleRowClick = (record,event) => {
|
|
|
|
|
|
// 如果点击的是操作列中的元素,不触发地图交互
|
|
|
|
|
|
if (event && (event.target.closest('button') || event.target.closest('.ant-btn'))) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
const feature = findFeatureByDeviceId(record.order);
|
|
|
|
|
|
if (feature) {
|
|
|
|
|
|
highlightFeature(feature);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-03-27 14:37:31 +08:00
|
|
|
|
useEffect(() => {
|
2025-09-19 17:14:29 +08:00
|
|
|
|
const params = {
|
|
|
|
|
|
search: {
|
|
|
|
|
|
...searchVal,
|
|
|
|
|
|
}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
};
|
2025-09-19 17:14:29 +08:00
|
|
|
|
search(params)
|
2025-03-27 14:37:31 +08:00
|
|
|
|
getCount();
|
2025-03-28 17:33:56 +08:00
|
|
|
|
}, [searchVal])
|
2025-09-28 17:45:29 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化地图
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!mapContainerRef.current) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建地图实例
|
|
|
|
|
|
const mapInstance = new Map({
|
|
|
|
|
|
target: mapContainerRef.current,
|
|
|
|
|
|
controls: [],
|
|
|
|
|
|
view: new View({
|
|
|
|
|
|
center: proj.fromLonLat([114.764317000, 31.496800000]), // 设置地图中心点坐标
|
|
|
|
|
|
zoom: 18.4, // 设置初始缩放级别
|
|
|
|
|
|
minZoom: 5.5,
|
|
|
|
|
|
maxZoom: 30,
|
|
|
|
|
|
}),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加天地图卫星影像图层
|
|
|
|
|
|
const satelliteLayer = new TileLayer({
|
|
|
|
|
|
source: new XYZSource({
|
|
|
|
|
|
url: "https://t{0-7}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=efc861f25f96dc6e5f884f0403ebfefd",
|
|
|
|
|
|
}),
|
|
|
|
|
|
maxZoom: 30,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 设置图层名称
|
|
|
|
|
|
satelliteLayer.set('name', 'SatelliteImage');
|
|
|
|
|
|
|
|
|
|
|
|
// 添加图层到地图
|
|
|
|
|
|
mapInstance.addLayer(satelliteLayer);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建高亮图层
|
|
|
|
|
|
const highlightVectorLayer = new VectorLayer({
|
|
|
|
|
|
source: new VectorSource(),
|
|
|
|
|
|
zIndex: 999, // 确保高亮图层在最上面
|
|
|
|
|
|
style: null
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 添加高亮图层到地图
|
|
|
|
|
|
mapInstance.addLayer(highlightVectorLayer);
|
|
|
|
|
|
setHighlightLayer(highlightVectorLayer);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建弹出层
|
|
|
|
|
|
const overlay = new Overlay({
|
|
|
|
|
|
element: popupRef.current,
|
|
|
|
|
|
positioning: 'bottom-center',
|
|
|
|
|
|
stopEvent: false,
|
|
|
|
|
|
offset: [0, -10]
|
|
|
|
|
|
});
|
|
|
|
|
|
mapInstance.addOverlay(overlay);
|
|
|
|
|
|
setPopupOverlay(overlay);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加地图点击事件
|
|
|
|
|
|
mapInstance.on('click', (event) => {
|
|
|
|
|
|
const feature = mapInstance.forEachFeatureAtPixel(event.pixel, function (feature) {
|
|
|
|
|
|
return feature;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (feature) {
|
|
|
|
|
|
setModalVisible(true)
|
|
|
|
|
|
setDetailPoint(feature?.values_?.properties)
|
|
|
|
|
|
highlightFeature(feature);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 保存地图实例
|
|
|
|
|
|
setMap(mapInstance);
|
|
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理地图
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
if (mapInstance) {
|
|
|
|
|
|
mapInstance.setTarget(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
// 当地图实例创建完成后获取测点数据
|
|
|
|
|
|
useEffect(() => {
|
2025-09-30 15:49:30 +08:00
|
|
|
|
if (map && searchVal) {
|
|
|
|
|
|
getCdList(searchVal);
|
2025-09-28 17:45:29 +08:00
|
|
|
|
}
|
2025-09-30 15:49:30 +08:00
|
|
|
|
}, [map,searchVal]);
|
2024-09-20 15:02:50 +08:00
|
|
|
|
return (
|
|
|
|
|
|
<>
|
2025-09-28 17:45:29 +08:00
|
|
|
|
<div className='content-root clearFloat xybm' style={{ paddingRight: "0", paddingBottom: "0" }}>
|
|
|
|
|
|
<div className='lf CrudAdcdTreeTableBox' style={{ width: "100%", display: 'flex' }}>
|
|
|
|
|
|
<div className='by-left' style={{ width: "60%", height: "calc(100vh - 180px)" }} ref={mapContainerRef}></div>
|
|
|
|
|
|
<div className='by-right' style={{ width: "40%", marginLeft: 10 }}>
|
|
|
|
|
|
<Row gutter={16} className='statsRow'>
|
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
|
<div className='statItem'>
|
|
|
|
|
|
<div className='valueWrapper'>
|
|
|
|
|
|
<span className='number' style={{ color: '#722ed1' }}>{count.totalPoint}</span>
|
|
|
|
|
|
<span className="unit">个</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span className='label'>总监测点数</span>
|
2025-03-21 17:36:23 +08:00
|
|
|
|
</div>
|
2025-09-28 17:45:29 +08:00
|
|
|
|
</Col>
|
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
|
<div className='statItem'>
|
|
|
|
|
|
<div className='valueWrapper'>
|
|
|
|
|
|
<span className='number' style={{ color: '#f5222d' }}>{count.hasAnt}</span>
|
|
|
|
|
|
<span className="unit">个</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span className='label'>有白蚁</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
|
<div className='statItem'>
|
|
|
|
|
|
<div className='valueWrapper'>
|
|
|
|
|
|
<span className='number' style={{ color: '#52c41a' }}>{count.notAnt}</span>
|
|
|
|
|
|
<span className="unit">个</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span className='label'>无白蚁</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
<Col span={6}>
|
|
|
|
|
|
<div className='statItem'>
|
|
|
|
|
|
<div className='valueWrapper'>
|
|
|
|
|
|
<span className='number' style={{ color: '#8c8c8c' }}>{count.noData}</span>
|
|
|
|
|
|
<span className="unit">个</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span className='label'>离线</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Col>
|
|
|
|
|
|
</Row>
|
|
|
|
|
|
<Card className='nonebox'>
|
|
|
|
|
|
<ToolBar
|
|
|
|
|
|
setSearchVal={setSearchVal}
|
|
|
|
|
|
initData={initData}
|
2025-03-21 17:36:23 +08:00
|
|
|
|
// onSave={command('save')}
|
|
|
|
|
|
// role={role}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
<div className="ant-card-body" style={{ padding: "20px 0 0 0", marginRight: 20 }}>
|
|
|
|
|
|
<Table
|
|
|
|
|
|
columns={columns}
|
|
|
|
|
|
rowKey="inx"
|
|
|
|
|
|
{...tableProps}
|
|
|
|
|
|
scroll={{ x: width, y: "calc( 100vh - 400px )" }}
|
|
|
|
|
|
onRow={(record) => ({
|
2025-09-29 17:57:17 +08:00
|
|
|
|
onClick: (event) => handleRowClick(record,event), // 添加行点击事件
|
2025-09-28 17:45:29 +08:00
|
|
|
|
style: { cursor: 'pointer' } // 添加鼠标指针样式
|
|
|
|
|
|
})}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2024-09-20 15:02:50 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-28 17:45:29 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
{/* 添加测点详情Modal */}
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
title={detailPoint?.order}
|
|
|
|
|
|
open={modalVisible}
|
|
|
|
|
|
onCancel={() => setModalVisible(false)}
|
2025-09-29 17:57:17 +08:00
|
|
|
|
width={1000}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
footer={null}
|
|
|
|
|
|
destroyOnClose
|
|
|
|
|
|
>
|
|
|
|
|
|
<PointHistory data={detailPoint} />
|
|
|
|
|
|
</Modal>
|
2025-09-29 17:57:17 +08:00
|
|
|
|
{/*处理弹框 */}
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
title={mode == 'save' ? "处理" : '工单详情'}
|
|
|
|
|
|
open={precessVisible}
|
|
|
|
|
|
onCancel={() => setPrecessVisible(false)}
|
|
|
|
|
|
width={1000}
|
|
|
|
|
|
footer={null}
|
|
|
|
|
|
destroyOnClose
|
|
|
|
|
|
>
|
|
|
|
|
|
<PrecessForm record={detailPoint} mode={mode} refresh={refresh} setPrecessVisible={setPrecessVisible} />
|
|
|
|
|
|
</Modal>
|
2024-09-20 15:02:50 +08:00
|
|
|
|
<BasicCrudModal
|
|
|
|
|
|
width={1000}
|
|
|
|
|
|
ref={refModal}
|
|
|
|
|
|
title=""
|
|
|
|
|
|
component={ModalForm}
|
|
|
|
|
|
onCrudSuccess={successCallback}
|
2025-09-28 17:45:29 +08:00
|
|
|
|
// onCrudSuccess={()=>{refresh({addvcd:localStorage.getItem('ADCD6')})}}
|
2024-09-20 15:02:50 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Page;
|