13 Commits

Author SHA1 Message Date
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
67 changed files with 1263 additions and 862 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

View File

@@ -70,6 +70,7 @@
"scripts": { "scripts": {
"start": "node scripts/start.js", "start": "node scripts/start.js",
"build": "node scripts/build.js", "build": "node scripts/build.js",
"server": "node websocket/server.js",
"test": "node scripts/test.js" "test": "node scripts/test.js"
}, },
"eslintConfig": { "eslintConfig": {

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.

View File

@@ -11,7 +11,7 @@ import { Switch } from "antd";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
const Menus = ["窑炉总览", "窑炉内部", "退火监测", "质检统计", "能耗分析"]; 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("窑炉总览");
@@ -22,7 +22,7 @@ function App() {
if (lunbo) { if (lunbo) {
timer = setInterval(() => { timer = setInterval(() => {
handleMenuChange(Menus[(Menus.indexOf(navActive) + 1) % Menus.length]); handleMenuChange(Menus[(Menus.indexOf(navActive) + 1) % Menus.length]);
}, 5000); }, LUNBO_INTERVAL);
} }
return () => { return () => {
clearInterval(timer); clearInterval(timer);

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 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

@@ -109,6 +109,7 @@ function WindFrequence(props) {
}, },
}; };
} else { } else {
console.log('runstate changeD!......')
dataList = dataList =
runState != null runState != null
? Object.keys(runState).map((fan) => ({ ? Object.keys(runState).map((fan) => ({

View File

@@ -57,7 +57,7 @@ function WindFrequence(props) {
currentTempList[1 + lines.indexOf(dataSource) + "#"]) || currentTempList[1 + lines.indexOf(dataSource) + "#"]) ||
[] []
); );
}, [dataSource]); }, [dataSource, currentTempList]);
return ( return (
<GraphBase <GraphBase

View File

@@ -35,10 +35,10 @@ const EnergyCostRealtime = () => {
paddingRight: "6px", paddingRight: "6px",
}} }}
> >
余热发电(实时) 余热发电(昨日)
</i> </i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}> <span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty2)?.toFixed(2) || 0}kWh {(+energyInfo?.elecQty1)?.toFixed(2) || 0}kWh
</span> </span>
</div> </div>
@@ -66,7 +66,7 @@ const EnergyCostRealtime = () => {
paddingRight: "6px", paddingRight: "6px",
}} }}
> >
水耗量 水耗量(昨日)
</i> </i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}> <span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.waterQty)?.toFixed(2) || 0}Km³ {(+energyInfo?.waterQty)?.toFixed(2) || 0}Km³
@@ -80,7 +80,7 @@ const EnergyCostRealtime = () => {
paddingRight: "6px", paddingRight: "6px",
}} }}
> >
天然气I 天然气I(累计)
</i> </i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}> <span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{energyInfo?.ngQty1 || "0Nm³"} {energyInfo?.ngQty1 || "0Nm³"}
@@ -94,7 +94,7 @@ const EnergyCostRealtime = () => {
paddingRight: "6px", paddingRight: "6px",
}} }}
> >
电耗量 电耗量(昨日)
</i> </i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}> <span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{(+energyInfo?.elecQty2)?.toFixed(2) || 0}kWh {(+energyInfo?.elecQty2)?.toFixed(2) || 0}kWh
@@ -108,7 +108,7 @@ const EnergyCostRealtime = () => {
paddingRight: "6px", paddingRight: "6px",
}} }}
> >
天然气II 天然气II(累计)
</i> </i>
<span style={{ fontSize: "17px", color: "#3ce8ff" }}> <span style={{ fontSize: "17px", color: "#3ce8ff" }}>
{energyInfo?.ngQty2 || "0Nm³"} {energyInfo?.ngQty2 || "0Nm³"}

View File

@@ -44,6 +44,7 @@ function GraphBase(props) {
selectWidth, 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);
@@ -72,9 +73,9 @@ function GraphBase(props) {
<span <span
style={{ style={{
color: "#fff", color: "#fff",
fontSize: "14px", fontSize: "calc(14px * var(--scale))",
lineHeight: 1, lineHeight: 1,
paddingLeft: "12px", paddingLeft: "calc(12px * var(--scale))",
}} }}
> >
- - - -
@@ -105,7 +106,7 @@ 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}>{desc}</div>} {desc && <div className={`${cls.graphBaseDesc} ${descSmall ? cls.graphBaseDescSmall : ''}`}>{desc}</div>}
</div> </div>
<div className={cls.graphBaseContent}> <div className={cls.graphBaseContent}>
{switchOptions && ( {switchOptions && (

View File

@@ -93,6 +93,11 @@
color: #76fff9; color: #76fff9;
} }
.graphBaseDescSmall {
font-size: 16px;
color: #76fff9;
}
.graphBaseSwitch { .graphBaseSwitch {
position: absolute; position: absolute;
top: 30px; top: 30px;

View File

@@ -9,6 +9,7 @@
.xc-date-selector-menu .ant-select-item-option-content { .xc-date-selector-menu .ant-select-item-option-content {
text-align: center; text-align: center;
font-size: calc(14px * var(--scale));
} }
.xc-date-selector-menu .ant-select-item-option-selected { .xc-date-selector-menu .ant-select-item-option-selected {
@@ -20,10 +21,16 @@
background-color: #02457E !important; background-color: #02457E !important;
color: #fff !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 { .ant-select-selector::after {
content: '\25BC' !important; content: '\25BC' !important;
visibility: visible !important; visibility: visible !important; L
position: absolute; position: absolute;
top: 2px; top: 2px;
right: 22px; right: 22px;

View File

@@ -1,5 +1,4 @@
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 = [

View File

@@ -33,9 +33,9 @@ const SmokeTrendChart = (props) => {
switch (period) { switch (period) {
case "day": case "day":
setDesc( setDesc(
dayjs().subtract(1, "day").format("YYYY.MM.DD") + dayjs().format("YYYY.MM.DD") +
" 7点 - " + " 7点 - " +
dayjs().format("YYYY.MM.DD") + dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点" " 7点"
); );
break; break;

View File

@@ -33,10 +33,9 @@ function FaultTotal(props) {
// time hint // time hint
let timeDesc = ""; let timeDesc = "";
const now = new Date();
switch (currentSelect) { switch (currentSelect) {
case "日": case "日":
timeDesc = dayjs().subtract(1, 'day').format('YYYY.MM.DD') + " 7点 - " + dayjs().format('YYYY.MM.DD') + " 7点"; timeDesc = dayjs().format('YYYY.MM.DD') + " 7点 - " + dayjs().add(1, 'day').format('YYYY.MM.DD') + " 7点";
break; break;
case "周": case "周":
timeDesc = dayjs().subtract(7, 'day').format('YYYY.MM.DD') + " - " + dayjs().subtract(1, 'day').format('YYYY.MM.DD') ; timeDesc = dayjs().subtract(7, 'day').format('YYYY.MM.DD') + " - " + dayjs().subtract(1, 'day').format('YYYY.MM.DD') ;
@@ -52,7 +51,6 @@ function FaultTotal(props) {
<GraphBase <GraphBase
icon="chart" icon="chart"
title="产线缺陷统计" title="产线缺陷统计"
dateOptions={["日", "周", "月", "年"]}
defaultSelect={currentSelect} defaultSelect={currentSelect}
onDateChange={handleDateChange} onDateChange={handleDateChange}
size={bgSize} size={bgSize}

View File

@@ -3,8 +3,8 @@ import GraphBase from "../GraphBase";
import ReactECharts from "echarts-for-react"; import ReactECharts from "echarts-for-react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { randomInt } from "../../../utils";
import * as echarts from "echarts"; import * as echarts from "echarts";
import dayjs from "dayjs";
function FaultType(props) { function FaultType(props) {
const [init, setInit] = useState(true); const [init, setInit] = useState(true);
@@ -17,6 +17,11 @@ function FaultType(props) {
: []; : [];
const lines = currentStatistic.map((item) => item.name); const lines = currentStatistic.map((item) => item.name);
const CHART_TYPE = "line"; // "pie" | "line"; const CHART_TYPE = "line"; // "pie" | "line";
const timestr =
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "d").format("YYYY.MM.DD") +
" 7点";
useEffect(() => { useEffect(() => {
if (init == false) return; if (init == false) return;
@@ -47,6 +52,8 @@ function FaultType(props) {
<GraphBase <GraphBase
icon="default" icon="default"
title="产线当日缺陷分类" title="产线当日缺陷分类"
desc={timestr}
descSmall={true}
dateOptions={[...lines]} dateOptions={[...lines]}
defaultSelect={currentLine} defaultSelect={currentLine}
onDateChange={handleLineChange} onDateChange={handleLineChange}
@@ -146,7 +153,7 @@ function getOptions(data, chart_type) {
axisPointer: { axisPointer: {
type: "shadow", type: "shadow",
}, },
symbol: 'rect', symbol: "rect",
className: "xc-chart-tooltip", className: "xc-chart-tooltip",
// backgroundColor: '' // backgroundColor: ''
}, },
@@ -210,7 +217,9 @@ function getOptions(data, chart_type) {
color: "#fffc", color: "#fffc",
}, },
data: (dataList || []).map((item) => data: (dataList || []).map((item) =>
item.value == null || isNaN(+item.value) ? null : (+item.value).toFixed(0) item.value == null || isNaN(+item.value)
? null
: (+item.value).toFixed(0)
), ),
}, },
], ],

View File

@@ -29,9 +29,9 @@ const GoodRateChart = (props) => {
} }
const [timestr, setTimestr] = useState( const [timestr, setTimestr] = useState(
dayjs().subtract(1, "day").format("YYYY.MM.DD") + dayjs().format("YYYY.MM.DD") +
" 7点 - " + " 7点 - " +
dayjs().format("YYYY.MM.DD") + dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点" " 7点"
); );
function handleDateChange(value) { function handleDateChange(value) {
@@ -40,9 +40,9 @@ const GoodRateChart = (props) => {
switch (value) { switch (value) {
case "日": case "日":
setTimestr( setTimestr(
dayjs().subtract(1, "day").format("YYYY.MM.DD") + dayjs().format("YYYY.MM.DD") +
" 7点 - " + " 7点 - " +
dayjs().format("YYYY.MM.DD") + dayjs().add(1, "day").format("YYYY.MM.DD") +
" 7点" " 7点"
); );
break; break;

View File

@@ -0,0 +1,16 @@
// 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></div>
<div></div>
</div>
</div>
);
}
export default VideoMonitor;

View File

@@ -0,0 +1,30 @@
.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;
}
.video-container > div {
flex: 1;
height: 100%;
background: #ccc1;
}

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(0.64);
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

@@ -2,33 +2,40 @@ import cls from "./index.module.css";
import GradientText from "../../../Common/GradientText"; import GradientText from "../../../Common/GradientText";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import eIcon1 from "../../../../assets/Icon/dontknowwhatitis.png";
import eIcon2 from "../../../../assets/Icon/lightnen.png";
function Energy(props) { function Energy(props) {
const [isPage1, setIsPage1] = useState(true); const [isPage1] = useState(props.page === 1);
const energyInfo = useSelector((state) => state.energy?.info); const energyInfo = useSelector((state) => state.energy?.info);
useEffect(() => { // useEffect(() => {
const timer = setInterval(() => { // const timer = setInterval(() => {
setIsPage1((pre) => !pre); // setIsPage1((pre) => !pre);
}, 10000); // }, 10000);
return () => { // return () => {
clearInterval(timer); // clearInterval(timer);
} // }
}, []); // }, []);
return ( return (
<div className={" " + cls.layout} style={{ color: "#fff" }}> <div className={" " + cls.layout} style={{ color: "#fff" }}>
<span <span
className={cls.shadowBorder} className={`${cls.shadowBorder} ${cls.border}`}
style={{ style={{
gridRow: "1 / 3", gridRow: "1 / 3",
paddingTop: "104px",
paddingLeft: "32px",
userSelect: "none", userSelect: "none",
textAlign: "center",
paddingTop: "96px",
}} }}
> >
<GradientText text="能源" /> {isPage1 ? (
<img src={eIcon1} width={32} alt="eicon1" />
) : (
<img src={eIcon2} width={32} alt="eicon2" />
)}
<GradientText text={"\u2002\u2002能源"} />
</span> </span>
{!isPage1 && ( {!isPage1 && (
<div <div
@@ -65,7 +72,9 @@ function Energy(props) {
{(+energyInfo?.elecQty7)?.toFixed(2) || 0} {(+energyInfo?.elecQty7)?.toFixed(2) || 0}
</span> </span>
</div> </div>
<div className={cls.shadowBorder + " " + cls.infoText}> <div
className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}
>
<span style={{ lineHeight: 1.5 }}>智慧能源光伏发电(总量)/kWh</span> <span style={{ lineHeight: 1.5 }}>智慧能源光伏发电(总量)/kWh</span>
<span <span
style={{ style={{
@@ -77,7 +86,9 @@ function Energy(props) {
{(+energyInfo?.elecQty4)?.toFixed(2) || 0} {(+energyInfo?.elecQty4)?.toFixed(2) || 0}
</span> </span>
</div> </div>
<div className={cls.shadowBorder + " " + cls.infoText}> <div
className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}
>
<span style={{ lineHeight: 1.5 }}>许昌安彩光伏发电(总量)/kWh</span> <span style={{ lineHeight: 1.5 }}>许昌安彩光伏发电(总量)/kWh</span>
<span <span
style={{ style={{
@@ -105,7 +116,7 @@ function Energy(props) {
style={{ flex: 1 }} style={{ flex: 1 }}
className={cls.shadowBorder + " " + cls.infoText} className={cls.shadowBorder + " " + cls.infoText}
> >
<span style={{ lineHeight: 1.5 }}>余热发电(实时)/kWh</span> <span style={{ lineHeight: 1.5 }}>余热发电(昨日)/kWh</span>
<span <span
style={{ style={{
lineHeight: 1.5, lineHeight: 1.5,
@@ -118,7 +129,9 @@ function Energy(props) {
</div> </div>
<div <div
style={{ flex: 1 }} style={{ flex: 1 }}
className={cls.shadowBorder + " " + cls.infoText} className={
cls.shadowBorder + " " + cls.infoText + " " + cls.border
}
> >
<span style={{ lineHeight: 1.5 }}>余热发电(总量)/kWh</span> <span style={{ lineHeight: 1.5 }}>余热发电(总量)/kWh</span>
<span <span
@@ -133,25 +146,29 @@ function Energy(props) {
</div> </div>
</div> </div>
<span className={cls.shadowBorder + " " + cls.infoText}> <span className={cls.shadowBorder + " " + cls.infoText}>
<span style={{ lineHeight: 1.5 }}>水耗量/Km³</span> <span style={{ lineHeight: 1.5 }}>水耗量(昨日)/Km³</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{(+energyInfo?.waterQty)?.toFixed(2) || 0} {(+energyInfo?.waterQty)?.toFixed(2) || 0}
</span> </span>
</span> </span>
<span className={cls.shadowBorder + " " + cls.infoText}> <span className={cls.shadowBorder + " " + cls.infoText}>
<span style={{ lineHeight: 1.5 }}>天然气I/Nm³</span> <span style={{ lineHeight: 1.5 }}>天然气I(累计)/Nm³</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{energyInfo?.ngQty1?.replace("Nm³", "") || "0Nm³"} {energyInfo?.ngQty1?.replace("Nm³", "") || "0Nm³"}
</span> </span>
</span> </span>
<span className={cls.shadowBorder + " " + cls.infoText}> <span
<span style={{ lineHeight: 1.5 }}>电耗量/kWh</span> className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}
>
<span style={{ lineHeight: 1.5 }}>电耗量(昨日)/kWh</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{(+energyInfo?.elecQty2)?.toFixed(2) || 0} {(+energyInfo?.elecQty2)?.toFixed(2) || 0}
</span> </span>
</span> </span>
<span className={cls.shadowBorder + " " + cls.infoText}> <span
<span style={{ lineHeight: 1.5 }}>天然气II/Nm³</span> className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}
>
<span style={{ lineHeight: 1.5 }}>天然气II(累计)/Nm³</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{energyInfo?.ngQty2?.replace("Nm³", "") || "0Nm³"} {energyInfo?.ngQty2?.replace("Nm³", "") || "0Nm³"}
</span> </span>

View File

@@ -4,7 +4,8 @@
/* grid-template-columns: 133px 158px 292px 292px; */ /* grid-template-columns: 133px 158px 292px 292px; */
grid-template-columns: 125px 250px 250px 250px; grid-template-columns: 125px 250px 250px 250px;
/* grid-template-rows: 60px 60px; */ /* grid-template-rows: 60px 60px; */
grid-template-rows: 129px 129px; grid-template-rows: auto;
height: 100%;
} }
.shadowBorder { .shadowBorder {
@@ -13,6 +14,29 @@
padding: 4px; padding: 4px;
} }
.shadowBorder.border {
position: relative;
border-bottom: 2px solid #00fff7;
}
.shadowBorder.border::before,
.shadowBorder.border::after {
content: "";
position: absolute;
bottom: 0;
display: inline-block;
height: 100%;
width: 2px;
background: linear-gradient(to top, #00fff7, #00fff708, transparent);
}
.shadowBorder.border::before {
left: 0;
}
.shadowBorder.border::after {
right: 0;
}
.infoText { .infoText {
text-align: center; text-align: center;
font-size: 22px; font-size: 22px;
@@ -27,6 +51,6 @@
} }
.infoText > span:last-child { .infoText > span:last-child {
color: #00FFF7; color: #00fff7;
font-size: 24px; font-size: 24px;
} }

View File

@@ -6,17 +6,38 @@ import { useState } from "react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import dayjs from "dayjs"; import dayjs from "dayjs";
function getTimeStr(period) {
return {
:
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "d").format("YYYY.MM.DD") +
" 7点",
:
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",
}[period];
}
function NO(props) { function NO(props) {
const dayTrend = useSelector((state) => state.smoke?.dayTrend); const dayTrend = useSelector((state) => state.smoke?.dayTrend);
const weekTrend = useSelector((state) => state.smoke?.weekTrend); const weekTrend = useSelector((state) => state.smoke?.weekTrend);
const monthTrend = useSelector((state) => state.smoke?.monthTrend); const monthTrend = useSelector((state) => state.smoke?.monthTrend);
const yearTrend = useSelector((state) => state.smoke?.yearTrend); const yearTrend = useSelector((state) => state.smoke?.yearTrend);
const [period, setPeriod] = useState("日"); const [period, setPeriod] = useState("日");
const [timestr, setTimestr] = useState(
dayjs().subtract(7, "day").format("YYYY.MM.DD") + let timestr = getTimeStr(period);
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
const currentTrend = const currentTrend =
period === "日" period === "日"
@@ -33,35 +54,13 @@ function NO(props) {
function handleDateChange(value) { function handleDateChange(value) {
setPeriod(value); setPeriod(value);
setTimestr( timestr = getTimeStr(value);
{
:
dayjs().subtract(1, "day").format("YYYY.MM.DD") +
" 7点 - " +
dayjs().format("YYYY.MM.DD") +
" 7点",
:
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 (
<GraphBase <GraphBase
icon="smoke" icon="smoke"
title="氮氧化物" title="氮氧化物"
desc={`能耗趋势图 ${timestr}`} desc={`烟气趋势图 ${timestr}`}
switchOptions={false} switchOptions={false}
defaultSelect={period} defaultSelect={period}
onSwitch={handleSwitch} onSwitch={handleSwitch}

View File

@@ -6,17 +6,38 @@ import { useState } from "react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import dayjs from "dayjs"; import dayjs from "dayjs";
function getTimeStr(period) {
return {
:
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, 'd').format("YYYY.MM.DD") +
" 7点",
:
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",
}[period];
}
function Dust(props) { function Dust(props) {
const dayTrend = useSelector((state) => state.smoke?.dayTrend); const dayTrend = useSelector((state) => state.smoke?.dayTrend);
const weekTrend = useSelector((state) => state.smoke?.weekTrend); const weekTrend = useSelector((state) => state.smoke?.weekTrend);
const monthTrend = useSelector((state) => state.smoke?.monthTrend); const monthTrend = useSelector((state) => state.smoke?.monthTrend);
const yearTrend = useSelector((state) => state.smoke?.yearTrend); const yearTrend = useSelector((state) => state.smoke?.yearTrend);
const [period, setPeriod] = useState("日"); const [period, setPeriod] = useState("日");
const [timestr, setTimestr] = useState(
dayjs().subtract(7, "day").format("YYYY.MM.DD") + let timestr = getTimeStr(period);
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
const currentTrend = const currentTrend =
period === "日" period === "日"
? dayTrend ? dayTrend
@@ -32,36 +53,14 @@ function Dust(props) {
function handleDateChange(value) { function handleDateChange(value) {
setPeriod(value); setPeriod(value);
setTimestr( timestr = getTimeStr(value);
{
:
dayjs().subtract(1, "day").format("YYYY.MM.DD") +
" 7点 - " +
dayjs().format("YYYY.MM.DD") +
" 7点",
:
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 (
<GraphBase <GraphBase
icon="smoke" icon="smoke"
title="颗粒物" title="颗粒物"
desc={`能耗趋势图 ${timestr}`} desc={`烟气趋势图 ${timestr}`}
switchOptions={false} switchOptions={false}
defaultSelect={period} defaultSelect={period}
onSwitch={handleSwitch} onSwitch={handleSwitch}

View File

@@ -8,7 +8,8 @@ import { lunarYear } from "../../../../utils/energeChartOption";
import dayjs from "dayjs"; import dayjs from "dayjs";
function NatGas(props) { function NatGas(props) {
const elecTrend = useSelector((state) => state.energy.trend.natGas1); const natGasTrend = useSelector((state) => state.energy.trend.natGas1);
const gasTrend = useSelector((state) => state.energy.trend.natGas2);
const [period, setPeriod] = useState("周"); const [period, setPeriod] = useState("周");
const [timestr, setTimestr] = useState( const [timestr, setTimestr] = useState(
dayjs().subtract(7, "day").format("YYYY.MM.DD") + dayjs().subtract(7, "day").format("YYYY.MM.DD") +
@@ -18,7 +19,7 @@ function NatGas(props) {
const options = getOptions( const options = getOptions(
{ : "week", : "month", : "year" }[period], { : "week", : "month", : "year" }[period],
elecTrend ?? { week: [], month: [], year: [] } [natGasTrend, gasTrend] ?? { week: [], month: [], year: [] }
); );
function handleSwitch(v) { function handleSwitch(v) {
@@ -50,7 +51,7 @@ function NatGas(props) {
return ( return (
<GraphBase <GraphBase
icon="battery" icon="battery"
title="天然气I" title="天然气"
desc={`能耗趋势图 ${timestr}`} desc={`能耗趋势图 ${timestr}`}
switchOptions={false} switchOptions={false}
onSwitch={handleSwitch} onSwitch={handleSwitch}
@@ -60,6 +61,45 @@ function NatGas(props) {
onDateChange={handleDateChange} onDateChange={handleDateChange}
size={["long", "middle"]} size={["long", "middle"]}
> >
<div
className="nat-gas-legend"
style={{
position: "absolute",
top: 28,
right: 144,
display: "flex",
gap: "24px",
}}
>
<div className="legend-item">
<div
className="legend-color"
style={{
display: "inline-block",
width: "12px",
height: "12px",
borderRadius: "2px",
marginRight: "8px",
backgroundColor: "#FFD160",
}}
/>
<span style={{ color: "#fff" }}>天然气I</span>
</div>
<div className="legend-item">
<div
className="legend-color"
style={{
display: "inline-block",
width: "12px",
height: "12px",
borderRadius: "2px",
marginRight: "8px",
backgroundColor: "#12FFF5",
}}
/>
<span style={{ color: "#fff" }}>天然气II</span>
</div>
</div>
{/* real echarts here */} {/* real echarts here */}
{options && ( {options && (
<ReactECharts <ReactECharts
@@ -89,8 +129,9 @@ function NatGas(props) {
export default NatGas; export default NatGas;
function getOptions(period, trend) { function getOptions(period, trendArr) {
if (trend[period].length === 0) return null; if (trendArr[0][period].length === 0 || trendArr[1][period].length === 0)
return null;
// export default function getOptions(seriesData, name) { // export default function getOptions(seriesData, name) {
const today = new Date(); const today = new Date();
const currentYear = today.getFullYear(); const currentYear = today.getFullYear();
@@ -185,21 +226,38 @@ function getOptions(period, trend) {
}, },
}, },
}, },
series: { series: [
data: trend[period].map((item) => {
item != null ? (+item).toFixed(2) : null data: trendArr[0][period].map((item) =>
), item != null ? (+item).toFixed(2) : null
type: "line", ),
symbol: "circle", type: "line",
symbolSize: 6, symbol: "circle",
areaStyle: { symbolSize: 6,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ areaStyle: {
{ offset: 0, color: colors[0] + "40" }, color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0.5, color: colors[0] + "20" }, { offset: 0, color: colors[0] + "40" },
{ offset: 1, color: colors[0] + "00" }, { offset: 0.5, color: colors[0] + "20" },
]), { offset: 1, color: colors[0] + "00" },
]),
},
}, },
}, {
data: trendArr[1][period].map((item) =>
item != null ? (+item).toFixed(2) : null
),
type: "line",
symbol: "circle",
symbolSize: 6,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors[1] + "40" },
{ offset: 0.5, color: colors[1] + "20" },
{ offset: 1, color: colors[1] + "00" },
]),
},
},
],
// series: seriesData.map((arr, index) => ({ // series: seriesData.map((arr, index) => ({
// name: index + 1 + '#' + name, // name: index + 1 + '#' + name,
// data: arr, // data: arr,

View File

@@ -6,17 +6,37 @@ import { useState } from "react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import dayjs from "dayjs"; import dayjs from "dayjs";
function getTimeStr(period) {
return {
:
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, "d").format("YYYY.MM.DD") +
" 7点",
:
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",
}[period];
}
function Oxygen(props) { function Oxygen(props) {
const dayTrend = useSelector((state) => state.smoke?.dayTrend); const dayTrend = useSelector((state) => state.smoke?.dayTrend);
const weekTrend = useSelector((state) => state.smoke?.weekTrend); const weekTrend = useSelector((state) => state.smoke?.weekTrend);
const monthTrend = useSelector((state) => state.smoke?.monthTrend); const monthTrend = useSelector((state) => state.smoke?.monthTrend);
const yearTrend = useSelector((state) => state.smoke?.yearTrend); const yearTrend = useSelector((state) => state.smoke?.yearTrend);
const [period, setPeriod] = useState("日"); const [period, setPeriod] = useState("日");
const [timestr, setTimestr] = useState( let timestr = getTimeStr(period);
dayjs().subtract(7, "day").format("YYYY.MM.DD") +
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
const currentTrend = const currentTrend =
period === "日" period === "日"
@@ -33,35 +53,13 @@ function Oxygen(props) {
function handleDateChange(value) { function handleDateChange(value) {
setPeriod(value); setPeriod(value);
setTimestr( timestr = getTimeStr(value);
{
:
dayjs().subtract(1, "day").format("YYYY.MM.DD") +
" 7点 - " +
dayjs().format("YYYY.MM.DD") +
" 7点",
:
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 (
<GraphBase <GraphBase
icon="smoke" icon="smoke"
title="氧气含量" title="氧气含量"
desc={`能耗趋势图 ${timestr}`} desc={`烟气趋势图 ${timestr}`}
switchOptions={false} switchOptions={false}
defaultSelect={period} defaultSelect={period}
onSwitch={handleSwitch} onSwitch={handleSwitch}

View File

@@ -6,6 +6,30 @@ import { useState } from "react";
import * as echarts from "echarts"; import * as echarts from "echarts";
import dayjs from "dayjs"; import dayjs from "dayjs";
function getTimeStr(period) {
return {
:
dayjs().format("YYYY.MM.DD") +
" 7点 - " +
dayjs().add(1, 'd').format("YYYY.MM.DD") +
" 7点",
:
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",
}[period];
}
function SO2(props) { function SO2(props) {
const dayTrend = useSelector((state) => state.smoke?.dayTrend); const dayTrend = useSelector((state) => state.smoke?.dayTrend);
const weekTrend = useSelector((state) => state.smoke?.weekTrend); const weekTrend = useSelector((state) => state.smoke?.weekTrend);
@@ -21,47 +45,22 @@ function SO2(props) {
: period === "月" : period === "月"
? monthTrend ? monthTrend
: yearTrend; : yearTrend;
const [timestr, setTimestr] = useState(
dayjs().subtract(7, "day").format("YYYY.MM.DD") + let timestr = getTimeStr(period);
" - " +
dayjs().subtract(1, "day").format("YYYY.MM.DD")
);
const options = getOptions("SO2_float", period, currentTrend); const options = getOptions("SO2_float", period, currentTrend);
function handleSwitch(v) {} function handleSwitch(v) {}
function handleDateChange(value) { function handleDateChange(value) {
setPeriod(value); setPeriod(value);
setTimestr( timestr = getTimeStr(value);
{
:
dayjs().subtract(1, "day").format("YYYY.MM.DD") +
" 7点 - " +
dayjs().format("YYYY.MM.DD") +
" 7点",
:
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 (
<GraphBase <GraphBase
icon="smoke" icon="smoke"
title="二氧化硫" title="二氧化硫"
desc={`能耗趋势图 ${timestr}`} desc={`烟气趋势图 ${timestr}`}
switchOptions={false} switchOptions={false}
defaultSelect={period} defaultSelect={period}
onSwitch={handleSwitch} onSwitch={handleSwitch}

View File

@@ -1,21 +1,23 @@
import cls from "./index.module.css"; import cls from "./index.module.css";
import GradientText from "../../../Common/GradientText"; import GradientText from "../../../Common/GradientText";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import eIcon1 from '../../../../assets/Icon/oilstation.png';
function SmokeHandle(props) { function SmokeHandle(props) {
const smokeInfo = useSelector((state) => state.smoke?.info); const smokeInfo = useSelector((state) => state.smoke?.info);
return ( return (
<div className={" " + cls.smoke} style={{ color: "#fff" }}> <div className={" " + cls.smoke} style={{ color: "#fff" }}>
<span <span
className={cls.shadowBorder} className={cls.shadowBorder + " " + cls.border}
style={{ style={{
gridRow: "1 / 3", gridRow: "1 / 3",
paddingTop: "96px", paddingTop: "96px",
paddingLeft: "32px",
userSelect: "none", userSelect: "none",
textAlign: "center",
}} }}
> >
<GradientText text="烟气处理" /> <img src={eIcon1} width={32} alt="eIcon1" />
<GradientText text={"\u2002\u2002烟气处理"} />
</span> </span>
<span <span
className={cls.shadowBorder + " " + cls.infoText} className={cls.shadowBorder + " " + cls.infoText}
@@ -32,13 +34,13 @@ function SmokeHandle(props) {
{(+smokeInfo?.NOX_float)?.toFixed(2) || 0} {(+smokeInfo?.NOX_float)?.toFixed(2) || 0}
</span> </span>
</span> </span>
<span className={cls.shadowBorder + " " + cls.infoText}> <span className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}>
<span style={{ lineHeight: 1.5 }}>二氧化硫浓度 mg/</span> <span style={{ lineHeight: 1.5 }}>二氧化硫浓度 mg/</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{(+smokeInfo?.SO2_float)?.toFixed(2) || 0} {(+smokeInfo?.SO2_float)?.toFixed(2) || 0}
</span> </span>
</span> </span>
<span className={cls.shadowBorder + " " + cls.infoText}> <span className={cls.shadowBorder + " " + cls.infoText + " " + cls.border}>
<span style={{ lineHeight: 1.5 }}>颗粒物浓度 mg/</span> <span style={{ lineHeight: 1.5 }}>颗粒物浓度 mg/</span>
<span style={{ lineHeight: 1.5 }}> <span style={{ lineHeight: 1.5 }}>
{(+smokeInfo?.dust_float)?.toFixed(2) || 0} {(+smokeInfo?.dust_float)?.toFixed(2) || 0}

View File

@@ -3,7 +3,8 @@
gap: 6px; gap: 6px;
grid-template-columns: 187px 347px 347px; grid-template-columns: 187px 347px 347px;
/* grid-template-rows: 60px 60px; */ /* grid-template-rows: 60px 60px; */
grid-template-rows: 129px 129px; /* grid-template-rows: 129px 129px; */
grid-template-rows: auto;
height: 100%; height: 100%;
} }
@@ -13,6 +14,29 @@
padding: 4px; padding: 4px;
} }
.shadowBorder.border {
position: relative;
border-bottom: 2px solid #00fff7;
}
.shadowBorder.border::before,
.shadowBorder.border::after {
content: "";
position: absolute;
bottom: 0;
display: inline-block;
height: 100%;
width: 2px;
background: linear-gradient(to top, #00fff7, #00fff708, transparent);
}
.shadowBorder.border::before {
left: 0;
}
.shadowBorder.border::after {
right: 0;
}
.infoText { .infoText {
text-align: center; text-align: center;
font-size: 24px; font-size: 24px;

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import Item2 from './RightTable'; import Item2 from './RightTable';
import Item1 from '../../../Common/TimeFireDir'; // import Item1 from '../../../Common/TimeFireDir';
import Item1 from '../../../Common/VideoMonitor';
import cls from './index.module.scss'; import cls from './index.module.scss';

View File

@@ -17,6 +17,10 @@ export default function useSlider(defaultSize) {
const v = (value / 100).toFixed(2); const v = (value / 100).toFixed(2);
useEffect(() => {
document.documentElement.style.setProperty('--scale', v);
}, [v])
const styles = { const styles = {
transform: `scale(${v})`, transform: `scale(${v})`,
// transform: `scale(${v * 24 / 33}, ${v})`, // transform: `scale(${v * 24 / 33}, ${v})`,

View File

@@ -37,19 +37,22 @@ function EnergyAnalysis(props) {
<NatGas /> <NatGas />
</div> </div>
<div style={{ gridRow: 3 }}> <div style={{ gridRow: 3 }}>
<Gas /> {/* <Gas /> */}
<ElecCost />
</div> </div>
</div> </div>
<div className={cls.vvgrid + " col-4"}> <div className={cls.vvgrid + " col-4"}>
<div className=" electronic"> <div className=" electronic">
<Energy /> <Energy key="2" page={2} />
</div> </div>
<div className=" gas"> <div className=" gas">
<SmokeHandle /> <Energy key="1" page={1} />
{/* <SmokeHandle /> */}
</div> </div>
<div style={{ height: "100%" }}> <div style={{ height: "100%" }}>
<ElecCost /> {/* <ElecCost /> */}
<SmokeHandle />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -27,10 +27,18 @@
gap: 24px; gap: 24px;
grid-template-rows: 128px 389px 389px; grid-template-rows: 128px 389px 389px;
} }
.vvgrid { .vvgrid {
display: grid; display: flex;
gap: 24px; flex-direction: column;
grid-template-rows: 258px 258px 389px; gap: 32px;
/* display: grid;
gap: 32px;
grid-template-rows: 280px 280px 410px; */
}
.vvgrid > div {
flex: 1;
} }
.shadowBorder { .shadowBorder {

View File

@@ -13,6 +13,9 @@ import QualityCheckRight from "../../components/Modules/QualityCheck/RightSide";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import useRefresh from "../../hooks/useRefresh"; import useRefresh from "../../hooks/useRefresh";
import TimeFireDir from "../../components/Common/TimeFireDir";
import WarnAlertList from "../../components/Common/WarnAlert/ListContainer";
export default function Home({ active }) { export default function Home({ active }) {
useRefresh(true); useRefresh(true);
@@ -33,8 +36,22 @@ export default function Home({ active }) {
return ( return (
<div className="Main"> <div className="Main">
{active == "窑炉总览" && (
<div
style={{
position: "fixed",
top: "210px",
left: "50%",
transform: "translateX(-40%)",
}}
>
<TimeFireDir />
</div>
)}
{active != "窑炉总览" && <div className="bgDitu"></div>} {active != "窑炉总览" && <div className="bgDitu"></div>}
{active == "窑炉总览" && <div className="bgOverview"></div>} {active == "窑炉总览" && (
<div className="bgOverview" id="bgOverview"></div>
)}
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
<div <div
className="left-side" className="left-side"
@@ -54,6 +71,9 @@ export default function Home({ active }) {
<div className="Center"> <div className="Center">
{active == "窑炉总览" && ( {active == "窑炉总览" && (
<> <>
<div id="alarm-list-container">
<WarnAlertList />
</div>
<AnimatePresence> <AnimatePresence>
<motion.div <motion.div
key="center-top" key="center-top"
@@ -103,38 +123,6 @@ export default function Home({ active }) {
)} )}
</div> </div>
{/* {fireDir && fireDir == "东火" && (
<video
src="/video/fire_little_top.webm"
muted
autoPlay
loop
width={4200}
style={{
position: "absolute",
top: "-160px",
left: "-910px",
zIndex: -1,
}}
></video>
)}
{fireDir && fireDir == "西火" && (
<video
src="/video/fire_little_down.webm"
muted
autoPlay
loop
width={4200}
style={{
position: "absolute",
top: "-180px",
left: "-910px",
zIndex: -1,
}}
></video>
)} */}
<div key="bottom-bar" className="Button"> <div key="bottom-bar" className="Button">
<BottomBar /> <BottomBar />
</div> </div>

View File

@@ -0,0 +1,30 @@
import { createSlice } from "@reduxjs/toolkit";
export const initialState = {
list: [],
};
const alarmSlice = createSlice({
name: "alarm",
initialState,
reducers: {
setList(state, action) {
// action.payload 是 { 'A1_1_1': 'detail' } 的结构
console.log("[alarm store] setting list ---> ", action);
const rawData = action.payload;
const list = [];
Object.entries(rawData).forEach(([key, value]) => {
const n = [key, value];
list.push({
id: key,
title: n[0],
content: n[1],
});
});
state.list = list;
},
},
});
export default alarmSlice.reducer;
export const { setList } = alarmSlice.actions;

View File

@@ -14,9 +14,12 @@ import annealFanFrequenceReducer from "./features/annealFanFrequenceSlice";
import annealFanInfoReducer from "./features/annealFanInfoSlice"; import annealFanInfoReducer from "./features/annealFanInfoSlice";
import cuttingReducer from "./features/cuttingSlice"; import cuttingReducer from "./features/cuttingSlice";
import smokeReducer from "./features/smokeSlice"; import smokeReducer from "./features/smokeSlice";
import alarmSlice from "./features/alarmSlice";
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
// 报警信息
alarm: alarmSlice,
// 窑炉信息 // 窑炉信息
kiln: kilnReducer, kiln: kilnReducer,
// 投料机信息 // 投料机信息

View File

@@ -1,8 +1,7 @@
import { store } from "../store"; import { store } from "../store";
import { MessageItem } from "./checkTypeHelper";
export default function handler(msg: MessageEvent) { export default function handler(msg) {
let serializedData: MessageItem | null = null; let serializedData = null;
try { try {
serializedData = JSON.parse(msg.data); serializedData = JSON.parse(msg.data);
} catch (error) { } catch (error) {

View File

@@ -1,26 +0,0 @@
type CheckTypeItem = {
checkDiscard?: boolean;
checkType: string;
checkNum: number;
ip?: string;
israDefectType?: string;
israSeriousGrade?: string;
};
type ProductLineItem = {
name: string;
sum: number;
data: CheckTypeItem[];
};
export type MessageItem = {
type: string;
name: string;
detData: {
checkType: string[];
dayStatistic?: ProductLineItem[];
weekStatistic?: ProductLineItem[];
monthStatistic?: ProductLineItem[];
yearStatistic?: ProductLineItem[];
};
};

View File

@@ -1,30 +1,14 @@
import { store } from "../store"; import { store } from "../store";
type TableDataType = {
name: "table";
type: "cutting";
data: any[];
};
type ChartDataType = {
name: "chart";
type: "cutting";
nightPushData: any[];
dayPushData: any[];
allPushData: any[];
dateType: "day" | "week" | "month" | "year";
};
export default function handler(msg: MessageEvent) { export default function handler(msg) {
let serializedData: TableDataType | ChartDataType | null = null; let serializedData = null;
try { try {
serializedData = JSON.parse(msg.data); serializedData = JSON.parse(msg.data);
} catch (error) { } catch (error) {
console.log("[*] websocket: [unable to serialize] ---> ", msg); console.log("[*] websocket: [unable to serialize] ---> ", msg);
} }
console.log("[CUTTING DATA] ---> ", serializedData);
if (serializedData == null) return; if (serializedData == null) return;
switch (serializedData.name) { switch (serializedData.name) {
case "table": case "table":
store.dispatch({ store.dispatch({

View File

@@ -1,13 +1,18 @@
import { store } from "../store"; import { store } from "../store";
import { setList } from "../store/features/alarmSlice";
export default function handler(msg: MessageEvent) { export default function handler(msg) {
let serializedData: { type: string; data: any } | null = null; let serializedData = null;
try { try {
serializedData = JSON.parse(msg.data); serializedData = JSON.parse(msg.data);
} catch (error) { } catch (error) {
console.log("[*] websocket: [unable to serialize] ---> ", msg); console.log("[*] websocket: [unable to serialize] ---> ", msg);
} }
switch (serializedData?.type) { switch (serializedData?.type) {
case "alarmList": {
store.dispatch(setList(serializedData.data));
break;
}
case "KilnInfo": { case "KilnInfo": {
store.dispatch({ store.dispatch({
type: "kiln/setKilnInfo", type: "kiln/setKilnInfo",

View File

@@ -1,7 +1,7 @@
import { store } from "../store"; import { store } from "../store";
export default function handler(msg: MessageEvent) { export default function handler(msg) {
let serializedData: { type: string; data: any } | null = null; let serializedData = null;
try { try {
serializedData = JSON.parse(msg.data); serializedData = JSON.parse(msg.data);
} catch (error) { } catch (error) {

View File

@@ -88,9 +88,6 @@ export function getOptions(period, source, trend, options = {}) {
color: "#213259a0", color: "#213259a0",
}, },
}, },
// interval: 10,
// min: 0,
// max: 100,
}, },
series: [ series: [
{ {
@@ -123,7 +120,6 @@ export function getOptions(period, source, trend, options = {}) {
type: "shadow", type: "shadow",
}, },
className: "xc-chart-tooltip", className: "xc-chart-tooltip",
// backgroundColor: ''
}, },
...options, ...options,
}; };

View File

@@ -9,28 +9,22 @@ import smokeHandler from "./smoke";
* new XClient('ws://192.168.1.12:8081/xc-screen/websocket/xc001', 'DCS') * new XClient('ws://192.168.1.12:8081/xc-screen/websocket/xc001', 'DCS')
*/ */
class XClient { class XClient {
url: string; // url;
name: string; // name;
ws: WebSocket; // ws;
timeout: number = 1000 * 5; // timeout = 1000 * 5;
heartbeatDelay: number = 1000 * 60 * 3; // heartbeatDelay = 1000 * 60 * 3;
reconnectCount: number = 0; // reconnectCount = 0;
onmessage: (msg: MessageEvent) => void; // onmessage = (msg) => console.log(msg);
hb: number = 0; // hb = 0;
constructor( constructor(config, onmessage = (msg) => console.log(msg)) {
config: {
url: string;
name: string;
timeout?: number;
reconnectCount?: number;
},
onmessage: (msg: MessageEvent) => void
) {
this.url = config.url; this.url = config.url;
this.name = config.name; this.name = config.name;
this.ws = new WebSocket(config.url); this.ws = new WebSocket(config.url);
this.timeout = config.timeout || 1000 * 5; this.timeout = config.timeout || 1000 * 5;
this.heartbeatDelay = 1000 * 60 * 3;
this.reconnectCount = 0;
this.ws.onopen = () => { this.ws.onopen = () => {
console.log(`[*] ${this.name} 初始化连接成功`); console.log(`[*] ${this.name} 初始化连接成功`);
@@ -113,6 +107,7 @@ const newUser = uuidv4();
new XClient( new XClient(
{ {
url: "ws://10.70.180.10:8081/xc-screen/websocket/xc001" + newUser, url: "ws://10.70.180.10:8081/xc-screen/websocket/xc001" + newUser,
// url: "ws://127.0.0.1:9800/alarm?user=" + newUser,
name: "DCS_DATA", name: "DCS_DATA",
// "ws://m306416y13.yicp.fun:35441/xc-screen/websocket/xc001", // "ws://m306416y13.yicp.fun:35441/xc-screen/websocket/xc001",
// "ws://192.168.1.114:8081/xc-screen/websocket/xc001", // "ws://192.168.1.114:8081/xc-screen/websocket/xc001",
@@ -164,7 +159,7 @@ new XClient(
smokeHandler smokeHandler
); );
export function randomInt(min: number, max: number, includeMax = false) { export function randomInt(min, max, includeMax = false) {
let Fn = includeMax ? Math.ceil : Math.floor; let Fn = includeMax ? Math.ceil : Math.floor;
let num = Fn(Math.random() * max); let num = Fn(Math.random() * max);
while (num < min) { while (num < min) {

View File

@@ -1,4 +0,0 @@
export type MessageEvent = {
type: string;
data: any;
}

32
src/utils/smoke.js Normal file
View File

@@ -0,0 +1,32 @@
import { store } from "../store";
export default function handler(msg) {
let serializedData = null;
try {
serializedData = JSON.parse(msg.data);
} catch (error) {
console.log("[*] websocket: [unable to serialize] ---> ", msg);
}
switch (serializedData?.type) {
case "exhaustGas": {
store.dispatch({
type: "smoke/setInfo",
payload: serializedData.realtime,
});
store.dispatch({
type: "smoke/setTrend",
payload: {
dayTrend: serializedData.dayTrend,
weekTrend: serializedData.weekTrend,
monthTrend: serializedData.monthTrend,
yearTrend: serializedData.yearTrend,
},
});
break;
}
default: {
console.log("websocket message: [unknown] ---> ", msg.data);
}
}
}

View File

@@ -1,114 +0,0 @@
import { store } from "../store";
type SmokeMessageItem = {
type: string;
realtime: {
SO2_float: number;
NOX_float: number;
O2_float: number;
dust_float: number;
};
dayTrend: {
SO2_float: Array<{
time: string;
value: number;
}>;
NOX_float: Array<{
time: string;
value: number;
}>;
O2_float: Array<{
time: string;
value: number;
}>;
dust_float: Array<{
time: string;
value: number;
}>;
};
weekTrend: {
SO2_float: Array<{
time: string;
value: number;
}>;
NOX_float: Array<{
time: string;
value: number;
}>;
O2_float: Array<{
time: string;
value: number;
}>;
dust_float: Array<{
time: string;
value: number;
}>;
};
monthTrend: {
SO2_float: Array<{
time: string;
value: number;
}>;
NOX_float: Array<{
time: string;
value: number;
}>;
O2_float: Array<{
time: string;
value: number;
}>;
dust_float: Array<{
time: string;
value: number;
}>;
};
yearTrend: {
SO2_float: Array<{
time: string;
value: number;
}>;
NOX_float: Array<{
time: string;
value: number;
}>;
O2_float: Array<{
time: string;
value: number;
}>;
dust_float: Array<{
time: string;
value: number;
}>;
};
};
export default function handler(msg: MessageEvent) {
let serializedData: SmokeMessageItem | null = null;
try {
serializedData = JSON.parse(msg.data);
} catch (error) {
console.log("[*] websocket: [unable to serialize] ---> ", msg);
}
switch (serializedData?.type) {
case "exhaustGas": {
store.dispatch({
type: "smoke/setInfo",
payload: serializedData.realtime,
});
store.dispatch({
type: "smoke/setTrend",
payload: {
dayTrend: serializedData.dayTrend,
weekTrend: serializedData.weekTrend,
monthTrend: serializedData.monthTrend,
yearTrend: serializedData.yearTrend,
},
});
break;
}
default: {
console.log("websocket message: [unknown] ---> ", msg.data);
}
}
}

View File

@@ -1,109 +0,0 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View File

@@ -0,0 +1,120 @@
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#压延机报警
`;
// const totalAlarmList = total.split("\n");
const getRandomAlarmList = function (num) {
const totalAlarmList = total.split("\n");
let alarmList = [];
for (let i = 0; i < num; i++) {
let index = Math.floor(Math.random() * totalAlarmList.length);
const chosen = totalAlarmList[index];
totalAlarmList.splice(index, 1);
alarmList.push(chosen);
}
return alarmList;
};
module.exports = {
getRandomAlarmList,
};

View File

@@ -1,18 +0,0 @@
import utils from '../utils';
function genKilnInfo() {
return {
kilnPressure: utils.rand(0, 100) + 'Kpa',
waterTemp: utils.rand(0, 100) + '℃',
waterFlow: utils.rand(30, 90) + 'm³/h',
waterPressure: utils.rand(10, 50) + 'Kpa',
windPressure: utils.rand(10, 30) + 'Kpa',
gasPressure: utils.rand(10, 30) + 'Kpa',
// 碹顶加权温度
topTemp: utils.rand(30, 60) + '℃',
// 融化加权温度
meltTemp: utils.rand(100, 200) + '℃',
};
}
export default genKilnInfo;

View File

@@ -1,13 +0,0 @@
// 天然气
import utils from '../utils';
function getNavGasInfo(type: 'history' | 'realtime') {
switch (type) {
case 'history':
break;
case 'realtime':
break;
}
}
export default getNavGasInfo;

44
websocket/package-lock.json generated Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "ws-server",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ws-server",
"version": "0.0.1",
"license": "ISC",
"dependencies": {
"ws": "^8.16.0"
}
},
"node_modules/ws": {
"version": "8.16.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
},
"dependencies": {
"ws": {
"version": "8.16.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"requires": {}
}
}
}

15
websocket/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "ws-server",
"version": "0.0.1",
"description": "a simple dev ws-server",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"ws": "^8.16.0"
}
}

105
websocket/server copy.js Normal file
View File

@@ -0,0 +1,105 @@
import { WebSocket, WebSocketServer } from "ws";
import template from "./template.json";
import utils from "./utils";
const wss = new WebSocketServer({ port: 9800 });
const frequency = 10; // seconds
const frequency1 = 1200; // seconds
wss.on("connection", function (ws, req) {
// console.log("ws", ws);
console.log(
"Client in: ",
req.socket.remoteAddress,
"current users:",
wss.clients.size
);
// ws.on("error", console.error);
// ws.emit("message", "connected");
ws.on("open", function () {
console.log("connected");
ws.send("connected");
});
ws.on("message", function (msg) {
console.log("message from client", msg);
ws.send("echo " + msg.toString());
});
ws.on("error", console.error);
const timer = setInterval(() => {
sendMsg(ws, "kiln-info"); // 窑炉信息
sendMsg(ws, "energy-cost"); // 运行状态
sendMsg(ws, "run-state"); // 运行状态
sendMsg(ws, "realtime");
sendMsg(ws, "his-trend");
// sendMsg(ws, 'gas');
// sendMsg(ws, 'kiln-top');
// sendMsg(ws, 'kiln-bottom');
}, frequency * 1000);
const timer1 = setInterval(() => {
// sendMsg(ws, 'run-state'); // 运行状态
}, frequency1 * 1000);
ws.on("close", function () {
console.log("停止监听");
clearInterval(timer);
clearInterval(timer1);
});
});
function sendMsg(ws, type) {
let data = {};
switch (type) {
case "kiln-info":
for (const key in template.kilnInfo) {
data[key] = utils.getRandom(template.kilnInfo[key]);
}
break;
case "energy-cost":
for (const key in template.energyCost) {
data[key] = utils.getRandom(template.energyCost[key]);
}
break;
case "run-state":
data = template.runState;
data.fireDirection =
Math.floor(Math.random() * 10) % 2 === 0 ? "南火" : "北火";
break;
case "realtime":
/** 天然气 实时流量 */
data.gasii = template.realtime.gasii.map((v) => utils.getRandom(v));
/** 助燃风 实时流量 */
data.wind = template.realtime.wind.map((v) => utils.getRandom(v));
break;
case "his-trend":
const hisTrend = {
gas: {},
wind: {},
};
Object.keys(template.hisTrend.gas).forEach((key) => {
hisTrend.gas[key] = template.hisTrend.gas[key].map((v) =>
utils.getRandom(v)
);
});
Object.keys(template.hisTrend.wind).forEach((key) => {
hisTrend.wind[key] = template.hisTrend.wind[key].map((v) =>
utils.getRandom(v)
);
});
data = hisTrend;
break;
case "gas":
// data = template.gas;
break;
case "kiln-top":
// data = template.kilnTop;
break;
case "kiln-bottom":
// data = template.kilnBottom;
break;
default:
// data = 'You are connected!';
break;
}
ws.send(JSON.stringify({ type, data }));
}

95
websocket/server.js Normal file
View File

@@ -0,0 +1,95 @@
const { WebSocket } = require("ws");
const { getRandomAlarmList } = require("./fakedata/alarmList");
const wss = new WebSocket.Server({ port: 9800 });
console.log('[websocket] server created');
wss.on("connection", function (ws, req) {
console.log(
"[用户连接]: ",
req.socket.remoteAddress,
"当前总用户数:",
wss.clients.size
);
ws.on("open", function () {
console.log('[websocket] opened');
ws.send("connected");
});
ws.on("message", function (msg) {
console.log("[==>]", msg);
});
ws.on("error", console.error);
const timer = setInterval(() => {
sendMsg(ws, "alarmList"); // 报警信息
}, 10 * 1000);
ws.on("close", function () {
console.log("停止监听");
clearInterval(timer);
});
});
function sendMsg(ws, type) {
let data = {};
switch (type) {
case "alarmList":
const alarmList = getRandomAlarmList(Math.floor(Math.random() * 10) + 1);
alarmList.forEach((str) => {
const [code, detail] = str.split(",");
data[code] = detail;
});
break;
case "kiln-info":
for (const key in template.kilnInfo) {
data[key] = utils.getRandom(template.kilnInfo[key]);
}
break;
case "energy-cost":
for (const key in template.energyCost) {
data[key] = utils.getRandom(template.energyCost[key]);
}
break;
case "run-state":
data = template.runState;
data.fireDirection =
Math.floor(Math.random() * 10) % 2 === 0 ? "南火" : "北火";
break;
case "realtime":
/** 天然气 实时流量 */
data.gasii = template.realtime.gasii.map((v) => utils.getRandom(v));
/** 助燃风 实时流量 */
data.wind = template.realtime.wind.map((v) => utils.getRandom(v));
break;
case "his-trend":
const hisTrend = {
gas: {},
wind: {},
};
Object.keys(template.hisTrend.gas).forEach((key) => {
hisTrend.gas[key] = template.hisTrend.gas[key].map((v) =>
utils.getRandom(v)
);
});
Object.keys(template.hisTrend.wind).forEach((key) => {
hisTrend.wind[key] = template.hisTrend.wind[key].map((v) =>
utils.getRandom(v)
);
});
data = hisTrend;
break;
case "gas":
// data = template.gas;
break;
case "kiln-top":
// data = template.kilnTop;
break;
case "kiln-bottom":
// data = template.kilnBottom;
break;
default:
// data = 'You are connected!';
break;
}
ws.send(JSON.stringify({ type, data }));
}

View File

@@ -1,133 +0,0 @@
import { WebSocket, WebSocketServer } from 'ws';
import template from './template.json';
import utils from './utils';
const wss = new WebSocketServer({ port: 9800 });
const frequency = 10; // seconds
const frequency1 = 1200; // seconds
wss.on('connection', function (ws, req) {
// console.log("ws", ws);
console.log(
'Client in: ',
req.socket.remoteAddress,
'current users:',
wss.clients.size,
);
// ws.on("error", console.error);
// ws.emit("message", "connected");
ws.on('open', function () {
console.log('connected');
ws.send('connected');
});
ws.on('message', function (msg) {
console.log('message from client', msg);
ws.send('echo ' + msg.toString());
});
ws.on('error', console.error);
const timer = setInterval(() => {
sendMsg(ws, 'kiln-info'); // 窑炉信息
sendMsg(ws, 'energy-cost'); // 运行状态
sendMsg(ws, 'run-state'); // 运行状态
sendMsg(ws, 'realtime');
sendMsg(ws, 'his-trend');
// sendMsg(ws, 'gas');
// sendMsg(ws, 'kiln-top');
// sendMsg(ws, 'kiln-bottom');
}, frequency * 1000);
const timer1 = setInterval(() => {
// sendMsg(ws, 'run-state'); // 运行状态
}, frequency1 * 1000);
ws.on('close', function () {
console.log('停止监听');
clearInterval(timer);
clearInterval(timer1);
});
});
type MsgType =
| 'kiln-info'
| 'run-state'
| 'energy-cost'
| 'realtime'
| 'his-trend'
| 'fan'
| 'gas'
| 'kiln-top'
| 'kiln-bottom';
type ResponseData = {
[key: string]: string | string[];
};
type ResponseDataComplex = {
[key: string]: ResponseData;
};
function sendMsg(ws: WebSocket, type: MsgType) {
let data: ResponseData | ResponseDataComplex = {};
switch (type) {
case 'kiln-info':
for (const key in template.kilnInfo) {
data[key] = utils.getRandom(
template.kilnInfo[key as keyof typeof template.kilnInfo],
);
}
break;
case 'energy-cost':
for (const key in template.energyCost) {
data[key] = utils.getRandom(
template.energyCost[key as keyof typeof template.energyCost],
);
}
break;
case 'run-state':
data = template.runState;
data.fireDirection =
Math.floor(Math.random() * 10) % 2 === 0 ? '南火' : '北火';
break;
case 'realtime':
/** 天然气 实时流量 */
data.gasii = template.realtime.gasii.map((v) => utils.getRandom(v));
/** 助燃风 实时流量 */
data.wind = template.realtime.wind.map((v) => utils.getRandom(v));
break;
case 'his-trend':
const hisTrend: {
gas: ResponseData;
wind: ResponseData;
} = {
gas: {},
wind: {},
};
Object.keys(template.hisTrend.gas).forEach((key) => {
hisTrend.gas[key] = template.hisTrend.gas[
key as keyof typeof template.hisTrend.gas
].map((v) => utils.getRandom(v));
});
Object.keys(template.hisTrend.wind).forEach((key) => {
hisTrend.wind[key] = template.hisTrend.wind[
key as keyof typeof template.hisTrend.wind
].map((v) => utils.getRandom(v));
});
data = hisTrend;
break;
case 'gas':
// data = template.gas;
break;
case 'kiln-top':
// data = template.kilnTop;
break;
case 'kiln-bottom':
// data = template.kilnBottom;
break;
default:
// data = 'You are connected!';
break;
}
// console.log("sendMsg: ", ws);
// ws.emit("message", JSON.stringify(data));
ws.send(JSON.stringify({ type, data }));
}

View File

@@ -1,109 +0,0 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
"resolveJsonModule": true /* Enable importing .json files. */,
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

49
websocket/utils/index.js Normal file
View File

@@ -0,0 +1,49 @@
export default {
// 生成随机数
randomNum({ min, max }, isFloat = false) {
if (isFloat) return (Math.random() * (max - min) + min).toFixed(2);
return Math.floor(Math.random() * (max - min + 1) + min);
},
getMinmax(type) {
// : '*' | '.' | '+' | '$'
let min, max;
switch (type) {
case "*":
min = 30;
max = 150;
break;
case ".":
min = 60;
max = 200;
break;
case "+":
min = 20;
max = 70;
break;
case "$":
min = 1;
max = 100;
break;
}
return { min, max };
},
getRandom(value) {
value = value.replace(
"***",
"" + this.randomNum({ ...this.getMinmax("*") })
);
value = value.replace(
"...",
"" + this.randomNum({ ...this.getMinmax(".") })
);
value = value.replace(
"+++",
"" + this.randomNum({ ...this.getMinmax("+") })
);
value = value.replace(
"$$$",
"" + this.randomNum({ ...this.getMinmax("$") }, true)
);
return value;
},
};

View File

@@ -1,7 +0,0 @@
function rand(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export default {
rand,
};

View File

@@ -1,48 +0,0 @@
export default {
// 生成随机数
randomNum({ min, max }: { min: number; max: number }, isFloat = false) {
if (isFloat) return (Math.random() * (max - min) + min).toFixed(2);
return Math.floor(Math.random() * (max - min + 1) + min);
},
getMinmax(type: '*' | '.' | '+' | '$') {
let min: number, max: number;
switch (type) {
case '*':
min = 30;
max = 150;
break;
case '.':
min = 60;
max = 200;
break;
case '+':
min = 20;
max = 70;
break;
case '$':
min = 1;
max = 100;
break;
}
return { min, max };
},
getRandom(value: string) {
value = value.replace(
'***',
'' + this.randomNum({ ...this.getMinmax('*') }),
);
value = value.replace(
'...',
'' + this.randomNum({ ...this.getMinmax('.') }),
);
value = value.replace(
'+++',
'' + this.randomNum({ ...this.getMinmax('+') }),
);
value = value.replace(
'$$$',
'' + this.randomNum({ ...this.getMinmax('$') }, true),
);
return value;
},
};