ru.coon 2.8.65 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +319 -6
- package/package.json +1 -1
- package/src/Function.js +1 -1
- package/src/VisualLinker.js +610 -0
- package/src/VisualLinker.scss +219 -0
- package/src/app/Application.js +1 -0
- package/src/app/ApplicationSettings.js +49 -0
- package/src/app/Config.js +60 -0
- package/src/app/Router.js +37 -21
- package/src/app/viewPort/CVWrapperPanel.js +53 -0
- package/src/app/viewPort/CenterView.js +153 -46
- package/src/app/viewPort/CenterView.scss +151 -0
- package/src/app/viewPort/ComponentContextManager.js +24 -0
- package/src/app/viewPort/Main.js +4 -1
- package/src/app/viewPort/Routing.d2 +23 -0
- package/src/app/viewPort/TabHistory.js +81 -0
- package/src/common/ComponentFactory.js +167 -0
- package/src/common/button/DropdownContentButton.js +146 -0
- package/src/common/button/DropdownContentButton.scss +92 -0
- package/src/common/button/DropdownContentButtonController.js +60 -0
- package/src/common/component/editor/EditorFactory.js +3 -1
- package/src/common/component/formeditor/UiCustomFilterForm.scss +0 -1
- package/src/common/component/settings/modules/settingClosePageConfirmation.js +1 -3
- package/src/common/component/settings/modules/settingFavoritePanelShow.js +21 -0
- package/src/common/component/settings/modules/settingReportCalculator.js +22 -0
- package/src/common/component/settings/modules/settingShowNeedReloadMessage.js +1 -3
- package/src/common/component/settings/modules/settingwindowHolder.js +2 -3
- package/src/common/panel/WindowWrap.js +19 -11
- package/src/common/tree/BaseContextMenu.js +4 -3
- package/src/log.js +4 -5
- package/src/nav/AppNavCalcButton.js +23 -0
- package/src/nav/AppNavCalcButton.scss +6 -0
- package/src/nav/AppNavigationBar.js +1 -1
- package/src/nav/AppNavigationMenuController.js +2 -2
- package/src/nav/AppNavigationMenuMinimized.js +61 -0
- package/src/nav/AppNavigationPanel.js +115 -0
- package/src/nav/AppNavigationPanel.scss +178 -0
- package/src/nav/AppNavigationPanelController.js +386 -0
- package/src/nav/FavoriteCfg.js +18 -0
- package/src/nav/MenuEntity.js +23 -15
- package/src/nav/MenuFavoritesBar.js +100 -0
- package/src/nav/MenuFavoritesBar.scss +92 -0
- package/src/nav/editor/NavigateElementEditorView.js +2 -2
- package/src/nav/editor/workspace/NavWorkspaceListView.js +1 -4
- package/src/nav/menu/WorkspaceMenuViewMinimized.js +22 -0
- package/src/overrides/panel/TabPanel.js +36 -0
- package/src/overrides/panel/TabPanel.scss +65 -0
- package/src/report/component/ClearFiltersButton.js +4 -1
- package/src/report/component/CopyCellValueMenuItem.js +18 -0
- package/src/report/component/ReportFieldMap.js +274 -0
- package/src/report/component/ReportPanel.js +73 -44
- package/src/report/component/ReportPanel.scss +2 -2
- package/src/report/component/ReportTagLookup.js +59 -2
- package/src/report/component/calculator/ReportCalculatorController.js +266 -0
- package/src/report/component/calculator/ReportCalculatorField.js +47 -0
- package/src/report/component/calculator/ReportCalculatorHistoryPlugin.js +128 -0
- package/src/report/component/calculator/ReportCalculatorHistoryPlugin.scss +33 -0
- package/src/report/component/calculator/ReportCalculatorMenuItem.js +101 -0
- package/src/report/component/calculator/ReportCalculatorMenuItem.scss +41 -0
- package/src/report/component/calculator/ReportCalculatorPanel.js +363 -0
- package/src/report/component/calculator/ReportCalculatorPanel.scss +86 -0
- package/src/report/component/reportpanel/CopyReportPanelController.js +1 -1
- package/src/report/component/reportpanel/FilterPanel.js +13 -15
- package/src/report/component/reportpanel/FilterPanel.scss +5 -1
- package/src/report/component/reportpanel/FormFieldFocusPlugin.js +157 -0
- package/src/report/component/reportpanel/FormFieldFocusPlugin.scss +14 -0
- package/src/report/component/reportpanel/NorthPanel.js +16 -17
- package/src/report/component/reportpanel/NorthPanel.scss +1 -1
- package/src/report/component/reportpanel/ReportContextMenu.js +219 -0
- package/src/report/component/reportpanel/ReportGrid.js +1 -0
- package/src/report/component/reportpanel/ReportGrid.scss +4 -0
- package/src/report/component/settings/field/ReportFormFieldsGrid.js +2 -2
- package/src/report/component/settings/field/ReportFormFieldsGridController.js +2 -2
- package/src/report/component/settings/property/ReportPropertiesPanelController.js +1 -1
- package/src/report/component/settings/property/ReportPropertyDictionary.js +7 -0
- package/src/report/plugin/configPanel/AddFilterConditionPluginConfigPanel.js +34 -11
- package/src/report/plugin/configPanel/GridFiltersPluginConfigPanelFiltersGrid.js +3 -2
- package/src/report/plugin/configPanel/openCustomPanelButtonPlugin/OpenCustomPanelButtonPluginConfigPanel.js +274 -255
- package/src/report/plugin/configPanel/openCustomPanelButtonPlugin/OpenCustomPanelButtonPluginConfigPanel.scss +17 -0
- package/src/report/plugin/grid/AddFilterConditionPlugin.js +530 -87
- package/src/report/plugin/grid/CalculatorPlugin.js +90 -0
- package/src/report/plugin/grid/GridContextMenu.js +12 -10
- package/src/report/plugin/grid/GridRowCountPlugin.js +0 -1
- package/src/report/plugin/grid/GridToolbarButtonPlugin.js +11 -2
- package/src/report/plugin/grid/OpenCustomPanelButtonPlugin.js +126 -89
- package/src/report/plugin/grid/ReportCharacteristicBindPlugin.js +6 -4
- package/src/report/plugin/grid/ReportColumnStatePlugin.js +15 -3
- package/src/report/plugin/grid/SetSingleParameterPlugin.js +1 -1
- package/src/report/plugin/grid/ToolbarButtonPlugin.js +1 -1
- package/src/report/plugin/grid/addFilterConditionPlugin/AdvancedSearchPanel.js +55 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/AdvancedSearchPanelController.js +226 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterConfigMixin.js +138 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterFieldFactory.js +223 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterItem.js +164 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterItem.scss +21 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterMenu.js +29 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterWrapPanel.js +53 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/FilterWrapPanelController.js +57 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/InfoMenuItem.js +111 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/InfoMenuItem.scss +83 -0
- package/src/report/plugin/grid/addFilterConditionPlugin/SelectColumnPanel.js +102 -0
- package/src/report/selectionModels/MixedRowSelectionModel.js +36 -45
- package/src/report/toolbar/dropdown/ToolbarOverflowButton.js +16 -5
- package/src/report/toolbar/dropdown/ToolbarOverflowPanel.scss +26 -14
- package/src/report/toolbar/layout/ReportToolbarOverflow.js +5 -2
- package/src/ringBuffer.js +7 -3
- package/src/uielement/command/GetUIElementCommand.js +0 -1
- package/src/uielement/component/UiCPWrapper.js +26 -36
- package/src/uielement/component/UiCustomController.js +7 -0
- package/src/uielement/component/UiCustomPanel.js +46 -2
- package/src/uielement/component/settings/UiCustomPanelEditorController.js +35 -29
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginGrid.js +146 -33
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginGrid.scss +28 -0
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginGridController.js +366 -22
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginModel.js +1 -0
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginPanel.js +10 -4
- package/src/uielement/component/settings/plugin/UiCustomPanelPluginPanelController.js +28 -30
- package/src/uielement/plugin/UnifiedButtonToolbarPlugin.js +203 -22
- package/src/uielement/plugin/configPanel/ExecuteFunctionPluginConfigPanelFormEditor.js +4 -36
- package/src/uielement/plugin/configPanel/FireEventPluginConfigPanelFormEditor.js +5 -36
- package/src/uielement/plugin/configPanel/MethodChainPluginConfigPanelFormEditor.js +4 -36
- package/src/uielement/plugin/configPanel/OpenPanelPluginConfigPanelFormEditor.js +2 -38
- package/src/uielement/plugin/configPanel/PrintPdfPluginConfigPanelFormEditor.js +2 -35
- package/src/uielement/plugin/configPanel/UiCPPluginFormPanel.js +54 -0
- package/src/uielement/plugin/configPanel/UnifiedButtonToolbarPluginConfigPanelFormEditor.js +28 -18
- package/src/userSettings.js +1 -0
- package/src/util/ContextManager.js +109 -0
- package/src/util.js +96 -15
- package/src/version.js +1 -1
- package/src/app/viewPort/CenterViewController.js +0 -158
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Словарь уникальных значений полей репорта
|
|
3
|
+
*
|
|
4
|
+
* Условия сбора данных:
|
|
5
|
+
* Строковые данные:
|
|
6
|
+
* в словарь собираются уникальные значения поля, до тех пор пока не достигнут максимум (maxMapSize),
|
|
7
|
+
* после чего в зависимости от флага clearMapAfterOverflow он может быть очищен.
|
|
8
|
+
* Числовые данные и даты:
|
|
9
|
+
* в словарь собираются минимум и максимум данного поля.
|
|
10
|
+
*
|
|
11
|
+
* Определение истинного типа данных полей, с динамическим типом.
|
|
12
|
+
* Параметры поля с динамическим типом данных:
|
|
13
|
+
* dynamicTypeDetect - поле имеет динамический тип данных
|
|
14
|
+
* autoNormalizeSort - автоматическая нормализованная сортировка
|
|
15
|
+
*/
|
|
16
|
+
Ext.define('Coon.report.component.ReportFieldMap', {
|
|
17
|
+
fields: undefined,
|
|
18
|
+
extremumDataTypes: ['DATETIME', 'TIME', 'DATE', 'MONEY', 'DECIMAL', 'INTEGER'],
|
|
19
|
+
|
|
20
|
+
config: {
|
|
21
|
+
maxMapSize: 500,
|
|
22
|
+
clearMapAfterOverflow: false,
|
|
23
|
+
collectOnlyVisible: true,
|
|
24
|
+
},
|
|
25
|
+
maps: undefined,
|
|
26
|
+
dynamicTypeFields: undefined,
|
|
27
|
+
|
|
28
|
+
constructor(config) {
|
|
29
|
+
this.maps = new Map();
|
|
30
|
+
this.dynamicTypeFields = {};
|
|
31
|
+
Ext.apply(this, config);
|
|
32
|
+
if (Ext.isObject(this.rawConfig)) {
|
|
33
|
+
Ext.apply(this, Coon.util.createObjFromTpl(this.config, this.rawConfig));
|
|
34
|
+
}
|
|
35
|
+
this.configureMaps(this.fields);
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/** Создание конфига для словаря уникальных значений
|
|
39
|
+
* @param fields
|
|
40
|
+
*/
|
|
41
|
+
configureMaps(fields) {
|
|
42
|
+
fields.forEach((field) => {
|
|
43
|
+
const fieldProps = Coon.Function.convertAdvancedProperties(field.properties);
|
|
44
|
+
const fieldMapConfig = fieldProps.fieldMapConfig;
|
|
45
|
+
const dynamicTypeDetect = (fieldMapConfig && fieldMapConfig.dynamicTypeDetect) || false;
|
|
46
|
+
const autoNormalizeSort = (fieldMapConfig && fieldMapConfig.autoNormalizeSort) || false;
|
|
47
|
+
dynamicTypeDetect && this.prepareDataForDynamicTypeCheck(field.reportFieldCd, {autoNormalizeSort});
|
|
48
|
+
if (
|
|
49
|
+
(!fieldMapConfig || (fieldMapConfig && fieldMapConfig.enabled)) &&
|
|
50
|
+
(!this.collectOnlyVisible || (this.collectOnlyVisible && field.visibleSwitch))
|
|
51
|
+
) {
|
|
52
|
+
const isExtremum = this.extremumDataTypes.includes(field.reportFieldTypeLookup);
|
|
53
|
+
const config = {
|
|
54
|
+
maxMapSize: this.maxMapSize,
|
|
55
|
+
data: this.prepareData(isExtremum),
|
|
56
|
+
clearMapAfterOverflow: this.clearMapAfterOverflow,
|
|
57
|
+
isExtremum: isExtremum,
|
|
58
|
+
isFull: false,
|
|
59
|
+
isFalsyValues: false,
|
|
60
|
+
};
|
|
61
|
+
Ext.apply(config, fieldMapConfig);
|
|
62
|
+
this.maps.set(field.reportFieldCd, config);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Подготовка данных для анализа полей, все данные которого могут иметь динамический тип.
|
|
69
|
+
* @param originName - имя поля
|
|
70
|
+
*/
|
|
71
|
+
prepareDataForDynamicTypeCheck(originName, config) {
|
|
72
|
+
this.dynamicTypeFields[originName] = {
|
|
73
|
+
originName: originName,
|
|
74
|
+
convertedFieldName: this.getDynamicTypeFieldName(originName),
|
|
75
|
+
data: [],
|
|
76
|
+
allValuesOneType: true,
|
|
77
|
+
};
|
|
78
|
+
Ext.apply(this.dynamicTypeFields[originName], config);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {boolean} isExtremum
|
|
83
|
+
* @returns {Map|Set}
|
|
84
|
+
*/
|
|
85
|
+
prepareData(isExtremum) {
|
|
86
|
+
return isExtremum? new Map().set('min').set('max') : new Set();
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Сброс данных
|
|
91
|
+
*/
|
|
92
|
+
clearData() {
|
|
93
|
+
this.maps.forEach((map, fieldName) => {
|
|
94
|
+
map.data = this.prepareData(map.isExtremum);
|
|
95
|
+
map.isFull = false;
|
|
96
|
+
map.isFalsyValues = false;
|
|
97
|
+
map.dynamicTypeDetect && this.clearDynamicTypeField(fieldName);
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Сброс данных дублирующего поля, хранящее информацию об анализе данных оригинального поля,
|
|
103
|
+
* у которого все данные могут иметь динамический тип.
|
|
104
|
+
* @param fieldName - имя оригинального поля, чьи данные будут анализироваться.
|
|
105
|
+
*/
|
|
106
|
+
clearDynamicTypeField(fieldName) {
|
|
107
|
+
Object.keys(this.dynamicTypeFields).forEach((key) => {
|
|
108
|
+
this.dynamicTypeFields[key].data = [];
|
|
109
|
+
this.dynamicTypeFields[key].allValuesOneType = true;
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Функция convert для дополнительного поля. Функция заполняет уникальные значения и вычисляет мин и макс.
|
|
115
|
+
*/
|
|
116
|
+
getConvert() {
|
|
117
|
+
return function(_, record) {
|
|
118
|
+
this.maps.forEach((map, key) => {
|
|
119
|
+
const recordValue = record.get(key);
|
|
120
|
+
|
|
121
|
+
if (map.dynamicTypeDetect && this.dynamicTypeFields[key].allValuesOneType) {
|
|
122
|
+
this.checkValueDynamicType(recordValue, key, record);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if ((map.data.size === map.maxMapSize) || map.isFull) {
|
|
126
|
+
map.isFull = true;
|
|
127
|
+
if (map.clearMapAfterOverflow) {
|
|
128
|
+
map.data.clear();
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
if (recordValue === null || recordValue === undefined) {
|
|
132
|
+
map.isFalsyValues = true;
|
|
133
|
+
}
|
|
134
|
+
if (map.isExtremum) {
|
|
135
|
+
const min = map.data.get('min');
|
|
136
|
+
const max = map.data.get('max');
|
|
137
|
+
|
|
138
|
+
map.data.set('min', this.getExtremumValue(min, recordValue, Math.min));
|
|
139
|
+
map.data.set('max', this.getExtremumValue(max, recordValue, Math.max));
|
|
140
|
+
} else {
|
|
141
|
+
map.data.add(recordValue);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}.bind(this);
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Имя дублирующего поля, хранящего информацию об оригинальном поле, данные которого могут иметь динамический тип.
|
|
150
|
+
* @param originName - имя оригинального поля, чьи данные будут анализироваться.
|
|
151
|
+
* @returns {string} - имя дублирующего поля, с результатом анализа данных.
|
|
152
|
+
*/
|
|
153
|
+
getDynamicTypeFieldName(originName) {
|
|
154
|
+
return `_${originName}_convert`;
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Возвращает поля, данные которого могут иметь динамический тип.
|
|
159
|
+
* @returns {*}
|
|
160
|
+
*/
|
|
161
|
+
getDynamicTypeFields() {
|
|
162
|
+
return this.dynamicTypeFields;
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Возвращает функцию sorterFn, нормализующую сортировку.
|
|
167
|
+
* Если у всех данных поля одинаковый тип, для сравнения импользуются значения после конвертации,
|
|
168
|
+
* в противном случае используются оригинальные значения.
|
|
169
|
+
* @param originalFieldName
|
|
170
|
+
* @returns {any}
|
|
171
|
+
*/
|
|
172
|
+
getNormalizeSorterFn(originalFieldName) {
|
|
173
|
+
const convertedFieldName = this.dynamicTypeFields[originalFieldName].convertedFieldName;
|
|
174
|
+
return function(record1, record2) {
|
|
175
|
+
const allValuesOneType = this.dynamicTypeFields[originalFieldName].allValuesOneType;
|
|
176
|
+
const value1 = allValuesOneType ? record1.get(convertedFieldName) : record1.get(originalFieldName);
|
|
177
|
+
const value2 = allValuesOneType ? record2.get(convertedFieldName) : record2.get(originalFieldName);
|
|
178
|
+
return value1 > value2 ? 1 : (value1 === value2) ? 0 : -1;
|
|
179
|
+
}.bind(this);
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Проверка данных поля, все данные которого могут иметь динамический тип.
|
|
184
|
+
* @param recordValue - значение поля
|
|
185
|
+
* @param colName - имя оригинального поля
|
|
186
|
+
* @param record
|
|
187
|
+
*/
|
|
188
|
+
checkValueDynamicType(recordValue, colName, record) {
|
|
189
|
+
let convertedValue = recordValue;
|
|
190
|
+
if (typeof convertedValue === 'string') {
|
|
191
|
+
convertedValue = Ext.String.trim(convertedValue).replaceAll(',', '.');
|
|
192
|
+
convertedValue = Ext.Number.parseFloat(convertedValue);
|
|
193
|
+
if (convertedValue === null) {
|
|
194
|
+
this.dynamicTypeFields[colName].allValuesOneType = false;
|
|
195
|
+
} else {
|
|
196
|
+
this.dynamicTypeFields[colName].data.push(convertedValue || undefined);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const convertFieldName = this.getDynamicTypeFieldName(colName);
|
|
200
|
+
record.set(convertFieldName, (convertedValue || undefined));
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Map всех словарей уникальных значений.
|
|
205
|
+
* Ключами являются идентификаторы полей.
|
|
206
|
+
* Значения - объекты вида:
|
|
207
|
+
* {
|
|
208
|
+
* isExtremum - Если тип поля относится к extremumDataTypes
|
|
209
|
+
* Если тип поля относится к extremumDataTypes (isExtremum=true), то в data содержатся минимальное и максимальное значения данных поля
|
|
210
|
+
* ! Для данных типа Date содержится число (результат функции getTime)
|
|
211
|
+
* data: {
|
|
212
|
+
* min,
|
|
213
|
+
* max
|
|
214
|
+
* },
|
|
215
|
+
* Иначе data содержит Set из уникальных значений данных по колонке
|
|
216
|
+
* data: Set,
|
|
217
|
+
* clearMapAfterOverflow - флаг очистки в случае переполнения
|
|
218
|
+
* isFalsyValues признак присутствия в наборе значений поля null или undefined
|
|
219
|
+
* isFull - признак достижения maxMapSize - максимального количества сохраненных уникальных значений
|
|
220
|
+
* maxMapSize - максимального количества сохраненных уникальных значений
|
|
221
|
+
* }
|
|
222
|
+
* @returns {*} undefined | Map
|
|
223
|
+
*/
|
|
224
|
+
getMaps() {
|
|
225
|
+
return this.maps;
|
|
226
|
+
},
|
|
227
|
+
|
|
228
|
+
getColumnData(reportFieldCd) {
|
|
229
|
+
if (!reportFieldCd) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
const fieldData = this.getMaps().get(reportFieldCd);
|
|
233
|
+
if (!fieldData) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
return fieldData;
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
getExtremum(reportFieldCd) {
|
|
240
|
+
return this.getColumnData(reportFieldCd) && this.getColumnData(reportFieldCd).isExtremum && this.getColumnData(reportFieldCd).data;
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Валидация value для Math.min() или Math.max()
|
|
245
|
+
* @param value
|
|
246
|
+
* @returns {boolean}
|
|
247
|
+
*/
|
|
248
|
+
validateExtremumValue(value) {
|
|
249
|
+
return (!isNaN(Number(value)) && (value !== null));
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Получение минимального или максимального значения из двух
|
|
254
|
+
* @param a
|
|
255
|
+
* @param b
|
|
256
|
+
* @param mathFunc функция стравнения (Math.min | Math.max)
|
|
257
|
+
* @returns {undefined} одно из чисел или undefined если сравнение невозможно
|
|
258
|
+
*/
|
|
259
|
+
getExtremumValue(a, b, mathFunc) {
|
|
260
|
+
let result;
|
|
261
|
+
const validateA = this.validateExtremumValue(a);
|
|
262
|
+
const validateB = this.validateExtremumValue(b);
|
|
263
|
+
if (validateA && validateB) {
|
|
264
|
+
result = mathFunc.call(this, a, b);
|
|
265
|
+
} else if (validateB) {
|
|
266
|
+
result = b;
|
|
267
|
+
} else if (validateA) {
|
|
268
|
+
result = a;
|
|
269
|
+
} else {
|
|
270
|
+
result = undefined;
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
},
|
|
274
|
+
});
|
|
@@ -20,6 +20,7 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
20
20
|
'Coon.report.column.HintColumn',
|
|
21
21
|
'Coon.report.component.reportpanel.ReportGrid',
|
|
22
22
|
'Coon.report.component.reportpanel.FilterPanel',
|
|
23
|
+
'Coon.report.component.ReportFieldMap',
|
|
23
24
|
'Coon.report.model.*',
|
|
24
25
|
'Coon.report.model.CharacteristicBeanFields',
|
|
25
26
|
'Coon.report.plugin.form.EnterConfirmFormPlugin',
|
|
@@ -56,6 +57,7 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
56
57
|
enableAutoSize: true,
|
|
57
58
|
enableSummaryFeature: false,
|
|
58
59
|
enableGroupingFeature: false,
|
|
60
|
+
disableFieldMap: false,
|
|
59
61
|
toggleFilterPanel: false,
|
|
60
62
|
startCollapsed: false,
|
|
61
63
|
enableTextSelection: false,
|
|
@@ -76,6 +78,10 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
76
78
|
locals: {
|
|
77
79
|
plugins: new Map(),
|
|
78
80
|
},
|
|
81
|
+
/**
|
|
82
|
+
* @property {Coon.report.component.ReportFieldMap}
|
|
83
|
+
*/
|
|
84
|
+
serviceMap: undefined,
|
|
79
85
|
|
|
80
86
|
statics: {
|
|
81
87
|
getColumnsConfig: function(reportBeanFields, gridConfig) {
|
|
@@ -353,7 +359,13 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
353
359
|
|
|
354
360
|
this.layout = 'card';
|
|
355
361
|
|
|
356
|
-
this.
|
|
362
|
+
this._visibleFieldsMap = new Map();
|
|
363
|
+
|
|
364
|
+
// для совместимости со старым кодом.
|
|
365
|
+
this.dockedItems = [].concat(this.dockedItems || []);
|
|
366
|
+
|
|
367
|
+
this.dockedItems.push({
|
|
368
|
+
xtype: 'NorthPanel',
|
|
357
369
|
hideFilterPanel: this.hideFilterPanel,
|
|
358
370
|
hideFilterButtons: this.hideFilterButtons,
|
|
359
371
|
findButtonConfig: this.findButtonConfig || {},
|
|
@@ -365,7 +377,23 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
365
377
|
header: false,
|
|
366
378
|
});
|
|
367
379
|
|
|
368
|
-
this.
|
|
380
|
+
this.items = [
|
|
381
|
+
Ext.apply(this.centerProperties, {
|
|
382
|
+
xtype: 'panel',
|
|
383
|
+
itemId: 'centerPanel',
|
|
384
|
+
region: 'center',
|
|
385
|
+
minHeight: 100,
|
|
386
|
+
layout: 'fit',
|
|
387
|
+
cls: 'buttonsCenterFilterPanel',
|
|
388
|
+
})
|
|
389
|
+
];
|
|
390
|
+
|
|
391
|
+
this.callParent();
|
|
392
|
+
|
|
393
|
+
this.centerPanel = this.down('panel#centerPanel');
|
|
394
|
+
this.northPanel = this.down('NorthPanel');
|
|
395
|
+
this.filterContainer = this.northPanel.filterContainer;
|
|
396
|
+
|
|
369
397
|
this.northPanel.on('hide', function() {
|
|
370
398
|
this.query('[validate][isReportFilterField][hidden=false]').forEach((field) => {
|
|
371
399
|
this._visibleFieldsMap.set(field, field.hidden);
|
|
@@ -380,25 +408,6 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
380
408
|
});
|
|
381
409
|
}, this);
|
|
382
410
|
|
|
383
|
-
// для совместимости со старым кодом.
|
|
384
|
-
this.filterContainer = this.northPanel.filterContainer;
|
|
385
|
-
this.centerPanel = Ext.widget('panel', Ext.apply(this.centerProperties, {
|
|
386
|
-
region: 'center',
|
|
387
|
-
minHeight: 100,
|
|
388
|
-
layout: 'fit',
|
|
389
|
-
cls: 'buttonsCenterFilterPanel',
|
|
390
|
-
}));
|
|
391
|
-
this.dockedItems = [].concat(this.dockedItems || []);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
this.dockedItems.push(this.northPanel);
|
|
395
|
-
|
|
396
|
-
this.items = [
|
|
397
|
-
this.centerPanel
|
|
398
|
-
];
|
|
399
|
-
|
|
400
|
-
this.callParent();
|
|
401
|
-
|
|
402
411
|
if (this.reportID) {
|
|
403
412
|
this.reportId = this.reportID;
|
|
404
413
|
}
|
|
@@ -758,7 +767,8 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
758
767
|
return acc;
|
|
759
768
|
}, new Map());
|
|
760
769
|
|
|
761
|
-
|
|
770
|
+
const configProperties = Coon.Function.convertAdvancedProperties(reportFormBean[ns.$properties]);
|
|
771
|
+
Ext.merge(this, configProperties, {configProperties});
|
|
762
772
|
if (this.getToggleFilterPanel() && !this.hideFilterPanel) {
|
|
763
773
|
this.addTool({
|
|
764
774
|
iconCls: 'x-fa fa-eye-slash',
|
|
@@ -872,18 +882,34 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
872
882
|
}
|
|
873
883
|
}
|
|
874
884
|
},
|
|
885
|
+
|
|
886
|
+
mixPlugins(gridPlugins, basicPlugins) {
|
|
887
|
+
const plugins = [];
|
|
888
|
+
basicPlugins.forEach((plugin) => {
|
|
889
|
+
const found = gridPlugins.find((item) => plugin.ptype === item.ptype);
|
|
890
|
+
if (!found) {
|
|
891
|
+
plugins.push(plugin);
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
plugins.push(...gridPlugins);
|
|
895
|
+
return plugins;
|
|
896
|
+
},
|
|
897
|
+
|
|
875
898
|
createGrid: function(reportBean) {
|
|
876
899
|
const ns = Coon.report.model.ReportBeanFields;
|
|
877
|
-
const
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
this.getPluginConfigByType(
|
|
882
|
-
'GRID_PLUGIN',
|
|
883
|
-
'p',
|
|
884
|
-
reportBean[ns.$plugins]
|
|
885
|
-
)
|
|
900
|
+
const gridPlugins = this.getPluginConfigByType(
|
|
901
|
+
'GRID_PLUGIN',
|
|
902
|
+
'p',
|
|
903
|
+
reportBean[ns.$plugins]
|
|
886
904
|
);
|
|
905
|
+
|
|
906
|
+
const plugins = this.mixPlugins(gridPlugins, [
|
|
907
|
+
{ptype: 'GridContextPlugin'},
|
|
908
|
+
{ptype: 'GridContextMenu'},
|
|
909
|
+
{ptype: 'gridexporter'},
|
|
910
|
+
{ptype: 'AddFilterConditionPlugin'},
|
|
911
|
+
{ptype: 'CalculatorPlugin'}
|
|
912
|
+
]);
|
|
887
913
|
plugins.sort(this.raiseUpGroupButton);
|
|
888
914
|
|
|
889
915
|
const gridConfig = {
|
|
@@ -914,29 +940,32 @@ Ext.define('Coon.report.component.ReportPanel', {
|
|
|
914
940
|
|
|
915
941
|
const defaultGridConfig = Coon.report.component.ReportPanel.getColumnsConfig(reportBean[ns.$fields], gridConfig);
|
|
916
942
|
|
|
943
|
+
const fieldMapConfig = Coon.Function.convertAdvancedProperties(reportBean[ns.$properties]).fieldMapConfig || {};
|
|
944
|
+
if (!this.disableFieldMap && !fieldMapConfig.disabled) {
|
|
945
|
+
this.serviceMap = new Coon.report.component.ReportFieldMap({
|
|
946
|
+
maxMapSize: 100,
|
|
947
|
+
fields: reportBean.fields,
|
|
948
|
+
rawConfig: fieldMapConfig,
|
|
949
|
+
});
|
|
950
|
+
defaultGridConfig.fields.push({
|
|
951
|
+
convert: this.serviceMap.getConvert(),
|
|
952
|
+
});
|
|
953
|
+
this.northPanel.on('filterhandlerevent', this.serviceMap.clearData, this.serviceMap);
|
|
954
|
+
}
|
|
955
|
+
|
|
917
956
|
const widget = Ext.widget(
|
|
918
957
|
this.getIsTree() ? 'ReportTree' : 'ReportGrid',
|
|
919
958
|
Ext.apply(defaultGridConfig, this.gridProperties, {reportId: reportBean[ns.$reportId]})
|
|
920
959
|
);
|
|
921
960
|
|
|
922
961
|
if (widget.contextMenu) {
|
|
923
|
-
const copyButton =
|
|
924
|
-
|
|
925
|
-
handler: this.onCopyCellClick.bind(widget.contextMenu),
|
|
926
|
-
});
|
|
927
|
-
widget.contextMenu.add(copyButton);
|
|
928
|
-
widget.contextMenu.on('requestMenuItems', (params) => {
|
|
929
|
-
copyButton.setHidden(!params.td);
|
|
930
|
-
}, this);
|
|
962
|
+
const copyButton = Ext.widget('CopyCellValueMenuItem');
|
|
963
|
+
widget.contextMenu.addCopyButton(copyButton);
|
|
931
964
|
}
|
|
932
965
|
widget.on('buttonIsAdded', this.sortButtons, this);
|
|
933
966
|
return widget;
|
|
934
967
|
},
|
|
935
|
-
|
|
936
|
-
if (this.context && this.context.td) {
|
|
937
|
-
Coon.util.copyToClipboard(this.context.td.innerText);
|
|
938
|
-
}
|
|
939
|
-
},
|
|
968
|
+
|
|
940
969
|
sortButtons: function(params) {
|
|
941
970
|
if (params.bar.items.length === 1) {
|
|
942
971
|
return;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
background-color: #f6f6f6;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
/*.x-panel-header-default {
|
|
17
17
|
padding: 6px 16px;
|
|
18
18
|
background-color: #f6f6f6;
|
|
19
19
|
font-size: 17px;
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
color: #3e4752;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
}
|
|
24
|
+
}*/
|
|
25
25
|
|
|
26
26
|
.x-toolbar-default{
|
|
27
27
|
background-color: #ffffff;
|
|
@@ -43,10 +43,12 @@ Ext.define('Coon.report.component.ReportTagLookup', {
|
|
|
43
43
|
// Количество страниц
|
|
44
44
|
count: 0,
|
|
45
45
|
},
|
|
46
|
+
autoSortDynamicData: false,
|
|
46
47
|
},
|
|
47
48
|
|
|
48
49
|
initComponent: function() {
|
|
49
50
|
this.callParent();
|
|
51
|
+
this.autoSortDynamicData && this.prepareForNormalizedSortDynamicData();
|
|
50
52
|
// clear trigger
|
|
51
53
|
if (this.resettable) {
|
|
52
54
|
this.setTriggers(Object.assign({
|
|
@@ -70,6 +72,32 @@ Ext.define('Coon.report.component.ReportTagLookup', {
|
|
|
70
72
|
}
|
|
71
73
|
},
|
|
72
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Подготовка к автоматической нормализованнной сортировке данных,
|
|
77
|
+
* где displayField имеет динамический тип данных.
|
|
78
|
+
*/
|
|
79
|
+
prepareForNormalizedSortDynamicData() {
|
|
80
|
+
this.serviceMap = Ext.create('Coon.report.component.ReportFieldMap', {
|
|
81
|
+
fields: [
|
|
82
|
+
{
|
|
83
|
+
reportFieldCd: this.displayField,
|
|
84
|
+
properties: {
|
|
85
|
+
fieldMapConfig: {
|
|
86
|
+
enabled: true,
|
|
87
|
+
dynamicTypeDetect: true,
|
|
88
|
+
autoNormalizeSort: true,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
clearMapAfterOverflow: false,
|
|
94
|
+
collectOnlyVisible: false,
|
|
95
|
+
});
|
|
96
|
+
this.getStore().getModel().addFields([{
|
|
97
|
+
convert: this.serviceMap.getConvert(),
|
|
98
|
+
}]);
|
|
99
|
+
},
|
|
100
|
+
|
|
73
101
|
onClearInput: function() {
|
|
74
102
|
this.resetPageControl();
|
|
75
103
|
this.loadLocalPage(1);
|
|
@@ -218,18 +246,19 @@ Ext.define('Coon.report.component.ReportTagLookup', {
|
|
|
218
246
|
data = this.checkDangerousAmount(data);
|
|
219
247
|
|
|
220
248
|
// исходные данные для возможности фильтрации
|
|
221
|
-
this.initialData = data;
|
|
249
|
+
this.initialData = this.autoSortDynamicData ? this.getNormalizedSortedStoreData(data) : data;
|
|
222
250
|
this.isLoaded = true;
|
|
223
251
|
|
|
224
252
|
// размер данных больше одной страницы
|
|
225
253
|
if (data.length > this.pageControl.pageSize) {
|
|
226
254
|
this.isPagingEnabled = true;
|
|
227
|
-
this.unpagedData = data;
|
|
255
|
+
this.unpagedData = this.autoSortDynamicData ? this.getNormalizedSortedStoreData(data) : data;
|
|
228
256
|
this.configurePagination();
|
|
229
257
|
this.loadPage(1);
|
|
230
258
|
} else {
|
|
231
259
|
this.isPagingEnabled = false;
|
|
232
260
|
this.store.loadData(data);
|
|
261
|
+
this.autoSortDynamicData && this.setStoreNormalizeSort();
|
|
233
262
|
}
|
|
234
263
|
|
|
235
264
|
this.store.fireEvent('load', this.store, this.store.getRange(), true);
|
|
@@ -243,6 +272,34 @@ Ext.define('Coon.report.component.ReportTagLookup', {
|
|
|
243
272
|
}
|
|
244
273
|
},
|
|
245
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Возвращает данные Store после их нормализованной сортировки.
|
|
277
|
+
* @param data
|
|
278
|
+
* @returns {*}
|
|
279
|
+
*/
|
|
280
|
+
getNormalizedSortedStoreData(data) {
|
|
281
|
+
this.store.loadData(data);
|
|
282
|
+
this.setStoreNormalizeSort();
|
|
283
|
+
return this.store.getData().items.map((item) => item.getData());
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Применяет нормализованную сортировку к Store.
|
|
288
|
+
* Сортировка происходит относительно displayField, чьи данные могут иметь динамический тип.
|
|
289
|
+
*/
|
|
290
|
+
setStoreNormalizeSort() {
|
|
291
|
+
const normalizedSortFields = this.serviceMap.getDynamicTypeFields();
|
|
292
|
+
if (!Ext.Object.isEmpty(normalizedSortFields)) {
|
|
293
|
+
const autoSortField = Object.values(normalizedSortFields).find((value) => value.autoNormalizeSort);
|
|
294
|
+
if (!autoSortField) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
this.getStore().setSorters({
|
|
298
|
+
sorterFn: this.serviceMap.getNormalizeSorterFn(autoSortField.originName),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
|
|
246
303
|
setValue(value) {
|
|
247
304
|
Coon.log.debug('setValue', value);
|
|
248
305
|
if (value && Array.isArray(value) && value.length) {
|