report.typ 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. // Метка для ссылок из глав: #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.bibliographies.len() > 0 {
  118. pagebreak()
  119. render-bibliographies(ctx.bibliographies)
  120. }
  121. #if ctx.attachments.items.len() > 0 {
  122. render-report-attachments(ctx.attachments)
  123. }
  124. ]
  125. report(
  126. composed,
  127. company_info: report-company-summary(company),
  128. udk: data.udk,
  129. director_company: company.director.title + " " + company.legal.name,
  130. director_name: company.director.name,
  131. director_date: data.at("director-date"),
  132. sign_image: signature,
  133. stamp_image: stamp,
  134. logo_image: logo,
  135. is_research: data.at("is-research"),
  136. is_intermediate: data.at("is-intermediate"),
  137. stage_num: data.at("stage-number"),
  138. vol_num: data.at("volume-number"),
  139. title: data.title,
  140. theme: data.theme,
  141. contract_num: data.at("contract-number"),
  142. contract_date: data.at("contract-date"),
  143. city: data.city,
  144. year: data.year,
  145. executors: data.executors,
  146. figure-before: data.at("figure-before"),
  147. figure-after: data.at("figure-after"),
  148. table-before: data.at("table-before"),
  149. table-after: data.at("table-after"),
  150. figure-caption-before: data.at("figure-caption-before"),
  151. figure-caption-after: data.at("figure-caption-after"),
  152. table-caption-before: data.at("table-caption-before"),
  153. table-caption-after: data.at("table-caption-after"),
  154. report_mode: mode,
  155. watermark: watermark,
  156. )
  157. }
  158. #let report-profile(
  159. title: "Название работы",
  160. theme: none,
  161. udk: none,
  162. director_date: none,
  163. is_research: false,
  164. is_intermediate: false,
  165. stage_number: none,
  166. volume_number: none,
  167. contract_number: none,
  168. contract_date: none,
  169. city: "Екатеринбург",
  170. year: datetime.today().year(),
  171. executors: (),
  172. attachments: attachment-set(numbering: "cyrillic"),
  173. bibliographies: (),
  174. figure_before: 0.75em,
  175. figure_after: 0.75em,
  176. table_before: 0.75em,
  177. table_after: 0.75em,
  178. figure_caption_before: 0pt,
  179. figure_caption_after: 0pt,
  180. table_caption_before: 0pt,
  181. table_caption_after: 0pt,
  182. ) = {
  183. document-profile(
  184. "report",
  185. render-report,
  186. metadata: (
  187. title: title,
  188. theme: theme,
  189. udk: udk,
  190. director-date: director_date,
  191. is-research: is_research,
  192. is-intermediate: is_intermediate,
  193. stage-number: stage_number,
  194. volume-number: volume_number,
  195. contract-number: contract_number,
  196. contract-date: contract_date,
  197. city: city,
  198. year: year,
  199. executors: executors,
  200. parties: (),
  201. attachments: attachments,
  202. bibliographies: bibliographies,
  203. figure-before: figure_before,
  204. figure-after: figure_after,
  205. table-before: table_before,
  206. table-after: table_after,
  207. figure-caption-before: figure_caption_before,
  208. figure-caption-after: figure_caption_after,
  209. table-caption-before: table_caption_before,
  210. table-caption-after: table_caption_after,
  211. ),
  212. normalize: normalize-report,
  213. validate: validate-report,
  214. )
  215. }