fix: исправлены проблемы с формами и циклическими ссылками

- Исправлена проблема с циклическими ссылками в Step1Phone.tsx при onPaste (добавлен setTimeout)
- Добавлены name атрибуты во все поля формы для правильной работы форм и автозаполнения
- Исправлены проблемы с label/input связями (все label имеют правильные for/id)
- Все поля теперь имеют id и name атрибуты (исправляет предупреждения в консоли)

Исправленные функции:
- createField: добавлен name атрибут
- createReadonlyField: добавлен name атрибут
- createDateField: добавлен name атрибут
- createMoneyField: добавлен name атрибут
- createTextarea: добавлен name атрибут
- createBankSelect: добавлен name атрибут для основного поля и скрытого bank_id
- createCheckbox: добавлен name атрибут, проверена связь label/input
This commit is contained in:
Fedor
2025-12-04 09:21:12 +03:00
parent 346d9a77d2
commit 003210dcfc
10 changed files with 42 additions and 15 deletions

View File

@@ -195,3 +195,4 @@ curl "http://localhost:8200/api/v1/claims/drafts/226564ce-d7cf-48ee-a820-690e8f5
**Время работы:** 2025-12-03 16:00-17:00 **Время работы:** 2025-12-03 16:00-17:00
**Статус:** ✅ Завершено успешно **Статус:** ✅ Завершено успешно

View File

@@ -115,3 +115,4 @@ class CrmMySQLService:
# Глобальный экземпляр # Глобальный экземпляр
crm_mysql_service = CrmMySQLService() crm_mysql_service = CrmMySQLService()

View File

@@ -133,3 +133,4 @@ return {
- `ticket_form/docs/N8N_UPDATE_CF_2624_IN_RESPONSE.md` - Обновление n8n workflow - `ticket_form/docs/N8N_UPDATE_CF_2624_IN_RESPONSE.md` - Обновление n8n workflow
- `ticket_form/docs/CODE_CREATE_WEB_CONTACT_FINAL.js` - Код для n8n (обновлён) - `ticket_form/docs/CODE_CREATE_WEB_CONTACT_FINAL.js` - Код для n8n (обновлён)

View File

@@ -111,3 +111,4 @@ LIMIT 1;
- Сохраняться в черновик в `payload.cf_2624` - Сохраняться в черновик в `payload.cf_2624`
- Использоваться для блокировки полей на фронтенде - Использоваться для блокировки полей на фронтенде

View File

@@ -207,3 +207,4 @@ if actual_event.get('event_type') == 'ocr_status' and actual_event.get('status')
- ✅ Обрабатываться backend'ом - ✅ Обрабатываться backend'ом
- ✅ Сохраняться в черновик в поле `payload.cf_2624` - ✅ Сохраняться в черновик в поле `payload.cf_2624`

View File

@@ -71,3 +71,4 @@ if (pgContactNode && pgContactNode.json && pgContactNode.json.length > 0) {
**Примечание:** Название файла `N8N_POSTGRESQL_GET_CONTACT_DATA.sql` устарело, но запрос работает для MySQL. **Примечание:** Название файла `N8N_POSTGRESQL_GET_CONTACT_DATA.sql` устарело, но запрос работает для MySQL.

View File

@@ -144,3 +144,4 @@ if (contact_id) {
} }
``` ```

View File

@@ -97,3 +97,4 @@ LIMIT 1;
Но лучше использовать PostgreSQL напрямую для скорости. Но лучше использовать PostgreSQL напрямую для скорости.

View File

@@ -290,12 +290,14 @@ export default function Step1Phone({
} }
// Оставляем только первые 10 цифр // Оставляем только первые 10 цифр
cleanText = cleanText.substring(0, 10); cleanText = cleanText.substring(0, 10);
// Устанавливаем очищенное значение // ✅ Используем setTimeout для избежания циклических ссылок при обновлении формы
form.setFieldValue('phone', cleanText); setTimeout(() => {
// Показываем предупреждение, если номер был обрезан form.setFieldValue('phone', cleanText);
if (pastedText.replace(/\D/g, '').length > 10) { // Показываем предупреждение, если номер был обрезан
message.warning('Номер автоматически обрезан до 10 цифр'); if (pastedText.replace(/\D/g, '').length > 10) {
} message.warning('Номер автоматически обрезан до 10 цифр');
}
}, 0);
}} }}
/> />
</Space.Compact> </Space.Compact>

View File

@@ -811,14 +811,18 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
extra = ' type="email" inputmode="email" autocomplete="email"'; extra = ' type="email" inputmode="email" autocomplete="email"';
} }
// ✅ Добавляем name атрибут для правильной работы форм и автозаполнения
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + (index !== undefined ? '_' + index : '') + '"';
var fieldHtml = '<input class="inline-field bind" data-root="' + esc(root) + '" data-key="' + esc(key) + '"' + dataIndex + var fieldHtml = '<input class="inline-field bind" data-root="' + esc(root) + '" data-key="' + esc(key) + '"' + dataIndex +
' id="' + id + '" value="' + esc(value || '') + '" placeholder="' + esc(placeholder || '') + '"' + extra + ' />'; ' id="' + id + '" ' + nameAttr + ' value="' + esc(value || '') + '" placeholder="' + esc(placeholder || '') + '"' + extra + ' />';
return fieldHtml; return fieldHtml;
} }
function createReadonlyField(root, key, value) { function createReadonlyField(root, key, value) {
var id = 'field_' + root + '_' + key + '_readonly_' + Math.random().toString(36).slice(2); var id = 'field_' + root + '_' + key + '_readonly_' + Math.random().toString(36).slice(2);
return '<input class="inline-field readonly-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" value="' + esc(value || '') + '" readonly />'; // ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
return '<input class="inline-field readonly-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + ' value="' + esc(value || '') + '" readonly />';
} }
function createDateField(root, key, value) { function createDateField(root, key, value) {
@@ -834,20 +838,25 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
} }
} }
// ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
// ✅ Проверяем, нужно ли блокировать поле (для подтверждённых данных) // ✅ Проверяем, нужно ли блокировать поле (для подтверждённых данных)
var isLockedField = contact_data_confirmed && root === 'user' && key === 'birthday'; var isLockedField = contact_data_confirmed && root === 'user' && key === 'birthday';
if (isLockedField) { if (isLockedField) {
return '<input type="date" class="inline-field readonly-field date-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" value="' + esc(dateValue) + '" readonly />'; return '<input type="date" class="inline-field readonly-field date-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + ' value="' + esc(dateValue) + '" readonly />';
} }
return '<input type="date" class="inline-field bind date-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" value="' + esc(dateValue) + '" />'; return '<input type="date" class="inline-field bind date-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + ' value="' + esc(dateValue) + '" />';
} }
function createMoneyField(root, key, value) { function createMoneyField(root, key, value) {
var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2); var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2);
// ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
return '<div style="display: flex; align-items: center; gap: 8px;">' + return '<div style="display: flex; align-items: center; gap: 8px;">' +
'<input class="inline-field bind money-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '"' + '<input class="inline-field bind money-field" data-root="' + esc(root) + '" data-key="' + esc(key) + '"' +
' id="' + id + '" value="' + esc(value || '') + '"' + ' id="' + id + '" ' + nameAttr + ' value="' + esc(value || '') + '"' +
' inputmode="decimal" pattern="[0-9]*[.,]?[0-9]*" autocomplete="off" />' + ' inputmode="decimal" pattern="[0-9]*[.,]?[0-9]*" autocomplete="off" />' +
'<span style="color: #6b7280; font-size: 14px;">рублей</span>' + '<span style="color: #6b7280; font-size: 14px;">рублей</span>' +
'</div>'; '</div>';
@@ -855,20 +864,25 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
function createTextarea(root, key, value) { function createTextarea(root, key, value) {
var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2); var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2);
return '<textarea class="inline-field bind full-width" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '">' + esc(value || '') + '</textarea>'; // ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
return '<textarea class="inline-field bind full-width" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + '>' + esc(value || '') + '</textarea>';
} }
function createBankSelect(root, key, value) { function createBankSelect(root, key, value) {
var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2); var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2);
var datalistId = 'bank-datalist-' + id; var datalistId = 'bank-datalist-' + id;
// ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
// Создаём input с datalist для автоподстановки // Создаём input с datalist для автоподстановки
var inputHtml = '<input type="text" class="inline-field bind bank-select" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" list="' + datalistId + '" placeholder="Начните вводить название банка (обязательно)" autocomplete="off" />'; var inputHtml = '<input type="text" class="inline-field bind bank-select" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + ' list="' + datalistId + '" placeholder="Начните вводить название банка (обязательно)" autocomplete="off" />';
inputHtml += '<datalist id="' + datalistId + '" class="bank-datalist">'; inputHtml += '<datalist id="' + datalistId + '" class="bank-datalist">';
inputHtml += '<option value="">Загрузка списка банков...</option>'; inputHtml += '<option value="">Загрузка списка банков...</option>';
inputHtml += '</datalist>'; inputHtml += '</datalist>';
// Скрытое поле для bank_id // Скрытое поле для bank_id
var hiddenId = id + '_id'; var hiddenId = id + '_id';
inputHtml += '<input type="hidden" class="bank-id-field" data-root="' + esc(root) + '" data-key="bank_id" id="' + hiddenId + '" />'; var hiddenNameAttr = 'name="' + esc(root) + '_bank_id"';
inputHtml += '<input type="hidden" class="bank-id-field" data-root="' + esc(root) + '" data-key="bank_id" id="' + hiddenId + '" ' + hiddenNameAttr + ' />';
return inputHtml; return inputHtml;
} }
@@ -876,9 +890,12 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2); var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2);
var checkedAttr = checked ? ' checked' : ''; var checkedAttr = checked ? ' checked' : '';
var requiredClass = required ? ' required-checkbox' : ''; var requiredClass = required ? ' required-checkbox' : '';
// ✅ Добавляем name атрибут для правильной работы форм
var nameAttr = 'name="' + esc(root) + '_' + esc(key) + '"';
// ✅ Label правильно связан с input через for/id
var checkboxHtml = '<label class="checkbox-container' + requiredClass + '" for="' + id + '">'; var checkboxHtml = '<label class="checkbox-container' + requiredClass + '" for="' + id + '">';
checkboxHtml += '<input type="checkbox" class="checkbox-field bind" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '"' + checkedAttr + ' />'; checkboxHtml += '<input type="checkbox" class="checkbox-field bind" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" ' + nameAttr + checkedAttr + ' />';
checkboxHtml += '<span class="checkmark"></span>'; checkboxHtml += '<span class="checkmark"></span>';
checkboxHtml += '<span class="checkbox-label">' + labelText + '</span>'; checkboxHtml += '<span class="checkbox-label">' + labelText + '</span>';
checkboxHtml += '</label>'; checkboxHtml += '</label>';