mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-14 18:04:58 +03:00
feat(form-decompile,form-compile): группировка строк динамического списка (StructureItemGroup в ListSettings, кластер B)
Структура группировок дин-списка (`<dcsset:item StructureItemGroup>` → groupItems →
GroupItemField, вложенность через дочерний item) — переиспользована модель/реализация
из skd (Emit-GroupItems/Get-GroupFields), но плоская: группировка списка всегда
линейная цепочка одно-польных уровней над неявными деталями (без children/selection/
order/details — корпус подтверждает).
DSL — новый ключ `settings.grouping` (forgiving-синонимы `structure`/`группировка`):
- шорткат "A > B > C" (вложенные уровни, внешний→внутренний) или массив;
- элемент уровня — строка (имя поля) или объект {field, groupType?, periodAdditionType?,
periodAdditionBegin?, periodAdditionEnd?} для нестандартного поля (ключи = теги
исходника; periodAddition с авто-детектом ISO-дата/dcscor:Field).
Корпус 8.3.24 (29 форм/34 уровня): groupType Items 33 / Hierarchy 1, periodAddition нет.
Компилятор (ps1+py): Emit-ListGrouping + рекурсивная цепочка StructureItemGroup в
позиции после conditionalAppearance, до itemsViewMode. Оба пути — shape-дескриптор
(round-trip) и канонический (авторинг). Декомпилятор: Build-ListGrouping (линейная
цепочка; bail→$null на ветвлении/мультиполе/доп.содержимом = честный LOST, не порча);
Get-ListSettingsShape распознаёт `item`→`structure` (раньше → $null/канон-fallback,
из-за чего терялась группировка и додумывался itemsUserSettingID).
Выборка 17 форм с группировкой: match 0→10, TOTAL 75→25 (остаток — др. кластеры:
presentation xs:string, order-item use). Широкая (cat-a 102): match 82→84, TOTAL
280→256, ноль регрессий. Кейс dynamic-list-form (+grouping "Description > Code")
сертифицирован загрузкой в 1С. Регресс 43/43 (ps1+py).
Фикс по пути: PS-ловушка — одноэлементный массив разворачивался при return из
Parse-ListGrouping → строка → индексация давала char → пустой <field>. Unary comma ,@().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# form-compile v1.138 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.139 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$JsonPath,
|
||||
@@ -2006,6 +2006,67 @@ function Emit-ConditionalAppearance {
|
||||
X "$indent</$wrapTag>"
|
||||
}
|
||||
|
||||
# === Группировка строк динамического списка (DCS-структура ListSettings) ===
|
||||
# Линейная цепочка <dcsset:item StructureItemGroup> (каждый уровень = одно поле в groupItems;
|
||||
# вложенность — через дочерний <dcsset:item>). Зеркало skd Emit-GroupItems/Emit-StructureItem,
|
||||
# но плоская модель уровней (список всегда линеен, без selection/order/children).
|
||||
function Get-ListGroupingValue {
|
||||
param($st)
|
||||
foreach ($k in 'grouping','structure','группировка') {
|
||||
if ($st.PSObject.Properties[$k] -and $st.$k) { return $st.$k }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Parse-ListGrouping {
|
||||
param($grouping)
|
||||
# Шорткат "A > B > C" → массив имён; массив строк/объектов → как есть.
|
||||
# Unary comma: иначе PS разворачивает одноэлементный массив при return → строка → индексация даёт char.
|
||||
if (-not $grouping) { return ,@() }
|
||||
if ($grouping -is [string]) { return ,@($grouping -split '\s*>\s*' | Where-Object { "$_" -ne '' }) }
|
||||
return ,@($grouping)
|
||||
}
|
||||
|
||||
function Emit-GroupItemField {
|
||||
param($level, [string]$indent)
|
||||
if ($level -is [string]) {
|
||||
$field = $level; $gt = 'Items'; $pat = 'None'; $pab = '0001-01-01T00:00:00'; $pae = '0001-01-01T00:00:00'
|
||||
} else {
|
||||
$field = "$($level.field)"
|
||||
$gt = if ($level.groupType) { "$($level.groupType)" } else { 'Items' }
|
||||
$pat = if ($level.periodAdditionType) { "$($level.periodAdditionType)" } else { 'None' }
|
||||
$pab = if ($level.periodAdditionBegin) { "$($level.periodAdditionBegin)" } else { '0001-01-01T00:00:00' }
|
||||
$pae = if ($level.periodAdditionEnd) { "$($level.periodAdditionEnd)" } else { '0001-01-01T00:00:00' }
|
||||
}
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:GroupItemField`">"
|
||||
X "$indent`t<dcsset:field>$(Esc-Xml $field)</dcsset:field>"
|
||||
X "$indent`t<dcsset:groupType>$(Esc-Xml $gt)</dcsset:groupType>"
|
||||
X "$indent`t<dcsset:periodAdditionType>$(Esc-Xml $pat)</dcsset:periodAdditionType>"
|
||||
# Авто-детект: ISO-дата → xs:dateTime, иначе путь → dcscor:Field.
|
||||
$pabT = if ($pab -match '^\d{4}-\d{2}-\d{2}T') { 'xs:dateTime' } else { 'dcscor:Field' }
|
||||
$paeT = if ($pae -match '^\d{4}-\d{2}-\d{2}T') { 'xs:dateTime' } else { 'dcscor:Field' }
|
||||
X "$indent`t<dcsset:periodAdditionBegin xsi:type=`"$pabT`">$(Esc-Xml $pab)</dcsset:periodAdditionBegin>"
|
||||
X "$indent`t<dcsset:periodAdditionEnd xsi:type=`"$paeT`">$(Esc-Xml $pae)</dcsset:periodAdditionEnd>"
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
|
||||
function Emit-ListGroupingLevels {
|
||||
param($levels, [int]$i, [string]$indent)
|
||||
X "$indent<dcsset:item xsi:type=`"dcsset:StructureItemGroup`">"
|
||||
X "$indent`t<dcsset:groupItems>"
|
||||
Emit-GroupItemField $levels[$i] "$indent`t`t"
|
||||
X "$indent`t</dcsset:groupItems>"
|
||||
if ($i -lt $levels.Count - 1) { Emit-ListGroupingLevels $levels ($i + 1) "$indent`t" }
|
||||
X "$indent</dcsset:item>"
|
||||
}
|
||||
|
||||
function Emit-ListGrouping {
|
||||
param($grouping, [string]$indent)
|
||||
$levels = Parse-ListGrouping $grouping
|
||||
if ($levels.Count -eq 0) { return }
|
||||
Emit-ListGroupingLevels $levels 0 $indent
|
||||
}
|
||||
|
||||
# --- 5. Type emitter ---
|
||||
|
||||
$script:formTypeSynonyms = New-Object System.Collections.Hashtable
|
||||
@@ -5517,6 +5578,7 @@ function Emit-Attributes {
|
||||
'conditionalAppearance' { $bus = if ($meta -match 'u') { $script:CANON_CA_ID } else { $null }; Emit-ConditionalAppearance -items $st.conditionalAppearance -indent $lsi -blockViewMode $bvm -blockUserSettingID $bus }
|
||||
'itemsViewMode' { X "$lsi<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>" }
|
||||
'itemsUserSettingID' { X "$lsi<dcsset:itemsUserSettingID>$($script:CANON_ITEMS_ID)</dcsset:itemsUserSettingID>" }
|
||||
'structure' { Emit-ListGrouping (Get-ListGroupingValue $st) $lsi }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -5526,6 +5588,8 @@ function Emit-Attributes {
|
||||
if ($st.PSObject.Properties['dataParameters']) { Emit-DataParameters -items $st.dataParameters -indent $lsi }
|
||||
Emit-Order -items $st.order -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_ORDER_ID
|
||||
Emit-ConditionalAppearance -items $st.conditionalAppearance -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_CA_ID
|
||||
# Группировка строк списка (авторинг без round-trip дескриптора) — после CA, до itemsViewMode
|
||||
Emit-ListGrouping (Get-ListGroupingValue $st) $lsi
|
||||
X "$lsi<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>"
|
||||
X "$lsi<dcsset:itemsUserSettingID>$($script:CANON_ITEMS_ID)</dcsset:itemsUserSettingID>"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# form-compile v1.138 — Compile 1C managed form from JSON or object metadata
|
||||
# form-compile v1.139 — Compile 1C managed form from JSON or object metadata
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import copy
|
||||
@@ -1689,6 +1689,64 @@ def emit_appearance_value(lines, key, val, indent):
|
||||
lines.append(f'{indent}</dcscor:item>')
|
||||
|
||||
|
||||
# === Группировка строк динамического списка (DCS-структура ListSettings) ===
|
||||
# Линейная цепочка <dcsset:item StructureItemGroup> (каждый уровень = одно поле в groupItems;
|
||||
# вложенность — через дочерний <dcsset:item>). Плоская модель уровней (список всегда линеен).
|
||||
def get_list_grouping_value(s):
|
||||
for k in ('grouping', 'structure', 'группировка'):
|
||||
if s.get(k):
|
||||
return s[k]
|
||||
return None
|
||||
|
||||
|
||||
def parse_list_grouping(grouping):
|
||||
# Шорткат "A > B > C" → массив имён; массив строк/объектов → как есть.
|
||||
if not grouping:
|
||||
return []
|
||||
if isinstance(grouping, str):
|
||||
return [p.strip() for p in re.split(r'\s*>\s*', grouping) if p.strip()]
|
||||
return list(grouping)
|
||||
|
||||
|
||||
def emit_group_item_field(lines, level, indent):
|
||||
if isinstance(level, str):
|
||||
field, gt, pat = level, 'Items', 'None'
|
||||
pab = pae = '0001-01-01T00:00:00'
|
||||
else:
|
||||
field = str(level.get('field', ''))
|
||||
gt = str(level.get('groupType') or 'Items')
|
||||
pat = str(level.get('periodAdditionType') or 'None')
|
||||
pab = str(level.get('periodAdditionBegin') or '0001-01-01T00:00:00')
|
||||
pae = str(level.get('periodAdditionEnd') or '0001-01-01T00:00:00')
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:GroupItemField">')
|
||||
lines.append(f'{indent}\t<dcsset:field>{esc_xml(field)}</dcsset:field>')
|
||||
lines.append(f'{indent}\t<dcsset:groupType>{esc_xml(gt)}</dcsset:groupType>')
|
||||
lines.append(f'{indent}\t<dcsset:periodAdditionType>{esc_xml(pat)}</dcsset:periodAdditionType>')
|
||||
# Авто-детект: ISO-дата → xs:dateTime, иначе путь → dcscor:Field.
|
||||
pab_t = 'xs:dateTime' if re.match(r'^\d{4}-\d{2}-\d{2}T', pab) else 'dcscor:Field'
|
||||
pae_t = 'xs:dateTime' if re.match(r'^\d{4}-\d{2}-\d{2}T', pae) else 'dcscor:Field'
|
||||
lines.append(f'{indent}\t<dcsset:periodAdditionBegin xsi:type="{pab_t}">{esc_xml(pab)}</dcsset:periodAdditionBegin>')
|
||||
lines.append(f'{indent}\t<dcsset:periodAdditionEnd xsi:type="{pae_t}">{esc_xml(pae)}</dcsset:periodAdditionEnd>')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
|
||||
def emit_list_grouping_levels(lines, levels, i, indent):
|
||||
lines.append(f'{indent}<dcsset:item xsi:type="dcsset:StructureItemGroup">')
|
||||
lines.append(f'{indent}\t<dcsset:groupItems>')
|
||||
emit_group_item_field(lines, levels[i], f'{indent}\t\t')
|
||||
lines.append(f'{indent}\t</dcsset:groupItems>')
|
||||
if i < len(levels) - 1:
|
||||
emit_list_grouping_levels(lines, levels, i + 1, f'{indent}\t')
|
||||
lines.append(f'{indent}</dcsset:item>')
|
||||
|
||||
|
||||
def emit_list_grouping(lines, grouping, indent):
|
||||
levels = parse_list_grouping(grouping)
|
||||
if not levels:
|
||||
return
|
||||
emit_list_grouping_levels(lines, levels, 0, indent)
|
||||
|
||||
|
||||
def emit_conditional_appearance(lines, items, indent, block_view_mode=None, block_user_setting_id=None, wrap_tag='dcsset:conditionalAppearance'):
|
||||
has_items = bool(items) and len(items) > 0
|
||||
has_block_meta = (block_view_mode is not None) or (block_user_setting_id is not None)
|
||||
@@ -5262,6 +5320,8 @@ def emit_attributes(lines, attrs, indent, conditional_appearance=None):
|
||||
lines.append(f'{lsi}<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>')
|
||||
elif tag == 'itemsUserSettingID':
|
||||
lines.append(f'{lsi}<dcsset:itemsUserSettingID>{CANON_ITEMS_ID}</dcsset:itemsUserSettingID>')
|
||||
elif tag == 'structure':
|
||||
emit_list_grouping(lines, get_list_grouping_value(s), lsi)
|
||||
else:
|
||||
# Полный каноничный скелет (умолчание, ~93% форм) — без изменений.
|
||||
emit_filter(lines, s.get('filter'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_FILTER_ID)
|
||||
@@ -5270,6 +5330,8 @@ def emit_attributes(lines, attrs, indent, conditional_appearance=None):
|
||||
emit_data_parameters(lines, s.get('dataParameters'), lsi)
|
||||
emit_order(lines, s.get('order'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_ORDER_ID)
|
||||
emit_conditional_appearance(lines, s.get('conditionalAppearance'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_CA_ID)
|
||||
# Группировка строк списка (авторинг без round-trip дескриптора) — после CA, до itemsViewMode
|
||||
emit_list_grouping(lines, get_list_grouping_value(s), lsi)
|
||||
lines.append(f'{lsi}<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>')
|
||||
lines.append(f'{lsi}<dcsset:itemsUserSettingID>{CANON_ITEMS_ID}</dcsset:itemsUserSettingID>')
|
||||
if len(lines) - 1 == ls_open_idx:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# form-decompile v0.111 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# form-decompile v0.112 — Decompile 1C managed Form.xml to JSON DSL (draft)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
|
||||
param(
|
||||
@@ -118,7 +118,7 @@ function Test-ListSettingsHasContent {
|
||||
# полному каноничному скелету (компилятор регенерит сам) ИЛИ содержит неподдержанные top-level элементы
|
||||
# (item/dataParameters/viewMode/userSettingID/… → fallback на канон). Иначе — дескриптор для компилятора.
|
||||
function Get-ListSettingsShape {
|
||||
param($lsNode)
|
||||
param($lsNode, [bool]$hasGrouping = $false)
|
||||
if (-not $lsNode) { return $null }
|
||||
$shape = [ordered]@{}
|
||||
foreach ($child in $lsNode.ChildNodes) {
|
||||
@@ -130,7 +130,8 @@ function Get-ListSettingsShape {
|
||||
$shape[$tag] = "$(if ($hasVM) {'v'})$(if ($hasUS) {'u'})"
|
||||
} elseif ($tag -eq 'itemsViewMode') { $shape['itemsViewMode'] = $true }
|
||||
elseif ($tag -eq 'itemsUserSettingID') { $shape['itemsUserSettingID'] = $true }
|
||||
else { return $null } # item/dataParameters/itemsUserSettingPresentation/… → канон-fallback
|
||||
elseif ($tag -eq 'item') { if ($hasGrouping) { $shape['structure'] = $true } else { return $null } }
|
||||
else { return $null } # dataParameters/itemsUserSettingPresentation/… → канон-fallback
|
||||
}
|
||||
# Полный каноничный скелет → опускаем (компилятор регенерит)
|
||||
if ($shape.Count -eq 5 -and $shape['filter'] -eq 'vu' -and $shape['order'] -eq 'vu' -and `
|
||||
@@ -138,6 +139,60 @@ function Get-ListSettingsShape {
|
||||
return $shape
|
||||
}
|
||||
|
||||
# Группировка строк динамического списка: цепочка <dcsset:item StructureItemGroup> (каждый уровень =
|
||||
# один groupItems-field; вложенность через дочерний <dcsset:item>). Возвращает ПЛОСКИЙ массив уровней
|
||||
# (string для дефолтного поля; объект {field,groupType?,periodAdditionType?,periodAdditionBegin?,periodAdditionEnd?}
|
||||
# для нестандартного) ИЛИ $null, если структура не «чистая линейная цепочка одно-польных уровней»
|
||||
# (ветвление/мультиполе/доп.содержимое) → честный fallback на канон (LOST), а не тихая порча.
|
||||
function Build-GroupLevel {
|
||||
param($fn)
|
||||
$field = Get-Child $fn 'field'
|
||||
$gt = Get-Child $fn 'groupType'
|
||||
$pat = Get-Child $fn 'periodAdditionType'
|
||||
$pabN = $fn.SelectSingleNode("dcsset:periodAdditionBegin", $ns)
|
||||
$paeN = $fn.SelectSingleNode("dcsset:periodAdditionEnd", $ns)
|
||||
$pab = $null; $pae = $null
|
||||
if ($pabN) { $pt = $pabN.GetAttribute("type", $NS_XSI); $pv = $pabN.InnerText; if (($pt -match 'Field$') -or ($pv -and $pv -ne '0001-01-01T00:00:00')) { $pab = $pv } }
|
||||
if ($paeN) { $pt = $paeN.GetAttribute("type", $NS_XSI); $pv = $paeN.InnerText; if (($pt -match 'Field$') -or ($pv -and $pv -ne '0001-01-01T00:00:00')) { $pae = $pv } }
|
||||
$isDefault = ((-not $gt) -or $gt -eq 'Items') -and ((-not $pat) -or $pat -eq 'None') -and (-not $pab) -and (-not $pae)
|
||||
if ($isDefault) { return $field }
|
||||
$o = [ordered]@{ field = $field }
|
||||
if ($gt -and $gt -ne 'Items') { $o['groupType'] = $gt }
|
||||
if ($pat -and $pat -ne 'None') { $o['periodAdditionType'] = $pat }
|
||||
if ($pab) { $o['periodAdditionBegin'] = $pab }
|
||||
if ($pae) { $o['periodAdditionEnd'] = $pae }
|
||||
return $o
|
||||
}
|
||||
|
||||
function Build-ListGrouping {
|
||||
param($itemNode)
|
||||
$levels = New-Object System.Collections.ArrayList
|
||||
$cur = $itemNode
|
||||
while ($cur) {
|
||||
if (($cur.GetAttribute("type", $NS_XSI)) -notmatch 'StructureItemGroup$') { return $null }
|
||||
$gi = $null; $nested = @()
|
||||
foreach ($ch in $cur.ChildNodes) {
|
||||
if ($ch.NodeType -ne [System.Xml.XmlNodeType]::Element) { continue }
|
||||
switch ($ch.LocalName) {
|
||||
'groupItems' { if ($gi) { return $null }; $gi = $ch }
|
||||
'item' { $nested += $ch }
|
||||
default { return $null } # use/name/filter/order/… — здесь не поддержано
|
||||
}
|
||||
}
|
||||
if (-not $gi) { return $null }
|
||||
$fieldItems = @($gi.SelectNodes("dcsset:item", $ns))
|
||||
if ($fieldItems.Count -ne 1) { return $null }
|
||||
$fn = $fieldItems[0]
|
||||
if (($fn.GetAttribute("type", $NS_XSI)) -notmatch 'GroupItemField$') { return $null }
|
||||
[void]$levels.Add((Build-GroupLevel $fn))
|
||||
if ($nested.Count -eq 0) { break }
|
||||
if ($nested.Count -gt 1) { return $null } # ветвление — не линейно
|
||||
$cur = $nested[0]
|
||||
}
|
||||
if ($levels.Count -eq 0) { return $null }
|
||||
return ,@($levels)
|
||||
}
|
||||
|
||||
# --- 1b. Ring-3 scan: конструкции вне зоны поддержки (draft list) ---
|
||||
function Fail-Ring3 {
|
||||
param([string]$kind, [string]$loc)
|
||||
@@ -2562,7 +2617,12 @@ if ($attrsNode) {
|
||||
}
|
||||
# Форма скелета ListSettings: дескриптор только для НЕ-каноничных форм (частичные/минимальные).
|
||||
# Канон → $null (компилятор регенерит полный скелет, как раньше).
|
||||
$lsShape = Get-ListSettingsShape $lsNode
|
||||
# Группировка строк списка: прямой <dcsset:item> ListSettings (не в filter/order/CA).
|
||||
$grpItemNode = $lsNode.SelectSingleNode("dcsset:item", $ns)
|
||||
$grouping = $null
|
||||
if ($grpItemNode) { $grouping = Build-ListGrouping $grpItemNode }
|
||||
if ($null -ne $grouping) { $so['grouping'] = $grouping }
|
||||
$lsShape = Get-ListSettingsShape $lsNode ($null -ne $grouping)
|
||||
if ($null -ne $lsShape) { $so['listSettings'] = $lsShape }
|
||||
}
|
||||
if ($so.Count -gt 0) { $ao['settings'] = $so }
|
||||
|
||||
@@ -946,6 +946,7 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и
|
||||
| `filter` | array | Отбор списка (грамматика как в СКД) |
|
||||
| `dataParameters` | array | Значения параметров запроса в настройках (`<dcsset:dataParameters>`). **Грамматика как в СКД**: shorthand `"Имя = Значение @off @user"` или объект `{ parameter, value?, valueType?, use?, nilValue?, viewMode?, userSettingID?, userSettingPresentation? }`. В дин-списке частый паттерн — плейсхолдер отключённого параметра без значения: `"ИмяПараметра @off"` |
|
||||
| `conditionalAppearance` | array | Условное оформление списка (грамматика как в СКД) |
|
||||
| `grouping` | string \| array | Группировка строк списка (см. ниже). Forgiving-синонимы: `structure`, `группировка` |
|
||||
|
||||
`ManualQuery` выводится из наличия `query` — отдельным ключом не задаётся.
|
||||
|
||||
@@ -983,6 +984,35 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и
|
||||
|
||||
> **`value: null` при `valueListAllowed: true`** — явный маркер «эмитить `<dcssch:value xsi:nil/>`». Платформа пишет nil-значение для valueListAllowed-параметра не всегда (корпус 27 с / 47 без); по умолчанию (ключ `value` отсутствует) компилятор его НЕ эмитит. Декомпилятор ставит `value: null`, когда оригинал содержит nil-тег.
|
||||
|
||||
#### grouping — группировка строк списка
|
||||
|
||||
Уровни группировки над детальными записями списка (XML: цепочка `<dcsset:item StructureItemGroup>` в `<ListSettings>`). Группировка списка — **линейная цепочка** (каждый уровень = одно поле; несколько уровней вкладываются друг в друга), поэтому DSL плоский:
|
||||
|
||||
```json
|
||||
"grouping": "Контрагент" // один уровень
|
||||
"grouping": "Контрагент > Договор > Заказ" // вложенные уровни (внешний → внутренний)
|
||||
"grouping": ["Контрагент", "Договор"] // то же массивом
|
||||
```
|
||||
|
||||
Шорткат `>` разделяет уровни. Элемент уровня — строка (имя поля) ИЛИ объект для нестандартного поля (ключи = теги исходника):
|
||||
|
||||
```json
|
||||
"grouping": [
|
||||
"Контрагент",
|
||||
{ "field": "Период", "groupType": "Hierarchy" },
|
||||
{ "field": "Дата", "periodAdditionType": "...", "periodAdditionBegin": "2024-01-01T00:00:00", "periodAdditionEnd": "Параметр.КонецПериода" }
|
||||
]
|
||||
```
|
||||
|
||||
| Ключ уровня | Значение |
|
||||
|-------------|----------|
|
||||
| `field` | Имя поля группировки |
|
||||
| `groupType` | Тип группировки (умолчание `Items`; `Hierarchy` — с учётом иерархии) |
|
||||
| `periodAdditionType` | Дополнение периода для группировки по дате (умолчание `None`) |
|
||||
| `periodAdditionBegin` / `periodAdditionEnd` | Границы дополнения периода: ISO-дата (`xs:dateTime`) или путь к полю (`dcscor:Field`) — авто-детект |
|
||||
|
||||
> Грамматика уровня совпадает с элементом `groupBy`/`groupFields` структуры СКД (см. [skd-dsl-spec.md](skd-dsl-spec.md)); отличие от СКД — плоская модель (нет `children`/`selection`/`order`/детальных записей, которых у группировки списка не бывает).
|
||||
|
||||
#### order / filter / conditionalAppearance
|
||||
|
||||
Грамматика этих ключей идентична настройкам СКД — см. [skd-dsl-spec.md](skd-dsl-spec.md) (разделы filter / order / conditionalAppearance). Кратко:
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
{ "name": "Список", "type": "DynamicList", "useAlways": ["~Артикул", "Список.Code", "Description"], "settings": {
|
||||
"mainTable": "Catalog.Товары", "dynamicDataRead": true, "autoSaveUserSettings": false,
|
||||
"parameters": [ { "name": "ВыборТовара", "type": "CatalogRef.Товары", "valueListAllowed": true, "value": null } ],
|
||||
"grouping": "Description > Code",
|
||||
"order": [ "Description", "Code desc" ],
|
||||
"filter": [ "Артикул = _ @off @user", "Артикул like %тест%", "Description подобно %abc%",
|
||||
{ "field": "Code", "op": "=", "userSettingID": "auto", "userSettingPresentation": "Код товара" },
|
||||
|
||||
+22
@@ -196,6 +196,28 @@
|
||||
<dcsset:viewMode>Normal</dcsset:viewMode>
|
||||
<dcsset:userSettingID>UUID-007</dcsset:userSettingID>
|
||||
</dcsset:conditionalAppearance>
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup">
|
||||
<dcsset:groupItems>
|
||||
<dcsset:item xsi:type="dcsset:GroupItemField">
|
||||
<dcsset:field>Description</dcsset:field>
|
||||
<dcsset:groupType>Items</dcsset:groupType>
|
||||
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
|
||||
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
|
||||
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
|
||||
</dcsset:item>
|
||||
</dcsset:groupItems>
|
||||
<dcsset:item xsi:type="dcsset:StructureItemGroup">
|
||||
<dcsset:groupItems>
|
||||
<dcsset:item xsi:type="dcsset:GroupItemField">
|
||||
<dcsset:field>Code</dcsset:field>
|
||||
<dcsset:groupType>Items</dcsset:groupType>
|
||||
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
|
||||
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
|
||||
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
|
||||
</dcsset:item>
|
||||
</dcsset:groupItems>
|
||||
</dcsset:item>
|
||||
</dcsset:item>
|
||||
<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>
|
||||
<dcsset:itemsUserSettingID>UUID-008</dcsset:itemsUserSettingID>
|
||||
</ListSettings>
|
||||
|
||||
Reference in New Issue
Block a user