ЦИТК-878. Состояние панели на 07.11.24
This commit is contained in:
parent
4d2c76eca8
commit
29c8ecf4ae
@ -15,20 +15,31 @@ import { TaskFormDialog } from "./components/task_form"; //Компонент ф
|
|||||||
import { Filter } from "./filter.js"; //Компонент фильтров
|
import { Filter } from "./filter.js"; //Компонент фильтров
|
||||||
import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
|
import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
|
||||||
import { TaskCardSettings } from "./components/task_card_settings.js"; //Компонент настроек карточки события
|
import { TaskCardSettings } from "./components/task_card_settings.js"; //Компонент настроек карточки события
|
||||||
import { useTasks, useWindowResize, COLORS } from "./hooks.js"; //Вспомогательные хуки
|
import { useTasks, COLORS } from "./hooks.js"; //Вспомогательные хуки
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
|
//Высота заголовка
|
||||||
|
const TITLE_HEIGHT = "64px";
|
||||||
|
|
||||||
|
//Нижний отступ заголовка
|
||||||
|
const TITLE_PADDING_BOTTOM = "16px";
|
||||||
|
|
||||||
|
//Высота фильтра
|
||||||
|
const FILTER_HEIGHT = "56px";
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { width: "100%", padding: 1 },
|
CONTAINER: { width: "100%", padding: 0 },
|
||||||
|
FILTER: { position: "fixed" },
|
||||||
|
STATUSES_STACK: { maxWidth: "99vw", paddingBottom: "5px", overflowX: "auto", ...APP_STYLES.SCROLL },
|
||||||
STATUS_BLOCK: statusColor => {
|
STATUS_BLOCK: statusColor => {
|
||||||
return {
|
return {
|
||||||
maxWidth: "300px",
|
width: "315px",
|
||||||
minWidth: "300px",
|
height: `calc(100vh - ${TITLE_HEIGHT} - ${TITLE_PADDING_BOTTOM} - ${FILTER_HEIGHT} - 8px)`,
|
||||||
minHeight: "100px",
|
|
||||||
backgroundColor: statusColor,
|
backgroundColor: statusColor,
|
||||||
padding: "8px"
|
padding: "8px"
|
||||||
};
|
};
|
||||||
@ -36,6 +47,15 @@ const STYLES = {
|
|||||||
BLOCK_OPACITY: isAvailable => {
|
BLOCK_OPACITY: isAvailable => {
|
||||||
return isAvailable ? { opacity: 1 } : { opacity: 0.5 };
|
return isAvailable ? { opacity: 1 } : { opacity: 0.5 };
|
||||||
},
|
},
|
||||||
|
STATUSES_DIV: { position: "fixed", left: "8px", top: `calc(${TITLE_HEIGHT} + ${FILTER_HEIGHT})` },
|
||||||
|
CARD_CONTENT: {
|
||||||
|
padding: 0,
|
||||||
|
paddingRight: "5px",
|
||||||
|
paddingBottom: "5px !important",
|
||||||
|
overflowY: "auto",
|
||||||
|
maxHeight: `calc(100vh - ${TITLE_HEIGHT} - ${TITLE_PADDING_BOTTOM} - ${FILTER_HEIGHT} - 85px)`,
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
|
},
|
||||||
MARK_INFO: {
|
MARK_INFO: {
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
@ -43,7 +63,8 @@ const STYLES = {
|
|||||||
whiteSpace: "pre",
|
whiteSpace: "pre",
|
||||||
maxWidth: "calc(250px)",
|
maxWidth: "calc(250px)",
|
||||||
width: "-webkit-fill-available"
|
width: "-webkit-fill-available"
|
||||||
}
|
},
|
||||||
|
PADDING_0: { padding: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
@ -57,6 +78,7 @@ const ClntTaskBoard = () => {
|
|||||||
tasks,
|
tasks,
|
||||||
eventRoutes,
|
eventRoutes,
|
||||||
docLinks,
|
docLinks,
|
||||||
|
accounts,
|
||||||
taskFormOpen,
|
taskFormOpen,
|
||||||
setTaskFormOpen,
|
setTaskFormOpen,
|
||||||
cardSettings,
|
cardSettings,
|
||||||
@ -68,7 +90,8 @@ const ClntTaskBoard = () => {
|
|||||||
handleCardSettingsCancel,
|
handleCardSettingsCancel,
|
||||||
handleReload,
|
handleReload,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
handleOrderChanged
|
handleOrderChanged,
|
||||||
|
getDocLinks
|
||||||
] = useTasks();
|
] = useTasks();
|
||||||
|
|
||||||
//Состояние доступных маршрутов события
|
//Состояние доступных маршрутов события
|
||||||
@ -77,6 +100,7 @@ const ClntTaskBoard = () => {
|
|||||||
//Состояние перетаскиваемого события
|
//Состояние перетаскиваемого события
|
||||||
const [dragItem, setDragItem] = useState({ type: "", status: "" });
|
const [dragItem, setDragItem] = useState({ type: "", status: "" });
|
||||||
|
|
||||||
|
//Отпустить перетаскиваемый объект
|
||||||
const clearDragItem = () => {
|
const clearDragItem = () => {
|
||||||
setDragItem({ type: "", status: "" });
|
setDragItem({ type: "", status: "" });
|
||||||
};
|
};
|
||||||
@ -91,22 +115,17 @@ const ClntTaskBoard = () => {
|
|||||||
return availableRoutes.sorce === code || availableRoutes.routes.find(r => r.dest === code) || !availableRoutes.sorce ? true : false;
|
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 (
|
return (
|
||||||
<Box sx={STYLES.CONTAINER}>
|
<Box sx={STYLES.CONTAINER}>
|
||||||
{tasks.filters.isOpen ? (
|
{tasks.filters.isOpen ? (
|
||||||
<FilterDialog initial={tasks.filters.values} docs={docLinks} onOk={handleFilterOk} onCancel={handleFilterCancel} />
|
<FilterDialog
|
||||||
|
initial={tasks.filters.values}
|
||||||
|
docs={docLinks}
|
||||||
|
onOk={handleFilterOk}
|
||||||
|
onCancel={handleFilterCancel}
|
||||||
|
getDocLinks={getDocLinks}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Filter
|
<Filter
|
||||||
filter={tasks.filters.values}
|
filter={tasks.filters.values}
|
||||||
@ -115,6 +134,7 @@ const ClntTaskBoard = () => {
|
|||||||
handleReload={handleReload}
|
handleReload={handleReload}
|
||||||
orders={tasks.orders}
|
orders={tasks.orders}
|
||||||
handleOrderChanged={handleOrderChanged}
|
handleOrderChanged={handleOrderChanged}
|
||||||
|
sx={STYLES.FILTER}
|
||||||
/>
|
/>
|
||||||
{tasks.filters.values.type ? (
|
{tasks.filters.values.type ? (
|
||||||
<DragDropContext
|
<DragDropContext
|
||||||
@ -127,11 +147,11 @@ const ClntTaskBoard = () => {
|
|||||||
clearARState();
|
clearARState();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div style={STYLES.STATUSES_DIV}>
|
||||||
<Droppable droppableId="Statuses" type="droppableTask">
|
<Droppable droppableId="Statuses" type="droppableTask">
|
||||||
{provided => (
|
{provided => (
|
||||||
<div ref={provided.innerRef}>
|
<div ref={provided.innerRef}>
|
||||||
<Stack direction="row" spacing={2}>
|
<Stack direction="row" spacing={2} sx={STYLES.STATUSES_STACK}>
|
||||||
{tasks.statuses.map((status, index) => (
|
{tasks.statuses.map((status, index) => (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<Droppable isDropDisabled={!isCardAvailable(status.code)} droppableId={status.id.toString()}>
|
<Droppable isDropDisabled={!isCardAvailable(status.code)} droppableId={status.id.toString()}>
|
||||||
@ -161,28 +181,28 @@ const ClntTaskBoard = () => {
|
|||||||
subheader={
|
subheader={
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDragItem({ type: tasks.filters.values.type, status: status.code });
|
setDragItem({
|
||||||
|
type: tasks.filters.values.type,
|
||||||
|
status: status.code
|
||||||
|
});
|
||||||
setTaskFormOpen(true);
|
setTaskFormOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
+ Добавить
|
+ Добавить
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
sx={{ padding: 0 }}
|
sx={STYLES.PADDING_0}
|
||||||
/>
|
/>
|
||||||
<CardContent
|
<CardContent sx={STYLES.CARD_CONTENT}>
|
||||||
sx={{
|
|
||||||
padding: 0,
|
|
||||||
overflowY: "auto",
|
|
||||||
maxHeight: height * 0.749
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Stack spacing={1}>
|
<Stack spacing={1}>
|
||||||
{tasks.rows
|
{tasks.rows
|
||||||
.filter(item => item.category === status.id)
|
.filter(item => item.category === status.id)
|
||||||
.map((item, index) => (
|
.map((item, index) => (
|
||||||
<TaskCard
|
<TaskCard
|
||||||
task={item}
|
task={item}
|
||||||
|
account={accounts.find(a =>
|
||||||
|
a.evRnList.find(rn => rn == item.nrn)
|
||||||
|
)}
|
||||||
index={index}
|
index={index}
|
||||||
handleReload={handleReload}
|
handleReload={handleReload}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Панель мониторинга: Корневая панель доски задач
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState, useContext, useCallback, useEffect, useRef } from "react"; //Классы React
|
|
||||||
import { DragDropContext, Droppable } from "react-beautiful-dnd";
|
|
||||||
import { Stack, Card, CardHeader, CardContent, Box, Button, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
//import { Draggable } from "react-draggable";
|
|
||||||
import { TaskCard } from "./components/task_card";
|
|
||||||
import { TaskFormDialog } from "./components/task_form";
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { width: "100%", padding: 1 },
|
|
||||||
DEF_SIZE: { minWidth: "200px", minHeight: "100px" },
|
|
||||||
SETTINGS_BUTTON: {
|
|
||||||
position: "absolute",
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
color: theme => theme.palette.grey[500]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Корневая панель доски задач
|
|
||||||
const ClntTaskBoard = () => {
|
|
||||||
const [insertTask, setInsertTask] = useState(false);
|
|
||||||
|
|
||||||
const [categories, setCategories] = useState([
|
|
||||||
{ id: 1, name: "Новое" },
|
|
||||||
{ id: 2, name: "Старое" }
|
|
||||||
]);
|
|
||||||
const [tasks, setTasks] = useState([
|
|
||||||
{ nrn: 150688812, id: 1, name: "Задание1", category: 1 },
|
|
||||||
{ nrn: 150688812, id: 2, name: "Задание2", category: 1 },
|
|
||||||
{ nrn: 150688812, id: 3, name: "Задание3", category: 2 },
|
|
||||||
{ nrn: 150688812, id: 4, name: "Задание4", category: 2 }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const onDragEnd = result => {
|
|
||||||
const { source, destination } = result;
|
|
||||||
|
|
||||||
if (!destination) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destination.droppableId === "Categories") {
|
|
||||||
setCategories(categories);
|
|
||||||
} else if (destination.droppableId !== source.droppableId) {
|
|
||||||
setTasks(tasks =>
|
|
||||||
tasks.map(task =>
|
|
||||||
task.id === parseInt(result.draggableId)
|
|
||||||
? {
|
|
||||||
...task,
|
|
||||||
category: parseInt(result.destination.droppableId)
|
|
||||||
}
|
|
||||||
: task
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setTasks(tasks);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.CONTAINER}>
|
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
|
||||||
<div>
|
|
||||||
<Droppable droppableId="Categories" type="droppableTask">
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
{categories.map((category, index) => (
|
|
||||||
<div key={index}>
|
|
||||||
<Droppable droppableId={category.id.toString()}>
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Card
|
|
||||||
className="category-card"
|
|
||||||
sx={{ ...STYLES.DEF_SIZE, backgroundColor: "#FFA500", padding: 1 }}
|
|
||||||
>
|
|
||||||
<CardHeader
|
|
||||||
action={
|
|
||||||
<IconButton
|
|
||||||
aria-label="settings"
|
|
||||||
onClick={() => {
|
|
||||||
console.log("Опции типа");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
title={category.name}
|
|
||||||
subheader={<Button onClick={() => setInsertTask(true)}>+ Добавить</Button>}
|
|
||||||
sx={{ padding: 0 }}
|
|
||||||
/>
|
|
||||||
<CardContent sx={{ padding: 0 }}>
|
|
||||||
<Stack spacing={1}>
|
|
||||||
{tasks
|
|
||||||
.filter(item => item.category === category.id)
|
|
||||||
.map((item, index) => (
|
|
||||||
<TaskCard task={item} index={index} key={item.id} />
|
|
||||||
// <Draggable draggableId={item.id.toString()} key={item.id} index={index}>
|
|
||||||
// {provided => (
|
|
||||||
// <Card
|
|
||||||
// ref={provided.innerRef}
|
|
||||||
// {...provided.draggableProps}
|
|
||||||
// {...provided.dragHandleProps}
|
|
||||||
// >
|
|
||||||
// <CardHeader
|
|
||||||
// action={
|
|
||||||
// <IconButton
|
|
||||||
// aria-label="settings"
|
|
||||||
// onClick={() => {
|
|
||||||
// console.log("Опции задачи");
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <Icon>more_vert</Icon>
|
|
||||||
// </IconButton>
|
|
||||||
// }
|
|
||||||
// title={
|
|
||||||
// <Typography
|
|
||||||
// className="task-info"
|
|
||||||
// sx={{ padding: "2px" }}
|
|
||||||
// >
|
|
||||||
// {item.id} {item.name}
|
|
||||||
// </Typography>
|
|
||||||
// }
|
|
||||||
// sx={{ padding: 0 }}
|
|
||||||
// />
|
|
||||||
// </Card>
|
|
||||||
// )}
|
|
||||||
// </Draggable>
|
|
||||||
))}
|
|
||||||
{provided.placeholder}
|
|
||||||
</Stack>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
{provided.placeholder}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
</DragDropContext>
|
|
||||||
{insertTask ? (
|
|
||||||
<TaskFormDialog
|
|
||||||
onClose={() => {
|
|
||||||
setInsertTask(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { ClntTaskBoard };
|
|
@ -7,26 +7,49 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useState, useContext } from "react"; //Классы React
|
import React, { useState, useContext, useEffect, useCallback } from "react"; //Классы React
|
||||||
|
import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, DialogActions, Button, Box } from "@mui/material"; //Интерфейсные компоненты
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
IconButton,
|
||||||
|
Icon,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Button,
|
||||||
|
Box,
|
||||||
|
Stack,
|
||||||
|
Checkbox,
|
||||||
|
FormControlLabel,
|
||||||
|
Radio,
|
||||||
|
RadioGroup
|
||||||
|
} from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { FilterInputField } from "./filter_input_field"; //Компонент поля ввода
|
import { FilterInputField } from "./filter_input_field"; //Компонент поля ввода
|
||||||
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
||||||
import { hasValue } from "../../../core/utils"; //Вспомогательные функции
|
import { hasValue } from "../../../core/utils"; //Вспомогательные функции
|
||||||
|
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
//---------
|
//---------
|
||||||
|
|
||||||
|
export const EVENT_STATES = Object.freeze({ 0: "Все", 1: "Не аннулированные", 2: "Аннулированные" });
|
||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
DIALOG_ACTIONS: { justifyContent: "center" },
|
FILTERS_SCROLL: { overflowY: "auto", ...APP_STYLES.SCROLL },
|
||||||
|
DIALOG_ACTIONS: { justifyContent: "end", paddingRight: "24px", paddingLeft: "24px" },
|
||||||
CLOSE_BUTTON: {
|
CLOSE_BUTTON: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 8,
|
top: 8,
|
||||||
color: theme => theme.palette.grey[500]
|
color: theme => theme.palette.grey[500]
|
||||||
}
|
},
|
||||||
|
DOCLINK_STACK: { alignItems: "baseline" },
|
||||||
|
SELECT: { width: "450px" },
|
||||||
|
BOX_WITH_LEGEND: { border: "1px solid #939393" },
|
||||||
|
LEGEND: { textAlign: "left" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------
|
//-----------------------
|
||||||
@ -42,6 +65,18 @@ const selectEventType = (value, showDictionary, callBack) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Выбор каталога
|
||||||
|
const selectCatalog = (value, showDictionary, callBack) => {
|
||||||
|
showDictionary({
|
||||||
|
unitCode: "CatalogTree",
|
||||||
|
inputParameters: [
|
||||||
|
{ name: "in_DOCNAME", value: "ClientEvents" },
|
||||||
|
{ name: "in_NAME", value: value }
|
||||||
|
],
|
||||||
|
callBack: res => (res.success === true ? callBack(res.outParameters.out_NAME) : callBack(null))
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//Выбор производственного объекта
|
//Выбор производственного объекта
|
||||||
const selectSendPerson = (value, showDictionary, callBack) => {
|
const selectSendPerson = (value, showDictionary, callBack) => {
|
||||||
showDictionary({
|
showDictionary({
|
||||||
@ -74,10 +109,41 @@ const selectSendUsrGrp = (value, showDictionary, callBack) => {
|
|||||||
//---------------
|
//---------------
|
||||||
|
|
||||||
//Диалоговое окно фильтра отбора
|
//Диалоговое окно фильтра отбора
|
||||||
const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
const FilterDialog = ({ initial, docs, onCancel, onOk, getDocLinks }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [filter, setFilter] = useState({ ...initial });
|
const [filter, setFilter] = useState({ ...initial });
|
||||||
|
|
||||||
|
const [curType, setCurType] = useState(initial.type);
|
||||||
|
|
||||||
|
const [curDocLinks, setCurDocLinks] = useState([...docs]);
|
||||||
|
|
||||||
|
const [typeDif, setTypeDif] = useState(false);
|
||||||
|
|
||||||
|
//const [catalogs, setCatalogs] = useState(initial.wSubcatalogs ? initial.crn : initial.crn.split(";")[0]);
|
||||||
|
|
||||||
|
//const [curDocLink, setCurDocLink] = useState(initial.docLink ? initial.docLink : "");
|
||||||
|
|
||||||
|
//Подключение к контексту взаимодействия с сервером
|
||||||
|
const { executeStored } = useContext(BackEndСtx);
|
||||||
|
|
||||||
|
//const promisedSetCrn = crn => new Promise(resolve => setFilter(pv => ({ ...pv, crn: crn }), resolve));
|
||||||
|
|
||||||
|
//Получение субкаталогов
|
||||||
|
const getSubCatalogs = useCallback(async () => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SUBCATALOGS_GET",
|
||||||
|
args: {
|
||||||
|
SNAME: filter.catalog,
|
||||||
|
NSUBCAT: filter.wSubcatalogs ? 1 : 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//Заполняем субкаталоги
|
||||||
|
//setCatalogs(data.SRESULT);
|
||||||
|
//setFilter(pv => ({ ...pv, crn: data.SRESULT }));
|
||||||
|
return data.SRESULT;
|
||||||
|
//await promisedSetCrn(data.SRESULT);
|
||||||
|
}, [executeStored, filter.catalog, filter.wSubcatalogs]);
|
||||||
|
|
||||||
//Подключение к контексту приложения
|
//Подключение к контексту приложения
|
||||||
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
||||||
|
|
||||||
@ -87,7 +153,11 @@ const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
|||||||
//При очистке фильтра
|
//При очистке фильтра
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
setFilter({
|
setFilter({
|
||||||
|
evState: EVENT_STATES[1],
|
||||||
type: "",
|
type: "",
|
||||||
|
catalog: "",
|
||||||
|
crn: "",
|
||||||
|
wSubcatalogs: false,
|
||||||
sendPerson: "",
|
sendPerson: "",
|
||||||
sendDivision: "",
|
sendDivision: "",
|
||||||
sendUsrGrp: "",
|
sendUsrGrp: "",
|
||||||
@ -96,11 +166,71 @@ const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//При закрытии диалога с изменением фильтра
|
//При закрытии диалога с изменением фильтра
|
||||||
const handleOK = () => (onOk ? onOk(filter) : null);
|
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);
|
||||||
|
|
||||||
|
// if (filter.catalog && filter.wSubcatalogs) {
|
||||||
|
// const crns = await getSubCatalogs(filter.crn);
|
||||||
|
// let filterCopy = { ...filter };
|
||||||
|
// crns ? (filterCopy.crn = crns) : null;
|
||||||
|
// onOk(filterCopy);
|
||||||
|
// } else onOk(filter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//При изменении значения элемента
|
//При изменении значения элемента
|
||||||
const handleFilterItemChange = (item, value) => setFilter(pv => ({ ...pv, [item]: value }));
|
const handleFilterItemChange = (item, value) => setFilter(pv => ({ ...pv, [item]: value }));
|
||||||
|
|
||||||
|
//Очистка учётного документа
|
||||||
|
const clearDocLink = () => setFilter(pv => ({ ...pv, docLink: "" }));
|
||||||
|
|
||||||
|
//Очистка галочки "Включая подкаталоги"
|
||||||
|
//const clearWSubcatalogs = () => setFilter(pv => ({ ...pv, wSubcatalogs: false }));
|
||||||
|
|
||||||
|
//Очистка сотстояния подкаталогов
|
||||||
|
//const clearCatalogs = () => setCatalogs("");
|
||||||
|
|
||||||
|
//При изменении типа события
|
||||||
|
useEffect(() => {
|
||||||
|
if (curType) {
|
||||||
|
if (curType === filter.type) setTypeDif(false);
|
||||||
|
else {
|
||||||
|
setTypeDif(true);
|
||||||
|
clearDocLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [curType, filter.type]);
|
||||||
|
|
||||||
|
//При очистке каталога
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (!filter.catalog && filter.wSubcatalogs) {
|
||||||
|
// clearWSubcatalogs();
|
||||||
|
// //clearCatalogs();
|
||||||
|
// }
|
||||||
|
// }, [filter.catalog, filter.wSubcatalogs]);
|
||||||
|
|
||||||
|
//Обработка изменений с каталогами
|
||||||
|
useEffect(() => {
|
||||||
|
if (!filter.catalog && filter.wSubcatalogs) setFilter(pv => ({ ...pv, wSubcatalogs: false }));
|
||||||
|
if (filter.catalog !== initial.catalog && filter.crn) setFilter(pv => ({ ...pv, crn: "" }));
|
||||||
|
if (filter.catalog === initial.catalog && filter.crn !== initial.crn && filter.wSubcatalogs === initial.wSubcatalogs)
|
||||||
|
setFilter(pv => ({ ...pv, crn: initial.crn }));
|
||||||
|
if (filter.catalog === initial.catalog && filter.wSubcatalogs !== initial.wSubcatalogs && !filter.wSubcatalogs)
|
||||||
|
setFilter(pv => ({ ...pv, crn: initial.crn.split(";")[0] }));
|
||||||
|
if (filter.catalog === initial.catalog && filter.wSubcatalogs !== initial.wSubcatalogs && filter.wSubcatalogs)
|
||||||
|
setFilter(pv => ({ ...pv, crn: "" }));
|
||||||
|
}, [filter.catalog, filter.crn, filter.wSubcatalogs, initial.catalog, initial.crn, initial.wSubcatalogs]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log(`State changed: ${filter.crn}`);
|
||||||
|
// }, [filter.crn]);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -109,7 +239,22 @@ const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
|||||||
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
||||||
<Icon>close</Icon>
|
<Icon>close</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent>
|
<DialogContent sx={STYLES.FILTERS_SCROLL}>
|
||||||
|
<Box sx={STYLES.BOX_WITH_LEGEND} component="fieldset">
|
||||||
|
<legend style={STYLES.LEGEND}>Состояние</legend>
|
||||||
|
<RadioGroup
|
||||||
|
row
|
||||||
|
aria-labelledby="evState-label"
|
||||||
|
id="evState"
|
||||||
|
name="evState"
|
||||||
|
value={filter.evState}
|
||||||
|
onChange={e => handleFilterItemChange(e.target.name, e.target.value)}
|
||||||
|
>
|
||||||
|
{Object.keys(EVENT_STATES).map(function (k) {
|
||||||
|
return <FormControlLabel key={k} value={EVENT_STATES[k]} control={<Radio />} label={EVENT_STATES[k]} />;
|
||||||
|
})}
|
||||||
|
</RadioGroup>
|
||||||
|
</Box>
|
||||||
<Box component="section" p={1}>
|
<Box component="section" p={1}>
|
||||||
<FilterInputField
|
<FilterInputField
|
||||||
elementCode="type"
|
elementCode="type"
|
||||||
@ -119,6 +264,27 @@ const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
|||||||
onChange={handleFilterItemChange}
|
onChange={handleFilterItemChange}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box component="section" p={1}>
|
||||||
|
<FilterInputField
|
||||||
|
elementCode="catalog"
|
||||||
|
elementValue={filter.catalog}
|
||||||
|
labelText="Каталог"
|
||||||
|
dictionary={callBack => selectCatalog(filter.catalog, pOnlineShowDictionary, callBack)}
|
||||||
|
onChange={handleFilterItemChange}
|
||||||
|
/>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
id="wSubcatalogs"
|
||||||
|
name="wSubcatalogs"
|
||||||
|
checked={filter.wSubcatalogs}
|
||||||
|
disabled={filter.catalog ? false : true}
|
||||||
|
onChange={e => handleFilterItemChange(e.target.name, e.target.checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Включая подкаталоги"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
<Box component="section" p={1}>
|
<Box component="section" p={1}>
|
||||||
<FilterInputField
|
<FilterInputField
|
||||||
elementCode="sendPerson"
|
elementCode="sendPerson"
|
||||||
@ -146,21 +312,40 @@ const FilterDialog = ({ initial, docs, onCancel, onOk }) => {
|
|||||||
onChange={handleFilterItemChange}
|
onChange={handleFilterItemChange}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{docs.length > 0 && initial.type === filter.type ? (
|
|
||||||
<Box component="section" p={1}>
|
<Box component="section" p={1}>
|
||||||
|
<Stack direction="row" sx={STYLES.DOCLINK_STACK}>
|
||||||
<FilterInputField
|
<FilterInputField
|
||||||
elementCode="docLink"
|
elementCode="docLink"
|
||||||
elementValue={filter.docLink ? filter.docLink : ""}
|
elementValue={!typeDif ? filter.docLink : ""}
|
||||||
labelText="Учётный документ"
|
labelText="Учётный документ"
|
||||||
items={docs}
|
items={!typeDif ? curDocLinks : []}
|
||||||
|
disabled={typeDif || curDocLinks.length === 0 ? true : false}
|
||||||
onChange={handleFilterItemChange}
|
onChange={handleFilterItemChange}
|
||||||
|
sx={STYLES.SELECT}
|
||||||
/>
|
/>
|
||||||
|
<IconButton title="Очистить" disabled={!filter.docLink} onClick={clearDocLink}>
|
||||||
|
<Icon>clear</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
title="Обновить"
|
||||||
|
//disabled={!((!curType && filter.type) || (typeDif && filter.type))}
|
||||||
|
disabled={!((!curType || typeDif) && filter.type)}
|
||||||
|
onClick={() => {
|
||||||
|
setCurType(filter.type);
|
||||||
|
clearDocLink();
|
||||||
|
getDocLinks(filter.type).then(dl => {
|
||||||
|
setCurDocLinks([...dl]);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon>refresh</Icon>
|
||||||
|
</IconButton>
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
||||||
<Button disabled={!hasValue(filter.type)} variant="text" onClick={handleOK}>
|
<Button disabled={!hasValue(filter.type)} variant="text" onClick={handleOK}>
|
||||||
Применить
|
ОК
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="text" onClick={handleClear}>
|
<Button variant="text" onClick={handleClear}>
|
||||||
Очистить
|
Очистить
|
||||||
@ -179,7 +364,8 @@ FilterDialog.propTypes = {
|
|||||||
initial: PropTypes.object.isRequired,
|
initial: PropTypes.object.isRequired,
|
||||||
docs: PropTypes.arrayOf(PropTypes.object),
|
docs: PropTypes.arrayOf(PropTypes.object),
|
||||||
onOk: PropTypes.func,
|
onOk: PropTypes.func,
|
||||||
onCancel: PropTypes.func
|
onCancel: PropTypes.func,
|
||||||
|
getDocLinks: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
|
@ -25,7 +25,7 @@ const STYLES = {
|
|||||||
//---------------
|
//---------------
|
||||||
|
|
||||||
//Поле ввода
|
//Поле ввода
|
||||||
const FilterInputField = ({ elementCode, elementValue, labelText, onChange, required = false, items = null, dictionary }) => {
|
const FilterInputField = ({ elementCode, elementValue, labelText, onChange, required = false, items = null, dictionary, ...other }) => {
|
||||||
//Значение элемента
|
//Значение элемента
|
||||||
const [value, setValue] = useState(elementValue);
|
const [value, setValue] = useState(elementValue);
|
||||||
|
|
||||||
@ -35,8 +35,9 @@ const FilterInputField = ({ elementCode, elementValue, labelText, onChange, requ
|
|||||||
}, [elementValue]);
|
}, [elementValue]);
|
||||||
|
|
||||||
//Выбор значения из словаря
|
//Выбор значения из словаря
|
||||||
const handleDictionaryClick = () =>
|
const handleDictionaryClick = () => {
|
||||||
dictionary ? dictionary(res => (res ? handleChange({ target: { name: elementCode, value: res } }) : null)) : null;
|
dictionary ? dictionary(res => (res ? handleChange({ target: { name: elementCode, value: res } }) : null)) : null;
|
||||||
|
};
|
||||||
|
|
||||||
//Изменение значения элемента
|
//Изменение значения элемента
|
||||||
const handleChange = e => {
|
const handleChange = e => {
|
||||||
@ -64,6 +65,7 @@ const FilterInputField = ({ elementCode, elementValue, labelText, onChange, requ
|
|||||||
aria-describedby={`${elementCode}-helper-text`}
|
aria-describedby={`${elementCode}-helper-text`}
|
||||||
label={labelText}
|
label={labelText}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
{...other}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -79,6 +81,7 @@ const FilterInputField = ({ elementCode, elementValue, labelText, onChange, requ
|
|||||||
aria-describedby={`${elementCode}-helper-text`}
|
aria-describedby={`${elementCode}-helper-text`}
|
||||||
label={labelText}
|
label={labelText}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
{...other}
|
||||||
>
|
>
|
||||||
{items
|
{items
|
||||||
? items.map((item, i) => (
|
? items.map((item, i) => (
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import React from "react"; //Классы React
|
import React from "react"; //Классы React
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
import { Card, CardHeader, Typography, IconButton, Icon, Box, Menu, MenuItem } from "@mui/material"; //Интерфейсные компоненты
|
import { Card, CardHeader, Typography, IconButton, Icon, Box, Menu, MenuItem, CardContent, Avatar, Stack } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { useTaskCard } from "../hooks"; //Вспомогательные хуки
|
import { useTaskCard } from "../hooks"; //Вспомогательные хуки
|
||||||
import { TaskFormDialog } from "./task_form"; //Форма события
|
import { TaskFormDialog } from "./task_form"; //Форма события
|
||||||
|
|
||||||
@ -22,7 +22,24 @@ import { TaskFormDialog } from "./task_form"; //Форма события
|
|||||||
const STYLES = {
|
const STYLES = {
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
||||||
MENU_ITEM_DELIMITER: { borderBottom: "1px solid lightgrey" },
|
MENU_ITEM_DELIMITER: { borderBottom: "1px solid lightgrey" },
|
||||||
CARD_HEADER_TITLE: { padding: "2px" }
|
CARD_HEADER_TITLE: {
|
||||||
|
padding: "4px",
|
||||||
|
width: "252px",
|
||||||
|
display: "-webkit-box",
|
||||||
|
hyphens: "auto",
|
||||||
|
WebkitBoxOrient: "vertical",
|
||||||
|
WebkitLineClamp: 2,
|
||||||
|
overflow: "hidden"
|
||||||
|
},
|
||||||
|
CARD_HEADER_DESC: { padding: 0, cursor: "pointer" },
|
||||||
|
CARD_CONTENT: { padding: "4px !important" },
|
||||||
|
CARD_CONTENT_BOX: { display: "flex", alignItems: "center" },
|
||||||
|
ACCOUNT_STACK: { alignItems: "center", marginLeft: "auto" },
|
||||||
|
SECONDARY_TEXT: {
|
||||||
|
color: "text.secondary",
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
ICON_COLOR: { color: theme => theme.palette.grey[500] }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
@ -38,6 +55,7 @@ const DataCellCardActions = ({ taskRn, menuItems, cardActions, handleMethodsMenu
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<Menu id={`${taskRn}_menu`} anchorEl={cardActions.anchorMenuMethods} open={cardActions.openMethods} onClose={handleMethodsMenuClose}>
|
<Menu id={`${taskRn}_menu`} anchorEl={cardActions.anchorMenuMethods} open={cardActions.openMethods} onClose={handleMethodsMenuClose}>
|
||||||
{menuItems.map(action => {
|
{menuItems.map(action => {
|
||||||
|
if (action.visible)
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
sx={action.delimiter ? STYLES.MENU_ITEM_DELIMITER : {}}
|
sx={action.delimiter ? STYLES.MENU_ITEM_DELIMITER : {}}
|
||||||
@ -74,7 +92,7 @@ DataCellCardActions.propTypes = {
|
|||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Карточка события
|
//Карточка события
|
||||||
const TaskCard = ({ task, index, handleReload }) => {
|
const TaskCard = ({ task, account, index, handleReload }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [taskCard, setTaskCard, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose, menuItems] = useTaskCard();
|
const [taskCard, setTaskCard, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose, menuItems] = useTaskCard();
|
||||||
|
|
||||||
@ -86,11 +104,18 @@ const TaskCard = ({ task, index, handleReload }) => {
|
|||||||
<Card ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
<Card ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
title={
|
title={
|
||||||
<Typography className="task-info" sx={STYLES.CARD_HEADER_TITLE}>
|
<Typography
|
||||||
{task.id} {task.name}
|
className="task-info"
|
||||||
|
sx={STYLES.CARD_HEADER_TITLE}
|
||||||
|
lang="ru"
|
||||||
|
onClick={() => {
|
||||||
|
menuItems.find(a => (a.method === "EDIT" ? a.func(task.nrn, a.needReload ? handleReload : null) : null));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{task.sdescription}
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
sx={{ padding: 0 }}
|
sx={STYLES.CARD_HEADER_DESC}
|
||||||
action={
|
action={
|
||||||
<DataCellCardActions
|
<DataCellCardActions
|
||||||
taskRn={task.nrn}
|
taskRn={task.nrn}
|
||||||
@ -102,6 +127,18 @@ const TaskCard = ({ task, index, handleReload }) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<CardContent sx={STYLES.CARD_CONTENT}>
|
||||||
|
<Box sx={STYLES.CARD_CONTENT_BOX}>
|
||||||
|
<Icon sx={STYLES.ICON_COLOR}>assignment</Icon>
|
||||||
|
<Typography sx={STYLES.SECONDARY_TEXT}>{task.name}</Typography>
|
||||||
|
{account ? (
|
||||||
|
<Stack /*title={task.sto_clnperson}*/ direction="row" spacing={0.5} sx={STYLES.ACCOUNT_STACK}>
|
||||||
|
<Typography sx={STYLES.SECONDARY_TEXT}>{account.authId ? account.authId : account.agnAbbr}</Typography>
|
||||||
|
<Avatar src={account.image ? `data:image/png;base64,${account.image}` : null} />
|
||||||
|
</Stack>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
@ -120,6 +157,7 @@ const TaskCard = ({ task, index, handleReload }) => {
|
|||||||
//Контроль свойств - Карточка события
|
//Контроль свойств - Карточка события
|
||||||
TaskCard.propTypes = {
|
TaskCard.propTypes = {
|
||||||
task: PropTypes.object.isRequired,
|
task: PropTypes.object.isRequired,
|
||||||
|
account: PropTypes.object,
|
||||||
index: PropTypes.number.isRequired,
|
index: PropTypes.number.isRequired,
|
||||||
handleReload: PropTypes.func
|
handleReload: PropTypes.func
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ import {
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
DIALOG_ACTIONS: { justifyContent: "center" },
|
DIALOG_ACTIONS: { justifyContent: "end", paddingRight: "24px", paddingLeft: "24px" },
|
||||||
CLOSE_BUTTON: {
|
CLOSE_BUTTON: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
right: 8,
|
right: 8,
|
||||||
@ -81,6 +81,7 @@ const TaskCardSettings = ({ initial, availableClrs, onCancel, onOk }) => {
|
|||||||
labelId="color-label"
|
labelId="color-label"
|
||||||
id="color"
|
id="color"
|
||||||
label="Цвет"
|
label="Цвет"
|
||||||
|
variant="standard"
|
||||||
sx={STYLES.BCKG_COLOR(settings.color)}
|
sx={STYLES.BCKG_COLOR(settings.color)}
|
||||||
onChange={handleSettingsItemChange}
|
onChange={handleSettingsItemChange}
|
||||||
>
|
>
|
||||||
|
@ -11,6 +11,7 @@ import React, { useState } from "react"; //Классы React
|
|||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Box, Typography, TextField, Dialog, DialogContent, DialogActions, Button, Tabs, Tab, InputAdornment, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
import { Box, Typography, TextField, Dialog, DialogContent, DialogActions, Button, Tabs, Tab, InputAdornment, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { useClientEvent } from "../hooks"; //Вспомогательные хуки
|
import { useClientEvent } from "../hooks"; //Вспомогательные хуки
|
||||||
|
import { APP_STYLES } from "../../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -23,21 +24,9 @@ const STYLES = {
|
|||||||
paddingBottom: "0px",
|
paddingBottom: "0px",
|
||||||
maxHeight: "740px",
|
maxHeight: "740px",
|
||||||
minHeight: "740px",
|
minHeight: "740px",
|
||||||
"&::-webkit-scrollbar": {
|
...APP_STYLES.SCROLL
|
||||||
width: "8px"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-track": {
|
|
||||||
borderRadius: "8px",
|
|
||||||
backgroundColor: "#EBEBEB"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb": {
|
|
||||||
borderRadius: "8px",
|
|
||||||
backgroundColor: "#b4b4b4"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb:hover": {
|
|
||||||
backgroundColor: "#808080"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
DIALOG_ACTIONS: { justifyContent: "end", paddingRight: "24px", paddingLeft: "24px" },
|
||||||
BOX_WITH_LEGEND: { border: "1px solid #939393" },
|
BOX_WITH_LEGEND: { border: "1px solid #939393" },
|
||||||
BOX_SINGLE_COLUMN: { display: "flex", flexDirection: "column", gap: "10px" },
|
BOX_SINGLE_COLUMN: { display: "flex", flexDirection: "column", gap: "10px" },
|
||||||
BOX_FEW_COLUMNS: { display: "flex", flexWrap: "wrap", justifyContent: "space-between" },
|
BOX_FEW_COLUMNS: { display: "flex", flexWrap: "wrap", justifyContent: "space-between" },
|
||||||
@ -103,16 +92,7 @@ CustomTabPanel.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Вкладка основной информации
|
//Вкладка основной информации
|
||||||
const MainEventInfoTab = ({
|
const MainEventInfoTab = ({ task, handleFieldEdit, handleClientClientsOpen, handleClientPersonOpen, handleCrnOpen, handleEventNextNumbGet }) => {
|
||||||
task,
|
|
||||||
handleFieldEdit,
|
|
||||||
//handleTypeOpen,
|
|
||||||
//handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box sx={STYLES.BOX_WITH_LEGEND} component="fieldset">
|
<Box sx={STYLES.BOX_WITH_LEGEND} component="fieldset">
|
||||||
@ -122,9 +102,9 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD()}
|
sx={STYLES.TEXT_FIELD()}
|
||||||
id="scrn"
|
id="scrn"
|
||||||
label="Каталог"
|
label="Каталог"
|
||||||
variant="outlined"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
value={task.scrn}
|
value={task.scrn}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
InputProps={getInputProps(handleCrnOpen)}
|
InputProps={getInputProps(handleCrnOpen)}
|
||||||
required
|
required
|
||||||
@ -134,8 +114,8 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD("225px")}
|
sx={STYLES.TEXT_FIELD("225px")}
|
||||||
id="sprefix"
|
id="sprefix"
|
||||||
label="Префикс"
|
label="Префикс"
|
||||||
variant="outlined"
|
|
||||||
value={task.sprefix}
|
value={task.sprefix}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
required
|
required
|
||||||
disabled={task.isUpdate}
|
disabled={task.isUpdate}
|
||||||
@ -144,8 +124,8 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD("225px")}
|
sx={STYLES.TEXT_FIELD("225px")}
|
||||||
id="snumber"
|
id="snumber"
|
||||||
label="Номер"
|
label="Номер"
|
||||||
variant="outlined"
|
|
||||||
value={task.snumber}
|
value={task.snumber}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
required
|
required
|
||||||
disabled={task.isUpdate}
|
disabled={task.isUpdate}
|
||||||
@ -155,31 +135,29 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
||||||
id="stype"
|
id="stype"
|
||||||
label="Тип"
|
label="Тип"
|
||||||
variant="outlined"
|
|
||||||
value={task.stype}
|
value={task.stype}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
required
|
required
|
||||||
//InputProps={getInputProps(handleTypeOpen, task.isUpdate)}
|
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
||||||
id="sstatus"
|
id="sstatus"
|
||||||
label="Статус"
|
label="Статус"
|
||||||
variant="outlined"
|
|
||||||
value={task.sstatus}
|
value={task.sstatus}
|
||||||
|
variant="standard"
|
||||||
disabled
|
disabled
|
||||||
required
|
required
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
//InputProps={getInputProps(handleStatusOpen, !task.stype || task.isUpdate)}
|
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
sx={STYLES.TEXT_FIELD()}
|
sx={STYLES.TEXT_FIELD()}
|
||||||
fullWidth
|
fullWidth
|
||||||
id="sdescription"
|
id="sdescription"
|
||||||
label="Описание"
|
label="Описание"
|
||||||
variant="outlined"
|
|
||||||
value={task.sdescription}
|
value={task.sdescription}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={!task.stype}
|
disabled={!task.stype}
|
||||||
required
|
required
|
||||||
@ -195,8 +173,8 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD()}
|
sx={STYLES.TEXT_FIELD()}
|
||||||
id="sclnt_clnclients"
|
id="sclnt_clnclients"
|
||||||
label="Организация"
|
label="Организация"
|
||||||
variant="outlined"
|
|
||||||
value={task.sclnt_clnclients}
|
value={task.sclnt_clnclients}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={!task.stype}
|
disabled={!task.stype}
|
||||||
InputProps={getInputProps(handleClientClientsOpen, !task.stype)}
|
InputProps={getInputProps(handleClientClientsOpen, !task.stype)}
|
||||||
@ -205,8 +183,8 @@ const MainEventInfoTab = ({
|
|||||||
sx={STYLES.TEXT_FIELD()}
|
sx={STYLES.TEXT_FIELD()}
|
||||||
id="sclnt_clnperson"
|
id="sclnt_clnperson"
|
||||||
label="Сотрудник"
|
label="Сотрудник"
|
||||||
variant="outlined"
|
|
||||||
value={task.sclnt_clnperson}
|
value={task.sclnt_clnperson}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={!task.stype}
|
disabled={!task.stype}
|
||||||
InputProps={getInputProps(() => handleClientPersonOpen(0), !task.stype)}
|
InputProps={getInputProps(() => handleClientPersonOpen(0), !task.stype)}
|
||||||
@ -220,8 +198,6 @@ const MainEventInfoTab = ({
|
|||||||
MainEventInfoTab.propTypes = {
|
MainEventInfoTab.propTypes = {
|
||||||
task: PropTypes.object.isRequired,
|
task: PropTypes.object.isRequired,
|
||||||
handleFieldEdit: PropTypes.func.isRequired,
|
handleFieldEdit: PropTypes.func.isRequired,
|
||||||
//handleTypeOpen: PropTypes.func.isRequired,
|
|
||||||
//handleStatusOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientClientsOpen: PropTypes.func.isRequired,
|
handleClientClientsOpen: PropTypes.func.isRequired,
|
||||||
handleClientPersonOpen: PropTypes.func.isRequired,
|
handleClientPersonOpen: PropTypes.func.isRequired,
|
||||||
handleCrnOpen: PropTypes.func.isRequired,
|
handleCrnOpen: PropTypes.func.isRequired,
|
||||||
@ -237,9 +213,9 @@ const ExecutorEventInfoTab = ({ task, handleFieldEdit, handleClientPersonOpen })
|
|||||||
<TextField
|
<TextField
|
||||||
id="dstart_date"
|
id="dstart_date"
|
||||||
label="Начало работ"
|
label="Начало работ"
|
||||||
variant="outlined"
|
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
variant="standard"
|
||||||
value={task.dstart_date}
|
value={task.dstart_date}
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={task.isUpdate}
|
disabled={task.isUpdate}
|
||||||
@ -250,8 +226,8 @@ const ExecutorEventInfoTab = ({ task, handleFieldEdit, handleClientPersonOpen })
|
|||||||
<TextField
|
<TextField
|
||||||
id="sinit_clnperson"
|
id="sinit_clnperson"
|
||||||
label="Сотрудник"
|
label="Сотрудник"
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_clnperson}
|
value={task.sinit_clnperson}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={task.isUpdate}
|
disabled={task.isUpdate}
|
||||||
InputProps={getInputProps(() => handleClientPersonOpen(1), task.isUpdate)}
|
InputProps={getInputProps(() => handleClientPersonOpen(1), task.isUpdate)}
|
||||||
@ -259,16 +235,16 @@ const ExecutorEventInfoTab = ({ task, handleFieldEdit, handleClientPersonOpen })
|
|||||||
<TextField
|
<TextField
|
||||||
id="sinit_user"
|
id="sinit_user"
|
||||||
label="Пользователь"
|
label="Пользователь"
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_user}
|
value={task.sinit_user}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sinit_reason"
|
id="sinit_reason"
|
||||||
label="Основание"
|
label="Основание"
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_reason}
|
value={task.sinit_reason}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled={task.isUpdate}
|
disabled={task.isUpdate}
|
||||||
></TextField>
|
></TextField>
|
||||||
@ -278,64 +254,64 @@ const ExecutorEventInfoTab = ({ task, handleFieldEdit, handleClientPersonOpen })
|
|||||||
<TextField
|
<TextField
|
||||||
id="sto_company"
|
id="sto_company"
|
||||||
label="Организация"
|
label="Организация"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_company}
|
value={task.sto_company}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_department"
|
id="sto_department"
|
||||||
label="Подразделение"
|
label="Подразделение"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_department}
|
value={task.sto_department}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_clnpost"
|
id="sto_clnpost"
|
||||||
label="Должность"
|
label="Должность"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnpost}
|
value={task.sto_clnpost}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_clnpsdep"
|
id="sto_clnpsdep"
|
||||||
label="Штатная должность"
|
label="Штатная должность"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnpsdep}
|
value={task.sto_clnpsdep}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_clnperson"
|
id="sto_clnperson"
|
||||||
label="Сотрудник"
|
label="Сотрудник"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnperson}
|
value={task.sto_clnperson}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_fcstaffgrp"
|
id="sto_fcstaffgrp"
|
||||||
label="Нештатная должность"
|
label="Нештатная должность"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_fcstaffgrp}
|
value={task.sto_fcstaffgrp}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_user"
|
id="sto_user"
|
||||||
label="Пользователь"
|
label="Пользователь"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_user}
|
value={task.sto_user}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
<TextField
|
<TextField
|
||||||
id="sto_usergrp"
|
id="sto_usergrp"
|
||||||
label="Группа пользователей"
|
label="Группа пользователей"
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_usergrp}
|
value={task.sto_usergrp}
|
||||||
|
variant="standard"
|
||||||
onChange={handleFieldEdit}
|
onChange={handleFieldEdit}
|
||||||
disabled
|
disabled
|
||||||
></TextField>
|
></TextField>
|
||||||
@ -356,16 +332,7 @@ ExecutorEventInfoTab.propTypes = {
|
|||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Форма события
|
//Форма события
|
||||||
const TaskForm = ({
|
const TaskForm = ({ task, setTask, handleClientClientsOpen, handleClientPersonOpen, handleCrnOpen, handleEventNextNumbGet }) => {
|
||||||
task,
|
|
||||||
setTask,
|
|
||||||
//handleTypeOpen,
|
|
||||||
//handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
}) => {
|
|
||||||
//Состояние вкладки
|
//Состояние вкладки
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(0);
|
||||||
|
|
||||||
@ -399,8 +366,6 @@ const TaskForm = ({
|
|||||||
<MainEventInfoTab
|
<MainEventInfoTab
|
||||||
task={task}
|
task={task}
|
||||||
handleFieldEdit={handleFieldEdit}
|
handleFieldEdit={handleFieldEdit}
|
||||||
//handleTypeOpen={handleTypeOpen}
|
|
||||||
//handleStatusOpen={handleStatusOpen}
|
|
||||||
handleClientClientsOpen={handleClientClientsOpen}
|
handleClientClientsOpen={handleClientClientsOpen}
|
||||||
handleClientPersonOpen={handleClientPersonOpen}
|
handleClientPersonOpen={handleClientPersonOpen}
|
||||||
handleCrnOpen={handleCrnOpen}
|
handleCrnOpen={handleCrnOpen}
|
||||||
@ -418,8 +383,6 @@ const TaskForm = ({
|
|||||||
TaskForm.propTypes = {
|
TaskForm.propTypes = {
|
||||||
task: PropTypes.object.isRequired,
|
task: PropTypes.object.isRequired,
|
||||||
setTask: PropTypes.func.isRequired,
|
setTask: PropTypes.func.isRequired,
|
||||||
//handleTypeOpen: PropTypes.func.isRequired,
|
|
||||||
//handleStatusOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientClientsOpen: PropTypes.func.isRequired,
|
handleClientClientsOpen: PropTypes.func.isRequired,
|
||||||
handleClientPersonOpen: PropTypes.func.isRequired,
|
handleClientPersonOpen: PropTypes.func.isRequired,
|
||||||
handleCrnOpen: PropTypes.func.isRequired,
|
handleCrnOpen: PropTypes.func.isRequired,
|
||||||
@ -429,18 +392,8 @@ TaskForm.propTypes = {
|
|||||||
//Диалог с формой события
|
//Диалог с формой события
|
||||||
const TaskFormDialog = ({ taskRn, taskType, taskStatus, onClose }) => {
|
const TaskFormDialog = ({ taskRn, taskType, taskStatus, onClose }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [
|
const [task, setTask, insertEvent, updateEvent, handleClientClientsOpen, handleClientPersonOpen, handleCrnOpen, handleEventNextNumbGet] =
|
||||||
task,
|
useClientEvent(taskRn, taskType, taskStatus);
|
||||||
setTask,
|
|
||||||
insertEvent,
|
|
||||||
updateEvent,
|
|
||||||
//handleTypeOpen,
|
|
||||||
//handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
] = useClientEvent(taskRn, taskType, taskStatus);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onClose={onClose ? onClose : null} fullWidth>
|
<Dialog open onClose={onClose ? onClose : null} fullWidth>
|
||||||
@ -448,8 +401,6 @@ const TaskFormDialog = ({ taskRn, taskType, taskStatus, onClose }) => {
|
|||||||
<TaskForm
|
<TaskForm
|
||||||
task={task}
|
task={task}
|
||||||
setTask={setTask}
|
setTask={setTask}
|
||||||
//handleTypeOpen={handleTypeOpen}
|
|
||||||
//handleStatusOpen={handleStatusOpen}
|
|
||||||
handleClientClientsOpen={handleClientClientsOpen}
|
handleClientClientsOpen={handleClientClientsOpen}
|
||||||
handleClientPersonOpen={handleClientPersonOpen}
|
handleClientPersonOpen={handleClientPersonOpen}
|
||||||
handleCrnOpen={handleCrnOpen}
|
handleCrnOpen={handleCrnOpen}
|
||||||
@ -457,7 +408,7 @@ const TaskFormDialog = ({ taskRn, taskType, taskStatus, onClose }) => {
|
|||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
{onClose ? (
|
{onClose ? (
|
||||||
<DialogActions>
|
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
||||||
{taskRn ? (
|
{taskRn ? (
|
||||||
<Button onClick={() => updateEvent(onClose)} disabled={task.updateDisabled}>
|
<Button onClick={() => updateEvent(onClose)} disabled={task.updateDisabled}>
|
||||||
Исправить
|
Исправить
|
||||||
|
@ -11,6 +11,7 @@ import React from "react"; //Классы React
|
|||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
import { Chip, Stack, Icon, IconButton, Box, Menu, MenuItem, Typography } from "@mui/material"; //Интерфейсные компоненты
|
import { Chip, Stack, Icon, IconButton, Box, Menu, MenuItem, Typography } from "@mui/material"; //Интерфейсные компоненты
|
||||||
import { useOrders } from "./hooks.js"; //Хук меню сортировки
|
import { useOrders } from "./hooks.js"; //Хук меню сортировки
|
||||||
|
import { APP_STYLES } from "../../../app.styles"; //Типовые стили
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -22,11 +23,16 @@ const STYLES = {
|
|||||||
return orders.length > 0 ? { color: "#1976d2" } : {};
|
return orders.length > 0 ? { color: "#1976d2" } : {};
|
||||||
},
|
},
|
||||||
ORDER_MENU: {
|
ORDER_MENU: {
|
||||||
width: "250px"
|
width: "260px"
|
||||||
},
|
},
|
||||||
ORDER_MENU_ITEM: {
|
ORDER_MENU_ITEM: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between"
|
justifyContent: "space-between"
|
||||||
|
},
|
||||||
|
FILTERS_STACK: {
|
||||||
|
paddingBottom: "5px",
|
||||||
|
overflowX: "auto",
|
||||||
|
...APP_STYLES.SCROLL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +71,7 @@ const SortMenu = ({ menuOrders, handleOrdersMenuClose, orders, handleOrderChange
|
|||||||
onClose={handleOrdersMenuClose}
|
onClose={handleOrdersMenuClose}
|
||||||
MenuListProps={{ sx: STYLES.ORDER_MENU }}
|
MenuListProps={{ sx: STYLES.ORDER_MENU }}
|
||||||
>
|
>
|
||||||
|
<SortMenuItem item={"DCHANGE_DATE"} caption={"Дата последнего изменения"} orders={orders} handleOrderChanged={handleOrderChanged} />
|
||||||
<SortMenuItem item={"DPLAN_DATE"} caption={"Дата начала работ"} orders={orders} handleOrderChanged={handleOrderChanged} />
|
<SortMenuItem item={"DPLAN_DATE"} caption={"Дата начала работ"} orders={orders} handleOrderChanged={handleOrderChanged} />
|
||||||
<SortMenuItem item={"SPREF_NUMB"} caption={"Номер"} orders={orders} handleOrderChanged={handleOrderChanged} />
|
<SortMenuItem item={"SPREF_NUMB"} caption={"Номер"} orders={orders} handleOrderChanged={handleOrderChanged} />
|
||||||
</Menu>
|
</Menu>
|
||||||
@ -89,7 +96,8 @@ const FilterItem = ({ caption, value, onClick }) => {
|
|||||||
<Chip
|
<Chip
|
||||||
label={
|
label={
|
||||||
<Stack direction={"row"} alignItems={"center"}>
|
<Stack direction={"row"} alignItems={"center"}>
|
||||||
<strong>{caption}</strong>: {value}
|
<strong>{caption}</strong>
|
||||||
|
{value ? `:\u00A0${value}` : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@ -101,7 +109,7 @@ const FilterItem = ({ caption, value, onClick }) => {
|
|||||||
//Контроль свойств компонента - Элемент фильтра
|
//Контроль свойств компонента - Элемент фильтра
|
||||||
FilterItem.propTypes = {
|
FilterItem.propTypes = {
|
||||||
caption: PropTypes.string.isRequired,
|
caption: PropTypes.string.isRequired,
|
||||||
value: PropTypes.any.isRequired,
|
value: PropTypes.any,
|
||||||
onClick: PropTypes.func
|
onClick: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -110,7 +118,7 @@ FilterItem.propTypes = {
|
|||||||
//---------------
|
//---------------
|
||||||
|
|
||||||
//Фильтр отбора
|
//Фильтр отбора
|
||||||
const Filter = ({ filter, selectedDoc, handleFilterClick, handleReload, orders, handleOrderChanged }) => {
|
const Filter = ({ filter, selectedDoc, handleFilterClick, handleReload, orders, handleOrderChanged, ...other }) => {
|
||||||
//Меню сортировки
|
//Меню сортировки
|
||||||
const [menuOrders, handleOrdersMenuButtonClick, handleOrdersMenuClose] = useOrders();
|
const [menuOrders, handleOrdersMenuButtonClick, handleOrdersMenuClose] = useOrders();
|
||||||
|
|
||||||
@ -119,8 +127,8 @@ const Filter = ({ filter, selectedDoc, handleFilterClick, handleReload, orders,
|
|||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box {...other}>
|
||||||
<Stack direction="row" spacing={1} p={1} alignItems={"center"}>
|
<Stack direction="row" spacing={1} p={1} alignItems={"center"} sx={{ maxWidth: "99vw" }}>
|
||||||
<IconButton title="Обновить" onClick={handleReload}>
|
<IconButton title="Обновить" onClick={handleReload}>
|
||||||
<Icon>refresh</Icon>
|
<Icon>refresh</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -130,11 +138,18 @@ const Filter = ({ filter, selectedDoc, handleFilterClick, handleReload, orders,
|
|||||||
<IconButton title="Фильтр" onClick={handleClick}>
|
<IconButton title="Фильтр" onClick={handleClick}>
|
||||||
<Icon>filter_alt</Icon>
|
<Icon>filter_alt</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
<Stack direction="row" spacing={1} alignItems={"center"} sx={STYLES.FILTERS_STACK}>
|
||||||
|
{filter.evState ? <FilterItem caption={"Состояние"} value={filter.evState} onClick={handleClick} /> : null}
|
||||||
{filter.type ? <FilterItem caption={"Тип"} value={filter.type} onClick={handleClick} /> : null}
|
{filter.type ? <FilterItem caption={"Тип"} value={filter.type} onClick={handleClick} /> : null}
|
||||||
|
{filter.catalog ? <FilterItem caption={"Каталог"} value={filter.catalog} onClick={handleClick} /> : null}
|
||||||
|
{filter.wSubcatalogs ? <FilterItem caption={"Включая подкаталоги"} onClick={handleClick} /> : null}
|
||||||
{filter.sendPerson ? <FilterItem caption={"Исполнитель"} value={filter.sendPerson} onClick={handleClick} /> : null}
|
{filter.sendPerson ? <FilterItem caption={"Исполнитель"} value={filter.sendPerson} onClick={handleClick} /> : null}
|
||||||
{filter.sendDivision ? <FilterItem caption={"Подразделение"} value={filter.sendDivision} onClick={handleClick} /> : null}
|
{filter.sendDivision ? <FilterItem caption={"Подразделение"} value={filter.sendDivision} onClick={handleClick} /> : null}
|
||||||
{filter.sendUsrGrp ? <FilterItem caption={"Группа пользователей"} value={filter.sendUsrGrp} onClick={handleClick} /> : null}
|
{filter.sendUsrGrp ? <FilterItem caption={"Группа пользователей"} value={filter.sendUsrGrp} onClick={handleClick} /> : null}
|
||||||
{filter.docLink && selectedDoc ? <FilterItem caption={"Учётный документ"} value={selectedDoc.descr} onClick={handleClick} /> : null}
|
{filter.docLink && selectedDoc ? (
|
||||||
|
<FilterItem caption={"Учётный документ"} value={selectedDoc.descr} onClick={handleClick} />
|
||||||
|
) : null}
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
<SortMenu menuOrders={menuOrders} handleOrdersMenuClose={handleOrdersMenuClose} orders={orders} handleOrderChanged={handleOrderChanged} />
|
<SortMenu menuOrders={menuOrders} handleOrdersMenuClose={handleOrdersMenuClose} orders={orders} handleOrderChanged={handleOrderChanged} />
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -7,12 +7,13 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import { useState, useContext, useEffect, useCallback, useLayoutEffect } from "react"; //Классы React
|
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
||||||
import { object2Base64XML, deepCopyObject } from "../../core/utils"; //Вспомогательные функции
|
import { object2Base64XML, deepCopyObject } from "../../core/utils"; //Вспомогательные функции
|
||||||
import dayjs from "dayjs"; //Работа с датами
|
import dayjs from "dayjs"; //Работа с датами
|
||||||
|
import { EVENT_STATES } from "./components/filter_dialog"; //Перечисление состояний события
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -41,27 +42,41 @@ export const COLORS = [
|
|||||||
//Формирование случайного цвета
|
//Формирование случайного цвета
|
||||||
const randomColor = index => {
|
const randomColor = index => {
|
||||||
const hue = index * 137.508;
|
const hue = index * 137.508;
|
||||||
return `hsl(${hue},50%,75%)`;
|
return hslToRgba(hue, 50, 70);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Хук для отработки изменений ширины и высоты рабочей области окна
|
const hslToRgba = (h, s, l) => {
|
||||||
const useWindowResize = () => {
|
s /= 100;
|
||||||
//Состояние размера рабочей области
|
l /= 100;
|
||||||
const [size, setSize] = useState([0, 0]);
|
const k = n => (n + h / 30) % 12;
|
||||||
|
const a = s * Math.min(l, 1 - l);
|
||||||
//При изменении размера
|
const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
||||||
useLayoutEffect(() => {
|
return `rgba(${Math.floor(255 * f(0))},${Math.floor(255 * f(8))},${Math.floor(255 * f(4))},0.3)`;
|
||||||
const updateSize = () => {
|
|
||||||
setSize([document.documentElement.clientWidth, document.documentElement.clientHeight]);
|
|
||||||
};
|
};
|
||||||
window.addEventListener("resize", updateSize);
|
|
||||||
updateSize();
|
|
||||||
return () => window.removeEventListener("resize", updateSize);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//Вернём размеры
|
//Формирование случайного цвета rgba
|
||||||
return size;
|
// const randomColorRgba = index => {
|
||||||
};
|
// const s = [255, 204, 153, 102, 51, 0];
|
||||||
|
// function rValue() {
|
||||||
|
// return s[Math.floor(Math.random() * s.length)];
|
||||||
|
// }
|
||||||
|
// let t = 3;
|
||||||
|
// let rgb = [0, 0, 0];
|
||||||
|
// function howMuchToLearnJS(x) {
|
||||||
|
// if (t === 0) return;
|
||||||
|
// rgb[3 - t] = x % 6;
|
||||||
|
// t--;
|
||||||
|
// howMuchToLearnJS(Math.floor(x / 6));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //let r = rValue();
|
||||||
|
// //let g = rValue();
|
||||||
|
// //let b = rValue();
|
||||||
|
// let r, g, b;
|
||||||
|
// howMuchToLearnJS(index);
|
||||||
|
// //while ((r === 0 && g === 0 && b === 0) || b === 255) b = rValue();
|
||||||
|
// return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ",0.2)";
|
||||||
|
// };
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
//Тело модуля
|
//Тело модуля
|
||||||
@ -81,6 +96,9 @@ const useTasks = () => {
|
|||||||
//Состояние учётных документов
|
//Состояние учётных документов
|
||||||
const [docLinks, setDocLinks] = useState([]);
|
const [docLinks, setDocLinks] = useState([]);
|
||||||
|
|
||||||
|
//Состояние аккаунтов
|
||||||
|
const [accounts, setAccounts] = useState([]);
|
||||||
|
|
||||||
//Состояние событий
|
//Состояние событий
|
||||||
const [tasks, setTasks] = useState({
|
const [tasks, setTasks] = useState({
|
||||||
groupsLoaded: false,
|
groupsLoaded: false,
|
||||||
@ -90,9 +108,21 @@ const useTasks = () => {
|
|||||||
isOpen: true,
|
isOpen: true,
|
||||||
isSetByUser: false,
|
isSetByUser: false,
|
||||||
needSave: false,
|
needSave: false,
|
||||||
values: { type: "", sendPerson: "", sendDivision: "", sendUsrGrp: "", docLink: "" },
|
values: {
|
||||||
|
evState: EVENT_STATES[1],
|
||||||
|
type: "",
|
||||||
|
catalog: "",
|
||||||
|
crn: "",
|
||||||
|
wSubcatalogs: false,
|
||||||
|
sendPerson: "",
|
||||||
|
sendDivision: "",
|
||||||
|
sendUsrGrp: "",
|
||||||
|
docLink: ""
|
||||||
|
},
|
||||||
fArray: [
|
fArray: [
|
||||||
|
{ name: "NCLOSED", from: 0, to: 1 },
|
||||||
{ name: "SEVTYPE_CODE", from: "", to: "" },
|
{ name: "SEVTYPE_CODE", from: "", to: "" },
|
||||||
|
{ name: "NCRN", from: "", to: "" },
|
||||||
{ name: "SSEND_PERSON", from: "", to: "" },
|
{ name: "SSEND_PERSON", from: "", to: "" },
|
||||||
{ name: "SSEND_DIVISION", from: "", to: "" },
|
{ name: "SSEND_DIVISION", from: "", to: "" },
|
||||||
{ name: "SSEND_USRGRP", from: "", to: "" },
|
{ name: "SSEND_USRGRP", from: "", to: "" },
|
||||||
@ -126,18 +156,27 @@ const useTasks = () => {
|
|||||||
sdescription: task.SEVDESCR,
|
sdescription: task.SEVDESCR,
|
||||||
sclnt_clnclients: "",
|
sclnt_clnclients: "",
|
||||||
sclnt_clnperson: "",
|
sclnt_clnperson: "",
|
||||||
|
dchange_date: task.DCHANGE_DATE,
|
||||||
dstart_date: task.DREG_DATE,
|
dstart_date: task.DREG_DATE,
|
||||||
dplan_date: task.DPLAN_DATE,
|
dplan_date: task.DPLAN_DATE,
|
||||||
sinit_clnperson: task.SINIT_PERSON,
|
sinit_clnperson: task.SINIT_PERSON,
|
||||||
sinit_user: "",
|
sinit_user: "",
|
||||||
sinit_reason: "",
|
sinit_reason: "",
|
||||||
|
//SEND_CLIENT
|
||||||
sto_company: "",
|
sto_company: "",
|
||||||
sto_department: "",
|
//SEND_DIVISION
|
||||||
|
sto_department: task.SSEND_DIVISION,
|
||||||
|
//SEND_POST
|
||||||
sto_clnpost: "",
|
sto_clnpost: "",
|
||||||
|
//SEND_PERFORM
|
||||||
sto_clnpsdep: "",
|
sto_clnpsdep: "",
|
||||||
sto_clnperson: "",
|
//SEND_PERSON
|
||||||
|
sto_clnperson: task.SSEND_PERSON,
|
||||||
|
//SEND_STAFFGRP
|
||||||
sto_fcstaffgrp: "",
|
sto_fcstaffgrp: "",
|
||||||
sto_user: task.SSEND_PERSON,
|
//SEND_USER_AUTHID
|
||||||
|
sto_user: "",
|
||||||
|
//SEND_USER_GROUP
|
||||||
sto_usergrp: task.SSEND_USRGRP,
|
sto_usergrp: task.SSEND_USRGRP,
|
||||||
scurrent_user: ""
|
scurrent_user: ""
|
||||||
};
|
};
|
||||||
@ -159,8 +198,23 @@ const useTasks = () => {
|
|||||||
const setFilterValues = (values, ns = true) => {
|
const setFilterValues = (values, ns = true) => {
|
||||||
//Считываем массив фильтров
|
//Считываем массив фильтров
|
||||||
let filterArr = tasks.filters.fArray.slice();
|
let filterArr = tasks.filters.fArray.slice();
|
||||||
|
//Состояние
|
||||||
|
if (values.evState) {
|
||||||
|
if (values.evState === EVENT_STATES[0]) {
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").from = 0;
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").to = 1;
|
||||||
|
} else if (values.evState === EVENT_STATES[1]) {
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").from = 0;
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").to = 0;
|
||||||
|
} else if (values.evState === EVENT_STATES[2]) {
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").from = 1;
|
||||||
|
filterArr.find(f => f.name === "NCLOSED").to = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
//Тип
|
//Тип
|
||||||
filterArr.find(f => f.name === "SEVTYPE_CODE").from = values.type ? values.type : null;
|
filterArr.find(f => f.name === "SEVTYPE_CODE").from = values.type ? values.type : null;
|
||||||
|
//Каталог
|
||||||
|
filterArr.find(f => f.name === "NCRN").from = values.crn ? values.crn : null;
|
||||||
//Исполнитель
|
//Исполнитель
|
||||||
filterArr.find(f => f.name === "SSEND_PERSON").from = values.sendPerson ? values.sendPerson : null;
|
filterArr.find(f => f.name === "SSEND_PERSON").from = values.sendPerson ? values.sendPerson : null;
|
||||||
//Подразделение
|
//Подразделение
|
||||||
@ -180,11 +234,14 @@ const useTasks = () => {
|
|||||||
//Загрузка значений фильтра из локального хранилища браузера
|
//Загрузка значений фильтра из локального хранилища браузера
|
||||||
const loadLocalFilter = useCallback(async () => {
|
const loadLocalFilter = useCallback(async () => {
|
||||||
let vs = { ...tasks.filters.values };
|
let vs = { ...tasks.filters.values };
|
||||||
|
if (localStorage.getItem("type")) {
|
||||||
Object.keys(vs).map(function (k) {
|
Object.keys(vs).map(function (k) {
|
||||||
k !== "docLink" ? (vs[k] = localStorage.getItem(k)) : null;
|
if (k === "wSubcatalogs") vs[k] = localStorage.getItem(k) === "true";
|
||||||
|
else k !== "docLink" ? (vs[k] = localStorage.getItem(k)) : null;
|
||||||
});
|
});
|
||||||
setFilterValues(vs, false);
|
setFilterValues(vs, false);
|
||||||
setFilterOpen(false);
|
setFilterOpen(false);
|
||||||
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -358,8 +415,33 @@ const useTasks = () => {
|
|||||||
[handleStateChange, tasks.rows, tasks.statuses]
|
[handleStateChange, tasks.rows, tasks.statuses]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Получение учётных документов
|
||||||
|
const getDocLinks = useCallback(
|
||||||
|
async (type = tasks.filters.values.type) => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_DOCLINKS",
|
||||||
|
args: {
|
||||||
|
SCODE: type
|
||||||
|
},
|
||||||
|
respArg: "COUT"
|
||||||
|
});
|
||||||
|
//Инициализируем учётные документы
|
||||||
|
let newDocLinks = [];
|
||||||
|
//Если найдены учётные документы
|
||||||
|
if (data.XDOCLINKS) {
|
||||||
|
data.XDOCLINKS.map(d => {
|
||||||
|
newDocLinks.push({ id: d.NRN, descr: d.SDESCR });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//Указываем сформированные учётные документы
|
||||||
|
setDocLinks([...newDocLinks]);
|
||||||
|
return newDocLinks;
|
||||||
|
},
|
||||||
|
[executeStored, tasks.filters.values.type]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//Считываем дополнительные данные
|
//Считывание вспомогательных данных
|
||||||
let getEventData = async () => {
|
let getEventData = async () => {
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_INFO_BY_CODE",
|
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_INFO_BY_CODE",
|
||||||
@ -376,25 +458,32 @@ const useTasks = () => {
|
|||||||
newRoutes.push({ src: r.SSOURCE, dest: r.SDESTINATION });
|
newRoutes.push({ src: r.SSOURCE, dest: r.SDESTINATION });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//Инициализируем учётные документы
|
//Инициализируем пользователей
|
||||||
let newDocLinks = [];
|
let newAccounts = [];
|
||||||
//Если найдены учётные документы
|
//Если найдены пользователи
|
||||||
if (data.XDOCLINKS) {
|
if (data.XACCOUNTS) {
|
||||||
data.XDOCLINKS.map(d => {
|
data.XACCOUNTS.map(a => {
|
||||||
newDocLinks.push({ id: d.NRN, descr: d.SDESCR });
|
//console.log(a.SEVRN_LIST.toString().includes(";"));
|
||||||
|
newAccounts.push({
|
||||||
|
agnAbbr: a.SAGNABBR,
|
||||||
|
image: a.BIMAGE,
|
||||||
|
evRnList: a.SEVRN_LIST.toString().includes(";") ? a.SEVRN_LIST.toString().split(";") : [a.SEVRN_LIST.toString()]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//Указываем сформированные маршруты
|
//Указываем сформированные маршруты
|
||||||
setEventRoutes([...newRoutes]);
|
setEventRoutes([...newRoutes]);
|
||||||
//Указываем сформированные учётные документы
|
//Указываем сформированные аккаунты
|
||||||
setDocLinks([...newDocLinks]);
|
setAccounts([...newAccounts]);
|
||||||
};
|
};
|
||||||
//Если указан тип событий
|
//Если указан тип событий
|
||||||
if (tasks.filters.values.type) {
|
if (tasks.filters.values.type) {
|
||||||
//Загружаем данные
|
//Загружаем данные
|
||||||
getEventData();
|
getEventData();
|
||||||
|
//Загружаем учётные документы
|
||||||
|
getDocLinks();
|
||||||
}
|
}
|
||||||
}, [tasks.filters.values.type, executeStored]);
|
}, [tasks.filters.values.type, executeStored, getDocLinks]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//Считывание данных с учетом фильтрации
|
//Считывание данных с учетом фильтрации
|
||||||
@ -456,6 +545,7 @@ const useTasks = () => {
|
|||||||
tasks,
|
tasks,
|
||||||
eventRoutes,
|
eventRoutes,
|
||||||
docLinks,
|
docLinks,
|
||||||
|
accounts,
|
||||||
taskFormOpen,
|
taskFormOpen,
|
||||||
setTaskFormOpen,
|
setTaskFormOpen,
|
||||||
cardSettings,
|
cardSettings,
|
||||||
@ -467,7 +557,8 @@ const useTasks = () => {
|
|||||||
handleCardSettingsCancel,
|
handleCardSettingsCancel,
|
||||||
handleReload,
|
handleReload,
|
||||||
onDragEnd,
|
onDragEnd,
|
||||||
handleOrderChanged
|
handleOrderChanged,
|
||||||
|
getDocLinks
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -878,6 +969,26 @@ const useTaskCard = () => {
|
|||||||
setTaskCard(pv => ({ ...pv, openEdit: true }));
|
setTaskCard(pv => ({ ...pv, openEdit: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//По нажатия действия "Редактировать в разделе"
|
||||||
|
const handleTaskEditClient = useCallback(
|
||||||
|
async nEvent => {
|
||||||
|
const data = await executeStored({
|
||||||
|
stored: "PKG_P8PANELS_CLNTTSKBRD.SELECT_CLNEVENT",
|
||||||
|
args: {
|
||||||
|
NRN: nEvent
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (data.NIDENT) {
|
||||||
|
pOnlineShowDictionary({
|
||||||
|
unitCode: "ClientEvents",
|
||||||
|
showMethod: "main",
|
||||||
|
inputParameters: [{ name: "in_IDENT", value: data.NIDENT }]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[executeStored, pOnlineShowDictionary]
|
||||||
|
);
|
||||||
|
|
||||||
//По нажатию действия "Удалить"
|
//По нажатию действия "Удалить"
|
||||||
const handleTaskDelete = (nEvent, handleReload) => {
|
const handleTaskDelete = (nEvent, handleReload) => {
|
||||||
showMsgWarn("Удалить событие?", () => deleteTask(nEvent, handleReload));
|
showMsgWarn("Удалить событие?", () => deleteTask(nEvent, handleReload));
|
||||||
@ -1072,16 +1183,42 @@ const useTaskCard = () => {
|
|||||||
|
|
||||||
//Формируем меню показателей
|
//Формируем меню показателей
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ method: "EDIT", name: "Исправить", icon: "edit", delimiter: false, needReload: false, func: handleTaskEdit },
|
{ method: "EDIT", name: "Исправить", icon: "edit", visible: false, delimiter: false, needReload: false, func: handleTaskEdit },
|
||||||
{ method: "DELETE", name: "Удалить", icon: "delete", delimiter: true, needReload: true, func: handleTaskDelete },
|
{
|
||||||
{ method: "TASK_STATE_CHANGE", name: "Перейти", icon: "turn_right", delimiter: false, needReload: true, func: handleStateChange },
|
method: "EDIT_CLIENT",
|
||||||
{ method: "TASK_RETURN", name: "Выполнить возврат", icon: "turn_left", delimiter: false, needReload: true, func: handleTaskReturn },
|
name: "Исправить в разделе",
|
||||||
{ method: "TASK_SEND", name: "Направить", icon: "send", delimiter: true, needReload: true, func: handleSend },
|
icon: "edit_note",
|
||||||
{ method: "NOTES", name: "Примечания", icon: "event_note", delimiter: true, needReload: false, func: handleEventNotesOpen },
|
visible: true,
|
||||||
|
delimiter: false,
|
||||||
|
needReload: false,
|
||||||
|
func: handleTaskEditClient
|
||||||
|
},
|
||||||
|
{ method: "DELETE", name: "Удалить", icon: "delete", visible: true, delimiter: true, needReload: true, func: handleTaskDelete },
|
||||||
|
{
|
||||||
|
method: "TASK_STATE_CHANGE",
|
||||||
|
name: "Перейти",
|
||||||
|
icon: "turn_right",
|
||||||
|
visible: true,
|
||||||
|
delimiter: false,
|
||||||
|
needReload: true,
|
||||||
|
func: handleStateChange
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: "TASK_RETURN",
|
||||||
|
name: "Выполнить возврат",
|
||||||
|
icon: "turn_left",
|
||||||
|
visible: true,
|
||||||
|
delimiter: false,
|
||||||
|
needReload: true,
|
||||||
|
func: handleTaskReturn
|
||||||
|
},
|
||||||
|
{ method: "TASK_SEND", name: "Направить", icon: "send", visible: true, delimiter: true, needReload: true, func: handleSend },
|
||||||
|
{ method: "NOTES", name: "Примечания", icon: "event_note", visible: true, delimiter: true, needReload: false, func: handleEventNotesOpen },
|
||||||
{
|
{
|
||||||
method: "FILE_LINKS",
|
method: "FILE_LINKS",
|
||||||
name: "Присоединенные документы",
|
name: "Присоединенные документы",
|
||||||
icon: "attach_file",
|
icon: "attach_file",
|
||||||
|
visible: true,
|
||||||
delimiter: false,
|
delimiter: false,
|
||||||
needReload: false,
|
needReload: false,
|
||||||
func: handleFileLinksOpen
|
func: handleFileLinksOpen
|
||||||
@ -1109,4 +1246,4 @@ const useOrders = () => {
|
|||||||
return [menuOrders, handleOrdersMenuButtonClick, handleOrdersMenuClose];
|
return [menuOrders, handleOrdersMenuButtonClick, handleOrdersMenuClose];
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useTasks, useClientEvent, useTaskCard, useOrders, useWindowResize };
|
export { useTasks, useClientEvent, useTaskCard, useOrders };
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Панель мониторинга: Корневая панель доски задач
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
|
||||||
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
|
||||||
import { Stack, Card, CardHeader, CardContent, Typography, Box, Button, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
//import { Draggable } from "react-draggable";
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { width: "100%", padding: 1 },
|
|
||||||
DEF_SIZE: { minWidth: "200px", minHeight: "100px" },
|
|
||||||
SETTINGS_BUTTON: {
|
|
||||||
position: "absolute",
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
color: theme => theme.palette.grey[500]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Корневая панель доски задач
|
|
||||||
const ClntTaskBoard = () => {
|
|
||||||
const [categories, setCategories] = useState([
|
|
||||||
{ id: 1, name: "Новое" },
|
|
||||||
{ id: 2, name: "Старое" }
|
|
||||||
]);
|
|
||||||
const [tasks, setTasks] = useState([
|
|
||||||
{ id: 1, name: "Задание1", category: 1 },
|
|
||||||
{ id: 2, name: "Задание2", category: 1 },
|
|
||||||
{ id: 3, name: "Задание3", category: 2 },
|
|
||||||
{ id: 4, name: "Задание4", category: 2 }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const onDragEnd = result => {
|
|
||||||
const { source, destination } = result;
|
|
||||||
|
|
||||||
if (!destination) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destination.droppableId === "Categories") {
|
|
||||||
setCategories(categories);
|
|
||||||
} else if (destination.droppableId !== source.droppableId) {
|
|
||||||
setTasks(tasks =>
|
|
||||||
tasks.map(task =>
|
|
||||||
task.id === parseInt(result.draggableId)
|
|
||||||
? {
|
|
||||||
...task,
|
|
||||||
category: parseInt(result.destination.droppableId)
|
|
||||||
}
|
|
||||||
: task
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setTasks(tasks);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.CONTAINER}>
|
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
|
||||||
<div>
|
|
||||||
<Droppable droppableId="Categories" type="droppableTask">
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
{categories.map((category, index) => (
|
|
||||||
<div key={index}>
|
|
||||||
<Droppable droppableId={category.id.toString()}>
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Card
|
|
||||||
className="category-card"
|
|
||||||
sx={{ ...STYLES.DEF_SIZE, backgroundColor: "#FFA500", padding: 1 }}
|
|
||||||
>
|
|
||||||
<CardHeader
|
|
||||||
action={
|
|
||||||
<IconButton
|
|
||||||
aria-label="settings"
|
|
||||||
onClick={() => {
|
|
||||||
console.log("Опции типа");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
title={category.name}
|
|
||||||
subheader={
|
|
||||||
<Button onClick={() => console.log("Добавление события")}>+ Добавить</Button>
|
|
||||||
}
|
|
||||||
sx={{ padding: 0 }}
|
|
||||||
/>
|
|
||||||
<CardContent sx={{ padding: 0 }}>
|
|
||||||
<Stack spacing={1}>
|
|
||||||
{tasks
|
|
||||||
.filter(item => item.category === category.id)
|
|
||||||
.map((item, index) => (
|
|
||||||
<Draggable draggableId={item.id.toString()} key={item.id} index={index}>
|
|
||||||
{provided => (
|
|
||||||
<Card
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
>
|
|
||||||
<CardHeader
|
|
||||||
action={
|
|
||||||
<IconButton
|
|
||||||
aria-label="settings"
|
|
||||||
onClick={() => {
|
|
||||||
console.log("Опции задачи");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
title={
|
|
||||||
<Typography
|
|
||||||
className="task-info"
|
|
||||||
sx={{ padding: "2px" }}
|
|
||||||
>
|
|
||||||
{item.id} {item.name}
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
sx={{ padding: 0 }}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
))}
|
|
||||||
{provided.placeholder}
|
|
||||||
</Stack>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
{provided.placeholder}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
</DragDropContext>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { ClntTaskBoard };
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Фильтр отбора
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Chip, Stack, Icon, IconButton } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//--------------------------
|
|
||||||
//Вспомогательные компоненты
|
|
||||||
//--------------------------
|
|
||||||
|
|
||||||
//Элемент фильтра
|
|
||||||
const FilterItem = ({ caption, value, onClick }) => {
|
|
||||||
//При нажатии на элемент
|
|
||||||
const handleClick = () => (onClick ? onClick() : null);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Chip
|
|
||||||
label={
|
|
||||||
<Stack direction={"row"} alignItems={"center"}>
|
|
||||||
<strong>{caption}</strong>: {value}
|
|
||||||
</Stack>
|
|
||||||
}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={handleClick}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Элемент фильтра
|
|
||||||
FilterItem.propTypes = {
|
|
||||||
caption: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.any.isRequired,
|
|
||||||
onClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Фильтр отбора
|
|
||||||
const Filter = ({ filter, onClick }) => {
|
|
||||||
//При нажатии на фильтр
|
|
||||||
const handleClick = () => (onClick ? onClick() : null);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Stack direction="row" spacing={1} p={1} alignItems={"center"}>
|
|
||||||
<IconButton onClick={handleClick}>
|
|
||||||
<Icon>filter_alt</Icon>
|
|
||||||
</IconButton>
|
|
||||||
{/*filter. ? <FilterItem caption={""} value={filter.} onClick={handleClick} /> : null*/}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Фильтр отбора
|
|
||||||
Filter.propTypes = {
|
|
||||||
filter: PropTypes.object.isRequired,
|
|
||||||
onClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { Filter };
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Панель мониторинга: Точка входа
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import { ClntTaskBoard } from "./clnt_task_board"; //Корневая панель выполнения работ
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export const RootClass = ClntTaskBoard;
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Карточка события
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import {} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Карточка события
|
|
||||||
const TaskCard = () => {
|
|
||||||
//Генерация содержимого
|
|
||||||
return <div></div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Контейнер типа события
|
|
||||||
TaskCard.propTypes = {};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { TaskCard };
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Контейнер типа события
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import {} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Контейнер типа события
|
|
||||||
const TasksCategory = () => {
|
|
||||||
//Генерация содержимого
|
|
||||||
return <div></div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Контейнер типа события
|
|
||||||
TasksCategory.propTypes = {};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { TasksCategory };
|
|
@ -1,346 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Панель мониторинга: Корневая панель доски задач
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState, useContext, useCallback, useEffect, useRef } from "react"; //Классы React
|
|
||||||
import { DragDropContext, Droppable } from "react-beautiful-dnd";
|
|
||||||
import { Stack, Card, CardHeader, CardContent, Box, Button, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
|
||||||
//import { Draggable } from "react-draggable";
|
|
||||||
import { TaskCard } from "./components/task_card";
|
|
||||||
import { TaskFormDialog } from "./components/task_form";
|
|
||||||
import { object2Base64XML } from "../../core/utils";
|
|
||||||
import { Filter } from "./filter.js";
|
|
||||||
import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
|
|
||||||
import { TaskCardSettings } from "./components/task_card_settings.js"; //
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { width: "100%", padding: 1 },
|
|
||||||
DEF_SIZE: { minWidth: "200px", minHeight: "100px" },
|
|
||||||
SETTINGS_BUTTON: {
|
|
||||||
position: "absolute",
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
color: theme => theme.palette.grey[500]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const COLORS = [
|
|
||||||
"mediumSlateBlue",
|
|
||||||
"lightSalmon",
|
|
||||||
"fireBrick",
|
|
||||||
"orange",
|
|
||||||
"gold",
|
|
||||||
"limeGreen",
|
|
||||||
"yellowGreen",
|
|
||||||
"mediumAquaMarine",
|
|
||||||
"paleTurquoise",
|
|
||||||
"steelBlue",
|
|
||||||
"skyBlue",
|
|
||||||
"tan"
|
|
||||||
];
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Корневая панель доски задач
|
|
||||||
const ClntTaskBoard = () => {
|
|
||||||
const [insertTask, setInsertTask] = useState(false);
|
|
||||||
|
|
||||||
const [cardSettings, setCardSettings] = useState({ isOpen: false, settings: {} });
|
|
||||||
|
|
||||||
const [config, setConfig] = useState({
|
|
||||||
groupsLoaded: false,
|
|
||||||
tasksLoaded: false,
|
|
||||||
filters: {
|
|
||||||
isOpen: false,
|
|
||||||
isSetByUser: false,
|
|
||||||
values: { type: "", sendPerson: "", sendDivision: "", sendUsrGrp: "" },
|
|
||||||
fArray: [
|
|
||||||
{ name: "SEVTYPE_CODE", from: "", to: "" },
|
|
||||||
{ name: "SSEND_PERSON", from: "", to: "" },
|
|
||||||
{ name: "SSEND_DIVISION", from: "", to: "" },
|
|
||||||
{ name: "SSEND_USRGRP", from: "", to: "" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
reload: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const [statuses, setStatuses] = useState([]);
|
|
||||||
|
|
||||||
const [tasks, setTasks] = useState([]);
|
|
||||||
|
|
||||||
let usedColors = useRef([]);
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
// const appendGroup = newStatus => {};
|
|
||||||
|
|
||||||
// const appendTask = task => {
|
|
||||||
// //setTasks([...tasks, task]);
|
|
||||||
// };
|
|
||||||
|
|
||||||
const randomColor = () => {
|
|
||||||
let color = COLORS[Math.floor(Math.random() * COLORS.length)];
|
|
||||||
while (usedColors.current.find(c => c === color) !== undefined) {
|
|
||||||
color = COLORS[Math.floor(Math.random() * COLORS.length)];
|
|
||||||
}
|
|
||||||
usedColors.current = [...usedColors.current, color];
|
|
||||||
return color;
|
|
||||||
};
|
|
||||||
|
|
||||||
const initTask = (id, gp, task) => {
|
|
||||||
return {
|
|
||||||
id: id,
|
|
||||||
name: `${task.SEVPREF}-${task.NEVNUMB}`,
|
|
||||||
category: gp,
|
|
||||||
nrn: task.NRN,
|
|
||||||
scrn: "",
|
|
||||||
sprefix: task.SEVPREF,
|
|
||||||
snumber: task.NEVNUMB,
|
|
||||||
stype: task.SEVTYPE_CODE,
|
|
||||||
sstatus: task.SEVSTAT_NAME,
|
|
||||||
sdescription: task.SEVDESCR,
|
|
||||||
sclnt_clnclients: "",
|
|
||||||
sclnt_clnperson: "",
|
|
||||||
dstart_date: task.DREG_DATE,
|
|
||||||
sinit_clnperson: task.SINIT_PERSON,
|
|
||||||
sinit_user: "",
|
|
||||||
sinit_reason: "",
|
|
||||||
sto_company: "",
|
|
||||||
sto_department: "",
|
|
||||||
sto_clnpost: "",
|
|
||||||
sto_clnpsdep: "",
|
|
||||||
sto_clnperson: "",
|
|
||||||
sto_fcstaffgrp: "",
|
|
||||||
sto_user: task.SSEND_PERSON,
|
|
||||||
sto_usergrp: task.SSEND_USRGRP,
|
|
||||||
scurrent_user: ""
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTasks = useCallback(async () => {
|
|
||||||
if (config.reload) {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_DATASET",
|
|
||||||
args: {
|
|
||||||
CFILTERS: { VALUE: object2Base64XML(config.filters.fArray, { arrayNodeName: "filters" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
|
||||||
NINCLUDE_DEF: config.tasksLoaded ? 0 : 1
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
console.log(object2Base64XML(config.filters.fArray, { arrayNodeName: "filters" }));
|
|
||||||
let newSt = [];
|
|
||||||
if (data.XGROUPS != null) {
|
|
||||||
const x = statuses.length;
|
|
||||||
data.XGROUPS.map((group, i) => {
|
|
||||||
//setStatuses([...statuses, { id: x + i, name: group.name }]);
|
|
||||||
newSt.push({ id: x + i, name: group.name, color: randomColor() });
|
|
||||||
//console.log(`${x + i} ${group.name}`);
|
|
||||||
});
|
|
||||||
setStatuses([...newSt].sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1)));
|
|
||||||
setConfig(pv => ({ ...pv, groupsLoaded: true }));
|
|
||||||
}
|
|
||||||
if (data.XROWS != null) {
|
|
||||||
let newT = [];
|
|
||||||
const x = tasks.length;
|
|
||||||
data.XROWS.map((task, i) => {
|
|
||||||
//setStatuses([...statuses, { id: x + i, name: group.name }]);
|
|
||||||
//console.log(statuses.find(x => x.name === task.groupName).id ? newSt.find(x => x.name === task.groupName) : null);
|
|
||||||
newT.push(initTask(x + i, newSt.find(x => x.name === task.groupName).id, task));
|
|
||||||
});
|
|
||||||
setTasks([...newT]);
|
|
||||||
setConfig(pv => ({ ...pv, tasksLoaded: true, reload: false }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [SERV_DATA_TYPE_CLOB, config.filters, config.reload, config.tasksLoaded, executeStored, statuses, tasks]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getTasks();
|
|
||||||
}, [config.reload, getTasks]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// config.groupsLoaded ? console.log(statuses) : null;
|
|
||||||
// config.tasksLoaded ? console.log(tasks) : null;
|
|
||||||
// }, [config.groupsLoaded, statuses]);
|
|
||||||
|
|
||||||
const onDragEnd = result => {
|
|
||||||
const { source, destination } = result;
|
|
||||||
|
|
||||||
if (!destination) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destination.droppableId !== source.droppableId) {
|
|
||||||
setTasks(tasks =>
|
|
||||||
tasks.map(task =>
|
|
||||||
task.id === parseInt(result.draggableId)
|
|
||||||
? {
|
|
||||||
...task,
|
|
||||||
category: parseInt(result.destination.droppableId)
|
|
||||||
}
|
|
||||||
: task
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log(statuses.find(s => s.id == destination.droppableId).name); // Тут вызов смены статуса
|
|
||||||
} else {
|
|
||||||
setTasks(tasks);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//При открытии диалога фильтра
|
|
||||||
const handleFilterClick = () => setFilterOpen(true);
|
|
||||||
|
|
||||||
//При изменении фильтра в диалоге
|
|
||||||
const handleFilterOk = filter => {
|
|
||||||
setFilterValues(filter);
|
|
||||||
setFilterOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
//При закрытии диалога фильтра
|
|
||||||
const handleFilterCancel = () => setFilterOpen(false);
|
|
||||||
|
|
||||||
//Установить значение фильтра
|
|
||||||
const setFilterValues = values => {
|
|
||||||
let filterArr = config.filters.fArray.slice();
|
|
||||||
values.type ? (filterArr.find(f => f.name === "SEVTYPE_CODE").from = values.type) : null;
|
|
||||||
values.sendPerson ? (filterArr.find(f => f.name === "SSEND_PERSON").from = values.sendPerson) : null;
|
|
||||||
values.sendDivision ? (filterArr.find(f => f.name === "SSEND_DIVISION").from = values.sendDivision) : null;
|
|
||||||
values.sendUsrGrp ? (filterArr.find(f => f.name === "SSEND_USRGRP").from = values.sendUsrGrp) : null;
|
|
||||||
setConfig(pv => ({ ...pv, filters: { ...pv.filters, isSetByUser: true, values: { ...values }, fArray: [...filterArr] }, reload: true }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//Показать/скрыть фильтр
|
|
||||||
const setFilterOpen = isOpen => setConfig(pv => ({ ...pv, filters: { ...pv.filters, isOpen } }));
|
|
||||||
|
|
||||||
const handleCardSettingsClick = curSettings => {
|
|
||||||
setCardSettings({ isOpen: true, settings: { ...curSettings } });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCardSettingsCancel = () => setCardSettings(pv => ({ ...pv, isOpen: false }));
|
|
||||||
|
|
||||||
const handleCardSettingsOk = settings => {
|
|
||||||
let cloneS = statuses.slice();
|
|
||||||
cloneS[statuses.findIndex(x => x.id === settings.id)] = { ...settings };
|
|
||||||
setStatuses(cloneS);
|
|
||||||
setCardSettings({ isOpen: false, settings: {} });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.CONTAINER}>
|
|
||||||
{config.filters.isOpen ? <FilterDialog initial={config.filters.values} onOk={handleFilterOk} onCancel={handleFilterCancel} /> : null}
|
|
||||||
<Filter filter={config.filters.values} onClick={handleFilterClick} />
|
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
|
||||||
<div>
|
|
||||||
<Droppable droppableId="Statuses" type="droppableTask">
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
{statuses.map((status, index) => (
|
|
||||||
<div key={index}>
|
|
||||||
<Droppable droppableId={status.id.toString()}>
|
|
||||||
{provided => (
|
|
||||||
<div ref={provided.innerRef}>
|
|
||||||
<Card
|
|
||||||
className="category-card"
|
|
||||||
sx={{ ...STYLES.DEF_SIZE, backgroundColor: status.color, padding: 1 }}
|
|
||||||
>
|
|
||||||
<CardHeader
|
|
||||||
action={
|
|
||||||
<IconButton aria-label="settings" onClick={() => handleCardSettingsClick(status)}>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
title={status.name}
|
|
||||||
subheader={<Button onClick={() => setInsertTask(true)}>+ Добавить</Button>}
|
|
||||||
sx={{ padding: 0 }}
|
|
||||||
/>
|
|
||||||
<CardContent sx={{ padding: 0 }}>
|
|
||||||
<Stack spacing={1}>
|
|
||||||
{tasks
|
|
||||||
.filter(item => item.category === status.id)
|
|
||||||
.map((item, index) => (
|
|
||||||
<TaskCard task={item} index={index} key={item.id} />
|
|
||||||
// <Draggable draggableId={item.id.toString()} key={item.id} index={index}>
|
|
||||||
// {provided => (
|
|
||||||
// <Card
|
|
||||||
// ref={provided.innerRef}
|
|
||||||
// {...provided.draggableProps}
|
|
||||||
// {...provided.dragHandleProps}
|
|
||||||
// >
|
|
||||||
// <CardHeader
|
|
||||||
// action={
|
|
||||||
// <IconButton
|
|
||||||
// aria-label="settings"
|
|
||||||
// onClick={() => {
|
|
||||||
// console.log("Опции задачи");
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// <Icon>more_vert</Icon>
|
|
||||||
// </IconButton>
|
|
||||||
// }
|
|
||||||
// title={
|
|
||||||
// <Typography
|
|
||||||
// className="task-info"
|
|
||||||
// sx={{ padding: "2px" }}
|
|
||||||
// >
|
|
||||||
// {item.id} {item.name}
|
|
||||||
// </Typography>
|
|
||||||
// }
|
|
||||||
// sx={{ padding: 0 }}
|
|
||||||
// />
|
|
||||||
// </Card>
|
|
||||||
// )}
|
|
||||||
// </Draggable>
|
|
||||||
))}
|
|
||||||
{provided.placeholder}
|
|
||||||
</Stack>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
{provided.placeholder}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Droppable>
|
|
||||||
</div>
|
|
||||||
</DragDropContext>
|
|
||||||
{insertTask ? (
|
|
||||||
<TaskFormDialog
|
|
||||||
onClose={() => {
|
|
||||||
setInsertTask(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{cardSettings.isOpen ? (
|
|
||||||
<TaskCardSettings
|
|
||||||
initial={cardSettings.settings}
|
|
||||||
availableClrs={COLORS.filter(c => !usedColors.current.includes(c))}
|
|
||||||
onOk={handleCardSettingsOk}
|
|
||||||
onCancel={handleCardSettingsCancel}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { ClntTaskBoard };
|
|
@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Диалоговое окно фильтра отбора
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState, useContext } from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Dialog, DialogTitle, IconButton, Icon, DialogContent, DialogActions, Button, Box } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { FilterInputField } from "./filter_input_field"; //Компонент поля ввода
|
|
||||||
import { ApplicationСtx } from "../../../context/application"; //Контекст приложения
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
DIALOG_ACTIONS: { justifyContent: "center" },
|
|
||||||
CLOSE_BUTTON: {
|
|
||||||
position: "absolute",
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
color: theme => theme.palette.grey[500]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------
|
|
||||||
//Вспомогательные функции
|
|
||||||
//-----------------------
|
|
||||||
|
|
||||||
//Выбор типа события
|
|
||||||
const selectEventType = (showDictionary, callBack) => {
|
|
||||||
showDictionary({
|
|
||||||
unitCode: "ClientEventTypes",
|
|
||||||
callBack: res => (res.success === true ? callBack(res.outParameters.out_EVNTYPE_CODE) : callBack(null))
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Выбор производственного объекта
|
|
||||||
const selectSendPerson = (showDictionary, callBack) => {
|
|
||||||
showDictionary({
|
|
||||||
unitCode: "ClientPersons",
|
|
||||||
callBack: res => (res.success === true ? callBack(res.outParameters.out_CODE) : callBack(null))
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Выбор подразделения
|
|
||||||
const selectSendDivision = (showDictionary, callBack) => {
|
|
||||||
showDictionary({
|
|
||||||
unitCode: "INS_DEPARTMENT",
|
|
||||||
callBack: res => (res.success === true ? callBack(res.outParameters.out_CODE) : callBack(null))
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//Выбор группы пользователей
|
|
||||||
const selectSendUsrGrp = (showDictionary, callBack) => {
|
|
||||||
showDictionary({
|
|
||||||
unitCode: "CostStaffGroups",
|
|
||||||
callBack: res => (res.success === true ? callBack(res.outParameters.out_CODE) : callBack(null))
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Диалоговое окно фильтра отбора
|
|
||||||
const FilterDialog = ({ initial, onCancel, onOk }) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [filter, setFilter] = useState({ ...initial });
|
|
||||||
|
|
||||||
//Подключение к контексту приложения
|
|
||||||
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
|
||||||
|
|
||||||
//При закрытии диалога без изменения фильтра
|
|
||||||
const handleCancel = () => (onCancel ? onCancel() : null);
|
|
||||||
|
|
||||||
//При очистке фильтра
|
|
||||||
const handleClear = () => {
|
|
||||||
setFilter({
|
|
||||||
type: "",
|
|
||||||
sendPerson: "",
|
|
||||||
sendDivision: "",
|
|
||||||
sendUsrGrp: ""
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//При закрытии диалога с изменением фильтра
|
|
||||||
const handleOK = () => (onOk ? onOk(filter) : null);
|
|
||||||
|
|
||||||
//При изменении значения элемента
|
|
||||||
const handleFilterItemChange = (item, value) => setFilter(pv => ({ ...pv, [item]: value }));
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Dialog open onClose={handleCancel} fullWidth maxWidth="sm">
|
|
||||||
<DialogTitle>Фильтр отбора</DialogTitle>
|
|
||||||
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
|
||||||
<Icon>close</Icon>
|
|
||||||
</IconButton>
|
|
||||||
<DialogContent>
|
|
||||||
<Box component="section" p={1}>
|
|
||||||
<FilterInputField
|
|
||||||
elementCode="type"
|
|
||||||
elementValue={filter.type}
|
|
||||||
labelText="Тип"
|
|
||||||
dictionary={callBack => selectEventType(pOnlineShowDictionary, callBack)}
|
|
||||||
onChange={handleFilterItemChange}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box component="section" p={1}>
|
|
||||||
<FilterInputField
|
|
||||||
elementCode="sendPerson"
|
|
||||||
elementValue={filter.sendPerson}
|
|
||||||
labelText="Исполнитель"
|
|
||||||
dictionary={callBack => selectSendPerson(pOnlineShowDictionary, callBack)}
|
|
||||||
onChange={handleFilterItemChange}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box component="section" p={1}>
|
|
||||||
<FilterInputField
|
|
||||||
elementCode="sendDivision"
|
|
||||||
elementValue={filter.sendDivision}
|
|
||||||
labelText="Подразделение"
|
|
||||||
dictionary={callBack => selectSendDivision(pOnlineShowDictionary, callBack)}
|
|
||||||
onChange={handleFilterItemChange}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Box component="section" p={1}>
|
|
||||||
<FilterInputField
|
|
||||||
elementCode="sendUsrGrp"
|
|
||||||
elementValue={filter.sendUsrGrp}
|
|
||||||
labelText="Группа пользователей"
|
|
||||||
dictionary={callBack => selectSendUsrGrp(pOnlineShowDictionary, callBack)}
|
|
||||||
onChange={handleFilterItemChange}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
|
||||||
<Button variant="text" onClick={handleOK}>
|
|
||||||
Применить
|
|
||||||
</Button>
|
|
||||||
<Button variant="text" onClick={handleClear}>
|
|
||||||
Очистить
|
|
||||||
</Button>
|
|
||||||
<Button variant="text" onClick={handleCancel}>
|
|
||||||
Отмена
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Диалоговое окно фильтра отбора
|
|
||||||
FilterDialog.propTypes = {
|
|
||||||
initial: PropTypes.object.isRequired,
|
|
||||||
onOk: PropTypes.func,
|
|
||||||
onCancel: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { FilterDialog };
|
|
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Поле ввода диалога фильтра
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { FormControl, InputLabel, Input, InputAdornment, IconButton, Icon, FormHelperText, Select, MenuItem } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
HELPER_TEXT: { color: "red" }
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Поле ввода
|
|
||||||
const FilterInputField = ({ elementCode, elementValue, labelText, onChange, required = false, items = null, dictionary }) => {
|
|
||||||
//Значение элемента
|
|
||||||
const [value, setValue] = useState(elementValue);
|
|
||||||
|
|
||||||
//При получении нового значения из вне
|
|
||||||
useEffect(() => {
|
|
||||||
setValue(elementValue);
|
|
||||||
}, [elementValue]);
|
|
||||||
|
|
||||||
//Выбор значения из словаря
|
|
||||||
const handleDictionaryClick = () =>
|
|
||||||
dictionary ? dictionary(res => (res ? handleChange({ target: { name: elementCode, value: res } }) : null)) : null;
|
|
||||||
|
|
||||||
//Изменение значения элемента
|
|
||||||
const handleChange = e => {
|
|
||||||
setValue(e.target.value);
|
|
||||||
if (onChange) onChange(e.target.name, e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация поля с выбором из словаря Парус
|
|
||||||
const renderInput = validationError => {
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
error={validationError}
|
|
||||||
id={elementCode}
|
|
||||||
name={elementCode}
|
|
||||||
value={value}
|
|
||||||
endAdornment={
|
|
||||||
dictionary ? (
|
|
||||||
<InputAdornment position="end">
|
|
||||||
<IconButton aria-label={`${elementCode} select`} onClick={handleDictionaryClick} edge="end">
|
|
||||||
<Icon>list</Icon>
|
|
||||||
</IconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
) : null
|
|
||||||
}
|
|
||||||
aria-describedby={`${elementCode}-helper-text`}
|
|
||||||
label={labelText}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация поля с выпадающим списком
|
|
||||||
const renderSelect = (items, validationError) => {
|
|
||||||
return (
|
|
||||||
<Select
|
|
||||||
error={validationError}
|
|
||||||
id={elementCode}
|
|
||||||
name={elementCode}
|
|
||||||
value={value}
|
|
||||||
aria-describedby={`${elementCode}-helper-text`}
|
|
||||||
label={labelText}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{items
|
|
||||||
? items.map((item, i) => (
|
|
||||||
<MenuItem key={i} value={item.value}>
|
|
||||||
{item.caption}
|
|
||||||
</MenuItem>
|
|
||||||
))
|
|
||||||
: null}
|
|
||||||
</Select>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Признак ошибки валидации
|
|
||||||
const validationError = !value && required ? true : false;
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<FormControl fullWidth variant="standard">
|
|
||||||
<InputLabel htmlFor={elementCode}>{labelText}</InputLabel>
|
|
||||||
{items ? renderSelect(items, validationError) : renderInput(validationError)}
|
|
||||||
{validationError ? (
|
|
||||||
<FormHelperText id={`${elementCode}-helper-text`} sx={STYLES.HELPER_TEXT}>
|
|
||||||
*Обязательное поле
|
|
||||||
</FormHelperText>
|
|
||||||
) : null}
|
|
||||||
</FormControl>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Поле ввода
|
|
||||||
FilterInputField.propTypes = {
|
|
||||||
elementCode: PropTypes.string.isRequired,
|
|
||||||
elementValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
||||||
labelText: PropTypes.string.isRequired,
|
|
||||||
required: PropTypes.bool,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
dictionary: PropTypes.func,
|
|
||||||
onChange: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { FilterInputField };
|
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент панели: Карточка задачи
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
|
||||||
import { Card, CardHeader, Typography, IconButton, Icon, Box, Menu, MenuItem } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { useTaskCard } from "../hooks"; //Вспомогательные хуки
|
|
||||||
import { TaskFormDialog } from "./task_form"; //Форма события
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
|
||||||
DATA_GRID_CELL_DEFAULT: { cursor: "pointer", backgroundColor: "#ADD8E6" }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//Действия карты показателя
|
|
||||||
const DataCellCardActions = ({ taskRn, menuItems, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose }) => {
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.BOX_ROW}>
|
|
||||||
<IconButton id={`${taskRn}_menu_button`} aria-haspopup="true" onClick={handleMethodsMenuButtonClick}>
|
|
||||||
<Icon>more_vert</Icon>
|
|
||||||
</IconButton>
|
|
||||||
<Menu id={`${taskRn}_menu`} anchorEl={cardActions.anchorMenuMethods} open={cardActions.openMethods} onClose={handleMethodsMenuClose}>
|
|
||||||
{menuItems.map(el => {
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
key={`${taskRn}_${el.method}`}
|
|
||||||
onClick={() => {
|
|
||||||
el.func(taskRn);
|
|
||||||
handleMethodsMenuClose();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon>{el.icon}</Icon>
|
|
||||||
{el.name}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Menu>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Действия карты показателя
|
|
||||||
DataCellCardActions.propTypes = {
|
|
||||||
taskRn: PropTypes.number.isRequired,
|
|
||||||
menuItems: PropTypes.array.isRequired,
|
|
||||||
cardActions: PropTypes.object.isRequired,
|
|
||||||
handleMethodsMenuButtonClick: PropTypes.func.isRequired,
|
|
||||||
handleMethodsMenuClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Карточка задачи
|
|
||||||
const TaskCard = ({ task, index }) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [taskCard, setTaskCard, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose, menuItems] = useTaskCard();
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Draggable draggableId={task.id.toString()} key={task.id} index={index}>
|
|
||||||
{provided => (
|
|
||||||
<Card ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
|
||||||
<CardHeader
|
|
||||||
title={
|
|
||||||
<Typography className="task-info" sx={{ padding: "2px" }}>
|
|
||||||
{task.id} {task.name}
|
|
||||||
</Typography>
|
|
||||||
}
|
|
||||||
sx={{ padding: 0 }}
|
|
||||||
action={
|
|
||||||
<DataCellCardActions
|
|
||||||
taskRn={task.nrn}
|
|
||||||
menuItems={menuItems}
|
|
||||||
cardActions={cardActions}
|
|
||||||
handleMethodsMenuButtonClick={handleMethodsMenuButtonClick}
|
|
||||||
handleMethodsMenuClose={handleMethodsMenuClose}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
{taskCard.openEdit ? (
|
|
||||||
<TaskFormDialog
|
|
||||||
taskRn={task.nrn}
|
|
||||||
onClose={() => {
|
|
||||||
setTaskCard(pv => ({ ...pv, openEdit: false }));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Карточка задачи
|
|
||||||
TaskCard.propTypes = {
|
|
||||||
task: PropTypes.object.isRequired,
|
|
||||||
index: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { TaskCard };
|
|
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Диалоговое окно настройки карточки событий
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
IconButton,
|
|
||||||
Icon,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
Button,
|
|
||||||
Box,
|
|
||||||
FormControl,
|
|
||||||
InputLabel,
|
|
||||||
Select,
|
|
||||||
MenuItem
|
|
||||||
} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
DIALOG_ACTIONS: { justifyContent: "center" },
|
|
||||||
CLOSE_BUTTON: {
|
|
||||||
position: "absolute",
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
color: theme => theme.palette.grey[500]
|
|
||||||
},
|
|
||||||
BCKG_COLOR: backgroundColor => ({ backgroundColor: backgroundColor })
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------------------
|
|
||||||
//Вспомогательные функции
|
|
||||||
//-----------------------
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Диалоговое окно фильтра отбора
|
|
||||||
const TaskCardSettings = ({ initial, availableClrs, onCancel, onOk }) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [settings, setSettings] = useState({ ...initial });
|
|
||||||
|
|
||||||
//При закрытии диалога без изменений
|
|
||||||
const handleCancel = () => (onCancel ? onCancel() : null);
|
|
||||||
|
|
||||||
//При закрытии диалога с изменениями
|
|
||||||
const handleOK = () => (onOk ? onOk(settings) : null);
|
|
||||||
|
|
||||||
//При изменении значения элемента
|
|
||||||
const handleSettingsItemChange = e => {
|
|
||||||
setSettings(pv => ({ ...pv, color: e.target.value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Dialog open onClose={handleCancel} fullWidth maxWidth="sm">
|
|
||||||
<DialogTitle>Настройки</DialogTitle>
|
|
||||||
<IconButton aria-label="close" onClick={handleCancel} sx={STYLES.CLOSE_BUTTON}>
|
|
||||||
<Icon>close</Icon>
|
|
||||||
</IconButton>
|
|
||||||
<DialogContent>
|
|
||||||
<Box component="section" p={1}>
|
|
||||||
<FormControl fullWidth>
|
|
||||||
<InputLabel id="color-label">Цвет</InputLabel>
|
|
||||||
<Select
|
|
||||||
defaultValue={initial.color}
|
|
||||||
labelId="color-label"
|
|
||||||
id="color"
|
|
||||||
label="Цвет"
|
|
||||||
sx={STYLES.BCKG_COLOR(settings.color)}
|
|
||||||
onChange={handleSettingsItemChange}
|
|
||||||
>
|
|
||||||
<MenuItem key={0} value={initial.color} sx={STYLES.BCKG_COLOR(initial.color)}>
|
|
||||||
{initial.color}
|
|
||||||
</MenuItem>
|
|
||||||
{availableClrs.map((clr, i) => {
|
|
||||||
return (
|
|
||||||
<MenuItem key={i + 1} value={clr} sx={STYLES.BCKG_COLOR(clr)}>
|
|
||||||
{clr}
|
|
||||||
</MenuItem>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</Box>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions sx={STYLES.DIALOG_ACTIONS}>
|
|
||||||
<Button variant="text" onClick={handleOK}>
|
|
||||||
Применить
|
|
||||||
</Button>
|
|
||||||
<Button variant="text" onClick={handleCancel}>
|
|
||||||
Отмена
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Диалоговое окно настройки карточки событий
|
|
||||||
TaskCardSettings.propTypes = {
|
|
||||||
initial: PropTypes.object.isRequired,
|
|
||||||
availableClrs: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
||||||
onOk: PropTypes.func,
|
|
||||||
onCancel: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { TaskCardSettings };
|
|
@ -1,487 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент панели: Диалог формы события
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Box, Typography, TextField, Dialog, DialogContent, DialogActions, Button, Tabs, Tab, InputAdornment, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { useClientEvent } from "../hooks"; //Вспомогательные хуки
|
|
||||||
|
|
||||||
//---------
|
|
||||||
//Константы
|
|
||||||
//---------
|
|
||||||
|
|
||||||
//Стили
|
|
||||||
const STYLES = {
|
|
||||||
CONTAINER: { margin: "5px 0px", textAlign: "center" },
|
|
||||||
DIALOG_CONTENT: {
|
|
||||||
paddingBottom: "0px",
|
|
||||||
maxHeight: "740px",
|
|
||||||
minHeight: "740px",
|
|
||||||
"&::-webkit-scrollbar": {
|
|
||||||
width: "8px"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-track": {
|
|
||||||
borderRadius: "8px",
|
|
||||||
backgroundColor: "#EBEBEB"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb": {
|
|
||||||
borderRadius: "8px",
|
|
||||||
backgroundColor: "#b4b4b4"
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb:hover": {
|
|
||||||
backgroundColor: "#808080"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BOX_WITH_LEGEND: { border: "1px solid #939393" },
|
|
||||||
BOX_SINGLE_COLUMN: { display: "flex", flexDirection: "column", gap: "10px" },
|
|
||||||
BOX_FEW_COLUMNS: { display: "flex", flexWrap: "wrap", justifyContent: "space-between" },
|
|
||||||
BOX_LEFT_ALIGN: { display: "flex", justifyContent: "flex-start" },
|
|
||||||
LEGEND: { textAlign: "left" },
|
|
||||||
TEXT_FIELD: (widthVal, greyDisabled = false) => ({
|
|
||||||
margin: "4px",
|
|
||||||
...(widthVal ? { width: widthVal } : {}),
|
|
||||||
...(greyDisabled
|
|
||||||
? {
|
|
||||||
"& .MuiInputBase-input.Mui-disabled": {
|
|
||||||
WebkitTextFillColor: "rgba(0, 0, 0, 0.87)"
|
|
||||||
},
|
|
||||||
"& .MuiInputLabel-root.Mui-disabled": {
|
|
||||||
WebkitTextFillColor: "rgba(0, 0, 0, 0.6)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: {})
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------
|
|
||||||
//Вспомогательные функции и компоненты
|
|
||||||
//------------------------------------
|
|
||||||
|
|
||||||
//Свойства вкладки
|
|
||||||
function a11yProps(index) {
|
|
||||||
return {
|
|
||||||
id: `simple-tab-${index}`,
|
|
||||||
"aria-controls": `simple-tabpanel-${index}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//Формирование кнопки для открытия раздела
|
|
||||||
const getInputProps = (onClick, disabled = false, icon = "list") => {
|
|
||||||
return {
|
|
||||||
endAdornment: (
|
|
||||||
<InputAdornment position="end">
|
|
||||||
<IconButton disabled={disabled} aria-label={`select`} onClick={onClick} edge="end">
|
|
||||||
<Icon>{icon}</Icon>
|
|
||||||
</IconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//Вкладка информации
|
|
||||||
function CustomTabPanel(props) {
|
|
||||||
const { children, value, index, ...other } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box role="tabpanel" hidden={value !== index} id={`simple-tabpanel-${index}`} aria-labelledby={`simple-tab-${index}`} {...other}>
|
|
||||||
{value === index && <Box pt={1}>{children}</Box>}
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Контроль свойств - Вкладка информации
|
|
||||||
CustomTabPanel.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
index: PropTypes.number.isRequired,
|
|
||||||
value: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Вкладка основной информации
|
|
||||||
const MainEventInfoTab = ({
|
|
||||||
task,
|
|
||||||
handleFieldEdit,
|
|
||||||
handleTypeOpen,
|
|
||||||
handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Box sx={STYLES.BOX_WITH_LEGEND} component="fieldset">
|
|
||||||
<legend style={STYLES.LEGEND}>Событие</legend>
|
|
||||||
<Box sx={STYLES.BOX_FEW_COLUMNS}>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD()}
|
|
||||||
id="scrn"
|
|
||||||
label="Каталог"
|
|
||||||
variant="outlined"
|
|
||||||
fullWidth
|
|
||||||
value={task.scrn}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
InputProps={getInputProps(handleCrnOpen)}
|
|
||||||
required
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD("225px")}
|
|
||||||
id="sprefix"
|
|
||||||
label="Префикс"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sprefix}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
required
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD("225px")}
|
|
||||||
id="snumber"
|
|
||||||
label="Номер"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.snumber}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
required
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
InputProps={getInputProps(handleEventNextNumbGet, !task.sprefix || task.isUpdate, "refresh")}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
|
||||||
id="stype"
|
|
||||||
label="Тип"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.stype}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
required
|
|
||||||
InputProps={getInputProps(handleTypeOpen, task.isUpdate)}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD("225px", !task.isUpdate)}
|
|
||||||
id="sstatus"
|
|
||||||
label="Статус"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sstatus}
|
|
||||||
disabled
|
|
||||||
required
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
InputProps={getInputProps(handleStatusOpen, !task.stype || task.isUpdate)}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD()}
|
|
||||||
fullWidth
|
|
||||||
id="sdescription"
|
|
||||||
label="Описание"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sdescription}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={!task.stype}
|
|
||||||
required
|
|
||||||
multiline
|
|
||||||
minRows={7}
|
|
||||||
maxRows={7}
|
|
||||||
></TextField>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ ...STYLES.BOX_WITH_LEGEND, ...STYLES.BOX_SINGLE_COLUMN }} component="fieldset">
|
|
||||||
<legend style={STYLES.LEGEND}>Клиент</legend>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD()}
|
|
||||||
id="sclnt_clnclients"
|
|
||||||
label="Организация"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sclnt_clnclients}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={!task.stype}
|
|
||||||
InputProps={getInputProps(handleClientClientsOpen, !task.stype)}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
sx={STYLES.TEXT_FIELD()}
|
|
||||||
id="sclnt_clnperson"
|
|
||||||
label="Сотрудник"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sclnt_clnperson}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={!task.stype}
|
|
||||||
InputProps={getInputProps(() => handleClientPersonOpen(0), !task.stype)}
|
|
||||||
></TextField>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Вкладка основной информации
|
|
||||||
MainEventInfoTab.propTypes = {
|
|
||||||
task: PropTypes.object.isRequired,
|
|
||||||
handleFieldEdit: PropTypes.func.isRequired,
|
|
||||||
handleTypeOpen: PropTypes.func.isRequired,
|
|
||||||
handleStatusOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientClientsOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientPersonOpen: PropTypes.func.isRequired,
|
|
||||||
handleCrnOpen: PropTypes.func.isRequired,
|
|
||||||
handleEventNextNumbGet: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Вкладка информации об исполнителе
|
|
||||||
const ExecutorEventInfoTab = ({ task, handleFieldEdit, handleClientPersonOpen }) => {
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Box sx={{ ...STYLES.BOX_WITH_LEGEND, ...STYLES.BOX_LEFT_ALIGN }} component="fieldset">
|
|
||||||
<legend style={STYLES.LEGEND}>Планирование</legend>
|
|
||||||
<TextField
|
|
||||||
id="dstart_date"
|
|
||||||
label="Начало работ"
|
|
||||||
variant="outlined"
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="datetime-local"
|
|
||||||
value={task.dstart_date}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
></TextField>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ ...STYLES.BOX_WITH_LEGEND, ...STYLES.BOX_SINGLE_COLUMN }} component="fieldset">
|
|
||||||
<legend style={STYLES.LEGEND}>Инициатор</legend>
|
|
||||||
<TextField
|
|
||||||
id="sinit_clnperson"
|
|
||||||
label="Сотрудник"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_clnperson}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
InputProps={getInputProps(() => handleClientPersonOpen(1), task.isUpdate)}
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sinit_user"
|
|
||||||
label="Пользователь"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_user}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sinit_reason"
|
|
||||||
label="Основание"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sinit_reason}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled={task.isUpdate}
|
|
||||||
></TextField>
|
|
||||||
</Box>
|
|
||||||
<Box sx={{ ...STYLES.BOX_WITH_LEGEND, ...STYLES.BOX_SINGLE_COLUMN }} component="fieldset">
|
|
||||||
<legend style={STYLES.LEGEND}>Направить</legend>
|
|
||||||
<TextField
|
|
||||||
id="sto_company"
|
|
||||||
label="Организация"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_company}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_department"
|
|
||||||
label="Подразделение"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_department}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_clnpost"
|
|
||||||
label="Должность"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnpost}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_clnpsdep"
|
|
||||||
label="Штатная должность"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnpsdep}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_clnperson"
|
|
||||||
label="Сотрудник"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_clnperson}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_fcstaffgrp"
|
|
||||||
label="Нештатная должность"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_fcstaffgrp}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_user"
|
|
||||||
label="Пользователь"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_user}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
<TextField
|
|
||||||
id="sto_usergrp"
|
|
||||||
label="Группа пользователей"
|
|
||||||
variant="outlined"
|
|
||||||
value={task.sto_usergrp}
|
|
||||||
onChange={handleFieldEdit}
|
|
||||||
disabled
|
|
||||||
></TextField>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Вкладка информации об исполнителе
|
|
||||||
ExecutorEventInfoTab.propTypes = {
|
|
||||||
task: PropTypes.object.isRequired,
|
|
||||||
handleFieldEdit: PropTypes.func.isRequired,
|
|
||||||
handleClientPersonOpen: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Форма события
|
|
||||||
const TaskForm = ({
|
|
||||||
task,
|
|
||||||
setTask,
|
|
||||||
handleTypeOpen,
|
|
||||||
handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
}) => {
|
|
||||||
//Состояние вкладки
|
|
||||||
const [value, setValue] = useState(0);
|
|
||||||
|
|
||||||
//При изменении вкладки
|
|
||||||
const handleChange = (event, newValue) => {
|
|
||||||
setValue(newValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
//При изменении поля
|
|
||||||
const handleFieldEdit = e => {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
[e.target.id]: e.target.value,
|
|
||||||
//Связанные значения, если меняется одно, то необходимо обнулить другое
|
|
||||||
...(e.target.id === "sclnt_clnperson" ? { sclnt_clnclients: "" } : {}),
|
|
||||||
...(e.target.id === "sclnt_clnclients" ? { sclnt_clnperson: "" } : {})
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Box sx={STYLES.CONTAINER}>
|
|
||||||
<Typography pb={1} variant="h6">
|
|
||||||
{task.nrn ? "Исправление события" : "Добавление события"}
|
|
||||||
</Typography>
|
|
||||||
<Tabs value={value} onChange={handleChange} aria-label="tabs of values">
|
|
||||||
<Tab label="Событие" {...a11yProps(0)} />
|
|
||||||
<Tab label="Исполнитель" {...a11yProps(1)} />
|
|
||||||
</Tabs>
|
|
||||||
<CustomTabPanel value={value} index={0}>
|
|
||||||
<MainEventInfoTab
|
|
||||||
task={task}
|
|
||||||
handleFieldEdit={handleFieldEdit}
|
|
||||||
handleTypeOpen={handleTypeOpen}
|
|
||||||
handleStatusOpen={handleStatusOpen}
|
|
||||||
handleClientClientsOpen={handleClientClientsOpen}
|
|
||||||
handleClientPersonOpen={handleClientPersonOpen}
|
|
||||||
handleCrnOpen={handleCrnOpen}
|
|
||||||
handleEventNextNumbGet={handleEventNextNumbGet}
|
|
||||||
/>
|
|
||||||
</CustomTabPanel>
|
|
||||||
<CustomTabPanel value={value} index={1}>
|
|
||||||
<ExecutorEventInfoTab task={task} handleFieldEdit={handleFieldEdit} handleClientPersonOpen={handleClientPersonOpen} />
|
|
||||||
</CustomTabPanel>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Форма события
|
|
||||||
TaskForm.propTypes = {
|
|
||||||
task: PropTypes.object.isRequired,
|
|
||||||
setTask: PropTypes.func.isRequired,
|
|
||||||
handleTypeOpen: PropTypes.func.isRequired,
|
|
||||||
handleStatusOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientClientsOpen: PropTypes.func.isRequired,
|
|
||||||
handleClientPersonOpen: PropTypes.func.isRequired,
|
|
||||||
handleCrnOpen: PropTypes.func.isRequired,
|
|
||||||
handleEventNextNumbGet: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//Диалог с формой события
|
|
||||||
const TaskFormDialog = ({ taskRn, onClose }) => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [
|
|
||||||
task,
|
|
||||||
setTask,
|
|
||||||
insertEvent,
|
|
||||||
updateEvent,
|
|
||||||
handleTypeOpen,
|
|
||||||
handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
handleEventNextNumbGet
|
|
||||||
] = useClientEvent(taskRn);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dialog open onClose={onClose ? onClose : null} fullWidth>
|
|
||||||
<DialogContent sx={STYLES.DIALOG_CONTENT}>
|
|
||||||
<TaskForm
|
|
||||||
task={task}
|
|
||||||
setTask={setTask}
|
|
||||||
handleTypeOpen={handleTypeOpen}
|
|
||||||
handleStatusOpen={handleStatusOpen}
|
|
||||||
handleClientClientsOpen={handleClientClientsOpen}
|
|
||||||
handleClientPersonOpen={handleClientPersonOpen}
|
|
||||||
handleCrnOpen={handleCrnOpen}
|
|
||||||
handleEventNextNumbGet={handleEventNextNumbGet}
|
|
||||||
/>
|
|
||||||
</DialogContent>
|
|
||||||
{onClose ? (
|
|
||||||
<DialogActions>
|
|
||||||
{taskRn ? (
|
|
||||||
<Button onClick={() => updateEvent(onClose)} disabled={task.updateDisabled}>
|
|
||||||
Исправить
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button onClick={() => insertEvent(onClose)} disabled={task.insertDisabled}>
|
|
||||||
Добавить
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<Button onClick={onClose}>Закрыть</Button>
|
|
||||||
</DialogActions>
|
|
||||||
) : null}
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств - Диалог с формой события
|
|
||||||
TaskFormDialog.propTypes = {
|
|
||||||
taskRn: PropTypes.number,
|
|
||||||
onClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export { TaskFormDialog };
|
|
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент панели: Диалог примечаний события
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React, { useState } from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Box, Typography, TextField, Dialog, DialogContent, DialogActions, Button, Tabs, Tab, InputAdornment, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
import { useClientEvent } from "../hooks"; //Вспомогательные хуки
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Контейнер с типом событий
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import {} from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Контейнер типа события
|
|
||||||
const TasksGroup = () => {
|
|
||||||
//Генерация содержимого
|
|
||||||
return <div></div>;
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Контейнер типа события
|
|
||||||
TasksGroup.propTypes = {};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { TasksGroup };
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Компонент: Фильтр отбора
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import React from "react"; //Классы React
|
|
||||||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
|
||||||
import { Chip, Stack, Icon, IconButton } from "@mui/material"; //Интерфейсные компоненты
|
|
||||||
|
|
||||||
//--------------------------
|
|
||||||
//Вспомогательные компоненты
|
|
||||||
//--------------------------
|
|
||||||
|
|
||||||
//Элемент фильтра
|
|
||||||
const FilterItem = ({ caption, value, onClick }) => {
|
|
||||||
//При нажатии на элемент
|
|
||||||
const handleClick = () => (onClick ? onClick() : null);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Chip
|
|
||||||
label={
|
|
||||||
<Stack direction={"row"} alignItems={"center"}>
|
|
||||||
<strong>{caption}</strong>: {value}
|
|
||||||
</Stack>
|
|
||||||
}
|
|
||||||
variant="outlined"
|
|
||||||
onClick={handleClick}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Элемент фильтра
|
|
||||||
FilterItem.propTypes = {
|
|
||||||
caption: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.any.isRequired,
|
|
||||||
onClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------
|
|
||||||
//Тело компонента
|
|
||||||
//---------------
|
|
||||||
|
|
||||||
//Фильтр отбора
|
|
||||||
const Filter = ({ filter, onClick }) => {
|
|
||||||
//При нажатии на фильтр
|
|
||||||
const handleClick = () => (onClick ? onClick() : null);
|
|
||||||
|
|
||||||
//Генерация содержимого
|
|
||||||
return (
|
|
||||||
<Stack direction="row" spacing={1} p={1} alignItems={"center"}>
|
|
||||||
<IconButton onClick={handleClick}>
|
|
||||||
<Icon>filter_alt</Icon>
|
|
||||||
</IconButton>
|
|
||||||
{filter.type ? <FilterItem caption={"Тип"} value={filter.type} onClick={handleClick} /> : null}
|
|
||||||
{filter.sendPerson ? <FilterItem caption={"Исполнитель"} value={filter.sendPerson} onClick={handleClick} /> : null}
|
|
||||||
{filter.sendDivision ? <FilterItem caption={"Подразделение"} value={filter.sendDivision} onClick={handleClick} /> : null}
|
|
||||||
{filter.sendUsrGrp ? <FilterItem caption={"Группа пользователей"} value={filter.sendUsrGrp} onClick={handleClick} /> : null}
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
//Контроль свойств компонента - Фильтр отбора
|
|
||||||
Filter.propTypes = {
|
|
||||||
filter: PropTypes.object.isRequired,
|
|
||||||
onClick: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//Интерфейс компонента
|
|
||||||
//--------------------
|
|
||||||
|
|
||||||
export { Filter };
|
|
@ -1,404 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - Редактор настройки регламентированного отчёта
|
|
||||||
Пользовательские хуки
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import { useState, useContext, useEffect, useCallback } from "react"; //Классы React
|
|
||||||
import { ApplicationСtx } from "../../context/application"; //Контекст приложения
|
|
||||||
import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с сервером
|
|
||||||
import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений
|
|
||||||
import dayjs from "dayjs"; //Работа с датами
|
|
||||||
|
|
||||||
//---------------------------------------------
|
|
||||||
//Вспомогательные функции форматирования данных
|
|
||||||
//---------------------------------------------
|
|
||||||
|
|
||||||
//-----------
|
|
||||||
//Тело модуля
|
|
||||||
//-----------
|
|
||||||
|
|
||||||
//Хук для события
|
|
||||||
const useClientEvent = taskRn => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [task, setTask] = useState({
|
|
||||||
init: true,
|
|
||||||
nrn: taskRn,
|
|
||||||
scrn: "",
|
|
||||||
sprefix: "",
|
|
||||||
snumber: "",
|
|
||||||
stype: "",
|
|
||||||
sstatus: "",
|
|
||||||
sdescription: "",
|
|
||||||
sclnt_clnclients: "",
|
|
||||||
sclnt_clnperson: "",
|
|
||||||
dstart_date: "",
|
|
||||||
sinit_clnperson: "",
|
|
||||||
sinit_user: "",
|
|
||||||
sinit_reason: "",
|
|
||||||
sto_company: "",
|
|
||||||
sto_department: "",
|
|
||||||
sto_clnpost: "",
|
|
||||||
sto_clnpsdep: "",
|
|
||||||
sto_clnperson: "",
|
|
||||||
sto_fcstaffgrp: "",
|
|
||||||
sto_user: "",
|
|
||||||
sto_usergrp: "",
|
|
||||||
scurrent_user: "",
|
|
||||||
isUpdate: false,
|
|
||||||
insertDisabled: true,
|
|
||||||
updateDisabled: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Подключение к контексту приложения
|
|
||||||
const { pOnlineShowDictionary } = useContext(ApplicationСtx);
|
|
||||||
|
|
||||||
//Отображение раздела "Типы событий"
|
|
||||||
const handleTypeOpen = useCallback(async () => {
|
|
||||||
pOnlineShowDictionary({
|
|
||||||
unitCode: "ClientEventTypes",
|
|
||||||
showMethod: "main",
|
|
||||||
inputParameters: [{ name: "in_EVNTYPE_NAME", value: task.stype }],
|
|
||||||
callBack: async res => {
|
|
||||||
if (res.success) {
|
|
||||||
//Считываем параметры исходя из типа события
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVNTYPES_INIT",
|
|
||||||
args: {
|
|
||||||
SEVENT_TYPE: res.outParameters.out_EVNTYPE_CODE,
|
|
||||||
SCURRENT_PREF: task.sprefix
|
|
||||||
},
|
|
||||||
tagValueProcessor: () => undefined
|
|
||||||
});
|
|
||||||
if (data) {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
stype: res.outParameters.out_EVNTYPE_CODE,
|
|
||||||
sprefix: data.SPREF,
|
|
||||||
snumber: data.SNUMB,
|
|
||||||
sstatus: data.SDEFAULT_STATUS
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [executeStored, pOnlineShowDictionary, task.sprefix, task.stype]);
|
|
||||||
|
|
||||||
//Отображение раздела "Статусы типового события"
|
|
||||||
const handleStatusOpen = useCallback(async () => {
|
|
||||||
pOnlineShowDictionary({
|
|
||||||
unitCode: "ClientEventTypesStates",
|
|
||||||
showMethod: "main",
|
|
||||||
inputParameters: [
|
|
||||||
{ name: "in_SEVNTYPE_CODE", value: task.stype },
|
|
||||||
{ name: "in_EVENT_STATUS_EVNSTAT_CODE", value: task.sstatus }
|
|
||||||
],
|
|
||||||
callBack: res => {
|
|
||||||
res.success
|
|
||||||
? setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
sstatus: res.outParameters.out_EVENT_STATUS_EVNSTAT_CODE
|
|
||||||
}))
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [pOnlineShowDictionary, task.sstatus, task.stype]);
|
|
||||||
|
|
||||||
//Отображение раздела "Клиенты"
|
|
||||||
const handleClientClientsOpen = useCallback(async () => {
|
|
||||||
pOnlineShowDictionary({
|
|
||||||
unitCode: "ClientClients",
|
|
||||||
showMethod: "main",
|
|
||||||
inputParameters: [{ name: "in_CLIENT_CODE", value: task.sclnt_clnclients }],
|
|
||||||
callBack: res => {
|
|
||||||
res.success
|
|
||||||
? setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
sclnt_clnclients: res.outParameters.out_CLIENT_CODE,
|
|
||||||
sclnt_clnperson: ""
|
|
||||||
}))
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [pOnlineShowDictionary, task.sclnt_clnclients]);
|
|
||||||
|
|
||||||
//Отображение раздела "Сотрудники"
|
|
||||||
const handleClientPersonOpen = useCallback(
|
|
||||||
//Тип открытия (0 - для клиента, 1 - для инициатора)
|
|
||||||
async (nType = 0) => {
|
|
||||||
pOnlineShowDictionary({
|
|
||||||
unitCode: "ClientPersons",
|
|
||||||
showMethod: "main",
|
|
||||||
inputParameters: [{ name: "in_CODE", value: nType === 0 ? task.sclnt_clnperson : task.sinit_clnperson }],
|
|
||||||
callBack: res => {
|
|
||||||
if (res.success) {
|
|
||||||
if (nType === 0) {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
sclnt_clnperson: res.outParameters.out_CODE,
|
|
||||||
sclnt_clnclients: ""
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
sinit_clnperson: res.outParameters.out_CODE
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[pOnlineShowDictionary, task.sclnt_clnperson, task.sinit_clnperson]
|
|
||||||
);
|
|
||||||
|
|
||||||
//Отображение раздела "Каталоги" для событий
|
|
||||||
const handleCrnOpen = useCallback(async () => {
|
|
||||||
pOnlineShowDictionary({
|
|
||||||
unitCode: "CatalogTree",
|
|
||||||
showMethod: "main",
|
|
||||||
inputParameters: [
|
|
||||||
{ name: "in_DOCNAME", value: "ClientEvents" },
|
|
||||||
{ name: "in_NAME", value: task.scrn }
|
|
||||||
],
|
|
||||||
callBack: res => {
|
|
||||||
res.success
|
|
||||||
? setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
scrn: res.outParameters.out_NAME
|
|
||||||
}))
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [pOnlineShowDictionary, task.scrn]);
|
|
||||||
|
|
||||||
//Считывание следующего номера события
|
|
||||||
const getEventNextNumb = useCallback(async () => {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_NEXTNUMB_GET",
|
|
||||||
args: {
|
|
||||||
SPREFIX: task.sprefix
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (data) {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
snumber: data.SEVENT_NUMB
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}, [executeStored, task.sprefix]);
|
|
||||||
|
|
||||||
//Добавление события
|
|
||||||
const insertEvent = useCallback(
|
|
||||||
async callBack => {
|
|
||||||
await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_INSERT",
|
|
||||||
args: {
|
|
||||||
SCRN: task.scrn,
|
|
||||||
SPREF: task.sprefix,
|
|
||||||
SNUMB: task.snumber,
|
|
||||||
STYPE: task.stype,
|
|
||||||
SSTATUS: task.sstatus,
|
|
||||||
SPLAN_DATE: task.dstart_date ? dayjs(task.dstart_date).format("DD.MM.YYYY HH:mm") : null,
|
|
||||||
SINIT_PERSON: task.sinit_clnperson,
|
|
||||||
SCLIENT_CLIENT: task.sclnt_clnclients,
|
|
||||||
SCLIENT_PERSON: task.sclnt_clnperson,
|
|
||||||
SDESCRIPTION: task.sdescription,
|
|
||||||
SREASON: task.sinit_reason
|
|
||||||
}
|
|
||||||
});
|
|
||||||
callBack();
|
|
||||||
},
|
|
||||||
[
|
|
||||||
executeStored,
|
|
||||||
task.dstart_date,
|
|
||||||
task.sclnt_clnclients,
|
|
||||||
task.sclnt_clnperson,
|
|
||||||
task.scrn,
|
|
||||||
task.sdescription,
|
|
||||||
task.sinit_clnperson,
|
|
||||||
task.sinit_reason,
|
|
||||||
task.snumber,
|
|
||||||
task.sprefix,
|
|
||||||
task.sstatus,
|
|
||||||
task.stype
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
//Исправление события
|
|
||||||
const updateEvent = useCallback(
|
|
||||||
async callBack => {
|
|
||||||
await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_UPDATE",
|
|
||||||
args: {
|
|
||||||
NCLNEVENTS: task.nrn,
|
|
||||||
SCLIENT_CLIENT: task.sclnt_clnclients,
|
|
||||||
SCLIENT_PERSON: task.sclnt_clnperson,
|
|
||||||
SDESCRIPTION: task.sdescription
|
|
||||||
}
|
|
||||||
});
|
|
||||||
callBack();
|
|
||||||
},
|
|
||||||
[executeStored, task.nrn, task.sclnt_clnclients, task.sclnt_clnperson, task.sdescription]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (task.init) {
|
|
||||||
if (taskRn) {
|
|
||||||
//Считывание параметров события
|
|
||||||
const readEvent = async () => {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_GET",
|
|
||||||
args: {
|
|
||||||
NCLNEVENTS: task.nrn
|
|
||||||
},
|
|
||||||
respArg: "COUT"
|
|
||||||
});
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
scrn: data.XEVENT.SCRN,
|
|
||||||
sprefix: data.XEVENT.SPREF,
|
|
||||||
snumber: data.XEVENT.SNUMB,
|
|
||||||
stype: data.XEVENT.STYPE,
|
|
||||||
sstatus: data.XEVENT.SSTATUS,
|
|
||||||
sdescription: data.XEVENT.SDESCRIPTION,
|
|
||||||
sclnt_clnclients: data.XEVENT.SCLIENT_CLIENT,
|
|
||||||
sclnt_clnperson: data.XEVENT.SCLIENT_PERSON,
|
|
||||||
dstart_date: data.XEVENT.SPLAN_DATE ? dayjs(data.XEVENT.SPLAN_DATE).format("YYYY-MM-DD HH:mm") : "",
|
|
||||||
sinit_clnperson: data.XEVENT.SINIT_PERSON,
|
|
||||||
sinit_user: data.XEVENT.SINIT_AUTHID,
|
|
||||||
sinit_reason: data.XEVENT.SREASON,
|
|
||||||
sto_company: data.XEVENT.SSEND_CLIENT,
|
|
||||||
sto_department: data.XEVENT.SSEND_DIVISION,
|
|
||||||
sto_clnpost: data.XEVENT.SSEND_POST,
|
|
||||||
sto_clnpsdep: data.XEVENT.SSEND_PERFORM,
|
|
||||||
sto_clnperson: data.XEVENT.SSEND_PERSON,
|
|
||||||
sto_fcstaffgrp: data.XEVENT.SSEND_STAFFGRP,
|
|
||||||
sto_user: data.XEVENT.SSEND_USER_NAME,
|
|
||||||
sto_usergrp: data.XEVENT.SSEND_USER_GROUP,
|
|
||||||
scurrent_user: data.XEVENT.SINIT_AUTHID,
|
|
||||||
isUpdate: true,
|
|
||||||
init: false
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
//Инициализация параметров события
|
|
||||||
readEvent();
|
|
||||||
} else {
|
|
||||||
//Считывание изначальных параметров события
|
|
||||||
const initEvent = async () => {
|
|
||||||
const data = await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_INIT",
|
|
||||||
args: {}
|
|
||||||
});
|
|
||||||
if (data) {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
sprefix: data.SPREF,
|
|
||||||
snumber: data.SNUMB,
|
|
||||||
scurrent_user: data.SINIT_AUTHNAME,
|
|
||||||
sinit_clnperson: data.SINIT_PERSON,
|
|
||||||
sinit_user: !data.SINIT_PERSON ? data.SINIT_AUTHNAME : "",
|
|
||||||
init: false
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//Инициализация изначальных параметров события
|
|
||||||
initEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!task.init) {
|
|
||||||
setTask(pv => ({ ...pv, sinit_user: !task.sinit_clnperson ? task.scurrent_user : "" }));
|
|
||||||
}
|
|
||||||
}, [executeStored, task.init, task.nrn, task.scurrent_user, task.sinit_clnperson, taskRn]);
|
|
||||||
|
|
||||||
//Проверка доступности действия
|
|
||||||
useEffect(() => {
|
|
||||||
setTask(pv => ({
|
|
||||||
...pv,
|
|
||||||
insertDisabled:
|
|
||||||
!task.scrn ||
|
|
||||||
!task.sprefix ||
|
|
||||||
!task.snumber ||
|
|
||||||
!task.stype ||
|
|
||||||
!task.sstatus ||
|
|
||||||
!task.sdescription ||
|
|
||||||
(!task.sinit_clnperson && !task.sinit_user),
|
|
||||||
updateDisabled: !task.sdescription
|
|
||||||
}));
|
|
||||||
}, [task.scrn, task.sdescription, task.sinit_clnperson, task.sinit_user, task.snumber, task.sprefix, task.sstatus, task.stype]);
|
|
||||||
|
|
||||||
return [
|
|
||||||
task,
|
|
||||||
setTask,
|
|
||||||
insertEvent,
|
|
||||||
updateEvent,
|
|
||||||
handleTypeOpen,
|
|
||||||
handleStatusOpen,
|
|
||||||
handleClientClientsOpen,
|
|
||||||
handleClientPersonOpen,
|
|
||||||
handleCrnOpen,
|
|
||||||
getEventNextNumb
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
//Карточка события
|
|
||||||
const useTaskCard = () => {
|
|
||||||
//Собственное состояние
|
|
||||||
const [taskCard, setTaskCard] = useState({
|
|
||||||
openEdit: false
|
|
||||||
});
|
|
||||||
//Состояние действий
|
|
||||||
const [cardActions, setCardActions] = useState({ anchorMenuMethods: null, openMethods: false });
|
|
||||||
|
|
||||||
//Подключение к контексту взаимодействия с сервером
|
|
||||||
const { executeStored } = useContext(BackEndСtx);
|
|
||||||
|
|
||||||
//Подключение к контексту сообщений
|
|
||||||
const { showMsgWarn } = useContext(MessagingСtx);
|
|
||||||
|
|
||||||
//Удаление контрагента
|
|
||||||
const deleteEvent = useCallback(
|
|
||||||
async rn => {
|
|
||||||
await executeStored({
|
|
||||||
stored: "UDO_P8PANELS_TEST.CLNEVENTS_DELETE",
|
|
||||||
args: { NCLNEVENTS: rn }
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[executeStored]
|
|
||||||
);
|
|
||||||
|
|
||||||
//По нажатию на открытие меню действий
|
|
||||||
const handleMethodsMenuButtonClick = event => {
|
|
||||||
setCardActions(pv => ({ ...pv, anchorMenuMethods: event.currentTarget, openMethods: true }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//При закрытии меню
|
|
||||||
const handleMethodsMenuClose = () => {
|
|
||||||
setCardActions(pv => ({ ...pv, anchorMenuMethods: null, openMethods: false }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//По нажатия действия "Редактировать"
|
|
||||||
const handleTaskEdit = id => {
|
|
||||||
setTaskCard(pv => ({ ...pv, openEdit: true }));
|
|
||||||
};
|
|
||||||
|
|
||||||
//По нажатию действия "Удалить"
|
|
||||||
const handleTaskDelete = id => {
|
|
||||||
showMsgWarn("Удалить событие?", () => deleteEvent(id));
|
|
||||||
};
|
|
||||||
|
|
||||||
//Формируем меню показателей
|
|
||||||
const menuItems = [
|
|
||||||
{ method: "EDIT", name: "Исправить", icon: "edit", func: handleTaskEdit },
|
|
||||||
{ method: "DELETE", name: "Удалить", icon: "delete", func: handleTaskDelete }
|
|
||||||
];
|
|
||||||
|
|
||||||
return [taskCard, setTaskCard, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose, menuItems];
|
|
||||||
};
|
|
||||||
|
|
||||||
export { useClientEvent, useTaskCard };
|
|
@ -1,16 +0,0 @@
|
|||||||
/*
|
|
||||||
Парус 8 - Панели мониторинга - УДП - Доски задач
|
|
||||||
Панель мониторинга: Точка входа
|
|
||||||
*/
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//Подключение библиотек
|
|
||||||
//---------------------
|
|
||||||
|
|
||||||
import { ClntTaskBoard } from "./clnt_task_board"; //Корневая панель выполнения работ
|
|
||||||
|
|
||||||
//----------------
|
|
||||||
//Интерфейс модуля
|
|
||||||
//----------------
|
|
||||||
|
|
||||||
export const RootClass = ClntTaskBoard;
|
|
BIN
dist/app/panels/clnt_task_board/components/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
BIN
dist/app/panels/clnt_task_board/components/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
dist/app/panels/clnt_task_board/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
BIN
dist/app/panels/clnt_task_board/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
dist/app/panels/clnt_task_board/img/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
BIN
dist/app/panels/clnt_task_board/img/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
dist/img/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
BIN
dist/img/default_avatar.d169f535d2a783bef4eb3e98da3ed6c1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
Loading…
x
Reference in New Issue
Block a user