235 lines
12 KiB
JavaScript
235 lines
12 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
||
Панель мониторинга: Корневая панель доски задач
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import React, { useState } from "react"; //Классы React
|
||
import { DragDropContext, Droppable } from "react-beautiful-dnd"; //Работа с drag&drop
|
||
import { Stack, Card, CardHeader, CardContent, Box, Button, IconButton, Icon, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||
import { TaskCard } from "./components/task_card"; //Компонент карточки события
|
||
import { TaskFormDialog } from "./components/task_form"; //Компонент формы события
|
||
import { Filter } from "./filter.js"; //Компонент фильтров
|
||
import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
|
||
import { TaskCardSettings } from "./components/task_card_settings.js"; //Компонент настроек карточки события
|
||
import { useTasks, useWindowResize, COLORS } from "./hooks.js"; //Вспомогательные хуки
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Стили
|
||
const STYLES = {
|
||
CONTAINER: { width: "100%", padding: 1 },
|
||
STATUS_BLOCK: statusColor => {
|
||
return {
|
||
maxWidth: "300px",
|
||
minWidth: "300px",
|
||
minHeight: "100px",
|
||
backgroundColor: statusColor,
|
||
padding: "8px"
|
||
};
|
||
},
|
||
BLOCK_OPACITY: isAvailable => {
|
||
return isAvailable ? { opacity: 1 } : { opacity: 0.5 };
|
||
},
|
||
MARK_INFO: {
|
||
textAlign: "left",
|
||
textOverflow: "ellipsis",
|
||
overflow: "hidden",
|
||
whiteSpace: "pre",
|
||
maxWidth: "calc(250px)",
|
||
width: "-webkit-fill-available"
|
||
}
|
||
};
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Корневая панель доски задач
|
||
const ClntTaskBoard = () => {
|
||
//Собственное состояние
|
||
const [
|
||
tasks,
|
||
eventRoutes,
|
||
docLinks,
|
||
taskFormOpen,
|
||
setTaskFormOpen,
|
||
cardSettings,
|
||
handleFilterOk,
|
||
handleFilterCancel,
|
||
handleFilterClick,
|
||
handleCardSettingsClick,
|
||
handleCardSettingsOk,
|
||
handleCardSettingsCancel,
|
||
handleReload,
|
||
onDragEnd,
|
||
handleOrderChanged
|
||
] = useTasks();
|
||
|
||
//Состояние доступных маршрутов события
|
||
const [availableRoutes, setAvailableRoutes] = useState({ sorce: "", routes: [] });
|
||
|
||
//Состояние перетаскиваемого события
|
||
const [dragItem, setDragItem] = useState({ type: "", status: "" });
|
||
|
||
const clearDragItem = () => {
|
||
setDragItem({ type: "", status: "" });
|
||
};
|
||
|
||
//Очистка состояния
|
||
const clearARState = () => {
|
||
setAvailableRoutes({ sorce: "", routes: [] });
|
||
};
|
||
|
||
//Проверка доступности карточки события
|
||
const isCardAvailable = code => {
|
||
return availableRoutes.sorce === code || availableRoutes.routes.find(r => r.dest === code) || !availableRoutes.sorce ? true : false;
|
||
};
|
||
|
||
//Состояние ширины и высоты рабочей области окна
|
||
// eslint-disable-next-line no-unused-vars
|
||
const [width, height] = useWindowResize();
|
||
|
||
// useEffect(() => {
|
||
// console.log(`w: ${width}, h: ${height}`);
|
||
// }, [width, height]);
|
||
|
||
// useEffect(() => {
|
||
// console.log(availableRoutes);
|
||
// }, [availableRoutes]);
|
||
|
||
return (
|
||
<Box sx={STYLES.CONTAINER}>
|
||
{tasks.filters.isOpen ? (
|
||
<FilterDialog initial={tasks.filters.values} docs={docLinks} onOk={handleFilterOk} onCancel={handleFilterCancel} />
|
||
) : null}
|
||
<Filter
|
||
filter={tasks.filters.values}
|
||
selectedDoc={tasks.filters.values.docLink ? docLinks.find(d => d.id === tasks.filters.values.docLink) : null}
|
||
handleFilterClick={handleFilterClick}
|
||
handleReload={handleReload}
|
||
orders={tasks.orders}
|
||
handleOrderChanged={handleOrderChanged}
|
||
/>
|
||
{tasks.filters.values.type ? (
|
||
<DragDropContext
|
||
onDragStart={e => {
|
||
let srcCode = tasks.statuses.find(s => s.id == e.source.droppableId).code;
|
||
setAvailableRoutes({ sorce: srcCode, routes: [...eventRoutes.filter(r => r.src === srcCode)] });
|
||
}}
|
||
onDragEnd={e => {
|
||
onDragEnd(e);
|
||
clearARState();
|
||
}}
|
||
>
|
||
<div>
|
||
<Droppable droppableId="Statuses" type="droppableTask">
|
||
{provided => (
|
||
<div ref={provided.innerRef}>
|
||
<Stack direction="row" spacing={2}>
|
||
{tasks.statuses.map((status, index) => (
|
||
<div key={index}>
|
||
<Droppable isDropDisabled={!isCardAvailable(status.code)} droppableId={status.id.toString()}>
|
||
{provided => (
|
||
<div ref={provided.innerRef}>
|
||
<Card
|
||
className="category-card"
|
||
sx={{
|
||
...STYLES.STATUS_BLOCK(status.color),
|
||
...STYLES.BLOCK_OPACITY(isCardAvailable(status.code))
|
||
}}
|
||
>
|
||
<CardHeader
|
||
action={
|
||
<IconButton
|
||
aria-label="settings"
|
||
onClick={() => handleCardSettingsClick(status)}
|
||
>
|
||
<Icon>more_vert</Icon>
|
||
</IconButton>
|
||
}
|
||
title={
|
||
<Typography sx={STYLES.MARK_INFO} title={status.caption} variant="h5">
|
||
{status.caption}
|
||
</Typography>
|
||
}
|
||
subheader={
|
||
<Button
|
||
onClick={() => {
|
||
setDragItem({ type: tasks.filters.values.type, status: status.code });
|
||
setTaskFormOpen(true);
|
||
}}
|
||
>
|
||
+ Добавить
|
||
</Button>
|
||
}
|
||
sx={{ padding: 0 }}
|
||
/>
|
||
<CardContent
|
||
sx={{
|
||
padding: 0,
|
||
overflowY: "auto",
|
||
maxHeight: height * 0.749
|
||
}}
|
||
>
|
||
<Stack spacing={1}>
|
||
{tasks.rows
|
||
.filter(item => item.category === status.id)
|
||
.map((item, index) => (
|
||
<TaskCard
|
||
task={item}
|
||
index={index}
|
||
handleReload={handleReload}
|
||
key={item.id}
|
||
/>
|
||
))}
|
||
{provided.placeholder}
|
||
</Stack>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
)}
|
||
</Droppable>
|
||
</div>
|
||
))}
|
||
</Stack>
|
||
{provided.placeholder}
|
||
</div>
|
||
)}
|
||
</Droppable>
|
||
</div>
|
||
</DragDropContext>
|
||
) : null}
|
||
{taskFormOpen ? (
|
||
<TaskFormDialog
|
||
taskType={dragItem.type}
|
||
taskStatus={dragItem.status}
|
||
onClose={() => {
|
||
setTaskFormOpen(false);
|
||
clearDragItem();
|
||
}}
|
||
/>
|
||
) : null}
|
||
{cardSettings.isOpen ? (
|
||
<TaskCardSettings
|
||
initial={cardSettings.settings}
|
||
availableClrs={COLORS}
|
||
onOk={handleCardSettingsOk}
|
||
onCancel={handleCardSettingsCancel}
|
||
/>
|
||
) : null}
|
||
</Box>
|
||
);
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { ClntTaskBoard };
|