第一次提交
24
src/App.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.background {
|
||||
height: 1080px;
|
||||
width: 3840px;
|
||||
background: url(/public/image/background.png) 100% no-repeat;
|
||||
background-size: 100% 100%;
|
||||
position: relative;
|
||||
}
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.handan-chart-tooltip {
|
||||
background: #0a2b4f77 !important;
|
||||
border: none !important;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.handan-chart-tooltip * {
|
||||
color: #fff !important;
|
||||
}
|
||||
35
src/App.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import "./App.css";
|
||||
import { useAppSelector } from "./store/hooks";
|
||||
// import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import { createHashRouter, RouterProvider } from "react-router-dom";
|
||||
|
||||
import ErrorPage from "./page/ErrorPage";
|
||||
import { MyObservable } from "./context/MyObservable";
|
||||
import { Observable } from "@babylonjs/core";
|
||||
import { selectGlassStatus } from "./store/ProductionMonitoringEntity";
|
||||
import HomePage from "./page/HomePage";
|
||||
|
||||
const onGlassObservable = new Observable();
|
||||
|
||||
function App() {
|
||||
const thisLineGlassStatus = useAppSelector(selectGlassStatus);
|
||||
onGlassObservable.notifyObservers(thisLineGlassStatus);
|
||||
|
||||
const router = createHashRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <HomePage />,
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<MyObservable.Provider value={onGlassObservable}>
|
||||
<div className="background">
|
||||
<RouterProvider router={router} />
|
||||
</div>
|
||||
</MyObservable.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
BIN
src/assets/fonts/DINCondensed.ttf
Normal file
BIN
src/assets/image/chartA.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
src/assets/image/chartB.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
src/assets/image/eqInfoBg.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/image/eqInfoIcon.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/image/icon1.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/image/icon2.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/image/icon3.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/image/icon4.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/image/icon5.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/image/icon6.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/image/icon7.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/image/icon8.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
src/assets/image/t1.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/assets/image/t2.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/image/t3.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/image/t4.png
Normal file
|
After Width: | Height: | Size: 643 B |
BIN
src/assets/image/t5.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/assets/image/t6.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/image/t7.png
Normal file
|
After Width: | Height: | Size: 920 B |
BIN
src/assets/image/t8.png
Normal file
|
After Width: | Height: | Size: 899 B |
277
src/babylonjs/MybabylonJS.tsx
Normal file
@@ -0,0 +1,277 @@
|
||||
import React, { useEffect, useRef, useState, useContext, useMemo } from "react";
|
||||
import * as BABYLON from "@babylonjs/core";
|
||||
import "@babylonjs/core/Debug/debugLayer";
|
||||
import "@babylonjs/inspector";
|
||||
import "@babylonjs/loaders/glTF";
|
||||
import { GridMaterial } from "@babylonjs/materials/";
|
||||
import {
|
||||
Animatable,
|
||||
HemisphericLight,
|
||||
Mesh,
|
||||
Observable,
|
||||
Vector3,
|
||||
} from "@babylonjs/core";
|
||||
import { useAppSelector } from "../store/hooks";
|
||||
import { EquStatusInterface, selectEquStatus } from "../store/EquStatusEntity";
|
||||
import eqInfoIcon from "../assets/image/eqInfoIcon.png";
|
||||
import axios from "axios";
|
||||
|
||||
const onEquObservable = new Observable();
|
||||
|
||||
const myStyle = {
|
||||
width: "2635px",
|
||||
height: "536px",
|
||||
outline: "none",
|
||||
};
|
||||
interface EqSubListInterface {
|
||||
eqName: string;
|
||||
subList: string[];
|
||||
}
|
||||
function MybabylonJS() {
|
||||
const EquStatus = useAppSelector(selectEquStatus);
|
||||
const canvasRef = useRef(null);
|
||||
onEquObservable.notifyObservers(EquStatus);
|
||||
// const [selectedMeshName, setSelectedMeshName] = useState<string | null>(null);
|
||||
const [eqSubList, setEqSubList] = useState<EqSubListInterface>();
|
||||
|
||||
// 使用 useRef 来存储当前加载的模型引用
|
||||
const currentMeshesRef = useRef<Array<BABYLON.AbstractMesh>>([]);
|
||||
useEffect(() => {
|
||||
// 确保 canvas 引用存在
|
||||
if (!canvasRef.current) return;
|
||||
|
||||
const canvas = canvasRef.current;
|
||||
const engine = new BABYLON.Engine(canvas, true, {
|
||||
preserveDrawingBuffer: true,
|
||||
stencil: true,
|
||||
});
|
||||
|
||||
const createScene = async function () {
|
||||
// This creates a basic Babylon Scene object (non-mesh)
|
||||
const scene = new BABYLON.Scene(engine);
|
||||
scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
|
||||
|
||||
const baseLight = new HemisphericLight(
|
||||
"hemiLight",
|
||||
new Vector3(1, 1, 0),
|
||||
scene
|
||||
);
|
||||
baseLight.intensity = 0.7;
|
||||
// baseLight.diffuse = new BABYLON.Color3(1, 1, 1);
|
||||
// baseLight.specular = new BABYLON.Color3(0.25, 0.25, 0.25);
|
||||
// baseLight.groundColor = new BABYLON.Color3(0.5, 0.5, 0.5);
|
||||
|
||||
//add an arcRotateCamera to the scene
|
||||
const camera = new BABYLON.ArcRotateCamera(
|
||||
"camera",
|
||||
-Math.PI / 2,
|
||||
Math.PI / 2.9,
|
||||
120,
|
||||
new BABYLON.Vector3(0, 10, 0)
|
||||
);
|
||||
// console.log("camera", camera);
|
||||
camera.lowerRadiusLimit = 10;
|
||||
camera.upperRadiusLimit = 600;
|
||||
camera.fov = 0.4;
|
||||
|
||||
// This attaches the camera to the canvas
|
||||
camera.attachControl(canvas, true);
|
||||
|
||||
//创建一个材质
|
||||
const newMt = new BABYLON.StandardMaterial("newMt");
|
||||
newMt.diffuseColor = BABYLON.Color3.Blue();
|
||||
|
||||
const ground = BABYLON.MeshBuilder.CreateGround(
|
||||
"ground",
|
||||
{
|
||||
width: 1000,
|
||||
height: 1000,
|
||||
subdivisions: 1,
|
||||
},
|
||||
scene
|
||||
);
|
||||
|
||||
ground.scaling.x = 100;
|
||||
ground.scaling.z = ground.scaling.x;
|
||||
ground.isPickable = false;
|
||||
|
||||
let grid = new GridMaterial("grid", scene);
|
||||
|
||||
grid.majorUnitFrequency = 10;
|
||||
grid.minorUnitVisibility = 0.3;
|
||||
grid.gridRatio = 0.04;
|
||||
grid.backFaceCulling = !1;
|
||||
grid.mainColor = new BABYLON.Color3(1, 1, 1);
|
||||
grid.lineColor = new BABYLON.Color3(1, 1, 1);
|
||||
grid.opacity = 0;
|
||||
grid.zOffset = 1;
|
||||
// grid.opacityTexture = new BABYLON.Texture(
|
||||
// "/public/png/backgroundGround.png",
|
||||
// scene
|
||||
// );
|
||||
ground.material = grid;
|
||||
|
||||
let hl = new BABYLON.HighlightLayer("hl1", scene);
|
||||
let hl2 = new BABYLON.HighlightLayer("hl2", scene);
|
||||
|
||||
// 定义一个函数来加载或重新加载模型
|
||||
const loadOrReloadModel = async () => {
|
||||
// 在加载新模型之前卸载已加载的模型
|
||||
currentMeshesRef.current.forEach((mesh) => {
|
||||
if (mesh && mesh.parent) {
|
||||
scene.removeMesh(mesh, true);
|
||||
}
|
||||
});
|
||||
currentMeshesRef.current = []; // 重置模型数组
|
||||
try {
|
||||
// 使用 ImportMeshAsync 加载新模型
|
||||
var LOD0MESH = await BABYLON.SceneLoader.ImportMeshAsync(
|
||||
"",
|
||||
"/Line/",
|
||||
"line.babylon",
|
||||
scene
|
||||
);
|
||||
// 将新加载的模型添加到 currentMeshesRef 中
|
||||
currentMeshesRef.current.push(...LOD0MESH.meshes);
|
||||
|
||||
// ...为新加载的模型设置交互逻辑
|
||||
|
||||
LOD0MESH.meshes.map((mesh) => {
|
||||
mesh.isPickable = true;
|
||||
mesh.actionManager = new BABYLON.ActionManager(scene);
|
||||
//鼠标移动到物体上亮显
|
||||
mesh.actionManager.registerAction(
|
||||
new BABYLON.ExecuteCodeAction(
|
||||
BABYLON.ActionManager.OnPointerOverTrigger,
|
||||
() => {
|
||||
// @ts-ignore
|
||||
hl.addMesh(mesh, BABYLON.Color3.Green());
|
||||
}
|
||||
)
|
||||
);
|
||||
mesh.actionManager.registerAction(
|
||||
new BABYLON.ExecuteCodeAction(
|
||||
BABYLON.ActionManager.OnPointerOutTrigger,
|
||||
() => {
|
||||
// @ts-ignore
|
||||
hl.removeMesh(mesh);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// mesh._scene.onPointerDown = async (event, _pickResult) => {
|
||||
// const pickInfo = mesh._scene.pick(
|
||||
// mesh._scene.pointerX,
|
||||
// mesh._scene.pointerY
|
||||
// );
|
||||
|
||||
// const clickedPosition = _pickResult.pickedPoint;
|
||||
// //如果需要获取吗模型根节点,而不是模型中某个组件,请用一下方法
|
||||
// // getRootNode(pickInfo.pickedMesh as BABYLON.Node) 如上篇文章getRootNode函数
|
||||
// //判断是否是右键
|
||||
// if (!(event.buttons === 1 && pickInfo.pickedMesh)) return;
|
||||
// const MeshId = pickInfo.pickedMesh.metadata.tags;
|
||||
// if (MeshId) {
|
||||
// // setSelectedMeshName(pickInfo.pickedMesh.name);
|
||||
// // axios.get("/wsconfig.json").then((r) => {
|
||||
// // console.log(r.data.url)
|
||||
// axios
|
||||
// .post(
|
||||
// "api/visual/DataCenter/equipmentSubstrateList",
|
||||
// { id: MeshId }
|
||||
// )
|
||||
// .then((res) => {
|
||||
// let obj = { eqName: "-", subList: [] };
|
||||
// obj.eqName = res.data.data.eqName || "-";
|
||||
// obj.subList = res.data.data.subList || [];
|
||||
// setEqSubList(obj);
|
||||
// });
|
||||
// // });
|
||||
// }
|
||||
// };
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("加载模型失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 调用函数以加载或重新加载模型
|
||||
loadOrReloadModel();
|
||||
|
||||
function reset() {
|
||||
camera.target = new BABYLON.Vector3(0, 10, 0);
|
||||
camera.alpha = -Math.PI / 2;
|
||||
camera.beta = Math.PI / 2.9;
|
||||
camera.radius = 120;
|
||||
camera.fov = 0.4;
|
||||
}
|
||||
|
||||
let resetCamera = setTimeout(reset, 15000);
|
||||
scene.onPointerObservable.add((pointerInfo) => {
|
||||
switch (pointerInfo.type) {
|
||||
case BABYLON.PointerEventTypes.POINTERMOVE:
|
||||
clearTimeout(resetCamera);
|
||||
resetCamera = setTimeout(reset, 15000);
|
||||
}
|
||||
});
|
||||
return scene;
|
||||
};
|
||||
|
||||
// call the createScene function
|
||||
const scene = createScene();
|
||||
|
||||
scene.then((scene) => {});
|
||||
|
||||
// run the render loop
|
||||
scene.then(
|
||||
(scene) => {
|
||||
engine.runRenderLoop(function () {
|
||||
scene.render();
|
||||
});
|
||||
},
|
||||
(reason) => {
|
||||
console.log(reason);
|
||||
}
|
||||
);
|
||||
|
||||
// Resize
|
||||
window.addEventListener("resize", function () {
|
||||
engine.resize();
|
||||
});
|
||||
|
||||
// 组件卸载时的清理逻辑
|
||||
return () => {
|
||||
// 清理场景和引擎资源
|
||||
engine.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={myStyle}>
|
||||
{/* <h1 style={{ position: "absolute", top: "140px", left: "0px" }}>
|
||||
当前选中的设备是:{selectedMeshName}
|
||||
</h1> */}
|
||||
{/* <div className="eq_info_box">
|
||||
<div>
|
||||
<img src={eqInfoIcon} alt="" width={34} />
|
||||
<span className="title">设备名称:{eqSubList?.eqName || "-"}</span>
|
||||
</div>
|
||||
<div className="content">
|
||||
<span className="bg">{eqSubList?.subList[0] || "-"}</span>
|
||||
<span className="bg">{eqSubList?.subList[1] || "-"}</span>
|
||||
<span>{eqSubList?.subList[2] || "-"}</span>
|
||||
<span>{eqSubList?.subList[3] || "-"}</span>
|
||||
<span className="bg">{eqSubList?.subList[4] || "-"}</span>
|
||||
<span className="bg">{eqSubList?.subList[5] || "-"}</span>
|
||||
<span>{eqSubList?.subList[6] || "-"}</span>
|
||||
<span>{eqSubList?.subList[7] || "-"}</span>
|
||||
<span className="bg">{eqSubList?.subList[8] || "-"}</span>
|
||||
<span className="bg">{eqSubList?.subList[9] || "-"}</span>
|
||||
</div>
|
||||
</div> */}
|
||||
<canvas ref={canvasRef} style={myStyle} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MybabylonJS;
|
||||
5
src/context/MyObservable.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createContext } from 'react';
|
||||
import {Observable} from "@babylonjs/core";
|
||||
|
||||
const onGlassObservable = new Observable();
|
||||
export const MyObservable = createContext(onGlassObservable);
|
||||
4
src/context/ThisLineID.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import {createContext} from 'react';
|
||||
|
||||
let LineID: string | undefined;
|
||||
export const ThisLineID = createContext(LineID);
|
||||
22
src/index.css
Normal file
@@ -0,0 +1,22 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
|
||||
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
.error-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
27
src/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
|
||||
import { store } from "./store/store";
|
||||
import { Provider } from "react-redux";
|
||||
import UpdateData from "./store/UpdateData";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById("root") as HTMLElement
|
||||
);
|
||||
|
||||
root.render(
|
||||
// <React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
<UpdateData />
|
||||
</Provider>
|
||||
// </React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
54
src/locales/en-US.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"ProductLine": "Line",
|
||||
"CLICK": "Click",
|
||||
"TITLE": "Digital Factory Production Monitor",
|
||||
"alarmInfo": "Abnormal Alarm Info",
|
||||
"alarmsNumber": "Number of Alarms",
|
||||
"serialNo": "No.",
|
||||
"alarmTime": "Time",
|
||||
"alarmCode": "Code",
|
||||
"alarmContent": "Content",
|
||||
"eachLineInputAndOutput": "Input And Output Line Chart",
|
||||
"ThisDay": "This Day",
|
||||
"ThisWeek": "This Week",
|
||||
"ThisMonth": "This Month",
|
||||
"ThisDayShort": "Day",
|
||||
"ThisWeekShort": "Week",
|
||||
"ThisMonthShort": "Month",
|
||||
"All": "All",
|
||||
"YieldLineChart": "Yield Line Chart",
|
||||
"ProductionLine": "Line",
|
||||
"Output": "Output",
|
||||
"InputAndOutputSummaryTable": "Input And Output Summary Table",
|
||||
"InputAndOutputTable": "Input And Output Table",
|
||||
"ProductionLineName": "Name",
|
||||
"InputNum": "InputNum",
|
||||
"OutputNum": "OutputNum",
|
||||
"OutputArea": "OutputArea",
|
||||
"PassRate": "PassRate",
|
||||
"TITLE_E": "Digital Factory Equipment Monitor",
|
||||
"AbnormalEquipmentAlarm": "Abnormal Equipment Alarm",
|
||||
"EquipmentOperationMonitoring": "Equipment Operation Monitoring",
|
||||
"EquipmentTurnover": "Equipment Turnover(Weekly)",
|
||||
"EquipmentProcessingQuantity": "Equipment Processing Quantity",
|
||||
"TITLE_Q": "Digital Factory Quality Monitor",
|
||||
"EquipmentName": "Name",
|
||||
"AlarmLevel": "Level",
|
||||
"WorkRate": "WorkRate",
|
||||
"StopRate": "StopRate",
|
||||
"DownRate": "DownRate",
|
||||
"SectionName": "Section",
|
||||
"DefectSummary": "Defects Summary",
|
||||
"LineDefectSummary": "Line Defects Summary",
|
||||
"DefectType": "Defect Type",
|
||||
"DefectNumber": "Defect Number",
|
||||
"DefectSummaryLine1": "Line 1 Defects Summary",
|
||||
"DefectSummaryLine2": "Line 2 Defects Summary",
|
||||
"DefectSummaryLine3": "Line 3 Defects Summary",
|
||||
"DefectSummaryLine4": "Line 4 Defects Summary",
|
||||
"AutoSwitch": "ATS",
|
||||
"Part1": "Part1",
|
||||
"Part2": "Part2",
|
||||
"Part3": "Part3",
|
||||
"Part4": "Part4"
|
||||
}
|
||||
8
src/locales/locales.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import en_US from './en-US.json'
|
||||
import zh_CN from './zh-CN.json'
|
||||
|
||||
const locales = {
|
||||
'en-US': en_US,
|
||||
'zh-CN': zh_CN,
|
||||
};
|
||||
export default locales;
|
||||
54
src/locales/zh-CN.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"ProductLine": "产线",
|
||||
"CLICK": "点击",
|
||||
"TITLE": "数智工厂生产监控驾驶舱",
|
||||
"alarmInfo": "成产异常报警",
|
||||
"alarmsNumber": "报警总数",
|
||||
"serialNo": "序号",
|
||||
"alarmTime": "报警时间",
|
||||
"alarmCode": "报警编码",
|
||||
"alarmContent": "报警内容",
|
||||
"eachLineInputAndOutput": "各产线投入数量和产出数量",
|
||||
"ThisDay": "当天",
|
||||
"ThisWeek": "本周",
|
||||
"ThisMonth": "本月",
|
||||
"ThisDayShort": "当天",
|
||||
"ThisWeekShort": "本周",
|
||||
"ThisMonthShort": "本月",
|
||||
"All": "全部",
|
||||
"YieldLineChart": "成品率折线展示",
|
||||
"ProductionLine": "产线",
|
||||
"Output": "产出量",
|
||||
"InputAndOutputSummaryTable": "每产线总投入数量和产出数量",
|
||||
"InputAndOutputTable": "各产线投入数量和产出数量",
|
||||
"ProductionLineName": "产线名",
|
||||
"InputNum": "上片数据量",
|
||||
"OutputNum": "下片数据量",
|
||||
"OutputArea": "成品下片总面积",
|
||||
"PassRate": "合格率",
|
||||
"TITLE_E": "数智工厂设备运行智能驾驶舱",
|
||||
"AbnormalEquipmentAlarm": "设备报警异常",
|
||||
"EquipmentOperationMonitoring": "设备运行监控",
|
||||
"EquipmentTurnover": "设备稼动率(周)",
|
||||
"EquipmentProcessingQuantity": "设备加工数量",
|
||||
"TITLE_Q": "数智工厂质量管理驾驶舱",
|
||||
"EquipmentName": "设备名称",
|
||||
"AlarmLevel": "报警级别",
|
||||
"WorkRate": "工作比率",
|
||||
"StopRate": "停机比率",
|
||||
"DownRate": "故障比率",
|
||||
"SectionName": "工段",
|
||||
"DefectSummary": "缺陷汇总",
|
||||
"LineDefectSummary": "产线缺陷汇总",
|
||||
"DefectType": "缺陷种类",
|
||||
"DefectNumber": "缺陷数量",
|
||||
"DefectSummaryLine1": "产线一缺陷汇总",
|
||||
"DefectSummaryLine2": "产线二缺陷汇总",
|
||||
"DefectSummaryLine3": "产线三缺陷汇总",
|
||||
"DefectSummaryLine4": "产线四缺陷汇总",
|
||||
"AutoSwitch": "自动",
|
||||
"Part1": "第一部分",
|
||||
"Part2": "第二部分",
|
||||
"Part3": "第三部分",
|
||||
"Part4": "第四部分"
|
||||
}
|
||||
1
src/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
45
src/page/Component/ScrollBoard/index.css
Normal file
@@ -0,0 +1,45 @@
|
||||
.dv-scroll-board {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
}
|
||||
.dv-scroll-board .text {
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.dv-scroll-board .header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: 15px;
|
||||
}
|
||||
.dv-scroll-board .header .header-item {
|
||||
transition: all 0.3s;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.dv-scroll-board .rows {
|
||||
overflow: hidden;
|
||||
}
|
||||
.dv-scroll-board .rows .ceil {
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.dv-scroll-board .rows .row-item {
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.dv-scroll-board .rows .row-item .index {
|
||||
border-radius: 3px;
|
||||
padding: 0px 3px;
|
||||
}
|
||||
440
src/page/Component/ScrollBoard/index.tsx
Normal file
@@ -0,0 +1,440 @@
|
||||
import React, { useEffect, useState, useRef, useMemo, forwardRef } from "react";
|
||||
import useAutoResize from "./use/autoResize";
|
||||
import { deepMerge } from "./util";
|
||||
import { deepClone } from "./util/utils";
|
||||
import { co } from "./util";
|
||||
import classnames from "classnames";
|
||||
import "./index.css";
|
||||
import { current } from "@reduxjs/toolkit";
|
||||
interface ScrollBoardProps {
|
||||
config?: object;
|
||||
onClick?: () => void;
|
||||
onMouseOver?: () => void;
|
||||
className?: string;
|
||||
style?: object;
|
||||
}
|
||||
interface TaskType {
|
||||
end: () => void;
|
||||
pause: () => void;
|
||||
resume: () => void;
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
/**
|
||||
* @description Board header
|
||||
* @type {Array<String>}
|
||||
* @default header = []
|
||||
* @example header = ['column1', 'column2', 'column3']
|
||||
*/
|
||||
header: [],
|
||||
/**
|
||||
* @description Board data
|
||||
* @type {Array<Array>}
|
||||
* @default data = []
|
||||
*/
|
||||
data: [],
|
||||
/**
|
||||
* @description Row num
|
||||
* @type {Number}
|
||||
* @default rowNum = 5
|
||||
*/
|
||||
rowNum: 5,
|
||||
/**
|
||||
* @description Header background color
|
||||
* @type {String}
|
||||
* @default headerBGC = '#00BAFF'
|
||||
*/
|
||||
headerBGC: "#00BAFF",
|
||||
/**
|
||||
* @description Odd row background color
|
||||
* @type {String}
|
||||
* @default oddRowBGC = '#003B51'
|
||||
*/
|
||||
oddRowBGC: "#003B51",
|
||||
/**
|
||||
* @description Even row background color
|
||||
* @type {String}
|
||||
* @default evenRowBGC = '#003B51'
|
||||
*/
|
||||
evenRowBGC: "#0A2732",
|
||||
/**
|
||||
* @description Scroll wait time
|
||||
* @type {Number}
|
||||
* @default waitTime = 2000
|
||||
*/
|
||||
waitTime: 2000,
|
||||
/**
|
||||
* @description Header height
|
||||
* @type {Number}
|
||||
* @default headerHeight = 35
|
||||
*/
|
||||
headerHeight: 35,
|
||||
/**
|
||||
* @description Column width
|
||||
* @type {Array<Number>}
|
||||
* @default columnWidth = []
|
||||
*/
|
||||
columnWidth: [],
|
||||
/**
|
||||
* @description Column align
|
||||
* @type {Array<String>}
|
||||
* @default align = []
|
||||
* @example align = ['left', 'center', 'right']
|
||||
*/
|
||||
align: [],
|
||||
/**
|
||||
* @description Show index
|
||||
* @type {Boolean}
|
||||
* @default index = false
|
||||
*/
|
||||
index: false,
|
||||
/**
|
||||
* @description index Header
|
||||
* @type {String}
|
||||
* @default indexHeader = '#'
|
||||
*/
|
||||
indexHeader: "#",
|
||||
/**
|
||||
* @description Carousel type
|
||||
* @type {String}
|
||||
* @default carousel = 'single'
|
||||
* @example carousel = 'single' | 'page'
|
||||
*/
|
||||
carousel: "single",
|
||||
/**
|
||||
* @description Pause scroll when mouse hovered
|
||||
* @type {Boolean}
|
||||
* @default hoverPause = true
|
||||
* @example hoverPause = true | false
|
||||
*/
|
||||
hoverPause: true,
|
||||
};
|
||||
function calcHeaderData({ header, index, indexHeader }: any) {
|
||||
if (!header.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
header = [...header];
|
||||
|
||||
if (index) header.unshift(indexHeader);
|
||||
|
||||
return header;
|
||||
}
|
||||
function calcRows({ data, index, headerBGC, rowNum }: any) {
|
||||
if (index) {
|
||||
data = data.map((row: any, i: any) => {
|
||||
row = [...row];
|
||||
|
||||
const indexTag = `<span class="index" style="background-color: ${headerBGC};">${
|
||||
i + 1
|
||||
}</span>`;
|
||||
|
||||
row.unshift(indexTag);
|
||||
|
||||
return row;
|
||||
});
|
||||
}
|
||||
|
||||
data = data.map((ceils: any, i: any) => ({ ceils, rowIndex: i }));
|
||||
|
||||
const rowLength = data.length;
|
||||
|
||||
if (rowLength > rowNum && rowLength < 2 * rowNum) {
|
||||
data = [...data, ...data];
|
||||
}
|
||||
|
||||
return data.map((d: any, i: any) => ({ ...d, scroll: i }));
|
||||
}
|
||||
function calcAligns(mergedConfig: any, header: any) {
|
||||
const columnNum = header.length;
|
||||
|
||||
let aligns = new Array(columnNum).fill("left");
|
||||
|
||||
const { align } = mergedConfig;
|
||||
|
||||
return deepMerge(aligns, align);
|
||||
}
|
||||
const ScrollBoard = forwardRef(
|
||||
(
|
||||
{ config, onClick, onMouseOver, className, style }: ScrollBoardProps,
|
||||
ref
|
||||
) => {
|
||||
const { width, height, domRef } = useAutoResize(ref);
|
||||
const [state, setState] = useState({
|
||||
mergedConfig: {
|
||||
align: [],
|
||||
carousel: "",
|
||||
columnWidth: [],
|
||||
data: [],
|
||||
evenRowBGC: "",
|
||||
header: [],
|
||||
headerBGC: "",
|
||||
headerHeight: 35,
|
||||
hoverPause: true,
|
||||
index: false,
|
||||
oddRowBGC: "",
|
||||
indexHeader: "#",
|
||||
rowNum: 5,
|
||||
waitTime: 2000,
|
||||
},
|
||||
header: [],
|
||||
rows: [],
|
||||
widths: [],
|
||||
heights: [],
|
||||
aligns: [],
|
||||
});
|
||||
const { mergedConfig, header, rows, widths, heights, aligns } = state;
|
||||
const stateRef = useRef({
|
||||
...state,
|
||||
rowsData: [],
|
||||
avgHeight: 0,
|
||||
animationIndex: 0,
|
||||
});
|
||||
Object.assign(stateRef.current, state);
|
||||
function onResize() {
|
||||
if (!mergedConfig) return;
|
||||
|
||||
const widths = calcWidths(mergedConfig, stateRef.current.rowsData);
|
||||
|
||||
const heights = calcHeights(mergedConfig, header);
|
||||
|
||||
const data: any = { widths, heights };
|
||||
|
||||
Object.assign(stateRef.current, data);
|
||||
setState((state) => ({ ...state, ...data }));
|
||||
}
|
||||
function calcData() {
|
||||
const mergedConfig = deepMerge(
|
||||
// deepClone(defaultConfig, true),
|
||||
deepClone(defaultConfig),
|
||||
config || {}
|
||||
);
|
||||
|
||||
const header = calcHeaderData(mergedConfig);
|
||||
|
||||
const rows = calcRows(mergedConfig);
|
||||
|
||||
const widths = calcWidths(mergedConfig, stateRef.current.rowsData);
|
||||
|
||||
const heights = calcHeights(mergedConfig, header);
|
||||
|
||||
const aligns = calcAligns(mergedConfig, header);
|
||||
|
||||
const data: any = {
|
||||
mergedConfig,
|
||||
header,
|
||||
rows,
|
||||
widths,
|
||||
aligns,
|
||||
heights,
|
||||
};
|
||||
|
||||
Object.assign(stateRef.current, data, {
|
||||
rowsData: rows,
|
||||
animationIndex: 0,
|
||||
});
|
||||
|
||||
setState((state) => ({ ...state, ...data }));
|
||||
}
|
||||
|
||||
function calcWidths({ columnWidth, header }: any, rowsData: any) {
|
||||
const usedWidth = columnWidth.reduce((all: any, w: any) => all + w, 0);
|
||||
|
||||
let columnNum = 0;
|
||||
if (rowsData[0]) {
|
||||
columnNum = rowsData[0].ceils.length;
|
||||
} else if (header.length) {
|
||||
columnNum = header.length;
|
||||
}
|
||||
|
||||
const avgWidth = (width - usedWidth) / (columnNum - columnWidth.length);
|
||||
|
||||
const widths = new Array(columnNum).fill(avgWidth);
|
||||
|
||||
return deepMerge(widths, columnWidth);
|
||||
}
|
||||
function calcHeights({ headerHeight, rowNum, data }: any, header: any) {
|
||||
let allHeight = height;
|
||||
|
||||
if (header.length) allHeight -= headerHeight;
|
||||
|
||||
const avgHeight = allHeight / rowNum;
|
||||
|
||||
Object.assign(stateRef.current, { avgHeight });
|
||||
|
||||
return new Array(data.length).fill(avgHeight);
|
||||
}
|
||||
function* animation(
|
||||
start = false
|
||||
): Generator<Promise<void>, void, unknown> {
|
||||
let {
|
||||
avgHeight,
|
||||
animationIndex,
|
||||
mergedConfig: { waitTime, carousel, rowNum },
|
||||
rowsData,
|
||||
} = stateRef.current;
|
||||
const rowLength = rowsData.length;
|
||||
|
||||
if (start) yield new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||
|
||||
const animationNum = carousel === "single" ? 1 : rowNum;
|
||||
|
||||
let rows: any = rowsData.slice(animationIndex);
|
||||
rows.push(...rowsData.slice(0, animationIndex));
|
||||
rows = rows.slice(0, carousel === "page" ? rowNum * 2 : rowNum + 1);
|
||||
|
||||
const heights: any = new Array(rowLength).fill(avgHeight);
|
||||
setState((state) => ({ ...state, rows, heights }));
|
||||
|
||||
yield new Promise((resolve) => setTimeout(resolve, 300));
|
||||
|
||||
animationIndex += animationNum;
|
||||
|
||||
const back = animationIndex - rowLength;
|
||||
if (back >= 0) animationIndex = back;
|
||||
|
||||
const newHeights: any = [...heights];
|
||||
newHeights.splice(0, animationNum, ...new Array(animationNum).fill(0));
|
||||
|
||||
Object.assign(stateRef.current, { animationIndex });
|
||||
setState((state) => ({ ...state, heights: newHeights }));
|
||||
}
|
||||
function emitEvent(handle: any, ri: any, ci: any, row: any, ceil: any) {
|
||||
const { ceils, rowIndex } = row;
|
||||
|
||||
handle && handle({ row: ceils, ceil, rowIndex, columnIndex: ci });
|
||||
}
|
||||
|
||||
function handleHover(
|
||||
enter: any,
|
||||
ri?: any,
|
||||
ci?: any,
|
||||
row?: any,
|
||||
ceil?: any
|
||||
) {
|
||||
if (enter) emitEvent(onMouseOver, ri, ci, row, ceil);
|
||||
|
||||
if (!mergedConfig.hoverPause) return;
|
||||
|
||||
if (task.current) {
|
||||
const { pause, resume } = task.current;
|
||||
|
||||
enter
|
||||
? (function () {
|
||||
if (pause) pause();
|
||||
})()
|
||||
: (function () {
|
||||
if (resume) resume();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
const getBackgroundColor = (rowIndex: any) =>
|
||||
mergedConfig[rowIndex % 2 === 0 ? "evenRowBGC" : "oddRowBGC"];
|
||||
|
||||
const task = useRef<TaskType>(null);
|
||||
|
||||
useEffect(() => {
|
||||
calcData();
|
||||
|
||||
let start = true;
|
||||
|
||||
function* loop() {
|
||||
while (true) {
|
||||
yield* animation(start);
|
||||
|
||||
start = false;
|
||||
|
||||
const { waitTime } = stateRef.current.mergedConfig;
|
||||
|
||||
yield new Promise((resolve) => setTimeout(resolve, waitTime - 300));
|
||||
}
|
||||
}
|
||||
|
||||
const {
|
||||
mergedConfig: { rowNum },
|
||||
rows: rowsData,
|
||||
} = stateRef.current;
|
||||
|
||||
const rowLength = rowsData.length;
|
||||
if (rowNum >= rowLength) return;
|
||||
// @ts-ignore
|
||||
task.current = co(loop);
|
||||
if (task.current) {
|
||||
return task.current.end;
|
||||
}
|
||||
}, [config, domRef.current]);
|
||||
|
||||
useEffect(onResize, [width, height, domRef.current]);
|
||||
|
||||
const classNames = useMemo(
|
||||
() => classnames("dv-scroll-board", className),
|
||||
[className]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classNames} style={style} ref={domRef}>
|
||||
{!!header.length && !!mergedConfig && (
|
||||
<div
|
||||
className="header"
|
||||
style={{ backgroundColor: `${mergedConfig.headerBGC}` }}
|
||||
>
|
||||
{header.map((headerItem, i) => (
|
||||
<div
|
||||
className="header-item"
|
||||
key={`${headerItem}-${i}`}
|
||||
style={{
|
||||
height: `${mergedConfig.headerHeight}px`,
|
||||
lineHeight: `${mergedConfig.headerHeight}px`,
|
||||
width: `${widths[i]}px`,
|
||||
}}
|
||||
// @ts-ignore
|
||||
align={aligns[i]}
|
||||
dangerouslySetInnerHTML={{ __html: headerItem }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!!mergedConfig && (
|
||||
<div
|
||||
className="rows"
|
||||
style={{
|
||||
height: `${
|
||||
height - (header.length ? mergedConfig.headerHeight : 0)
|
||||
}px`,
|
||||
}}
|
||||
>
|
||||
{rows.map((row: any, ri) => (
|
||||
<div
|
||||
className="row-item"
|
||||
key={`${row.toString()}-${row.scroll}`}
|
||||
style={{
|
||||
height: `${heights[ri]}px`,
|
||||
lineHeight: `${heights[ri]}px`,
|
||||
backgroundColor: `${getBackgroundColor(row.rowIndex)}`,
|
||||
}}
|
||||
>
|
||||
{row.ceils.map((ceil: any, ci: any) => (
|
||||
<div
|
||||
className="ceil"
|
||||
key={`${ceil}-${ri}-${ci}`}
|
||||
style={{ width: `${widths[ci]}px` }}
|
||||
// @ts-ignore
|
||||
align={aligns[ci]}
|
||||
dangerouslySetInnerHTML={{ __html: ceil }}
|
||||
onClick={() => emitEvent(onClick, ri, ci, row, ceil)}
|
||||
onMouseEnter={() => handleHover(true, ri, ci, row, ceil)}
|
||||
onMouseLeave={() => handleHover(false)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ScrollBoard;
|
||||
57
src/page/Component/ScrollBoard/use/autoResize.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
useState,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { debounce, observerDomResize } from "../util/index";
|
||||
|
||||
export default function useAutoResize(ref: any) {
|
||||
const [state, setState] = useState({ width: 0, height: 0 });
|
||||
|
||||
const domRef = useRef(null);
|
||||
|
||||
const setWH = useCallback(() => {
|
||||
const { clientWidth, clientHeight } = domRef.current || {
|
||||
clientWidth: 0,
|
||||
clientHeight: 0,
|
||||
};
|
||||
|
||||
setState({ width: clientWidth, height: clientHeight });
|
||||
|
||||
if (!domRef.current) {
|
||||
console.warn(
|
||||
"DataV: Failed to get dom node, component rendering may be abnormal!"
|
||||
);
|
||||
} else if (!clientWidth || !clientHeight) {
|
||||
console.warn(
|
||||
"DataV: Component width or height is 0px, rendering abnormality may occur!"
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useImperativeHandle(ref, () => ({ setWH }), []);
|
||||
|
||||
useEffect(() => {
|
||||
const debounceSetWHFun = debounce(setWH, 100);
|
||||
|
||||
debounceSetWHFun();
|
||||
const domObserver = observerDomResize(domRef.current, debounceSetWHFun);
|
||||
|
||||
window.addEventListener("resize", debounceSetWHFun);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", debounceSetWHFun);
|
||||
|
||||
if (!domObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
domObserver.disconnect();
|
||||
domObserver.takeRecords();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { ...state, domRef, setWH };
|
||||
}
|
||||
57
src/page/Component/ScrollBoard/use/autoResize1.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
useState,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
import { debounce, observerDomResize } from "../util/index";
|
||||
|
||||
export default function useAutoResize(ref) {
|
||||
const [state, setState] = useState({ width: 0, height: 0 });
|
||||
|
||||
const domRef = useRef(null);
|
||||
|
||||
const setWH = useCallback(() => {
|
||||
const { clientWidth, clientHeight } = domRef.current || {
|
||||
clientWidth: 0,
|
||||
clientHeight: 0,
|
||||
};
|
||||
|
||||
setState({ width: clientWidth, height: clientHeight });
|
||||
|
||||
if (!domRef.current) {
|
||||
console.warn(
|
||||
"DataV: Failed to get dom node, component rendering may be abnormal!"
|
||||
);
|
||||
} else if (!clientWidth || !clientHeight) {
|
||||
console.warn(
|
||||
"DataV: Component width or height is 0px, rendering abnormality may occur!"
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useImperativeHandle(ref, () => ({ setWH }), []);
|
||||
|
||||
useEffect(() => {
|
||||
const debounceSetWHFun = debounce(setWH, 100);
|
||||
|
||||
debounceSetWHFun();
|
||||
const domObserver = observerDomResize(domRef.current, debounceSetWHFun);
|
||||
|
||||
window.addEventListener("resize", debounceSetWHFun);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", debounceSetWHFun);
|
||||
|
||||
if (!domObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
domObserver.disconnect();
|
||||
domObserver.takeRecords();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { ...state, domRef, setWH };
|
||||
}
|
||||
114
src/page/Component/ScrollBoard/util/index.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
export function co(gen: any) {
|
||||
let destroyed = false;
|
||||
|
||||
// 处理 return 之后 resume 的问题
|
||||
let stop = false;
|
||||
|
||||
let val: any = null;
|
||||
|
||||
if (typeof gen === "function") gen = gen();
|
||||
|
||||
if (!gen || typeof gen.next !== "function") return () => ({});
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
destroyed || next(gen.next());
|
||||
});
|
||||
|
||||
return {
|
||||
end() {
|
||||
destroyed = true;
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
gen.return();
|
||||
|
||||
gen = null;
|
||||
});
|
||||
},
|
||||
pause() {
|
||||
if (!destroyed) {
|
||||
stop = true;
|
||||
}
|
||||
},
|
||||
resume() {
|
||||
const oldVal = val;
|
||||
|
||||
if (!destroyed && stop) {
|
||||
stop = false;
|
||||
|
||||
Promise.resolve(val).then(function () {
|
||||
if (!destroyed && !stop && oldVal === val) {
|
||||
next(gen.next());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function next(ret: any) {
|
||||
if (ret.done) return ret.value;
|
||||
|
||||
val = ret.value;
|
||||
|
||||
return Promise.resolve(ret.value).then(() => {
|
||||
!destroyed && !stop && next(gen.next());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将函数转成防抖动函数
|
||||
* @param {Function} 需要转成防抖动函数的函数
|
||||
* @param {number} 延迟时间(毫秒数)
|
||||
* @param {boolean} 是否执行第一次
|
||||
* @return {undefined} 无返回值
|
||||
*/
|
||||
export function debounce(fn: any, delay = 600, runFirstFn = true) {
|
||||
let timer: any = null;
|
||||
|
||||
return function (this: any, ...rest: any) {
|
||||
// 清除定时器
|
||||
clearTimeout(timer);
|
||||
if (runFirstFn) {
|
||||
fn.apply(this, rest);
|
||||
runFirstFn = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置定时器
|
||||
timer = setTimeout(fn.bind(this, ...rest), delay);
|
||||
};
|
||||
}
|
||||
export function observerDomResize(dom: any, callback: any) {
|
||||
const MutationObserver = window.MutationObserver;
|
||||
// window.WebKitMutationObserver ||
|
||||
// window.MozMutationObserver;
|
||||
|
||||
const observer = new MutationObserver(callback);
|
||||
|
||||
observer.observe(dom, {
|
||||
attributes: true,
|
||||
attributeFilter: ["style"],
|
||||
attributeOldValue: true,
|
||||
});
|
||||
return observer;
|
||||
}
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
||||
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
||||
var _util = require("./../util/utils");
|
||||
export function deepMerge(target: any, merged: any) {
|
||||
for (var key in merged) {
|
||||
if (target[key] && _typeof2["default"](target[key]) === "object") {
|
||||
deepMerge(target[key], merged[key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_typeof2["default"](merged[key]) === "object") {
|
||||
target[key] = _util.deepClone(merged[key], true);
|
||||
continue;
|
||||
}
|
||||
|
||||
target[key] = merged[key];
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
32
src/page/Component/ScrollBoard/util/utils.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @description Clone an object or array
|
||||
* @param {Object|Array} object Cloned object
|
||||
* @param {Boolean} recursion Whether to use recursive cloning
|
||||
* @return {Object|Array} Clone object
|
||||
*/
|
||||
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
||||
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
||||
export function deepClone(object: any) {
|
||||
var recursion =
|
||||
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
if (!object) return object;
|
||||
var parse = JSON.parse,
|
||||
stringify = JSON.stringify;
|
||||
if (!recursion) return parse(stringify(object));
|
||||
var clonedObj: any = object instanceof Array ? [] : {};
|
||||
|
||||
if (object && _typeof2["default"](object) === "object") {
|
||||
for (var key in object) {
|
||||
if (object.hasOwnProperty(key)) {
|
||||
if (object[key] && _typeof2["default"](object[key]) === "object") {
|
||||
// clonedObj[key] = deepClone(object[key], true);
|
||||
clonedObj[key] = deepClone(object[key]);
|
||||
} else {
|
||||
clonedObj[key] = object[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clonedObj;
|
||||
}
|
||||
24
src/page/Component/TopTitle/index.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.top_block {
|
||||
width: 3840px;
|
||||
height: 123px;
|
||||
background-image: url(/public/image/topTitle.png);
|
||||
background-size:3840px;
|
||||
position: relative;
|
||||
font-weight: 500;
|
||||
font-size: 26px;
|
||||
color: #51f0ff;
|
||||
}
|
||||
/* .top_left__title {
|
||||
position: absolute;
|
||||
left: 2334px;
|
||||
top: 98px;
|
||||
} */
|
||||
.top_right__title {
|
||||
position: absolute;
|
||||
right: 955px;
|
||||
top: 69px;
|
||||
}
|
||||
.time {
|
||||
display: inline-block;
|
||||
margin-left: 45px;
|
||||
}
|
||||
30
src/page/Component/TopTitle/index.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import "./index.css";
|
||||
import moment from "moment";
|
||||
import "moment/locale/zh-cn";
|
||||
import { useState, useEffect } from "react";
|
||||
function TopTitle() {
|
||||
const [date, setDate] = useState<string>(moment().format("YYYY.MM.DD"));
|
||||
const [week, setWeek] = useState<string>(
|
||||
moment().locale("zh-cn").format("dddd")
|
||||
);
|
||||
const [time, setTime] = useState<string>(moment().format("HH:mm:ss"));
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setDate(moment().format("YYYY.MM.DD"));
|
||||
setWeek(moment().locale("zh-cn").format("dddd"));
|
||||
setTime(moment().format("HH:mm:ss"));
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
return (
|
||||
<div className="top_block">
|
||||
{/* <div className="top_left__title">设计单位:中建材智能自动化研究院</div> */}
|
||||
<div className="top_right__title">
|
||||
{date}
|
||||
{week} <span className="time">{time}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default TopTitle;
|
||||
12
src/page/ErrorPage.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import "./../index.css";
|
||||
|
||||
function ErrorPage() {
|
||||
return (
|
||||
<div className="error-page">
|
||||
<h1>Oops!</h1>
|
||||
<p>Sorry, an unexpected error has occurred.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorPage;
|
||||
23
src/page/HomePage/Center/Center.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import MybabylonJS from "../../../babylonjs/MybabylonJS";
|
||||
import Production from "./Production"
|
||||
import DefectClass from "./DefectClass"
|
||||
import Power from "./Power"
|
||||
import TempAndHumidity from "./TempAndHumidity"
|
||||
import Produce from "./Produce"
|
||||
function Center() {
|
||||
return (
|
||||
<div>
|
||||
<div className="center_up">
|
||||
<MybabylonJS />
|
||||
</div>
|
||||
<div className="center-down flex-row">
|
||||
<Production/>
|
||||
<DefectClass />
|
||||
<Power />
|
||||
<TempAndHumidity/>
|
||||
<Produce />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Center;
|
||||
155
src/page/HomePage/Center/DefectClass/chart.config.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
function getCoordinates(startArc: number, endArc: number) {
|
||||
const posi = [
|
||||
Math.sin(startArc),
|
||||
-Math.cos(startArc),
|
||||
Math.sin(endArc),
|
||||
-Math.cos(endArc),
|
||||
];
|
||||
const dx = posi[2] - posi[0];
|
||||
const dy = posi[3] - posi[1];
|
||||
|
||||
return getLocation(dx, dy);
|
||||
}
|
||||
function getLocation(dx: number, dy: number) {
|
||||
const tanV = dx / dy;
|
||||
const directSign = Math.abs(tanV) < 1;
|
||||
const t = directSign ? tanV : 1 / tanV;
|
||||
|
||||
const sign1 = t > 0 ? 1 : -1;
|
||||
const sign2 = dx > 0 ? 1 : -1;
|
||||
const sign = directSign ? sign1 * sign2 : sign2;
|
||||
|
||||
const group1 = [0.5 - (sign * t) / 2, 0.5 + (sign * t) / 2];
|
||||
const group2 = sign > 0 ? [0, 1] : [1, 0];
|
||||
const group = [...group1, ...group2];
|
||||
const keys = directSign ? ["x", "x2", "y", "y2"] : ["y", "y2", "x", "x2"];
|
||||
|
||||
let res: { [key: string]: any } = {};
|
||||
keys.forEach((k, idx) => {
|
||||
res[k] = group[idx];
|
||||
});
|
||||
return res;
|
||||
}
|
||||
let rangArrValue: any[] = [];
|
||||
let dataList: any = [];
|
||||
let totalValue = 0;
|
||||
const colors = [
|
||||
"rgb(39, 96, 255)",
|
||||
"rgb(91, 155, 255)",
|
||||
"rgb(255, 209, 96)",
|
||||
"rgb(129, 103, 246)",
|
||||
"rgb(153, 214, 108)",
|
||||
"rgb(255, 138, 64)",
|
||||
"rgb(18, 255, 245)",
|
||||
];
|
||||
const getPersonnelList = async (dataProps: any) => {
|
||||
totalValue = dataProps.reduce(
|
||||
(total: any, value: any) => total + value.value,
|
||||
0
|
||||
);
|
||||
let cacheNum = 0;
|
||||
for (let i = 0; i < dataProps.length; i++) {
|
||||
const endNum = cacheNum + dataProps[i].value;
|
||||
rangArrValue.push([cacheNum, endNum]);
|
||||
cacheNum = endNum;
|
||||
}
|
||||
const angleArr = rangArrValue.map((arr) =>
|
||||
arr.map((num: any) => (num / totalValue) * Math.PI * 2)
|
||||
);
|
||||
dataList = dataProps.map((item: any, index: any) => {
|
||||
const range = getCoordinates(angleArr[index][0], angleArr[index][1]);
|
||||
const startColor = colors[index];
|
||||
const color = {
|
||||
type: "linear",
|
||||
x: range.x,
|
||||
x2: range.x2,
|
||||
y: range.y,
|
||||
y2: range.y2,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: startColor, // 起始颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: `${startColor.substring(0, startColor.length - 1)}, 0)`, // 终点颜色
|
||||
},
|
||||
],
|
||||
global: false,
|
||||
};
|
||||
|
||||
return {
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
// itemStyle: {
|
||||
// color: color,
|
||||
// },
|
||||
};
|
||||
});
|
||||
};
|
||||
export default function getOptions(dataProps: any) {
|
||||
if (dataProps.length === 0) return null;
|
||||
getPersonnelList(dataProps);
|
||||
const colors = [
|
||||
"rgb(39, 96, 255)",
|
||||
"rgb(91, 155, 255)",
|
||||
"rgb(255, 209, 96)",
|
||||
"rgb(129, 103, 246)",
|
||||
"rgb(153, 214, 108)",
|
||||
"rgb(255, 138, 64)",
|
||||
"rgb(18, 255, 245)",
|
||||
];
|
||||
return {
|
||||
color: colors,
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
className: "handan-chart-tooltip",
|
||||
},
|
||||
graphic: [
|
||||
{
|
||||
type: "text",
|
||||
left: "center",
|
||||
top: "44%",
|
||||
style: {
|
||||
text: totalValue,
|
||||
fill: "#fff",
|
||||
width: 150,
|
||||
height: 48,
|
||||
fontSize: 31,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
left: "center",
|
||||
top: "60%",
|
||||
style: {
|
||||
text: "总数",
|
||||
fill: "rgba(255, 255, 255, 0.70)",
|
||||
width: 32,
|
||||
height: 16,
|
||||
fontSize: 16,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "产线缺陷分类",
|
||||
type: "pie",
|
||||
radius: ["60%", "80%"],
|
||||
center: ["50%", "50%"],
|
||||
label: {
|
||||
formatter: "{d}%",
|
||||
color: "#fff",
|
||||
// color: function (params: any) {
|
||||
// // 根据数据项的索引从颜色数组中选取颜色作为标签颜色
|
||||
// var colorIndex = params.dataIndex;
|
||||
// return colors[colorIndex];
|
||||
// },
|
||||
},
|
||||
data: dataList,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
75
src/page/HomePage/Center/DefectClass/index.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import ReactECharts from "echarts-for-react";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectDefectsClassDEFECT } from "../../../../store/HomePageSlice";
|
||||
import getOptions from "./chart.config";
|
||||
function DefectClass() {
|
||||
const data = useAppSelector(selectDefectsClassDEFECT);
|
||||
// console.log("33333333333333产线缺陷分类", data);
|
||||
const colors = [
|
||||
"rgb(39, 96, 255)",
|
||||
"rgb(91, 155, 255)",
|
||||
"rgb(255, 209, 96)",
|
||||
"rgb(129, 103, 246)",
|
||||
"rgb(153, 214, 108)",
|
||||
"rgb(255, 138, 64)",
|
||||
"rgb(18, 255, 245)",
|
||||
];
|
||||
let keys = [];
|
||||
let dataProps: any[] = [];
|
||||
if (Object.keys(data).length !== 0) {
|
||||
keys = Object.keys(data);
|
||||
keys.map((item: any, index) => {
|
||||
dataProps.push({ name: item, value: data[item], color: colors[index] });
|
||||
});
|
||||
}
|
||||
//@ts-ignore
|
||||
const options = getOptions(dataProps);
|
||||
return (
|
||||
<div className="left_right_up">
|
||||
<TitleBox title="left_right_up" />
|
||||
|
||||
{options && (
|
||||
<div style={{ width: "240px", height: "220px", marginTop: "10px" }}>
|
||||
{<ReactECharts option={options} style={{ height: "100%" }} />}
|
||||
</div>
|
||||
)}
|
||||
<div className="right_up_legend">
|
||||
{dataProps.map((item, index) => {
|
||||
return (
|
||||
<div className="item" key={index}>
|
||||
<span
|
||||
className="dot"
|
||||
style={{ backgroundColor: item.color }}
|
||||
></span>
|
||||
{item.name}
|
||||
<span
|
||||
style={{
|
||||
color: "rgba(255, 255, 255, 0.70)",
|
||||
display: "inline-block",
|
||||
marginLeft: "10px",
|
||||
}}
|
||||
>
|
||||
{item.value}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!options && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default DefectClass;
|
||||
120
src/page/HomePage/Center/Power/chart.config.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import * as echarts from "echarts";
|
||||
export default function getOptions(xData: any, outputList: any, rateList: any) {
|
||||
if (xData.length === 0 || outputList.length === 0 || rateList.length === 0)
|
||||
return null;
|
||||
return {
|
||||
grid: { top: 30, right: 48, bottom: 26, left: 48 },
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: xData,
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.8)",
|
||||
fontSize: 12,
|
||||
interval: 0,
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
name: "单位/片",
|
||||
nameTextStyle: {
|
||||
color: "rgba(223, 241, 254, 0.8)",
|
||||
fontSize: 12,
|
||||
align: "right",
|
||||
},
|
||||
type: "value",
|
||||
alignTicks: true,
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "单位/%",
|
||||
nameTextStyle: {
|
||||
color: "rgba(223, 241, 254, 0.8)",
|
||||
fontSize: 12,
|
||||
align: "center",
|
||||
},
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
className: "handan-chart-tooltip",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: outputList,
|
||||
type: "bar",
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "#34C1FF" },
|
||||
{ offset: 1, color: "#3449FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
data: rateList,
|
||||
color: "rgba(18, 255, 245, 1)",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(18, 255, 245, 0.6)" },
|
||||
{ offset: 0.4, color: "rgba(18, 255, 245, 0.1)" },
|
||||
{ offset: 0.8, color: "rgba(18, 255, 245, 0)" },
|
||||
{ offset: 1, color: "rgba(18, 255, 245, 0)" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
54
src/page/HomePage/Center/Power/index.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import ReactECharts from "echarts-for-react";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectPowerDistributionpow } from "../../../../store/HomePageSlice";
|
||||
import getOptions from "./chart.config";
|
||||
function Power() {
|
||||
const data = useAppSelector(selectPowerDistributionpow);
|
||||
console.log("66666666666FUCH功率分布", data);
|
||||
let xData: any = [];
|
||||
let outputList: Number[] = [];
|
||||
let rateList: Number[] = [];
|
||||
if (data.length !== 0) {
|
||||
data.map((item: any) => {
|
||||
xData.push(item.scope)
|
||||
outputList.push(item.value);
|
||||
rateList.push(item.proportion);
|
||||
});
|
||||
}else{
|
||||
xData = [];
|
||||
outputList = [];
|
||||
rateList = [];
|
||||
}
|
||||
const options = getOptions(xData, outputList, rateList);
|
||||
return (
|
||||
<div className="right_up">
|
||||
<TitleBox title="right_left_up" />
|
||||
<div className="legend_right">
|
||||
<span className="dot2"></span>
|
||||
<span>产量</span>
|
||||
<span className="dot1"></span>
|
||||
<span>占比</span>
|
||||
</div>
|
||||
{options && (
|
||||
<div style={{ height: "230px", marginTop: "10px" }}>
|
||||
<ReactECharts option={options} style={{ height: "100%" }} />
|
||||
</div>
|
||||
)}
|
||||
{!options && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Power;
|
||||
112
src/page/HomePage/Center/Produce/chart.config.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import * as echarts from "echarts";
|
||||
export default function getOptions(
|
||||
xData: any,
|
||||
outputList: any,
|
||||
powerList: any
|
||||
) {
|
||||
if (xData.length === 0 || outputList.length === 0 || powerList.length === 0)
|
||||
return null;
|
||||
return {
|
||||
grid: { top: 10, right: 48, bottom: 26, left: 48 },
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: xData,
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.8)",
|
||||
fontSize: 12,
|
||||
interval: 0,
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
alignTicks: true,
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
className: "handan-chart-tooltip",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: outputList,
|
||||
type: "bar",
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "#34C1FF" },
|
||||
{ offset: 1, color: "#3449FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
data: powerList,
|
||||
color: "rgba(18, 255, 245, 1)",
|
||||
type: "line",
|
||||
yAxisIndex: 1,
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(18, 255, 245, 0.6)" },
|
||||
{ offset: 0.4, color: "rgba(18, 255, 245, 0.1)" },
|
||||
{ offset: 0.8, color: "rgba(18, 255, 245, 0)" },
|
||||
{ offset: 1, color: "rgba(18, 255, 245, 0)" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
78
src/page/HomePage/Center/Produce/index.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import ReactECharts from "echarts-for-react";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectOutputFUCH } from "../../../../store/HomePageSlice";
|
||||
import getOptions from "./chart.config";
|
||||
function Produce() {
|
||||
const data = useAppSelector(selectOutputFUCH);
|
||||
// console.log("7777777777777FUCH产出", data);
|
||||
let year = new Date().getFullYear();
|
||||
let xData: any = [];
|
||||
let outputList: Number[] = [];
|
||||
let powerList: Number[] = [];
|
||||
let totalOutput;
|
||||
let totalPower;
|
||||
if (Object.keys(data).length !== 0) {
|
||||
xData = Object.keys(data.monthOutput);
|
||||
xData.map((item: any) => {
|
||||
outputList.push(data.monthOutput[item]);
|
||||
powerList.push(data.monthPower[item]);
|
||||
});
|
||||
totalOutput = data.totalOutput;
|
||||
totalPower = data.totalPower;
|
||||
}
|
||||
const options = getOptions(xData, outputList, powerList);
|
||||
return (
|
||||
<div className="produce">
|
||||
<TitleBox title="right_left_down" />
|
||||
<div className="legend_right">
|
||||
<span className="dot2"></span>
|
||||
<span>产量</span>
|
||||
<span className="dot1"></span>
|
||||
<span>功率</span>
|
||||
</div>
|
||||
<div
|
||||
style={{ marginLeft: "-5px", marginTop: "10px", marginBottom: "10px" }}
|
||||
>
|
||||
<div className="top_unit" style={{marginRight: "5px"}}>单位/片</div>
|
||||
<div className="top_box" style={{ marginRight: "5px" }}>
|
||||
<span className="t1">{year}年总产量:</span>
|
||||
<span>
|
||||
{totalOutput ? totalOutput : totalOutput === 0 ? totalOutput : "-"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="top_box">
|
||||
<span className="t1">{year}年总功率:</span>
|
||||
<span>
|
||||
{totalPower
|
||||
? totalPower.toFixed(2)
|
||||
: totalPower === 0
|
||||
? totalPower
|
||||
: "-"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="top_unit" style={{marginLeft: "5px"}}>单位/MW</div>
|
||||
</div>
|
||||
|
||||
{options && (
|
||||
<div style={{ height: "190px" }}>
|
||||
{<ReactECharts option={options} style={{ height: "100%" }} />}
|
||||
</div>
|
||||
)}
|
||||
{!options && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Produce;
|
||||
82
src/page/HomePage/Center/Production/chart.config.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import * as echarts from "echarts";
|
||||
export default function getOptions(xData: any, outputList: any) {
|
||||
const colors = ["#1A99FF", "#FFB70C", "#C69DFF", "#50F4E3", "#E02094"];
|
||||
if (xData.length === 0 || outputList.length === 0) return null;
|
||||
return {
|
||||
color: colors,
|
||||
grid: { top: 30, right: 20, bottom: 40, left: 48 },
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: xData,
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.8)",
|
||||
fontSize: 10,
|
||||
interval: 0,
|
||||
rotate:25,
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
name: "单位/片",
|
||||
nameTextStyle: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
align:'right'
|
||||
},
|
||||
type: "value",
|
||||
axisLabel: {
|
||||
color: "rgba(223, 241, 254, 0.65)",
|
||||
fontSize: 12,
|
||||
formatter: "{value}",
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: "rgba(69, 97, 174, 1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
},
|
||||
className: "handan-chart-tooltip",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: outputList,
|
||||
type: "bar",
|
||||
barWidth: 16,
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: 12,
|
||||
color: "#9CD4FF",
|
||||
position: "top",
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "#34C1FF" },
|
||||
{ offset: 1, color: "#3449FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
42
src/page/HomePage/Center/Production/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import ReactECharts from "echarts-for-react";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectProductionBarChart } from "../../../../store/HomePageSlice";
|
||||
import getOptions from "./chart.config";
|
||||
function Production() {
|
||||
const data = useAppSelector(selectProductionBarChart);
|
||||
// console.log("44444444产量柱状图", data);
|
||||
let xData: any = [];
|
||||
let outputList: Number[] = [];
|
||||
if (Object.keys(data).length !== 0) {
|
||||
xData = Object.keys(data);
|
||||
xData.map((item: any) => {
|
||||
outputList.push(data[item]);
|
||||
});
|
||||
}
|
||||
const options = getOptions(xData, outputList);
|
||||
return (
|
||||
<div className="left_right_center">
|
||||
<TitleBox title="left_right_center" />
|
||||
{options && (
|
||||
<div style={{ height: "230px", marginTop: "10px" }}>
|
||||
{<ReactECharts option={options} style={{ height: "100%" }} />}
|
||||
</div>
|
||||
)}
|
||||
{!options && (
|
||||
<p
|
||||
style={{
|
||||
color: "#ccc",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Production;
|
||||
69
src/page/HomePage/Center/TempAndHumidity/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import Rectangle2 from "../../Component/Rectangle2";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectTempAndHumidityTEMP } from "../../../../store/HomePageSlice";
|
||||
function TempAndHumidity() {
|
||||
const data = useAppSelector(selectTempAndHumidityTEMP);
|
||||
// console.log("55555555镀膜与活化温度", data);
|
||||
const list1 = [
|
||||
{ name: "镀膜间温度1", ename: "acoatTemp1", value: "" },
|
||||
{ name: "镀膜间温度2", ename: "acoatTemp2", value: "" },
|
||||
{ name: "活化间温度1", ename: "afurTemp1", value: "" },
|
||||
{ name: "活化间温度2", ename: "afurTemp2", value: "" },
|
||||
{ name: "层压间温度1", ename: "lamaTemp1", value: "" },
|
||||
];
|
||||
const list2 = [
|
||||
{ name: "镀膜间湿度1", ename: "acoatHum1", value: "" },
|
||||
{ name: "镀膜间湿度2", ename: "acoatHum2", value: "" },
|
||||
{ name: "活化间湿度1", ename: "afurHum1", value: "" },
|
||||
{ name: "活化间湿度2", ename: "afurHum2", value: "" },
|
||||
{ name: "层压间湿度1", ename: "lamaHum1", value: "" },
|
||||
];
|
||||
list1.map((item, index) => {
|
||||
item.value = data[item.ename] ? data[item.ename] + "℃":'-';
|
||||
});
|
||||
list2.map((item, index) => {
|
||||
item.value = data[item.ename] ? data[item.ename] + "%RH":'-';
|
||||
});
|
||||
return (
|
||||
<div className="left_right_down">
|
||||
<TitleBox title="left_right_down" />
|
||||
{Object.keys(data).length !== 0 && (
|
||||
<div className="box flex-row">
|
||||
<div className="flex-col" style={{ marginRight: "8px" }}>
|
||||
{list1.map((item, index) => {
|
||||
return (
|
||||
<div className="item" key={index}>
|
||||
<Rectangle2 name={item.name} value={item.value} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="flex-col">
|
||||
{list2.map((item, index) => {
|
||||
return (
|
||||
<div className="item" key={index}>
|
||||
<Rectangle2 name={item.name} value={item.value} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{Object.keys(data).length === 0 && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default TempAndHumidity;
|
||||
26
src/page/HomePage/Component/Rectangle/index.css
Normal file
@@ -0,0 +1,26 @@
|
||||
.rectangle_box {
|
||||
width: 246px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
background: url(../../../../../public/image/homePage/b1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 15px;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.rectangle_box img {
|
||||
width: 32px;
|
||||
height: 34px;
|
||||
position: relative;
|
||||
top: 10px;
|
||||
margin: 0 8px 0 20px;
|
||||
}
|
||||
.rectangle_box .title {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
padding-right: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
16
src/page/HomePage/Component/Rectangle/index.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import "./index.css";
|
||||
interface RectangleProps {
|
||||
name: string;
|
||||
rate: string;
|
||||
icon: number;
|
||||
}
|
||||
function Rectangle(props: RectangleProps) {
|
||||
return (
|
||||
<div className="rectangle_box">
|
||||
<img src={require(`./../../../../assets/image/icon${props.icon}.png`)} />
|
||||
<span className="title">{props.name}:</span>
|
||||
<span>{props.rate}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Rectangle;
|
||||
21
src/page/HomePage/Component/Rectangle2/index.css
Normal file
@@ -0,0 +1,21 @@
|
||||
.rectangle2 {
|
||||
width: 245px;
|
||||
height: 41px;
|
||||
line-height: 41px;
|
||||
background: url(../../../../../public/image/homePage/b2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 16px;
|
||||
letter-spacing: 2px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.rectangle2_title {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
}
|
||||
.rectangle2_content {
|
||||
display: inline-block;
|
||||
}
|
||||
16
src/page/HomePage/Component/Rectangle2/index.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import "./index.css";
|
||||
interface Props {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
function Rectangle2(props: Props) {
|
||||
return (
|
||||
<div className="rectangle2">
|
||||
<div>
|
||||
<span className="rectangle2_title">{props.name}:</span>
|
||||
<span className="rectangle2_content">{props.value}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Rectangle2;
|
||||
15
src/page/HomePage/Component/TitleBox/index.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.title_box {
|
||||
font-family: PingFangSC, PingFang SC;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.title_box img {
|
||||
width: 24px;
|
||||
height: 25px;
|
||||
vertical-align: bottom;
|
||||
margin-right: 8px;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
70
src/page/HomePage/Component/TitleBox/index.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import t1 from "./../../../../assets/image/t1.png";
|
||||
import t2 from "./../../../../assets/image/t2.png";
|
||||
import t3 from "./../../../../assets/image/t3.png";
|
||||
import t4 from "./../../../../assets/image/t4.png";
|
||||
import t5 from "./../../../../assets/image/t5.png";
|
||||
import t6 from "./../../../../assets/image/t6.png";
|
||||
import t7 from "./../../../../assets/image/t7.png";
|
||||
import t8 from "./../../../../assets/image/t8.png";
|
||||
import "./index.css";
|
||||
interface titleProps {
|
||||
title: string;
|
||||
}
|
||||
function TitleBox(props: titleProps) {
|
||||
const filteredTitles = () => {
|
||||
switch (props.title) {
|
||||
case "left_left_up":
|
||||
return {
|
||||
img: t1,
|
||||
title: "设备稼动率",
|
||||
};
|
||||
case "left_left_down":
|
||||
return {
|
||||
img: t2,
|
||||
title: "封装工单完成情况",
|
||||
};
|
||||
case "left_right_up":
|
||||
return {
|
||||
img: t3,
|
||||
title: "产线缺陷分类(当日)",
|
||||
};
|
||||
case "left_right_center":
|
||||
return {
|
||||
img: t4,
|
||||
title: "产量柱状图(当日)",
|
||||
};
|
||||
case "left_right_down":
|
||||
return {
|
||||
img: t5,
|
||||
title: "温湿度",
|
||||
};
|
||||
case "right_left_up":
|
||||
return {
|
||||
img: t6,
|
||||
title: "FUCH功率分布",
|
||||
};
|
||||
case "right_left_down":
|
||||
return {
|
||||
img: t4,
|
||||
title: "FUCH产出",
|
||||
};
|
||||
case "right_right_up":
|
||||
return {
|
||||
img: t7,
|
||||
title: "前中后段良率",
|
||||
};
|
||||
default:
|
||||
return {
|
||||
img: t8,
|
||||
title: "下片分档信息",
|
||||
};
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="title_box">
|
||||
<img src={filteredTitles().img} alt="title" />
|
||||
<span>{filteredTitles().title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default TitleBox;
|
||||
75
src/page/HomePage/Left/LeftDown/index.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import ScrollBoard from "../../../Component/ScrollBoard";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectOrderCompletionWO } from "../../../../store/HomePageSlice";
|
||||
function LeftDown() {
|
||||
const data = useAppSelector(selectOrderCompletionWO);
|
||||
// console.log("222222封装工单完成情况+", data);
|
||||
const config = {
|
||||
header: ["工单号", "目标产量", "实际投入", "实际产出", "完成度"],
|
||||
headerHeight: 40,
|
||||
rowNum: 10,
|
||||
headerBGC: "rgba(4, 74, 132, 0.2)",
|
||||
oddRowBGC: "rgba(4, 74, 132, 0.2)",
|
||||
evenRowBGC: "rgba(11, 84, 153, 0.36)",
|
||||
columnWidth: [140, 100, 100, 100, 90],
|
||||
data: [],
|
||||
};
|
||||
let arr: any = [];
|
||||
data &&
|
||||
data.map((item: any, index: any) => {
|
||||
let arrInner = [];
|
||||
arrInner.push(
|
||||
item.workOrderNo ? item.workOrderNo : "-",
|
||||
item.planQuantity
|
||||
? item.planQuantity
|
||||
: item.planQuantity === 0
|
||||
? item.planQuantity
|
||||
: "-",
|
||||
item.actualPutIn
|
||||
? item.actualPutIn
|
||||
: item.actualPutIn === 0
|
||||
? item.actualPutIn
|
||||
: "-",
|
||||
item.actualQuantity
|
||||
? item.actualQuantity
|
||||
: item.actualQuantity === 0
|
||||
? item.actualQuantity
|
||||
: "-",
|
||||
item.completeness
|
||||
? item.completeness + "%"
|
||||
: item.completeness === 0
|
||||
? item.completeness + "%"
|
||||
: "-"
|
||||
);
|
||||
arr.push(arrInner);
|
||||
});
|
||||
config.data = arr;
|
||||
return (
|
||||
<div className="left_left_down">
|
||||
<TitleBox title="left_left_down" />
|
||||
{data.length !== 0 && (
|
||||
<div style={{ marginTop: "15px" }}>
|
||||
<ScrollBoard
|
||||
config={config}
|
||||
style={{ width: "500px", height: "440px" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{data.length === 0 && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default LeftDown;
|
||||
82
src/page/HomePage/Left/LeftUp/index.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import Rectangle from "../../Component/Rectangle";
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectEqRateAVA } from "../../../../store/HomePageSlice";
|
||||
function LeftUp() {
|
||||
const data = useAppSelector(selectEqRateAVA);
|
||||
console.log("111111111设备稼动率", data);
|
||||
const eqRate1 = [
|
||||
{ icon: 1, name: "", rate: "" },
|
||||
{ icon: 2, name: "", rate: "" },
|
||||
{ icon: 3, name: "", rate: "" },
|
||||
{ icon: 4, name: "", rate: "" },
|
||||
];
|
||||
const eqRate2 = [
|
||||
{ icon: 5, name: "", rate: "" },
|
||||
{ icon: 6, name: "", rate: "" },
|
||||
{ icon: 7, name: "", rate: "" },
|
||||
{ icon: 8, name: "", rate: "" },
|
||||
];
|
||||
let keys = Object.keys(data);
|
||||
eqRate1.map((item, index) => {
|
||||
item.name = keys[index];
|
||||
})
|
||||
eqRate2.map((item, index) => {
|
||||
item.name = keys[index + 4];
|
||||
})
|
||||
eqRate1.map((item, index) => {
|
||||
item.rate = data[item.name] + "%";
|
||||
});
|
||||
eqRate2.map((item, index) => {
|
||||
item.rate = data[item.name] + "%";
|
||||
});
|
||||
return (
|
||||
<div className="left_left_up">
|
||||
<TitleBox title="left_left_up" />
|
||||
{Object.keys(data).length !== 0 && (
|
||||
<div className="box flex-row">
|
||||
<div className="flex-col" style={{ marginRight: "8px" }}>
|
||||
{eqRate1.map((item, index) => {
|
||||
return (
|
||||
<div className="item" key={index}>
|
||||
<Rectangle
|
||||
name={item.name}
|
||||
rate={item.rate}
|
||||
icon={item.icon}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="item flex-col">
|
||||
{eqRate2.map((item, index) => {
|
||||
return (
|
||||
<div className="item" key={index}>
|
||||
<Rectangle
|
||||
name={item.name}
|
||||
rate={item.rate}
|
||||
icon={item.icon}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{Object.keys(data).length === 0 && (
|
||||
<p
|
||||
style={{
|
||||
color: "#ccc",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default LeftUp;
|
||||
11
src/page/HomePage/Left/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import LeftUp from "./LeftUp";
|
||||
import LeftDown from "./LeftDown";
|
||||
function Left() {
|
||||
return (
|
||||
<div className="left_part">
|
||||
<LeftUp />
|
||||
<LeftDown />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Left;
|
||||
60
src/page/HomePage/Right/RightDown/index.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import ScrollBoard from "../../../Component/ScrollBoard";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectOutputMsgBOX } from "../../../../store/HomePageSlice";
|
||||
function RightDown() {
|
||||
const data = useAppSelector(selectOutputMsgBOX);
|
||||
// console.log("9999999999999下片分档信息", data);
|
||||
const config = {
|
||||
header: ["序号", "功率/W", "当日产量", "当前装箱号", "装箱数量"],
|
||||
headerHeight: 49,
|
||||
rowNum: 8,
|
||||
align: ["center", "left", "left", "left", "left"],
|
||||
headerBGC: "rgba(4, 74, 132, 0.2)",
|
||||
oddRowBGC: "rgba(4, 74, 132, 0.2)",
|
||||
evenRowBGC: "rgba(11, 84, 153, 0.36)",
|
||||
columnWidth: [70, 100, 117, 138, 100],
|
||||
data: [],
|
||||
};
|
||||
let arr: any = [];
|
||||
data &&
|
||||
data.map((item: any, index: any) => {
|
||||
let arrInner = [];
|
||||
arrInner.push(
|
||||
index + 1,
|
||||
item.power ? item.power : item.power === 0 ? item.power : "-",
|
||||
item.output ? item.output : item.output === 0 ? item.output : "-",
|
||||
item.boxNo ? item.boxNo : item.boxNo === 0 ? item.boxNo : "-",
|
||||
item.boxNum ? item.boxNum : item.boxNum === 0 ? item.boxNum : "-"
|
||||
);
|
||||
arr.push(arrInner);
|
||||
});
|
||||
config.data = arr;
|
||||
return (
|
||||
<div className="right_down">
|
||||
<TitleBox title="right_right_down" />
|
||||
{data.length !== 0 && (
|
||||
<div style={{ marginTop: "15px" }}>
|
||||
<ScrollBoard
|
||||
config={config}
|
||||
style={{ width: "498px", height: "435px" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{data.length === 0 && (
|
||||
<p
|
||||
style={{
|
||||
color: "#cccf",
|
||||
fontSize: "24px",
|
||||
userSelect: "none",
|
||||
textAlign: "center",
|
||||
paddingTop: "72px",
|
||||
}}
|
||||
>
|
||||
暂无数据
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default RightDown;
|
||||
72
src/page/HomePage/Right/RightUp/index.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import TitleBox from "../../Component/TitleBox";
|
||||
import chartA from "./../../../../assets/image/chartA.png";
|
||||
import chartB from "./../../../../assets/image/chartB.png";
|
||||
import { useAppSelector } from "../../../../store/hooks";
|
||||
import { selectYield } from "../../../../store/HomePageSlice";
|
||||
function RightUp() {
|
||||
const data = useAppSelector(selectYield);
|
||||
// console.log("888888888前中后段良率", data);
|
||||
let before = data?.before || 100;
|
||||
let middle = data?.middle || 100;
|
||||
let after = data?.after || 100;
|
||||
return (
|
||||
<div className="right_right_up">
|
||||
<TitleBox title="right_right_up" />
|
||||
<div className="chart1">
|
||||
<img
|
||||
src={chartA}
|
||||
alt=""
|
||||
width={"121px"}
|
||||
height={30 + before + "px"}
|
||||
style={{ position: "relative", top: "4px" }}
|
||||
/>
|
||||
<img src={chartB} alt="" width={"121px"} height={"130px"} />
|
||||
<span
|
||||
className="num_percentage"
|
||||
style={{ top: -61 + before * 0.2 + "px" }}
|
||||
>
|
||||
{before}
|
||||
<span className="small">%</span>
|
||||
</span>
|
||||
<span className="title">前段良率</span>
|
||||
</div>
|
||||
<div className="chart2">
|
||||
<img
|
||||
src={chartA}
|
||||
alt=""
|
||||
width={"121px"}
|
||||
height={30 + middle + "px"}
|
||||
style={{ position: "relative", top: "4px" }}
|
||||
/>
|
||||
<img src={chartB} alt="" width={"121px"} height={"130px"} />
|
||||
<span
|
||||
className="num_percentage"
|
||||
style={{ top: -61 + middle * 0.2 + "px" }}
|
||||
>
|
||||
{middle}
|
||||
<span className="small">%</span>
|
||||
</span>
|
||||
<span className="title">中段良率</span>
|
||||
</div>
|
||||
<div className="chart3">
|
||||
<img
|
||||
src={chartA}
|
||||
alt=""
|
||||
width={"121px"}
|
||||
height={30 + after + "px"}
|
||||
style={{ position: "relative", top: "4px" }}
|
||||
/>
|
||||
<img src={chartB} alt="" width={"121px"} height={"130px"} />
|
||||
<span
|
||||
className="num_percentage"
|
||||
style={{ top: -61 + after * 0.2 + "px" }}
|
||||
>
|
||||
{after}
|
||||
<span className="small">%</span>
|
||||
</span>
|
||||
<span className="title">后段良率</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default RightUp;
|
||||
11
src/page/HomePage/Right/index.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import RightUp from "./RightUp";
|
||||
import RightDown from "./RightDown";
|
||||
function Right() {
|
||||
return (
|
||||
<div className="right_part">
|
||||
<RightUp />
|
||||
<RightDown />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Right;
|
||||
304
src/page/HomePage/index.css
Normal file
@@ -0,0 +1,304 @@
|
||||
@font-face {
|
||||
font-family: "DINCondensed";
|
||||
src: url("../../assets/fonts/DINCondensed.ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
.left_part {
|
||||
width: 542px;
|
||||
position: absolute;
|
||||
top: 110px;
|
||||
margin-left: 39px;
|
||||
}
|
||||
.left_part .left_inner {
|
||||
width: 626px;
|
||||
margin-right: 22px;
|
||||
}
|
||||
.left_left_up {
|
||||
width: 542px;
|
||||
height: 399px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
margin-bottom: 22px;
|
||||
padding: 20px 0 0 21px;
|
||||
}
|
||||
.left_left_up .box {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.left_left_up .box .item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.left_left_down {
|
||||
width: 542px;
|
||||
height: 525px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 21px;
|
||||
}
|
||||
.left_right_up,
|
||||
.left_right_center{
|
||||
width: 494px;
|
||||
height: 306px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 18px;
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.left_right_down {
|
||||
width: 536px;
|
||||
height: 306px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 18px;
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.right_up_legend {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 80px;
|
||||
width: 190px;
|
||||
height: 200px;
|
||||
}
|
||||
.right_up_legend {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
.right_up_legend .item {
|
||||
/* border: 1px solid blue; */
|
||||
width: 235px;
|
||||
/* height: 20px; */
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
.right_up_legend .item .dot {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.left_right_down .box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.left_right_down .box .item {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.right_part {
|
||||
width: 540px;
|
||||
position: absolute;
|
||||
top: 110px;
|
||||
right: 38px;
|
||||
}
|
||||
.right_up {
|
||||
width: 534px;
|
||||
height: 304px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 21px;
|
||||
position: relative;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.right_right_up {
|
||||
width: 540px;
|
||||
height: 399px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/R1.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
margin-bottom: 22px;
|
||||
padding: 20px 0 0 21px;
|
||||
position: relative;
|
||||
}
|
||||
.right_right_up .chart1,
|
||||
.chart2,
|
||||
.chart3 {
|
||||
position: absolute;
|
||||
width: 121px;
|
||||
bottom: 32px;
|
||||
}
|
||||
.right_right_up .chart1 {
|
||||
left: 50px;
|
||||
}
|
||||
.right_right_up .chart2 {
|
||||
left: 210px;
|
||||
}
|
||||
.right_right_up .chart3 {
|
||||
left: 370px;
|
||||
}
|
||||
.right_right_up .title {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
left: 25px;
|
||||
bottom: 100px;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
.right_right_up .num_percentage {
|
||||
font-family: "DINCondensed";
|
||||
font-size: 64px;
|
||||
color: #fff;
|
||||
text-shadow: 0px 2px 4px #62d8ff;
|
||||
position: absolute;
|
||||
left: 19px;
|
||||
display: block;
|
||||
width: 85px;
|
||||
text-align: center;
|
||||
}
|
||||
.right_right_up .num_percentage .small {
|
||||
font-size: 29px;
|
||||
}
|
||||
.right_down {
|
||||
width: 540px;
|
||||
height: 525px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 21px;
|
||||
position: relative;
|
||||
}
|
||||
.produce{
|
||||
width: 494px;
|
||||
height: 304px;
|
||||
box-sizing: border-box;
|
||||
background: url(../../../public/image/homePage/L2.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
padding: 20px 0 0 21px;
|
||||
position: relative;
|
||||
}
|
||||
.produce .top_unit{
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: rgba(223, 241, 254, 0.8);
|
||||
}
|
||||
.produce .top_box {
|
||||
width: 185px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
display: inline-block;
|
||||
background: url(../../../public/image/homePage/b3.png) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-position: 0 0;
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
.produce .top_box .t1 {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
text-align: right;
|
||||
}
|
||||
.legend_right {
|
||||
position: absolute;
|
||||
right: 28px;
|
||||
top: 28px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 14px;
|
||||
}
|
||||
.legend_right .dot1 {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #12fff5;
|
||||
border-radius: 5px;
|
||||
margin: 0 8px 0 16px;
|
||||
position: relative;
|
||||
}
|
||||
.legend_right .dot1::before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
width: 18px;
|
||||
height: 2px;
|
||||
background: #12fff5;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: -4px;
|
||||
}
|
||||
.legend_right .dot2 {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #34bdff;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.center_up {
|
||||
width: 2635px;
|
||||
height: 536px;
|
||||
position: absolute;
|
||||
top: 180px;
|
||||
left: 600px;
|
||||
}
|
||||
.center-down {
|
||||
width: 2635px;
|
||||
height: 304px;
|
||||
position: absolute;
|
||||
bottom: 23px;
|
||||
left: 606px;
|
||||
}
|
||||
.eq_info_box {
|
||||
position: absolute;
|
||||
top: -90px;
|
||||
left: 16px;
|
||||
width: 555px;
|
||||
height: 245px;
|
||||
background: url("./../../assets/image/eqInfoBg.png") 100% no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding: 15px 13px 15px 15px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.eq_info_box .title {
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
}
|
||||
.eq_info_box .content {
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
}
|
||||
.eq_info_box .content span {
|
||||
display: inline-block;
|
||||
width: 260px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
margin-right: 2px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.eq_info_box .content .bg {
|
||||
background: rgba(126, 255, 250, 0.12);
|
||||
}
|
||||
.dv-scroll-board {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.dv-scroll-board .header .header-item,
|
||||
.dv-scroll-board .rows .ceil {
|
||||
border-right: 1px solid #0b193e;
|
||||
}
|
||||
.dv-scroll-board .header .header-item:last-child,
|
||||
.dv-scroll-board .rows .ceil:last-child {
|
||||
border-right: none;
|
||||
border: none;
|
||||
}
|
||||
.dv-scroll-board .header {
|
||||
font-size: 18px;
|
||||
}
|
||||
.dv-scroll-board .rows .row-item {
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
19
src/page/HomePage/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
import TopTitle from "../Component/TopTitle";
|
||||
import Left from "./Left";
|
||||
import Center from "./Center/Center";
|
||||
import Right from "./Right";
|
||||
import "./index.css";
|
||||
function HomePage() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TopTitle />
|
||||
<div>
|
||||
<Left />
|
||||
<Center />
|
||||
<Right />
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
export default HomePage;
|
||||
71
src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="react" />
|
||||
/// <reference types="react-dom" />
|
||||
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
readonly NODE_ENV: 'development' | 'production' | 'test';
|
||||
readonly PUBLIC_URL: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare module '*.avif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.bmp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpeg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.webp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
import * as React from 'react';
|
||||
|
||||
export const ReactComponent: React.FunctionComponent<React.SVGProps<
|
||||
SVGSVGElement
|
||||
> & { title?: string }>;
|
||||
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.module.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.scss' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.sass' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
15
src/reportWebVitals.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
5
src/setupTests.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
37
src/store/ChangeLineID.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {createSlice} from "@reduxjs/toolkit";
|
||||
import type {RootState} from "./store";
|
||||
|
||||
const initialState = {
|
||||
LineID: 1,
|
||||
}
|
||||
|
||||
export const ChangeLineID = createSlice({
|
||||
name: 'ChangeLineID',
|
||||
initialState,
|
||||
reducers: {
|
||||
UpdateChangeLineID: (state, action) => {
|
||||
switch (action.payload) {
|
||||
case '1':
|
||||
state.LineID = 1;
|
||||
break;
|
||||
case '2':
|
||||
state.LineID = 2;
|
||||
break;
|
||||
case '3':
|
||||
state.LineID = 3;
|
||||
break;
|
||||
case '4':
|
||||
state.LineID = 4;
|
||||
break;
|
||||
default:
|
||||
state.LineID = 1;
|
||||
break
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export const {UpdateChangeLineID} = ChangeLineID.actions;
|
||||
export const selectChangeLineID = (state: RootState) => state.ChangeLineID.LineID;
|
||||
|
||||
export default ChangeLineID.reducer;
|
||||
191
src/store/EquStatusEntity.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
import {createSlice} from "@reduxjs/toolkit";
|
||||
import type {RootState} from "./store";
|
||||
|
||||
export interface EquStatusInterface {
|
||||
CleanAfterEdge1_1: number
|
||||
CleanAfterEdge1_2: number
|
||||
CleanAfterEdge2_1: number
|
||||
CleanAfterEdge2_2: number
|
||||
CleanAfterEdge3_1: number
|
||||
CleanAfterEdge3_2: number
|
||||
CleanAfterEdge4_1: number
|
||||
CleanAfterEdge4_2: number
|
||||
CleanAfterTemper1_1: number
|
||||
CleanAfterTemper2_1: number
|
||||
CleanAfterTemper3_1: number
|
||||
CleanAfterTemper4_1: number
|
||||
CleanBeforCoat1_1: number
|
||||
CleanBeforCoat1_2: number
|
||||
CleanBeforCoat4_1: number
|
||||
CleanBeforCoat4_2: number
|
||||
Edge1_1: number
|
||||
Edge1_2: number
|
||||
Edge2_1: number
|
||||
Edge2_2: number
|
||||
Edge3_1: number
|
||||
Edge3_2: number
|
||||
Edge4_1: number
|
||||
Edge4_2: number
|
||||
FirstCoat1_1: number
|
||||
FirstCoat1_2: number
|
||||
FirstCoat2_1: number
|
||||
FirstCoat2_2: number
|
||||
FirstCoat3_1: number
|
||||
FirstCoat3_2: number
|
||||
FirstCoat4_1: number
|
||||
FirstCoat4_2: number
|
||||
Punch1_1: number
|
||||
Punch1_2: number
|
||||
Punch4_1: number
|
||||
Punch4_2: number
|
||||
SecondCoat1_1: number
|
||||
SecondCoat1_2: number
|
||||
SecondCoat2_1: number
|
||||
SecondCoat2_2: number
|
||||
SecondCoat3_1: number
|
||||
SecondCoat3_2: number
|
||||
SecondCoat4_1: number
|
||||
SecondCoat4_2: number
|
||||
Temper1_1: number
|
||||
Temper2_1: number
|
||||
Temper3_1: number
|
||||
Temper4_1: number
|
||||
Unload1_1: number
|
||||
Unload1_2: number
|
||||
Unload2_1: number
|
||||
Unload2_2: number
|
||||
Unload3_1: number
|
||||
Unload3_2: number
|
||||
Unload4_1: number
|
||||
Unload4_2: number
|
||||
}
|
||||
|
||||
const initialState: EquStatusInterface = {
|
||||
CleanAfterEdge1_1: 0,
|
||||
CleanAfterEdge1_2: 0,
|
||||
CleanAfterEdge2_1: 0,
|
||||
CleanAfterEdge2_2: 0,
|
||||
CleanAfterEdge3_1: 0,
|
||||
CleanAfterEdge3_2: 0,
|
||||
CleanAfterEdge4_1: 0,
|
||||
CleanAfterEdge4_2: 0,
|
||||
CleanAfterTemper1_1: 0,
|
||||
CleanAfterTemper2_1: 0,
|
||||
CleanAfterTemper3_1: 0,
|
||||
CleanAfterTemper4_1: 0,
|
||||
CleanBeforCoat1_1: 0,
|
||||
CleanBeforCoat1_2: 0,
|
||||
CleanBeforCoat4_1: 0,
|
||||
CleanBeforCoat4_2: 0,
|
||||
Edge1_1: 0,
|
||||
Edge1_2: 0,
|
||||
Edge2_1: 0,
|
||||
Edge2_2: 0,
|
||||
Edge3_1: 0,
|
||||
Edge3_2: 0,
|
||||
Edge4_1: 0,
|
||||
Edge4_2: 0,
|
||||
FirstCoat1_1: 0,
|
||||
FirstCoat1_2: 0,
|
||||
FirstCoat2_1: 0,
|
||||
FirstCoat2_2: 0,
|
||||
FirstCoat3_1: 0,
|
||||
FirstCoat3_2: 0,
|
||||
FirstCoat4_1: 0,
|
||||
FirstCoat4_2: 0,
|
||||
Punch1_1: 0,
|
||||
Punch1_2: 0,
|
||||
Punch4_1: 0,
|
||||
Punch4_2: 0,
|
||||
SecondCoat1_1: 0,
|
||||
SecondCoat1_2: 0,
|
||||
SecondCoat2_1: 0,
|
||||
SecondCoat2_2: 0,
|
||||
SecondCoat3_1: 0,
|
||||
SecondCoat3_2: 0,
|
||||
SecondCoat4_1: 0,
|
||||
SecondCoat4_2: 0,
|
||||
Temper1_1: 0,
|
||||
Temper2_1: 0,
|
||||
Temper3_1: 0,
|
||||
Temper4_1: 0,
|
||||
Unload1_1: 0,
|
||||
Unload1_2: 0,
|
||||
Unload2_1: 0,
|
||||
Unload2_2: 0,
|
||||
Unload3_1: 0,
|
||||
Unload3_2: 0,
|
||||
Unload4_1: 0,
|
||||
Unload4_2: 0
|
||||
}
|
||||
export const EquStatusEntity = createSlice({
|
||||
name: 'EquStatusEntity',
|
||||
initialState,
|
||||
reducers: {
|
||||
UpdateEquStatus: (state, action) => {
|
||||
const JsonData = action.payload;
|
||||
state.CleanAfterEdge1_1 = JsonData['CleanAfterEdge1-1'].status;
|
||||
state.CleanAfterEdge1_2 = JsonData['CleanAfterEdge1-2'].status;
|
||||
state.CleanAfterEdge2_1 = JsonData['CleanAfterEdge2-1'].status;
|
||||
state.CleanAfterEdge2_2 = JsonData['CleanAfterEdge2-2'].status;
|
||||
state.CleanAfterEdge3_1 = JsonData['CleanAfterEdge3-1'].status;
|
||||
state.CleanAfterEdge3_2 = JsonData['CleanAfterEdge3-2'].status;
|
||||
state.CleanAfterEdge4_1 = JsonData['CleanAfterEdge4-1'].status;
|
||||
state.CleanAfterEdge4_2 = JsonData['CleanAfterEdge4-2'].status;
|
||||
state.CleanAfterTemper1_1 = JsonData['CleanAfterTemper1-1'].status;
|
||||
state.CleanAfterTemper2_1 = JsonData['CleanAfterTemper2-1'].status;
|
||||
state.CleanAfterTemper3_1 = JsonData['CleanAfterTemper3-1'].status;
|
||||
state.CleanAfterTemper4_1 = JsonData['CleanAfterTemper4-1'].status;
|
||||
state.CleanBeforCoat1_1 = JsonData['CleanBeforCoat1-1'].status;
|
||||
state.CleanBeforCoat1_2 = JsonData['CleanBeforCoat1-2'].status;
|
||||
state.CleanBeforCoat4_1 = JsonData['CleanBeforCoat4-1'].status;
|
||||
state.CleanBeforCoat4_2 = JsonData['CleanBeforCoat4-2'].status;
|
||||
state.Edge1_1 = JsonData['Edge1-1'].status;
|
||||
state.Edge1_2 = JsonData['Edge1-2'].status;
|
||||
state.Edge2_1 = JsonData['Edge2-1'].status;
|
||||
state.Edge2_2 = JsonData['Edge2-2'].status;
|
||||
state.Edge3_1 = JsonData['Edge3-1'].status;
|
||||
state.Edge3_2 = JsonData['Edge3-2'].status;
|
||||
state.Edge4_1 = JsonData['Edge4-1'].status;
|
||||
state.Edge4_2 = JsonData['Edge4-2'].status;
|
||||
state.FirstCoat1_1 = JsonData['FirstCoat1-1'].status;
|
||||
state.FirstCoat1_2 = JsonData['FirstCoat1-2'].status;
|
||||
state.FirstCoat2_1 = JsonData['FirstCoat2-1'].status;
|
||||
state.FirstCoat2_2 = JsonData['FirstCoat2-2'].status;
|
||||
state.FirstCoat3_1 = JsonData['FirstCoat3-1'].status;
|
||||
state.FirstCoat3_2 = JsonData['FirstCoat3-2'].status;
|
||||
state.FirstCoat4_1 = JsonData['FirstCoat4-1'].status;
|
||||
state.FirstCoat4_2 = JsonData['FirstCoat4-2'].status;
|
||||
state.Punch1_1 = JsonData['Punch1-1'].status;
|
||||
state.Punch1_2 = JsonData['Punch1-2'].status;
|
||||
state.Punch4_1 = JsonData['Punch4-1'].status;
|
||||
state.Punch4_2 = JsonData['Punch4-2'].status;
|
||||
state.SecondCoat1_1 = JsonData['SecondCoat1-1'].status;
|
||||
state.SecondCoat1_2 = JsonData['SecondCoat1-2'].status;
|
||||
state.SecondCoat2_1 = JsonData['SecondCoat2-1'].status;
|
||||
state.SecondCoat2_2 = JsonData['SecondCoat2-2'].status;
|
||||
state.SecondCoat3_1 = JsonData['SecondCoat3-1'].status;
|
||||
state.SecondCoat3_2 = JsonData['SecondCoat3-2'].status;
|
||||
state.SecondCoat4_1 = JsonData['SecondCoat4-1'].status;
|
||||
state.SecondCoat4_2 = JsonData['SecondCoat4-2'].status;
|
||||
state.Temper1_1 = JsonData['Temper1-1'].status;
|
||||
state.Temper2_1 = JsonData['Temper2-1'].status;
|
||||
state.Temper3_1 = JsonData['Temper3-1'].status;
|
||||
state.Temper4_1 = JsonData['Temper4-1'].status;
|
||||
state.Unload1_1 = JsonData['Unload1-1'].status;
|
||||
state.Unload1_2 = JsonData['Unload1-2'].status;
|
||||
state.Unload2_1 = JsonData['Unload2-1'].status;
|
||||
state.Unload2_2 = JsonData['Unload2-2'].status;
|
||||
state.Unload3_1 = JsonData['Unload3-1'].status;
|
||||
state.Unload3_2 = JsonData['Unload3-2'].status;
|
||||
state.Unload4_1 = JsonData['Unload4-1'].status;
|
||||
state.Unload4_2 = JsonData['Unload4-2'].status;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const {UpdateEquStatus} = EquStatusEntity.actions;
|
||||
|
||||
export const selectEquStatus = (state: RootState) => state.EquStatusEntity;
|
||||
|
||||
export default EquStatusEntity.reducer;
|
||||
93
src/store/EquipmentMonitorEntity.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import type { RootState } from "./store";
|
||||
|
||||
export interface Alarm {
|
||||
alarmContent: string;
|
||||
equName: string;
|
||||
alarmCode: any;
|
||||
alarmEquipmentId: number;
|
||||
alarmValue: string;
|
||||
alarmId: number;
|
||||
alarmSource: string;
|
||||
}
|
||||
|
||||
export interface TickCount {
|
||||
equName: string;
|
||||
tickCount: number;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
externalCode: number;
|
||||
equipmentCode: number;
|
||||
outputNum: number;
|
||||
lineName: string;
|
||||
equipmentId: number;
|
||||
sectionName: string;
|
||||
inputNum: number;
|
||||
recordTime: number;
|
||||
equipmentName: string;
|
||||
}
|
||||
|
||||
export interface Oee {
|
||||
workRate: number;
|
||||
equName: string;
|
||||
downRate: number;
|
||||
stopRate: number;
|
||||
}
|
||||
|
||||
export interface EquipmentLine {
|
||||
equipmentAlarm: Array<Alarm>;
|
||||
equipmentTickCounts: Array<TickCount>;
|
||||
equipmentOees: Array<Oee>;
|
||||
equipmentProductDays: Array<Product>;
|
||||
equipmentProductWeeks: Array<Product>;
|
||||
equipmentProductMonths: Array<Product>;
|
||||
equipmentProductAll: Array<Product>;
|
||||
}
|
||||
|
||||
export interface EquipmentMonitorEntityInterface {
|
||||
Line_1: EquipmentLine;
|
||||
Line_2: EquipmentLine;
|
||||
Line_3: EquipmentLine;
|
||||
Line_4: EquipmentLine;
|
||||
}
|
||||
|
||||
const emptyEquipmentLine: EquipmentLine = {
|
||||
equipmentAlarm: [],
|
||||
equipmentTickCounts: [],
|
||||
equipmentOees: [],
|
||||
equipmentProductDays: [],
|
||||
equipmentProductWeeks: [],
|
||||
equipmentProductMonths: [],
|
||||
equipmentProductAll: [],
|
||||
};
|
||||
|
||||
const initialState: EquipmentMonitorEntityInterface = {
|
||||
Line_1: emptyEquipmentLine,
|
||||
Line_2: emptyEquipmentLine,
|
||||
Line_3: emptyEquipmentLine,
|
||||
Line_4: emptyEquipmentLine,
|
||||
};
|
||||
|
||||
export const EquipmentMonitorEntity = createSlice({
|
||||
name: "EquipmentMonitorEntity",
|
||||
initialState,
|
||||
reducers: {
|
||||
UpdateEquipmentMonitorEntity: (state, action) => {
|
||||
if (action.payload.toString().includes("客户端")) {
|
||||
} else {
|
||||
const BasicEquipmentMonitorEntity = JSON.parse(action.payload);
|
||||
state.Line_1 = BasicEquipmentMonitorEntity.Line_1;
|
||||
state.Line_2 = BasicEquipmentMonitorEntity.Line_2;
|
||||
state.Line_3 = BasicEquipmentMonitorEntity.Line_3;
|
||||
state.Line_4 = BasicEquipmentMonitorEntity.Line_4;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { UpdateEquipmentMonitorEntity } = EquipmentMonitorEntity.actions;
|
||||
|
||||
// export const selectAllLineEquipmentData = (state: RootState) => state.EquipmentMonitorEntity;
|
||||
|
||||
export default EquipmentMonitorEntity.reducer;
|
||||
88
src/store/HomePageSlice.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import type { RootState } from "./store";
|
||||
export interface HomePageSliceInterface {
|
||||
eqRateAVA: any;
|
||||
orderCompletionWO: any;
|
||||
defectsClassDEFECT: any;
|
||||
productionBarChart: any;
|
||||
tempAndHumidityTEMP: any;
|
||||
powerDistributionpow: any;
|
||||
outputFUCH: any;
|
||||
outputMsgBOX: any;
|
||||
yield: any;
|
||||
}
|
||||
const initialState: HomePageSliceInterface = {
|
||||
eqRateAVA: {},
|
||||
orderCompletionWO: [],
|
||||
defectsClassDEFECT: {},
|
||||
productionBarChart: [],
|
||||
tempAndHumidityTEMP: {},
|
||||
powerDistributionpow: [],
|
||||
outputFUCH: {},
|
||||
outputMsgBOX: [],
|
||||
yield: {},
|
||||
};
|
||||
export const HomePageSlice = createSlice({
|
||||
name: "HomePageSlice",
|
||||
initialState,
|
||||
reducers: {
|
||||
UpdateEqRateAVA: (state, action) => {
|
||||
state.eqRateAVA = action.payload;
|
||||
},
|
||||
UpdateOrderCompletionWO: (state, action) => {
|
||||
state.orderCompletionWO = action.payload;
|
||||
},
|
||||
UpdateDefectsClassDEFECT: (state, action) => {
|
||||
state.defectsClassDEFECT = action.payload;
|
||||
},
|
||||
UpdateProductionBarChart: (state, action) => {
|
||||
state.productionBarChart = action.payload;
|
||||
},
|
||||
UpdateTempAndHumidityTEMP: (state, action) => {
|
||||
state.tempAndHumidityTEMP = action.payload;
|
||||
},
|
||||
UpdatePowerDistributionpow: (state, action) => {
|
||||
state.powerDistributionpow = action.payload;
|
||||
},
|
||||
UpdateOutputFUCH: (state, action) => {
|
||||
state.outputFUCH = action.payload;
|
||||
},
|
||||
UpdateOutputMsgBOX: (state, action) => {
|
||||
state.outputMsgBOX = action.payload;
|
||||
},
|
||||
UpdateYield: (state, action) => {
|
||||
state.yield = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
export const {
|
||||
UpdateEqRateAVA,
|
||||
UpdateOrderCompletionWO,
|
||||
UpdateDefectsClassDEFECT,
|
||||
UpdateProductionBarChart,
|
||||
UpdateTempAndHumidityTEMP,
|
||||
UpdatePowerDistributionpow,
|
||||
UpdateOutputFUCH,
|
||||
UpdateOutputMsgBOX,
|
||||
UpdateYield,
|
||||
} = HomePageSlice.actions;
|
||||
|
||||
export const selectEqRateAVA = (state: RootState) =>
|
||||
state.HomePageSlice.eqRateAVA;
|
||||
export const selectOrderCompletionWO = (state: RootState) =>
|
||||
state.HomePageSlice.orderCompletionWO;
|
||||
export const selectDefectsClassDEFECT = (state: RootState) =>
|
||||
state.HomePageSlice.defectsClassDEFECT;
|
||||
export const selectProductionBarChart = (state: RootState) =>
|
||||
state.HomePageSlice.productionBarChart;
|
||||
export const selectTempAndHumidityTEMP = (state: RootState) =>
|
||||
state.HomePageSlice.tempAndHumidityTEMP;
|
||||
export const selectPowerDistributionpow = (state: RootState) =>
|
||||
state.HomePageSlice.powerDistributionpow;
|
||||
export const selectOutputFUCH = (state: RootState) =>
|
||||
state.HomePageSlice.outputFUCH;
|
||||
export const selectOutputMsgBOX = (state: RootState) =>
|
||||
state.HomePageSlice.outputMsgBOX;
|
||||
export const selectYield = (state: RootState) => state.HomePageSlice.yield;
|
||||
|
||||
export default HomePageSlice.reducer;
|
||||
214
src/store/ProductionMonitoringEntity.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
import {createSlice} from "@reduxjs/toolkit";
|
||||
import type {RootState} from "./store";
|
||||
|
||||
export interface alarm {
|
||||
alarmContent: string;
|
||||
alarmTime: string;
|
||||
alarmCode: string;
|
||||
}
|
||||
|
||||
export interface ProductionDet {
|
||||
lineName: string;
|
||||
inputNum: number;
|
||||
outputNum: number;
|
||||
passRate: number;
|
||||
}
|
||||
|
||||
export interface ProductionRate {
|
||||
lineName: string;
|
||||
lineId: number;
|
||||
lineExCode: string;
|
||||
passRate: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export interface RateLine {
|
||||
Line_1: Array<ProductionRate>,
|
||||
Line_2: Array<ProductionRate>,
|
||||
Line_3: Array<ProductionRate>,
|
||||
Line_4: Array<ProductionRate>,
|
||||
}
|
||||
|
||||
export interface SingleGlassStatus {
|
||||
lineViewCode: string,
|
||||
status: number
|
||||
}
|
||||
|
||||
export interface GlassStatus {
|
||||
LINE_1_1: number,
|
||||
LINE_1_2U: number,
|
||||
LINE_1_2D: number,
|
||||
LINE_1_3: number,
|
||||
LINE_1_4: number,
|
||||
LINE_2_1: number,
|
||||
LINE_2_2U: number,
|
||||
LINE_2_2D: number,
|
||||
LINE_2_3: number,
|
||||
LINE_2_4: number,
|
||||
LINE_3_1: number,
|
||||
LINE_3_2U: number,
|
||||
LINE_3_2D: number,
|
||||
LINE_3_3: number,
|
||||
LINE_3_4: number,
|
||||
LINE_4_1: number,
|
||||
LINE_4_2U: number,
|
||||
LINE_4_2D: number,
|
||||
LINE_4_3: number,
|
||||
LINE_4_4: number,
|
||||
}
|
||||
|
||||
const initLineGlassStatus: GlassStatus = {
|
||||
LINE_1_1: 1,
|
||||
LINE_1_2U: 1,
|
||||
LINE_1_2D: 1,
|
||||
LINE_1_3: 1,
|
||||
LINE_1_4: 1,
|
||||
LINE_2_1: 1,
|
||||
LINE_2_2U: 1,
|
||||
LINE_2_2D: 1,
|
||||
LINE_2_3: 1,
|
||||
LINE_2_4: 1,
|
||||
LINE_3_1: 1,
|
||||
LINE_3_2U: 1,
|
||||
LINE_3_2D: 1,
|
||||
LINE_3_3: 1,
|
||||
LINE_3_4: 1,
|
||||
LINE_4_1: 1,
|
||||
LINE_4_2U: 1,
|
||||
LINE_4_2D: 1,
|
||||
LINE_4_3: 1,
|
||||
LINE_4_4: 1,
|
||||
}
|
||||
|
||||
export interface ProductionMonitoringEntityInterface {
|
||||
sumNumber: number;
|
||||
alarms: Array<alarm>;
|
||||
sumProductionDets: Array<ProductionDet>;
|
||||
todayProductionDets: Array<ProductionDet>;
|
||||
weekProductionDets: Array<ProductionDet>;
|
||||
monthProductionDets: Array<ProductionDet>;
|
||||
todayProductionRates: RateLine,
|
||||
weekProductionRates: RateLine,
|
||||
monthProductionRates: RateLine,
|
||||
lineGlassStatus: GlassStatus,
|
||||
}
|
||||
|
||||
const emptyProductionRates: RateLine = {
|
||||
Line_4: [
|
||||
{
|
||||
"lineId": 1,
|
||||
"lineName": "产线1",
|
||||
"lineExCode": "Line_1",
|
||||
"passRate": 101.88,
|
||||
"time": 1676840400000
|
||||
},
|
||||
],
|
||||
Line_3: [
|
||||
{
|
||||
"lineId": 1619974755856867329,
|
||||
"lineName": "产线3",
|
||||
"lineExCode": "Line_3",
|
||||
"passRate": 32.04,
|
||||
"time": 1676822400000
|
||||
}
|
||||
],
|
||||
Line_2: [
|
||||
{
|
||||
"lineId": 1619974755856867329,
|
||||
"lineName": "产线3",
|
||||
"lineExCode": "Line_3",
|
||||
"passRate": 32.04,
|
||||
"time": 1676822400000
|
||||
}
|
||||
],
|
||||
Line_1: [
|
||||
{
|
||||
"lineId": 1619974755856867329,
|
||||
"lineName": "产线3",
|
||||
"lineExCode": "Line_3",
|
||||
"passRate": 32.04,
|
||||
"time": 1676822400000
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const initialState: ProductionMonitoringEntityInterface = {
|
||||
sumNumber: 0,
|
||||
alarms: [],
|
||||
sumProductionDets: [],
|
||||
todayProductionDets: [],
|
||||
weekProductionDets: [],
|
||||
monthProductionDets: [],
|
||||
todayProductionRates: emptyProductionRates,
|
||||
weekProductionRates: emptyProductionRates,
|
||||
monthProductionRates: emptyProductionRates,
|
||||
lineGlassStatus: initLineGlassStatus,
|
||||
}
|
||||
|
||||
export const ProductionMonitoringEntity = createSlice({
|
||||
name: 'ProductionMonitoringEntity',
|
||||
initialState,
|
||||
reducers: {
|
||||
UpdateProductionMonitoringEntity: (state, action) => {
|
||||
if (action.payload.toString().includes('客户端')) {
|
||||
} else {
|
||||
const ProductionMonitoringEntityData = JSON.parse(action.payload);
|
||||
|
||||
//sumNumber
|
||||
state.sumNumber = ProductionMonitoringEntityData.alarms.length;
|
||||
|
||||
//alarms
|
||||
state.alarms = [];
|
||||
for (let i = 0; i < 6; i++) {
|
||||
state.alarms.push({
|
||||
alarmContent: ProductionMonitoringEntityData.alarms[i].alarmContent,
|
||||
alarmCode: ProductionMonitoringEntityData.alarms[i].alarmCode,
|
||||
alarmTime: new Date(ProductionMonitoringEntityData.alarms[i].alarmTime).toLocaleDateString(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//sumProductionDets
|
||||
state.sumProductionDets = ProductionMonitoringEntityData.sumProductionDets;
|
||||
|
||||
//todayProductionDets
|
||||
state.todayProductionDets = ProductionMonitoringEntityData.todayProductionDets;
|
||||
|
||||
|
||||
//weekProductionDets
|
||||
state.weekProductionDets = ProductionMonitoringEntityData.weekProductionDets;
|
||||
|
||||
//monthProductionDets
|
||||
state.monthProductionDets = ProductionMonitoringEntityData.monthProductionDets;
|
||||
|
||||
//todayProductionRates
|
||||
state.todayProductionRates = ProductionMonitoringEntityData.todayProductionRates;
|
||||
|
||||
//weekProductionRates
|
||||
state.weekProductionRates = ProductionMonitoringEntityData.weekProductionRates;
|
||||
|
||||
//monthProductionRates
|
||||
state.monthProductionRates = ProductionMonitoringEntityData.monthProductionRates;
|
||||
|
||||
}
|
||||
},
|
||||
UpdateGlassStatus: (state, action) => {
|
||||
//lineGlassStatus
|
||||
state.lineGlassStatus = action.payload;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const {UpdateProductionMonitoringEntity, UpdateGlassStatus} = ProductionMonitoringEntity.actions;
|
||||
|
||||
export const selectAlarms = (state: RootState) => state.ProductionMonitoringEntity.alarms;
|
||||
export const selectSumNumber = (state: RootState) => state.ProductionMonitoringEntity.sumNumber;
|
||||
export const selectSumProductionDets = (state: RootState) => state.ProductionMonitoringEntity.sumProductionDets;
|
||||
export const selectTodayProductionDets = (state: RootState) => state.ProductionMonitoringEntity.todayProductionDets;
|
||||
export const selectWeekProductionDets = (state: RootState) => state.ProductionMonitoringEntity.weekProductionDets;
|
||||
export const selectMonthProductionDets = (state: RootState) => state.ProductionMonitoringEntity.monthProductionDets;
|
||||
export const selectTodayProductionRates = (state: RootState) => state.ProductionMonitoringEntity.todayProductionRates;
|
||||
export const selectWeekProductionRates = (state: RootState) => state.ProductionMonitoringEntity.weekProductionRates;
|
||||
export const selectMonthProductionRates = (state: RootState) => state.ProductionMonitoringEntity.monthProductionRates;
|
||||
export const selectGlassStatus = (state: RootState) => state.ProductionMonitoringEntity.lineGlassStatus;
|
||||
export default ProductionMonitoringEntity.reducer;
|
||||
112
src/store/UpdateData.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useState } from "react";
|
||||
import axios from "axios";
|
||||
import {
|
||||
UpdateEqRateAVA,
|
||||
UpdateOrderCompletionWO,
|
||||
UpdateDefectsClassDEFECT,
|
||||
UpdateProductionBarChart,
|
||||
UpdateTempAndHumidityTEMP,
|
||||
UpdatePowerDistributionpow,
|
||||
UpdateOutputFUCH,
|
||||
UpdateOutputMsgBOX,
|
||||
UpdateYield,
|
||||
} from "./HomePageSlice";
|
||||
import { useAppDispatch } from "./hooks";
|
||||
|
||||
function UpdateData() {
|
||||
// const [myUrl, setUrl] = useState("");
|
||||
// axios.get("/wsconfig.json").then((r) => {
|
||||
// setUrl(r.data.url);
|
||||
// });
|
||||
const myUrl = window.location.host;
|
||||
let websocketHome = null;
|
||||
if ("WebSocket" in window) {
|
||||
websocketHome = new WebSocket(
|
||||
"ws://" + myUrl + "/websocket/message?userId=DC" + new Date().getTime()
|
||||
);
|
||||
//连接成功建立的回调方法
|
||||
} else {
|
||||
alert("Not support websocket");
|
||||
}
|
||||
// @ts-ignore
|
||||
websocketHome.onopen = function (event) {
|
||||
console.log("websocketHome-open");
|
||||
};
|
||||
interface MsgDataType {
|
||||
type: string;
|
||||
}
|
||||
// const [msgData, setMsgData] = useState<MsgDataType | null>(null);
|
||||
//接收到消息的回调方法
|
||||
// @ts-ignore
|
||||
websocketHome.onmessage = function (event) {
|
||||
// console.log("接收到消息:", event);
|
||||
let msgData: MsgDataType = { type: "example" };
|
||||
try {
|
||||
msgData = JSON.parse(event.data);
|
||||
} catch (error) {
|
||||
console.log("websocket: [unable to msgData] : ", event.data);
|
||||
}
|
||||
if (!msgData) return;
|
||||
switch (msgData?.type) {
|
||||
case "AVA": {
|
||||
// 设备稼动率
|
||||
// @ts-ignore
|
||||
dispatch(UpdateEqRateAVA(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "WO": {
|
||||
// 封装工单完成情况
|
||||
// @ts-ignore
|
||||
dispatch(UpdateOrderCompletionWO(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "DEFECT": {
|
||||
// 产线缺陷分类
|
||||
// @ts-ignore
|
||||
dispatch(UpdateDefectsClassDEFECT(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "OUT": {
|
||||
// 产量柱状图
|
||||
// @ts-ignore
|
||||
dispatch(UpdateProductionBarChart(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "TEMP": {
|
||||
// 温湿度
|
||||
// @ts-ignore
|
||||
dispatch(UpdateTempAndHumidityTEMP(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "POW": {
|
||||
// FUCH功率分布
|
||||
// @ts-ignore
|
||||
dispatch(UpdatePowerDistributionpow(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "FUCH": {
|
||||
// FUCH产出
|
||||
// @ts-ignore
|
||||
dispatch(UpdateOutputFUCH(msgData));
|
||||
break;
|
||||
}
|
||||
case "BOX": {
|
||||
// 下片分档信息
|
||||
// @ts-ignore
|
||||
dispatch(UpdateOutputMsgBOX(msgData.data));
|
||||
break;
|
||||
}
|
||||
case "YIELD": {
|
||||
// 前中后段良率
|
||||
// @ts-ignore
|
||||
dispatch(UpdateYield(msgData.data));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
};
|
||||
const dispatch = useAppDispatch();
|
||||
return null;
|
||||
}
|
||||
|
||||
export default UpdateData;
|
||||
6
src/store/hooks.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||
import type { RootState, AppDispatch } from './store';
|
||||
|
||||
// Use throughout your app instead of plain `useDispatch` and `useSelector`
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
19
src/store/store.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import ProductionMonitoringEntityReducer from "./ProductionMonitoringEntity";
|
||||
import ChangeLineIDReducer from "./ChangeLineID";
|
||||
// import QualityMonitorEntityReducer from "./QualityMonitorEntity";
|
||||
import EquStatusEntityReducer, { EquStatusEntity } from "./EquStatusEntity";
|
||||
import HomePageReducer from "./HomePageSlice";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
ProductionMonitoringEntity: ProductionMonitoringEntityReducer,
|
||||
ChangeLineID: ChangeLineIDReducer,
|
||||
// QualityMonitorEntity: QualityMonitorEntityReducer,
|
||||
EquStatusEntity: EquStatusEntityReducer,
|
||||
HomePageSlice: HomePageReducer,
|
||||
},
|
||||
});
|
||||
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||