Compare commits

...

18 Commits

Author SHA1 Message Date
zwq
025366bb65 更新折线图显示数值 2025-08-26 16:04:56 +08:00
gtz
aaa420822d 1 2025-08-25 15:33:01 +08:00
5feeded363 Merge pull request '改变链接位置,改成在每个页面链接' (#7) from zjl into master
Reviewed-on: #7
2025-03-06 08:29:19 +08:00
40791bc619 改变链接位置,改成在每个页面链接 2025-03-06 08:27:31 +08:00
60786f59b8 Merge pull request '接口后面加随机数' (#6) from zjl into master
Reviewed-on: #6
2025-02-27 08:57:40 +08:00
45c8563892 接口后面加随机数 2025-02-27 08:54:31 +08:00
bff87fbcee Merge pull request 'zjl' (#5) from zjl into master
Reviewed-on: #5
2025-02-21 16:04:53 +08:00
288e2c8e04 消除警告信息 2025-02-21 16:03:07 +08:00
84b34d7b79 删除多余代码 2025-02-21 13:26:56 +08:00
1812afd680 2.21日版 2025-02-21 11:10:35 +08:00
128b362587 1 2024-12-06 17:22:49 +08:00
e8ca7d16ee 修改 2024-11-29 10:34:06 +08:00
1f7b867dc5 三维接口调试 2024-11-01 10:35:32 +08:00
022bf57feb 5个页面的ws接口 2024-10-29 14:38:12 +08:00
d142b16df3 1-1对接接口 2024-09-12 16:14:54 +08:00
c12c0e72e9 Merge pull request 'zjl' (#4) from zjl into master
Reviewed-on: #4
2024-09-11 10:18:49 +08:00
0dcff0c256 假数据版本 2024-09-11 10:16:17 +08:00
b6fb156c2c 修改 2024-08-29 15:12:39 +08:00
338 changed files with 24115 additions and 33643 deletions

25367
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,7 @@
"@types/node": "^16.11.56", "@types/node": "^16.11.56",
"@types/react": "^18.0.17", "@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"antd": "^5.22.2",
"axios": "^1.3.3", "axios": "^1.3.3",
"babel-jest": "^27.4.2", "babel-jest": "^27.4.2",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
@@ -80,7 +81,7 @@
"workbox-webpack-plugin": "^6.4.1" "workbox-webpack-plugin": "^6.4.1"
}, },
"scripts": { "scripts": {
"start": "node scripts/start.js", "start": "node --max-old-space-size=4096 scripts/start.js",
"build": "node scripts/build.js", "build": "node scripts/build.js",
"test": "node scripts/test.js" "test": "node scripts/test.js"
}, },

Binary file not shown.

Binary file not shown.

View File

@@ -1,177 +0,0 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 3575,
"type": "VEC2"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 3575,
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 3575,
"type": "VEC4"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 3575,
"type": "VEC3",
"max": [
0.009921154,
0.00977163,
0.0100762453
],
"min": [
-0.009921154,
-0.00977163,
-0.0100762453
]
},
{
"bufferView": 4,
"componentType": 5123,
"count": 18108,
"type": "SCALAR"
}
],
"asset": {
"generator": "glTF Tools for Unity",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 28600
},
{
"buffer": 0,
"byteOffset": 28600,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 71500,
"byteLength": 57200
},
{
"buffer": 0,
"byteOffset": 128700,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 171600,
"byteLength": 36216
}
],
"buffers": [
{
"uri": "BoomBox.bin",
"byteLength": 207816
}
],
"images": [
{
"uri": "BoomBox_baseColor.png"
},
{
"uri": "BoomBox_occlusionRoughnessMetallic.png"
},
{
"uri": "BoomBox_normal.png"
},
{
"uri": "BoomBox_emissive.png"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"TEXCOORD_0": 0,
"NORMAL": 1,
"TANGENT": 2,
"POSITION": 3
},
"indices": 4,
"material": 0
}
],
"name": "BoomBox"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
},
"normalTexture": {
"index": 2
},
"occlusionTexture": {
"index": 1
},
"emissiveFactor": [
1.0,
1.0,
1.0
],
"emissiveTexture": {
"index": 3
},
"name": "BoomBox_Mat"
}
],
"nodes": [
{
"mesh": 0,
"rotation": [
0.0,
1.0,
0.0,
0.0
],
"scale": [ 1, 1, 1 ],
"name": "BoomBox"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"name": "baseColor",
"source": 0
},
{
"name": "occlusionRoughnessMetallic",
"source": 1
},
{
"name": "normal",
"source": 2
},
{
"name": "emissive",
"source": 3
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 MiB

View File

@@ -1,183 +0,0 @@
{
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 3575,
"type": "VEC2"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 3575,
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5126,
"count": 3575,
"type": "VEC4"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 3575,
"type": "VEC3",
"max": [
0.009921154,
0.00977163,
0.0100762453
],
"min": [
-0.009921154,
-0.00977163,
-0.0100762453
]
},
{
"bufferView": 4,
"componentType": 5123,
"count": 18108,
"type": "SCALAR"
}
],
"asset": {
"generator": "glTF Tools for Unity",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 28600
},
{
"buffer": 0,
"byteOffset": 28600,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 71500,
"byteLength": 57200
},
{
"buffer": 0,
"byteOffset": 128700,
"byteLength": 42900
},
{
"buffer": 0,
"byteOffset": 171600,
"byteLength": 36216
}
],
"buffers": [
{
"uri": "BoomBox.bin",
"byteLength": 207816
}
],
"extensionsUsed": [
"KHR_materials_unlit"
],
"images": [
{
"uri": "BoomBox_baseColor.png"
},
{
"uri": "BoomBox_occlusionRoughnessMetallic.png"
},
{
"uri": "BoomBox_normal.png"
},
{
"uri": "BoomBox_emissive.png"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"TEXCOORD_0": 0,
"NORMAL": 1,
"TANGENT": 2,
"POSITION": 3
},
"indices": 4,
"material": 0
}
],
"name": "BoomBox"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1
}
},
"normalTexture": {
"index": 2
},
"occlusionTexture": {
"index": 1
},
"emissiveFactor": [
1.0,
1.0,
1.0
],
"emissiveTexture": {
"index": 3
},
"name": "BoomBox_Mat",
"extensions": {
"KHR_materials_unlit": {}
}
}
],
"nodes": [
{
"mesh": 0,
"rotation": [
0.0,
1.0,
0.0,
0.0
],
"scale": [ 1, 1, 1 ],
"name": "BoomBox"
}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"name": "baseColor",
"source": 0
},
{
"name": "occlusionRoughnessMetallic",
"source": 1
},
{
"name": "normal",
"source": 2
},
{
"name": "emissive",
"source": 3
}
]
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -14,7 +14,7 @@
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> -->
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>数智工厂生产监控驾驶舱</title>
</head> </head>
<body style="overflow: hidden"> <body style="overflow: hidden">
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

Binary file not shown.

Binary file not shown.

BIN
public/png/numberBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

75
public/svg/topbackLD.svg Normal file
View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1920px" height="93.0031818px" viewBox="0 0 1920 93.0031818" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 11</title>
<defs>
<linearGradient x1="50%" y1="-2.22044605e-14%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#081C43" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#27778E" stop-opacity="0.205883769" offset="57.0640297%"></stop>
<stop stop-color="#37A5B4" stop-opacity="0.311188811" offset="100%"></stop>
</linearGradient>
<linearGradient x1="98.361014%" y1="49.8254916%" x2="-6.66133815e-14%" y2="49.7796521%" id="linearGradient-2">
<stop stop-color="#3797C6" stop-opacity="0.31441215" offset="0%"></stop>
<stop stop-color="#52FFF1" offset="100%"></stop>
</linearGradient>
<linearGradient x1="103.601203%" y1="50.6276601%" x2="-6.66133815e-14%" y2="49.5379248%" id="linearGradient-3">
<stop stop-color="#31A6AE" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#31A6AE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="98.361014%" y1="49.8437805%" x2="-6.66133815e-14%" y2="49.8027451%" id="linearGradient-4">
<stop stop-color="#3797C6" stop-opacity="0.31441215" offset="0%"></stop>
<stop stop-color="#52FFF1" offset="100%"></stop>
</linearGradient>
<linearGradient x1="103.601203%" y1="51.0279165%" x2="-6.66133815e-14%" y2="49.2432614%" id="linearGradient-5">
<stop stop-color="#3797C6" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#31A6AE" offset="100%"></stop>
</linearGradient>
<linearGradient x1="103.601203%" y1="50.0057357%" x2="-6.66133815e-14%" y2="49.9957774%" id="linearGradient-6">
<stop stop-color="#31A6AE" offset="0%"></stop>
<stop stop-color="#3797C6" stop-opacity="0" offset="100%"></stop>
</linearGradient>
<linearGradient x1="103.601203%" y1="50.03033%" x2="-6.66133815e-14%" y2="49.9776715%" id="linearGradient-7">
<stop stop-color="#31A6AE" offset="0%"></stop>
<stop stop-color="#3797C6" stop-opacity="0" offset="100%"></stop>
</linearGradient>
</defs>
<g id="洛阳" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-11">
<polygon id="路径-5" fill="url(#linearGradient-1)" points="1.90545852e-13 -4.50993001e-15 2.88853814e-14 31.7045455 82.7768328 31.7045455 120.694098 57.9834285 585.064327 57.9834285 633.594326 93 1284.71703 93 1333.41502 57.5262217 1517.36351 57.5262217 1554.66659 31.7045455 1866 31.7045455 1866 1.08915917e-12"></polygon>
<g id="编组-12">
<g id="编组-8" transform="translate(711.263222, 24.306818)"></g>
<g id="编组-4" transform="translate(0.750956, 31.704545)">
<polyline id="路径-9" stroke="url(#linearGradient-2)" stroke-width="2.12" points="1866.47546 1.64272616e-13 1556.20507 -1.48645149e-14 1518.30238 26.2788831 1332.03314 26.2788831 1284.10896 60.2386364 959.060954 60.2386364"></polyline>
<g id="编组-29" transform="translate(1426.559836, 49.142045) scale(-1, 1) translate(-1426.559836, -49.142045) translate(1331.116205, 38.045455)">
<polyline id="路径-10" stroke="url(#linearGradient-3)" stroke-width="2.12" points="190.887262 22.1931818 166.031081 4.22727273 4.00078371 4.22727273"></polyline>
<ellipse id="椭圆形" fill="#31A6AE" cx="4.00078371" cy="4.22727273" rx="4.00078371" ry="4.22727273"></ellipse>
</g>
<polyline id="路径-9" stroke="url(#linearGradient-4)" stroke-width="2.12" transform="translate(479.530477, 30.119318) scale(-1, 1) translate(-479.530477, -30.119318) " points="959.060954 -1.33756642e-14 876.066883 -4.67997966e-14 838.164187 26.2788831 373.972385 26.2788831 326.048198 60.2386364 -4.54174955e-13 60.2386364"></polyline>
<g id="编组-28" transform="translate(114.894416, 36.988636)">
<polyline id="路径-10" stroke="url(#linearGradient-5)" stroke-width="2.12" points="472.111287 23.25 447.255105 5.28409091 326.074844 5.28409091"></polyline>
<ellipse id="椭圆形" fill="#31A6AE" cx="321.073864" cy="5.28409091" rx="4.00078371" ry="4.22727273"></ellipse>
<ellipse id="椭圆形备份" fill="#31A6AE" cx="233.056623" cy="5.28409091" rx="4.00078371" ry="4.22727273"></ellipse>
<g id="编组-2" transform="translate(247.059366, 0.000000)" fill="#31A6AE">
<polygon id="路径-11" points="51.8543795 6.33584094e-14 48.0094045 0 56.5647535 10.5681818 60.0117556 10.5681818"></polygon>
<polygon id="路径-11备份" opacity="0.8" points="39.8520284 6.33584094e-14 36.0070534 0 44.5624024 10.5681818 48.0094045 10.5681818"></polygon>
<polygon id="路径-11备份-3" opacity="0.4" points="15.8473261 6.33584094e-14 12.0023511 0 20.5577001 10.5681818 24.0047022 10.5681818"></polygon>
<polygon id="路径-11备份-2" opacity="0.601434" points="27.8496773 6.33584094e-14 24.0047022 0 32.5600513 10.5681818 36.0070534 10.5681818"></polygon>
<polygon id="路径-11备份-4" opacity="0.201434" points="3.84497501 6.33584094e-14 4.67611706e-16 0 8.55534901 10.5681818 12.0023511 10.5681818"></polygon>
</g>
<line x1="229.055839" y1="4.75568182" x2="0.354627912" y2="5.28409091" id="路径-12" stroke="url(#linearGradient-6)" stroke-width="2.12"></line>
</g>
<g id="编组-3" transform="translate(117.896179, 0.000000)">
<g id="编组-2备份" fill="#31A6AE">
<polygon id="路径-11" points="77.7815693 9.50376141e-14 72.0141067 0 84.8471303 15.8522727 90.0176334 15.8522727"></polygon>
<polygon id="路径-11备份" opacity="0.8" points="59.7780426 9.50376141e-14 54.0105801 0 66.8436036 15.8522727 72.0141067 15.8522727"></polygon>
<polygon id="路径-11备份-3" opacity="0.4" points="23.7709892 9.50376141e-14 18.0035267 0 30.8365502 15.8522727 36.0070534 15.8522727"></polygon>
<polygon id="路径-11备份-2" opacity="0.601434" points="41.7745159 9.50376141e-14 36.0070534 0 48.8400769 15.8522727 54.0105801 15.8522727"></polygon>
<polygon id="路径-11备份-4" opacity="0.201434" points="5.76746252 9.50376141e-14 7.01417559e-16 0 12.8330235 15.8522727 18.0035267 15.8522727"></polygon>
</g>
<line x1="103.02018" y1="7.92613636" x2="203.018671" y2="8.45454545" id="路径-13" stroke="url(#linearGradient-7)" stroke-width="2.12"></line>
</g>
</g>
<rect id="矩形" stroke="#979797" stroke-width="1.06" opacity="0" x="0.53" y="0.53" width="1918.94" height="91.94"></rect>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 971 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 942 KiB

View File

@@ -1,3 +1,3 @@
{ {
"url": "india.mes.picaiba.com/api/" "url": "192.168.8.22"
} }

View File

@@ -1,114 +1,97 @@
import React, {useEffect, useState, useContext} from 'react'; import { useEffect } from "react";
import intl from 'react-intl-universal'; import "./App.css";
import locales from "./locales/locales"; import { createHashRouter, RouterProvider } from "react-router-dom";
import './App.css';
import {useAppSelector} from "./store/hooks";
import {selectChangeLangAndCss} from "./store/ChangeLangAndCss";
import {createBrowserRouter, RouterProvider,} from "react-router-dom";
import ErrorPage from "./page/ErrorPage"; import ErrorPage from "./page/ErrorPage";
import MainP from "./page/MainP/MainP"; import { MyObservable } from "./context/MyObservable";
import MainE from "./page/MainE/MainE"; import { Observable } from "@babylonjs/core";
import MainQ from "./page/MainQ/MainQ"; import LDPage from "./page/LDPage";
import SwitchAll from "./page/AutoSwitch/SwitchAll"; import LinePageOneOne from "./page/LinePage1-1";
import SwitchLine from "./page/AutoSwitch/SwitchLine"; import LinePageOneTwo from "./page/LinePage1-2";
import {MyObservable} from "./context/MyObservable"; import LinePageTwoOne from "./page/LinePage2-1";
import {Observable} from "@babylonjs/core"; import LinePageTwoTwo from "./page/LinePage2-2";
import {selectGlassStatus} from "./store/ProductionMonitoringEntity"; import LinePageThreeOne from "./page/LinePage3-1";
import TestPage from "./page/TestPage"; import LinePageThreeTwo from "./page/LinePage3-2";
import LDPage from "./page/LDPage" import LinePageFourOne from "./page/LinePage4-1";
import LinePage from './page/LinePage'; import LinePageFourTwo from "./page/LinePage4-2";
import LinePageFiveOne from "./page/LinePage5-1";
// const LOCALES_LIST = [ import LinePageFiveTwo from "./page/LinePage5-2";
// {
// label: "English",
// value: "en-US",
// },
// {
// label: "简体中文",
// value: "zh-CN",
// },
// ];
const onGlassObservable = new Observable(); const onGlassObservable = new Observable();
function App() { function App() {
const thisLineGlassStatus = useAppSelector(selectGlassStatus)
onGlassObservable.notifyObservers(thisLineGlassStatus)
const Locale = useAppSelector(selectChangeLangAndCss).Locale; const router = createHashRouter([
const setCurrentLocale = (currentLocale: string) => {
intl.init({
currentLocale,
locales: locales,
}).then(() => {
console.log('Language Changed to ' + currentLocale);
});
};
setCurrentLocale(Locale);
const router = createBrowserRouter([
{
path: "/",
element: <MainP/>,
errorElement: <ErrorPage/>
},
{
path: "/P",
element: <MainP/>,
errorElement: <ErrorPage/>
},
{
path: "/Q",
element: <MainQ/>,
errorElement: <ErrorPage/>
},
{
path: "/E/:LineID?",
element: <MainE/>,
errorElement: <ErrorPage/>
},
///////////////////////////////////////////////////////////////////////////
{
path: "/SA",
element: <SwitchAll/>,
errorElement: <ErrorPage/>
},
{
path: "/SL/:LineID?",
element: <SwitchLine/>,
errorElement: <ErrorPage/>
},
/////////////////////////////////////////////////////////////////////////////
{
path: "/TP/:LineID?",
element: <TestPage/>,
errorElement: <ErrorPage/>
},
{ {
path: "/LD", path: "/LD",
element: <LDPage/>, element: <LDPage />,
errorElement: <ErrorPage/> errorElement: <ErrorPage />,
}, },
///////////////////////////////////////////////////////////////
{ {
path: "/LP/:LineID?", path: "/LP/1-1",
element: <LinePage/>, element: <LinePageOneOne />,
errorElement: <ErrorPage/> errorElement: <ErrorPage />,
},
{
path: "/LP/1-2",
element: <LinePageOneTwo />,
errorElement: <ErrorPage />,
},
{
path: "/LP/2-1",
element: <LinePageTwoOne />,
errorElement: <ErrorPage />,
},
{
path: "/LP/2-2",
element: <LinePageTwoTwo />,
errorElement: <ErrorPage />,
},
{
path: "/LP/3-1",
element: <LinePageThreeOne />,
errorElement: <ErrorPage />,
},
{
path: "/LP/3-2",
element: <LinePageThreeTwo />,
errorElement: <ErrorPage />,
},
{
path: "/LP/4-1",
element: <LinePageFourOne />,
errorElement: <ErrorPage />,
},
{
path: "/LP/4-2",
element: <LinePageFourTwo />,
errorElement: <ErrorPage />,
},
{
path: "/LP/5-1",
element: <LinePageFiveOne />,
errorElement: <ErrorPage />,
},
{
path: "/LP/5-2",
element: <LinePageFiveTwo />,
errorElement: <ErrorPage />,
}, },
// {
// path: "/TP/:LineID?",
// element: <TestPage/>,
// errorElement: <ErrorPage/>
// },
]); ]);
useEffect(() => {
const timerId = setInterval(() => {
window.location.reload();
}, 43200000);
return () => {
clearInterval(timerId);
};
}, []);
return ( return (
<MyObservable.Provider value={onGlassObservable}> <MyObservable.Provider value={onGlassObservable}>
<div className="background"> <div className="background">
<RouterProvider router={router}/> <RouterProvider router={router} />
</div> </div>
</MyObservable.Provider> </MyObservable.Provider>
); );

View File

@@ -1,101 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Babylon.js Product Page Demo</title>
<!-- <link rel="stylesheet" href="https://use.typekit.net/pyp7dhw.css"> -->
<link href='https://d33wubrfki0l68.cloudfront.net/css/c204e345dce3e9e660ec5e23ae93696b9c5b9d42/demos/productpage/styles.css'
rel='stylesheet' type='text/css'/>
<script src="https://use.typekit.net/pyp7dhw.js"></script>
<script>try {
Typekit.load({async: false});
} catch (e) {
}</script>
<script src="https://preview.babylonjs.com/babylon.js"></script>
<script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
<script src="https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js"></script>
<script src="https://preview.babylonjs.com/gui/babylon.gui.js"></script>
<script src="https://code.jquery.com/pep/0.4.3/pep.js"></script>
</head>
<body>
<canvas id="renderCanvas" touch-action="none"></canvas> <!-- touch-action="none" for best results from PEP -->
<script src='https://d33wubrfki0l68.cloudfront.net/bundles/67cad91c66fe8e5633757e23e16f4220bf108fb5.js'></script>
<div id="header">
<div class="headerContent">
<a href="https://www.babylonjs.com/"><img src="assets/textures/babylonLogo_48px.svg"/></a><span id="headerType">eCommerce Product Demo</span>
</div>
</div>
<div id="htmlLayer">
<div id="loader">
<div class="lds-ripple">
<div></div>
<div></div>
</div>
<div id="loadingText">
<h1>Loading...</h1>
</div>
</div>
<div id="block_1">&nbsp;
<h1 id="head_1" class="track">Interactive Product Pages</h1>
<p>Babylon.js gives you all the power you need to create realistic interactive experiences for your product's
audience. Leverage the power of 3D rendering empowered by animation,
behaviors, audio, video, and a full GUI layer.
</p>
</div>
<div id="bg1">
<div id="block_2">
<h1 id="head_2" class="track">PBR Node Materials</h1>
<p>Create custom shaders for your assets using the node materials with full support for physically based
rendering materials. This includes support for
image-based lighting, real-time environment probes, subsurface translucency, refraction, and more!
</p>
</div>
<div id="block_3">
<h1 id="head_3" class="track">Advanced PBR Features</h1>
<p>Node material's physically-based rendering supports advanced features like clearcoat and sheen. Enjoy the
flexibility of creating custom shaders to unlock complete creative freedom while retaining the ability
to
render a wide range of materials accurately.
</p>
</div>
</div>
<div id="bg2">
<div id="block_4">
<h1 id="head_4" class="track">Procedural Textures</h1>
<p>Node materials can now create procedural textures to be used as you wish. A custom procedural texture
created in the node material editor is being used to morph between materials on this asset. Notice
how the morph is always different due to our custom shader allowing us to change the procedural texture
every time we use it.
</p>
</div>
</div>
<div id="bg3">
<div id="block_5">
<h1 id="head_5" class="track">Animating Material Parameters</h1>
<p>Node materials allow us to manipulate parameters directly or through animation. This enables interations
such as the animated ring light in the demo asset. We are also able to tie this animation into our post
processing like the glow layer you see here. And we still retain the ability to add all of this
functionality to PBR materials for the best possible rendering.
</p>
</div>
<div id="block_6">
<h1 id="head_6" class="track">GUI Controls in Materials</h1>
<p>Babylon.js also allows you to put GUI controls directly into our materials used on a mesh. You can see
how we can make a fully function product demo by displaying the actual time and date on the device
screen.
</p>
</div>
</div>
</div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
import React from 'react'
import intl from 'react-intl-universal';
const BasicComponent: React.FC<any> = () => {
return (
<div>
<div className="title">Basic Examples:</div>
<div>{intl.get('SIMPLE')}</div>
<div>{intl.get('HELLO', { name: 'Tony', where: 'Alibaba' })}</div>
</div>
);
}
export default BasicComponent;

View File

@@ -1,14 +0,0 @@
import React from 'react'
import intl from 'react-intl-universal';
const CurrencyComponent: React.FC<any> = () => {
let price = 123456.78;
return (
<div>
<div className="title">Currency Example:</div>
<div>{intl.get('SALE_PRICE', { price })}</div>
</div>
)
}
export default CurrencyComponent;

View File

@@ -1,18 +0,0 @@
import React from 'react'
import intl from 'react-intl-universal';
const DateComponent: React.FC<any> = () => {
const start = new Date();
const end = new Date();
const expires = new Date();
return (
<div>
<div className="title">Date Examples:</div>
<div>{intl.get('SALE_START', { start })}</div>
<div>{intl.get('SALE_END', { end })}</div>
<div>{intl.get('COUPON', { expires })}</div>
</div>
)
}
export default DateComponent;

View File

@@ -1,15 +0,0 @@
import React from 'react'
import intl from 'react-intl-universal';
const HtmlComponent: React.FC<any> = () => {
return (
<div>
<div className="title">Html Examples:</div>
<div>{intl.getHTML('TIP')}</div>
<div>{intl.getHTML('TIP_VAR', { message: 'HTML with variables' })}</div>
<div>{intl.getHTML('TIP_VAR', { message: '<script>alert("ReactIntlUniversal prevents from xss attack")</script>' })}</div>
</div>
);
}
export default HtmlComponent;

View File

@@ -1,13 +0,0 @@
import React from 'react';
import util from '../core/util';
const MessageNotInComponent: React.FC<any> = () => {
return (
<div>
<div className="title">Message Not in Component Example:</div>
<div>{util.getMessage()}</div>
</div>
)
}
export default MessageNotInComponent;

View File

@@ -1,15 +0,0 @@
import React from 'react'
import intl from 'react-intl-universal';
const PluralComponent: React.FC<any> = () => {
return (
<div>
<div className="title">Plural Examples:</div>
<div>{intl.get("PHOTO", { photoNum: 0 })}</div>
<div>{intl.get("PHOTO", { photoNum: 1 })}</div>
<div>{intl.get("PHOTO", { photoNum: 1000000 })}</div>
</div>
);
}
export default PluralComponent;

View File

@@ -1,7 +0,0 @@
import intl from 'react-intl-universal';
const util = {
getMessage: () => intl.get('MESSAGE_NOT_IN_COMPONENT'),
};
export default util;

View File

@@ -1,41 +0,0 @@
import React, {useEffect, useState} from "react";
import intl from 'react-intl-universal';
import locales from "../locales/locales";
import useForceUpdate from 'use-force-update';
import BasicComponent from "./components/basic";
function Test() {
const forceUpdate = useForceUpdate();
useEffect(() => {
setthetext();
})
const setthetext = ()=>{
let currenttext = "zh-CN";
setCurrentLocale(currenttext);
};
const setCurrentLocale = (currentLocale: string) => {
intl.init({
currentLocale,
locales: locales,
});
};
const OnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setCurrentLocale(e.target.value)
forceUpdate();
}
return (
<div>
<select onChange={OnChange}>
<option value={"zh-CN"}></option>
<option value={"en-US"}></option>
</select>
<div id='name'>{intl.get('SIMPLE')}</div>
<BasicComponent/>
</div>
)
}
export default Test;

View File

@@ -1,77 +0,0 @@
import React, {useEffect, useState} from "react";
import intl from 'react-intl-universal';
import useForceUpdate from 'use-force-update';
import locales from "../locales/locales";
import BasicComponent from "./components/basic";
const LOCALES_LIST = [
{
label: "English",
value: "en-US",
},
{
label: "简体中文",
value: "zh-CN",
},
];
function Test2() {
const forceUpdate = useForceUpdate();
const [initDone, setInitDone] = React.useState(false);
useEffect(() => {
initializeIntl();
})
const initializeIntl = () => {
// 1. Get the currentLocale from url, cookie, or browser setting
let currentLocale = intl.determineLocale({
urlLocaleKey: 'lang', // Example: https://fe-tool.com/react-intl-universal?lang=en-US
cookieLocaleKey: 'lang', // Example: "lang=en-US" in cookie
});
// 2. Fallback to "en-US" if the currentLocale isn't supported in LOCALES_LIST
if (!LOCALES_LIST.some(item => item.value === currentLocale)) {
currentLocale = "en-US"
}
// 3. Set currentLocale and load locale data
setCurrentLocale(currentLocale);
// 4. After loading locale data, start to render
setInitDone(true);
}
const setCurrentLocale = (currentLocale: string) => {
intl.init({
currentLocale,
locales: locales,
});
};
const onLocaleChange = (e: React.ChangeEvent<HTMLSelectElement>)=>{
setCurrentLocale(e.target.value);
forceUpdate();
}
const localeSelector = (
<select onChange={onLocaleChange} defaultValue="">
<option value="" disabled>Change Language</option>
{LOCALES_LIST.map(locale=>(
<option key={locale.value} value={locale.value}>{locale.label}</option>
))}
</select>
);
return (
<div>
{initDone && (
<div className="react-intl-universal-example">
{localeSelector}
<BasicComponent/>
</div>
)}
</div>
);
}
export default Test2;

View File

@@ -0,0 +1,441 @@
import { useEffect, useRef, useState } 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 { HemisphericLight, Vector3 } from "@babylonjs/core";
import { useAppSelector } from "../store/hooks";
import "../page/style/standard.css";
import AlarmTipGreen from "./../page/assets/icon/g.png";
import AlarmTipYellow from "./../page/assets/icon/y.png";
import AlarmTipRed from "./../page/assets/icon/r.png";
import { selectLine1Before } from "../store/LinePageSlice";
import { selectAllLine } from "../store/LeaderPageSlice";
const myStyle = {
width: "1041px",
height: "599px",
outline: "none",
};
interface MybabylonJSProps {
modelPath: string; // 明确 modelPath 属性的类型为 string
}
interface EqListType {
[key: string]: EqMsg
}
interface EqMsg {
equipmentName?:string;
run?:boolean;
error?:boolean;
inputNum?:number;
outputNum?:number;
quantityTime?:number;
status?:string;
statusTime?:number;
localDateTime?:number;
equipmentCode?:string;
equipmentId?:number;
num?:number;
}
function MybabylonJS({ modelPath }: MybabylonJSProps) {
const [eqList, setEqList] = useState<EqListType>({});
const allEquStatus = useAppSelector(selectLine1Before) as any;
const allData = useAppSelector(selectAllLine) as any; // 使用`any`来绕过类型检查
const canvasRef = useRef(null);
const resetRef = useRef<(() => void) | null>(null);
const [numAlarm, setNumAlarm] = useState('0');
const [monthNum, setMonthNum] = useState('0');
const [todayNum, setTodayNum] = useState('0');
const [yieldNum, setYieldNum] = useState('0');
const [selectedMeshName, setSelectedMeshName] = useState<string | null>(null);
const [selectedMeshId, setSelectedMeshId] = useState<string | null>(null);
const [selectedMeshObj, setSelectedMeshObj] = useState<EqMsg>({
equipmentName: "",
run: true,
error: false,
num: 0,
});
// 使用 useRef 来存储当前加载的模型引用
const currentMeshesRef = useRef<Array<BABYLON.AbstractMesh>>([]);
useEffect(() => {
const equStatus = allEquStatus?.equStatus;
if (equStatus) {
setEqList(equStatus);
}
},[allEquStatus])
// 中间顶部数据
useEffect(() => {
const numAlarm = allData?.numAlarm;
setNumAlarm(numAlarm || '0');
const monthMap = allData?.monthMap;
setMonthNum(monthMap?.output || '0');
const todayMap = allData?.todayMap;
setTodayNum(todayMap?.output || '0');
setYieldNum(todayMap?.Yield || '0');
},[allData])
useEffect(() => {
if (selectedMeshId && eqList[selectedMeshId]) {
setSelectedMeshObj({
equipmentName:eqList[selectedMeshId].equipmentName,
run:eqList[selectedMeshId].run ? eqList[selectedMeshId].run : true,
error:eqList[selectedMeshId].error ? eqList[selectedMeshId].error : false,
num:eqList[selectedMeshId].inputNum ? eqList[selectedMeshId].inputNum : (eqList[selectedMeshId].outputNum ? eqList[selectedMeshId].outputNum : 0),
});
}
},[selectedMeshId])
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 = 1;
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",
BABYLON.Tools.ToRadians(270),
BABYLON.Tools.ToRadians(25),
220,
new BABYLON.Vector3(0, 0, 10)
);
camera.lowerRadiusLimit = 10;
camera.upperRadiusLimit = 600;
// 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);
// 定义一个函数来加载或重新加载模型
const loadOrReloadModel = async () => {
// 在加载新模型之前卸载已加载的模型
currentMeshesRef.current.forEach((mesh) => {
if (mesh && mesh.parent) {
scene.removeMesh(mesh, true);
}
});
currentMeshesRef.current = []; // 重置模型数组
try {
// 使用 ImportMeshAsync 加载新模型
var LOD0MESH1 = await BABYLON.SceneLoader.ImportMeshAsync(
"",
"/Line/",
"part1.babylon",
scene
);
// 将新加载的模型添加到 currentMeshesRef 中
currentMeshesRef.current.push(...LOD0MESH1.meshes);
var LOD0MESH2 = await BABYLON.SceneLoader.ImportMeshAsync(
"",
"/Line/",
"part2.babylon",
scene
);
currentMeshesRef.current.push(...LOD0MESH2.meshes);
// ...为新加载的模型设置交互逻辑
LOD0MESH1.meshes.forEach((mesh) => {
mesh.isPickable = true;
mesh.actionManager = new BABYLON.ActionManager(scene);
if (modelPath.slice(-1) === "1") {
if (
mesh.name.includes("磨边") ||
mesh.name.includes("清洗") ||
mesh.name.includes("镀膜") ||
mesh.name.includes("固化") ||
mesh.name.includes("丝印") ||
mesh.name.includes("打孔")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
} else {
if (
mesh.name.includes("钢化") ||
mesh.name.includes("包装") ||
mesh.name.includes("铺纸") ||
mesh.name.includes("下片机械手")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
}
// 模型点击事件
mesh._scene.onPointerDown = async (event, _pickResult) => {
console.log('_pickResult',_pickResult)
const pickInfo = mesh._scene.pick(
mesh._scene.pointerX,
mesh._scene.pointerY
);
//判断是否是右键
if (!(event.buttons === 1 && pickInfo.pickedMesh)) return;
const MeshName = pickInfo.pickedMesh.name;
const MeshNameId = pickInfo.pickedMesh.metadata.tags;
setSelectedMeshName(MeshName);
setSelectedMeshId(MeshNameId);
};
});
LOD0MESH2.meshes.forEach((mesh) => {
mesh.isPickable = true;
mesh.actionManager = new BABYLON.ActionManager(scene);
if (modelPath.slice(-1) === "1") {
if (
mesh.name.includes("磨边") ||
mesh.name.includes("清洗") ||
mesh.name.includes("镀膜") ||
mesh.name.includes("固化") ||
mesh.name.includes("丝印") ||
mesh.name.includes("打孔")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
} else {
if (
mesh.name.includes("钢化") ||
mesh.name.includes("包装") ||
mesh.name.includes("铺纸") ||
mesh.name.includes("下片机械手")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
}
// 模型点击事件
mesh._scene.onPointerDown = async (event, _pickResult) => {
console.log('_pickResult',_pickResult)
const pickInfo = mesh._scene.pick(
mesh._scene.pointerX,
mesh._scene.pointerY
);
//判断是否是右键
if (!(event.buttons === 1 && pickInfo.pickedMesh)) return;
const MeshName = pickInfo.pickedMesh.name;
const MeshNameId = pickInfo.pickedMesh.metadata.tags;
setSelectedMeshName(MeshName);
setSelectedMeshId(MeshNameId);
};
});
} catch (error) {
console.error("加载模型失败:", error);
}
};
// 调用函数以加载或重新加载模型
loadOrReloadModel();
function reset() {
camera.target = new BABYLON.Vector3(0, 0, 10);
camera.alpha = BABYLON.Tools.ToRadians(270);
camera.beta = BABYLON.Tools.ToRadians(25);
camera.radius = 220;
setSelectedMeshName(null);
}
// 外部初始位置按钮
resetRef.current = reset;
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();
// run the render loop
scene.then(
(scene) => {
console.log("createScene被调用了=====", scene);
engine.runRenderLoop(function () {
scene.render();
});
},
(reason) => {
console.log("reason=============", reason);
}
);
// Resize
window.addEventListener("resize", function () {
engine.resize();
});
// 组件卸载时的清理逻辑
return () => {
// 清理场景和引擎资源
engine.dispose();
};
}, [modelPath]);
const resetModel = () => {
//模型初始位置
if (resetRef.current) {
resetRef.current();
}
};
function formatNumber(str: string, separator = ',') {
// 使用正则表达式从右到左每隔3位添加分隔符
str = str.toString();
return str.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
}
function toPercentage(decimalStr: string) {
let decimal = parseFloat(decimalStr);
if (isNaN(decimal)) {
throw new Error('Invalid decimal number provided.');
}
let percent = decimal * 100;
let formattedPercent = percent.toFixed(2);
return formattedPercent + '%';
}
return (
<div style={myStyle}>
<div className="model_top_container">
<div className="model_top_style1">
<div className="model_top_num">{toPercentage(yieldNum)}</div>
<div className="model_top_text"></div>
</div>
<div className="model_top_style2">
<div className="model_top_num">{formatNumber(todayNum)}</div>
<div className="model_top_text"></div>
</div>
<div className="model_top_style2">
<div className="model_top_num">{formatNumber(monthNum)}</div>
<div className="model_top_text"></div>
</div>
<div className="model_top_style1">
<div className="model_top_num">{formatNumber(numAlarm)}</div>
<div className="model_top_text"></div>
</div>
</div>
{selectedMeshName && (
<div className="eq_detail_info">
<div>
<span className="left_name"></span>
<span className="right_value">{selectedMeshObj.equipmentName}</span>
</div>
<div>
<span className="left_name">/</span>
<span className="right_value">{selectedMeshObj.num}</span>
</div>
{/* <div>
<span className="left_name">出口数量:</span>
<span className="right_value">1,312</span>
</div> */}
<div>
<span className="left_name"></span>
<span className="right_value">
{selectedMeshObj.error ? (
<>
<img
src={AlarmTipRed}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
) : (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
)}
</span>
</div>
<div>
<span className="left_name">线</span>
<span className="right_value">
{selectedMeshObj.run ? (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
) : (
<>
<img
src={AlarmTipYellow}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
)}
</span>
</div>
</div>
)}
<canvas ref={canvasRef} style={myStyle} />
</div>
);
}
export default MybabylonJS;

445
src/babylonjs/EqInfoData.ts Normal file
View File

@@ -0,0 +1,445 @@
interface EqInfoInterface {
name: string;
data: Array<{ name: string; value: number, code:string, label:string}>;
position: Array<number>;
}
interface EqInfoDataInterface {
[key: string]: Array<EqInfoInterface>;
}
const EqInfoData:EqInfoDataInterface = {
"Line1-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 0, code:'1-edge1', label:'inputNum' },
{ name: "2支线", value: 0, code:'1-edge2', label:'inputNum' },
{ name: "3支线", value: 0, code:'1-edge3', label:'inputNum' },
],
position: [180, 210],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 0, code:'1-edgeclean1', label:'outputNum' },
{ name: "2支线", value: 0, code:'1-edgeclean2', label:'outputNum' },
{ name: "3支线", value: 0, code:'1-edgeclean3', label:'outputNum' },
],
position: [340, 130],
},
{
name: "打孔出口",
data: [
{ name: "1支线", value: 0, code:'1-punch1', label:'outputNum' },
{ name: "2支线", value: 0, code:'1-punch2', label:'outputNum' },
{ name: "3支线", value: 0, code:'1-punch3', label:'outputNum' },
],
position: [590, 300],
},
{
name: "丝印进口",
data: [
{ name: "1支线", value: 0, code:'1-silk1', label:'inputNum' },
{ name: "2支线", value: 0, code:'1-silk2', label:'inputNum' },
{ name: "3支线", value: 0, code:'1-silk3', label:'inputNum' },
],
position: [510, 65],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 0, code:'1-secsolid1', label:'outputNum' },
{ name: "2支线", value: 0, code:'1-secsolid2', label:'outputNum' },
{ name: "3支线", value: 0, code:'1-secsolid3', label:'outputNum' },
],
position: [850, 190],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 0, code:'1-temper1', label:'inputNum' }],
position: [750, 10],
},
],
"Line1-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 0, code:'1-temper1', label:'outputNum' }],
position: [140, 250],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机1_1", value: 0, code:'1-packclean1', label:'inputNum' },
{ name: "包装清洗机1_2", value: 0, code:'1-packclean2', label:'inputNum' },
],
position: [450, 320],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机1_1", value: 0, code:'1-packclean1', label:'outputNum' },
{ name: "包装清洗机1_2", value: 0, code:'1-packclean2', label:'outputNum' },
],
position: [350, 130],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机1_1", value: 0, code:'1-paper1', label:'outputNum' },
{ name: "铺纸机1_2", value: 0, code:'1-paper2', label:'outputNum' },
],
position: [640, 240],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手1_1", value: 0, code:'1-down1', label:'outputNum'},
{ name: "下片机械手1_2", value: 0, code:'1-down2', label:'outputNum'},
{ name: "下片机械手1_3", value: 0, code:'1-down3', label:'outputNum'},
],
position: [570, 10],
},
],
"Line2-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 0, code:'2-edge1', label:'inputNum' },
{ name: "2支线", value: 0, code:'2-edge2', label:'inputNum' },
],
position: [150, 245],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 0, code:'2-edgeclean1', label:'outputNum' },
{ name: "2支线", value: 0, code:'2-edgeclean2', label:'outputNum' },
],
position: [310, 180],
},
{
name: "打孔出口",
data: [
{ name: "1支线", value: 0, code:'2-punch1', label:'outputNum' },
{ name: "2支线", value: 0, code:'2-punch2', label:'outputNum' },
],
position: [540, 300],
},
{
name: "丝印进口",
data: [
{ name: "1支线", value: 0, code:'2-silk1', label:'inputNum' },
{ name: "2支线", value: 0, code:'2-silk2', label:'inputNum' },
],
position: [530, 100],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 0, code:'2-secsolid1', label:'outputNum' },
{ name: "2支线", value: 0, code:'2-secsolid2', label:'outputNum' },
],
position: [850, 170],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 0, code:'2-temper1', label:'inputNum' }],
position: [810, 10],
},
],
"Line2-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 0, code:'2-temper1', label:'outputNum' }],
position: [305, 260],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机", value: 0, code:'2-packclean1', label:'inputNum' },
],
position: [640, 270],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机", value: 0, code:'2-packclean1', label:'outputNum' },
],
position: [550, 140],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机", value: 0, code:'2-paper1', label:'outputNum' },
],
position: [810, 210],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手2_1", value: 0, code:'2-down1', label:'outputNum'},
{ name: "下片机械手2_2", value: 0, code:'2-down2', label:'outputNum'},
],
position: [630, 10],
},
],
"Line3-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 0, code:'3-edge1', label:'inputNum' },
{ name: "2支线", value: 0, code:'3-edge2', label:'inputNum' },
],
position: [150, 225],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 0, code:'3-edgeclean1', label:'outputNum' },
{ name: "2支线", value: 0, code:'3-edgeclean2', label:'outputNum' },
],
position: [380, 150],
},
{
name: "打孔出口",
data: [
{ name: "1支线", value: 0, code:'3-punch1', label:'outputNum' },
{ name: "2支线", value: 0, code:'3-punch2', label:'outputNum' },
],
position: [620, 280],
},
{
name: "丝印进口",
data: [
{ name: "1支线", value: 0, code:'3-silk1', label:'inputNum' },
{ name: "2支线", value: 0, code:'3-silk2', label:'inputNum' },
],
position: [560, 90],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 0, code:'3-secsolid1', label:'outputNum' },
{ name: "2支线", value: 0, code:'3-secsolid2', label:'outputNum' },
],
position: [870, 170],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 0, code:'3-temper1', label:'inputNum' }],
position: [820, 28],
},
],
"Line3-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 0, code:'3-temper1', label:'outputNum' }],
position: [300, 190],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机", value: 0, code:'3-packclean1', label:'inputNum' },
],
position: [580, 250],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机", value: 0, code:'3-packclean1', label:'outputNum' },
],
position: [520, 100],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机", value: 0, code:'3-paper1', label:'outputNum' },
],
position: [760, 190],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手3_1", value: 0, code:'3-down1', label:'outputNum'},
{ name: "下片机械手3_2", value: 0, code:'3-down2', label:'outputNum'},
],
position: [670, 10],
},
],
"Line4-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 0, code:'4-edge1', label:'inputNum' },
{ name: "2支线", value: 0, code:'4-edge2', label:'inputNum' },
],
position: [200, 150],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 0, code:'4-edgeclean1', label:'outputNum' },
{ name: "2支线", value: 0, code:'4-edgeclean2', label:'outputNum' },
],
position: [420, 150],
},
{
name: "一次镀膜进口",
data: [
{ name: "1支线", value: 0, code:'4-fircoat1', label:'inputNum' },
{ name: "2支线", value: 0, code:'4-fircoat2', label:'inputNum' },
],
position: [650, 290],
},
{
name: "二次镀膜进口",
data: [
{ name: "1支线", value: 0, code:'4-seccoat1', label:'inputNum' },
{ name: "2支线", value: 0, code:'4-seccoat2', label:'inputNum' },
],
position: [640, 60],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 0, code:'4-secsolid1', label:'outputNum' },
{ name: "2支线", value: 0, code:'4-secsolid2', label:'outputNum' },
],
position: [860, 190],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 0, code:'4-temper1', label:'inputNum' }],
position: [820, 20],
},
],
"Line4-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 0, code:'4-temper1', label:'outputNum' }],
position: [290, 230],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机", value: 0, code:'4-packclean1', label:'inputNum' },
],
position: [550, 280],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机", value: 0, code:'4-packclean1', label:'outputNum' },
],
position: [500, 130],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机4_1", value: 0, code:'4-paper1', label:'outputNum'},
{ name: "铺纸机4_2", value: 0, code:'4-paper2', label:'outputNum'},
],
position: [765, 210],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手4_1", value: 0, code:'4-down1', label:'outputNum' },
{ name: "下片机械手4_2", value: 0, code:'4-down2', label:'outputNum' },
],
position: [560, 10],
},
],
"Line5-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 0, code:'5-edge1', label:'inputNum' },
{ name: "2支线", value: 0, code:'5-edge2', label:'inputNum' },
{ name: "3支线", value: 0, code:'5-edge3', label:'inputNum' },
],
position: [150, 370],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 0, code:'5-edgeclean1', label:'outputNum' },
{ name: "2支线", value: 0, code:'5-edgeclean2', label:'outputNum' },
{ name: "3支线", value: 0, code:'5-edgeclean3', label:'outputNum' },
],
position: [380, 130],
},
{
name: "一次镀膜进口",
data: [
{ name: "1支线", value: 0, code:'5-fircoat1', label:'inputNum' },
{ name: "2支线", value: 0, code:'5-fircoat2', label:'inputNum' },
{ name: "3支线", value: 0, code:'5-fircoat3', label:'inputNum' },
],
position: [650, 310],
},
{
name: "二次镀膜进口",
data: [
{ name: "1支线", value: 0, code:'5-seccoat1', label:'inputNum' },
{ name: "2支线", value: 0, code:'5-seccoat2', label:'inputNum' },
{ name: "3支线", value: 0, code:'5-seccoat3', label:'inputNum' },
],
position: [640, 20],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 0, code:'5-secsolid1', label:'outputNum' },
{ name: "2支线", value: 0, code:'5-secsolid2', label:'outputNum' },
{ name: "3支线", value: 0, code:'5-secsolid3', label:'outputNum' },
],
position: [850, 220],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 0, code:'5-temper1', label:'inputNum' }],
position: [830, 10],
},
],
"Line5-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 0, code:'5-temper1', label:'outputNum' }],
position: [260, 255],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机5_1", value: 0, code:'5-packclean1', label:'inputNum' },
{ name: "包装清洗机5_2", value: 0, code:'5-packclean2', label:'inputNum' },
],
position: [508, 350],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机5_1", value: 0, code:'5-packclean1', label:'outputNum' },
{ name: "包装清洗机5_2", value: 0, code:'5-packclean2', label:'outputNum' },
],
position: [444, 120],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机5_1", value: 0, code:'5-paper1', label:'outputNum' },
{ name: "铺纸机5_2", value: 0, code:'5-paper2', label:'outputNum' },
],
position: [710, 272],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手5_1", value: 0, code:'5-down1', label:'outputNum'},
{ name: "下片机械手5_2", value: 0, code:'5-down2', label:'outputNum'},
{ name: "下片机械手5_3", value: 0, code:'5-down3', label:'outputNum'},
],
position: [700, 10],
},
],
}
export default EqInfoData

View File

@@ -1,59 +0,0 @@
const EquMap = {
CleanAfterEdge1_1: ['object_1_003'],
CleanAfterEdge1_2: ['object_1_004'],
CleanAfterEdge2_1: ['object_2_003'],
CleanAfterEdge2_2: ['object_2_004'],
CleanAfterEdge3_1: ['object_3_003'],
CleanAfterEdge3_2: ['object_3_004'],
CleanAfterEdge4_1: ['object_4_003'],
CleanAfterEdge4_2: ['object_4_004'],
CleanAfterTemper1_1: ['object_1_026', 'object_1_027'],
CleanAfterTemper2_1: ['object_2_022', 'object_2_023'],
CleanAfterTemper3_1: ['object_3_022', 'object_3_023'],
CleanAfterTemper4_1: ['object_4_026', 'object_4_027'],
CleanBeforCoat1_1: ['object_1_009'],
CleanBeforCoat1_2: ['object_1_010'],
CleanBeforCoat4_1: ['object_4_009'],
CleanBeforCoat4_2: ['object_4_010'],
Edge1_1: ['object_1_001'],
Edge1_2: ['object_1_002'],
Edge2_1: ['object_2_001'],
Edge2_2: ['object_2_002'],
Edge3_1: ['object_3_001'],
Edge3_2: ['object_3_002'],
Edge4_1: ['object_4_001'],
Edge4_2: ['object_4_002'],
FirstCoat1_1: ['object_1_011'],
FirstCoat1_2: ['object_1_012'],
FirstCoat2_1: ['object_2_007'],
FirstCoat2_2: ['object_2_008'],
FirstCoat3_1: ['object_3_007'],
FirstCoat3_2: ['object_3_008'],
FirstCoat4_1: ['object_4_011'],
FirstCoat4_2: ['object_4_012'],
Punch1_1: ['object_1_007'],
Punch1_2: ['object_1_008'],
Punch4_1: ['object_4_007'],
Punch4_2: ['object_4_008'],
SecondCoat1_1: ['object_1_013'],
SecondCoat1_2: ['object_1_014'],
SecondCoat2_1: ['object_2_009'],
SecondCoat2_2: ['object_2_010'],
SecondCoat3_1: ['object_3_009'],
SecondCoat3_2: ['object_3_010'],
SecondCoat4_1: ['object_4_013'],
SecondCoat4_2: ['object_4_014'],
Temper1_1: ['object_1_017', 'object_1_018', 'object_1_019', 'object_1_020', 'object_1_021', 'object_1_022', 'object_1_023', 'object_1_024', 'object_1_025'],
Temper2_1: ['object_2_013', 'object_2_014', 'object_2_015', 'object_2_016', 'object_2_017', 'object_2_018', 'object_2_019', 'object_2_020', 'object_2_021'],
Temper3_1: ['object_3_013', 'object_3_014', 'object_3_015', 'object_3_016', 'object_3_017', 'object_3_018', 'object_3_019', 'object_3_020', 'object_3_021'],
Temper4_1: ['object_4_017', 'object_4_018', 'object_4_019', 'object_4_020', 'object_4_021', 'object_4_022', 'object_4_023', 'object_4_024', 'object_4_025'],
Unload1_1: ['object_1_028'],
Unload1_2: ['object_1_029'],
Unload2_1: ['object_2_024'],
Unload2_2: ['object_2_025'],
Unload3_1: ['object_3_024'],
Unload3_2: ['object_3_025'],
Unload4_1: ['object_4_028'],
Unload4_2: ['object_4_029']
}
export default EquMap;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,648 +0,0 @@
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 "../page/style/standard.css";
import { EquStatusInterface, selectEquStatus } from "../store/EquStatusEntity";
import EquMap from "./EquMap";
import AlarmTipGreen from "./../page/LinePage/assets/icon/g.png";
import AlarmTipYellow from "./../page/LinePage/assets/icon/y.png";
import AlarmTipRed from "./../page/LinePage/assets/icon/r.png";
// const onEquObservable = new Observable();
const myStyle = {
width: "1041px",
height: "562px",
outline: "none",
};
interface MybabylonJSProps {
modelPath: string; // 明确 modelPath 属性的类型为 string
}
interface EqInfoListInterface {
[key: string]: EqInfo[];
}
interface EqInfo {
name: string;
inputNum: number;
outPut: number;
position: [number, number];
}
const eqInfoList: EqInfoListInterface = {
"Line1-1": [
{ name: "磨边机", inputNum: 100, outPut: 100, position: [134, 202] },
{ name: "磨边机", inputNum: 101, outPut: 101, position: [82, 306] },
{ name: "磨边机", inputNum: 105, outPut: 105, position: [342, 400] },
{ name: "打孔机", inputNum: 100, outPut: 100, position: [337, 51] },
{ name: "打孔机", inputNum: 101, outPut: 101, position: [338, 156] },
{ name: "打孔机", inputNum: 105, outPut: 105, position: [510, 310] },
{ name: "丝印机", inputNum: 100, outPut: 100, position: [521, 4] },
{ name: "丝印机", inputNum: 101, outPut: 101, position: [520, 90] },
{ name: "丝印机", inputNum: 105, outPut: 105, position: [672, 226] },
{ name: "一次固化", inputNum: 100, outPut: 100, position: [756, 2] },
{ name: "一次固化", inputNum: 101, outPut: 101, position: [833, 90] },
{ name: "一次固化", inputNum: 105, outPut: 105, position: [835, 186] },
],
"Line1-2": [
{ name: "退火", inputNum: 100, outPut: 100, position: [100, 210] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [410, 58] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [594, 252] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [610, 5] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [838, 1] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [837, 145] },
],
"Line2-1": [
{ name: "磨边机", inputNum: 100, outPut: 100, position: [134, 202] },
{ name: "磨边机", inputNum: 105, outPut: 105, position: [342, 400] },
{ name: "打孔机", inputNum: 101, outPut: 101, position: [338, 156] },
{ name: "打孔机", inputNum: 105, outPut: 105, position: [510, 310] },
{ name: "丝印机", inputNum: 101, outPut: 101, position: [520, 90] },
{ name: "丝印机", inputNum: 105, outPut: 105, position: [672, 226] },
{ name: "一次固化", inputNum: 100, outPut: 100, position: [724, 38] },
{ name: "一次固化", inputNum: 105, outPut: 105, position: [835, 186] },
],
"Line2-2": [
{ name: "退火", inputNum: 100, outPut: 100, position: [215, 247] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [710, 237] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [502, 58] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [733, 3] },
],
"Line3-1": [
{ name: "磨边机", inputNum: 100, outPut: 100, position: [134, 202] },
{ name: "磨边机", inputNum: 105, outPut: 105, position: [342, 400] },
{ name: "打孔机", inputNum: 101, outPut: 101, position: [338, 156] },
{ name: "打孔机", inputNum: 105, outPut: 105, position: [510, 310] },
{ name: "丝印机", inputNum: 101, outPut: 101, position: [520, 90] },
{ name: "丝印机", inputNum: 105, outPut: 105, position: [672, 226] },
{ name: "一次固化", inputNum: 100, outPut: 100, position: [724, 38] },
{ name: "一次固化", inputNum: 105, outPut: 105, position: [835, 186] },
],
"Line3-2": [
{ name: "退火", inputNum: 100, outPut: 100, position: [187, 247] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [502, 58] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [733, 3] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [710, 237] },
],
"Line4-1": [
{ name: "磨边机", inputNum: 100, outPut: 100, position: [231, 216] },
{ name: "磨边机", inputNum: 105, outPut: 105, position: [403, 400] },
{ name: "一次固化", inputNum: 101, outPut: 101, position: [520, 90] },
{ name: "一次固化", inputNum: 105, outPut: 105, position: [643, 276] },
{ name: "二次固化", inputNum: 100, outPut: 100, position: [724, 38] },
{ name: "二次固化", inputNum: 105, outPut: 105, position: [835, 186] },
],
"Line4-2": [
{ name: "退火", inputNum: 100, outPut: 100, position: [187, 247] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [710, 237] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [820, 237] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [553, 7] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [839, 137] },
],
"Line5-1": [
{ name: "磨边机", inputNum: 100, outPut: 100, position: [134, 202] },
{ name: "磨边机", inputNum: 101, outPut: 101, position: [82, 306] },
{ name: "磨边机", inputNum: 105, outPut: 105, position: [342, 400] },
{ name: "一次固化", inputNum: 100, outPut: 100, position: [521, 4] },
{ name: "一次固化", inputNum: 101, outPut: 101, position: [520, 90] },
{ name: "一次固化", inputNum: 105, outPut: 105, position: [672, 287] },
{ name: "二次固化", inputNum: 100, outPut: 100, position: [756, 2] },
{ name: "二次固化", inputNum: 101, outPut: 101, position: [833, 90] },
{ name: "二次固化", inputNum: 105, outPut: 105, position: [835, 186] },
],
"Line5-2": [
{ name: "退火", inputNum: 100, outPut: 100, position: [100, 270] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [434, 133] },
{ name: "铺纸机", inputNum: 100, outPut: 100, position: [640, 305] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [645, 54] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [838, 1] },
{ name: "下片机", inputNum: 100, outPut: 100, position: [837, 226] },
],
};
interface EqInfoInterface {
name: string;
data: Array<{ name: string; value: number }>;
position: Array<number>;
}
interface EqInfoDataInterface {
[key: string]: Array<EqInfoInterface>;
}
const eqInfoData: EqInfoDataInterface = {
"Line5-1": [
{
name: "磨边进口",
data: [
{ name: "1支线", value: 413 },
{ name: "2支线", value: 435 },
{ name: "3支线", value: 397 },
],
position: [154, 266],
},
{
name: "磨边清洗出口",
data: [
{ name: "1支线", value: 401 },
{ name: "2支线", value: 418 },
{ name: "3支线", value: 389 },
],
position: [331, 177],
},
{
name: "一次镀膜进口",
data: [
{ name: "1支线", value: 400 },
{ name: "2支线", value: 418 },
{ name: "3支线", value: 388 },
],
position: [555, 329],
},
{
name: "二次镀膜进口",
data: [
{ name: "1支线", value: 387 },
{ name: "2支线", value: 399 },
{ name: "3支线", value: 381 },
],
position: [550, 85],
},
{
name: "二次固化出口",
data: [
{ name: "1支线", value: 384 },
{ name: "2支线", value: 398 },
{ name: "3支线", value: 377 },
],
position: [857, 184],
},
{
name: "钢化进口",
data: [{ name: "钢化进口", value: 1157 }],
position: [870, 48],
},
],
"Line5-2": [
{
name: "钢化出口",
data: [{ name: "钢化出口", value: 1124 }],
position: [305, 255],
},
{
name: "包装清洗机入口",
data: [
{ name: "包装清洗机5_1", value: 515 },
{ name: "包装清洗机5_2", value: 507 },
],
position: [508, 319],
},
{
name: "包装清洗机出口",
data: [
{ name: "包装清洗机5_1", value: 515 },
{ name: "包装清洗机5_2", value: 505 },
],
position: [444, 159],
},
{
name: "铺纸机",
data: [
{ name: "铺纸机5_1", value: 509 },
{ name: "铺纸机5_2", value: 504 },
],
position: [696, 272],
},
{
name: "下片机械手",
data: [
{ name: "下片机械手5_1", value: 347 },
{ name: "下片机械手5_2", value: 334 },
{ name: "下片机械手5_3", value: 316 },
],
position: [712, 28],
},
],
};
interface EqStatusListInterface {
[key: string]: Array<{
equipment: string;
alarm: boolean;
online: boolean;
}>;
}
const eqStatusList: EqStatusListInterface = {
"Line5-1": [
{ equipment: "磨边机5_1", alarm: false, online: true },
{ equipment: "磨边机5_2", alarm: false, online: true },
{ equipment: "磨边机5_3", alarm: false, online: true },
{ equipment: "清洗机5_1", alarm: false, online: true },
{ equipment: "清洗机5_2", alarm: false, online: true },
{ equipment: "清洗机5_3", alarm: false, online: true },
{ equipment: "一次镀膜5_2", alarm: false, online: true },
{ equipment: "一次镀膜5_3", alarm: false, online: true },
{ equipment: "一次固化5_1", alarm: false, online: true },
{ equipment: "一次镀膜5_1", alarm: false, online: true },
{ equipment: "一次固化5_2", alarm: false, online: true },
{ equipment: "一次固化5_3", alarm: false, online: true },
{ equipment: "二次镀膜5_1", alarm: false, online: true },
{ equipment: "二次镀膜5_2", alarm: false, online: true },
{ equipment: "二次镀膜5_3", alarm: false, online: true },
{ equipment: "二次固化5_1", alarm: false, online: true },
{ equipment: "二次固化5_2", alarm: false, online: true },
{ equipment: "二次固化5_3", alarm: false, online: true },
],
"Line5-2": [
{ equipment: "钢化炉5", alarm: false, online: true },
{ equipment: "包装清洗机5_1", alarm: false, online: true },
{ equipment: "包装清洗机5_2", alarm: false, online: true },
{ equipment: "在线铺纸机5_1", alarm: false, online: true },
{ equipment: "在线铺纸机5_2", alarm: false, online: true },
{ equipment: "下片机械手5_1", alarm: false, online: true },
{ equipment: "下片机械手5_2", alarm: false, online: true },
{ equipment: "下片机械手5_3", alarm: false, online: true },
],
};
function MybabylonJS({ modelPath }: MybabylonJSProps) {
console.log("modelPath:;;;;;;", modelPath);
// const EquStatus = useAppSelector(selectEquStatus);
const canvasRef = useRef(null);
const resetRef = useRef<(() => void) | null>(null);
// onEquObservable.notifyObservers(EquStatus);
const [selectedMeshName, setSelectedMeshName] = useState<string | null>(null);
const [selectedMeshObj, setSelectedMeshObj] = useState({
equipment: "",
alarm: false,
online: true,
});
const [showInfo, setShowInfo] = useState(true);
// 使用 useRef 来存储当前加载的模型引用
const currentMeshesRef = useRef<Array<BABYLON.AbstractMesh>>([]);
useEffect(() => {
console.log("canvasRef++++++", canvasRef);
console.log("resetRef++++++", resetRef);
// 确保 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 = 1;
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",
BABYLON.Tools.ToRadians(245),
BABYLON.Tools.ToRadians(25),
modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: 75,
new BABYLON.Vector3(-13, 0, 0)
);
camera.lowerRadiusLimit = 10;
camera.upperRadiusLimit = 600;
// 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/",
`${modelPath}.babylon`,
scene
);
// 将新加载的模型添加到 currentMeshesRef 中
currentMeshesRef.current.push(...LOD0MESH.meshes);
// ...为新加载的模型设置交互逻辑
LOD0MESH.meshes.map((mesh) => {
mesh.isPickable = true;
mesh.actionManager = new BABYLON.ActionManager(scene);
// console.log("mesh==========", mesh);
if (modelPath.slice(-1) === "1") {
if (
mesh.name.includes("磨边") ||
mesh.name.includes("清洗") ||
mesh.name.includes("镀膜") ||
mesh.name.includes("固化")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
} else {
if (
mesh.name.includes("钢化") ||
mesh.name.includes("包装") ||
mesh.name.includes("铺纸") ||
mesh.name.includes("下片机械手")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
}
//鼠标移动到物体上亮显
// mesh.actionManager.registerAction(
// new BABYLON.ExecuteCodeAction(
// BABYLON.ActionManager.OnPointerOverTrigger,
// (a) => {
// console.log("================", a);
// // @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 MeshName1 = pickInfo.pickedMesh.name.split(".")[0];
setSelectedMeshName(MeshName1);
eqStatusList[modelPath].map((item: any) => {
if (item.equipment === MeshName1) {
setSelectedMeshObj(item);
}
});
};
});
// onEquObservable.add((eventData, eventState) => {
// LOD0MESH.meshes.find((mesh) => {
// // @ts-ignore
// hl2.removeMesh(mesh);
// });
// Object.keys(eventData as EquStatusInterface).map((key) => {
// // @ts-ignore
// if (eventData[key] == 2) {
// // @ts-ignore
// EquMap[key].map((name) => {
// LOD0MESH.meshes.find((mesh) => {
// if (mesh.name == name) {
// // @ts-ignore
// hl2.addMesh(mesh, BABYLON.Color3.Red());
// }
// });
// });
// }
// });
// });
} catch (error) {
console.error("加载模型失败:", error);
}
};
// 调用函数以加载或重新加载模型
loadOrReloadModel();
function reset() {
camera.target = new BABYLON.Vector3(-13, 0, 0);
camera.alpha = BABYLON.Tools.ToRadians(245);
camera.beta = BABYLON.Tools.ToRadians(25);
camera.radius =
modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: 75;
setShowInfo(true);
setSelectedMeshName(null);
}
// 外部初始位置按钮
resetRef.current = reset;
let resetCamera = setTimeout(reset, 15000);
scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERMOVE:
clearTimeout(resetCamera);
resetCamera = setTimeout(reset, 15000);
setShowInfo(false);
}
});
return scene;
};
// call the createScene function
const scene = createScene();
// run the render loop
scene.then(
(scene) => {
console.log("createScene被调用了=====", scene);
engine.runRenderLoop(function () {
scene.render();
});
},
(reason) => {
console.log("reason=============", reason);
}
);
// Resize
window.addEventListener("resize", function () {
engine.resize();
});
// 组件卸载时的清理逻辑
return () => {
// 清理场景和引擎资源
engine.dispose();
};
}, [modelPath]);
const resetModel = () => {
//模型初始位置
console.log("回到初始位置");
if (resetRef.current) {
resetRef.current();
}
};
return (
<div style={myStyle}>
{/* <h2 className="model_name">当前选择: {selectedMeshName}</h2> */}
<div className="model_info">
<span className="reset_btn" onClick={resetModel}></span>
<span className="title">
线{modelPath.slice(-1) === "1" ? "前段" : "后段"}
</span>
</div>
{selectedMeshName && (
<div className="eq_detail_info">
<div>
<span className="left_name"></span>
<span className="right_value">{selectedMeshObj.equipment}</span>
</div>
<div>
<span className="left_name"></span>
<span className="right_value">
{selectedMeshObj.alarm ? (
<>
<img
src={AlarmTipRed}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
) : (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
)}
</span>
</div>
<div>
<span className="left_name">线</span>
<span className="right_value">
{selectedMeshObj.online ? (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
) : (
<>
<img
src={AlarmTipYellow}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
)}
</span>
</div>
</div>
)}
{showInfo &&
eqInfoData[modelPath] &&
eqInfoData[modelPath].map((item, index) => {
return (
<div
className="eq_info"
key={index}
style={{ left: item.position[0], top: item.position[1] }}
>
<div className="eq_info_inner" style={{ color: "#00FFF0" }}>
{item.name}
</div>
{item.data.map((info, index) => {
return (
<div className="eq_info_inner">
{info.name}{info.value}
</div>
);
})}
</div>
);
})}
<canvas ref={canvasRef} style={myStyle} />
</div>
);
}
export default MybabylonJS;

View File

@@ -0,0 +1,421 @@
import { useEffect, useRef, useState } 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 { HemisphericLight, Vector3 } from "@babylonjs/core";
import { useAppSelector } from "../store/hooks";
import "../page/style/standard.css";
import EqInfoData from "./EqInfoData";
import AlarmTipGreen from "./../page/assets/icon/g.png";
import AlarmTipYellow from "./../page/assets/icon/y.png";
import AlarmTipRed from "./../page/assets/icon/r.png";
import {selectLine1Before} from "../store/LinePageSlice";
import {selectLine1After} from "../store/LinePageSlice";
import {selectLine2Before} from "../store/LinePageSlice";
import {selectLine2After} from "../store/LinePageSlice";
import {selectLine3Before} from "../store/LinePageSlice";
import {selectLine3After} from "../store/LinePageSlice";
import {selectLine4Before} from "../store/LinePageSlice";
import {selectLine4After} from "../store/LinePageSlice";
import {selectLine5Before} from "../store/LinePageSlice";
import {selectLine5After} from "../store/LinePageSlice";
const lineNameNo = ["一","二","三","四","五"]
const myStyle = {
width: "1041px",
height: "562px",
outline: "none",
};
interface MybabylonJSProps {
modelPath: string; // 明确 modelPath 属性的类型为 string
}
interface EqListType {
[key: string]: EqMsg
}
interface EqMsg {
equipmentName?:string;
run?:boolean;
error?:boolean;
inputNum?:number;
outputNum?:number;
quantityTime?:number;
status?:string;
statusTime?:number;
localDateTime?:number;
equipmentCode?:string;
equipmentId?:number;
}
function MybabylonJS({ modelPath }: MybabylonJSProps) {
const [eqList, setEqList] = useState<EqListType>({});
const canvasRef = useRef(null);
const resetRef = useRef<(() => void) | null>(null);
const [selectedMeshName, setSelectedMeshName] = useState<string | null>(null);
const [selectedMeshId, setSelectedMeshId] = useState<string | null>(null);
const [selectedMeshObj, setSelectedMeshObj] = useState<EqMsg>({
equipmentName: "",
run: true,
error: false,
});
const [showInfo, setShowInfo] = useState(true);
const selectorMap: Record<string, (state: any) => any> = {
"Line1-1": selectLine1Before,
"Line1-2": selectLine1After,
"Line2-1": selectLine2Before,
"Line2-2": selectLine2After,
"Line3-1": selectLine3Before,
"Line3-2": selectLine3After,
"Line4-1": selectLine4Before,
"Line4-2": selectLine4After,
"Line5-1": selectLine5Before,
"Line5-2": selectLine5After
};
const selectedSelector = selectorMap[modelPath];
const allData = useAppSelector(selectedSelector);
// const allData = useAppSelector(selectLine1Before) as any;
// 使用 useRef 来存储当前加载的模型引用
const currentMeshesRef = useRef<Array<BABYLON.AbstractMesh>>([]);
useEffect(() => {
const equStatus = allData?.equStatus;
if (equStatus) {
setEqList(equStatus);
}
},[allData])
useEffect(() => {
const equStatus = allData?.equStatus;
if (equStatus) {
for (let i = 0; i < EqInfoData[modelPath].length; i++) {
for (let j = 0; j < EqInfoData[modelPath][i].data.length; j++) {
EqInfoData[modelPath][i].data[j].value = equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] ? equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] : 0
}
}
}
},[allData,modelPath])
useEffect(() => {
if (selectedMeshId && eqList[selectedMeshId]) {
setSelectedMeshObj({
equipmentName:eqList[selectedMeshId].equipmentName,
run:eqList[selectedMeshId].run ? eqList[selectedMeshId].run : true,
error:eqList[selectedMeshId].error ? eqList[selectedMeshId].error : false,
});
}
},[selectedMeshId])
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 = 1;
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",
BABYLON.Tools.ToRadians(245),
BABYLON.Tools.ToRadians(25),
modelPath.slice(-3) === "2-1"
? 120
: modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: modelPath.slice(-3) === "1-2"
? 90
: 65,
new BABYLON.Vector3(-13, 0, 0)
);
camera.lowerRadiusLimit = 10;
camera.upperRadiusLimit = 600;
// 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/",
`${modelPath}.babylon`,
scene
);
// 将新加载的模型添加到 currentMeshesRef 中
currentMeshesRef.current.push(...LOD0MESH.meshes);
// ...为新加载的模型设置交互逻辑
LOD0MESH.meshes.forEach((mesh) => {
mesh.isPickable = true;
mesh.actionManager = new BABYLON.ActionManager(scene);
if (modelPath.slice(-1) === "1") {
if (
mesh.name.includes("磨边") ||
mesh.name.includes("清洗") ||
mesh.name.includes("镀膜") ||
mesh.name.includes("固化") ||
mesh.name.includes("丝印") ||
mesh.name.includes("打孔")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
} else {
if (
mesh.name.includes("钢化") ||
mesh.name.includes("包装") ||
mesh.name.includes("铺纸") ||
mesh.name.includes("下片机械手")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
}
mesh._scene.onPointerDown = async (event, _pickResult) => {
console.log('_pickResult',_pickResult)
const pickInfo = mesh._scene.pick(
mesh._scene.pointerX,
mesh._scene.pointerY
);
//判断是否是右键
if (!(event.buttons === 1 && pickInfo.pickedMesh)) return;
const MeshName = pickInfo.pickedMesh.name;
const MeshNameId = pickInfo.pickedMesh.metadata.tags;
setSelectedMeshName(MeshName);
setSelectedMeshId(MeshNameId);
};
});
} catch (error) {
console.error("加载模型失败:", error);
}
};
// 调用函数以加载或重新加载模型
loadOrReloadModel();
function reset() {
camera.target = new BABYLON.Vector3(-13, 0, 0);
camera.alpha = BABYLON.Tools.ToRadians(245);
camera.beta = BABYLON.Tools.ToRadians(25);
camera.radius =
modelPath.slice(-3) === "2-1"
? 120
: modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: modelPath.slice(-3) === "1-2"
? 90
: 65
setShowInfo(true);
setSelectedMeshName(null);
}
// 外部初始位置按钮
resetRef.current = reset;
let resetCamera = setTimeout(reset, 15000);
scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERMOVE:
clearTimeout(resetCamera);
resetCamera = setTimeout(reset, 15000);
setShowInfo(false);
}
});
return scene;
};
// call the createScene function
const scene = createScene();
// run the render loop
scene.then(
(scene) => {
console.log("createScene被调用了=====", scene);
engine.runRenderLoop(function () {
scene.render();
});
},
(reason) => {
console.log("reason=============", reason);
}
);
// Resize
window.addEventListener("resize", function () {
engine.resize();
});
// 组件卸载时的清理逻辑
return () => {
// 清理场景和引擎资源
engine.dispose();
};
}, [modelPath]);
const resetModel = () => {
//模型初始位置
if (resetRef.current) {
resetRef.current();
}
};
return (
<div style={myStyle}>
{/* <h2 className="model_name">当前选择: {selectedMeshName}</h2> */}
<div className="model_info">
<span className="reset_btn" onClick={resetModel}></span>
<span className="title">
{lineNameNo[Number(modelPath.slice(-3,-2))-1]}线{modelPath.slice(-1) === "1" ? "前段" : "后段"}
</span>
</div>
{selectedMeshName && (
<div className="eq_detail_info">
<div>
<span className="left_name"></span>
<span className="right_value">{selectedMeshObj.equipmentName}</span>
</div>
<div>
<span className="left_name"></span>
<span className="right_value">
{selectedMeshObj.error ? (
<>
<img
src={AlarmTipRed}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
) : (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
)}
</span>
</div>
<div>
<span className="left_name">线</span>
<span className="right_value">
{selectedMeshObj.run ? (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
) : (
<>
<img
src={AlarmTipYellow}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
)}
</span>
</div>
</div>
)}
{showInfo &&
EqInfoData[modelPath] &&
EqInfoData[modelPath].map((item) => {
return (
<div
className="eq_info"
key={item.data[0].code+item.data[0].label}
style={{ left: item.position[0], top: item.position[1] }}
>
<div className="eq_info_inner" style={{ color: "#00FFF0" }}>
{item.name}
</div>
{item.data.map((info) => {
return (
<div className="eq_info_inner" key={info.code+info.label}>
{info.name}{info.value}
</div>
);
})}
</div>
);
})}
<canvas ref={canvasRef} style={myStyle} />
</div>
);
}
export default MybabylonJS;

View File

@@ -1,363 +0,0 @@
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 {
GlassAnimation1_1, GlassAnimation1_2D, GlassAnimation1_2U, GlassAnimation1_3, GlassAnimation1_4,
GlassAnimation2_1, GlassAnimation2_2D, GlassAnimation2_2U, GlassAnimation2_3, GlassAnimation2_4,
GlassAnimation3_1, GlassAnimation3_2D, GlassAnimation3_2U, GlassAnimation3_3, GlassAnimation3_4,
GlassAnimation4_1, GlassAnimation4_2D, GlassAnimation4_2U, GlassAnimation4_3, GlassAnimation4_4
} from "./GlassAnimation";
import { useAppSelector } from "../store/hooks";
import { GlassStatus, selectGlassStatus } from "../store/ProductionMonitoringEntity";
import '../page/style/standard.css';
import { MyObservable } from "../context/MyObservable";
import { Button, ButtonGroup } from "@mui/material";
import intl from "react-intl-universal";
import { EquStatusInterface, selectEquStatus } from "../store/EquStatusEntity";
import EquMap from "./EquMap";
const onMainCamObservable = new Observable();
const onEquObservable = new Observable();
const myStyle = {
width: '1036px',
height: '666px',
outline: 'none',
}
const DetailCamera = {
Part_1: {
alpha: BABYLON.Tools.ToRadians(270),
beta: BABYLON.Tools.ToRadians(25),
radius: 85,
target: new BABYLON.Vector3(-110, 0, -8)
},
Part_2: {
alpha: BABYLON.Tools.ToRadians(270),
beta: BABYLON.Tools.ToRadians(25),
radius: 85,
target: new BABYLON.Vector3(-40, 0, -8)
},
Part_3: {
alpha: BABYLON.Tools.ToRadians(270),
beta: BABYLON.Tools.ToRadians(25),
radius: 85,
target: new BABYLON.Vector3(0, 0, -8)
},
Part_4: {
alpha: BABYLON.Tools.ToRadians(270),
beta: BABYLON.Tools.ToRadians(25),
radius: 85,
target: new BABYLON.Vector3(110, 0, -8)
},
}
interface MybabylonJSProps {
modelPath: string; // 明确 modelPath 属性的类型为 string
}
function MybabylonJS({ modelPath }: MybabylonJSProps) {
const onGlassObservable = useContext(MyObservable);
const EquStatus = useAppSelector(selectEquStatus);
const canvasRef = useRef(null);
onEquObservable.notifyObservers(EquStatus);
// const thisLineGlassStatus = useAppSelector(selectGlassStatus)
// onGlassObservable.notifyObservers(thisLineGlassStatus)
const [SelectedMeshName, setSelectedMeshName] = useState<string | null>(null);
interface MybabylonJSProps {
modelPath: string;
}
// 使用 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 light = new BABYLON.DirectionalLight('light', new BABYLON.Vector3(20, 20, 100), scene);
const light2 = new BABYLON.PointLight('light2', new BABYLON.Vector3(20, 20, 100), scene);
const Glass1_1 = new BABYLON.TransformNode('Glass1_1')
const baseLight = new HemisphericLight('hemiLight', new Vector3(-1, 1, 0), scene);
baseLight.intensity = 1;
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", BABYLON.Tools.ToRadians(245), BABYLON.Tools.ToRadians(25), 215, new BABYLON.Vector3(-2, 0, -8));
camera.lowerRadiusLimit = 10;
camera.upperRadiusLimit = 600;
// 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 = .3
grid.gridRatio = .04
grid.backFaceCulling = !1
grid.mainColor = new BABYLON.Color3(1, 1, 1)
grid.lineColor = new BABYLON.Color3(1, 1, 1)
grid.opacity = .8
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);
// var LOD0MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `${modelPath}.babylon`, 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('', '/test/', `${modelPath}.babylon`, scene);
// var LOD0MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `line1.babylon`, scene);
// var LOD1MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `line2.babylon`, scene);
// var LOD2MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `line3.babylon`, scene);
// var LOD3MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `line4.babylon`, scene);
// var LOD4MESH = await BABYLON.SceneLoader.ImportMeshAsync('', '/test/', `line5.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 MeshName1 = pickInfo.pickedMesh.name.split(".")[0]
setSelectedMeshName(MeshName1)
} })
/////////////////////////////////////////////////////////////////////////////////////////////////
onEquObservable.add((eventData, eventState) => {
LOD0MESH.meshes.find((mesh) => {
// @ts-ignore
hl2.removeMesh(mesh);
})
Object.keys(eventData as EquStatusInterface).map((key) => {
// @ts-ignore
if (eventData[key] == 2) {
// @ts-ignore
EquMap[key].map((name) => {
LOD0MESH.meshes.find((mesh) => {
if (mesh.name == name) {
// @ts-ignore
hl2.addMesh(mesh, BABYLON.Color3.Red());
}
})
})
}
})
})
/////////////////////////////////////////////////////////////////////////////////////////////////
} catch (error) {
console.error('加载模型失败:', error);
}
};
// 调用函数以加载或重新加载模型
loadOrReloadModel();
function reset() {
camera.target = new BABYLON.Vector3(-2, 0, -8);
camera.alpha = BABYLON.Tools.ToRadians(245);
camera.beta = BABYLON.Tools.ToRadians(25);
camera.radius = 215;
}
let resetCamera = setTimeout(reset, 15000)
scene.onPointerObservable.add((pointerInfo) => {
// console.log(camera.target, camera.alpha * 180 / 3.14, camera.beta * 180 / 3.14, camera.radius)
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERMOVE:
clearTimeout(resetCamera);
resetCamera = setTimeout(reset, 15000)
}
})
onMainCamObservable.add((eventData, eventState) => {
clearTimeout(resetCamera);
resetCamera = setTimeout(reset, 5000);
switch (eventData) {
case 1:
camera.target = DetailCamera.Part_1.target;
camera.alpha = DetailCamera.Part_1.alpha;
camera.beta = DetailCamera.Part_1.beta;
camera.radius = DetailCamera.Part_1.radius;
break;
case 2:
camera.target = DetailCamera.Part_2.target;
camera.alpha = DetailCamera.Part_2.alpha;
camera.beta = DetailCamera.Part_2.beta;
camera.radius = DetailCamera.Part_2.radius;
break;
case 3:
camera.target = DetailCamera.Part_3.target;
camera.alpha = DetailCamera.Part_3.alpha;
camera.beta = DetailCamera.Part_3.beta;
camera.radius = DetailCamera.Part_3.radius;
break;
case 4:
camera.target = DetailCamera.Part_4.target;
camera.alpha = DetailCamera.Part_4.alpha;
camera.beta = DetailCamera.Part_4.beta;
camera.radius = DetailCamera.Part_4.radius;
break;
}
})
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();
};
},
[modelPath]
);
const handleClick1 = () => {
onMainCamObservable.notifyObservers(1)
}
const handleClick2 = () => {
onMainCamObservable.notifyObservers(2)
}
const handleClick3 = () => {
onMainCamObservable.notifyObservers(3)
}
const handleClick4 = () => {
onMainCamObservable.notifyObservers(4)
}
return (
<div style={myStyle}>
<ButtonGroup variant="contained" aria-label="outlined button group" className={'btnArea'}>
<h2>: {SelectedMeshName}</h2>
<Button sx={{ backgroundColor: 'rgba(86, 244, 231, 0.69)' }} onClick={handleClick1}>{intl.get('Part1')}</Button>
<Button sx={{ backgroundColor: 'rgba(86, 244, 231, 0.69)' }} onClick={handleClick2}>{intl.get('Part2')}</Button>
<Button sx={{ backgroundColor: 'rgba(86, 244, 231, 0.69)' }} onClick={handleClick3}>{intl.get('Part3')}</Button>
<Button sx={{ backgroundColor: 'rgba(86, 244, 231, 0.69)' }} onClick={handleClick4}>{intl.get('Part4')}</Button>
</ButtonGroup>
<canvas ref={canvasRef} style={myStyle} />
</div>
);
}
export default MybabylonJS;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,65 +0,0 @@
import React, {useContext, useEffect, useState} from "react";
import intl from "react-intl-universal";
import MainP from "../MainP/MainP";
import MainE from "../MainE/MainE";
import MainQ from "../MainQ/MainQ";
import TabPanel from "../Component/TabPanel";
import SwitchOnOff from "../Component/SwitchOnOff";
import {useAppSelector} from "../../store/hooks";
import {selectSwitchState} from "../../store/ChangeSwitchState";
import {ThisLineID} from "../../context/ThisLineID";
function SwitchAll() {
const [PageIndex, setPageIndex] = useState(1)
const state = useAppSelector(selectSwitchState)
useEffect(() => {
let timerId: NodeJS.Timer;
function StartSwitch() {
timerId = setTimeout(() => {
if (PageIndex < 6) {
setPageIndex(PageIndex + 1)
} else {
setPageIndex(1)
}
}, 30000)
}
function StopSwitch() {
clearInterval(timerId)
}
if (state) {
StartSwitch()
} else {
StopSwitch()
}
window.dispatchEvent(new Event('resize'))
return () => {
clearInterval(timerId)
}
}, [PageIndex, state]
)
return (
<div>
<SwitchOnOff/>
<TabPanel index={1} value={PageIndex}><MainP/></TabPanel>
<TabPanel index={2} value={PageIndex}><MainQ/></TabPanel>
<ThisLineID.Provider value={'1'}>
<TabPanel index={3} value={PageIndex}><MainE/></TabPanel>
</ThisLineID.Provider>
<ThisLineID.Provider value={'2'}>
<TabPanel index={4} value={PageIndex}><MainE/></TabPanel>
</ThisLineID.Provider>
<ThisLineID.Provider value={'3'}>
<TabPanel index={5} value={PageIndex}><MainE/></TabPanel>
</ThisLineID.Provider>
<ThisLineID.Provider value={'4'}>
<TabPanel index={6} value={PageIndex}><MainE/></TabPanel>
</ThisLineID.Provider>
</div>
)
}
export default SwitchAll;

View File

@@ -1,53 +0,0 @@
import React, {useContext, useEffect, useState} from "react";
import intl from "react-intl-universal";
import MainP from "../MainP/MainP";
import MainE from "../MainE/MainE";
import MainQ from "../MainQ/MainQ";
import TabPanel from "../Component/TabPanel";
import SwitchOnOff from "../Component/SwitchOnOff";
import {useAppSelector} from "../../store/hooks";
import {selectSwitchState} from "../../store/ChangeSwitchState";
function SwitchLine() {
const [PageIndex, setPageIndex] = useState(1)
const state = useAppSelector(selectSwitchState)
useEffect(() => {
let timerId: NodeJS.Timer;
function StartSwitch() {
timerId = setInterval(() => {
if (PageIndex < 3) {
setPageIndex(PageIndex + 1)
} else {
setPageIndex(1)
}
}, 30000)
}
function StopSwitch() {
clearInterval(timerId)
}
if (state) {
StartSwitch()
} else {
StopSwitch()
}
window.dispatchEvent(new Event('resize'))
return () => {
clearInterval(timerId)
}
}, [PageIndex, state]
)
return (
<div>
<SwitchOnOff/>
<TabPanel index={1} value={PageIndex}><MainP/></TabPanel>
<TabPanel index={2} value={PageIndex}><MainQ/></TabPanel>
<TabPanel index={3} value={PageIndex}><MainE/></TabPanel>
</div>
)
}
export default SwitchLine;

View File

@@ -1,18 +1,20 @@
import * as echarts from "echarts"; import * as echarts from "echarts";
export default function getOptions(dataProps: number[], color: string[]) { export default function getOptions(dataProps: number[],xData:string[], color: string[]) {
if (dataProps.length === 0) return null; if (dataProps.length === 0) return null;
return { return {
grid: { top: 30, right: 12, bottom: 26, left: 48 }, grid: { top: 30, right: 10, bottom: 5, left: 10, containLabel: true },
legend: { legend: {
show: false, show: false,
}, },
xAxis: { xAxis: {
type: "category", type: "category",
data: ["磨边后", "包装1", "包装2"], data: xData,
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 10,
interval: 0, interval: 0,
rotate:20
}, },
axisTick: { show: false }, axisTick: { show: false },
axisLine: { axisLine: {
@@ -26,12 +28,12 @@ export default function getOptions(dataProps: number[], color: string[]) {
name: "单位/片", name: "单位/片",
nameTextStyle: { nameTextStyle: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
}, },
type: "value", type: "value",
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
formatter: "{value}", formatter: "{value}",
}, },
axisLine: { axisLine: {

View File

@@ -0,0 +1,126 @@
import * as echarts from "echarts";
export default function getOptions(dataProps:any) {
if (dataProps.length === 0) return null;
return {
grid: { top: 40, right: 10, bottom: 5, left: 10, containLabel: true },
legend: {
show: false,
},
xAxis: {
type: "category",
data: dataProps.time,
axisLabel: {
color: "#fff",
fontSize: 12,
interval: 0,
rotate:20
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},
yAxis: [{
name: "单位/片",
nameTextStyle: {
color: "#fff",
fontSize: 12,
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
width: 2,
color: "#5982B2",
},
},
splitLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},{
name: "良品率/%",
nameTextStyle: {
color: "#fff",
fontSize: 12,
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
width: 2,
color: "#5982B2",
},
},
splitLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
}],
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "luoyang-chart-tooltip",
show: false,
},
series: [
{
data: dataProps.input,
type: "bar",
barWidth: 10,
barGap:0,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(157, 234, 245, 1)' },
{ offset: 1, color: 'rgba(110, 249, 222, 1)' },
]),
},
},
{
data:dataProps.output,
type: "bar",
barWidth: 10,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(92, 183, 255, 1)' },
{ offset: 1, color: 'rgba(54, 75, 254, 1)' },
]),
},
},
{
data: dataProps.yield,
type: "line",
yAxisIndex: 1,
symbol:'circle',
symbolSize: 7,
color:'rgba(18, 255, 245, 1)',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(18, 255, 245, 0.8)' },
{ offset: 0.2, color: 'rgba(18, 255, 245, 0.2)' },
{ offset: 0.4, color: 'rgba(18, 255, 245, 0)' },
]),
}
}
],
};
}

View File

@@ -1,36 +0,0 @@
import React, {useState} from "react";
import intl from "react-intl-universal";
import '../../lanhuapp/common.css';
import "../../lanhuapp/index.css";
function ChangeFullButton() {
const [isFull, setIsFull] = useState(false);
function fullExit() {
let element = document.documentElement;
//HTML5 W3C 提议
document.exitFullscreen();
setIsFull(false)
}
function fullScreen() {
let element = document.documentElement;
//HTML W3C 提议
element.requestFullscreen();
setIsFull(true)
}
const click = () => {
isFull ? fullExit() : fullScreen();
}
return (
<button className="section_1 flex-col" onClick={click}/>
)
}
export default ChangeFullButton;

View File

@@ -1,19 +0,0 @@
import React from "react";
import intl from "react-intl-universal";
import '../../lanhuapp/common.css';
import "../../lanhuapp/index.css";
import {useAppDispatch} from "../../store/hooks";
import {UpdateChangeLangAndCss} from "../../store/ChangeLangAndCss";
function ChangeLangButton() {
const dispatch = useAppDispatch();
const changeTitle = () => {
dispatch(UpdateChangeLangAndCss())
}
return (
<button className="box_76 flex-col" onClick={changeTitle}/>
)
}
export default ChangeLangButton;

View File

@@ -2,13 +2,13 @@ export default function getOptions(chartData: any) {
if (Object.keys(chartData).length === 0) { if (Object.keys(chartData).length === 0) {
return null; return null;
} }
const colors = ["#1A99FF", "#FFB70C", "#C69DFF", "#50F4E3", "#E02094"]; const colors = ["#2760FF", "#8167F6", "#5B9BFF", "#99D66C", "#FFD160","#D680FF","#FF6860"];
return { return {
color: colors, color: colors,
grid: { top: 38, right: 12, bottom: 26, left: 48 }, grid: { top: 50, right: 12, bottom: 5, left: 15, containLabel: true },
legend: { legend: {
show: true, show: true,
top: 10, top: 5,
right: 10, right: 10,
padding: 0, padding: 0,
itemWidth: 14, itemWidth: 14,
@@ -17,12 +17,13 @@ export default function getOptions(chartData: any) {
height: 10, height: 10,
textStyle: { textStyle: {
color: "#DFF1FE", color: "#DFF1FE",
fontSize: 14, fontSize: 12,
}, },
}, },
xAxis: { xAxis: {
type: "category", type: "category",
data: ["8/22", "8/23", "8/24", "8/25", "8/26", "8/27", "8/28"], data: chartData.xData,
// data: ["8/22", "8/23", "8/24", "8/25", "8/26", "8/27", "8/28"],
// data: Array(7) // data: Array(7)
// .fill(1) // .fill(1)
// .map((_, index) => { // .map((_, index) => {
@@ -36,7 +37,7 @@ export default function getOptions(chartData: any) {
// .reverse(), // .reverse(),
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
}, },
axisTick: { show: false }, axisTick: { show: false },
axisLine: { axisLine: {
@@ -51,12 +52,12 @@ export default function getOptions(chartData: any) {
min: 50, min: 50,
nameTextStyle: { nameTextStyle: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
}, },
type: "value", type: "value",
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
formatter: "{value}", formatter: "{value}",
}, },
axisLine: { axisLine: {
@@ -78,42 +79,43 @@ export default function getOptions(chartData: any) {
className: "luoyang-chart-tooltip", className: "luoyang-chart-tooltip",
show: false, show: false,
}, },
series: [ series:chartData.series
{ // series: [
name: "产线1", // {
type: "line", // name: "产线1",
symbol: "circle", // type: "line",
symbolSize: 4, // symbol: "circle",
data: chartData.yData1, // symbolSize: 4,
}, // data: chartData.yData[0],
{ // },
name: "产线2", // {
type: "line", // name: "产线2",
symbol: "circle", // type: "line",
symbolSize: 4, // symbol: "circle",
data: chartData.yData2, // symbolSize: 4,
}, // data: chartData.yData[1],
{ // },
name: "产线3", // {
type: "line", // name: "产线3",
symbol: "circle", // type: "line",
symbolSize: 4, // symbol: "circle",
data: chartData.yData3, // symbolSize: 4,
}, // data: chartData.yData[2],
{ // },
name: "产线4", // {
type: "line", // name: "产线4",
symbol: "circle", // type: "line",
symbolSize: 4, // symbol: "circle",
data: chartData.yData4, // symbolSize: 4,
}, // data: chartData.yData[3],
{ // },
name: "产线5", // {
type: "line", // name: "产线5",
symbol: "circle", // type: "line",
symbolSize: 4, // symbol: "circle",
data: chartData.yData5, // symbolSize: 4,
}, // data: chartData.yData[4],
], // },
// ],
}; };
} }

View File

@@ -1,4 +1,4 @@
import * as echarts from "echarts";
export default function getOptions(tempData: any) { export default function getOptions(tempData: any) {
if (Object.keys(tempData).length === 0) { if (Object.keys(tempData).length === 0) {
return null; return null;
@@ -6,20 +6,19 @@ export default function getOptions(tempData: any) {
const colors = ["#1A99FF", "#50F4E3"]; const colors = ["#1A99FF", "#50F4E3"];
return { return {
color: colors, color: colors,
grid: { top: 30, right: 12, bottom: 10, left: 10, containLabel: true }, grid: { top: 30, right: 12, bottom: 10, left: 5, containLabel: true },
legend: { legend: {
show: true, show: true,
icon: "roundRect",
top: 10, top: 10,
right: 10, right: 10,
padding: 0, padding: 0,
itemWidth: 10, itemWidth: 14,
itemHeight: 10, itemHeight: 10,
itemGap: 3, itemGap: 8,
height: 10, height: 10,
textStyle: { textStyle: {
color: "#DFF1FE", color: "#DFF1FE",
fontSize: 14, fontSize: 12,
}, },
}, },
xAxis: { xAxis: {
@@ -38,7 +37,7 @@ export default function getOptions(tempData: any) {
// .reverse(), // .reverse(),
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
}, },
axisTick: { show: false }, axisTick: { show: false },
axisLine: { axisLine: {
@@ -52,12 +51,12 @@ export default function getOptions(tempData: any) {
name: "单位/千片", name: "单位/千片",
nameTextStyle: { nameTextStyle: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
}, },
type: "value", type: "value",
axisLabel: { axisLabel: {
color: "#fff", color: "#fff",
fontSize: 14, fontSize: 12,
formatter: "{value}", formatter: "{value}",
}, },
axisLine: { axisLine: {
@@ -81,6 +80,11 @@ export default function getOptions(tempData: any) {
symbol: "circle", symbol: "circle",
symbolSize: 4, symbolSize: 4,
data: tempData.input, data: tempData.input,
label: {
show: true,
position: 'top',
color:'inherit'
},
}, },
{ {
name: "产出", name: "产出",
@@ -88,6 +92,11 @@ export default function getOptions(tempData: any) {
symbol: "circle", symbol: "circle",
symbolSize: 4, symbolSize: 4,
data: tempData.output, data: tempData.output,
label: {
show: true,
position: 'top',
color:'inherit'
},
}, },
], ],
tooltip: { tooltip: {

View File

@@ -1,51 +0,0 @@
import React from "react";
import intl from "react-intl-universal";
import '../../lanhuapp/common.css';
import "../../lanhuapp/index.css";
import {useAppSelector} from "../../store/hooks";
import {Quality, selectQualityMonitorEntity} from "../../store/QualityMonitorEntity";
import {Table, TableBody, TableHead} from "@mui/material";
import {StyledTableCell, StyledTableContainer, StyledTableRow} from "./StyledTable";
interface param {
timeName: "todayQualityLineAll" | "weekQualityLineAll" | "monthQualityLineAll";
lineName: "Line_1" | "Line_2" | "Line_3" | "Line_4";
}
function QualityRightTable(props: param) {
const AllData = useAppSelector(selectQualityMonitorEntity);
const TimeData = AllData[props.timeName];
const LineData = TimeData[props.lineName];
const SlicedLineData = LineData.slice(0, 6);
return (
<div className="rightTableAreaQ">
<StyledTableContainer>
<Table>
<TableHead>
<StyledTableRow>
<StyledTableCell align="center" sx={{width: 100}}>{intl.get('serialNo')}</StyledTableCell>
<StyledTableCell align="center" sx={{width: 250}}>{intl.get('DefectType')}</StyledTableCell>
<StyledTableCell align="center" sx={{width: 120}}>{intl.get('DefectNumber')}</StyledTableCell>
</StyledTableRow>
</TableHead>
<TableBody>
{SlicedLineData.map((item: Quality, index: number) => (
<StyledTableRow key={index}>
<StyledTableCell align="center">{item.sort}</StyledTableCell>
<StyledTableCell align="center" sx={{
maxWidth: 250,
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
}}>{item.content}</StyledTableCell>
<StyledTableCell align="center">{item.num}</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</StyledTableContainer>
</div>
)
}
export default QualityRightTable;

View File

@@ -5,7 +5,6 @@ import { deepClone } from "./util/utils";
import { co } from "./util"; import { co } from "./util";
import classnames from "classnames"; import classnames from "classnames";
import "./index.css"; import "./index.css";
import { current } from "@reduxjs/toolkit";
interface ScrollBoardProps { interface ScrollBoardProps {
config?: object; config?: object;
onClick?: () => void; onClick?: () => void;

View File

@@ -1,71 +0,0 @@
import React from "react";
import {styled, TableCell, tableCellClasses, TableContainer, TableRow, ToggleButton} from "@mui/material";
export const StyledTableCell = styled(TableCell)(({theme}) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: 'rgba(32, 55, 96, 0.7)',
color: theme.palette.common.white,
fontSize: 14,
padding: 0,
border: 0,
height: 28,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 12,
color: theme.palette.common.white,
padding: 0,
border: 0,
height: 26
},
}));
export const StyledTableRow = styled(TableRow)(({theme}) => ({
'&:nth-of-type(odd)': {
backgroundColor: 'rgba(14, 32, 62, 0.7)',
},
backgroundColor: 'rgba(32, 55, 96, 0.7)',
}));
export const StyledTableContainer = styled(TableContainer)(({theme}) => ({
overflow: 'auto hidden',
'&::-webkit-scrollbar': {
height: 8,
WebkitAppearance: 'none'
},
'&::-webkit-scrollbar-thumb': {
borderRadius: 2,
backgroundColor: 'rgba(91, 196, 190, 0.5)',
},
'&::-webkit-scrollbar-button': {
width: 8,
borderBottomLeftRadius: 2,
borderBottomRightRadius: 2,
backgroundColor: 'rgba(91, 196, 190, 1)',
},
'&::-webkit-scrollbar-track': {
backgroundColor: 'rgba(12, 32, 67, 1)',
}
}));
export const StyledToggleButton = styled(ToggleButton)({
width: 120,
height: 24,
backgroundColor: 'rgba(49, 135, 140, 0.29)',
color: "white",
'&.Mui-selected': {
backgroundColor: 'rgba(86, 244, 231, 0.69)',
color: "white",
'&:hover': {
backgroundColor: 'rgba(86, 244, 231, 0.5)',
color: "white",
},
},
'&:hover': {
backgroundColor: 'rgba(86, 244, 231, 0.5)',
color: "white",
},
'&:active': {
backgroundColor: 'rgba(86, 244, 231, 0.69)',
color: "white",
},
});

View File

@@ -0,0 +1,75 @@
export default function getOptions(chartData: any) {
if (Object.keys(chartData).length === 0) {
return null;
}
const colors = ["#2760FF", "#8167F6", "#5B9BFF", "#99D66C", "#FFD160","#D680FF","#FF6860"];
return {
color: colors,
grid: { top: 48, right: 20, bottom: 5, left: 10, containLabel: true },
legend: {
show: true,
icon: "roundRect",
top: 5,
right: 20,
padding: 0,
itemWidth: 10,
itemHeight: 10,
itemGap: 15,
height: 10,
textStyle: {
color: "#DFF1FE",
fontSize: 12,
},
},
xAxis: {
type: "category",
data: chartData.xData,
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},
yAxis: {
name: "单位/片",
nameTextStyle: {
color: "#fff",
fontSize: 12,
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
width: 2,
color: "#5982B2",
},
},
splitLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},
tooltip: {
show: false,
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "luoyang-chart-tooltip",
},
series:chartData.series
};
}

View File

@@ -1,26 +0,0 @@
import React, {useState} from "react";
import intl from "react-intl-universal";
import '../../lanhuapp/common.css';
import "../../lanhuapp/index.css";
import {FormControlLabel, Switch} from "@mui/material";
import {useAppSelector, useAppDispatch} from "../../store/hooks";
import {selectSwitchState,ChangeSwitch} from "../../store/ChangeSwitchState";
function SwitchOnOff() {
const dispatch = useAppDispatch();
const [isSwitch, setIsSwitch] = useState(useAppSelector(selectSwitchState));
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
dispatch(ChangeSwitch())
setIsSwitch(event.target.checked);
}
return (
<div className={'switchBtn'}>
<FormControlLabel control={<Switch color={'warning'} checked={isSwitch} onChange={handleChange}/>}
label={intl.get('AutoSwitch')}/>
</div>
)
}
export default SwitchOnOff;

View File

@@ -1,19 +0,0 @@
import React from "react";
import "../style/standard.css"
interface TabPanelProps {
children?: React.ReactNode;
index: number;
value: number;
}
function TabPanel(props: TabPanelProps) {
const {children, value, index, ...other} = props;
return (
<div hidden={value !== index}>
{children}
</div>
)
}
export default TabPanel;

View File

@@ -1,6 +1,4 @@
import React from "react";
import "./style/standard.css" import "./style/standard.css"
import intl from "react-intl-universal";
function ErrorPage() { function ErrorPage() {

View File

@@ -0,0 +1,73 @@
import TitleBox from "../Component/TitleBox";
import NumberBox from "../Component/NumberBox";
import {useAppSelector} from "./../../../store/hooks"
import { selectAllLine } from "./../../../store/LeaderPageSlice";
import { formatNumberWithCommas } from './../../../utils/index';
function CenterDown() {
interface mapInterface {
inputRate:string,
outputRate:string,
input:string,
output:string
}
let monthMap = {
inputRate:'',
outputRate:'',
input:'',
output:''
}
let lastMonthMap = {
input:'',
output:''
}
let yearMap = {
inputRate:'',
outputRate:'',
input:'',
output:''
}
const data = useAppSelector(selectAllLine);
if (data.monthMap) {
monthMap = data.monthMap as mapInterface
lastMonthMap = data.lastMonthMap as mapInterface
yearMap = data.yearMap as mapInterface
}
return(
<div className="ld_center_down flex-row">
<div className="ld_center_down_inner flex-col ld_left-box">
<TitleBox title={"center_down_left"} />
<div style={{padding:'10px 0px 0px 20px'}}>
<div style={{width:'300px',height:'128px',marginBottom:'5px'}}>
<NumberBox num={monthMap.inputRate?monthMap.inputRate:'-'} show={true} title={'总投入片数'} bigNum={monthMap.input?formatNumberWithCommas(monthMap.input):'-'}/>
</div>
<div style={{width:'300px',height:'128px'}}>
<NumberBox num={monthMap.outputRate || '-'} show={true} title={'总生产片数'} bigNum={monthMap.output?formatNumberWithCommas(monthMap.output):'-'}/>
</div>
</div>
</div>
<div className="ld_center_down_inner flex-col ld_center-box">
<TitleBox title={"center_down_center"} />
<div style={{padding:'10px 0px 0px 20px'}}>
<div style={{width:'300px',height:'128px',marginBottom:'5px'}}>
<NumberBox num={''} show={false} title={'总投入片数'} bigNum={lastMonthMap.input?formatNumberWithCommas(lastMonthMap.input):'-'}/>
</div>
<div style={{width:'300px',height:'128px'}}>
<NumberBox num={''} show={false} title={'总生产片数'} bigNum={lastMonthMap.output?formatNumberWithCommas(lastMonthMap.output):'-'}/>
</div>
</div>
</div>
<div className="ld_center_down_inner flex-col ld_right-box">
<TitleBox title={"center_down_right"} />
<div style={{padding:'10px 0px 0px 20px'}}>
<div style={{width:'300px',height:'128px',marginBottom:'5px'}}>
<NumberBox num={yearMap.inputRate || '_'} show={true} title={'总投入片数/万'} bigNum={monthMap.input?formatNumberWithCommas(monthMap.input):'-'}/>
</div>
<div style={{width:'300px',height:'128px'}}>
<NumberBox num={yearMap.outputRate || '_'} show={true} title={'总生产片数/万'} bigNum={yearMap.output?formatNumberWithCommas(yearMap.output):'-'}/>
</div>
</div>
</div>
</div>
)
}
export default CenterDown;

View File

@@ -0,0 +1,10 @@
import LinePageBabylon from "../../../babylonjs/AllLinePageBabylon";
function CenterUp() {
const lineID = "1-1"
return(
<div className="ld_center_up">
<LinePageBabylon modelPath={`Line${lineID}`} />
</div>
)
}
export default CenterUp;

View File

@@ -0,0 +1,27 @@
.number_box_container {
width: 100%;
height: 100%;
background: url(../../../../../public/png/numberBox.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
margin:0 auto;
padding: 25px 20px 20px;
}
.number_box_container .big_number {
font-size:38px;
color: #fff;
}
.number_box_container .big_number_title {
margin-bottom: 10px;
}
.number_box_container .big_number_title_left {
font-size: 20px;
color: #fff;
letter-spacing: 2px;
}
.number_box_container .big_number_title_right {
font-size: 18px;
position: relative;
top: 6px;
left:10px;
}

View File

@@ -0,0 +1,35 @@
import './index.css';
import a_r from './../../../assets/icon/a_r.png';
import a_g from './../../../assets/icon/a_g.png';
interface boxProps {
num:string | number,
show?:boolean,
title:string,
lastYear?:boolean,
bigNum:string | number
}
function NumberBox(props: boxProps) {
return (
<div className="number_box_container" style={{paddingLeft:props.lastYear?'45px':'25px'}}>
<div className='flex-row big_number_title'>
<div className='big_number_title_left'>{props.title}</div>
{
props.show?(
<div className='big_number_title_right' style={{color:Number(props.num)>0?'#FF0000':'#00FF00'}}>
{Number(props.num)>0?'+':''}{props.num}%
{
Number(props.num)>0?(
<img src={a_r} alt="" width='5px'/>
):(
<img src={a_g} alt="" width='5px'/>
)
}
</div>
):''
}
</div>
<div className='big_number'>{props.bigNum}</div>
</div>
)
}
export default NumberBox;

View File

@@ -0,0 +1,56 @@
import Defect from "./../../../assets/icon/defect.png";
import NumBar from "./../../../assets/icon/numBar.png";
import Defe from "./../../../assets/icon/defe.png";
import Record from "./../../../assets/icon/record.png";
import "./index.css";
interface titleProps {
title: string;
}
function TitleBox(props: titleProps) {
const filteredTitles = () => {
switch (props.title) {
case "left_up":
return {
img: Record,
title: "近期数据对比",
};
case "left_down":
return {
img: NumBar,
title: "投入产出及良品率",
};
case "center_down_left":
return {
img: Defect,
title: "本月数据",
};
case "center_down_center":
return {
img: Defect,
title: "上月数据",
};
case "center_down_right":
return {
img: Defect,
title: "本年数据",
};
case "right_up":
return {
img: Defe,
title: "缺陷情况",
};
default:
return {
img: Defect,
title: "上年数据",
};
}
};
return (
<div className="title_box">
<img src={filteredTitles().img} alt="title" />
<span>{filteredTitles().title}</span>
</div>
);
}
export default TitleBox;

View File

@@ -0,0 +1,164 @@
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;
}
// 数据格式
// const dataProps = [
// {value: 14,name:'缺陷1'},
// {value: 20,name:'缺陷2'},
// {value: 22,name:'缺陷3'},
// {value: 14,name:'缺陷4'},
// {value: 30,name:'缺陷5'}
// ]
let rangArrValue: any[] = [];
let dataList: any = [];
let totalValue = 0;
const colors = [
"rgb(39, 96, 255)",
"rgb(91, 155, 255)",
"rgb(153, 214, 108)",
"rgb(18, 255, 245)",
"rgb(221, 177, 18)",
];
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%5];
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.2)`, // 终点颜色
},
],
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);
return {
color: colors,
graphic: [
{
type: "text",
left: "center",
top: "44%",
style: {
text: totalValue,
fill: "#fff",
width: 150,
height: 44,
fontSize: 31,
fontWeight: 400,
},
},
{
type: "text",
left: "center",
top: "55%",
style: {
text: "总数/件",
fill: "rgba(255, 255, 255, 0.70)",
width: 32,
height: 16,
fontSize: 16,
fontWeight: 400,
},
},
],
series: [
{
name: "产线缺陷分类",
type: "pie",
radius: ["45%", "60%"],
center: ["50%", "50%"],
// label: {
// formatter: "{d}%",
// color: "#fff",
// },
label:{
formatter:function(params:any){
return `{color${params.dataIndex}|${params.percent}%}\n{style2|${params.name}}`
},
rich:{
color0:{color:'rgb(39, 96, 255)',fontSize:22},
color1:{color:'rgb(91, 155, 255)',fontSize:22},
color2:{color:'rgb(153, 214, 108)',fontSize:22},
color3:{color:'rgb(18, 255, 245)',fontSize:22},
color4:{color:'rgb(221, 177, 18)',fontSize:22},
color5:{color:'rgb(39, 96, 255)',fontSize:22},
color6:{color:'rgb(91, 155, 255)',fontSize:22},
color7:{color:'rgb(153, 214, 108)',fontSize:22},
color8:{color:'rgb(18, 255, 245)',fontSize:22},
color9:{color:'rgb(221, 177, 18)',fontSize:22},
style2:{
color:'#fff',
fontSize:14
}
}
},
data: dataList,
},
],
};
}

View File

@@ -0,0 +1,72 @@
import ReactECharts from "echarts-for-react";
import TitleBox from "../Component/TitleBox";
import getOptions from "../../Component/BarLineChart/chart.config";
import {useAppSelector} from "./../../../store/hooks"
import { selectAllLine } from "./../../../store/LeaderPageSlice";
function LeftDown() {
const data = useAppSelector(selectAllLine);
interface Detail {
time: string;
input: string;
output: string;
Yield: string;
}
interface DataSource {
time: string[];
input: number[];
output: number[];
yield: number[];
}
let dataSource:DataSource = {
time:[],
input:[],
output:[],
yield:[]
};
if (data.numDet && Array.isArray(data.numDet)) {
(data.numDet as Detail[]).forEach((item: Detail) => {
dataSource.time.push(item.time);
dataSource.input.push(Number(item.input));
dataSource.output.push(Number(item.output));
dataSource.yield.push(Number(item.Yield));
})
}else{
dataSource.time = []
dataSource.input = []
dataSource.output = []
dataSource.yield = []
}
const options1 = getOptions(dataSource);
return(
<div className="ld_left_down">
<TitleBox title={"left_down"} />
{
dataSource.time.length>0?(
<div>
<div className="top_legend">
<span className="chart_legend_icon1"></span>
<span className="chart_legend_icon2"></span>
<span><span className="chart_legend_icon3"></span></span>
</div>
<div style={{ width: "402px", height: "288px" }}>
<ReactECharts option={options1} style={{ height: "100%" }} />
</div>
</div>
):(<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "50px",
margin:0
}}
>
</p>)
}
</div>
)
}
export default LeftDown;

View File

@@ -0,0 +1,85 @@
import TitleBox from "../Component/TitleBox";
import inputImg from "../../assets/icon/input.png"
import prod from '../../assets/icon/prod.png'
import {useAppSelector} from "./../../../store/hooks"
import { selectAllLine } from "./../../../store/LeaderPageSlice";
import { formatNumberWithCommas,parseAndFormatStringToTwoDecimalPlaces } from './../../../utils/index'
function LeftUp() {
const data = useAppSelector(selectAllLine);
console.log(data)
interface DataProps {
input: string,
inputArea: string,
output: string,
outputArea: string
}
let todayData:DataProps = {} as DataProps;
let yesterdayData:DataProps = {} as DataProps;
if (data.todayMap) {
todayData = data.todayMap as DataProps;
yesterdayData = data.yesterdayMap as DataProps;
}
return(
<div className="ld_left_up">
<TitleBox title={"left_up"} />
<div style={{ padding: "10px", height: "555px" }}>
<div className="left_down_title flex-row" style={{marginBottom:"8px"}}>
<div className="left_down_box1 flex-col" />
<span className="left_down_text"></span>
<div className="left_down_box2 flex-col" />
</div>
<div className="ld_left_up_inner">
<div className="num_contrast flex-row">
<div>
<img src={inputImg} alt="" width="54px"/>
<p style={{position:"relative",top:"-3px",left:"3px",color:'#9DEAF5'}}></p>
</div>
<div className="num_contrast_right">
<p style={{height:"45px",paddingTop:'5px'}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{todayData.input?formatNumberWithCommas(todayData.input):'-'}</span></p>
<p style={{height:"40px"}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{todayData.inputArea?parseAndFormatStringToTwoDecimalPlaces(todayData.inputArea):'-'}</span>/</p>
</div>
</div>
<div className="num_contrast flex-row">
<div>
<img src={prod} alt="" width="54px"/>
<p style={{position:"relative",top:"-3px",left:"3px",color:'#9DEAF5'}}></p>
</div>
<div className="num_contrast_right">
<p style={{height:"45px",paddingTop:'5px'}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{todayData.output?formatNumberWithCommas(todayData.output):'-'}</span></p>
<p style={{height:"40px"}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{todayData.outputArea?parseAndFormatStringToTwoDecimalPlaces(todayData.outputArea):'-'}</span>/</p>
</div>
</div>
</div>
<div className="left_down_title flex-row" style={{margin:"10px 0px 8px 0px"}}>
<div className="left_down_box1 flex-col" />
<span className="left_down_text"></span>
<div className="left_down_box2 flex-col" />
</div>
<div className="ld_left_up_inner">
<div className="num_contrast flex-row">
<div>
<img src={inputImg} alt="" width="54px"/>
<p style={{position:"relative",top:"-3px",left:"3px",color:'#9DEAF5'}}></p>
</div>
<div className="num_contrast_right">
<p style={{height:"45px",paddingTop:'5px'}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{yesterdayData.input?formatNumberWithCommas(yesterdayData.input):'-'}</span></p>
<p style={{height:"40px"}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{yesterdayData.inputArea?parseAndFormatStringToTwoDecimalPlaces(yesterdayData.inputArea):'-'}</span>/</p>
</div>
</div>
<div className="num_contrast flex-row">
<div>
<img src={prod} alt="" width="54px"/>
<p style={{position:"relative",top:"-3px",left:"3px",color:'#9DEAF5'}}></p>
</div>
<div className="num_contrast_right">
<p style={{height:"45px",paddingTop:'5px'}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{yesterdayData.output?formatNumberWithCommas(yesterdayData.output):'-'}</span></p>
<p style={{height:"40px"}}><span style={{fontSize:'32px',display:'inline-block',marginRight:'5px'}}>{yesterdayData.outputArea?parseAndFormatStringToTwoDecimalPlaces(yesterdayData.outputArea):'-'}</span>/</p>
</div>
</div>
</div>
</div>
</div>
)
}
export default LeftUp;

View File

@@ -0,0 +1,11 @@
import LeftUp from "./LeftUp";
import LeftDown from "./LeftDown";
function Left() {
return (
<div className="group_left flex-col">
<LeftUp />
<LeftDown />
</div>
);
}
export default Left;

View File

@@ -0,0 +1,33 @@
import TitleBox from "../Component/TitleBox";
import NumberBox from "../Component/NumberBox";
import {useAppSelector} from "./../../../store/hooks"
import { selectAllLine } from "./../../../store/LeaderPageSlice";
import { formatNumberWithCommas } from './../../../utils/index';
function RightDown() {
interface mapInterface {
input:string,
output:string
}
let lastYearMap = {
input:'',
output:''
} as mapInterface
const data = useAppSelector(selectAllLine);
if (data.lastYearMap) {
lastYearMap = data.lastYearMap as mapInterface
}
return(
<div className="ld_right_down">
<TitleBox title={"right_down"} />
<div style={{padding:'10px 0px 0px 20px'}}>
<div style={{width:'365px',height:'128px',marginBottom:'5px'}}>
<NumberBox num={''} show={false} title={'总投入片数/万'} lastYear={true} bigNum={lastYearMap.input?formatNumberWithCommas(lastYearMap.input):'-'}/>
</div>
<div style={{width:'365px',height:'128px'}}>
<NumberBox num={''} show={false} title={'总生产片数/万'} lastYear={true} bigNum={lastYearMap.output?formatNumberWithCommas(lastYearMap.output):'-'}/>
</div>
</div>
</div>
)
}
export default RightDown;

View File

@@ -0,0 +1,86 @@
import TitleBox from "../Component/TitleBox";
import a_r from './../../assets/icon/a_r.png';
import a_g from './../../assets/icon/a_g.png';
import ReactECharts from "echarts-for-react";
import getOptions from "../Component/pieChart/chart.config";
import dayjs from 'dayjs';
function RightUp() {
const monthData = (Math.floor(Math.random() * (1100-900+1))+900)*(dayjs().date());
const dataProps = [
{value: 121,name:'打孔'},
{value: 41,name:'丝印'},
{value: 194,name:'磨边'},
{value: 33,name:'一次镀膜'},
{value: 25,name:'二次镀膜'},
{value: 51,name:'钢化'},
]
const options1 = getOptions(dataProps);
return(
<div className="ld_right_up">
<TitleBox title={"right_up"} />
<div>
<div className="left_down_title flex-row" style={{marginBottom:"8px"}}>
<div className="left_down_box1 flex-col" />
<span className="left_down_text"></span>
<div className="left_down_box2 flex-col" />
</div>
<div className="ld_right_up_box">
<div className="ld_right_up_box1 flex-row">
<div style={{width:"106px"}}>
<p>
{/* <img src={a_r} alt="" width='5px' className="ld_right_up_img"/> */}
<img src={a_g} alt="" width='5px' className="ld_right_up_img"/>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>465</p>
</div>
<div style={{width:"106px"}}>
<p>
<img src={monthData > 29456 ? a_r : a_g} alt="" width='5px' className="ld_right_up_img"/>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>{monthData}</p>
</div>
<div style={{width:"106px"}}>
<p>
<img src={a_r} alt="" width='5px' className="ld_right_up_img"/>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>48549</p>
</div>
</div>
<div className="ld_right_up_box1 flex-row">
<div style={{width:"106px"}}>
<p>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>968</p>
</div>
<div style={{width:"106px"}}>
<p>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>29456</p>
</div>
<div style={{width:"106px"}}>
<p>
</p>
<p style={{fontSize:'28px',textShadow: '0px 5px 2px rgba(0,0,0,0.62)'}}>0</p>
</div>
</div>
</div>
<div className="left_down_title flex-row" style={{marginBottom:"8px"}}>
<div className="left_down_box1 flex-col" />
<span className="left_down_text"></span>
<div className="left_down_box2 flex-col" />
</div>
<div style={{ width: "400px", height: "320px" }}>
<ReactECharts option={options1} style={{ height: "100%" }} />
</div>
</div>
</div>
)
}
export default RightUp;

View File

@@ -0,0 +1,12 @@
import RightDown from "./RightDown";
import RightUp from "./RightUp";
function Right() {
return (
<div className="group_right flex-col">
<RightUp />
<RightDown />
</div>
);
}
export default Right;

32
src/page/LDPage/TopP.tsx Normal file
View File

@@ -0,0 +1,32 @@
import '../../lanhuapp/common.css';
import "./index.css";
import { useState } from "react";
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
function TopP() {
const [time, setTime] = useState(dayjs().format('HH:mm'));
const [date, setDate] = useState(dayjs().format('YY/MM/DD'));
const [weekday, setWeekday] = useState(dayjs().locale('zh-cn').format('dddd'));
setInterval(() => {
setTime(dayjs().format('HH:mm'));
setDate(dayjs().format('YY/MM/DD'));
setWeekday(dayjs().locale('zh-cn').format('dddd'));
})
return (
<div className="flex-row">
<div className="block_top_ld flex-row">
<div className='block_top_title'></div>
<div className='block_top_time'>
<div className='time-title'>{time}</div>
<div className='time-content'>
<div>{weekday}</div>
<div>{date}</div>
</div>
</div>
</div>
</div>
);
}
export default TopP;

View File

@@ -1,4 +1,346 @@
.main-box { /* 顶部 */
font-size: 50px; .block_top_ld {
width: 1920px;
height: 94px;
background: url(/public/svg/topbackLD.svg) 100% no-repeat;
background-size: 100% 100%;
opacity: 1;
display: flex;
justify-content: center;
position: relative;
}
.block_top_title {
width: 651px;
height: 77px;
background: url(/public/png/topTiltle.png) 100% no-repeat;
background-size: 100% 100%;
margin-top: 18px;
}
.block_top_time {
position:absolute;
right:22px;
top:54px;
color:#fff;
letter-spacing: 1px;
}
.block_top_time .time-title {
display:inline-block;
width:113px;
height: 42px;
line-height: 42px;
font-size: 42px;
text-align: center;
}
.block_top_time .time-content {
display:inline-block;
font-size: 18px;
width:95px;
height: 42px;
padding-left:12px;
}
/* 中部 */
.block_bottom {
width: 1920px;
height: 966px;
padding-top: 20px;
}
.group_left {
width: 402px;
height: 966px;
margin: 0 0 0 24px;
}
.group_center {
width: 1041px;
height: 966px;
margin: 0 0 0 15px;
}
.group_right {
width: 401px;
height: 966px;
margin-left: 15px;
}
.ld_left_up {
width: 402px;
height: 599px;
background: url(../../../public/png/rect/lp_left_down.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
position: relative;
}
.ld_left_up_inner {
width: 360px;
height: 236px;
background: url(../../../public/png/rect/ld_left_up_innerbox.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
margin:0 auto;
}
.ld_left_up_inner .num_contrast {
height:113px;
padding:20px 18px 0px 29px;
color:#fff;
}
.ld_left_up_inner .num_contrast p{
margin: 0px;
text-shadow: 0px 4px 2px rgba(0,0,0,0.62);
}
.ld_left_up_inner .num_contrast .num_contrast_right {
padding-left: 18px;
}
.ld_left_down {
width: 402px;
height: 332px;
background: url(../../../public/png/rect/lp_left_up.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
margin-top: 14px;
position: relative;
}
.ld_left_down .top_legend {
color: #fff; color: #fff;
font-size: 14px;
position: absolute;
left:120px;
}
.ld_left_down .top_legend .chart_legend_icon1{
margin-right: 10px;
}
.ld_left_down .top_legend .chart_legend_icon2{
margin-right: 14px;
}
.ld_left_down .top_legend .chart_legend_icon1:before {
display: inline-block;
content: "";
width: 10px;
height: 10px;
margin-right: 5px;
border-radius: 2px;
background: #73F8E0;
}
.ld_left_down .top_legend .chart_legend_icon2:before {
display: inline-block;
content: "";
width: 10px;
height: 10px;
margin-right: 5px;
border-radius: 2px;
background: #497EFF;
}
.ld_left_down .top_legend .chart_legend_icon3 {
display: inline-block;
width: 8px;
height: 8px;
margin-right: 8px;
border-radius: 4px;
background: #73F8E0;
position:relative;
}
.ld_left_down .top_legend .chart_legend_icon3:before {
display: inline-block;
content: "";
width: 16px;
height:2px;
background: #73F8E0;
position:absolute;
top:3px;
left:-4px;
}
.ld_center_up {
width: 1041px;
height: 599px;
background: url(../../../public/png/rect/lp_center_up.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
position: relative;
}
.ld_center_down {
width: 1041px;
height: 332px;
margin-top: 17px;
}
.ld_center_down_inner {
width: 337px;
height: 329px;
background: url(../../../public/png/rect/ld_center_down.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
position: relative;
}
.ld_center_down .ld_left-box, .ld_center_down .ld_center-box {
margin-right: 15px;
position: relative;
}
.ld_right_up {
width: 402px;
height: 599px;
background: url(../../../public/png/rect/lp_left_down.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
position: relative;
}
.ld_right_down {
width: 402px;
height: 332px;
background: url(../../../public/png/rect/lp_left_up.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
margin-top: 14px;
position: relative;
}
.ld_right_up .ld_right_up_box {
width: 358px;
height:160px;
background: url(../../../public/png/rect/ld_left_up_innerbox.png) no-repeat;
background-size: 100% 100%;
background-position: 0 0;
margin:0 auto 20px;
}
.ld_right_up .ld_right_up_box .ld_right_up_box1 {
width:100%;
height: 80px;
color: #fff;
padding:12px 20px;
}
.ld_right_up .ld_right_up_box .ld_right_up_box1 p {
margin:0;
letter-spacing:2px;
font-size:20px;
}
.ld_right_up_img {
position:relative;
left:2px;
top:2px;
}
/* 三维页面部分 */
.ld_center_up .model_name {
position: absolute;
left: 0px;
top: 0px;
z-index: 1000;
}
.ld_center_up .model_info {
position: absolute;
left: 100px;
bottom: 0px;
z-index: 1000;
width: 841px;
height: 62px;
background: url(/public/png/lp/line_part.png) 100% no-repeat;
background-size: 100% 100%;
}
.ld_center_up .model_info .reset_btn {
position: absolute;
top: 20px;
left: 40px;
width: 140px;
height: 40px;
cursor: pointer;
}
.ld_center_up .model_info .title {
display: inline-block;
width: 361px;
text-align: center;
font-size: 32px;
color: #fff;
letter-spacing: 5px;
position: absolute;
left: 241px;
bottom: 10px;
}
.ld_center_up .eq_detail_info {
position: absolute;
right: 0px;
bottom: 0px;
z-index: 1002;
width: 300px;
height: 140px;
background: url(/public/png/lp/eq_msg_detail.png) 100% no-repeat;
background-size: 100% 100%;
color: #fff;
padding: 15px 0 0 15px;
}
.ld_center_up .eq_detail_info .left_name {
display: inline-block;
width: 115px;
height: 28px;
text-align: right;
font-size: 18px;
}
.ld_center_up .eq_detail_info .right_value {
display: inline-block;
height: 28px;
font-size: 18px;
}
.ld_center_up .eq_info {
position: absolute;
z-index: 1002;
background: url(/public/png/lp/eq_msg_always.png) 100% no-repeat;
background-size: 100% 100%;
color: #fff;
padding: 10px 15px;
}
.ld_center_up .eq_info .eq_info_inner {
height: 24px;
font-size: 17px;
white-space: nowrap;
}
.ld_center_up .model_top_container {
width:936px;
height:100px;
position: absolute;
top: 20px;
left: 45px;
z-index: 1002;
text-align: center;
}
.ld_center_up .model_top_container .model_top_style1 {
display: inline-block;
width:203px;
}
.model_top_style1 .model_top_num {
width:100%;
height:65px;
line-height: 65px;
font-size: 38px;
font-weight: 500;
color: #FFFFFF;
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
background: url(./../assets/blue-box.png) 100% no-repeat;
background-size: 100% 100%;
margin-bottom: 5px;
}
.model_top_style2 .model_top_num {
width:100%;
height:65px;
line-height: 65px;
font-size: 38px;
font-weight: 500;
color: #FFFFFF;
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
background: url(./../assets/yellow-box.png) 100% no-repeat;
background-size: 100% 100%;
margin-bottom: 5px;
}
.model_top_style1 .model_top_text {
font-size: 20px;
font-weight: 500;
color: #00C8F7;
letter-spacing: 2px;
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
}
.model_top_style2 .model_top_text {
font-size: 20px;
font-weight: 500;
color: #FFB625;
letter-spacing: 2px;
text-shadow: 0px 5px 2px rgba(0,0,0,0.62);
}
.ld_center_up .model_top_container .model_top_style2 {
display: inline-block;
width:261px;
} }

View File

@@ -1,35 +1,45 @@
import "./index.css" import React from "react";
import TopP from "./TopP";
import Left from "./Left";
import Right from "./Right";
import Center from "./Center";
import {useEffect} from 'react'; import {useEffect} from 'react';
import {useLocation,useNavigate} from "react-router-dom"; import {useLocation,useNavigate} from "react-router-dom";
function LDPage() { function LDPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const {state} = useLocation(); const location = useLocation();
const LineID = location.search.split('=')[1];
console.log(location)
console.log("LDPage被加载了") console.log("LDPage被加载了")
useEffect(() => { useEffect(() => {
const handleKeyDown = (event:any) => { const handleKeyDown = (event:any) => {
if (event.key === 'ArrowUp') { if (event.key === 'ArrowUp') {
console.log('LDPage向上键被按下'); console.log('LDPage向上键被按下');
navigate(`/TP/${state.LineID}`); navigate(`/LP/${LineID}`);
// 执行向上键的逻辑 // 执行向上键的逻辑
} else if (event.key === 'ArrowDown') { } else if (event.key === 'ArrowDown') {
console.log('LDPage向下键被按下'); console.log('LDPage向下键被按下');
// 执行向下键的逻辑 // 执行向下键的逻辑
} navigate(`/LP/${LineID}`);
}; }
};
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keydown', handleKeyDown); return () => {
window.removeEventListener('keydown', handleKeyDown);
};
});
return () => { return (
window.removeEventListener('keydown', handleKeyDown); <React.Fragment>
}; <TopP />
}, []); <div className="block_bottom flex-row">
<Left />
return ( <Center />
<> <Right />
<div className="main-box">LDPage{state.LineID}</div> </div>
<div className="main-box" style={{display:'none'}}>3434</div> </React.Fragment>
</> );
);
} }
export default LDPage; export default LDPage;

View File

@@ -1,248 +0,0 @@
import ReactECharts from "echarts-for-react";
import TitleBox from "../Component/TitleBox";
import ScrollBoard from "./../../Component/ScrollBoard";
import SwitchButton from "../Component/SwitchButton";
import { useState } from "react";
import getOptions from "./LineChart/chart.config";
import { useParams } from "react-router-dom";
function CenterDown() {
const { LineID } = useParams();
const lineID = LineID?.toString() || "1-1";
console.log(lineID.slice(-1));
// 假数据
const dataSource = {
day: {
yData1: [76.1, 77.4, 75.2, 74.1, 78.5, 81.3, 79.2],
yData2: [77.2, 78.1, 78.2, 77.1, 79.2, 78.3, 79.5],
yData3: [75.1, 74.3, 71.3, 79.8, 82.3, 81.4, 80.3],
yData4: [82.4, 83.1, 88.4, 85.3, 87.1, 82.5, 84.9],
yData5: [82.3, 81.9, 85.8, 81.9, 84.1, 83.5, 82.3],
},
week: {
yData1: [120, 200, 150, 80, 100, 89, 69],
yData2: [100, 150, 120, 70, 90, 97, 89],
yData3: [80, 120, 90, 60, 80, 79, 98],
yData4: [60, 90, 70, 40, 60, 69, 98],
yData5: [40, 60, 50, 20, 40, 89, 99],
},
month: {
yData1: [1200, 2000, 1500, 800, 1000, 999, 889],
yData2: [1000, 1500, 1200, 700, 900, 987, 897],
yData3: [800, 1200, 900, 600, 800, 962, 759],
yData4: [600, 900, 700, 400, 600, 896, 987],
yData5: [400, 600, 500, 200, 400, 986, 951],
},
};
const nameList = [
{ name: "天", ename: "day" },
{ name: "周", ename: "week" },
{ name: "月", ename: "month" },
];
const [activeName, setActiveName] = useState<string>(nameList[0].ename);
let chartData = (dataSource as { [key: string]: any })[activeName];
const handleButtonChange = (activeName: string) => {
setActiveName(activeName);
};
const options = getOptions(chartData);
const config = {
header: ["序号", "报警时间", "报警编码", "设备状态"],
headerHeight: 36,
rowNum: 6,
align: ["center", "left", "left", "left"],
headerBGC: "rgba(79, 114, 136, 0.3)",
oddRowBGC: "rgba(79, 114, 136, 0.3)",
evenRowBGC: "rgba(76, 97, 123, 0.1)",
columnWidth: [80, 137, 137, 137],
data: [
["1", "行1列1", "行1列2", "<span style='color:#FF1E1E'>行1列3</span>"],
["2", "行2列1", "行2列2", "<span style='color:#FF1E1E'>行2列3</span>"],
["3", "行3列1", "行3列2", "<span style='color:#FF1E1E'>行3列3</span>"],
["4", "行4列1", "行4列2", "<span style='color:#FFB40F'>行4列3</span>"],
["5", "行5列1", "行5列2", "<span style='color:#FF1E1E'>行5列3</span>"],
["6", "行6列1", "行6列2", "<span style='color:#FFB40F'>行6列3</span>"],
["7", "行7列1", "行7列2", "<span style='color:#FF1E1E'>行7列3</span>"],
["8", "行8列1", "行8列2", "<span style='color:#FF1E1E'>行8列3</span>"],
["9", "行9列1", "行9列2", "<span style='color:#FF1E1E'>行9列3</span>"],
[
"10",
"行10列1",
"行10列2",
"<span style='color:#FFB40F'>行10列3</span>",
],
],
};
const config1 = {
header: ["序号", "报警时间", "报警设备", "报警内容"],
headerHeight: 36,
rowNum: 6,
align: ["center", "left", "left", "left"],
headerBGC: "rgba(79, 114, 136, 0.3)",
oddRowBGC: "rgba(79, 114, 136, 0.3)",
evenRowBGC: "rgba(76, 97, 123, 0.1)",
columnWidth: [80, 137, 137, 137],
data: [
[
"1",
"2024/8/28 08:32",
"清洗机5_1",
"<span style='color:#FF1E1E'>故障</span>",
],
[
"2",
"2024/8/28 06:12",
"清洗机5_1",
"<span style='color:#FFB40F'>离线</span>",
],
[
"3",
"2024/8/28 06:05",
"磨边机5_2",
"<span style='color:#FFB40F'>离线</span>",
],
[
"4",
"2024/8/28 04:43",
"二次镀膜机5_1",
"<span style='color:#FFB40F'>离线</span>",
],
[
"5",
"2024/8/28 02:14",
"磨边机5_1",
"<span style='color:#FF1E1E'>故障</span>",
],
[
"6",
"2024/8/27 22:54",
"磨边机5_2",
"<span style='color:#FFB40F'>离线</span>",
],
[
"7",
"2024/8/27 21:55",
"磨边机5_1",
"<span style='color:#FFB40F'>离线</span>",
],
[
"8",
"2024/8/27 21:42",
"一次镀膜机5_2",
"<span style='color:#FFB40F'>离线</span>",
],
[
"9",
"2024/8/27 21:37",
"磨边机5_1",
"<span style='color:#FFB40F'>离线</span>",
],
],
};
const config2 = {
header: ["序号", "报警时间", "报警设备", "报警内容"],
headerHeight: 36,
rowNum: 6,
align: ["center", "left", "left", "left"],
headerBGC: "rgba(79, 114, 136, 0.3)",
oddRowBGC: "rgba(79, 114, 136, 0.3)",
evenRowBGC: "rgba(76, 97, 123, 0.1)",
columnWidth: [80, 137, 137, 137],
data: [
[
"1",
"2024/8/28 07:44",
"下片机械手5_1",
"<span style='color:#FF1E1E'>故障</span>",
],
[
"2",
"2024/8/28 07:35",
"下片机械手5_1",
"<span style='color:#FF1E1E'>故障</span>",
],
[
"3",
"2024/8/28 03:23",
"在线铺纸机5_1",
"<span style='color:#FFB40F'>离线</span>",
],
[
"4",
"2024/8/28 01:36",
"下片机械手5_2",
"<span style='color:#FF1E1E'>故障</span>",
],
[
"5",
"2024/8/28 00:38",
"钢化炉5",
"<span style='color:#FFB40F'>离线</span>",
],
[
"6",
"2024/8/27 23:58",
"下片机械手5_3",
"<span style='color:#FFB40F'>离线</span>",
],
[
"7",
"2024/8/27 23:45",
"下片机械手5_2",
"<span style='color:#FFB40F'>离线</span>",
],
[
"8",
"2024/8/27 22:34",
"钢化炉5",
"<span style='color:#FFB40F'>离线</span>",
],
[
"9",
"2024/8/27 20:31",
"在线铺纸机5_1",
"<span style='color:#FF1E1E'>故障</span>",
],
],
};
return (
<div className="center_down flex-row">
<div className="center_down_inner flex-col left-box">
<TitleBox title={"center_down_left"} />
<span className="alarm_num_title"> </span>
<div className="alarm_num">321,343</div>
<div style={{ padding: 10, height: "270px" }}>
<ScrollBoard
config={lineID.slice(-1) === "1" ? config1 : config2}
style={{ width: "492px", height: "250px" }}
/>
</div>
</div>
{/* 产线成品率 */}
<div className="center_down_inner flex-col right_box">
<TitleBox title={"center_down_right"} />
{/* <div className="left_up_switch">
<SwitchButton nameList={nameList} onChange={handleButtonChange} />
</div> */}
{options && (
<div className="chart_box">
{<ReactECharts option={options} style={{ height: "100%" }} />}
</div>
)}
{!options && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "72px",
}}
>
</p>
)}
</div>
</div>
);
}
export default CenterDown;

View File

@@ -1,12 +0,0 @@
import LinePageBabylon from "../../../babylonjs/LinePageBabylon";
import { useParams } from "react-router-dom";
function CenterUp() {
const { LineID } = useParams();
const lineID = LineID?.toString() || "1-1";
return (
<div className="center_up">
<LinePageBabylon modelPath={`Line${lineID}`} />
</div>
);
}
export default CenterUp;

View File

@@ -1,69 +0,0 @@
import ReactECharts from "echarts-for-react";
import TitleBox from "../Component/TitleBox";
import SwitchButton from "../Component/SwitchButton";
import getOptions from "./SummaryBarChart/chart.config";
import { useState } from "react";
function LeftUp() {
// 假数据
const dataSource = {
day: {
xData: ["钢1线", "钢2线", "钢3线", "钢4线", "钢5线"],
yData1: [236, 214, 196, 239, 224],
yData2: [346, 296, 327, 311, 322],
yData3: [78, 85, 56, 106, 66],
sumData: [660, 595, 579, 656, 612],
},
week: {
xData: ["钢1线", "钢2线", "钢3线", "钢4线", "钢5线"],
yData1: [1336, 1223, 1313, 1134, 1119],
yData2: [2146, 1996, 2053, 1857, 1798],
yData3: [892, 658, 467, 758, 435],
sumData: [4374, 3877, 3833, 3749, 3352],
},
month: {
xData: ["钢1线", "钢2线", "钢3线", "钢4线", "钢5线"],
yData1: [5789, 6432, 4679, 5456, 5004],
yData2: [8762, 9732, 8137, 8820, 9122],
yData3: [2468, 3120, 2782, 2395, 1924],
sumData: [17019, 19284, 15598, 16671, 16050],
},
};
const nameList = [
{ name: "天", ename: "day" },
{ name: "周", ename: "week" },
{ name: "月", ename: "month" },
];
const [activeName, setActiveName] = useState<string>(nameList[0].ename);
let chartData = (dataSource as { [key: string]: any })[activeName];
const handleButtonChange = (activeName: string) => {
setActiveName(activeName);
};
const options = getOptions(chartData);
return (
<div className="left_up">
<TitleBox title={"left_up"} />
<div className="left_up_switch">
<SwitchButton nameList={nameList} onChange={handleButtonChange} />
</div>
{options && (
<div className="left_up_chart">
{<ReactECharts option={options} style={{ height: "100%" }} />}
</div>
)}
{!options && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "72px",
}}
>
</p>
)}
</div>
);
}
export default LeftUp;

View File

@@ -1,149 +0,0 @@
export default function getOptions(chartData: any) {
if (Object.keys(chartData).length === 0) {
return null;
}
const colors = ["#2760FF", "#8167F6", "#5B9BFF", "#99D66C", "#FFD160"];
let sum = chartData.sumData;
return {
color: colors,
grid: { top: 48, right: 20, bottom: 5, left: 15, containLabel: true },
legend: {
show: true,
icon: "roundRect",
top: 10,
right: 20,
padding: 0,
itemWidth: 10,
itemHeight: 10,
itemGap: 15,
height: 10,
textStyle: {
color: "#DFF1FE",
fontSize: 14,
},
},
xAxis: {
type: "category",
data: chartData.xData,
axisLabel: {
color: "#fff",
fontSize: 16,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},
yAxis: {
name: "单位/片",
nameTextStyle: {
color: "#fff",
fontSize: 14,
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 16,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
width: 2,
color: "#5982B2",
},
},
splitLine: {
lineStyle: {
width: 2,
color: "#5982B2",
},
},
},
tooltip: {
show: false,
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "luoyang-chart-tooltip",
},
// Declare several bar series, each will be mapped
// to a column of dataset.source by default.
series: [
{
data: chartData.yData1,
type: "bar",
stack: "a",
name: "磨边后",
barWidth: 14,
label: {
show: true,
position: "right",
color: "inherit",
},
},
{
data: chartData.yData2,
type: "bar",
stack: "a",
name: "包装1",
label: {
show: true,
position: "right",
color: "inherit",
},
},
{
data: chartData.yData3,
type: "bar",
stack: "a",
name: "包装2",
label: {
show: true,
position: "right",
color: "inherit",
},
},
// {
// data: chartData.yData4,
// type: "bar",
// stack: "a",
// name: "镀膜",
// label: {
// show: true,
// position: "right",
// color: "inherit",
// },
// },
// {
// data: chartData.yData5,
// type: "bar",
// stack: "a",
// name: "包装",
// label: {
// show: true,
// position: "right",
// color: "inherit",
// },
// },
{
data: [0, 0, 0, 0, 0],
type: "bar",
stack: "a",
name: "",
label: {
show: true,
position: "top",
color: "#fff",
formatter: function (params: any) {
return sum[params.dataIndex];
},
},
},
],
};
}

View File

@@ -1,4 +0,0 @@
function Table() {
return <div>111</div>;
}
export default Table;

View File

@@ -1,33 +0,0 @@
import TitleBox from "../Component/TitleBox";
import ScrollBoard from "./../../Component/ScrollBoard";
function RightUp() {
const config = {
header: ["序号", "产线", "上片数据量", "成品下片数量"],
headerHeight: 32,
rowNum: 5,
align: ["center", "left", "left", "left"],
headerBGC: "rgba(79, 114, 136, 0.3)",
oddRowBGC: "rgba(79, 114, 136, 0.3)",
evenRowBGC: "rgba(76, 97, 123, 0.1)",
columnWidth: [70, 90, 106, 114],
data: [
["1", "钢1线", "82315", "64268"],
["2", "钢2线", "78246", "61235"],
["3", "钢3线", "79092", "63562"],
["4", "钢4线", "84125", "66789"],
["5", "钢5线", "85223", "68246"],
],
};
return (
<div className="right_up">
<TitleBox title={"right_up"} />
<div style={{ padding: "10px", height: "213px" }}>
<ScrollBoard
config={config}
style={{ width: "380px", height: "193px" }}
/>
</div>
</div>
);
}
export default RightUp;

View File

@@ -1,18 +0,0 @@
import React from "react";
import TopP from "./TopP";
import Left from "./Left";
import Right from "./Right";
import Center from "./Center";
function LinePage() {
return (
<React.Fragment>
<TopP />
<div className="block_bottom flex-row">
<Left />
<Center />
<Right />
</div>
</React.Fragment>
);
}
export default LinePage;

View File

@@ -0,0 +1,213 @@
import ReactECharts from "echarts-for-react";
import TitleBox from "../Component/TitleBox";
import ScrollBoard from "./../../Component/ScrollBoard";
// import SwitchButton from "../Component/SwitchButton";
import { useState } from "react";
import getOptions from "../../Component/LineChart/chart.config";
import {useAppSelector} from "./../../../store/hooks"
import {selectLine1Before} from "./../../../store/LinePageSlice"
import dayjs from "dayjs";
function CenterDown() {
const data = useAppSelector(selectLine1Before);
// 假数据
const dataSource = {
day: {
xData:[],
series: [] as { name: string; type: string; symbol: string; symbolSize: number; data: never[]; }[],
},
week: {
xData:[],
series: [] as { name: string; type: string; symbol: string; symbolSize: number; data: never[]; }[],
},
month: {
xData:[],
series: [] as { name: string; type: string; symbol: string; symbolSize: number; data: never[]; }[],
},
};
const nameList = [
{ name: "天", ename: "day" },
{ name: "周", ename: "week" },
{ name: "月", ename: "month" },
];
const [activeName] = useState<string>(nameList[1].ename);
// const handleButtonChange = (activeName: string) => {
// setActiveName(activeName);
// };
const config = {
header: ["序号", "报警时间", "报警设备", "报警内容"],
headerHeight: 36,
rowNum: 6,
align: ["center", "left", "left", "left"],
headerBGC: "rgba(79, 114, 136, 0.3)",
oddRowBGC: "rgba(79, 114, 136, 0.3)",
evenRowBGC: "rgba(76, 97, 123, 0.1)",
columnWidth: [80, 137, 177, 97],
data: []
};
// 报警数据
let arr:any = []
let sumAlarm = 0
// @ts-ignore
if (data.alarms && data.alarms.length > 0) {
// @ts-ignore
sumAlarm = data.alarms.length
// @ts-ignore
data.alarms.forEach((item,index) => {
let arrInner = []
arrInner.push(
index+1,
dayjs(item.recTime).format("YYYY/MM/DD HH:mm"),
item.name,
item.status === '故障'?"<span style='color:#FF1E1E'>故障</span>":"<span style='color:#FFB40F'>离线</span>",
);
arr.push(arrInner)
});
}
config.data = arr
// 工段成品率
// @ts-ignore
if (data.todayProductionRates && Object.keys(data.todayProductionRates).length > 0) {
// @ts-ignore
let keys = Object.keys(data.todayProductionRates)
// @ts-ignore
data.todayProductionRates[keys[0]].forEach((item,index)=>{
// @ts-ignore
dataSource.day.xData.push(dayjs(item.recTime).format("HH:mm"))
})
keys.forEach((item,index)=>{
let obj = {
name: "",
type: "line",
symbol: "circle",
symbolSize: 4,
data:[]
}
// @ts-ignore
obj.name = data.todayProductionRates[item][0].lineName
// @ts-ignore
data.todayProductionRates[item].forEach((subItem,index)=>{
// @ts-ignore
obj.data.push(subItem.passRate)
})
dataSource.day.series.push(obj)
})
}else{
dataSource.day.xData = []
dataSource.day.series = []
}
// @ts-ignore
if (data.weekProductionRates && Object.keys(data.weekProductionRates).length > 0) {
// @ts-ignore
let keys = Object.keys(data.weekProductionRates)
// @ts-ignore
data.weekProductionRates[keys[0]].forEach((item,index)=>{
// @ts-ignore
dataSource.week.xData.push(dayjs(item.recTime).format("MM-DD"))
})
keys.forEach((item,index)=>{
let obj = {
name: "",
type: "line",
symbol: "circle",
symbolSize: 4,
data:[]
}
// @ts-ignore
obj.name = data.weekProductionRates[item][0].lineName
// @ts-ignore
data.weekProductionRates[item].forEach((subItem,index)=>{
// @ts-ignore
obj.data.push(subItem.passRate)
})
dataSource.week.series.push(obj)
})
}else{
dataSource.week.xData = []
dataSource.week.series = []
}
// @ts-ignore
if (data.monthProductionRates && Object.keys(data.monthProductionRates).length > 0) {
// @ts-ignore
let keys = Object.keys(data.monthProductionRates)
// @ts-ignore
data.monthProductionRates[keys[0]].forEach((item,index)=>{
// @ts-ignore
dataSource.month.xData.push(dayjs(item.recTime).format("HH:mm"))
})
keys.forEach((item,index)=>{
let obj = {
name: "",
type: "line",
symbol: "circle",
symbolSize: 4,
data:[]
}
// @ts-ignore
obj.name = data.monthProductionRates[item][0].lineName
// @ts-ignore
data.monthProductionRates[item].forEach((subItem,index)=>{
// @ts-ignore
obj.data.push(subItem.passRate)
})
dataSource.month.series.push(obj)
})
}else{
dataSource.month.xData = []
dataSource.month.series = []
}
let chartData = (dataSource as { [key: string]: any })[activeName];
const options = getOptions(chartData);
return (
<div className="center_down flex-row">
<div className="center_down_inner flex-col left-box">
<TitleBox title={"center_down_left"} />
<span className="alarm_num_title"> </span>
<div className="alarm_num">{sumAlarm}</div>
<div style={{ padding: 10, height: "270px" }}>
{arr.length>0?<ScrollBoard
config={config}
style={{ width: "492px", height: "250px" }}
/>:(<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "50px",
margin:0
}}
>
</p>)}
</div>
</div>
{/* 工段成品率 */}
<div className="center_down_inner flex-col right_box">
<TitleBox title={"center_down_right"} />
{/* <div className="left_up_switch">
<SwitchButton nameList={nameList} onChange={handleButtonChange} />
</div> */}
{chartData.xData.length>0 && (
<div className="chart_box">
{<ReactECharts option={options} style={{ height: "100%" }} />}
</div>
)}
{chartData.xData.length===0 && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "120px",
margin:0
}}
>
</p>
)}
</div>
</div>
);
}
export default CenterDown;

View File

@@ -0,0 +1,10 @@
import LinePageBabylon from "../../../babylonjs/LinePageBabylonNew";
function CenterUp() {
const lineID = "1-1"
return (
<div className="center_up">
<LinePageBabylon modelPath={`Line${lineID}`} />
</div>
);
}
export default CenterUp;

Some files were not shown because too many files have changed in this diff Show More