/* Парус 8 - Панели мониторинга - УДП - Доски задач Компонент: Карточка события */ //--------------------- //Подключение библиотек //--------------------- import React, { useState, useContext, useCallback } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Draggable } from "react-beautiful-dnd"; //Работа с drag&drop import { Card, CardHeader, Typography, IconButton, Icon, Box, Menu, MenuItem, CardContent, Avatar, Stack } from "@mui/material"; //Интерфейсные компоненты import { TaskDialog } from "../task_dialog"; //Форма события import { ApplicationСtx } from "../../../context/application"; //Контекст приложения import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером import { MessagingСtx } from "../../../context/messaging"; //Контекст сообщений import { EVENT_INDICATORS, indicatorColorRule, bgColorRule } from "../layouts"; //Дополнительная разметка и вёрстка клиентских элементов //--------- //Константы //--------- //Стили const STYLES = { CONTAINER: { margin: "5px 0px", textAlign: "center" }, MENU_ITEM_DELIMITER: { borderBottom: "1px solid lightgrey" }, CARD: (indicatorClr, bgClr) => { const i = indicatorClr ? { borderLeft: `solid ${indicatorClr}` } : null; const bc = bgClr ? { backgroundColor: bgClr } : null; return { ...i, ...bc }; }, CARD_HEADER_TITLE: { padding: "4px", width: "292px", 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: linked => { return { color: theme => (linked ? EVENT_INDICATORS.LINKED : theme.palette.grey[500]) }; } }; //------------------------------------ //Вспомогательные функции и компоненты //------------------------------------ //Действия карточки события const DataCellCardActions = ({ taskRn, menuItems, cardActions, onMethodsMenuButtonClick, onMethodsMenuClose, onReload, eventPoints, pointSettings, onOpenNoteDialog }) => { return ( more_vert {menuItems.map(action => { if (action.visible) return ( { if (onOpenNoteDialog && action.method === "TASK_STATE_CHANGE") { action.func(taskRn, action.needReload ? onReload : null, eventPoints, onOpenNoteDialog); } else if (onOpenNoteDialog && action.method === "TASK_SEND" && pointSettings.addNoteOnSend) { onOpenNoteDialog(n => action.func(taskRn, action.needReload ? onReload : null, n)); } else { //Выполняем действие action.func(taskRn, action.needReload ? onReload : null); } //Закрываем меню onMethodsMenuClose(); }} > {action.icon} {action.name} ); })} ); }; //Контроль свойств - Действия карточки события DataCellCardActions.propTypes = { taskRn: PropTypes.number.isRequired, menuItems: PropTypes.array.isRequired, cardActions: PropTypes.object.isRequired, onMethodsMenuButtonClick: PropTypes.func.isRequired, onMethodsMenuClose: PropTypes.func.isRequired, onReload: PropTypes.func, eventPoints: PropTypes.array, pointSettings: PropTypes.object, onOpenNoteDialog: PropTypes.func }; //----------- //Тело модуля //----------- //Карточка события const TaskCard = ({ task, avatar, index, onReload, eventPoints, colorRule, pointSettings, onOpenNoteDialog }) => { //Состояние диалога события const [taskDialogOpen, setTaskDialogOpen] = useState(false); //Состояние действий события const [cardActions, setCardActions] = useState({ anchorMenuMethods: null, openMethods: false }); //Подключение к контексту взаимодействия с сервером const { executeStored } = useContext(BackEndСtx); //Подключение к контексту сообщений const { showMsgWarn } = useContext(MessagingСtx); //Подключение к контексту приложения const { pOnlineShowDictionary } = useContext(ApplicationСtx); //Подключение к контексту приложения const { pOnlineShowDocument } = useContext(ApplicationСtx); //Удаление контрагента const deleteTask = useCallback( async (nEvent, handleReload) => { await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_DELETE", args: { NCLNEVENTS: nEvent } }); //Если требуется перезагрузить данные if (handleReload) { handleReload(); } }, [executeStored] ); //Возврат в предыдущую точку события const returnTask = useCallback( async (nEvent, handleReload) => { await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_RETURN", args: { NCLNEVENTS: nEvent } }); //Если требуется перезагрузить данные if (handleReload) { handleReload(); } }, [executeStored] ); //По нажатию на открытие меню действий const handleMethodsMenuButtonClick = event => { setCardActions(pv => ({ ...pv, anchorMenuMethods: event.currentTarget, openMethods: true })); }; //При закрытии меню const handleMethodsMenuClose = () => { setCardActions(pv => ({ ...pv, anchorMenuMethods: null, openMethods: false })); }; //По нажатия действия "Редактировать" const handleTaskEdit = () => { setTaskDialogOpen(true); }; //По нажатия действия "Редактировать в разделе" const handleTaskEditClient = useCallback( async nEvent => { const data = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SELECT", args: { NCLNEVENTS: nEvent } }); if (data.NIDENT) { pOnlineShowDictionary({ unitCode: "ClientEvents", inputParameters: [{ name: "in_Ident", value: data.NIDENT }] }); } }, [executeStored, pOnlineShowDictionary] ); //По нажатию действия "Удалить" const handleTaskDelete = (nEvent, handleReload) => { showMsgWarn("Удалить событие?", () => deleteTask(nEvent, handleReload)); }; //По нажатию действия "Выполнить возврат" const handleTaskReturn = (nEvent, handleReload) => { showMsgWarn("Выполнить возврат события в предыдущую точку?", () => returnTask(nEvent, handleReload)); }; //По нажатию действия "Примечания" const handleEventNotesOpen = useCallback( async nEvent => { pOnlineShowDictionary({ unitCode: "ClientEventsNotes", showMethod: "main", inputParameters: [{ name: "in_PRN", value: nEvent }] }); }, [pOnlineShowDictionary] ); //По нажатию действия "Присоединенные документы" const handleFileLinksOpen = useCallback( async nEvent => { pOnlineShowDictionary({ unitCode: "FileLinks", showMethod: "main_link", inputParameters: [ { name: "in_PRN", value: nEvent }, { name: "in_UNITCODE", value: "ClientEvents" } ] }); }, [pOnlineShowDictionary] ); //По нажатию действия "Перейти" const handleStateChange = useCallback( async (nEvent, handleReload, evPoints, handleNote) => { //Выполняем инициализацию параметров const firstStep = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: { NSTEP: 1, NEVENT: nEvent } }); if (firstStep) { //Открываем раздел "Маршруты событий (точки перехода)" для выбора следующей точки pOnlineShowDictionary({ unitCode: "EventRoutesPointsPasses", showMethod: "main_passes", inputParameters: [ { name: "in_ENVTYPE_CODE", value: firstStep.SEVENT_TYPE }, { name: "in_ENVSTAT_CODE", value: firstStep.SEVENT_STAT }, { name: "in_POINT", value: firstStep.NPOINT } ], callBack: async point => { //Выполняем проверку необходимости выбора исполнителя const secondStep = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: { NIDENT: firstStep.NIDENT, NSTEP: 2, NPASS: point.outParameters.out_RN } }); const pointSettings = evPoints.find(ep => ep.point === point.outParameters.out_NEXT_POINT); if (secondStep) { //Если требуется выбрать получателя if (secondStep.NSELECT_EXEC === 1) { //Открываем раздел "Маршруты событий (исполнители в точках)" для выбора исполнителя pOnlineShowDictionary({ unitCode: "EventRoutesPointExecuters", showMethod: "executers", inputParameters: [ { name: "in_IDENT", value: firstStep.NIDENT }, { name: "in_EVENT", value: nEvent }, { name: "in_EVENT_TYPE", value: firstStep.SEVENT_TYPE }, { name: "in_EVENT_STAT", value: firstStep.SEVENT_STAT }, { name: "in_INIT_PERSON", value: firstStep.SINIT_PERSON }, { name: "in_INIT_AUTHNAME", value: firstStep.SINIT_AUTHNAME }, { name: "in_CLIENT_CLIENT", value: firstStep.SCLIENT_CLIENT }, { name: "in_CLIENT_PERSON", value: firstStep.SCLIENT_PERSON } ], callBack: async send => { //Общие аргументы const mainArgs = { NIDENT: firstStep.NIDENT, NSTEP: 3, NEVENT: nEvent, SEVENT_STAT: point.outParameters.out_NEXT_POINT, SSEND_CLIENT: send.outParameters.out_CLIENT_CODE, SSEND_DIVISION: send.outParameters.out_DIVISION_CODE, SSEND_POST: send.outParameters.out_POST_CODE, SSEND_PERFORM: send.outParameters.out_POST_IN_DIV_CODE, SSEND_PERSON: send.outParameters.out_PERSON_CODE, SSEND_STAFFGRP: send.outParameters.out_STAFFGRP_CODE, SSEND_USER_GROUP: send.outParameters.out_USER_GROUP_CODE, SSEND_USER_NAME: send.outParameters.out_USER_NAME, NSEND_PREDEFINED_EXEC: send.outParameters.out_PREDEFINED_EXEC, NSEND_PREDEFINED_PROC: send.outParameters.out_PREDEFINED_PROC }; //Выполняем переход к выбранной точке с исполнителем pointSettings.addNoteOnChst ? handleNote(async n => { //Если требуется примечание await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: { ...mainArgs, ...{ SNOTE_HEADER: n.header, SNOTE: n.text } } }); //Если требуется перезагрузить данные if (handleReload) { handleReload(); } }) : await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: mainArgs }); //Если требуется перезагрузить данные if (handleReload && !pointSettings.addNoteOnChst) { handleReload(); } } }); } else { //Общие аргументы const mainArgs = { NIDENT: firstStep.NIDENT, NSTEP: 3, NEVENT: nEvent, SEVENT_STAT: point.outParameters.out_NEXT_POINT }; //Выполняем переход к выбранной точке с предопределенным исполнителем pointSettings.addNoteOnChst ? handleNote(async n => { //Если требуется примечание await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: { ...mainArgs, ...{ SNOTE_HEADER: n.header, SNOTE: n.text } } }); //Если требуется перезагрузить данные if (handleReload) { handleReload(); } }) : await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: mainArgs }); //Если требуется перезагрузить данные if (handleReload && !pointSettings.addNoteOnChst) { handleReload(); } } } } }); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [executeStored, pOnlineShowDictionary] ); //Изменение статуса события const handleSend = useCallback( async (nEvent, handleReload, note = null) => { //Выполняем инициализацию параметров const firstStep = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SEND", args: { NSTEP: 1, NEVENT: nEvent } }); if (firstStep) { //Открываем раздел "Маршруты событий (исполнители в точках)" для выбора исполнителя pOnlineShowDictionary({ unitCode: "EventRoutesPointExecuters", showMethod: "executers", inputParameters: [ { name: "in_IDENT", value: firstStep.NIDENT }, { name: "in_EVENT", value: nEvent }, { name: "in_PERSON_CODE", value: firstStep.SSEND_PERSON }, { name: "in_USER_NAME", value: firstStep.SSEND_USER_NAME }, { name: "in_EVENT_TYPE", value: firstStep.SEVENT_TYPE }, { name: "in_EVENT_STAT", value: firstStep.SEVENT_STAT }, { name: "in_INIT_PERSON", value: firstStep.SINIT_PERSON }, { name: "in_INIT_AUTHNAME", value: firstStep.SINIT_AUTHNAME }, { name: "in_CLIENT_CLIENT", value: firstStep.SCLIENT_CLIENT }, { name: "in_CLIENT_PERSON", value: firstStep.SCLIENT_PERSON } ], callBack: async send => { //Выполняем проверку необходимости выбора исполнителя await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_SEND", args: { NIDENT: firstStep.NIDENT, NSTEP: 2, NEVENT: nEvent, SSEND_CLIENT: send.outParameters.out_CLIENT_CODE, SSEND_DIVISION: send.outParameters.out_DIVISION_CODE, SSEND_POST: send.outParameters.out_POST_CODE, SSEND_PERFORM: send.outParameters.out_POST_IN_DIV_CODE, SSEND_PERSON: send.outParameters.out_PERSON_CODE, SSEND_STAFFGRP: send.outParameters.out_STAFFGRP_CODE, SSEND_USER_GROUP: send.outParameters.out_USER_GROUP_CODE, SSEND_USER_NAME: send.outParameters.out_USER_NAME, NSEND_PREDEFINED_EXEC: send.outParameters.out_PREDEFINED_EXEC, NSEND_PREDEFINED_PROC: send.outParameters.out_PREDEFINED_PROC, SNOTE_HEADER: note.text ? note.header : null, SNOTE: note.text ? note.text : null } }); //Если требуется перезагрузить данные if (handleReload) { handleReload(); } } }); } }, [executeStored, pOnlineShowDictionary] ); const mItems = [ { method: "EDIT", name: "Исправить", icon: "edit", visible: false, delimiter: false, needReload: false, func: handleTaskEdit }, { method: "EDIT_CLIENT", name: "Исправить в разделе", icon: "edit_note", 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", name: "Присоединенные документы", icon: "attach_file", visible: true, delimiter: false, needReload: false, func: handleFileLinksOpen } ]; //Генерация содержимого return ( {taskDialogOpen ? ( { setTaskDialogOpen(false); }} /> ) : null} {provided => ( { mItems.find(a => (a.method === "EDIT" ? a.func(task.nrn, a.needReload ? onReload : null) : null)); }} > {task.sdescription} } sx={STYLES.CARD_HEADER_DESC} action={ } /> pOnlineShowDocument({ unitCode: task.slinked_unit, document: task.nlinked_rn }) : null } sx={STYLES.ICON_COLOR(task.nlinked_rn)} disabled={!task.nlinked_rn} > assignment {task.name} {task.sSender ? ( {task.sSender} ) : null} )} ); }; //Контроль свойств - Карточка события TaskCard.propTypes = { task: PropTypes.object.isRequired, avatar: PropTypes.string, index: PropTypes.number.isRequired, onReload: PropTypes.func, eventPoints: PropTypes.array, colorRule: PropTypes.object, pointSettings: PropTypes.object, onOpenNoteDialog: PropTypes.func }; //---------------- //Интерфейс модуля //---------------- export { TaskCard };