diff --git a/app/panels/clnt_task_board/clnt_task_board.js b/app/panels/clnt_task_board/clnt_task_board.js
index 48ae00e..1137d96 100644
--- a/app/panels/clnt_task_board/clnt_task_board.js
+++ b/app/panels/clnt_task_board/clnt_task_board.js
@@ -7,18 +7,18 @@
//Подключение библиотек
//---------------------
-import React, { useState } from "react"; //Классы React
+import React, { useEffect, useState, useCallback } 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 { Stack, Box, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
+import { StatusCard } from "./components/status_card.js";
+import { TaskDialog } from "./task_dialog.js"; //Компонент формы события
import { Filter } from "./filter.js"; //Компонент фильтров
-import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
-import { TaskCardSettings } from "./components/task_card_settings.js"; //Компонент настроек карточки события
-import { useTasks, useSettings, COLORS } from "./hooks.js"; //Вспомогательные хуки
+import { useExtraData, useTasks, useSettings } from "./hooks/hooks.js"; //Вспомогательные хуки
+import { useFilters } from "./hooks/filter_hooks.js";
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
import { NoteDialog } from "./components/note_dialog.js"; //Диалог примечания
import { SettingsDialog } from "./components/settings_dialog.js"; //Диалог дополнительных настроек
+import { deepCopyObject } from "../../core/utils.js"; //Вспомогательные функции
//---------
//Константы
@@ -36,6 +36,8 @@ const FILTER_HEIGHT = "56px";
//Стили
const STYLES = {
CONTAINER: { width: "100%", padding: 0 },
+ FS_BOX: { display: "flex", alignItems: "center" },
+ SETTINGS_MARGIN: { marginLeft: "auto" },
STATUSES_STACK: { maxWidth: "99vw", paddingBottom: "5px", overflowX: "auto", ...APP_STYLES.SCROLL },
STATUS_BLOCK: statusColor => {
return {
@@ -79,39 +81,60 @@ const STYLES = {
//Корневая панель доски задач
const ClntTaskBoard = () => {
- //Собственное состояние
- const [
- tasks,
- taskFormOpen,
- setTaskFormOpen,
- cardSettings,
- handleFilterOk,
- handleFilterCancel,
- handleFilterClick,
- handleCardSettingsClick,
- handleCardSettingsOk,
- handleCardSettingsCancel,
- handleReload,
- onDragEnd,
- handleOrderChanged,
- getDocLinks
- ] = useTasks();
+ //Состояние вспомогательных диалогов
+ const [dialogsState, setDialogsState] = useState({
+ filterOpen: false,
+ settingsOpen: false,
+ note: { isOpen: false, callback: null },
+ taskDialogOpen: false
+ });
+
+ //Открыть-закрыть диалог фильтра
+ const handleFilterOpen = isOpen => {
+ setDialogsState(pv => ({ ...pv, filterOpen: isOpen }));
+ };
+
+ //Открыть-закрыть диалог дополнительных настроек
+ const handleSettingsOpen = () => setDialogsState(pv => ({ ...pv, settingsOpen: !dialogsState.settingsOpen }));
+
+ //Открыть-закрыть диалог примечания
+ const handleNoteOpen = (f = null) => setDialogsState(pv => ({ ...pv, note: { isOpen: !dialogsState.noteOpen, callback: f ? v => f(v) : null } }));
+
+ //Открыть-закрыть диалог события
+ const handleTaskDialogOpen = () => setDialogsState(pv => ({ ...pv, taskDialogOpen: !dialogsState.taskDialogOpen }));
+
+ //Состояние фильтров
+ const [filters, handleFiltersChange] = useFilters(handleFilterOpen);
+
+ //Состояние сортировок
+ const [orders, setOrders] = useState([]);
+
+ //Состояние дополнительных данных
+ const [extraData, getDocLinks, needUpdateExtraData] = useExtraData(filters.values.type);
+
+ //Состояние событий
+ const [tasks, handleReload, onDragEnd, needUpdateTasks] = useTasks({ filters, orders, extraData, getDocLinks });
//Состояние дополнительных настроек
- const [settings, settingsOpen, settingsClose, handleSettingsOk] = useSettings(tasks.statuses);
-
- //Состояние диалога примечания
- const [noteDialog, setNoteDialog] = useState({ visible: false, callback: null });
-
- //Открытие диалога примечания
- const handleNoteDialogOpen = f => setNoteDialog({ visible: true, callback: v => f(v) });
-
- //Закрытие диалога примечания
- const handleNoteDialogClose = () => setNoteDialog({ visible: false, callback: null });
+ const [settings, handleSettingsChange] = useSettings(tasks.statuses);
//Состояние доступных маршрутов события
const [availableRoutes, setAvailableRoutes] = useState({ sorce: "", routes: [] });
+ //При изменении сортировки
+ const handleOrderChanged = useCallback(
+ columnName => {
+ let newOrders = deepCopyObject(orders);
+ const colOrder = newOrders.find(o => o.name == columnName);
+ const newDirection = colOrder?.direction == "ASC" ? "DESC" : colOrder?.direction == "DESC" ? null : "ASC";
+ if (newDirection == null && colOrder) newOrders.splice(newOrders.indexOf(colOrder), 1);
+ if (newDirection != null && !colOrder) newOrders.push({ name: columnName, direction: newDirection });
+ if (newDirection != null && colOrder) colOrder.direction = newDirection;
+ setOrders(newOrders);
+ },
+ [orders]
+ );
+
//Очистка состояния доступных маршрутов события
const clearAvailableRoutesState = () => {
setAvailableRoutes({ sorce: "", routes: [] });
@@ -120,8 +143,15 @@ const ClntTaskBoard = () => {
//Состояние перетаскиваемого события
const [dragItem, setDragItem] = useState({ type: "", status: "" });
+ //Захватить перетаскиваемый объект
+ const handleDragItemChange = (filtersType, statusCode) =>
+ setDragItem({
+ type: filtersType,
+ status: statusCode
+ });
+
//Отпустить перетаскиваемый объект
- const clearDragItem = () => {
+ const handleDragItemClear = () => {
setDragItem({ type: "", status: "" });
};
@@ -130,46 +160,65 @@ const ClntTaskBoard = () => {
return availableRoutes.sorce === code || availableRoutes.routes.find(r => r.dest === code) || !availableRoutes.sorce ? true : false;
};
+ //При смене типа события
+ useEffect(() => {
+ if (filters.values.type) {
+ //Обновление вспомогательных данных
+ filters.values.type !== extraData.typeLoaded ? needUpdateExtraData() : null;
+ //Обновление событий
+ needUpdateTasks();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [filters.values.type]);
+
//Генерация содержимого
return (
- {tasks.filters.isOpen ? (
-
+ ) : null}
+ {dialogsState.taskDialogOpen ? (
+ {
+ handleTaskDialogOpen();
+ handleDragItemClear();
+ }}
/>
) : null}
- {settings.open ? : null}
-
+
d.id === tasks.filters.values.docLink) : null}
- handleFilterClick={handleFilterClick}
- handleReload={handleReload}
- orders={tasks.orders}
- handleOrderChanged={handleOrderChanged}
- //sx={STYLES.FILTER}
+ isFilterDialogOpen={dialogsState.filterOpen}
+ filter={filters.values}
+ docs={extraData.docLinks}
+ selectedDoc={filters.values.docLink ? extraData.docLinks.find(d => d.id === filters.values.docLink) : null}
+ onFilterChange={handleFiltersChange}
+ getDocLinks={getDocLinks}
+ onFilterOpen={() => handleFilterOpen(true)}
+ onFilterClose={() => handleFilterOpen(false)}
+ onReload={handleReload}
+ orders={orders}
+ onOrderChanged={handleOrderChanged}
/>
-
+
settings
- {noteDialog.visible ? (
- noteDialog.callback(n)} onCancel={handleNoteDialogClose} />
+ {dialogsState.note.isOpen ? (
+ dialogsState.note.callback(n)} onNoteOpen={handleNoteOpen} />
) : null}
- {tasks.filters.values.type ? (
+ {filters.loaded && filters.values.type && extraData.dataLoaded && tasks.groupsLoaded && tasks.tasksLoaded ? (
{
let srcCode = tasks.statuses.find(s => s.id == e.source.droppableId).code;
- setAvailableRoutes({ sorce: srcCode, routes: [...tasks.extraData.evRoutes.filter(r => r.src === srcCode)] });
+ setAvailableRoutes({ sorce: srcCode, routes: [...extraData.evRoutes.filter(r => r.src === srcCode)] });
}}
onDragEnd={e => {
- onDragEnd(e, tasks.extraData.evPoints, handleNoteDialogOpen);
+ onDragEnd(e, extraData.evPoints, handleNoteOpen);
clearAvailableRoutesState();
}}
>
@@ -184,73 +233,19 @@ const ClntTaskBoard = () => {
{provided => (
-
- handleCardSettingsClick(status)}
- >
- more_vert
-
- }
- title={
-
- {status[settings.statusesSort.attr] || status.name}
-
- }
- subheader={
-
- }
- sx={STYLES.PADDING_0}
- />
-
-
- {tasks.rows
- .filter(item => item.category === status.id)
- .map((item, index) => (
- a.agnAbbr === item.sSender
- ).image
- }
- index={index}
- handleReload={handleReload}
- key={item.id}
- eventPoints={tasks.extraData.evPoints}
- colorRule={settings.colorRule}
- pointSettings={tasks.extraData.evPoints.find(
- p => p.point === status.code
- )}
- openNoteDialog={handleNoteDialogOpen}
- />
- ))}
- {provided.placeholder}
-
-
-
+
)}
@@ -265,25 +260,6 @@ const ClntTaskBoard = () => {
) : null}
- {taskFormOpen ? (
- {
- setTaskFormOpen(false);
- clearDragItem();
- }}
- />
- ) : null}
- {cardSettings.isOpen ? (
-
- ) : null}
);
};
diff --git a/app/panels/clnt_task_board/components/filter_dialog.js b/app/panels/clnt_task_board/components/filter_dialog.js
index 68197fe..800cef4 100644
--- a/app/panels/clnt_task_board/components/filter_dialog.js
+++ b/app/panels/clnt_task_board/components/filter_dialog.js
@@ -29,14 +29,12 @@ import { FilterInputField } from "./filter_input_field"; //Компонент п
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
import { hasValue } from "../../../core/utils"; //Вспомогательные функции
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
+import { EVENT_STATES } from "../layouts"; //Перечисление состояний события
//---------
//Константы
//---------
-//Перечисление "Состояние события"
-export const EVENT_STATES = Object.freeze({ 0: "Все", 1: "Не аннулированные", 2: "Аннулированные" });
-
//Стили
const STYLES = {
FILTERS_SCROLL: { overflowY: "auto", ...APP_STYLES.SCROLL },
@@ -112,7 +110,7 @@ const selectSendUsrGrp = (value, showDictionary, callBack) => {
//---------------
//Диалоговое окно фильтра отбора
-const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
+const FilterDialog = ({ initial, docs, onFilterChange, onFilterOpen, getDocLinks }) => {
//Собственное состояние
const [filter, setFilter] = useState({ ...initial });
@@ -130,7 +128,7 @@ const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
const data = await executeStored({
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SUBCATALOGS_GET",
args: {
- SNAME: filter.catalog,
+ SCRN_NAME: filter.catalog,
NSUBCAT: filter.wSubcatalogs ? 1 : 0
}
});
@@ -141,7 +139,7 @@ const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
//При закрытии диалога без изменения фильтра
- const handleCancel = () => (onCancel ? onCancel() : null);
+ const handleCancel = () => onFilterOpen();
//При очистке фильтра
const handleClear = () => {
@@ -159,14 +157,16 @@ const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
};
//При закрытии диалога с изменением фильтра
- const handleOK = async () => {
- if (onOk) {
- if (filter.catalog && !filter.crn) {
- const crns = await getSubCatalogs();
- let filterCopy = { ...filter };
- crns ? (filterCopy.crn = crns) : null;
- onOk(filterCopy);
- } else onOk(filter);
+ const handleOk = async () => {
+ if (filter.catalog && !filter.crn) {
+ const crns = await getSubCatalogs();
+ let filterCopy = { ...filter };
+ crns ? (filterCopy.crn = crns) : null;
+ onFilterChange(filterCopy);
+ onFilterOpen();
+ } else {
+ onFilterChange(filter);
+ onFilterOpen();
}
};
@@ -301,10 +301,7 @@ const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
onClick={() => {
setCurType(filter.type);
clearDocLink();
- getDocLinks(filter.type).then(dl => {
- setCurDocLinks(dl);
- console.log(dl);
- });
+ getDocLinks(filter.type).then(dl => setCurDocLinks(dl));
}}
>
refresh
@@ -313,7 +310,7 @@ const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
-
@@ -129,8 +128,8 @@ const NoteDialog = ({ noteTypes, onOk, onCancel }) => {
//Контроль свойств - Диалог примечания
NoteDialog.propTypes = {
noteTypes: PropTypes.array,
- onOk: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired
+ onCallback: PropTypes.func.isRequired,
+ onNoteOpen: PropTypes.func.isRequired
};
//----------------
diff --git a/app/panels/clnt_task_board/components/rules_select.js b/app/panels/clnt_task_board/components/rules_select.js
index 35eee62..68c4e0c 100644
--- a/app/panels/clnt_task_board/components/rules_select.js
+++ b/app/panels/clnt_task_board/components/rules_select.js
@@ -10,7 +10,7 @@
import React, { useEffect, useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { FormControl, InputLabel, Select, MenuItem } from "@mui/material"; //Интерфейсные компоненты
-import { useColorRules } from "../hooks.js"; //Вспомогательные хуки
+import { useColorRules } from "../hooks/hooks.js"; //Вспомогательные хуки
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
//---------
diff --git a/app/panels/clnt_task_board/components/settings_dialog.js b/app/panels/clnt_task_board/components/settings_dialog.js
index 8f826df..f0c4438 100644
--- a/app/panels/clnt_task_board/components/settings_dialog.js
+++ b/app/panels/clnt_task_board/components/settings_dialog.js
@@ -10,9 +10,10 @@
import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
import { Dialog, DialogTitle, DialogContent, DialogActions, IconButton, Icon, Button, Box, Stack } from "@mui/material"; //Интерфейсные компоненты
-import { RulesSelect } from "./rules_select.js";
-import { FilterInputField } from "./filter_input_field.js";
+import { RulesSelect } from "./rules_select.js"; //Выпадающий список выбора заливки событий
+import { FilterInputField } from "./filter_input_field.js"; //Поле ввода
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
+import { sortAttrs, sortDest } from "../layouts.js"; //Допустимые значение поля и направления сортировки
//---------
//Константы
@@ -42,24 +43,12 @@ const STYLES = {
//---------------
//Диалог дополнительных настроек
-const SettingsDialog = ({ initial, onOk, onCancel, ...other }) => {
+const SettingsDialog = ({ initial, onSettingsChange, onOpen, ...other }) => {
//Состояние дополнительных настроек
const [settings, setSettings] = useState(
initial.statusesSort.attr ? { ...initial } : { ...initial, statusesSort: { sorted: true, attr: "name", dest: "asc" } }
);
- //Допустимые значение поля сортировки
- const sortAttrs = [
- { id: "code", descr: "Мнемокод" },
- { id: "name", descr: "Наименование" },
- { id: "pointDescr", descr: "Описание точки маршрута" }
- ];
-
- //Допустимые значения направления сортировки
- const sortDest = [];
- sortDest[-1] = "desc";
- sortDest[1] = "asc";
-
//Изменение заливки событий
const handleColorRuleChange = cr => setSettings(pv => ({ ...pv, colorRule: cr }));
@@ -72,9 +61,9 @@ const SettingsDialog = ({ initial, onOk, onCancel, ...other }) => {
//Генерация содержимого
return (
-