rtgk-screen-web/pages/screen/processBoard/index.js

417 lines
14 KiB
JavaScript
Raw Normal View History

2024-06-20 11:26:44 +08:00
import {useRouter} from "next/router";
import React, {useMemo, useState, useRef, useEffect} from "react";
import _ from "lodash";
import moment from 'moment';
import Footer from "../../../components/screen/Footer";
import Header from "../../../components/screen/Header";
import Chart from "../../../components/screen/Chart";
import Row from "../../../components/screen/Row";
import Card from '../../../components/screen/Card';
import Table from "../../../components/screen/Table";
import ProcessCard from "../../components/ProcessCard";
import {useSocket} from "../../../utils/hooks";
/**
* 生产工序总图
*/
const socketScreenType = 'AllOperationType';
const gutter = 20;
const bottom = 0;
//关键生产信息
const getProdOpt = (workCenter, data) => {
let {xData = [], yData = []} = data;
let opt = {
xAxis: {
type: 'category',
data: []
},
title: {
text: `${workCenter}日生产进度`,
textStyle: {
fontSize: "14px"
},
top: 15,
left: 60
},
yAxis: {
type: 'value'
},
grid: {
top: 50,
left: 55
},
series: [
{
data: yData,
type: 'bar'
}
]
};
let newXData = []
xData.forEach(item => {
let date = (new Date(item).getMonth() + 1) + "." + new Date(item).getDate();
newXData.push(date)
})
opt.xAxis.data = newXData;
return opt;
};
//关键能耗信息
const getUsedOpt = (data = {}, params = []) => {
let {
energyOfDay = 0, //电
energyOfMonth = 0,
gasOfDay = 0, //气
gasOfMonth = 0,
waterOfDay = 0,//水
waterOfMonth = 0,
} = data;
if (params.length > 0) {
params[0].values[0].value = energyOfMonth;
params[0].values[1].value = energyOfDay;
params[1].values[0].value = waterOfMonth;
params[1].values[1].value = waterOfDay;
params[2].values[0].value = gasOfMonth;
params[2].values[1].value = gasOfDay;
}
let opt = {
title: {
text: "",
left: "center",
top: 70,
textStyle: {
fontWeight: "normal",
fontSize: "16px"
},
},
tooltip: {
trigger: "item",
},
legend: {
bottom: 10,
left: "center",
orient: "vertical",
textStyle: {
fontSize: 13,
lineHeight: 16
},
},
series: [
{
type: "pie",
radius: ["45%", "70%"],
center: ["50%", "40%"],
avoidLabelOverlap: false,
label: {
show: false,
position: "center",
},
labelLine: {
show: false,
},
data: [],
},
],
};
let res = [];
let colors = ["#6FE621", "#FF005A", "#4D7BF3", "#4FCCFF"]
params.forEach(({name, unit, values}, index) => {
let newOpt = _.cloneDeep(opt);
newOpt.color = [colors[index], "#FFC760"];
newOpt.title.text = `${name}\n(${unit})`;
newOpt.series[0].data = values;
newOpt.legend.formatter = name => {
let {value = ""} = values.find(item => item.name === name) || {};
return `${name}: ${value}`
}
res.push(newOpt);
});
return res;
};
//维保列表字段
const prodTableColumns = [
{title: "任务编码", code: "code"},
{title: "维保类型", code: "type"},
{title: "设备名称", code: "equipSerialName"},
{title: "任务状态", code: "status"},
]
const ProcessBoard = () => {
const [isClear, setClear] = useState(true)
const router = useRouter();
const productTableRef = useRef();
const tableTimeoutRef = useRef();
const spacing = [30, 50]; //工序流程图间距
const {
processBoard: {
workCenter,
taskTableNext,
reloadTime,
pages = {},
energyParams = []
} = {}
} = global.config || {};
const {workCenterCode, date = moment().format('YYYY-MM-DD')} = router.query;
const title = pages['title'];
const [{productionRecords = {}, maintenance = [], coreProcess = [], energy = {}} = {},
reload,
] = useSocket({socketScreenType, workCenterCode, date});
//核心工序数据分组
const [ruleLength, setRuleLength] = useState(6); //一行摆放多少个
const memoData = useMemo(() => {
let res = [];
if (coreProcess.length > 0) {
let newCoreProcess = _.cloneDeep(coreProcess) || [];
let ccIndex = _.findIndex(coreProcess, item => item.code == "L7-CC"); //除磁->双层除磁
newCoreProcess[ccIndex].code = 'L7-SCCC'
newCoreProcess[ccIndex].name = '双层除磁'
let xmIndex = _.findIndex(coreProcess, item => item.code == "L7-XM"); //细磨
newCoreProcess.splice(xmIndex + 1, 0, coreProcess[ccIndex]) //细磨后面添加除磁
newCoreProcess.forEach((item, index) => {
let row = Math.ceil((index + 1) / ruleLength);
let rowIndex = index % ruleLength;
if (!res[row]) res[row] = [];
res[row][rowIndex] = item;
})
}
return res;
}, [coreProcess, ruleLength]);
console.log("memoData", memoData)
//关键生产信息
const prodData = useMemo(() => {
return getProdOpt(workCenter, productionRecords);
}, [productionRecords]);
//关键能耗信息
const usedInfo = useMemo(() => {
return getUsedOpt(energy, energyParams);
}, [energy])
//表格定时刷新
useEffect(() => {
tableTimeoutRef.current = setInterval(() => {
productTableRef.current && productTableRef.current.nextPage();
}, taskTableNext);
return () => {
clearInterval(tableTimeoutRef.current)
}
}, [])
//整体刷新
useEffect(() => {
tableTimeoutRef.current = setInterval(() => {
reload()
}, reloadTime);
return () => {
clearInterval(tableTimeoutRef.current)
}
}, [reload])
return (
<div className="screen-container">
{isClear && (
<React.Fragment>
<Header title={title}/>
<div className="screen-container-content">
<Row className='height-100' gutter={gutter} bottom={bottom}>
<Row.Col span={17}>
<Card title="核心工序流程图" overVisible={true}>
<div className='process-flow-list'>
<div className="list-flex">
{memoData.map((row, rowIndex) => {
let reverse = rowIndex % 2 > 0;
return (
<div className={`list-flex-row ${reverse ? '' : 'reverse'}`}
key={rowIndex}>
{row.map(item => {
return (
<div
className={"list-flex-item"}
key={item['code']}>
<ProcessCard itemData={item}/>
</div>
);
})}
</div>
);
})}
</div>
</div>
</Card>
</Row.Col>
<Row.Col span={7}>
<Card>
<div className="used-content">
<Row className="height-30">
<Card title="关键生产信息" titleSpace={true} overVisible={true}
withBorder={false}>
<Chart option={prodData}/>
</Card>
</Row>
<Row className="height-30">
<Card title="关键能耗信息" titleSpace={true} overVisible={true}
withBorder={false} padding={"0 16px"}>
<Row className='height-100'>
{usedInfo.map((opt, index) => {
return (
<Row.Col span={8} key={index}>
<Chart option={opt}/>
</Row.Col>
);
})}
</Row>
</Card>
</Row>
<Row className="height-40">
<Card title="车间维保计划" titleSpace={true} overVisible={true}
withBorder={false} padding={"16px"}>
<Table
ref={productTableRef}
mainKey="taskCode"
columns={prodTableColumns}
dataSource={maintenance}
/>
</Card>
</Row>
</div>
</Card>
</Row.Col>
</Row>
</div>
<Footer/>
</React.Fragment>
)}
<style jsx>{`
.screen-container {
height: 100vh;
min-height: 1080px;
min-width: 1920px;
background: url("/img/bg.png") center center;
position: relative;
padding-top: 96px;
padding-bottom: 82px;
overflow: hidden;
}
.screen-container-content {
height: 100%;
padding: ${gutter}px;
}
.process-flow-list {
width: 100%;
height: 100%;
padding: 50px 30px 30px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.list-flex {
width: 100%;
height: 100%;
overflow: hidden;
}
.list-flex-row {
display: flex;
margin: 0 -${spacing[0] / 2}px;
}
.list-flex-row.reverse {
flex-direction: row-reverse;
}
.list-flex-item {
width: ${100 / ruleLength}%;
padding: 0 ${spacing[0] / 2}px;
margin-bottom: ${spacing[1]}px;
position: relative;
}
.list-flex-row:last-child .list-flex-item {
margin-bottom: 0;
}
.list-flex-item::after {
content: '';
display: block;
position: absolute;
}
// 右箭头
.list-flex-row:not(.reverse) .list-flex-item::after {
width: 42px;
height: 42px;
right: 0;
left: unset;
bottom: unset;
top: 50%;
transform: translate(50%, -50%);
background: url('/img/arrow.png') center center no-repeat;
z-index: 9;
}
.reverse {
justify-content: space-between;
}
// 左箭头
.list-flex-row.reverse .list-flex-item::after {
width: 42px;
height: 42px;
left: -${spacing[1] / 2}px;
right: unset;
top: 50%;
bottom: unset;
transform: translate(-50%, -50%) rotate(180deg);
transform-origin: 50% 50%;
background: url('/img/arrow.png') center center no-repeat;
z-index: 9;
}
// 下箭头
.list-flex-row .list-flex-item:last-child::after {
width: 42px;
height: 42px;
left: unset;
right: calc(50% - 44px);
top: unset;
bottom: -${(spacing[1] - 44) / 2}px;
transform: translate(-50%, 100%) rotate(90deg);
transform-origin: 50% 50%;
background: url('/img/arrow.png') center center no-repeat;
z-index: 9;
}
// 无箭头
.list-flex-row:last-child .list-flex-item:last-child::after {
display: none;
}
.used-content {
overflow: hidden;
height: 100%;
}
.used-content :global(.screen-card) {
border: none !important;
}
`}</style>
</div>
);
};
export default ProcessBoard;