From 3f539065ba4ce412555889d214885cca6f71d458 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Mon, 21 Jul 2025 10:09:27 +0300 Subject: [PATCH 1/3] =?UTF-8?q?WEBAPP:=20=D0=9D=D0=BE=D0=B2=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D1=8B=20?= =?UTF-8?q?P8PDialog=20=D0=B8=20P8PInput?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/p8p_dialog.js | 76 +++++++++++++++++++ app/components/p8p_input.js | 137 +++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 app/components/p8p_dialog.js create mode 100644 app/components/p8p_input.js diff --git a/app/components/p8p_dialog.js b/app/components/p8p_dialog.js new file mode 100644 index 0000000..30ab288 --- /dev/null +++ b/app/components/p8p_dialog.js @@ -0,0 +1,76 @@ +/* + Парус 8 - Панели мониторинга + Компонент: Диалог +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useEffect, useState } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from "@mui/material"; //Интерфейсные компоненты +import { BUTTONS } from "../../app.text"; //Общие текстовые ресурсы +import { P8P_INPUT, P8PInput } from "./p8p_input"; //Поле ввода + +//----------- +//Тело модуля +//----------- + +//Диалог +const P8PDialog = ({ title, inputs = [], children, onOk, onCancel, onClose }) => { + //Состояние диалога + const [state, setState] = useState({}); + + //При изменении элемента ввода + const handleInputChange = (name, value) => setState(pv => ({ ...pv, [name]: value })); + + //При нажатии на "ОК" диалога + const handleOk = () => onOk && onOk(state); + + //При нажатии на "Отмена" диалога + const handleCancel = () => onCancel && onCancel(); + + //При нажатии на "Закрыть" диалога + const handleClose = () => (onClose ? onClose() : onCancel ? onCancel() : null); + + //При подключении к старнице + useEffect(() => { + setState(inputs.reduce((res, input) => ({ ...res, [input.name]: input.value == undefined ? null : input.value }), {})); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + //Формирование представления + return ( + + {title} + + {inputs.map((input, i) => ( + + ))} + {children} + + + {onOk && } + {onCancel && } + {onClose && } + + + ); +}; + +//Контроль свойств - Диалог +P8PDialog.propTypes = { + title: PropTypes.string.isRequired, + inputs: PropTypes.arrayOf(PropTypes.shape(P8P_INPUT)), + children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]), + onOk: PropTypes.func, + onCancel: PropTypes.func, + onClose: PropTypes.func +}; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8PDialog }; diff --git a/app/components/p8p_input.js b/app/components/p8p_input.js new file mode 100644 index 0000000..2adc568 --- /dev/null +++ b/app/components/p8p_input.js @@ -0,0 +1,137 @@ +/* + Парус 8 - Панели мониторинга + Компонент: Поле ввода +*/ + +//--------------------- +//Подключение библиотек +//--------------------- + +import React, { useState, useEffect } from "react"; //Классы React +import PropTypes from "prop-types"; //Контроль свойств компонента +import { Box, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton, Autocomplete, TextField } from "@mui/material"; //Интерфейсные компоненты + +//--------- +//Константы +//--------- + +//Формат свойств поля ввода +const P8P_INPUT = { + name: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.instanceOf(Date)]), + label: PropTypes.string.isRequired, + onChange: PropTypes.func, + dictionary: PropTypes.func, + list: PropTypes.array, + type: PropTypes.string, + freeSolo: PropTypes.bool, + disabled: PropTypes.bool, + formValues: PropTypes.object +}; + +//----------- +//Тело модуля +//----------- + +//Поле ввода +const P8PInput = ({ name, value, label, onChange, dictionary, list, type, freeSolo = false, disabled = false, formValues, ...other }) => { + //Значение элемента + const [currentValue, setCurrentValue] = useState(value); + + //При получении нового значения из вне + useEffect(() => { + setCurrentValue(value); + }, [value]); + + //Выбор значения из словаря + const handleDictionaryClick = () => dictionary && dictionary(formValues, res => (res ? res.map(i => handleChangeByName(i.name, i.value)) : null)); + + //Изменение значения элемента (по событию) + const handleChange = e => { + setCurrentValue(e.target.value); + if (onChange) onChange(e.target.name, e.target.value); + }; + + //Изменение значения элемента (по имени и значению) + const handleChangeByName = (targetName, value) => { + if (targetName === name) setCurrentValue(value); + if (onChange) onChange(targetName, value); + }; + + //Генерация содержимого + return ( + + + {list ? ( + freeSolo ? ( + handleChangeByName(name, newValue)} + onInputChange={(event, newInputValue) => handleChangeByName(name, newInputValue)} + options={list} + renderInput={params => } + /> + ) : ( + <> + + {label} + + + + ) + ) : ( + <> + + {label} + + + + list + + + ) : null + } + {...(type ? { type } : {})} + onChange={handleChange} + disabled={disabled} + /> + + )} + + + ); +}; + +//Контроль свойств - Поле ввода +P8PInput.propTypes = P8P_INPUT; + +//---------------- +//Интерфейс модуля +//---------------- + +export { P8P_INPUT, P8PInput }; From a3fd089452134c673337b9bd2ddb33ea83953fcc Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Mon, 21 Jul 2025 10:13:32 +0300 Subject: [PATCH 2/3] =?UTF-8?q?WEBAPP:=20"=D0=A0=D0=B5=D0=B4=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5?= =?UTF-8?q?=D0=BA=20=D0=A0=D0=9E"=20-=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=B4=D0=B8=D0=B0=D0=BB=D0=BE=D0=B3=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D1=8B=20?= =?UTF-8?q?P8PDialog=20=D0=B8=20P8PInput?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rrp_conf_editor/components/dialog_help.js | 6 +- .../components/dialog_mark_iu.js | 18 +-- .../components/dialog_order.js | 10 +- .../components/dialog_section_iu.js | 10 +- app/panels/rrp_conf_editor/components/form.js | 76 --------- .../rrp_conf_editor/components/form_field.js | 149 ------------------ .../rrp_conf_editor/components/marks.js | 15 +- .../rrp_conf_editor/components/sections.js | 12 +- 8 files changed, 38 insertions(+), 258 deletions(-) delete mode 100644 app/panels/rrp_conf_editor/components/form.js delete mode 100644 app/panels/rrp_conf_editor/components/form_field.js diff --git a/app/panels/rrp_conf_editor/components/dialog_help.js b/app/panels/rrp_conf_editor/components/dialog_help.js index b6a8b43..f54c810 100644 --- a/app/panels/rrp_conf_editor/components/dialog_help.js +++ b/app/panels/rrp_conf_editor/components/dialog_help.js @@ -10,7 +10,7 @@ import React from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Typography, List, ListItem } from "@mui/material"; //Интерфейсные элементы -import { Form } from "./form"; //Типовая форма +import { P8PDialog } from "../../../components/p8p_dialog"; //Типовой диалог //--------- //Константы @@ -53,7 +53,7 @@ const DialogHelp = ({ onClose }) => { //Генерация содержимого return ( -
+ Карточки показателей содержат сокращенную информацию о типе состава показателя. Список сокращений: @@ -71,7 +71,7 @@ const DialogHelp = ({ onClose }) => { - +
); }; diff --git a/app/panels/rrp_conf_editor/components/dialog_mark_iu.js b/app/panels/rrp_conf_editor/components/dialog_mark_iu.js index 5c726f1..d59bf4f 100644 --- a/app/panels/rrp_conf_editor/components/dialog_mark_iu.js +++ b/app/panels/rrp_conf_editor/components/dialog_mark_iu.js @@ -10,7 +10,7 @@ import React from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { useDictionary } from "../hooks"; //Кастомные хуки -import { Form } from "./form"; //Типовая форма +import { P8PDialog } from "../../../components/p8p_dialog"; //Типовой диалог //----------- //Тело модуля @@ -67,15 +67,15 @@ const DialogMarkIU = ({ //Генерация содержимого return ( -
{ //Генерация содержимого return ( - { - //Состояние формы - const [state, setState] = useState({}); - - //При изменении элемента формы - const handleFieldChange = (name, value) => setState(pv => ({ ...pv, [name]: value })); - - //При нажатии на "ОК" формы - const handleOk = () => onOk && onOk(state); - - //При нажатии на "Отмена" формы - const handleCancel = () => onCancel && onCancel(); - - //При нажатии на "Закрыть" формы - const handleClose = () => (onClose ? onClose() : onCancel ? onCancel() : null); - - //При подключении к старнице - useEffect(() => { - setState(fields.reduce((res, f) => ({ ...res, [f.elementCode]: f.elementValue == undefined ? null : f.elementValue }), {})); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - //Формирование представления - return ( - - {title} - - {fields.map((f, i) => ( - - ))} - {children} - - - {onOk && } - {onCancel && } - {onClose && } - - - ); -}; - -//Контроль свойств - Форма -Form.propTypes = { - title: PropTypes.string.isRequired, - fields: PropTypes.arrayOf(PropTypes.shape(FORM_FILED)), - children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]), - onOk: PropTypes.func, - onCancel: PropTypes.func, - onClose: PropTypes.func -}; - -//---------------- -//Интерфейс модуля -//---------------- - -export { Form }; diff --git a/app/panels/rrp_conf_editor/components/form_field.js b/app/panels/rrp_conf_editor/components/form_field.js deleted file mode 100644 index 587a1ad..0000000 --- a/app/panels/rrp_conf_editor/components/form_field.js +++ /dev/null @@ -1,149 +0,0 @@ -/* - Парус 8 - Панели мониторинга - РО - Редактор настройки регламентированного отчёта - Компонент панели: Поле ввода формы -*/ - -//--------------------- -//Подключение библиотек -//--------------------- - -import React, { useState, useEffect } from "react"; //Классы React -import PropTypes from "prop-types"; //Контроль свойств компонента -import { Box, Icon, Input, InputAdornment, FormControl, Select, InputLabel, MenuItem, IconButton, Autocomplete, TextField } from "@mui/material"; //Интерфейсные компоненты - -//--------- -//Константы -//--------- - -//Формат свойств поля формы -const FORM_FILED = { - elementCode: PropTypes.string.isRequired, - elementValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.instanceOf(Date)]), - labelText: PropTypes.string.isRequired, - onChange: PropTypes.func, - dictionary: PropTypes.func, - list: PropTypes.array, - type: PropTypes.string, - freeSolo: PropTypes.bool, - disabled: PropTypes.bool, - formValues: PropTypes.object -}; - -//----------- -//Тело модуля -//----------- - -//Поле ввода формы -const FormField = ({ - elementCode, - elementValue, - labelText, - onChange, - dictionary, - list, - type, - freeSolo = false, - disabled = false, - formValues, - ...other -}) => { - //Значение элемента - const [value, setValue] = useState(elementValue); - - //При получении нового значения из вне - useEffect(() => { - setValue(elementValue); - }, [elementValue]); - - //Выбор значения из словаря - const handleDictionaryClick = () => dictionary && dictionary(formValues, res => (res ? res.map(i => handleChangeByName(i.name, i.value)) : null)); - - //Изменение значения элемента (по событию) - const handleChange = e => { - setValue(e.target.value); - if (onChange) onChange(e.target.name, e.target.value); - }; - - //Изменение значения элемента (по имени и значению) - const handleChangeByName = (name, value) => { - if (name === elementCode) setValue(value); - if (onChange) onChange(name, value); - }; - - //Генерация содержимого - return ( - - - {list ? ( - freeSolo ? ( - handleChangeByName(elementCode, newValue)} - onInputChange={(event, newInputValue) => handleChangeByName(elementCode, newInputValue)} - options={list} - renderInput={params => } - /> - ) : ( - <> - - {labelText} - - - - ) - ) : ( - <> - - {labelText} - - - - list - - - ) : null - } - {...(type ? { type } : {})} - onChange={handleChange} - disabled={disabled} - /> - - )} - - - ); -}; - -//Контроль свойств - Поле ввода формы -FormField.propTypes = FORM_FILED; - -//---------------- -//Интерфейс модуля -//---------------- - -export { FORM_FILED, FormField }; diff --git a/app/panels/rrp_conf_editor/components/marks.js b/app/panels/rrp_conf_editor/components/marks.js index b62520f..a8ea9f1 100644 --- a/app/panels/rrp_conf_editor/components/marks.js +++ b/app/panels/rrp_conf_editor/components/marks.js @@ -103,14 +103,14 @@ const Marks = ({ marks, order, marksLoading, marksInit, onRefresh, onMarkInsert, //При переходе к составу показателя const handleMarkCnOpen = (mark, constitution) => showMarkCn(mark, constitution, res => res.success && handleRefresh()); - //При закрытии формы добавления/исправления по "ОК" - const handleIUFormOk = values => { + //При закрытии диалога добавления/исправления по "ОК" + const handleIUDialogOk = values => { if (modMark === true) onMarkInsert && onMarkInsert(values, res => res && setModMark(null)); else onMarkUpdate && onMarkUpdate({ ...modMark, ...values }, res => res && setModMark(null)); }; - //При закрытии формы добавления/исправления по "Отмена" - const handleIUFormCancel = () => setModMark(null); + //При закрытии диалога добавления/исправления по "Отмена" + const handleIUDialogCancel = () => setModMark(null); //Формирование представления return ( @@ -118,7 +118,12 @@ const Marks = ({ marks, order, marksLoading, marksInit, onRefresh, onMarkInsert, {dialogOrder && } {dialogHelp && } {modMark && ( - + )} {marksInit && (marks ? ( diff --git a/app/panels/rrp_conf_editor/components/sections.js b/app/panels/rrp_conf_editor/components/sections.js index 4c63745..3d25186 100644 --- a/app/panels/rrp_conf_editor/components/sections.js +++ b/app/panels/rrp_conf_editor/components/sections.js @@ -118,15 +118,15 @@ const Sections = ({ conf, onSectionChange, onSectionCountChange }) => { //При удалении раздела настройки const handleSectionDelete = section => showMsgWarn("Удалить раздел?", () => deleteSection(section)); - //При закрытии формы добавления/исправления по "ОК" - const handleIUFormOk = async values => { + //При закрытии диалога добавления/исправления по "ОК" + const handleIUDialogOk = async values => { if (modSection === true) await insertSection({ conf, ...values }); else await updateSection({ rn: modSection.NRN, ...values }); setModSection(null); }; - //При закрытии формы добавления/исправления по "Отмена" - const handleIUFormCancel = () => setModSection(null); + //При закрытии диалога добавления/исправления по "Отмена" + const handleIUDialogCancel = () => setModSection(null); //При изменении состава разделов useEffect(() => { @@ -155,8 +155,8 @@ const Sections = ({ conf, onSectionChange, onSectionCountChange }) => { code={modSection?.SCODE} name={modSection?.SNAME} insert={modSection === true} - onOk={handleIUFormOk} - onCancel={handleIUFormCancel} + onOk={handleIUDialogOk} + onCancel={handleIUDialogCancel} /> )} {sections.length > 0 ? ( From d792187ff92715a53a6d4b8a48718fedeb3e03ef Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Mon, 21 Jul 2025 11:52:08 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A0=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=20=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB=D0=B5=D0=B9:=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20P8PDia?= =?UTF-8?q?log,=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panels_editor/components/components_hooks.js | 2 +- .../panels_editor/components/editors_common.js | 16 ++++------------ ...G_P8PANELS_EDITOR.pck => PKG_P8PANELS_PE.pck} | 8 ++++---- 3 files changed, 9 insertions(+), 17 deletions(-) rename db/{PKG_P8PANELS_EDITOR.pck => PKG_P8PANELS_PE.pck} (97%) diff --git a/app/panels/panels_editor/components/components_hooks.js b/app/panels/panels_editor/components/components_hooks.js index a23fce5..518cd82 100644 --- a/app/panels/panels_editor/components/components_hooks.js +++ b/app/panels/panels_editor/components/components_hooks.js @@ -59,7 +59,7 @@ const useUserProcDesc = ({ code, refresh }) => { try { setLoading(true); const data = await executeStored({ - stored: "PKG_P8PANELS_EDITOR.USERPROCS_DESC", + stored: "PKG_P8PANELS_PE.USERPROCS_DESC", args: { SCODE: code }, respArg: "COUT", isArray: name => name === "arguments", diff --git a/app/panels/panels_editor/components/editors_common.js b/app/panels/panels_editor/components/editors_common.js index 2c2f172..20bf1d0 100644 --- a/app/panels/panels_editor/components/editors_common.js +++ b/app/panels/panels_editor/components/editors_common.js @@ -17,10 +17,6 @@ import { Typography, Divider, Chip, - Dialog, - DialogTitle, - DialogContent, - DialogActions, Button, TextField, InputAdornment, @@ -34,6 +30,7 @@ import { import client from "../../../core/client"; //Клиент БД import { ApplicationСtx } from "../../../context/application"; //Контекст приложения import { BUTTONS } from "../../../../app.text"; //Общие текстовые ресурсы +import { P8PDialog } from "../../../components/p8p_dialog"; //Типовой диалог import { useUserProcDesc } from "./components_hooks"; //Общие хуки компонентов import "../panels_editor.css"; //Стили редактора @@ -168,14 +165,9 @@ EditorSubHeader.propTypes = { const ConfigDialog = ({ title, children, onOk, onCancel }) => { //Формирование представления return ( - - {title} - {children} - - - - - + + {children} + ); }; diff --git a/db/PKG_P8PANELS_EDITOR.pck b/db/PKG_P8PANELS_PE.pck similarity index 97% rename from db/PKG_P8PANELS_EDITOR.pck rename to db/PKG_P8PANELS_PE.pck index 0a7a734..4f70e50 100644 --- a/db/PKG_P8PANELS_EDITOR.pck +++ b/db/PKG_P8PANELS_PE.pck @@ -1,4 +1,4 @@ -create or replace package PKG_P8PANELS_EDITOR as +create or replace package PKG_P8PANELS_PE as /* Список аргументов пользовательской процедуры */ procedure USERPROCS_DESC @@ -7,9 +7,9 @@ create or replace package PKG_P8PANELS_EDITOR as COUT out clob -- Сериализованный список аргументов ); -end PKG_P8PANELS_EDITOR; +end PKG_P8PANELS_PE; / -create or replace package body PKG_P8PANELS_EDITOR as +create or replace package body PKG_P8PANELS_PE as /* Описание пользовательской процедуры */ procedure USERPROCS_DESC @@ -123,5 +123,5 @@ create or replace package body PKG_P8PANELS_EDITOR as end if; end USERPROCS_DESC; -end PKG_P8PANELS_EDITOR; +end PKG_P8PANELS_PE; /