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

668 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)