Substitui o formato de colunas { key, label } (Nuxt UI v2) pelo formato
correto { id, accessorKey, header } exigido pelo TanStack Table no Nuxt UI v3.
Afetou 7 arquivos: EditaisTable, index, orgaos, concorrentes, contratos,
inteligencia/index e sistema/usuarios.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
3.6 KiB
Vue
86 lines
3.6 KiB
Vue
<!-- front-end/app/pages/inteligencia/index.vue -->
|
|
<script setup lang="ts">
|
|
const { taxaVitoria, valorGanho, ticketMedio, porModalidade, motivoPerda, concorrentesFrequentes } = useInteligencia()
|
|
|
|
const modalidadeLabel: Record<string, string> = {
|
|
pregao_eletronico: 'Pregão Eletrônico',
|
|
pregao_presencial: 'Pregão Presencial',
|
|
concorrencia: 'Concorrência',
|
|
dispensa: 'Dispensa',
|
|
inexigibilidade: 'Inexigibilidade',
|
|
}
|
|
|
|
const fmt = (v: number) => new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', maximumFractionDigits: 0 }).format(v)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page">
|
|
<AppTopbar title="Inteligência de Mercado" breadcrumb="Inteligência" />
|
|
<div class="content">
|
|
|
|
<!-- Stats topo -->
|
|
<div class="stats-grid mb-4">
|
|
<StatCard label="Taxa de Vitória" :value="`${taxaVitoria}%`" color="#10b981" sub="Processos ganhos" />
|
|
<StatCard label="Valor Ganho Total" :value="fmt(valorGanho)" color="#667eea" />
|
|
<StatCard label="Ticket Médio" :value="fmt(ticketMedio)" color="#764ba2" />
|
|
<StatCard label="Concorrentes" :value="concorrentesFrequentes.length" sub="Cadastrados" />
|
|
</div>
|
|
|
|
<div class="grid-2 mb-4">
|
|
<!-- Por modalidade -->
|
|
<div class="card">
|
|
<div class="card-header"><h3>Modalidades</h3></div>
|
|
<div class="pad">
|
|
<div v-for="(val, key) in porModalidade" :key="key" class="modal-row">
|
|
<span class="modal-nome">{{ modalidadeLabel[key] }}</span>
|
|
<span class="modal-stats">{{ val.vitorias }}/{{ val.total }} — {{ val.total > 0 ? Math.round((val.vitorias / val.total) * 100) : 0 }}%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Motivo de perda -->
|
|
<div class="card">
|
|
<div class="card-header"><h3>Classificação de Perdas</h3></div>
|
|
<div class="pad">
|
|
<div v-for="m in motivoPerda" :key="m.motivo" class="modal-row">
|
|
<span class="modal-nome">{{ m.motivo }}</span>
|
|
<UBadge :label="String(m.quantidade)" variant="soft" color="error" size="xs" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Concorrentes frequentes -->
|
|
<div class="card">
|
|
<div class="card-header"><h3>Concorrentes Mais Frequentes</h3></div>
|
|
<UTable
|
|
:data="concorrentesFrequentes"
|
|
:columns="[
|
|
{ id: 'nome', accessorKey: 'nome', header: 'Empresa' },
|
|
{ id: 'cnpj', accessorKey: 'cnpj', header: 'CNPJ' },
|
|
{ id: 'totalDisputas', accessorKey: 'totalDisputas', header: 'Disputas' },
|
|
{ id: 'totalVitorias', accessorKey: 'totalVitorias', header: 'Vitórias' },
|
|
]"
|
|
/>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.page { display: flex; flex-direction: column; height: 100vh; }
|
|
.content { padding: 20px 22px; flex: 1; overflow-y: auto; }
|
|
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
|
|
.mb-4 { margin-bottom: 14px; }
|
|
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
|
.card { background: white; border-radius: 11px; border: 1px solid #e2e8f0; overflow: hidden; }
|
|
.card-header { padding: 14px 18px 10px; border-bottom: 1px solid #f1f5f9; }
|
|
.card-header h3 { font-size: 13px; font-weight: 700; color: #0f172a; }
|
|
.pad { padding: 12px 18px; }
|
|
.modal-row { display: flex; justify-content: space-between; align-items: center; padding: 7px 0; border-bottom: 1px solid #f8fafc; font-size: 12px; }
|
|
.modal-row:last-child { border-bottom: none; }
|
|
.modal-nome { color: #374151; }
|
|
.modal-stats { font-weight: 600; color: #667eea; }
|
|
</style>
|