From 7515a9cce309090a4c036996c20c28538e51ac04 Mon Sep 17 00:00:00 2001 From: Mikhail Chechnev Date: Wed, 3 Sep 2025 15:16:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-979=20-=20=D0=A0=D0=B5?= =?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BD=D1=8F=D1=82=D0=B8=D0=B9=20=D0=A1=D1=83=D1=89=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C,=20=D0=90=D1=82=D1=80=D0=B8=D0=B1?= =?UTF-8?q?=D1=83=D1=82,=20=D0=9E=D1=82=D0=BD=D0=BE=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5,=20=D0=AD=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD=D1=82=20?= =?UTF-8?q?=D0=B4=D0=B8=D0=B0=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D1=8B,=20?= =?UTF-8?q?=D0=A1=D0=B2=D1=8F=D0=B7=D1=8C=20=D0=B4=D0=B8=D0=B0=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BC=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/attribute/attribute.js | 8 +- .../query_editor/components/entity/entity.js | 14 ++- .../components/inspector/inspector.js | 13 +- .../inspector_query_ents/attrs_list.js | 4 +- .../inspector_query_ents.js | 4 +- .../inspector_query_rls.js | 4 +- .../components/query_diagram/query_diagram.js | 48 ++++---- .../components/relation/relation.js | 4 +- app/panels/query_editor/hooks.js | 112 ++++++++++-------- app/panels/query_editor/query_editor.js | 15 ++- db/PKG_P8PANELS_QE_BASE.pck | 63 +++++----- 11 files changed, 159 insertions(+), 130 deletions(-) diff --git a/app/panels/query_editor/components/attribute/attribute.js b/app/panels/query_editor/components/attribute/attribute.js index ff8fc9b..95a7cd8 100644 --- a/app/panels/query_editor/components/attribute/attribute.js +++ b/app/panels/query_editor/components/attribute/attribute.js @@ -51,9 +51,9 @@ const STYLES = { const ICONS = { ...DATA_TYPE_ICON, DEFAULT: "category" }; //Структура данных об атрибуте сущности -const ATTRIBUTE_DATA_SHAPE = PropTypes.shape({ +const ATTRIBUTE_SHAPE = PropTypes.shape({ id: PropTypes.string.isRequired, - parentEntity: PropTypes.string, + parentEntity: PropTypes.string.isRequired, name: PropTypes.string.isRequired, title: PropTypes.string.isRequired, dataType: PropTypes.oneOf(Object.values(DATA_TYPE)), @@ -136,11 +136,11 @@ const Attribute = ({ data }) => { //Контроль свойств компонента - Атрибут сущности Attribute.propTypes = { - data: ATTRIBUTE_DATA_SHAPE + data: ATTRIBUTE_SHAPE }; //---------------- //Интерфейс модуля //---------------- -export { Attribute, ATTRIBUTE_DATA_SHAPE, attrGetUse, attrGetShow }; +export { Attribute, ATTRIBUTE_SHAPE, attrGetUse, attrGetShow }; diff --git a/app/panels/query_editor/components/entity/entity.js b/app/panels/query_editor/components/entity/entity.js index 9750ec1..b2503f5 100644 --- a/app/panels/query_editor/components/entity/entity.js +++ b/app/panels/query_editor/components/entity/entity.js @@ -10,16 +10,20 @@ import React from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import "./entity.css"; //Стили компомнента +import { ATTRIBUTE_SHAPE } from "../attribute/attribute"; //Описание атрибута сущности //--------- //Константы //--------- //Структура данных о сущности запроса -const ENTITY_DATA_SHAPE = PropTypes.shape({ +const ENTITY_SHAPE = PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, - title: PropTypes.string.isRequired + title: PropTypes.string.isRequired, + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired, + attrs: PropTypes.arrayOf(ATTRIBUTE_SHAPE).isRequired }); //----------- @@ -40,12 +44,12 @@ const Entity = ({ data, selected = false }) => { //Контроль свойств компонента - Сущность запроса Entity.propTypes = { - data: ENTITY_DATA_SHAPE, - selected: PropTypes.bool.isRequired + data: ENTITY_SHAPE.isRequired, + selected: PropTypes.bool }; //---------------- //Интерфейс модуля //---------------- -export { Entity, ENTITY_DATA_SHAPE }; +export { Entity, ENTITY_SHAPE }; diff --git a/app/panels/query_editor/components/inspector/inspector.js b/app/panels/query_editor/components/inspector/inspector.js index 3a9de4e..e29b329 100644 --- a/app/panels/query_editor/components/inspector/inspector.js +++ b/app/panels/query_editor/components/inspector/inspector.js @@ -11,8 +11,8 @@ import React from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента 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 { ENTITY_SHAPE } from "../entity/entity"; //Описание сущности +import { RELATION_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"; //Управление условиями отбора запроса @@ -24,7 +24,7 @@ import { InspectorQueryRelations } from "../inspector_query_rls/inspector_query_ //----------- //Инспектор свойств -const Inspector = ({ query, entity, relation, args = [], cond = null, onOptionsChanged = null }) => { +const Inspector = ({ query, entity, relation, entities = [], args = [], cond = null, onOptionsChanged = null }) => { //При изменении настроек запроса const handleOptionsChanged = () => onOptionsChanged && onOptionsChanged(); @@ -34,7 +34,7 @@ const Inspector = ({ query, entity, relation, args = [], cond = null, onOptionsC - + {relation && ( @@ -50,8 +50,9 @@ const Inspector = ({ query, entity, relation, args = [], cond = null, onOptionsC //Контроль свойств компонента - Инспектор свойств Inspector.propTypes = { query: PropTypes.number.isRequired, - entity: ENTITY_DATA_SHAPE, - relation: RELATION_DATA_SHAPE, + entity: ENTITY_SHAPE, + relation: RELATION_SHAPE, + entities: PropTypes.arrayOf(ENTITY_SHAPE), args: PropTypes.arrayOf(ARGUMENT_SHAPE), cond: PropTypes.string, onOptionsChanged: PropTypes.func diff --git a/app/panels/query_editor/components/inspector_query_ents/attrs_list.js b/app/panels/query_editor/components/inspector_query_ents/attrs_list.js index 705aac1..08eda21 100644 --- a/app/panels/query_editor/components/inspector_query_ents/attrs_list.js +++ b/app/panels/query_editor/components/inspector_query_ents/attrs_list.js @@ -10,7 +10,7 @@ import React from "react"; //Классы React import PropTypes from "prop-types"; //Контроль свойств компонента import { Stack, List, ListItem, IconButton, Icon, ListItemButton, ListItemText, ListItemIcon, Checkbox, Typography } from "@mui/material"; //Интерфейсные компоненты MUI -import { ATTRIBUTE_DATA_SHAPE, attrGetUse, attrGetShow } from "../attribute/attribute"; //Атрибут сущности +import { ATTRIBUTE_SHAPE, attrGetUse, attrGetShow } from "../attribute/attribute"; //Атрибут сущности import { APP_STYLES } from "../../../../../app.styles"; //Общие стили приложения //--------- @@ -84,7 +84,7 @@ const AttrsList = ({ attrs = [], filter, onSelect = null, onShow = null } = {}) //Контроль свойств компонента - Список атрибутов сущности AttrsList.propTypes = { - attrs: PropTypes.arrayOf(ATTRIBUTE_DATA_SHAPE), + attrs: PropTypes.arrayOf(ATTRIBUTE_SHAPE), filter: PropTypes.string, onSelect: PropTypes.func, onShow: PropTypes.func diff --git a/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js b/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js index 118e014..0e0cea4 100644 --- a/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js +++ b/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js @@ -13,7 +13,7 @@ import { Icon, Button } from "@mui/material"; //Интерфейсные эле import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений приложения import { P8PEditorSubHeader } from "../../../../components/editors/p8p_editor_sub_header"; //Подзаголовок группы параметров редактора import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы -import { ENTITY_DATA_SHAPE } from "../entity/entity"; //Описание сущности +import { ENTITY_SHAPE } from "../entity/entity"; //Описание сущности import { EntityAddDialog } from "./entity_add_dialog"; //Диалог добавления сущности import { EntityAttrsDialog } from "./entity_attrs_dialog"; //Диалог настройки атрибутов сущности import { useQueryEntities } from "./hooks"; //Хуки для работы с сущностями на сервере @@ -101,7 +101,7 @@ const InspectorQueryEntities = ({ query, entity, onOptionsChanged }) => { //Контроль свойств компонента - Компонент инспектора - Сущности запроса InspectorQueryEntities.propTypes = { query: PropTypes.number.isRequired, - entity: ENTITY_DATA_SHAPE, + entity: ENTITY_SHAPE, onOptionsChanged: PropTypes.func }; diff --git a/app/panels/query_editor/components/inspector_query_rls/inspector_query_rls.js b/app/panels/query_editor/components/inspector_query_rls/inspector_query_rls.js index 7295c3c..31cb9c3 100644 --- a/app/panels/query_editor/components/inspector_query_rls/inspector_query_rls.js +++ b/app/panels/query_editor/components/inspector_query_rls/inspector_query_rls.js @@ -12,7 +12,7 @@ import PropTypes from "prop-types"; //Контроль свойств компо import { Icon, Button } from "@mui/material"; //Интерфейсные элементы import { MessagingСtx } from "../../../../context/messaging"; //Контекст сообщений приложения import { BUTTONS } from "../../../../../app.text"; //Общие текстовые ресурсы -import { RELATION_DATA_SHAPE } from "../relation/relation"; //Описание связи +import { RELATION_SHAPE } from "../relation/relation"; //Описание связи import { useQueryRelations } from "./hooks"; //Хуки для работы со связями //----------- @@ -50,7 +50,7 @@ const InspectorQueryRelations = ({ query, relation, onOptionsChanged }) => { //Контроль свойств компонента - Компонент инспектора - Связи запроса InspectorQueryRelations.propTypes = { query: PropTypes.number.isRequired, - relation: RELATION_DATA_SHAPE.isRequired, + relation: RELATION_SHAPE.isRequired, onOptionsChanged: PropTypes.func }; diff --git a/app/panels/query_editor/components/query_diagram/query_diagram.js b/app/panels/query_editor/components/query_diagram/query_diagram.js index 71f5b2c..a269c9d 100644 --- a/app/panels/query_editor/components/query_diagram/query_diagram.js +++ b/app/panels/query_editor/components/query_diagram/query_diagram.js @@ -11,8 +11,8 @@ import React, { useState, useCallback, useEffect } from "react"; //Классы import PropTypes from "prop-types"; //Контроль свойств компонента import ReactFlow, { addEdge, Controls, getOutgoers, applyNodeChanges, applyEdgeChanges } from "reactflow"; //Библиотека редактора диаграмм import { NODE_TYPE } from "../../common"; //Общие ресурсы и константы редактора -import { Entity, ENTITY_DATA_SHAPE } from "../entity/entity"; //Сущность запроса -import { Attribute, ATTRIBUTE_DATA_SHAPE } from "../attribute/attribute"; //Атрибут сущности +import { Entity, ENTITY_SHAPE } from "../entity/entity"; //Сущность запроса +import { Attribute, ATTRIBUTE_SHAPE } from "../attribute/attribute"; //Атрибут сущности import "reactflow/dist/style.css"; //Типовые стили библиотеки редактора диаграмм import "./query_diagram.css"; //Стили компонента @@ -37,18 +37,18 @@ const NODE_TYPES_COMPONENTS = { [NODE_TYPE.ATTRIBUTE]: Attribute }; -//Структура сущности запроса -const ENTITY_SHAPE = PropTypes.shape({ +//Структура элемента диаграммы +const NODE_SHAPE = PropTypes.shape({ id: PropTypes.string.isRequired, type: PropTypes.oneOf([NODE_TYPE.ENTITY, NODE_TYPE.ATTRIBUTE]).isRequired, style: PropTypes.object, position: PropTypes.shape({ x: PropTypes.number.isRequired, y: PropTypes.number.isRequired }), draggable: PropTypes.bool.isRequired, - data: PropTypes.oneOfType([ENTITY_DATA_SHAPE, ATTRIBUTE_DATA_SHAPE]) + data: PropTypes.oneOfType([ENTITY_SHAPE, ATTRIBUTE_SHAPE]) }); -//Структура связи запроса -const RELATION_SHAPE = PropTypes.shape({ id: PropTypes.string.isRequired, source: PropTypes.string.isRequired, target: PropTypes.string.isRequired }); +//Структура связи диаграммы +const EDGE_SHAPE = PropTypes.shape({ id: PropTypes.string.isRequired, source: PropTypes.string.isRequired, target: PropTypes.string.isRequired }); //------------------------------------ //Вспомогательные функции и компоненты @@ -88,8 +88,8 @@ const isValidConnection = (connection, nodes, edges) => { //Диаграмма запроса const QueryDiagram = ({ - entities = [], - relations = [], + nodes = [], + edges = [], onEntityClick, onEntityAttrClick, onEntityPositionChange, @@ -100,10 +100,10 @@ const QueryDiagram = ({ onPaneClick }) => { //Собственное состояние - элементы - const [nodes, setNodes] = useState(entities); + const [nodesCurrent, setNodesCurrent] = useState(nodes); //Собственное состояние - связи - const [edges, setEdges] = useState(relations); + const [edgesCurrent, setEdgesCurrent] = useState(edges); //Собственное состояние - перемещённый элемент const [movedNode, setMovedNode] = useState(null); @@ -115,7 +115,7 @@ const QueryDiagram = ({ const tmpChanges = changes.reduce((prevChanges, curChanges) => { const tmp = { ...curChanges }; if (tmp.type == "select") { - const chEnt = entities.find(e => e.id === tmp.id); + const chEnt = nodes.find(n => n.id === tmp.id); if (chEnt && chEnt?.data?.parentEntity) { prevChanges.push({ ...curChanges, id: chEnt.data.parentEntity }); tmp.selected = false; @@ -125,7 +125,7 @@ const QueryDiagram = ({ return prevChanges; }, []); //Применим изменения в диаграмме - setNodes(nodesSnapshot => applyNodeChanges(tmpChanges, nodesSnapshot)); + setNodesCurrent(nodesSnapshot => applyNodeChanges(tmpChanges, nodesSnapshot)); //Если двигали сущность - запомним начало движения if (changes.length == 1 && changes[0].type == "position" && changes[0].dragging) setMovedNode({ id: changes[0].id, position: { ...changes[0].position } }); @@ -136,10 +136,10 @@ const QueryDiagram = ({ setMovedNode(null); } //Если удалили сущность - вызываем колбэк для удаления - if (changes[0].type == "remove" && entities.find(e => e.id == changes[0].id && e.type == NODE_TYPE.ENTITY) && onEntityRemove) + if (changes[0].type == "remove" && nodes.find(n => n.id == changes[0].id && n.type == NODE_TYPE.ENTITY) && onEntityRemove) onEntityRemove(changes[0].id); }, - [movedNode, entities, onEntityClick, onEntityPositionChange, onEntityRemove] + [movedNode, nodes, onEntityClick, onEntityPositionChange, onEntityRemove] ); //При выборе элемента диаграммы @@ -153,7 +153,7 @@ const QueryDiagram = ({ //При связывании элементов на диаграмме const handleConnect = connection => { - setEdges(state => addEdge({ ...connection, id: `${connection.source}-${connection.target}` }, state)); + setEdgesCurrent(state => addEdge({ ...connection, id: `${connection.source}-${connection.target}` }, state)); onRelationAdd && onRelationAdd(connection.source, connection.target); }; @@ -163,7 +163,7 @@ const QueryDiagram = ({ //При изменении связей на диаграмме const handleEdgesChange = useCallback( changes => { - setEdges(edgesSnapshot => applyEdgeChanges(changes, edgesSnapshot)); + setEdgesCurrent(edgesSnapshot => applyEdgeChanges(changes, edgesSnapshot)); if (changes.length == 1 && changes[0].type == "remove" && onRelationRemove) onRelationRemove(changes[0].id); }, [onRelationRemove] @@ -173,22 +173,22 @@ const QueryDiagram = ({ const handlePaneClick = () => onPaneClick && onPaneClick(); //Валидация связи - const validateConnection = connection => isValidConnection(connection, nodes, edges); + const validateConnection = connection => isValidConnection(connection, nodesCurrent, edgesCurrent); //Подсветка выбранной сущности //При изменении состава сущностей - useEffect(() => setNodes(entities), [entities]); + useEffect(() => setNodesCurrent(nodes), [nodes]); //При изменении состава связей - useEffect(() => setEdges(relations), [relations]); + useEffect(() => setEdgesCurrent(edges), [edges]); //Генерация содержимого return ( ({ borderBottom: isLast ? "none" : "1px solid #dee2e6" }) +}; + //------------------------------------ //Вспомогательные функции и компоненты //------------------------------------ //Конвертация серверного описания сущностей запроса в элементы диаграммы const serverEntity2QueryDiagramNodes = entity => { - const groupWidth = 250; - const nameColumnHeight = 50; - const columns = entity?.XATTRS?.XATTR || []; - const columnsCount = columns.length; - const groupHeight = nameColumnHeight + columnsCount * 50; - - const groupNode = { + //Ссылка на атрибуты + const attrs = entity.attrs || []; + //Количество атрибутов + const attrsCount = attrs.length; + //Высота группового элемента диаграммы + const entityNodeHeight = GROUP_NODE_ITEM_HEIGHT + attrsCount * GROUP_NODE_ITEM_HEIGHT; + //Элемент диаграммы для сущности (групповой элемент) + const entityNode = { id: entity.id, type: NODE_TYPE.ENTITY, data: { ...entity }, position: { x: entity.x, y: entity.y }, style: { - width: groupWidth, - height: groupHeight + width: NODE_WIDTH, + height: entityNodeHeight }, draggable: true }; - - const columnNodes = columns.map((column, index, columns) => { - const x = 1; - const y = 50 * (index + 1); - const width = groupWidth - 2; - const height = 50; - - const isLast = index === columns.length - 1; - const defaultColumnStyles = { - borderBottom: "1px solid #dee2e6" - }; - const lastColumnStyles = { - borderBottom: "none" - }; - const otherStyles = isLast ? lastColumnStyles : defaultColumnStyles; - - return { - id: column.id, - type: NODE_TYPE.ATTRIBUTE, - data: { - ...column, - included: false, - parentEntity: entity.id - }, - position: { x, y }, - parentId: entity.id, - extent: "parent", - style: { - width, - height, - ...otherStyles - }, - draggable: false, - selectable: true - }; - }); - - return [groupNode, ...columnNodes]; + //Элементы диаграммы для атрибутов сущности (состав группового элемента) + const attrsNodes = attrs.map((attr, index, attrs) => ({ + id: attr.id, + type: NODE_TYPE.ATTRIBUTE, + data: { ...attr }, + position: { x: 1, y: GROUP_NODE_ITEM_HEIGHT * (index + 1) }, + parentId: entity.id, + extent: "parent", + style: { + width: NODE_WIDTH - 2, + height: GROUP_NODE_ITEM_HEIGHT, + ...STYLES.ATTRIBUTE(index === attrs.length - 1) + }, + draggable: false, + selectable: true + })); + //Возвращаем элемент для сущности (групповой) и элементы для атрибутов (состав группового) + return [entityNode, ...attrsNodes]; }; //Конвертация серверного описания запроса в данные для редактора диаграмм const serverQueryData2QueryDiagram = (entities, relations) => { - const result = { entities: [], relations: [...relations] }; - entities.forEach(entity => { - const nodes = serverEntity2QueryDiagramNodes(entity); - result.entities = [...result.entities, ...nodes]; + //Инициализация результата + const result = { entities: [], relations: [], nodes: [], edges: [] }; + //Сущности (почти как есть на сервере, только массив XATTRS.XATTR перемещается в attrs) + result.entities = entities.map(e => { + const tmp = { ...e }; + tmp.attrs = tmp?.XATTRS?.XATTR?.map(a => ({ ...a })) || []; + delete tmp.XATTRS; + return tmp; }); + //Связи сущностей + result.relations = relations.map(r => ({ ...r })); + //Элементы для диаграммы + result.entities.forEach(entity => { + const nodes = serverEntity2QueryDiagramNodes(entity); + result.nodes = [...result.nodes, ...nodes]; + }); + //Грани для диаграммы + result.edges = relations.map(r => ({ ...r })); + //Вернем итоговый результат return result; }; diff --git a/app/panels/query_editor/query_editor.js b/app/panels/query_editor/query_editor.js index a1b0e3e..c95a83e 100644 --- a/app/panels/query_editor/query_editor.js +++ b/app/panels/query_editor/query_editor.js @@ -67,7 +67,7 @@ const QueryEditor = () => { const selectEntity = ent => { setRelation(null); const queryEnt = queryDiagram.entities.find(e => e.id === ent); - if (queryEnt) setEntity({ ...queryEnt.data }); + if (queryEnt) setEntity({ ...queryEnt }); }; //Выбор связи @@ -137,6 +137,7 @@ const QueryEditor = () => { setAppBarTitle(`Запрос [${name}]`); setQuery(rn); setOpenQueriesManager(false); + cleanupEnRlSelection(); }; //При изменении свойств запроса @@ -163,7 +164,8 @@ const QueryEditor = () => { {queryDiagram && ( { {toolBar} {query && ( - + )} diff --git a/db/PKG_P8PANELS_QE_BASE.pck b/db/PKG_P8PANELS_QE_BASE.pck index a57aa9c..7f2535c 100644 --- a/db/PKG_P8PANELS_QE_BASE.pck +++ b/db/PKG_P8PANELS_QE_BASE.pck @@ -23,6 +23,7 @@ create or replace package PKG_P8PANELS_QE_BASE as type TATTR is record ( SID PKG_STD.TSTRING, -- Уникальный идентификатор в запросе + SPARENT_ENTITY PKG_STD.TSTRING, -- Идентификатор родительской сущности SNAME PKG_STD.TSTRING, -- Имя STITLE PKG_STD.TSTRING, -- Заголовок NDATA_TYPE PKG_STD.TNUMBER, -- Тип данных (см. константы PKG_STD.DATA_TYPE_*) @@ -310,27 +311,28 @@ create or replace package body PKG_P8PANELS_QE_BASE as STAG_COND constant PKG_STD.TSTRING := 'XCOND'; -- Условия запроса /* Константы - Атрибуты для сериализации */ - SATTR_ID constant PKG_STD.TSTRING := 'id'; -- Идентификатор - SATTR_RN constant PKG_STD.TSTRING := 'rn'; -- Регистрационный номер - SATTR_CODE constant PKG_STD.TSTRING := 'code'; -- Код - SATTR_NAME constant PKG_STD.TSTRING := 'name'; -- Имя - SATTR_AUTHOR constant PKG_STD.TSTRING := 'author'; -- Автор - SATTR_CH_DATE constant PKG_STD.TSTRING := 'chDate'; -- Дата изменения - SATTR_READY constant PKG_STD.TSTRING := 'ready'; -- Готовность к использованию - SATTR_PBL constant PKG_STD.TSTRING := 'pbl'; -- Публичность - SATTR_MODIFY constant PKG_STD.TSTRING := 'modify'; -- Изменяемость - SATTR_TITLE constant PKG_STD.TSTRING := 'title'; -- Заголовок - SATTR_TYPE constant PKG_STD.TSTRING := 'type'; -- Тип - SATTR_DATA_TYPE constant PKG_STD.TSTRING := 'dataType'; -- Тип данных - SATTR_MANDATORY constant PKG_STD.TSTRING := 'mandatory'; -- Обязательность - SATTR_X constant PKG_STD.TSTRING := 'x'; -- Координата по X - SATTR_Y constant PKG_STD.TSTRING := 'y'; -- Координата по Y - SATTR_SOURCE constant PKG_STD.TSTRING := 'source'; -- Источник - SATTR_TARGET constant PKG_STD.TSTRING := 'target'; -- Приёмник - SATTR_AGG constant PKG_STD.TSTRING := 'agg'; -- Агрегатная функция - SATTR_ALIAS constant PKG_STD.TSTRING := 'alias'; -- Псевдоним - SATTR_USE constant PKG_STD.TSTRING := 'use'; -- Применение в запросе - SATTR_SHOW constant PKG_STD.TSTRING := 'show'; -- Отображение в запросе + SATTR_ID constant PKG_STD.TSTRING := 'id'; -- Идентификатор + SATTR_RN constant PKG_STD.TSTRING := 'rn'; -- Регистрационный номер + SATTR_CODE constant PKG_STD.TSTRING := 'code'; -- Код + SATTR_NAME constant PKG_STD.TSTRING := 'name'; -- Имя + SATTR_AUTHOR constant PKG_STD.TSTRING := 'author'; -- Автор + SATTR_CH_DATE constant PKG_STD.TSTRING := 'chDate'; -- Дата изменения + SATTR_READY constant PKG_STD.TSTRING := 'ready'; -- Готовность к использованию + SATTR_PBL constant PKG_STD.TSTRING := 'pbl'; -- Публичность + SATTR_MODIFY constant PKG_STD.TSTRING := 'modify'; -- Изменяемость + SATTR_TITLE constant PKG_STD.TSTRING := 'title'; -- Заголовок + SATTR_TYPE constant PKG_STD.TSTRING := 'type'; -- Тип + SATTR_DATA_TYPE constant PKG_STD.TSTRING := 'dataType'; -- Тип данных + SATTR_MANDATORY constant PKG_STD.TSTRING := 'mandatory'; -- Обязательность + SATTR_X constant PKG_STD.TSTRING := 'x'; -- Координата по X + SATTR_Y constant PKG_STD.TSTRING := 'y'; -- Координата по Y + SATTR_SOURCE constant PKG_STD.TSTRING := 'source'; -- Источник + SATTR_TARGET constant PKG_STD.TSTRING := 'target'; -- Приёмник + SATTR_AGG constant PKG_STD.TSTRING := 'agg'; -- Агрегатная функция + SATTR_ALIAS constant PKG_STD.TSTRING := 'alias'; -- Псевдоним + SATTR_USE constant PKG_STD.TSTRING := 'use'; -- Применение в запросе + SATTR_SHOW constant PKG_STD.TSTRING := 'show'; -- Отображение в запросе + SATTR_PARENT_ENTITY constant PKG_STD.TSTRING := 'parentEntity'; -- Идентификатор родительской сущности /* Константы - зарезервированные имена рагументов */ SARG_NAME_PAGE constant PKG_STD.TSTRING := 'NPAGE'; -- Номер страницы @@ -767,6 +769,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as PKG_XFAST.DOWN_NODE(SNAME => STAG_ATTR); /* Атрибут */ PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RATTR.SID); + PKG_XFAST.ATTR(SNAME => SATTR_PARENT_ENTITY, SVALUE => RATTR.SPARENT_ENTITY); PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RATTR.SNAME); PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RATTR.STITLE); PKG_XFAST.ATTR(SNAME => SATTR_DATA_TYPE, NVALUE => RATTR.NDATA_TYPE); @@ -798,14 +801,15 @@ create or replace package body PKG_P8PANELS_QE_BASE as XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XDOC); XNODE := PKG_XPATH.SINGLE_NODE(RPARENT_NODE => XROOT, SPATTERN => '/' || STAG_ATTR); /* Получаем значения */ - RRES.SID := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ID); - RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME); - RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE); - RRES.NDATA_TYPE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_DATA_TYPE); - RRES.SAGG := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_AGG); - RRES.SALIAS := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ALIAS); - RRES.NUSE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_USE); - RRES.NSHOW := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_SHOW); + RRES.SID := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ID); + RRES.SPARENT_ENTITY := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_PARENT_ENTITY); + RRES.SNAME := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_NAME); + RRES.STITLE := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_TITLE); + RRES.NDATA_TYPE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_DATA_TYPE); + RRES.SAGG := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_AGG); + RRES.SALIAS := PKG_XPATH.ATTRIBUTE(RNODE => XNODE, SNAME => SATTR_ALIAS); + RRES.NUSE := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_USE); + RRES.NSHOW := PKG_XPATH.ATTRIBUTE_NUM(RNODE => XNODE, SNAME => SATTR_SHOW); /* Освободим документ */ PKG_XPATH.FREE(RDOCUMENT => XDOC); exception @@ -908,6 +912,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as else /* Такого элемента нет - берем из представления */ RRES(RRES.LAST).SID := TATTR_ID_MAKE(SENT_ID => RENT.SID, SNAME => RVIEW_FIELD.COLUMN_NAME); + RRES(RRES.LAST).SPARENT_ENTITY := RENT.SID; RRES(RRES.LAST).SNAME := RVIEW_FIELD.COLUMN_NAME; RRES(RRES.LAST).STITLE := DMSCLVIEWSATTRS_TITLE_GET(SVIEW_NAME => RENT.SNAME, SATTR_NAME => RRES(RRES.LAST).SNAME);