Update
This commit is contained in:
parent
240dfdff2c
commit
54ed6c95e8
|
|
@ -8,38 +8,39 @@ export default class StationsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async store({ request, response }: HttpContext) {
|
public async store({ request, response }: HttpContext) {
|
||||||
let payload = request.only(Array.from(Station.$columnsDefinitions.keys()))
|
const payload = request.only(Array.from(Station.$columnsDefinitions.keys()))
|
||||||
let lines: Line[] = request.body().lines || []
|
const lines: Line[] = request.body().lines || []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stationName = await Station.findBy('name', payload.name)
|
// Kiểm tra trùng name hoặc ip
|
||||||
if (stationName) return response.status(400).json({ message: 'Station name exist!' })
|
if (await Station.findBy('name', payload.name))
|
||||||
|
return response.status(400).json({ message: 'Station name exist!' })
|
||||||
|
|
||||||
const stationIP = await Station.findBy('ip', payload.ip)
|
if (await Station.findBy('ip', payload.ip))
|
||||||
if (stationIP) return response.status(400).json({ message: 'Ip of station is exist!' })
|
return response.status(400).json({ message: 'Ip of station is exist!' })
|
||||||
|
|
||||||
|
// Tạo station
|
||||||
const station = await Station.create(payload)
|
const station = await Station.create(payload)
|
||||||
|
|
||||||
|
// Xử lý lines (chờ từng dòng)
|
||||||
const newLines: Line[] = []
|
const newLines: Line[] = []
|
||||||
if (lines && Array.isArray(lines)) {
|
for (const line of lines) {
|
||||||
lines.forEach(async (line) => {
|
|
||||||
if (line.id) {
|
if (line.id) {
|
||||||
const value = await Line.find(line.id)
|
const existing = await Line.find(line.id)
|
||||||
if (value) {
|
if (existing) {
|
||||||
Object.assign(value, line)
|
Object.assign(existing, line)
|
||||||
await value.save()
|
await existing.save()
|
||||||
newLines.push(value)
|
newLines.push(existing)
|
||||||
} else {
|
continue
|
||||||
const value1 = await Line.create({ ...line, stationId: station.id })
|
|
||||||
newLines.push(value1)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const value2 = await Line.create({ ...line, stationId: station.id })
|
|
||||||
newLines.push(value2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tạo mới nếu không tồn tại
|
||||||
|
const created = await Line.create({ ...line, stationId: station.id })
|
||||||
|
newLines.push(created)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lấy lại station kèm lines
|
||||||
const resStation = await Station.query().where('id', station.id).preload('lines')
|
const resStation = await Station.query().where('id', station.id).preload('lines')
|
||||||
|
|
||||||
return response.created({
|
return response.created({
|
||||||
|
|
@ -48,7 +49,12 @@ export default class StationsController {
|
||||||
data: resStation.map((el) => ({ ...el.$original, lines: newLines })),
|
data: resStation.map((el) => ({ ...el.$original, lines: newLines })),
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return response.badRequest({ error: error, message: 'Station create failed', status: false })
|
console.error(error)
|
||||||
|
return response.badRequest({
|
||||||
|
error,
|
||||||
|
message: 'Station create failed',
|
||||||
|
status: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +71,13 @@ export default class StationsController {
|
||||||
let lines: Line[] = request.body().lines || []
|
let lines: Line[] = request.body().lines || []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Kiểm tra trùng name hoặc ip
|
||||||
|
if (await Station.findBy('name', payload.name))
|
||||||
|
return response.status(400).json({ message: 'Station name exist!' })
|
||||||
|
|
||||||
|
if (await Station.findBy('ip', payload.ip))
|
||||||
|
return response.status(400).json({ message: 'Ip of station is exist!' })
|
||||||
|
|
||||||
const station = await Station.find(request.body().id)
|
const station = await Station.find(request.body().id)
|
||||||
|
|
||||||
// If the station does not exist, return a 404 response
|
// If the station does not exist, return a 404 response
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,9 @@ dist-ssr
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.production.local
|
||||||
|
.env.development.local
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import ModalTerminal from "./components/ModalTerminal";
|
||||||
import PageLogin from "./components/Authentication/LoginPage";
|
import PageLogin from "./components/Authentication/LoginPage";
|
||||||
import DrawerLogs from "./components/DrawerLogs";
|
import DrawerLogs from "./components/DrawerLogs";
|
||||||
import DraggableTabs from "./components/DragTabs";
|
import DraggableTabs from "./components/DragTabs";
|
||||||
|
import { isJsonString } from "./untils/helper";
|
||||||
|
|
||||||
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
|
||||||
|
|
@ -46,11 +47,15 @@ const apiUrl = import.meta.env.VITE_BACKEND_URL;
|
||||||
function App() {
|
function App() {
|
||||||
const user = useMemo(() => {
|
const user = useMemo(() => {
|
||||||
return localStorage.getItem("user") &&
|
return localStorage.getItem("user") &&
|
||||||
typeof localStorage.getItem("user") === "string"
|
isJsonString(localStorage.getItem("user"))
|
||||||
? JSON.parse(localStorage.getItem("user") || "")
|
? JSON.parse(localStorage.getItem("user") || "")
|
||||||
: null;
|
: null;
|
||||||
}, []);
|
}, []);
|
||||||
if (!user) window.location.href = "/";
|
|
||||||
|
if (!user) {
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
window.location.href = "/";
|
||||||
|
}
|
||||||
|
|
||||||
document.title = "Automation Test";
|
document.title = "Automation Test";
|
||||||
const { socket } = useSocket();
|
const { socket } = useSocket();
|
||||||
|
|
@ -484,6 +489,8 @@ function App() {
|
||||||
setLoadingTerminal(true);
|
setLoadingTerminal(true);
|
||||||
}, 100);
|
}, 100);
|
||||||
}}
|
}}
|
||||||
|
setActive={setActiveTab}
|
||||||
|
active={activeTab}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<StationSetting
|
<StationSetting
|
||||||
|
|
@ -496,9 +503,14 @@ function App() {
|
||||||
}}
|
}}
|
||||||
isEdit={isEditStation}
|
isEdit={isEditStation}
|
||||||
setStations={setStations}
|
setStations={setStations}
|
||||||
setActiveTab={() =>
|
setActiveTab={(id: string) => {
|
||||||
setActiveTab(stations.length ? stations[0]?.id.toString() : "0")
|
setActiveTab(id);
|
||||||
}
|
setLoadingTerminal(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
setLoadingTerminal(true);
|
||||||
|
}, 100);
|
||||||
|
}}
|
||||||
|
stations={stations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ModalTerminal
|
<ModalTerminal
|
||||||
|
|
@ -523,7 +535,13 @@ function App() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Main() {
|
export default function Main() {
|
||||||
const user = localStorage.getItem("user");
|
const user = useMemo(() => {
|
||||||
|
return localStorage.getItem("user") &&
|
||||||
|
isJsonString(localStorage.getItem("user"))
|
||||||
|
? JSON.parse(localStorage.getItem("user") || "")
|
||||||
|
: null;
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MantineProvider>
|
<MantineProvider>
|
||||||
<SocketProvider>
|
<SocketProvider>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Anchor, Image, Paper, Text } from "@mantine/core";
|
import { Anchor, Image, Paper, Text } from "@mantine/core";
|
||||||
import Login from "./Login";
|
import Login from "./Login";
|
||||||
import Register from "./Register";
|
import Register from "./Register";
|
||||||
|
|
@ -7,6 +7,12 @@ import classes from "./AuthenticationImage.module.css";
|
||||||
export const PageLogin = () => {
|
export const PageLogin = () => {
|
||||||
const [isRegister, setIsRegister] = useState(false);
|
const [isRegister, setIsRegister] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (localStorage.getItem("user")) {
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ interface DraggableTabsProps {
|
||||||
setIsEditStation: (value: React.SetStateAction<boolean>) => void;
|
setIsEditStation: (value: React.SetStateAction<boolean>) => void;
|
||||||
setIsOpenAddStation: (value: React.SetStateAction<boolean>) => void;
|
setIsOpenAddStation: (value: React.SetStateAction<boolean>) => void;
|
||||||
setStationEdit: (value: React.SetStateAction<TStation | undefined>) => void;
|
setStationEdit: (value: React.SetStateAction<TStation | undefined>) => void;
|
||||||
|
active: string;
|
||||||
|
setActive: (value: React.SetStateAction<string>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SortableTab({
|
function SortableTab({
|
||||||
|
|
@ -99,6 +101,8 @@ export default function DraggableTabs({
|
||||||
setIsEditStation,
|
setIsEditStation,
|
||||||
setIsOpenAddStation,
|
setIsOpenAddStation,
|
||||||
setStationEdit,
|
setStationEdit,
|
||||||
|
active,
|
||||||
|
setActive,
|
||||||
}: DraggableTabsProps) {
|
}: DraggableTabsProps) {
|
||||||
const user = useMemo(() => {
|
const user = useMemo(() => {
|
||||||
return localStorage.getItem("user") &&
|
return localStorage.getItem("user") &&
|
||||||
|
|
@ -109,9 +113,9 @@ export default function DraggableTabs({
|
||||||
const [tabs, setTabs] = useState<TStation[]>(tabsData);
|
const [tabs, setTabs] = useState<TStation[]>(tabsData);
|
||||||
const [isChangeTab, setIsChangeTab] = useState<boolean>(false);
|
const [isChangeTab, setIsChangeTab] = useState<boolean>(false);
|
||||||
const [isSetActive, setIsSetActive] = useState<boolean>(false);
|
const [isSetActive, setIsSetActive] = useState<boolean>(false);
|
||||||
const [active, setActive] = useState<string | null>(
|
// const [active, setActive] = useState<string | null>(
|
||||||
tabsData?.length > 0 ? tabsData[0]?.id.toString() : null
|
// tabsData?.length > 0 ? tabsData[0]?.id.toString() : null
|
||||||
);
|
// );
|
||||||
|
|
||||||
const sensors = useSensors(useSensor(PointerSensor));
|
const sensors = useSensors(useSensor(PointerSensor));
|
||||||
|
|
||||||
|
|
@ -119,10 +123,12 @@ export default function DraggableTabs({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isChangeTab) {
|
if (isChangeTab) {
|
||||||
setTabs((pre) =>
|
setTabs((pre) =>
|
||||||
pre.map((t) => {
|
pre
|
||||||
|
.map((t) => {
|
||||||
const updatedTab = tabsData.find((td) => td.id === t.id);
|
const updatedTab = tabsData.find((td) => td.id === t.id);
|
||||||
return updatedTab ? updatedTab : t;
|
return updatedTab ? updatedTab : t;
|
||||||
})
|
})
|
||||||
|
.filter((t) => (tabsData.find((td) => td.id === t.id) ? true : false))
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const saved = localStorage.getItem(storageKey);
|
const saved = localStorage.getItem(storageKey);
|
||||||
|
|
@ -193,7 +199,7 @@ export default function DraggableTabs({
|
||||||
setIsChangeTab(false);
|
setIsChangeTab(false);
|
||||||
setIsSetActive(false);
|
setIsSetActive(false);
|
||||||
setTabs([]);
|
setTabs([]);
|
||||||
setActive(null);
|
setActive("0");
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -208,7 +214,7 @@ export default function DraggableTabs({
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
setIsChangeTab(true);
|
setIsChangeTab(true);
|
||||||
onChange(val);
|
onChange(val);
|
||||||
setActive(val);
|
setActive(val || "0");
|
||||||
}}
|
}}
|
||||||
w={w}
|
w={w}
|
||||||
>
|
>
|
||||||
|
|
@ -242,7 +248,7 @@ export default function DraggableTabs({
|
||||||
))}
|
))}
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
|
|
||||||
<Flex gap={"sm"}>
|
<Flex gap={"md"} ms={"xs"} align={"center"}>
|
||||||
{Number(active) ? (
|
{Number(active) ? (
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
title="Edit Station"
|
title="Edit Station"
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,15 @@ const StationSetting = ({
|
||||||
dataStation,
|
dataStation,
|
||||||
setStations,
|
setStations,
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
|
stations,
|
||||||
}: {
|
}: {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
dataStation?: TStation;
|
dataStation?: TStation;
|
||||||
setStations: (value: React.SetStateAction<TStation[]>) => void;
|
setStations: (value: React.SetStateAction<TStation[]>) => void;
|
||||||
setActiveTab: () => void;
|
setActiveTab: (value: string) => void;
|
||||||
|
stations: TStation[];
|
||||||
}) => {
|
}) => {
|
||||||
const [lines, setLines] = useState<TLine[]>([lineInit]);
|
const [lines, setLines] = useState<TLine[]>([lineInit]);
|
||||||
const [openConfirm, setOpenConfirm] = useState<boolean>(false);
|
const [openConfirm, setOpenConfirm] = useState<boolean>(false);
|
||||||
|
|
@ -258,8 +260,11 @@ const StationSetting = ({
|
||||||
id: dataStation?.id,
|
id: dataStation?.id,
|
||||||
});
|
});
|
||||||
if (response.data.status) {
|
if (response.data.status) {
|
||||||
setStations((pre) => pre.filter((el) => el.id !== dataStation?.id));
|
const listStations = stations.filter((el) => el.id !== dataStation?.id);
|
||||||
setActiveTab();
|
setStations(listStations);
|
||||||
|
setActiveTab(
|
||||||
|
listStations.length ? listStations[0]?.id.toString() : "0"
|
||||||
|
);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
message: response.data.message,
|
message: response.data.message,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import React, {
|
||||||
import { io, Socket } from "socket.io-client";
|
import { io, Socket } from "socket.io-client";
|
||||||
import { SOCKET_EVENTS } from "../untils/constanst";
|
import { SOCKET_EVENTS } from "../untils/constanst";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
|
import { isJsonString } from "../untils/helper";
|
||||||
|
|
||||||
interface ISocketContext {
|
interface ISocketContext {
|
||||||
socket: Socket | null;
|
socket: Socket | null;
|
||||||
|
|
@ -23,7 +24,7 @@ export const SocketProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||||
const [socket, setSocket] = useState<Socket | null>(null);
|
const [socket, setSocket] = useState<Socket | null>(null);
|
||||||
const user = useMemo(() => {
|
const user = useMemo(() => {
|
||||||
return localStorage.getItem("user") &&
|
return localStorage.getItem("user") &&
|
||||||
typeof localStorage.getItem("user") === "string"
|
isJsonString(localStorage.getItem("user"))
|
||||||
? JSON.parse(localStorage.getItem("user") || "")
|
? JSON.parse(localStorage.getItem("user") || "")
|
||||||
: null;
|
: null;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,15 @@ export const passwordRegex =
|
||||||
/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&#])[A-Za-z\d@$!%*?&#]{8,}$/;
|
/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&#])[A-Za-z\d@$!%*?&#]{8,}$/;
|
||||||
|
|
||||||
export const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
export const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
||||||
|
|
||||||
|
export function isJsonString(str: string | null) {
|
||||||
|
if (typeof str !== "string") return false;
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(str);
|
||||||
|
// Kiểm tra xem parsed có phải là object hoặc array thật sự
|
||||||
|
return parsed !== null && typeof parsed === "object";
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error isJsonString", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue