Files
agenciapsilmno/src/composables/Usedocshealth.js
T

104 lines
3.9 KiB
JavaScript

/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Criado e desenvolvido por Leonardo Nohama
|
| Tecnologia aplicada à escuta.
| Estrutura para o cuidado.
|
| Arquivo: src/composables/Usedocshealth.js
| Data: 2026
| Local: São Carlos/SP — Brasil
|--------------------------------------------------------------------------
| © 2026 — Todos os direitos reservados
|--------------------------------------------------------------------------
*/
// 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.3; // 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
};
}