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