Commit 1ac84839 authored by 涂茜's avatar 涂茜

feat: add ec_realtimeinfo

parent 45f05857
Pipeline #27527 failed with stages
in 1 minute 38 seconds
......@@ -102,8 +102,8 @@ export default {
],
'/extend-components': [
{
title: '数据展示',
children: ['EC_DeviceTree', 'EC_QuotaSelect', 'EC_HistoryInfo'],
title: '业务数据展示',
children: ['EC_DeviceTree', 'EC_QuotaSelect', 'EC_HistoryInfo', 'EC_RealTimeInfo'],
},
],
},
......
......@@ -138,7 +138,7 @@
"registry": "https://g.civnet.cn:4873"
},
"dependencies": {
"@wisdom-components/basictable": "^1.4.5",
"@wisdom-components/basictable": "^1.5.5",
"@wisdom-components/empty": "^1.3.9",
"@wisdom-components/timerangepicker": "^1.3.4",
"@wisdom-utils/utils": "0.0.46",
......
......@@ -5,7 +5,7 @@
## Usage
```
const ECDeviceTree = require('@wisdom-components/ec_devicetree');
import ECDeviceTree from '@wisdom-components/ec_devicetree';
// TODO: DEMONSTRATE API
```
......@@ -5,7 +5,7 @@
## Usage
```
const ECHistoryInfo = require('@wisdom-components/ec_historyinfo');
import ECHistoryInfo from '@wisdom-components/ec_historyinfo';
// TODO: DEMONSTRATE API
```
---
title: EC-HistoryInfo - 历史数据查看
title: EC_HistoryInfo - 历史数据查看
nav:
title: 基础组件
path: /extend-components
......
......@@ -5,7 +5,7 @@
## Usage
```
const ECQuotaSelect = require('@wisdom-components/ec_quotaselect');
import ECQuotaSelect from '@wisdom-components/ec_quotaselect';
// TODO: DEMONSTRATE API
```
---
title: EC-QuotaSelect - 指标选择
title: EC_QuotaSelect - 指标选择
nav:
title: 业务组件
path: /extend-components
......
# `@wisdom-components/ec_realtimeinfo`
> TODO: description
## Usage
```
import ECRealTimeInfo from '@wisdom-components/ec_realtimeinfo';
// TODO: DEMONSTRATE API
```
{
"name": "@wisdom-components/ec_realtimeinfo",
"version": "1.0.0",
"description": "> TODO: description",
"author": "tuqian <webtuqian@163.com>",
"homepage": "",
"license": "ISC",
"main": "lib/index.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"publishConfig": {
"registry": "https://g.civnet.cn:4873/"
},
"repository": {
"type": "git",
"url": "https://g.civnet.cn:8443/ReactWeb5/wisdom-components.git"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
}
}
---
title: EC_RealTimeInfo - 实时数据查看
nav:
title: 业务组件
path: /extend-components
group:
path: /
---
# RealTimeInfo 实时数据查看
基础业务组件
- 查看指标名称对应的实时数据
- 允许对重点指标和全部指标筛选
- 允许搜索指标名称
## 何时使用
- 实时指标监控,查看实时指标数据时。
## 代码演示
<code src="./demos/Basic.tsx">
## API
api 参考 Antd Table 组件 https://ant.design/components/table-cn/#API
| 参数 | 说明 | 类型 | 默认值 |
| ------------------------------ | ---------------------------- | ------- | -------------- |
| buttonText | 按钮文本 | string | 查看更多 |
| modalTitle | 模态框标题 | string | 实时指标监控 |
| placeholder | 搜索框占位符 | string | 输入指标名称等 |
| defaultTargetValue | 默认选中‘重要指标’或者‘全部’ | string | emphasis |
| user | 当前登录用户的用户名 | string | 1 |
| deviceRealInfoParams`必需` | 设备实时信息的服务参数 | object | {} |
| deviceConfService`必需` | 获取设备配置服务 | promise | - |
| pointAddressEntryService`必需` | 获取点表信息服务 | promise | - |
| sensorTypeService`必需` | 获取传感器类型服务 | promise | - |
| deviceRealInfoService`必需` | 获取设备实时数据服务 | promise | - |
import React, { useEffect, useState } from 'react';
import { service } from '@wisdom-utils/utils';
import RealTimeInfo from '../index';
const REQUEST_HTTP = 'http';
const REQUEST_METHOD_GET = 'get';
const REQUEST_METHOD_POST = 'post';
const GET_DEVICE_CONF =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/Publish/Monitor/Device/GetDeviceConf'; //获取设备配置
const GET_POINT_ADDRESS_ENTRY =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/Publish/GCK/PointAddress/GetPointAddressEntry'; //获取点表信息
const GET_SENSOR_TYPE =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/Publish/GCK/Sensor/GetSensorType'; //获取传感器类型
const GET_DEVICE_REAL_INFO =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/Publish/GCK/Device/DeviceRealInfo'; //获取设备实时数据
// const GET_DEVICE_CONF = '/api/Publish/GCK/Device/GetDeviceConf'; //获取设备配置
// const GET_POINT_ADDRESS_ENTRY = '/api/Publish/GCK/PointAddress/GetPointAddressEntry'; //获取点表信息
// const GET_SENSOR_TYPE = '/api/Publish/GCK/Sensor/GetSensorType'; //获取传感器类型
// const GET_DEVICE_REAL_INFO = '/api/Publish/GCK/Device/DeviceRealInfo'; //获取设备实时数据
const realTimeInfoService = {
getDeviceConf: {
url: GET_DEVICE_CONF,
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getPointAddressEntry: {
url: GET_POINT_ADDRESS_ENTRY,
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getSensorType: {
url: GET_SENSOR_TYPE,
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getDeviceRealInfo: {
url: GET_DEVICE_REAL_INFO,
method: REQUEST_METHOD_POST,
type: REQUEST_HTTP,
},
};
const rtService = service(realTimeInfoService);
const getDeviceConf = rtService.getDeviceConf;
const getPointAddressEntry = rtService.getPointAddressEntry;
const getSensorType = rtService.getSensorType;
const getDeviceRealInfo = rtService.getDeviceRealInfo;
const Demo = () => {
return (
<div style={{ width: '200px', height: '60px', background: 'black' }}>
<RealTimeInfo
deviceConfService={getDeviceConf}
pointAddressEntryService={getPointAddressEntry}
sensorTypeService={getSensorType}
deviceRealInfoService={getDeviceRealInfo}
deviceRealInfoParams={{
userID: '1',
pageIndex: 1,
pageSize: 20,
isFocus: false,
accountFieldParams: [{ AName: '二供泵房' }, { AName: '二供机组' }],
equipmentCode: 'EGBF00000001',
}}
user={'1'}
/>
</div>
);
};
export default Demo;
import React, { useState, useEffect, useContext } from 'react';
import PropTypes from 'prop-types';
import Empty from '@wisdom-components/empty';
import classNames from 'classnames';
import { Modal, Button, Tabs, Input, Radio, ConfigProvider } from 'antd';
import BasicTable from '@wisdom-components/basictable';
import './index.less';
const { TabPane } = Tabs;
const RealTimeInfo = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('realtime-info');
const {
deviceConfService,
pointAddressEntryService,
sensorTypeService,
deviceRealInfoService,
deviceRealInfoParams,
user,
placeholder,
defaultTargetValue,
modalTitle,
buttonText,
} = props;
const [isModalVisible, setIsModalVisible] = useState(false);
const [targetValue, setTargetValue] = useState(defaultTargetValue); // 重点/全部
const [searchValue, setSearchValue] = useState(''); // 搜索框内容
const [columns, setColumns] = useState(defaultColumns); // 搜索框内容
const [tabData, setTabData] = useState([]);
const [tabKey, setTabKey] = useState('');
const [guid, setGuid] = useState('');
const [deviceConf, setDeviceConf] = useState({}); // 设备配置
const [deviceInfo, setDeviceInfo] = useState({}); // 设备实时数据
const [sensorType, setSensorType] = useState({}); // sensorType
const [pointAddress, setPointAddress] = useState([]); // pointAddress
const [tableData, setTableData] = useState([]); // 表格数据
const [searchData, setSearchData] = useState([]); // 表格搜索数据
const handleTabData = (data = {}) => {
let tData = [];
tData.push({
key: data.code,
title: data.name,
guid: data.guid,
versionID: data.versionID,
deviceType: data.aName,
});
if (data.child && data.child.length) {
data.child.forEach((child) => {
tData.push({
key: child.code,
title: data.name + child.name,
guid: child.guid,
versionID: child.versionID,
deviceType: child.aName,
});
});
}
setTabData(tData);
setTabKey(tData[0].key);
};
// 过滤重点指标
const filterEmphasis = (dataSource) => {
const cur = tabData.filter((item) => item.key === tabKey);
const conf =
cur.length > 0 ? deviceConf.filter((item) => item.deviceType === cur[0].deviceType) : [];
const dPoints = conf.length > 0 && conf[0].dPoints ? conf[0].dPoints.split(',') : [];
const data = dataSource.filter((item) => dPoints.includes(item.name));
setSearchData(data);
};
const handleFilterColumns = (data = []) => {
const keyArr = defaultColumns.map((item) => item.dataIndex);
const filter = [];
keyArr.forEach((key) => {
let length = 0;
data.forEach((item) => {
if (item[key] === '--' || item[key] === '') {
length++;
}
});
if (data.length === length) {
filter.push(key);
}
});
const column = defaultColumns.filter((item) => !filter.includes(item.dataIndex));
setColumns(column);
setTableData(data);
};
const handleData = (data1 = [], data2 = [], data3 = {}) => {
let time = data3.pt;
if (time) time = time.slice(5, 19).replace('-', '/');
let newData = data1.map((item, index) => {
return {
id: item.id,
key: item.id,
index: index + 1,
name: item.name,
value: 0,
unit: '--',
type: '--',
time: time,
desc: item.valDesc || '--',
...item,
};
});
newData.forEach((item) => {
let curData1 = data2.filter((child) => child.id == item.sensorTypeID);
let curData2 = data3.dataList.filter((child) => child.paid == item.id);
if (curData1.length) {
item.unit = curData1[0].unit || '--';
item.type = curData1[0].name || '--';
}
if (curData2.length) {
item.value = curData2[0].pv || '--';
}
});
handleFilterColumns(newData);
// setTableData(newData);
const data = searchValue
? newData.filter((item) => item.name.indexOf(searchValue) !== -1)
: newData;
if (targetValue === 'emphasis') {
filterEmphasis(data);
} else {
setSearchData(data);
}
};
const GetDeviceConf = () => {
const deviceType =
deviceRealInfoParams.accountFieldParams.length > 0
? deviceRealInfoParams.accountFieldParams.map((item) => item.AName).join(',')
: '二供泵房,二供机组';
deviceConfService({
user: user || '1',
showAll: true,
deviceType,
}).then((res) => {
if (res.code === 0 && res.data.length) {
setDeviceConf(res.data);
}
});
};
const GetDeviceRealInfo = () => {
const params = {
userID: deviceRealInfoParams.userID || '1',
pageIndex: deviceRealInfoParams.pageIndex || 1,
pageSize: deviceRealInfoParams.pageSize || 20,
isFocus: deviceRealInfoParams.isFocus || false,
accountFieldParams: deviceRealInfoParams.accountFieldParams || [
{ AName: '二供泵房' },
{ AName: '二供机组' },
],
equipmentCode: deviceRealInfoParams.equipmentCode || 'EGBF00000001',
...deviceRealInfoParams,
};
deviceRealInfoService(params).then((res) => {
if (res.code === 0 && res.data) {
setDeviceInfo(res.data.list[0]);
handleTabData(res.data.list[0]);
}
});
};
const GetSensorType = () => {
sensorTypeService({}).then((res) => {
if (res.code === 0 && res.data.length) {
setSensorType(res.data);
}
});
};
const GetPointAddressEntry = () => {
const cur = tabData.filter((item) => item.key === tabKey);
!!cur.length &&
pointAddressEntryService({ versionID: cur[0].versionID }).then((res) => {
if (res.code === 0 && res.data.length) {
setPointAddress(res.data);
}
});
};
useEffect(() => {
if (isModalVisible) {
GetDeviceConf();
GetDeviceRealInfo();
GetSensorType();
}
}, [isModalVisible]);
useEffect(() => {
GetPointAddressEntry();
}, [tabKey]);
useEffect(() => {
handleData(pointAddress, sensorType, deviceInfo);
}, [pointAddress]);
useEffect(() => {
if (targetValue === 'emphasis') {
// 重点指标
filterEmphasis(searchData);
} else {
// 全部
if (searchValue) {
const data = tableData.filter((item) => item.name.indexOf(searchValue) !== -1);
setSearchData(data);
} else {
setSearchData(tableData);
}
}
}, [targetValue]);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
const onSearch = (e) => {
// 前端搜索
if (e.target.value) {
if (targetValue === 'emphasis') {
// 重点指标
const cur = tabData.filter((item) => item.key === tabKey);
const conf =
cur.length > 0 ? deviceConf.filter((item) => item.deviceType === cur[0].deviceType) : [];
const dPoints = conf.length > 0 && conf[0].dPoints ? conf[0].dPoints.split(',') : [];
const data = tableData.filter((item) => dPoints.includes(item.name));
const newDate = data.filter((item) => item.name.indexOf(e.target.value) !== -1);
setSearchData(newDate);
} else {
// 全部
const data = tableData.filter((item) => item.name.indexOf(e.target.value) !== -1);
setSearchData(data);
}
} else {
if (targetValue === 'emphasis') {
// 重点指标
filterEmphasis(tableData);
} else {
// 全部
setSearchData(tableData);
}
}
setSearchValue(e.target.value);
};
const onTabChange = (key) => {
const g = tabData.filter((item) => item.key === key);
setGuid(g[0].guid);
setTabKey(key);
};
const onRadioChange = (e) => {
setTargetValue(e.target.value);
};
const renderTitle = () => {
return (
<div className={classNames(`${prefixCls}-modal-title`)}>
<Tabs
tabBarExtraContent={{ left: <h3 style={{ fontWeight: 'bold' }}>{modalTitle}</h3> }}
activeKey={tabKey}
onChange={onTabChange}
centered
>
{tabData.map((item) => (
<TabPane tab={item.title} key={item.key} />
))}
</Tabs>
</div>
);
};
return (
<div className={classNames(prefixCls)}>
<Button type="link" onClick={showModal}>
{buttonText}
</Button>
<Modal
className={classNames(`${prefixCls}-modal`)}
width={915}
title={renderTitle()}
footer={null}
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<div className={classNames(`${prefixCls}-modal-content`)}>
<div className={classNames(`${prefixCls}-search-wrap`)}>
<div className={classNames(`${prefixCls}-search`)}>
<div className={classNames(`${prefixCls}-label`)}>搜索:</div>
<Input placeholder={placeholder} onChange={onSearch} value={searchValue} />
</div>
<div className={classNames(`${prefixCls}-target`)}>
<div className={classNames(`${prefixCls}-label`)}>指标:</div>
<Radio.Group onChange={onRadioChange} defaultValue={targetValue}>
<Radio.Button value="emphasis">重点指标</Radio.Button>
<Radio.Button value="all">全部</Radio.Button>
</Radio.Group>
</div>
</div>
<div className={classNames(`${prefixCls}-code-wrap`)}>
<div>采集编码:{guid || '--'}</div>
<div>更新时间:{(tableData.length && tableData[0].time) || '--'}</div>
</div>
<div className={classNames(`${prefixCls}-modal-table`)}>
<BasicTable
bordered
columns={columns}
locale={{ emptyText: <Empty /> }}
pagination={false}
dataSource={searchData}
{...props}
/>
</div>
</div>
</Modal>
</div>
);
};
RealTimeInfo.defaultProps = {
buttonText: '查看更多',
modalTitle: '实时指标监控',
placeholder: '输入指标名称等',
defaultTargetValue: 'emphasis',
user: '',
deviceRealInfoParams: {},
deviceConfService: () => {},
pointAddressEntryService: () => {},
sensorTypeService: () => {},
deviceRealInfoService: () => {},
};
RealTimeInfo.propTypes = {
buttonText: PropTypes.string,
modalTitle: PropTypes.string,
placeholder: PropTypes.string,
defaultTargetValue: PropTypes.string,
user: PropTypes.string,
deviceRealInfoParams: PropTypes.object,
deviceConfService: PropTypes.func,
pointAddressEntryService: PropTypes.func,
sensorTypeService: PropTypes.func,
deviceRealInfoService: PropTypes.func,
};
export default RealTimeInfo;
const defaultColumns = [
{
title: '序号',
dataIndex: 'index',
width: 60,
},
{
title: '指标名称',
dataIndex: 'name',
width: 150,
},
{
title: '最新指标',
dataIndex: 'value',
render: (text) => <a>{text}</a>,
},
{
title: '单位',
dataIndex: 'unit',
},
{
title: '指标类型',
dataIndex: 'type',
},
{
title: '数据描述',
dataIndex: 'desc',
},
{
title: '更新时间',
dataIndex: 'time',
},
];
@import (reference) '../../../../node_modules/antd/es/style/themes/default';
@realtime-info-prefix-cls: ~'@{ant-prefix}-realtime-info';
.@{realtime-info-prefix-cls} {
padding: 10px;
.ant-btn-link {
color: #d0d6e8;
}
&-search-wrap {
display: flex;
margin-bottom: 20px;
}
&-search,
&-target {
display: flex;
align-items: center;
margin-right: 20px;
}
&-label {
white-space: nowrap;
}
&-code-wrap {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
}
.@{realtime-info-prefix-cls}-modal {
.ant-modal-header {
height: 63px;
padding: 16px 48px 0 24px;
}
&-title {
.ant-tabs-nav {
margin: 0;
}
.ant-tabs-nav:before {
border: none;
}
.ant-tabs-extra-content {
margin-right: 10px;
}
.ant-tabs-content-holder {
display: none;
}
}
.ant-modal-content {
height: 705px;
}
&-table {
height: 500px;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment