Chat client changes
- Form values shown correct in MessageHistory of Chat client - Improements to CSS - Move css en js to assets directory - Introduce better Personal Contact Form & Professional Contact Form - Start working on actual Selection Specialist
This commit is contained in:
@@ -32,7 +32,6 @@
|
||||
border-radius: 15px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
max-width: 1000px; /* Optimale breedte */
|
||||
@@ -377,7 +376,7 @@
|
||||
|
||||
/* User message bubble styling */
|
||||
.message.user .message-content {
|
||||
background: linear-gradient(135deg, #007bff, #0056b3);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
color: white;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
@@ -385,9 +384,8 @@
|
||||
/* AI/Bot message bubble styling */
|
||||
.message.ai .message-content,
|
||||
.message.bot .message-content {
|
||||
background: #f8f9fa;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #212529;
|
||||
border: 1px solid #e9ecef;
|
||||
border-bottom-left-radius: 4px;
|
||||
margin-right: 60px;
|
||||
}
|
||||
@@ -670,7 +668,6 @@
|
||||
/* Progress Tracker Styling */
|
||||
.progress-tracker {
|
||||
margin: 8px 0;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 8px;
|
||||
background: #f8f9fa;
|
||||
overflow: hidden;
|
||||
@@ -683,8 +680,7 @@
|
||||
}
|
||||
|
||||
.progress-tracker.completed {
|
||||
border-color: #28a745;
|
||||
background: #d4edda;
|
||||
background: rgba(155, 255, 155, 0.1);
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
120
eveai_chat_client/static/assets/css/chat-input.css
Normal file
120
eveai_chat_client/static/assets/css/chat-input.css
Normal file
@@ -0,0 +1,120 @@
|
||||
/* ChatInput component styling */
|
||||
|
||||
/* Algemene container */
|
||||
.chat-input-container {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Input veld en knoppen */
|
||||
.chat-input {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.input-main {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding: 10px 40px 10px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
resize: none;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.message-input:focus {
|
||||
border-color: #0084ff;
|
||||
}
|
||||
|
||||
.message-input.over-limit {
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
|
||||
/* Character counter */
|
||||
.character-counter {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.character-counter.over-limit {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
/* Input actions */
|
||||
.input-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Verzendknop */
|
||||
.send-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #0084ff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.send-btn:hover {
|
||||
background-color: #0077e6;
|
||||
}
|
||||
|
||||
.send-btn:disabled {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.send-btn.form-mode {
|
||||
background-color: #4caf50;
|
||||
}
|
||||
|
||||
.send-btn.form-mode:hover {
|
||||
background-color: #43a047;
|
||||
}
|
||||
|
||||
/* Loading spinner */
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Formulier in chat input */
|
||||
.dynamic-form-container {
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px 15px 5px 15px;
|
||||
position: relative;
|
||||
background-color: #f9f9f9;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
161
eveai_chat_client/static/assets/css/chat-message.css
Normal file
161
eveai_chat_client/static/assets/css/chat-message.css
Normal file
@@ -0,0 +1,161 @@
|
||||
/* chat-message.css */
|
||||
|
||||
/* Algemene styling voor berichten */
|
||||
.message {
|
||||
max-width: 90%;
|
||||
margin-bottom: 15px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.message.ai {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
width: 100%;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Formulier styling */
|
||||
.form-display {
|
||||
margin: 15px 0;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(245, 245, 245, 0.7);
|
||||
padding: 15px;
|
||||
border: 1px solid #e0e0e0;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* Tabel styling voor formulieren */
|
||||
.form-result-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.form-result-table th {
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 600;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-result-table td {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-result-table td:first-child {
|
||||
font-weight: 500;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
/* Styling voor formulier invoervelden */
|
||||
.form-result-table input.form-input,
|
||||
.form-result-table textarea.form-textarea,
|
||||
.form-result-table select.form-select {
|
||||
width: 100%;
|
||||
padding: 6px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.form-result-table textarea.form-textarea {
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
/* Styling voor tabel cellen */
|
||||
.form-result-table .field-label {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
font-weight: 500;
|
||||
width: 35%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.form-result-table .field-value {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Toggle Switch styling */
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.toggle-input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.toggle-slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .4s;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.toggle-knob {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Material icon styling */
|
||||
.material-symbols-outlined {
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
/* Zorgt dat het lettertype consistent is */
|
||||
.message-text {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Form error styling */
|
||||
.form-error {
|
||||
color: red;
|
||||
padding: 10px;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
91
eveai_chat_client/static/assets/css/form-message.css
Normal file
91
eveai_chat_client/static/assets/css/form-message.css
Normal file
@@ -0,0 +1,91 @@
|
||||
/* Styling voor formulier in berichten */
|
||||
.message .form-display {
|
||||
margin-bottom: 12px;
|
||||
border-radius: 8px;
|
||||
background-color: rgba(245, 245, 245, 0.7);
|
||||
padding: 12px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.message.user .form-display {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.message.ai .form-display {
|
||||
background-color: rgba(245, 245, 250, 0.7);
|
||||
}
|
||||
/* Styling voor formulieren in berichten */
|
||||
|
||||
.form-display {
|
||||
margin-bottom: 10px;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
background-color: rgba(0, 0, 0, 0.03);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.user-form-values {
|
||||
background-color: rgba(0, 123, 255, 0.05);
|
||||
}
|
||||
|
||||
/* Speciale styling voor read-only formulieren in user messages */
|
||||
.user-form .form-field {
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.user-form .field-label {
|
||||
font-weight: 500 !important;
|
||||
color: #555 !important;
|
||||
padding: 2px 0 !important;
|
||||
}
|
||||
|
||||
.user-form .field-value {
|
||||
padding: 2px 0 !important;
|
||||
}
|
||||
|
||||
/* Schakel hover effecten uit voor read-only formulieren */
|
||||
.read-only .form-field:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Subtiele scheiding tussen velden */
|
||||
.dynamic-form.read-only .form-fields {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
margin-top: 10px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
/* Verklein vorm titels in berichten */
|
||||
.message-form .form-title {
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
.message-form .form-description {
|
||||
font-size: 0.85em !important;
|
||||
}
|
||||
.form-readonly {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-readonly .field-label {
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.form-readonly .field-value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.form-readonly .text-value {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/* Algemene styling verbetering voor berichten */
|
||||
.message-text {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
@@ -170,21 +170,22 @@ export const ChatApp = {
|
||||
},
|
||||
|
||||
// Message management
|
||||
addMessage(content, sender, type = 'text', formData = null) {
|
||||
addMessage(content, sender, type = 'text', formData = null, formValues = null) {
|
||||
const message = {
|
||||
id: this.messageIdCounter++,
|
||||
content,
|
||||
sender,
|
||||
type,
|
||||
formData,
|
||||
formValues,
|
||||
timestamp: new Date().toISOString(),
|
||||
status: sender === 'user' ? 'sent' : 'delivered'
|
||||
};
|
||||
|
||||
this.allMessages.push(message);
|
||||
|
||||
// Initialize form values if it's a form
|
||||
if (type === 'form' && formData) {
|
||||
// Initialize form values if it's a form and no values were provided
|
||||
if (type === 'form' && formData && !formValues) {
|
||||
// Vue 3 compatibele manier om reactieve objecten bij te werken
|
||||
this.formValues[message.id] = {};
|
||||
formData.fields.forEach(field => {
|
||||
@@ -203,19 +204,32 @@ export const ChatApp = {
|
||||
return message;
|
||||
},
|
||||
|
||||
// Helper functie om formulierdata toe te voegen aan bestaande berichten
|
||||
attachFormDataToMessage(messageId, formData, formValues) {
|
||||
const message = this.allMessages.find(m => m.id === messageId);
|
||||
if (message) {
|
||||
message.formData = formData;
|
||||
message.formValues = formValues;
|
||||
}
|
||||
},
|
||||
|
||||
updateCurrentMessage(value) {
|
||||
this.currentMessage = value;
|
||||
},
|
||||
|
||||
// Message sending
|
||||
// Message sending (alleen voor gewone tekstberichten, geen formulieren)
|
||||
async sendMessage() {
|
||||
const text = this.currentMessage.trim();
|
||||
|
||||
// Controleer of we kunnen verzenden
|
||||
if (!text || this.isLoading) return;
|
||||
|
||||
console.log('Sending message:', text);
|
||||
console.log('Sending text message:', text);
|
||||
|
||||
// Add user message
|
||||
const userMessage = this.addMessage(text, 'user', 'text');
|
||||
|
||||
// Wis input
|
||||
this.currentMessage = '';
|
||||
|
||||
// Show typing and loading state
|
||||
@@ -223,11 +237,14 @@ export const ChatApp = {
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
const response = await this.callAPI('/api/send_message', {
|
||||
// Verzamel gegevens voor de API call
|
||||
const apiData = {
|
||||
message: text,
|
||||
conversation_id: this.conversationId,
|
||||
user_id: this.userId
|
||||
});
|
||||
};
|
||||
|
||||
const response = await this.callAPI('/api/send_message', apiData);
|
||||
|
||||
// Hide typing indicator
|
||||
this.isTyping = false;
|
||||
@@ -278,35 +295,61 @@ export const ChatApp = {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Submitting form from input:', this.currentInputFormData.title, formValues);
|
||||
console.log('Form values received:', formValues);
|
||||
console.log('Current input form data:', this.currentInputFormData);
|
||||
|
||||
try {
|
||||
const response = await this.callAPI('/api/submit_form', {
|
||||
formData: formValues,
|
||||
formType: this.currentInputFormData.title,
|
||||
// Maak een user message met formuliergegevens én eventuele tekst
|
||||
const userMessage = this.addMessage(
|
||||
this.currentMessage.trim(), // Voeg tekst toe als die er is
|
||||
'user',
|
||||
'text'
|
||||
);
|
||||
|
||||
// Voeg formuliergegevens toe aan het bericht
|
||||
userMessage.formData = this.currentInputFormData;
|
||||
userMessage.formValues = formValues;
|
||||
|
||||
// Reset het tekstbericht
|
||||
this.currentMessage = '';
|
||||
this.$emit('update-message', '');
|
||||
|
||||
// Toon laad-indicator
|
||||
this.isTyping = true;
|
||||
this.isLoading = true;
|
||||
|
||||
// Verzamel gegevens voor de API call
|
||||
const apiData = {
|
||||
message: userMessage.content,
|
||||
conversation_id: this.conversationId,
|
||||
user_id: this.userId
|
||||
});
|
||||
user_id: this.userId,
|
||||
form_values: formValues // Voeg formuliergegevens toe aan API call
|
||||
};
|
||||
|
||||
if (response.success) {
|
||||
this.addMessage(
|
||||
`✅ ${response.message || 'Formulier succesvol verzonden!'}`,
|
||||
'ai',
|
||||
'text'
|
||||
);
|
||||
// Verstuur bericht naar de API
|
||||
const response = await this.callAPI('/api/send_message', apiData);
|
||||
|
||||
// Wis het huidige formulier (ongeacht of het succesvol was of niet)
|
||||
this.currentInputFormData = null;
|
||||
} else {
|
||||
this.addMessage(
|
||||
`❌ Er ging iets mis: ${response.error || 'Onbekende fout'}`,
|
||||
'ai',
|
||||
'text'
|
||||
);
|
||||
// Wis ook hier het formulier na een fout
|
||||
this.currentInputFormData = null;
|
||||
// Verberg de typing indicator
|
||||
this.isTyping = false;
|
||||
|
||||
// Markeer het gebruikersbericht als afgeleverd
|
||||
userMessage.status = 'delivered';
|
||||
|
||||
// Voeg AI response toe met task_id voor tracking
|
||||
const aiMessage = this.addMessage(
|
||||
'',
|
||||
'ai',
|
||||
'text'
|
||||
);
|
||||
|
||||
if (response.task_id) {
|
||||
console.log('Monitoring Task ID: ', response.task_id);
|
||||
aiMessage.taskId = response.task_id;
|
||||
}
|
||||
|
||||
// Reset formulier na succesvolle verzending
|
||||
this.currentInputFormData = null;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
this.addMessage(
|
||||
@@ -318,6 +361,7 @@ export const ChatApp = {
|
||||
this.currentInputFormData = null;
|
||||
} finally {
|
||||
this.isSubmittingForm = false;
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -125,9 +125,15 @@
|
||||
const hasValidForm = this.formData && this.validateForm();
|
||||
const hasValidMessage = this.localMessage.trim() && !this.isOverLimit;
|
||||
|
||||
// We kunnen nu verzenden als er een geldig formulier OF een geldig bericht is
|
||||
// Bij een formulier is aanvullende tekst optioneel
|
||||
return (!this.isLoading) && (hasValidForm || hasValidMessage);
|
||||
},
|
||||
|
||||
hasFormDataToSend() {
|
||||
return this.formData && this.validateForm();
|
||||
},
|
||||
|
||||
sendButtonText() {
|
||||
if (this.isLoading) {
|
||||
return 'Verzenden...';
|
||||
@@ -181,20 +187,31 @@
|
||||
sendMessage() {
|
||||
if (!this.canSend) return;
|
||||
|
||||
// Bij een formulier gaan we het formulier en optioneel bericht combineren
|
||||
if (this.formData) {
|
||||
// Valideer het formulier
|
||||
if (this.validateForm()) {
|
||||
// Verstuur het formulier
|
||||
// Verstuur het formulier, eventueel met aanvullende tekst
|
||||
this.$emit('submit-form', this.formValues);
|
||||
this.formValues = {};
|
||||
}
|
||||
} else if (this.localMessage.trim()) {
|
||||
// Verstuur normaal bericht
|
||||
// Verstuur normaal bericht zonder formulier
|
||||
this.$emit('send-message');
|
||||
}
|
||||
},
|
||||
|
||||
// Deze methode houden we voor de volledigheid, maar zal niet meer direct worden aangeroepen
|
||||
getFormValuesForSending() {
|
||||
// Geeft de huidige formulierwaarden terug voor verzending
|
||||
return this.formValues;
|
||||
},
|
||||
|
||||
// Reset het formulier en de waarden
|
||||
resetForm() {
|
||||
this.formValues = {};
|
||||
this.initFormValues();
|
||||
},
|
||||
|
||||
// Annuleer het formulier (wordt momenteel niet gebruikt)
|
||||
cancelForm() {
|
||||
this.formValues = {};
|
||||
// We sturen geen emit meer, maar het kan nuttig zijn om in de toekomst te hebben
|
||||
@@ -261,7 +278,7 @@
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
|
||||
</div>
|
||||
<!-- Dynamisch formulier container -->
|
||||
<div v-if="formData" class="dynamic-form-container" style="margin-bottom: 10px; border: 1px solid #ddd; border-radius: 8px; padding: 15px 15px 5px 15px; position: relative; background-color: #f9f9f9; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
|
||||
<div v-if="formData" class="dynamic-form-container">
|
||||
<!-- De titel wordt in DynamicForm weergegeven en niet hier om dubbele titels te voorkomen -->
|
||||
<div v-if="!formData.fields" style="color: red; padding: 10px;">Fout: Geen velden gevonden in formulier</div>
|
||||
<dynamic-form
|
||||
@@ -1,3 +1,33 @@
|
||||
// Voeg stylesheets toe voor formulier en chat berichten weergave
|
||||
const addStylesheets = () => {
|
||||
// Formulier stylesheet
|
||||
if (!document.querySelector('link[href*="form-message.css"]')) {
|
||||
const formLink = document.createElement('link');
|
||||
formLink.rel = 'stylesheet';
|
||||
formLink.href = '/static/assets/css/form-message.css';
|
||||
document.head.appendChild(formLink);
|
||||
}
|
||||
|
||||
// Chat bericht stylesheet
|
||||
if (!document.querySelector('link[href*="chat-message.css"]')) {
|
||||
const chatLink = document.createElement('link');
|
||||
chatLink.rel = 'stylesheet';
|
||||
chatLink.href = '/static/assets/css/chat-message.css';
|
||||
document.head.appendChild(chatLink);
|
||||
}
|
||||
|
||||
// Material Icons font stylesheet
|
||||
if (!document.querySelector('link[href*="Material+Symbols+Outlined"]')) {
|
||||
const iconLink = document.createElement('link');
|
||||
iconLink.rel = 'stylesheet';
|
||||
iconLink.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0';
|
||||
document.head.appendChild(iconLink);
|
||||
}
|
||||
};
|
||||
|
||||
// Laad de stylesheets
|
||||
addStylesheets();
|
||||
|
||||
export const ChatMessage = {
|
||||
name: 'ChatMessage',
|
||||
props: {
|
||||
@@ -17,11 +47,38 @@ export const ChatMessage = {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Zorg ervoor dat het icoon geladen wordt als iconManager beschikbaar is
|
||||
if (window.iconManager && this.message.formData && this.message.formData.icon) {
|
||||
window.iconManager.loadIcon(this.message.formData.icon);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'message.formData.icon': {
|
||||
handler(newIcon) {
|
||||
if (newIcon && window.iconManager) {
|
||||
window.iconManager.loadIcon(newIcon);
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
emits: ['image-loaded', 'retry-message', 'specialist-complete', 'specialist-error'],
|
||||
data() {
|
||||
return {
|
||||
formVisible: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasFormData() {
|
||||
return this.message.formData &&
|
||||
((Array.isArray(this.message.formData.fields) && this.message.formData.fields.length > 0) ||
|
||||
(typeof this.message.formData.fields === 'object' && Object.keys(this.message.formData.fields).length > 0));
|
||||
},
|
||||
hasFormValues() {
|
||||
return this.message.formValues && Object.keys(this.message.formValues).length > 0;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSpecialistError(eventData) {
|
||||
console.log('ChatMessage received specialist-error event:', eventData);
|
||||
@@ -90,7 +147,7 @@ export const ChatMessage = {
|
||||
<div :class="getMessageClass()" :data-message-id="message.id">
|
||||
<!-- Normal text messages -->
|
||||
<template v-if="message.type === 'text'">
|
||||
<div class="message-content">
|
||||
<div class="message-content" style="width: 100%;">
|
||||
<!-- Voortgangstracker voor AI berichten met task_id - NU BINNEN DE BUBBLE -->
|
||||
<progress-tracker
|
||||
v-if="message.sender === 'ai' && message.taskId"
|
||||
@@ -101,9 +158,79 @@ export const ChatMessage = {
|
||||
@specialist-error="handleSpecialistError"
|
||||
></progress-tracker>
|
||||
|
||||
<!-- Form data display if available (alleen in user messages) -->
|
||||
<div v-if="message.formValues && message.sender === 'user'" class="form-display user-form-values">
|
||||
<dynamic-form
|
||||
:form-data="message.formData"
|
||||
:form-values="message.formValues"
|
||||
:read-only="true"
|
||||
hide-actions
|
||||
class="message-form user-form"
|
||||
></dynamic-form>
|
||||
</div>
|
||||
|
||||
<!-- Formulier in AI berichten -->
|
||||
<div v-if="message.formData && message.sender === 'ai'" class="form-display ai-form-values" style="margin-top: 15px;">
|
||||
<!-- Dynamisch toevoegen van Material Symbols Outlined voor iconen -->
|
||||
<table class="form-result-table">
|
||||
<thead v-if="message.formData.title || message.formData.name || message.formData.icon">
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
<div class="form-header">
|
||||
<span v-if="message.formData.icon" class="material-symbols-outlined">{{ message.formData.icon }}</span>
|
||||
<span>{{ message.formData.title || message.formData.name }}</span>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(field, fieldId) in message.formData.fields" :key="fieldId">
|
||||
<td class="field-label">{{ field.name }}:</td>
|
||||
<td class="field-value">
|
||||
<input
|
||||
v-if="field.type === 'str' || field.type === 'string' || field.type === 'int' || field.type === 'integer' || field.type === 'float'"
|
||||
:type="field.type === 'int' || field.type === 'integer' || field.type === 'float' ? 'number' : 'text'"
|
||||
:placeholder="field.placeholder || ''"
|
||||
class="form-input"
|
||||
>
|
||||
<textarea
|
||||
v-else-if="field.type === 'text'"
|
||||
:placeholder="field.placeholder || ''"
|
||||
:rows="field.rows || 3"
|
||||
class="form-textarea"
|
||||
></textarea>
|
||||
<select
|
||||
v-else-if="field.type === 'enum'"
|
||||
class="form-select"
|
||||
>
|
||||
<option value="">Selecteer een optie</option>
|
||||
<option
|
||||
v-for="option in (field.allowedValues || field.allowed_values || [])"
|
||||
:key="option"
|
||||
:value="option"
|
||||
>
|
||||
{{ option }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-else-if="field.type === 'boolean'" class="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle-input"
|
||||
>
|
||||
<span class="toggle-slider">
|
||||
<span class="toggle-knob"></span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- View mode -->
|
||||
<div>
|
||||
<div
|
||||
v-if="message.content"
|
||||
v-html="formatMessage(message.content)"
|
||||
class="message-text"
|
||||
></div>
|
||||
@@ -151,12 +151,12 @@ export const DynamicForm = {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="readOnly" class="form-readonly">
|
||||
<div v-if="readOnly" class="form-readonly" style="display: grid; grid-template-columns: 35% 65%; gap: 8px; width: 100%;">
|
||||
<!-- Array-based fields -->
|
||||
<template v-if="Array.isArray(formData.fields)">
|
||||
<div v-for="field in formData.fields" :key="field.id || field.name" class="form-field-readonly">
|
||||
<div class="field-label">{{ field.name }}:</div>
|
||||
<div class="field-value">
|
||||
<template v-for="field in formData.fields" :key="field.id || field.name">
|
||||
<div class="field-label" style="font-weight: 500; color: #555; padding: 4px 0;">{{ field.name }}:</div>
|
||||
<div class="field-value" style="padding: 4px 0;">
|
||||
<template v-if="field.type === 'enum' && (field.allowedValues || field.allowed_values)">
|
||||
{{ localFormValues[field.id || field.name] || field.default || '-' }}
|
||||
</template>
|
||||
@@ -164,19 +164,19 @@ export const DynamicForm = {
|
||||
{{ localFormValues[field.id || field.name] ? 'Ja' : 'Nee' }}
|
||||
</template>
|
||||
<template v-else-if="field.type === 'text'">
|
||||
<div class="text-value">{{ localFormValues[field.id || field.name] || '-' }}</div>
|
||||
<div class="text-value" style="white-space: pre-wrap;">{{ localFormValues[field.id || field.name] || '-' }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ localFormValues[field.id || field.name] || field.default || '-' }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<!-- Object-based fields -->
|
||||
<template v-else>
|
||||
<div v-for="(field, fieldId) in formData.fields" :key="fieldId" class="form-field-readonly">
|
||||
<div class="field-label">{{ field.name }}:</div>
|
||||
<div class="field-value">
|
||||
<template v-for="(field, fieldId) in formData.fields" :key="fieldId">
|
||||
<div class="field-label" style="font-weight: 500; color: #555; padding: 4px 0;">{{ field.name }}:</div>
|
||||
<div class="field-value" style="padding: 4px 0;">
|
||||
<template v-if="field.type === 'enum' && (field.allowedValues || field.allowed_values)">
|
||||
{{ localFormValues[fieldId] || field.default || '-' }}
|
||||
</template>
|
||||
@@ -184,13 +184,13 @@ export const DynamicForm = {
|
||||
{{ localFormValues[fieldId] ? 'Ja' : 'Nee' }}
|
||||
</template>
|
||||
<template v-else-if="field.type === 'text'">
|
||||
<div class="text-value">{{ localFormValues[fieldId] || '-' }}</div>
|
||||
<div class="text-value" style="white-space: pre-wrap;">{{ localFormValues[fieldId] || '-' }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ localFormValues[fieldId] || field.default || '-' }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/* Animation styles for ChatInput component */
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Add more ChatInput-specific styles here */
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Stijlen voor het FormMessage component in chatberichten */
|
||||
.form-message {
|
||||
background-color: #f5f8ff;
|
||||
border: 1px solid #e1e8f5;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.form-message-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e1e8f5;
|
||||
}
|
||||
|
||||
.form-message-icon {
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
color: #4a6fa5;
|
||||
}
|
||||
|
||||
.form-message-title {
|
||||
font-weight: 600;
|
||||
color: #3a5a80;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.form-message-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.form-message-field {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.field-message-label {
|
||||
flex: 0 0 120px;
|
||||
font-weight: 500;
|
||||
color: #4a6fa5;
|
||||
font-size: 0.85rem;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.field-message-value {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 0.9rem;
|
||||
color: #333;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.field-message-value.text-value {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.form-message-field {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.field-message-label {
|
||||
flex: 0 0 100%;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.field-message-value {
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user