/* Парус 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 { object2Base64XML, deepCopyObject } from "../../core/utils"; //Вспомогательные функции import dayjs from "dayjs"; //Работа с датами import { EVENT_STATES } from "./components/filter_dialog"; //Перечисление состояний события //--------- //Константы //--------- //Цвета статусов export const COLORS = [ "mediumSlateBlue", "lightSalmon", "fireBrick", "orange", "gold", "limeGreen", "yellowGreen", "mediumAquaMarine", "paleTurquoise", "steelBlue", "skyBlue", "tan" ]; //--------------------------------------------- //Вспомогательные функции форматирования данных //--------------------------------------------- //Формирование случайного цвета const randomColor = index => { const hue = index * 137.508; return hslToRgba(hue, 50, 70); }; //Цвет из hsl формата в rgba формат const hslToRgba = (h, s, l) => { s /= 100; l /= 100; 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))); return `rgba(${Math.floor(255 * f(0))},${Math.floor(255 * f(8))},${Math.floor(255 * f(4))},0.3)`; }; //Формирование массива из 0, 1 и 1< элементов export const arrayFormer = arr => { return arr ? (arr.length ? arr : [arr]) : []; }; //----------- //Тело модуля //----------- //Хук основных данных const useTasks = () => { //Состояние открытия формы события const [taskFormOpen, setTaskFormOpen] = useState(false); //Состояние изменения настройки статуса const [cardSettings, setCardSettings] = useState({ isOpen: false, settings: {} }); //Состояние маршрута события const [eventRoutes, setEventRoutes] = useState([]); //Состояние точек маршрута события const [eventPoints, setEventPoints] = useState([]); //Состояние типов заголовков событий const [noteTypes, setNoteTypes] = useState([]); //Состояние учётных документов const [docLinks, setDocLinks] = useState([]); //Состояние аккаунтов const [accounts, setAccounts] = useState([]); //Состояние событий const [tasks, setTasks] = useState({ groupsLoaded: false, tasksLoaded: false, orders: [], filters: { isOpen: true, isSetByUser: false, needSave: false, values: { evState: EVENT_STATES[1], type: "", catalog: "", crn: "", wSubcatalogs: false, sendPerson: "", sendDivision: "", sendUsrGrp: "", docLink: "" }, fArray: [ { name: "NCLOSED", from: 0, to: 1 }, { name: "SEVTYPE_CODE", from: "", to: "" }, { name: "NCRN", from: "", to: "" }, { name: "SSEND_PERSON", from: "", to: "" }, { name: "SSEND_DIVISION", from: "", to: "" }, { name: "SSEND_USRGRP", from: "", to: "" }, { name: "NLINKED_RN", from: "", to: "" } ] }, rows: [], statuses: [], openCardForm: false, reload: true }); //Подключение к контексту взаимодействия с сервером const { executeStored, SERV_DATA_TYPE_CLOB } = useContext(BackEndСtx); //Подключение к контексту приложения const { pOnlineShowDictionary } = useContext(ApplicationСtx); //Инициализация параметров события const initTask = (id, gp, task) => { return { id: id, name: task.SPREF_NUMB, category: gp, nrn: task.NRN, scrn: "", sprefix: task.SEVPREF, snumber: task.SEVNUMB, stype: task.SEVTYPE_CODE, sstatus: task.SEVSTAT_NAME, sdescription: task.SEVDESCR, sclnt_clnclients: "", sclnt_clnperson: "", dchange_date: task.DCHANGE_DATE, dstart_date: task.DREG_DATE, dplan_date: task.DPLAN_DATE, sinit_clnperson: task.SINIT_PERSON, sinit_user: "", sinit_reason: "", //SEND_CLIENT sto_company: "", //SEND_DIVISION sto_department: task.SSEND_DIVISION, //SEND_POST sto_clnpost: "", //SEND_PERFORM sto_clnpsdep: "", //SEND_PERSON sto_clnperson: task.SSEND_PERSON, //SEND_STAFFGRP sto_fcstaffgrp: "", //SEND_USER_AUTHID sto_user: "", //SEND_USER_GROUP sto_usergrp: task.SSEND_USRGRP, scurrent_user: "" }; }; //При открытии диалога фильтра const handleFilterClick = () => setFilterOpen(true); //При изменении фильтра в диалоге const handleFilterOk = filter => { setFilterValues(filter); setFilterOpen(false); }; //При закрытии диалога фильтра const handleFilterCancel = () => setFilterOpen(false); //Установить значение фильтра const setFilterValues = (values, ns = true) => { //Считываем массив фильтров 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 === "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_DIVISION").from = values.sendDivision ? values.sendDivision : null; //Группа пользователей filterArr.find(f => f.name === "SSEND_USRGRP").from = values.sendUsrGrp ? values.sendUsrGrp : null; //Учётный документ filterArr.find(f => f.name === "NLINKED_RN").from = values.docLink ? values.docLink : null; //Устанавливаем фильтры setTasks(pv => ({ ...pv, filters: { ...pv.filters, isSetByUser: true, needSave: ns, values: { ...values }, fArray: [...filterArr] }, reload: true })); }; //Загрузка значений фильтра из локального хранилища браузера const loadLocalFilter = useCallback(async () => { let vs = { ...tasks.filters.values }; if (localStorage.getItem("type")) { Object.keys(vs).map(function (k) { if (k === "wSubcatalogs") vs[k] = localStorage.getItem(k) === "true"; else k !== "docLink" ? (vs[k] = localStorage.getItem(k)) : null; }); setFilterValues(vs, false); setFilterOpen(false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); //При закрытии панели useEffect(() => { tasks.filters.needSave ? window.addEventListener("beforeunload", function () { Object.keys(tasks.filters.values).map(function (k) { k !== "docLink" ? localStorage.setItem(k, tasks.filters.values[k]) : null; }); }) : null; }, [tasks.filters.needSave, tasks.filters.values]); //При отсутствии пользовательских настроек фильтра useEffect(() => { if (!tasks.filters.isSetByUser) setFilterOpen(true); }, [tasks.filters.isSetByUser]); //При подключении к странице useEffect(() => { localStorage.length > 0 ? loadLocalFilter() : null; }, [loadLocalFilter]); //Показать/скрыть фильтр const setFilterOpen = isOpen => { setTasks(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 = tasks.statuses.slice(); //Изменяем статус у выбранного cloneS[tasks.statuses.findIndex(x => x.id === settings.id)] = { ...settings }; setTasks(pv => ({ ...pv, statuses: cloneS })); setCardSettings({ isOpen: false, settings: {} }); }; //При изменении сортировки const handleOrderChanged = useCallback( columnName => { let newOrders = deepCopyObject(tasks.orders); const colOrder = newOrders.find(o => o.name == columnName); const newDirection = colOrder?.direction == "ASC" ? "DESC" : colOrder?.direction == "DESC" ? null : "ASC"; if (newDirection == null && colOrder) newOrders.splice(newOrders.indexOf(colOrder), 1); if (newDirection != null && !colOrder) newOrders.push({ name: columnName, direction: newDirection }); if (newDirection != null && colOrder) colOrder.direction = newDirection; setTasks(pv => ({ ...pv, orders: newOrders, reload: true })); }, [tasks.orders] ); //Изменение статуса события (переносом) const handleStateChange = useCallback( async (nEvent, sNextStat, note) => { try { //Выполняем инициализацию параметров const firstStep = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: { NSTEP: 1, NEVENT: nEvent, SNEXT_STAT: sNextStat } }); if (firstStep) { //Если требуется выбрать получателя if (firstStep.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: firstStep.SEVENT_STAT, 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 }; //Выполняем переход к выбранной точке с исполнителем await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: note ? { ...mainArgs, SNOTE_HEADER: note.header, SNOTE: note.text } : mainArgs }); //Необходимо обновить данные setTasks(pv => ({ ...pv, reload: true })); } }); } else { //Общие аргументы const mainArgs = { NIDENT: firstStep.NIDENT, NSTEP: 3, NEVENT: nEvent, SEVENT_STAT: firstStep.SEVENT_STAT }; //Выполняем переход к выбранной точке с предопределенным исполнителем await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_STATE_CHANGE", args: note ? { ...mainArgs, ...{ SNOTE_HEADER: note.header, SNOTE: note.text } } : mainArgs }); //Необходимо обновить данные setTasks(pv => ({ ...pv, reload: true })); } } } catch (e) { //Необходимо обновить данные setTasks(pv => ({ ...pv, reload: true })); } }, [executeStored, pOnlineShowDictionary] ); //При необходимости обновить события const handleReload = useCallback(() => { setTasks(pv => ({ ...pv, reload: true })); }, []); //Взаимодействие с событием (через перенос) const onDragEnd = useCallback( (result, eventPoints, openNoteDialog) => { //Определяем нужные параметры const { source, destination } = result; //Если путь не указан if (!destination) { return; } //Если происходит изменение статуса if (destination.droppableId !== source.droppableId) { //Считываем строку, у которой изменяется статус let row = tasks.rows.find(f => f.id === parseInt(result.draggableId)); //Формируем события с учетом изменения let rows = tasks.rows.map(task => task.id === parseInt(result.draggableId) ? { ...task, category: parseInt(result.destination.droppableId) } : task ); //Мнемокод точки назначения const destCode = tasks.statuses.find(s => s.id == destination.droppableId).code; //Получение настройки точки назначения const pointSettings = eventPoints.find(ep => ep.point === destCode); //Если необходимо примечание при переходе if (pointSettings.addNoteOnChst) { //Изменяем статус события с добавлением примечания openNoteDialog(n => { setTasks(pv => ({ ...pv, rows: [...rows] })); handleStateChange(row.nrn, destCode, n); }); } //Изменяем статус события else { //Переинициализируем строки с учетом изменений (для визуального отображения) setTasks(pv => ({ ...pv, rows: [...rows] })); handleStateChange(row.nrn, destCode); } } }, [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) { arrayFormer(data.XDOCLINKS).map(d => { newDocLinks.push({ id: d.NRN, descr: d.SDESCR }); }); } //Указываем сформированные учётные документы setDocLinks([...newDocLinks]); return newDocLinks; }, [executeStored, tasks.filters.values.type] ); useEffect(() => { //Считывание вспомогательных данных let getEventData = async () => { const data = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_INFO_BY_CODE", args: { SCODE: tasks.filters.values.type }, respArg: "COUT" }); //Инициализируем маршруты событий let newRoutes = []; //Если найдены маршруты if (data.XEVROUTES) { arrayFormer(data.XEVROUTES).map(r => { newRoutes.push({ src: r.SSOURCE, dest: r.SDESTINATION }); }); } //Инициализируем точки событий let newPoints = []; if (data.XEVPOINTS) { arrayFormer(data.XEVPOINTS).map(p => { newPoints.push({ point: p.SEVPOINT, addNoteOnChst: p.ADDNOTE_ONCHST, addNoteOnSend: p.ADDNOTE_ONSEND, banUpdate: p.BAN_UPDATE }); }); } //Инициализируем типы заголовков примечаний let newNoteTypes = []; if (data.XNOTETYPES) { arrayFormer(data.XNOTETYPES).map(nt => { newNoteTypes.push(nt.SNAME); }); } //Инициализируем пользователей let newAccounts = []; //Если найдены пользователи if (data.XACCOUNTS) { arrayFormer(data.XACCOUNTS).map(a => { 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]); //Указываем сформированные точки маршрута setEventPoints([...newPoints]); //Указываем типы заголовков примечаний setNoteTypes([...newNoteTypes]); //Указываем сформированные аккаунты setAccounts([...newAccounts]); }; //Если указан тип событий if (tasks.filters.values.type) { //Загружаем данные getEventData(); //Загружаем учётные документы getDocLinks(); } }, [tasks.filters.values.type, executeStored, getDocLinks]); useEffect(() => { //Считывание данных с учетом фильтрации let getTasks = async () => { const data = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVENTS_DATASET", args: { CFILTERS: { VALUE: object2Base64XML(tasks.filters.fArray, { arrayNodeName: "filters" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, CORDERS: { VALUE: object2Base64XML(tasks.orders, { arrayNodeName: "orders" }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, NINCLUDE_DEF: tasks.tasksLoaded ? 0 : 1 }, respArg: "COUT" }); //Инициализируем статусы и события let newGroups = []; let newRows = []; //Если статусы есть if (data.XGROUPS) { //Формируем структуру статусов arrayFormer(data.XGROUPS).map((group, i) => { newGroups.push({ id: i, code: group.name, caption: group.caption, color: randomColor(i + 1) }); }); //Если есть события if (data.XROWS) { //Формируем структуру событий arrayFormer(data.XROWS).map((task, i) => { newRows.push(initTask(i, newGroups.find(x => x.caption === task.groupName).id, task)); }); } } //Указываем сформированные данные setTasks(pv => ({ ...pv, groupsLoaded: true, tasksLoaded: true, statuses: [...newGroups], rows: [...newRows], reload: false })); }; //Если необходимо загрузить данные и указан тип событий if (tasks.reload && tasks.filters.values.type) { //Загружаем данные getTasks(); } }, [ tasks.reload, tasks.filters.values.type, tasks.filters.fArray, tasks.orders, tasks.tasksLoaded, tasks.statuses.length, tasks.rows.length, executeStored, SERV_DATA_TYPE_CLOB ]); return [ tasks, eventRoutes, eventPoints, noteTypes, docLinks, accounts, taskFormOpen, setTaskFormOpen, cardSettings, handleFilterOk, handleFilterCancel, handleFilterClick, handleCardSettingsClick, handleCardSettingsOk, handleCardSettingsCancel, handleReload, onDragEnd, handleOrderChanged, getDocLinks ]; }; //Хук для события const useClientEvent = (taskRn, taskType = "", taskStatus = "") => { //Собственное состояние const [task, setTask] = useState({ init: true, nrn: taskRn, scrn: "", sprefix: "", snumber: "", stype: taskType, sstatus: taskStatus, 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 initEventType = useCallback(async () => { //Считываем параметры исходя из типа события const data = await executeStored({ stored: "PKG_P8PANELS_CLNTTSKBRD.CLNEVNTYPES_INIT", args: { SEVENT_TYPE: task.stype, SCURRENT_PREF: task.sprefix }, tagValueProcessor: () => undefined }); if (data) { setTask(pv => ({ ...pv, sprefix: data.SPREF, snumber: data.SNUMB })); } }, [task.sprefix, task.stype, executeStored]); //Отображение раздела "Клиенты" 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: "PKG_P8PANELS_CLNTTSKBRD.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: "PKG_P8PANELS_CLNTTSKBRD.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: "PKG_P8PANELS_CLNTTSKBRD.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: "PKG_P8PANELS_CLNTTSKBRD.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: "PKG_P8PANELS_CLNTTSKBRD.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(); initEventType(); } } if (!task.init) { setTask(pv => ({ ...pv, sinit_user: !task.sinit_clnperson ? task.scurrent_user : "" })); } }, [executeStored, task.init, task.nrn, task.stype, task.scurrent_user, task.sinit_clnperson, taskRn, initEventType]); //Проверка доступности действия 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, 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 { pOnlineShowDictionary } = 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 = () => { 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", 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 menuItems = [ { 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 [taskCard, setTaskCard, cardActions, handleMethodsMenuButtonClick, handleMethodsMenuClose, menuItems]; }; //Хук для сортировок const useOrders = () => { //Состояние меню сортировки const [menuOrders, setMenuOrders] = useState({ anchorMenuOrders: null, openOrders: false }); //По нажатию на открытие меню сортировки const handleOrdersMenuButtonClick = event => { setMenuOrders(pv => ({ ...pv, anchorMenuOrders: event.currentTarget, openOrders: true })); }; //При закрытии меню const handleOrdersMenuClose = () => { setMenuOrders(pv => ({ ...pv, anchorMenuOrders: null, openOrders: false })); }; return [menuOrders, handleOrdersMenuButtonClick, handleOrdersMenuClose]; }; export { useTasks, useClientEvent, useTaskCard, useOrders };