|
|
@ -1,7 +1,7 @@ |
|
|
|
import React, { useState, useEffect, useMemo } from 'react'; |
|
|
|
import { connect } from 'react-redux'; |
|
|
|
import { |
|
|
|
Spin, Row, Col, Select, Radio, Empty, |
|
|
|
Spin, Row, Col, Select, Radio, Empty, |
|
|
|
} from 'antd'; |
|
|
|
// import { LayoutContent, ExportData } from '@peace/components';
|
|
|
|
import ProTable from '@ant-design/pro-table'; |
|
|
@ -11,20 +11,31 @@ import { ApartmentOutlined, TableOutlined } from '@ant-design/icons'; |
|
|
|
import { PinyinHelper, Func as PeaceFunc } from '@peace/utils'; |
|
|
|
import DeviceTree from '../components/device-tree'; |
|
|
|
import { DeviceTypes } from '../constant'; |
|
|
|
import qs from "qs"; |
|
|
|
|
|
|
|
import '../style.less'; |
|
|
|
|
|
|
|
function DeviceMonitor({ ...props }) { |
|
|
|
const { |
|
|
|
dispatch, actions, user, clientWidth, clientHeight, loading, |
|
|
|
myStructList, deviceMetasWithFollow, devices, dimensions, deviceListAlarms, factorStations, |
|
|
|
} = props; |
|
|
|
function DeviceMonitor ({ ...props }) { |
|
|
|
const { |
|
|
|
dispatch, actions, user, clientWidth, clientHeight, loading, |
|
|
|
myStructList, deviceMetasWithFollow, devices, dimensions, deviceListAlarms, factorStations, |
|
|
|
} = props; |
|
|
|
|
|
|
|
|
|
|
|
const [params, setParams] = useState({}); |
|
|
|
const [selectStructure, setSelectStructure] = useState(null); |
|
|
|
const [extraType, setExtraType] = useState('tree'); |
|
|
|
const [params, setParams] = useState({}); |
|
|
|
const [selectStructure, setSelectStructure] = useState(null); |
|
|
|
const [extraType, setExtraType] = useState('tree'); |
|
|
|
// const pageStyle = Func.getPaginationStyle();
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
let strucParam = JSON.parse((qs.parse(props.location?.search.slice(1)) || {})?.strucData) |
|
|
|
console.log(1111, strucParam) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
|
|
|
|
// dispatch(actions.dataMonitor.getDeviceMeta());
|
|
|
|
// dispatch(actions.dataMonitor.getMyStructList(user?.orgId)).then((res) => {
|
|
|
|
// if (res.success) {
|
|
|
@ -34,238 +45,238 @@ function DeviceMonitor({ ...props }) { |
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (selectStructure && myStructList?.length > 0) { |
|
|
|
const curStructure = myStructList.find((v) => v.id === selectStructure); |
|
|
|
if (curStructure) { |
|
|
|
// dispatch(actions.dataMonitor.getStationList(curStructure?.id));
|
|
|
|
// dispatch(actions.dataMonitor.getDeviceList(curStructure?.iotaThingId)).then((res) => {
|
|
|
|
// if (res.success) {
|
|
|
|
// const instances = res?.payload?.data?.instances;
|
|
|
|
// if (instances) {
|
|
|
|
// const deviceIds = Object.keys(instances).filter((k) => instances[k]?.type == 's.d');
|
|
|
|
// dispatch(actions.dataMonitor.getDevicesAlarms(deviceIds, { limit: 5 }));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
// dispatch(actions.dataMonitor.getDimensionsList(curStructure?.iotaThingId));
|
|
|
|
} |
|
|
|
} |
|
|
|
}, [selectStructure]); |
|
|
|
useEffect(() => { |
|
|
|
if (selectStructure && myStructList?.length > 0) { |
|
|
|
const curStructure = myStructList.find((v) => v.id === selectStructure); |
|
|
|
if (curStructure) { |
|
|
|
// dispatch(actions.dataMonitor.getStationList(curStructure?.id));
|
|
|
|
// dispatch(actions.dataMonitor.getDeviceList(curStructure?.iotaThingId)).then((res) => {
|
|
|
|
// if (res.success) {
|
|
|
|
// const instances = res?.payload?.data?.instances;
|
|
|
|
// if (instances) {
|
|
|
|
// const deviceIds = Object.keys(instances).filter((k) => instances[k]?.type == 's.d');
|
|
|
|
// dispatch(actions.dataMonitor.getDevicesAlarms(deviceIds, { limit: 5 }));
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
// dispatch(actions.dataMonitor.getDimensionsList(curStructure?.iotaThingId));
|
|
|
|
} |
|
|
|
} |
|
|
|
}, [selectStructure]); |
|
|
|
|
|
|
|
// 结构物切换
|
|
|
|
const sturctureChange = (value) => { |
|
|
|
setSelectStructure(value); |
|
|
|
}; |
|
|
|
// 展示切换
|
|
|
|
const onExtraChange = (e) => { |
|
|
|
setExtraType(e.target.value); |
|
|
|
}; |
|
|
|
// 结构物切换
|
|
|
|
const sturctureChange = (value) => { |
|
|
|
setSelectStructure(value); |
|
|
|
}; |
|
|
|
// 展示切换
|
|
|
|
const onExtraChange = (e) => { |
|
|
|
setExtraType(e.target.value); |
|
|
|
}; |
|
|
|
|
|
|
|
const renderExtra = () => ( |
|
|
|
<Radio.Group onChange={onExtraChange} value={extraType}> |
|
|
|
<Radio.Button value="tree"> |
|
|
|
<ApartmentOutlined /> |
|
|
|
{' '} |
|
|
|
树状展示 |
|
|
|
</Radio.Button> |
|
|
|
<Radio.Button value="table"> |
|
|
|
<TableOutlined /> |
|
|
|
{' '} |
|
|
|
表格展示 |
|
|
|
</Radio.Button> |
|
|
|
</Radio.Group> |
|
|
|
); |
|
|
|
const renderExtra = () => ( |
|
|
|
<Radio.Group onChange={onExtraChange} value={extraType}> |
|
|
|
<Radio.Button value="tree"> |
|
|
|
<ApartmentOutlined /> |
|
|
|
{' '} |
|
|
|
树状展示 |
|
|
|
</Radio.Button> |
|
|
|
<Radio.Button value="table"> |
|
|
|
<TableOutlined /> |
|
|
|
{' '} |
|
|
|
表格展示 |
|
|
|
</Radio.Button> |
|
|
|
</Radio.Group> |
|
|
|
); |
|
|
|
|
|
|
|
// 计算设备列表数据缓存
|
|
|
|
const dataSource = useMemo(() => { |
|
|
|
const result = []; |
|
|
|
if (devices?.instances) { |
|
|
|
const { instances } = devices; |
|
|
|
const stations = factorStations.reduce((p, c) => p.concat(c.groups), []).reduce((pre, cur) => pre.concat(cur.stations), []); |
|
|
|
Object.keys(instances).forEach((k) => { |
|
|
|
if (instances[k].type == 's.d') { |
|
|
|
const dType = instances[k]?.instance?.properties?.deviceType; |
|
|
|
result.push({ |
|
|
|
id: k, |
|
|
|
name: instances[k].name || '', |
|
|
|
deviceTypeId: dType, |
|
|
|
deviceType: dType ? DeviceTypes[dType] : '', |
|
|
|
productName: instances[k]?.instance?.properties?.productName || '', |
|
|
|
productType: instances[k]?.instance?.properties?.productType || '', |
|
|
|
location: stations.filter((f) => Object.keys(f.iotaDevices).includes(k)).map((v) => v.name).toString(), |
|
|
|
status: deviceListAlarms.find((v) => v.deviceId === k) ? 'alarm' : 'normal', |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
// 计算设备列表数据缓存
|
|
|
|
const dataSource = useMemo(() => { |
|
|
|
const result = []; |
|
|
|
if (devices?.instances) { |
|
|
|
const { instances } = devices; |
|
|
|
const stations = factorStations.reduce((p, c) => p.concat(c.groups), []).reduce((pre, cur) => pre.concat(cur.stations), []); |
|
|
|
Object.keys(instances).forEach((k) => { |
|
|
|
if (instances[k].type == 's.d') { |
|
|
|
const dType = instances[k]?.instance?.properties?.deviceType; |
|
|
|
result.push({ |
|
|
|
id: k, |
|
|
|
name: instances[k].name || '', |
|
|
|
deviceTypeId: dType, |
|
|
|
deviceType: dType ? DeviceTypes[dType] : '', |
|
|
|
productName: instances[k]?.instance?.properties?.productName || '', |
|
|
|
productType: instances[k]?.instance?.properties?.productType || '', |
|
|
|
location: stations.filter((f) => Object.keys(f.iotaDevices).includes(k)).map((v) => v.name).toString(), |
|
|
|
status: deviceListAlarms.find((v) => v.deviceId === k) ? 'alarm' : 'normal', |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
}, [devices, deviceListAlarms]); |
|
|
|
return result; |
|
|
|
}, [devices, deviceListAlarms]); |
|
|
|
|
|
|
|
// 筛选过滤数据
|
|
|
|
const filterDataSource = () => { |
|
|
|
const { |
|
|
|
name, deviceType, productType, productName, location, status, |
|
|
|
} = params; |
|
|
|
return dataSource.filter((s) => (name ? s.name ? (s.name.indexOf(name) != -1 || PinyinHelper.isPinyinMatched(s.name, name)) : false : true) |
|
|
|
&& (location ? s.location ? (s.location.indexOf(location) != -1 || PinyinHelper.isPinyinMatched(s.location, location)) : false : true) |
|
|
|
&& (deviceType ? s.deviceTypeId == deviceType : true) |
|
|
|
&& (productType ? s.productType == productType : true) |
|
|
|
&& (status ? s.status == status : true) |
|
|
|
&& (productName ? s.productName ? (s.productName.indexOf(productName) != -1 || PinyinHelper.isPinyinMatched(s.productName, productName)) : false : true)); |
|
|
|
}; |
|
|
|
// 筛选过滤数据
|
|
|
|
const filterDataSource = () => { |
|
|
|
const { |
|
|
|
name, deviceType, productType, productName, location, status, |
|
|
|
} = params; |
|
|
|
return dataSource.filter((s) => (name ? s.name ? (s.name.indexOf(name) != -1 || PinyinHelper.isPinyinMatched(s.name, name)) : false : true) |
|
|
|
&& (location ? s.location ? (s.location.indexOf(location) != -1 || PinyinHelper.isPinyinMatched(s.location, location)) : false : true) |
|
|
|
&& (deviceType ? s.deviceTypeId == deviceType : true) |
|
|
|
&& (productType ? s.productType == productType : true) |
|
|
|
&& (status ? s.status == status : true) |
|
|
|
&& (productName ? s.productName ? (s.productName.indexOf(productName) != -1 || PinyinHelper.isPinyinMatched(s.productName, productName)) : false : true)); |
|
|
|
}; |
|
|
|
|
|
|
|
// const deviceTypeIds = Func.uniqueArr(dataSource, 'deviceTypeId');
|
|
|
|
// const productTypeIds = Func.uniqueArr(dataSource, 'productType');
|
|
|
|
|
|
|
|
const columns = [{ |
|
|
|
title: '名称', |
|
|
|
dataIndex: 'name', |
|
|
|
ellipsis: true, |
|
|
|
const columns = [{ |
|
|
|
title: '名称', |
|
|
|
dataIndex: 'name', |
|
|
|
ellipsis: true, |
|
|
|
|
|
|
|
}, { |
|
|
|
title: '设备类型', |
|
|
|
dataIndex: 'deviceType', |
|
|
|
}, { |
|
|
|
title: '设备类型', |
|
|
|
dataIndex: 'deviceType', |
|
|
|
// valueEnum: Func.transValueEnum(deviceTypeIds, 'deviceTypeId', 'deviceType'),
|
|
|
|
// fieldProps: Func.getSelectCommonProps(),
|
|
|
|
|
|
|
|
}, { |
|
|
|
title: '产品名称', |
|
|
|
dataIndex: 'productName', |
|
|
|
ellipsis: true, |
|
|
|
}, { |
|
|
|
title: '产品名称', |
|
|
|
dataIndex: 'productName', |
|
|
|
ellipsis: true, |
|
|
|
|
|
|
|
}, { |
|
|
|
title: '产品型号', |
|
|
|
dataIndex: 'productType', |
|
|
|
}, { |
|
|
|
title: '产品型号', |
|
|
|
dataIndex: 'productType', |
|
|
|
// valueEnum: Func.transValueEnum(productTypeIds, 'productType', 'productType'),
|
|
|
|
// fieldProps: Func.getSelectCommonProps(),
|
|
|
|
}, { |
|
|
|
title: '测点', |
|
|
|
dataIndex: 'location', |
|
|
|
}, { |
|
|
|
title: '测点', |
|
|
|
dataIndex: 'location', |
|
|
|
|
|
|
|
}, { |
|
|
|
title: '状态', |
|
|
|
dataIndex: 'status', |
|
|
|
filters: true, |
|
|
|
onFilter: true, |
|
|
|
valueEnum: { |
|
|
|
normal: { text: '正常', status: 'Success' }, |
|
|
|
alarm: { text: '异常', status: 'Error' }, |
|
|
|
}, |
|
|
|
}, { |
|
|
|
title: '状态', |
|
|
|
dataIndex: 'status', |
|
|
|
filters: true, |
|
|
|
onFilter: true, |
|
|
|
valueEnum: { |
|
|
|
normal: { text: '正常', status: 'Success' }, |
|
|
|
alarm: { text: '异常', status: 'Error' }, |
|
|
|
}, |
|
|
|
// fieldProps: Func.getSelectCommonProps(),
|
|
|
|
}]; |
|
|
|
}]; |
|
|
|
|
|
|
|
const renderTitle = () => ( |
|
|
|
<div className="device-monitor"> |
|
|
|
设备总数: |
|
|
|
{' '} |
|
|
|
{dataSource.length} |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
异常设备: |
|
|
|
<span className="title-alarm">{dataSource.filter((f) => f.status === 'alarm').length}</span> |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
正常设备: |
|
|
|
<span className="title-normal">{dataSource.filter((f) => f.status === 'normal').length}</span> |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
</div> |
|
|
|
); |
|
|
|
const data = filterDataSource(); |
|
|
|
return ( |
|
|
|
const renderTitle = () => ( |
|
|
|
<div className="device-monitor"> |
|
|
|
设备总数: |
|
|
|
{' '} |
|
|
|
{dataSource.length} |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
异常设备: |
|
|
|
<span className="title-alarm">{dataSource.filter((f) => f.status === 'alarm').length}</span> |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
正常设备: |
|
|
|
<span className="title-normal">{dataSource.filter((f) => f.status === 'normal').length}</span> |
|
|
|
{' '} |
|
|
|
个; |
|
|
|
</div> |
|
|
|
); |
|
|
|
const data = filterDataSource(); |
|
|
|
return ( |
|
|
|
// <div>div</div>
|
|
|
|
// <LayoutContent>
|
|
|
|
<Spin spinning={false}> |
|
|
|
<Select |
|
|
|
allowClear |
|
|
|
placeholder="选择结构物" |
|
|
|
style={{ minWidth: 300, marginBottom: 15 }} |
|
|
|
getPopupContainer={(triggerNode) => triggerNode.parentNode} |
|
|
|
value={selectStructure} |
|
|
|
onChange={sturctureChange} |
|
|
|
optionFilterProp="children" |
|
|
|
showSearch |
|
|
|
filterOption={PeaceFunc.selectFilterOption} |
|
|
|
> |
|
|
|
{myStructList.map((v) => <Select.Option key={v.id} value={v.id}>{v.name}</Select.Option>)} |
|
|
|
</Select> |
|
|
|
<ProCard title={renderTitle()} extra={renderExtra()} headerBordered> |
|
|
|
{ |
|
|
|
extraType === 'tree' |
|
|
|
? (myStructList.find((v) => v.id === selectStructure) |
|
|
|
&& deviceMetasWithFollow?.devices?.length > 0 |
|
|
|
&& devices.instances) |
|
|
|
? ( |
|
|
|
<DeviceTree |
|
|
|
deviceMetasWithFollow={deviceMetasWithFollow} |
|
|
|
deviceList={devices} |
|
|
|
dimensionlist={dimensions} |
|
|
|
dispatch={dispatch} |
|
|
|
struct={myStructList.find((v) => v.id === selectStructure)} |
|
|
|
clientHeight={clientHeight} |
|
|
|
clientWidth={clientWidth} |
|
|
|
/> |
|
|
|
) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> |
|
|
|
: ( |
|
|
|
<ProTable |
|
|
|
tableClassName="device-monitor-pro-table" |
|
|
|
className="device-monitor-pro-table" |
|
|
|
columns={columns} |
|
|
|
rowKey="id" |
|
|
|
request={async (params) => { |
|
|
|
setParams(params); |
|
|
|
return { |
|
|
|
data: [], |
|
|
|
success: true, |
|
|
|
}; |
|
|
|
}} |
|
|
|
pagination={{ }} |
|
|
|
options={{ |
|
|
|
search: false, |
|
|
|
reload: false, |
|
|
|
}} |
|
|
|
search={{ |
|
|
|
className: 'device-monitor-search', |
|
|
|
}} |
|
|
|
toolBarRender={() => { |
|
|
|
const node = []; |
|
|
|
node.push(<ExportData showIcon fileName="设备列表" exportType="fileSaver" data={data} columns={columns} key="export" />); |
|
|
|
return node; |
|
|
|
}} |
|
|
|
// scroll={{ y: Func.getContentHeight(clientHeight) - 421 }}
|
|
|
|
dateFormatter="string" |
|
|
|
headerTitle="设备列表" |
|
|
|
dataSource={data} |
|
|
|
/> |
|
|
|
) |
|
|
|
} |
|
|
|
</ProCard> |
|
|
|
</Spin> |
|
|
|
<Spin spinning={false}> |
|
|
|
<Select |
|
|
|
allowClear |
|
|
|
placeholder="选择结构物" |
|
|
|
style={{ minWidth: 300, marginBottom: 15 }} |
|
|
|
getPopupContainer={(triggerNode) => triggerNode.parentNode} |
|
|
|
value={selectStructure} |
|
|
|
onChange={sturctureChange} |
|
|
|
optionFilterProp="children" |
|
|
|
showSearch |
|
|
|
filterOption={PeaceFunc.selectFilterOption} |
|
|
|
> |
|
|
|
{myStructList.map((v) => <Select.Option key={v.id} value={v.id}>{v.name}</Select.Option>)} |
|
|
|
</Select> |
|
|
|
<ProCard title={renderTitle()} extra={renderExtra()} headerBordered> |
|
|
|
{ |
|
|
|
extraType === 'tree' |
|
|
|
? (myStructList.find((v) => v.id === selectStructure) |
|
|
|
&& deviceMetasWithFollow?.devices?.length > 0 |
|
|
|
&& devices.instances) |
|
|
|
? ( |
|
|
|
<DeviceTree |
|
|
|
deviceMetasWithFollow={deviceMetasWithFollow} |
|
|
|
deviceList={devices} |
|
|
|
dimensionlist={dimensions} |
|
|
|
dispatch={dispatch} |
|
|
|
struct={myStructList.find((v) => v.id === selectStructure)} |
|
|
|
clientHeight={clientHeight} |
|
|
|
clientWidth={clientWidth} |
|
|
|
/> |
|
|
|
) : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> |
|
|
|
: ( |
|
|
|
<ProTable |
|
|
|
tableClassName="device-monitor-pro-table" |
|
|
|
className="device-monitor-pro-table" |
|
|
|
columns={columns} |
|
|
|
rowKey="id" |
|
|
|
request={async (params) => { |
|
|
|
setParams(params); |
|
|
|
return { |
|
|
|
data: [], |
|
|
|
success: true, |
|
|
|
}; |
|
|
|
}} |
|
|
|
pagination={{}} |
|
|
|
options={{ |
|
|
|
search: false, |
|
|
|
reload: false, |
|
|
|
}} |
|
|
|
search={{ |
|
|
|
className: 'device-monitor-search', |
|
|
|
}} |
|
|
|
toolBarRender={() => { |
|
|
|
const node = []; |
|
|
|
node.push(<ExportData showIcon fileName="设备列表" exportType="fileSaver" data={data} columns={columns} key="export" />); |
|
|
|
return node; |
|
|
|
}} |
|
|
|
// scroll={{ y: Func.getContentHeight(clientHeight) - 421 }}
|
|
|
|
dateFormatter="string" |
|
|
|
headerTitle="设备列表" |
|
|
|
dataSource={data} |
|
|
|
/> |
|
|
|
) |
|
|
|
} |
|
|
|
</ProCard> |
|
|
|
</Spin> |
|
|
|
// </LayoutContent>
|
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
function mapStateToProps(state) { |
|
|
|
const { |
|
|
|
auth, global, myStructList, deviceMeta, deviceList, dimensionsList, deviceListAlarms, factorStations, |
|
|
|
} = state; |
|
|
|
return { |
|
|
|
loading: myStructList?.isRequesting || deviceMeta?.isRequesting || deviceList?.isRequesting || dimensionsList?.isRequesting, |
|
|
|
user: auth?.user, |
|
|
|
actions: global?.actions, |
|
|
|
clientWidth: global?.clientWidth, |
|
|
|
clientHeight: global?.clientHeight, |
|
|
|
myStructList: myStructList?.data || [], |
|
|
|
deviceMetasWithFollow: deviceMeta?.data || {}, |
|
|
|
devices: deviceList?.data || {}, |
|
|
|
dimensions: dimensionsList?.data || { dimensions: [], total: 0 }, |
|
|
|
deviceListAlarms: deviceListAlarms?.data || [], |
|
|
|
factorStations: factorStations?.data || [], |
|
|
|
}; |
|
|
|
function mapStateToProps (state) { |
|
|
|
const { |
|
|
|
auth, global, myStructList, deviceMeta, deviceList, dimensionsList, deviceListAlarms, factorStations, |
|
|
|
} = state; |
|
|
|
return { |
|
|
|
loading: myStructList?.isRequesting || deviceMeta?.isRequesting || deviceList?.isRequesting || dimensionsList?.isRequesting, |
|
|
|
user: auth?.user, |
|
|
|
actions: global?.actions, |
|
|
|
clientWidth: global?.clientWidth, |
|
|
|
clientHeight: global?.clientHeight, |
|
|
|
myStructList: myStructList?.data || [], |
|
|
|
deviceMetasWithFollow: deviceMeta?.data || {}, |
|
|
|
devices: deviceList?.data || {}, |
|
|
|
dimensions: dimensionsList?.data || { dimensions: [], total: 0 }, |
|
|
|
deviceListAlarms: deviceListAlarms?.data || [], |
|
|
|
factorStations: factorStations?.data || [], |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
export default connect(mapStateToProps)(DeviceMonitor); |
|
|
|