Correcao Sidebar Classico e Rail, Correcao Layout, Ajuste de Breakpoint para Tailwind, Ajuste AppTopbar, Ajuste Menu PopOver, Recriado Paleta de Cores, Inserido algumas animações leves, Reajuste Cor items NOVOS da tabela, Drawer Ajuda Corrigido no Logout, Whatsapp, sms, email, recursos extras

This commit is contained in:
Leonardo
2026-03-24 21:26:58 -03:00
parent a89d1f5560
commit 53a4980396
453 changed files with 121427 additions and 174407 deletions
+63 -68
View File
@@ -23,86 +23,81 @@
// // No lugar onde saasMenu() é chamado:
// saasMenu(sessionCtx, { mismatchCount, docsAtencaoCount: countAtencao.value })
import { ref, computed } from 'vue'
import { ref, computed } from 'vue';
const THRESHOLD_NEGATIVO = 0.30 // 30%
const MIN_VOTOS = 3 // mínimo de votos para considerar
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([])
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'
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 const countAtencao = computed(() => _docs.value.filter((d) => saudeDocItem(d) === 'atencao').length);
export function useDocsHealth () {
export function useDocsHealth() {
function setDocs(docs) {
_docs.value = docs;
}
function setDocs (docs) {
_docs.value = docs
}
function saudeDoc(doc) {
return saudeDocItem(doc);
}
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);
}
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'));
// ── 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;
});
});
// 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);
});
}
// ── 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,
}
}
return {
setDocs,
saudeDoc,
pctNegativo,
totalDocs,
docsAtencao,
docsOk,
docsSemDados,
countAtencao,
docMaisUtil,
sortBySaude,
THRESHOLD_NEGATIVO,
MIN_VOTOS
};
}