diff --git a/ticket_form/frontend/src/components/form/generateConfirmationFormHTML.ts b/ticket_form/frontend/src/components/form/generateConfirmationFormHTML.ts
index 2f116820..589088f5 100644
--- a/ticket_form/frontend/src/components/form/generateConfirmationFormHTML.ts
+++ b/ticket_form/frontend/src/components/form/generateConfirmationFormHTML.ts
@@ -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 += '';
html += '
Заявитель: ';
- html += createField('user', 'lastname', u.lastname, 'Фамилия (обязательно)');
+ html += createField('user', 'lastname', u.lastname, 'Фамилия') + '*';
html += ' ';
- html += createField('user', 'firstname', u.firstname, 'Имя (обязательно)');
+ html += createField('user', 'firstname', u.firstname, 'Имя') + '*';
html += ' ';
html += createField('user', 'secondname', u.secondname, 'Отчество');
html += '
';
html += 'Дата рождения: ';
html += createDateField('user', 'birthday', u.birthday);
- html += '
';
+ html += '*';
html += 'Место рождения: ';
- html += createField('user', 'birthplace', u.birthplace, 'Место рождения (обязательно)');
- html += '
';
+ html += createField('user', 'birthplace', u.birthplace, 'Место рождения');
+ html += '*';
html += 'ИНН: ';
- html += createField('user', 'inn', u.inn, '12-значный ИНН (обязательно)');
- html += '
';
+ html += createField('user', 'inn', u.inn, '12-значный ИНН');
+ html += '*';
html += 'Адрес: ';
- html += createField('user', 'mailingstreet', u.mailingstreet, 'Адрес регистрации как в паспорте (обязательно)');
- html += '
';
+ html += createField('user', 'mailingstreet', u.mailingstreet, 'Адрес регистрации как в паспорте');
+ html += '*';
html += 'Телефон: ';
html += createReadonlyField('user', 'mobile', u.mobile);
@@ -961,9 +1013,9 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
// Возмещение
html += '
Возмещение:
';
html += 'Выплата возмещения возможна по системе быстрых платежей (СБП) по номеру телефона заявителя: ' + esc(u.mobile || '') + '
';
- html += 'Банк для получения выплаты (обязательно): ';
+ html += '
Банк для получения выплаты: ';
html += createBankSelect('user', 'bank_id', u.bank_id || '');
- html += '
';
+ html += '*';
html += '';
@@ -983,12 +1035,12 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
// Дата события / заключения договора
html += 'Дата события / заключения договора: ';
html += createDateField('project', 'agrdate', p.agrdate);
- html += '
';
+ html += '*';
// Сумма оплаты / стоимость
html += 'Сумма оплаты / стоимость: ';
html += createMoneyField('project', 'agrprice', p.agrprice);
- html += '
';
+ html += '*';
// Период
html += 'Период: ';
@@ -1013,19 +1065,19 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
html += '
Наименование: ';
html += createField('offender', 'accountname', offender.accountname, 'Название организации', i);
- html += '
';
+ html += '*';
html += 'ИНН: ';
- html += createField('offender', 'inn', offender.inn, 'ИНН организации (10 или 12 цифр) (обязательно)', i);
- html += '
';
+ html += createField('offender', 'inn', offender.inn, 'ИНН организации (10 или 12 цифр)', i);
+ html += '*';
html += 'Адрес: ';
- html += createField('offender', 'address', offender.address, 'Адрес (обязательно)', i);
- html += '
';
+ html += createField('offender', 'address', offender.address, 'Адрес', i);
+ html += '*';
html += 'E-mail: ';
- html += createField('offender', 'email', offender.email, 'email@example.com (обязательно)', i);
- html += '
';
+ html += createField('offender', 'email', offender.email, 'email@example.com', i);
+ html += '*';
html += 'Телефон: ';
html += createField('offender', 'phone', offender.phone, '+7 (___) ___-__-__', i);
@@ -1043,15 +1095,18 @@ export function generateConfirmationFormHTML(data: any, contact_data_confirmed:
// Причина обращения (редактируемая)
html += '
Причина обращения: ';
html += createField('project', 'reason', p.reason, 'Можете уточнить или изменить причину обращения');
- html += '
';
+ html += '*';
- html += 'Описание проблемы:
';
+ html += 'Описание проблемы: *
';
html += createTextarea('project', 'description', p.description);
html += 'На основании вышеизложенного и руководствуясь ст. 45 Закона «О защите прав потребителей», ст. 3, ч. 1 ст. 46 ГПК РФ, прошу вас защитить мои потребительские права, обратиться в суд с заявлением о защите моих потребительских прав и/или с коллективным иском о защите группы потребителей, и представлять мои интересы во всех судебных органах РФ, а также обращаться с заявлениями во все госорганы, подавать претензии, письма и жалобы.
';
html += '';
+ // Блок с предупреждением о незаполненных полях (будет обновляться динамически)
+ html += '';
+
// Согласие на обработку персональных данных
html += '';
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 = '
';
+ warningHtml += '
';
+ warningHtml += '⚠️ Пожалуйста, заполните все обязательные поля (' + validationErrors.length + '):';
+ warningHtml += '
';
+ warningHtml += '
';
+ for (var i = 0; i < validationErrors.length; i++) {
+ warningHtml += '- ' + esc(validationErrors[i]) + '
';
+ }
+ warningHtml += '
';
+ warningHtml += '
';
+
+ 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');
+ }
}
}