Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wisdom-components
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ReactWeb5
wisdom-components
Commits
e6ad7ff7
Commit
e6ad7ff7
authored
Dec 14, 2022
by
崔佳豪
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 新增历史曲线业务组件
parent
4be9d1c4
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1212 additions
and
0 deletions
+1212
-0
.gitignore
packages/extend-components/EC_HistoryView/.gitignore
+45
-0
README.md
packages/extend-components/EC_HistoryView/README.md
+11
-0
package.json
packages/extend-components/EC_HistoryView/package.json
+26
-0
EC_HistoryView.md
...es/extend-components/EC_HistoryView/src/EC_HistoryView.md
+51
-0
GridChart.js
packages/extend-components/EC_HistoryView/src/GridChart.js
+61
-0
SingleChart.js
packages/extend-components/EC_HistoryView/src/SingleChart.js
+21
-0
index.js
packages/extend-components/EC_HistoryView/src/apis/index.js
+16
-0
GridDemo.js
...es/extend-components/EC_HistoryView/src/demos/GridDemo.js
+18
-0
index.js
packages/extend-components/EC_HistoryView/src/demos/index.js
+18
-0
useQTime.js
...es/extend-components/EC_HistoryView/src/hooks/useQTime.js
+23
-0
index.js
packages/extend-components/EC_HistoryView/src/index.js
+632
-0
index.less
packages/extend-components/EC_HistoryView/src/index.less
+139
-0
utils.js
packages/extend-components/EC_HistoryView/src/utils.js
+151
-0
No files found.
packages/extend-components/EC_HistoryView/.gitignore
0 → 100644
View file @
e6ad7ff7
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
**/node_modules
# roadhog-api-doc ignore
/src/utils/request-temp.js
_roadhog-api-doc
# production
**/dist
/.vscode
**/**/lib/**
**/**/es/**
# misc
.DS_Store
npm-debug.log*
yarn-error.log
/coverage
.idea
package-lock.json
*bak
.vscode
# visual studio code
.history
*.log
functions/mock
.temp/**
# umi
.umi
.umi-production
# screenshot
screenshot
.firebase
.eslintcache
.changelog
# devServer-host
host/
webpack.host.js
\ No newline at end of file
packages/extend-components/EC_HistoryView/README.md
0 → 100644
View file @
e6ad7ff7
# `@wisdom-components/ec_historyview`
> TODO: description
## Usage
```
const ecHistoryview = require('@wisdom-components/ec_historyview');
// TODO: DEMONSTRATE API
```
packages/extend-components/EC_HistoryView/package.json
0 → 100644
View file @
e6ad7ff7
{
"name"
:
"@wisdom-components/ec_historyview"
,
"version"
:
"1.0.0"
,
"description"
:
"> TODO: description"
,
"author"
:
"cuijiahao <15927252954@163.com>"
,
"homepage"
:
""
,
"license"
:
"ISC"
,
"main"
:
"src/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"
}
}
packages/extend-components/EC_HistoryView/src/EC_HistoryView.md
0 → 100644
View file @
e6ad7ff7
---
title
:
EC_HistoryView - 历史曲线
nav
:
title
:
业务组件
path
:
/extend-components
group
:
path
:
/
---
# HistoryView 历史数据查看
基础业务组件
-
曲线模式
-
数据强制自动抽稀
-
表格模式
-
默认开启抽稀模式,可选择抽稀
## 何时使用
-
以图表或表格形式,查看历史数据时。
## 单图表
<code
src=
"./demos/index.js"
>
## 多图表
<code
src=
"./demos/GridDemo.js"
>
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| --- | --- | --- | --- | --- |
| grid | 是否为分组模式 | boolean | false | - |
| title | 标题 | string | 指标曲线 | - |
| defaultChecked | 默认选中自定义时间 key | string |
`oneHour`
|
`oneHour`
/
`fourHour`
/
`twelveHours`
/
`roundClock`
/
`yesterday`
|
| tableProps | 表格其他 props | object | { } | - |
| deviceParams | 设备参数信息 | array | - | - |
### deviceParams
```
javascript
[
{
deviceCode
:
'EGBF00000146'
,
// 设备编码
sensors
:
'进水压力,出水瞬时流量'
,
// 设备查询指标
deviceCode
:
'二供泵房'
,
// 设备类型
},
...
]
```
\ No newline at end of file
packages/extend-components/EC_HistoryView/src/GridChart.js
0 → 100644
View file @
e6ad7ff7
import
React
,
{
memo
,
useMemo
}
from
'react'
;
import
_
from
'lodash'
;
import
{
BasicChart
}
from
'@wisdom-components/basicchart'
;
import
optionGenerator
from
'./utils'
;
const
GridChart
=
memo
((
props
)
=>
{
const
{
dataSource
,
contrast
=
false
,
contrastOption
=
'day'
,
smooth
=
true
}
=
props
;
const
{
prefixCls
}
=
props
;
const
gridData
=
useMemo
(()
=>
{
const
grids
=
dataSource
.
reduce
((
pre
,
item
,
index
)
=>
{
const
{
sensorName
}
=
item
;
let
grid
=
pre
.
find
((
g
)
=>
g
.
key
===
sensorName
);
if
(
!
grid
)
{
const
restProp
=
_
.
pick
(
item
,
[
'equipmentName'
,
'sensorName'
,
'stationCode'
,
'unit'
]);
grid
=
{
key
:
sensorName
,
list
:
[],
...
restProp
,
};
pre
.
push
(
grid
);
}
grid
.
list
.
push
(
item
);
return
pre
;
},
[]);
return
grids
;
},
[
dataSource
]);
const
options
=
useMemo
(()
=>
{
return
gridData
.
map
((
item
)
=>
{
const
{
key
,
list
,
equipmentName
,
sensorName
,
stationCode
,
unit
}
=
item
;
const
cusOption
=
{
title
:
{
show
:
true
,
text
:
`{prefix|}{t|
${
sensorName
}
}
${
unit
?
'{suffix|(单位:'
+
unit
+
')}'
:
''
}
`
,
},
};
const
option
=
optionGenerator
(
list
,
cusOption
,
contrast
,
contrastOption
,
smooth
);
return
{
key
,
option
:
option
,
};
});
},
[
gridData
,
smooth
]);
return
(
<
div
className
=
{
`
${
prefixCls
}
-grid`
}
>
{
options
.
map
(
item
=>
(
<
div
key
=
{
item
.
key
}
className
=
{
`
${
prefixCls
}
-grid-item`
}
>
<
div
className
=
{
`
${
prefixCls
}
-grid-item-wrap`
}
>
<
BasicChart
style
=
{{
width
:
'100%'
,
height
:
'100%'
}}
option
=
{
item
.
option
}
notMerge
/>
<
/div
>
<
/div
>
))
}
<
/div
>
);
});
export
default
GridChart
;
packages/extend-components/EC_HistoryView/src/SingleChart.js
0 → 100644
View file @
e6ad7ff7
import
React
,
{
memo
,
useMemo
}
from
'react'
;
import
{
BasicChart
}
from
'@wisdom-components/basicchart'
;
import
optionGenerator
from
'./utils'
;
const
SimgleChart
=
memo
((
props
)
=>
{
const
{
dataSource
,
contrast
=
false
,
contrastOption
=
'day'
,
smooth
=
true
}
=
props
;
const
option
=
useMemo
(()
=>
{
const
config
=
{
needUnit
:
true
,
};
return
optionGenerator
(
dataSource
,
null
,
contrast
,
contrastOption
,
smooth
,
config
);
},
[
dataSource
,
smooth
]);
return
<
BasicChart
option
=
{
option
}
notMerge
style
=
{{
width
:
'100%'
,
height
:
'100%'
}}
/
>
});
export
default
SimgleChart
;
\ No newline at end of file
packages/extend-components/EC_HistoryView/src/apis/index.js
0 → 100644
View file @
e6ad7ff7
import
{
request
}
from
'@wisdom-utils/utils'
;
const
REQUEST_METHOD_GET
=
'get'
;
const
REQUEST_METHOD_POST
=
'post'
;
// eslint-disable-next-line no-undef
const
baseUrl
=
typeof
DUMI_TYPE
!==
'undefined'
&&
DUMI_TYPE
===
'dumi'
?
'/api'
:
''
;
// 获取历史数据
export
function
getHistoryInfo
(
data
)
{
return
request
({
url
:
`
${
baseUrl
}
/PandaMonitor/Monitor/Device/GetSensorsDataForStation`
,
method
:
REQUEST_METHOD_POST
,
data
,
});
}
packages/extend-components/EC_HistoryView/src/demos/GridDemo.js
0 → 100644
View file @
e6ad7ff7
import
React
from
'react'
;
import
HistoryView
from
'../index'
;
const
deviceParams
=
[{
deviceCode
:
"EGBF00000146"
,
sensors
:
"进水压力,出水瞬时流量,出水累计流量"
,
deviceType
:
"二供泵房"
}]
const
Demo
=
()
=>
{
return
(
<
div
style
=
{{
height
:
700
}}
>
<
HistoryView
deviceParams
=
{
deviceParams
}
grid
/>
<
/div
>
);
};
export
default
Demo
;
packages/extend-components/EC_HistoryView/src/demos/index.js
0 → 100644
View file @
e6ad7ff7
import
React
from
'react'
;
import
HistoryView
from
'../index'
;
const
deviceParams
=
[{
deviceCode
:
"EGBF00000146"
,
sensors
:
"进水压力,出水瞬时流量,出水累计流量"
,
deviceType
:
"二供泵房"
}]
const
Demo
=
()
=>
{
return
(
<
div
style
=
{{
height
:
700
}}
>
<
HistoryView
deviceParams
=
{
deviceParams
}
/
>
<
/div
>
);
};
export
default
Demo
;
packages/extend-components/EC_HistoryView/src/hooks/useQTime.js
0 → 100644
View file @
e6ad7ff7
const
TIMELIST
=
[
{
key
:
'oneHour'
,
name
:
'近1小时'
,
},
{
key
:
'fourHour'
,
name
:
'近4小时'
,
},
{
key
:
'twelveHours'
,
name
:
'近12小时'
,
},
{
key
:
'roundClock'
,
name
:
'近24小时'
,
},
{
key
:
'yesterday'
,
name
:
'昨天'
,
},
];
packages/extend-components/EC_HistoryView/src/index.js
0 → 100644
View file @
e6ad7ff7
import
React
,
{
useContext
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
PropTypes
from
'prop-types'
;
import
classNames
from
'classnames'
;
import
{
Button
,
Checkbox
,
ConfigProvider
,
DatePicker
,
Radio
,
Select
,
Spin
,
Tabs
}
from
'antd'
;
import
{
CloseCircleFilled
,
DownloadOutlined
,
PlusCircleOutlined
}
from
'@ant-design/icons'
;
import
moment
from
'moment'
;
import
_
from
'lodash'
;
import
TimeRangePicker
from
'@wisdom-components/timerangepicker'
;
import
BasicTable
from
'@wisdom-components/basictable'
;
import
{
getHistoryInfo
}
from
'./apis'
;
import
SimgleChart
from
'./SingleChart'
;
import
GridChart
from
'./GridChart'
;
import
'./index.less'
;
const
{
RangePicker
}
=
DatePicker
;
const
{
Option
}
=
Select
;
const
startFormat
=
'YYYY-MM-DD 00:00:00'
;
const
endFormat
=
'YYYY-MM-DD 23:59:59'
;
const
timeFormat
=
'YYYY-MM-DD HH:mm:ss'
;
const
timeList
=
[
{
key
:
'oneHour'
,
name
:
'近1小时'
,
},
{
key
:
'fourHour'
,
name
:
'近4小时'
,
},
{
key
:
'twelveHours'
,
name
:
'近12小时'
,
},
{
key
:
'roundClock'
,
name
:
'近24小时'
,
},
{
key
:
'yesterday'
,
name
:
'昨天'
,
},
];
const
CheckboxData
=
[
{
key
:
'curveCenter'
,
label
:
'曲线居中'
,
checked
:
false
,
},
{
key
:
'ignoreOutliers'
,
label
:
'过滤异常值'
,
type
:
'updateIgnoreOutliers'
,
checked
:
false
,
},
{
key
:
'dataThin'
,
label
:
'数据抽稀'
,
type
:
'updateDataThin'
,
checked
:
true
,
},
];
const
timeIntervalList
=
[
{
key
:
'5'
,
zoom
:
'5'
,
unit
:
'min'
,
name
:
'5分钟'
,
},
{
key
:
'10'
,
zoom
:
'10'
,
unit
:
'min'
,
name
:
'10分钟'
,
},
{
key
:
'30'
,
zoom
:
'30'
,
unit
:
'min'
,
name
:
'30分钟'
,
},
{
key
:
'1'
,
zoom
:
'1'
,
unit
:
'h'
,
name
:
'1小时'
,
},
{
key
:
'2'
,
zoom
:
'2'
,
unit
:
'h'
,
name
:
'2小时'
,
},
{
key
:
'6'
,
zoom
:
'6'
,
unit
:
'h'
,
name
:
'6小时'
,
},
{
key
:
'12'
,
zoom
:
'12'
,
unit
:
'h'
,
name
:
'12小时'
,
},
];
const
updateTime
=
(
key
)
=>
{
let
start
=
''
,
end
=
''
;
if
(
Array
.
isArray
(
key
))
{
start
=
moment
(
key
[
0
]).
format
(
timeFormat
);
end
=
moment
(
key
[
1
]).
format
(
timeFormat
);
}
else
{
switch
(
key
)
{
case
'oneHour'
:
start
=
moment
().
subtract
(
1
,
'hour'
).
format
(
timeFormat
);
end
=
moment
().
format
(
timeFormat
);
break
;
case
'fourHour'
:
start
=
moment
().
subtract
(
4
,
'hour'
).
format
(
timeFormat
);
end
=
moment
().
format
(
timeFormat
);
break
;
case
'twelveHours'
:
start
=
moment
().
subtract
(
12
,
'hour'
).
format
(
timeFormat
);
end
=
moment
().
format
(
timeFormat
);
break
;
case
'roundClock'
:
start
=
moment
().
subtract
(
24
,
'hour'
).
format
(
timeFormat
);
end
=
moment
().
format
(
timeFormat
);
break
;
case
'yesterday'
:
start
=
moment
().
subtract
(
1
,
'days'
).
format
(
startFormat
);
end
=
moment
().
subtract
(
1
,
'days'
).
format
(
endFormat
);
break
;
}
}
return
[
{
dateFrom
:
start
,
dateTo
:
end
,
},
];
};
const
DefaultDatePicker
=
(
value
)
=>
[
{
key
:
1
,
value
:
moment
(),
},
{
key
:
2
,
value
:
moment
().
subtract
(
1
,
value
),
},
];
const
handleBatchTime
=
(
arr
,
cOption
)
=>
{
let
newArr
=
[];
arr
.
forEach
((
child
)
=>
{
if
(
child
.
value
)
{
newArr
.
push
({
dateFrom
:
moment
(
child
.
value
).
startOf
(
cOption
).
format
(
startFormat
),
dateTo
:
moment
(
child
.
value
).
endOf
(
cOption
).
format
(
endFormat
),
});
}
});
newArr
=
_
.
uniqWith
(
newArr
,
_
.
isEqual
);
// 去掉重复日期时间
return
newArr
;
};
const
timeColumn
=
{
title
:
'采集时间'
,
dataIndex
:
'time'
,
key
:
'time'
,
width
:
160
,
fixed
:
'left'
,
ellipsis
:
true
,
align
:
'center'
,
};
const
HistoryView
=
props
=>
{
const
{
getPrefixCls
}
=
useContext
(
ConfigProvider
.
ConfigContext
);
const
prefixCls
=
getPrefixCls
(
'history-view'
);
const
{
title
,
grid
,
defaultChecked
,
tableProps
,
deviceParams
}
=
props
;
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
activeTabKey
,
setActiveTabKey
]
=
useState
(
'curve'
);
// 时间模式: 自定义模式/同期对比模式
const
[
timeValue
,
setTimeValue
]
=
useState
(
'customer'
);
// 自定义模式
const
[
customerChecked
,
setCustomerChecked
]
=
useState
(
defaultChecked
);
// 时间快速选择类型值
const
[
customerTime
,
setCustomerTime
]
=
useState
();
// 自定义时间选择值
// 同期对比模式
const
[
contrastOption
,
setContrastOption
]
=
useState
(
'day'
);
// 对比时间类型: 日/月
const
[
datePickerArr
,
setDatePickerArr
]
=
useState
(
DefaultDatePicker
(
'day'
));
// 对比时间段配置值
const
[
checkboxData
,
setCheckboxData
]
=
useState
(
CheckboxData
);
// 曲线设置项
const
[
dataThinKey
,
setDataThinKey
]
=
useState
(
timeIntervalList
[
0
].
key
);
// 曲线抽稀时间设置
const
[
columns
,
setColumns
]
=
useState
([]);
const
[
tableData
,
setTableData
]
=
useState
([]);
const
[
chartDataSource
,
setChartDataSource
]
=
useState
([]);
// 选择的时间范围值
const
dateRange
=
useMemo
(()
=>
{
if
(
timeValue
===
'customer'
)
{
return
updateTime
(
customerChecked
||
customerTime
);
}
else
{
return
handleBatchTime
(
datePickerArr
,
contrastOption
);
}
},
[
contrastOption
,
customerChecked
,
customerTime
,
datePickerArr
,
timeValue
]);
// 数据配置
const
dataConfig
=
useMemo
(()
=>
{
const
initial
=
{
ignoreOutliers
:
false
,
dataThin
:
false
,
zoom
:
''
,
// 数据抽稀时间
unit
:
''
,
// 数据抽稀时间单位
};
// 曲线居中,过滤异常值,数据抽稀
const
config
=
checkboxData
.
reduce
((
pre
,
item
)
=>
((
item
.
key
!==
'curveCenter'
&&
(
pre
[
item
.
key
]
=
item
.
checked
)),
pre
),
initial
);
// 数据抽稀时间单位
const
dataThin
=
timeIntervalList
.
find
(
item
=>
item
.
key
===
dataThinKey
);
config
.
zoom
=
activeTabKey
===
'curve'
?
''
:
(
dataThin
?.
zoom
??
''
);
config
.
unit
=
activeTabKey
===
'curve'
?
''
:
(
dataThin
?.
unit
??
''
);
config
.
dataThin
=
activeTabKey
===
'curve'
?
true
:
config
.
dataThin
;
// 曲线强制抽稀
return
config
;
},
[
checkboxData
,
dataThinKey
,
activeTabKey
]);
// 图表居中
const
curveCenter
=
useMemo
(()
=>
checkboxData
.
find
(
item
=>
item
.
key
===
'curveCenter'
)?.
checked
,
[
checkboxData
]);
// 自定义模式: 快速选择
const
onCustomerTimeChange
=
(
key
)
=>
{
setCustomerChecked
(
key
);
!!
customerTime
&&
setCustomerTime
(
null
);
};
// 自定义模式: 自定义时间选择
const
onCustomerRangeChange
=
(
value
)
=>
{
if
(
!
value
)
{
// 时间清空,回到默认时间选择
setCustomerChecked
(
'oneHour'
);
setCustomerTime
(
value
);
}
else
{
setCustomerChecked
(
null
);
setCustomerTime
(
value
);
}
};
// 同期对比模式: 选择(日/月)
const
onContrastChange
=
(
value
)
=>
{
setContrastOption
(
value
);
setDatePickerArr
([...
DefaultDatePicker
(
value
)]);
};
// 同期对比模式: 时间段选择
const
onContrastPickerChange
=
(
date
,
dateString
,
item
)
=>
{
const
arr
=
[...
datePickerArr
];
arr
.
forEach
((
child
)
=>
{
if
(
child
.
key
===
item
.
key
)
{
child
.
value
=
date
;
}
});
setDatePickerArr
(
arr
);
};
// 同期对比模式: 新增日期选择组件
const
handleAddDatePicker
=
()
=>
{
setDatePickerArr
([
...
datePickerArr
,
{
key
:
datePickerArr
[
datePickerArr
.
length
-
1
].
key
+
1
,
value
:
''
,
},
]);
};
// 同期对比模式: 删除日期选择组件
const
handleDeleteDatePicker
=
(
index
)
=>
{
const
arr
=
[...
datePickerArr
];
arr
.
splice
(
index
,
1
);
setDatePickerArr
(
arr
);
};
// 时间设置切换(自定义/同期对比)
const
onTimeSetChange
=
(
e
)
=>
{
setTimeValue
(
e
.
target
.
value
);
if
(
e
.
target
.
value
===
'contrast'
)
{
// 同期对比
onContrastChange
(
contrastOption
);
}
else
{
// 自定义
// 不需要处理
}
};
const
renderTimeOption
=
()
=>
{
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-date`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
时间
<
/div
>
<
Radio
.
Group
value
=
{
timeValue
}
onChange
=
{
onTimeSetChange
}
>
<
Radio
.
Button
value
=
"customer"
>
自定义
<
/Radio.Button
>
<
Radio
.
Button
value
=
"contrast"
>
同期对比
<
/Radio.Button
>
<
/Radio.Group
>
{
timeValue
===
'customer'
&&
(
// 自定义
<>
<
TimeRangePicker
onChange
=
{
onCustomerTimeChange
}
value
=
{
customerChecked
}
dataSource
=
{
timeList
}
/
>
<
RangePicker
className
=
{
classNames
(
`
${
prefixCls
}
-custime-customer`
)}
onChange
=
{
onCustomerRangeChange
}
value
=
{
customerTime
}
showTime
/>
<
/
>
)}
{
timeValue
===
'contrast'
&&
(
// 同期对比
<>
<
Select
value
=
{
contrastOption
}
style
=
{{
width
:
60
}}
onChange
=
{
onContrastChange
}
>
<
Option
value
=
"day"
>
日
<
/Option
>
<
Option
value
=
"month"
>
月
<
/Option
>
<
/Select
>
{
datePickerArr
.
map
((
child
,
index
)
=>
(
<
div
key
=
{
child
.
key
}
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-list`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-wrap`
)}
>
<
DatePicker
picker
=
{
contrastOption
}
value
=
{
child
.
value
}
onChange
=
{(
date
,
dateString
)
=>
onContrastPickerChange
(
date
,
dateString
,
child
)
}
/
>
{
datePickerArr
.
length
>
2
&&
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-delete`
)}
onClick
=
{()
=>
handleDeleteDatePicker
(
index
)}
>
<
CloseCircleFilled
/>
<
/div
>
)}
<
/div
>
{
index
<
datePickerArr
.
length
-
1
&&
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-contrast-connect`
)}
>
与
<
/div
>
)}
<
/div
>
))}
{
datePickerArr
.
length
<
5
&&
<
PlusCircleOutlined
onClick
=
{
handleAddDatePicker
}
/>
}
<
/
>
)}
<
/div
>
);
};
// 曲线设置项选择/取消
const
onCheckboxChange
=
(
e
,
key
)
=>
{
let
data
=
[...
checkboxData
];
data
.
forEach
((
item
)
=>
{
if
(
item
.
key
===
key
)
{
item
.
checked
=
e
.
target
.
checked
;
}
});
setCheckboxData
(
data
);
};
// 数据抽稀时间间隔
const
onTimeIntervalChange
=
(
value
)
=>
{
setDataThinKey
(
value
);
};
const
renderCheckbox
=
(
child
)
=>
(
<
Checkbox
checked
=
{
child
.
checked
}
onChange
=
{(
e
)
=>
onCheckboxChange
(
e
,
child
.
key
)}
>
{
child
.
label
}
<
/Checkbox
>
);
const
renderCurveOption
=
()
=>
{
return
(
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-cover`
)}
>
<
div
className
=
{
classNames
(
`
${
prefixCls
}
-label`
)}
>
曲线设置
<
/div
>
{
checkboxData
.
map
((
child
)
=>
(
<
div
key
=
{
child
.
key
}
>
{
activeTabKey
===
'curve'
&&
child
.
key
===
'curveCenter'
&&
renderCheckbox
(
child
)}
{
activeTabKey
===
'table'
&&
child
.
key
!==
'curveCenter'
&&
renderCheckbox
(
child
)}
<
/div
>
))}
{
activeTabKey
===
'table'
&&
(
<
Select
value
=
{
dataThinKey
}
style
=
{{
width
:
90
}}
onChange
=
{
onTimeIntervalChange
}
disabled
=
{
!
dataConfig
.
dataThin
}
>
{
timeIntervalList
.
map
((
child
)
=>
(
<
Option
key
=
{
child
.
key
}
unit
=
{
child
.
unit
}
value
=
{
child
.
key
}
>
{
child
.
name
}
<
/Option
>
))}
<
/Select
>
)}
<
/div
>
)
};
const
exportExcelBtn
=
()
=>
{
};
const
handleTableData
=
(
data
)
=>
{
const
ignoreOutliers
=
checkboxData
.
find
((
item
)
=>
item
.
key
===
'ignoreOutliers'
).
checked
;
const
dataIndexAccess
=
(
dataItem
,
index
)
=>
{
const
{
stationCode
,
sensorName
}
=
dataItem
;
return
`
${
stationCode
}
-
${
sensorName
}
-
${
index
}
`
;
};
let
format
=
timeFormat
;
if
(
timeValue
===
'contrast'
)
{
format
=
contrastOption
===
'day'
?
'2020-01-01 HH:mm:00'
:
'2020-01-DD HH:mm:00'
;
}
// 处理表头数据
const
columnsData
=
data
.
map
((
item
,
index
)
=>
{
const
{
stationCode
,
equipmentName
,
sensorName
,
unit
,
dataModel
}
=
item
;
const
dataIndex
=
dataIndexAccess
(
item
,
index
);
let
col
=
{
title
:
`
${
equipmentName
}
-
${
sensorName
}${
unit
?
`(
${
unit
}
)`
:
''
}
`
,
dataIndex
:
dataIndex
,
key
:
dataIndex
,
ellipsis
:
true
,
align
:
'center'
,
};
// 同期对比
if
(
timeValue
===
'contrast'
&&
dataModel
[
0
])
{
const
time
=
item
.
dataModel
[
0
].
pt
.
slice
(
0
,
contrastOption
===
'day'
?
10
:
7
)
.
replace
(
/-/g
,
''
);
col
.
title
=
`
${
equipmentName
}
-
${
sensorName
}
-
${
time
}
`
;
}
return
col
;
});
// 格式化时间对齐数据, 生成行数
const
timeData
=
{};
const
buildDefaultData
=
(
time
)
=>
{
const
obj
=
{
key
:
time
,
time
:
time
};
data
.
forEach
((
item
,
index
)
=>
{
const
dataIndex
=
dataIndexAccess
(
item
,
index
);
obj
[
dataIndex
]
=
'--'
;
});
return
obj
}
data
.
forEach
((
item
,
index
)
=>
{
const
{
stationCode
,
sensorName
,
dataModel
}
=
item
;
dataModel
.
forEach
((
data
)
=>
{
const
formatTime
=
moment
(
data
.
pt
).
format
(
format
);
let
time
=
formatTime
;
if
(
timeValue
===
'contrast'
)
{
time
=
time
.
slice
(
contrastOption
===
'day'
?
11
:
8
,
16
);
}
timeData
[
formatTime
]
=
timeData
[
formatTime
]
||
buildDefaultData
(
time
);
});
});
// 处理表格数据
data
.
forEach
((
child
,
index
)
=>
{
const
{
dataModel
}
=
child
;
const
dataIndex
=
dataIndexAccess
(
child
,
index
);
dataModel
.
forEach
((
value
,
j
)
=>
{
const
formatTime
=
moment
(
value
.
pt
).
format
(
format
);
const
dataRow
=
timeData
[
formatTime
];
if
(
dataRow
)
{
dataRow
[
dataIndex
]
=
value
.
pv
===
null
?
'--'
:
value
.
pv
;
}
});
});
const
timeSort
=
(
a
,
b
)
=>
{
let
aa
=
a
,
bb
=
b
;
if
(
timeValue
===
'contrast'
)
{
aa
=
a
.
slice
(
contrastOption
===
'day'
?
11
:
8
,
16
);
bb
=
b
.
slice
(
contrastOption
===
'day'
?
11
:
8
,
16
);
}
return
aa
.
localeCompare
(
bb
);
};
const
times
=
Object
.
keys
(
timeData
).
sort
(
timeSort
);
const
tableData
=
times
.
map
((
time
)
=>
timeData
[
time
]);
setColumns
([
timeColumn
,
...
columnsData
]);
setTableData
(
tableData
);
};
// 处理接口服务参数的变化
const
onChangeParams
=
(
value
=
{})
=>
{
const
{
dateRange
,
isDilute
,
ignoreOutliers
,
zoom
,
unit
}
=
value
;
const
requestArr
=
[];
dateRange
.
forEach
((
item
)
=>
{
const
param
=
{
isDilute
,
zoom
,
unit
,
ignoreOutliers
,
isVertical
:
false
,
// 是否查询竖表
dateFrom
:
item
.
dateFrom
,
dateTo
:
item
.
dateTo
,
acrossTables
:
deviceParams
,
};
requestArr
.
push
(
getHistoryInfo
(
param
));
});
setLoading
(
true
);
Promise
.
all
(
requestArr
).
then
((
results
)
=>
{
if
(
results
.
length
)
{
let
data
=
[];
results
.
forEach
((
res
,
index
)
=>
{
const
{
dateFrom
,
dateTo
}
=
dateRange
?.[
index
]
??
{};
if
(
res
.
code
===
0
&&
res
.
data
.
length
)
{
res
.
data
.
forEach
(
d
=>
{
d
.
dateFrom
=
dateFrom
;
d
.
dateTo
=
dateTo
;
});
data
=
data
.
concat
(
res
.
data
);
}
});
setLoading
(
false
);
handleTableData
(
data
);
setChartDataSource
(
data
);
}
});
};
useEffect
(()
=>
{
const
{
dataThin
,
ignoreOutliers
,
zoom
,
unit
}
=
dataConfig
;
onChangeParams
({
isDilute
:
dataThin
,
ignoreOutliers
,
zoom
,
unit
,
dateRange
,
});
},
[
dateRange
,
dataConfig
,
deviceParams
]);
return
(
<
div
className
=
{
classNames
(
prefixCls
)}
>
<
Spin
spinning
=
{
loading
}
wrapperClassName
=
{
classNames
(
`
${
prefixCls
}
-spin`
)}
>
<
Tabs
activeKey
=
{
activeTabKey
}
onChange
=
{(
key
)
=>
setActiveTabKey
(
key
)}
centered
tabBarExtraContent
=
{{
left
:
<
h3
>
{
title
}
<
/h3>
,
right
:
(
<
div
className
=
{
`
${
prefixCls
}
-extra-right`
}
>
{
/* {activeTabKey === 'table' && (
<Button onClick={exportExcelBtn}>
<DownloadOutlined />
下载
</Button>
)} */
}
<
/div
>
)
}}
>
<
Tabs
.
TabPane
key
=
"curve"
tab
=
"曲线"
>
<
div
className
=
{
`
${
prefixCls
}
-options`
}
>
{
renderTimeOption
()}
{
renderCurveOption
()}
<
/div
>
<
div
className
=
{
`
${
prefixCls
}
-content`
}
>
{
grid
===
true
?
(
<
GridChart
prefixCls
=
{
prefixCls
}
dataSource
=
{
chartDataSource
}
contrast
=
{
timeValue
===
'contrast'
}
contrastOption
=
{
contrastOption
}
/
>
)
:
(
<
SimgleChart
prefixCls
=
{
prefixCls
}
dataSource
=
{
chartDataSource
}
contrast
=
{
timeValue
===
'contrast'
}
contrastOption
=
{
contrastOption
}
/
>
)
}
<
/div
>
<
/Tabs.TabPane
>
<
Tabs
.
TabPane
key
=
"table"
tab
=
"表格"
>
<
div
className
=
{
`
${
prefixCls
}
-options`
}
>
{
renderTimeOption
()}
{
renderCurveOption
()}
<
/div
>
<
div
className
=
{
`
${
prefixCls
}
-content`
}
>
{
<
BasicTable
dataSource
=
{
tableData
}
columns
=
{
columns
}
{...
tableProps
}
pagination
=
{{
showQuickJumper
:
true
,
showSizeChanger
:
true
}}
onChange
=
{()
=>
{}}
/
>
}
<
/div
>
<
/Tabs.TabPane
>
<
/Tabs
>
<
/Spin
>
<
/div
>
);
};
HistoryView
.
propTypes
=
{
grid
:
PropTypes
.
bool
,
title
:
PropTypes
.
string
,
defaultChecked
:
PropTypes
.
oneOf
([
'oneHour'
,
'fourHour'
,
'twelveHours'
,
'roundClock'
,
'yesterday'
]),
tableProps
:
PropTypes
.
object
,
deviceParams
:
PropTypes
.
arrayOf
(
PropTypes
.
objectOf
({
deviceCode
:
PropTypes
.
string
,
sensors
:
PropTypes
.
string
,
deviceType
:
PropTypes
.
string
,
}))
};
HistoryView
.
defaultProps
=
{
grid
:
false
,
title
:
'指标曲线'
,
defaultChecked
:
'oneHour'
,
tableProps
:
{},
};
export
default
HistoryView
;
packages/extend-components/EC_HistoryView/src/index.less
0 → 100644
View file @
e6ad7ff7
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@history-view: ~'@{ant-prefix}-history-view';
.@{history-view} {
height: 100%;
&-label {
position: relative;
width: 80px;
&::after {
position: absolute;
top: 0;
right: 7px;
content: ':';
}
}
&-extra-right {
width: 82px;
}
.@{history-view}-spin,
.@{history-view}-spin > .@{ant-prefix}-spin-container,
.@{ant-prefix}-tabs,
.@{ant-prefix}-tabs-content,
.@{ant-prefix}-tabs-tabpane {
height: 100%;
}
.@{ant-prefix}-tabs-tabpane-active {
display: flex;
flex-direction: column;
}
}
.@{history-view}-date {
display: flex;
align-items: center;
white-space: nowrap;
.@{history-view}-label {
letter-spacing: 27px;
&::after {
right: -20px;
}
}
.@{ant-prefix}-radio-group,
.@{ant-prefix}-select {
margin-right: 16px;
}
.anticon-plus-circle {
margin-left: 10px;
color: @primary-color;
font-size: 16px;
cursor: pointer;
}
}
.@{history-view}-contrast {
&-wrap {
position: relative;
cursor: pointer;
}
&-list {
display: flex;
align-items: center;
}
&-delete {
position: absolute;
top: -12px;
right: -8px;
.anticon.anticon-close-circle {
color: #d9d9d9;
background: white;
}
&:hover {
.anticon.anticon-close-circle {
color: rgba(0, 0, 0, 0.45);
background: white;
}
}
}
&-connect {
margin: 0 10px;
}
}
.@{history-view}-options {
display: flex;
align-items: center;
flex-wrap: wrap;
column-gap: 20px;
row-gap: 10px;
padding-bottom: 10px;
}
.@{history-view}-cover {
display: flex;
align-items: center;
white-space: nowrap;
}
.@{history-view}-content {
flex: 1;
overflow: hidden;
}
.@{history-view}-grid {
height: 100%;
overflow-y: auto;
display: flex;
flex-wrap: wrap;
background-color: #F0F2F5;
padding: 4px;
&-item {
width: 50%;
padding: 4px;
}
&-item-wrap {
height: 350px;
background-color: #FFF;
border-radius: 4px;
}
}
\ No newline at end of file
packages/extend-components/EC_HistoryView/src/utils.js
0 → 100644
View file @
e6ad7ff7
import
moment
from
'moment'
;
import
_
from
'lodash'
;
/**
* 轴宽度, 用于计算多轴显示时, 轴线偏移和绘图区域尺寸
*/
const
axisWidth
=
40
;
/**
* 图表系列名称格式化
* @param {*} data
* @param {boolean} contrast 是否为同期对比
* @param {*} contrastOption 同期对比周期配置, day|month
* @returns
*/
const
nameFormatter
=
(
data
,
contrast
,
contrastOption
)
=>
{
const
{
equipmentName
,
sensorName
,
unit
,
dataModel
,
dateFrom
,
dateTo
}
=
data
;
let
name
=
`
${
equipmentName
}
-
${
sensorName
}
`
;
if
(
contrast
)
{
const
time
=
dateFrom
.
slice
(
0
,
contrastOption
===
'day'
?
10
:
7
).
replace
(
/-/g
,
''
);
name
=
`
${
name
}
-
${
time
}
`
;
}
return
name
;
};
/**
* 图表系列数据格式化
* @param {*} data
* @param {boolean} contrast 是否为同期对比
* @param {*} contrastOption 同期对比周期配置, day|month
* @returns 图表系列数据, [[DateTime, value]]
*/
const
dataAccessor
=
(
data
,
contrast
,
contrastOption
)
=>
{
const
{
dataModel
}
=
data
;
const
formatStr
=
contrastOption
===
'day'
?
'2020-01-01 HH:mm:00'
:
'2020-01-DD HH:mm:00'
;
return
dataModel
.
map
(
item
=>
{
const
time
=
contrast
?
moment
(
item
.
pt
).
format
(
formatStr
)
:
item
.
pt
;
return
[
moment
(
time
).
valueOf
(),
item
.
pv
];
});
};
/**
* 面积图配置(目前默认曲线图)
* @param {*} data 数据项
* @returns null/areaStyle, 为null显示曲线图, 为areaStyle对象显示为面积图.
*/
const
areaStyleFormatter
=
(
data
)
=>
{
const
{
sensorName
}
=
data
;
return
sensorName
&&
sensorName
.
indexOf
(
'流量'
)
>
-
1
?
{}
:
null
;
};
/**
* 图表配置项生成
* @param {*} dataSource 数据源
* @param {*} cusOption 自定义属性
* @param {*} contrast 是否为同期对比
* @param {*} contrastOption 同期对比周期配置, day|month
* @param {*} smooth ture/false, 曲线/折线
* @param {*} config 额外配置信息
*/
const
optionGenerator
=
(
dataSource
,
cusOption
,
contrast
,
contrastOption
,
smooth
,
config
)
=>
{
const
needUnit
=
_
.
get
(
config
,
'needUnit'
,
false
);
// 自定义属性
const
restOption
=
_
.
pick
(
cusOption
,
[
'title'
,]);
// 一种指标一个y轴
const
yAxisMap
=
new
Map
();
dataSource
.
forEach
((
item
,
index
)
=>
{
const
{
sensorName
,
unit
}
=
item
;
const
key
=
sensorName
;
if
(
!
yAxisMap
.
has
(
key
))
{
const
i
=
yAxisMap
.
size
;
const
axis
=
{
type
:
'value'
,
name
:
needUnit
?
unit
:
null
,
position
:
i
%
2
===
0
?
'left'
:
'right'
,
offset
:
Math
.
floor
(
i
/
2
)
*
axisWidth
,
axisLabel
:
{
formatter
:
(
value
)
=>
value
>
100000
?
`
${
value
/
1000
}
k`
:
value
,
},
axisLine
:
{
show
:
true
,
},
nameTextStyle
:
{
align
:
i
%
2
===
0
?
'right'
:
'left'
},
}
yAxisMap
.
set
(
key
,
axis
);
}
});
const
yAxis
=
yAxisMap
.
size
>
0
?
[...
yAxisMap
.
values
()]
:
{
type
:
'value'
};
// 根据y轴个数调整边距
const
leftNum
=
Math
.
ceil
(
yAxisMap
.
size
/
2
);
const
rightNum
=
Math
.
floor
(
yAxisMap
.
size
/
2
);
const
grid
=
{
top
:
needUnit
?
80
:
60
,
left
:
10
+
leftNum
*
axisWidth
,
right
:
rightNum
===
0
?
20
:
rightNum
*
axisWidth
,
};
// 根据"指标名称"分类yAxis
const
yAxisInterator
=
(()
=>
{
const
map
=
new
Map
();
let
current
=
-
1
;
const
get
=
(
name
)
=>
map
.
has
(
name
)
?
map
.
get
(
name
)
:
map
.
set
(
name
,
++
current
).
get
(
name
);
return
{
get
}
})();
const
series
=
dataSource
.
map
(
item
=>
{
const
{
sensorName
,
unit
}
=
item
;
const
name
=
nameFormatter
(
item
,
contrast
,
contrastOption
);
const
data
=
dataAccessor
(
item
,
contrast
,
contrastOption
);
const
type
=
'line'
;
const
areaStyle
=
areaStyleFormatter
(
item
);
const
yAxisIndex
=
yAxisInterator
.
get
(
sensorName
);
return
{
notMerge
:
true
,
name
,
type
,
data
,
areaStyle
,
yAxisIndex
,
smooth
,
unit
,
}
});
// 由于series更新后,没有的数据曲线仍然停留在图表区上,导致图表可视区范围有问题
const
min
=
Math
.
min
(...
series
.
map
(
item
=>
item
.
data
?.[
0
]?.[
0
]).
filter
(
item
=>
item
!==
undefined
));
const
max
=
Math
.
max
(...
series
.
map
(
item
=>
item
.
data
?.[
item
.
data
.
length
-
1
]?.[
0
]).
filter
(
item
=>
item
!==
undefined
));
const
xAxis
=
{
type
:
'time'
,
min
,
max
};
const
tooltipTimeFormat
=
!
contrast
?
'YYYY-MM-DD HH:mm:ss'
:
contrastOption
===
'day'
?
'HH:mm'
:
'DD HH:mm'
;
const
tooltip
=
{
timeFormat
:
tooltipTimeFormat
};
return
{
yAxis
,
grid
,
xAxis
,
series
,
tooltip
,
...
restOption
,
}
};
export
default
optionGenerator
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment