OmniBoard/resources/js/Components/AgentListCompact.vue

115 lines
5.7 KiB
Vue

<script setup>
import { computed, ref } from 'vue';
import { Link } from '@inertiajs/vue3';
const props = defineProps({
agents: Array
});
const search = ref('');
// Estatísticas Rápidas
const stats = computed(() => {
const total = props.agents.length;
if (total === 0) return { online: 0, talking: 0, paused: 0 };
return {
online: props.agents.filter(a => a.status !== 'offline').length,
talking: props.agents.filter(a => a.status === 'talking').length,
paused: props.agents.filter(a => a.status === 'paused').length
};
});
// Filtro e Ordenação
const filteredAgents = computed(() => {
const term = search.value.toLowerCase();
// 1. Filtra por nome ou ramal
let list = props.agents.filter(a =>
a.name.toLowerCase().includes(term) ||
a.interface.toLowerCase().includes(term)
);
// 2. Ordena: Falando > Pausado > Livre > Offline
const priority = { talking: 1, paused: 2, available: 3, offline: 4 };
return list.sort((a, b) => (priority[a.status] || 99) - (priority[b.status] || 99));
});
const getStatusColor = (status) => {
switch(status) {
case 'available': return 'text-green-600 bg-green-50 border-green-100';
case 'paused': return 'text-yellow-600 bg-yellow-50 border-yellow-100';
case 'talking': return 'text-blue-600 bg-blue-50 border-blue-100';
default: return 'text-gray-400 bg-gray-50 border-gray-100';
}
};
const getStatusDot = (status) => {
switch(status) {
case 'available': return 'bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]';
case 'paused': return 'bg-yellow-500';
case 'talking': return 'bg-blue-500 shadow-[0_0_8px_rgba(59,130,246,0.6)]';
default: return 'bg-gray-300';
}
};
</script>
<template>
<div class="bg-white rounded-xl shadow-sm border border-gray-100 flex flex-col h-full max-h-[calc(100vh-200px)]">
<div class="p-4 border-b border-gray-50">
<div class="flex justify-between items-center mb-3">
<h3 class="font-bold text-gray-800">Equipe</h3>
<Link :href="route('agents.index')" class="text-xs text-indigo-600 hover:underline">
Ver Detalhes &rarr;
</Link>
</div>
<div class="flex gap-1 h-1.5 mb-3 rounded-full overflow-hidden bg-gray-100">
<div class="bg-blue-500 transition-all duration-500" :style="{ width: (stats.talking / agents.length * 100) + '%' }"></div>
<div class="bg-yellow-500 transition-all duration-500" :style="{ width: (stats.paused / agents.length * 100) + '%' }"></div>
<div class="bg-green-500 transition-all duration-500" :style="{ width: ((stats.online - stats.talking - stats.paused) / agents.length * 100) + '%' }"></div>
</div>
<div class="relative">
<input v-model="search" type="text" placeholder="Buscar agente..."
class="w-full pl-8 pr-3 py-1.5 text-xs border border-gray-200 rounded-lg focus:ring-indigo-500 focus:border-indigo-500 bg-gray-50 transition focus:bg-white" />
<svg class="w-3.5 h-3.5 text-gray-400 absolute left-2.5 top-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
</div>
</div>
<div class="flex-1 overflow-y-auto custom-scrollbar p-2 space-y-1">
<div v-for="agent in filteredAgents" :key="agent.id"
class="group p-2.5 rounded-lg hover:bg-gray-50 transition flex items-center justify-between border border-transparent hover:border-gray-100">
<div class="flex items-center gap-3 overflow-hidden">
<div :class="`flex-shrink-0 h-2.5 w-2.5 rounded-full ${getStatusDot(agent.status)} transition-colors`"></div>
<div class="min-w-0">
<p class="text-sm font-semibold text-gray-700 truncate group-hover:text-indigo-600 transition-colors">
{{ agent.name }}
</p>
<p class="text-[10px] text-gray-400 font-mono truncate">{{ agent.interface }}</p>
</div>
</div>
<div v-if="agent.status !== 'offline'" class="flex-shrink-0">
<span :class="`px-2 py-0.5 rounded text-[9px] font-bold uppercase border ${getStatusColor(agent.status)}`">
<span v-if="agent.status === 'paused'">{{ agent.pause_reason || 'Pausa' }}</span>
<span v-else-if="agent.status === 'talking'">Falando</span>
<span v-else>Livre</span>
</span>
</div>
</div>
<div v-if="filteredAgents.length === 0" class="text-center py-6">
<p class="text-xs text-gray-400">Ninguém encontrado.</p>
</div>
</div>
</div>
</template>
<style scoped>
/* Scrollbar fina e elegante */
.custom-scrollbar::-webkit-scrollbar { width: 4px; }
.custom-scrollbar::-webkit-scrollbar-track { background: transparent; }
.custom-scrollbar::-webkit-scrollbar-thumb { background-color: #e5e7eb; border-radius: 20px; }
</style>