Деталь
Технические вопросы
7.x

Деталь с реестром в виде иерархии

Добрый день, коллеги!
Подскажите, в продукте версии 7.8 есть деталь "Структура" , в разделе "Проекты".
Хочу сделать со своей кастомной деталью тоже самое, иерархию.

Пока что добавил вот такой код, к старнице детали:

define("UsrReportingDetailV2", ["ConfigurationEnums", "css!ProjectCSSModule"], function(enums) {
        return {
                entitySchemaName: "UsrReporting",
                attributes: {
                        /**
                         * Отвечает за загруженные уровни иерархии
                         */

                        "expandedElements": {
                                dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
                        },
                        /**
                         * Отвечает за список развернутых элементов,
                         * хранит массив уникальных идетификаторов записей
                         */

                        "expandHierarchyLevels": {
                                dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
                        },

                        /**
                         * Отвечает за хранение разворачиваемого элемента иерархии
                         */

                        "ExpandItemId": {
                                dataValueType: Terrasoft.DataValueType.GUID,
                                type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
                        }
                },
                methods: {
                        /**
                         * @overridden
                         */

                        disableGridSorting: Ext.emptyFn,

                        /**
                         * @overridden
                         */

                        sortColumn: Ext.emptyFn,

                        /**
                         * Обнавляет страницы редактирования проекта
                         * @overridden
                         * @private
                         */

                        initEditPages: function() {
                                this.callParent(arguments);
                                debugger;
                                var editPages = this.get("EditPages");
                                var workPage = editPages.collection.items[0];
                                workPage.set("Click", {"bindTo": "addToRootRecord"});
                                workPage.set("Caption", "Super");
                                workPage.set("Visible", true);
                                var childItemId = Terrasoft.utils.generateGUID();
                                var config = {
                                        "Id": childItemId,
                                        "Caption": "Sub",
                                        "Click": {"bindTo": "addToChildRecord"},
                                        "Enabled": {"bindTo": "isSingleSelected"},
                                        "Tag": childItemId,
                                        "SchemaName": "UsrReportingPageV2"
                                };
                                var addToChildMenuItem = this.getActionsMenuItem(config);
                                editPages.add(childItemId, addToChildMenuItem);
                        },
                        /**
                         * Открывает страницу Работы для добавления элемента дочернего элемента выбранной записи
                         * @protected
                         * @virtual
                         */

                        addToChildRecord: function() {
                                var scope = this;
                                var selectedItems = this.getSelectedItems();
                                this.set("ExpandItemId", selectedItems[0]);
                                this.replaceDefaultValue("UsrParent", selectedItems[0]);
                                var masterRecordId = this.get("MasterRecordId");
                                this.addRecord();
                        },
                        /**
                         * Устанавливает значение по умолчанию для параметра страницы редактировани новой записи
                         * @protected
                         * @virtual
                         * @param {String} key Имя параметра
                         * @param {*} value значение параметра
                         */

                        replaceDefaultValue: function(key, value) {
                                var defaultValues = this.get("DefaultValues");
                                var oldValue = defaultValues.filter(function(item) {
                                        return item.name === key;
                                });
                                if (Ext.isEmpty(oldValue)) {
                                        defaultValues.push({
                                                name: key,
                                                value: value
                                        });
                                } else {
                                        Terrasoft.each(oldValue, function(item) {
                                                item.value = value;
                                        });
                                }
                        },
                        /**
                         * Открывает страницу Проекта или Работы для добавления элемента в текущий уровань иерархии
                         * @protected
                         * @virtual
                         * @param {String} typeUId Уникальный идентификатор типа записи проекта
                         */

                        addToRootRecord: function(typeUId) {
                                var masterRecordId = this.Terrasoft.GUID_EMPTY;
                                this.replaceDefaultValue("UsrParent", masterRecordId);
                                this.addRecord();
                        },
                        /**
                         * Обработчик загрузки дочерних элементов. Осуществляет проверку загружености
                         * дочерних элеметов выбранной записи. Запускает загрузку нового уровня.
                         * @protected
                         * @virtual
                         * @param {String} primaryColumnValue Уникальный идентификатор записи
                         * @param {Boolean} isExpanded Признак того, разворачивает или сворачивает пользователь дочерние элеметы
                         * true - если разворачивает, false в обратном случае
                         */

                        onExpandHierarchyLevels: function(primaryColumnValue, isExpanded) {
                                if (!isExpanded || this.isItemExpanded(primaryColumnValue)) {
                                        return;
                                }
                                this.setExpandedItem(primaryColumnValue);
                                this.set("ExpandItemId", primaryColumnValue);
                                this.loadGridData();
                        },

                        /**
                         * Удаляет логику постраничности если загружаются дочерние объекты
                         * @protected
                         * @overridden
                         */

                        initQueryOptions: function() {
                                var parentItem = this.get("ExpandItemId");
                                if (!parentItem) {
                                        var isClearGridData = this.get("IsClearGridData");
                                        if (isClearGridData) {
                                                this.clearExpandHierarchyLevels();
                                        }
                                        this.callParent(arguments);
                                }
                        },
                        /**
                         * Удаляет логику постраничности если загружаются дочерние объекты
                         * @protected
                         * @overridden
                         */

                        initCanLoadMoreData: function() {
                                var parentItem = this.get("ExpandItemId");
                                if (!parentItem) {
                                        this.callParent(arguments);
                                }

                                this.get("expandedElements")["EB64FD9A-DF42-4275-8F1B-0A32ABB68AD5"] = {
                                        page: 0
                                };
                        },
                        /**
                         * Инициализирует параметры детали
                         * @protected
                         * @overridden
                         */

                        initData: function() {
                                this.callParent(arguments);
                                this.set("expandedElements", {});
                                this.set("expandHierarchyLevels", []);
                        },
                },
                diff: /**SCHEMA_DIFF*/[
                        {
                                "operation": "merge",
                                "name": "DataGrid",
                                "values": {
                                        "type": "listed",
                                        "hierarchical": true,
                                        "sortColumnDirection": {"bindTo": "disableGridSorting"},
                                        "hierarchicalColumnName": "ParentId",
                                        "updateExpandHierarchyLevels": {
                                                "bindTo": "onExpandHierarchyLevels"
                                        },
                                        expandHierarchyLevels: {
                                                "bindTo": "expandHierarchyLevels"
                                        },
                                        "listedConfig": {
                                                "name": "DataGridListedConfig",
                                                "items": [
                                                        {
                                                                "name": "UsrFileNameListedGridColumn",
                                                                "bindTo": "UsrFileName",
                                                                "position": {
                                                                        "column": 1,
                                                                        "colSpan": 12
                                                                }
                                                        },
                                                        {
                                                                "name": "UsrDisplayPortalListedGridColumn",
                                                                "bindTo": "UsrDisplayPortal",
                                                                "position": {
                                                                        "column": 21,
                                                                        "colSpan": 4
                                                                }
                                                        }
                                                ]
                                        },
                                        "tiledConfig": {
                                                "name": "DataGridTiledConfig",
                                                "grid": {
                                                        "columns": 24,
                                                        "rows": 3
                                                },
                                                "items": [
                                                        {
                                                                "name": "UsrFileNameTiledGridColumn",
                                                                "bindTo": "UsrFileName",
                                                                "position": {
                                                                        "row": 1,
                                                                        "column": 1,
                                                                        "colSpan": 12
                                                                }
                                                        },
                                                        {
                                                                "name": "UsrDisplayPortalTiledGridColumn",
                                                                "bindTo": "UsrDisplayPortal",
                                                                "position": {
                                                                        "row": 1,
                                                                        "column": 21,
                                                                        "colSpan": 4
                                                                }
                                                        }
                                                ]
                                        }
                                }
                        },
                        {
                                "operation": "insert",
                                "name": "UpButton",
                                "parentName": "Detail",
                                "propertyName": "tools",
                                "index": 0,
                                "values": {
                                        "itemType": Terrasoft.ViewItemType.BUTTON,
                                        "tag": -1,
                                        "imageConfig": {
                                                "bindTo": "Resources.Images.UpImage"
                                        },
                                        "click": {"bindTo": "changePosition"},
                                        "visible": {"bindTo": "getToolsVisible"},
                                        "enabled": {"bindTo": "canChangeSelectedItemPosition"},
                                        "hint": {"bindTo": "Resources.Strings.ChangePositionUpButtonCaption"}
                                }
                        },
                        {
                                "operation": "insert",
                                "name": "DownButton",
                                "parentName": "Detail",
                                "propertyName": "tools",
                                "index": 1,
                                "values": {
                                        "itemType": Terrasoft.ViewItemType.BUTTON,
                                        "tag": 1,
                                        "imageConfig": {
                                                "bindTo": "Resources.Images.DownImage"
                                        },
                                        "click": {"bindTo": "changePosition"},
                                        "visible": {"bindTo": "getToolsVisible"},
                                        "enabled": {"bindTo": "canChangeSelectedItemPosition"},
                                        "hint": {"bindTo": "Resources.Strings.ChangePositionDownButtonCaption"}
                                }
                        },
                        {
                                "operation": "remove",
                                "name": "ViewSortMenu",
                                "parentName": "ViewButton",
                                "propertyName": "menu"
                        }
                ]/**SCHEMA_DIFF*/
        };
});

Результат, кнопка добавить записи ("+") появилась новая, но с двумья кнопками, я старую убрал пока что. Отступ появился перед записей , там есть какое-то простарнство видимо для открывающегося списка, но плюсик там не появился. Я хочу сделать обычную деталь, и обычные дочерние записи, без всех проверок и сложной логики. На сколько я понимаю, она вообще не сложная, если сделать простую, главное корректно сохранять связь между родителями. Вопрос, где хранятся признаки что у записи есть дочерние, или нет, видимо я их где то не сечу, где не могу понять ...

Нравится

9 комментариев

Может кто то делал подобное

Или как и когда , правильно добавлять в эти объекты ('expandHierarchyLevels', 'expandedElements') Id дочерних записей ?

Роман, все вычисляется напрямую запросом к колонкам UsrPosition и UsrParent.

Пример кода рабочей пользовательской детали:

[javascript]
define("UsrSchema2Detail", ["XRMConstants", "terrasoft", "css!ProjectCSSModule"], function(XRMConstants, Terrasoft) {
return {
entitySchemaName: "UsrTestTest",
messages: {
"CardModuleEntityInfo": {
"mode": Terrasoft.MessageMode.PTP,
"direction": Terrasoft.MessageDirectionType.SUBSCRIBE
}
},
attributes: {
"expandedElements": {
dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},
"expandHierarchyLevels": {
dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},
"ExpandItemId": {
dataValueType: Terrasoft.DataValueType.GUID,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
}
},
details: /**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/,
diff: /**SCHEMA_DIFF*/[
{
"operation": "merge",
"name": "DataGrid",
"values": {
"type": "listed",
"hierarchical": true,
"sortColumnDirection": {"bindTo": "disableGridSorting"},
"hierarchicalColumnName": "ParentId",
"updateExpandHierarchyLevels": {
"bindTo": "onExpandHierarchyLevels"
},
expandHierarchyLevels: {
"bindTo": "expandHierarchyLevels"
}
}
},
{
"operation": "insert",
"name": "UpButton",
"parentName": "Detail",
"propertyName": "tools",
"index": 0,
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"tag": -1,
"imageConfig": {
"bindTo": "Resources.Images.UpImage"
},
"click": {"bindTo": "changePosition"},
"visible": {"bindTo": "getToolsVisible"},
"enabled": {"bindTo": "canChangeSelectedItemPosition"},
"hint": {"bindTo": "Resources.Strings.ChangePositionUpButtonCaption"}
}
},
{
"operation": "insert",
"name": "DownButton",
"parentName": "Detail",
"propertyName": "tools",
"index": 1,
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"tag": 1,
"imageConfig": {
"bindTo": "Resources.Images.DownImage"
},
"click": {"bindTo": "changePosition"},
"visible": {"bindTo": "getToolsVisible"},
"enabled": {"bindTo": "canChangeSelectedItemPosition"},
"hint": {"bindTo": "Resources.Strings.ChangePositionDownButtonCaption"}
}
},
{
"operation": "remove",
"name": "ViewSortMenu",
"parentName": "ViewButton",
"propertyName": "menu"
}
]/**SCHEMA_DIFF*/,
methods: {
disableGridSorting: Ext.emptyFn,
sortColumn: Ext.emptyFn,
init: function() {
this.callParent(arguments);
},
initData: function() {
this.callParent(arguments);
this.set("expandedElements", {});
this.set("expandHierarchyLevels", []);
},
onDeleted: function(result) {
this.callParent(arguments);
if (result.Success) {
this.reloadGridData();
}
},
clearExpandHierarchyLevels: function() {
this.set("expandedElements", {});
this.set("expandHierarchyLevels", []);
var grid = Ext.getCmp("ProjectDetailV2DataGridGrid");
if (grid) {
grid.expandHierarchyLevels = [];
}
},
removeExpandHierarchyLevel: function(itemId) {
var expandHierarchyLevels = this.get("expandHierarchyLevels");
this.set("expandHierarchyLevels", Terrasoft.without(expandHierarchyLevels, itemId));
var grid = Ext.getCmp("ProjectDetailV2DataGridGrid");
if (grid) {
grid.expandHierarchyLevels = Terrasoft.without(grid.expandHierarchyLevels, itemId);
}
},
addGridDataColumns: function(esq) {
this.callParent(arguments);
this.putParentColumn(esq);
this.putNestingColumn(esq);
this.putPositionColumn(esq);
},
putParentColumn: function(esq) {
var parentItem = this.get("ExpandItemId");
if (parentItem && !esq.columns.contains("ParentId")) {
esq.addColumn("UsrParent.Id", "ParentId");
}
},
putPositionColumn: function(esq) {
if (!esq.columns.contains("UsrPosition")) {
esq.addColumn("UsrPosition");
}
},
putNestingColumn: function(esq) {
var aggregationColumn = this.Ext.create("Terrasoft.AggregationQueryColumn", {
aggregationType: Terrasoft.AggregationType.COUNT,
columnPath: "[UsrTestTest:UsrParent].Id"
});
if (!esq.columns.contains("HasNesting")) {
esq.addColumn(aggregationColumn, "HasNesting");
}
},
getParents: function(primaryValues) {
var parentPrimaryValues = [];
var gridData = this.getGridData();
if (Ext.isEmpty(primaryValues)) {
return parentPrimaryValues;
}
primaryValues.forEach(function(primaryColumnValue) {
var project = gridData.get(primaryColumnValue);
var parentPrimaryColumnValue = project.get("ParentId");
if (parentPrimaryColumnValue) {
parentPrimaryValues.push(parentPrimaryColumnValue);
}
});
return parentPrimaryValues;
},
removeGridRecords: function(primaryColumnValues) {
var updateNestingCollection = this.getParents(primaryColumnValues);
this.callParent(arguments);
var gridData = this.getGridData();
Terrasoft.each(updateNestingCollection, function(projectId) {
var count = gridData.filterByFn(function(item) {
return item.get("ParentId") === projectId;
}, this).getCount();
if (gridData.contains(projectId)) {
this.removeExpandHierarchyLevel(projectId);
var parent = gridData.get(projectId);
parent.set("HasNesting", count);
}
}, this);
},
getExpandedItems: function() {
return this.get("expandedElements");
},
setExpandedItem: function(primaryColumnValue) {
(this.getExpandedItems()[primaryColumnValue]) = {"page": 0};
},
isItemExpanded: function(primaryColumnValue) {
return Boolean(this.getExpandedItems()[primaryColumnValue]);
},
addItemsToGridData: function(dataCollection, options) {
if (dataCollection.isEmpty()) {
return;
}
var firstItem = dataCollection.getByIndex(0);
var parentId = firstItem.get("ParentId");
if (parentId) {
options = {
mode: "child",
target: parentId
};
var gridData = this.getGridData();
var parentObj = gridData.get(parentId);
if (parentObj) {
parentObj.set("HasNesting", 1);
}
if (!this.isItemExpanded(parentId)) {
return;
}
} else {
this.set("LastRecord", dataCollection.getByIndex(dataCollection.getCount() - 1));
}
this.callParent([dataCollection, options]);
if (options && (options.mode === "child" || options.mode === "top")) {
var gridDataChild = this.getGridData();
var tempCollection = this.Ext.create("Terrasoft.Collection");
tempCollection.loadAll(gridDataChild);
this.sortCollection(tempCollection);
gridDataChild.clear();
gridDataChild.loadAll(tempCollection);
}
this.set("ExpandItemId", null);
},
onExpandHierarchyLevels: function(primaryColumnValue, isExpanded) {
if (!isExpanded || this.isItemExpanded(primaryColumnValue)) {
return;
}
this.setExpandedItem(primaryColumnValue);
this.set("ExpandItemId", primaryColumnValue);
this.loadGridData();
},
initQueryOptions: function() {
var parentItem = this.get("ExpandItemId");
if (!parentItem) {
var isClearGridData = this.get("IsClearGridData");
if (isClearGridData) {
this.clearExpandHierarchyLevels();
}
this.callParent(arguments);
}
},
initCanLoadMoreData: function() {
var parentItem = this.get("ExpandItemId");
if (!parentItem) {
this.callParent(arguments);
}
},
changeSorting: function() {
this.clearExpandHierarchyLevels();
this.callParent(arguments);
},
initQuerySorting: function(esq) {
var sortedColumn = esq.columns.get("UsrPosition");
sortedColumn.orderPosition = 0;
sortedColumn.orderDirection = Terrasoft.OrderDirection.ASC;
},
getFilters: function() {
var parentItem = this.get("ExpandItemId");
if (parentItem) {
var parentProjectFilterGroup = this.Terrasoft.createFilterGroup();
parentProjectFilterGroup.addItem(this.Terrasoft.createColumnFilterWithParameter(
this.Terrasoft.ComparisonType.EQUAL,
"UsrParent",
parentItem,
Terrasoft.DataValueType.GUID
));
return parentProjectFilterGroup;
} else {
var filters = this.callParent(arguments);
if (this.get("DetailColumnName") !== "UsrParent") {
var group = this.Terrasoft.createFilterGroup();
group.addItem(filters);
group.addItem(
Terrasoft.createColumnIsNullFilter(this.entitySchema.hierarchicalColumnName)
);
filters = group;
}
return filters;
}
},
isProjectsInRoot: function() {
return (this.get("DetailColumnName") !== "UsrParent");
},
isWorkInRoot: function() {
return !this.isProjectsInRoot();
},
initEditPages: function() {
this.callParent(arguments);
var editPages = this.get("EditPages");
var workPage = editPages.collection.items[0];
workPage.set("Click", {"bindTo": "addToRootRecord"});
workPage.set("Caption", "Add");
workPage.set("Visible", true);
var childItemId = editPages.collection.items[0].imstanceId;
var config = {
"Id": childItemId,
"Caption": "New",
"Click": {"bindTo": "addToChildRecord"},
"Enabled": {"bindTo": "isSingleSelected"},
"Tag": childItemId,
"SchemaName": "UsrTestTest1Page"
};
var addToChildMenuItem = this.getActionsMenuItem(config);
editPages.add(childItemId, addToChildMenuItem);
},
replaceDefaultValue: function(key, value) {
var defaultValues = this.get("DefaultValues");
var oldValue = defaultValues.filter(function(item) {
return item.name === key;
});
if (Ext.isEmpty(oldValue)) {
defaultValues.push({
name: key,
value: value
});
} else {
Terrasoft.each(oldValue, function(item) {
item.value = value;
});
}
},
getDetailInfo: function() {
var detailInfo = this.sandbox.publish("GetDetailInfo", null, [this.sandbox.id]) || {};
var defaultValues = this.get("DefaultValues");
detailInfo.defaultValues = defaultValues;
return detailInfo;
},
addToRootRecord: function(typeUId) {
var masterRecordId = (typeUId === XRMConstants.Project.EntryType.Project)
? this.Terrasoft.GUID_EMPTY
: this.get("MasterRecordId");
this.replaceDefaultValue("UsrParent", masterRecordId);
this.addRecord(typeUId);
},
addToChildRecord: function() {
var scope = this;
var selectedItems = this.getSelectedItems();
this.set("ExpandItemId", selectedItems[0]);
this.replaceDefaultValue("UsrParent", selectedItems[0]);
var masterRecordId = this.get("MasterRecordId");
if (masterRecordId !== null) {
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchemaName: "UsrTestTest"});
var filter = Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
"Id", masterRecordId, Terrasoft.DataValueType.GUID);
esq.filters.add("filter", filter);
esq.getEntityCollection(function(response) {
if (!response || !response.success) {
return;
}
var result = response.collection;
result.each(function(resultItem) {
scope.addRecord('c485c4e3-c0a1-4008-a8fe-054f167d5068');
});
}, this);
} else {
this.addRecord('c485c4e3-c0a1-4008-a8fe-054f167d5068');
}
},
canChangeSelectedItemPosition: function() {
var selectedItems = this.getSelectedItems();
return (!Ext.isEmpty(selectedItems) && (selectedItems.length <= 1));
},
changePosition: function() {
var shift = arguments[3];
var activeRow = this.getActiveRow();
var projectId = activeRow.get("Id");
this.updateProjectPosition(projectId, shift, this.onPositionChanged, this);
},
onPositionChanged: function(result) {
if (!result) {
return;
}
var activeRow = this.getActiveRow();
var parentId = activeRow.get("ParentId");
if (!parentId) {
parentId = this.get("MasterRecordId");
}
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchema: this.entitySchema});
esq.addColumn("UsrPosition");
var filter = Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
"UsrParent", parentId, Terrasoft.DataValueType.GUID);
esq.filters.add("filter", filter);
esq.getEntityCollection(function(response) {
if (!response || !response.success) {
return;
}
var gridData = this.getGridData();
var result = response.collection;
result.each(function(resultItem) {
var resultItemId = resultItem.get("Id");
var newPosition = resultItem.get("UsrPosition");
var gridRecord = gridData.get(resultItemId);
gridRecord.set("UsrPosition", newPosition);
});
var tempCollection = this.Ext.create("Terrasoft.Collection");
tempCollection.loadAll(gridData);
this.sortCollection(tempCollection);
gridData.clear();
gridData.loadAll(tempCollection);
}, this);
},
sortCollection: function(collection) {
collection.sortByFn(function(a, b) {
var positionA = a.get("UsrPosition");
var positionB = b.get("UsrPosition");
var q = positionA - positionB;
return q === 0 ? 0 : (q) / Math.abs(q);
});
},
}
};
});

[/javascript]

Доброго времени суток.
Недавно столкнулся с такой же задачкой. Вот примерный алгоритм:
1) Отрубить в системных настройках ненавистный префикс "Usr" (необяз. пункт).
2) Создать Объект (род. объект - Базовый объект), заполнить его нужными полями, сохранить, опубликовать.
3) Еще раз открыть объект на редактирование и создать там справочник Parent, род. объект - ставим ссылку на только что созданный объект. В свойствах объекта (справа кнопка списка-свойства-все) в графе "Родитель в иерархии" ставим поле Parent. Сохраняем, Публикуем.
4) Когда заполнять таблицу - решаете сами. Либо в схеме (через InsertQuery), либо через хранимку, либо через С# код. Без разницы (в крайнем случае - this.reloadGridData()). Главное у нужных записей заполнять поле Parent айдишником записи-родителя (тем самым формируя иерархию)
5) Теперь сама схема. Создаем схему. Род. объект - Базовая схема детали с реестром. Код приложу. Там надо поменять название схемы в define, ссылку на entitySchemaName (объект, который мы создали ранее) и ссылку на колонку объекта в putNestingColumn.
6) Все. Теперь добавляем деталь на страницу (из кода. в дизайнере не отобразится, т.к. не зарегистрирована). Если все сделано правильно и карточка загрузилась без ошибок, последний шаг - настроить вывод информации в гриде. Это можно сделать через ToolButton прямо в карточке.

[quote="Мотков Илья"]

Роман, все вычисляется напрямую запросом к колонкам UsrPosition и UsrParent.

Спасибо вам большое, вы мне очень помогли. Но теперь такая проблема, во первых не сохраняется ID записи, родителя, если это нормально, то я переделаю просто save на карточке и все. Во-вторых не открывается одновременно две записи с дочерними записями, пишет в консоли

 message: Uncaught Terrasoft.ItemNotFoundException: Item with key f5695207-a45d-4975-a484-92384cb438d1 Does not exist 

Виртуальный обьект и коллекцию, проверил, все корректно добавляет и удаляет. Уже несколько раз сравниваю с разделом "Проекты" , не могу найти разницу ...
Код схемы:
[javascript]
define("UsrReportingDetailV2", ["XRMConstants","ConfigurationGrid", "ConfigurationGridGenerator", "ProcessModuleUtilities", "ConfigurationGridUtilities", "ConfigurationEnums"],
function(XRMConstants, ProcessModuleUtilities, ConfigurationGridUtilities, enums) {
return {
entitySchemaName: "UsrReporting",
messages: {
"CardModuleEntityInfo": {
"mode": Terrasoft.MessageMode.PTP,
"direction": Terrasoft.MessageDirectionType.SUBSCRIBE
}
},
attributes: {
"isPortal": {
"dataValueType": Terrasoft.DataValueType.BOOLEAN,
"value": false
},
"isCRM": {
"dataValueType": Terrasoft.DataValueType.BOOLEAN,
"value": true
},
/**
* Отвечает за загруженные уровни иерархии
*/
"expandedElements": {
dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},
/**
* Отвечает за список развернутых элементов,
* хранит массив уникальных идетификаторов записей
*/
"expandHierarchyLevels": {
dataValueType: Terrasoft.DataValueType.CUSTOM_OBJECT,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
},
/**
* Отвечает за хранение разворачиваемого элемента иерархии
*/
"ExpandItemId": {
dataValueType: Terrasoft.DataValueType.GUID,
type: Terrasoft.ViewModelColumnType.VIRTUAL_COLUMN
}
},
mixins: {
ConfigurationGridUtilites: "Terrasoft.ConfigurationGridUtilities"
},
methods: {
disableGridSorting: Ext.emptyFn,
sortColumn: Ext.emptyFn,
init: function() {
this.callParent(arguments);
},
initData: function() {
this.callParent(arguments);
this.set("expandedElements", {});
this.set("expandHierarchyLevels", []);
},
onDeleted: function(result) {
this.callParent(arguments);
if (result.Success) {
this.reloadGridData();
}
},
clearExpandHierarchyLevels: function() {
this.set("expandedElements", {});
this.set("expandHierarchyLevels", []);
var grid = Ext.getCmp("ProjectDetailV2DataGridGrid");
if (grid) {
grid.expandHierarchyLevels = [];
}
},
removeExpandHierarchyLevel: function(itemId) {
var expandHierarchyLevels = this.get("expandHierarchyLevels");
this.set("expandHierarchyLevels", Terrasoft.without(expandHierarchyLevels, itemId));
var grid = Ext.getCmp("ProjectDetailV2DataGridGrid");
if (grid) {
grid.expandHierarchyLevels = Terrasoft.without(grid.expandHierarchyLevels, itemId);
}
},
addGridDataColumns: function(esq) {
this.callParent(arguments);
this.putParentColumn(esq);
this.putNestingColumn(esq);
this.putPositionColumn(esq);
},
putParentColumn: function(esq) {
var parentItem = this.get("ExpandItemId");
if (parentItem && !esq.columns.contains("ParentId")) {
esq.addColumn("UsrParent.Id", "ParentId");
}
},
putPositionColumn: function(esq) {
if (!esq.columns.contains("UsrPosition")) {
esq.addColumn("UsrPosition");
}
},
putNestingColumn: function(esq) {
var aggregationColumn = this.Ext.create("Terrasoft.AggregationQueryColumn", {
aggregationType: Terrasoft.AggregationType.COUNT,
columnPath: "[UsrReporting:UsrParent].Id"
});
if (!esq.columns.contains("HasNesting")) {
esq.addColumn(aggregationColumn, "HasNesting");
}
},
getParents: function(primaryValues) {
var parentPrimaryValues = [];
var gridData = this.getGridData();
if (Ext.isEmpty(primaryValues)) {
return parentPrimaryValues;
}
primaryValues.forEach(function(primaryColumnValue) {
var project = gridData.get(primaryColumnValue);
var parentPrimaryColumnValue = project.get("ParentId");
if (parentPrimaryColumnValue) {
parentPrimaryValues.push(parentPrimaryColumnValue);
}
});
return parentPrimaryValues;
},
removeGridRecords: function(primaryColumnValues) {
var updateNestingCollection = this.getParents(primaryColumnValues);
this.callParent(arguments);
var gridData = this.getGridData();
Terrasoft.each(updateNestingCollection, function(projectId) {
var count = gridData.filterByFn(function(item) {
return item.get("ParentId") === projectId;
}, this).getCount();
if (gridData.contains(projectId)) {
this.removeExpandHierarchyLevel(projectId);
var parent = gridData.get(projectId);
parent.set("HasNesting", count);
}
}, this);
},
getExpandedItems: function() {
return this.get("expandedElements");
},
setExpandedItem: function(primaryColumnValue) {
(this.getExpandedItems()[primaryColumnValue]) = {"page": 0};
},
isItemExpanded: function(primaryColumnValue) {
return Boolean(this.getExpandedItems()[primaryColumnValue]);
},
addItemsToGridData: function(dataCollection, options) {
if (dataCollection.isEmpty()) {
return;
}
var firstItem = dataCollection.getByIndex(0);
var parentId = firstItem.get("ParentId");
if (parentId) {
options = {
mode: "child",
target: parentId
};
var gridData = this.getGridData();
var parentObj = gridData.get(parentId);
if (parentObj) {
parentObj.set("HasNesting", 1);
}
if (!this.isItemExpanded(parentId)) {
return;
}
} else {
this.set("LastRecord", dataCollection.getByIndex(dataCollection.getCount() - 1));
}
this.callParent([dataCollection, options]);
if (options && (options.mode === "child" || options.mode === "top")) {
var gridDataChild = this.getGridData();
var tempCollection = this.Ext.create("Terrasoft.Collection");
tempCollection.loadAll(gridDataChild);
this.sortCollection(tempCollection);
gridDataChild.clear();
gridDataChild.loadAll(tempCollection);
}
this.set("ExpandItemId", null);
},
onExpandHierarchyLevels: function(primaryColumnValue, isExpanded) {
if (!isExpanded || this.isItemExpanded(primaryColumnValue)) {
return;
}
this.setExpandedItem(primaryColumnValue);
this.set("ExpandItemId", primaryColumnValue);
this.loadGridData();
},
initQueryOptions: function() {
var parentItem = this.get("ExpandItemId");
if (!parentItem) {
var isClearGridData = this.get("IsClearGridData");
if (isClearGridData) {
this.clearExpandHierarchyLevels();
}
this.callParent(arguments);
}
},
initCanLoadMoreData: function() {
var parentItem = this.get("ExpandItemId");
if (!parentItem) {
this.callParent(arguments);
}
},
changeSorting: function() {
this.clearExpandHierarchyLevels();
this.callParent(arguments);
},
initQuerySorting: function(esq) {
var sortedColumn = esq.columns.get("UsrPosition");
sortedColumn.orderPosition = 0;
sortedColumn.orderDirection = Terrasoft.OrderDirection.ASC;
},
getFilters: function() {
var parentItem = this.get("ExpandItemId");
if (parentItem) {
var parentProjectFilterGroup = this.Terrasoft.createFilterGroup();
parentProjectFilterGroup.addItem(this.Terrasoft.createColumnFilterWithParameter(
this.Terrasoft.ComparisonType.EQUAL, "UsrParent", parentItem, Terrasoft.DataValueType.GUID));
return parentProjectFilterGroup;
} else {
var filters = this.callParent(arguments);
if (this.get("DetailColumnName") !== "UsrParent") {
var group = this.Terrasoft.createFilterGroup();
group.addItem(filters);
group.addItem(Terrasoft.createColumnIsNullFilter(this.entitySchema.hierarchicalColumnName));
filters = group;
}
return filters;
}
},
isProjectsInRoot: function() {
return (this.get("DetailColumnName") !== "UsrParent");
},
isWorkInRoot: function() {
return !this.isProjectsInRoot();
},
initEditPages: function() {
this.callParent(arguments);
var editPages = this.get("EditPages");
var workPage = editPages.collection.items[0];
workPage.set("Click", {"bindTo": "addToRootRecord"});
workPage.set("Caption", "Add");
workPage.set("Visible", true);
var childItemId = editPages.collection.items[0].instanceId;
var config = {
"Id": childItemId,
"Caption": "New",
"Click": {"bindTo": "addToChildRecord"},
"Enabled": {"bindTo": "isSingleSelected"},
"Tag": childItemId,
"SchemaName": "UsrReportingPageV2"
};
var addToChildMenuItem = this.getActionsMenuItem(config);
editPages.add(childItemId, addToChildMenuItem);
},
replaceDefaultValue: function(key, value) {
var defaultValues = this.get("DefaultValues");
var oldValue = defaultValues.filter(function(item) {
return item.name === key;
});
if (Ext.isEmpty(oldValue)) {
defaultValues.push({
name: key,
value: value
});
} else {
Terrasoft.each(oldValue, function(item) {
item.value = value;
});
}
},
getDetailInfo: function() {
var detailInfo = this.sandbox.publish("GetDetailInfo", null, [this.sandbox.id]) || {};
var defaultValues = this.get("DefaultValues");
detailInfo.defaultValues = defaultValues;
return detailInfo;
},
addToRootRecord: function(typeUId) {
var masterRecordId = (typeUId === XRMConstants.Project.EntryType.Project)
? this.Terrasoft.GUID_EMPTY
: this.get("MasterRecordId");
this.replaceDefaultValue("UsrParent", masterRecordId);
this.addRecord(typeUId);
},
addToChildRecord: function() {
var scope = this;
var selectedItems = this.getSelectedItems();
this.set("ExpandItemId", selectedItems[0]);
this.replaceDefaultValue("UsrParent", selectedItems[0]);
var masterRecordId = this.get("MasterRecordId");
if (masterRecordId !== null) {
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchemaName: "UsrReporting"});
var filter = Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL, "UsrAccount", masterRecordId, Terrasoft.DataValueType.GUID);
esq.filters.add("filter", filter);
esq.getEntityCollection(function(response) {
if (!response || !response.success) {
return;
}
var result = response.collection;
result.each(function(resultItem) {
scope.addRecord('c485c4e3-c0a1-4008-a8fe-054f167d5068');
});
}, this);
} else {
this.addRecord('c485c4e3-c0a1-4008-a8fe-054f167d5068');
}
},
canChangeSelectedItemPosition: function() {
var selectedItems = this.getSelectedItems();
return (!Ext.isEmpty(selectedItems) && (selectedItems.length <= 1));
},
changePosition: function() {
var shift = arguments[3];
var activeRow = this.getActiveRow();
var projectId = activeRow.get("Id");
this.updateProjectPosition(projectId, shift, this.onPositionChanged, this);
},
onPositionChanged: function(result) {
if (!result) {
return;
}
var activeRow = this.getActiveRow();
var parentId = activeRow.get("ParentId");
if (!parentId) {
parentId = this.get("MasterRecordId");
}
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {rootSchema: this.entitySchema});
esq.addColumn("UsrPosition");
var filter = Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL, "UsrParent", parentId, Terrasoft.DataValueType.GUID);
esq.filters.add("filter", filter);
esq.getEntityCollection(function(response) {
if (!response || !response.success) {
return;
}
var gridData = this.getGridData();
var result = response.collection;
result.each(function(resultItem) {
var resultItemId = resultItem.get("Id");
var newPosition = resultItem.get("UsrPosition");
var gridRecord = gridData.get(resultItemId);
gridRecord.set("UsrPosition", newPosition);
});
var tempCollection = this.Ext.create("Terrasoft.Collection");
tempCollection.loadAll(gridData);
this.sortCollection(tempCollection);
gridData.clear();
gridData.loadAll(tempCollection);
}, this);
},
sortCollection: function(collection) {
collection.sortByFn(function(a, b) {
var positionA = a.get("UsrPosition");
var positionB = b.get("UsrPosition");
var q = positionA - positionB;
return q === 0 ? 0 : (q) / Math.abs(q);
});
},
},
diff: /**SCHEMA_DIFF*/[
{
"operation": "merge",
"name": "DataGrid",
"values": {
"type": "listed",
"hierarchical": true,
"sortColumnDirection": {"bindTo": "disableGridSorting"},
"hierarchicalColumnName": "ParentId",
"updateExpandHierarchyLevels": {
"bindTo": "onExpandHierarchyLevels"
},
expandHierarchyLevels: {
"bindTo": "expandHierarchyLevels"
}
}
},
{
"operation": "insert",
"name": "OpenReportButton",
"parentName": "Detail",
"propertyName": "tools",
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"click": {"bindTo": "openReport"},
"visible": {"bindTo": "isPortal"},
"enabled": {"bindTo": "isPortal"},
"caption": "Open"
},
"index": 0
},
{
"operation": "remove",
"name": "AddRecordButton",
"values": {
"visible": {"bindTo": "isCRM"}
}
},
{
"operation": "insert",
"name": "UpButton",
"parentName": "Detail",
"propertyName": "tools",
"index": 0,
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"tag": -1,
"imageConfig": {
"bindTo": "Resources.Images.UpImage"
},
"click": {"bindTo": "changePosition"},
"visible": {"bindTo": "getToolsVisible"},
"enabled": {"bindTo": "canChangeSelectedItemPosition"},
"hint": {"bindTo": "Resources.Strings.ChangePositionUpButtonCaption"}
}
},
{
"operation": "insert",
"name": "DownButton",
"parentName": "Detail",
"propertyName": "tools",
"index": 1,
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"tag": 1,
"imageConfig": {
"bindTo": "Resources.Images.DownImage"
},
"click": {"bindTo": "changePosition"},
"visible": {"bindTo": "getToolsVisible"},
"enabled": {"bindTo": "canChangeSelectedItemPosition"},
"hint": {"bindTo": "Resources.Strings.ChangePositionDownButtonCaption"}
}
}
]/**SCHEMA_DIFF*/
};
});
[/javascript]

Ошибка Uncaught Terrasoft.ItemNotFoundException: Item with key f5695207-a45d-4975-a484-92384cb438d1 Does not exist говорит, что не был найден какой-то элемент.

Уточните, пожалуйста, Вы не удаляли колонки из объекта?

Нет конечно, в обьект вообще не заходил после того как добавил колонки.
Ну и плюс смотрите, если я зайду на страницу, и открою первую запись, её дерево откроется, а у второй не открывается тогда дерерво. Но если обновить страницу, и открыть сначала вторую запись, то у неё дерево откроется, но тогда уже у первой не откроется. Ошибка та же самая в консоли ... То есть могу сейчас открыть только одну иерархию, и после обновления страницы другую, но только одну !

Попробуйте заместить метод addItemToGridData следующим образом:

[javascript]
addItemsToGridData: function(dataCollection, options) {
if (dataCollection.isEmpty()) {
return;
}
var firstItem = dataCollection.getByIndex(0);
var parentId = firstItem.get("ParentId");
if (parentId) {
options = {
mode: "child",
target: parentId
};
var gridData = this.getGridData();
var parentObj = gridData.contains(parentId) ? gridData.get(parentId) : undefined;
if (parentObj) {
parentObj.set("HasNesting", 1);
}
if (!this.isItemExpanded(parentId)) {
return;
}
} else {
this.set("LastRecord", dataCollection.getByIndex(dataCollection.getCount() - 1));
}
this.callParent([dataCollection, options]);
if (options && (options.mode === "child" || options.mode === "top")) {
var gridDataChild = this.getGridData();
var tempCollection = this.Ext.create("Terrasoft.Collection");
tempCollection.loadAll(gridDataChild);
this.sortCollection(tempCollection);
gridDataChild.clear();
gridDataChild.loadAll(tempCollection);
}
this.set("ExpandItemId", null);
},
[/javascript]

Коллеги, подскажите, все работает в принцепе хорошо, но после создания дочерней записи, если я добавляю метод onRender и в нем вызвать reloadGridData, то реестр просто пропадает , и после обновления страницы все гуд, а если не делать рендер и обновлять деталь, то доч. запись появляется просто в начале реестра не как дочерняя, и после обновления страницы, тоже все гуд ... Вот код, я уже даже не понимаю что нужно сделать ... Подскажите

[javascript]
define("UsrReportingPageV2", [],
function() {
return {
entitySchemaName: "UsrReporting",
messages: {},
attributes: {
"enabledForPortal": {
"dataValueType": Terrasoft.DataValueType.BOOLEAN,
"value": true
},
"visibleEnablePortalBool": {
"dataValueType": Terrasoft.DataValueType.BOOLEAN,
"value": true
}
},
details: /**SCHEMA_DETAILS*/{
Files: {
schemaName: "FileDetailV2",
entitySchemaName: "UsrReportingFile",
filter: {
masterColumn: "Id",
detailColumn: "UsrReporting"
}
}
}/**SCHEMA_DETAILS*/,

mixins: {},
methods: {
init: function () {
var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
"rootSchemaName": "SysAdminUnit"
});
esq.addColumn("Id");
esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL, "Id", Terrasoft.SysValue.CURRENT_USER.value));
esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
Terrasoft.ComparisonType.EQUAL, "[SysAdminUnitInRole:SysAdminUnit:Id].SysAdminUnitRoleId",
"720B771C-E7A7-4F31-9CFB-52CD21C3739F"));
esq.getEntityCollection(function(result) {
var isPortalUser = result.success && (result.collection.getCount() === 1);
this.set("enabledForPortal", !isPortalUser);
this.set("visibleEnablePortalBool", !isPortalUser);
if (isPortalUser) this.checkEnabled();
}, this);
this.callParent(arguments);
},
checkEnabled: function () {
if (this.get("UsrEnablePortal")) {

}
},
onSaved: function() {
if (Terrasoft.configuration.Storage.hasOwnProperty("newChildReport")) {
var accountID, parentID;
var defValues = this.get("DefaultValues");
for (var i = 0; i < defValues.length; i++) {
switch (defValues[i].name) {
case "UsrAccount":
accountID = defValues[i].value;
break;
case "UsrParent":
parentID = defValues[i].value;
break;
}
}
var update = Ext.create("Terrasoft.UpdateQuery", {
rootSchemaName: "UsrReporting"
});
update.setParameterValue("UsrAccount", accountID, Terrasoft.DataValueType.GUID);
update.setParameterValue("UsrParent", parentID, Terrasoft.DataValueType.GUID);
var filter = update.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Id" , this.get("Id"));
update.filters.add("FilterId", filter);

update.execute(function(result) {

});
delete Terrasoft.configuration.Storage.newChildReport;
}
this.callParent(arguments);
}
},
diff: /**SCHEMA_DIFF*/[
{
"operation": "insert",
"name": "UsrDisplayPortal",
"values": {
"layout": {
"colSpan": 12,
"rowSpan": 1,
"column": 12,
"row": 1,
"layoutName": "Header"
},
"enabled": {"bindTo": "enabledForPortal"},
"visible": {"bindTo": "visibleEnablePortalBool"},
"bindTo": "UsrDisplayPortal"
},
"parentName": "Header",
"propertyName": "items",
"index": 0
},
{
"operation": "insert",
"name": "UsrFileName",
"values": {
"layout": {
"colSpan": 12,
"rowSpan": 1,
"column": 0,
"row": 0,
"layoutName": "Header"
},
"bindTo": "UsrFileName",
"enabled": {"bindTo": "enabledForPortal"},
"visible": true
},
"parentName": "Header",
"propertyName": "items",
"index": 1
},
{
"operation": "insert",
"name": "HistoryTabContainer",
"values": {
"caption": {
"bindTo": "Resources.Strings.HistoryTabCaption"
},
"items": []
},
"parentName": "Tabs",
"propertyName": "tabs",
"index": 0
},
{
"operation": "insert",
"name": "Files",
"values": {
"itemType": 2
},
"parentName": "HistoryTabContainer",
"propertyName": "items",
"index": 0
},
{
"operation": "remove",
"name": "ESNTab"
},
{
"operation": "remove",
"name": "ESNFeedContainer"
},
{
"operation": "remove",
"name": "ESNFeed"
}
]/**SCHEMA_DIFF*/
};
});
[/javascript]

Показать все комментарии