Initial commit

This commit is contained in:
tkachenko committed 2026-10-09 01:45:17 +00:00
commit 41d230d524
163 files changed
+11500

No files matched your search

@@ -0,0 +1,245 @@
// ==========================================
// PROFILE: НАУЧНО-ТЕХНИЧЕСКИЙ ОТЧЁТ
// ==========================================
#import "../../domain/document.typ": document-profile, fail
#import "../../domain/attachments.typ": attachment-set
#import "../../report.typ": report
#import "../../appendices.typ": make_appendices
#import "../references.typ": render-bibliographies
#let placeholder-path(kind) = {
if kind == "signature" {
path("../../assets/placeholders/signature.svg")
} else if kind == "stamp" {
path("../../assets/placeholders/stamp.svg")
} else {
path("../../assets/placeholders/logo.svg")
}
}
#let report-company-summary(company) = {
let summary = company.contacts.at("summary", default: none)
if summary != none {
summary
} else {
let lines = (company.legal.name,)
let ids = ()
for key in ("inn", "kpp", "ogrn", "bin", "kbe") {
let value = company.legal.at(key, default: none)
if value != none { ids.push(upper(key) + " " + value) }
}
if ids.len() > 0 { lines.push(ids.join(" ")) }
for key in ("address", "phone", "email", "website") {
let value = company.contacts.at(key, default: none)
if value != none { lines.push(value) }
}
lines.join("\n")
}
}
#let resolve-signing-resource(resource, kind, ctx) = {
if ctx.options.mode != "final" {
none
} else if resource != none {
resource
} else if ctx.options.at("media-policy") == "placeholder" {
placeholder-path(kind)
} else {
none
}
}
#let render-report-appendices(sources, numbering, start) = {
if sources.len() > 0 {
make_appendices(
[
#for source in sources {
include(source)
}
],
numbering: numbering,
start: start,
)
}
}
#let normalize-report(metadata) = metadata
#let validate-report(metadata) = {
if type(metadata.title) != str or metadata.title.trim() == "" {
fail("report.title", "название отчёта обязательно")
}
if type(metadata.year) != int {
fail("report.year", "ожидалось целое число")
}
if type(metadata.executors) != array {
fail("report.executors", "ожидался array")
}
for key in ("show-title-page", "show-executors", "show-outline") {
if type(metadata.at(key)) != bool {
fail("report." + key, "ожидался bool")
}
}
if type(metadata.appendices) != array {
fail("report.appendices", "ожидался array путей к файлам")
}
let seen = ()
for source in metadata.appendices {
if type(source) != path {
fail("report.appendices", "каждый элемент должен быть path(...)")
}
if source in seen {
fail("report.appendices", "файл указан повторно: " + repr(source))
}
seen.push(source)
}
if metadata.at("appendix-numbering") not in ("cyrillic", "arabic", "none") {
fail("report.appendix-numbering", "допустимы cyrillic, arabic или none")
}
if type(metadata.at("appendix-start")) != int or metadata.at("appendix-start") < 1 {
fail("report.appendix-start", "нужно положительное целое число")
}
metadata
}
#let render-report(body, ctx) = {
let company = ctx.company
let data = ctx.metadata
let mode = if ctx.options.mode == "final" { "default" } else { "draft" }
let watermark = if ctx.options.mode == "draft" and ctx.options.watermark == none {
"DRAFT"
} else {
ctx.options.watermark
}
let signature = resolve-signing-resource(company.resources.signature, "signature", ctx)
let stamp = resolve-signing-resource(company.resources.stamp, "stamp", ctx)
let logo = if company.resources.logo != none {
company.resources.logo
} else if ctx.options.at("media-policy") == "placeholder" {
placeholder-path("logo")
} else {
none
}
let composed = [
#body
#if ctx.bibliographies.len() > 0 {
pagebreak()
render-bibliographies(ctx.bibliographies)
}
#if data.appendices.len() > 0 {
render-report-appendices(
data.appendices,
data.at("appendix-numbering"),
data.at("appendix-start"),
)
}
]
report(
composed,
company_info: report-company-summary(company),
udk: data.udk,
director_company: company.director.title + " " + company.legal.name,
director_name: company.director.name,
director_date: data.at("director-date"),
sign_image: signature,
stamp_image: stamp,
logo_image: logo,
is_research: data.at("is-research"),
is_intermediate: data.at("is-intermediate"),
stage_num: data.at("stage-number"),
vol_num: data.at("volume-number"),
title: data.title,
theme: data.theme,
contract_num: data.at("contract-number"),
contract_date: data.at("contract-date"),
city: data.city,
year: data.year,
executors: data.executors,
figure-before: data.at("figure-before"),
figure-after: data.at("figure-after"),
table-before: data.at("table-before"),
table-after: data.at("table-after"),
figure-caption-before: data.at("figure-caption-before"),
figure-caption-after: data.at("figure-caption-after"),
table-caption-before: data.at("table-caption-before"),
table-caption-after: data.at("table-caption-after"),
show_title_page: data.at("show-title-page"),
show_executors: data.at("show-executors"),
show_outline: data.at("show-outline"),
report_mode: mode,
watermark: watermark,
)
}
#let report-profile(
title: "Название работы",
theme: none,
udk: none,
director_date: none,
is_research: false,
is_intermediate: false,
stage_number: none,
volume_number: none,
contract_number: none,
contract_date: none,
city: "Екатеринбург",
year: datetime.today().year(),
executors: (),
appendices: (),
appendix_numbering: "cyrillic",
appendix_start: 1,
bibliographies: (),
show_title_page: true,
show_executors: true,
show_outline: true,
figure_before: 0.75em,
figure_after: 0.75em,
table_before: 0.75em,
table_after: 0.75em,
figure_caption_before: 0pt,
figure_caption_after: 0pt,
table_caption_before: 0pt,
table_caption_after: 0pt,
) = {
document-profile(
"report",
render-report,
metadata: (
title: title,
theme: theme,
udk: udk,
director-date: director_date,
is-research: is_research,
is-intermediate: is_intermediate,
stage-number: stage_number,
volume-number: volume_number,
contract-number: contract_number,
contract-date: contract_date,
city: city,
year: year,
executors: executors,
parties: (),
// Общая attachment-модель остаётся для писем и договоров. Отчётные
// приложения являются самодостаточными Typst-файлами.
attachments: attachment-set(),
appendices: appendices,
appendix-numbering: appendix_numbering,
appendix-start: appendix_start,
bibliographies: bibliographies,
show-title-page: show_title_page,
show-executors: show_executors,
show-outline: show_outline,
figure-before: figure_before,
figure-after: figure_after,
table-before: table_before,
table-after: table_after,
figure-caption-before: figure_caption_before,
figure-caption-after: figure_caption_after,
table-caption-before: table_caption_before,
table-caption-after: table_caption_after,
),
normalize: normalize-report,
validate: validate-report,
)
}