report.typ 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // ==========================================
  2. // PROFILE: НАУЧНО-ТЕХНИЧЕСКИЙ ОТЧЁТ
  3. // ==========================================
  4. #import "../../domain/document.typ": document-profile, fail
  5. #import "../../domain/attachments.typ": attachment-set
  6. #import "../../report.typ": report
  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. heading(level: 1, outlined: item.outlined)[#item.title]
  53. if item.subtitle != none {
  54. align(center)[#text(weight: "bold")[#item.subtitle]]
  55. v(0.5cm)
  56. }
  57. if type(item.body) == function { (item.body)() } else { item.body }
  58. }
  59. ])
  60. }
  61. }
  62. #let normalize-report(metadata) = {
  63. if type(metadata.attachments) == array {
  64. metadata.insert(
  65. "attachments",
  66. attachment-set(items: metadata.attachments, numbering: "cyrillic"),
  67. )
  68. }
  69. metadata
  70. }
  71. #let validate-report(metadata) = {
  72. if type(metadata.title) != str or metadata.title.trim() == "" {
  73. fail("report.title", "название отчёта обязательно")
  74. }
  75. if type(metadata.year) != int {
  76. fail("report.year", "ожидалось целое число")
  77. }
  78. if type(metadata.executors) != array {
  79. fail("report.executors", "ожидался array")
  80. }
  81. if type(metadata.attachments) != dictionary or metadata.attachments.at("kind", default: none) != "attachment-set" {
  82. fail("report.attachments", "ожидался attachment-set")
  83. }
  84. metadata
  85. }
  86. #let render-report(body, ctx) = {
  87. let company = ctx.company
  88. let data = ctx.metadata
  89. let mode = if ctx.options.mode == "final" { "default" } else { "draft" }
  90. let watermark = if ctx.options.mode == "draft" and ctx.options.watermark == none {
  91. "DRAFT"
  92. } else {
  93. ctx.options.watermark
  94. }
  95. let signature = resolve-signing-resource(company.resources.signature, "signature", ctx)
  96. let stamp = resolve-signing-resource(company.resources.stamp, "stamp", ctx)
  97. let logo = if company.resources.logo != none {
  98. company.resources.logo
  99. } else if ctx.options.at("media-policy") == "placeholder" {
  100. placeholder-path("logo")
  101. } else {
  102. none
  103. }
  104. let composed = [
  105. #body
  106. #if ctx.bibliographies.len() > 0 {
  107. pagebreak()
  108. render-bibliographies(ctx.bibliographies)
  109. }
  110. #if ctx.attachments.items.len() > 0 {
  111. render-report-attachments(ctx.attachments)
  112. }
  113. ]
  114. report(
  115. composed,
  116. company_info: report-company-summary(company),
  117. udk: data.udk,
  118. director_company: company.director.title + " " + company.legal.name,
  119. director_name: company.director.name,
  120. director_date: data.at("director-date"),
  121. sign_image: signature,
  122. stamp_image: stamp,
  123. logo_image: logo,
  124. is_research: data.at("is-research"),
  125. is_intermediate: data.at("is-intermediate"),
  126. stage_num: data.at("stage-number"),
  127. vol_num: data.at("volume-number"),
  128. title: data.title,
  129. theme: data.theme,
  130. contract_num: data.at("contract-number"),
  131. contract_date: data.at("contract-date"),
  132. city: data.city,
  133. year: data.year,
  134. executors: data.executors,
  135. figure-before: data.at("figure-before"),
  136. figure-after: data.at("figure-after"),
  137. table-before: data.at("table-before"),
  138. table-after: data.at("table-after"),
  139. figure-caption-before: data.at("figure-caption-before"),
  140. figure-caption-after: data.at("figure-caption-after"),
  141. table-caption-before: data.at("table-caption-before"),
  142. table-caption-after: data.at("table-caption-after"),
  143. report_mode: mode,
  144. watermark: watermark,
  145. )
  146. }
  147. #let report-profile(
  148. title: "Название работы",
  149. theme: none,
  150. udk: none,
  151. director_date: none,
  152. is_research: false,
  153. is_intermediate: false,
  154. stage_number: none,
  155. volume_number: none,
  156. contract_number: none,
  157. contract_date: none,
  158. city: "Екатеринбург",
  159. year: datetime.today().year(),
  160. executors: (),
  161. attachments: attachment-set(numbering: "cyrillic"),
  162. bibliographies: (),
  163. figure_before: 0.75em,
  164. figure_after: 0.75em,
  165. table_before: 0.75em,
  166. table_after: 0.75em,
  167. figure_caption_before: 0pt,
  168. figure_caption_after: 0pt,
  169. table_caption_before: 0pt,
  170. table_caption_after: 0pt,
  171. ) = {
  172. document-profile(
  173. "report",
  174. render-report,
  175. metadata: (
  176. title: title,
  177. theme: theme,
  178. udk: udk,
  179. director-date: director_date,
  180. is-research: is_research,
  181. is-intermediate: is_intermediate,
  182. stage-number: stage_number,
  183. volume-number: volume_number,
  184. contract-number: contract_number,
  185. contract-date: contract_date,
  186. city: city,
  187. year: year,
  188. executors: executors,
  189. parties: (),
  190. attachments: attachments,
  191. bibliographies: bibliographies,
  192. figure-before: figure_before,
  193. figure-after: figure_after,
  194. table-before: table_before,
  195. table-after: table_after,
  196. figure-caption-before: figure_caption_before,
  197. figure-caption-after: figure_caption_after,
  198. table-caption-before: table_caption_before,
  199. table-caption-after: table_caption_after,
  200. ),
  201. normalize: normalize-report,
  202. validate: validate-report,
  203. )
  204. }