From f35d39fefa31bd1cdcec3389e76e382b2c1d61d9 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Wed, 16 Oct 2024 19:23:57 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B0=D0=BD=D0=B5=D0=BB=D1=8C=20-=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D1=8C=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0,=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?,=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=B5=D1=80=D0=B5=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправлена ошибка с "лишним" запросом к серверу на получение списка выборок данных --- panels/eqs_tech_cond_forecast/admin_tab.js | 145 +++++++++----- .../admin_tab_layout.js | 108 ++++++++++- .../eqs_tech_cond_forecast_hooks.js | 8 +- .../forecast_tab_layout.js | 181 +++++++++--------- 4 files changed, 294 insertions(+), 148 deletions(-) diff --git a/panels/eqs_tech_cond_forecast/admin_tab.js b/panels/eqs_tech_cond_forecast/admin_tab.js index eda0cc8..f561e19 100644 --- a/panels/eqs_tech_cond_forecast/admin_tab.js +++ b/panels/eqs_tech_cond_forecast/admin_tab.js @@ -12,6 +12,7 @@ import PropTypes from "prop-types"; //Контроль свойств компо import { Box, Grid, Stack, Icon, Button, IconButton } from "@mui/material"; //Интерфейсные компоненты import { ApplicationСtx } from "../../context/application"; //Контекст приложения import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с серверомs +import { P8PAppInlineError } from "../../components/p8p_app_message"; //Встраиваемое сообщение об ошибке import { DS_RN_DEFAULT, useEquipDataSelectionList } from "./eqs_tech_cond_forecast_hooks"; //Общие вспомогательные хуки import { EquipDataSelectionIU, @@ -75,7 +76,9 @@ const AdminTab = ({ dataSelection = DS_RN_DEFAULT, dataSelectionClassMachine = n const [equipDataSelectionClassMachine, setDataSelectionClassMachine] = useState(dataSelectionClassMachine); //Загрузка списка выборок данных - const { equipDataSelectionList } = useEquipDataSelectionList(refresh.dataSelection); + const { equipDataSelectionList, equipDataSelectionListIsLoading, equipDataSelectionListAccess } = useEquipDataSelectionList( + refresh.dataSelection + ); //Загрузка классов оборудования выбранной выборки данных const { equipDataSelectionClassMachineList } = useEquipDataSelectionClassMachineList(equipDataSelection, refresh.dataSelectionClassMachine); @@ -164,16 +167,43 @@ const AdminTab = ({ dataSelection = DS_RN_DEFAULT, dataSelectionClassMachine = n setDataSelectionClassMachine(data.NRN); }; + //Отработка результатов выполнения пользовательской процедуры формирования данных выборки + const processMakeEquipDataSelectionClassMachineFilesResults = async (equipDSCM, dataSetIdent, dataSetConfigIdent, clear) => { + await executeStored({ + stored: "UDO_PKG_EQUIPDS.CMFL_MAKE", + args: { + NEQUIPDSCM: equipDSCM, + NDATASET_IDENT: dataSetIdent, + NDATASET_CONFIG_IDENT: dataSetConfigIdent, + NCLEAR: clear + } + }); + setRefresh(pv => ({ ...pv, dataSelectionClassMachineFilesList: pv.dataSelectionClassMachineFilesList + 1 })); + }; + //При нажатии "Сформировать" в списке файлов карточки класса оборудования - const handleMakeEquipDataSelectionClassMachineFiles = (equipDSCM, procedure) => { + const handleMakeEquipDataSelectionClassMachineFiles = (equipDSCM, procedure, clear) => { pOnlineUserProcedure({ code: procedure, inputParameters: [{ name: "NEQUIPDSCM", value: equipDSCM }], - callBack: res => - res.success ? setRefresh(pv => ({ ...pv, dataSelectionClassMachineFilesList: pv.dataSelectionClassMachineFilesList + 1 })) : null + callBack: res => { + if (res.success) + processMakeEquipDataSelectionClassMachineFilesResults( + equipDSCM, + res.outParameters.NDATASET_IDENT, + res.outParameters.NDATASET_CONFIG_IDENT, + clear + ); + } }); }; + //При нажатии "Удалить" в списке файлов карточки класса оборудования + const handleDeleteEquipDataSelectionClassMachineFiles = async equipDSCMFL => { + await executeStored({ stored: "UDO_PKG_EQUIPDS.CMFL_DEL", args: { NRN: equipDSCMFL } }); + setRefresh(pv => ({ ...pv, dataSelectionClassMachineFilesList: pv.dataSelectionClassMachineFilesList + 1 })); + }; + //При нажатии "Загрузить на сервер" в списке файлов карточки класса оборудования const handleUploadEquipDataSelectionClassMachineFiles = async equipDSCM => { await executeStored({ stored: "UDO_PKG_EQUIPDS.CMFL_UPLOAD", args: { NEQUIPDSCM: equipDSCM } }); @@ -249,54 +279,67 @@ const AdminTab = ({ dataSelection = DS_RN_DEFAULT, dataSelectionClassMachine = n /> ) : null} - - - - - - add - - {equipDataSelection != DS_RN_DEFAULT ? ( - - delete - - ) : null} - - - - - - - + {equipDataSelectionListIsLoading ? null : !equipDataSelectionListAccess ? ( + + - + ) : ( + <> + + + + + + add + + {equipDataSelection != DS_RN_DEFAULT ? ( + + delete + + ) : null} + + + + + + + + + + + )} ); diff --git a/panels/eqs_tech_cond_forecast/admin_tab_layout.js b/panels/eqs_tech_cond_forecast/admin_tab_layout.js index 9996358..e90e540 100644 --- a/panels/eqs_tech_cond_forecast/admin_tab_layout.js +++ b/panels/eqs_tech_cond_forecast/admin_tab_layout.js @@ -7,7 +7,7 @@ //Подключение библиотек //--------------------- -import React, { useState, useContext } from "react"; //Классы React +import React, { useState, useContext, useRef } from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Box, @@ -29,7 +29,12 @@ import { DialogContent, DialogActions, IconButton, - Icon + Icon, + Popper, + ButtonGroup, + ClickAwayListener, + Paper, + MenuList } from "@mui/material"; //Интерфейсные компоненты import { useTheme } from "@mui/material/styles"; //Темы оформления import { ApplicationСtx } from "../../context/application"; //Контекст приложения @@ -138,13 +143,23 @@ const formatFileStateValue = (theme, value, err) => { }; //Форматирование колонок таблицы файлов класса оборудования выборки данных -const filesListDataCellRender = ({ row, columnDef, theme }) => { +const filesListDataCellRender = ({ row, columnDef, theme, onDelete }) => { switch (columnDef.name) { case "NSTATUS": return { cellProps: { align: "left" }, data: formatFileStateValue(theme, row.NSTATUS, row.SERR) }; + case "SACTIONS": + return { + data: ( + + (onDelete ? onDelete(row.NRN) : null)}> + delete + + + ) + }; } }; @@ -183,6 +198,75 @@ const classMachineCardTableHeadCellRender = ({ columnDef }) => { } }; +//Кнопка с всплывающим меню опций +const PopUpButton = ({ onClick, options = [], zIndex = 10000 }) => { + //Собственное состояние - выбранная опция + const [selectedOption, setSelectedOption] = useState(0); + + //Собственное состояние - флаг открытия списка опций + const [open, setOpen] = useState(false); + + //Ссылка на группу кнопок для аттача всплывающего меню + const anchorRef = useRef(null); + + //Отработка нажатия на кнопку + const handleClick = () => (onClick && options[selectedOption] ? onClick(options[selectedOption]) : null); + + //Отработка открытия/закрытия меню опций + const handleToggle = () => { + setOpen(prevOpen => !prevOpen); + }; + + //Принудительное закрытие меню опций (с проверкой открытости) + const handleClose = event => { + if (anchorRef.current && anchorRef.current.contains(event.target)) return; + setOpen(false); + }; + + //Отработка нажатия на элемент меню опций + const handleMenuItemClick = index => { + setSelectedOption(index); + setOpen(false); + }; + + //Генерация содержимого + return Array.isArray(options) && options.length > 0 ? ( + <> + + + + + + + + + {options.map((o, index) => ( + handleMenuItemClick(index)}> + {o.label} + + ))} + + + + + + ) : null; +}; + +//Контроль свойств - Кнопка с всплывающим меню опций +PopUpButton.propTypes = { + onClick: PropTypes.func, + options: PropTypes.arrayOf( + PropTypes.shape({ + code: PropTypes.string.isRequired, + label: PropTypes.string.isRequired + }) + ), + zIndex: PropTypes.number +}; + //----------- //Тело модуля //----------- @@ -452,6 +536,7 @@ const EquipDataSelectionClassMachineCard = ({ modelsList, onCardDelete, onClassMachineFilesMake, + onClassMachineFilesDelete, onClassMachineFilesUpload, onClassMachineFilesSendMd, onClassMachineModelAdd, @@ -465,7 +550,8 @@ const EquipDataSelectionClassMachineCard = ({ const handleCardDeleteClick = () => (onCardDelete ? onCardDelete(card.NRN) : null); //При нажатии на "Сформировать" для файлов данных - const handleClassMachineFilesMakeClick = () => (onClassMachineFilesMake ? onClassMachineFilesMake(card.NRN, card.SUSERPROCS_DATA) : null); + const handleClassMachineFilesMakeClick = option => + onClassMachineFilesMake ? onClassMachineFilesMake(card.NRN, card.SUSERPROCS_DATA, option.code === "CLEAR_AND_MAKE" ? 1 : 0) : null; //При нажатии на "Загрузить на сервер" для файлов данных const handleClassMachineFilesUploadClick = () => (onClassMachineFilesUpload ? onClassMachineFilesUpload(card.NRN) : null); @@ -473,6 +559,9 @@ const EquipDataSelectionClassMachineCard = ({ //При нажатии на "Загрузить на сервер" для файлов данных const handleClassMachineFilesSendMdClick = () => (onClassMachineFilesSendMd ? onClassMachineFilesSendMd(card.NRN) : null); + //При нажатии на "Удалить" для файлов данных + const handleClassMachineFilesDeleteClick = equipDSCMFL => (onClassMachineFilesDelete ? onClassMachineFilesDelete(equipDSCMFL) : null); + //При нажатии на "Добавить" для моделей const handleClassMachineModelAddClick = () => (onClassMachineModelAdd ? onClassMachineModelAdd() : null); @@ -502,7 +591,13 @@ const EquipDataSelectionClassMachineCard = ({ Файлы данных - + @@ -517,7 +612,7 @@ const EquipDataSelectionClassMachineCard = ({ fixedHeader={true} reloading={false} headCellRender={classMachineCardTableHeadCellRender} - dataCellRender={prms => filesListDataCellRender({ ...prms, theme })} + dataCellRender={prms => filesListDataCellRender({ ...prms, theme, onDelete: handleClassMachineFilesDeleteClick })} /> @@ -565,6 +660,7 @@ EquipDataSelectionClassMachineCard.propTypes = { modelsList: PropTypes.object.isRequired, onCardDelete: PropTypes.func, onClassMachineFilesMake: PropTypes.func, + onClassMachineFilesDelete: PropTypes.func, onClassMachineFilesUpload: PropTypes.func, onClassMachineFilesSendMd: PropTypes.func, onClassMachineModelAdd: PropTypes.func, diff --git a/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_hooks.js b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_hooks.js index 4ef129c..0b6d253 100644 --- a/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_hooks.js +++ b/panels/eqs_tech_cond_forecast/eqs_tech_cond_forecast_hooks.js @@ -44,7 +44,7 @@ const useEquipDataSelectionList = refresh => { const [isLoading, setLoading] = useState(false); //Собственное состояние - данные - const [data, setData] = useState([DS_DEFAULT]); + const [data, setData] = useState({ list: [DS_DEFAULT], access: false }); //Подключение к контексту взаимодействия с сервером const { executeStored } = useContext(BackEndСtx); @@ -61,16 +61,16 @@ const useEquipDataSelectionList = refresh => { attributeValueProcessor: (name, val) => (["SNAME"].includes(name) ? undefined : val), loader: false }); - setData([DS_DEFAULT, ...(data?.XDS ? data.XDS : [])]); + setData({ list: [DS_DEFAULT, ...(data?.XDS ? data.XDS : [])], access: data?.NACCESS == 1 ? true : false }); } finally { setLoading(false); } }; - loadData(); + if (refresh > 0) loadData(); }, [refresh, executeStored]); //Вернём данные - return { equipDataSelectionList: data, equipDataSelectionListIsLoading: isLoading }; + return { equipDataSelectionList: data.list, equipDataSelectionListIsLoading: isLoading, equipDataSelectionListAccess: data.access }; }; //---------------- diff --git a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js index 9f77f4d..9b23fb7 100644 --- a/panels/eqs_tech_cond_forecast/forecast_tab_layout.js +++ b/panels/eqs_tech_cond_forecast/forecast_tab_layout.js @@ -15,6 +15,7 @@ import { ApplicationСtx } from "../../context/application"; //Контекст import { BackEndСtx } from "../../context/backend"; //Контекст взаимодействия с серверомs import { MessagingСtx } from "../../context/messaging"; //Контекст сообщений import { BUTTONS, TEXTS } from "../../../app.text"; //Текстовые ресурсы и константы +import { P8PAppInlineError } from "../../components/p8p_app_message"; //Встраиваемое сообщение об ошибке import { P8PDataGrid, P8P_DATA_GRID_SIZE } from "../../components/p8p_data_grid"; //Таблица данных import { P8P_DATA_GRID_CONFIG_PROPS } from "../../config_wrapper"; //Подключение компонентов к настройкам приложения import { formatDateRF, xml2JSON } from "../../core/utils"; //Вспомогательные функции @@ -641,7 +642,7 @@ const TechObjMakeDataSet = ({ eqobjKind, measureUnit, onOk, onCancel }) => { const { pOnlineShowDictionary } = useContext(ApplicationСtx); //Загрузка списка выборок данных - const { equipDataSelectionList } = useEquipDataSelectionList(true); + const { equipDataSelectionList, equipDataSelectionListIsLoading, equipDataSelectionListAccess } = useEquipDataSelectionList(true); //Собственное состояние - значения формы const [values, setValues] = useState({ @@ -667,94 +668,100 @@ const TechObjMakeDataSet = ({ eqobjKind, measureUnit, onOk, onCancel }) => { (onOk ? onCancel() : null)}> Регистрация выборки данных класса технического объекта - item.NRN != DS_RN_DEFAULT).map(item => item.SCODE)} - freeSolo={true} - /> - - selectMeasureUnit(pOnlineShowDictionary, "measureUnit", callBack)} - /> - selectUserProcsData(pOnlineShowDictionary, "userprocsData", callBack)} - /> - - selectServiceFn(pOnlineShowDictionary, "exsServiceFnUpload", callBack)} - /> - - selectServiceFn(pOnlineShowDictionary, "exsServiceFnSendMd", callBack)} - /> - - selectServiceFn(pOnlineShowDictionary, "exsServiceFnSendRq", callBack)} - /> - - + {equipDataSelectionListIsLoading ? null : equipDataSelectionListAccess ? ( + <> + item.NRN != DS_RN_DEFAULT).map(item => item.SCODE)} + freeSolo={true} + /> + + selectMeasureUnit(pOnlineShowDictionary, "measureUnit", callBack)} + /> + selectUserProcsData(pOnlineShowDictionary, "userprocsData", callBack)} + /> + + selectServiceFn(pOnlineShowDictionary, "exsServiceFnUpload", callBack)} + /> + + selectServiceFn(pOnlineShowDictionary, "exsServiceFnSendMd", callBack)} + /> + + selectServiceFn(pOnlineShowDictionary, "exsServiceFnSendRq", callBack)} + /> + + + + ) : ( + + )} - + {equipDataSelectionListAccess ? : null}