226 lines
7.2 KiB
TypeScript
226 lines
7.2 KiB
TypeScript
import Table from "@mui/material/Table";
|
||
import TableBody from "@mui/material/TableBody";
|
||
import TableCell from "@mui/material/TableCell";
|
||
import TableContainer from "@mui/material/TableContainer";
|
||
import TableHead from "@mui/material/TableHead";
|
||
import TableRow from "@mui/material/TableRow";
|
||
import Paper from "@mui/material/Paper";
|
||
import { Check, RotateCcw, Send, X } from "lucide-react";
|
||
import {
|
||
authInstance,
|
||
devicesStore,
|
||
Modal,
|
||
snapshotStore,
|
||
vehicleStore,
|
||
} from "@shared";
|
||
import { useEffect, useState } from "react";
|
||
import { observer } from "mobx-react-lite";
|
||
import { Button, Checkbox } from "@mui/material";
|
||
|
||
const formatDate = (dateString: string | undefined) => {
|
||
if (!dateString) return "Нет данных";
|
||
|
||
try {
|
||
const date = new Date(dateString);
|
||
return new Intl.DateTimeFormat("ru-RU", {
|
||
day: "2-digit",
|
||
month: "2-digit",
|
||
year: "numeric",
|
||
hour: "2-digit",
|
||
minute: "2-digit",
|
||
second: "2-digit",
|
||
hour12: false,
|
||
}).format(date);
|
||
} catch (error) {
|
||
console.error("Error formatting date:", error);
|
||
return "Некорректная дата";
|
||
}
|
||
};
|
||
|
||
function createData(
|
||
uuid: string,
|
||
online: boolean,
|
||
lastUpdate: string,
|
||
gps: boolean,
|
||
media: boolean,
|
||
connection: boolean
|
||
) {
|
||
return { uuid, online, lastUpdate, gps, media, connection };
|
||
}
|
||
|
||
const rows = (devices: any[], vehicles: any[]) => {
|
||
return devices.map((device) => {
|
||
const { device_status } = vehicles.find(
|
||
(v) => v?.device_status?.device_uuid === device
|
||
);
|
||
const findVehicle = vehicles.find((v) => v?.vehicle?.uuid === device);
|
||
|
||
console.log(findVehicle);
|
||
return createData(
|
||
findVehicle?.vehicle?.tail_number ?? "1243000",
|
||
device_status?.online,
|
||
device_status?.last_update,
|
||
device_status?.gps_ok,
|
||
device_status?.media_service_ok,
|
||
device_status?.is_connected
|
||
);
|
||
});
|
||
};
|
||
|
||
export const DevicesTable = observer(() => {
|
||
const {
|
||
devices,
|
||
getDevices,
|
||
uuid,
|
||
setSelectedDevice,
|
||
sendSnapshotModalOpen,
|
||
toggleSendSnapshotModal,
|
||
} = devicesStore;
|
||
const { snapshots, getSnapshots } = snapshotStore;
|
||
const { vehicles, getVehicles } = vehicleStore;
|
||
const [selectedDevices, setSelectedDevices] = useState<string[]>([]);
|
||
useEffect(() => {
|
||
const fetchData = async () => {
|
||
await getVehicles();
|
||
await getDevices();
|
||
await getSnapshots();
|
||
};
|
||
fetchData();
|
||
}, []);
|
||
|
||
const handleSendSnapshot = (uuid: string) => {
|
||
setSelectedDevice(uuid);
|
||
toggleSendSnapshotModal();
|
||
};
|
||
|
||
const handleReloadStatus = async (uuid: string) => {
|
||
setSelectedDevice(uuid);
|
||
await authInstance.post(`/devices/${uuid}/request-status`);
|
||
await getDevices();
|
||
};
|
||
|
||
const handleSelectDevice = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||
if (event.target.checked) {
|
||
setSelectedDevices([...selectedDevices, event.target.value]);
|
||
} else {
|
||
setSelectedDevices(
|
||
selectedDevices.filter((device) => device !== event.target.value)
|
||
);
|
||
}
|
||
};
|
||
|
||
const handleSendSnapshotAction = async (uuid: string, snapshotId: string) => {
|
||
await authInstance.post(`/devices/${uuid}/force-snapshot`, {
|
||
snapshot_id: snapshotId,
|
||
});
|
||
await getDevices();
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<TableContainer component={Paper}>
|
||
<div className="flex justify-end p-3 gap-5">
|
||
<Button variant="contained" color="primary">
|
||
Выбрать все
|
||
</Button>
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
disabled={selectedDevices.length === 0}
|
||
className="ml-auto"
|
||
onClick={() => handleSendSnapshot(uuid ?? "")}
|
||
>
|
||
Отправить снапшот
|
||
</Button>
|
||
</div>
|
||
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||
<TableHead>
|
||
<TableRow>
|
||
<TableCell align="center"></TableCell>
|
||
<TableCell align="center">Бортовой номер</TableCell>
|
||
<TableCell align="center">Онлайн</TableCell>
|
||
<TableCell align="center">Последнее обновление</TableCell>
|
||
<TableCell align="center">ГПС</TableCell>
|
||
<TableCell align="center">Медиа-данные</TableCell>
|
||
<TableCell align="center">Подключение</TableCell>
|
||
<TableCell align="center">Перезапросить</TableCell>
|
||
</TableRow>
|
||
</TableHead>
|
||
<TableBody>
|
||
{rows(devices, vehicles).map((row) => (
|
||
<TableRow
|
||
key={row?.uuid}
|
||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||
className="flex items-center"
|
||
>
|
||
<TableCell align="center">
|
||
<Checkbox
|
||
className="h-full"
|
||
onChange={handleSelectDevice}
|
||
value={row?.uuid}
|
||
/>
|
||
</TableCell>
|
||
|
||
<TableCell align="center" component="th" scope="row">
|
||
{row?.uuid}
|
||
</TableCell>
|
||
<TableCell align="center">
|
||
{row?.online ? (
|
||
<Check className="m-auto text-green-500" />
|
||
) : (
|
||
<X className="m-auto text-red-500" />
|
||
)}
|
||
</TableCell>
|
||
<TableCell align="center">
|
||
{formatDate(row?.lastUpdate)}
|
||
</TableCell>
|
||
<TableCell align="center">
|
||
{row?.gps ? (
|
||
<Check className="m-auto text-green-500" />
|
||
) : (
|
||
<X className="m-auto text-red-500" />
|
||
)}
|
||
</TableCell>
|
||
<TableCell align="center">
|
||
{row?.media ? (
|
||
<Check className="m-auto text-green-500" />
|
||
) : (
|
||
<X className="m-auto text-red-500" />
|
||
)}
|
||
</TableCell>
|
||
<TableCell align="center">
|
||
{row?.connection ? (
|
||
<Check className="m-auto text-green-500" />
|
||
) : (
|
||
<X className="m-auto text-red-500" />
|
||
)}
|
||
</TableCell>
|
||
<TableCell align="center" className="flex justify-center">
|
||
<button onClick={() => handleReloadStatus(row?.uuid ?? "")}>
|
||
<RotateCcw className="m-auto" />
|
||
</button>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</TableContainer>
|
||
<Modal open={sendSnapshotModalOpen} onClose={toggleSendSnapshotModal}>
|
||
<p>Выбрать снапшот</p>
|
||
<div className="mt-5 flex flex-col gap-2 max-h-[300px] overflow-y-auto">
|
||
{snapshots &&
|
||
snapshots.map((snapshot) => (
|
||
<button
|
||
onClick={() => handleSendSnapshotAction(uuid!, snapshot.ID)}
|
||
className="p-2 rounded-xl bg-slate-100"
|
||
key={snapshot.ID}
|
||
>
|
||
{snapshot.Name}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</Modal>
|
||
</>
|
||
);
|
||
});
|