// ========================================== // 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, ) }