118 Commits

Author SHA1 Message Date
bace9fa501 Merge pull request 'zjl' (#1) from zjl into features/warning
Reviewed-on: #1
2024-07-12 15:11:34 +08:00
c6cd097433 1优化 2024-07-12 14:52:07 +08:00
4d7af62305 窑炉优化 2024-07-12 14:12:10 +08:00
214e9fe892 底&顶ok 2024-07-10 15:39:02 +08:00
9968280724 7.9 2024-07-09 14:50:29 +08:00
lb
8b4322996e update 注释 2024-04-29 13:28:08 +08:00
lb
b325c3fc05 update 报警大小 2024-04-28 13:55:59 +08:00
lb
28c9c1906e update 烟气处理 2024-04-25 11:04:52 +08:00
lb
7ddae1b3a4 update videos 2024-04-25 10:01:25 +08:00
lb
61477cdd30 Merge branch 'features/warning' of http://git.picaiba.com/mt-fe-group/xuchang-new into features/warning 2024-04-25 09:44:40 +08:00
lb
6e5badf01a add video 2024-04-25 09:44:36 +08:00
gtz
311cdfc5f7 1' 2024-04-24 17:02:20 +08:00
lb
bc8b68e449 1 2024-04-24 16:58:38 +08:00
lb
024f4bcf14 1 2024-04-23 15:27:54 +08:00
lb
361aedd4ad done alarm 2024-04-23 15:26:55 +08:00
lb
60c6fdda79 1 2024-04-23 11:24:31 +08:00
lb
15708c0eef update 2024-04-23 09:33:41 +08:00
lb
2996c061dc merge bugfix 2024-04-22 16:58:15 +08:00
lb
9894aeca50 update WarnAlert 2024-04-19 17:03:43 +08:00
lb
9f7652d9f3 update ts->js 2024-04-19 16:55:10 +08:00
lb
e854b966dc add fake websocket server 2024-04-19 16:38:41 +08:00
lb
dff017a5a2 update 2024-04-19 16:11:10 +08:00
lb
e796a07e66 update Home Element Position 2024-04-16 10:28:14 +08:00
lb
43635ff398 add warn-alert 2024-04-15 16:18:21 +08:00
lb
19ea3287ae Merge branch 'bugfix#4.4' 2024-04-15 13:51:16 +08:00
lb
4f6e4cbcf8 bugfix4.4 2024-04-15 13:50:49 +08:00
lb
c9ccc6ebcb fire and kiln inner 2024-01-26 17:25:24 +08:00
lb
4374260acd update lunbo 2024-01-26 17:19:39 +08:00
lb
6cf533e718 add 轮播功能 2024-01-26 14:08:31 +08:00
lb
b0e7a7ca34 update kiln inner 2024-01-26 11:11:26 +08:00
lb
0b48f68078 add refresher 2024-01-26 09:24:26 +08:00
lb
c767a7fe2e update video playbackrate 2024-01-25 16:51:12 +08:00
lb
97409d61a9 1 2024-01-25 16:36:12 +08:00
lb
0da9ba434d update video 2024-01-25 16:15:53 +08:00
lb
0bd1f8dcac update energy cost page 2024-01-25 15:42:25 +08:00
lb
6e10a5aacd update energy 2024-01-25 15:19:27 +08:00
lb
2fb3d05f8c 1 2024-01-25 10:55:22 +08:00
lb
b27a20f3cf update rightbar 2024-01-25 10:24:08 +08:00
lb
be5fbe1c01 update 2024-01-25 09:10:00 +08:00
lb
d6f9744ded 1 2024-01-24 17:01:29 +08:00
lb
1ebda5cf6f 1 2024-01-24 16:13:45 +08:00
lb
b7b2ad2ee5 1 2024-01-24 15:39:42 +08:00
lb
446234c2aa update 2024-01-24 14:41:24 +08:00
lb
909bd92ee6 update 2024-01-11 16:50:55 +08:00
lb
b16ee86def bugfix 20240111 2024-01-11 16:03:33 +08:00
lb
c8d392ce51 update 2024-01-08 13:28:03 +08:00
lb
d1212c8729 update 2024-01-04 17:03:00 +08:00
lb
9d3c877628 update 2024-01-04 16:58:43 +08:00
lb
e1e73b341d update 2024-01-04 16:44:15 +08:00
lb
ac772e2caf fix ui 2024-01-04 10:58:20 +08:00
lb
0b1d3aa4b3 fix ui 2024-01-03 17:00:31 +08:00
lb
bee1aedda4 update 2024-01-03 15:21:43 +08:00
lb
678c1b86ed update 2024-01-03 15:09:59 +08:00
lb
0f56538c27 update websocket reconnect policy & fix some bugs 2024-01-03 15:07:43 +08:00
lb
6b838ce089 update 天然气历史 2024-01-03 11:28:26 +08:00
lb
e40e897882 update 2024-01-02 17:07:07 +08:00
lb
15d05c26d8 update energe layout 2024-01-02 17:01:27 +08:00
lb
c9829d4f5a update faninfostretch 2024-01-02 16:11:37 +08:00
lb
a32e6fb591 update 2024-01-02 14:34:35 +08:00
lb
4b043214ca update elec 2024-01-02 10:53:43 +08:00
lb
871efd2eb2 update 能耗 2023-12-29 12:47:30 +08:00
lb
0cd25a6972 update right table 2023-12-29 12:33:25 +08:00
lb
a73d61fad8 update 2023-12-29 11:06:07 +08:00
lb
3f44cb9e9a update 2023-12-29 09:31:33 +08:00
Melete
060616e845 fix error 2023-12-28 18:54:55 +08:00
lb
2722ca6122 update 2023-12-28 16:59:43 +08:00
lb
049a0804ac update烟气 2023-12-28 16:16:31 +08:00
lb
4e73410495 update 能源,规格: 2023-12-28 15:16:23 +08:00
lb
c2802627d6 update 当前产线生产规格 2023-12-28 10:44:13 +08:00
lb
b57b65ffd4 update 2023-12-27 16:44:24 +08:00
lb
b35cf01fc8 update 2023-12-21 17:41:54 +08:00
lb
f6cbc3a34a del test data 2023-12-20 09:15:12 +08:00
lb
373f990517 update table style 2023-12-19 16:36:53 +08:00
lb
94a713a803 Merge branch 'master' of http://git.picaiba.com/g7hoo/xuchang-new 2023-12-19 15:49:55 +08:00
lb
903a576cdc update 2023-12-19 15:49:24 +08:00
lb
4fc0cf19e9 update 2023-12-19 15:15:10 +08:00
gtz
6374fcdb6f 'add_cutting_newuser' 2023-12-18 18:10:18 +08:00
lb
31e065fa5a update 2023-12-18 09:51:28 +08:00
gtz
98ad9f590c 'update' 2023-12-15 18:42:45 +08:00
gtz
682cfc0407 Merge branch 'master' of git.picaiba.com:g7hoo/xuchang-new 2023-12-15 17:33:17 +08:00
gtz
f32306096f '1' 2023-12-15 17:33:15 +08:00
lb
a2349e6f26 update data 2023-12-15 17:31:33 +08:00
lb
5107dd8ce8 update isra 2023-12-15 15:20:20 +08:00
lb
0b91868b4f update 2023-12-15 11:16:54 +08:00
lb
bb541962dd update 2023-12-15 09:58:40 +08:00
lb
c3511e1bfe update 2023-12-14 13:57:49 +08:00
lb
e4a2af8458 update 2023-12-14 11:24:03 +08:00
lb
68065b612a update 缺陷分类 2023-12-14 11:06:19 +08:00
lb
ac711e6f2a update 2023-12-13 16:59:58 +08:00
lb
19825dcb5f before using typescript 2023-12-13 13:44:45 +08:00
lb
cb0de3b5d0 update 退火-风机信息 2023-12-11 16:04:46 +08:00
lb
85ed13d8f5 update 退火左侧组件 2023-12-11 15:33:34 +08:00
lb
aa2a730acc done 当前温度 2023-12-11 15:28:59 +08:00
lb
c549f38231 add AnnealFanFrequence 2023-12-11 13:52:44 +08:00
lb
9f51f2b3cb update 2023-12-07 09:56:21 +08:00
lb
d4a4e82aa6 update 能源数据对接 2023-12-07 09:20:32 +08:00
lb
dd5ce4d90d update 2023-12-07 09:19:12 +08:00
lb
eadbfcb982 update energy 2023-12-06 16:46:44 +08:00
lb
42e5bea184 update websocket 2023-12-06 16:37:53 +08:00
lb
5f92580c7e add energe slice 2023-12-06 16:24:34 +08:00
gtz
9a4f60a75a 'del_console' 2023-12-04 17:50:49 +08:00
gtz
9814c2b6e9 'update' 2023-12-04 17:47:13 +08:00
lb
49ac95fbbd update 风机信息 2023-12-01 16:30:04 +08:00
lb
6eb4102863 update 风机信息 2023-12-01 16:15:32 +08:00
lb
ad305f0c46 update firedir 2023-12-01 16:05:09 +08:00
lb
4a882104c8 update 投料机 2023-12-01 15:50:33 +08:00
lb
ca6a1c6ede update 2023-12-01 15:19:50 +08:00
lb
52f028d806 update一层温度 2023-12-01 15:15:10 +08:00
lb
69dcea7909 update 2023-12-01 14:40:19 +08:00
lb
04a15dc14c update 一层温度 2023-12-01 13:59:53 +08:00
lb
b601e9065a update 一层温度 2023-12-01 11:34:54 +08:00
lb
550da629c0 update 风机运行频率 2023-12-01 10:17:47 +08:00
lb
d1d47cf5ac update 天然气流量 2023-12-01 09:31:44 +08:00
lb
a880f62393 update 天然气数据 2023-11-30 17:01:30 +08:00
lb
d65fc0e3ed connect 助燃风流量 2023-11-30 16:40:02 +08:00
lb
af531456f4 connect KilnInfo 2023-11-30 16:07:41 +08:00
lb
bc03a717bb Merge branch 'testing-redux' 2023-11-10 10:10:18 +08:00
lb
3821121a6f add more slices 2023-11-10 10:09:50 +08:00
247 changed files with 18030 additions and 9961 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies # dependencies
/node_modules **/node_modules
/.pnp /.pnp
.pnp.js .pnp.js

12377
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.2.6",
"@babel/core": "^7.16.0", "@babel/core": "^7.16.0",
"@jiaminghi/data-view-react": "^1.2.5", "@jiaminghi/data-view-react": "^1.2.5",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
@@ -22,6 +23,7 @@
"case-sensitive-paths-webpack-plugin": "^2.4.0", "case-sensitive-paths-webpack-plugin": "^2.4.0",
"css-loader": "^6.5.1", "css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.2.0", "css-minimizer-webpack-plugin": "^3.2.0",
"dayjs": "^1.11.10",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0", "dotenv-expand": "^5.1.0",
"echarts": "^5.4.3", "echarts": "^5.4.3",
@@ -59,6 +61,7 @@
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"tailwindcss": "^3.0.2", "tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5", "terser-webpack-plugin": "^5.2.5",
"uuid": "^9.0.1",
"webpack": "^5.64.4", "webpack": "^5.64.4",
"webpack-dev-server": "^4.6.0", "webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2", "webpack-manifest-plugin": "^4.0.2",
@@ -67,7 +70,9 @@
"scripts": { "scripts": {
"start": "node scripts/start.js", "start": "node scripts/start.js",
"build": "node scripts/build.js", "build": "node scripts/build.js",
"test": "node scripts/test.js" "server": "node websocket/server.js",
"test": "node scripts/test.js",
"ws": "node websocket/server.js"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
@@ -89,8 +94,10 @@
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@types/uuid": "^9.0.7",
"less": "^4.2.0", "less": "^4.2.0",
"less-loader": "^11.1.3" "less-loader": "^11.1.3",
"typescript": "^5.3.3"
}, },
"jest": { "jest": {
"roots": [ "roots": [

View File

@@ -29,6 +29,8 @@
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!-- <div id="alarm-list-container"></div> -->
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.

Binary file not shown.

BIN
public/video/1to2_old.webm Normal file

Binary file not shown.

Binary file not shown.

BIN
public/video/2to1_old.webm Normal file

Binary file not shown.

BIN
public/video/east_fire.webm Normal file

Binary file not shown.

Binary file not shown.

BIN
public/video/enter_old.webm Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/video/west_fire.webm Normal file

Binary file not shown.

View File

@@ -1,27 +1,68 @@
// import "./App.css";
import "./global.css"; import "./global.css";
import "./index.css"; import "./index.css";
import Head from "./components/Common/Company"; import Head from "./components/Common/Company";
// import { SocketContextProvider } from "../store/socket-data-provider";
import useSlider, { Slider } from "./hooks/useSlider"; import useSlider, { Slider } from "./hooks/useSlider";
import NavMenu from "./components/Common/NavMenu"; import NavMenu from "./components/Common/NavMenu";
import { useState } from "react"; import { useEffect, useState } from "react";
import Home from "./pages/Home"; import Home from "./pages/Home";
import EnergyAnalysis from "./pages/EnergyCostAnalysis"; import EnergyAnalysis from "./pages/EnergyCostAnalysis";
import RulerContainer from "./components/Tools/Ruler"; import RulerContainer from "./components/Tools/Ruler";
import { Switch } from "antd";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
const Menus = ["窑炉总览", "窑炉内部", "窑炉优化","退火监测", "质检统计", "能耗分析"];
const LUNBO_INTERVAL = 60 * 1000;
function App() { function App() {
const { styles, value, setValue } = useSlider(100); const { styles, value, setValue } = useSlider(100);
const [navActive, setNavActive] = useState("窑炉总览"); const [navActive, setNavActive] = useState("窑炉总览");
const [lunbo, setlunbo] = useState(false);
useEffect(() => {
let timer;
if (lunbo) {
timer = setInterval(() => {
handleMenuChange(Menus[(Menus.indexOf(navActive) + 1) % Menus.length]);
}, LUNBO_INTERVAL);
}
return () => {
clearInterval(timer);
};
}, [lunbo, navActive]);
function handleSwitchChange(val) {
setlunbo(val);
}
function handleMenuChange(value) {
setNavActive(value);
}
return ( return (
<> <>
<div id="FullScreen" style={styles}> <div id="FullScreen" style={{ ...styles, overflow: "hidden" }}>
<NavMenu active={navActive} onChangeActive={(v) => setNavActive(v)} /> <NavMenu active={navActive} onChangeActive={handleMenuChange} />
<Head /> <Head />
<div
className="lunbo-setting"
style={{
position: "fixed",
top: "48px",
right: "680px",
display: "flex",
alignItems: "center",
gap: "16px",
}}
>
<span style={{ fontSize: "20px", color: "#00fff7" }}>模块轮播</span>
<Switch
className="lunbo-btn"
size="small"
value={lunbo}
onChange={handleSwitchChange}
/>
</div>
{navActive == "能耗分析" && <EnergyAnalysis />} {navActive == "能耗分析" && <EnergyAnalysis />}
{navActive == "能耗分析" && <div className="bgDitu"></div>}
{navActive != "能耗分析" && <Home active={navActive} />} {navActive != "能耗分析" && <Home active={navActive} />}
</div> </div>
<Slider value={value} setValue={setValue} /> <Slider value={value} setValue={setValue} />

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
src/assets/Icon/kilnTop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

14
src/assets/Icon/temp.svg Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>温度</title>
<g id="退火监测" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-64.000000, -134.000000)" fill-rule="nonzero" id="编组-8备份">
<g transform="translate(40.000000, 112.000000)">
<g id="温度" transform="translate(24.000000, 22.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="24" height="24"></rect>
<path d="M18.6,15 C18.15,14.25 17.4,13.5 16.5,13.05 L16.5,3 C16.5,1.35 15.3,0 13.65,0 C12,0 10.8,1.35 10.8,3 L10.8,13.2 C9.9,13.5 9.3,14.25 8.7,15 C8.1,15.9 7.8,16.95 7.8,18.15 C7.8,19.65 8.4,21.15 9.45,22.2 C10.5,23.25 12.15,24 13.65,24 C15.15,24 16.65,23.4 17.7,22.35 C18.75,21.3 19.35,19.8 19.35,18.3 C19.5,17.1 19.2,16.05 18.6,15 Z M13.65,22.95 C10.95,22.95 8.85,20.7 8.85,18.15 C8.85,16.35 9.9,14.7 11.55,13.8 L11.85,13.65 L11.85,3 C11.85,1.95 12.75,1.05 13.8,1.05 C14.85,1.05 15.75,1.95 15.75,3 L15.75,13.8 L16.05,13.95 C17.7,14.85 18.75,16.5 18.75,18.3 C18.6,20.85 16.35,22.95 13.65,22.95 Z M14.55,15.6 L14.55,6.15 C14.55,5.7 14.1,5.25 13.65,5.25 C13.2,5.25 12.75,5.7 12.75,6.15 L12.75,15.6 C11.7,15.9 11.1,16.95 11.1,18 C11.1,19.35 12.3,20.55 13.65,20.55 C15,20.55 16.2,19.35 16.2,18 C16.2,16.95 15.6,15.9 14.55,15.6 Z M8.25,4.35 L3.6,4.35 C3,4.35 2.7,4.05 2.7,3.45 C2.7,3 3,2.55 3.6,2.55 L8.4,2.55 C8.85,2.55 9.3,3 9.3,3.45 C9.15,4.05 8.85,4.35 8.25,4.35 L8.25,4.35 Z M8.25,7.2 L5.25,7.2 C4.8,7.2 4.35,6.75 4.35,6.3 C4.35,5.85 4.8,5.4 5.25,5.4 L8.25,5.4 C8.7,5.4 9.15,5.85 9.15,6.3 C9.15,6.9 8.85,7.2 8.25,7.2 Z M8.25,10.2 L7.35,10.2 C6.9,10.2 6.45,9.75 6.45,9.3 C6.45,8.85 6.9,8.4 7.35,8.4 L8.4,8.4 C8.85,8.4 9.3,8.85 9.3,9.3 C9.15,9.75 8.85,10.2 8.25,10.2 Z" id="形状" fill="#59D0E2"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 13</title>
<g id="·窑炉总览" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="总览" transform="translate(-1823.000000, -772.000000)">
<g id="编组-20备份-5" transform="translate(1786.000000, 764.000000)">
<g id="编组-13" transform="translate(45.000000, 16.000000) scale(1, -1) rotate(-180.000000) translate(-45.000000, -16.000000) translate(37.000000, 8.000000)">
<rect id="矩形" stroke="#979797" fill="#D8D8D8" opacity="0" x="0.5" y="0.5" width="15" height="15"></rect>
<path d="M3.67840479,4.47768215 L12.3215952,4.47768215 C12.87388,4.47768215 13.3215952,4.9253974 13.3215952,5.47768215 C13.3215952,5.70423387 13.2446673,5.92407165 13.1034098,6.1011931 L8.78181462,11.5200015 C8.43745903,11.9517857 7.80827335,12.0226607 7.37648905,11.6783051 C7.31796217,11.6316289 7.2648616,11.5785283 7.21818538,11.5200015 L2.89659016,6.1011931 C2.55223458,5.6694088 2.62310955,5.04022312 3.05489384,4.69586753 C3.23201529,4.55461005 3.45185307,4.47768215 3.67840479,4.47768215 Z" id="路径-2" fill="#03233C"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 7.5 MiB

BIN
src/assets/kilnSpeed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
src/assets/offline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/assets/online.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
src/assets/tempIntr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
src/assets/warn-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
src/assets/warn-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,5 @@
function AmenSelector() {
return <div className="amen-selector"></div>;
}
export default AmenSelector;

View File

@@ -0,0 +1,213 @@
// AnnealFanRunFrequence
import cls from "./index.module.css";
import * as echarts from "echarts";
import GraphBase from "../GraphBase";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
function WindFrequence(props) {
const [currLine, setCurrLine] = useState('Y61')
const [showChart, setShowChart] = useState(false);
const [currentLine, setCurrentLine] = useState([]);
const runState = useSelector((state) => state.annealFanFrequence.runtime);
const hisState = useSelector((state) => state.annealFanFrequence.history);
let dataList = [];
let seriesData = [];
const colors = [
"#12FFF5",
"#2760FF",
"#FFD160",
"#E80091",
"#8064ff",
"#ff8a3b",
"#8cd26d",
"#2aa1ff",
];
let options = null;
if (showChart) {
// keys() 结果不是按照顺序,需要 sort()
seriesData =
hisState != null
? Object.keys(hisState)
.sort()
.map((key) => hisState[key])
: Array(8)
.fill(1)
.map((_) => Array(7).fill(0));
options = {
color: colors,
grid: { top: 32, right: 12, bottom: 20, left: 48 },
xAxis: {
type: "category",
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp
).getDate()}`;
})
.reverse(),
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
},
yAxis: {
name: "单位/m³",
nameTextStyle: {
color: "#fff",
fontSize: 10,
align: "right",
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
// interval: 10,
// min: 0,
// max: 100,
},
series: seriesData.map((v, i) => ({
name: i + 1 + "#风机",
data: v,
type: "line",
symbol: "circle",
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// i % 8 避免超过8个数据时无颜色的问题
{ offset: 0, color: colors[i % 8] + "40" },
{ offset: 0.5, color: colors[i % 8] + "20" },
{ offset: 1, color: colors[i % 8] + "00" },
]),
},
})),
tooltip: {
trigger: "axis",
},
};
} else {
console.log('runstate changeD!......')
dataList =
runState != null
? Object.keys(runState).map((fan) => ({
id: Math.random(),
name: fan,
value: runState[fan],
}))
: [
{ id: 1, name: "1#风机#1", value: "0m³/h" },
// { id: 133, name: "1#风机#1", value: "0m³/h" },
// { id: 134, name: "1#风机#1", value: "0m³/h" },
// { id: 1344, name: "1#风机#1", value: "0m³/h" },
// { id: 51, name: "1#风机#1", value: "0m³/h" },
// { id: 1534, name: "1#风机#1", value: "0m³/h" },
// { id: 154, name: "1#风机#1", value: "0m³/h" },
// { id: 153, name: "1#风机#1", value: "0m³/h" },
// { id: 111, name: "1#风机#1", value: "0m³/h" },
{ id: 2, name: "2#风机#1", value: "0m³/h" },
{ id: 3, name: "3#风机#1", value: "0m³/h" },
{ id: 4, name: "4#风机#1", value: "0m³/h" },
{ id: 5, name: "5#风机#1", value: "0m³/h" },
{ id: 11, name: "1#风机#2", value: "0m³/h" },
{ id: 12, name: "2#风机#2", value: "0m³/h" },
{ id: 13, name: "3#风机#2", value: "0m³/h" },
{ id: 14, name: "4#风机#2", value: "0m³/h" },
{ id: 15, name: "5#风机#2", value: "0m³/h" },
];
}
function handleSwitchChange(val) {
if (val) {
setShowChart(true);
} else {
setShowChart(false);
}
}
useEffect(() => {
if (!showChart) {
setCurrentLine((old) =>
dataList.filter((item) => item?.name.startsWith("1#"))
);
}
}, [showChart]);
function handleLineChange(line) {
const lineNum = line[2];
setCurrLine(line);
setCurrentLine((old) =>
dataList.filter((item) => item?.name.startsWith(`${lineNum}#`))
);
}
return (
<GraphBase
icon="kiln"
title="风机运行频率"
size={["middle", "long"]}
switchOptions={false}
switchPosition={[null, 200]} // [top, left]
onSwitch={handleSwitchChange}
dateOptions={["Y61", "Y62", "Y63", "Y64", "Y65"]}
selectWidth={70}
defaultSelect={currLine}
onDateChange={handleLineChange}
>
<div className={cls.chart} style={{ marginTop: "24px" }}>
{/* {showChart && (
<ReactECharts option={options} style={{ height: "100%" }} />
)} */}
{!showChart && (
<div className={cls.gridList}>
{currentLine.map((item) => (
<div
key={item.id}
className={cls.listItem}
style={{ padding: props.stretch ? "20px 0" : "" }}
>
<span className={cls.fanName}>{item.name}</span>
<span
className={cls.fanValue}
style={{
fontWeight: 700,
letterSpacing: 1,
fontSize: 16,
// color: "#e03537",
color: "#24aebb",
}}
>
{item.value}
</span>
</div>
))}
</div>
)}
</div>
</GraphBase>
);
}
export default WindFrequence;

View File

@@ -0,0 +1,52 @@
.chart {
height: 100%;
}
.gridList {
margin-top: 12px;
display: grid;
grid-template-columns: 1fr 1fr;
/* grid-auto-row: ; */
gap: 8px;
}
.listItem {
border-radius: 2px;
padding: 10px 0;
text-align: center;
color: #fff;
box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197);
display: flex;
align-items: center;
gap: 12px;
}
.headWidget {
position: absolute;
top: 22px;
right: 24px;
height: 32px;
width: 410px;
display: flex;
align-items: center;
justify-content: flex-start;
color: #fff;
}
.relative {
position: relative;
}
.flex {
display: flex;
align-items: center;
}
.fanName {
text-align: right;
flex: 7;
}
.fanValue {
flex: 3;
text-align: left;
}

View File

@@ -0,0 +1,28 @@
import cls from "./index.module.css";
const Arrow = ({ direction, disabled, onClick }) => {
function handleClick() {
onClick(direction)
}
return (
<button
className={`${cls["arrow"]} ${
direction == "right" ? cls["arrow__right"] : ""
} ${true ? "disabled" : ""}`}
onClick={handleClick}
>
<div
className={`${cls["arrow-top"]} ${
direction == "right" ? cls["arrow-top__right"] : ""
}`}
></div>
<div
className={`${cls["arrow-bottom"]} ${
direction == "right" ? cls["arrow-bottom__right"] : ""
}`}
></div>
</button>
);
};
export default Arrow;

View File

@@ -0,0 +1,60 @@
.arrow {
appearance: none;
outline: none;
border: none;
background: transparent;
width: 16px;
height: 48px;
position: absolute;
top: 112px;
left: 5px;
cursor: pointer;
z-index: 10;
}
.arrow.disabled > div {
background: #3d4a56;
}
.arrow__right {
left: unset;
right: 5px;
}
.arrow:hover > div {
background: #00f3ed;
}
.arrow-top {
transition: background 0.1s ease-out;
background: #1eaba9;
width: 8px;
height: 24px;
position: absolute;
top: 0;
left: 0;
border-radius: 12px;
transform: rotateZ(20deg) translateY(2px) translateX(4px);
}
.arrow-bottom {
transition: background 0.1s ease-out;
background: #1eaba9;
width: 8px;
height: 24px;
position: absolute;
bottom: 0;
left: 0;
border-radius: 12px;
transform: rotateZ(-20deg) translateY(-2px) translateX(4px);
}
.arrow-top__right {
transform: rotateZ(-20deg) translateY(4px) translateX(4px);
}
.arrow-bottom__right {
transform: rotateZ(20deg) translateY(-4px) translateX(4px);
}

View File

@@ -0,0 +1,32 @@
import cls from "./index.module.css";
function BlueRect(props) {
const title = props.title || "DEFAULT";
const value = props.value || "0℃";
return (
<div
className={`${cls.blueRect} ${cls[title]}`}
style={{
background: props.blue ? "#0a4268ee" : "#0a426860",
}}
>
<span
className="title"
style={{
fontSize: "18px",
lineHeight: "24px",
color: props.blue ? "#40afb8" : "#fff",
fontWeight: 600,
userSelect: "none",
}}
>
{title}
</span>
<span className="value" style={{ userSelect: "none", fontSize: "22px" }}>
{value}
</span>
</div>
);
}
export default BlueRect;

View File

@@ -0,0 +1,544 @@
.blueRect {
display: inline-block;
width: 106px;
height: 68px;
position: absolute;
top: 0;
left: 0;
padding: 6px 0;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
background: #0a426820;
border-radius: 4px;
}
.blueRect::before {
content: "";
display: inline-block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: linear-gradient(
to right,
transparent 0%,
transparent 50%,
#24aebb 100%
);
border-radius: 3px;
}
.blueRect::after {
content: "";
display: inline-block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
background: linear-gradient(
to right,
#24aebb 0%,
transparent 50%,
transparent 100%
);
border-radius: 3px;
}
/** left **/
.TE271 {
top: 160px;
left: 70px;
}
.TE272 {
top: 254px; /* +94px */
left: 70px;
}
.TE273 {
top: 348px; /* +94px */
left: 70px;
}
.TE274 {
top: 442px;
left: 70px;
}
.TE279 {
top: 536px;
left: 70px;
}
.TE275 {
top: 160px;
left: 206px;
}
.TE276 {
top: 254px;
left: 206px; /* +136px */
}
.TE277 {
top: 348px; /* +94px */
left: 206px; /* +136px */
}
.TE278 {
top: 442px; /* +94px */
left: 206px; /* +136px */
}
.TE280 {
top: 536px; /* +94px */
left: 206px; /* +136px */
}
/** center top **/
.TE227 {
top: 128px;
left: 630px;
}
.TE229 {
top: 128px;
left: 746px; /* +120px */
}
.TE231 {
top: 128px;
left: 866px;
}
.TE233 {
top: 128px;
left: 980px;
}
.TE235 {
top: 128px;
left: 1100px;
}
.TE237 {
top: 128px;
left: 1220px;
}
.TE239 {
top: 128px;
left: 1330px;
}
.TE241 {
top: 128px;
left: 1450px;
}
/** center bottom **/
.TE228 {
top: 620px;
left: 600px;
}
.TE230 {
top: 620px;
left: 720px;
}
.TE232 {
top: 620px;
left: 850px;
}
.TE234 {
top: 620px;
left: 970px;
}
.TE236 {
top: 620px;
left: 1100px;
}
.TE238 {
top: 620px;
left: 1225px;
}
.TE240 {
top: 620px;
left: 1350px;
}
.TE242 {
top: 620px;
left: 1470px;
}
/** center middle **/
.TE201 {
top: 410px;
/* transform: rotate(-1deg); */
left: 480px;
}
.TE202 {
top: 410px;
/* transform: rotate(-1deg); */
left: 610px;
}
.TE203 {
top: 410px;
/* transform: rotate(-1deg); */
left: 740px;
}
.TE204 {
top: 410px;
/* transform: rotate(-1deg); */
left: 870px;
}
.TE205 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1000px;
}
.TE206 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1130px;
}
.TE207 {
top: 330px;
/* transform: rotate(-1deg); */
left: 1260px;
}
.TE208 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1260px;
}
.TE209 {
top: 485px;
/* transform: rotate(-1deg); */
left: 1260px;
}
.TE210 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1390px;
}
.TE211 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1520px;
}
.TE212 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1650px;
}
.TE213 {
top: 410px;
/* transform: rotate(-1deg); */
left: 1780px;
}
/** right **/
.TE214 {
top: 168px;
left: 2000px;
}
.TE215 {
top: 265px;
left: 2030px;
}
.TE216 {
top: 400px;
left: 2050px;
}
.TE217 {
top: 520px;
left: 2070px;
}
.TE218 {
top: 660px;
left: 2090px;
}
.TE219 {
top: 168px;
left: 2120px;
}
.TE220 {
top: 265px;
left: 2135px;
}
.TE221 {
top: 400px;
left: 2170px;
}
.TE222 {
top: 520px;
left: 2180px;
}
.TE223 {
top: 660px;
left: 2200px;
}
.TE224 {
top: 265px;
left: 2240px;
}
.TE225 {
top: 400px;
left: 2290px;
}
.TE226 {
top: 520px;
left: 2290px;
}
/** 一层 --- 窑底 **/
.TE401 {
top: 420px;
left: 20px;
}
.TE402 {
top: 420px;
left: 140px;
}
.TE403 {
top: 420px;
left: 260px;
}
.PE401 {
top: 320px;
left: 20px;
}
.PE402 {
top: 320px;
left: 140px;
}
.PE403 {
top: 320px;
left: 260px;
}
/** center top **/
.TE333 {
top: 128px;
left: 660px;
}
.TE335 {
top: 128px;
left: 775px;
}
.TE337 {
top: 128px;
left: 880px;
}
.TE339 {
top: 128px;
left: 1000px;
}
.TE341 {
top: 128px;
left: 1110px;
}
.TE343 {
top: 128px;
left: 1225px;
}
.TE345 {
top: 128px;
left: 1335px;
}
.TE347 {
top: 128px;
left: 1440px;
}
/** center bottom **/
.TE334 {
top: 620px;
left: 610px;
}
.TE336 {
top: 620px;
left: 730px;
}
.TE338 {
top: 620px;
left: 860px;
}
.TE340 {
top: 620px;
left: 980px;
}
.TE342 {
top: 620px;
left: 1110px;
}
.TE344 {
top: 620px;
left: 1235px;
}
.TE346 {
top: 620px;
left: 1360px;
}
.TE348 {
top: 620px;
left: 1480px;
}
/** center middle **/
.TE301 {
top: 340px;
transform: scaleY(0.8);
left: 450px;
}
.TE302 {
top: 400px;
transform: scaleY(0.8);
left: 450px;
}
.TE303 {
top: 460px;
transform: scaleY(0.8);
left: 450px;
}
.TE304 {
top: 400px;
/* transform: scaleY(0.8) skewX(-2deg); */
transform: scaleY(0.8);
left: 580px;
}
.TE305 {
top: 340px;
/* transform: scaleY(0.8) skewX(-2deg); */
transform: scaleY(0.8);
left: 720px;
}
.TE306 {
top: 400px;
/* transform: scaleY(0.8) skewX(-2deg); */
/* transform: scaleY(0.8) rotate(-1deg); */
transform: scaleY(0.8);
left: 720px;
}
.TE307 {
top: 460px;
/* transform: scaleY(0.8) rotate(-1deg); */
transform: scaleY(0.8);
left: 720px;
}
.TE308 {
top: 400px;
transform: scaleY(0.8);
left: 860px;
}
.TE309 {
top: 400px;
transform: scaleY(0.8);
left: 1000px;
}
.TE310 {
top: 400px;
transform: scaleY(0.8);
left: 1140px;
}
.TE311 {
top: 340px;
transform: scaleY(0.8);
left: 1280px;
}
.TE312 {
top: 400px;
transform: scaleY(0.8);
left: 1280px;
}
.TE313 {
top: 460px;
transform: scaleY(0.8);
left: 1280px;
}
.TE314 {
top: 400px;
transform: scaleY(0.8);
left: 1420px;
}
.TE315 {
top: 400px;
transform: scaleY(0.8);
left: 1560px;
}
.TE316 {
top: 400px;
transform: scaleY(0.8);
left: 1700px;
}
.TE317 {
top: 340px;
transform: scaleY(0.8);
left: 1840px;
}
.TE318 {
top: 400px;
transform: scaleY(0.8);
left: 1840px;
}
.TE319 {
top: 460px;
transform: scaleY(0.8);
left: 1840px;
}
/** right **/
.TE327 {
top: 152px;
left: 2000px;
transform: scale(0.8) skewX(5deg);
}
.TE320 {
top: 252px;
left: 2020px;
transform: scale(0.8) skewX(7deg);
}
.TE321 {
top: 400px;
left: 2040px;
transform: scale(0.8) skewX(7deg);
}
.TE322 {
top: 532px;
left: 2060px;
transform: scale(0.8) skewX(7deg);
}
.TE330 {
top: 656px;
left: 2080px;
transform: scale(0.8) skewX(7deg);
}
.TE323 {
top: 152px;
left: 2100px;
transform: scale(0.8) skewX(7deg);
}
.TE328 {
top: 252px;
left: 2120px;
transform: scale(0.8) skewX(7deg);
}
.TE331 {
top: 400px;
left: 2140px;
transform: scale(0.8) skewX(7deg);
}
.TE329 {
top: 532px;
left: 2160px;
transform: scale(0.8) skewX(7deg);
}
.TE326 {
top: 656px;
left: 2180px;
transform: scale(0.8) skewX(7deg);
}
.TE324 {
top: 252px;
left: 2220px;
transform: scale(0.8) skewX(7deg);
}
.TE332 {
top: 400px;
left: 2260px;
transform: scale(0.8) skewX(7deg);
}
.TE325 {
top: 532px;
left: 2260px;
transform: scale(0.8) skewX(7deg);
}

View File

@@ -6,6 +6,7 @@ function BottomBarItem(props) {
<Container <Container
icon={props.icon} icon={props.icon}
title={props.title} title={props.title}
desc={props.desc}
className={`${cls.bottomBarItem} ${props.className}`} className={`${cls.bottomBarItem} ${props.className}`}
style={props.style} style={props.style}
> >

View File

@@ -32,7 +32,7 @@ export default function CompanyName() {
<img src={TopSide} alt="图片丢失" className={cls.TopSideLeft}/> <img src={TopSide} alt="图片丢失" className={cls.TopSideLeft}/>
<div className={cls.TopSideLeftLine}> <div className={cls.TopSideLeftLine}>
<img src={LeftLine} alt="图片丢失" className={cls.TopSideLeftLineicon}/> <img src={LeftLine} alt="图片丢失" className={cls.TopSideLeftLineicon}/>
<h2 className={cls.TopSideLeftTxt}>单位河南汇融科技服务有限公司</h2> <h2 className={cls.TopSideLeftTxt}>单位河南汇融数字科技有限公司</h2>
</div> </div>
<div> <div>
<h2 className={cls.TopTitleText}> <h2 className={cls.TopTitleText}>

View File

@@ -38,9 +38,10 @@
.TopSideLeftTxt { .TopSideLeftTxt {
margin-right: 120px; margin-right: 120px;
margin-top: 15px; margin-top: 15px;
color: rgb(255, 255, 255, 0.8); color: rgb(255, 255, 255, 0.6);
font-size: 20px; font-size: 20px;
font-weight: 300px; font-weight: 300px;
letter-spacing: 1px;
line-height: 22.174976px; line-height: 22.174976px;
} }
} }
@@ -77,9 +78,9 @@
} }
.TopTitleText { .TopTitleText {
margin-top: 16px; margin-top: 40px;
letter-spacing: 8px; letter-spacing: 8px;
font-size: 32px; font-size: 34px;
color: #00fff7; color: #00fff7;
text-align: center; text-align: center;
letter-spacing: 2px; letter-spacing: 2px;

View File

@@ -1,60 +1,36 @@
import BottomBarItem from "../BottomItemBackground"; import BottomBarItem from "../BottomItemBackground";
import React, { Component } from "react";
import cls from "./righttable.module.scss"; import cls from "./righttable.module.scss";
import { useSelector } from "react-redux";
import { ScrollBoard } from "@jiaminghi/data-view-react"; import { ScrollBoard } from "@jiaminghi/data-view-react";
let data = [ function Chart1(props) {
["产线0", "10mm", "10mm", "10mm"], const rawData = useSelector((state) => state.cutting.productData);
["产线2", "8mm", "8mm", "8mm"],
["产线3", "15mm", "15mm", "15mm"],
["产线4", "15mm", "15mm", "15mm"],
["产线42", "15mm", "15mm", "15mm"],
["产线5", "15mm", "15mm", "15mm"],
["产线6", "15mm", "15mm", "15mm"],
];
let header = ["产线名", "原板宽度", "净板宽", "玻璃厚度"]; let config = {
// headerBGC: "rgba(4, 44, 76, 0.3)",
let config = { headerBGC: "#044A8460",
headerBGC: "rgba(4, 44, 76, 0.3)",
header: [ header: [
'<span style="color:#fff">产线名<span/>', '<span style="color:#fff; padding-left: 8px;">产线名<span/>',
'<span style="color:#fff">原板宽度<span/>', '<span style="color:#fff; padding-left: 8px;">玻璃长度<span/>',
'<span style="color:#fff">净板宽<span/>', '<span style="color:#fff; padding-left: 8px;">玻璃宽度<span/>',
'<span style="color:#fff">玻璃厚度<span/>', '<span style="color:#fff; padding-left: 8px;">玻璃厚度<span/>',
], ],
oddRowBGC: "#042444", // oddRowBGC: "#042444",
evenRowBGC: "#042c4c", // evenRowBGC: "#042c4c",
oddRowBGC: "#044A8460",
evenRowBGC: "#0b549970",
columnWidth: [128], columnWidth: [128],
headerHeight: 40, headerHeight: 40,
hoverPause: false, hoverPause: true,
data: replaceStyle(data, 0.7), data: replaceStyle(filterData(rawData), 0.7),
}; };
function replaceStyle(Arr, opencity) {
let temp = [];
for (let i = 0; i < Arr.length; i++) {
temp[i] = [];
for (let j = 0; j < Arr[i].length; j++) {
temp[i][
j
] = ` <span style="color:rgba(255, 255, 255,${opencity})">${Arr[i][j]}<span/>`;
}
}
return temp;
}
class Chart1 extends Component {
render() {
return ( return (
<BottomBarItem <BottomBarItem
icon="pause" icon="pause"
title="当前产线生产规格" title="当前产线生产规格"
className={this.props.className} className={props.className}
style={this.props.style} style={props.style}
> >
<div <div
className={cls.CenterChart1itemDetailBorder} className={cls.CenterChart1itemDetailBorder}
@@ -63,11 +39,115 @@ class Chart1 extends Component {
<span className={cls.CenterFormitemDetailBorderLine1}></span> <span className={cls.CenterFormitemDetailBorderLine1}></span>
<span className={cls.CenterFormitemDetailBorderLine2}></span> <span className={cls.CenterFormitemDetailBorderLine2}></span>
<span className={cls.CenterFormitemDetailBorderLine3}></span> <span className={cls.CenterFormitemDetailBorderLine3}></span>
<ScrollBoard config={config} style={{}} /> {config.data.length !== 0 && <ScrollBoard config={config} style={{}} />}
{config.data.length === 0 && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "72px",
}}
>
暂无数据
</p>
)}
</div> </div>
</BottomBarItem> </BottomBarItem>
); );
}
} }
export default Chart1; export default Chart1;
// 测试数据
var rawData = [
{
id: 1,
length: 1209,
productionLine: "Y61",
square: 123.3,
thick: 2,
wide: 1089,
},
{
id: 2,
length: 1119,
productionLine: "Y62",
square: 103.3,
thick: 2,
wide: 1339,
},
{
id: 3,
length: 1019,
productionLine: "Y63",
square: 233,
thick: 1,
wide: 1111,
},
{
id: 4,
length: 2000,
productionLine: "Y64",
square: 233,
thick: 1,
wide: 1232,
},
{
id: 5,
length: 1560,
productionLine: "Y65",
square: 233,
thick: 1,
wide: 996,
},
{
id: 6,
length: 1990,
productionLine: "Y66",
square: 233,
thick: 1,
wide: 416,
},
];
function filterData(rawData) {
return (rawData ?? []).map((item) => [
// 产线名
item.productionLine,
// 原板宽度
item.length,
// 净板宽
item.wide,
// 玻璃厚度
item.thick,
]);
}
// let data = [
// ["产线0", "10mm", "10mm", "10mm"],
// ["产线2", "8mm", "8mm", "8mm"],
// ["产线3", "15mm", "15mm", "15mm"],
// ["产线4", "15mm", "15mm", "15mm"],
// ["产线42", "15mm", "15mm", "15mm"],
// ["产线5", "15mm", "15mm", "15mm"],
// ["产线6", "15mm", "15mm", "15mm"],
// ];
// let header = ["产线名", "原板宽度", "净板宽", "玻璃厚度"];
function replaceStyle(Arr, opacity) {
let temp = [];
for (let i = 0; i < Arr.length; i++) {
temp[i] = [];
for (let j = 0; j < Arr[i].length; j++) {
temp[i][j] = `<span style="color:rgba(255, 255, 255,${opacity})">${
Arr[i][j]
} ${j == 0 ? "" : "mm"}<span/>`;
}
}
return temp;
}

View File

@@ -5,7 +5,7 @@
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
background-color: rgba(4, 44, 76, 0.2); // background-color: rgba(4, 44, 76, 0.2);
.CenterChart1itemTXT { .CenterChart1itemTXT {
width: 100%; width: 100%;
height: 10%; height: 10%;

Binary file not shown.

View File

@@ -0,0 +1,7 @@
@font-face {
font-family: "HelloFont WenYiHei";
/* font-style: normal;
font-weight: 400; */
src: url("./ziyou.ttf");
/* font-display: swap; */
}

View File

@@ -1,37 +1,39 @@
import BottomBarItem from '../BottomItemBackground'; import GraphBase from "../GraphBase";
import GraphBase from '../GraphBase'; import "./font.css";
import { Radio } from 'antd'; import cls from "./index.module.css";
import cls from './index.module.css'; import { useEffect, useState } from "react";
import { useState } from 'react'; import { Tooltip, Button } from "antd";
import { InfoCircleOutlined } from "@ant-design/icons";
import { useSelector } from "react-redux";
const SmallBox = (props) => { const SmallBox = (props) => {
return ( return (
<div <div
className="small-box" className="small-box"
style={{ style={{
boxShadow: 'inset 0 0 18px 10px #fff1', boxShadow: "inset 0 0 18px 10px #fff1",
borderRadius: '3px', borderRadius: "3px",
padding: '6px', padding: "6px",
display: 'flex', display: "flex",
alignItems: 'center', alignItems: "center",
justifyContent: 'center', justifyContent: "center",
color: '#fff', color: "#fff",
position: 'relative', position: "relative",
userSelect: 'none', userSelect: "none",
}} }}
> >
{props.split !== false && ( {props.split !== false && (
<span <span
className="vertical-line" className="vertical-line"
style={{ style={{
position: 'absolute', position: "absolute",
display: 'inline-block', display: "inline-block",
width: '2px', width: "2px",
height: '80%', height: "80%",
top: '10%', top: "10%",
left: '50%', left: "45%",
background: background:
'linear-gradient(to bottom, transparent, #fff3, #fffa, #fff3, transparent)', "linear-gradient(to bottom, transparent, #fff3, #fffa, #fff3, transparent)",
}} }}
></span> ></span>
)} )}
@@ -41,93 +43,212 @@ const SmallBox = (props) => {
}; };
function WindFrequence(props) { function WindFrequence(props) {
const [dataSource, setDataSource] = useState('风机'); const [dataSource, setDataSource] = useState("Y61");
const [currentLineTemp, setCurrentLineTemp] = useState([]);
function handleSourceChange(v) { const currentTempList = useSelector((state) => state.annealTemperature?.data);
console.log('val', v); const lines = ["Y61", "Y62", "Y63", "Y64", "Y65"];
function handleSourceChange(line) {
setDataSource(line);
} }
useEffect(() => {
setCurrentLineTemp(
(currentTempList &&
currentTempList[1 + lines.indexOf(dataSource) + "#"]) ||
[]
);
}, [dataSource, currentTempList]);
return ( return (
<GraphBase <GraphBase
icon="pause" icon="temp"
title="当前温度" title="当前温度"
dateOptions={['风机', '风阀', '电加热']} dateOptions={["Y61", "Y62", "Y63", "Y64", "Y65"]}
selectWidth={70}
defaultSelect={dataSource}
onDateChange={handleSourceChange} onDateChange={handleSourceChange}
size={['middle', 'long']} size={["middle", "long"]}
> >
<div className={cls.mainContent + ' ' + cls.grid}> <div className={cls.mainContent + " " + cls.grid}>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>A1区板上</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
<span className={cls.areaValue}>123.8</span> {(+currentLineTemp[0]).toFixed(2) || 0}
<span className={cls.areaValue}>123.8</span> </span>
<span className={cls.areaValue}>
{(+currentLineTemp[1]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[2]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>A2区板上</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
<span className={cls.areaValue}>123.8</span> {(+currentLineTemp[6]).toFixed(2) || 0}
<span className={cls.areaValue}>123.8</span> </span>
<span className={cls.areaValue}>
{(+currentLineTemp[7]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[8]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>B区板上</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
<span className={cls.areaValue}>123.8</span> {(+currentLineTemp[12]).toFixed(2) || 0}
<span className={cls.areaValue}>123.8</span> </span>
<span className={cls.areaValue}>
{(+currentLineTemp[13]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[14]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>C区板上</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
<span className={cls.areaValue}>123.8</span> {(+currentLineTemp[18]).toFixed(2) || 0}
<span className={cls.areaValue}>123.8</span> </span>
<span className={cls.areaValue}>
{(+currentLineTemp[19]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[20]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板</h1> <h1 className={cls.areaName}>A1区板</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
<span className={cls.areaValue}>123.8</span> {(+currentLineTemp[3]).toFixed(2) || 0}
<span className={cls.areaValue}>123.8</span> </span>
<span className={cls.areaValue}>
{(+currentLineTemp[4]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[5]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox split={false}> <SmallBox>
<h1 className={cls.areaName}>A2区板下</h1>
<div className={cls.areaContent}>
<span className={cls.areaValue}>
{(+currentLineTemp[9]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[10]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[11]).toFixed(2) || 0}
</span>
</div>
</SmallBox>
<SmallBox>
<h1 className={cls.areaName}>B区板下</h1>
<div className={cls.areaContent}>
<span className={cls.areaValue}>
{(+currentLineTemp[15]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[16]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[17]).toFixed(2) || 0}
</span>
</div>
</SmallBox>
<SmallBox>
<h1 className={cls.areaName}>C区板下</h1>
<div className={cls.areaContent}>
<span className={cls.areaValue}>
{(+currentLineTemp[21]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[22]).toFixed(2) || 0}
</span>
<span className={cls.areaValue}>
{(+currentLineTemp[23]).toFixed(2) || 0}
</span>
</div>
</SmallBox>
<SmallBox split={false} style={{ position: "relative" }}>
<div className={cls.areaPureContent}> <div className={cls.areaPureContent}>
<span className={cls.areaPureValue}>123.8</span> <div
<span className={cls.areaPureValue}>123.8</span> className="hint"
<span className={cls.areaPureValue}>123.8</span> style={{ position: "absolute", top: "3px", right: "3px" }}
>
<Tooltip title="红外温度">
<Button
shape="circle"
type="text"
style={{ color: "#cccc" }}
icon={<InfoCircleOutlined />}
></Button>
</Tooltip>
</div>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[26]).toFixed(2) || 0}
</span>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[27]).toFixed(2) || 0}
</span>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[28]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <SmallBox split={false} style={{ position: "relative" }}>
<div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span>
<span className={cls.areaValue}>123.8</span>
<span className={cls.areaValue}>123.8</span>
</div>
</SmallBox>
<SmallBox split={false}>
<div className={cls.areaPureContent}> <div className={cls.areaPureContent}>
<span className={cls.areaPureValue}>123.8</span> <div
<span className={cls.areaPureValue}>123.8</span> className="hint"
<span className={cls.areaPureValue}>123.8</span> style={{ position: "absolute", top: "3px", right: "3px" }}
>
<Tooltip title="压延机冷却水温度 | 过度辊台冷却水温度 | 唇砖冷却水温度">
<Button
shape="circle"
type="text"
style={{ color: "#cccc" }}
icon={<InfoCircleOutlined />}
></Button>
</Tooltip>
</div>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[29]).toFixed(2) || 0}
</span>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[30]).toFixed(2) || 0}
</span>
<span className={cls.areaPureValue} style={{ fontSize: "12px" }}>
{(+currentLineTemp[31]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>RET1区</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
{(+currentLineTemp[24]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
<SmallBox> <SmallBox>
<h1 className={cls.areaName}>A1区板上</h1> <h1 className={cls.areaName}>RET2区</h1>
<div className={cls.areaContent}> <div className={cls.areaContent}>
<span className={cls.areaValue}>123.8</span> <span className={cls.areaValue}>
{(+currentLineTemp[25]).toFixed(2) || 0}
</span>
</div> </div>
</SmallBox> </SmallBox>
</div> </div>

View File

@@ -50,7 +50,7 @@
.areaName { .areaName {
color: #fff; color: #fff;
font-size: 20px; font-size: 18px;
line-height: 1; line-height: 1;
letter-spacing: 1.5px; letter-spacing: 1.5px;
margin: 0; margin: 0;
@@ -66,7 +66,7 @@
padding: 0 8px; padding: 0 8px;
} }
.areaPureValue:not(:first-child) { span.areaPureValue:not(:first-of-type) {
border-left: 2px solid #fff6; border-left: 2px solid #fff6;
} }
@@ -80,9 +80,11 @@
.areaPureValue, .areaPureValue,
.areaValue { .areaValue {
display: inline-block; display: inline-block;
font-size: 17px; font-size: 14px;
line-height: 22px; line-height: 16px;
letter-spacing: 1.2px; letter-spacing: 1.2px;
font-family: "HelloFont WenYiHei", sans-serif;
color: #53c2d4;
} }
.switchLabel { .switchLabel {

Binary file not shown.

View File

@@ -0,0 +1,184 @@
import { useEffect, useState } from "react";
import cls from "./index.module.scss";
import { useSelector } from "react-redux";
import Arrow from "../../Arrow";
const EnergyCostRealtime = () => {
const [isPage1, setIsPage1] = useState(false);
const energyInfo = useSelector((state) => state.energy?.info);
// function handleClick() {
// setIsPage1((pre) => !pre);
// }
useEffect(() => {
const timer = setInterval(() => {
setIsPage1(pre => !pre);
}, 10000);
return () => {
clearInterval(timer);
}
}, []);
return (
<>
{/* <Arrow key="left" direction="left" onClick={handleClick} />
<Arrow key="right" direction="right" onClick={handleClick} /> */}
{isPage1 && (
<div className={`${cls.cost__info} flex`}>
<div className={`${cls.info__item_groups_col1}`}>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
余热发电(昨日)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty1)?.toFixed(2) || 0}kWh
</span>
</div>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
余热发电(总量)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty3)?.toFixed(2) || 0}kWh
</span>
</div>
</div>
<div className={cls.info__item_groups}>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
水耗量(昨日)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.waterQty)?.toFixed(2) || 0}Km³
</span>
</div>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
天然气I(累计)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{energyInfo?.ngQty1 || "0Nm³"}
</span>
</div>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
电耗量(昨日)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty2)?.toFixed(2) || 0}kWh
</span>
</div>
<div className={cls.info__item}>
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
天然气II(累计)
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{energyInfo?.ngQty2 || "0Nm³"}
</span>
</div>
</div>
</div>
)}
{!isPage1 && (
<div className={cls.energy_info_new}>
<div className="energy_info_new--item">
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
智慧能源光伏发电(昨日)/kwh
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty6)?.toFixed(2) || 0}kWh
</span>
</div>
<div className="energy_info_new--item">
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
许昌安彩光伏发电(昨日)/kwh
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty7)?.toFixed(2) || 0}kWh
</span>
</div>
<div className="energy_info_new--item">
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
智慧能源光伏发电(总量)/kwh
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty4)?.toFixed(2) || 0}kWh
</span>
</div>
<div className="energy_info_new--item">
<i
style={{
fontSize: "18px",
fontStyle: "normal",
paddingRight: "6px",
}}
>
许昌安彩光伏发电(总量)/kwh
</i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty5)?.toFixed(2) || 0}kWh
</span>
</div>
</div>
)}
</>
);
};
export default EnergyCostRealtime;

View File

@@ -0,0 +1,60 @@
.cost__info {
margin-top: 4px;
margin-bottom: 6px;
// margin-bottom: 12px;
}
.info__item {
border-radius: 2px;
color: hsl(0, 0%, 100%, 0.9);
box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15);
font-size: 14px;
line-height: 28px;
padding-left: 12px;
padding: 8px 0;
user-select: none;
display: flex;
flex-direction: column;
align-items: center;
}
.hAuto {
height: auto;
}
.info__item_groups {
flex: 2;
margin-left: 8px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.info__item_groups_col1 {
flex: 1;
display: grid;
grid-template-rows: 1fr 1fr;
gap: 8px;
}
.energy_info_new {
color: #fff;
display: grid;
gap: 8px;
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr 1fr;
height: 162px;
padding: 4px 0;
}
.energy_info_new > div {
border-radius: 2px;
box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15);
font-size: 14px;
line-height: 28px;
color: hsl(0, 0%, 100%, 0.9);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@@ -1,112 +1,92 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import { randomInt } from '../../../../utils'; import { Radio, Select } from "antd";
import * as echarts from 'echarts'; import ReactECharts from "echarts-for-react";
import { Switch, Radio } from 'antd'; import { useState } from "react";
import ReactECharts from 'echarts-for-react'; import { useSelector } from "react-redux";
import { getOptions } from "../../../../utils/energeChartOption";
import triangle from "../../../../assets/Icon/triangle.svg";
import dayjs from "dayjs";
const EnergyCostChart = (props) => { const EnergyCostChart = (props) => {
const options = { const elecTrend = useSelector((state) => state.energy.trend.elec);
color: ['#FFD160', '#12FFF5', '#2760FF'], const gasITrend = useSelector((state) => state.energy.trend.natGas1);
grid: { top: 32, right: 12, bottom: 20, left: 48 }, const gasIITrend = useSelector((state) => state.energy.trend.natGas2);
xAxis: { const [source, setSource] = useState("elec");
type: 'category', const [period, setPeriod] = useState("week");
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp,
).getDate()}`;
})
.reverse(),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
name: '单位/m³',
nameTextStyle: {
color: '#fff',
fontSize: 10,
align: 'right',
},
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
formatter: '{value} %',
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
interval: 10,
min: 0,
max: 100,
},
series: [
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#FFD16040' },
{ offset: 0.5, color: '#FFD16020' },
{ offset: 1, color: '#FFD16010' },
]),
},
// smooth: true,
},
],
tooltip: {
trigger: 'axis',
},
};
function handleSwitchChange(val) { const [timestr, setTimestr] = useState(
// val: boolean dayjs().subtract(7, "day").format("YYYY.MM.DD") +
console.log('switch change', val); " - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
const currentTrend =
source == "elec" ? elecTrend : source == "gasi" ? gasITrend : gasIITrend;
const options = getOptions(
period,
source,
currentTrend ?? { week: [], month: [], year: [] }
);
function handleDateChange(value) {
setPeriod(
{
: "week",
: "month",
: "year",
}[value]
);
setTimestr(
{
:
dayjs().subtract(1, "year").endOf("year").format("YYYY.MM.") +
"29 - " +
dayjs().endOf("year").format("YYYY.MM.") +
"28",
:
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD"),
:
dayjs().subtract(1, "month").format("YYYY.MM.") +
"29 - " +
dayjs().format("YYYY.MM.") +
"28",
}[value]
);
} }
return ( return (
<div className={cls.energyCostChart}> <div className={cls.energyCostChart}>
<div className={cls.titleBar}> <div className={cls.titleBar}>
<h2>能耗趋势图</h2> <h2>能耗趋势图</h2>
<Switch defaultChecked onChange={handleSwitchChange} />
<div className={cls.legend}>
<span className="legend__title">班次详情</span>
<ul className="legend__list">
<li>总量</li>
</ul>
</div> </div>
<div className={`${cls.choiceBar} flex items-center justify-between`}>
<Radio.Group <Radio.Group
defaultValue="week" value={source}
buttonStyle="solid" buttonStyle="solid"
onChange={(v) => setSource(v.target.value)}
className={`${cls.radioGroup} flex items-center justify-between`}
>
<Radio.Button value="elec" className="radio-group__item">
</Radio.Button>
<Radio.Button value="gasi" className="radio-group__item">
天然气I
</Radio.Button>
<Radio.Button value="gasii" className="radio-group__item">
天然气II
</Radio.Button>
</Radio.Group>
{/* <Radio.Group
value={period}
buttonStyle="solid"
onChange={(v) => setPeriod(v.target.value)}
className={cls.radioGroup} className={cls.radioGroup}
> >
<Radio.Button value="day" className="radio-group__item">
</Radio.Button>
<Radio.Button value="week" className="radio-group__item"> <Radio.Button value="week" className="radio-group__item">
</Radio.Button> </Radio.Button>
@@ -116,10 +96,53 @@ const EnergyCostChart = (props) => {
<Radio.Button value="year" className="radio-group__item"> <Radio.Button value="year" className="radio-group__item">
</Radio.Button> </Radio.Button>
</Radio.Group> </Radio.Group> */}
<div className={cls.graphBaseDesc}>{timestr}</div>
<Select
defaultValue={"周"}
style={{ width: 60 }}
popupClassName="xc-date-selector-menu"
className={cls.radioGroupShort}
options={["周", "月", "年"].map((item) => ({
label: item,
value: item,
}))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "14px",
lineHeight: 1,
paddingLeft: "12px",
}}
>
- -
</span>
}
onChange={(value, option) => handleDateChange(value)}
/>
</div> </div>
<div className="flex-1">
<ReactECharts option={options} style={{ height: '180px' }} /> <div className="flex-1" style={{ marginTop: "8px" }}>
{options && (
<ReactECharts option={options} style={{ height: "180px" }} />
)}
{!options && (
<p
style={{
color: "#cccf",
fontSize: "20px",
userSelect: "none",
textAlign: "center",
paddingTop: "32px",
}}
>
暂无数据
</p>
)}
</div> </div>
</div> </div>
); );

View File

@@ -16,6 +16,12 @@
letter-spacing: 1.2px; letter-spacing: 1.2px;
color: #52fff8; color: #52fff8;
} }
.graphBaseDesc {
margin: 0 12px;
line-height: 1;
color: #76fff9;
flex: 1;
}
.energyCostChart .titleBar .legend { .energyCostChart .titleBar .legend {
display: flex; display: flex;
@@ -41,7 +47,7 @@
padding-left: 16px; padding-left: 16px;
} }
.energyCostChart .titleBar .legend ul li::before { .energyCostChart .titleBar .legend ul li::before {
content: ''; content: "";
position: absolute; position: absolute;
left: 2px; left: 2px;
top: 2px; top: 2px;
@@ -67,6 +73,10 @@
border: none !important; border: none !important;
border-radius: 0 !important; border-radius: 0 !important;
} }
.radioGroupShort * {
border: none !important;
border-radius: 6px !important;
}
.radioGroup *:focus-within { .radioGroup *:focus-within {
box-shadow: none !important; box-shadow: none !important;
} }

View File

@@ -1,26 +1,15 @@
import cls from './index.module.scss'; import cls from "./index.module.scss";
import Container from '../../Container'; import Container from "../../Container";
import TechSplitline from '../TechSplitline'; import TechSplitline from "../TechSplitline";
import EnergyCostChart from './EnergyCostChart'; import EnergyCostChart from "./EnergyCostChart";
import EnergyCostRealtime from "./EnergeCostRealtime";
function EnergyCost(props) { function EnergyCost(props) {
return ( return (
<Container title="能耗" icon="charger" className={cls.energyCost}> <Container title="能耗" icon="battery" className={cls.energyCost}>
<div className={`flex flex-col`}> <div className={`flex flex-col`}>
<div className={`${cls.cost__info} flex`}> <EnergyCostRealtime />
<div
className={`${cls.info__item} ${cls.hAuto} flex flex-col justify-center items-center self-stretch`}
>
<span> </span>
<span>922kWh</span>
</div>
<div className={cls.info__item_groups}>
<div className={cls.info__item}> : 32Km³</div>
<div className={cls.info__item}> I : 83</div>
<div className={cls.info__item}> : 52kWh</div>
<div className={cls.info__item}> II: 32</div>
</div>
</div>
<TechSplitline /> <TechSplitline />

View File

@@ -2,7 +2,7 @@
background: url(../../../assets/energy.png) no-repeat; background: url(../../../assets/energy.png) no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
width: 626px; width: 626px;
height: 400px; height: 460px;
} }
.cost__info { .cost__info {
@@ -18,12 +18,9 @@
border-radius: 2px; border-radius: 2px;
color: hsl(0, 0%, 100%, 0.9); color: hsl(0, 0%, 100%, 0.9);
box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15); box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15);
// width: 288px; font-size: 14px;
height: 43px;
font-size: 20px;
letter-spacing: 1.43px;
line-height: 40px; line-height: 40px;
text-align: center; padding-left: 12px;
user-select: none; user-select: none;
} }

View File

@@ -1,46 +1,20 @@
import GraphBase from "../../Common/GraphBase"; import GraphBase from "../../Common/GraphBase";
import "./index.module.scss"; import "./index.module.scss";
import { useSelector } from "react-redux";
import { ScrollBoard } from "@jiaminghi/data-view-react"; import { ScrollBoard } from "@jiaminghi/data-view-react";
function getRandomRow() {
const idx = Math.ceil(Math.random() * 100);
return [idx, `${idx}#风机`, Math.ceil(Math.random() * 2) - 1];
}
function getRandomRows(rows) {
return Array(rows)
.fill(0)
.map(() => getRandomRow());
}
// let data = [
// [1, '1#风机', 1], // 1 正常 2 故障 0 离线
// [2, '2#风机', 1],
// [3, '3#风机', 1],
// [4, '4#风机', 0],
// [5, '5#风机', 1],
// [6, '6#风机', 1],
// [7, '7#风机', 0],
// [8, '8#风机', 1],
// [9, '9#风机', 1],
// [10, '10#风机', 1],
// ];
// let header = ['序号', '风机名称', '故障情况'];
function attachStyle(data) { function attachStyle(data) {
return data.map((arr) => { return data.map((arr) => {
return arr.map((item, index) => { return arr.map((item, index) => {
if (index == arr.length - 1) { if (index == arr.length - 1) {
return `<div style="display: flex; align-items: center"> return `<div style="display: flex; align-items: center">
<span style="box-shadow: 0 0 4px 4px ${ <span style="box-shadow: 0 0 4px 4px ${
item == 1 ? "#2760ff55" : "#a81b2655" item == 1 ? "#2760ff55" : item == 0 ? "#a81b2655" : "#E6A23C55"
}; margin-right: 8px; width: 8px; height: 8px; border-radius: 8px; background: ${ }; margin-right: 8px; width: 8px; height: 8px; border-radius: 8px; background: ${
item == 1 ? "#2760ff" : "#a81b26" item == 1 ? "#2760ff" : item == 0 ? "#a81b26" : "#E6A23C"
}"></span><span style="color: ${item == 1 ? "#2760ff" : "#a81b26"}">${ }"></span><span style="color: ${
item == 1 ? "正常" : "故障" item == 1 ? "#2760ff" : item == 0 ? "#a81b26" : "#E6A23C"
}</span></div>`; }">${item == 1 ? "运行" : item == 0 ? "故障" : "未运行"}</span></div>`;
} }
return `<span style='color: #fffa'>${item}</span>`; return `<span style='color: #fffa'>${item}</span>`;
}); });
@@ -49,7 +23,17 @@ function attachStyle(data) {
function FanInfo(props) { function FanInfo(props) {
const rowNum = props.rows || 8; const rowNum = props.rows || 8;
let data = getRandomRows(100); // 默认使用风机信息,可以使用 source 来调整该组件使用 annealFanInfo 的数据
const fanInfo = useSelector((state) => state[props.source ?? "fanInfo"].data);
const data = Object.keys(fanInfo).map((key, index) => {
return [
index + 1,
key,
fanInfo[key] == "运行" ? 1 : fanInfo[key] == "故障" ? 0 : 2,
];
});
const dataRight = [...data.slice(rowNum), ...data.slice(0, rowNum)];
let config = { let config = {
headerBGC: "rgba(4, 44, 76, 0.3)", headerBGC: "rgba(4, 44, 76, 0.3)",
@@ -60,11 +44,10 @@ function FanInfo(props) {
], ],
oddRowBGC: "#042444", oddRowBGC: "#042444",
evenRowBGC: "#042c4c", evenRowBGC: "#042c4c",
columnWidth: [70, 96], // columnWidth: data.length > 12 ? [50, 136] : [88, 256],
columnWidth: [50, 136],
rowNum, rowNum,
// headerHeight: 40, hoverPause: true,
hoverPause: false,
// data: replaceStyle(data, 0.7),
data: attachStyle(data), data: attachStyle(data),
}; };
@@ -78,7 +61,9 @@ function FanInfo(props) {
className="flex" className="flex"
style={{ style={{
display: "flex", display: "flex",
flex: 1,
gap: "20px", gap: "20px",
// gap: data.length > 12 ? "20px" : 0,
height: "100%", height: "100%",
position: "relative", position: "relative",
}} }}
@@ -86,9 +71,15 @@ function FanInfo(props) {
<div className="flex-1" style={{ flex: 1 }}> <div className="flex-1" style={{ flex: 1 }}>
<ScrollBoard <ScrollBoard
config={config} config={config}
style={{ width: "280px", height: "100%" }} style={{
width: "280px",
// width: data.length > 12 ? "280px" : "100%",
height: "100%",
}}
/> />
</div> </div>
{/* {data.length > 12 && (
<> */}
<div <div
className="verticalLine" className="verticalLine"
style={{ style={{
@@ -103,10 +94,12 @@ function FanInfo(props) {
></div> ></div>
<div className="flex-1" style={{ flex: 1 }}> <div className="flex-1" style={{ flex: 1 }}>
<ScrollBoard <ScrollBoard
config={config} config={{ ...config, data: attachStyle(dataRight) }}
style={{ width: "280px", height: "100%" }} style={{ width: "280px", height: "100%" }}
/> />
</div> </div>
{/* </>
)} */}
</div> </div>
</GraphBase> </GraphBase>
); );

View File

@@ -0,0 +1,248 @@
import GraphBase from "../GraphBase";
import "./index.module.scss";
import { useSelector } from "react-redux";
import { ScrollBoard } from "@jiaminghi/data-view-react";
import { useMemo } from "react";
function attachStyle(data) {
return data.map((arr) => {
return arr.map((item, index) => {
if (index == arr.length - 1) {
return `<div style="display: flex; align-items: center">
<span style="box-shadow: 0 0 4px 4px ${
item == 1 ? "#2760ff55" : item == 0 ? "#a81b2655" : "#E6A23C55"
}; margin-right: 8px; width: 8px; height: 8px; border-radius: 8px; background: ${
item == 1 ? "#2760ff" : item == 0 ? "#a81b26" : "#E6A23C"
}"></span><span style="color: ${
item == 1 ? "#2760ff" : item == 0 ? "#a81b26" : "#E6A23C"
}">${item == 1 ? "运行" : item == 0 ? "故障" : "未运行"}</span></div>`;
}
return `<span style='color: #fffa'>${item}</span>`;
});
});
}
function FanInfo(props) {
// 默认使用风机信息,可以使用 source 来调整该组件使用 annealFanInfo 的数据
const fanInfo = useSelector((state) => state[props.source ?? "fanInfo"].data);
const data = Object.keys(fanInfo).map((key, index) => {
return [
index + 1,
key,
fanInfo[key] == "运行" ? 1 : fanInfo[key] == "故障" ? 0 : 2,
];
});
const y61 = useMemo(
() => data.filter((item) => item[1].startsWith("1#")) || [],
[data]
);
const y62 = useMemo(
() => data.filter((item) => item[1].startsWith("2#")) || [],
[data]
);
const y63 = useMemo(
() => data.filter((item) => item[1].startsWith("3#")) || [],
[data]
);
const y64 = useMemo(
() => data.filter((item) => item[1].startsWith("4#")) || [],
[data]
);
const y65 = useMemo(
() => data.filter((item) => item[1].startsWith("5#")) || [],
[data]
);
const y66 = useMemo(() => [...y65.slice(5), ...y65.slice(0, 5)], [y65]);
let config = {
headerBGC: "rgba(4, 44, 76, 0.3)",
header: [
'<span style="color:#fff">序号<span/>',
'<span style="color:#fff">风机名称<span/>',
'<span style="color:#fff">故障情况<span/>',
],
oddRowBGC: "#042444",
evenRowBGC: "#042c4c",
// columnWidth: data.length > 12 ? [50, 136] : [88, 256],
columnWidth: [50, 136],
rowNum: 6,
hoverPause: true,
data: [],
};
return (
<GraphBase
icon="kiln"
title="风机信息"
size={props.longBg ? ["middle", "full"] : ["middle", "short"]}
>
<div
style={{
display: "grid",
gridTemplateRows: "auto 2px auto 2px auto",
gap: "4px",
// height: "100%",
position: "relative",
}}
>
<div className="" style={{ display: "flex", gap: "8px" }}>
<div>
<h1
style={{
fontSize: "16px",
fontWeight: 400,
textAlign: "center",
letterSpacing: "2px",
color: "#fff",
background: "#012041",
padding: "4px 0",
}}
>
产线Y61
</h1>
<ScrollBoard
key="y61"
config={{ ...config, data: attachStyle(y61) }}
style={{
width: "280px",
height: "280px",
}}
/>
</div>
<div>
<h1
style={{
fontSize: "16px",
fontWeight: 400,
textAlign: "center",
letterSpacing: "2px",
color: "#fff",
background: "#012041",
padding: "4px 0",
}}
>
产线Y62
</h1>
<ScrollBoard
key="y62"
config={{ ...config, data: attachStyle(y62) }}
style={{
width: "280px",
height: "280px",
}}
/>
</div>
</div>
<div
className="horizontalLine"
style={{
height: "2px",
background:
"radial-gradient(ellipse, #15E8F563, #15E8F599, transparent, transparent)",
}}
></div>
<div className="" style={{ display: "flex", gap: "8px" }}>
<div>
<h1
style={{
fontSize: "16px",
fontWeight: 400,
textAlign: "center",
letterSpacing: "2px",
color: "#fff",
background: "#012041",
padding: "4px 0",
}}
>
产线Y63
</h1>
<ScrollBoard
key="y63"
config={{ ...config, data: attachStyle(y63) }}
style={{
width: "280px",
height: "280px",
}}
/>
</div>
<div>
{/* <div style={{ display: "flex", flexDirection: "column" }}> */}
<h1
style={{
fontSize: "16px",
fontWeight: 400,
textAlign: "center",
letterSpacing: "2px",
color: "#fff",
background: "#012041",
padding: "4px 0",
}}
>
产线Y64
</h1>
<ScrollBoard
key="y64"
config={{ ...config, data: attachStyle(y64) }}
style={{
width: "280px",
height: "280px",
}}
/>
</div>
</div>
<div
className="horizontalLine"
style={{
height: "2px",
background:
"radial-gradient(ellipse, #15E8F563, #15E8F599, transparent, transparent)",
}}
></div>
<div
className=""
style={{ height: "240px", display: "flex", flexDirection: "column" }}
>
<h1
style={{
fontSize: "16px",
fontWeight: 400,
textAlign: "center",
letterSpacing: "2px",
color: "#fff",
background: "#012041",
padding: "4px 0",
}}
>
产线Y65
</h1>
<div style={{ flex: 1, height: "1px", display: "flex", gap: "4px" }}>
<ScrollBoard
key="y65"
config={{ ...config, data: attachStyle(y65), rowNum: 5 }}
style={{
width: "280px",
height: "220px",
}}
/>
<ScrollBoard
key="y66"
config={{ ...config, data: attachStyle(y66), rowNum: 5 }}
style={{
width: "280px",
height: "220px",
}}
/>
</div>
</div>
</div>
</GraphBase>
);
}
export default FanInfo;

View File

@@ -0,0 +1,50 @@
.CenterChart1itemDetailBorder {
width: 100%;
height: 240px;
display: flex;
flex-direction: column;
justify-content: flex-start;
background-color: rgba(4, 44, 76, 0.2);
.CenterChart1itemTXT {
width: 100%;
height: 10%;
font-size: 20px;
color: rgba(255, 255, 255, 0.8);
text-align: center;
margin-top: 2%;
}
.CenterChart1itemContainer {
width: 95%;
height: 100px;
position: relative;
.CenterFormitemDetailBorderLine1 {
width: 1px;
height: 200px;
background-color: #041c2c;
float: left;
margin-left: 18%;
z-index: 10;
position: absolute;
}
.CenterFormitemDetailBorderLine2 {
width: 1px;
height: 200px;
background-color: #041c2c;
float: left;
margin-left: 46%;
z-index: 10;
position: absolute;
}
.CenterFormitemDetailBorderLine3 {
width: 1px;
height: 200px;
background-color: #041c2c;
float: left;
margin-left: 72%;
z-index: 10;
position: absolute;
}
}
}

View File

@@ -1,20 +1,71 @@
// FanRunFrequence // FanRunFrequence
import cls from "./index.module.css"; import cls from "./index.module.css";
import ReactECharts from "echarts-for-react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { Switch } from "antd";
import GraphBase from "../../Common/GraphBase"; import GraphBase from "../../Common/GraphBase";
import { useState, useContext } from "react"; import { useState } from "react";
// import SocketContext from '../../../store/socket-data-provider'; import { useSelector } from "react-redux";
function WindFrequence(props) { function WindFrequence(props) {
const [showChart, setShowChart] = useState(true); const [showChart, setShowChart] = useState(false);
// const { runState, hisState } = useContext(SocketContext); const runState = useSelector((state) => state.fanFrequence.runtime);
const hisState = useSelector((state) => state.fanFrequence.history);
const runState = null; const [options, dataList] = getOptions(showChart, hisState, runState);
const hisState = null;
let dataList = []; function handleSwitchChange(val) {
if (val) {
setShowChart(true);
} else {
setShowChart(false);
}
}
return (
<GraphBase
icon="smoke"
title="风机运行频率"
size={["middle", "long"]}
switchOptions={false}
switchPosition={[null, 200]} // [top, left]
onSwitch={handleSwitchChange}
>
<div className={cls.chart}>
{/* {showChart && (
<ReactECharts option={options} style={{ height: "100%" }} />
)} */}
{!showChart && (
<div className={cls.gridList}>
{dataList.map((item) => (
<div
key={item.id}
className={cls.listItem}
style={{ padding: props.stretch ? "16px 0" : "" }}
>
<span className={cls.fanName}>{item.name}</span>
<span
className={cls.fanValue}
style={{
fontWeight: 700,
letterSpacing: 1,
fontSize: 16,
// color: "#e03537",
color: "#24aebb",
}}
>
{item.value}
</span>
</div>
))}
</div>
)}
</div>
</GraphBase>
);
}
export default WindFrequence;
function getOptions(showChart, hisState, runState) {
let dataList = null;
let seriesData = []; let seriesData = [];
const colors = [ const colors = [
"#12FFF5", "#12FFF5",
@@ -29,20 +80,15 @@ function WindFrequence(props) {
let options = null; let options = null;
if (showChart) { if (showChart) {
// keys() 结果不是按照顺序,需要 sort() // keys() 结果不是按照顺序,需要 sort()
seriesData = hisState?.combustionAir seriesData =
? Object.keys(hisState.combustionAir) hisState != null
? Object.keys(hisState)
.sort() .sort()
.map((key) => hisState.combustionAir[key]) .map((key) => hisState[key])
: Array(8) : Array(8)
.fill(1) .fill(1)
.map((_) => Array(7).fill(0)); .map((_) => Array(7).fill(0));
// debug
console.log(
"助燃风 chart series data",
hisState?.combustionAir,
seriesData
);
options = { options = {
color: colors, color: colors,
grid: { top: 32, right: 12, bottom: 20, left: 48 }, grid: { top: 32, right: 12, bottom: 20, left: 48 },
@@ -104,9 +150,10 @@ function WindFrequence(props) {
symbol: "circle", symbol: "circle",
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors[i] + "40" }, // i % 8 避免超过8个数据时无颜色的问题
{ offset: 0.5, color: colors[i] + "20" }, { offset: 0, color: colors[i % 8] + "40" },
{ offset: 1, color: colors[i] + "00" }, { offset: 0.5, color: colors[i % 8] + "20" },
{ offset: 1, color: colors[i % 8] + "00" },
]), ]),
}, },
})), })),
@@ -115,27 +162,12 @@ function WindFrequence(props) {
}, },
}; };
} else { } else {
dataList = runState?.combustionAirPressureArr dataList =
? [ runState != null
{ id: 1, name: "1#风机", value: "0m³/h" }, ? Object.keys(runState).map((fan) => ({
{ id: 2, name: "2#风机", value: "0m³/h" }, id: Math.random(),
{ id: 3, name: "3#风机", value: "0m³/h" }, name: fan,
{ id: 4, name: "4#风机", value: "0m³/h" }, value: (+runState[fan])?.toFixed(2),
{ id: 5, name: "5#风机", value: "0m³/h" },
{ id: 6, name: "6#风机", value: "0m³/h" },
{ id: 7, name: "7#风机", value: "0m³/h" },
{ id: 8, name: "8#风机", value: "0m³/h" },
{ id: 9, name: "9#风机", value: "0m³/h" },
{ id: 10, name: "10#风机", value: "0m³/h" },
{ id: 11, name: "11#风机", value: "0m³/h" },
{ id: 12, name: "12#风机", value: "0m³/h" },
{ id: 13, name: "13#风机", value: "0m³/h" },
{ id: 14, name: "14#风机", value: "0m³/h" },
{ id: 15, name: "15#风机", value: "0m³/h" },
{ id: 16, name: "16#风机", value: "0m³/h" },
].map((item, index) => ({
...item,
value: runState.combustionAirPressureArr[index] ?? "/",
})) }))
: [ : [
{ id: 1, name: "1#风机", value: "0m³/h" }, { id: 1, name: "1#风机", value: "0m³/h" },
@@ -157,38 +189,5 @@ function WindFrequence(props) {
]; ];
} }
function handleSwitchChange(val) { return [options, dataList];
if (val) {
setShowChart(true);
} else {
setShowChart(false);
}
}
return (
<GraphBase
icon="kiln"
title="风机运行频率"
size={["middle", "long"]}
switchOptions={true}
switchPosition={[null, 200]} // [top, left]
onSwitch={handleSwitchChange}
>
<div className={cls.chart}>
{showChart && (
<ReactECharts option={options} style={{ height: "100%" }} />
)}
{!showChart && (
<div className={cls.gridList}>
{dataList.map((item) => (
<div key={item.id} className={cls.listItem}>
{item.name}: {item.value}
</div>
))}
</div>
)}
</div>
</GraphBase>
);
} }
export default WindFrequence;

View File

@@ -12,11 +12,15 @@
.listItem { .listItem {
border-radius: 2px; border-radius: 2px;
padding: 9px 0; padding: 10px 0;
text-align: center; text-align: center;
color: #fff; color: #fff;
box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197); box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197);
display: flex;
align-items: center;
gap: 12px;
} }
.headWidget { .headWidget {
position: absolute; position: absolute;
top: 22px; top: 22px;
@@ -31,3 +35,18 @@
.relative { .relative {
position: relative; position: relative;
} }
.flex {
display: flex;
align-items: center;
}
.fanName {
text-align: right;
flex: 7;
}
.fanValue {
flex: 3;
text-align: left;
}

View File

@@ -0,0 +1,16 @@
.feeder {
flex: 1;
}
.feeder-running {
background: url(../../../assets/online.png);
background-size: 100% 100%;
}
.feeder-stop {
background: url(../../../assets/offline.png);
background-size: 100% 100%;
}
.feeder-error {
background: url(../../../assets/offline.png);
background-size: 100% 100%;
}

View File

@@ -0,0 +1,104 @@
import { useSelector } from "react-redux";
import { motion } from "framer-motion";
import "./feeder.css";
function FeederStatus(props) {
const feeder = useSelector((state) => state.feeder);
const rightFeeder = feeder.rightFeeder;
const leftFeeder = feeder.leftFeeder;
return (
<motion.div
className="feeder"
style={{
position: "absolute",
bottom: "56px",
left: "740px",
width: "400px",
height: "128px",
zIndex: "-1",
display: "flex",
gap: "8px",
paddingTop: "12px",
justifyContent: "center",
...props.style,
}}
animate={{
opacity: [0, 0, 0, 0.6, 1],
transition: { duration: 0.3, delay: 2 },
}}
>
<span
style={{
position: "absolute",
color: "#6be1e1",
top: "-32px",
left: "20px",
fontSize: "22px",
}}
>
1#投料{" "}
<b
style={{
fontWeight: 400,
color:
leftFeeder == "故障"
? "#f83a35"
: leftFeeder == "运行"
? "#9af72b"
: "#ccc",
}}
>
{leftFeeder}
</b>
</span>
<span
style={{
position: "absolute",
color: "#6be1e1",
top: "-32px",
left: "230px",
fontSize: "22px",
}}
>
2#投料{" "}
<b
style={{
fontWeight: 400,
color:
rightFeeder == "故障"
? "#f83a35"
: rightFeeder == "运行"
? "#9af72b"
: "#ccc",
}}
>
{rightFeeder}
</b>
</span>
<span
className={`
feeder ${
leftFeeder == "运行"
? "feeder-running"
: leftFeeder == "故障"
? "feeder-error"
: "feeder-stop"
}
`}
></span>
<span
className={`
feeder ${
rightFeeder == "运行"
? "feeder-running"
: rightFeeder == "故障"
? "feeder-error"
: "feeder-stop"
}
`}
></span>
</motion.div>
);
}
export default FeederStatus;

View File

@@ -1,148 +1,20 @@
// 助燃风流量 // 助燃风流量
import cls from './index.module.css'; import cls from "./index.module.css";
import BottomBarItem from '../BottomItemBackground'; import BottomBarItem from "../BottomItemBackground";
import ReactECharts from 'echarts-for-react'; import ReactECharts from "echarts-for-react";
import * as echarts from 'echarts'; import * as echarts from "echarts";
import { randomInt } from '../../../utils'; import { Switch } from "antd";
import { Switch } from 'antd'; import { useState, useEffect } from "react";
import { useState, useContext } from 'react'; import { useSelector, useDispatch } from "react-redux";
// import SocketContext from '../../../store/socket-data-provider'; import dayjs from "dayjs";
/** 助燃风流量 */
function GasI(props) { function GasI(props) {
const [showChart, setShowChart] = useState(true); const [showChart, setShowChart] = useState(true);
// const { runState, hisState } = useContext(SocketContext); const runState = useSelector((state) => state.combustionAir.runtime);
const hisState = useSelector((state) => state.combustionAir.history);
const runState = null; let [options, dataList] = getOptions(showChart, hisState, runState);
const hisState = null;
let dataList = [];
let seriesData = [];
const colors = [
'#12FFF5',
'#2760FF',
'#FFD160',
'#E80091',
'#8064ff',
'#ff8a3b',
'#8cd26d',
'#2aa1ff',
];
let options = null;
if (showChart) {
// keys() 结果不是按照顺序,需要 sort()
seriesData = hisState?.combustionAir
? Object.keys(hisState.combustionAir)
.sort()
.map((key) => hisState.combustionAir[key])
: Array(8)
.fill(1)
.map((_) => Array(7).fill(0));
// debug
console.log(
'助燃风 chart series data',
hisState?.combustionAir,
seriesData,
);
options = {
color: colors,
grid: { top: 32, right: 12, bottom: 20, left: 48 },
xAxis: {
type: 'category',
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp,
).getDate()}`;
})
.reverse(),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
name: '单位/m³',
nameTextStyle: {
color: '#fff',
fontSize: 10,
align: 'right',
},
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
// interval: 10,
// min: 0,
// max: 100,
},
series: seriesData.map((v, i) => ({
name: i + 1 + '#助燃风',
data: v,
type: 'line',
symbol: 'circle',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors[i] + '40' },
{ offset: 0.5, color: colors[i] + '20' },
{ offset: 1, color: colors[i] + '00' },
]),
},
})),
tooltip: {
trigger: 'axis',
},
};
} else {
dataList = runState?.combustionAirPressureArr
? [
{ id: 1, name: '1#助燃风', value: '0m³/h' },
{ id: 2, name: '2#助燃风', value: '0m³/h' },
{ id: 3, name: '3#助燃风', value: '0m³/h' },
{ id: 4, name: '4#助燃风', value: '0m³/h' },
{ id: 5, name: '5#助燃风', value: '0m³/h' },
{ id: 6, name: '6#助燃风', value: '0m³/h' },
{ id: 7, name: '7#助燃风', value: '0m³/h' },
{ id: 8, name: '8#助燃风', value: '0m³/h' },
].map((item, index) => ({
...item,
value: runState.combustionAirPressureArr[index] ?? '/',
}))
: [
{ id: 1, name: '1#助燃风', value: '0m³/h' },
{ id: 2, name: '2#助燃风', value: '0m³/h' },
{ id: 3, name: '3#助燃风', value: '0m³/h' },
{ id: 4, name: '4#助燃风', value: '0m³/h' },
{ id: 5, name: '5#助燃风', value: '0m³/h' },
{ id: 6, name: '6#助燃风', value: '0m³/h' },
{ id: 7, name: '7#助燃风', value: '0m³/h' },
{ id: 8, name: '8#助燃风', value: '0m³/h' },
];
// debug
console.log('助燃风 实时 data', runState?.combustionAirPressureArr);
}
function handleSwitchChange(val) { function handleSwitchChange(val) {
if (val) { if (val) {
@@ -151,10 +23,17 @@ function GasI(props) {
setShowChart(false); setShowChart(false);
} }
} }
const desc =
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD");
return ( return (
<BottomBarItem <BottomBarItem
icon="pause" icon="pause"
title="助燃风流量" title="助燃风流量"
desc={desc}
className={cls.gas} className={cls.gas}
style={props.style} style={props.style}
> >
@@ -168,13 +47,15 @@ function GasI(props) {
<div className={cls.chart}> <div className={cls.chart}>
{showChart && ( {showChart && (
<ReactECharts option={options} style={{ height: '100%' }} /> <ReactECharts option={options} style={{ height: "100%" }} />
)} )}
{!showChart && ( {!showChart && (
<div className={cls.gridList}> <div className={cls.gridList}>
{dataList.map((item) => ( {dataList.map((item) => (
<div key={item.id} className={cls.listItem}> <div key={item.id} className={cls.listItem}>
{item.name}: {item.value} <span className={cls.item_label}>{item.name}</span>
<span className={cls.item_value}>{item.value}</span>
{/* {item.name}: {item.value} */}
</div> </div>
))} ))}
</div> </div>
@@ -185,3 +66,158 @@ function GasI(props) {
} }
export default GasI; export default GasI;
function getOptions(showChart, hisState, runState) {
const colors = [
"#12FFF5",
"#2760FF",
"#FFD160",
"#E80091",
"#8064ff",
"#ff8a3b",
"#8cd26d",
"#2aa1ff",
];
let seriesData = null;
let dataList = null;
let options = null;
if (showChart) {
// keys() 结果不是按照顺序,需要 sort()
seriesData =
hisState != null
? Object.keys(hisState)
.sort()
.map((key) => hisState[key])
: Array(8)
.fill(1)
.map((_) => Array(7).fill(0));
options = {
color: colors,
grid: { top: 36, right: 12, bottom: 20, left: 48 },
legend: {
show: true,
icon: "roundRect",
top: 10,
right: 10,
padding: 0,
itemWidth: 8,
itemHeight: 8,
itemGap: 3,
height: 8,
textStyle: {
color: "#DFF1FE",
fontSize: 10,
},
},
xAxis: {
type: "category",
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - (index + 1) * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp
).getDate()}`;
})
.reverse(),
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
},
yAxis: {
name: "单位m³/h",
nameTextStyle: {
color: "#fff",
fontSize: 10,
align: "right",
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
// interval: 10,
// min: 0,
// max: 100,
},
series: seriesData.map((v, i) => ({
name: i + 1 + "#流量",
data: v,
type: "line",
symbol: "circle",
symbolSize: 6,
// label: {
// show: true,
// position: "top",
// distance: 10,
// color: "#fffc",
// },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors[i % colors.length] + "40" },
{ offset: 0.5, color: colors[i % colors.length] + "20" },
{ offset: 1, color: colors[i % colors.length] + "00" },
]),
},
})),
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "xc-chart-tooltip",
// backgroundColor: ''
},
};
} else {
dataList =
runState != null
? [
{ id: 1, name: "1#助燃风流量", value: "0m³/h" },
{ id: 2, name: "2#助燃风流量", value: "0m³/h" },
{ id: 3, name: "3#助燃风流量", value: "0m³/h" },
{ id: 4, name: "4#助燃风流量", value: "0m³/h" },
{ id: 5, name: "5#助燃风流量", value: "0m³/h" },
{ id: 6, name: "6#助燃风流量", value: "0m³/h" },
{ id: 7, name: "7#助燃风流量", value: "0m³/h" },
{ id: 8, name: "8#助燃风流量", value: "0m³/h" },
].map((item, index) => ({
...item,
value: runState[index] ?? "/",
}))
: [
{ id: 1, name: "1#助燃风流量", value: "0m³/h" },
{ id: 2, name: "2#助燃风流量", value: "0m³/h" },
{ id: 3, name: "3#助燃风流量", value: "0m³/h" },
{ id: 4, name: "4#助燃风流量", value: "0m³/h" },
{ id: 5, name: "5#助燃风流量", value: "0m³/h" },
{ id: 6, name: "6#助燃风流量", value: "0m³/h" },
{ id: 7, name: "7#助燃风流量", value: "0m³/h" },
{ id: 8, name: "8#助燃风流量", value: "0m³/h" },
];
}
return [options, dataList];
}

View File

@@ -26,9 +26,10 @@
position: absolute; position: absolute;
/* background: #00ee33; */ /* background: #00ee33; */
top: 20px; top: 20px;
left: 180px;
right: 24px; right: 24px;
height: 32px; height: 32px;
width: 190px; width: 128px;
text-align: right; text-align: right;
} }
@@ -62,7 +63,21 @@
padding: 12px 0; padding: 12px 0;
text-align: center; text-align: center;
color: #fff; color: #fff;
box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197); box-shadow: inset 0 0 12px 2px rgba(255, 255, 255, 0.197);
display: flex;
align-items: center;
gap: 12px;
}
.item_label {
flex: 5;
text-align: right;
}
.item_value {
flex: 4;
text-align: left;
} }
.headWidget { .headWidget {

View File

@@ -1,34 +1,36 @@
// TODO: 通用组件 - 按钮 菜单控制层 // TODO: 通用组件 - 按钮 菜单控制层
import useIcon from '../../../hooks/useIcon'; import useIcon from "../../../hooks/useIcon";
import cls from './index.module.css'; import cls from "./index.module.css";
import { useMemo, useState } from 'react'; import { useMemo, useState } from "react";
import { Switch, Radio } from 'antd'; import { Switch, Select } from "antd";
import "./selector.style.overwrite.css";
import triangle from "../../../assets/Icon/triangle.svg";
function choseBg(size) { function choseBg(size) {
const [width, height] = size; const [width, height] = size;
return width === 'long' && height === 'middle' return width === "long" && height === "middle"
? 'long-middle' ? "long-middle"
: width === 'long' && height === 'short' : width === "long" && height === "short"
? 'long-short' ? "long-short"
: width === 'short' && height === 'middle' : width === "short" && height === "middle"
? 'short-middle' ? "short-middle"
: width === 'short' && height === 'short' : width === "short" && height === "short"
? 'short-short' ? "short-short"
: width === 'short' && height === 'long' : width === "short" && height === "long"
? 'short-long' ? "short-long"
: width === 'middle' && height === 'middle' : width === "middle" && height === "middle"
? 'middle-middle' ? "middle-middle"
: width === 'middle' && height === 'short' : width === "middle" && height === "short"
? 'middle-short' ? "middle-short"
: width === 'middle' && height === 'long' : width === "middle" && height === "long"
? 'middle-long' ? "middle-long"
: width === 'middle' && height === 'full' : width === "middle" && height === "full"
? 'middle-full' ? "middle-full"
: 'middle-middle'; : "middle-middle";
} }
function GraphBase(props) { function GraphBase(props) {
const size = props.size || ['middle', 'middle']; const size = props.size || ["middle", "middle"];
const bgClass = choseBg(size); const bgClass = choseBg(size);
const { const {
icon, icon,
@@ -38,10 +40,13 @@ function GraphBase(props) {
onSwitch, onSwitch,
dateOptions, dateOptions,
onDateChange, onDateChange,
defaultSelect,
selectWidth,
legend, legend,
} = props; } = props;
const descSmall = props.descSmall || false;
const iconSrc = useIcon(icon); const iconSrc = useIcon(icon);
const colors = useMemo(() => ['#ffd160', '#2760ff', '#15e8f5'], []); const colors = useMemo(() => ["#ffd160", "#2760ff", "#15e8f5"], []);
const [showChart, setShowChart] = useState(true); const [showChart, setShowChart] = useState(true);
let dto = null; let dto = null;
@@ -50,16 +55,35 @@ function GraphBase(props) {
if (props.switchPosition) { if (props.switchPosition) {
props.switchPosition.forEach((item, index) => { props.switchPosition.forEach((item, index) => {
if (item != null) { if (item != null) {
switchStyle[index == 0 ? 'top' : 'left'] = item + 'px'; switchStyle[index == 0 ? "top" : "left"] = item + "px";
} }
}); });
} }
if (dateOptions) { if (dateOptions) {
dto = dateOptions.map((item) => ( dto = (
<Radio.Button value={item} key={item} className="radio-group__item"> <Select
{item} defaultValue={defaultSelect || dateOptions[0]}
</Radio.Button> style={{ width: selectWidth || 60 }}
)); popupClassName="xc-date-selector-menu"
className={cls.graphBaseDate + " " + cls.radioGroup}
options={dateOptions.map((item) => ({ label: item, value: item }))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "calc(14px * var(--scale))",
lineHeight: 1,
paddingLeft: "calc(12px * var(--scale))",
}}
>
- -
</span>
}
onChange={(value, option) => onDateChange(value)}
/>
);
} }
function handleSwitchChange(v) { function handleSwitchChange(v) {
@@ -70,11 +94,11 @@ function GraphBase(props) {
return ( return (
<div <div
className={ className={
'graph-base ' + "graph-base " +
cls[bgClass] + cls[bgClass] +
' ' + " " +
cls.graphBase + cls.graphBase +
' ' + " " +
props.className props.className
} }
style={{ ...props.style }} style={{ ...props.style }}
@@ -82,9 +106,9 @@ function GraphBase(props) {
<div className={cls.graphBaseTitle}> <div className={cls.graphBaseTitle}>
<img src={iconSrc} alt="#" /> <img src={iconSrc} alt="#" />
<h2>{title}</h2> <h2>{title}</h2>
{desc && <div className={`${cls.graphBaseDesc} ${descSmall ? cls.graphBaseDescSmall : ''}`}>{desc}</div>}
</div> </div>
<div className={cls.graphBaseContent}> <div className={cls.graphBaseContent}>
{desc && <div className={cls.graphBaseDesc}>{desc}</div>}
{switchOptions && ( {switchOptions && (
<div className={cls.graphBaseSwitch} style={switchStyle}> <div className={cls.graphBaseSwitch} style={switchStyle}>
<Switch size="small" defaultChecked onChange={handleSwitchChange} /> <Switch size="small" defaultChecked onChange={handleSwitchChange} />
@@ -105,16 +129,7 @@ function GraphBase(props) {
))} ))}
</div> </div>
)} )}
{dateOptions && ( {dateOptions && dto}
<Radio.Group
defaultValue={dateOptions[0]}
buttonStyle="solid"
className={cls.graphBaseDate + ' ' + cls.radioGroup}
onChange={({ target }) => onDateChange(target.value)}
>
{dto}
</Radio.Group>
)}
{props.children} {props.children}
</div> </div>
</div> </div>

View File

@@ -63,7 +63,7 @@
} }
.graphBaseTitle > img { .graphBaseTitle > img {
width: 20px; width: 24px;
} }
.graphBaseTitle > h2 { .graphBaseTitle > h2 {
@@ -72,7 +72,7 @@
'Source Han Sans SC', 'Noto Sans CJK SC', 'WenQuanYi Micro Hei', sans-serif; 'Source Han Sans SC', 'Noto Sans CJK SC', 'WenQuanYi Micro Hei', sans-serif;
margin: 0; margin: 0;
margin-left: 6px; margin-left: 6px;
font-size: 20px; font-size: 22px;
color: #fff; color: #fff;
letter-spacing: 2px; letter-spacing: 2px;
font-weight: 500; font-weight: 500;
@@ -85,13 +85,19 @@
} }
.graphBaseDesc { .graphBaseDesc {
position: absolute; margin-left: 8px;
/* position: absolute;
top: 25px; top: 25px;
left: 150px; left: 150px; */
font-size: 19px; font-size: 19px;
color: #76fff9; color: #76fff9;
} }
.graphBaseDescSmall {
font-size: 16px;
color: #76fff9;
}
.graphBaseSwitch { .graphBaseSwitch {
position: absolute; position: absolute;
top: 30px; top: 30px;
@@ -114,7 +120,7 @@
.radioGroup * { .radioGroup * {
border: none !important; border: none !important;
border-radius: 0 !important; border-radius: 6px !important;
} }
.radioGroup *:focus-within { .radioGroup *:focus-within {

View File

@@ -0,0 +1,38 @@
.xc-date-selector-menu {
background-color: #04233c !important;
}
.xc-date-selector-menu .ant-select-item {
color: #fff;
background: transparent;
}
.xc-date-selector-menu .ant-select-item-option-content {
text-align: center;
font-size: calc(14px * var(--scale));
}
.xc-date-selector-menu .ant-select-item-option-selected {
color: #fff !important;
background-color: #02457E !important;
}
.ant-select-selector {
background-color: #02457E !important;
color: #fff !important;
}
.xc-date-selector-menu .ant-select-item-option {
/* padding: 5px 8px; */
padding: .3em .35em;
min-height: unset;
}
/*
.ant-select-selector::after {
content: '\25BC' !important;
visibility: visible !important; L
position: absolute;
top: 2px;
right: 22px;
color: #04233c;
} */

View File

@@ -1,60 +1,24 @@
import cls from "./kiln.module.scss"; import cls from "./kiln.module.scss";
import Container from "../../Container"; import Container from "../../Container";
import { useEffect } from "react"; import { useSelector } from "react-redux";
import { useSelector, useDispatch } from "react-redux";
import { stateNameMap } from "../../../store/features/kilnSlice"; import { stateNameMap } from "../../../store/features/kilnSlice";
export default function Kiln() { export default function Kiln() {
const kilnInfo = useSelector((state) => state.kiln); const kilnInfo = useSelector((state) => state.kiln);
const dispatch = useDispatch();
console.log("state: ", kilnInfo, stateNameMap);
const infos = Object.keys(kilnInfo).map((key) => ({ const infos = Object.keys(kilnInfo).map((key) => ({
label: stateNameMap[key], label: stateNameMap[key],
value: kilnInfo[key], value: kilnInfo[key],
})); }));
useEffect(() => {
setInterval(() => {
dispatch({
type: "kiln/setKilnInfo",
payload: {
kilnPressure: Math.ceil(Math.random() * 100) + "Pa",
waterTemp: Math.ceil(Math.random() * 100) + "℃",
waterFlow: Math.ceil(Math.random() * 100) + "m³/h",
waterPressure: Math.ceil(Math.random() * 100) + "Pa",
combustionAirPressure: Math.ceil(Math.random() * 100) + "Pa",
topTemp: Math.ceil(Math.random() * 100) + "℃",
compressedAirPressure: Math.ceil(Math.random() * 100) + "Pa",
meltTemp: Math.ceil(Math.random() * 100) + "℃",
},
});
}, 30000);
}, []);
// const infos = [
// { label: "窑炉压力", value: ctx?.runState?.kilnPressure || "0Pa" },
// { label: "循环水温度", value: ctx?.runState?.waterTemp || "0℃" },
// { label: "循环水流量", value: ctx?.runState?.waterFlow || "0㎡/h" },
// { label: "循环水压力", value: ctx?.runState?.waterPressure || "0Pa" },
// {
// label: "助燃风压力",
// value: ctx?.runState?.combustionAirPressure || "0℃",
// },
// { label: "碹顶加权温度", value: ctx?.runState?.topTemp || "0℃" },
// {
// label: "压缩气压力",
// value: ctx?.runState?.compressedAirPressure || "0Pa",
// },
// { label: "融化加权温度", value: ctx?.runState?.meltTemp || "0℃" },
// ];
return ( return (
<Container title="窑炉信息" icon="kiln" className={cls.leftBar__top}> <Container title="窑炉信息" icon="kiln" className={cls.leftBar__top}>
<div className={cls.leftBar__top__content}> <div className={cls.leftBar__top__content}>
{infos.map((item) => ( {infos.map((item) => (
<div key={item.label} className={cls.info__item}> <div key={item.label} className={cls.info__item}>
{item.label}: {item.value} <span className={cls.label}>{item.label}</span>
<span className={cls.value}>{item.value}</span>
{/* {item.label}: {item.value} */}
</div> </div>
))} ))}
</div> </div>

View File

@@ -24,6 +24,19 @@
line-height: 40px; line-height: 40px;
text-align: center; text-align: center;
user-select: none; user-select: none;
display: flex;
align-items: center;
gap: 12px;
.label {
flex: 6;
text-align: right;
}
.value {
flex: 4;
text-align: left;
}
} }
} }
} }

View File

@@ -1,23 +1,22 @@
import * as echarts from 'echarts'; import * as echarts from "echarts";
import { randomInt } from '../../../../utils';
export default function getOptions(seriesData, name) { export default function getOptions(seriesData, name) {
const colors = [ const colors = [
'#12FFF5', "#12FFF5",
'#2760FF', "#2760FF",
'#FFD160', "#FFD160",
'#E80091', "#E80091",
'#8064ff', "#8064ff",
'#ff8a3b', "#ff8a3b",
'#8cd26d', "#8cd26d",
'#2aa1ff', "#2aa1ff",
]; ];
return { return {
color: colors, color: colors,
grid: { top: 38, right: 12, bottom: 20, left: 48 }, grid: { top: 38, right: 12, bottom: 20, left: 48 },
legend: { legend: {
show: true, show: true,
icon: 'roundRect', icon: "roundRect",
top: 10, top: 10,
right: 10, right: 10,
padding: 0, padding: 0,
@@ -26,73 +25,80 @@ export default function getOptions(seriesData, name) {
itemGap: 3, itemGap: 3,
height: 8, height: 8,
textStyle: { textStyle: {
color: '#DFF1FE', color: "#DFF1FE",
fontSize: 10, fontSize: 10,
}, },
}, },
xAxis: { xAxis: {
type: 'category', type: "category",
data: Array(7) data: Array(7)
.fill(1) .fill(1)
.map((_, index) => { .map((_, index) => {
const today = new Date(); const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000; const dtimestamp = today - (index+1) * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date( return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp, dtimestamp
).getDate()}`; ).getDate()}`;
}) })
.reverse(), .reverse(),
axisLabel: { axisLabel: {
color: '#fff', color: "#fff",
fontSize: 12, fontSize: 12,
}, },
axisTick: { show: false }, axisTick: { show: false },
axisLine: { axisLine: {
lineStyle: { lineStyle: {
width: 1, width: 1,
color: '#213259', color: "#213259",
}, },
}, },
}, },
yAxis: { yAxis: {
name: '单位m³/h', name: "单位m³/h",
nameTextStyle: { nameTextStyle: {
color: '#fff', color: "#fff",
fontSize: 10, fontSize: 10,
align: 'right', align: "right",
}, },
type: 'value', type: "value",
axisLabel: { axisLabel: {
color: '#fff', color: "#fff",
fontSize: 12, fontSize: 12,
formatter: '{value}', formatter: "{value}",
}, },
axisLine: { axisLine: {
show: true, show: true,
lineStyle: { lineStyle: {
color: '#213259', color: "#213259",
}, },
}, },
splitLine: { splitLine: {
lineStyle: { lineStyle: {
color: '#213259a0', color: "#213259a0",
}, },
}, },
}, },
series: seriesData.map((arr, index) => ({ series: seriesData.map((arr, index) => ({
name: index + 1 + '#' + name, name: index + 1 + "#" + name,
data: arr, data: arr,
type: 'line', type: "line",
symbol: 'circle',
symbolSize: 6,
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors[index] + '40' }, { offset: 0, color: colors[index] + "40" },
{ offset: 0.5, color: colors[index] + '20' }, { offset: 0.5, color: colors[index] + "20" },
{ offset: 1, color: colors[index] + '00' }, { offset: 1, color: colors[index] + "00" },
]), ]),
}, },
})), })),
tooltip: { tooltip: {
trigger: 'axis', trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "xc-chart-tooltip",
// backgroundColor: ''
}, },
}; };
} }

View File

@@ -1,34 +1,28 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import ReactECharts from 'echarts-for-react'; import ReactECharts from "echarts-for-react";
import getOptions from './chart.config'; import getOptions from "./chart.config";
// import SocketContext from '../../../../store/socket-data-provider'; import { useSelector, useDispatch } from "react-redux";
import { useContext } from 'react';
function GasChart(props) { function GasChart(props) {
const { dataSource } = props; const { dataSource } = props;
// const { hisState } = useContext(SocketContext); const hisState = useSelector((state) => state.natGas.history);
const hisState = null; const dataName = dataSource == "gas-i" ? "gasIHistory" : "gasIIHistory";
const dataName = dataSource == 'gas-i' ? 'kilnGasT1' : 'kilnGasT2';
// keys() 的结果不是按照顺序的,需要 sort()
const seriesData = hisState?.[dataName] const seriesData = hisState?.[dataName]
? Object.keys(hisState?.[dataName]) ? Object.keys(hisState?.[dataName])
.sort() .sort()
.map((key, index) => hisState?.[dataName][key]) .map((key, index) => hisState?.[dataName][key])
: Array(dataSource == 'gas-i' ? 8 : 4).fill(Array(7).fill(0)); : Array(dataSource == "gas-i" ? 8 : 4).fill(Array(7).fill(0));
// debug
console.log('天然气 series data', dataName, hisState?.[dataName], seriesData);
return ( return (
<div className={cls.gasChart}> <div className={cls.gasChart}>
<ReactECharts <ReactECharts
key={Math.random()} key={dataSource}
option={getOptions( option={getOptions(
seriesData, seriesData,
dataSource == 'gas-i' ? '天然气I' : '天然气II', dataSource == "gas-i" ? "天然气I" : "天然气II"
)} )}
style={{ height: '100%' }} style={{ height: "100%" }}
/> />
</div> </div>
); );

View File

@@ -1,28 +1,27 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import { useContext, useEffect, useState } from 'react'; import { useSelector } from "react-redux";
// import SocketContext from '../../../../store/socket-data-provider';
function getData(type) { function getData(type) {
let data = []; let data = [];
switch (type) { switch (type) {
case 'gas-i': case "gas-i":
data = [ data = [
{ id: 1, name: '1#天然气I', value: '0m³/h' }, { id: 1, name: "1#天然气I", value: "0m³/h" },
{ id: 2, name: '2#天然气I', value: '0m³/h' }, { id: 2, name: "2#天然气I", value: "0m³/h" },
{ id: 3, name: '3#天然气I', value: '0m³/h' }, { id: 3, name: "3#天然气I", value: "0m³/h" },
{ id: 4, name: '4#天然气I', value: '0m³/h' }, { id: 4, name: "4#天然气I", value: "0m³/h" },
{ id: 5, name: '5#天然气I', value: '0m³/h' }, { id: 5, name: "5#天然气I", value: "0m³/h" },
{ id: 6, name: '6#天然气I', value: '0m³/h' }, { id: 6, name: "6#天然气I", value: "0m³/h" },
{ id: 7, name: '7#天然气I', value: '0m³/h' }, { id: 7, name: "7#天然气I", value: "0m³/h" },
{ id: 8, name: '8#天然气I', value: '0m³/h' }, { id: 8, name: "8#天然气I", value: "0m³/h" },
]; ];
break; break;
case 'gas-ii': case "gas-ii":
data = [ data = [
{ id: 11, name: '1#天然气II', value: '0m³/h' }, { id: 11, name: "1#天然气II", value: "0m³/h" },
{ id: 12, name: '2#天然气II', value: '0m³/h' }, { id: 12, name: "2#天然气II", value: "0m³/h" },
{ id: 13, name: '3#天然气II', value: '0m³/h' }, { id: 13, name: "3#天然气II", value: "0m³/h" },
{ id: 14, name: '4#天然气II', value: '0m³/h' }, { id: 14, name: "4#天然气II", value: "0m³/h" },
// { id: 15, name: '5#天然气II', value: '0m³/h' }, // { id: 15, name: '5#天然气II', value: '0m³/h' },
]; ];
break; break;
@@ -31,21 +30,25 @@ function getData(type) {
} }
function GridList(props) { function GridList(props) {
// const { runState } = useContext(SocketContext); const runState = useSelector((state) => state.natGas.runtime);
const runState = null;
const key = props.dataSource == 'gas-i' ? 'gasFlowArr' : 'furnaceGasFlowArr'; const key = props.dataSource == "gas-i" ? "gasIRuntime" : "gasIIRuntime";
let dataList = getData(props.dataSource); let dataList = getData(props.dataSource);
dataList = runState?.[key] dataList = runState?.[key]
? dataList.map((v, i) => ({ ...v, value: runState[key][i] ?? '/' })) ? dataList.map((v, i) => ({
...v,
value: (runState[key][i] || 0) + "m³/h",
}))
: dataList; : dataList;
return ( return (
<div className={cls.gridList}> <div className={cls.gridList}>
{dataList.map((item) => ( {dataList.map((item) => (
<div key={item.id} className={cls.listItem}> <div key={item.id} className={cls.listItem}>
{item.name}: {item.value} <span className={cls.item_label}>{item.name}</span>
<span className={cls.item_value}>{item.value}</span>
{/* {item.name}: {item.value} */}
</div> </div>
))} ))}
</div> </div>

View File

@@ -11,4 +11,17 @@
text-align: center; text-align: center;
color: #fff; color: #fff;
box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197); box-shadow: inset 0 0 16px 4px rgba(255, 255, 255, 0.197);
display: flex;
align-items: center;
gap: 12px;
}
.item_label {
flex: 5;
text-align: right;
}
.item_value {
flex: 6;
text-align: left;
} }

View File

@@ -1,14 +1,15 @@
// 天然气流量 // 天然气流量
import cls from './index.module.css'; import cls from "./index.module.css";
import BottomBarItem from '../BottomItemBackground'; import BottomBarItem from "../BottomItemBackground";
import triangle from "../../../assets/Icon/triangle.svg";
import { Switch, Radio } from 'antd'; import { Switch, Select, Radio } from "antd";
import { useState } from 'react'; import { useState } from "react";
import GridList from './gridList'; import GridList from "./gridList";
import GasChart from './gasChart'; import GasChart from "./gasChart";
import dayjs from "dayjs";
function GasII(props) { function GasII(props) {
const [dataSource, setDataSource] = useState('gas-i'); // gas-i , gas-ii const [dataSource, setDataSource] = useState("gas-i"); // gas-i , gas-ii
const [showChart, setShowChart] = useState(true); const [showChart, setShowChart] = useState(true);
function handleSwitchChange(val) { function handleSwitchChange(val) {
@@ -19,21 +20,33 @@ function GasII(props) {
} }
} }
function handleSourceChange(e) { // function handleSourceChange(e) {
console.log('val', e.target.value); // if (e.target.value == "ii") {
if (e.target.value == 'ii') { // // 天然气II
// 天然气II // setDataSource("gas-ii");
setDataSource('gas-ii'); // } else if (e.target.value == "i") {
} else if (e.target.value == 'i') { // // 天然气 I
// 天然气 I // setDataSource("gas-i");
setDataSource('gas-i'); // }
// }
function handleDateChange(value) {
if (value == "天然气I") {
setDataSource("gas-i");
} else {
setDataSource("gas-ii");
} }
} }
const desc =
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD");
return ( return (
<BottomBarItem <BottomBarItem
icon="pause" icon="pause"
title="天然气流量" title="天然气流量"
desc={desc}
className={`${cls.gas} ${props.className}`} className={`${cls.gas} ${props.className}`}
style={props.style} style={props.style}
> >
@@ -45,7 +58,32 @@ function GasII(props) {
{!showChart && <span className={cls.switchLabel}>实时流量</span>} {!showChart && <span className={cls.switchLabel}>实时流量</span>}
</div> </div>
<Radio.Group <Select
defaultValue={"天然气I"}
style={{ width: 90 }}
popupClassName="xc-date-selector-menu"
className={cls.radioGroup}
options={["天然气I", "天然气II"].map((item) => ({
label: item,
value: item,
}))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "14px",
lineHeight: 1,
paddingLeft: "12px",
}}
>
- -
</span>
}
onChange={(value, option) => handleDateChange(value)}
/>
{/* <Radio.Group
defaultValue="i" defaultValue="i"
buttonStyle="solid" buttonStyle="solid"
className={cls.radioGroup} className={cls.radioGroup}
@@ -57,7 +95,7 @@ function GasII(props) {
<Radio.Button value="ii" className="radio-group__item"> <Radio.Button value="ii" className="radio-group__item">
天然气 II 天然气 II
</Radio.Button> </Radio.Button>
</Radio.Group> </Radio.Group> */}
</div> </div>
<div className={cls.chart}> <div className={cls.chart}>

View File

@@ -24,9 +24,10 @@
.headWidget { .headWidget {
position: absolute; position: absolute;
top: 22px; top: 22px;
right: 24px; left: 178px;
height: 32px; height: 32px;
width: 410px; width: calc(100% - 200px);
/* background: #12fff5; */
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@@ -69,7 +70,7 @@
.radioGroup * { .radioGroup * {
border: none !important; border: none !important;
border-radius: 0 !important; border-radius: 6px !important;
} }
.radioGroup *:focus-within { .radioGroup *:focus-within {

View File

@@ -1,20 +1,21 @@
import { useCallback, useState } from 'react'; import { useCallback, useEffect, useState } from "react";
import cls from './index.module.scss'; import cls from "./index.module.scss";
export default function CenterMenu({ active, onChangeActive }) { export default function CenterMenu({ active, onChangeActive }) {
const menuList = [ const menuList = [
['窑炉总览', '/kilnSummary'], ["窑炉总览", "/kilnSummary"],
['窑炉内部', '/kilnInner'], ["窑炉内部", "/kilnInner"],
['退火监测', '/stopFire'], ["窑炉优化", "/kilnOptimize"],
['质检统计', '/quailtyCheck'], ["退火监测", "/stopFire"],
['能耗分析', '/energyCost'], ["质检统计", "/quailtyCheck"],
["能耗分析", "/energyCost"],
]; ];
return ( return (
<div className={`${cls.centerMenu} flex`}> <div className={`${cls.centerMenu} flex`}>
{menuList.map((menu) => ( {menuList.map((menu) => (
<div <div
key={menu[0]} key={menu[0]}
className={`${cls.menuItem} ${active == menu[0] ? cls.active : ''}`} className={`${cls.menuItem} ${active == menu[0] ? cls.active : ""}`}
onClick={() => onChangeActive(menu[0])} onClick={() => onChangeActive(menu[0])}
> >
{menu[0]} {menu[0]}

View File

@@ -1,7 +1,8 @@
.centerMenu { .centerMenu {
position: fixed; position: fixed;
top: 120px; top: 120px;
left: 1340px; // left: 1340px;
left: 1338px;
color: white; color: white;
z-index: 10000; z-index: 10000;
} }

View File

@@ -0,0 +1,24 @@
import { useSelector } from "react-redux";
import cls from "../index.module.scss";
const SmokeHandleTable = () => {
const smokeInfo = useSelector((state) => state.smoke?.info);
return (
<div className={cls.info__item_groups}>
<div className={cls.info__item}>
: {(+smokeInfo?.O2_float)?.toFixed(2) || 0}%
</div>
<div className={cls.info__item}>
氮氧化物浓度: {(+smokeInfo?.NOX_float)?.toFixed(2) || 0}mg/
</div>
<div className={cls.info__item} style={{ gridColumn: "span 2" }}>
二氧化硫浓度: {(+smokeInfo?.SO2_float)?.toFixed(2) || 0}mg/
</div>
<div className={cls.info__item + " " + cls.disabled}>
颗粒物浓度: {(+smokeInfo?.dust_float)?.toFixed(2) || 0}mg/
</div>
</div>
);
};
export default SmokeHandleTable;

View File

@@ -1,163 +1,156 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import { randomInt } from '../../../../utils'; import * as echarts from "echarts";
import { Select } from "antd";
import * as echarts from 'echarts'; import ReactECharts from "echarts-for-react";
import { Switch, Radio } from 'antd'; import { useEffect, useState } from "react";
import ReactECharts from 'echarts-for-react'; import { useSelector } from "react-redux";
import triangle from "../../../../assets/Icon/triangle.svg";
import dayjs from "dayjs";
const SmokeTrendChart = (props) => { const SmokeTrendChart = (props) => {
const options = { const dayTrend = useSelector((state) => state.smoke?.dayTrend);
color: ['#FFD160', '#12FFF5', '#2760FF'], const weekTrend = useSelector((state) => state.smoke?.weekTrend);
grid: { top: 38, right: 12, bottom: 20, left: 48 }, const monthTrend = useSelector((state) => state.smoke?.monthTrend);
xAxis: { const yearTrend = useSelector((state) => state.smoke?.yearTrend);
type: 'category',
data: Array(7)
.fill(1)
.map((_, index) => {
const today = new Date();
const dtimestamp = today - index * 24 * 60 * 60 * 1000;
return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
dtimestamp,
).getDate()}`;
})
.reverse(),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
name: '单位m³/h',
nameTextStyle: {
color: '#fff',
fontSize: 10,
align: 'right',
},
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
formatter: '{value} %',
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
interval: 10,
min: 0,
max: 100,
},
series: [
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#FFD16040' },
{ offset: 0.5, color: '#FFD16020' },
{ offset: 1, color: '#FFD16010' },
]),
},
// smooth: true,
},
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#12FFF540' },
{ offset: 0.5, color: '#12FFF520' },
{ offset: 1, color: '#12FFF510' },
]),
},
// smooth: true,
},
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2760FF40' },
{ offset: 0.5, color: '#2760FF20' },
{ offset: 1, color: '#2760FF10' },
]),
},
// smooth: true,
},
],
tooltip: {
trigger: 'axis',
},
};
function handleSwitchChange(val) { const [source, setSource] = useState("O2_float");
// val: boolean const [period, setPeriod] = useState("day");
console.log('switch change', val);
const currentTrend =
period === "day"
? dayTrend
: period === "week"
? weekTrend
: period === "month"
? monthTrend
: yearTrend;
const options = getOptions(source, period, currentTrend);
const [desc, setDesc] = useState("");
useEffect(() => {
switch (period) {
case "day":
setDesc(
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点"
);
break;
case "month":
setDesc(
dayjs().subtract(1, "month").format("YYYY.MM.") +
"29 - " +
dayjs().format("YYYY.MM.") +
"28"
);
break;
case "week":
setDesc(
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
break;
case "year":
setDesc(
dayjs().subtract(1, "year").endOf("year").format("YYYY.MM.") +
"29 - " +
dayjs().endOf("year").format("YYYY.MM.") +
"28"
);
break;
}
}, [period]);
function handleDateChange(value) {
setPeriod(
{
: "day",
: "week",
: "month",
: "year",
}[value]
);
}
function handleSourceChange(value) {
setSource(
{
氧气: "O2_float",
氮氧化物: "NOX_float",
二氧化硫: "SO2_float",
颗粒物: "dust_float",
}[value]
);
} }
return ( return (
<div className={cls.energyCostChart}> <div className={cls.energyCostChart}>
<div className={cls.titleBar}> <div className={cls.titleBar}>
<h2>烟气趋势图</h2> <h2>烟气趋势图</h2>
<Switch defaultChecked onChange={handleSwitchChange} /> {/* <Switch defaultChecked onChange={handleSwitchChange} /> */}
<div className={cls.legend}> {/* <div className={cls.legend}>
<span className="legend__title">班次详情</span> <span className="legend__title">班次详情</span>
<ul className="legend__list"> <ul className="legend__list">
<li>总量</li> <li>总量</li>
<li>白班</li> <li>白班</li>
<li>夜班</li> <li>夜班</li>
</ul> </ul>
</div> </div> */}
</div> </div>
<div className={`${cls.choiceBar} flex items-center justify-between`}> <div className={`${cls.choiceBar} flex items-center justify-between`}>
<Radio.Group {/* <Radio.Group
defaultValue="oxygen" value={source}
onChange={(e) => setSource(e.target.value)}
buttonStyle="solid" buttonStyle="solid"
className={`${cls.radioGroup} flex items-center justify-between`} className={`${cls.radioGroup} flex items-center justify-between`}
> >
<Radio.Button value="oxygen" className="radio-group__item"> <Radio.Button value="O2_float" className="radio-group__item">
氧气含量 氧气
</Radio.Button> </Radio.Button>
<Radio.Button value="so2" className="radio-group__item"> <Radio.Button value="NOX_float" className="radio-group__item">
氮氧化物
</Radio.Button>
<Radio.Button value="SO2_float" className="radio-group__item">
二氧化硫 二氧化硫
</Radio.Button> </Radio.Button>
<Radio.Button value="no" className="radio-group__item"> <Radio.Button value="dust_float" className="radio-group__item">
一氧化氮 颗粒物
</Radio.Button> </Radio.Button>
<Radio.Button value="no2" className="radio-group__item"> </Radio.Group> */}
二氧化氮 <Select
</Radio.Button> defaultValue={"氧气"}
</Radio.Group> style={{ width: 100 }}
popupClassName="xc-date-selector-menu"
className={cls.radioGroupShort}
options={["氧气", "氮氧化物", "二氧化硫", "颗粒物"].map((item) => ({
label: item,
value: item,
}))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "14px",
lineHeight: 1,
paddingLeft: "12px",
}}
>
- -
</span>
}
onChange={(value, option) => handleSourceChange(value)}
/>
<Radio.Group <div className={cls.graphBaseDesc}>{desc}</div>
defaultValue="week"
{/* <Radio.Group
value={period}
onChange={(e) => setPeriod(e.target.value)}
buttonStyle="solid" buttonStyle="solid"
className={cls.radioGroup} className={cls.radioGroup}
> >
@@ -173,11 +166,174 @@ const SmokeTrendChart = (props) => {
<Radio.Button value="year" className="radio-group__item"> <Radio.Button value="year" className="radio-group__item">
</Radio.Button> </Radio.Button>
</Radio.Group> </Radio.Group> */}
<Select
defaultValue={"日"}
style={{ width: 60 }}
popupClassName="xc-date-selector-menu"
className={cls.radioGroupShort}
options={["日", "周", "月", "年"].map((item) => ({
label: item,
value: item,
}))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "14px",
lineHeight: 1,
paddingLeft: "12px",
}}
>
- -
</span>
}
onChange={(value, option) => handleDateChange(value)}
/>
</div> </div>
<ReactECharts option={options} style={{ height: '240px' }} /> {options && <ReactECharts option={options} style={{ height: "220px" }} />}
{!options && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "96px",
}}
>
暂无数据
</p>
)}
</div> </div>
); );
}; };
export default SmokeTrendChart; export default SmokeTrendChart;
function getOptions(source, period, trend) {
if (
trend[source].length === 0 ||
trend[source].filter((item) => item.value).length == 0
)
return null;
return {
color: ["#FFD160", "#12FFF5", "#2760FF"],
grid: {
top: 40,
right: 12,
bottom: 20,
left: source == "O2_float" ? 56 : 72,
},
xAxis: {
type: "category",
// data: Array(7)
// .fill(1)
// .map((_, index) => {
// const today = new Date();
// const dtimestamp = today - index * 24 * 60 * 60 * 1000;
// return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
// dtimestamp
// ).getDate()}`;
// })
// .reverse(),
data: trend[source].map((item) => item.time),
axisLabel: {
color: "#fff",
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
},
yAxis: {
name: source == "O2_float" ? "单位:%" : "单位mg/m³",
nameTextStyle: {
color: "#fff",
fontSize: 13,
align: "right",
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 14,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
},
series: [
{
data: trend[source].map((item) =>
!(item.value == null || isNaN(+item.value))
? (+item.value).toFixed(2)
: null
),
type: "line",
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#FFD16040" },
{ offset: 0.5, color: "#FFD16020" },
{ offset: 1, color: "#FFD16010" },
]),
},
// smooth: true,
},
// {
// data: Array(7)
// .fill(1)
// .map((_) => {
// return randomInt(60, 100);
// }),
// type: "line",
// areaStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: "#12FFF540" },
// { offset: 0.5, color: "#12FFF520" },
// { offset: 1, color: "#12FFF510" },
// ]),
// },
// // smooth: true,
// },
// {
// data: Array(7)
// .fill(1)
// .map((_) => {
// return randomInt(60, 100);
// }),
// type: "line",
// areaStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: "#2760FF40" },
// { offset: 0.5, color: "#2760FF20" },
// { offset: 1, color: "#2760FF10" },
// ]),
// },
// // smooth: true,
// },
],
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "xc-chart-tooltip",
},
};
}

View File

@@ -43,7 +43,7 @@
padding-left: 16px; padding-left: 16px;
} }
.energyCostChart .titleBar .legend ul li::before { .energyCostChart .titleBar .legend ul li::before {
content: ''; content: "";
position: absolute; position: absolute;
left: 2px; left: 2px;
top: 2px; top: 2px;
@@ -73,6 +73,10 @@
border: none !important; border: none !important;
border-radius: 0 !important; border-radius: 0 !important;
} }
.radioGroupShort * {
border: none !important;
border-radius: 6px !important;
}
.radioGroup *:focus-within { .radioGroup *:focus-within {
box-shadow: none !important; box-shadow: none !important;
} }
@@ -89,3 +93,10 @@
.radioGroup_button_wrapper.ant-radio-button-wrapper-checked { .radioGroup_button_wrapper.ant-radio-button-wrapper-checked {
background: #02457e !important; background: #02457e !important;
} }
.graphBaseDesc {
margin: 0 12px;
line-height: 1;
color: #76fff9;
flex: 1;
}

View File

@@ -1,18 +1,14 @@
import cls from './index.module.scss'; import cls from "./index.module.scss";
import Container from '../../Container'; import Container from "../../Container";
import TechSplitline from '../TechSplitline'; import TechSplitline from "../TechSplitline";
import SmokeTrendChart from './SmokeTrendChart'; import SmokeTrendChart from "./SmokeTrendChart";
import SmokeHandleTable from "./SmokeHandleTable";
function SmokeHandle(props) { function SmokeHandle(props) {
return ( return (
<Container title="烟气处理" icon="smoke" className={cls.smokeHandle}> <Container title="烟气处理" icon="smoke" className={cls.smokeHandle}>
<div className={`${cls.smokeHandle__content} flex flex-col`}> <div className={`${cls.smokeHandle__content} flex flex-col`}>
<div className={cls.info__item_groups}> <SmokeHandleTable />
<div className={cls.info__item}> : 72%</div>
<div className={cls.info__item}>一氧化氮排放浓度:59mg/</div>
<div className={cls.info__item}>二氧化硫排放浓度:59mg/</div>
<div className={cls.info__item}>二氧化氮排放浓度:59mg/</div>
</div>
<TechSplitline /> <TechSplitline />
<SmokeTrendChart /> <SmokeTrendChart />
</div> </div>

View File

@@ -3,7 +3,7 @@
background: url(../../../assets/smoke.png) no-repeat; background: url(../../../assets/smoke.png) no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
width: 626px; width: 626px;
height: 540px; height: 490px;
.smokeHandle__content { .smokeHandle__content {
margin-top: 8px; margin-top: 8px;
} }
@@ -13,19 +13,24 @@
border-radius: 2px; border-radius: 2px;
color: hsl(0, 0%, 100%, 0.9); color: hsl(0, 0%, 100%, 0.9);
box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15); box-shadow: inset 0 0 17px 0px hsla(0, 0%, 100%, 0.15);
// width: 288px; height: 32px;
height: 56px; font-size: 16px;
font-size: 20px;
letter-spacing: 1.43px; letter-spacing: 1.43px;
line-height: 56px; line-height: 32px;
text-align: center; text-align: center;
user-select: none; user-select: none;
} }
.info__item_groups { .info__item_groups {
margin-bottom: 12px; margin-bottom: 12px;
margin-left: 8px;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 8px; gap: 4px;
}
.disabled {
display: none;
pointer-events: none;
opacity: 0.5;
color: transparent;
} }

View File

@@ -0,0 +1,55 @@
import BlueRect from "../BlueRect";
import { useSelector } from "react-redux";
import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useState } from "react";
const blueTe = ["TE401", "TE402", "TE403", "PE401", "PE402", "PE403"];
function TemperatureBottom(props) {
const tempBottom = useSelector((state) => state.temperature.bottom);
const speed = props.speed;
const floor = props.floor;
const [speedAn, setSpeedAn] = useState({});
useEffect(() => {
// 23互切不用展示动画
if (speed === "f") {
setSpeedAn({});
} else {
if (floor === 2) {
setSpeedAn({
opacity: [0, 0, 0, 0.6, 1],
transition: { duration: 0.3, delay: 1.8 },
});
} else {
setSpeedAn({});
}
}
}, [floor]);
return (
<motion.div
className="temperature-bottom"
style={{
position: "absolute",
top: "0",
left: "0",
width: "100%",
height: "80vh",
zIndex: "-1",
...props.style,
}}
animate={speedAn}
>
{Object.keys(tempBottom).map((d) => (
<BlueRect
title={d}
key={d + Math.random()}
value={tempBottom[d]}
blue={blueTe.includes(d)}
/>
))}
</motion.div>
);
}
export default TemperatureBottom;

View File

@@ -0,0 +1,50 @@
import BlueRect from "../BlueRect";
import { useSelector } from "react-redux";
import { motion, AnimatePresence } from "framer-motion";
const blueTe = [
"TE271",
"TE272",
"TE273",
"TE274",
"TE275",
"TE276",
"TE277",
"TE278",
"TE279",
"TE280",
];
function TemperatureTop(props) {
const tempTop = useSelector((state) => state.temperature.top);
return (
<motion.div
className="temperature-top"
style={{
position: "absolute",
top: "0",
left: "0",
width: "100%",
height: "80vh",
zIndex: "-1",
...props.style,
}}
animate={{
opacity: [0, 0, 0, 0.6, 1],
transition: { duration: 0.3, delay: 1.5 },
}}
>
{Object.keys(tempTop).map((d) => (
<BlueRect
title={d}
key={d + Math.random()}
value={tempTop[d]}
blue={blueTe.includes(d)}
/>
))}
</motion.div>
);
}
export default TemperatureTop;

View File

@@ -10,11 +10,15 @@ import icon3 from "../../../assets/CenterChart2icon3.svg";
import useTimeCounter from "../../../hooks/useTimeCounter"; import useTimeCounter from "../../../hooks/useTimeCounter";
const FireInfo = () => { const FireInfo = () => {
const dispatch = useDispatch(); // const dispatch = useDispatch();
const fireInfo = useSelector((state) => state.fireInfo); const fireInfo = useSelector((state) => state.fireInfo);
const time = fireInfo.lastFireChangeTime || "0分0秒"; const time = fireInfo.lastFireChangeTime || "0分0秒";
const [min, sec] = useTimeCounter(time); const minsec = useTimeCounter(time);
let [min, sec] = [0, 0];
if (minsec) {
min = minsec[0];
sec = minsec[1];
}
// useEffect(() => { // useEffect(() => {
// const restTime = ctx?.runState?.lastFireChangeTime; // const restTime = ctx?.runState?.lastFireChangeTime;
// if (restTime == null) return; // if (restTime == null) return;
@@ -76,22 +80,22 @@ const FireInfo = () => {
// }; // };
// }, [ctx?.runState?.lastFireChangeTime]); // }, [ctx?.runState?.lastFireChangeTime]);
useEffect(() => { // useEffect(() => {
setInterval(() => { // setInterval(() => {
dispatch({ // dispatch({
type: "fireInfo/setFireInfo", // type: "fireInfo/setFireInfo",
payload: { // payload: {
fireChangeTime: `${Math.ceil(Math.random() * 10)}:${Math.ceil( // fireChangeTime: `${Math.ceil(Math.random() * 10)}:${Math.ceil(
Math.random() * 10 // Math.random() * 10
)}`, // )}`,
fireDirection: Math.random * 10 < 5 ? "东火" : "西火", // fireDirection: Math.random * 10 < 5 ? "东火" : "西火",
lastFireChangeTime: `${Math.ceil(Math.random() * 60)}${Math.ceil( // lastFireChangeTime: `${Math.ceil(Math.random() * 60)}分${Math.ceil(
Math.random() * 50 // Math.random() * 50
)}`, // )}秒`,
}, // },
}); // });
}, 10000); // }, 10000);
}, []); // }, []);
const data = [ const data = [
{ {

View File

@@ -0,0 +1 @@
1.json

View File

@@ -1,163 +1,211 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import GraphBase from '../GraphBase'; import GraphBase from "../GraphBase";
import ReactECharts from 'echarts-for-react'; import ReactECharts from "echarts-for-react";
import { useSelector } from "react-redux";
import { useState } from "react";
import dayjs from 'dayjs'
function FaultTotal(props) { function FaultTotal(props) {
const options = { const [currentSelect, setCurrentSelect] = useState("日");
color: [ const isra = useSelector((state) => state.isra);
'#2760FF',
'#5B9BFF', const currentStatistic =
'#FFD160', currentSelect == "日"
'#8167F6', ? isra.dayStatistic
'#99D66C', : currentSelect == "周"
'#FF8A40', ? isra.weekStatistic
'#12FFF5', : currentSelect == "月"
], ? isra.monthStatistic
grid: { top: 42, right: 12, bottom: 20, left: 48 }, : currentSelect == "月"
legend: { ? isra.yearStatistic
top: 10, : [];
padding: 5,
itemWidth: 12, const series = preHandleStatisticData(currentStatistic, isra.checkType ?? []);
itemHeight: 12, const options = getOptions(series, isra, currentStatistic);
itemGap: 12,
height: 12,
textStyle: {
color: '#DFF1FE',
fontSize: 12,
},
},
xAxis: {
type: 'category',
data: Array(5)
.fill(1)
.map((_, index) => {
return '产线' + (index + 1);
}),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
name: '单位/个',
nameTextStyle: {
color: '#fff',
fontSize: 10,
align: 'right',
},
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
formatter: '{value}',
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
// interval: 10,
// min: 0,
// max: 100,
},
series: [
{
name: '缺陷1',
type: 'bar',
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [320, 332, 301, 334, 390, 330, 320],
},
{
name: '缺陷2',
type: 'bar',
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [120, 132, 101, 134, 90, 230, 210],
},
{
name: '缺陷3',
type: 'bar',
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [220, 182, 191, 234, 290, 330, 310],
},
{
name: '缺陷4',
type: 'bar',
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [150, 232, 201, 154, 190, 330, 410],
},
{
name: '缺陷5',
type: 'bar',
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [862, 1018, 964, 1026, 1679, 1600, 1570],
},
{
name: '缺陷6',
type: 'bar',
barGap: 20,
barWidth: 12,
stack: 'abcd',
emphasis: {
focus: 'series',
},
data: [620, 732, 701, 734, 1090, 1130, 1120],
},
],
tooltip: {
trigger: 'axis',
},
};
function handleDateChange(v) { function handleDateChange(v) {
console.log('date ', v); setCurrentSelect(v);
} }
// 根据使用的页面决定背景的大小 // 根据使用的页面决定背景的大小
const bgSize = const bgSize =
props.page == 'home' ? ['middle', 'short'] : ['middle', 'long']; props.page == "home" ? ["middle", "short"] : ["middle", "long"];
// time hint
let timeDesc = "";
switch (currentSelect) {
case "日":
timeDesc = dayjs().format('YYYY.MM.DD') + " 7点 - " + dayjs().add(1, 'day').format('YYYY.MM.DD') + " 7点";
break;
case "周":
timeDesc = dayjs().subtract(7, 'day').format('YYYY.MM.DD') + " - " + dayjs().subtract(1, 'day').format('YYYY.MM.DD') ;
break;
case "月":
timeDesc = dayjs().subtract(1, 'month').format('YYYY.MM.') + "29 - " + dayjs().format('YYYY.MM.') + '28' ;
break;
case "年":
timeDesc = dayjs().subtract(1, 'year').endOf('year').format('YYYY.MM.') + "29 - " + dayjs().endOf('year').format('YYYY.MM.') + '28' ;
break;
}
return ( return (
<GraphBase <GraphBase
icon="battery" icon="chart"
title="产线当日缺陷分类" title="产线缺陷统计"
dateOptions={['日', '周', '月', '年']} defaultSelect={currentSelect}
onDateChange={handleDateChange} onDateChange={handleDateChange}
size={bgSize} size={bgSize}
style={{ width: '600px' }} desc={timeDesc}
style={{ width: "600px" }}
> >
<div className={cls.chart}> <div className={cls.chart}>
<ReactECharts option={options} style={{ height: '100%' }} /> {currentStatistic.length != 0 && (
<ReactECharts option={options} style={{ height: "100%" }} />
)}
{currentStatistic.length == 0 && (
<p
style={{
paddingTop: "72px",
color: "#fff6",
textAlign: "center",
fontSize: "24px",
}}
>
暂无数据
</p>
)}
</div> </div>
</GraphBase> </GraphBase>
); );
} }
export default FaultTotal; export default FaultTotal;
function preHandleStatisticData(data, legend) {
const obj = {};
if (!data || !Array.isArray(data)) data = [];
data.forEach((item) => {
obj[item.name] = {};
item.data.forEach((d) => {
obj[item.name][d.checkType] = d.checkNum;
});
});
const series = Array(legend.length)
.fill(1)
.map((_) => ({
name: "",
type: "bar",
stack: "true",
barWidth: 12,
emphasis: {
focus: "series",
},
data: [],
}));
legend.forEach((item, index) => {
series[index].name = item;
data.forEach((d, idx) => {
if (index == legend.length - 1) {
series[index].label = {
show: true,
position: "top",
distance: 10,
color: "#fffc",
formatter: (params) => data[params.dataIndex].sum,
};
}
// const sum = d.sum;
// console.log("d", d, sum);
// series[index].label = ((fff) => {
// console.log("===>", fff);
// return {
// show: true,
// position: "top",
// distance: 10,
// color: "#fffc",
// formatter: "asdf" + fff,
// };
// })(sum);
series[index].data.push(obj[d.name][item] || 0);
});
});
return series;
}
function getOptions(series, isra, currentStatistic) {
return {
color: ["#2760FF", "#8167F6", "#5B9BFF", "#99D66C", "#FFD160", "#FF8A40"],
grid: {
top: (isra.checkType || []).length <= 10 ? 80 : 100,
right: 12,
bottom: 20,
left: 48,
},
legend: {
top: 10,
left: 60,
padding: 5,
itemWidth: 12,
itemHeight: 12,
itemGap: 12,
height: 12,
textStyle: {
color: "#DFF1FE",
fontSize: 12,
},
data: isra.checkType,
},
xAxis: {
type: "category",
data: currentStatistic.map((item) => item.name),
axisLabel: {
color: "#fffc",
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
},
yAxis: {
name: "单位/个",
nameTextStyle: {
color: "#fff",
fontSize: 10,
align: "right",
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
},
series,
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
className: "xc-chart-tooltip",
// backgroundColor: ''
},
};
}

View File

@@ -1,107 +1,253 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import GraphBase from '../GraphBase'; import GraphBase from "../GraphBase";
import ReactECharts from 'echarts-for-react'; import ReactECharts from "echarts-for-react";
import { useState } from 'react'; import { useSelector } from "react-redux";
import { useEffect, useState } from "react";
import * as echarts from "echarts";
import dayjs from "dayjs";
function FaultType(props) { function FaultType(props) {
const options = { const [init, setInit] = useState(true);
colors: [ const [currentLine, setCurrentLine] = useState("Y61");
'#2760FF', const isra = useSelector((state) => state.isra);
'#5B9BFF', const currentStatistic = isra.dayStatistic || [];
'#FFD160', const currentLineStatistic =
'#8167F6', currentLine != ""
'#99D66C', ? currentStatistic.find((item) => item.name === currentLine)?.data || []
'#FF8A40', : [];
'#12FFF5', const lines = currentStatistic.map((item) => item.name);
], const CHART_TYPE = "line"; // "pie" | "line";
grid: { const timestr =
left: 24, dayjs().format("YYYY.MM.DD") +
top: 10, " 7点 - " +
bottom: 10, dayjs().add(1, "d").format("YYYY.MM.DD") +
right: 24, " 7点";
},
legend: {
icon: 'circle',
top: 32,
right: 0,
bottom: 32,
width: 296,
height: 130,
itemGap: 30,
formatter: function (name) {
return `${name} {sub|${
options.series[0].data.find((o) => o.name == name).value
}}`;
},
textStyle: {
color: '#DFF1FE',
fontSize: 18,
rich: {
sub: {
color: '#fff9',
fontSize: 18,
},
},
},
},
series: [
{
type: 'pie',
center: ['26%', '54%'],
radius: ['55%', '75%'],
avoidLabelOverlap: false,
label: {
show: true,
formatter: '{d}%',
fontSize: 14,
color: 'inherit',
},
labelLine: {
length: 0,
},
data: [
{ value: 1048, name: '缺陷1' },
{ value: 735, name: '缺陷2' },
{ value: 580, name: '缺陷3' },
{ value: 484, name: '缺陷4' },
{ value: 300, name: '缺陷5' },
{ value: 300, name: '缺陷6' },
{ value: 300, name: '缺陷8' },
],
},
],
};
const [lines, setLines] = useState([ useEffect(() => {
{ id: 1, label: '产线1', value: 'l1' }, if (init == false) return;
{ id: 2, label: '产线2', value: 'l2' }, if (lines.length) {
{ id: 3, label: '产线3', value: 'l3' }, setInit(false);
{ id: 4, label: '产线4', value: 'l4' }, setCurrentLine(lines[0]);
{ id: 5, label: '产线5', value: 'l5' }, }
]); }, [lines]);
function handleDateChange(v) { const options = init
console.log('date ', v); ? {}
: getOptions(
CHART_TYPE == "pie"
? getSeries(currentStatistic, currentLine)
: currentLineStatistic,
CHART_TYPE
);
function handleLineChange(line) {
setCurrentLine(line);
} }
// 根据使用的页面决定背景的大小 // 根据使用的页面决定背景的大小
const bgSize = const bgSize =
props.page == 'home' ? ['middle', 'short'] : ['middle', 'short']; props.page == "home" ? ["middle", "short"] : ["middle", "short"];
return ( return (
<GraphBase <GraphBase
icon="battery" icon="default"
title="产线当日缺陷分类" title="产线当日缺陷分类"
dateOptions={lines.map((item) => item.label)} desc={timestr}
onDateChange={handleDateChange} descSmall={true}
dateOptions={[...lines]}
defaultSelect={currentLine}
onDateChange={handleLineChange}
size={bgSize} size={bgSize}
style={{ width: '600px' }} selectWidth={64}
style={{ width: "600px" }}
> >
<div className={cls.chart}> <div className={cls.chart}>
<ReactECharts option={options} style={{ height: '100%' }} /> {currentStatistic.length == 0 && (
<p
style={{
paddingTop: "72px",
color: "#fff6",
textAlign: "center",
fontSize: "24px",
}}
>
暂无数据
</p>
)}
{currentStatistic.length != 0 && (
<ReactECharts option={options} style={{ height: "100%" }} />
)}
</div> </div>
</GraphBase> </GraphBase>
); );
} }
export default FaultType; export default FaultType;
function getOptions(data, chart_type) {
const color = [
"#2760FF",
"#8167F6",
"#5B9BFF",
"#99D66C",
"#FFD160",
"#FF8A40",
];
const grid = {
left: 24,
top: 10,
bottom: 10,
right: 24,
};
const legend_common = {
icon: "circle",
top: 32,
right: 0,
bottom: 32,
width: 296,
height: 130,
itemGap: 30,
textStyle: {
color: "#DFF1FE",
fontSize: 18,
rich: {
sub: {
color: "#fff9",
fontSize: 18,
},
},
},
};
if (chart_type == "pie") {
return {
color,
grid,
legend: {
...legend_common,
formatter: function (name) {
return `${name} {sub|${
data[0].data.find((o) => o.name == name).value
}}`;
},
},
series: data,
};
} else if (chart_type == "line") {
const dataList = data.map((item) => ({
category: item.checkType,
value: item.checkNum,
}));
return {
grid: {
top: 48,
left: 48,
bottom: 40,
right: 18,
},
legend: {
...legend_common,
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
symbol: "rect",
className: "xc-chart-tooltip",
// backgroundColor: ''
},
xAxis: {
type: "category",
data: (dataList || []).map((item) => item.category),
axisLabel: {
color: "#fff",
fontSize: 10,
rotate: 20,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
},
yAxis: {
name: "单位/个",
nameTextStyle: {
color: "#fff",
fontSize: 10,
align: "right",
},
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value}",
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
},
series: [
{
type: "bar",
barWidth: 14,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// i % 8 避免超过8个数据时无颜色的问题
{ offset: 0, color: "#5CB7FF" },
{ offset: 1, color: "#364BFE" },
]),
},
label: {
show: true,
position: "top",
distance: 10,
fontSize: 10,
color: "#fffc",
},
data: (dataList || []).map((item) =>
item.value == null || isNaN(+item.value)
? null
: (+item.value).toFixed(0)
),
},
],
};
}
}
function getSeries(currentStatistic, currentLine) {
const currentItem = currentStatistic.find((item) => item.name == currentLine);
return [
{
type: "pie",
center: ["26%", "54%"],
radius: ["55%", "75%"],
avoidLabelOverlap: false,
label: {
show: true,
formatter: "{d}%",
fontSize: 14,
color: "inherit",
},
labelLine: {
length: 0,
},
data: currentItem.data.map((item) => ({
value: item.checkNum,
name: item.checkType,
})),
},
];
}

View File

@@ -1,8 +1,8 @@
import cls from './good.module.scss'; import cls from "./good.module.scss";
import Container from '../../Container'; import Container from "../../Container";
import TodayTableData from './components/TodayTableData'; import TodayTableData from "./components/TodayTableData";
import GoodRateChart from './components/GoodRateChart'; import GoodRateChart from "./components/GoodRateChart";
import TechSplitline from '../TechSplitline'; import TechSplitline from "../TechSplitline";
const GoodProduction = () => { const GoodProduction = () => {
return ( return (

View File

@@ -1,137 +1,132 @@
import cls from './index.module.css'; import cls from "./index.module.css";
import './overwrite.css'; // 覆写 antd 默认样式,全局 import "./overwrite.css"; // 覆写 antd 默认样式,全局
import ReactECharts from 'echarts-for-react'; import ReactECharts from "echarts-for-react";
import * as echarts from 'echarts'; import * as echarts from "echarts";
import { Switch, Radio } from 'antd'; import { Switch, Select, Radio } from "antd";
import { randomInt } from '../../../../../utils'; import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import triangle from "../../../../../assets/Icon/triangle.svg";
import dayjs from "dayjs";
const dateOptions = { day: "日", week: "周", month: "月", year: "年" };
const GoodRateChart = (props) => { const GoodRateChart = (props) => {
const options = { // 是否展示班次数据
color: ['#FFD160', '#12FFF5', '#2760FF'], const [showMore, setShowMore] = useState(false);
grid: { top: 28, right: 12, bottom: 32, left: 48 }, // 更新 key用于刷新图表
xAxis: { const [updateKey, setUpdateKey] = useState(Date.now());
type: 'category', // 默认的日期类型
data: Array(7) const [dateType, setDateType] = useState("day");
.fill(1) const [defaultSelect, setDefaultSelect] = useState(dateOptions[dateType]);
.map((_, index) => { const cutting = useSelector((state) => state.cutting);
const today = new Date(); useEffect(() => {
const dtimestamp = today - index * 24 * 60 * 60 * 1000; setUpdateKey(Date.now());
return `${new Date(dtimestamp).getMonth() + 1}.${new Date( }, [showMore]);
dtimestamp,
).getDate()}`;
})
.reverse(),
axisLabel: {
color: '#fff',
fontSize: 12,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: '#213259',
},
},
},
yAxis: {
type: 'value',
axisLabel: {
color: '#fff',
fontSize: 12,
formatter: '{value} %',
},
axisLine: {
show: true,
lineStyle: {
color: '#213259',
},
},
splitLine: {
lineStyle: {
color: '#213259a0',
},
},
interval: 10,
min: 0,
max: 100,
},
series: [
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#FFD16040' },
{ offset: 0.5, color: '#FFD16020' },
{ offset: 1, color: '#FFD16010' },
]),
},
// smooth: true,
},
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#12FFF540' },
{ offset: 0.5, color: '#12FFF520' },
{ offset: 1, color: '#12FFF510' },
]),
},
// smooth: true,
},
{
data: Array(7)
.fill(1)
.map((_) => {
return randomInt(60, 100);
}),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2760FF40' },
{ offset: 0.5, color: '#2760FF20' },
{ offset: 1, color: '#2760FF10' },
]),
},
// smooth: true,
},
],
tooltip: {
trigger: 'axis',
},
};
function handleSwitchChange(val) { function handleSwitchChange(val) {
// val: boolean // val: boolean
console.log('switch change', val); setShowMore(val);
} }
const [timestr, setTimestr] = useState(
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点"
);
function handleDateChange(value) {
// e: Event
let v = "day";
switch (value) {
case "日":
setTimestr(
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点"
);
break;
case "月":
v = "month";
setTimestr(
dayjs().subtract(1, "month").format("YYYY.MM.") +
"29 - " +
dayjs().format("YYYY.MM.") +
"28"
);
break;
case "周":
v = "week";
setTimestr(
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
break;
case "年":
v = "year";
setTimestr(
dayjs().subtract(1, "year").endOf("year").format("YYYY.MM.") +
"29 - " +
dayjs().endOf("year").format("YYYY.MM.") +
"28"
);
break;
}
setDateType(v);
}
// 根据日期类型,数据列表,是否展示班次数据,生成对应的 options
const options = getOptions(cutting.chart[dateType], showMore, dateType);
return ( return (
<div className={cls.GoodRateChart}> <div className={cls.GoodRateChart}>
<div className={cls.titleBar}> <div className={cls.titleBar}>
<h2>生产良品率</h2> <h2>生产良品率</h2>
<Switch defaultChecked onChange={handleSwitchChange} /> <Switch defaultChecked={showMore} onChange={handleSwitchChange} />
<div className={cls.legend}> <div className={cls.legend}>
<span className="legend__title">班次详情</span> <span className="legend__title">班次详情</span>
<ul className="legend__list"> <ul className="legend__list">
<li>总量</li> <li>总量</li>
{showMore && (
<>
<li>白班</li> <li>白班</li>
<li>夜班</li> <li>夜班</li>
</>
)}
</ul> </ul>
</div> </div>
<Radio.Group <div className={cls.graphBaseDesc}>{timestr}</div>
defaultValue="week" <Select
buttonStyle="solid" defaultValue={defaultSelect}
style={{ width: 60 }}
popupClassName="xc-date-selector-menu"
className={cls.radioGroup} className={cls.radioGroup}
options={["日", "周", "月", "年"].map((item) => ({
label: item,
value: item,
}))}
suffixIcon={<img src={triangle} alt="#" />}
notFoundContent={
<span
style={{
color: "#fff",
fontSize: "14px",
lineHeight: 1,
paddingLeft: "12px",
}}
>
- -
</span>
}
onChange={(value, option) => handleDateChange(value)}
/>
{/* <Radio.Group
defaultValue="day"
buttonStyle="solid"
onChange={handleDateChange}
className={cls.radioGroup}
style={{ flex: 1, textAlign: "right" }}
> >
<Radio.Button value="day" className="radio-group__item"> <Radio.Button value="day" className="radio-group__item">
@@ -145,11 +140,174 @@ const GoodRateChart = (props) => {
<Radio.Button value="year" className="radio-group__item"> <Radio.Button value="year" className="radio-group__item">
</Radio.Button> </Radio.Button>
</Radio.Group> </Radio.Group> */}
</div> </div>
<ReactECharts option={options} /> {options && <ReactECharts key={updateKey} option={options} />}
{!options && (
<p
style={{
paddingTop: "88px",
color: "#fffc",
textAlign: "center",
fontSize: "24px",
userSelect: "none",
}}
>
暂无数据
</p>
)}
</div> </div>
); );
}; };
export default GoodRateChart; export default GoodRateChart;
function getOptions(dataList, showMore, dateType) {
const list = [...dataList].sort((a, b) => a.dataTime - b.dataTime);
console.log(
"list ",
list.filter((item) => item.sum)
);
if (list.length === 0 || list.filter((item) => item.sum).length == 0)
return null;
const color = ["#FFD160", "#12FFF5", "#2760FF"];
const grid = { top: 28, right: 12, bottom: showMore ? 72 : 64, left: 48 };
const xAxis = {
type: "category",
data: list.map((item) =>
dateType == "day"
? item.dataTime.split("T")[1]
: item.dataTime.split("T")[0]
),
axisLabel: {
color: "#fff",
fontSize: 10,
rotate: 25,
margin: 13,
},
axisTick: { show: false },
axisLine: {
lineStyle: {
width: 1,
color: "#213259",
},
},
};
const yAxis = {
type: "value",
axisLabel: {
color: "#fff",
fontSize: 12,
formatter: "{value} %",
},
axisLine: {
show: true,
lineStyle: {
color: "#213259",
},
},
splitLine: {
lineStyle: {
color: "#213259a0",
},
},
interval: 10,
min: 0,
max: 100,
};
const seriesTeam = [
{
name: "白班",
data: list.map((item) => (item.day * 100).toFixed(2)),
type: "line",
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#12FFF540" },
{ offset: 0.5, color: "#12FFF520" },
{ offset: 1, color: "#12FFF510" },
]),
},
},
{
name: "夜班",
data: list.map((item) => (item.night * 100).toFixed(2)),
type: "line",
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#2760FF40" },
{ offset: 0.5, color: "#2760FF20" },
{ offset: 1, color: "#2760FF10" },
]),
},
},
];
return {
grid,
color,
xAxis,
yAxis,
tooltip: {
trigger: "axis",
color: "#fff",
formatter: showMore
? "{a0} {c0}%<br />{a1} {c1}%<br />{a2} {c2}%"
: "{b} {c}%",
axisPointer: {
type: "shadow",
},
textStyle: {
color: "#fffc",
},
className: "xc-chart-tooltip",
},
series: [
{
name: "总量",
data: list.map((item) =>
item.sum != null ? (item.sum * 100).toFixed(2) : "-- "
),
type: "line",
symbol: "circle",
symbolSize: 6,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#FFD16040" },
{ offset: 0.5, color: "#FFD16020" },
{ offset: 1, color: "#FFD16010" },
]),
},
// smooth: true,
},
...(showMore ? seriesTeam : []),
],
};
}
// {
// data: Array(7)
// .fill(1)
// .map((_) => {
// return randomInt(60, 100);
// }),
// type: "line",
// areaStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: "#FFD16040" },
// { offset: 0.5, color: "#FFD16020" },
// { offset: 1, color: "#FFD16010" },
// ]),
// },
// // smooth: true,
// },
// data: Array(7)
// .fill(1)
// .map((_, index) => {
// const today = new Date();
// const dtimestamp = today - index * 24 * 60 * 60 * 1000;
// return `${new Date(dtimestamp).getMonth() + 1}.${new Date(
// dtimestamp
// ).getDate()}`;
// })
// .reverse(),

View File

@@ -6,15 +6,16 @@
} }
.GoodRateChart .titleBar { .GoodRateChart .titleBar {
display: flex; display: flex;
justify-content: space-between; justify-content: flex-start;
align-items: center; align-items: center;
gap: 5px;
color: white; color: white;
} }
.GoodRateChart .titleBar h2 { .GoodRateChart .titleBar h2 {
margin: 0; margin: 0;
font-size: 18px; font-size: 16px;
line-height: 32px; line-height: 32px;
letter-spacing: 1.2px; letter-spacing: 1px;
color: #52fff8; color: #52fff8;
} }
@@ -28,10 +29,17 @@
color: #dff1fe; color: #dff1fe;
} }
.graphBaseDesc {
margin: 0 6px;
font-size: 16px;
color: #76fff9;
flex: 1;
}
.GoodRateChart .titleBar .legend ul { .GoodRateChart .titleBar .legend ul {
display: flex; display: flex;
margin: 0; margin: 0;
margin-left: 8px; margin-left: 5px;
padding: 0; padding: 0;
list-style: none; list-style: none;
align-items: center; align-items: center;
@@ -42,7 +50,7 @@
padding-left: 16px; padding-left: 16px;
} }
.GoodRateChart .titleBar .legend ul li::before { .GoodRateChart .titleBar .legend ul li::before {
content: ''; content: "";
position: absolute; position: absolute;
left: 2px; left: 2px;
top: 2px; top: 2px;
@@ -66,7 +74,8 @@
.radioGroup * { .radioGroup * {
border: none !important; border: none !important;
border-radius: 0 !important; border-radius: 6px !important;
/* transform: translateX(224px) !important; */
} }
.radioGroup *:focus-within { .radioGroup *:focus-within {
box-shadow: none !important; box-shadow: none !important;

View File

@@ -1,34 +1,82 @@
import { useState } from "react"; import { useState } from "react";
import cls from "./index.module.scss"; import cls from "./index.module.scss";
import { ScrollBoard } from "@jiaminghi/data-view-react"; import { ScrollBoard } from "@jiaminghi/data-view-react";
import { useSelector } from "react-redux";
function getRate(decimal) {
return decimal != null ? (decimal * 100).toFixed(2) + "%" : undefined;
}
const TodayTableData = (props) => { const TodayTableData = (props) => {
const [config, setConfig] = useState({ const cutting = useSelector((state) => state.cutting);
// let cutting = {
// table: [
// {
// lineName: "Y61",
// first: 0.37,
// second: 0.03,
// product: 0.99,
// waste: 0.01,
// },
// ],
// chart: {},
// };
const config = {
// headerBGC: 'rgba(4, 44, 76, 0.3)', // headerBGC: 'rgba(4, 44, 76, 0.3)',
headerBGC: "rgba(4, 44, 76, .8)", // headerBGC: "rgba(4, 44, 76, .8)",
headerBGC: "#044A8460",
header: [ header: [
'<span style="color:#fff">产线<span/>', '<span style="color:#fff; padding-left: 12px;">产线<span/>',
'<span style="color:#fff">一等率<span/>', '<span style="color:#fff; padding-left: 12px;">一等率<span/>',
'<span style="color:#fff">二等率<span/>', '<span style="color:#fff; padding-left: 12px;">二等率<span/>',
'<span style="color:#fff">成品率<span/>', '<span style="color:#fff; padding-left: 12px;">成品率<span/>',
'<span style="color:#fff">废品率<span/>', '<span style="color:#fff; padding-left: 12px;">废品率<span/>',
], ],
oddRowBGC: "#042444", // oddRowBGC: "#042444",
evenRowBGC: "#042c4c", // evenRowBGC: "#042c4c",
oddRowBGC: "#044A8460",
evenRowBGC: "#0b549970",
columnWidth: [90], columnWidth: [90],
headerHeight: 40, headerHeight: 40,
hoverPause: false, hoverPause: false,
data: [ data: cutting.table.map((line) => [
["产线1", "37%", "62%", "97%", "7%"], line.lineName,
["产线2", "95%", "10%", "99%", "3%"], getRate(line.first),
["产线3", "68%", "1%", "92%", "4%"], getRate(line.second),
["产线4", "94%", "21%", "97%", "2%"], getRate(line.product),
["产线5", "99%", "30%", "95%", "5%"], getRate(line.waste),
], ]),
}); // data: [
// ["Y61", "37%", "62%", "97%", "7%"],
// ["Y62", "95%", "10%", "99%", "3%"],
// ["Y63", "68%", "1%", "92%", "4%"],
// ["Y64", "94%", "21%", "97%", "2%"],
// ["Y65", "99%", "30%", "95%", "5%"],
// ],
};
return ( return (
<div className={cls.todayTableData}> <div className={cls.todayTableData}>
<ScrollBoard config={config} style={{ width: "100%" }} /> {config.data.length != 0 && (
<ScrollBoard
className={cls.paddingCeil}
config={config}
style={{ width: "100%", color: "#fffc" }}
/>
)}
{config.data.length == 0 && (
<p
style={{
color: "#cccf",
fontSize: "24px",
userSelect: "none",
textAlign: "center",
paddingTop: "48px",
}}
>
暂无数据
</p>
)}
</div> </div>
); );
}; };

View File

@@ -0,0 +1,40 @@
// import cls from "./index.module.css";
import "./video-monitor.css";
function VideoMonitor(props) {
return (
<div className="video-monitor">
<h2>泡界线监控</h2>
<div className="video-container">
<div>
{/* <video muted autoPlay loop src="https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"></video> */}
<img
style={{
width: "100%",
height: "100%",
display: "block",
margin: "auto",
backgrounColor: "hsl(0, 0%, 25%)",
}}
src="http://10.70.180.10:8001/video_feed"
></img>
</div>
<div>
{/* <video muted autoPlay loop src="https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"></video> */}
<img
style={{
width: "100%",
height: "100%",
display: "block",
margin: "auto",
backgrounColor: "hsl(0, 0%, 25%)",
}}
src="http://10.70.180.10:8000/video_feed"
></img>
</div>
</div>
</div>
);
}
export default VideoMonitor;

View File

@@ -0,0 +1,35 @@
.video-monitor {
display: flex;
flex-direction: column;
margin-left: 80px;
height: 200px;
width: 500px;
}
.video-monitor > h2 {
margin: 0;
padding: 10px 0;
background: #16253c;
color: #fff;
font-weight: 400;
letter-spacing: 2px;
font-size: 18px;
text-align: center;
}
.video-monitor > .video-container {
display: flex;
gap: 8px;
flex: 1;
max-height: 150px;
}
.video-container > div {
flex: 1;
height: 100%;
background: #ccc1;
}
.video-container > div > video {
width: 100%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,130 @@
import WarnAlert from ".";
import { useSelector } from "react-redux";
import posMap from "./position.json";
const total = `AN_1_1,助燃风故障报警
AN_1_2,压延机冷却风故障报警
AN_1_3,L吊墙冷却风机故障报警
AN_1_4,熔化带及部分澄清部冷却风机故障报警
AN_2_1,澄清带池壁冷却风机故障报警
AN_2_2,钢碴碴冷却风机故障报警
AN_2_3,支通路拐角冷却风机报警
AN_2_4,吊墙吊钩砖结构温升报警
AN_3_1,深层水包冷却水温升报警
AN_3_2,深层水包冷却水断水报警
AN_3_3,卡脖吊平冷却水断水报警
AN_3_4,卡脖吊平喧冷却水温升报警
AN_4_1,液面计冷却水断水报警
AN_4_2,液面计冷却水温升报警
AN_4_3,循环水入口压力低报警
AN_4_4,天然气压力高低报警
AN_5_1,助燃风风压低报警
AN_5_2,净化压缩气压力低报警
AN_5_3,普通压缩空气压力高低报警
AN_5_4,焦炉煤气气压力高低报警
AN_6_1,换向过程故障报警
AN_6_2,空交机换向不到位报警
AN_6_3,投料机故障报警
AN_6_4,备用
AN_7_1,1#压延机冷却水断水报警
AN_7_2,1#压延机冷却水温升报警
AN_7_3,1#过渡辊台冷却水断水报警
AN_7_4,1过渡辊台冷却水温升报警
AN_8_1,1#线唇砖冷却水断水报警
AN_8_2,1#线唇砖冷却水温升报警
AN_8_3,1#退火窑A区风机报警
AN_8_4,1#退火窑B区风机报警
AN_9_1,1#退火窑c区风机报警
AN_9_2,1#退火窑Ret1区风机报警
AN_9_3,1#退火窑Ret2区风机报警
AN_9_4,1#退火窑F1区风机报警
AN_10_1,1#退火窑F2区风机报警
AN_10_2,1#主传动报警
AN_10_3,1#压延机报警
AN_10_4,备用
AN_11_1,2#压延机冷却水断水报警
AN_11_2,2#压延机冷却水温升报警
AN_11_3,2#过渡辊台冷却水断水报警
AN_11_4,2#过渡辊台冷却水温升报警
AN_12_1,2#线唇砖冷却水断水报警
AN_12_2,2#线唇砖冷却水温升报警
AN_12_3,2#退火窑A区风机报警
AN_12_4,2#退火窑B区风机报警
AN_13_1,2#退火窑c区风机报警
AN_13_2,2#退火窑Ret1区风机报警
AN_13_3,2#退火窑Ret2区风机报警
AN_13_4,2#退火窑F1区风机报警
AN_14_1,2#退火窑F2区风机报警
AN_14_2,2#主传动报警
AN_14_3,2#压延机报警
AN_14_4,备用
AN_15_1,3#压延机冷却水断水报警
AN_15_2,3压延机冷却水温升报警
AN_15_3,3#过渡辊台冷却水断水报警
AN_15_4,3#过渡辊台冷却水温升报警
AN_16_1,3#线唇砖冷却水断水报警
AN_16_2,3#线唇砖冷却水温升报警
AN_16_3,3#退火窑A区风机报警
AN_16_4,3#退火窑B区风机报警
AN_17_1,3#退火窑c区风机报警
AN_17_2,3#退火窑Ret1区风机报警
AN_17_3,3#退火窑Ret2区风机报警
AN_17_4,3#退火窑F1区风机报警
AN_18_1,3#退火窑F2区风机报警
AN_18_2,3#主传动报警
AN_18_3,3#压延机报警
AN_18_4,备用
AN_19_1,4#压延机冷却水断水报警
AN_19_2,4压延机冷却水温升报警
AN_19_3,4#过渡辊台冷却水断水报警
AN_19_4,4#过渡辊台冷却水温升报警
AN_20_1,4#线唇砖冷却水断水报警
AN_20_2,4#线唇砖冷却水温升报警
AN_20_3,4#退火窑A区风机报警
AN_20_4,4#退火窑B区风机报警
AN_21_1,4#退火窑c区风机报警
AN_21_2,4#退火窑Ret1区风机报警
AN_21_3,4#退火窑Ret2区风机报警
AN_21_4,4#退火窑F1区风机报警
AN_22_1,4#退火窑F2区风机报警
AN_22_2,4#主传动报警
AN_22_3,4#压延机报警
AN_23_1,5#压延机冷却水断水报警
AN_23_2,5#压延机冷却水温升报警
AN_23_3,5#过渡辊台冷却水断水报警
AN_23_4,5#过渡台冷却水温升报警
AN_24_1,5#线唇砖冷却水断水报警
AN_24_2,5#线唇砖冷却水温升报警
AN_24_3,5#退火窑A区风机报警
AN_24_4,5#退火窑B区风机报警
AN_25_1,5#退火窑c区风机报警
AN_25_2,5#退火窑Ret1区风机报警
AN_25_3,5#退火窑Ret2区风机报警
AN_25_4,5#退火窑F1区风机报警
AN_26_1,5#退火窑F2区风机报警
AN_26_2,5#主传动报警
AN_26_3,5#压延机报警
`;
function AlarmListContainer(props) {
const alarmList = useSelector((state) => state.alarm.list);
// const alarmList = total
// .split("\n")
// .filter((str) => str.trim())
// .map((item) => ({
// id: item.split(",")[0],
// title: item.split(",")[0],
// content: item.split(",")[1],
// }));
return alarmList.map((alarm) => (
<WarnAlert
key={alarm.id}
title={alarm.title}
content={alarm.content}
x={posMap[alarm.title]?.x || 0}
y={posMap[alarm.title]?.y || 0}
/>
));
}
export default AlarmListContainer;

View File

@@ -0,0 +1,18 @@
// import cls from "./index.module.css";
import "./warn-alert.css";
import AlertIcon from "./warn-icon.png";
function WarnAlert(props) {
const { x, y, title, content } = props;
return (
<div className="warn-alert" style={{ top: `${y}px`, left: `${x}px` }}>
<h1 className="">
<img src={AlertIcon} width={24} alt="icon" />
{title || "test"}
</h1>
<p>{content || "Lorem ipsum dolor sit amet consectetur."}</p>
</div>
);
}
export default WarnAlert;

View File

@@ -0,0 +1,104 @@
{
"AN_1_1": { "x": 650, "y": 645 },
"AN_1_2": { "x": 1450, "y": 540 },
"AN_1_3": { "x": 640, "y": 285 },
"AN_1_4": { "x": 720, "y": 645 },
"AN_2_1": { "x": 1250, "y": 540 },
"AN_2_2": { "x": 1200, "y": 540 },
"AN_2_3": { "x": 1460, "y": 410 },
"AN_2_4": { "x": 650, "y": 420 },
"AN_3_1": { "x": 1360, "y": 380 },
"AN_3_2": { "x": 1360, "y": 380 },
"AN_3_3": { "x": 1360, "y": 420 },
"AN_3_4": { "x": 1360, "y": 420 },
"AN_4_1": { "x": 1350, "y": 460 },
"AN_4_2": { "x": 1350, "y": 460 },
"AN_4_3": { "x": 1270, "y": 320 },
"AN_4_4": { "x": 900, "y": 420 },
"AN_5_1": { "x": 650, "y": 645 },
"AN_5_2": { "x": 980, "y": 420 },
"AN_5_3": { "x": 1050, "y": 420 },
"AN_5_4": { "x": 1130, "y": 420 },
"AN_6_1": { "x": 1220, "y": 420 },
"AN_6_2": { "x": 1290, "y": 420 },
"AN_6_3": { "x": 650, "y": 440 },
"AN_6_4": { "x": 1400, "y": 650 },
"AN_7_1": { "x": 1450, "y": 540 },
"AN_7_2": { "x": 1450, "y": 540 },
"AN_7_3": { "x": 1470, "y": 540 },
"AN_7_4": { "x": 1470, "y": 540 },
"AN_8_1": { "x": 1470, "y": 540 },
"AN_8_2": { "x": 1470, "y": 540 },
"AN_8_3": { "x": 1480, "y": 540 },
"AN_8_4": { "x": 1580, "y": 540 },
"AN_9_1": { "x": 1700, "y": 540 },
"AN_9_2": { "x": 1760, "y": 540 },
"AN_9_3": { "x": 1780, "y": 540 },
"AN_9_4": { "x": 1780, "y": 540 },
"AN_10_1": { "x": 1780, "y": 540 },
"AN_10_2": { "x": 1390, "y": 540 },
"AN_10_3": { "x": 1450, "y": 540 },
"AN_10_4": { "x": 1400, "y": 650 },
"AN_11_1": { "x": 1450, "y": 480 },
"AN_11_2": { "x": 1450, "y": 480 },
"AN_11_3": { "x": 1450, "y": 480 },
"AN_11_4": { "x": 1450, "y": 480 },
"AN_12_1": { "x": 1450, "y": 480 },
"AN_12_2": { "x": 1450, "y": 480 },
"AN_12_3": { "x": 1550, "y": 480 },
"AN_12_4": { "x": 1650, "y": 480 },
"AN_13_1": { "x": 1750, "y": 480 },
"AN_13_2": { "x": 1850, "y": 480 },
"AN_13_3": { "x": 1900, "y": 480 },
"AN_13_4": { "x": 1910, "y": 480 },
"AN_14_1": { "x": 1920, "y": 480 },
"AN_14_2": { "x": 1450, "y": 480 },
"AN_14_3": { "x": 1450, "y": 480 },
"AN_14_4": { "x": 1400, "y": 650 },
"AN_15_1": { "x": 1450, "y": 430 },
"AN_15_2": { "x": 1450, "y": 430 },
"AN_15_3": { "x": 1470, "y": 430 },
"AN_15_4": { "x": 1470, "y": 430 },
"AN_16_1": { "x": 1470, "y": 430 },
"AN_16_2": { "x": 1470, "y": 430 },
"AN_16_3": { "x": 1600, "y": 430 },
"AN_16_4": { "x": 1700, "y": 430 },
"AN_17_1": { "x": 1800, "y": 430 },
"AN_17_2": { "x": 1900, "y": 430 },
"AN_17_3": { "x": 1950, "y": 430 },
"AN_17_4": { "x": 1960, "y": 430 },
"AN_18_1": { "x": 1970, "y": 430 },
"AN_18_2": { "x": 1450, "y": 430 },
"AN_18_3": { "x": 1450, "y": 430 },
"AN_18_4": { "x": 1400, "y": 650 },
"AN_19_1": { "x": 1450, "y": 370 },
"AN_19_2": { "x": 1450, "y": 370 },
"AN_19_3": { "x": 1460, "y": 370 },
"AN_19_4": { "x": 1460, "y": 370 },
"AN_20_1": { "x": 1460, "y": 370 },
"AN_20_2": { "x": 1460, "y": 370 },
"AN_20_3": { "x": 1500, "y": 370 },
"AN_20_4": { "x": 1600, "y": 370 },
"AN_21_1": { "x": 1700, "y": 370 },
"AN_21_2": { "x": 1800, "y": 370 },
"AN_21_3": { "x": 1850, "y": 370 },
"AN_21_4": { "x": 1860, "y": 370 },
"AN_22_1": { "x": 1870, "y": 370 },
"AN_22_2": { "x": 1450, "y": 370 },
"AN_22_3": { "x": 1460, "y": 370 },
"AN_23_1": { "x": 1460, "y": 320 },
"AN_23_2": { "x": 1460, "y": 320 },
"AN_23_3": { "x": 1465, "y": 320 },
"AN_23_4": { "x": 1465, "y": 320 },
"AN_24_1": { "x": 1465, "y": 320 },
"AN_24_2": { "x": 1465, "y": 320 },
"AN_24_3": { "x": 1480, "y": 320 },
"AN_24_4": { "x": 1580, "y": 320 },
"AN_25_1": { "x": 1680, "y": 320 },
"AN_25_2": { "x": 1780, "y": 320 },
"AN_25_3": { "x": 1750, "y": 320 },
"AN_25_4": { "x": 1760, "y": 320 },
"AN_26_1": { "x": 1770, "y": 320 },
"AN_26_2": { "x": 1430, "y": 320 },
"AN_26_3": { "x": 1460, "y": 320 }
}

View File

@@ -0,0 +1,65 @@
.warn-alert {
position: fixed;
top: 200px;
left: 200px;
/* height: 72px; */
z-index: 10000;
display: inline-block;
/* background: url(../../../assets/warn-bg.png) 0 0 / 116px 100% repeat-x; */
background: url(./3.png) 0 0 / 116px 100% repeat-x;
box-shadow: 0 0 24px 6px rgba(0, 0, 0, 0.5);
user-select: none;
transform: scale(1);
cursor: pointer;
}
.warn-alert:hover {
transform: scale(1.1);
box-shadow: 0 0 32px 12px rgba(0, 0, 0, 0.5);
z-index: 10001;
}
.warn-alert::before {
box-sizing: border-box;
content: "";
position: absolute;
top: 0;
left: -24px;
width: 24px;
height: 100%;
display: inline-block;
border: 12px solid transparent;
border-right-color: #ff2c2c;
}
.warn-alert::after {
box-sizing: border-box;
content: "";
position: absolute;
top: 0;
right: -24px;
width: 24px;
height: 100%;
display: inline-block;
border: 12px solid transparent;
border-left-color: #ff2c2c;
}
.warn-alert > h1 {
display: flex;
margin: 8px 0 0;
align-items: center;
color: #fff;
font-size: 16px;
text-transform: uppercase;
}
.warn-alert > h1 img {
padding-top: 3px;
margin-left: 10px;
}
.warn-alert > p {
color: #fff;
margin: 0 22px 16px 14px;
font-size: 14px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -1,21 +1,42 @@
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from "react";
import useIcon from '../hooks/useIcon'; import useIcon from "../hooks/useIcon";
import cls from './container.module.scss'; import cls from "./container.module.scss";
const Container = (props) => { const Container = (props) => {
let icon = useIcon(props.icon); let icon = useIcon(props.icon);
const desc = props.desc;
return ( return (
<div className={`${cls.container} ${props.className}`} style={props.style}> <div
className={`${cls.container} ${props.className}`}
style={props.pending ? { filter: "grayscale(100%)" } : props.style}
>
<div className={cls.container__head}> <div className={cls.container__head}>
<img <img
src={icon} src={icon}
alt="#" alt="#"
className={props.icon == 'kiln' ? cls.bigger : ''} className={props.icon == "kiln" ? cls.bigger : ""}
/> />
<h2>{props.title}</h2> <h2>{props.title}</h2>
{desc && <div className={cls.graphBaseDesc}>{desc}</div>}
</div> </div>
<div className={cls.container__content}>{props.children}</div> <div className={cls.container__content}>{props.children}</div>
{props.pending && (
<div
className={`${cls.container__content} pending-modal`}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
borderRadius: "20px",
userSelect: "none",
cursor: "not-allowed",
}}
></div>
)}
</div> </div>
); );
}; };

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