@@ -94,69 +94,69 @@ | |||
/** center top **/ | |||
.TE227 { | |||
top: 128px; | |||
left: 660px; | |||
left: 630px; | |||
} | |||
.TE229 { | |||
top: 128px; | |||
left: 776px; /* +120px */ | |||
left: 746px; /* +120px */ | |||
} | |||
.TE231 { | |||
top: 128px; | |||
left: 896px; | |||
left: 866px; | |||
} | |||
.TE233 { | |||
top: 128px; | |||
left: 1006px; | |||
left: 980px; | |||
} | |||
.TE235 { | |||
top: 128px; | |||
left: 1119px; | |||
left: 1100px; | |||
} | |||
.TE237 { | |||
top: 128px; | |||
left: 1236px; | |||
left: 1220px; | |||
} | |||
.TE239 { | |||
top: 128px; | |||
left: 1346px; | |||
left: 1330px; | |||
} | |||
.TE241 { | |||
top: 128px; | |||
left: 1456px; | |||
left: 1450px; | |||
} | |||
/** center bottom **/ | |||
.TE228 { | |||
top: 620px; | |||
left: 628px; | |||
left: 600px; | |||
} | |||
.TE230 { | |||
top: 620px; | |||
left: 750px; | |||
left: 720px; | |||
} | |||
.TE232 { | |||
top: 620px; | |||
left: 870px; | |||
left: 850px; | |||
} | |||
.TE234 { | |||
top: 620px; | |||
left: 995px; | |||
left: 970px; | |||
} | |||
.TE236 { | |||
top: 620px; | |||
left: 1120px; | |||
left: 1100px; | |||
} | |||
.TE238 { | |||
top: 620px; | |||
left: 1245px; | |||
left: 1225px; | |||
} | |||
.TE240 { | |||
top: 620px; | |||
left: 1370px; | |||
left: 1350px; | |||
} | |||
.TE242 { | |||
top: 620px; | |||
left: 1480px; | |||
left: 1470px; | |||
} | |||
/** center middle **/ | |||
@@ -244,7 +244,7 @@ | |||
left: 2070px; | |||
} | |||
.TE218 { | |||
top: 640px; | |||
top: 660px; | |||
left: 2090px; | |||
} | |||
.TE219 { | |||
@@ -264,7 +264,7 @@ | |||
left: 2180px; | |||
} | |||
.TE223 { | |||
top: 640px; | |||
top: 660px; | |||
left: 2200px; | |||
} | |||
.TE224 { | |||
@@ -309,69 +309,69 @@ | |||
/** center top **/ | |||
.TE333 { | |||
top: 128px; | |||
left: 620px; | |||
left: 670px; | |||
} | |||
.TE335 { | |||
top: 128px; | |||
left: 735px; | |||
left: 785px; | |||
} | |||
.TE337 { | |||
top: 128px; | |||
left: 855px; | |||
left: 890px; | |||
} | |||
.TE339 { | |||
top: 128px; | |||
left: 975px; | |||
left: 1010px; | |||
} | |||
.TE341 { | |||
top: 128px; | |||
left: 1090px; | |||
left: 1120px; | |||
} | |||
.TE343 { | |||
top: 128px; | |||
left: 1205px; | |||
left: 1235px; | |||
} | |||
.TE345 { | |||
top: 128px; | |||
left: 1325px; | |||
left: 1345px; | |||
} | |||
.TE347 { | |||
top: 128px; | |||
left: 1440px; | |||
left: 1450px; | |||
} | |||
/** center bottom **/ | |||
.TE334 { | |||
top: 620px; | |||
left: 588px; | |||
left: 620px; | |||
} | |||
.TE336 { | |||
top: 620px; | |||
left: 710px; | |||
left: 740px; | |||
} | |||
.TE338 { | |||
top: 620px; | |||
left: 840px; | |||
left: 860px; | |||
} | |||
.TE340 { | |||
top: 620px; | |||
left: 965px; | |||
left: 1000px; | |||
} | |||
.TE342 { | |||
top: 620px; | |||
left: 1090px; | |||
left: 1120px; | |||
} | |||
.TE344 { | |||
top: 620px; | |||
left: 1215px; | |||
left: 1245px; | |||
} | |||
.TE346 { | |||
top: 620px; | |||
left: 1340px; | |||
left: 1370px; | |||
} | |||
.TE348 { | |||
top: 620px; | |||
left: 1460px; | |||
left: 1490px; | |||
} | |||
/** center middle **/ | |||
@@ -7,7 +7,7 @@ import ReactECharts from 'echarts-for-react'; | |||
const EnergyCostChart = (props) => { | |||
const options = { | |||
color: ['#FFD160', '#12FFF5', '#2760FF'], | |||
grid: { top: 32, right: 12, bottom: 20, left: 48 }, | |||
grid: { top: 32, right: 12, bottom: 56, left: 48 }, | |||
xAxis: { | |||
type: 'category', | |||
data: Array(7) | |||
@@ -11,7 +11,7 @@ function FeederStatus(props) { | |||
style={{ | |||
position: "absolute", | |||
bottom: "128px", | |||
left: "800px", | |||
left: "740px", | |||
width: "300px", | |||
height: "80px", | |||
zIndex: "-1", | |||
@@ -51,7 +51,7 @@ function getOptions(series, isra, currentStatistic) { | |||
color: "#DFF1FE", | |||
fontSize: 12, | |||
}, | |||
data: isra.checkTypeList, | |||
data: isra.checkType, | |||
}, | |||
xAxis: { | |||
type: "category", | |||
@@ -115,7 +115,7 @@ function FaultTotal(props) { | |||
? isra.yearStatistic | |||
: []; | |||
const series = preHandleStatisticData(currentStatistic, isra.checkTypeList); | |||
const series = preHandleStatisticData(currentStatistic, isra.checkType); | |||
const options = getOptions(series, isra, currentStatistic); | |||
function handleDateChange(v) { | |||
@@ -1,77 +1,22 @@ | |||
import cls from "./index.module.css"; | |||
import GraphBase from "../GraphBase"; | |||
import ReactECharts from "echarts-for-react"; | |||
import { useSelector, useDispatch } from "react-redux"; | |||
import { useSelector } from "react-redux"; | |||
import { useEffect, useState } from "react"; | |||
function getOptions(series) { | |||
return { | |||
color: ["#2760FF", "#8167F6", "#5B9BFF", "#99D66C", "#FFD160", "#FF8A40"], | |||
grid: { | |||
left: 24, | |||
top: 10, | |||
bottom: 10, | |||
right: 24, | |||
}, | |||
legend: { | |||
icon: "circle", | |||
top: 32, | |||
right: 0, | |||
bottom: 32, | |||
width: 296, | |||
height: 130, | |||
itemGap: 30, | |||
formatter: function (name) { | |||
return `${name} {sub|${ | |||
series[0].data.find((o) => o.name == name).value | |||
}}`; | |||
}, | |||
textStyle: { | |||
color: "#DFF1FE", | |||
fontSize: 18, | |||
rich: { | |||
sub: { | |||
color: "#fff9", | |||
fontSize: 18, | |||
}, | |||
}, | |||
}, | |||
}, | |||
series, | |||
}; | |||
} | |||
function getSeries(currentStatistic, currentLine) { | |||
const currentItem = currentStatistic.find((item) => item.name == currentLine); | |||
return [ | |||
{ | |||
type: "pie", | |||
center: ["26%", "54%"], | |||
radius: ["55%", "75%"], | |||
avoidLabelOverlap: false, | |||
label: { | |||
show: true, | |||
formatter: "{d}%", | |||
fontSize: 14, | |||
color: "inherit", | |||
}, | |||
labelLine: { | |||
length: 0, | |||
}, | |||
data: currentItem.data.map((item) => ({ | |||
value: item.checkNum, | |||
name: item.checkType, | |||
})), | |||
}, | |||
]; | |||
} | |||
import { randomInt } from "../../../utils"; | |||
function FaultType(props) { | |||
const [init, setInit] = useState(true); | |||
const [currentLine, setCurrentLine] = useState(""); | |||
const isra = useSelector((state) => state.isra); | |||
const currentStatistic = isra.dayStatistic || []; | |||
const currentLineStatistic = | |||
currentLine != "" | |||
? currentStatistic.find((item) => item.name === currentLine)?.data || [] | |||
: []; | |||
const lines = currentStatistic.map((item) => item.name); | |||
const CHART_TYPE = "line"; // "pie" | "line"; | |||
useEffect(() => { | |||
if (init == false) return; | |||
if (lines.length) { | |||
@@ -82,7 +27,12 @@ function FaultType(props) { | |||
const options = init | |||
? {} | |||
: getOptions(getSeries(currentStatistic, currentLine)); | |||
: getOptions( | |||
CHART_TYPE == "pie" | |||
? getSeries(currentStatistic, currentLine) | |||
: currentLineStatistic, | |||
CHART_TYPE | |||
); | |||
function handleLineChange(line) { | |||
setCurrentLine(line); | |||
@@ -124,3 +74,149 @@ function FaultType(props) { | |||
} | |||
export default FaultType; | |||
function getOptions(data, chart_type) { | |||
const color = [ | |||
"#2760FF", | |||
"#8167F6", | |||
"#5B9BFF", | |||
"#99D66C", | |||
"#FFD160", | |||
"#FF8A40", | |||
]; | |||
const grid = { | |||
left: 24, | |||
top: 10, | |||
bottom: 10, | |||
right: 24, | |||
}; | |||
const legend_common = { | |||
icon: "circle", | |||
top: 32, | |||
right: 0, | |||
bottom: 32, | |||
width: 296, | |||
height: 130, | |||
itemGap: 30, | |||
textStyle: { | |||
color: "#DFF1FE", | |||
fontSize: 18, | |||
rich: { | |||
sub: { | |||
color: "#fff9", | |||
fontSize: 18, | |||
}, | |||
}, | |||
}, | |||
}; | |||
if (chart_type == "pie") { | |||
return { | |||
color, | |||
grid, | |||
legend: { | |||
...legend_common, | |||
formatter: function (name) { | |||
return `${name} {sub|${ | |||
data[0].data.find((o) => o.name == name).value | |||
}}`; | |||
}, | |||
}, | |||
series: data, | |||
}; | |||
} else if (chart_type == "line") { | |||
const dataList = data.map((item) => ({ | |||
category: item.checkType, | |||
value: item.checkNum, | |||
})); | |||
return { | |||
grid: { | |||
top: 48, | |||
left: 48, | |||
bottom: 40, | |||
right: 18, | |||
}, | |||
legend: { | |||
...legend_common, | |||
}, | |||
tooltip: { | |||
trigger: "item", | |||
}, | |||
xAxis: { | |||
type: "category", | |||
data: (dataList || []).map((item) => item.category), | |||
axisLabel: { | |||
color: "#fff", | |||
fontSize: 12, | |||
rotate: 24, | |||
}, | |||
axisTick: { show: false }, | |||
axisLine: { | |||
lineStyle: { | |||
width: 1, | |||
color: "#213259", | |||
}, | |||
}, | |||
}, | |||
yAxis: { | |||
name: "单位/个", | |||
nameTextStyle: { | |||
color: "#fff", | |||
fontSize: 10, | |||
align: "right", | |||
}, | |||
type: "value", | |||
axisLabel: { | |||
color: "#fff", | |||
fontSize: 12, | |||
formatter: "{value}", | |||
}, | |||
axisLine: { | |||
show: true, | |||
lineStyle: { | |||
color: "#213259", | |||
}, | |||
}, | |||
splitLine: { | |||
lineStyle: { | |||
color: "#213259a0", | |||
}, | |||
}, | |||
}, | |||
series: [ | |||
{ | |||
type: "bar", | |||
itemStyle: { | |||
color: color[randomInt(0, color.length - 1)], | |||
}, | |||
data: (dataList || []).map((item) => item.value), | |||
}, | |||
], | |||
}; | |||
} | |||
} | |||
function getSeries(currentStatistic, currentLine) { | |||
const currentItem = currentStatistic.find((item) => item.name == currentLine); | |||
return [ | |||
{ | |||
type: "pie", | |||
center: ["26%", "54%"], | |||
radius: ["55%", "75%"], | |||
avoidLabelOverlap: false, | |||
label: { | |||
show: true, | |||
formatter: "{d}%", | |||
fontSize: 14, | |||
color: "inherit", | |||
}, | |||
labelLine: { | |||
length: 0, | |||
}, | |||
data: currentItem.data.map((item) => ({ | |||
value: item.checkNum, | |||
name: item.checkType, | |||
})), | |||
}, | |||
]; | |||
} |
@@ -1,19 +1,19 @@ | |||
import cls from './good.module.scss'; | |||
import Container from '../../Container'; | |||
import TodayTableData from './components/TodayTableData'; | |||
import GoodRateChart from './components/GoodRateChart'; | |||
import TechSplitline from '../TechSplitline'; | |||
import cls from "./good.module.scss"; | |||
import Container from "../../Container"; | |||
import TodayTableData from "./components/TodayTableData"; | |||
import GoodRateChart from "./components/GoodRateChart"; | |||
import TechSplitline from "../TechSplitline"; | |||
const GoodProduction = () => { | |||
return ( | |||
<Container icon="good" title="本日生产良品率" className={cls.goodProd}> | |||
<div className={`${cls.goodProd__content} h-full`}> | |||
<TodayTableData /> | |||
<TechSplitline /> | |||
<GoodRateChart /> | |||
</div> | |||
</Container> | |||
); | |||
return ( | |||
<Container icon="good" title="本日生产良品率" className={cls.goodProd}> | |||
<div className={`${cls.goodProd__content} h-full`}> | |||
<TodayTableData /> | |||
<TechSplitline /> | |||
<GoodRateChart /> | |||
</div> | |||
</Container> | |||
); | |||
}; | |||
export default GoodProduction; |
@@ -1,154 +1,205 @@ | |||
import cls from './index.module.css'; | |||
import './overwrite.css'; // 覆写 antd 默认样式,全局 | |||
import ReactECharts from 'echarts-for-react'; | |||
import * as echarts from 'echarts'; | |||
import { Switch, Radio } from 'antd'; | |||
import { randomInt } from '../../../../../utils'; | |||
import cls from "./index.module.css"; | |||
import "./overwrite.css"; // 覆写 antd 默认样式,全局 | |||
import ReactECharts from "echarts-for-react"; | |||
import * as echarts from "echarts"; | |||
import { Switch, Radio } from "antd"; | |||
import { randomInt } from "../../../../../utils"; | |||
import { useEffect, useState } from "react"; | |||
import { useSelector } from "react-redux"; | |||
const GoodRateChart = (props) => { | |||
const options = { | |||
color: ['#FFD160', '#12FFF5', '#2760FF'], | |||
grid: { top: 28, right: 12, bottom: 32, left: 48 }, | |||
xAxis: { | |||
type: 'category', | |||
data: Array(7) | |||
.fill(1) | |||
.map((_, index) => { | |||
const today = new Date(); | |||
const dtimestamp = today - index * 24 * 60 * 60 * 1000; | |||
return `${new Date(dtimestamp).getMonth() + 1}.${new Date( | |||
dtimestamp, | |||
).getDate()}`; | |||
}) | |||
.reverse(), | |||
axisLabel: { | |||
color: '#fff', | |||
fontSize: 12, | |||
}, | |||
axisTick: { show: false }, | |||
axisLine: { | |||
lineStyle: { | |||
width: 1, | |||
color: '#213259', | |||
}, | |||
}, | |||
}, | |||
yAxis: { | |||
type: 'value', | |||
axisLabel: { | |||
color: '#fff', | |||
fontSize: 12, | |||
formatter: '{value} %', | |||
}, | |||
axisLine: { | |||
show: true, | |||
lineStyle: { | |||
color: '#213259', | |||
}, | |||
}, | |||
splitLine: { | |||
lineStyle: { | |||
color: '#213259a0', | |||
}, | |||
}, | |||
interval: 10, | |||
min: 0, | |||
max: 100, | |||
}, | |||
series: [ | |||
{ | |||
data: Array(7) | |||
.fill(1) | |||
.map((_) => { | |||
return randomInt(60, 100); | |||
}), | |||
type: 'line', | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: '#FFD16040' }, | |||
{ offset: 0.5, color: '#FFD16020' }, | |||
{ offset: 1, color: '#FFD16010' }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
{ | |||
data: Array(7) | |||
.fill(1) | |||
.map((_) => { | |||
return randomInt(60, 100); | |||
}), | |||
type: 'line', | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: '#12FFF540' }, | |||
{ offset: 0.5, color: '#12FFF520' }, | |||
{ offset: 1, color: '#12FFF510' }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
{ | |||
data: Array(7) | |||
.fill(1) | |||
.map((_) => { | |||
return randomInt(60, 100); | |||
}), | |||
type: 'line', | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: '#2760FF40' }, | |||
{ offset: 0.5, color: '#2760FF20' }, | |||
{ offset: 1, color: '#2760FF10' }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
], | |||
tooltip: { | |||
trigger: 'axis', | |||
}, | |||
}; | |||
// 是否展示班次数据 | |||
const [showMore, setShowMore] = useState(false); | |||
// 更新 key,用于刷新图表 | |||
const [updateKey, setUpdateKey] = useState(Date.now()); | |||
// 默认的日期类型 | |||
const [dateType, setDateType] = useState("day"); | |||
const cutting = useSelector((state) => state.cutting); | |||
function handleSwitchChange(val) { | |||
// val: boolean | |||
} | |||
console.log("cutting chart", dateType, cutting.chart[dateType]); | |||
return ( | |||
<div className={cls.GoodRateChart}> | |||
<div className={cls.titleBar}> | |||
<h2>生产良品率</h2> | |||
<Switch defaultChecked onChange={handleSwitchChange} /> | |||
<div className={cls.legend}> | |||
<span className="legend__title">班次详情</span> | |||
<ul className="legend__list"> | |||
<li>总量</li> | |||
<li>白班</li> | |||
<li>夜班</li> | |||
</ul> | |||
</div> | |||
<Radio.Group | |||
defaultValue="week" | |||
buttonStyle="solid" | |||
className={cls.radioGroup} | |||
> | |||
<Radio.Button value="day" className="radio-group__item"> | |||
日 | |||
</Radio.Button> | |||
<Radio.Button value="week" className="radio-group__item"> | |||
周 | |||
</Radio.Button> | |||
<Radio.Button value="month" className="radio-group__item"> | |||
月 | |||
</Radio.Button> | |||
<Radio.Button value="year" className="radio-group__item"> | |||
年 | |||
</Radio.Button> | |||
</Radio.Group> | |||
</div> | |||
<ReactECharts option={options} /> | |||
</div> | |||
); | |||
useEffect(() => { | |||
setUpdateKey(Date.now()); | |||
}, [showMore]); | |||
function handleSwitchChange(val) { | |||
// val: boolean | |||
setShowMore(val); | |||
} | |||
function handleDateChange({ target }) { | |||
// e: Event | |||
setDateType(target.value); | |||
} | |||
// 根据日期类型,数据列表,是否展示班次数据,生成对应的 options | |||
const options = getOptions(cutting.chart[dateType], showMore); | |||
return ( | |||
<div className={cls.GoodRateChart}> | |||
<div className={cls.titleBar}> | |||
<h2>生产良品率</h2> | |||
<Switch defaultChecked={showMore} onChange={handleSwitchChange} /> | |||
<div className={cls.legend}> | |||
<span className="legend__title">班次详情</span> | |||
<ul className="legend__list"> | |||
<li>总量</li> | |||
{showMore && ( | |||
<> | |||
<li>白班</li> | |||
<li>夜班</li> | |||
</> | |||
)} | |||
</ul> | |||
</div> | |||
<Radio.Group | |||
defaultValue="day" | |||
buttonStyle="solid" | |||
onChange={handleDateChange} | |||
className={cls.radioGroup} | |||
style={{ flex: 1, textAlign: "right" }} | |||
> | |||
<Radio.Button value="day" className="radio-group__item"> | |||
日 | |||
</Radio.Button> | |||
<Radio.Button value="week" className="radio-group__item"> | |||
周 | |||
</Radio.Button> | |||
<Radio.Button value="month" className="radio-group__item"> | |||
月 | |||
</Radio.Button> | |||
<Radio.Button value="year" className="radio-group__item"> | |||
年 | |||
</Radio.Button> | |||
</Radio.Group> | |||
</div> | |||
<ReactECharts key={updateKey} option={options} /> | |||
</div> | |||
); | |||
}; | |||
export default GoodRateChart; | |||
function getOptions(dataList, showMore) { | |||
console.log("showmore", showMore); | |||
const list = [...dataList].sort((a, b) => a.dataTime - b.dataTime); | |||
// data: Array(7) | |||
// .fill(1) | |||
// .map((_, index) => { | |||
// const today = new Date(); | |||
// const dtimestamp = today - index * 24 * 60 * 60 * 1000; | |||
// return `${new Date(dtimestamp).getMonth() + 1}.${new Date( | |||
// dtimestamp | |||
// ).getDate()}`; | |||
// }) | |||
// .reverse(), | |||
const color = ["#FFD160", "#12FFF5", "#2760FF"]; | |||
const grid = { top: 28, right: 12, bottom: 48, left: 48 }; | |||
const xAxis = { | |||
type: "category", | |||
data: list.map((item) => item.dataTime.split("T")[0]), | |||
axisLabel: { | |||
color: "#fff", | |||
fontSize: 12, | |||
rotate: 45, | |||
margin: 13, | |||
}, | |||
axisTick: { show: false }, | |||
axisLine: { | |||
lineStyle: { | |||
width: 1, | |||
color: "#213259", | |||
}, | |||
}, | |||
}; | |||
const yAxis = { | |||
type: "value", | |||
axisLabel: { | |||
color: "#fff", | |||
fontSize: 12, | |||
formatter: "{value} %", | |||
}, | |||
axisLine: { | |||
show: true, | |||
lineStyle: { | |||
color: "#213259", | |||
}, | |||
}, | |||
splitLine: { | |||
lineStyle: { | |||
color: "#213259a0", | |||
}, | |||
}, | |||
interval: 10, | |||
min: 0, | |||
max: 100, | |||
}; | |||
const seriesTeam = [ | |||
{ | |||
data: list.map((item) => item.day * 100), | |||
type: "line", | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: "#12FFF540" }, | |||
{ offset: 0.5, color: "#12FFF520" }, | |||
{ offset: 1, color: "#12FFF510" }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
{ | |||
data: list.map((item) => item.night * 100), | |||
type: "line", | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: "#2760FF40" }, | |||
{ offset: 0.5, color: "#2760FF20" }, | |||
{ offset: 1, color: "#2760FF10" }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
]; | |||
return { | |||
grid, | |||
color, | |||
xAxis, | |||
yAxis, | |||
tooltip: { | |||
trigger: "axis", | |||
formatter: "{b} {c}%", | |||
}, | |||
series: [ | |||
{ | |||
data: list.map((item) => item.sum * 100), | |||
type: "line", | |||
areaStyle: { | |||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
{ offset: 0, color: "#FFD16040" }, | |||
{ offset: 0.5, color: "#FFD16020" }, | |||
{ offset: 1, color: "#FFD16010" }, | |||
]), | |||
}, | |||
// smooth: true, | |||
}, | |||
...(showMore ? seriesTeam : []), | |||
], | |||
}; | |||
} | |||
// { | |||
// data: Array(7) | |||
// .fill(1) | |||
// .map((_) => { | |||
// return randomInt(60, 100); | |||
// }), | |||
// type: "line", | |||
// areaStyle: { | |||
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||
// { offset: 0, color: "#FFD16040" }, | |||
// { offset: 0.5, color: "#FFD16020" }, | |||
// { offset: 1, color: "#FFD16010" }, | |||
// ]), | |||
// }, | |||
// // smooth: true, | |||
// }, |
@@ -1,86 +1,87 @@ | |||
.GoodRateChart { | |||
height: 1px; | |||
flex: 1; | |||
padding-top: 8px; | |||
/* background: #ae27276a; */ | |||
height: 1px; | |||
flex: 1; | |||
padding-top: 8px; | |||
/* background: #ae27276a; */ | |||
} | |||
.GoodRateChart .titleBar { | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
color: white; | |||
display: flex; | |||
justify-content: flex-start; | |||
align-items: center; | |||
gap: 12px; | |||
color: white; | |||
} | |||
.GoodRateChart .titleBar h2 { | |||
margin: 0; | |||
font-size: 18px; | |||
line-height: 32px; | |||
letter-spacing: 1.2px; | |||
color: #52fff8; | |||
margin: 0; | |||
font-size: 18px; | |||
line-height: 32px; | |||
letter-spacing: 1.2px; | |||
color: #52fff8; | |||
} | |||
.GoodRateChart .titleBar .legend { | |||
display: flex; | |||
align-items: center; | |||
display: flex; | |||
align-items: center; | |||
} | |||
.GoodRateChart .titleBar .legend * { | |||
font-size: 14px; | |||
line-height: 14px; | |||
color: #dff1fe; | |||
font-size: 14px; | |||
line-height: 14px; | |||
color: #dff1fe; | |||
} | |||
.GoodRateChart .titleBar .legend ul { | |||
display: flex; | |||
margin: 0; | |||
margin-left: 8px; | |||
padding: 0; | |||
list-style: none; | |||
align-items: center; | |||
display: flex; | |||
margin: 0; | |||
margin-left: 8px; | |||
padding: 0; | |||
list-style: none; | |||
align-items: center; | |||
} | |||
.GoodRateChart .titleBar .legend ul li { | |||
position: relative; | |||
margin: 4px; | |||
padding-left: 16px; | |||
position: relative; | |||
margin: 4px; | |||
padding-left: 16px; | |||
} | |||
.GoodRateChart .titleBar .legend ul li::before { | |||
content: ''; | |||
position: absolute; | |||
left: 2px; | |||
top: 2px; | |||
display: inline-block; | |||
width: 12px; | |||
height: 12px; | |||
border-radius: 2px; | |||
content: ""; | |||
position: absolute; | |||
left: 2px; | |||
top: 2px; | |||
display: inline-block; | |||
width: 12px; | |||
height: 12px; | |||
border-radius: 2px; | |||
} | |||
.GoodRateChart .titleBar .legend ul li:first-child::before { | |||
background-color: #ffd160; | |||
background-color: #ffd160; | |||
} | |||
.GoodRateChart .titleBar .legend ul li:nth-child(2)::before { | |||
background-color: #12fff5; | |||
background-color: #12fff5; | |||
} | |||
.GoodRateChart .titleBar .legend ul li:nth-child(3)::before { | |||
background-color: #2760ff; | |||
background-color: #2760ff; | |||
} | |||
.radioGroup * { | |||
border: none !important; | |||
border-radius: 0 !important; | |||
border: none !important; | |||
border-radius: 0 !important; | |||
} | |||
.radioGroup *:focus-within { | |||
box-shadow: none !important; | |||
box-shadow: none !important; | |||
} | |||
.radioGroup *::before { | |||
width: 0 !important; | |||
width: 0 !important; | |||
} | |||
.radioGroup_button_wrapper { | |||
color: #fff !important; | |||
background: #03233c !important; | |||
color: #fff !important; | |||
background: #03233c !important; | |||
} | |||
.radioGroup_button_wrapper.ant-radio-button-wrapper-checked { | |||
background: #02457e !important; | |||
background: #02457e !important; | |||
} |
@@ -1,9 +1,16 @@ | |||
import { useState } from "react"; | |||
import cls from "./index.module.scss"; | |||
import { ScrollBoard } from "@jiaminghi/data-view-react"; | |||
import { useSelector } from "react-redux"; | |||
function getRate(decimal) { | |||
return (decimal.toFixed(2) * 100).toFixed(2) + "%"; | |||
} | |||
const TodayTableData = (props) => { | |||
const [config, setConfig] = useState({ | |||
const cutting = useSelector((state) => state.cutting); | |||
const config = { | |||
// headerBGC: 'rgba(4, 44, 76, 0.3)', | |||
headerBGC: "rgba(4, 44, 76, .8)", | |||
header: [ | |||
@@ -18,14 +25,21 @@ const TodayTableData = (props) => { | |||
columnWidth: [90], | |||
headerHeight: 40, | |||
hoverPause: false, | |||
data: [ | |||
["Y61", "37%", "62%", "97%", "7%"], | |||
["Y62", "95%", "10%", "99%", "3%"], | |||
["Y63", "68%", "1%", "92%", "4%"], | |||
["Y64", "94%", "21%", "97%", "2%"], | |||
["Y65", "99%", "30%", "95%", "5%"], | |||
], | |||
}); | |||
data: cutting.table.map((line) => [ | |||
line.lineName, | |||
getRate(line.first), | |||
getRate(line.second), | |||
getRate(line.product), | |||
getRate(line.waste), | |||
]), | |||
// data: [ | |||
// ["Y61", "37%", "62%", "97%", "7%"], | |||
// ["Y62", "95%", "10%", "99%", "3%"], | |||
// ["Y63", "68%", "1%", "92%", "4%"], | |||
// ["Y64", "94%", "21%", "97%", "2%"], | |||
// ["Y65", "99%", "30%", "95%", "5%"], | |||
// ], | |||
}; | |||
return ( | |||
<div className={cls.todayTableData}> | |||
<ScrollBoard config={config} style={{ width: "100%" }} /> | |||
@@ -2,12 +2,13 @@ import { motion, AnimatePresence } from "framer-motion"; | |||
import { useRef, useEffect, useMemo, useCallback, useState } from "react"; | |||
import FeederStatus from "../../../../Common/Feeder"; | |||
import TemperatureBottom from "../../../../Common/TemperatureBottom"; | |||
import TemperatureTop from "../../../../Common/TemperatureTop"; | |||
import { useSelector, useDispatch } from "react-redux"; | |||
function EnterToFloorOne(props) { | |||
// const ctx = useContext(SocketContext); | |||
const ctx = null; | |||
const fireInfo = useSelector((state) => state.fireInfo); | |||
const fireDir = fireInfo?.fireDirection || null; | |||
const fireDir = ctx?.runState?.fireDirection || null; | |||
const [fireCanPlay, setFireCanPlay] = useState(false); | |||
const vd = useRef(null); | |||
const show = props.opacity || 0; | |||
@@ -69,10 +70,10 @@ function EnterToFloorOne(props) { | |||
></video> | |||
)} | |||
<TemperatureBottom | |||
<TemperatureTop | |||
style={{ | |||
top: "218px", | |||
left: "688px", | |||
left: "678px", | |||
width: "2380px", | |||
zIndex: 0, | |||
}} | |||
@@ -2,12 +2,13 @@ import { motion, AnimatePresence } from "framer-motion"; | |||
import { useRef, useEffect, useMemo, useState } from "react"; | |||
import FeederStatus from "../../../../Common/Feeder"; | |||
import TemperatureTop from "../../../../../components/Common/TemperatureTop"; | |||
import TemperatureBottom from "../../../../Common/TemperatureBottom"; | |||
import { useSelector, useDispatch } from "react-redux"; | |||
function FloorOneToTwo(props) { | |||
const ctx = null; | |||
const fireInfo = useSelector((state) => state.fireInfo); | |||
const fireDir = fireInfo?.fireDirection || null; | |||
const fireDir = ctx?.runState?.fireDirection || null; | |||
const [fireCanPlay, setFireCanPlay] = useState(false); | |||
const vd = useRef(null); | |||
@@ -72,7 +73,7 @@ function FloorOneToTwo(props) { | |||
></video> | |||
)} | |||
<TemperatureTop | |||
<TemperatureBottom | |||
style={{ | |||
top: "208px", | |||
left: "638px", | |||
@@ -2,11 +2,12 @@ import { motion, AnimatePresence } from "framer-motion"; | |||
import { useRef, useEffect, useMemo, useState } from "react"; | |||
import FeederStatus from "../../../../Common/Feeder"; | |||
import TemperatureBottom from "../../../../Common/TemperatureBottom"; | |||
import TemperatureTop from "../../../../Common/TemperatureTop"; | |||
import { useSelector, useDispatch } from "react-redux"; | |||
function FloorTwoToOne(props) { | |||
const ctx = null; | |||
const fireDir = ctx?.runState?.fireDirection || null; | |||
const fireInfo = useSelector((state) => state.fireInfo); | |||
const fireDir = fireInfo?.fireDirection || null; | |||
const [fireCanPlay, setFireCanPlay] = useState(false); | |||
const vd = useRef(null); | |||
@@ -72,15 +73,15 @@ function FloorTwoToOne(props) { | |||
></video> | |||
)} | |||
<TemperatureBottom | |||
<TemperatureTop | |||
style={{ | |||
top: "208px", | |||
left: "638px", | |||
top: "200px", | |||
left: "628px", | |||
width: "2380px", | |||
zIndex: 0, | |||
}} | |||
/> | |||
<FeederStatus /> | |||
<FeederStatus style={{ left: "680px" }} /> | |||
</motion.div> | |||
)} | |||
</AnimatePresence> | |||
@@ -40,7 +40,7 @@ export default function useSlider(defaultSize) { | |||
return () => { | |||
document.removeEventListener('keydown', fn); | |||
document.getElementById('slider').removeEventListener('mouseleave', fn2); | |||
document.getElementById('slider')?.removeEventListener('mouseleave', fn2); | |||
}; | |||
}, [value]); | |||
@@ -60,6 +60,8 @@ body { | |||
background: url(./assets/moxing.png) no-repeat; | |||
background-position: 50% 50%; | |||
background-size: 170% 200%; | |||
position: relative; | |||
z-index: -1; | |||
} | |||
#FullScreen .Main .Center .Button { | |||
@@ -49,7 +49,7 @@ export default function Home({ active }) { | |||
<CenterTopData /> | |||
</motion.div> | |||
</AnimatePresence> | |||
<div key="v3d" className="V3DBorder"></div> | |||
<div key="v3d" className="V3DBorder" style={{ zIndex: -2 }}></div> | |||
{fireDir && fireDir == "东火" && ( | |||
<video | |||
@@ -58,7 +58,12 @@ export default function Home({ active }) { | |||
autoPlay | |||
loop | |||
width={4200} | |||
style={{ position: "absolute", top: "-160px", left: "-910px" }} | |||
style={{ | |||
position: "absolute", | |||
top: "-160px", | |||
left: "-910px", | |||
zIndex: -1, | |||
}} | |||
></video> | |||
)} | |||
@@ -69,7 +74,12 @@ export default function Home({ active }) { | |||
autoPlay | |||
loop | |||
width={4200} | |||
style={{ position: "absolute", top: "-180px", left: "-910px" }} | |||
style={{ | |||
position: "absolute", | |||
top: "-180px", | |||
left: "-910px", | |||
zIndex: -1, | |||
}} | |||
></video> | |||
)} | |||
@@ -1,7 +1,7 @@ | |||
import { createSlice } from "@reduxjs/toolkit"; | |||
export const initialState = { | |||
checkTypeList: [], | |||
checkType: [], | |||
dayStatistic: [], | |||
monthStatistic: [], | |||
yearStatistic: [], | |||
@@ -12,8 +12,8 @@ const israSlice = createSlice({ | |||
name: "isra", | |||
initialState, | |||
reducers: { | |||
setCheckTypeList: (state, action) => { | |||
state.checkTypeList = action.payload; | |||
setCheckType: (state, action) => { | |||
state.checkType = action.payload; | |||
}, | |||
setDayStatistic: (state, action) => { | |||
state.dayStatistic = action.payload; | |||
@@ -32,7 +32,7 @@ const israSlice = createSlice({ | |||
export default israSlice.reducer; | |||
export const { | |||
setCheckTypeList, | |||
setCheckType, | |||
setDayStatistic, | |||
setWeekStatistic, | |||
setMonthStatistic, | |||
@@ -0,0 +1,41 @@ | |||
import { createSlice } from "@reduxjs/toolkit"; | |||
export const initialState = { | |||
table: [], | |||
chart: { | |||
year: [], | |||
week: [], | |||
month: [], | |||
day: [], | |||
}, | |||
}; | |||
const cuttingSlice = createSlice({ | |||
name: "cutting", | |||
initialState, | |||
reducers: { | |||
setCuttingTable: (state, action) => { | |||
console.log("setting cuttting table..."); | |||
state.table = action.payload; | |||
}, | |||
setCuttingChart: (state, action) => { | |||
switch (action.payload.dateType) { | |||
case "year": | |||
state.chart.year = action.payload.detData; | |||
break; | |||
case "weekly": | |||
state.chart.week = action.payload.detData; | |||
break; | |||
case "month": | |||
state.chart.month = action.payload.detData; | |||
break; | |||
case "day": | |||
state.chart.day = action.payload.detData; | |||
break; | |||
} | |||
}, | |||
}, | |||
}); | |||
export default cuttingSlice.reducer; | |||
export const { setCuttingTable, setCuttingChart } = cuttingSlice.actions; |
@@ -19,7 +19,7 @@ export const stateNameMap = { | |||
combustionAirPressure: "助燃风压力", | |||
topTemp: "碹顶加权温度", | |||
compressedAirPressure: "压缩气压力", | |||
meltTemp: "融化加权温度", | |||
meltTemp: "熔化加权温度", | |||
}; | |||
const kilnSlice = createSlice({ | |||
@@ -12,6 +12,7 @@ import energySlice from "./features/EnergySlice"; | |||
import israReducer from "./features/QualityIsraSlice"; | |||
import annealFanFrequenceReducer from "./features/annealFanFrequenceSlice"; | |||
import annealFanInfoReducer from "./features/annealFanInfoSlice"; | |||
import cuttingReducer from "./features/cuttingSlice"; | |||
export const store = configureStore({ | |||
reducer: { | |||
@@ -41,5 +42,7 @@ export const store = configureStore({ | |||
energy: energySlice, | |||
// 能耗 | |||
isra: israReducer, | |||
// 切割 | |||
cutting: cuttingReducer | |||
}, | |||
}); |
@@ -14,7 +14,7 @@ type ProductLineItem = { | |||
}; | |||
export type MessageItem = { | |||
checkTypeList: string[]; | |||
checkType: string[]; | |||
dayStatistic?: ProductLineItem[]; | |||
weekStatistic?: ProductLineItem[]; | |||
monthStatistic?: ProductLineItem[]; | |||
@@ -214,11 +214,15 @@ new XClient( | |||
} catch (error) { | |||
console.log("[*] websocket: [unable to serialize] ---> ", msg); | |||
} | |||
console.log("[ISRA DATA] ---> ", serializedData); | |||
if (serializedData == null) return; | |||
// 处理 checkTypeList | |||
store.dispatch({ | |||
type: "isra/setCheckTypeList", | |||
payload: serializedData.checkTypeList, | |||
type: "isra/setCheckType", | |||
payload: serializedData.checkType, | |||
}); | |||
// for (const checkType of serializedData.checkTypeList) { | |||
// store.dispatch({ | |||
@@ -251,3 +255,50 @@ new XClient( | |||
} | |||
} | |||
); | |||
type TableDataType = { | |||
name: "table"; | |||
type: "cutting"; | |||
data: any[]; | |||
}; | |||
type ChartDataType = { | |||
name: "chart"; | |||
type: "cutting"; | |||
nightPushData: any[]; | |||
dayPushData: any[]; | |||
allPushData: any[]; | |||
dateType: "day" | "week" | "month" | "year"; | |||
}; | |||
// 良品率相关数据 | |||
new XClient( | |||
// "ws://10.70.27.122:8080/websocket/message?userId=CUTTING", | |||
"ws://10.70.2.2:8080/websocket/message?userId=CUTTING", | |||
"CUTTING_DATA", | |||
(msg) => { | |||
let serializedData: TableDataType | ChartDataType | null = null; | |||
try { | |||
serializedData = JSON.parse(msg.data); | |||
} catch (error) { | |||
console.log("[*] websocket: [unable to serialize] ---> ", msg); | |||
} | |||
console.log("[CUTTING DATA] ---> ", serializedData); | |||
if (serializedData == null) return; | |||
switch (serializedData.name) { | |||
case "table": | |||
store.dispatch({ | |||
type: "cutting/setCuttingTable", | |||
payload: serializedData.data, | |||
}); | |||
break; | |||
case "chart": | |||
store.dispatch({ | |||
type: "cutting/setCuttingChart", | |||
payload: serializedData, | |||
}); | |||
break; | |||
} | |||
} | |||
); |