mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-06-11 00:14:56 +03:00
feat(skd-compile): compact AreaTemplate DSL, fix dataPath and presentation fallback
- Fix empty dataPath when field is specified as object { field, title }
- Add title to presentation fallback chain: presentation → title → name
- Add compact DSL for AreaTemplate: rows/widths/style instead of raw XML
- Built-in style presets: header, data, subheader, total
- User-defined presets via skd-styles.json (project-level overrides)
- Support vertical merge ("|"), parameters ("{Name}"), static text, null cells
- Update SKILL.md, skd-dsl-spec.md, skd-guide.md with template DSL docs
- Add examples/skd-styles.json with all supported keys
- Bump version v1.1 → v1.2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,7 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
|
||||
## JSON DSL — краткий справочник
|
||||
|
||||
Полная спецификация: `docs/skd-dsl-spec.md`.
|
||||
Справочник ниже. Все примеры компилируемы как есть.
|
||||
|
||||
### Корневая структура
|
||||
|
||||
@@ -41,6 +41,8 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
"calculatedFields": [...],
|
||||
"totalFields": [...],
|
||||
"parameters": [...],
|
||||
"templates": [...],
|
||||
"groupTemplates": [...],
|
||||
"dataSetLinks": [...],
|
||||
"settingsVariants": [...]
|
||||
}
|
||||
@@ -58,7 +60,7 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
|
||||
Запрос поддерживает `@file` — ссылку на внешний .sql файл вместо inline-текста: `"query": "@queries/sales.sql"`. Путь разрешается относительно JSON-файла, затем CWD.
|
||||
|
||||
### Поля — shorthand
|
||||
### Поля — shorthand и объектная форма
|
||||
|
||||
```
|
||||
"Наименование" — просто имя
|
||||
@@ -67,6 +69,12 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
"Служебное: string #noFilter #noOrder" — + ограничения
|
||||
```
|
||||
|
||||
Объектная форма — когда нужен title или другие свойства:
|
||||
```json
|
||||
{ "field": "ОстатокНаНачалоПериода", "title": "Остаток на начало периода" }
|
||||
```
|
||||
`dataPath` автоматически берётся из `field`, если не указан явно.
|
||||
|
||||
Типы: `string`, `string(N)`, `decimal(D,F)`, `boolean`, `date`, `dateTime`, `CatalogRef.X`, `DocumentRef.X`, `EnumRef.X`, `StandardPeriod`. Ссылочные типы эмитируются с inline namespace `d5p1:` (`http://v8.1c.ru/8.1/data/enterprise/current-config`). Сборка EPF со ссылочными типами требует базу с соответствующей конфигурацией.
|
||||
|
||||
**Синонимы типов** (русские и альтернативные): `число` = decimal, `строка` = string, `булево` = boolean, `дата` = date, `датаВремя` = dateTime, `СтандартныйПериод` = StandardPeriod, `СправочникСсылка.X` = CatalogRef.X, `ДокументСсылка.X` = DocumentRef.X, `int`/`number` = decimal, `bool` = boolean. Регистронезависимые.
|
||||
@@ -143,6 +151,7 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
```json
|
||||
"settingsVariants": [{
|
||||
"name": "Основной",
|
||||
"title": "Продажи по организациям",
|
||||
"settings": {
|
||||
"selection": ["Номенклатура", "Количество", "Auto"],
|
||||
"filter": ["Организация = _ @off @user"],
|
||||
@@ -188,6 +197,53 @@ powershell.exe -NoProfile -File .claude/skills/skd-compile/scripts/skd-compile.p
|
||||
]
|
||||
```
|
||||
|
||||
### Шаблоны вывода — компактный DSL
|
||||
|
||||
Вместо raw XML (`template`) — табличное описание через `rows` + именованный стиль `style`:
|
||||
|
||||
```json
|
||||
"templates": [
|
||||
{
|
||||
"name": "Макет1",
|
||||
"style": "header",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"minHeight": 24.75,
|
||||
"rows": [
|
||||
["Виды кассы", "Валюта", "Остаток на начало\nпериода", "Остаток на\nконец периода"],
|
||||
["|", "|", "|", "|"],
|
||||
["К1", "К2", "К3", "К4"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Макет2",
|
||||
"style": "data",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"rows": [["{ВидКассы}", "{Валюта}", "{Остаток}", "{ОстатокКонец}"]],
|
||||
"parameters": [
|
||||
{ "name": "ВидКассы", "expression": "Представление(Счет)" },
|
||||
{ "name": "Остаток", "expression": "ОстатокНаНачалоПериода" }
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Синтаксис ячеек: `"текст"` — статика, `"{Имя}"` — параметр, `"|"` — объединение с ячейкой выше, `null` — пустая.
|
||||
|
||||
Встроенные стили: `header` (фон, центр, перенос), `data` (фон группы), `subheader` (без фона, центр), `total` (без фона). Все — Arial 10, рамки Solid 1px, цвета через стили платформы.
|
||||
|
||||
Пользовательские стили: файл `skd-styles.json` рядом с JSON или в корне проекта. Все допустимые ключи и формат цветов — в `examples/skd-styles.json`.
|
||||
|
||||
Raw XML (`"template": "<...>"`) остаётся как fallback. Детект: если есть `rows` — DSL, иначе — raw.
|
||||
|
||||
### Привязки макетов к группировкам
|
||||
|
||||
```json
|
||||
"groupTemplates": [
|
||||
{ "groupField": "Счет", "templateType": "GroupHeader", "template": "Макет1" },
|
||||
{ "groupField": "Счет", "templateType": "Header", "template": "Макет2" }
|
||||
]
|
||||
```
|
||||
|
||||
## Примеры
|
||||
|
||||
### Минимальный
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"header": {
|
||||
"font": "Arial",
|
||||
"fontSize": 10,
|
||||
"bold": false,
|
||||
"italic": false,
|
||||
"hAlign": "Center",
|
||||
"vAlign": "Center",
|
||||
"wrap": true,
|
||||
"bgColor": "style:ReportHeaderBackColor",
|
||||
"textColor": null,
|
||||
"borderColor": "style:ReportLineColor",
|
||||
"borders": true
|
||||
},
|
||||
"data": {
|
||||
"bgColor": "style:ReportGroup1BackColor",
|
||||
"borderColor": "style:ReportLineColor"
|
||||
},
|
||||
"total": {
|
||||
"bold": true,
|
||||
"borderColor": "style:ReportLineColor"
|
||||
},
|
||||
"myProjectStyle": {
|
||||
"bgColor": "#FFE0E0",
|
||||
"textColor": "#990000",
|
||||
"fontSize": 12,
|
||||
"bold": true,
|
||||
"hAlign": "Right"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# skd-compile v1.1 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.2 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
@@ -529,7 +529,7 @@ function Emit-Field {
|
||||
$f = Parse-FieldShorthand $fieldDef
|
||||
} else {
|
||||
$f = @{
|
||||
dataPath = "$($fieldDef.dataPath)"
|
||||
dataPath = if ($fieldDef.dataPath) { "$($fieldDef.dataPath)" } elseif ($fieldDef.field) { "$($fieldDef.field)" } else { "" }
|
||||
field = if ($fieldDef.field) { "$($fieldDef.field)" } else { "$($fieldDef.dataPath)" }
|
||||
title = if ($fieldDef.title) { "$($fieldDef.title)" } else { "" }
|
||||
type = if ($fieldDef.type) { Resolve-TypeStr "$($fieldDef.type)" } else { "" }
|
||||
@@ -931,25 +931,286 @@ function Emit-ParamValue {
|
||||
}
|
||||
}
|
||||
|
||||
# === AreaTemplate DSL ===
|
||||
|
||||
# Built-in style presets
|
||||
$script:areaStylePresets = @{
|
||||
data = @{
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = 'style:ReportGroup1BackColor'; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
header = @{
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = 'Center'; vAlign = $null; wrap = $true
|
||||
bgColor = 'style:ReportHeaderBackColor'; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
subheader = @{
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = 'Center'; vAlign = $null; wrap = $true
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
total = @{
|
||||
font = 'Arial'; fontSize = 10; bold = $false; italic = $false
|
||||
hAlign = $null; vAlign = $null; wrap = $false
|
||||
bgColor = $null; textColor = $null
|
||||
borderColor = 'style:ReportLineColor'; borders = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Load user presets from skd-styles.json (same dir as definition or cwd)
|
||||
$script:userStylesLoaded = $false
|
||||
foreach ($stylesDir in @($script:queryBaseDir, (Get-Location).Path)) {
|
||||
$stylesFile = Join-Path $stylesDir "skd-styles.json"
|
||||
if (Test-Path $stylesFile) {
|
||||
$userStyles = Get-Content -Raw -Encoding UTF8 $stylesFile | ConvertFrom-Json
|
||||
foreach ($prop in $userStyles.PSObject.Properties) {
|
||||
$preset = @{}
|
||||
# Start from 'data' defaults
|
||||
foreach ($k in $script:areaStylePresets['data'].Keys) {
|
||||
$preset[$k] = $script:areaStylePresets['data'][$k]
|
||||
}
|
||||
# If overriding existing preset, start from it instead
|
||||
if ($script:areaStylePresets.ContainsKey($prop.Name)) {
|
||||
foreach ($k in $script:areaStylePresets[$prop.Name].Keys) {
|
||||
$preset[$k] = $script:areaStylePresets[$prop.Name][$k]
|
||||
}
|
||||
}
|
||||
# Apply user overrides
|
||||
foreach ($up in $prop.Value.PSObject.Properties) {
|
||||
$preset[$up.Name] = $up.Value
|
||||
}
|
||||
$script:areaStylePresets[$prop.Name] = $preset
|
||||
}
|
||||
$script:userStylesLoaded = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function Emit-ColorValue {
|
||||
param([string]$color, [string]$indent)
|
||||
if ($color.StartsWith('style:')) {
|
||||
$styleName = $color.Substring(6)
|
||||
X "$indent<dcscor:value xmlns:d8p1=`"http://v8.1c.ru/8.1/data/ui/style`" xsi:type=`"v8ui:Color`">d8p1:$styleName</dcscor:value>"
|
||||
} else {
|
||||
X "$indent<dcscor:value xsi:type=`"v8ui:Color`">$(Esc-Xml $color)</dcscor:value>"
|
||||
}
|
||||
}
|
||||
|
||||
function Emit-CellAppearance {
|
||||
param($style, [double]$width = 0, [bool]$vMerge = $false, [double]$minHeight = 0)
|
||||
$ind = "`t`t`t`t`t"
|
||||
X "`t`t`t`t<dcsat:appearance>"
|
||||
# Background color
|
||||
if ($style.bgColor) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ЦветФона</dcscor:parameter>"
|
||||
Emit-ColorValue $style.bgColor "$ind`t"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Text color
|
||||
if ($style.textColor) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ЦветТекста</dcscor:parameter>"
|
||||
Emit-ColorValue $style.textColor "$ind`t"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Border color + border style (4 sides)
|
||||
if ($style.borders) {
|
||||
if ($style.borderColor) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ЦветГраницы</dcscor:parameter>"
|
||||
Emit-ColorValue $style.borderColor "$ind`t"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>СтильГраницы</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"v8ui:Line`" width=`"0`" gap=`"false`">"
|
||||
X "$ind`t`t<v8ui:style xsi:type=`"v8ui:SpreadsheetDocumentCellLineType`">None</v8ui:style>"
|
||||
X "$ind`t</dcscor:value>"
|
||||
foreach ($side in @('Слева','Сверху','Справа','Снизу')) {
|
||||
X "$ind`t<dcscor:item>"
|
||||
X "$ind`t`t<dcscor:parameter>СтильГраницы.$side</dcscor:parameter>"
|
||||
X "$ind`t`t<dcscor:value xsi:type=`"v8ui:Line`" width=`"1`" gap=`"false`">"
|
||||
X "$ind`t`t`t<v8ui:style xsi:type=`"v8ui:SpreadsheetDocumentCellLineType`">Solid</v8ui:style>"
|
||||
X "$ind`t`t</dcscor:value>"
|
||||
X "$ind`t</dcscor:item>"
|
||||
}
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Font
|
||||
$boldStr = if ($style.bold) { "true" } else { "false" }
|
||||
$italicStr = if ($style.italic) { "true" } else { "false" }
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>Шрифт</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"v8ui:Font`" faceName=`"$($style.font)`" height=`"$($style.fontSize)`" bold=`"$boldStr`" italic=`"$italicStr`" underline=`"false`" strikeout=`"false`" kind=`"Absolute`" scale=`"100`"/>"
|
||||
X "$ind</dcscor:item>"
|
||||
# Horizontal alignment
|
||||
if ($style.hAlign) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ГоризонтальноеПоложение</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"v8ui:HorizontalAlign`">$(Esc-Xml $style.hAlign)</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Vertical alignment
|
||||
if ($style.vAlign) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ВертикальноеПоложение</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"v8ui:VerticalAlign`">$(Esc-Xml $style.vAlign)</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Text placement (wrap)
|
||||
if ($style.wrap) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>Размещение</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"dcscor:DataCompositionTextPlacementType`">Wrap</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Width
|
||||
if ($width -gt 0) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>МинимальнаяШирина</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"xs:decimal`">$width</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>МаксимальнаяШирина</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"xs:decimal`">$width</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Min height
|
||||
if ($minHeight -gt 0) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>МинимальнаяВысота</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"xs:decimal`">$minHeight</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
# Vertical merge
|
||||
if ($vMerge) {
|
||||
X "$ind<dcscor:item>"
|
||||
X "$ind`t<dcscor:parameter>ОбъединятьПоВертикали</dcscor:parameter>"
|
||||
X "$ind`t<dcscor:value xsi:type=`"xs:boolean`">true</dcscor:value>"
|
||||
X "$ind</dcscor:item>"
|
||||
}
|
||||
X "`t`t`t`t</dcsat:appearance>"
|
||||
}
|
||||
|
||||
function Emit-AreaTemplateDSL {
|
||||
param($t)
|
||||
$styleName = if ($t.style) { "$($t.style)" } else { "data" }
|
||||
if (-not $script:areaStylePresets.ContainsKey($styleName)) {
|
||||
Write-Warning "Unknown area style preset '$styleName', falling back to 'data'"
|
||||
$styleName = "data"
|
||||
}
|
||||
$style = $script:areaStylePresets[$styleName]
|
||||
|
||||
$rows = @($t.rows)
|
||||
$widths = if ($t.widths) { @($t.widths) } else { @() }
|
||||
$minHeight = if ($t.minHeight) { [double]$t.minHeight } else { 0 }
|
||||
$colCount = if ($widths.Count -gt 0) { $widths.Count } else { $rows[0].Count }
|
||||
|
||||
# Build merge map: vMerge[row][col] = $true if cell is merged with above
|
||||
$vMerge = @{}
|
||||
for ($r = $rows.Count - 1; $r -ge 1; $r--) {
|
||||
$vMerge[$r] = @{}
|
||||
for ($c = 0; $c -lt $colCount; $c++) {
|
||||
$cellVal = $rows[$r][$c]
|
||||
if ($cellVal -is [string] -and $cellVal -eq '|') {
|
||||
$vMerge[$r][$c] = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $vMerge.ContainsKey(0)) { $vMerge[0] = @{} }
|
||||
|
||||
X "`t<template>"
|
||||
X "`t`t<name>$(Esc-Xml "$($t.name)")</name>"
|
||||
X "`t`t<template xmlns:dcsat=`"http://v8.1c.ru/8.1/data-composition-system/area-template`" xsi:type=`"dcsat:AreaTemplate`">"
|
||||
|
||||
for ($r = 0; $r -lt $rows.Count; $r++) {
|
||||
X "`t`t`t<dcsat:item xsi:type=`"dcsat:TableRow`">"
|
||||
for ($c = 0; $c -lt $colCount; $c++) {
|
||||
$cellVal = $rows[$r][$c]
|
||||
$w = if ($c -lt $widths.Count) { [double]$widths[$c] } else { 0 }
|
||||
$isMerged = $vMerge[$r][$c] -eq $true
|
||||
# Check if this cell starts a vertical merge (next row has "|" in same column)
|
||||
$startsVMerge = $false
|
||||
for ($nr = $r + 1; $nr -lt $rows.Count; $nr++) {
|
||||
if ($vMerge[$nr][$c] -eq $true) { $startsVMerge = $true } else { break }
|
||||
}
|
||||
|
||||
X "`t`t`t`t<dcsat:tableCell>"
|
||||
if ($isMerged) {
|
||||
# Merged cell — only appearance with vMerge flag + width
|
||||
Emit-CellAppearance $style $w $true
|
||||
} else {
|
||||
# Cell value
|
||||
if ($null -ne $cellVal -and $cellVal -ne '') {
|
||||
$cellStr = "$cellVal"
|
||||
if ($cellStr -match '^\{(.+)\}$') {
|
||||
# Parameter reference
|
||||
X "`t`t`t`t`t<dcsat:item xsi:type=`"dcsat:Field`">"
|
||||
X "`t`t`t`t`t`t<dcsat:value xsi:type=`"dcscor:Parameter`">$(Esc-Xml $Matches[1])</dcsat:value>"
|
||||
X "`t`t`t`t`t</dcsat:item>"
|
||||
} else {
|
||||
# Static text
|
||||
X "`t`t`t`t`t<dcsat:item xsi:type=`"dcsat:Field`">"
|
||||
X "`t`t`t`t`t`t<dcsat:value xsi:type=`"v8:LocalStringType`">"
|
||||
X "`t`t`t`t`t`t`t<v8:item>"
|
||||
X "`t`t`t`t`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
X "`t`t`t`t`t`t`t`t<v8:content>$(Esc-Xml $cellStr)</v8:content>"
|
||||
X "`t`t`t`t`t`t`t</v8:item>"
|
||||
X "`t`t`t`t`t`t</dcsat:value>"
|
||||
X "`t`t`t`t`t</dcsat:item>"
|
||||
}
|
||||
}
|
||||
# Appearance
|
||||
$h = if ($r -eq 0) { $minHeight } else { 0 }
|
||||
Emit-CellAppearance $style $w $startsVMerge $h
|
||||
}
|
||||
X "`t`t`t`t</dcsat:tableCell>"
|
||||
}
|
||||
X "`t`t`t</dcsat:item>"
|
||||
}
|
||||
|
||||
X "`t`t</template>"
|
||||
# Parameters (reuse existing logic)
|
||||
if ($t.parameters) {
|
||||
foreach ($tp in $t.parameters) {
|
||||
X "`t`t<parameter xmlns:dcsat=`"http://v8.1c.ru/8.1/data-composition-system/area-template`" xsi:type=`"dcsat:ExpressionAreaTemplateParameter`">"
|
||||
X "`t`t`t<dcsat:name>$(Esc-Xml "$($tp.name)")</dcsat:name>"
|
||||
X "`t`t`t<dcsat:expression>$(Esc-Xml "$($tp.expression)")</dcsat:expression>"
|
||||
X "`t`t</parameter>"
|
||||
}
|
||||
}
|
||||
X "`t</template>"
|
||||
}
|
||||
|
||||
# === Templates ===
|
||||
function Emit-Templates {
|
||||
if (-not $def.templates) { return }
|
||||
foreach ($t in $def.templates) {
|
||||
X "`t<template>"
|
||||
X "`t`t<name>$(Esc-Xml "$($t.name)")</name>"
|
||||
if ($t.template) {
|
||||
# Raw XML content
|
||||
X "`t`t$($t.template)"
|
||||
}
|
||||
if ($t.parameters) {
|
||||
foreach ($tp in $t.parameters) {
|
||||
X "`t`t<parameter xmlns:dcsat=`"http://v8.1c.ru/8.1/data-composition-system/area-template`" xsi:type=`"dcsat:ExpressionAreaTemplateParameter`">"
|
||||
X "`t`t`t<dcsat:name>$(Esc-Xml "$($tp.name)")</dcsat:name>"
|
||||
X "`t`t`t<dcsat:expression>$(Esc-Xml "$($tp.expression)")</dcsat:expression>"
|
||||
X "`t`t</parameter>"
|
||||
if ($t.rows) {
|
||||
# Compact DSL mode
|
||||
Emit-AreaTemplateDSL $t
|
||||
} else {
|
||||
# Raw XML mode
|
||||
X "`t<template>"
|
||||
X "`t`t<name>$(Esc-Xml "$($t.name)")</name>"
|
||||
if ($t.template) {
|
||||
X "`t`t$($t.template)"
|
||||
}
|
||||
if ($t.parameters) {
|
||||
foreach ($tp in $t.parameters) {
|
||||
X "`t`t<parameter xmlns:dcsat=`"http://v8.1c.ru/8.1/data-composition-system/area-template`" xsi:type=`"dcsat:ExpressionAreaTemplateParameter`">"
|
||||
X "`t`t`t<dcsat:name>$(Esc-Xml "$($tp.name)")</dcsat:name>"
|
||||
X "`t`t`t<dcsat:expression>$(Esc-Xml "$($tp.expression)")</dcsat:expression>"
|
||||
X "`t`t</parameter>"
|
||||
}
|
||||
}
|
||||
X "`t</template>"
|
||||
}
|
||||
X "`t</template>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1565,7 +1826,7 @@ function Emit-SettingsVariants {
|
||||
X "`t<settingsVariant>"
|
||||
X "`t`t<dcsset:name>$(Esc-Xml "$($v.name)")</dcsset:name>"
|
||||
|
||||
$pres = if ($v.presentation) { "$($v.presentation)" } else { "$($v.name)" }
|
||||
$pres = if ($v.presentation) { "$($v.presentation)" } elseif ($v.title) { "$($v.title)" } else { "$($v.name)" }
|
||||
X "`t`t<dcsset:presentation xsi:type=`"v8:LocalStringType`">"
|
||||
X "`t`t`t<v8:item>"
|
||||
X "`t`t`t`t<v8:lang>ru</v8:lang>"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# skd-compile v1.1 — Compile 1C DCS from JSON
|
||||
# skd-compile v1.2 — Compile 1C DCS from JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -417,7 +417,7 @@ def emit_field(lines, field_def, indent):
|
||||
f = parse_field_shorthand(field_def)
|
||||
else:
|
||||
f = {
|
||||
'dataPath': str(field_def.get('dataPath', '')),
|
||||
'dataPath': str(field_def.get('dataPath', '')) or str(field_def.get('field', '')),
|
||||
'field': str(field_def.get('field', '')) or str(field_def.get('dataPath', '')),
|
||||
'title': str(field_def.get('title', '')) if field_def.get('title') else '',
|
||||
'type': resolve_type_str(str(field_def['type'])) if field_def.get('type') else '',
|
||||
@@ -772,23 +772,238 @@ def emit_parameters(lines, defn):
|
||||
emit_single_param(lines, None, end_parsed)
|
||||
|
||||
|
||||
# === AreaTemplate DSL ===
|
||||
|
||||
AREA_STYLE_PRESETS = {
|
||||
'data': {
|
||||
'font': 'Arial', 'fontSize': 10, 'bold': False, 'italic': False,
|
||||
'hAlign': None, 'vAlign': None, 'wrap': False,
|
||||
'bgColor': 'style:ReportGroup1BackColor', 'textColor': None,
|
||||
'borderColor': 'style:ReportLineColor', 'borders': True,
|
||||
},
|
||||
'header': {
|
||||
'font': 'Arial', 'fontSize': 10, 'bold': False, 'italic': False,
|
||||
'hAlign': 'Center', 'vAlign': None, 'wrap': True,
|
||||
'bgColor': 'style:ReportHeaderBackColor', 'textColor': None,
|
||||
'borderColor': 'style:ReportLineColor', 'borders': True,
|
||||
},
|
||||
'subheader': {
|
||||
'font': 'Arial', 'fontSize': 10, 'bold': False, 'italic': False,
|
||||
'hAlign': 'Center', 'vAlign': None, 'wrap': True,
|
||||
'bgColor': None, 'textColor': None,
|
||||
'borderColor': 'style:ReportLineColor', 'borders': True,
|
||||
},
|
||||
'total': {
|
||||
'font': 'Arial', 'fontSize': 10, 'bold': False, 'italic': False,
|
||||
'hAlign': None, 'vAlign': None, 'wrap': False,
|
||||
'bgColor': None, 'textColor': None,
|
||||
'borderColor': 'style:ReportLineColor', 'borders': True,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def load_user_styles(base_dir):
|
||||
for d in [base_dir, os.getcwd()]:
|
||||
p = os.path.join(d, 'skd-styles.json')
|
||||
if os.path.isfile(p):
|
||||
with open(p, 'r', encoding='utf-8-sig') as f:
|
||||
user_styles = json.load(f)
|
||||
for name, overrides in user_styles.items():
|
||||
base = dict(AREA_STYLE_PRESETS.get(name, AREA_STYLE_PRESETS['data']))
|
||||
base.update(overrides)
|
||||
AREA_STYLE_PRESETS[name] = base
|
||||
return
|
||||
|
||||
|
||||
def _emit_color_value(lines, color, indent):
|
||||
if color.startswith('style:'):
|
||||
style_name = color[6:]
|
||||
lines.append(f'{indent}<dcscor:value xmlns:d8p1="http://v8.1c.ru/8.1/data/ui/style" xsi:type="v8ui:Color">d8p1:{style_name}</dcscor:value>')
|
||||
else:
|
||||
lines.append(f'{indent}<dcscor:value xsi:type="v8ui:Color">{esc_xml(color)}</dcscor:value>')
|
||||
|
||||
|
||||
def _emit_cell_appearance(lines, style, width=0, v_merge=False, min_height=0):
|
||||
ind = '\t\t\t\t\t'
|
||||
lines.append('\t\t\t\t<dcsat:appearance>')
|
||||
# Background color
|
||||
if style.get('bgColor'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0426\u0432\u0435\u0442\u0424\u043e\u043d\u0430</dcscor:parameter>')
|
||||
_emit_color_value(lines, style['bgColor'], f'{ind}\t')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Text color
|
||||
if style.get('textColor'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0426\u0432\u0435\u0442\u0422\u0435\u043a\u0441\u0442\u0430</dcscor:parameter>')
|
||||
_emit_color_value(lines, style['textColor'], f'{ind}\t')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Borders
|
||||
if style.get('borders'):
|
||||
if style.get('borderColor'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0426\u0432\u0435\u0442\u0413\u0440\u0430\u043d\u0438\u0446\u044b</dcscor:parameter>')
|
||||
_emit_color_value(lines, style['borderColor'], f'{ind}\t')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0421\u0442\u0438\u043b\u044c\u0413\u0440\u0430\u043d\u0438\u0446\u044b</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="v8ui:Line" width="0" gap="false">')
|
||||
lines.append(f'{ind}\t\t<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">None</v8ui:style>')
|
||||
lines.append(f'{ind}\t</dcscor:value>')
|
||||
for side in ['\u0421\u043b\u0435\u0432\u0430', '\u0421\u0432\u0435\u0440\u0445\u0443', '\u0421\u043f\u0440\u0430\u0432\u0430', '\u0421\u043d\u0438\u0437\u0443']:
|
||||
lines.append(f'{ind}\t<dcscor:item>')
|
||||
lines.append(f'{ind}\t\t<dcscor:parameter>\u0421\u0442\u0438\u043b\u044c\u0413\u0440\u0430\u043d\u0438\u0446\u044b.{side}</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t\t<dcscor:value xsi:type="v8ui:Line" width="1" gap="false">')
|
||||
lines.append(f'{ind}\t\t\t<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">Solid</v8ui:style>')
|
||||
lines.append(f'{ind}\t\t</dcscor:value>')
|
||||
lines.append(f'{ind}\t</dcscor:item>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Font
|
||||
bold_str = 'true' if style.get('bold') else 'false'
|
||||
italic_str = 'true' if style.get('italic') else 'false'
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0428\u0440\u0438\u0444\u0442</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="v8ui:Font" faceName="{style["font"]}" height="{style["fontSize"]}" bold="{bold_str}" italic="{italic_str}" underline="false" strikeout="false" kind="Absolute" scale="100"/>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Horizontal alignment
|
||||
if style.get('hAlign'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="v8ui:HorizontalAlign">{esc_xml(style["hAlign"])}</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Vertical alignment
|
||||
if style.get('vAlign'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="v8ui:VerticalAlign">{esc_xml(style["vAlign"])}</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Wrap
|
||||
if style.get('wrap'):
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u0420\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="dcscor:DataCompositionTextPlacementType">Wrap</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Width
|
||||
if width and width > 0:
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f\u0428\u0438\u0440\u0438\u043d\u0430</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="xs:decimal">{width}</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f\u0428\u0438\u0440\u0438\u043d\u0430</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="xs:decimal">{width}</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Min height
|
||||
if min_height and min_height > 0:
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f\u0412\u044b\u0441\u043e\u0442\u0430</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="xs:decimal">{min_height}</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
# Vertical merge
|
||||
if v_merge:
|
||||
lines.append(f'{ind}<dcscor:item>')
|
||||
lines.append(f'{ind}\t<dcscor:parameter>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c\u041f\u043e\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438</dcscor:parameter>')
|
||||
lines.append(f'{ind}\t<dcscor:value xsi:type="xs:boolean">true</dcscor:value>')
|
||||
lines.append(f'{ind}</dcscor:item>')
|
||||
lines.append('\t\t\t\t</dcsat:appearance>')
|
||||
|
||||
|
||||
def _emit_area_template_dsl(lines, t):
|
||||
style_name = str(t.get('style', '')) or 'data'
|
||||
if style_name not in AREA_STYLE_PRESETS:
|
||||
print(f"Warning: Unknown area style preset '{style_name}', falling back to 'data'", file=sys.stderr)
|
||||
style_name = 'data'
|
||||
style = AREA_STYLE_PRESETS[style_name]
|
||||
|
||||
rows = list(t['rows'])
|
||||
widths = list(t.get('widths', []))
|
||||
min_height = float(t.get('minHeight', 0))
|
||||
col_count = len(widths) if widths else len(rows[0])
|
||||
|
||||
# Build merge map
|
||||
v_merge = {}
|
||||
for r in range(len(rows) - 1, 0, -1):
|
||||
v_merge[r] = {}
|
||||
for c in range(col_count):
|
||||
cell_val = rows[r][c] if c < len(rows[r]) else None
|
||||
if isinstance(cell_val, str) and cell_val == '|':
|
||||
v_merge[r][c] = True
|
||||
if 0 not in v_merge:
|
||||
v_merge[0] = {}
|
||||
|
||||
lines.append('\t<template>')
|
||||
lines.append(f'\t\t<name>{esc_xml(str(t["name"]))}</name>')
|
||||
lines.append('\t\t<template xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template" xsi:type="dcsat:AreaTemplate">')
|
||||
|
||||
for r in range(len(rows)):
|
||||
lines.append('\t\t\t<dcsat:item xsi:type="dcsat:TableRow">')
|
||||
for c in range(col_count):
|
||||
cell_val = rows[r][c] if c < len(rows[r]) else None
|
||||
w = float(widths[c]) if c < len(widths) else 0
|
||||
is_merged = v_merge.get(r, {}).get(c, False)
|
||||
# Check if this cell starts a vertical merge
|
||||
starts_v_merge = False
|
||||
for nr in range(r + 1, len(rows)):
|
||||
if v_merge.get(nr, {}).get(c, False):
|
||||
starts_v_merge = True
|
||||
else:
|
||||
break
|
||||
|
||||
lines.append('\t\t\t\t<dcsat:tableCell>')
|
||||
if is_merged:
|
||||
_emit_cell_appearance(lines, style, w, True)
|
||||
else:
|
||||
if cell_val is not None and str(cell_val) != '':
|
||||
cell_str = str(cell_val)
|
||||
m = re.match(r'^\{(.+)\}$', cell_str)
|
||||
if m:
|
||||
lines.append('\t\t\t\t\t<dcsat:item xsi:type="dcsat:Field">')
|
||||
lines.append(f'\t\t\t\t\t\t<dcsat:value xsi:type="dcscor:Parameter">{esc_xml(m.group(1))}</dcsat:value>')
|
||||
lines.append('\t\t\t\t\t</dcsat:item>')
|
||||
else:
|
||||
lines.append('\t\t\t\t\t<dcsat:item xsi:type="dcsat:Field">')
|
||||
lines.append('\t\t\t\t\t\t<dcsat:value xsi:type="v8:LocalStringType">')
|
||||
lines.append('\t\t\t\t\t\t\t<v8:item>')
|
||||
lines.append('\t\t\t\t\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
lines.append(f'\t\t\t\t\t\t\t\t<v8:content>{esc_xml(cell_str)}</v8:content>')
|
||||
lines.append('\t\t\t\t\t\t\t</v8:item>')
|
||||
lines.append('\t\t\t\t\t\t</dcsat:value>')
|
||||
lines.append('\t\t\t\t\t</dcsat:item>')
|
||||
h = min_height if r == 0 else 0
|
||||
_emit_cell_appearance(lines, style, w, starts_v_merge, h)
|
||||
lines.append('\t\t\t\t</dcsat:tableCell>')
|
||||
lines.append('\t\t\t</dcsat:item>')
|
||||
|
||||
lines.append('\t\t</template>')
|
||||
if t.get('parameters'):
|
||||
for tp in t['parameters']:
|
||||
lines.append('\t\t<parameter xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template" xsi:type="dcsat:ExpressionAreaTemplateParameter">')
|
||||
lines.append(f'\t\t\t<dcsat:name>{esc_xml(str(tp["name"]))}</dcsat:name>')
|
||||
lines.append(f'\t\t\t<dcsat:expression>{esc_xml(str(tp["expression"]))}</dcsat:expression>')
|
||||
lines.append('\t\t</parameter>')
|
||||
lines.append('\t</template>')
|
||||
|
||||
|
||||
# === Templates ===
|
||||
|
||||
def emit_templates(lines, defn):
|
||||
if not defn.get('templates'):
|
||||
return
|
||||
for t in defn['templates']:
|
||||
lines.append('\t<template>')
|
||||
lines.append(f'\t\t<name>{esc_xml(str(t["name"]))}</name>')
|
||||
if t.get('template'):
|
||||
lines.append(f'\t\t{t["template"]}')
|
||||
if t.get('parameters'):
|
||||
for tp in t['parameters']:
|
||||
lines.append('\t\t<parameter xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template" xsi:type="dcsat:ExpressionAreaTemplateParameter">')
|
||||
lines.append(f'\t\t\t<dcsat:name>{esc_xml(str(tp["name"]))}</dcsat:name>')
|
||||
lines.append(f'\t\t\t<dcsat:expression>{esc_xml(str(tp["expression"]))}</dcsat:expression>')
|
||||
lines.append('\t\t</parameter>')
|
||||
lines.append('\t</template>')
|
||||
if t.get('rows'):
|
||||
_emit_area_template_dsl(lines, t)
|
||||
else:
|
||||
lines.append('\t<template>')
|
||||
lines.append(f'\t\t<name>{esc_xml(str(t["name"]))}</name>')
|
||||
if t.get('template'):
|
||||
lines.append(f'\t\t{t["template"]}')
|
||||
if t.get('parameters'):
|
||||
for tp in t['parameters']:
|
||||
lines.append('\t\t<parameter xmlns:dcsat="http://v8.1c.ru/8.1/data-composition-system/area-template" xsi:type="dcsat:ExpressionAreaTemplateParameter">')
|
||||
lines.append(f'\t\t\t<dcsat:name>{esc_xml(str(tp["name"]))}</dcsat:name>')
|
||||
lines.append(f'\t\t\t<dcsat:expression>{esc_xml(str(tp["expression"]))}</dcsat:expression>')
|
||||
lines.append('\t\t</parameter>')
|
||||
lines.append('\t</template>')
|
||||
|
||||
|
||||
# === GroupTemplates ===
|
||||
@@ -1288,7 +1503,7 @@ def emit_settings_variants(lines, defn):
|
||||
lines.append('\t<settingsVariant>')
|
||||
lines.append(f'\t\t<dcsset:name>{esc_xml(str(v["name"]))}</dcsset:name>')
|
||||
|
||||
pres = str(v.get('presentation', '')) or str(v['name'])
|
||||
pres = str(v.get('presentation', '')) or str(v.get('title', '')) or str(v['name'])
|
||||
lines.append('\t\t<dcsset:presentation xsi:type="v8:LocalStringType">')
|
||||
lines.append('\t\t\t<v8:item>')
|
||||
lines.append('\t\t\t\t<v8:lang>ru</v8:lang>')
|
||||
@@ -1375,6 +1590,9 @@ def main():
|
||||
global query_base_dir
|
||||
query_base_dir = os.path.dirname(def_file) if args.DefinitionFile else os.getcwd()
|
||||
|
||||
# Load user style presets
|
||||
load_user_styles(query_base_dir)
|
||||
|
||||
# --- 2. Resolve defaults ---
|
||||
|
||||
# DataSources
|
||||
|
||||
+94
-2
@@ -712,9 +712,99 @@ XML-маппинг — по `<group>` на каждый элемент:
|
||||
|
||||
## 10. Макеты и привязки (templates, groupTemplates)
|
||||
|
||||
Редко используются. Поддерживаются в объектной форме, близкой к XML.
|
||||
### templates — компактный DSL (рекомендуемый)
|
||||
|
||||
### templates
|
||||
Табличное описание шаблона вывода. Содержимое задаётся через `rows`, оформление — через именованный пресет `style`.
|
||||
|
||||
```json
|
||||
"templates": [
|
||||
{
|
||||
"name": "Макет1",
|
||||
"style": "header",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"minHeight": 24.75,
|
||||
"rows": [
|
||||
["Виды кассы", "Валюта", "Остаток на начало\nпериода", "Остаток на\nконец\nпериода"],
|
||||
["|", "|", "|", "|"],
|
||||
["К1", "К2", "К3", "К4"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Макет2",
|
||||
"style": "data",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"rows": [["{ВидКассы}", "{Валюта}", "{ОстатокНачало}", "{ОстатокКонец}"]],
|
||||
"parameters": [
|
||||
{ "name": "ВидКассы", "expression": "Представление(СчетМеждународногоУчета)" },
|
||||
{ "name": "ОстатокНачало", "expression": "ОстатокНаНачалоПериода" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Макет3",
|
||||
"style": "total",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"rows": [["Итого", "Х", "{ОстатокНачало}", "{ОстатокКонец}"]],
|
||||
"parameters": [
|
||||
{ "name": "ОстатокНачало", "expression": "ОстатокНаНачалоПериода" }
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### Свойства шаблона
|
||||
|
||||
| Свойство | Описание |
|
||||
|----------|----------|
|
||||
| `name` | Имя макета (ссылаются groupTemplate) |
|
||||
| `rows` | Массив строк; каждая строка — массив ячеек |
|
||||
| `style` | Именованный пресет оформления (по умолчанию `"data"`) |
|
||||
| `widths` | Массив ширин колонок (применяется ко всем строкам) |
|
||||
| `minHeight` | Минимальная высота первой строки (для шапок) |
|
||||
| `parameters` | Параметры макета — выражения для подстановки |
|
||||
|
||||
#### Синтаксис ячеек
|
||||
|
||||
| Значение | Описание |
|
||||
|----------|----------|
|
||||
| `"текст"` | Статический текст (`v8:LocalStringType`) |
|
||||
| `"{Имя}"` | Параметр шаблона (`dcscor:Parameter`), задаётся через `parameters` |
|
||||
| `"\|"` | Вертикальное объединение с ячейкой выше |
|
||||
| `null` | Пустая ячейка (без содержимого) |
|
||||
|
||||
#### Встроенные пресеты стилей
|
||||
|
||||
| Пресет | Фон | Шрифт | Выравнивание | Перенос | Рамки |
|
||||
|--------|-----|-------|-------------|---------|-------|
|
||||
| `header` | ReportHeaderBackColor | Arial 10 | Center | да | Solid 1px |
|
||||
| `data` | ReportGroup1BackColor | Arial 10 | — | нет | Solid 1px |
|
||||
| `subheader` | — | Arial 10 | Center | да | Solid 1px |
|
||||
| `total` | — | Arial 10 | — | нет | Solid 1px |
|
||||
|
||||
#### Пользовательские пресеты (skd-styles.json)
|
||||
|
||||
Файл `skd-styles.json` в директории определения или в корне проекта. Переопределяет встроенные пресеты или добавляет новые:
|
||||
|
||||
```json
|
||||
{
|
||||
"header": {
|
||||
"bgColor": "style:ReportHeaderBackColor",
|
||||
"borderColor": "style:ReportLineColor",
|
||||
"bold": true
|
||||
},
|
||||
"myStyle": {
|
||||
"font": "Arial", "fontSize": 12,
|
||||
"bgColor": "#FFE0E0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Допустимые ключи: `font`, `fontSize`, `bold`, `italic`, `hAlign`, `vAlign`, `wrap`, `bgColor`, `textColor`, `borderColor`, `borders`. Недостающие ключи берутся из пресета `data`.
|
||||
|
||||
Формат цветов: `"style:ИмяСтиля"` (ссылка на стиль платформы) или `"#RRGGBB"` (прямой цвет).
|
||||
|
||||
### templates — raw XML (fallback)
|
||||
|
||||
Для нестандартных случаев — raw XML вставляется как есть:
|
||||
|
||||
```json
|
||||
"templates": [
|
||||
@@ -728,6 +818,8 @@ XML-маппинг — по `<group>` на каждый элемент:
|
||||
]
|
||||
```
|
||||
|
||||
Детект: если есть `rows` — используется компактный DSL, иначе — raw XML из `template`.
|
||||
|
||||
### groupTemplates
|
||||
|
||||
```json
|
||||
|
||||
@@ -100,6 +100,40 @@
|
||||
- **structure shorthand**: `"Поле1 > Поле2 > details"` — `>` разделяет уровни группировки
|
||||
- **conditionalAppearance**: условное оформление с автоопределением типов значений (Color, Boolean, LocalStringType)
|
||||
|
||||
### Шаблоны вывода — компактный DSL
|
||||
|
||||
Для отчётов с фиксированным оформлением (ФСД, ведомости) — табличное описание вместо raw XML:
|
||||
|
||||
```json
|
||||
"templates": [
|
||||
{
|
||||
"name": "Макет1", "style": "header",
|
||||
"widths": [36, 33, 16, 17], "minHeight": 24.75,
|
||||
"rows": [
|
||||
["Виды кассы", "Валюта", "Остаток на начало\nпериода", "Остаток на конец периода"],
|
||||
["|", "|", "|", "|"],
|
||||
["К1", "К2", "К3", "К4"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Макет2", "style": "data",
|
||||
"widths": [36, 33, 16, 17],
|
||||
"rows": [["{ВидКассы}", "{Валюта}", "{Остаток}", "{ОстатокКонец}"]],
|
||||
"parameters": [
|
||||
{ "name": "ВидКассы", "expression": "Представление(Счет)" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"groupTemplates": [
|
||||
{ "groupField": "Счет", "templateType": "GroupHeader", "template": "Макет1" },
|
||||
{ "groupField": "Счет", "templateType": "Header", "template": "Макет2" }
|
||||
]
|
||||
```
|
||||
|
||||
Синтаксис ячеек: `"текст"` — статика, `"{Имя}"` — параметр, `"|"` — объединение с ячейкой выше, `null` — пустая.
|
||||
|
||||
Встроенные стили: `header` (фон, центр, перенос), `data` (фон группы), `subheader` (без фона, центр), `total` (без фона). Все — Arial 10, рамки Solid 1px, цвета через стили платформы. Пользовательские стили — через `skd-styles.json` в директории проекта.
|
||||
|
||||
### Объектная форма
|
||||
|
||||
Все секции поддерживают полную объектную форму для сложных случаев (title, appearance, role с выражениями, userSettingID, userSettingPresentation, conditionalAppearance, группы фильтров And/Or/Not и т.д.). Подробности — в [спецификации SKD DSL](skd-dsl-spec.md).
|
||||
|
||||
Reference in New Issue
Block a user