Agenda, Agendador, Configurações

This commit is contained in:
Leonardo
2026-03-12 08:58:36 -03:00
parent f733db8436
commit f4b185ae17
197 changed files with 33405 additions and 6507 deletions
+94
View File
@@ -0,0 +1,94 @@
// src/composables/useDocsHealth.js
// Singleton que computa métricas de saúde dos documentos.
// Critério de "atenção": mais de 30% dos votos são negativos
// (mínimo 3 votos totais para evitar falso-positivo com 1 voto negativo).
//
// O `countAtencao` é exportado como singleton para uso no menu SaaS:
//
// import { countAtencao } from '@/composables/useDocsHealth'
// // No lugar onde saasMenu() é chamado:
// saasMenu(sessionCtx, { mismatchCount, docsAtencaoCount: countAtencao.value })
import { ref, computed } from 'vue'
const THRESHOLD_NEGATIVO = 0.30 // 30%
const MIN_VOTOS = 3 // mínimo de votos para considerar
// Estado singleton — alimentado pelo SaasDocsPage após load()
const _docs = ref([])
// ── Classificação individual (exportada standalone p/ uso externo) ─
export function saudeDocItem (doc) {
const total = (doc.votos_util || 0) + (doc.votos_nao_util || 0)
if (total < MIN_VOTOS) return 'sem_dados'
const pctNeg = (doc.votos_nao_util || 0) / total
return pctNeg > THRESHOLD_NEGATIVO ? 'atencao' : 'ok'
}
// ── Singleton reativo — use no menu ou em qualquer lugar ──────
export const countAtencao = computed(() =>
_docs.value.filter(d => saudeDocItem(d) === 'atencao').length
)
export function useDocsHealth () {
function setDocs (docs) {
_docs.value = docs
}
function saudeDoc (doc) {
return saudeDocItem(doc)
}
function pctNegativo (doc) {
const total = (doc.votos_util || 0) + (doc.votos_nao_util || 0)
if (!total) return 0
return Math.round(((doc.votos_nao_util || 0) / total) * 100)
}
// ── Métricas globais ───────────────────────────────────────
const totalDocs = computed(() => _docs.value.length)
const docsAtencao = computed(() => _docs.value.filter(d => saudeDoc(d) === 'atencao'))
const docsOk = computed(() => _docs.value.filter(d => saudeDoc(d) === 'ok'))
const docsSemDados = computed(() => _docs.value.filter(d => saudeDoc(d) === 'sem_dados'))
// Doc mais útil (maior % positivo com mínimo de votos)
const docMaisUtil = computed(() => {
const comVotos = _docs.value.filter(d =>
(d.votos_util || 0) + (d.votos_nao_util || 0) >= MIN_VOTOS
)
if (!comVotos.length) return null
return comVotos.reduce((best, d) => {
const pct = (d.votos_util || 0) / ((d.votos_util || 0) + (d.votos_nao_util || 0))
const bestPct = (best.votos_util || 0) / ((best.votos_util || 0) + (best.votos_nao_util || 0))
return pct > bestPct ? d : best
})
})
// ── Ordenação por saúde ────────────────────────────────────
// Problemáticas primeiro → ok → sem dados
function sortBySaude (lista) {
const ordem = { atencao: 0, ok: 1, sem_dados: 2 }
return [...lista].sort((a, b) => {
const sa = saudeDoc(a)
const sb = saudeDoc(b)
if (ordem[sa] !== ordem[sb]) return ordem[sa] - ordem[sb]
return pctNegativo(b) - pctNegativo(a)
})
}
return {
setDocs,
saudeDoc,
pctNegativo,
totalDocs,
docsAtencao,
docsOk,
docsSemDados,
countAtencao,
docMaisUtil,
sortBySaude,
THRESHOLD_NEGATIVO,
MIN_VOTOS,
}
}