feat: добавлена визуальная подсветка обязательных полей
- Добавлены звёздочки (*) рядом с обязательными полями - Незаполненные обязательные поля подсвечиваются жёлтой рамкой - Добавлен блок с предупреждением о незаполненных полях перед кнопкой отправки - Улучшена валидация с визуальной обратной связью - Пользователю теперь понятно, какие поля нужно заполнить
This commit is contained in:
@@ -373,6 +373,58 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
box-shadow:0 0 0 2px rgba(239,68,68,0.1) !important;
|
||||
background-color:#fef2f2 !important;
|
||||
}
|
||||
/* ⚠️ Желтая рамка для незаполненных обязательных полей */
|
||||
.inline-field.required-empty{
|
||||
border-color:#f59e0b !important;
|
||||
background-color:#fffbeb !important;
|
||||
border-width:2px !important;
|
||||
}
|
||||
.inline-field.required-empty:focus{
|
||||
border-color:#f59e0b !important;
|
||||
box-shadow:0 0 0 3px rgba(245,158,11,0.2) !important;
|
||||
background-color:#fffbeb !important;
|
||||
}
|
||||
/* Звёздочка для обязательных полей */
|
||||
.required-marker{
|
||||
color:#ef4444;
|
||||
font-weight:bold;
|
||||
margin-left:2px;
|
||||
}
|
||||
/* Блок с предупреждением о незаполненных полях */
|
||||
.validation-warning{
|
||||
margin:16px 0;
|
||||
padding:12px 16px;
|
||||
background:#fffbeb;
|
||||
border:2px solid #f59e0b;
|
||||
border-radius:8px;
|
||||
font-size:14px;
|
||||
color:#92400e;
|
||||
}
|
||||
.validation-warning-title{
|
||||
font-weight:600;
|
||||
margin-bottom:8px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
gap:8px;
|
||||
}
|
||||
.validation-warning-list{
|
||||
margin:0;
|
||||
padding-left:20px;
|
||||
list-style:none;
|
||||
}
|
||||
.validation-warning-list li{
|
||||
margin:4px 0;
|
||||
padding-left:20px;
|
||||
position:relative;
|
||||
}
|
||||
.validation-warning-list li:before{
|
||||
content:'•';
|
||||
position:absolute;
|
||||
left:0;
|
||||
color:#f59e0b;
|
||||
font-weight:bold;
|
||||
font-size:18px;
|
||||
}
|
||||
.inline-field.large{
|
||||
min-width:200px;max-width:500px;
|
||||
}
|
||||
@@ -925,28 +977,28 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
html += '</div>';
|
||||
|
||||
html += '<p><strong>Заявитель:</strong> ';
|
||||
html += createField('user', 'lastname', u.lastname, 'Фамилия (обязательно)');
|
||||
html += createField('user', 'lastname', u.lastname, 'Фамилия') + '<span class="required-marker">*</span>';
|
||||
html += ' ';
|
||||
html += createField('user', 'firstname', u.firstname, 'Имя (обязательно)');
|
||||
html += createField('user', 'firstname', u.firstname, 'Имя') + '<span class="required-marker">*</span>';
|
||||
html += ' ';
|
||||
html += createField('user', 'secondname', u.secondname, 'Отчество');
|
||||
html += '</p>';
|
||||
|
||||
html += '<p><strong>Дата рождения:</strong> ';
|
||||
html += createDateField('user', 'birthday', u.birthday);
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Место рождения:</strong> ';
|
||||
html += createField('user', 'birthplace', u.birthplace, 'Место рождения (обязательно)');
|
||||
html += '</p>';
|
||||
html += createField('user', 'birthplace', u.birthplace, 'Место рождения');
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>ИНН:</strong> ';
|
||||
html += createField('user', 'inn', u.inn, '12-значный ИНН (обязательно)');
|
||||
html += '</p>';
|
||||
html += createField('user', 'inn', u.inn, '12-значный ИНН');
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Адрес:</strong> ';
|
||||
html += createField('user', 'mailingstreet', u.mailingstreet, 'Адрес регистрации как в паспорте (обязательно)');
|
||||
html += '</p>';
|
||||
html += createField('user', 'mailingstreet', u.mailingstreet, 'Адрес регистрации как в паспорте');
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Телефон:</strong> ';
|
||||
html += createReadonlyField('user', 'mobile', u.mobile);
|
||||
@@ -961,9 +1013,9 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
// Возмещение
|
||||
html += '<h3 style="font-size:16px;margin:0 0 16px;color:#1f2937">Возмещение:</h3>';
|
||||
html += '<p>Выплата возмещения возможна по системе быстрых платежей (СБП) по номеру телефона заявителя: <strong id="phone-display">' + esc(u.mobile || '') + '</strong></p>';
|
||||
html += '<p><strong>Банк для получения выплаты (обязательно):</strong> ';
|
||||
html += '<p><strong>Банк для получения выплаты:</strong> ';
|
||||
html += createBankSelect('user', 'bank_id', u.bank_id || '');
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<div class="section-break"></div>';
|
||||
|
||||
@@ -983,12 +1035,12 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
// Дата события / заключения договора
|
||||
html += '<p><strong>Дата события / заключения договора:</strong> ';
|
||||
html += createDateField('project', 'agrdate', p.agrdate);
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
// Сумма оплаты / стоимость
|
||||
html += '<p><strong>Сумма оплаты / стоимость:</strong> ';
|
||||
html += createMoneyField('project', 'agrprice', p.agrprice);
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
// Период
|
||||
html += '<p><strong>Период:</strong> ';
|
||||
@@ -1013,19 +1065,19 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
|
||||
html += '<p><strong>Наименование:</strong> ';
|
||||
html += createField('offender', 'accountname', offender.accountname, 'Название организации', i);
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>ИНН:</strong> ';
|
||||
html += createField('offender', 'inn', offender.inn, 'ИНН организации (10 или 12 цифр) (обязательно)', i);
|
||||
html += '</p>';
|
||||
html += createField('offender', 'inn', offender.inn, 'ИНН организации (10 или 12 цифр)', i);
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Адрес:</strong> ';
|
||||
html += createField('offender', 'address', offender.address, 'Адрес (обязательно)', i);
|
||||
html += '</p>';
|
||||
html += createField('offender', 'address', offender.address, 'Адрес', i);
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>E-mail:</strong> ';
|
||||
html += createField('offender', 'email', offender.email, 'email@example.com (обязательно)', i);
|
||||
html += '</p>';
|
||||
html += createField('offender', 'email', offender.email, 'email@example.com', i);
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Телефон:</strong> ';
|
||||
html += createField('offender', 'phone', offender.phone, '+7 (___) ___-__-__', i);
|
||||
@@ -1043,15 +1095,18 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
// Причина обращения (редактируемая)
|
||||
html += '<p><strong>Причина обращения:</strong> ';
|
||||
html += createField('project', 'reason', p.reason, 'Можете уточнить или изменить причину обращения');
|
||||
html += '</p>';
|
||||
html += '<span class="required-marker">*</span></p>';
|
||||
|
||||
html += '<p><strong>Описание проблемы:</strong></p>';
|
||||
html += '<p><strong>Описание проблемы:</strong> <span class="required-marker">*</span></p>';
|
||||
html += createTextarea('project', 'description', p.description);
|
||||
|
||||
html += '<p>На основании вышеизложенного и руководствуясь ст. 45 Закона «О защите прав потребителей», ст. 3, ч. 1 ст. 46 ГПК РФ, прошу вас защитить мои потребительские права, обратиться в суд с заявлением о защите моих потребительских прав и/или с коллективным иском о защите группы потребителей, и представлять мои интересы во всех судебных органах РФ, а также обращаться с заявлениями во все госорганы, подавать претензии, письма и жалобы.</p>';
|
||||
|
||||
html += '<div class="section-break"></div>';
|
||||
|
||||
// Блок с предупреждением о незаполненных полях (будет обновляться динамически)
|
||||
html += '<div id="validation-warning-block" style="display:none;"></div>';
|
||||
|
||||
// Согласие на обработку персональных данных
|
||||
html += '<div style="margin:24px 0;">';
|
||||
html += createCheckbox('meta', 'privacyConsent', state.meta && state.meta.privacyConsent,
|
||||
@@ -1183,39 +1238,62 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
return parseFloat(s) > 0;
|
||||
}
|
||||
|
||||
// Список обязательных полей
|
||||
var requiredFieldsList = [
|
||||
{ root: 'user', key: 'lastname', name: 'Фамилия' },
|
||||
{ root: 'user', key: 'firstname', name: 'Имя' },
|
||||
{ root: 'user', key: 'birthday', name: 'Дата рождения' },
|
||||
{ root: 'user', key: 'birthplace', name: 'Место рождения' },
|
||||
{ root: 'user', key: 'mailingstreet', name: 'Адрес' },
|
||||
{ root: 'user', key: 'inn', name: 'ИНН' },
|
||||
{ root: 'project', key: 'agrdate', name: 'Дата договора' },
|
||||
{ root: 'project', key: 'agrprice', name: 'Сумма' },
|
||||
{ root: 'project', key: 'reason', name: 'Причина обращения' },
|
||||
{ root: 'project', key: 'description', name: 'Описание проблемы' },
|
||||
{ root: 'offender', key: 'accountname', name: 'Название организации' },
|
||||
{ root: 'offender', key: 'inn', name: 'ИНН организации' },
|
||||
{ root: 'offender', key: 'address', name: 'Адрес организации' },
|
||||
{ root: 'offender', key: 'email', name: 'E-mail организации' },
|
||||
{ root: 'user', key: 'bank_id', name: 'Банк для получения выплаты' }
|
||||
];
|
||||
|
||||
// Функция проверки, является ли поле обязательным
|
||||
function isRequiredField(root, key) {
|
||||
return requiredFieldsList.some(function(f) {
|
||||
return f.root === root && f.key === key;
|
||||
});
|
||||
}
|
||||
|
||||
// Функция получения значения поля
|
||||
function getFieldValue(root, key, index) {
|
||||
if (root === 'user') {
|
||||
return state.user[key] || '';
|
||||
} else if (root === 'project') {
|
||||
return state.project[key] || '';
|
||||
} else if (root === 'offender') {
|
||||
var offender = state.offenders[index || 0];
|
||||
return (offender && offender[key]) || '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Функция проверки, заполнено ли поле
|
||||
function isFieldFilled(root, key, index) {
|
||||
var value = getFieldValue(root, key, index);
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === 'string') {
|
||||
return value.trim().length > 0;
|
||||
}
|
||||
return !!value;
|
||||
}
|
||||
|
||||
// Функция проверки всех обязательных полей
|
||||
function validateAllFields() {
|
||||
var requiredFields = [
|
||||
{ root: 'user', key: 'lastname', name: 'Фамилия' },
|
||||
{ root: 'user', key: 'firstname', name: 'Имя' },
|
||||
{ root: 'user', key: 'birthday', name: 'Дата рождения' },
|
||||
{ root: 'user', key: 'birthplace', name: 'Место рождения' },
|
||||
{ root: 'user', key: 'mailingstreet', name: 'Адрес' },
|
||||
{ root: 'user', key: 'inn', name: 'ИНН' },
|
||||
{ root: 'project', key: 'agrdate', name: 'Дата договора' },
|
||||
{ root: 'project', key: 'agrprice', name: 'Сумма' },
|
||||
{ root: 'project', key: 'reason', name: 'Причина обращения' },
|
||||
{ root: 'project', key: 'description', name: 'Описание проблемы' },
|
||||
{ root: 'offender', key: 'accountname', name: 'Название организации' },
|
||||
{ root: 'offender', key: 'inn', name: 'ИНН организации' },
|
||||
{ root: 'offender', key: 'address', name: 'Адрес организации' },
|
||||
{ root: 'offender', key: 'email', name: 'E-mail организации' },
|
||||
{ root: 'user', key: 'bank_id', name: 'Банк для получения выплаты' }
|
||||
];
|
||||
|
||||
var errors = [];
|
||||
|
||||
for (var i = 0; i < requiredFields.length; i++) {
|
||||
var field = requiredFields[i];
|
||||
var value = '';
|
||||
if (field.root === 'user') {
|
||||
value = state.user[field.key] || '';
|
||||
} else if (field.root === 'project') {
|
||||
value = state.project[field.key] || '';
|
||||
} else if (field.root === 'offender') {
|
||||
value = (state.offenders[0] && state.offenders[0][field.key]) || '';
|
||||
}
|
||||
if (!value || (typeof value === 'string' && value.trim() === '')) {
|
||||
for (var i = 0; i < requiredFieldsList.length; i++) {
|
||||
var field = requiredFieldsList[i];
|
||||
if (!isFieldFilled(field.root, field.key, field.root === 'offender' ? 0 : undefined)) {
|
||||
errors.push(field.name);
|
||||
}
|
||||
}
|
||||
@@ -1223,6 +1301,34 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Функция обновления блока с предупреждением о незаполненных полях
|
||||
function updateValidationWarning() {
|
||||
var warningBlock = document.getElementById('validation-warning-block');
|
||||
if (!warningBlock) return;
|
||||
|
||||
var validationErrors = validateAllFields();
|
||||
|
||||
if (validationErrors.length === 0) {
|
||||
warningBlock.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// Формируем HTML для предупреждения
|
||||
var warningHtml = '<div class="validation-warning">';
|
||||
warningHtml += '<div class="validation-warning-title">';
|
||||
warningHtml += '⚠️ Пожалуйста, заполните все обязательные поля (' + validationErrors.length + '):';
|
||||
warningHtml += '</div>';
|
||||
warningHtml += '<ul class="validation-warning-list">';
|
||||
for (var i = 0; i < validationErrors.length; i++) {
|
||||
warningHtml += '<li>' + esc(validationErrors[i]) + '</li>';
|
||||
}
|
||||
warningHtml += '</ul>';
|
||||
warningHtml += '</div>';
|
||||
|
||||
warningBlock.innerHTML = warningHtml;
|
||||
warningBlock.style.display = 'block';
|
||||
}
|
||||
|
||||
// Функция обновления состояния кнопки отправки
|
||||
function updateSubmitButton() {
|
||||
var confirmBtn = document.getElementById('confirmBtn');
|
||||
@@ -1231,6 +1337,15 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
var isConsentGiven = state.meta && state.meta.privacyConsent === true;
|
||||
var validationErrors = validateAllFields();
|
||||
|
||||
// Обновляем блок с предупреждением
|
||||
updateValidationWarning();
|
||||
|
||||
// Обновляем стили всех полей
|
||||
var fields = document.querySelectorAll('.bind');
|
||||
Array.prototype.forEach.call(fields, function(field) {
|
||||
updateFieldStyle(field);
|
||||
});
|
||||
|
||||
if (!isConsentGiven) {
|
||||
confirmBtn.disabled = true;
|
||||
confirmBtn.style.opacity = '0.6';
|
||||
@@ -1245,7 +1360,7 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
confirmBtn.disabled = true;
|
||||
confirmBtn.style.opacity = '0.6';
|
||||
confirmBtn.style.cursor = 'not-allowed';
|
||||
confirmBtn.textContent = '❌ Заполните все поля (' + validationErrors.length + ')';
|
||||
confirmBtn.textContent = '❌ Заполните все обязательные поля (' + validationErrors.length + ')';
|
||||
confirmBtn.title = 'Не заполнены: ' + validationErrors.join(', ');
|
||||
}
|
||||
}
|
||||
@@ -1256,10 +1371,16 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
var hasValue = field.type === 'checkbox' ? value : value.length > 0;
|
||||
var key = field.getAttribute('data-key');
|
||||
var root = field.getAttribute('data-root');
|
||||
var index = field.getAttribute('data-index');
|
||||
var fieldIndex = index !== null ? parseInt(index, 10) : undefined;
|
||||
|
||||
// Убираем оба класса сначала
|
||||
// Убираем все классы сначала
|
||||
field.classList.remove('filled');
|
||||
field.classList.remove('invalid');
|
||||
field.classList.remove('required-empty');
|
||||
|
||||
// Проверяем, является ли поле обязательным
|
||||
var isRequired = isRequiredField(root, key);
|
||||
|
||||
if (hasValue) {
|
||||
// Проверяем валидность для телефона и email
|
||||
@@ -1283,10 +1404,16 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
field.classList.add('filled');
|
||||
} else {
|
||||
field.classList.add('filled');
|
||||
} else {
|
||||
field.classList.add('invalid');
|
||||
}
|
||||
} else {
|
||||
// Поле не заполнено
|
||||
if (isRequired) {
|
||||
// Обязательное поле не заполнено - подсвечиваем жёлтым
|
||||
field.classList.add('required-empty');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user