report.typ 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // ==========================================
  2. // PROFILE: НАУЧНО-ТЕХНИЧЕСКИЙ ОТЧЁТ
  3. // ==========================================
  4. #import "../../domain/document.typ": document-profile, fail
  5. #import "../../domain/attachments.typ": attachment-set
  6. #import "../../report.typ": report, report-toc
  7. #import "../../appendices.typ": make_appendices
  8. #import "../references.typ": render-bibliographies
  9. #let placeholder-path(kind) = {
  10. if kind == "signature" {
  11. path("../../assets/placeholders/signature.svg")
  12. } else if kind == "stamp" {
  13. path("../../assets/placeholders/stamp.svg")
  14. } else {
  15. path("../../assets/placeholders/logo.svg")
  16. }
  17. }
  18. #let report-company-summary(company) = {
  19. let summary = company.contacts.at("summary", default: none)
  20. if summary != none {
  21. summary
  22. } else {
  23. let lines = (company.legal.name,)
  24. let ids = ()
  25. for key in ("inn", "kpp", "ogrn", "bin", "kbe") {
  26. let value = company.legal.at(key, default: none)
  27. if value != none { ids.push(upper(key) + " " + value) }
  28. }
  29. if ids.len() > 0 { lines.push(ids.join(" ")) }
  30. for key in ("address", "phone", "email", "website") {
  31. let value = company.contacts.at(key, default: none)
  32. if value != none { lines.push(value) }
  33. }
  34. lines.join("\n")
  35. }
  36. }
  37. #let resolve-signing-resource(resource, kind, ctx) = {
  38. if ctx.options.mode != "final" {
  39. none
  40. } else if resource != none {
  41. resource
  42. } else if ctx.options.at("media-policy") == "placeholder" {
  43. placeholder-path(kind)
  44. } else {
  45. none
  46. }
  47. }
  48. #let render-report-attachments(attachments) = {
  49. if attachments.items.len() > 0 {
  50. make_appendices([
  51. #for item in attachments.items [
  52. // Метка для ссылок из глав: #ref(<app-...>, supplement: [приложении]).
  53. #if item.at("label", default: none) != none [
  54. #heading(level: 1, outlined: item.outlined)[#item.title] #item.at("label")
  55. ] else [
  56. #heading(level: 1, outlined: item.outlined)[#item.title]
  57. ]
  58. #if item.subtitle != none {
  59. align(center)[#text(weight: "bold")[#item.subtitle]]
  60. v(0.5cm)
  61. }
  62. #if type(item.body) == function { (item.body)() } else { item.body }
  63. ]
  64. ])
  65. }
  66. }
  67. #let normalize-report(metadata) = {
  68. if type(metadata.attachments) == array {
  69. metadata.insert(
  70. "attachments",
  71. attachment-set(items: metadata.attachments, numbering: "cyrillic"),
  72. )
  73. }
  74. metadata
  75. }
  76. #let validate-report(metadata) = {
  77. if type(metadata.title) != str or metadata.title.trim() == "" {
  78. fail("report.title", "название отчёта обязательно")
  79. }
  80. if type(metadata.year) != int {
  81. fail("report.year", "ожидалось целое число")
  82. }
  83. if type(metadata.executors) != array {
  84. fail("report.executors", "ожидался array")
  85. }
  86. if type(metadata.attachments) != dictionary or metadata.attachments.at("kind", default: none) != "attachment-set" {
  87. fail("report.attachments", "ожидался attachment-set")
  88. }
  89. metadata
  90. }
  91. #let render-report(body, ctx) = {
  92. let company = ctx.company
  93. let data = ctx.metadata
  94. let mode = if ctx.options.mode == "final" {
  95. "default"
  96. } else if ctx.options.mode == "clean-copy" {
  97. "paper"
  98. } else {
  99. "draft"
  100. }
  101. let watermark = if ctx.options.mode == "draft" and ctx.options.watermark == none {
  102. "DRAFT"
  103. } else {
  104. ctx.options.watermark
  105. }
  106. let signature = resolve-signing-resource(company.resources.signature, "signature", ctx)
  107. let stamp = resolve-signing-resource(company.resources.stamp, "stamp", ctx)
  108. let logo = if company.resources.logo != none {
  109. company.resources.logo
  110. } else if ctx.options.at("media-policy") == "placeholder" {
  111. placeholder-path("logo")
  112. } else {
  113. none
  114. }
  115. let composed = [
  116. #body
  117. #if ctx.options.toc {
  118. pagebreak()
  119. report-toc()
  120. }
  121. #if ctx.bibliographies.len() > 0 {
  122. pagebreak()
  123. render-bibliographies(ctx.bibliographies)
  124. }
  125. #if ctx.attachments.items.len() > 0 {
  126. render-report-attachments(ctx.attachments)
  127. }
  128. ]
  129. report(
  130. composed,
  131. company_info: report-company-summary(company),
  132. udk: data.udk,
  133. director_company: company.director.title + " " + company.legal.name,
  134. director_name: company.director.name,
  135. director_date: data.at("director-date"),
  136. sign_image: signature,
  137. stamp_image: stamp,
  138. logo_image: logo,
  139. is_research: data.at("is-research"),
  140. is_intermediate: data.at("is-intermediate"),
  141. stage_num: data.at("stage-number"),
  142. vol_num: data.at("volume-number"),
  143. title: data.title,
  144. theme: data.theme,
  145. contract_num: data.at("contract-number"),
  146. contract_date: data.at("contract-date"),
  147. city: data.city,
  148. year: data.year,
  149. executors: data.executors,
  150. figure-before: data.at("figure-before"),
  151. figure-after: data.at("figure-after"),
  152. table-before: data.at("table-before"),
  153. table-after: data.at("table-after"),
  154. figure-caption-before: data.at("figure-caption-before"),
  155. figure-caption-after: data.at("figure-caption-after"),
  156. table-caption-before: data.at("table-caption-before"),
  157. table-caption-after: data.at("table-caption-after"),
  158. report_mode: mode,
  159. watermark: watermark,
  160. )
  161. }
  162. #let report-profile(
  163. title: "Название работы",
  164. theme: none,
  165. udk: none,
  166. director_date: none,
  167. is_research: false,
  168. is_intermediate: false,
  169. stage_number: none,
  170. volume_number: none,
  171. contract_number: none,
  172. contract_date: none,
  173. city: "Екатеринбург",
  174. year: datetime.today().year(),
  175. executors: (),
  176. attachments: attachment-set(numbering: "cyrillic"),
  177. bibliographies: (),
  178. figure_before: 0.75em,
  179. figure_after: 0.75em,
  180. table_before: 0.75em,
  181. table_after: 0.75em,
  182. figure_caption_before: 0pt,
  183. figure_caption_after: 0pt,
  184. table_caption_before: 0pt,
  185. table_caption_after: 0pt,
  186. ) = {
  187. document-profile(
  188. "report",
  189. render-report,
  190. metadata: (
  191. title: title,
  192. theme: theme,
  193. udk: udk,
  194. director-date: director_date,
  195. is-research: is_research,
  196. is-intermediate: is_intermediate,
  197. stage-number: stage_number,
  198. volume-number: volume_number,
  199. contract-number: contract_number,
  200. contract-date: contract_date,
  201. city: city,
  202. year: year,
  203. executors: executors,
  204. parties: (),
  205. attachments: attachments,
  206. bibliographies: bibliographies,
  207. figure-before: figure_before,
  208. figure-after: figure_after,
  209. table-before: table_before,
  210. table-after: table_after,
  211. figure-caption-before: figure_caption_before,
  212. figure-caption-after: figure_caption_after,
  213. table-caption-before: table_caption_before,
  214. table-caption-after: table_caption_after,
  215. ),
  216. normalize: normalize-report,
  217. validate: validate-report,
  218. )
  219. }