246 lines
7.5 KiB
Typst
246 lines
7.5 KiB
Typst
// ==========================================
|
|
// 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,
|
|
)
|
|
}
|