Commit a06fc420 authored by 左玲玲's avatar 左玲玲 😬

状态查看

parent 24e9a501
import React, { useState, useMemo, useEffect } from 'react';
import { Card, Form, Divider, Empty, Spin, Button } from 'antd';
import ReactEcharts from 'echarts-for-react';
import { useRequest, useAsyncEffect } from "ahooks";
import { doFetch } from '@/utils/doFetch';
import * as echarts from "echarts";
import moment from 'moment';
const Statuschart = ({ statusData = [], statusColorList = [], barStyle }) => {
const [datas, cdatas] = useState([]);
useEffect(() => {
cdatas([]);
statusData?.map((it, i) => {
let arrs = resetData(it.value, i, it.name);
cdatas(datas => [...datas, ...arrs]);
})
}, [statusData]);
function resetData(data, index, parentName) {
let reslist = data?.map((it, i) => {
let time = it.value[0],
endtime = it.value[1];
let typeItem = statusColorList.filter((item) => it.name == item.type)[0];
let baseTime = moment(time).valueOf(),
endTime = moment(endtime).valueOf(),
duration = moment(endtime).diff(moment(time), 'milliseconds');
return {
name: typeItem?.name,
value: [
index,
baseTime,
endTime,
duration
],
itemStyle: {
color: typeItem?.color
},
parentName: parentName
}
}) ?? [];
return reslist;
}
function renderItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.8;
var rectShape = echarts.graphic.clipRectByRect({
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
}, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height * 0.8
});
return rectShape && {
type: 'rect',
shape: rectShape,
style: api.style(),
transition: ['shape']
};
};
const options = useMemo(() => {
let xAxisoption = {
min: 'dataMin',
max: 'dataMax',
scale: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
formatter: (val) => {
let item = moment(val).format("YYYY-MM-DD HH:mm:ss").split(" ")[1];
return item;
},
// rotate: 25
}
}, yAxisoption = {
data: statusData?.map(it => it.name) ?? [],
axisLine: {
show: false
},
axisTick: {
show: false
},
splitLine: {
show: false
},
axisLabel: {
formatter: (params) => {
let newParamsName = '';
const paramsNameNumber = params.length;
const provideNumber = 10;
const rowNumber = Math.ceil(paramsNameNumber / provideNumber);
if (paramsNameNumber > provideNumber) {
for (let p = 0; p < rowNumber; p++) {
let tempStr = '';
const start = p * provideNumber;
const end = start + provideNumber;
if (p == rowNumber - 1) {
tempStr = params.substring(start, paramsNameNumber);
} else {
tempStr = params.substring(start, end) + '\n';
}
newParamsName += tempStr;
}
} else {
newParamsName = params;
}
return newParamsName;
},
// rotate:15
}
};
return {
grid: {
left: 10,
right: "2%",
bottom: 40,
containLabel: true
},
tooltip: {
formatter: function (params) {
return `设备:${params?.data?.parentName}
<br />
设备状态:${params.name}
<br />
开始时间:${moment(params.value[1]).format("YYYY-MM-DD HH:mm:ss")}
<br />
结束时间:${moment(params.value[2]).format("YYYY-MM-DD HH:mm:ss")}
`
}
},
dataZoom: [{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: true,
labelFormatter: '',
bottom: "1%"
},
{
type: 'inside',
filterMode: 'weakFilter'
}],
xAxis: xAxisoption,
yAxis: yAxisoption,
series: [{
type: 'custom',
renderItem: renderItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0
},
data: datas
}]
}
}, [datas, statusData]);
return <div className='screenwh center'>
<ReactEcharts
style={{ height: "100%", width: "100%" }}
option={options}
/>
</div>
}
export default Statuschart;
\ No newline at end of file
......@@ -585,4 +585,9 @@ ol {
}
}
}
}
.screenwh {
width: 100%;
height: 100%;
}
\ No newline at end of file
......@@ -532,6 +532,9 @@ function Contract(props) {
}
}, [activeTabKey, drawer?.val, drawer?.item?.id]);
const tabList = useMemo(() => {
return getcolumns();
}, [activeTabKey]);
const pathconfig = useMemo(() => {
let defpath = getcolumns(setdrawer).filter((it) => it.key == activeTabKey)[0]?.pathconfig ?? {};
return defpath;
......@@ -607,7 +610,7 @@ function Contract(props) {
},
},
}}
tabList={getcolumns()}
tabList={tabList}
activeTabKey={activeTabKey}
onTabChange={(key) => {
setactiveTabKey(key);
......
......@@ -40,6 +40,9 @@ const Costanalysis = () => {
render: (text, row, _, action) => rightExtra(text, row, _, action),
});
}, [activeKey]);
const tabList = useMemo(() => {
return getcolumns();
}, [activeKey]);
const rightExtra = (text, row, _, action) => {
return [
activeKey == 'item-1' && <PremButton
......@@ -208,7 +211,7 @@ const Costanalysis = () => {
setextraparams({})
}}
activeTabKey={activeKey}
tabList={getcolumns()}
tabList={tabList}
pageextra={'export'}
formRef={formRef}
dataSourceFieldsChange={(vals) => {
......
......@@ -92,7 +92,7 @@ const columnsa = [
key: 'standbyRate',
search: false,
render: (_, row) => {
return <span style={{ color: "#00bce4" }}>{row.runRate}%</span>
return <span style={{ color: "#00bce4" }}>{row.standbyRate}%</span>
}
},
{
......@@ -101,7 +101,7 @@ const columnsa = [
key: 'alarmRate',
search: false,
render: (_, row) => {
return <span style={{ color: "#fa4659" }}>{row.runRate}%</span>
return <span style={{ color: "#fa4659" }}>{row.alarmRate}%</span>
}
},
{
......@@ -110,7 +110,7 @@ const columnsa = [
key: 'offRate',
search: false,
render: (_, row) => {
return <span style={{ color: "#6a737b" }}>{row.runRate}%</span>
return <span style={{ color: "#6a737b" }}>{row.offRate}%</span>
}
},
];
......
......@@ -7,12 +7,29 @@ import dayjs from 'dayjs';
import AutoTable from '@/components/AutoTable/mtable';
import ReactEcharts from 'echarts-for-react';
import TreeRender from '@/components/TreeRender';
import Statuschart from '@/components/Statuschart';
const { RangePicker } = DatePicker;
const statusColors = {
报警: '#fa4659',
工作: '#7ac143',
待机: '#00bce4',
关机: '#6a737b'
1: {
name: '工作',
color: '#7ac143',
startColor: '#64e8fe'
},
2: {
name: '待机',
color: '#f59a23',
startColor: '#FCBB67'
},
3: {
name: '关机',
color: '#6a737b',
startColor: '#ccc'
},
4: {
name: '报警',
color: '#F83636',
startColor: '#a97fff'
}
},
format = 'YYYY-MM-DD HH:mm:ss';
const Devicestatus = ({ drawer }) => {
......@@ -44,61 +61,189 @@ const Devicestatus = ({ drawer }) => {
const onselecteTree = (selectedKeys, e, alldata) => {
cdv(e.node.key);
};
const optionsa = useMemo(() => {
const rateList = chartdata?.data?.data?.rateList ?? [];
const typeList = rateList?.map(it => it.name)?.concat(['总时长']) ?? ['总时长']; // 类型
const percentList = rateList?.map(it => it.rate)?.concat([chartdata?.data?.data?.timeRange]) ?? [chartdata?.data?.data?.timeRange];
const options = useMemo(() => {
let data = chartdata?.data?.data?.datalist ?? [];
const xAxisData = [];
const seriesData = [];
data.forEach((item) => {
xAxisData.push(item.start);
xAxisData.push(item.end);
const statusColor = statusColors[item.status];
seriesData.push([item.start, item.status, statusColor]);
seriesData.push([item.end, item.status, statusColor]);
});
/* 数据处理 */
let data = [], obj = {};
// 空格数据
const sum = percentList.reduce((per, cur) => per + cur, 0);
const gap = (1 * sum) / 100;
const gapData = {
name: '空格',
value: gap,
itemStyle: {
color: 'transparent',
},
};
for (let i in statusColors) {
data.push({
name: statusColors[i].name,
value: rateList?.filter(it => it.status == i)?.[0]?.rate,
itemStyle: {
borderRadius: "50%",
color: {
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: statusColors[i].startColor // 0% 处的颜色
}, {
offset: 1,
color: statusColors[i].color // 100% 处的颜色
}],
}
}
})
}
if (rateList?.length == 0) {
obj['value0'] = {
fontSize: 16,
fontWeight: 500,
height: 16,
align: 'left',
verticalAlign: "top",
padding: [5, 0, 0, 16],
color: '#5471c7',
fontFamily: 'PangMenZhengDao',
}
} else {
rateList.forEach((it, i) => {
obj['value' + i] = {
fontSize: 16,
fontWeight: 500,
height: 16,
align: 'left',
verticalAlign: "top",
padding: [5, 0, 0, 16],
color: statusColors[it.status].color,
fontFamily: 'PangMenZhengDao',
}
});
obj['value4'] = {
fontSize: 16,
fontWeight: 500,
height: 16,
align: 'left',
verticalAlign: "top",
padding: [5, 0, 0, 16],
color: '#5471c7',
fontFamily: 'PangMenZhengDao',
}
}
const option = {
tooltip: {
formatter: (params) => {
legend: {
type: "scroll",
orient: 'vertical',
height: '80%',
left: '65%',
top: 'center',
icon: "roundRect", //设置为圆,删除则为矩形
itemWidth: 5,
itemHeight: 16,
itemGap: 25,
data: typeList,
formatter: function (name) {
for (let i = 0; i < typeList.length; i++) {
if (name == typeList[i]) {
if (name != '总时长') {
return `{name|${name}}{value${i}|${rateList[i]['time']}小时} {value${i}|${percentList[i]}%}`
} else {
return `{name|${name}}{value${i}|${percentList[i]}小时}`
}
}
}
},
textStyle: {
rich: {
name: {
fontSize: 14,
fontWeight: 400,
height: 16,
verticalAlign: "top",
padding: [4, 0, 0, 4],
color: '#000',
fontFamily: 'Source Han Sans CN-Regular',
},
...obj
}
}
},
xAxis: {
type: 'category',
name: '小时',
boundaryGap: false,
data: chartdata?.data?.data?.timeList ?? []
},
yAxis: {
type: 'category',
data: ['报警', '工作', '待机', '关机']
series: [{
type: 'pie',
z: 2,
radius: ['43%', '55%'],
center: ["35%", "50%"],
label: {
show: false
},
labelLine: {
show: false
},
data: data
},
series: [
{
type: 'line',
step: 'start',
lineStyle: {
width: 2,
type: 'dotted'
},
data: seriesData.map((item) => ({
value: [item[0], item[1]],
itemStyle: {
color: item[2],
borderType: 'solid'
},
symbol:
item[2] == '#fa4659'
? 'triangle'
: item[2] == '#00fff5'
? 'rect'
: '',
symbolSize: 12
}))
}
]
{
type: 'pie',
z: 3,
radius: ['63%', '75%'],
center: ["35%", "50%"],
label: {
show: false
},
labelLine: {
show: false
},
data: [{
value: 100, name: '总时长', itemStyle: {
borderRadius: "50%",
color: {
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: '#73a0fb' // 0% 处的颜色
}, {
offset: 1,
color: '#5470c6' // 100% 处的颜色
}],
}
}
}]
}]
};
return option;
}, [chartdata?.data]);
const optionbData = useMemo(() => {
let colors = [];
let data = chartdata?.data?.data?.datalist?.length > 0 ? [{
name: '',
value: chartdata?.data?.data?.datalist?.map(it => {
return {
name: it.status,
value: [it.start, it.end]
}
}) ?? []
}] : [];
for (let i in statusColors) {
colors.push({
type: i,
color: statusColors[i].color,
name: statusColors[i].name
})
};
return {
statusData: data,
statusColorList: colors
}
}, [chartdata?.data]);
return <div style={{ display: "flex", justifyContent: "space-between", position: "relative" }}>
<div style={{ width: 300, padding: '0 16px', flexShrink: 0 }}>
<TreeRender dataSource={device?.data} onselected={onselecteTree} noaction={true} isSelectFirst={true} maxWidth={240} />
......@@ -148,25 +293,13 @@ const Devicestatus = ({ drawer }) => {
/>
</div>
<div style={{ flex: 2 }}>
<div style={{ display: "flex", flexWrap: "wrap", gap: 15 }}>
{
Object?.keys(statusColors)?.map(it => {
return <div key={it} style={{ width: '31%', display: 'flex', gap: 16, justifyContent: 'center' }} >
<div style={{ color: statusColors[it] }}>{it}时长</div>
<div>{chartdata?.data?.data?.rateList?.filter(item => item.name == it)?.[0]?.time ?? 0}小时</div>
<div>{chartdata?.data?.data?.rateList?.filter(item => item.name == it)?.[0]?.rate ?? 0}%</div>
</div>
})
}
<div style={{ width: '31%', display: 'flex', gap: 16, justifyContent: 'center' }} >
<div>总时长</div>
<div>{chartdata?.data?.data?.timeRange}小时</div>
</div>
</div>
<ReactEcharts
style={{ height: 600, width: '100%' }}
option={options}
style={{ height: 300, width: '100%' }}
option={optionsa}
/>
<div style={{ height: 200, width: '100%' }}>
<Statuschart statusData={optionbData.statusData} statusColorList={optionbData.statusColorList} />
</div>
</div>
</div>
</div>
......
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