feat: Add green border for filled fields and use field_label for documents

Changes:
1. Added green border styling for filled form fields (.filled class)
   - Green border (#10b981) and light green background (#f0fdf4)
   - Applied automatically when field has value
   - Works for inputs, textareas, and checkboxes

2. Updated document display to use field_label instead of filename
   - Changed ClaimForm.tsx to include field_label in attachments
   - Updated normalizeData to use full attachments array with field_label
   - Display shows field_label if available, falls back to filename

3. Added updateFieldStyle function
   - Updates field styling on input, blur, and change events
   - Automatically applies filled class when field has value

Files:
- frontend/src/pages/ClaimForm.tsx: Added field_label to attachments
- frontend/src/components/form/generateConfirmationFormHTML.ts:
  - Added .filled CSS class with green border
  - Added updateFieldStyle function
  - Updated document display to use field_label
  - Updated normalizeData to use attachments array
This commit is contained in:
AI Assistant
2025-11-24 17:57:47 +03:00
parent f82df1ebd7
commit 6bf5cfad26
2 changed files with 62 additions and 8 deletions

View File

@@ -123,9 +123,11 @@ export function generateConfirmationFormHTML(data: any): string {
console.log('period_end_fmt:', contract.period_end_fmt);
// Получаем список приложенных документов
const attachments = props.attachments_names || [];
// ✅ Используем полный массив attachments с field_label, если есть, иначе attachments_names
const attachments = props.attachments || props.attachments_names || [];
console.log('=== ОТЛАДКА ПРИЛОЖЕНИЙ ===');
console.log('attachments_names:', attachments);
console.log('attachments:', attachments);
console.log('attachments_names:', props.attachments_names);
return {
user: {
@@ -152,7 +154,7 @@ export function generateConfirmationFormHTML(data: any): string {
description: claim.description || null,
reason: claim.reason || caseData.category || null,
},
attachments: attachments,
attachments: attachments, // ✅ Теперь это массив объектов с field_label или массив строк
offenders: offenders.map((o: any) => ({
accountname: o.name || null,
address: o.address || null,
@@ -346,6 +348,20 @@ export function generateConfirmationFormHTML(data: any): string {
background:#f8fafc;
}
.inline-field:hover{border-color:#d1d5db}
/* ✅ Зеленая рамка для заполненных полей */
.inline-field.filled{
border-color:#10b981;
background-color:#f0fdf4;
}
.inline-field.filled:focus{
border-color:#10b981;
box-shadow:0 0 0 2px rgba(16,185,129,0.1);
background-color:#f0fdf4;
}
textarea.inline-field.filled{
border-color:#10b981;
background-color:#f0fdf4;
}
.inline-field.large{
min-width:200px;max-width:500px;
}
@@ -568,7 +584,8 @@ export function generateConfirmationFormHTML(data: any): string {
var claim = props.claim || {};
var meta = props.meta || {};
var attachments = props.attachments_names || [];
// ✅ Используем полный массив attachments с field_label, если есть, иначе attachments_names
var attachments = props.attachments || props.attachments_names || [];
return {
user: {
@@ -595,7 +612,7 @@ export function generateConfirmationFormHTML(data: any): string {
description: claim.description || null,
reason: claim.reason || caseData.category || null,
},
attachments: attachments,
attachments: attachments, // ✅ Теперь это массив объектов с field_label или массив строк
offenders: offenders.map(function(o) {
return {
accountname: o.name || null,
@@ -974,10 +991,18 @@ export function generateConfirmationFormHTML(data: any): string {
html += '<div style="background:#f9fafb;padding:12px;border-radius:8px;border:1px solid #e5e7eb;">';
for (var i = 0; i < state.attachments.length; i++) {
var fileName = state.attachments[i];
var attachment = state.attachments[i];
// ✅ Используем field_label если это объект, иначе имя файла
var displayName = '';
if (typeof attachment === 'object' && attachment !== null) {
displayName = attachment.field_label || attachment.label || attachment.original_file_name || attachment.file_name || 'Документ';
} else {
displayName = String(attachment);
}
html += '<div style="display:flex;align-items:center;margin-bottom:8px;padding:8px;background:white;border-radius:6px;border:1px solid #e5e7eb;">';
html += '<span style="color:#3b82f6;margin-right:8px;">📎</span>';
html += '<span style="color:#374151;font-size:14px;">' + esc(fileName) + '</span>';
html += '<span style="color:#374151;font-size:14px;">' + esc(displayName) + '</span>';
html += '</div>';
}
@@ -1147,15 +1172,34 @@ export function generateConfirmationFormHTML(data: any): string {
}
}
// ✅ Функция для обновления стиля заполненных полей
function updateFieldStyle(field) {
var value = field.type === 'checkbox' ? field.checked : (field.value || '').trim();
var hasValue = field.type === 'checkbox' ? value : value.length > 0;
if (hasValue) {
field.classList.add('filled');
} else {
field.classList.remove('filled');
}
}
function attachBindings() {
console.log('Attaching bindings...');
var fields = document.querySelectorAll('.bind');
console.log('Found fields:', fields.length);
// ✅ Устанавливаем начальный стиль для всех полей
Array.prototype.forEach.call(fields, function(field) {
updateFieldStyle(field);
});
Array.prototype.forEach.call(fields, function(field) {
// Обработка ввода
field.addEventListener('input', function() {
// ✅ Обновляем стиль при изменении
updateFieldStyle(this);
// Автозамена запятой на точку для денежных полей
if (this.classList.contains('money-field') && this.value.includes(',')) {
this.value = this.value.replace(/,/g, '.');
@@ -1240,12 +1284,21 @@ export function generateConfirmationFormHTML(data: any): string {
// Валидация при потере фокуса
field.addEventListener('blur', function() {
updateFieldStyle(this); // ✅ Обновляем стиль при потере фокуса
updateSubmitButton();
});
// ✅ Обновление стиля для чекбоксов при изменении
if (field.type === 'checkbox') {
field.addEventListener('change', function() {
updateFieldStyle(this);
});
}
// Дополнительная обработка для чекбоксов
if (field.type === 'checkbox') {
field.addEventListener('change', function() {
updateFieldStyle(this); // ✅ Обновляем стиль при изменении чекбокса
var root = this.getAttribute('data-root');
var key = this.getAttribute('data-key');
var value = this.checked;

View File

@@ -445,7 +445,8 @@ export default function ClaimForm() {
// Формируем attachments с полной информацией
const attachments = documentsMeta.map((doc: any) => ({
label: doc.original_file_name || doc.file_name || doc.field_name || 'Документ',
label: doc.field_label || doc.original_file_name || doc.file_name || doc.field_name || 'Документ', // ✅ Используем field_label
field_label: doc.field_label || doc.field_name || doc.original_file_name || doc.file_name || 'Документ', // ✅ Добавляем field_label отдельно
url: doc.file_id ? `https://s3.twcstorage.ru${doc.file_id}` : '',
file_id: doc.file_id || '',
stored_file_name: doc.file_name || '',