saap-deploy / frontend /src /components /modals /MultiAgentChatModal_Fixed.vue
Hwandji's picture
SAAP platform foundation
0a61b60
<template>
<div class="multi-agent-chat-modal">
<!-- Modal Backdrop -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click="closeModal">
<!-- Modal Container - Vergrößert für bessere Lesbarkeit -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-4xl max-h-[90vh] flex flex-col" @click.stop>
<!-- Modal Header -->
<div class="flex justify-between items-center p-6 border-b border-gray-200 dark:border-gray-700">
<div class="flex items-center space-x-3">
<div class="w-3 h-3 bg-purple-500 rounded-full"></div>
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">
🤖 Multi-Agent Communication
</h2>
</div>
<button @click="closeModal" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Available Specialists Section -->
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-700">
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">Verfügbare Spezialisten</h3>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-2">
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-teal-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">John Alesi</div>
<div class="text-gray-500 dark:text-gray-400">Development</div>
</div>
</div>
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-pink-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">Lara Alesi</div>
<div class="text-gray-500 dark:text-gray-400">Medical</div>
</div>
</div>
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-yellow-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">Justus Alesi</div>
<div class="text-gray-500 dark:text-gray-400">Legal</div>
</div>
</div>
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-orange-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">Theo Alesi</div>
<div class="text-gray-500 dark:text-gray-400">Finance</div>
</div>
</div>
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-blue-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">Leon Alesi</div>
<div class="text-gray-500 dark:text-gray-400">System</div>
</div>
</div>
<div class="flex items-center space-x-2 bg-white dark:bg-gray-800 px-3 py-2 rounded-lg shadow-sm">
<div class="w-2 h-2 bg-red-500 rounded-full"></div>
<div class="text-xs">
<div class="font-medium text-gray-900 dark:text-white">Luna Alesi</div>
<div class="text-gray-500 dark:text-gray-400">Coaching</div>
</div>
</div>
</div>
</div>
<!-- Chat Messages Area - VERGRÖSSERT für bessere Lesbarkeit -->
<div class="chat-messages flex-1 overflow-y-auto p-6 space-y-4"
style="min-height: 400px; max-height: 500px;">
<!-- Coordinator Status -->
<div class="flex items-start space-x-3">
<div class="w-8 h-8 bg-purple-500 rounded-full flex items-center justify-center">
<span class="text-white text-xs font-semibold">👑</span>
</div>
<div class="flex-1">
<div class="flex items-center space-x-2">
<span class="font-medium text-purple-600 dark:text-purple-400">Jane Alesi</span>
<span class="text-xs text-gray-500 dark:text-gray-400">(Master Coordinator)</span>
<span class="text-xs text-gray-400 dark:text-gray-500">18:50:28</span>
</div>
<div class="mt-1 text-sm text-gray-700 dark:text-gray-300">
Bereit für automatische Spezialist-Delegation. Stelle eine Frage oder gib eine Aufgabe ein...
</div>
</div>
</div>
<!-- Messages Container with better spacing -->
<div v-for="message in messages" :key="message.id" class="message-item py-3">
<!-- User Message -->
<div v-if="message.type === 'user'" class="flex justify-end mb-4">
<div class="max-w-lg">
<div class="bg-blue-500 text-white px-4 py-3 rounded-lg rounded-br-none">
<div class="font-medium text-sm">{{ message.content }}</div>
</div>
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1 text-right">
{{ formatTime(message.timestamp) }}
</div>
</div>
</div>
<!-- Agent Response -->
<div v-else-if="message.type === 'agent'" class="flex items-start space-x-3 mb-4">
<div class="w-8 h-8 rounded-full flex items-center justify-center"
:class="getAgentColor(message.agent)">
<span class="text-white text-xs font-semibold">
{{ getAgentInitial(message.agent) }}
</span>
</div>
<div class="flex-1">
<div class="flex items-center space-x-2">
<span class="font-medium" :class="getAgentTextColor(message.agent)">
{{ message.agent }}
</span>
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ formatTime(message.timestamp) }}
</span>
<span v-if="message.responseTime" class="text-xs text-gray-400 dark:text-gray-500">
• {{ message.responseTime }}s
</span>
</div>
<div class="mt-2 bg-gray-50 dark:bg-gray-700 px-4 py-3 rounded-lg">
<div class="text-sm text-gray-800 dark:text-gray-200 leading-relaxed">
{{ message.content }}
</div>
<div v-if="message.cost" class="mt-2 text-xs text-gray-500 dark:text-gray-400">
Cost: {{ message.cost }}
</div>
</div>
</div>
</div>
</div>
<!-- Loading State -->
<div v-if="isLoading" class="flex items-start space-x-3">
<div class="w-8 h-8 bg-purple-500 rounded-full flex items-center justify-center">
<div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
</div>
<div class="flex-1">
<div class="bg-gray-50 dark:bg-gray-700 px-4 py-3 rounded-lg">
<div class="flex items-center space-x-2 text-sm text-gray-600 dark:text-gray-400">
<div class="flex space-x-1">
<div class="w-2 h-2 bg-purple-500 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-purple-500 rounded-full animate-bounce" style="animation-delay: 0.1s"></div>
<div class="w-2 h-2 bg-purple-500 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
</div>
<span>{{ loadingText }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Input Area -->
<div class="p-6 border-t border-gray-200 dark:border-gray-700">
<div class="flex items-end space-x-3">
<div class="flex-1">
<textarea
v-model="message"
@keydown.enter.exact.prevent="sendMessage"
@keydown.enter.shift.exact="insertNewline"
placeholder="Stelle eine Frage oder gib eine Aufgabe ein..."
class="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg
focus:ring-2 focus:ring-purple-500 focus:border-purple-500
dark:bg-gray-700 dark:text-white resize-y min-h-[60px] max-h-32"
rows="2"
></textarea>
<div class="mt-2 flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
<span>Enter zum Senden • Shift+Enter für neue Zeile</span>
<div class="flex items-center space-x-4">
<span>Priorität:</span>
<select v-model="priority" class="bg-transparent border-none text-gray-600 dark:text-gray-400">
<option value="normal">Normal</option>
<option value="high">Hoch</option>
<option value="urgent">Dringend</option>
</select>
</div>
</div>
</div>
<button
@click="sendMessage"
:disabled="!message.trim() || isLoading"
class="px-6 py-3 bg-purple-600 hover:bg-purple-700 disabled:bg-gray-300
text-white rounded-lg font-medium transition-colors flex items-center space-x-2"
>
<span>Senden</span>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
</svg>
</button>
</div>
</div>
<!-- Statistics Footer -->
<div class="px-6 py-3 bg-gray-50 dark:bg-gray-800 rounded-b-lg border-t border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between text-sm text-gray-600 dark:text-gray-400">
<div class="flex items-center space-x-4">
<span>💬 {{ messageCount }} Messages</span>
<span>🤖 {{ activeAgents }} Agents</span>
<span>⏱️ {{ avgResponseTime }}s Avg Response</span>
</div>
<div class="flex items-center space-x-2">
<div class="w-2 h-2 bg-green-500 rounded-full"></div>
<span>Connected</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MultiAgentChatModal',
data() {
return {
message: '',
messages: [],
isLoading: false,
loadingText: 'Jane analysiert Intent...',
priority: 'normal',
messageCount: 3,
activeAgents: 2,
avgResponseTime: 0
}
},
methods: {
closeModal() {
this.$emit('close');
},
sendMessage() {
if (!this.message.trim() || this.isLoading) return;
// Add user message
const userMessage = {
id: Date.now(),
type: 'user',
content: this.message,
timestamp: new Date()
};
this.messages.push(userMessage);
// Clear input
const messageText = this.message;
this.message = '';
// Start loading
this.isLoading = true;
this.loadingText = 'Jane analysiert Intent...';
// Simulate multi-agent coordination
this.simulateMultiAgentResponse(messageText);
},
simulateMultiAgentResponse(messageText) {
// Simulate Jane analysis
setTimeout(() => {
this.loadingText = 'Delegiert an Specialist...';
setTimeout(() => {
this.loadingText = 'Koordiniert Response...';
setTimeout(() => {
// Add agent response
const agentResponse = {
id: Date.now(),
type: 'agent',
agent: 'Jane Alesi',
content: `Als Master Coordinator habe ich deine Anfrage "${messageText}" analysiert und an den passenden Spezialisten delegiert. Hier ist die koordinierte Antwort...`,
timestamp: new Date(),
responseTime: 2.3,
cost: '$0.002'
};
this.messages.push(agentResponse);
this.isLoading = false;
this.messageCount++;
// Scroll to bottom
this.$nextTick(() => {
const messagesContainer = this.$el.querySelector('.chat-messages');
messagesContainer.scrollTop = messagesContainer.scrollHeight;
});
}, 1000);
}, 800);
}, 1200);
},
insertNewline() {
this.message += '\n';
},
formatTime(date) {
return date.toLocaleTimeString('de-DE', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
},
getAgentColor(agent) {
const colors = {
'Jane Alesi': 'bg-purple-500',
'John Alesi': 'bg-teal-500',
'Lara Alesi': 'bg-pink-500',
'Justus Alesi': 'bg-yellow-500',
'Theo Alesi': 'bg-orange-500',
'Leon Alesi': 'bg-blue-500',
'Luna Alesi': 'bg-red-500'
};
return colors[agent] || 'bg-gray-500';
},
getAgentTextColor(agent) {
const colors = {
'Jane Alesi': 'text-purple-600 dark:text-purple-400',
'John Alesi': 'text-teal-600 dark:text-teal-400',
'Lara Alesi': 'text-pink-600 dark:text-pink-400',
'Justus Alesi': 'text-yellow-600 dark:text-yellow-400',
'Theo Alesi': 'text-orange-600 dark:text-orange-400',
'Leon Alesi': 'text-blue-600 dark:text-blue-400',
'Luna Alesi': 'text-red-600 dark:text-red-400'
};
return colors[agent] || 'text-gray-600 dark:text-gray-400';
},
getAgentInitial(agent) {
return agent.split(' ')[0][0] + agent.split(' ')[1][0];
}
}
}
</script>
<style scoped>
.chat-messages {
/* Verbesserte Scrollbar für bessere UX */
scrollbar-width: thin;
scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
}
.chat-messages::-webkit-scrollbar {
width: 6px;
}
.chat-messages::-webkit-scrollbar-track {
background: transparent;
}
.chat-messages::-webkit-scrollbar-thumb {
background-color: rgba(156, 163, 175, 0.5);
border-radius: 3px;
}
.chat-messages::-webkit-scrollbar-thumb:hover {
background-color: rgba(156, 163, 175, 0.8);
}
/* Improved message spacing */
.message-item {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>