diff --git a/.claude/skills/epf-add-template/SKILL.md b/.claude/skills/epf-add-template/SKILL.md
index 55100184..d005dfc4 100644
--- a/.claude/skills/epf-add-template/SKILL.md
+++ b/.claude/skills/epf-add-template/SKILL.md
@@ -25,7 +25,7 @@ allowed-tools:
|---------------|:------------:|-----------------|--------------------------------------------------|
| ProcessorName | да | — | Имя обработки |
| TemplateName | да | — | Имя макета |
-| TemplateType | да | — | Тип: HTML, Text, SpreadsheetDocument, BinaryData |
+| TemplateType | да | — | Тип: HTML, Text, SpreadsheetDocument, BinaryData, DataCompositionSchema |
| Synonym | нет | = TemplateName | Синоним макета |
| SrcDir | нет | `src` | Каталог исходников |
@@ -45,6 +45,7 @@ pwsh -NoProfile -File .claude/skills/epf-add-template/scripts/add-template.ps1 -
| Text, текстовый документ, текст | TextDocument | `.txt` | Пустой файл |
| SpreadsheetDocument, табличный документ, MXL | SpreadsheetDocument | `.xml` | Минимальный spreadsheet |
| BinaryData, двоичные данные | BinaryData | `.bin` | Пустой файл |
+| DataCompositionSchema, СКД, схема компоновки | DataCompositionSchema | `.xml` | Минимальная DCS-схема |
## Конвенция именования
diff --git a/.claude/skills/epf-add-template/scripts/add-template.ps1 b/.claude/skills/epf-add-template/scripts/add-template.ps1
index a63ac008..456d3444 100644
--- a/.claude/skills/epf-add-template/scripts/add-template.ps1
+++ b/.claude/skills/epf-add-template/scripts/add-template.ps1
@@ -6,7 +6,7 @@
[string]$TemplateName,
[Parameter(Mandatory)]
- [ValidateSet("HTML", "Text", "SpreadsheetDocument", "BinaryData")]
+ [ValidateSet("HTML", "Text", "SpreadsheetDocument", "BinaryData", "DataCompositionSchema")]
[string]$TemplateType,
[string]$Synonym = $TemplateName,
@@ -23,6 +23,7 @@ $typeMap = @{
"Text" = @{ TemplateType = "TextDocument"; Ext = ".txt" }
"SpreadsheetDocument" = @{ TemplateType = "SpreadsheetDocument"; Ext = ".xml" }
"BinaryData" = @{ TemplateType = "BinaryData"; Ext = ".bin" }
+ "DataCompositionSchema" = @{ TemplateType = "DataCompositionSchema"; Ext = ".xml" }
}
$tmpl = $typeMap[$TemplateType]
@@ -111,6 +112,25 @@ switch ($TemplateType) {
"BinaryData" {
[System.IO.File]::WriteAllBytes($templateFilePath, @())
}
+ "DataCompositionSchema" {
+ $content = @"
+
+
+
+ ИсточникДанных1
+ Local
+
+
+"@
+ [System.IO.File]::WriteAllText($templateFilePath, $content, $encBom)
+ }
}
# --- 3. Модификация корневого XML ---
diff --git a/.claude/skills/skd-compile/SKILL.md b/.claude/skills/skd-compile/SKILL.md
index 93fc6350..d4d7f191 100644
--- a/.claude/skills/skd-compile/SKILL.md
+++ b/.claude/skills/skd-compile/SKILL.md
@@ -94,7 +94,20 @@ powershell.exe -NoProfile -File .claude\skills\skd-compile\scripts\skd-compile.p
]
```
-Формат: `"Поле оператор значение @флаги"`. Значение `_` = пустое (placeholder). Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`.
+Формат: `"Поле оператор значение @флаги"`. Значение `_` = пустое (placeholder). Флаги: `@off` (use=false), `@user` (userSettingID=auto), `@quickAccess`, `@normal`, `@inaccessible`.
+
+В объектной форме доступны: `viewMode`, `userSettingID`, `userSettingPresentation`.
+
+Группы фильтров (Or/And/Not):
+```json
+{ "group": "Or", "items": [
+ { "group": "And", "items": [
+ { "field": "Статус", "op": "=", "value": "Активен" },
+ { "field": "Сумма", "op": ">", "value": 1000 }
+ ]},
+ { "field": "Количество", "op": "filled" }
+]}
+```
### Параметры данных — shorthand
@@ -127,6 +140,15 @@ powershell.exe -NoProfile -File .claude\skills\skd-compile\scripts\skd-compile.p
"selection": ["Номенклатура", "Количество", "Auto"],
"filter": ["Организация = _ @off @user"],
"order": ["Количество desc", "Auto"],
+ "conditionalAppearance": [
+ {
+ "filter": ["Просрочено = true"],
+ "appearance": { "ЦветТекста": "style:ПросроченныеДанныеЦвет" },
+ "presentation": "Выделять просроченные",
+ "viewMode": "Normal",
+ "userSettingID": "auto"
+ }
+ ],
"outputParameters": { "Заголовок": "Мой отчёт" },
"dataParameters": ["Период = LastMonth @user"],
"structure": "Организация > details"
@@ -134,6 +156,31 @@ powershell.exe -NoProfile -File .claude\skills\skd-compile\scripts\skd-compile.p
}]
```
+### Условное оформление (conditionalAppearance)
+
+```json
+"conditionalAppearance": [
+ {
+ "selection": ["Поле1"],
+ "filter": ["Поле1 notFilled"],
+ "appearance": { "Текст": "Не указано", "ЦветТекста": "style:XXX" },
+ "presentation": "Описание",
+ "viewMode": "Normal",
+ "userSettingID": "auto"
+ }
+]
+```
+
+Типы значений appearance: `style:XXX`/`web:XXX`/`win:XXX` → Color, `true`/`false` → Boolean, параметр `Текст` → LocalStringType, прочее → String.
+
+### Итоги с привязкой к группировкам
+
+```json
+"totalFields": [
+ { "dataPath": "Кол", "expression": "Сумма(Кол)", "group": ["Группа1", "Группа1 Иерархия", "ОбщийИтог"] }
+]
+```
+
## Примеры
### Минимальный
diff --git a/.claude/skills/skd-compile/scripts/skd-compile.ps1 b/.claude/skills/skd-compile/scripts/skd-compile.ps1
index 8ba7a00d..934986d2 100644
--- a/.claude/skills/skd-compile/scripts/skd-compile.ps1
+++ b/.claude/skills/skd-compile/scripts/skd-compile.ps1
@@ -381,6 +381,14 @@ function Parse-FilterShorthand {
$result.viewMode = "QuickAccess"
$s = $s -replace '\s*@quickAccess', ''
}
+ if ($s -match '@normal') {
+ $result.viewMode = "Normal"
+ $s = $s -replace '\s*@normal', ''
+ }
+ if ($s -match '@inaccessible') {
+ $result.viewMode = "Inaccessible"
+ $s = $s -replace '\s*@inaccessible', ''
+ }
$s = $s.Trim()
@@ -751,14 +759,16 @@ function Emit-TotalFields {
dataPath = "$($tf.dataPath)"
expression = "$($tf.expression)"
}
- if ($tf.group) { $parsed.group = "$($tf.group)" }
+ if ($tf.group) { $parsed.groups = @($tf.group) }
}
X "`t"
X "`t`t$(Esc-Xml $parsed.dataPath)"
X "`t`t$(Esc-Xml $parsed.expression)"
- if ($parsed.group) {
- X "`t`t$(Esc-Xml $parsed.group)"
+ if ($parsed.groups) {
+ foreach ($g in $parsed.groups) {
+ X "`t`t$(Esc-Xml "$g")"
+ }
}
X "`t"
}
@@ -1021,6 +1031,15 @@ function Emit-FilterItem {
X "$indent`t$(Esc-Xml $uid)"
}
+ if ($item.userSettingPresentation) {
+ X "$indent`t"
+ X "$indent`t`t"
+ X "$indent`t`t`tru"
+ X "$indent`t`t`t$(Esc-Xml "$($item.userSettingPresentation)")"
+ X "$indent`t`t"
+ X "$indent`t"
+ }
+
X "$indent"
}
@@ -1088,6 +1107,94 @@ function Emit-Order {
X "$indent"
}
+function Emit-AppearanceValue {
+ param([string]$key, $val, [string]$indent)
+
+ X "$indent"
+ if ($val -is [PSCustomObject] -and $val.use -ne $null -and $val.use -eq $false) {
+ X "$indent`tfalse"
+ X "$indent`t$(Esc-Xml $key)"
+ $actualVal = "$($val.value)"
+ } else {
+ X "$indent`t$(Esc-Xml $key)"
+ $actualVal = "$val"
+ }
+
+ # Auto-detect value type
+ if ($actualVal -match '^(style|web|win):') {
+ X "$indent`t$(Esc-Xml $actualVal)"
+ } elseif ($actualVal -eq "true" -or $actualVal -eq "false") {
+ X "$indent`t$actualVal"
+ } elseif ($key -eq "Текст" -or $key -eq "Заголовок") {
+ X "$indent`t"
+ X "$indent`t`t"
+ X "$indent`t`t`tru"
+ X "$indent`t`t`t$(Esc-Xml $actualVal)"
+ X "$indent`t`t"
+ X "$indent`t"
+ } else {
+ X "$indent`t$(Esc-Xml $actualVal)"
+ }
+ X "$indent"
+}
+
+function Emit-ConditionalAppearance {
+ param($items, [string]$indent)
+
+ if (-not $items -or $items.Count -eq 0) { return }
+
+ X "$indent"
+ foreach ($ca in $items) {
+ X "$indent`t"
+
+ # Selection (which fields to apply to; empty = all)
+ if ($ca.selection -and $ca.selection.Count -gt 0) {
+ X "$indent`t`t"
+ foreach ($sel in $ca.selection) {
+ X "$indent`t`t`t"
+ X "$indent`t`t`t`t$(Esc-Xml "$sel")"
+ X "$indent`t`t`t"
+ }
+ X "$indent`t`t"
+ } else {
+ X "$indent`t`t"
+ }
+
+ # Filter (reuse existing Emit-Filter logic)
+ if ($ca.filter) {
+ Emit-Filter -items $ca.filter -indent "$indent`t`t"
+ }
+
+ # Appearance (parameter-value pairs)
+ if ($ca.appearance) {
+ X "$indent`t`t"
+ foreach ($prop in $ca.appearance.PSObject.Properties) {
+ Emit-AppearanceValue -key $prop.Name -val $prop.Value -indent "$indent`t`t`t"
+ }
+ X "$indent`t`t"
+ }
+
+ # Presentation
+ if ($ca.presentation) {
+ X "$indent`t`t$(Esc-Xml "$($ca.presentation)")"
+ }
+
+ # ViewMode
+ if ($ca.viewMode) {
+ X "$indent`t`t$(Esc-Xml "$($ca.viewMode)")"
+ }
+
+ # UserSettingID
+ if ($ca.userSettingID) {
+ $uid = if ("$($ca.userSettingID)" -eq "auto") { New-Guid-String } else { "$($ca.userSettingID)" }
+ X "$indent`t`t$(Esc-Xml $uid)"
+ }
+
+ X "$indent`t"
+ }
+ X "$indent"
+}
+
function Emit-OutputParameters {
param($params, [string]$indent)
@@ -1183,6 +1290,15 @@ function Emit-DataParameters {
X "$indent`t`t$(Esc-Xml $uid)"
}
+ if ($dp.userSettingPresentation) {
+ X "$indent`t`t"
+ X "$indent`t`t`t"
+ X "$indent`t`t`t`tru"
+ X "$indent`t`t`t`t$(Esc-Xml "$($dp.userSettingPresentation)")"
+ X "$indent`t`t`t"
+ X "$indent`t`t"
+ }
+
X "$indent`t"
}
X "$indent"
@@ -1434,6 +1550,11 @@ function Emit-SettingsVariants {
Emit-Order -items $s.order -indent "`t`t`t" -skipAuto
}
+ # ConditionalAppearance
+ if ($s.conditionalAppearance) {
+ Emit-ConditionalAppearance -items $s.conditionalAppearance -indent "`t`t`t"
+ }
+
# OutputParameters
if ($s.outputParameters) {
Emit-OutputParameters -params $s.outputParameters -indent "`t`t`t"