This commit is contained in:
nguyentrungthat 2025-11-06 09:39:33 +07:00
parent 990f57a342
commit e4014054d2
10 changed files with 532 additions and 434 deletions

View File

@ -1,3 +1,4 @@
import axios from 'axios'
import type { HttpContext } from '@adonisjs/core/http'
import User from '../models/user.js'
@ -26,7 +27,31 @@ export default class AuthController {
const user = await User.query().where('user_name', userName).first()
if (!user) {
return response.status(401).json({ message: 'Invalid Username or password' })
const remoteUrl = process.env.ERP_URL || 'https://stage.nswteam.net'
const remoteResp = await axios.post(remoteUrl + '/api/login', {
userEmail: userName,
password: password,
})
if (!remoteResp?.data || !remoteResp.data.success) {
return response.badRequest({
status: false,
message: 'Login ERP Fail, Email or password is incorrect',
error: 'EMAIL_OR_PASSWORD_INCORRECT',
})
}
const remoteUser = remoteResp.data.data
const newUser = await User.create({
email: remoteUser.userEmail,
userName: userName,
password: password,
})
return response.json({
message: 'Login successful',
user: { id: newUser.id, email: newUser.email, userName: newUser.userName },
})
}
try {

View File

@ -16,7 +16,7 @@ interface SwitchControllerOptions {
port?: number
username: string
password: string
onData?: (data?: string, status?: string) => void
onData?: (data?: PortInfo[][], status?: string) => void
keep_connect?: boolean
}
@ -25,7 +25,7 @@ export default class SwitchController {
private port: number
private username: string
private password: string
private onData: (data?: string, status?: string) => void
private onData: (data?: PortInfo[][], status?: string) => void
private socket: net.Socket
public status: 'CONNECTED' | 'DISCONNECTED'
public buffer: string
@ -68,11 +68,12 @@ export default class SwitchController {
private _handleClose() {
this.status = 'DISCONNECTED'
this.isEnable = false
this.onData(`[DISCONNECTED]`, this.status)
this.onData(this.portGroups, this.status)
}
private _handleError(err: Error & { code?: string }) {
this.onData(`[ERROR] ${err.message}`, this.status)
console.log('[SWITCH CONNECTION ERROR]:', err.message)
this.onData(this.portGroups, this.status)
}
private _waitFor(prompt: string, timeout = 5000): Promise<string> {
@ -104,7 +105,7 @@ export default class SwitchController {
this.status = 'CONNECTED'
this.isEnable = false
this.socket.setEncoding('utf8')
// this.checkStatusAllPorts()
this.checkStatusAllPorts()
this.socket.on('data', (data) => this._handleData(data.toString()))
resolve()
})
@ -124,13 +125,17 @@ export default class SwitchController {
}
public checkStatusAllPorts() {
setInterval(async () => {
const interval = setInterval(async () => {
try {
if (this.status !== 'CONNECTED') {
clearInterval(interval)
return
}
await this.getPorts()
if (this.promptCallbacks.length === 0) this.buffer = ''
} catch (err: any) {
console.error('Error checking port status:', err)
this.onData(`[ERROR] ${err.message}`, this.status)
this.onData(this.portGroups, this.status)
}
}, 5000)
}
@ -281,7 +286,7 @@ export default class SwitchController {
const groupedArray = Object.values(grouped)
this.ports = ports
this.portGroups = groupedArray
this.onData('', this.status)
this.onData(this.portGroups, this.status)
return true
}

View File

@ -14,6 +14,7 @@
"@adonisjs/cors": "^2.2.1",
"@adonisjs/lucid": "^21.6.1",
"@vinejs/vine": "^3.0.1",
"axios": "^1.13.2",
"luxon": "^3.7.2",
"mysql2": "^3.15.3",
"net": "^1.0.2",
@ -2459,7 +2460,6 @@
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"devOptional": true,
"license": "MIT"
},
"node_modules/atomic-sleep": {
@ -2480,6 +2480,17 @@
"node": ">= 6.0.0"
}
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -2997,7 +3008,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
@ -3262,7 +3272,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@ -3538,7 +3547,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@ -4151,11 +4159,30 @@
"node": ">=8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@ -4172,7 +4199,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@ -4182,7 +4208,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@ -4470,7 +4495,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@ -6072,6 +6096,12 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",

View File

@ -56,6 +56,7 @@
"@adonisjs/cors": "^2.2.1",
"@adonisjs/lucid": "^21.6.1",
"@vinejs/vine": "^3.0.1",
"axios": "^1.13.2",
"luxon": "^3.7.2",
"mysql2": "^3.15.3",
"net": "^1.0.2",

View File

@ -331,7 +331,7 @@ export class WebSocketIo {
if (element && element.status === 'CONNECTED') {
socket.emit('switch_output', {
stationId: station.id,
ports: element.ports,
portGroups: element.portGroups,
status: element.status,
})
} else if (element && element.status !== 'CONNECTED') {
@ -350,6 +350,7 @@ export class WebSocketIo {
}
const element = this.switchControl.get(ip)
if (element) {
this.setTimeoutConnect(station.id, element)
switch (command) {
case 'on':
ports.forEach(async (port: string) => {
@ -446,7 +447,11 @@ export class WebSocketIo {
}
}
private setTimeoutConnect = (lineId: number, lineConn: LineConnection, timeout = 120000) => {
private setTimeoutConnect = (
lineId: number,
lineConn: LineConnection | SwitchController,
timeout = 120000
) => {
if (this.intervalMap[`${lineId}`]) {
clearInterval(this.intervalMap[`${lineId}`])
delete this.intervalMap[`${lineId}`]
@ -562,10 +567,10 @@ export class WebSocketIo {
port: port,
username: username,
password: password,
onData: (ports?: string, status?: string) => {
onData: (ports?: any, status?: string) => {
socket.emit('switch_output', {
stationId: station.id,
ports: ports,
portGroups: ports,
status,
})
},
@ -575,6 +580,7 @@ export class WebSocketIo {
await infoSwitch.login()
await infoSwitch.getPorts()
this.switchControl.set(ip, infoSwitch)
this.setTimeoutConnect(station.id, infoSwitch)
} catch (error) {
console.log(error)
}

View File

@ -2,6 +2,7 @@ import { Button, PasswordInput, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import { notifications } from "@mantine/notifications";
import axios from "axios";
import { useState } from "react";
const apiUrl = import.meta.env.VITE_BACKEND_URL;
@ -11,6 +12,7 @@ type TLogin = {
};
const Login = () => {
const [isSubmit, setIsSubmit] = useState(false);
const formLogin = useForm<TLogin>({
initialValues: {
user_name: "",
@ -41,6 +43,7 @@ const Login = () => {
});
return;
}
setIsSubmit(true);
const payload = {
user_name: formLogin.values.user_name,
password: formLogin.values.password,
@ -51,7 +54,9 @@ const Login = () => {
localStorage.setItem("user", JSON.stringify(user));
window.location.href = "/";
}
setIsSubmit(false);
} catch (error) {
setIsSubmit(false);
console.log(error);
notifications.show({
title: "Error",
@ -93,6 +98,7 @@ const Login = () => {
/>
<Button
disabled={isSubmit}
fullWidth
mt="xl"
size="md"

View File

@ -14,6 +14,7 @@ type TRegister = {
};
function Register() {
const [isSubmit, setIsSubmit] = useState(false);
const [formRegister, setFormRegister] = useState<TRegister>({
email: "",
user_name: "",
@ -39,6 +40,7 @@ function Register() {
});
return;
}
setIsSubmit(true);
const payload = {
email: formRegister.email,
password: formRegister.password,
@ -57,7 +59,9 @@ function Register() {
color: "red",
});
}
setIsSubmit(false);
} catch (error) {
setIsSubmit(false);
console.log(error);
notifications.show({
title: "Error",
@ -143,8 +147,9 @@ function Register() {
size="md"
loading={status === "loading"}
disabled={
formRegister.password !== "" &&
formRegister.password === formRegister.confirm_password
isSubmit ||
(formRegister.password !== "" &&
formRegister.password === formRegister.confirm_password)
? false
: true
}

View File

@ -220,6 +220,29 @@ export default function DraggableTabs({
};
}, []);
const connectApcSwitch = (station: TStation) => {
if (station?.apc_1_ip && station?.apc_1_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_1_ip,
apcName: "apc_1",
});
}
if (station?.apc_2_ip && station?.apc_2_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_2_ip,
apcName: "apc_2",
});
}
if (station?.switch_control_ip && station?.switch_control_port) {
socket?.emit("connect_switch", {
station: station,
ip: station?.switch_control_ip,
});
}
};
return (
<DndContext
sensors={sensors}
@ -275,36 +298,28 @@ export default function DraggableTabs({
);
if (!station) return;
setOpenedAPC(true);
if (station?.apc_1_ip && station?.apc_1_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_1_ip,
apcName: "apc_1",
});
}
if (station?.apc_2_ip && station?.apc_2_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_2_ip,
apcName: "apc_2",
});
}
connectApcSwitch(station);
}}
>
APC
</Button>
{/* <Button
<Button
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="yellow"
onClick={() => {
const station = tabs.find(
(el) => el.id.toString() === active
);
if (!station) return;
setOpenedSwitch(true);
connectApcSwitch(station);
}}
>
Switch
</Button> */}
</Button>
</Flex>
</Flex>
<Tabs.List className={classes.list}>

View File

@ -1,10 +1,8 @@
import { Box, Button, Card, Drawer, Grid, Text } from "@mantine/core";
import { Box, Button, Card, Drawer, Grid, Loader, Text } from "@mantine/core";
import { IconRepeat, IconSection } from "@tabler/icons-react";
import { useEffect, useState } from "react";
import classes from "./Component.module.css";
import type { APCProps, SwitchPortsProps, TStation } from "../untils/types";
import { useDebounce } from "../untils/helper";
import { SOCKET_EVENTS } from "../untils/constanst";
import type { Socket } from "socket.io-client";
interface DrawerProps {
@ -16,11 +14,6 @@ interface DrawerProps {
openedAPC?: () => void;
}
type TAppStatus = {
id: string;
connectionTime: string;
};
type TSelectedOutlet = {
number?: number;
name: string;
@ -246,7 +239,31 @@ export const DrawerAPCControl: React.FC<DrawerProps> = ({
style={{ position: "absolute", left: 0 }}
opened={open}
onClose={onClose}
title="APC Control"
title={
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
APC Control
<div style={{ marginLeft: "12px" }}>
<Button
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="blue"
onClick={() => {
if (openedSwitch) openedSwitch();
}}
>
Switch Control
</Button>
</div>
</div>
}
size="xs"
position="bottom"
>
@ -771,22 +788,6 @@ export const DrawerAPCControl: React.FC<DrawerProps> = ({
</fieldset>
</Grid.Col>
</Grid>
{/* <div
style={{ display: "flex", justifyContent: "end", marginTop: "20px" }}
>
<Button
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="yellow"
onClick={() => {
if (openedSwitch) openedSwitch();
}}
>
Switch Control
</Button>
</div> */}
</Drawer>
);
};
@ -803,7 +804,8 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
const [listPortsSelected, setListPortsSelected] = useState<
SwitchPortsProps[]
>([]);
const [isSubmit, setIsSubmit] = useState(true);
const [isSubmit, setIsSubmit] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!open) {
@ -812,31 +814,17 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
}, [open]);
useEffect(() => {
if (stationAPI?.switch_control_ip && stationAPI?.switch_control_port) {
setIsSubmit(false);
}
}, [stationAPI]);
useEffect(() => {
socket?.on(
SOCKET_EVENTS.DATA_SWITCH_RECEIVED.DATA_SWITCH_RECEIVED_TO_WEB,
(data: TStation[]) => {
data
?.filter((el) => stationAPI.id === el.id)
?.forEach((station) => {
const switches =
station?.switches && station?.switches?.length > 0
? station?.switches[0]
: null;
if (!switches) return;
setListPorts(switches?.portGroups || []);
});
setDataStation(
data?.find((el) => stationAPI.id === el.id) || stationAPI
);
}
);
}, [socket]);
socket?.on("switch_output", (data) => {
if (data.stationId !== stationAPI.id) return;
if (data?.portGroups && data?.portGroups.length > 0)
setListPorts(data?.portGroups || []);
setLoading(false);
setDataStation({ ...dataStation, switch: { status: data.status } });
});
return () => {
socket?.off("switch_output");
};
}, [socket, dataStation]);
const toggleSelect = (port: SwitchPortsProps) => {
setListPortsSelected((prev) =>
@ -907,56 +895,40 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
});
};
// const updateStatusPort = (name: string, value: string) => {
// const ports = listPorts.map((port) => {
// return port.map((el) => {
// if (el.name === name) {
// el.status = value
// el.poe = value
// }
// return el
// })
// })
// setListPorts([...ports])
// }
return (
<Drawer
style={{ position: "absolute", left: 0 }}
opened={open}
onClose={onClose}
title={
dataStation?.switches ? (
dataStation?.switch ? (
<div className={classes.titleAPC}>
<Text fw={700} c={"#514d4d"} fz={"sm"}>
Switch Control
</Text>
{dataStation?.switches[0]?.status &&
RenderAPCStatus(dataStation?.switches[0])}
{dataStation?.switches[0]?.status === "DISCONNECTED" ||
dataStation?.switches[0]?.status === "TIMEOUT" ? (
{dataStation?.switch?.status &&
RenderAPCStatus(dataStation?.switch)}
{dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT" ? (
<Button
size="xs"
disabled={isSubmit}
variant="filled"
color="yellow"
onClick={() => {
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
ports:
listPortsSelected?.length > 0
? listPortsSelected.map((el) => el.name)
: listPorts.flat().map((el) => el.name),
command: "reconnect",
station_id: Number(stationAPI.id),
}
);
socket?.emit("control_switch", {
ports:
listPortsSelected?.length > 0
? listPortsSelected.map((el) => el.name)
: listPorts.flat().map((el) => el.name),
command: "reconnect",
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}, 10000);
}}
>
<IconRepeat size={14} />
@ -964,365 +936,397 @@ export const DrawerSwitchControl: React.FC<DrawerProps> = ({
) : (
""
)}
<div
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<Button
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="blue"
onClick={() => {
if (openedAPC) openedAPC();
}}
>
APC Control
</Button>
</div>
</div>
) : (
"Switch Control"
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
Switch Control
<div style={{ marginLeft: "12px" }}>
<Button
miw={"80px"}
size="xs"
fz={"xs"}
variant="filled"
color="blue"
onClick={() => {
if (openedAPC) openedAPC();
}}
>
APC Control
</Button>
</div>
</div>
)
}
size="sm"
position="bottom"
>
<Grid>
<Grid.Col span={12}>
{listPorts?.length > 0 && (
<Box>
<Grid>
{listPorts?.map((group, key) => (
<Grid.Col
key={key}
span={
group?.length > 20
? 11
: group?.length > 0 && group?.length < 4
? 1
: 12
}
>
<fieldset
style={{
padding: "4px 6px",
paddingBottom: "12px",
height: "-webkit-fill-available",
}}
>
<legend>
<Text fw={700} c={"#514d4d"} fz={"sm"}>
{group[0]?.name.substring(0, 2) || ""}
</Text>
</legend>
<Box
style={{
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
gap: "10px",
overflowY: "auto",
maxHeight: "300px",
}}
>
{group?.length > 0 &&
sortedPorts(group)?.map((port, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
style={{
position: "relative",
width: "60px",
backgroundColor:
port.poe === "ON"
? "#f2dcf8"
: port.status === "ON"
? "#d4f1d3"
: "#f5f5f5",
cursor: "pointer",
border: listPortsSelected.find(
(el) => el.name === port.name
)?.name
? "1px solid #0018ff"
: "",
}}
className={`${
isSubmit ? classes.isDisabled : ""
}`}
onClick={() => {
toggleSelect(port);
}}
>
<Box
style={{
display: "flex",
alignItems: "center",
gap: "2px",
flexDirection: "column",
flexWrap: "wrap",
}}
>
<IconSection
size={"18px"}
color={
port.poe === "ON"
? "#b722d4"
: port.status === "ON"
? "#40c057"
: "#b8b8b8"
}
/>
<Text fw={500} fz={"12px"}>
{port.name}
</Text>
</Box>
</Card>
))}
</Box>
</fieldset>
</Grid.Col>
))}
</Grid>
</Box>
)}
</Grid.Col>
<div
{loading ? (
<Box
style={{
height: "300px",
width: "100%",
display: "flex",
justifyContent: "space-between",
borderTop: "1px #ccc solid",
marginTop: "6px",
minWidth: "98%",
justifyContent: "center",
alignItems: "center",
}}
>
<Loader color="blue" />
</Box>
) : (
<Grid>
<Grid.Col span={12}>
{listPorts?.length > 0 && (
<Box>
<Grid>
{listPorts?.map((group, key) => (
<Grid.Col
key={key}
span={
group?.length > 20
? 11
: group?.length > 0 && group?.length < 4
? 1
: 12
}
>
<fieldset
style={{
padding: "4px 6px",
paddingBottom: "12px",
height: "-webkit-fill-available",
}}
>
<legend>
<Text fw={700} c={"#514d4d"} fz={"sm"}>
{group[0]?.name.substring(0, 2) || ""}
</Text>
</legend>
<Box
style={{
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
gap: "10px",
overflowY: "auto",
maxHeight: "300px",
}}
>
{group?.length > 0 &&
sortedPorts(group)?.map((port, i) => (
<Card
key={i}
shadow="sm"
padding="xs"
radius="md"
withBorder
style={{
position: "relative",
width: "60px",
backgroundColor:
port.poe === "ON"
? "#f2dcf8"
: port.status === "ON"
? "#d4f1d3"
: "#f5f5f5",
cursor: "pointer",
border: listPortsSelected.find(
(el) => el.name === port.name
)?.name
? "1px solid #0018ff"
: "",
}}
className={`${
isSubmit ? classes.isDisabled : ""
}`}
onClick={() => {
toggleSelect(port);
}}
>
<Box
style={{
display: "flex",
alignItems: "center",
gap: "2px",
flexDirection: "column",
flexWrap: "wrap",
}}
>
<IconSection
size={"18px"}
color={
port.poe === "ON"
? "#b722d4"
: port.status === "ON"
? "#40c057"
: "#b8b8b8"
}
/>
<Text fw={500} fz={"12px"}>
{port.name}
</Text>
</Box>
</Card>
))}
</Box>
</fieldset>
</Grid.Col>
))}
</Grid>
</Box>
)}
</Grid.Col>
<div
style={{
display: "flex",
justifyContent: "left",
justifyContent: "space-between",
borderTop: "1px #ccc solid",
marginTop: "6px",
marginBottom: "10px",
gap: "20px",
minWidth: "98%",
}}
>
<Button
disabled={isSubmit}
title={
listPortsSelected.length === listPorts.flat().length
? "Deselect All"
: "Select All"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
onClick={() => {
if (listPortsSelected.length === listPorts.flat().length) {
setListPortsSelected([]);
} else {
setListPortsSelected(listPorts.flat());
}
<div
style={{
display: "flex",
justifyContent: "left",
marginTop: "6px",
marginBottom: "10px",
gap: "20px",
}}
>
{listPortsSelected.length === listPorts.flat().length
? "Deselect All"
: "Select All"}{" "}
{"(" + listPorts.flat().length + ")"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switches &&
(dataStation?.switches[0]?.status === "DISCONNECTED" ||
dataStation?.switches[0]?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Restart All"
: "Restart Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="yellow"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
<Button
disabled={isSubmit}
title={
listPortsSelected.length === listPorts.flat().length
? "Deselect All"
: "Select All"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
onClick={() => {
if (listPortsSelected.length === listPorts.flat().length) {
setListPortsSelected([]);
} else {
setListPortsSelected(listPorts.flat());
}
}}
>
{listPortsSelected.length === listPorts.flat().length
? "Deselect All"
: "Select All"}{" "}
{"(" + listPorts.flat().length + ")"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Restart All"
: "Restart Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="yellow"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (
listPortsRestart.filter((el) => el.poe !== "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "restart",
station_id: Number(stationAPI.id),
}
);
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
if (
listPortsRestart.filter((el) => el.poe === "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "restart-poe",
station_id: Number(stationAPI.id),
}
);
// listPortsRestart.forEach((el) => {
// updateStatusPort(el.name, 'OFF')
// })
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Restart All"
: "Restart Selected"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switches &&
(dataStation?.switches[0]?.status === "DISCONNECTED" ||
dataStation?.switches[0]?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn On All"
: "Turn On Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="green"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
? "Restart All"
: "Restart Selected"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn On All"
: "Turn On Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="green"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (
listPortsRestart.filter((el) => el.poe !== "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "on",
station_id: Number(stationAPI.id),
}
);
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
if (
listPortsRestart.filter((el) => el.poe === "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "on-poe",
station_id: Number(stationAPI.id),
}
);
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn On All"
: "Turn On Selected"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switches &&
(dataStation?.switches[0]?.status === "DISCONNECTED" ||
dataStation?.switches[0]?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="red"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (listPortsRestart.filter((el) => el.poe !== "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
? "Turn On All"
: "Turn On Selected"}
</Button>
<Button
disabled={
isSubmit ||
listPorts.flat().length === 0 ||
listPortsSelected.length === 0 ||
(dataStation?.switch &&
(dataStation?.switch?.status === "DISCONNECTED" ||
dataStation?.switch?.status === "TIMEOUT"))
}
title={
listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"
}
// mt={'xs'}
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="red"
onClick={() => {
const listPortsRestart =
listPortsSelected?.length > 0
? listPortsSelected
: listPorts.flat();
if (
listPortsRestart.filter((el) => el.poe !== "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe !== "ON")
.map((el) => el.name),
command: "off",
station_id: Number(stationAPI.id),
}
);
if (listPortsRestart.filter((el) => el.poe === "ON").length > 0)
socket?.emit(
SOCKET_EVENTS.SEND_COMMAND_TO_SWITCH
.SEND_COMMAND_TO_SWITCH_FROM_WEB,
{
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
if (
listPortsRestart.filter((el) => el.poe === "ON").length > 0
)
socket?.emit("control_switch", {
ports: listPortsRestart
.filter((el) => el.poe === "ON")
.map((el) => el.name),
command: "off-poe",
station_id: Number(stationAPI.id),
}
);
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"}
</Button>
station: stationAPI,
ip: stationAPI?.switch_control_ip,
});
setListPortsSelected([]);
setIsSubmit(true);
setTimeout(() => {
setIsSubmit(false);
}, 5000);
}}
>
{listPortsSelected.length === 0 ||
listPortsSelected.length === listPorts.flat().length
? "Turn Off All"
: "Turn Off Selected"}
</Button>
</div>
</div>
<div style={{ marginTop: "6px" }}>
<Button
miw={"80px"}
size="xs"
fz={"sm"}
variant="filled"
color="yellow"
onClick={() => {
if (openedAPC) openedAPC();
}}
>
APC Control
</Button>
</div>
</div>
</Grid>
</Grid>
)}
</Drawer>
);
};

View File

@ -54,6 +54,7 @@ export type TStation = {
switch_control_username?: string; // Optional
switch_control_password?: string; // Optional
switches?: SwitchesProps[];
switch?: SwitchesProps;
};
export type TLine = {