1088 lines
28 KiB
JavaScript
1088 lines
28 KiB
JavaScript
|
import React, {
|
|||
|
useRef,
|
|||
|
useEffect,
|
|||
|
useState,
|
|||
|
useCallback,
|
|||
|
useMemo,
|
|||
|
} from "react";
|
|||
|
import { withRouter } from "next/router";
|
|||
|
import moment from "moment";
|
|||
|
// import { Liquid, DualAxes } from "@ant-design/plots";
|
|||
|
import _ from "lodash";
|
|||
|
import Chart from "../../../components/screen/Chart";
|
|||
|
import * as echarts from "echarts";
|
|||
|
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 Table from "../../../components/screen/Table";
|
|||
|
import TableProgress from "../../../components/screen/TableProgress";
|
|||
|
import io from "../../../utils/socket.io.js";
|
|||
|
|
|||
|
const gutter = 20;
|
|||
|
const bottom = 20;
|
|||
|
const cardBg = "rgba(6, 36, 109, 0.2)";
|
|||
|
const socketEmit = "timePerformanceGoodProduct";
|
|||
|
const socketScreenType = "QualityDashBoardType";
|
|||
|
// 调试方式: local 本地完整数据调试, server 接口调试, dev 开发期调试
|
|||
|
const dataType = "server";
|
|||
|
|
|||
|
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 useSocket = ({ socketEmit, socketScreenType, dataType }) => {
|
|||
|
const { config: { ioSocketUrl } = {} } = global;
|
|||
|
|
|||
|
const [pageData, setPageData] = useState({});
|
|||
|
const socket = useRef();
|
|||
|
|
|||
|
const update = useCallback((data) => {
|
|||
|
if (dataType === "local") data = localData;
|
|||
|
|
|||
|
console.log("data", data);
|
|||
|
const { todayQuality } = data;
|
|||
|
// 今日合格率
|
|||
|
let todayPassRate = todayQuality.qualityRate;
|
|||
|
// 今日是否合格
|
|||
|
let todayIsPass = todayPassRate >= 0.7;
|
|||
|
// 本月不良率TOP5
|
|||
|
const { monthDefectRateTop5 = {} } = data;
|
|||
|
let monthUnPass = [];
|
|||
|
Object.keys(monthDefectRateTop5).forEach((name) => {
|
|||
|
monthUnPass.push({ name, value: monthDefectRateTop5[name] });
|
|||
|
});
|
|||
|
// 合格率趋势
|
|||
|
const { qualityTrend = [] } = data;
|
|||
|
let passTrend = { category: [], data: [] };
|
|||
|
try {
|
|||
|
let category = [];
|
|||
|
let proData = [[], []];
|
|||
|
qualityTrend.forEach((item, dateIndex) => {
|
|||
|
category.unshift(item.date);
|
|||
|
["zhhgl", "ztl"].forEach((type, typeIndex) => {
|
|||
|
Object.keys(item[type]).forEach((proName) => {
|
|||
|
let value = item[type][proName];
|
|||
|
if (!proData[typeIndex].find((i) => i.name === proName)) {
|
|||
|
proData[typeIndex].push({ name: proName, data: [] });
|
|||
|
}
|
|||
|
let proIndex = proData[typeIndex].findIndex(
|
|||
|
(i) => i.name === proName
|
|||
|
);
|
|||
|
proData[typeIndex][proIndex].data[
|
|||
|
-1 * dateIndex + qualityTrend.length - 1
|
|||
|
] = value;
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
// 折线图 所有值为0,则消失(过滤这条产品数据)
|
|||
|
proData[1] = proData[1].filter(({ data }) => {
|
|||
|
let total = 0;
|
|||
|
data.forEach(val => total += val);
|
|||
|
return total > 0;
|
|||
|
})
|
|||
|
let typeData = [
|
|||
|
{
|
|||
|
key: "zhhgl",
|
|||
|
name: "综合合格率",
|
|||
|
data: proData[0],
|
|||
|
},
|
|||
|
{
|
|||
|
key: "ztl",
|
|||
|
name: "一次性合格率",
|
|||
|
data: proData[1],
|
|||
|
},
|
|||
|
];
|
|||
|
passTrend = { category, data: typeData };
|
|||
|
} catch (e) {
|
|||
|
console.log("qualityTrend error", e, qualityTrend);
|
|||
|
}
|
|||
|
// 近三天不良率
|
|||
|
const { threeDayReject = [] } = data;
|
|||
|
let unPassRate = threeDayReject;
|
|||
|
// 任务提醒
|
|||
|
const { taskRemind = [] } = data;
|
|||
|
let taskReminder = taskRemind;
|
|||
|
|
|||
|
setPageData({
|
|||
|
todayPassRate,
|
|||
|
todayIsPass,
|
|||
|
monthUnPass,
|
|||
|
passTrend,
|
|||
|
unPassRate,
|
|||
|
taskReminder,
|
|||
|
});
|
|||
|
}, []);
|
|||
|
|
|||
|
const getData = useCallback(() => {
|
|||
|
let workCenterCode = getQueryVariable("workCenterCode");
|
|||
|
let date = getQueryVariable("date");
|
|||
|
if (!workCenterCode) return;
|
|||
|
|
|||
|
let query = {
|
|||
|
workCenterCode,
|
|||
|
screenType: socketScreenType,
|
|||
|
};
|
|||
|
if (date) query.date = date;
|
|||
|
console.log("fetch", socketEmit, { query });
|
|||
|
|
|||
|
if (dataType === "server") {
|
|||
|
socket.current.emit(socketEmit, "channel", { query });
|
|||
|
} else if (dataType === "local") {
|
|||
|
update();
|
|||
|
}
|
|||
|
}, [update]);
|
|||
|
|
|||
|
useEffect(() => {
|
|||
|
if (dataType === "dev") setPageData(devData);
|
|||
|
|
|||
|
if (dataType === "local") getData();
|
|||
|
|
|||
|
if (dataType === "server") {
|
|||
|
socket.current = io.connect(ioSocketUrl, {transports:['websocket']});
|
|||
|
socket.current.on("connect", function () {
|
|||
|
console.log("msg页面连接成功!");
|
|||
|
getData();
|
|||
|
});
|
|||
|
socket.current.on(socketEmit, function (res) {
|
|||
|
try {
|
|||
|
res = JSON.parse(res);
|
|||
|
} catch (e) {
|
|||
|
console.log(e);
|
|||
|
}
|
|||
|
update(res.data);
|
|||
|
});
|
|||
|
}
|
|||
|
}, [getData, update]);
|
|||
|
|
|||
|
return [pageData, getData];
|
|||
|
};
|
|||
|
|
|||
|
function QualityBoard(props) {
|
|||
|
const { config: { qualityBoard = {} } = {} } = global;
|
|||
|
const { threeDayRejectTableNext = 4000, taskRemindTableNext = 4000} = qualityBoard;
|
|||
|
|
|||
|
const [pageData, getPageData] = useSocket({
|
|||
|
socketEmit,
|
|||
|
socketScreenType,
|
|||
|
dataType,
|
|||
|
});
|
|||
|
|
|||
|
// 今日合格率
|
|||
|
const todayPassRateOpt = useMemo(
|
|||
|
() => chartConfig("todayPassRateConfig").init(pageData),
|
|||
|
[pageData]
|
|||
|
);
|
|||
|
// 今日是否合格
|
|||
|
const todayIsPass = useMemo(() => !!pageData.todayIsPass, [pageData]);
|
|||
|
// 本月不良率TOP5
|
|||
|
const monthUnPassOpt = useMemo(
|
|||
|
() => chartConfig("monthUnPassConfig").init(pageData),
|
|||
|
[pageData]
|
|||
|
);
|
|||
|
// 合格率趋势
|
|||
|
const passTrend = useMemo(
|
|||
|
() => chartConfig("passTrendConfig").init(pageData),
|
|||
|
[pageData]
|
|||
|
);
|
|||
|
// 近三天不良率
|
|||
|
const unPassRateTableRef = useRef();
|
|||
|
const unPassRateTableColumns = useMemo(
|
|||
|
() => [
|
|||
|
{
|
|||
|
title: "日期",
|
|||
|
code: "date",
|
|||
|
render: (value) => (value && moment(value).format("MM-DD")) || "",
|
|||
|
},
|
|||
|
{ title: "产品名称", code: "materialName" },
|
|||
|
{ title: "产品等级", code: "productLevel" },
|
|||
|
{ title: "生产批次", code: "scpc" },
|
|||
|
{ title: "产量", code: "cl" },
|
|||
|
{ title: "检验批次", code: "jypc" },
|
|||
|
{ title: "不良批次", code: "blpc" },
|
|||
|
{
|
|||
|
title: "不良率",
|
|||
|
width: 176,
|
|||
|
code: "bll",
|
|||
|
render: (value) => {
|
|||
|
if (isNaN(value)) return value;
|
|||
|
if (parseFloat(value) === 0) return value;
|
|||
|
return <TableProgress percent={value} rule={ 'strange' } />
|
|||
|
},
|
|||
|
},
|
|||
|
],
|
|||
|
[]
|
|||
|
);
|
|||
|
useEffect(() => {
|
|||
|
const { unPassRate = [] } = pageData;
|
|||
|
unPassRateTableRef.current.setData(unPassRate);
|
|||
|
let getNextPage = () => setTimeout(() => {
|
|||
|
unPassRateTableRef.current.nextPage();
|
|||
|
timmer = getNextPage();
|
|||
|
}, threeDayRejectTableNext);
|
|||
|
let timmer = getNextPage();
|
|||
|
return () => {
|
|||
|
clearTimeout(timmer);
|
|||
|
};
|
|||
|
}, [pageData]);
|
|||
|
// 任务提醒
|
|||
|
const taskReminderTableRef = useRef();
|
|||
|
// 8小时内含8小时数值显示绿色,8小时以上数值显示橙色,24小时以上数值显示红色。
|
|||
|
const getColor = useCallback((ms = 0) => {
|
|||
|
if (ms > 24 * 60 * 60) return "#FF005A";
|
|||
|
if (ms > 8 * 60 * 60) return "#F5A623";
|
|||
|
if (ms <= 8 * 60 * 60) return "#58BC17";
|
|||
|
}, []);
|
|||
|
const billstatusStyle = useCallback(
|
|||
|
(ms) => {
|
|||
|
return {
|
|||
|
fontSize: "16px",
|
|||
|
color: "#fff",
|
|||
|
lineHeight: "28px",
|
|||
|
padding: "0 8px",
|
|||
|
display: "inline-block",
|
|||
|
background: getColor(ms),
|
|||
|
};
|
|||
|
},
|
|||
|
[getColor]
|
|||
|
);
|
|||
|
const taskReminderTableColumns = useMemo(
|
|||
|
() => [
|
|||
|
{
|
|||
|
title: "任务状态",
|
|||
|
code: "billstatus",
|
|||
|
render: (value, config, rowData) => (
|
|||
|
<span style={billstatusStyle(rowData.ms)}>{value}</span>
|
|||
|
),
|
|||
|
},
|
|||
|
{ title: "任务名称", code: "templatename" },
|
|||
|
{ title: "产品名称", code: "materialname" },
|
|||
|
{ title: "产品等级", code: "materialdesc" },
|
|||
|
{ title: "批次号", code: "workordercode" },
|
|||
|
{ title: "工序", code: "processname" },
|
|||
|
{
|
|||
|
title: "任务产生时间",
|
|||
|
code: "createtime",
|
|||
|
render: (value) =>
|
|||
|
(value && moment(value).format("YYYY-MM-DD HH:mm")) || "",
|
|||
|
},
|
|||
|
{
|
|||
|
title: "持续时长",
|
|||
|
code: "cxsc",
|
|||
|
render: (value, config, rowData) => (
|
|||
|
<span style={{ color: getColor(rowData.ms) }}>{value}</span>
|
|||
|
),
|
|||
|
},
|
|||
|
],
|
|||
|
[billstatusStyle, getColor]
|
|||
|
);
|
|||
|
useEffect(() => {
|
|||
|
const { taskReminder = [] } = pageData;
|
|||
|
taskReminderTableRef.current.setData(taskReminder);
|
|||
|
let getNextPage = () => setTimeout(() => {
|
|||
|
taskReminderTableRef.current.nextPage();
|
|||
|
timmer = getNextPage();
|
|||
|
}, taskRemindTableNext);
|
|||
|
let timmer = getNextPage();
|
|||
|
return () => {
|
|||
|
clearTimeout(timmer);
|
|||
|
};
|
|||
|
}, [pageData]);
|
|||
|
|
|||
|
return (
|
|||
|
<div className="screen-container">
|
|||
|
<Header title={"质量看板"} />
|
|||
|
<div className="screen-container-content">
|
|||
|
<Row
|
|||
|
style={{ height: `${470 + bottom}px` }}
|
|||
|
bottom={bottom}
|
|||
|
gutter={gutter}
|
|||
|
>
|
|||
|
<Row.Col style={{ width: `${470 + gutter}px` }} bottom={bottom}>
|
|||
|
<Row bottom={bottom}>
|
|||
|
<Row.Col span={24} style={{ height: `${220 + bottom}px` }}>
|
|||
|
<Card
|
|||
|
title="今日合格率"
|
|||
|
titleSpace={true}
|
|||
|
overVisible={true}
|
|||
|
withBg={cardBg}
|
|||
|
>
|
|||
|
<div className="screen-container-hp">
|
|||
|
<Row className="height-100" gutter={gutter} bottom={bottom}>
|
|||
|
<Row.Col span={11} bottom={0}>
|
|||
|
<Chart option={todayPassRateOpt} />
|
|||
|
</Row.Col>
|
|||
|
<Row.Col span={13} bottom={0}>
|
|||
|
<div className="screen-container-hp-top">
|
|||
|
<span>检验合格率</span>
|
|||
|
</div>
|
|||
|
<div className="screen-container-hp-bottom">
|
|||
|
{todayIsPass ? "运行正常" : "运行异常"}
|
|||
|
</div>
|
|||
|
</Row.Col>
|
|||
|
</Row>
|
|||
|
</div>
|
|||
|
</Card>
|
|||
|
</Row.Col>
|
|||
|
<Row.Col span={24} style={{ height: `${230}px` }} bottom={0}>
|
|||
|
<Card title="本月不良率TOP5" titleSpace={true} withBg={cardBg}>
|
|||
|
<Chart option={monthUnPassOpt} />
|
|||
|
</Card>
|
|||
|
</Row.Col>
|
|||
|
</Row>
|
|||
|
</Row.Col>
|
|||
|
<Row.Col
|
|||
|
style={{ width: `${1390 + bottom}px`, height: `${470 + gutter}px` }}
|
|||
|
>
|
|||
|
<Card title="合格率趋势" titleSpace={false} withBg={cardBg}>
|
|||
|
<Chart option={passTrend} />
|
|||
|
</Card>
|
|||
|
</Row.Col>
|
|||
|
</Row>
|
|||
|
<Row style={{ height: `${404}px` }} gutter={gutter} bottom={0}>
|
|||
|
<Row.Col span={12}>
|
|||
|
<Card
|
|||
|
title="近三天不良率"
|
|||
|
titleSpace={true}
|
|||
|
withBg={cardBg}
|
|||
|
padding={gutter + "px"}
|
|||
|
>
|
|||
|
<Table
|
|||
|
mainKey="gid"
|
|||
|
ref={unPassRateTableRef}
|
|||
|
columns={unPassRateTableColumns}
|
|||
|
/>
|
|||
|
</Card>
|
|||
|
</Row.Col>
|
|||
|
<Row.Col span={12}>
|
|||
|
<Card
|
|||
|
title="任务提醒"
|
|||
|
titleSpace={true}
|
|||
|
withBg={cardBg}
|
|||
|
padding={gutter + "px"}
|
|||
|
>
|
|||
|
<Table
|
|||
|
mainKey="gid"
|
|||
|
autoNext={false}
|
|||
|
pageFinished={getPageData}
|
|||
|
ref={taskReminderTableRef}
|
|||
|
columns={taskReminderTableColumns}
|
|||
|
/>
|
|||
|
</Card>
|
|||
|
</Row.Col>
|
|||
|
</Row>
|
|||
|
</div>
|
|||
|
<Footer />
|
|||
|
<style jsx>{`
|
|||
|
.screen-container {
|
|||
|
height: 100vh;
|
|||
|
min-height: 1080px;
|
|||
|
min-width: 1920px;
|
|||
|
overflow: hidden;
|
|||
|
background: url("/img/bg.png") center center;
|
|||
|
position: relative;
|
|||
|
padding-top: 96px;
|
|||
|
padding-bottom: 82px;
|
|||
|
}
|
|||
|
.screen-container-content {
|
|||
|
height: 100%;
|
|||
|
padding: 0 ${gutter}px;
|
|||
|
}
|
|||
|
.screen-container-hp {
|
|||
|
height: 100%;
|
|||
|
overflow: hidden;
|
|||
|
}
|
|||
|
.screen-container-hp-top {
|
|||
|
height: 82px;
|
|||
|
background: url(/img/img1.png);
|
|||
|
background-repeat: no-repeat;
|
|||
|
position: relative;
|
|||
|
background-position: 0 10px;
|
|||
|
}
|
|||
|
.screen-container-hp-top span {
|
|||
|
color: #00f7fb;
|
|||
|
position: absolute;
|
|||
|
font-size: 18px;
|
|||
|
top: 25px;
|
|||
|
left: 46px;
|
|||
|
letter-spacing: 10px;
|
|||
|
}
|
|||
|
.screen-container-hp-bottom {
|
|||
|
font-size: 32px;
|
|||
|
line-height: 38px;
|
|||
|
width: 188px;
|
|||
|
color: #00f7fb;
|
|||
|
text-align: center;
|
|||
|
background-image: linear-gradient(
|
|||
|
180deg,
|
|||
|
rgba(0, 76, 167, 0.2) 0%,
|
|||
|
rgba(36, 53, 184, 0.5) 100%
|
|||
|
);
|
|||
|
border: 1px solid #0064f1;
|
|||
|
border-radius: 3px;
|
|||
|
margin-top: 12px;
|
|||
|
}
|
|||
|
.screen-container-hp-bottom::before {
|
|||
|
content: "";
|
|||
|
display: block;
|
|||
|
margin: -8px -10px 0 -10px;
|
|||
|
height: 20px;
|
|||
|
border-top: 1px solid #0064f1;
|
|||
|
border-left: 1px solid #0064f1;
|
|||
|
border-right: 1px solid #0064f1;
|
|||
|
border-top-left-radius: 3px;
|
|||
|
border-top-right-radius: 3px;
|
|||
|
}
|
|||
|
.screen-container-hp-bottom::after {
|
|||
|
content: "";
|
|||
|
display: block;
|
|||
|
margin: 0 -10px -8px -10px;
|
|||
|
height: 20px;
|
|||
|
border-bottom: 1px solid #0064f1;
|
|||
|
border-left: 1px solid #0064f1;
|
|||
|
border-right: 1px solid #0064f1;
|
|||
|
border-bottom-left-radius: 3px;
|
|||
|
border-bottom-right-radius: 3px;
|
|||
|
}
|
|||
|
`}</style>
|
|||
|
</div>
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
const devData = {
|
|||
|
// 今日合格率
|
|||
|
todayPassRate: 0.855555,
|
|||
|
// 今日是否合格
|
|||
|
todayIsPass: true,
|
|||
|
// 本月不良率TOP5
|
|||
|
monthUnPass: [
|
|||
|
{ value: 0.0909, name: "硫含量" },
|
|||
|
{ value: 0.3564, name: "DIO" },
|
|||
|
{ value: 0.1203, name: "粉体电阻率" },
|
|||
|
{ value: 0.1253, name: "包装袋" },
|
|||
|
{ value: 0.2005, name: "振实密度" },
|
|||
|
],
|
|||
|
// 合格率趋势
|
|||
|
passTrend: {
|
|||
|
category: ["08-01", "08-02", "08-03", "08-04", "08-05", "08-06", "08-07"],
|
|||
|
data: [
|
|||
|
{
|
|||
|
name: "综合合格率",
|
|||
|
data: [
|
|||
|
{
|
|||
|
name: "E60",
|
|||
|
data: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
|
|||
|
},
|
|||
|
{
|
|||
|
name: "E70",
|
|||
|
data: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
|
|||
|
},
|
|||
|
{
|
|||
|
name: "E80",
|
|||
|
data: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
|
|||
|
},
|
|||
|
],
|
|||
|
},
|
|||
|
{
|
|||
|
name: "一次性合格率",
|
|||
|
data: [
|
|||
|
{
|
|||
|
name: "E60",
|
|||
|
data: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
|
|||
|
},
|
|||
|
{
|
|||
|
name: "E70",
|
|||
|
data: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
|
|||
|
},
|
|||
|
{
|
|||
|
name: "E80",
|
|||
|
data: [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
|
|||
|
},
|
|||
|
],
|
|||
|
},
|
|||
|
],
|
|||
|
},
|
|||
|
// 近三天不良率
|
|||
|
unPassRate: [
|
|||
|
{
|
|||
|
gid: "1",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "0.123", //不良率
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "2",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "无", //不良率
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "3",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "1", //不良率
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "4",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "1.000", //不良率
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "5",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "0", //不良率
|
|||
|
},
|
|||
|
],
|
|||
|
// 任务提醒
|
|||
|
taskReminder: [
|
|||
|
{
|
|||
|
gid: "1",
|
|||
|
billstatus: "待检验", //任务状态
|
|||
|
templatename: "测试工单批次生成质检任务", //任务名称
|
|||
|
materialname: "L5车间成品", //产品名称
|
|||
|
materialdesc: "E80A", //产品等级
|
|||
|
workordercode: "HSR5A22082201", //批次号
|
|||
|
processname: "粗磨", //工序
|
|||
|
createtime: "2022-08-01 00:00:00", //任务产生时间
|
|||
|
cxsc: "50分钟", //持续时长
|
|||
|
ms: 1,
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "2",
|
|||
|
billstatus: "待检验", //任务状态
|
|||
|
templatename: "测试工单批次生成质检任务", //任务名称
|
|||
|
materialname: "L5车间成品", //产品名称
|
|||
|
materialdesc: "E80A", //产品等级
|
|||
|
workordercode: "HSR5A22082201", //批次号
|
|||
|
processname: "粗磨", //工序
|
|||
|
createtime: "2022-08-01 00:00:00", //任务产生时间
|
|||
|
cxsc: "50分钟", //持续时长
|
|||
|
ms: 1000000,
|
|||
|
},
|
|||
|
],
|
|||
|
};
|
|||
|
const localData = {
|
|||
|
todayQuality: {
|
|||
|
qualityRate: 0.231,
|
|||
|
},
|
|||
|
monthDefectRateTop5: {
|
|||
|
PH值: 0.3333,
|
|||
|
粒度: 0.3333,
|
|||
|
感应强度: 0.3333,
|
|||
|
包装袋: 0.1203,
|
|||
|
振实密度: 0.2005,
|
|||
|
},
|
|||
|
qualityTrend: [
|
|||
|
{
|
|||
|
date: "08-22",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-21",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-20",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-19",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-18",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-17",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
date: "08-16",
|
|||
|
ztl: {
|
|||
|
E60: 0.42,
|
|||
|
E70: 0.32,
|
|||
|
E80: 0.22,
|
|||
|
},
|
|||
|
zhhgl: {
|
|||
|
E60: 0.12,
|
|||
|
E70: 0.12,
|
|||
|
E80: 0.12,
|
|||
|
},
|
|||
|
},
|
|||
|
],
|
|||
|
threeDayReject: [
|
|||
|
{
|
|||
|
gid: "1",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "0.123123123123", //不良率
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "2",
|
|||
|
date: "2022-08-06", //日期
|
|||
|
materialName: "磷酸铁锂", //产品名称
|
|||
|
productLevel: "E80", //产品等级
|
|||
|
scpc: 2, //生产批次
|
|||
|
cl: 2, //产量
|
|||
|
jypc: 2, //检验批次
|
|||
|
blpc: 0, //不良批次
|
|||
|
bll: "无", //不良率
|
|||
|
},
|
|||
|
{ gid: "3" },
|
|||
|
{ gid: "4" },
|
|||
|
{ gid: "5" },
|
|||
|
{ gid: "6" },
|
|||
|
{ gid: "7" },
|
|||
|
{ gid: "8" },
|
|||
|
{ gid: "9" },
|
|||
|
],
|
|||
|
taskRemind: [
|
|||
|
{
|
|||
|
gid: "1",
|
|||
|
billstatus: "待检验", //任务状态
|
|||
|
templatename: "测试工单批次生成质检任务", //任务名称
|
|||
|
materialname: "L5车间成品", //产品名称
|
|||
|
materialdesc: "E80A", //产品等级
|
|||
|
workordercode: "HSR5A22082201", //批次号
|
|||
|
processname: "粗磨", //工序
|
|||
|
createtime: "2022-08-01 00:00:00", //任务产生时间
|
|||
|
cxsc: "50分钟", //持续时长
|
|||
|
ms: 1,
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "2",
|
|||
|
billstatus: "待检验", //任务状态
|
|||
|
templatename: "测试工单批次生成质检任务", //任务名称
|
|||
|
materialname: "L5车间成品", //产品名称
|
|||
|
materialdesc: "E80A", //产品等级
|
|||
|
workordercode: "HSR5A22082201", //批次号
|
|||
|
processname: "粗磨", //工序
|
|||
|
createtime: "2022-08-01 00:00:00", //任务产生时间
|
|||
|
cxsc: "50分钟", //持续时长
|
|||
|
ms: 1000000,
|
|||
|
},
|
|||
|
{
|
|||
|
gid: "3",
|
|||
|
billstatus: "待检验", //任务状态
|
|||
|
templatename: "测试工单批次生成质检任务", //任务名称
|
|||
|
materialname: "L5车间成品", //产品名称
|
|||
|
materialdesc: "E80A", //产品等级
|
|||
|
workordercode: "HSR5A22082201", //批次号
|
|||
|
processname: "粗磨", //工序
|
|||
|
createtime: "2022-08-01 00:00:00", //任务产生时间
|
|||
|
cxsc: "50分钟", //持续时长
|
|||
|
ms: 30000,
|
|||
|
},
|
|||
|
{ gid: "4" },
|
|||
|
{ gid: "5" },
|
|||
|
{ gid: "6" },
|
|||
|
{ gid: "7" },
|
|||
|
{ gid: "8" },
|
|||
|
{ gid: "9" },
|
|||
|
],
|
|||
|
};
|
|||
|
|
|||
|
// 今日合格率
|
|||
|
const todayPassRateConfig = {
|
|||
|
series: {
|
|||
|
type: "liquidFill",
|
|||
|
center: ["50%", "50%"],
|
|||
|
radius: "75%",
|
|||
|
data: [
|
|||
|
{
|
|||
|
value: 0.855,
|
|||
|
itemStyle: {
|
|||
|
opacity: 0.3,
|
|||
|
},
|
|||
|
},
|
|||
|
0.855,
|
|||
|
],
|
|||
|
itemStyle: {},
|
|||
|
label: {
|
|||
|
position: ["50%", "30%"],
|
|||
|
formatter: (opt) => `${parseFloat((opt.value * 100).toFixed(1))}%`,
|
|||
|
fontSize: 28,
|
|||
|
},
|
|||
|
backgroundStyle: {
|
|||
|
color: "none",
|
|||
|
},
|
|||
|
outline: {
|
|||
|
show: true,
|
|||
|
borderDistance: 2,
|
|||
|
itemStyle: {
|
|||
|
color: "none",
|
|||
|
borderColor: "#f6202f",
|
|||
|
borderWidth: 2,
|
|||
|
},
|
|||
|
},
|
|||
|
},
|
|||
|
};
|
|||
|
let todayPassRateColors = {
|
|||
|
red: {
|
|||
|
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|||
|
{
|
|||
|
offset: 0,
|
|||
|
color: "hsl(356deg 92% 65%)",
|
|||
|
},
|
|||
|
{
|
|||
|
offset: 1,
|
|||
|
color: "hsl(356deg 92% 25%)",
|
|||
|
},
|
|||
|
]),
|
|||
|
color: "#f6202f",
|
|||
|
},
|
|||
|
green: {
|
|||
|
fill: "#92D050",
|
|||
|
color: "#92D050",
|
|||
|
},
|
|||
|
orange: {
|
|||
|
fill: "#FFC000",
|
|||
|
color: "#FFC000",
|
|||
|
},
|
|||
|
};
|
|||
|
todayPassRateConfig.init = (pageData) => {
|
|||
|
let { todayPassRate = 0, todayIsPass } = pageData;
|
|||
|
let opt = _.cloneDeep(todayPassRateConfig);
|
|||
|
opt.series.data[0].value = todayPassRate;
|
|||
|
opt.series.data[1] = todayPassRate;
|
|||
|
|
|||
|
let { orange, green } = todayPassRateColors;
|
|||
|
let { fill, color } = todayIsPass ? green : orange;
|
|||
|
|
|||
|
opt.series.itemStyle.color = fill;
|
|||
|
opt.series.label.color = color;
|
|||
|
opt.series.outline.itemStyle.borderColor = color;
|
|||
|
return opt;
|
|||
|
};
|
|||
|
// 本月不良率TOP5
|
|||
|
const monthUnPassConfig = {
|
|||
|
color: ["#4D7BF3", "#4FCCFF", "#6EE420", "#FFC760", "#FF005A"],
|
|||
|
legend: {
|
|||
|
orient: "vertical",
|
|||
|
left: 10,
|
|||
|
top: "middle",
|
|||
|
itemGap: 16,
|
|||
|
textStyle: {
|
|||
|
rich: {
|
|||
|
0: { opacity: 0.75 },
|
|||
|
1: { opacity: 1 },
|
|||
|
},
|
|||
|
},
|
|||
|
},
|
|||
|
series: {
|
|||
|
type: "pie",
|
|||
|
radius: ["40%", "70%"],
|
|||
|
center: ["65%", "45%"],
|
|||
|
label: {
|
|||
|
show: true,
|
|||
|
textBorderColor: "transparent",
|
|||
|
rich: {
|
|||
|
0: { color: "#4D7BF3" },
|
|||
|
1: { color: "#4FCCFF" },
|
|||
|
2: { color: "#6EE420" },
|
|||
|
3: { color: "#FFC760" },
|
|||
|
4: { color: "#FF005A" },
|
|||
|
},
|
|||
|
},
|
|||
|
labelLine: {
|
|||
|
show: true,
|
|||
|
},
|
|||
|
data: [],
|
|||
|
},
|
|||
|
};
|
|||
|
monthUnPassConfig.init = (pageData) => {
|
|||
|
let { monthUnPass } = pageData;
|
|||
|
if (!monthUnPass) return;
|
|||
|
let opt = _.cloneDeep(monthUnPassConfig);
|
|||
|
opt.series.data = monthUnPass;
|
|||
|
opt.legend.formatter = (name) => {
|
|||
|
let { value } = monthUnPass.find((i) => i.name === name);
|
|||
|
return `{0|${name}:}{1|${(value * 100).toFixed(2)}%}`;
|
|||
|
};
|
|||
|
opt.series.label.formatter = (data) => {
|
|||
|
let { name, dataIndex } = data;
|
|||
|
return `{${dataIndex}|${name}}`;
|
|||
|
};
|
|||
|
return opt;
|
|||
|
};
|
|||
|
// 合格率趋势
|
|||
|
const passTrendConfig = {
|
|||
|
grid: {
|
|||
|
bottom: 40,
|
|||
|
top: 80,
|
|||
|
left: 70,
|
|||
|
right: 70,
|
|||
|
},
|
|||
|
legend: {
|
|||
|
right: 20,
|
|||
|
top: 20,
|
|||
|
},
|
|||
|
barMaxWidth: 30,
|
|||
|
xAxis: {
|
|||
|
type: "category",
|
|||
|
data: [],
|
|||
|
axisTick: {
|
|||
|
show: true,
|
|||
|
alignWithLabel: true,
|
|||
|
},
|
|||
|
axisLine: {
|
|||
|
lineStyle: {
|
|||
|
color: "rgba(255,255,255,0.65)",
|
|||
|
},
|
|||
|
},
|
|||
|
axisLabel: {
|
|||
|
color: "rgba(255,255,255,0.85)",
|
|||
|
},
|
|||
|
},
|
|||
|
yAxis: [
|
|||
|
{
|
|||
|
type: "value",
|
|||
|
max: 1,
|
|||
|
axisTick: {
|
|||
|
show: true,
|
|||
|
alignWithLabel: true,
|
|||
|
},
|
|||
|
axisLine: {
|
|||
|
lineStyle: {
|
|||
|
color: "rgba(255,255,255,0.65)",
|
|||
|
},
|
|||
|
},
|
|||
|
axisLabel: {
|
|||
|
color: "rgba(255,255,255,0.85)",
|
|||
|
formatter: (value) => (value * 100).toFixed(0) + "%",
|
|||
|
},
|
|||
|
},
|
|||
|
{
|
|||
|
type: "value",
|
|||
|
max: 1,
|
|||
|
axisTick: {
|
|||
|
show: true,
|
|||
|
alignWithLabel: true,
|
|||
|
},
|
|||
|
axisLine: {
|
|||
|
lineStyle: {
|
|||
|
color: "rgba(255,255,255,0.65)",
|
|||
|
},
|
|||
|
},
|
|||
|
axisLabel: {
|
|||
|
color: "rgba(255,255,255,0.85)",
|
|||
|
formatter: (value) => (value * 100).toFixed(0) + "%",
|
|||
|
},
|
|||
|
},
|
|||
|
],
|
|||
|
series: [],
|
|||
|
};
|
|||
|
const colors = [[new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(249, 203, 173)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(225, 193, 0)'
|
|||
|
}, {
|
|||
|
offset: 0.63, color: 'rgb(217, 199, 117)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.17, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(169, 209, 142)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(0, 176, 240)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(191, 144, 0)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(237, 125, 49)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(255, 153, 153)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(51, 102, 255)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(0, 255, 153)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}]), new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
|||
|
offset: 1, color: 'rgb(255, 51, 253)'
|
|||
|
}, {
|
|||
|
offset: 0.26, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0.16, color: 'rgb(183, 210, 236)'
|
|||
|
}, {
|
|||
|
offset: 0, color: 'rgb(208, 225, 242)'
|
|||
|
}])], [
|
|||
|
"#3366FF", "#00CCFF", "#FF6699", "#8497B0", "#C9C9C9",
|
|||
|
"#FFD966","#8FAADC","#ED7D31","#FFFF00","#92D050"
|
|||
|
],
|
|||
|
]
|
|||
|
passTrendConfig.init = (pageData) => {
|
|||
|
let { passTrend } = pageData;
|
|||
|
if (!passTrend) return;
|
|||
|
let opt = _.cloneDeep(passTrendConfig);
|
|||
|
|
|||
|
let { category, data } = passTrend;
|
|||
|
opt.xAxis.data = category;
|
|||
|
|
|||
|
opt.series = [];
|
|||
|
data.forEach((item, yAxisIndex) => {
|
|||
|
let type = yAxisIndex === 0 ? "bar" : "line";
|
|||
|
let { name: typeName } = item;
|
|||
|
item.data.forEach(({ name: proName, data }, index) => {
|
|||
|
let name = `${proName} ${typeName}`;
|
|||
|
opt.series.push({ name, yAxisIndex, type, data, color: colors[yAxisIndex][index] });
|
|||
|
});
|
|||
|
});
|
|||
|
return opt;
|
|||
|
};
|
|||
|
|
|||
|
let chartConfig = (() => {
|
|||
|
let chartOpt = {
|
|||
|
todayPassRateConfig,
|
|||
|
monthUnPassConfig,
|
|||
|
passTrendConfig,
|
|||
|
};
|
|||
|
let getOpt = (type) => chartOpt[type];
|
|||
|
return getOpt;
|
|||
|
})();
|
|||
|
|
|||
|
export default withRouter(QualityBoard);
|