982 lines
39 KiB
JavaScript
982 lines
39 KiB
JavaScript
|
import React, { useEffect, useState, useMemo } from 'react';
|
||
|
import dynamic from 'next/dynamic';
|
||
|
|
||
|
const Liquid = dynamic(() => import('@ant-design/plots').then(({ Liquid }) => Liquid),
|
||
|
{ ssr: false }
|
||
|
);
|
||
|
const RingProgress = dynamic(() => import('@ant-design/plots').then(({ RingProgress }) => RingProgress),
|
||
|
{ ssr: false }
|
||
|
);
|
||
|
|
||
|
const Progress = dynamic(() => import('@ant-design/plots').then(({ Progress }) => Progress),
|
||
|
{ ssr: false }
|
||
|
);
|
||
|
const Line = dynamic(() => import('@ant-design/plots').then(({ Line }) => Line),
|
||
|
{ ssr: false }
|
||
|
);
|
||
|
|
||
|
import { List, Carousel, Cascader, Skeleton, Spin } from 'antd';
|
||
|
import _ from 'lodash';
|
||
|
import {
|
||
|
getTimeRate,
|
||
|
getAbnlException,
|
||
|
getSevenQualifiedRate,
|
||
|
getOpByRouterLine,
|
||
|
getOrganization,
|
||
|
} from '../../../reportUtils/getHomePageData';
|
||
|
import homecss from '../../../styles/homecss.module.css';
|
||
|
function HomePage() {
|
||
|
let [loading, setLoading] = useState(false);
|
||
|
// 工厂选择
|
||
|
let [workShops, setWorkShops] = useState([]);
|
||
|
// 级联选择框的数据存储
|
||
|
let [workShopValue, setWorkShopValue] = useState([]);
|
||
|
// 级联选择工作中心
|
||
|
let [caWorkCenterCode, setCaWorkCenterCode] = useState('');
|
||
|
// 级联选择产线
|
||
|
let [caRouterLineCode, setCaRouterLineCode] = useState('');
|
||
|
// 水波图,柱形图,环形图
|
||
|
let [timeRate, setTimeRate] = useState({});
|
||
|
// 异常消息
|
||
|
let [abnlException, setAbnlException] = useState({
|
||
|
equip: [],
|
||
|
quality: [],
|
||
|
prodexec: [],
|
||
|
});
|
||
|
let [exceptions, setExceptions] = useState([]);
|
||
|
let [currentExceptions, setCurrentExceptions] = useState([]);
|
||
|
//存储工序消息
|
||
|
let [opData, setOpdata] = useState([]);
|
||
|
// 质量合格率
|
||
|
let [qualifiedRate, setQualifiedRate] = useState([]);
|
||
|
// 页面初始化加载
|
||
|
useEffect(() => {
|
||
|
getOrganization().then(data => {
|
||
|
if (data.length > 0) {
|
||
|
let defaultOrg = {};
|
||
|
for (let i = 0; i < data.length; i++) {
|
||
|
if (
|
||
|
data[i]['children'] &&
|
||
|
data[i]['children'].length === 0
|
||
|
) {
|
||
|
data[i]['isLeaf'] = false;
|
||
|
}
|
||
|
if (data[i]['defaultWorkCenter']) {
|
||
|
defaultOrg = data[i];
|
||
|
}
|
||
|
}
|
||
|
let defaultOrgValue = [];
|
||
|
if (defaultOrg['defaultWorkCenter']) {
|
||
|
defaultOrgValue.push(defaultOrg['value']);
|
||
|
|
||
|
let child = defaultOrg['children'];
|
||
|
let flag = true;
|
||
|
for (let i = 0; i < child.length; i++) {
|
||
|
if (child[i]['defaultRoute'] && flag) {
|
||
|
flag = false;
|
||
|
defaultOrgValue.push(child[i]['value']);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
setWorkShops(data);
|
||
|
setWorkShopValue(defaultOrgValue);
|
||
|
}
|
||
|
});
|
||
|
}, []);
|
||
|
|
||
|
useEffect(() => {
|
||
|
let workCenterCode = '';
|
||
|
let routerLineCode = '';
|
||
|
if (workShopValue.length > 0) {
|
||
|
workCenterCode = workShopValue[0];
|
||
|
setOpdata([]);
|
||
|
getTimeRate(workCenterCode).then(data => {
|
||
|
if (data) {
|
||
|
for (let key in data) {
|
||
|
if (data[key] == 1 || data[key] == 0) {
|
||
|
data[key] = parseInt(data[key]);
|
||
|
} else {
|
||
|
data[key] = parseFloat(data[key].toFixed(3));
|
||
|
}
|
||
|
}
|
||
|
setTimeRate(data);
|
||
|
}
|
||
|
});
|
||
|
getAbnlException(workCenterCode).then(data => {
|
||
|
if (data) {
|
||
|
let exceptions = {
|
||
|
equip: [],
|
||
|
quality: [],
|
||
|
prodexec: [],
|
||
|
};
|
||
|
for (let i = 0; i < data.length; i++) {
|
||
|
if (data[i].typeException === 'equip') {
|
||
|
exceptions['equip'].push(data[i]);
|
||
|
} else if (data[i].typeException === 'quality') {
|
||
|
exceptions['quality'].push(data[i]);
|
||
|
} else {
|
||
|
exceptions['prodexec'].push(data[i]);
|
||
|
}
|
||
|
}
|
||
|
setExceptions(data);
|
||
|
setCurrentExceptions(data);
|
||
|
setAbnlException(exceptions);
|
||
|
}
|
||
|
});
|
||
|
getSevenQualifiedRate(workCenterCode).then(data => {
|
||
|
if (data) {
|
||
|
let rates = [];
|
||
|
for (let key in data) {
|
||
|
rates.push({
|
||
|
month: key,
|
||
|
value: data[key],
|
||
|
});
|
||
|
}
|
||
|
setQualifiedRate(rates);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (workShopValue.length === 2) {
|
||
|
setLoading(true);
|
||
|
routerLineCode = workShopValue[1];
|
||
|
getOpByRouterLine(routerLineCode).then(data => {
|
||
|
setLoading(false);
|
||
|
if (data && data.length > 0) {
|
||
|
setOpdata(data);
|
||
|
} else {
|
||
|
setOpdata([]);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
} else {
|
||
|
setQualifiedRate([]);
|
||
|
setOpdata([]);
|
||
|
setCurrentExceptions([]);
|
||
|
setExceptions([]);
|
||
|
setTimeRate({});
|
||
|
setAbnlException({
|
||
|
equip: [],
|
||
|
quality: [],
|
||
|
prodexec: [],
|
||
|
});
|
||
|
}
|
||
|
}, [workShopValue]);
|
||
|
const clickException = type => {
|
||
|
let exceptionData = [];
|
||
|
if (type === 'all') {
|
||
|
exceptionData = exceptions;
|
||
|
} else if (type === 'equip') {
|
||
|
exceptionData = abnlException['equip'];
|
||
|
} else if (type === 'quality') {
|
||
|
exceptionData = abnlException['quality'];
|
||
|
} else {
|
||
|
exceptionData = abnlException['prodexec'];
|
||
|
}
|
||
|
setCurrentExceptions(exceptionData);
|
||
|
};
|
||
|
const factoryChange = (value, selectedOptions) => {
|
||
|
let currentValue = [];
|
||
|
if (value) {
|
||
|
currentValue = value;
|
||
|
}
|
||
|
console.log(currentValue);
|
||
|
setWorkShopValue(currentValue);
|
||
|
};
|
||
|
// 用来进行异步加载
|
||
|
/* const loadData = selectedOptions => {
|
||
|
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||
|
const { value = '' } = targetOption;
|
||
|
targetOption.loading = true;
|
||
|
getRouterLineByFactory(value).then(data => {
|
||
|
targetOption.loading = false;
|
||
|
let children = [];
|
||
|
if (data.length > 0) {
|
||
|
for (let i = 0; i < data.length; i++) {
|
||
|
children.push({
|
||
|
value: data[i].code,
|
||
|
label: data[i].name,
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
targetOption.children = children;
|
||
|
setWorkShops([...workShops]);
|
||
|
});
|
||
|
}; */
|
||
|
return (
|
||
|
<div className={homecss['home_page']}>
|
||
|
<div className={homecss['header']}>
|
||
|
<div className={homecss['header_title']}>
|
||
|
<span className={homecss['title']}>
|
||
|
<Cascader
|
||
|
className={homecss['header_workshop']}
|
||
|
bordered={false}
|
||
|
value={workShopValue}
|
||
|
suffixIcon={<Triangle />}
|
||
|
options={workShops}
|
||
|
onChange={factoryChange}
|
||
|
changeOnSelect
|
||
|
placeholder={'请选择产线'}
|
||
|
/>
|
||
|
</span>
|
||
|
<ul className={homecss['equip_state_mark']}>
|
||
|
<li>
|
||
|
<span style={{ backgroundColor: '#28A3FF' }}></span>
|
||
|
生产
|
||
|
</li>
|
||
|
<li>
|
||
|
<span style={{ backgroundColor: '#FAAB0C' }}></span>
|
||
|
待产
|
||
|
</li>
|
||
|
<li>
|
||
|
<span style={{ backgroundColor: '#F5222D' }}></span>
|
||
|
停产
|
||
|
</li>
|
||
|
</ul>
|
||
|
</div>
|
||
|
<div className={homecss['equip_state_card']}>
|
||
|
<Spin tip="Loading..." spinning={loading}>
|
||
|
<Skeleton loading={loading} active>
|
||
|
<ProcessCard
|
||
|
data={opData}
|
||
|
rowKey={'code'}
|
||
|
workCenterCode={workShopValue}
|
||
|
Content={OperationCard}
|
||
|
/>
|
||
|
</Skeleton>
|
||
|
</Spin>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div className={homecss['content']}>
|
||
|
<div className={homecss['content_row']}>
|
||
|
<div>
|
||
|
<span className={homecss['title']}>时间稼动率</span>
|
||
|
<div className={homecss['liquid_parent']}>
|
||
|
<div>
|
||
|
<WaterWave
|
||
|
color="#5487f3"
|
||
|
stroke="#5487f3"
|
||
|
percent={
|
||
|
timeRate['BY_TIME']
|
||
|
? timeRate['BY_TIME']
|
||
|
: 0
|
||
|
}
|
||
|
/>
|
||
|
<span className="echart_title">本月</span>
|
||
|
</div>
|
||
|
|
||
|
<div>
|
||
|
<WaterWave
|
||
|
color="#f8ae3c"
|
||
|
stroke="#f8ae3c"
|
||
|
percent={
|
||
|
timeRate['BZ_TIME']
|
||
|
? timeRate['BZ_TIME']
|
||
|
: 0
|
||
|
}
|
||
|
/>
|
||
|
<span className="echart_title">本周</span>
|
||
|
</div>
|
||
|
<div>
|
||
|
<WaterWave
|
||
|
color="#3ad18c"
|
||
|
stroke="#3ad18c"
|
||
|
percent={
|
||
|
timeRate['JR_TIME']
|
||
|
? timeRate['JR_TIME']
|
||
|
: 0
|
||
|
}
|
||
|
/>
|
||
|
<span className="echart_title">今日</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div>
|
||
|
<span className={homecss['title']}>性能稼动率</span>
|
||
|
<div className={homecss['progress_parent']}>
|
||
|
<div className={homecss['progress_child']}>
|
||
|
<span
|
||
|
className={homecss['progress_child_title']}
|
||
|
>
|
||
|
本月
|
||
|
</span>
|
||
|
<div className={homecss['progress_child_bar']}>
|
||
|
<ProgressBar
|
||
|
config={{
|
||
|
autoFit: true,
|
||
|
percent: timeRate['BY_PERFORMANCE']
|
||
|
? timeRate['BY_PERFORMANCE']
|
||
|
: 0,
|
||
|
barWidthRatio: 0.3,
|
||
|
color: ['#28A3FF', '#E4E4E4'],
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
<span className={homecss['progress_child_val']}>
|
||
|
{timeRate['BY_PERFORMANCE']
|
||
|
? parseFloat(
|
||
|
(
|
||
|
timeRate['BY_PERFORMANCE'] *
|
||
|
100
|
||
|
).toFixed(2)
|
||
|
) + '%'
|
||
|
: '0%'}
|
||
|
</span>
|
||
|
</div>
|
||
|
|
||
|
<div className={homecss['progress_child']}>
|
||
|
<span
|
||
|
className={homecss['progress_child_title']}
|
||
|
>
|
||
|
本周
|
||
|
</span>
|
||
|
<div className={homecss['progress_child_bar']}>
|
||
|
<ProgressBar
|
||
|
config={{
|
||
|
percent: timeRate['BZ_PERFORMANCE']
|
||
|
? timeRate['BZ_PERFORMANCE']
|
||
|
: 0,
|
||
|
barWidthRatio: 0.3,
|
||
|
color: ['#FFC760', '#E4E4E4'],
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
<span className={homecss['progress_child_val']}>
|
||
|
{timeRate['BZ_PERFORMANCE']
|
||
|
? parseFloat(
|
||
|
(
|
||
|
timeRate['BZ_PERFORMANCE'] *
|
||
|
100
|
||
|
).toFixed(2)
|
||
|
) + '%'
|
||
|
: '0%'}
|
||
|
</span>
|
||
|
</div>
|
||
|
<div className={homecss['progress_child']}>
|
||
|
<span
|
||
|
className={homecss['progress_child_title']}
|
||
|
>
|
||
|
今日
|
||
|
</span>
|
||
|
<div className={homecss['progress_child_bar']}>
|
||
|
<ProgressBar
|
||
|
config={{
|
||
|
percent: timeRate['JR_PERFORMANCE']
|
||
|
? timeRate['JR_PERFORMANCE']
|
||
|
: 0,
|
||
|
barWidthRatio: 0.3,
|
||
|
color: ['#17C082', '#E4E4E4'],
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
<span className={homecss['progress_child_val']}>
|
||
|
{timeRate['BZ_PERFORMANCE']
|
||
|
? parseFloat(
|
||
|
(
|
||
|
timeRate['JR_PERFORMANCE'] *
|
||
|
100
|
||
|
).toFixed(2)
|
||
|
) + '%'
|
||
|
: '0%'}
|
||
|
</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div className={homecss['content_last_col']}>
|
||
|
<span className={homecss['title']}>合格率</span>
|
||
|
<div className={homecss['ringgraph_parent']}>
|
||
|
<div className={homecss['ringgraph_child']}>
|
||
|
<CircleProgress
|
||
|
percent={
|
||
|
timeRate['JR_GOODPRODUCT']
|
||
|
? timeRate['JR_GOODPRODUCT']
|
||
|
: 0
|
||
|
}
|
||
|
/>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div className={homecss['footer']}>
|
||
|
<div className={homecss['footer_row']}>
|
||
|
<div>
|
||
|
<span
|
||
|
className={homecss['title']}
|
||
|
style={{ cursor: 'pointer' }}
|
||
|
onClick={() => clickException('all')}
|
||
|
>
|
||
|
今日预警通知
|
||
|
</span>
|
||
|
<div className={homecss['footer_content']}>
|
||
|
<ul className={homecss['footer_statistics']}>
|
||
|
<li onClick={() => clickException('equip')}>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_title']
|
||
|
}
|
||
|
>
|
||
|
设备预警
|
||
|
</span>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_val']
|
||
|
}
|
||
|
style={{ color: '#f5222d' }}
|
||
|
>
|
||
|
{abnlException['equip'].length}
|
||
|
</span>
|
||
|
</li>
|
||
|
<li onClick={() => clickException('quality')}>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_title']
|
||
|
}
|
||
|
>
|
||
|
质量预警
|
||
|
</span>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_val']
|
||
|
}
|
||
|
style={{ color: '#28A3FF' }}
|
||
|
>
|
||
|
{abnlException['quality'].length}
|
||
|
</span>
|
||
|
</li>
|
||
|
<li
|
||
|
className={
|
||
|
homecss['footer_statistics_last']
|
||
|
}
|
||
|
onClick={() => clickException('prodexec')}
|
||
|
>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_title']
|
||
|
}
|
||
|
>
|
||
|
生产预警
|
||
|
</span>
|
||
|
<span
|
||
|
className={
|
||
|
homecss['footer_statistics_val']
|
||
|
}
|
||
|
style={{ color: '#17C082' }}
|
||
|
>
|
||
|
{abnlException['prodexec'].length}
|
||
|
</span>
|
||
|
</li>
|
||
|
</ul>
|
||
|
<div className={homecss['footer_tips']}>
|
||
|
<List
|
||
|
itemLayout="horizontal"
|
||
|
split={false}
|
||
|
dataSource={currentExceptions}
|
||
|
renderItem={item => (
|
||
|
<List.Item
|
||
|
extra={
|
||
|
<div
|
||
|
className={
|
||
|
homecss[
|
||
|
'footer_tips_time'
|
||
|
]
|
||
|
}
|
||
|
>
|
||
|
{item.time}
|
||
|
</div>
|
||
|
}
|
||
|
>
|
||
|
<List.Item.Meta
|
||
|
avatar={
|
||
|
<div
|
||
|
className={
|
||
|
homecss[
|
||
|
'footer_tips_title'
|
||
|
]
|
||
|
}
|
||
|
style={{
|
||
|
color:
|
||
|
item.typeException ===
|
||
|
'equip'
|
||
|
? '#F5222D'
|
||
|
: item.typeException ===
|
||
|
'quality'
|
||
|
? '#28A3FF'
|
||
|
: '#17C082',
|
||
|
}}
|
||
|
>
|
||
|
{item.typeException ===
|
||
|
'equip'
|
||
|
? '【设备】'
|
||
|
: item.typeException ===
|
||
|
'quality'
|
||
|
? '【质量】'
|
||
|
: '【生产】'}
|
||
|
</div>
|
||
|
}
|
||
|
description={
|
||
|
<div
|
||
|
className={
|
||
|
homecss[
|
||
|
'footer_tips_content'
|
||
|
]
|
||
|
}
|
||
|
>
|
||
|
{item.phenomenonName}
|
||
|
</div>
|
||
|
}
|
||
|
/>
|
||
|
</List.Item>
|
||
|
)}
|
||
|
/>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div>
|
||
|
<span className={homecss['title']}>合格率走势图</span>
|
||
|
<div className={homecss['footer_qualified_rate']}>
|
||
|
<LineChart data={qualifiedRate} />
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
const WaterWave = React.memo(props => {
|
||
|
const { color, stroke, percent } = props;
|
||
|
let config = {
|
||
|
autoFit: true,
|
||
|
liquidStyle: { fill: color },
|
||
|
percent: percent,
|
||
|
outline: {
|
||
|
border: 3,
|
||
|
distance: 1,
|
||
|
style: {
|
||
|
stroke: stroke,
|
||
|
},
|
||
|
},
|
||
|
wave: {
|
||
|
length: 80,
|
||
|
count: 3,
|
||
|
},
|
||
|
statistic: {
|
||
|
title: {
|
||
|
style: {
|
||
|
fontFamily: 'PingFangSC-Medium',
|
||
|
fontSize: '28px',
|
||
|
color: 'rgba(0,0,0,0.85)',
|
||
|
textAlign: 'center',
|
||
|
lineHeight: '26px',
|
||
|
fontWeight: '500',
|
||
|
},
|
||
|
formatter: data => {
|
||
|
return `${parseFloat((data.percent * 100).toFixed(1))}%`;
|
||
|
},
|
||
|
offsetX: 3,
|
||
|
offsetY: -20,
|
||
|
},
|
||
|
content: false,
|
||
|
},
|
||
|
};
|
||
|
return <Liquid {...config} />;
|
||
|
});
|
||
|
const CircleProgress = React.memo(props => {
|
||
|
const { percent } = props;
|
||
|
let config = {
|
||
|
autoFit: true,
|
||
|
percent: percent,
|
||
|
color: ['#28a3ff', '#f1f1f1'],
|
||
|
statistic: {
|
||
|
title: {
|
||
|
style: {
|
||
|
fontFamily: 'PingFangSC-Medium',
|
||
|
fontSize: '14px',
|
||
|
color: 'rgba(0,0,0,0.85)',
|
||
|
textAlign: 'center',
|
||
|
lineHeight: '20px',
|
||
|
fontWeight: '400',
|
||
|
},
|
||
|
content: '合格率',
|
||
|
offsetX: 1,
|
||
|
offsetY: 35,
|
||
|
},
|
||
|
content: {
|
||
|
style: {
|
||
|
fontFamily: 'PingFangSC-Medium',
|
||
|
fontSize: '24px',
|
||
|
color: 'rgba(0,0,0,0.85)',
|
||
|
textAlign: 'center',
|
||
|
lineHeight: '18px',
|
||
|
fontWeight: '500',
|
||
|
},
|
||
|
formatter: data => {
|
||
|
return `${data.percent * 100}%`;
|
||
|
},
|
||
|
offsetX: 3,
|
||
|
offsetY: -18,
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
return <RingProgress {...config} />;
|
||
|
});
|
||
|
const ProgressBar = React.memo(props => {
|
||
|
const { percent, barWidthRatio, color } = props.config;
|
||
|
let config = {
|
||
|
autoFit: true,
|
||
|
percent: percent,
|
||
|
barWidthRatio: barWidthRatio,
|
||
|
color: color,
|
||
|
};
|
||
|
return <Progress {...config} />;
|
||
|
});
|
||
|
const LineChart = React.memo(props => {
|
||
|
let { data = [] } = props;
|
||
|
const config = {
|
||
|
autoFit: true,
|
||
|
smooth: true,
|
||
|
color: '#2D99FF',
|
||
|
lineStyle: {
|
||
|
fill: '#cae5ff',
|
||
|
},
|
||
|
yAxis: {
|
||
|
line: {
|
||
|
style: {
|
||
|
stroke: '#bfbfbf',
|
||
|
lineWidth: 1,
|
||
|
opacity: 0.75,
|
||
|
},
|
||
|
},
|
||
|
label: {
|
||
|
formatter: axisValue => {
|
||
|
if (axisValue > 0) {
|
||
|
return axisValue * 100 + '%';
|
||
|
}
|
||
|
return axisValue;
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
data,
|
||
|
xField: 'month',
|
||
|
yField: 'value',
|
||
|
point: {
|
||
|
size: 4,
|
||
|
shape: 'circle',
|
||
|
style: {
|
||
|
fill: '#2D99FF',
|
||
|
stroke: '#2D99FF',
|
||
|
lineWidth: 1,
|
||
|
},
|
||
|
},
|
||
|
tooltip: {
|
||
|
formatter: datum => {
|
||
|
return { name: '合格率', value: datum.value * 100 + '%' };
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
return <Line {...config} />;
|
||
|
});
|
||
|
const Triangle = React.memo(() => {
|
||
|
return (
|
||
|
<div className="triangle">
|
||
|
<style jsx>{`
|
||
|
.triangle {
|
||
|
margin-top: 3px;
|
||
|
width: 0;
|
||
|
height: 0;
|
||
|
border-top: 5px solid #000000;
|
||
|
border-right: 5px solid transparent;
|
||
|
border-left: 5px solid transparent;
|
||
|
}
|
||
|
`}</style>
|
||
|
</div>
|
||
|
);
|
||
|
});
|
||
|
const ProcessCard = React.memo(props => {
|
||
|
const spacing = [24, 24];
|
||
|
|
||
|
const { Content, data, rowKey, workCenterCode } = props;
|
||
|
const [ruleLength] = useState(5);
|
||
|
|
||
|
const memoData = useMemo(() => {
|
||
|
let res = [];
|
||
|
data.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;
|
||
|
}, [data, ruleLength]);
|
||
|
|
||
|
return (
|
||
|
<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[rowKey]}
|
||
|
>
|
||
|
<Content
|
||
|
workCenterCode={workCenterCode}
|
||
|
equipList={item.iotEquipmentVos || []}
|
||
|
title={`${item['code']}-${item['name']}`}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
})}
|
||
|
</div>
|
||
|
);
|
||
|
})}
|
||
|
|
||
|
<style jsx>{`
|
||
|
.list-flex {
|
||
|
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: 16px;
|
||
|
height: 14px;
|
||
|
right: 0;
|
||
|
left: unset;
|
||
|
bottom: unset;
|
||
|
top: 50%;
|
||
|
transform: translate(50%, -50%);
|
||
|
background: url('/img/jt.png') center center no-repeat;
|
||
|
}
|
||
|
// 左箭头
|
||
|
.list-flex-row.reverse .list-flex-item::after {
|
||
|
width: 16px;
|
||
|
height: 14px;
|
||
|
left: 0;
|
||
|
right: unset;
|
||
|
top: 50%;
|
||
|
bottom: unset;
|
||
|
transform: translate(-50%, -50%) rotate(180deg);
|
||
|
transform-origin: 50% 50%;
|
||
|
background: url('/img/jt.png') center center no-repeat;
|
||
|
}
|
||
|
// 下箭头
|
||
|
.list-flex-row .list-flex-item:last-child::after {
|
||
|
width: 16px;
|
||
|
height: 14px;
|
||
|
left: unset;
|
||
|
right: 50%;
|
||
|
top: unset;
|
||
|
bottom: -${(spacing[1] - 14) / 2}px;
|
||
|
top: unset;
|
||
|
transform: translate(-50%, 100%) rotate(90deg);
|
||
|
transform-origin: 50% 50%;
|
||
|
background: url('/img/jt.png') center center no-repeat;
|
||
|
}
|
||
|
// 无箭头
|
||
|
.list-flex-row:last-child .list-flex-item:last-child::after {
|
||
|
display: none;
|
||
|
}
|
||
|
`}</style>
|
||
|
</div>
|
||
|
);
|
||
|
});
|
||
|
const OperationCard = React.memo(props => {
|
||
|
let { equipList = [], title = '', workCenterCode = '' } = props;
|
||
|
return (
|
||
|
<div className="operation_card">
|
||
|
<div className="operation_card_title">
|
||
|
<span>{title}</span>
|
||
|
</div>
|
||
|
<div className="operation_card_content">
|
||
|
<Carousel autoplay dots={false} autoplaySpeed={10000}>
|
||
|
{equipList.map(item => {
|
||
|
return (
|
||
|
<div key={`${item.equipCode}-${item.equipName}`}>
|
||
|
<EquipCard
|
||
|
config={{
|
||
|
status: parseInt(item.runningstatus),
|
||
|
equipCode: item.equipCode,
|
||
|
equipName: item.equipName,
|
||
|
workCenterCode: workCenterCode,
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
})}
|
||
|
</Carousel>
|
||
|
</div>
|
||
|
<style jsx>{`
|
||
|
.operation_card {
|
||
|
width: 100%;
|
||
|
height: 116px;
|
||
|
background: #ffffff;
|
||
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
||
|
border-radius: 4px;
|
||
|
box-sizing: border-box;
|
||
|
}
|
||
|
.operation_card_title {
|
||
|
width: 100%;
|
||
|
height: 35px;
|
||
|
}
|
||
|
.operation_card_title > span {
|
||
|
display: inline-block;
|
||
|
padding: 6px 0 0 16px;
|
||
|
fontfamily: PingFangSC-Semibold;
|
||
|
fontsize: 14px;
|
||
|
color: #000000;
|
||
|
fontweight: 600;
|
||
|
}
|
||
|
.operation_card_content {
|
||
|
width: 100%;
|
||
|
height: 81px;
|
||
|
box-sizing: border-box;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
`}</style>
|
||
|
</div>
|
||
|
);
|
||
|
});
|
||
|
const EquipCard = React.memo(props => {
|
||
|
let { status, equipCode, equipName, workCenterCode } = props.config;
|
||
|
let title = '';
|
||
|
let background = '';
|
||
|
let img = '';
|
||
|
if (status === 1) {
|
||
|
title = '待产中';
|
||
|
background = 'linear-gradient(270deg, #FFDB93 0%, #FAAB0C 100%)';
|
||
|
img = '/img/dc.png';
|
||
|
} else if (status === 2) {
|
||
|
title = '生产中';
|
||
|
background = 'linear-gradient(270deg, #7AC7FF 0%, #28A3FF 100%)';
|
||
|
img = '/img/sz.png';
|
||
|
} else if (status === 3) {
|
||
|
title = '停产中';
|
||
|
background = 'linear-gradient(270deg, #FF735F 0%, #F5222D 100%)';
|
||
|
img = '/img/tc.png';
|
||
|
}
|
||
|
return (
|
||
|
<div
|
||
|
style={{
|
||
|
display: 'flex',
|
||
|
width: '100%',
|
||
|
height: '81px',
|
||
|
backgroundImage: background,
|
||
|
boxSizing: 'border-box',
|
||
|
cursor: 'pointer',
|
||
|
borderRadius: '0px 0px 4px 4px',
|
||
|
}}
|
||
|
onClick={() => {
|
||
|
setTimeout(() => {
|
||
|
window.parent.postMessage(
|
||
|
{
|
||
|
path: `/mdgeneric/neusoft_web/runtime/f4c2f3083ec84daca1b6bea7985194cb?workCenterCode=${workCenterCode[0]}`,
|
||
|
},
|
||
|
'*'
|
||
|
);
|
||
|
}, 0);
|
||
|
|
||
|
localStorage.setItem('workCenterCode', workCenterCode[0]);
|
||
|
console.log(workCenterCode[0], '+++++');
|
||
|
}}
|
||
|
>
|
||
|
<div
|
||
|
style={{
|
||
|
position: 'relative',
|
||
|
height: '81px',
|
||
|
marginLeft: '4%',
|
||
|
marginRight: '6%',
|
||
|
textAlign: 'center',
|
||
|
lineHeight: '75px',
|
||
|
}}
|
||
|
>
|
||
|
<span
|
||
|
style={{
|
||
|
position: 'absolute',
|
||
|
fontFamily: 'PingFangSC-Semibold',
|
||
|
fontSize: '12px',
|
||
|
color: '#FFFFFF',
|
||
|
fontWeight: '600',
|
||
|
left: '25%',
|
||
|
}}
|
||
|
>
|
||
|
{title}
|
||
|
</span>
|
||
|
<img
|
||
|
src={img}
|
||
|
style={{
|
||
|
display: 'inline-block',
|
||
|
verticalAlign: 'middle',
|
||
|
lineHeight: 'initial',
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
<div
|
||
|
style={{
|
||
|
display: 'flex',
|
||
|
flexDirection: 'column',
|
||
|
minWidth: '25%',
|
||
|
height: '81px',
|
||
|
textAlign: 'center',
|
||
|
}}
|
||
|
>
|
||
|
<span
|
||
|
style={{
|
||
|
display: 'inline-block',
|
||
|
padding: '16px 0 6px 0',
|
||
|
overflow: 'hidden',
|
||
|
textOverflow: 'ellipsis',
|
||
|
whiteSpace: 'nowrap',
|
||
|
minWidth: '25%',
|
||
|
fontFamily: 'PingFangSC-Medium',
|
||
|
fontSize: '14px',
|
||
|
color: '#FFFFFF',
|
||
|
fontWeight: '500',
|
||
|
}}
|
||
|
>
|
||
|
{equipName}
|
||
|
</span>
|
||
|
<span
|
||
|
style={{
|
||
|
display: 'inline-block',
|
||
|
overflow: 'hidden',
|
||
|
textOverflow: 'ellipsis',
|
||
|
whiteSpace: 'nowrap',
|
||
|
minWidth: '25%',
|
||
|
fontFamily: 'PingFangSC-Medium',
|
||
|
fontSize: '14px',
|
||
|
color: '#FFFFFF',
|
||
|
fontWeight: '500',
|
||
|
}}
|
||
|
>
|
||
|
{equipCode}
|
||
|
</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
});
|
||
|
export default HomePage;
|