From b09ae4d83b462eb342293678274b3868dbcc3650 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Fri, 22 Aug 2025 18:08:45 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-979=20-=20=D0=9D=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=B0=20-=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BE=D1=82=D0=B1=D0=BE=D1=80=D0=B0=20(=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=20=D0=B8=20=D0=BA=D0=BB=D0=B8?= =?UTF-8?q?=D0=B5=D0=BD=D1=82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/inspector/inspector.js | 4 +- .../cond_operation_buttons.js | 43 +++++++ .../components/inspector_query_cond/hooks.js | 38 +++++++ .../inspector_query_cond.js | 103 +++++++++++++++++ .../inspector_query_cond/query_cond_dialog.js | 105 ++++++++++++++++++ db/PKG_P8PANELS_QE.pck | 29 +++++ 6 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 app/panels/query_editor/components/inspector_query_cond/cond_operation_buttons.js create mode 100644 app/panels/query_editor/components/inspector_query_cond/hooks.js create mode 100644 app/panels/query_editor/components/inspector_query_cond/inspector_query_cond.js create mode 100644 app/panels/query_editor/components/inspector_query_cond/query_cond_dialog.js diff --git a/app/panels/query_editor/components/inspector/inspector.js b/app/panels/query_editor/components/inspector/inspector.js index 7ecb070..3a9de4e 100644 --- a/app/panels/query_editor/components/inspector/inspector.js +++ b/app/panels/query_editor/components/inspector/inspector.js @@ -13,10 +13,11 @@ import { P8PEditorBox } from "../../../../components/editors/p8p_editor_box"; // import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Подзаголовок группы параметров редактора import { ENTITY_DATA_SHAPE } from "../entity/entity"; //Описание сущности import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание связи +import { ARGUMENT_SHAPE } from "../argument/argument"; //Описание аргумента запроса import { InspectorQueryArguments } from "../inspector_query_args/inspector_query_args"; //Управление аргументами запроса +import { InspectorQueryConditions } from "../inspector_query_cond/inspector_query_cond"; //Управление условиями отбора запроса import { InspectorQueryEntities } from "../inspector_query_ents/inspector_query_ents"; //Управление сущностями запроса import { InspectorQueryRelations } from "../inspector_query_rls/inspector_query_rls"; //Управление связями запроса -import { ARGUMENT_SHAPE } from "../argument/argument"; //Аргументы запроса //----------- //Тело модуля @@ -33,6 +34,7 @@ const Inspector = ({ query, entity, relation, args = [], cond = null, onOptionsC + {relation && ( diff --git a/app/panels/query_editor/components/inspector_query_cond/cond_operation_buttons.js b/app/panels/query_editor/components/inspector_query_cond/cond_operation_buttons.js new file mode 100644 index 0000000..4008995 --- /dev/null +++ b/app/panels/query_editor/components/inspector_query_cond/cond_operation_buttons.js @@ -0,0 +1,43 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Компонент: Кнопки операций условий отбора +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { ButtonGroup, Button } from "@mui/material"; //Интерфейсные компоненты MUI + +//----------- +//Тело модуля +//----------- + +//Кнопки операций условий отбора +const CondOperationButtons = ({ buttons = [], onClick }) => { + return ( + + {buttons.map((button, i) => ( + + ))} + + ); +}; + +//Контроль свойств - Кнопки операций условий отбора +CondOperationButtons.propTypes = { + buttons: PropTypes.arrayOf( + PropTypes.shape({ caption: PropTypes.string.isRequired, title: PropTypes.string.isRequired, value: PropTypes.string.isRequired }) + ), + onClick: PropTypes.func.isRequired +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { CondOperationButtons }; diff --git a/app/panels/query_editor/components/inspector_query_cond/hooks.js b/app/panels/query_editor/components/inspector_query_cond/hooks.js new file mode 100644 index 0000000..04e06a5 --- /dev/null +++ b/app/panels/query_editor/components/inspector_query_cond/hooks.js @@ -0,0 +1,38 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Пользовательские хуки для работы с условиями отбора запроса +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import { useContext, useCallback } from "react"; //Классы React +import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером + +//----------- +//Тело модуля +//----------- + +//Работа с условиями отбора запроса +const useQueryConditions = query => { + //Подключение к контексту взаимодействия с сервером + const { executeStored } = useContext(BackEndСtx); + + //Установка условий отбора в запросе + const setCond = useCallback( + async cond => { + await executeStored({ stored: "PKG_P8PANELS_QE.QUERY_OPT_COND_SET", args: { NRN: query, SCOND: cond }, loader: false }); + }, + [query, executeStored] + ); + + //Возвращаем интерфейс хука + return { setCond }; +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { useQueryConditions }; diff --git a/app/panels/query_editor/components/inspector_query_cond/inspector_query_cond.js b/app/panels/query_editor/components/inspector_query_cond/inspector_query_cond.js new file mode 100644 index 0000000..acee7e8 --- /dev/null +++ b/app/panels/query_editor/components/inspector_query_cond/inspector_query_cond.js @@ -0,0 +1,103 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Компонент инспектора - Условия отбора запроса +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Card, CardActionArea, CardContent, Stack, Chip, Icon, Button } from "@mui/material"; //Интерфейсные элементы +import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы +import { STYLES as COMMON_STYLES } from "../../../../components/editors/p8p_editors_common"; //Общие ресурсы редаторов +import { useQueryConditions } from "./hooks"; //Хуки для работы с условиями отбора +import { QueryCondDialog } from "./query_cond_dialog"; //Диалог настройки условий отбора + +//--------- +//Константы +//--------- + +//Общий стиль многострочного компонента "Chip" +const COMMON_MULTILINE_CHIP = COMMON_STYLES.CHIP(true, true); + +//Стили +const STYLES = { + COND_CHIP: { + ...COMMON_MULTILINE_CHIP, + "& .MuiChip-label": { + ...COMMON_MULTILINE_CHIP["& .MuiChip-label"], + paddingTop: "5px", + paddingBottom: "5px" + } + } +}; + +//----------- +//Тело модуля +//----------- + +//Компонент инспектора - Условия отбора запроса +const InspectorQueryConditions = ({ query, cond, onOptionsChanged }) => { + //Собственное состояние - отображение диалога настройки условий отбора + const [openQueryCondDialog, setOpenQueryCondDialog] = useState(false); + + //Работа со связями на сервере + const { setCond } = useQueryConditions(query); + + //Уведомление родителя об изменении свойств + const notifyOptionsChanged = () => onOptionsChanged && onOptionsChanged(); + + //При нажатии на кнопку настройки условий отбора + const handleSetup = () => setOpenQueryCondDialog(true); + + //При закрытии диалога изменений условий отбора по "ОК" + const handleQueryCondDialogOk = async cond => { + await setCond(cond); + notifyOptionsChanged(); + setOpenQueryCondDialog(false); + }; + + //При закрытии диалога изменений условий отбора по "Отмена" + const handleQueryCondDialogCancel = () => setOpenQueryCondDialog(false); + + //Расчет флага сконфигурированности + const configured = cond ? true : false; + + //Формирование представления + return ( + <> + {openQueryCondDialog && } + {configured && ( + + + + + + + + + + )} + {!configured && ( + + )} + + ); +}; + +//Контроль свойств компонента - Компонент инспектора - Условия отбора запроса +InspectorQueryConditions.propTypes = { + query: PropTypes.number.isRequired, + cond: PropTypes.string, + onOptionsChanged: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { InspectorQueryConditions }; diff --git a/app/panels/query_editor/components/inspector_query_cond/query_cond_dialog.js b/app/panels/query_editor/components/inspector_query_cond/query_cond_dialog.js new file mode 100644 index 0000000..8874058 --- /dev/null +++ b/app/panels/query_editor/components/inspector_query_cond/query_cond_dialog.js @@ -0,0 +1,105 @@ +/* + Парус 8 - Панели мониторинга - Редактор запросов + Компонент: Диалог настройки условий отбора запроса +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState, useRef } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Stack, TextField } from "@mui/material"; //Интерфейсные компоненты MUI +import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог +import { CondOperationButtons } from "./cond_operation_buttons"; //Кнопки операций условия отбора + +//----------- +//Тело модуля +//----------- + +//Диалог настройки условий отбора запроса +const QueryCondDialog = ({ cond, onOk, onCancel }) => { + //Собственное состояние - условия отбора + const [conditions, setConditions] = useState(cond || ""); + + //Ссылка на элемент ввода условия + const condInputRef = useRef(null); + + //Перемещение курсора в конец поля ввода условия + const moveCondCursorToEnd = () => { + if (condInputRef.current) { + const length = condInputRef.current.value.length; + condInputRef.current.setSelectionRange(length, length); + condInputRef.current.focus(); + } + }; + + //Нажатие на кнопку "ОК" + const handleOk = () => onOk && onOk(conditions); + + //Нажатие на кнопку "Отмена" + const handleCancel = () => onCancel && onCancel(); + + //При изменении условия через компонент + const handleChange = e => setConditions(e.target.value); + + //При нажатии на кнопку операции + const handleOperationButtonClick = value => { + setConditions(pv => pv + value); + moveCondCursorToEnd(); + }; + + //Генерация содержимого + return ( + + + ", title: "Не равно", value: " <> " }, + { caption: ">", title: "Больше", value: " > " }, + { caption: ">=", title: "Больше или равно", value: " >= " }, + { caption: "<", title: "Меньше", value: " < " }, + { caption: "<=", title: "Меньше или равно", value: " <= " }, + { caption: "(", title: "Открывающая скобка", value: "(" }, + { caption: ")", title: "Закрывающая скобка", value: ")" } + ]} + onClick={handleOperationButtonClick} + /> + + + + + ); +}; + +//Контроль свойств - Диалог настройки условий отбора запроса +QueryCondDialog.propTypes = { + cond: PropTypes.string, + onOk: PropTypes.func, + onCancel: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { QueryCondDialog }; diff --git a/db/PKG_P8PANELS_QE.pck b/db/PKG_P8PANELS_QE.pck index 36c9bc5..f05edf2 100644 --- a/db/PKG_P8PANELS_QE.pck +++ b/db/PKG_P8PANELS_QE.pck @@ -130,6 +130,13 @@ create or replace package PKG_P8PANELS_QE as NRN in number, -- Рег. номер запроса SNAME in varchar2 -- Имя ); + + /* Установка условий отбора запроса */ + procedure QUERY_OPT_COND_SET + ( + NRN in number, -- Рег. номер запроса + SCOND in varchar2 -- Условия отбора + ); end PKG_P8PANELS_QE; / @@ -536,5 +543,27 @@ create or replace package body PKG_P8PANELS_QE as PKG_P8PANELS_QE_BASE.QUERY_OPT_SET(NRN => RQ.RN, ROPT => ROPT); end QUERY_OPT_ARG_REMOVE; + /* Установка условий отбора запроса */ + procedure QUERY_OPT_COND_SET + ( + NRN in number, -- Рег. номер запроса + SCOND in varchar2 -- Условия отбора + ) + is + RQ P8PNL_QE_QUERY%rowtype; -- Запись запроса + ROPT PKG_P8PANELS_QE_BASE.TOPT; -- Настройка запроса + begin + /* Провим права доступа */ + PKG_P8PANELS_QE_BASE.QUERY_ACCESS_MODIFY(NRN => NRN, SUSER => UTILIZER()); + /* Читаем запись запроса */ + RQ := PKG_P8PANELS_QE_BASE.QUERY_GET(NRN => NRN); + /* Читаем текущую настройку */ + ROPT := PKG_P8PANELS_QE_BASE.QUERY_OPT_GET(COPT => RQ.OPT); + /* Установим новые условия отбора */ + ROPT.SCOND := SCOND; + /* Сохраняем обновленную настройку */ + PKG_P8PANELS_QE_BASE.QUERY_OPT_SET(NRN => RQ.RN, ROPT => ROPT); + end QUERY_OPT_COND_SET; + end PKG_P8PANELS_QE; /