mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 06:43:06 +00:00
O builder cortava o texto no meio com "…" quando não cabia no A4, perdendo informação. Agora: - contrato de pesquisa ganha `brief` (`title` ≤80 / `note` ≤120) reescrito pelo researcher: o PDF imprime o brief reformulado e o registro/.md mantém `answer`/`details` integrais (sem fonte nova, sem trocar a fase); - sem `brief` o renderer cai no texto completo e a guarda de fit A4 falha fechado — nunca mais corta em silêncio; - tabelas longas (lacunas, notícias) e os cards de "Atuação registrada" das eras são paginados em folhas de continuação: nada é truncado nem descartado; - corrige honrarias da Era C vazando para a página da Era B; - remove o `clipCopy`/`MAX_NEWS_ROWS`; SKILL.md e agent doc documentam o `brief`.
71 lines
2.4 KiB
JavaScript
71 lines
2.4 KiB
JavaScript
/**
|
|
* Boletim model (C186): one A4 page, voter-facing. It reads ONLY the
|
|
* `bulletinFacts` ledger produced by `buildDossierReport` — every fact there
|
|
* already carries a source, so the boletim cannot introduce a new fact. No
|
|
* sources are printed (they live in the dossiê).
|
|
*/
|
|
|
|
import { formatDateTimeBr } from './cityReportFormat.mjs'
|
|
import { dossierSphereLabel } from './dossieBlocks.mjs'
|
|
import { BULLETIN_TIMELINE_STEPS } from './dossieCareer.mjs'
|
|
|
|
export const BULLETIN_HIGHLIGHT_LIMIT = 6
|
|
export const BULLETIN_MORE_LIMIT = 14
|
|
|
|
const sphereRank = { municipio: 0, regiao: 1, polo: 2 }
|
|
const eraRank = { C: 0, B: 1, A: 2 }
|
|
|
|
const rankFacts = (facts) =>
|
|
[...facts].sort((left, right) => {
|
|
const sphere = (sphereRank[left.sphere] ?? 9) - (sphereRank[right.sphere] ?? 9)
|
|
if (sphere !== 0) return sphere
|
|
const hasValue = (left.value ? 0 : 1) - (right.value ? 0 : 1)
|
|
if (hasValue !== 0) return hasValue
|
|
const era = (eraRank[left.era] ?? 9) - (eraRank[right.era] ?? 9)
|
|
if (era !== 0) return era
|
|
return String(left.id).localeCompare(String(right.id))
|
|
})
|
|
|
|
/**
|
|
* @param {{
|
|
* facts?: Array<{ id: string, era: string, sphere: string, area: string, headline: string, detail: string|null, value: string|null, year: string|null, phase: string|null, sourceUrl: string, sourceDate: string }>,
|
|
* municipality: string,
|
|
* region?: string | null,
|
|
* generatedAt?: Date,
|
|
* }} params
|
|
*/
|
|
export const buildBulletin = ({
|
|
facts = [],
|
|
municipality,
|
|
region = null,
|
|
generatedAt = new Date(),
|
|
}) => {
|
|
const ordered = rankFacts(facts)
|
|
const highlights = ordered.slice(0, BULLETIN_HIGHLIGHT_LIMIT).map((fact) => ({
|
|
eyebrow: `${fact.area ?? 'Atuação'} · ${dossierSphereLabel(fact.sphere)}`,
|
|
number: fact.value,
|
|
title: fact.brief?.title ?? fact.headline,
|
|
note: fact.brief?.note ?? fact.detail,
|
|
}))
|
|
const moreItems = ordered
|
|
.slice(BULLETIN_HIGHLIGHT_LIMIT, BULLETIN_HIGHLIGHT_LIMIT + BULLETIN_MORE_LIMIT)
|
|
.map((fact) => ({
|
|
label: fact.brief?.title ?? fact.headline,
|
|
detail: fact.brief?.note ?? fact.detail ?? fact.value ?? fact.area,
|
|
}))
|
|
|
|
return {
|
|
meta: {
|
|
title: 'Boletim informativo modelo',
|
|
kicker: 'Boletim informativo · atuação pública',
|
|
municipality,
|
|
region,
|
|
generatedAt,
|
|
generatedAtLabel: formatDateTimeBr(generatedAt),
|
|
modelLabel: 'Modelo — insumo interno',
|
|
},
|
|
highlights,
|
|
moreItems,
|
|
timeline: BULLETIN_TIMELINE_STEPS,
|
|
}
|
|
}
|