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

668 lines
18 KiB
JavaScript
Raw Normal View History

2024-06-20 11:26:44 +08:00
import React, { useRef, useEffect, useCallback } from 'react';
import _ from 'lodash';
import { withRouter } from 'next/router';
import Footer from '../../../components/screen/Footer';
import Header from '../../../components/screen/Header';
import Row from '../../../components/screen/Row';
import Card from '../../../components/screen/Card';
import Chart from '../../../components/screen/Chart';
import Table from '../../../components/screen/Table';
import TableProgress from '../../../components/screen/TableProgress';
import io from '../../../utils/socket.io.js';
const gutter = 20;
const bottom = 20;
// 返回结果是个字符串,需要转一下
let testData = {
"code": "0000",
"data": {
//今日生产总数
"productCount": {
"planQty": 3162.000000, //计划总数
"productQty": 199.000000, //生产总数
"unFinishedQty": 2963.000000 //未完成数量
},
//今日生产统计
"productDayCountList": [
{
"productQty": 0.000000, //生产数量
"qualityQty": 0.000000, //合格数量
"time": "00:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "01:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "02:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "03:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "04:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "05:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "06:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "07:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "08:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "09:00"
},
{
"productQty": 69.000000,
"qualityQty": 17.000000,
"time": "10:00"
},
{
"productQty": 12.000000,
"qualityQty": 12.000000,
"time": "11:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "12:00"
},
{
"productQty": 15.000000,
"qualityQty": 15.000000,
"time": "13:00"
},
{
"productQty": 25.000000,
"qualityQty": 25.000000,
"time": "14:00"
},
{
"productQty": 26.000000,
"qualityQty": 26.000000,
"time": "15:00"
},
{
"productQty": 52.000000,
"qualityQty": 51.000000,
"time": "16:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "17:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "18:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "19:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "20:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "21:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "22:00"
},
{
"productQty": 0.000000,
"qualityQty": 0.000000,
"time": "23:00"
}
],
//日产能概况
"productDayRecordList": [
{
"code": "WO202203300001", //工单号
"materialCode": "L5CP", //产品编码
"materialName": "L5车间成品", //产品名称
"planQty": 1000.000000, //计划数量
"productQty": 10.000000, //生产数量
"productRate": 0.010, //生产进度
"productStatus": "已完工", //生产状态
"unQualityQty": 0.000000, //不合格数量
"unQualityRate": 0.000, //不合格率
"workCenterCode": "L5", //产线编码
"workCenterName": "L5车间" //产线名称
},
{
"code": "WO202204010001",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 100.000000,
"productQty": 15.000000,
"productRate": 0.150,
"productStatus": "已创建",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204010002",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 10.000000,
"productQty": 15.000000,
"productRate": 1.500,
"productStatus": "生产中",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204010003",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 10.000000,
"productQty": 12.000000,
"productRate": 1.200,
"productStatus": "生产中",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204060001",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 1000.000000,
"productQty": 14.000000,
"productRate": 0.014,
"productStatus": "生产中",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204060002",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 10.000000,
"productQty": 12.000000,
"productRate": 1.200,
"productStatus": "生产中",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204060003",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 10.000000,
"productQty": 14.000000,
"productRate": 1.400,
"productStatus": "生产中",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204070001",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 10.000000,
"productQty": 52.000000,
"productRate": 5.200,
"productStatus": "生产中",
"unQualityQty": 1.000000,
"unQualityRate": 0.019,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "WO202204080001",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 12.000000,
"productQty": 55.000000,
"productRate": 4.583,
"productStatus": "生产中",
"unQualityQty": 52.000000,
"unQualityRate": 0.945,
"workCenterCode": "L5",
"workCenterName": "L5车间"
},
{
"code": "RcQuickWearStr",
"materialCode": "L5CP",
"materialName": "L5车间成品",
"planQty": 1000.000000,
"productQty": 0.000000,
"productRate": 0.000,
"productStatus": "待生产",
"unQualityQty": 0.000000,
"unQualityRate": 0.000,
"workCenterCode": "L5",
"workCenterName": "L5车间"
}
],
// 今日生产合格数
"qualityDayCount": {
"qualityQty": 146.000000, //合格数量
"qualityRate": 0.734, //合格率
"unQualityQty": 53.000000 //不合格数量
}
},
"success": true
};
const polarBarOpt = {
title: {
text: '计划总数',
left: 'center',
bottom: 24,
textStyle: {
fontSize: 20,
}
},
legend: {
show: false
},
radiusAxis: {
show: false,
type: 'category',
data: ['%']
},
tooltip: {
show: false,
},
series: {
type: 'gauge',
center: ['50%', "40%"],
radius: "70%",
startAngle: 90,
endAngle: -270,
pointer: {
show: false
},
progress: {
show: true,
overlap: false,
roundCap: false,
clip: false,
itemStyle: {
borderWidth: 0,
},
},
axisLine: {
lineStyle: {
width: 20,
color: [[1, 'rgba(40, 163, 255, 0.2)']],
}
},
splitLine: {
show: false,
},
axisTick: {
show: false
},
axisLabel: {
show: false,
},
data: [{
value: 0,
name: '生产总数'
}],
title: {
offsetCenter: ['0%', '20'],
color: "#fff",
fontSize: 20,
},
detail: {
show: true,
offsetCenter: ['0%', '-20'],
width: 'auto',
height: 32,
fontSize: 32,
color: '#00E1FA',
borderColor: 'auto',
borderWidth: 0,
formatter: '{value}'
}
}
};
const setNumOpt = (total, done, title) => {
let res = _.cloneDeep(polarBarOpt);
if(title) res.title.text = `${title}${total}`;
let percent = (100 * done / total).toFixed(2);
res.series.data[0].name = "生产总数";
res.series.data[0].value = percent;
res.series.detail.formatter = () => done;
return res;
}
const setOkNumOpt = (total, done, title) => {
let res = _.cloneDeep(polarBarOpt);
let percent = (100 * done / (total === 0 ? 1 : total)).toFixed(2);
if(isNaN(percent)) percent = 0;
if(title) res.title.text = `${title}${percent}%`;
res.series.data[0].value = percent;
res.series.data[0].name = "合格数量";
res.series.detail.formatter = () => done;
res.series.detail.color = "#6FE621";
res.series.progress.itemStyle.color = "#6FE621";
return res;
}
const barOpt = {
legend: {
show: true,
data: ['生产数量', '合格数量'],
top: 10,
right: 10,
textStyle: {
fontSize: 14,
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
axisTick: {
lineStyle: {opacity: 0.3},
alignWithLabel: true,
},
axisLine: {
lineStyle: {opacity: 0.3},
},
axisLabel: {
color: 'rgba(255, 255, 255, 0.8)'
},
data: []
},
yAxis: {
type: 'value',
axisTick: {
lineStyle: {opacity: 0.3}
},
axisLine: {
lineStyle: {opacity: 0.3}
},
axisLabel: {
color: 'rgba(255, 255, 255, 0.8)'
},
},
grid: {
bottom: 40,
top: 60,
left: 50,
},
barWidth: 20,
series: [{
name: '生产数量',
type: 'bar',
barGap: -1,
data: []
},
{
name: '合格数量',
itemStyle: {
color: "#6FE621",
},
type: 'bar',
data: []
}]
}
const setBarOpt = (data) => {
let res = _.cloneDeep(barOpt);
data.forEach(({productQty, qualityQty, time}, index) => {
res.xAxis.data.push(time);
res.series[0].data[index] = productQty;
res.series[1].data[index] = qualityQty;
})
return res;
};
const productTableColumns = [
{title: "机台", code: "workCenterName"},
{title: "生产状态", code: "productStatus",
color: val => {
if(val === '待生产') return "#d5542d";
if(val === '已创建') return "#1a7cc6";
if(val === '生产中') return "#0aac61";
if(val === '已完工') return "#0db5a4";
if(val === '已关闭') return "#c1c1c1";
if(val === '已取消') return "#c1c1c1";
},
render: (text, config, rowData) => {
const {color} = config;
let resColor = color(text);
return (
<div style={{color: resColor}}>
<span style={{
background: resColor,
width: '8px',
height: '8px',
display: 'inline-block',
borderRadius: '50%',
verticalAlign: 'middle',
}}></span>
<span style={{
verticalAlign: 'middle',
marginLeft: '6px',
}}>{text}</span>
</div>
)
},
},
{title: "产品编码", code: "materialCode"},
{title: "产品名称", code: "materialName"},
{title: "工单编号", code: "code"},
{title: "生产数量", code: "productQty"},
{title: "计划数量", code: "planQty"},
{title: "生产进度", code: "productRate",
width: 200,
render: (value, config, rowData) => {
return <TableProgress percent={value}/>
},
},
{title: "不良品数量", code: "unQualityQty"},
{title: "不良品率", code: "unQualityRate",
render: (value, config, rowData) => {
return <span>{value * 100}%</span>
},
},
]
function PlanBoard(props) {
const {config : {ioSocketUrl, planBoard = {}} = {}} = global;
const tableToNextPage = planBoard.productTableNext;
const {router} = props;
const planNumRef = useRef();
const okNumRef = useRef();
const productNumRef = useRef();
const productTableRef = useRef();
const socket = useRef();
const workCenterCodeRef = useRef();
const tableTimeoutRef = useRef();
const getQueryVariable = (variable) => {
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i = 0; i < vars.length; i++) {
let pair = vars[i].split("=");
if (pair[0] == variable) { return pair[1]; }
}
return (false);
}
const getData = () => {
let workCenterCode = workCenterCodeRef.current
let date = getQueryVariable('date');
console.log("fetch", workCenterCode)
if(!workCenterCode) return;
let query = {
workCenterCode,
screenType: "ProductPlanType",
}
if (date) query.date = date;
else{
query.date = new Date().toJSON().split('T').join(' ').substr(0,10)
}
socket.current.emit('timePerformanceGoodProduct', 'channel', {query})
setTimeGetData()
};
const setTimeGetData = () => {
setTimeout(() => {
getData()
}, 300000)
}
const pageFinished = useCallback(() => {
console.log("finished")
clearInterval(tableTimeoutRef.current);
getData();
})
const setTableNextPage = useCallback(() => {
tableTimeoutRef.current = setInterval(() => {
productTableRef.current.nextPage();
}, tableToNextPage);
}, [])
const update = (data) => {
try{ data = JSON.parse(data) }catch(e){console.log(e)}
// if(!data) data = testData;
const {productCount, productDayCountList, qualityDayCount, productDayRecordList} = data.data;
console.log("data", data.data)
planNumRef.current.setOption(setNumOpt(
productCount.planQty,
productCount.productQty,
"计划总数"
));
okNumRef.current.setOption(setOkNumOpt(
qualityDayCount.qualityQty,
qualityDayCount.qualityQty - qualityDayCount.unQualityQty,
"合格率"
));
productNumRef.current.setOption(setBarOpt(productDayCountList));
productTableRef.current.setData(productDayRecordList);
setTableNextPage();
};
useEffect(() => {
const {workCenterCode} = router.query;
if(!workCenterCode) return;
workCenterCodeRef.current = workCenterCode;
}, [router])
useEffect(() => {
socket.current = io.connect(ioSocketUrl, {transports:['websocket']});
socket.current.on('connect', function() {
console.log("msg页面连接成功");
getData();
});
socket.current.on('timePerformanceGoodProduct', function(data) {
update(data)
});
// update();
}, [])
return (
<div className='screen-container'>
<Header title={"计划看板"} />
<div className="screen-container-content">
<Row className='height-45' gutter={gutter} bottom={bottom}>
<Row.Col span={5}>
<Card title="今日生产总数" titleSpace={true} overVisible={true}>
<Chart ref={planNumRef} />
</Card>
</Row.Col>
<Row.Col span={14}>
<Card title="今日生产统计" overVisible={true}>
<Chart ref={productNumRef} />
</Card>
</Row.Col>
<Row.Col span={5}>
<Card title="今日生产合格总数" titleSpace={true} overVisible={true}>
<Chart ref={okNumRef} />
</Card>
</Row.Col>
</Row>
<Row className='height-55' gutter={gutter}>
<Row.Col span={24}>
<Card title="生产概况" titleSpace={true} padding={`15px ${gutter}px`}>
<Table
ref={productTableRef}
mainKey="code"
columns={productTableColumns}
autoNext={false}
pageFinished={pageFinished}
/>
</Card>
</Row.Col>
</Row>
</div>
<Footer />
<style jsx>{`
.screen-container{
height: 100vh;
overflow: auto;
background: url('/img/bg.png') center center;
position: relative;
padding-top: 96px;
padding-bottom: 82px;
}
.screen-container-content{
height: 100%;
padding: 0 ${gutter}px;
}
`}</style>
</div>
);
}
export default withRouter(PlanBoard)