2136 lines
88 KiB
JavaScript
2136 lines
88 KiB
JavaScript
// Функция инициализации автодополнения адресов через DaData
|
||
function initAddressSuggestions() {
|
||
if (typeof $.fn.suggestions !== 'undefined') {
|
||
// Инициализируем автодополнение адресов для поля с классом .js-adres
|
||
$('.js-adres').each(function() {
|
||
// Проверяем, не инициализировано ли уже
|
||
if (!$(this).data('suggestions-initialized')) {
|
||
$(this).suggestions({
|
||
token: "d2fa8613e186d54c6c62fc321414552353ffdfa8",
|
||
type: "ADDRESS",
|
||
onSelect: function(suggestion) {
|
||
// При выборе адреса заполняем поле
|
||
$(this).val(suggestion.value);
|
||
}
|
||
});
|
||
$(this).data('suggestions-initialized', true);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
/** Возраст в годах по дате дд-мм-гггг; null при пустой/некорректной дате. Глобально для доступа из всех обработчиков. */
|
||
function getAge(dateString) {
|
||
if (!dateString) return null;
|
||
var today = new Date();
|
||
var birthDate = new Date(dateString.replace(/(\d{2})-(\d{2})-(\d{4})/, "$2/$1/$3"));
|
||
if (isNaN(birthDate.getTime())) return null;
|
||
var age = today.getFullYear() - birthDate.getFullYear();
|
||
var m = today.getMonth() - birthDate.getMonth();
|
||
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) age--;
|
||
return age;
|
||
}
|
||
|
||
$(function() {
|
||
$(document).ready(function(){
|
||
|
||
// F: нормальный регистр для списка стран (первая буква заглавная, остальные строчные)
|
||
function normalizeCountryLabel(text) {
|
||
return (text || '').trim().replace(/\S+/g, function(word) {
|
||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
||
});
|
||
}
|
||
$('select[name=countryevent] option, select[name=countrycode] option').each(function() {
|
||
var $opt = $(this), t = $opt.text().trim();
|
||
if (t) $opt.text(normalizeCountryLabel(t));
|
||
});
|
||
|
||
// Блокируем кнопку "Отправить смс" по умолчанию, пока полис не проверен
|
||
$('.js-send-sms').addClass('disabled');
|
||
$('.js-send-sms').prop('disabled', true);
|
||
|
||
// Поля телефона и банка скрыты по умолчанию (через класс d-none в HTML)
|
||
|
||
// Блокируем поле "ФИО Получателя" по умолчанию (доступно только для несовершеннолетних)
|
||
$("input[data-enableby=birthday]").addClass('disabled');
|
||
$("input[data-enableby=birthday]").prop('disabled', true);
|
||
$("input[data-enableby=birthday]").prop('readonly', true);
|
||
|
||
$(".js-progress-mask").inputmask("99");
|
||
$(".js-inn-mask").inputmask("999999999999");
|
||
$(".js-inn-mask2").inputmask("9{10,12}");
|
||
$(".js-bank-mask").inputmask({ mask: ["9999 9999 9999 9999", "9999 9999 9999 9999", "9999 9999 9999 9999", "9999 999999 99999"], greedy: false, "placeholder": "*", "clearIncomplete": true });
|
||
|
||
$(".js-code-mask").inputmask("999999");
|
||
$(".js-date-mask").inputmask("99-99-9999",{ "placeholder": "дд-мм-гггг" });
|
||
|
||
$(".js-doccode-mask").inputmask("99");
|
||
$(".js-countrycode-mask").inputmask("999");
|
||
|
||
// $("#country").countrySelect();
|
||
Inputmask.extendDefinitions({
|
||
'*': { //masksymbol
|
||
"validator": "[0-9\(\)\.\+/ ]"
|
||
},
|
||
});
|
||
|
||
// Номер полиса: буква + 3–5 цифр + дефис + до 20 символов (чтобы влезало A270-11968314/10 и т.п.)
|
||
$(".js-inndb-mask").inputmask("A9{3,5}-*{6,20}");
|
||
|
||
$(".js-inndb-mask").keyup(function(){
|
||
//if($this)
|
||
});
|
||
|
||
|
||
document.querySelector('input').addEventListener('keydown', function (e) {
|
||
if (e.which == 9) {
|
||
e.preventDefault();
|
||
}
|
||
});
|
||
|
||
|
||
let month =['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
|
||
let days = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
|
||
|
||
|
||
if($('input[name="birthday"]').length) {
|
||
|
||
var birthday = datepicker('input[name="birthday"]',
|
||
{
|
||
customOverlayMonths: month,
|
||
customMonths: month,
|
||
customDays: days,
|
||
maxDate: new Date(),
|
||
disableYearOverlay: false, // C1: выбор года включён
|
||
formatter: function(input, date, instance) {
|
||
var d = date.getDate(), m = date.getMonth() + 1, y = date.getFullYear();
|
||
input.value = (d < 10 ? '0' + d : d) + '-' + (m < 10 ? '0' + m : m) + '-' + y; // дд-мм-гггг
|
||
},
|
||
onSelect: function(dateText, inst) {
|
||
var birthdayVal = $('input[name="birthday"]').val();
|
||
applyRepresentativeBlockVisibility(birthdayVal);
|
||
}
|
||
});
|
||
|
||
// C2: по умолчанию блок законного представителя скрыт
|
||
applyRepresentativeBlockVisibility($('input[name="birthday"]').val());
|
||
}
|
||
|
||
function applyRepresentativeBlockVisibility(birthdayVal) {
|
||
var age = birthdayVal ? getAge(birthdayVal) : null;
|
||
if (age !== null && age < 18) {
|
||
$('.form-item.js-representative-block[data-enableby-block=birthday], .form-item.js-representative-block[data-disabledby-block=birthday]').removeClass('d-none');
|
||
$("input[data-enableby=birthday]").removeClass('disabled').prop('disabled', false).prop('readonly', false);
|
||
$("input[data-disabledby=birthday]").removeClass('disabled').prop('disabled', false);
|
||
} else {
|
||
$('.form-item.js-representative-block[data-enableby-block=birthday], .form-item.js-representative-block[data-disabledby-block=birthday]').addClass('d-none');
|
||
$("input[data-enableby=birthday]").addClass('disabled').prop('disabled', true).prop('readonly', true).val('');
|
||
$("input[data-disabledby=birthday]").addClass('disabled').prop('disabled', true);
|
||
var $fileInput = $('input[data-disabledby=birthday]');
|
||
if ($fileInput.length) { $fileInput[0].value = ''; $fileInput.removeAttr('data-uploadurl'); $fileInput.closest('.form-item').find('.fileList').empty(); }
|
||
}
|
||
}
|
||
|
||
// Инициализация datepicker для поля даты рейса отправления
|
||
if($('input[name="departure_date"]').length) {
|
||
var departure_date = datepicker('input[name="departure_date"]',{
|
||
customOverlayMonths: month,
|
||
customMonths: month,
|
||
customDays: days,
|
||
maxDate: new Date(),
|
||
formatter: (input, date, instance) => {
|
||
const value = date.toLocaleDateString()
|
||
input.value = value // => '1/1/2099'
|
||
}
|
||
});
|
||
}
|
||
|
||
// Инициализация datepicker для всех полей «Дата наступления страхового случая» (авиа и отель)
|
||
$('input[name="insurence_date"]').each(function() {
|
||
datepicker(this, {
|
||
customOverlayMonths: month,
|
||
customMonths: month,
|
||
customDays: days,
|
||
maxDate: new Date(),
|
||
disableYearOverlay: false,
|
||
formatter: function(input, date, instance) {
|
||
var d = date.getDate(), m = date.getMonth() + 1, y = date.getFullYear();
|
||
input.value = (d < 10 ? '0' + d : d) + '-' + (m < 10 ? '0' + m : m) + '-' + y;
|
||
}
|
||
});
|
||
});
|
||
|
||
var phone = document.querySelectorAll('.js-phone-mask');
|
||
// Маска телефона (10 цифр без +7, т.к. код страны показываем отдельно)
|
||
// Нормализуем вставку 11-значных номеров (7/8 + 10 цифр) ДО того, как Inputmask обрежет лишнее.
|
||
function normalizeRfPhoneDigits(val) {
|
||
var digits = String(val || '').replace(/\D/g, '');
|
||
// Запрет +7, 8, 7 в начале — оставляем только 10 цифр номера РФ
|
||
if (digits.length >= 11 && (digits[0] === '7' || digits[0] === '8')) digits = digits.slice(1);
|
||
if (digits.length === 12 && digits.startsWith('77')) digits = digits.slice(2);
|
||
return digits.slice(0, 10);
|
||
}
|
||
function formatRfPhoneMasked(digits) {
|
||
if (digits.length === 0) return '';
|
||
var d = digits.slice(0, 10);
|
||
var s = d.slice(0,3);
|
||
if (d.length > 3) s += ' ' + d.slice(3,6);
|
||
if (d.length > 6) s += '-' + d.slice(6,8);
|
||
if (d.length > 8) s += '-' + d.slice(8,10);
|
||
return s;
|
||
}
|
||
$('.js-phone-mask').inputmask('999 999-99-99', {
|
||
onBeforePaste: function(pastedValue) {
|
||
var digits = normalizeRfPhoneDigits(pastedValue);
|
||
return digits;
|
||
}
|
||
});
|
||
$('.js-phone-mask').on('input', function() {
|
||
var $el = $(this);
|
||
var digits = normalizeRfPhoneDigits($el.val());
|
||
var formatted = formatRfPhoneMasked(digits);
|
||
if (formatted !== $el.val()) $el.val(formatted);
|
||
});
|
||
$('.js-phone-mask').on('keypress', function(e) {
|
||
var ch = String.fromCharCode(e.which || e.keyCode);
|
||
if (!/^\d$/.test(ch)) { e.preventDefault(); return; }
|
||
var digits = normalizeRfPhoneDigits($(this).val());
|
||
if (digits.length >= 10) e.preventDefault();
|
||
});
|
||
$('.js-phone-mask').on('keydown', function(e) {
|
||
var key = e.which || e.keyCode;
|
||
if (key !== 56 && key !== 55) return;
|
||
var el = this;
|
||
var start = el.selectionStart, end = el.selectionEnd;
|
||
var val = el.value || '';
|
||
var digitsBeforeCaret = val.slice(0, start).replace(/\D/g, '');
|
||
if (digitsBeforeCaret.length === 0 && (key === 56 || key === 55)) e.preventDefault();
|
||
});
|
||
phone.forEach(el => {
|
||
const iti = window.intlTelInput(el, {
|
||
initialCountry: 'ru',
|
||
onlyCountries : ['ru'],
|
||
separateDialCode: true,
|
||
customContainer: ".form-item",
|
||
autoPlaceholder: 'off', // Отключаем автоматический placeholder
|
||
allowDropdown: false, // Убираем выпадающий список
|
||
utilsScript: "libs/intl-tel-input-master/build/js/utils.js",
|
||
});
|
||
// Устанавливаем кастомный placeholder без "8", соответствует маске 999 999-99-99
|
||
el.setAttribute('placeholder', '912 345-67-89');
|
||
});
|
||
|
||
// Телефон средства размещения (отель и т.д.) — международный формат, без привязки к РФ
|
||
var placePhoneEls = document.querySelectorAll('.js-place-phone');
|
||
if (window.intlTelInput && placePhoneEls.length) {
|
||
placePhoneEls.forEach(function(el) {
|
||
window.intlTelInput(el, {
|
||
initialCountry: 'ru',
|
||
separateDialCode: true,
|
||
utilsScript: "libs/intl-tel-input-master/build/js/utils.js",
|
||
allowDropdown: true,
|
||
autoPlaceholder: 'off',
|
||
placeholderNumberType: 'MOBILE'
|
||
});
|
||
// Подсказка без кода страны — код уже показывается отдельно (флаг +7)
|
||
el.setAttribute('placeholder', '912 345-67-89');
|
||
// Очистка артефакта "kkkk..." при фокусе (если осталось от старого бага или маски)
|
||
el.addEventListener('focus', function() {
|
||
var v = (el.value || '').replace(/\s/g, '');
|
||
if (/^\+?7?k+$/.test(v) || /^k+$/.test(v)) el.value = '';
|
||
});
|
||
// Только цифры и символы номера; не более 15 цифр (маска)
|
||
function enforcePlacePhoneMask(inputEl) {
|
||
var v = inputEl.value || '';
|
||
var digits = v.replace(/\D/g, '');
|
||
if (digits.length > 15) digits = digits.slice(0, 15);
|
||
var allowed = v.replace(/[^\d+\s\-()]/g, '');
|
||
var allowedDigits = allowed.replace(/\D/g, '');
|
||
if (allowedDigits.length > 15) {
|
||
var take = '';
|
||
for (var i = 0, d = 0; i < allowed.length && d < 15; i++) {
|
||
if (/\d/.test(allowed[i])) d++;
|
||
take += allowed[i];
|
||
}
|
||
allowed = take;
|
||
}
|
||
if (v !== allowed) inputEl.value = allowed;
|
||
}
|
||
el.addEventListener('input', function() { enforcePlacePhoneMask(this); });
|
||
el.addEventListener('paste', function(e) {
|
||
var pasted = (e.clipboardData || window.clipboardData).getData('text');
|
||
var digits = pasted.replace(/\D/g, '').slice(0, 15);
|
||
var allowed = pasted.replace(/[^\d+\s\-()]/g, '');
|
||
if (allowed.replace(/\D/g, '').length > 15) allowed = digits;
|
||
if (pasted !== allowed) {
|
||
e.preventDefault();
|
||
var start = this.selectionStart, end = this.selectionEnd;
|
||
this.value = this.value.slice(0, start) + allowed + this.value.slice(end);
|
||
enforcePlacePhoneMask(this);
|
||
this.setSelectionRange(Math.min(start + allowed.length, this.value.length), Math.min(start + allowed.length, this.value.length));
|
||
}
|
||
});
|
||
});
|
||
}
|
||
// Дополнительно: делегированный обработчик, чтобы маска работала и при динамическом появлении поля
|
||
$(document).on('input', '.js-place-phone', function() {
|
||
var v = this.value || '';
|
||
var digits = v.replace(/\D/g, '');
|
||
if (digits.length > 15) {
|
||
var take = '';
|
||
for (var i = 0, d = 0; i < v.length && d < 15; i++) {
|
||
if (/\d/.test(v[i])) d++;
|
||
take += v[i];
|
||
}
|
||
this.value = take;
|
||
}
|
||
var allowed = v.replace(/[^\d+\s\-()]/g, '');
|
||
if (v !== allowed) this.value = allowed;
|
||
});
|
||
|
||
// Поля ФИО: только буквы (кириллица, латиница), пробел, дефис (для двойных фамилий)
|
||
var nameFieldsSelector = 'input[name="lastname"], input[name="firstname"], input[name="patronymic"]';
|
||
var nameAllowedRegex = /[^\u0400-\u04FFa-zA-Z\s\-]/g;
|
||
$(document).on('input', nameFieldsSelector, function() {
|
||
var v = this.value;
|
||
var allowed = v.replace(nameAllowedRegex, '');
|
||
if (v !== allowed) this.value = allowed;
|
||
});
|
||
$(document).on('paste', nameFieldsSelector, function(e) {
|
||
var pasted = (e.originalEvent && e.originalEvent.clipboardData) ? e.originalEvent.clipboardData.getData('text') : (window.clipboardData ? window.clipboardData.getData('Text') : '');
|
||
var allowed = pasted.replace(nameAllowedRegex, '');
|
||
if (pasted !== allowed) {
|
||
e.preventDefault();
|
||
var start = this.selectionStart, end = this.selectionEnd;
|
||
this.value = this.value.slice(0, start) + allowed + this.value.slice(end);
|
||
this.setSelectionRange(start + allowed.length, start + allowed.length);
|
||
}
|
||
});
|
||
|
||
// Защита от изменения подтвержденного номера телефона (в т.ч. через автозаполнение) — только для своего номера
|
||
$('.js-phone-mask').on('input change', function() {
|
||
var $this = $(this);
|
||
var confirmedPhone = $this.attr('data-confirmed-phone');
|
||
|
||
if (confirmedPhone && $this.prop('readonly')) {
|
||
var currentValue = $this.val();
|
||
if (currentValue !== confirmedPhone) {
|
||
$this.val(confirmedPhone);
|
||
}
|
||
}
|
||
|
||
// Дополнительно обновляем состояние кнопки SMS только для основного телефона
|
||
if ($this.attr('name') === 'phonenumber') {
|
||
updateSmsButtonState();
|
||
}
|
||
});
|
||
|
||
// Обработчик смены страны отключен, так как выпадающий список убран
|
||
// $('.js-phone-mask').on('countrychange', e => {
|
||
// let $this = $(e.currentTarget),
|
||
// placeholder = $this.attr('placeholder'),
|
||
// mask = placeholder.replace(/[0-9]/g, 9);
|
||
// $this.val('').inputmask(mask);
|
||
// let inputCode = $(".code"),
|
||
// flag = document.querySelector(".iti__selected-flag"),
|
||
// codeTitle = flag.getAttribute("title");
|
||
// inputCode.val(codeTitle);
|
||
// });
|
||
|
||
|
||
|
||
let index=1;
|
||
|
||
// miniapp: шаги с выбором авиа/отель
|
||
var isMiniapp = $('.js-step-choice').length > 0;
|
||
var miniappStepList = [];
|
||
var miniappStepIndex = -1;
|
||
var miniappClaimType = null;
|
||
var DEBUG_MINIAPP = false; // I: отладочный флаг для логирования claim_type и stepKey
|
||
|
||
function miniappShowStep(stepKey) {
|
||
if (DEBUG_MINIAPP) console.log('miniappShowStep:', stepKey);
|
||
$('.form-step').removeClass('active');
|
||
$('.js-step-common-applicant, .js-step-common-final').addClass('d-none');
|
||
$('.form-branch-avia, .form-branch-hotel').addClass('d-none');
|
||
if (stepKey === 'choice') {
|
||
$('.js-step-choice').removeClass('d-none').addClass('active');
|
||
} else if (stepKey === 'applicant') {
|
||
$('.js-step-choice').addClass('d-none');
|
||
$('.js-step-common-applicant').removeClass('d-none').addClass('active');
|
||
// Ветку не показываем — только ФИО; ветка откроется на следующем шаге (avia-1 / hotel-1)
|
||
} else if (stepKey === 'avia-1') {
|
||
$('.js-step-common-applicant').addClass('d-none');
|
||
$('.form-branch-avia').removeClass('d-none');
|
||
$('.form-branch-avia .form-step[data-step=avia-1]').addClass('active');
|
||
} else if (stepKey === 'hotel-1' || stepKey === 'hotel-2') {
|
||
$('.js-step-common-applicant').addClass('d-none');
|
||
$('.form-branch-hotel').removeClass('d-none');
|
||
$('.form-branch-hotel .form-step[data-step=' + stepKey + ']').addClass('active');
|
||
} else if (stepKey === 'final') {
|
||
$('.form-branch-avia .form-step, .form-branch-hotel .form-step').removeClass('active');
|
||
$('.form-branch-avia, .form-branch-hotel').addClass('d-none');
|
||
$('.js-step-common-final').removeClass('d-none').addClass('active');
|
||
}
|
||
}
|
||
|
||
function miniappValidateChoice() {
|
||
if ($('input[name=claim_type]:checked').length === 0) {
|
||
$('.js-step-choice .form-item__warning').text('Выберите тип обращения');
|
||
return false;
|
||
}
|
||
$('.js-step-choice .form-item__warning').text('');
|
||
return true;
|
||
}
|
||
|
||
// G: при смене типа обращения обновляем список шагов и счётчик в прогрессбаре
|
||
$('input[name=claim_type]').on('change', function() {
|
||
if (!isMiniapp || miniappStepList.length === 0) return;
|
||
miniappClaimType = $(this).val();
|
||
miniappStepList = miniappClaimType === 'avia' ? ['choice', 'applicant', 'avia-1', 'final'] : ['choice', 'applicant', 'hotel-1', 'hotel-2', 'final'];
|
||
$('.span-progress .total').text(miniappStepList.length);
|
||
});
|
||
|
||
$('.js-btn-next').on("click",function(e){
|
||
e.preventDefault();
|
||
if($(this).hasClass('disabled') || $(this).prop('disabled')) return false;
|
||
|
||
if (isMiniapp) {
|
||
// G: первый логический шаг — выбор типа (choice)
|
||
if (miniappStepIndex === 0) {
|
||
if (!miniappValidateChoice()) return;
|
||
miniappClaimType = $('input[name=claim_type]:checked').val();
|
||
miniappStepList = miniappClaimType === 'avia' ? ['choice', 'applicant', 'avia-1', 'final'] : ['choice', 'applicant', 'hotel-1', 'hotel-2', 'final'];
|
||
if (DEBUG_MINIAPP) console.log('miniapp claim_type:', miniappClaimType, 'stepList:', miniappStepList);
|
||
$('.span-progress .total').text(miniappStepList.length);
|
||
miniappStepIndex = 1;
|
||
miniappShowStep(miniappStepList[1]);
|
||
$('.span-progress .current').text(2);
|
||
$('.js-btn-prev').show();
|
||
return;
|
||
}
|
||
if (!validate_step(miniappStepIndex + 1)) return;
|
||
miniappStepIndex++;
|
||
$('.span-progress .current').text(miniappStepIndex + 1);
|
||
miniappShowStep(miniappStepList[miniappStepIndex]);
|
||
if (miniappStepIndex === miniappStepList.length - 1) {
|
||
$(this).hide();
|
||
$('.btn--submit').show();
|
||
} else {
|
||
$('.js-btn-prev').show();
|
||
}
|
||
return;
|
||
}
|
||
|
||
let isvalid=validate_step(index);
|
||
|
||
if(isvalid) {
|
||
index++;
|
||
$('.span-progress .current').text(index);
|
||
if(index==3) {
|
||
$(this).hide();
|
||
$('.btn--submit').show();
|
||
} else {
|
||
$(this).show();
|
||
$('.js-btn-prev').show();
|
||
}
|
||
$('.form-step').removeClass('active');
|
||
$('.form-step[data-step='+index+']').addClass('active');
|
||
}
|
||
|
||
|
||
});
|
||
|
||
// Сброс файлов при переходе «назад», чтобы повторная загрузка работала (A4)
|
||
function resetFileInputsForActiveStep() {
|
||
$('.form-step.active').find('input[type=file].js-attach').each(function() {
|
||
var $input = $(this);
|
||
$input[0].value = '';
|
||
$input.removeAttr('data-uploadurl').removeAttr('data-uploadurl_real');
|
||
$input.closest('.form-item').find('.fileList').empty();
|
||
$input.closest('.form-item').find('.form-item__warning').text('');
|
||
});
|
||
}
|
||
|
||
$('.js-btn-prev').on("click",function(e){
|
||
e.preventDefault();
|
||
if (isMiniapp && miniappStepList.length) {
|
||
miniappStepIndex--;
|
||
if (miniappStepIndex < 0) { miniappStepIndex = 0; return; }
|
||
$('.span-progress .current').text(miniappStepIndex + 1);
|
||
miniappShowStep(miniappStepList[miniappStepIndex]);
|
||
// Не сбрасываем файлы при «назад» — загруженные документы должны сохраняться
|
||
$('.btn--submit').hide();
|
||
$('.js-btn-next').show();
|
||
if (miniappStepIndex === 0) $('.js-btn-prev').hide();
|
||
return;
|
||
}
|
||
index--;
|
||
if(index==1) {$(this).hide();} else $(this).show();
|
||
if(index<1) index=1;
|
||
if(index<4) {
|
||
$('.btn--submit').hide();
|
||
$('.js-btn-next').show();
|
||
}
|
||
$('.span-progress .current').text(index);
|
||
$('.form-step').removeClass('active');
|
||
$('.form-step[data-step='+index+']').addClass('active');
|
||
// Не сбрасываем файлы при «назад» — загруженные документы должны сохраняться
|
||
});
|
||
|
||
$('select[name=claim]').on("change",function(e){
|
||
if($(this).val()==0) {
|
||
$(this).closest('.form-step').find('input[type=text]').addClass('disabled');
|
||
$(this).closest('.form-step').find('input[type=file]').addClass('disabled');
|
||
$(this).closest('.form-step').find('input[type=file]').parent().addClass('disabled');
|
||
|
||
} else {
|
||
$(this).closest('.form-step').find('input[type=text]').removeClass('disabled');
|
||
$(this).closest('.form-step').find('input[type=file]').removeClass('disabled');
|
||
$(this).closest('.form-step').find('input[type=file]').parent().removeClass('disabled');
|
||
}
|
||
|
||
});
|
||
|
||
$('select[name=countryevent]').on("change",function(e){
|
||
$('.countryevent').val($(this).find(":selected").text());
|
||
});
|
||
|
||
// Обработка изменения типа события
|
||
$('select[name="event_type"]').on('change', function() {
|
||
const selectedValue = $(this).val();
|
||
|
||
// Скрываем все дополнительные поля
|
||
$('.connection-fields, .connection-date-fields, .cancel-flight-docs').hide();
|
||
|
||
// Меняем лейблы в зависимости от выбора
|
||
if (selectedValue === 'miss_connection') {
|
||
$('#transport_number_label').text('Укажите номер рейса прибытия');
|
||
$('#insurence_date_label').text('Дата рейса прибытия');
|
||
$('.connection-fields, .connection-date-fields').show();
|
||
} else if (selectedValue === 'cancel_flight') {
|
||
$('#transport_number_label').text('Номер рейса/поезда/парома');
|
||
$('#insurence_date_label').text('Дата наступления страхового случая');
|
||
$('.cancel-flight-docs').show();
|
||
} else {
|
||
$('#transport_number_label').text('Номер рейса/поезда/парома');
|
||
$('#insurence_date_label').text('Дата наступления страхового случая');
|
||
}
|
||
});
|
||
|
||
function validate_step(step_index){
|
||
// B2: ветка НУ — на шаге hotel-2 требуется хотя бы один выбранный риск
|
||
if ($('.form-step.active[data-step="hotel-2"]').length) {
|
||
var riskChecked = $('.form-step.active').find('.js-enable-inputs input[type=checkbox]:checked').length;
|
||
if (riskChecked === 0) {
|
||
$('.form-step.active').find('.form-item__warning').first().text('Выберите хотя бы один тип риска');
|
||
return false;
|
||
}
|
||
}
|
||
// B3: для выбранных рисков в hotel-2 требуем файл
|
||
if ($('.form-step.active[data-step="hotel-2"]').length) {
|
||
$('.form-step.active').find('.form-item').each(function() {
|
||
var $item = $(this);
|
||
var $chk = $item.find('.js-enable-inputs input[type=checkbox]:checked');
|
||
if ($chk.length && $item.find('input[type=file].js-attach').length) {
|
||
var fileInput = $item.find('input[type=file].js-attach')[0];
|
||
var fileListCount = $item.find('.fileList li').length;
|
||
if (!fileInput.files.length && fileListCount === 0) {
|
||
$item.find('.form-item__warning').text('Загрузите подтверждающие документы по выбранному риску');
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
let inputs=$('.form-step.active').find('input[type="text"], input[type="tel"], input[type="file"], input[type="email"], textarea.form-input, input[type="checkbox"]');
|
||
let all_filled=false;
|
||
let res_array=[];
|
||
inputs.each(function(e){
|
||
let field_fill=false;
|
||
let $this = $(this);
|
||
|
||
// Пропускаем поля, которые помечены как не требующие валидации
|
||
if($this.hasClass('notvalidate')) {
|
||
field_fill=true; // Считаем невалидируемые поля валидными
|
||
res_array.push(field_fill);
|
||
return;
|
||
}
|
||
|
||
// Пропускаем поля, которые заблокированы (disabled или readonly)
|
||
if($this.prop('disabled') || $this.prop('readonly') || $this.hasClass('disabled')) {
|
||
field_fill=true; // Считаем заблокированные поля валидными
|
||
res_array.push(field_fill); // Добавляем в массив результатов
|
||
return; // Пропускаем дальнейшую проверку
|
||
}
|
||
|
||
// Пропускаем поля, которые находятся в скрытых блоках (d-none или display: none)
|
||
if($this.closest('.d-none').length > 0) {
|
||
field_fill=true; // Считаем скрытые поля валидными
|
||
res_array.push(field_fill);
|
||
return;
|
||
}
|
||
|
||
// Проверяем, скрыт ли родительский блок через inline стиль display: none
|
||
let $parentContainer = $this.closest('.form-item');
|
||
if($parentContainer.length > 0 && $parentContainer.is(':hidden')) {
|
||
field_fill=true; // Считаем скрытые поля валидными
|
||
res_array.push(field_fill);
|
||
return;
|
||
}
|
||
|
||
if(($this.val()=='' && !$this.hasClass('disabled') && !$this.hasClass('notvalidate') && !$this.hasClass('error') )) {
|
||
$this.closest('.form-item').find('.form-item__warning').text('Пожалуйста, заполните все обязательные поля');
|
||
field_fill=false;
|
||
|
||
} else {
|
||
$this.closest('.form-item').find('.form-item__warning').text('');
|
||
|
||
if($this.attr('type')=='email'){
|
||
var emailVal = ($this.val() || '').trim();
|
||
if(emailVal && validateEmail(emailVal)) {
|
||
field_fill=true;
|
||
} else if(!emailVal) {
|
||
field_fill=false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Пожалуйста, заполните все обязательные поля');
|
||
} else {
|
||
field_fill=false;
|
||
$this.closest('.form-item').find('.form-item__warning').text($this.data('warmes') || 'Укажите корректный email');
|
||
}
|
||
} else if($this.hasClass('js-phone-mask') || $this.attr('name') === 'phonenumber') {
|
||
var digits = ($this.val() || '').replace(/\D/g, '');
|
||
if (digits.length === 11 && (digits[0] === '7' || digits[0] === '8')) digits = digits.slice(1);
|
||
if (digits.length === 10) {
|
||
field_fill = true;
|
||
$this.closest('.form-item').find('.form-item__warning').text('');
|
||
} else {
|
||
field_fill = false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Укажите номер телефона: 10 цифр без 8 или +7');
|
||
}
|
||
} else if($this.hasClass('js-place-phone')) {
|
||
var digitsPlace = ($this.val() || '').replace(/\D/g, '');
|
||
if (digitsPlace.length >= 10 && digitsPlace.length <= 15) {
|
||
field_fill = true;
|
||
$this.closest('.form-item').find('.form-item__warning').text('');
|
||
} else if (digitsPlace.length === 0) {
|
||
field_fill = false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Пожалуйста, заполните все обязательные поля');
|
||
} else {
|
||
field_fill = false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Номер телефона: от 10 до 15 цифр');
|
||
}
|
||
} else if($this.attr('type')=='file') {
|
||
// Специальная валидация для файлов
|
||
var fileInput = this;
|
||
var filesCount = fileInput.files ? fileInput.files.length : 0;
|
||
// Проверяем также через fileList, если файлы уже обработаны
|
||
var fileListItems = $this.closest('.form-item').find('.fileList li').length;
|
||
|
||
// Если поле находится в скрытом блоке, но есть другое видимое поле с таким же name - пропускаем
|
||
var fieldName = $this.attr('name');
|
||
var isHidden = $this.closest('.d-none').length > 0;
|
||
|
||
if(isHidden && fieldName) {
|
||
// Проверяем, есть ли видимое поле с таким же name
|
||
var visibleField = $('.form-step.active').find('input[name="' + fieldName + '"]').not($this).filter(function() {
|
||
return $(this).closest('.d-none').length === 0;
|
||
});
|
||
if(visibleField.length > 0) {
|
||
// Есть видимое поле с таким же name - пропускаем скрытое
|
||
field_fill=true;
|
||
res_array.push(field_fill);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Для видимых полей проверяем наличие файлов
|
||
if(!isHidden) {
|
||
if(filesCount > 0 || fileListItems > 0) {
|
||
field_fill=true;
|
||
} else {
|
||
field_fill=false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Пожалуйста, загрузите файлы');
|
||
}
|
||
} else {
|
||
// Скрытое поле без видимого дубликата - считаем валидным
|
||
field_fill=true;
|
||
}
|
||
} else {
|
||
// Специальная валидация для поля банка
|
||
if($this.hasClass('js-bank-autocomplete')) {
|
||
var bankId = $this.closest('.form-item').find('input[name="bank_id"]').val();
|
||
if(bankId && bankId !== '') {
|
||
field_fill=true;
|
||
} else {
|
||
field_fill=false;
|
||
$this.closest('.form-item').find('.form-item__warning').text('Пожалуйста, выберите банк из списка');
|
||
}
|
||
} else {
|
||
field_fill=true;
|
||
}
|
||
}
|
||
if($this.attr('type')=='checkbox'){
|
||
|
||
if($this.is(':checked')){
|
||
field_fill=true;
|
||
$this.parent().parent().find('.form-item__warning').text();
|
||
} else {
|
||
field_fill=false;
|
||
$this.parent().parent().find('.form-item__warning').text('Пожалуйста, заполните все обязательные поля');
|
||
}
|
||
if(($this.parent().hasClass('js-enable-inputs'))){
|
||
field_fill=true;
|
||
$this.parent().parent().find('.form-item__warning').text('');
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
res_array.push(field_fill);
|
||
|
||
// Отладочный вывод для незаполненных полей отключен
|
||
});
|
||
|
||
// C3: проверка длины описания (50–2000 символов) на шагах, где есть textarea[name=description]
|
||
var $descField = $('.form-step.active').find('textarea[name=description]');
|
||
if ($descField.length && $descField.closest('.d-none').length === 0) {
|
||
var len = ($descField.val() || '').length;
|
||
if (len < 50) {
|
||
$descField.closest('.form-item').find('.form-item__warning').text('Опишите ситуацию: не менее 50 символов (сейчас ' + len + ')');
|
||
return false;
|
||
}
|
||
if (len > 2000) {
|
||
$descField.closest('.form-item').find('.form-item__warning').text('Описание не должно превышать 2000 символов');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Согласие на обработку ПД (последний шаг):
|
||
// - в старом трёхшаговом потоке — на шаге 3
|
||
// - в miniapp — только на общем финальном шаге js-step-common-final
|
||
var isFinalStep = (!isMiniapp && step_index === 3) || $('.form-step.active.js-step-common-final').length > 0;
|
||
if (isFinalStep && $('.form-step.active').find('input[name=agree]:checked').length < 1) {
|
||
$('.form__warning').show();
|
||
$('.form__warning').text('Необходимо согласие с политикой обработки персональных данных');
|
||
return false;
|
||
} else {
|
||
$('.form__warning').text('Пожалуйста, заполните все обязательные поля');
|
||
}
|
||
|
||
if(!res_array.includes(false)){
|
||
$('.form__warning').hide();
|
||
return true;
|
||
} else {
|
||
$('.form__warning').show();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
const validateEmail = (email) => {
|
||
return email.match(
|
||
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||
);
|
||
};
|
||
|
||
$('.js-enable-inputs input[type=checkbox]').on("change",function(e){
|
||
e.preventDefault();
|
||
var $formItem = $(this).closest('.form-item');
|
||
$formItem.find('input[type=file]').toggleClass('disabled');
|
||
$formItem.find('input[type=file]+label').toggleClass('disabled');
|
||
if (!$(this).is(':checked')) {
|
||
var $fileInput = $formItem.find('input[type=file].js-attach');
|
||
if ($fileInput.length) {
|
||
$fileInput[0].value = '';
|
||
$formItem.find('.fileList').empty();
|
||
$formItem.find('.form-item__warning').text('');
|
||
}
|
||
}
|
||
});
|
||
|
||
// start sms
|
||
|
||
// Глобальные переменные и помощники для SMS
|
||
var sms_verify_token = null;
|
||
var smsCooldownIntervalId = null;
|
||
var smsCooldownExpiresAt = null;
|
||
var smsIsSending = false;
|
||
|
||
function getSmsSecondsLeft() {
|
||
if (!smsCooldownExpiresAt) return 0;
|
||
var diff = Math.floor((smsCooldownExpiresAt - Date.now()) / 1000);
|
||
return diff > 0 ? diff : 0;
|
||
}
|
||
|
||
function updateSmsCountdownUI() {
|
||
var secondsLeft = getSmsSecondsLeft();
|
||
var $container = $('.sms-countdown');
|
||
if (!$container.length) return;
|
||
|
||
if (secondsLeft <= 0) {
|
||
$container.hide();
|
||
$container.find('.time').text('');
|
||
$('.modal .js-send-sms').show();
|
||
$('.sms-checking button.js-accept-sms').hide();
|
||
return;
|
||
}
|
||
|
||
$container.show();
|
||
$container.find('.time').text(secondsLeft + 'с');
|
||
// Пока таймер тикает, кнопка повторной отправки скрыта
|
||
$('.modal .js-send-sms').hide();
|
||
$('.sms-checking button.js-accept-sms').show();
|
||
}
|
||
|
||
function startSmsCooldown(seconds) {
|
||
if (!seconds || seconds <= 0) return;
|
||
smsCooldownExpiresAt = Date.now() + seconds * 1000;
|
||
if (smsCooldownIntervalId) {
|
||
clearInterval(smsCooldownIntervalId);
|
||
smsCooldownIntervalId = null;
|
||
}
|
||
updateSmsCountdownUI();
|
||
smsCooldownIntervalId = setInterval(function() {
|
||
if (getSmsSecondsLeft() <= 0) {
|
||
clearInterval(smsCooldownIntervalId);
|
||
smsCooldownIntervalId = null;
|
||
updateSmsCountdownUI();
|
||
} else {
|
||
updateSmsCountdownUI();
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
// Нормализация номера телефона для SMS (приводим к виду +7XXXXXXXXXX)
|
||
function getPhoneForSms($phoneInput) {
|
||
let raw = ($phoneInput && $phoneInput.length) ? ($phoneInput.val() || '') : '';
|
||
|
||
// Пробуем взять номер через intlTelInput (если он инициализирован)
|
||
if ($phoneInput && $phoneInput.length && window.intlTelInput && window.intlTelInputGlobals) {
|
||
const iti = window.intlTelInputGlobals.getInstance($phoneInput[0]);
|
||
if (iti) {
|
||
try {
|
||
const fullNumber = iti.getNumber(); // обычно возвращает +7...
|
||
if (fullNumber) raw = fullNumber;
|
||
} catch (e) {
|
||
// игнорируем
|
||
}
|
||
}
|
||
}
|
||
|
||
raw = (raw || '').trim();
|
||
if (!raw) return '';
|
||
|
||
// Оставляем только цифры
|
||
let digits = raw.replace(/\D/g, '');
|
||
|
||
// Фикс кейса "+77..." (двойная 7 из-за некорректной нормализации на фронте)
|
||
// Примеры:
|
||
// - +77927961181 -> digits=77927961181 (11) -> должно стать 7927961181 (10)
|
||
// - +77XXXXXXXXXX -> digits=77.......... (12) -> должно стать 7.......... (11), далее доведём до 10
|
||
if (digits.startsWith('77') && (digits.length === 11 || digits.length === 12)) {
|
||
digits = '7' + digits.slice(2);
|
||
}
|
||
|
||
// РФ: 11 цифр с лидирующей 7 или 8 -> приводим к 10 цифрам
|
||
if (digits.length === 11 && (digits[0] === '7' || digits[0] === '8')) {
|
||
digits = digits.slice(1);
|
||
}
|
||
|
||
// РФ: 10 цифр -> +7 + 10 цифр
|
||
if (digits.length === 10) {
|
||
return '+7' + digits;
|
||
}
|
||
|
||
// Если вдруг осталось 11 цифр и начинается с 7 (редкий случай) — возвращаем как +7XXXXXXXXXX
|
||
if (digits.length === 11 && digits.startsWith('7')) {
|
||
return '+' + digits;
|
||
}
|
||
|
||
// Fallback: если цифр >= 10 — берём последние 10 как РФ-номер
|
||
if (digits.length >= 10) {
|
||
return '+7' + digits.slice(-10);
|
||
}
|
||
|
||
return raw;
|
||
}
|
||
|
||
function isValidSmsPhone(phone) {
|
||
if (!phone) return false;
|
||
var digits = String(phone).replace(/\D/g, '');
|
||
// Для РФ требуем строго 11 цифр и первую 7 (формат +7XXXXXXXXXX)
|
||
return digits.length === 11 && digits[0] === '7';
|
||
}
|
||
|
||
function validateSmsPhone($phoneInput, options) {
|
||
options = options || {};
|
||
var phone = getPhoneForSms($phoneInput);
|
||
var $warning = $phoneInput.closest('.form-item').find('.form-item__warning');
|
||
|
||
if (!phone || !isValidSmsPhone(phone)) {
|
||
if (options.showError) {
|
||
$warning.text('Пожалуйста, укажите полный номер телефона');
|
||
}
|
||
return null;
|
||
}
|
||
|
||
$warning.text('');
|
||
return phone;
|
||
}
|
||
|
||
function updateSmsButtonState() {
|
||
var $phoneInput = $('input[name=\"phonenumber\"]');
|
||
if (!$phoneInput.length) return;
|
||
|
||
var phone = validateSmsPhone($phoneInput, { showError: false });
|
||
var isValid = !!phone && getSmsSecondsLeft() === 0;
|
||
|
||
var $btn = $('.sms-check .js-send-sms');
|
||
$btn.prop('disabled', !isValid).toggleClass('disabled', !isValid);
|
||
}
|
||
if (typeof window !== 'undefined') { window.updateSmsButtonState = updateSmsButtonState; }
|
||
|
||
function send_sms(){
|
||
var $phoneInput = $('input[name=\"phonenumber\"]');
|
||
var phone = validateSmsPhone($phoneInput, { showError: true });
|
||
|
||
if (!phone) {
|
||
return false;
|
||
}
|
||
|
||
// Блокируем повторные отправки, пока идёт запрос или работает таймер
|
||
if (smsIsSending || getSmsSecondsLeft() > 0) {
|
||
return false;
|
||
}
|
||
|
||
smsIsSending = true;
|
||
|
||
// Показываем загрузку
|
||
$('.sms-check .js-send-sms').prop('disabled', true).addClass('disabled').text('Отправка...');
|
||
|
||
$.ajax({
|
||
url: 'sms-verify.php?action=send',
|
||
method: 'post',
|
||
data: {
|
||
phonenumber: phone
|
||
},
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
if (data.success) {
|
||
smsIsSending = false;
|
||
// После успешной отправки запускаем единый таймер повторной отправки
|
||
startSmsCooldown(30);
|
||
updateSmsButtonState();
|
||
$('.sms-check .js-send-sms').text('Отправить смс');
|
||
if (data.demo_code) {
|
||
$('.js-code-warning').text('Режим без SMS: введите код из модалки').show();
|
||
$('#confirm_sms .js-code-mask').val(data.demo_code);
|
||
$('#confirm_sms .js-demo-code-display').remove();
|
||
$('#confirm_sms .form-item.sms-checking').first().prepend('<div class="js-demo-code-display" style="margin-bottom:12px;padding:10px;background:#f0f9ff;border:1px solid #0ea5e9;border-radius:6px;font-weight:600;">Код для проверки: ' + data.demo_code + '</div>');
|
||
} else {
|
||
$('.js-code-warning').text('Код отправлен на ваш номер телефона');
|
||
}
|
||
$.fancybox.open({
|
||
src: '#confirm_sms',
|
||
type: 'inline'
|
||
});
|
||
} else {
|
||
var $warning = $('input[name=\"phonenumber\"]').closest('.form-item').find('.form-item__warning');
|
||
$warning.text(data.message || 'Ошибка отправки SMS');
|
||
smsIsSending = false;
|
||
updateSmsButtonState();
|
||
}
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
var errorMsg = 'Ошибка отправки SMS';
|
||
if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
|
||
errorMsg = jqXHR.responseJSON.message;
|
||
}
|
||
var $warning = $('input[name=\"phonenumber\"]').closest('.form-item').find('.form-item__warning');
|
||
$warning.text(errorMsg);
|
||
smsIsSending = false;
|
||
updateSmsButtonState();
|
||
}
|
||
});
|
||
|
||
return null; // Код больше не генерируется на клиенте
|
||
}
|
||
|
||
// Функция countDown больше не используется напрямую, оставлена как заглушка
|
||
function countDown(elm, duration, fn){
|
||
startSmsCooldown(duration);
|
||
}
|
||
|
||
// Отправка SMS из основного блока (после проверки полиса и выбора банка)
|
||
$('.sms-check .js-send-sms').on('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
// Не даём кликать, пока идёт запрос или работает таймер
|
||
if (smsIsSending || getSmsSecondsLeft() > 0) {
|
||
return false;
|
||
}
|
||
|
||
// Проверка валидности полиса перед отправкой SMS
|
||
var indatabase = $('.js-indatabase').val();
|
||
// Проверяем, был ли полис загружен вручную (через policy-upload-section)
|
||
var polisInput = $('#polis_upload')[0];
|
||
var polisUploaded = polisInput && polisInput.files && polisInput.files.length > 0;
|
||
|
||
// Если полис невалидный И не загружен вручную - блокируем отправку
|
||
if((indatabase == '0' || indatabase == '' || indatabase == undefined) && !polisUploaded) {
|
||
$('.form__warning').show();
|
||
$('.form__warning').text('Пожалуйста, проверьте полис. Ваш полис не покрывает данный вид обращения.');
|
||
return false;
|
||
}
|
||
|
||
// Валидация телефона перед отправкой SMS
|
||
var $phoneInput = $('input[name=\"phonenumber\"]');
|
||
var phone = validateSmsPhone($phoneInput, { showError: true });
|
||
if (!phone) {
|
||
return false;
|
||
}
|
||
|
||
// Валидация поля банка перед отправкой SMS
|
||
var bankInput = $('.js-bank-autocomplete');
|
||
var bankId = $('input[name="bank_id"]').val();
|
||
|
||
if (!bankInput.val() || !bankId || bankId === '') {
|
||
bankInput.closest('.form-item').find('.form-item__warning').text('Пожалуйста, выберите банк из списка');
|
||
bankInput.focus();
|
||
return false;
|
||
} else {
|
||
bankInput.closest('.form-item').find('.form-item__warning').text('');
|
||
}
|
||
|
||
// Отправляем SMS через новый безопасный API (только после успешной валидации)
|
||
send_sms();
|
||
// Старт таймера будет выполнен в send_sms() при успешном ответе
|
||
$('.modal .form-item__warning').text("");
|
||
});
|
||
|
||
// Обработчик для повторной отправки SMS из модального окна
|
||
$(document).on('click', '.modal .js-send-sms', function(e) {
|
||
e.preventDefault();
|
||
|
||
// Не даём кликать, пока идёт запрос или работает таймер
|
||
if (smsIsSending || getSmsSecondsLeft() > 0) {
|
||
return false;
|
||
}
|
||
|
||
var $phoneInput = $('input[name="phonenumber"]');
|
||
var phone = validateSmsPhone($phoneInput, { showError: true });
|
||
|
||
if (!phone) {
|
||
return false;
|
||
}
|
||
|
||
// Отправляем SMS
|
||
$('.modal .js-send-sms').prop('disabled', true).text('Отправка...');
|
||
$('.modal .form-item__warning').text('');
|
||
|
||
$.ajax({
|
||
url: 'sms-verify.php?action=send',
|
||
method: 'post',
|
||
data: {
|
||
phonenumber: phone
|
||
},
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
if (data.success) {
|
||
smsIsSending = false;
|
||
$('.modal .form-item__warning').text('').removeClass('form-item__warning--error');
|
||
if (data.demo_code) {
|
||
$('.js-code-warning').text('Режим без SMS: введите код из модалки').show();
|
||
$('#confirm_sms .js-code-mask').val(data.demo_code);
|
||
$('#confirm_sms .js-demo-code-display').remove();
|
||
$('#confirm_sms .form-item.sms-checking').first().prepend('<div class="js-demo-code-display" style="margin-bottom:12px;padding:10px;background:#f0f9ff;border:1px solid #0ea5e9;border-radius:6px;font-weight:600;">Код для проверки: ' + data.demo_code + '</div>');
|
||
} else {
|
||
$('.js-code-warning').text('Код отправлен на ваш номер телефона').show();
|
||
}
|
||
// После успешной повторной отправки запускаем/продлеваем таймер
|
||
startSmsCooldown(30);
|
||
updateSmsButtonState();
|
||
} else {
|
||
$('.modal .form-item__warning').text(data.message || 'Ошибка отправки SMS');
|
||
$('.modal .js-send-sms').prop('disabled', false).text('Отправить повторно');
|
||
}
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
var errorMsg = 'Ошибка отправки SMS';
|
||
if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
|
||
errorMsg = jqXHR.responseJSON.message;
|
||
}
|
||
$('.modal .form-item__warning').text(errorMsg);
|
||
$('.modal .js-send-sms').prop('disabled', false).text('Отправить повторно');
|
||
smsIsSending = false;
|
||
}
|
||
});
|
||
});
|
||
|
||
$('.sms-checking .js-accept-sms').on('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
var code = $('.sms-checking input[type="text"]').val();
|
||
var $phoneInput = $('input[name="phonenumber"]');
|
||
var phone = validateSmsPhone($phoneInput, { showError: true });
|
||
|
||
if (!code || !phone) {
|
||
$('.modal .form-item__warning').text("Введите код подтверждения");
|
||
return false;
|
||
}
|
||
|
||
// Показываем загрузку
|
||
$('.js-accept-sms').prop('disabled', true).text('Проверка...');
|
||
$('.modal .form-item__warning').text('');
|
||
|
||
// Проверяем код на сервере
|
||
$.ajax({
|
||
url: 'sms-verify.php?action=verify',
|
||
method: 'post',
|
||
data: {
|
||
phonenumber: phone,
|
||
code: code
|
||
},
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
if (data.success) {
|
||
// Код подтвержден (токен больше не используется)
|
||
// sms_verify_token = data.token; // Убрано - токен больше не нужен
|
||
|
||
$('.sms-success').removeClass('d-none');
|
||
|
||
// Проверяем, был ли полис уже проверен
|
||
var indatabase = $('.js-indatabase').val();
|
||
if(indatabase == '1') {
|
||
// Если полис валидный, сразу показываем форму для заполнения
|
||
$('.db-success').removeClass('d-none');
|
||
$('.form-step[data-step=1]').removeClass('disabled');
|
||
// Инициализируем автодополнение адресов после показа формы
|
||
setTimeout(function() {
|
||
initAddressSuggestions();
|
||
}, 500);
|
||
} else {
|
||
// Если полис невалидный, но был загружен через policy-upload-section, показываем форму
|
||
var polisInput = $('#polis_upload')[0];
|
||
var polisUploaded = polisInput && polisInput.files && polisInput.files.length > 0;
|
||
if(polisUploaded) {
|
||
$('.db-success').removeClass('d-none');
|
||
$('.form-step[data-step=1]').removeClass('disabled');
|
||
// Инициализируем автодополнение адресов
|
||
setTimeout(function() {
|
||
initAddressSuggestions();
|
||
}, 500);
|
||
}
|
||
}
|
||
|
||
$('.modal .js-send-sms').show();
|
||
$('.sms-check .form-item > .js-send-sms').hide();
|
||
$.fancybox.close();
|
||
$.fancybox.close();
|
||
$('.sms-check').addClass("disabled");
|
||
// G: скрываем блок проверки полиса, показываем только шаг выбора
|
||
$('.sms-check').addClass('d-none');
|
||
// Инициализируем шаги miniapp: choice — первый логический шаг
|
||
if (typeof isMiniapp !== 'undefined' && isMiniapp) {
|
||
miniappStepList = ['choice', 'applicant', 'avia-1', 'final'];
|
||
miniappStepIndex = 0;
|
||
$('.span-progress .total').text(miniappStepList.length);
|
||
$('.span-progress .current').text(1);
|
||
$('.js-btn-prev').hide();
|
||
$('.js-btn-next').show();
|
||
}
|
||
// Только у поля «Ваш номер телефона» (phonenumber), не у телефона отеля
|
||
var $phoneField = $('input[name="phonenumber"]');
|
||
$phoneField.closest('.form-item').find('.form-item__warning')
|
||
.addClass('form-item__warning--success')
|
||
.text("Вы успешно подтвердили номер");
|
||
|
||
// Блокируем только поле своего телефона после подтверждения
|
||
var confirmedPhone = $phoneField.val();
|
||
$phoneField.attr('data-confirmed-phone', confirmedPhone)
|
||
// .attr('data-verify-token', sms_verify_token) // Убрано - токен больше не нужен
|
||
.prop('readonly', true)
|
||
.attr('autocomplete', 'off');
|
||
|
||
$('.js-accept-sms').prop('disabled', false).text('Подтвердить');
|
||
} else {
|
||
$('.modal .form-item__warning').text(data.message || "Неверный код");
|
||
$('.sms-success').addClass('d-none');
|
||
$('.js-accept-sms').prop('disabled', false).text('Подтвердить');
|
||
}
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
var errorMsg = "Ошибка проверки кода";
|
||
if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
|
||
errorMsg = jqXHR.responseJSON.message;
|
||
}
|
||
$('.modal .form-item__warning').text(errorMsg);
|
||
$('.sms-success').addClass('d-none');
|
||
$('.js-accept-sms').prop('disabled', false).text('Подтвердить');
|
||
}
|
||
});
|
||
});
|
||
|
||
$('.form.active form').submit(function(e){
|
||
|
||
if(!validate_step(index)){ e.preventDefault(); } else {
|
||
e.preventDefault();
|
||
|
||
$('button[type="submit"]').attr("disabled", true);
|
||
|
||
if(1) {
|
||
$('.js-code-warning').text('');
|
||
$('.js-code-warning').hide();
|
||
$('.js-send-sms').hide();
|
||
|
||
|
||
$.fancybox.open({
|
||
src: '#confirm_sms',
|
||
type: 'inline'
|
||
});
|
||
|
||
$('.loader-wrap').removeClass('d-none');
|
||
|
||
$('button[type="submit"]').attr("disabled", false);
|
||
|
||
$('button[type="submit"]').text("Данные отправляются...");
|
||
|
||
var formData = new FormData();
|
||
|
||
let fileIndex = 0; // Счетчик для правильной индексации файлов
|
||
// Отправляем файлы напрямую как бинарные данные (без предварительной загрузки через fileupload_v2.php)
|
||
jQuery.each(jQuery('input[type=file].js-attach').not('.disabled'), function(i, file) {
|
||
|
||
if(!$(this).hasClass('disabled')) {
|
||
// Используем field-type или name для группировки файлов
|
||
let field_name=jQuery(this).data('field-type') || jQuery(this).attr('name');
|
||
let docname=jQuery(this).data('docname');
|
||
|
||
// Отправляем файлы напрямую как бинарные данные в submit.php
|
||
jQuery.each(jQuery(this)[0].files, function(i, file) {
|
||
formData.append(field_name+'-'+i, file);
|
||
});
|
||
|
||
// УБРАНО: старая система загрузки через fileupload_v2.php
|
||
// Теперь файлы отправляются напрямую в submit.php как бинарные данные
|
||
// n8n будет обрабатывать файлы сам
|
||
}
|
||
});
|
||
|
||
jQuery.each(jQuery('.js-append'), function(i, file) {
|
||
|
||
let ws_name=jQuery(this).data('ws_name');
|
||
let ws_type=jQuery(this).data('ws_type');
|
||
|
||
let val="";
|
||
if(jQuery(this).attr('type') == 'checkbox'){
|
||
if(jQuery(this).is(':checked')){
|
||
val=jQuery(this).val();
|
||
}
|
||
} else {
|
||
val=jQuery(this).val();
|
||
}
|
||
let array={
|
||
ws_name : ws_name,
|
||
ws_type: ws_type,
|
||
field_val : val
|
||
};
|
||
formData.append('appends[]',JSON.stringify(array));
|
||
|
||
});
|
||
|
||
formData.append('lastname',jQuery('[name="lastname"]').val());
|
||
|
||
formData.append('getservice',jQuery('[name="getservice"]').val()); //Если есть агент посредник
|
||
|
||
let sub_dir=jQuery('input[name=sub_dir]').val();
|
||
formData.append('sub_dir',sub_dir);
|
||
if (typeof isMiniapp !== 'undefined' && isMiniapp && miniappClaimType) {
|
||
formData.append('claim_type', miniappClaimType);
|
||
}
|
||
|
||
// Отладочный вывод отключен
|
||
// for (var pair of formData.entries()) {
|
||
// console.log(pair[0]+ ', ' + pair[1]);
|
||
// }
|
||
|
||
$.ajax({
|
||
url: 'submit.php',
|
||
method: 'post',
|
||
cache: false,
|
||
contentType: false,
|
||
processData: false,
|
||
data: formData,
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
// Отладочный вывод отключен
|
||
// console.log(data);
|
||
|
||
$('.loader-wrap').addClass('d-none');
|
||
$.fancybox.close();
|
||
$.fancybox.open({
|
||
src: '#success_modal',
|
||
type: 'inline'
|
||
});
|
||
setTimeout(function(){
|
||
$.fancybox.close();
|
||
},30)
|
||
setTimeout(function(){
|
||
window.location.href = "https://lexpriority.ru/ok";
|
||
},30)
|
||
|
||
$('button[type="submit"]').text("Отправить");
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
// Отладочный вывод отключен
|
||
// console.log(jqXHR);
|
||
if (jqXHR.status === 0) {
|
||
alert('Not connect. Verify Network.');
|
||
} else if (jqXHR.status == 404) {
|
||
alert('Requested page not found (404).');
|
||
} else if (jqXHR.status == 500) {
|
||
alert('Internal Server Error (500).');
|
||
} else if (exception === 'parsererror') {
|
||
} else if (exception === 'timeout') {
|
||
alert('Time out error.');
|
||
} else if (exception === 'abort') {
|
||
alert('Ajax request aborted.');
|
||
} else {
|
||
alert('Uncaught Error. ' + jqXHR.responseText);
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
return false;
|
||
} else {
|
||
$('.js-code-warning').text('Неверный код');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
});
|
||
|
||
});
|
||
|
||
$('input[name=place],input[name=place_adres],input[name=place_inn]').keyup(function(e){
|
||
var sourceInput = $(this);
|
||
var query = $(this).val();
|
||
var settings = {
|
||
"url": "https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/party",
|
||
"method": "POST",
|
||
"timeout": 0,
|
||
"headers": {
|
||
"Authorization": "Token d2fa8613e186d54c6c62fc321414552353ffdfa8",
|
||
"Content-Type": "application/json"
|
||
},
|
||
"data": JSON.stringify({
|
||
"query": query
|
||
}),
|
||
};
|
||
$('.autocomplete__item').remove();
|
||
var address_array = [];
|
||
$.ajax(settings).done(function (response) {
|
||
for(let i=0; i<response.suggestions.length; i++) {
|
||
$('<div class="autocomplete__item" data-address="'+response.suggestions[i].data.address.value+'" data-inn="'+response.suggestions[i].data.inn+'">'+response.suggestions[i].value+'</div>').appendTo(sourceInput.closest('.form-item').find('.form-item__dropdown'));
|
||
}
|
||
});
|
||
});
|
||
|
||
$(document).on('click', '.autocomplete__item', function() {
|
||
let currentAutocompleteItem=$(this);
|
||
let prefix = $(this).closest('.autocomplete').data('groupename');
|
||
$('.'+prefix+'_name').val(currentAutocompleteItem.text());
|
||
$('.'+prefix+'_adres').val(currentAutocompleteItem.attr('data-address'));
|
||
$('.'+prefix+'_inn').val(currentAutocompleteItem.attr('data-inn'));
|
||
currentAutocompleteItem.closest('.form-item').find('.form-item__dropdown').empty();
|
||
});
|
||
|
||
// Автоподстановка банков из API
|
||
let banksList = []; // Кэш списка банков
|
||
let banksLoading = false; // Флаг загрузки
|
||
|
||
// Загрузка списка банков через прокси на сервере (обход CORS)
|
||
function loadBanksList() {
|
||
if (banksLoading) return; // Предотвращаем множественные запросы
|
||
banksLoading = true;
|
||
|
||
$.ajax({
|
||
url: 'load_banks.php', // PHP скрипт на сервере для обхода CORS
|
||
method: 'GET',
|
||
dataType: 'json',
|
||
timeout: 15000, // 15 секунд таймаут
|
||
success: function(data) {
|
||
banksLoading = false;
|
||
if (Array.isArray(data)) {
|
||
banksList = data;
|
||
// Отладочный вывод отключен
|
||
// console.log('Загружено банков:', banksList.length);
|
||
// Убираем предупреждение об ошибке, если оно было
|
||
$('.js-bank-autocomplete').closest('.form-item').find('.form-item__warning').text('');
|
||
} else if (data && data.error) {
|
||
// Отладочный вывод отключен
|
||
// console.error('Ошибка от сервера:', data.error);
|
||
showBanksLoadError('Ошибка сервера: ' + data.error);
|
||
} else {
|
||
// Отладочный вывод отключен
|
||
// console.error('Неверный формат данных:', data);
|
||
showBanksLoadError('Неверный формат данных от сервера');
|
||
}
|
||
},
|
||
error: function(jqXHR, exception) {
|
||
banksLoading = false;
|
||
// Отладочный вывод отключен
|
||
// console.error('Ошибка загрузки списка банков:', exception, jqXHR);
|
||
var errorMsg = 'Не удалось загрузить список банков';
|
||
if (jqXHR.status === 0) {
|
||
errorMsg += ' (нет соединения)';
|
||
} else if (jqXHR.status === 404) {
|
||
errorMsg += ' (файл прокси не найден)';
|
||
} else if (jqXHR.status === 500) {
|
||
errorMsg += ' (ошибка сервера)';
|
||
} else if (exception === 'timeout') {
|
||
errorMsg += ' (превышено время ожидания)';
|
||
}
|
||
showBanksLoadError(errorMsg);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Показать ошибку загрузки банков
|
||
function showBanksLoadError(message) {
|
||
var bankInput = $('.js-bank-autocomplete');
|
||
if (bankInput.length) {
|
||
var warningText = message || 'Не удалось загрузить список банков. Пожалуйста, обновите страницу или введите название банка вручную.';
|
||
bankInput.closest('.form-item').find('.form-item__warning')
|
||
.text(warningText)
|
||
.css('color', '#dc3545');
|
||
}
|
||
}
|
||
|
||
// Загружаем банки при загрузке страницы
|
||
$(document).ready(function() {
|
||
// Небольшая задержка, чтобы убедиться, что DOM готов
|
||
setTimeout(function() {
|
||
loadBanksList();
|
||
}, 100);
|
||
});
|
||
|
||
// Популярные банки (показываются первыми)
|
||
var popularBanks = ['Сбербанк', 'ВТБ', 'Альфа-Банк', 'Тинькофф', 'Райффайзен Банк', 'Газпромбанк', 'Россельхозбанк', 'ПСБ', 'МКБ', 'ЮМани'];
|
||
|
||
// Функция для сортировки банков (популярные вверху)
|
||
function sortBanks(banks) {
|
||
return banks.sort(function(a, b) {
|
||
var aIndex = popularBanks.findIndex(function(name) {
|
||
return a.bankName.indexOf(name) !== -1;
|
||
});
|
||
var bIndex = popularBanks.findIndex(function(name) {
|
||
return b.bankName.indexOf(name) !== -1;
|
||
});
|
||
|
||
if (aIndex === -1 && bIndex === -1) return 0;
|
||
if (aIndex === -1) return 1;
|
||
if (bIndex === -1) return -1;
|
||
return aIndex - bIndex;
|
||
});
|
||
}
|
||
|
||
// Автоподстановка банков
|
||
$('.js-bank-autocomplete').on('input keyup', function(e) {
|
||
var sourceInput = $(this);
|
||
var query = $(this).val().toLowerCase().trim();
|
||
var formItem = sourceInput.closest('.form-item');
|
||
var dropdown = formItem.find('.form-item__dropdown');
|
||
|
||
// При ручном изменении поля убираем подпись «Банк выбран»
|
||
formItem.find('.form-item__warning').removeClass('form-item__warning--success').text('');
|
||
|
||
// Очищаем предыдущие результаты
|
||
dropdown.empty();
|
||
|
||
// Если запрос пустой, показываем больше банков (30) с популярными вверху
|
||
if (query.length === 0) {
|
||
var sortedBanks = sortBanks(banksList.slice());
|
||
showBanksDropdown(sortedBanks.slice(0, 30), dropdown, sourceInput, banksList.length, true);
|
||
return;
|
||
}
|
||
|
||
// Фильтруем банки по запросу
|
||
var filteredBanks = banksList.filter(function(bank) {
|
||
return bank.bankName.toLowerCase().indexOf(query) !== -1;
|
||
});
|
||
|
||
// Показываем результаты (максимум 50 при поиске)
|
||
showBanksDropdown(filteredBanks.slice(0, 50), dropdown, sourceInput, filteredBanks.length, false);
|
||
});
|
||
|
||
// Функция для отображения выпадающего списка банков
|
||
function showBanksDropdown(banks, dropdown, sourceInput, totalCount, showHint) {
|
||
dropdown.empty();
|
||
|
||
if (banks.length === 0) {
|
||
dropdown.append('<div class="autocomplete__item" style="padding: 10px; color: #999;">Банки не найдены</div>');
|
||
return;
|
||
}
|
||
|
||
banks.forEach(function(bank) {
|
||
var item = $('<div class="autocomplete__item" data-bank-id="' + bank.bankId + '" data-bank-name="' + bank.bankName + '" style="cursor: pointer;">' + bank.bankName + '</div>');
|
||
dropdown.append(item);
|
||
});
|
||
|
||
// Добавляем подсказку внизу списка
|
||
if (showHint && totalCount > banks.length) {
|
||
var hint = $('<div class="autocomplete__hint" style="padding: 12px 15px; background: #f8f9fa; border-top: 1px solid #e9ecef; font-size: 12px; color: #6c757d; text-align: center; border-radius: 0 0 4px 4px;">' +
|
||
'<strong>Показано ' + banks.length + ' из ' + totalCount + ' банков</strong><br>' +
|
||
'Начните вводить название банка для поиска по всем ' + totalCount + ' банкам'
|
||
+ '</div>');
|
||
dropdown.append(hint);
|
||
} else if (!showHint && totalCount > banks.length) {
|
||
var hint = $('<div class="autocomplete__hint" style="padding: 10px 15px; background: #f8f9fa; border-top: 1px solid #e9ecef; font-size: 12px; color: #6c757d; text-align: center;">' +
|
||
'Найдено: ' + totalCount + ' банков. Показано ' + banks.length + '. Уточните запрос для более точного поиска.'
|
||
+ '</div>');
|
||
dropdown.append(hint);
|
||
}
|
||
}
|
||
|
||
// Обработчик выбора банка - используем mousedown для надежности
|
||
$(document).on('mousedown', '.form-item__dropdown .autocomplete__item', function(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
var selectedItem = $(this);
|
||
var bankId = selectedItem.attr('data-bank-id');
|
||
var bankName = selectedItem.attr('data-bank-name');
|
||
var formItem = selectedItem.closest('.form-item');
|
||
|
||
// Проверяем, что это не подсказка
|
||
if (selectedItem.hasClass('autocomplete__hint')) {
|
||
return false;
|
||
}
|
||
|
||
// Заполняем поля
|
||
var bankInput = formItem.find('.js-bank-autocomplete');
|
||
var bankIdInput = formItem.find('input[name="bank_id"]');
|
||
|
||
bankInput.val(bankName);
|
||
bankIdInput.val(bankId);
|
||
|
||
// Очищаем выпадающий список
|
||
formItem.find('.form-item__dropdown').empty();
|
||
|
||
// Показываем подтверждение выбора банка
|
||
formItem.find('.form-item__warning').removeClass('form-item__warning--error').addClass('form-item__warning--success').text('Банк выбран');
|
||
|
||
// Убираем фокус с input
|
||
bankInput.blur();
|
||
|
||
// Отладочный вывод отключен
|
||
// console.log('Банк выбран:', bankName, 'ID:', bankId);
|
||
|
||
return false;
|
||
});
|
||
|
||
// Дублируем обработчик на click для совместимости
|
||
$(document).on('click', '.form-item__dropdown .autocomplete__item', function(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
var selectedItem = $(this);
|
||
|
||
// Проверяем, что это не подсказка
|
||
if (selectedItem.hasClass('autocomplete__hint')) {
|
||
return false;
|
||
}
|
||
|
||
// Если mousedown не сработал, обрабатываем здесь
|
||
var bankId = selectedItem.attr('data-bank-id');
|
||
var bankName = selectedItem.attr('data-bank-name');
|
||
var formItem = selectedItem.closest('.form-item');
|
||
|
||
if (bankId && bankName) {
|
||
formItem.find('.js-bank-autocomplete').val(bankName);
|
||
formItem.find('input[name="bank_id"]').val(bankId);
|
||
formItem.find('.form-item__dropdown').empty();
|
||
formItem.find('.form-item__warning').removeClass('form-item__warning--error').addClass('form-item__warning--success').text('Банк выбран');
|
||
}
|
||
|
||
return false;
|
||
});
|
||
|
||
// При фокусе показываем список банков
|
||
$('.js-bank-autocomplete').on('focus', function() {
|
||
var sourceInput = $(this);
|
||
var dropdown = sourceInput.closest('.form-item').find('.form-item__dropdown');
|
||
var query = $(this).val().toLowerCase().trim();
|
||
|
||
if (banksList.length === 0) {
|
||
// Если банки еще не загружены, пробуем загрузить
|
||
loadBanksList();
|
||
return;
|
||
}
|
||
|
||
if (query.length === 0) {
|
||
var sortedBanks = sortBanks(banksList.slice());
|
||
showBanksDropdown(sortedBanks.slice(0, 30), dropdown, sourceInput, banksList.length, true);
|
||
} else {
|
||
// Триггерим событие input для фильтрации
|
||
$(this).trigger('input');
|
||
}
|
||
});
|
||
|
||
// Скрываем выпадающий список при потере фокуса (с задержкой для клика)
|
||
$('.js-bank-autocomplete').on('blur', function(e) {
|
||
var sourceInput = $(this);
|
||
var dropdown = sourceInput.closest('.form-item').find('.form-item__dropdown');
|
||
|
||
// Увеличиваем задержку, чтобы клик успел обработаться
|
||
setTimeout(function() {
|
||
// Проверяем, не кликнули ли мы на элемент списка или внутри dropdown
|
||
var activeElement = document.activeElement;
|
||
var relatedTarget = e.relatedTarget;
|
||
|
||
// Если фокус перешел на элемент из dropdown, не скрываем
|
||
if (relatedTarget && $(relatedTarget).closest('.form-item__dropdown').length) {
|
||
return;
|
||
}
|
||
|
||
if (!$(activeElement).hasClass('autocomplete__item') &&
|
||
!$(activeElement).closest('.form-item__dropdown').length) {
|
||
dropdown.empty();
|
||
}
|
||
}, 200);
|
||
});
|
||
|
||
// Предотвращаем blur при клике на dropdown
|
||
$(document).on('mousedown', '.form-item__dropdown', function(e) {
|
||
// Останавливаем всплытие, чтобы blur не сработал на input
|
||
e.stopPropagation();
|
||
});
|
||
|
||
|
||
// Инициализация автодополнения адресов при загрузке страницы
|
||
setTimeout(function() {
|
||
initAddressSuggestions();
|
||
}, 1000);
|
||
|
||
// $('input[name=db_birthday],input[name=db_inn]').keyup(function(e){
|
||
|
||
$(document).on('click', '.js-check-in', function(e) {
|
||
|
||
e.preventDefault();
|
||
let birthday=$('input[name=birthday]').val();
|
||
let police_number=$('input[name=police_number]').val();
|
||
|
||
if(police_number.slice(0,1)=="Е"){
|
||
police_number=police_number.replace(/Е/g, 'E');
|
||
}
|
||
|
||
if(police_number.slice(0,1)=="А"){
|
||
police_number=police_number.replace(/А/g, 'A');
|
||
}
|
||
|
||
let dbdata={
|
||
"action" : "user_verify",
|
||
'birthday' : birthday.replace(/-/g, '.'),
|
||
'inn' : police_number
|
||
}
|
||
|
||
// Показываем загрузку
|
||
$('.js-check-in').prop('disabled', true).text('Проверка...');
|
||
$('.js-result').html('').removeClass('danger form-item__warning--success');
|
||
|
||
$.ajax({
|
||
url: 'database.php',
|
||
method: 'post',
|
||
data: dbdata,
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
$('.js-check-in').prop('disabled', false).text('Проверить наличие полиса');
|
||
|
||
// Если data уже объект, не парсим
|
||
let res = typeof data === 'string' ? JSON.parse(data) : data;
|
||
if(res.success=="true"){
|
||
// Полис валидный - показываем успешное сообщение
|
||
$('.js-result').html(res.message);
|
||
$('.js-result').removeClass("danger");
|
||
$('.js-result').addClass("form-item__warning--success");
|
||
|
||
$('input[name=insured_from]').val(res.result.insured_from.replace(/\./g, '-'));
|
||
$('input[name=insured_to]').val(res.result.insured_to.replace(/\./g, '-'));
|
||
|
||
|
||
$('.js-indatabase').val('1');
|
||
$('.policy-upload-section').addClass('d-none');
|
||
|
||
// Показываем поля телефона и банка после успешной проверки полиса
|
||
$('.policy-validated-fields').removeClass('d-none');
|
||
// Скрываем кнопку «Проверить наличие полиса» — полис уже проверен
|
||
$('.js-check-in').closest('.form-item').addClass('d-none');
|
||
|
||
// Разблокируем кнопку \"Отправить смс\" если полис валидный (с учётом валидности номера и cooldown)
|
||
if (typeof window.updateSmsButtonState === 'function') window.updateSmsButtonState();
|
||
$('.form__warning').hide();
|
||
|
||
// Если SMS уже подтверждено, сразу показываем форму для заполнения
|
||
if($('.sms-success').is(':visible') || !$('.sms-success').hasClass('d-none')) {
|
||
$('.db-success').removeClass('d-none');
|
||
$('.form-step[data-step=1]').removeClass('disabled');
|
||
}
|
||
// Инициализируем автодополнение адресов после проверки полиса
|
||
setTimeout(function() {
|
||
initAddressSuggestions();
|
||
}, 500);
|
||
|
||
} else {
|
||
// Полис не найден - показываем ТОЛЬКО поле для загрузки скана полиса
|
||
$('.js-indatabase').val('0');
|
||
|
||
// Убираем сообщение об ошибке из .js-result
|
||
$('.js-result').html('');
|
||
$('.js-result').removeClass("danger form-item__warning--success");
|
||
|
||
// НЕ показываем форму (.sms-success), только блок загрузки полиса
|
||
$('.sms-success').addClass('d-none');
|
||
$('.db-success').addClass('d-none');
|
||
|
||
// Показываем ТОЛЬКО блок для загрузки полиса
|
||
$('.policy-upload-section').removeClass('d-none');
|
||
$('.policy-upload-section').find('input[type=file]').removeClass("notvalidate");
|
||
$('.policy-upload-section').find('input[type=file]').removeClass("disabled");
|
||
|
||
// Показываем уведомление о необходимости загрузить полис
|
||
$('.policy-upload-section').find('.form-item__warning')
|
||
.text('Загрузите скан полиса для продолжения')
|
||
.css('color', '#856404')
|
||
.show();
|
||
|
||
// Скрываем поля телефона и банка
|
||
$('.policy-validated-fields').addClass('d-none');
|
||
// Показываем кнопку «Проверить наличие полиса» снова (полис не найден)
|
||
$('.js-check-in').closest('.form-item').removeClass('d-none');
|
||
|
||
// Блокируем кнопку "Отправить смс"
|
||
$('.js-send-sms').addClass('disabled');
|
||
$('.js-send-sms').prop('disabled', true);
|
||
$('.form__warning').hide();
|
||
|
||
|
||
}
|
||
return false;
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
$('.js-check-in').prop('disabled', false).text('Проверить наличие полиса');
|
||
|
||
var errorMsg = 'Ошибка при проверке полиса';
|
||
if (jqXHR.responseText) {
|
||
try {
|
||
var errorData = JSON.parse(jqXHR.responseText);
|
||
if (errorData.message) {
|
||
errorMsg = errorData.message;
|
||
}
|
||
} catch(e) {
|
||
errorMsg = jqXHR.responseText.substring(0, 100);
|
||
}
|
||
}
|
||
|
||
$('.js-result').html(errorMsg)
|
||
.removeClass('form-item__warning--success')
|
||
.addClass('danger');
|
||
|
||
console.error('Ошибка проверки полиса:', jqXHR, exception);
|
||
return false;
|
||
}
|
||
});
|
||
|
||
});
|
||
|
||
|
||
$('input[name=birthday]').on("change input", function (e) {
|
||
// Отладочный вывод отключен
|
||
// console.log("Date changed: ", e.target.value);
|
||
|
||
let birthday=$(this).val();
|
||
|
||
|
||
if(getAge(birthday)<18) {
|
||
// Если возраст меньше 18 - разблокируем поле
|
||
$("input[data-enableby=birthday]").removeClass('disabled');
|
||
$("input[data-disabledby=birthday]").removeClass('disabled');
|
||
$("input[data-enableby=birthday]").prop('disabled', false);
|
||
$("input[data-enableby=birthday]").prop('readonly', false);
|
||
} else {
|
||
// Если возраст 18 и больше - блокируем поле
|
||
$("input[data-enableby=birthday]").addClass('disabled');
|
||
$("input[data-disabledby=birthday]").addClass('disabled');
|
||
$("input[data-enableby=birthday]").prop('disabled', true);
|
||
$("input[data-enableby=birthday]").prop('readonly', true);
|
||
$("input[data-enableby=birthday]").val(''); // Очищаем значение при блокировке
|
||
}
|
||
|
||
});
|
||
|
||
|
||
|
||
$('input[name=lastname],input[name=firstname],input[name=patronymic]').keyup(function(e){
|
||
let full_name=$('input[name=lastname]').val()+" "+$('input[name=firstname]').val()+" "+$('input[name=patronymic]').val();
|
||
$("input[data-enableby=birthday]").val(full_name);
|
||
});
|
||
|
||
// C3: счётчик и ограничение описания (50–2000)
|
||
$('textarea[name=description]').on('input', function() {
|
||
var len = (this.value || '').length;
|
||
$(this).closest('.form-item').find('.js-description-counter').text(len + ' / 2000');
|
||
}).trigger('input');
|
||
|
||
// C4: серия и номер документа — макс. 20 символов, только буквы/цифры/пробелы
|
||
$('.js-doc-number').on('input', function() {
|
||
var val = this.value.replace(/[^\d A-Za-zА-Яа-яЁё]/g, '').slice(0, 20);
|
||
if (val !== this.value) this.value = val;
|
||
});
|
||
|
||
|
||
// Загрузка файлов
|
||
|
||
function declOfNum(number, words) {
|
||
return words[(number % 100 > 4 && number % 100 < 20) ? 2 : [2, 0, 1, 1, 1, 2][(number % 10 < 5) ? Math.abs(number) % 10 : 5]];
|
||
}
|
||
|
||
function updateSize(elem) {
|
||
var filesQty = elem[0].files.length;
|
||
if(filesQty>10) {
|
||
elem.closest('.form-item').find('.form-item__warning').text("Разрешено не более 10 файлов");
|
||
return;
|
||
}
|
||
|
||
elem.closest('.form-item').find('.form-item__warning').text('');
|
||
let file_status=[];
|
||
var formats = ['pdf','jpg','png','jpeg'];
|
||
for(var i=0; i<filesQty; i++) {
|
||
|
||
|
||
var file = elem[0].files[i],
|
||
ext = "не определилось",
|
||
parts = file.name.split('.');
|
||
|
||
if (parts.length > 1) ext = parts.pop();
|
||
if(!formats.includes((ext || '').toLowerCase())) {
|
||
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Допустимые форматы: pdf, jpg, png </div>');
|
||
elem.addClass('error');
|
||
file_status.push(false);
|
||
} else {
|
||
// elem.closest('.form-item').find('.form-item__warning').text();
|
||
if((file.size/1024/1024) > 20){
|
||
file_status.push(false);
|
||
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 20 Мб. </div>');
|
||
} else {
|
||
elem.removeClass('error');
|
||
file_status.push(true);
|
||
|
||
|
||
|
||
}
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
// ОТКЛЮЧЕНО: старая система загрузки файлов через fileupload_v2.php
|
||
// Файлы теперь отправляются напрямую в submit.php как бинарные данные
|
||
if(file_status.every(val => val === true))
|
||
{
|
||
// upload_file(elem); // ОТКЛЮЧЕНО - файлы отправляются напрямую при submit формы
|
||
$('.form__action').find('.js-btn-next').removeClass('disabled');
|
||
} else {
|
||
$('.form__action').find('.js-btn-next').addClass('disabled');
|
||
}
|
||
}
|
||
|
||
function upload_file(thisfile) {
|
||
|
||
let formData = new FormData();
|
||
|
||
let field_name=thisfile.data('crmname') || thisfile.data('field-type');
|
||
let docname=thisfile.data('docname');
|
||
|
||
// Отладочный вывод отключен
|
||
// console.log('=== UPLOAD_FILE FUNCTION ===');
|
||
// console.log('Uploading for field:', field_name, 'docname:', docname);
|
||
// console.log('File input element:', thisfile[0]);
|
||
// console.log('Files in input:', thisfile[0].files);
|
||
// console.log('Field type:', thisfile.data('field-type'));
|
||
// console.log('Form item:', thisfile.closest('.form-item')[0]);
|
||
let sub_dir=jQuery('input[name=sub_dir]').val();
|
||
|
||
jQuery.each(thisfile[0].files, function(i, file) {
|
||
formData.append(field_name+'-'+i, file);
|
||
});
|
||
thisfile.closest('.form-item').find('.suсcess-upload').remove();
|
||
|
||
|
||
formData.append('lastname',jQuery('input[name=lastname]').val());
|
||
formData.append('files_names[]',field_name);
|
||
formData.append('docs_names[]',docname);
|
||
|
||
|
||
formData.append('sub_dir',sub_dir);
|
||
|
||
thisfile.closest('.form-item').append("<p class='info-upload'></p>");
|
||
|
||
|
||
// for (var pair of formData.entries()) {
|
||
// console.log(pair[0]+ ', ' + pair[1]);
|
||
// }
|
||
$.ajax({
|
||
xhr: function() {
|
||
var xhr = new window.XMLHttpRequest();
|
||
// Upload progress
|
||
xhr.upload.addEventListener("progress", function(evt){
|
||
if (evt.lengthComputable) {
|
||
var percentComplete = evt.loaded / evt.total;
|
||
//Do something with upload progress
|
||
|
||
let complete=Math.round(percentComplete * 100);
|
||
// Отладочный вывод отключен
|
||
// console.log(complete);
|
||
thisfile.closest('.form-item').find(".info-upload").text("Загружено "+complete+" %");
|
||
|
||
}
|
||
}, false);
|
||
// Download progress
|
||
xhr.addEventListener("progress", function(evt){
|
||
if (evt.lengthComputable) {
|
||
var percentComplete = evt.loaded / evt.total;
|
||
// Do something with download progress
|
||
// Отладочный вывод отключен
|
||
// console.log(percentComplete);
|
||
}
|
||
}, false);
|
||
return xhr;
|
||
},
|
||
url: 'https://form.clientright.ru/fileupload_v2.php',
|
||
method: 'post',
|
||
cache: false,
|
||
contentType: false,
|
||
processData: false,
|
||
data: formData,
|
||
// dataType : 'json',
|
||
beforeSend : function (){
|
||
$('.form__action').find('.js-btn-next').addClass('disabled');
|
||
$('.form__action').find('.btn--submit').addClass('disabled');
|
||
},
|
||
success: function(data) {
|
||
|
||
let res=JSON.parse(data);
|
||
if(res.success=="true"){
|
||
// Отладочный вывод отключен
|
||
// console.log(res);
|
||
// thisfile.closest('.form-item').append("<p class='suсcess-upload'>Файл успешно загружен на сервер.</p>");
|
||
thisfile.attr('data-uploadurl',res.empty_file);
|
||
thisfile.attr('data-uploadurl_real',res.real_file);
|
||
// thisfile.closest('.form-item').append("<p class='suсcess-upload'>"+res.message+"</p>");
|
||
thisfile.closest('.form-item').find('.info-upload').remove();
|
||
|
||
|
||
$('.form__action').find('.js-btn-next').removeClass('disabled');
|
||
$('.form__action').find('.btn--submit').removeClass('disabled');
|
||
|
||
|
||
} else {
|
||
}
|
||
return false;
|
||
},
|
||
error: function (jqXHR, exception) {
|
||
return false;
|
||
}
|
||
});
|
||
|
||
}
|
||
|
||
function formatBytes(bytes, decimals = 2) {
|
||
if (!+bytes) return '0 Bytes'
|
||
const k = 1024
|
||
const dm = decimals < 0 ? 0 : decimals
|
||
const sizes = ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`
|
||
}
|
||
|
||
var fileIdCounter = 0;
|
||
|
||
jQuery('.js-attach').each(function() {
|
||
var fieldType = $(this).data('field-type'); // Получаем тип поля
|
||
let filethis = $(this);
|
||
|
||
// Создаем изолированное хранилище файлов для каждого поля
|
||
var fieldFiles = {
|
||
filesToUpload: [],
|
||
fieldType: fieldType
|
||
};
|
||
|
||
filethis.change(function (evt) {
|
||
var output = [];
|
||
let elem= $(this);
|
||
let currentFieldFiles = fieldFiles; // Используем изолированное хранилище
|
||
let currentFormItem = elem.closest('.form-item');
|
||
|
||
// Очищаем предупреждения только для текущего поля
|
||
currentFormItem.find('.form-item__warning').text('');
|
||
let file_status=[];
|
||
var formats = ['pdf','jpg','png','jpeg'];
|
||
|
||
// Отладочный вывод отключен
|
||
// console.log('=== FILE UPLOAD START ===');
|
||
// console.log('Processing files for field type:', currentFieldFiles.fieldType);
|
||
// console.log('Field element:', elem[0]);
|
||
// console.log('Form item:', currentFormItem[0]);
|
||
// console.log('Files to process:', evt.target.files);
|
||
// console.log('Current fieldFiles state:', currentFieldFiles);
|
||
|
||
if(evt.target.files.length>10) {
|
||
elem.closest('.form-item').find('.form-item__warning').text("Разрешено не более 10 файлов");
|
||
return;
|
||
}
|
||
|
||
// Очищаем предыдущий список файлов для этого поля
|
||
currentFormItem.find('.fileList').empty();
|
||
currentFieldFiles.filesToUpload = [];
|
||
|
||
for (var i = 0; i < evt.target.files.length; i++) {
|
||
fileIdCounter++;
|
||
var file = evt.target.files[i];
|
||
var fileId = "fileid_" + fileIdCounter;
|
||
|
||
// Отладочный вывод отключен
|
||
// console.log(file);
|
||
|
||
let ext = "не определилось";
|
||
let parts = file.name.split('.');
|
||
|
||
if (parts.length > 1) ext = parts.pop();
|
||
if(!formats.includes((ext || '').toLowerCase())) {
|
||
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Допустимые форматы: pdf, jpg, png </div>');
|
||
elem.addClass('error');
|
||
file_status.push(false);
|
||
} else {
|
||
if((file.size/1024/1024) > 20){
|
||
file_status.push(false);
|
||
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 20 Мб. </div>');
|
||
} else {
|
||
elem.removeClass('error');
|
||
file_status.push(true);
|
||
|
||
|
||
var removeLink = "<a class=\"removefile\" href=\"#\" data-fileid=\"" + fileId + "\"></a>";
|
||
output.push("<li><strong>", file.name, "</strong> <span class='size'> ", formatBytes(file.size) , " </span> ", removeLink, "</li> ");
|
||
|
||
currentFieldFiles.filesToUpload.push({
|
||
id: fileId,
|
||
file: file
|
||
});
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|
||
|
||
//evt.target.value = null;
|
||
|
||
|
||
|
||
// elem.closest('.form-item').find('.upload-action').removeClass('d-none');
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
};
|
||
|
||
currentFormItem.find(".fileList").append(output.join(""));
|
||
|
||
let container = new DataTransfer();
|
||
for (var i = 0, len = currentFieldFiles.filesToUpload.length; i < len; i++) {
|
||
container.items.add(currentFieldFiles.filesToUpload[i].file);
|
||
}
|
||
|
||
elem[0].files = container.files;
|
||
|
||
if(file_status.every(val => val === true))
|
||
{
|
||
// Отладочный вывод отключен
|
||
// console.log('=== FILE UPLOAD SUCCESS ===');
|
||
// console.log('Uploading files for field type:', currentFieldFiles.fieldType);
|
||
// console.log('Final fieldFiles state:', currentFieldFiles);
|
||
// console.log('Files in DataTransfer:', elem[0].files);
|
||
// upload_file(elem); // ОТКЛЮЧЕНО - файлы отправляются напрямую при submit формы
|
||
$('.form__action').find('.js-btn-next').removeClass('disabled');
|
||
|
||
// Если загружен полис из блока policy-upload-section, показываем телефон и банк
|
||
if(currentFieldFiles.fieldType === 'polis' && elem.closest('.policy-upload-section').length > 0) {
|
||
// Полис остаётся виден в блоке загрузки (список файлов остаётся на экране),
|
||
// дополнительно показываем поля телефона и банка
|
||
$('.policy-validated-fields').removeClass('d-none');
|
||
// Разблокируем кнопку "Отправить смс" (с учётом дальнейшей валидации номера)
|
||
if (typeof window.updateSmsButtonState === 'function') window.updateSmsButtonState();
|
||
// Убираем уведомление
|
||
$('.policy-upload-section').find('.form-item__warning').text('').hide();
|
||
}
|
||
} else {
|
||
// Отладочный вывод отключен
|
||
// console.log('=== FILE UPLOAD FAILED ===');
|
||
// console.log('File status:', file_status);
|
||
$('.form__action').find('.js-btn-next').addClass('disabled');
|
||
}
|
||
});
|
||
|
||
// Обработчик удаления файлов с доступом к fieldFiles через замыкание
|
||
$(this).closest('.form-item').on("click", ".removefile", function (e) {
|
||
let elem = $(this);
|
||
e.preventDefault();
|
||
var fileId = elem.data("fileid");
|
||
|
||
// Находим соответствующий input файла для этого .form-item
|
||
let fileInput = elem.closest('.form-item').find('input[type="file"].js-attach');
|
||
let fieldType = fileInput.data('field-type');
|
||
|
||
// Отладочный вывод отключен
|
||
// console.log('=== REMOVE FILE ===');
|
||
// console.log('Removing file with ID:', fileId);
|
||
// console.log('From field type:', fieldType);
|
||
// console.log('Current fieldFiles:', fieldFiles);
|
||
|
||
// Используем fieldFiles из замыкания
|
||
for (var i = 0; i < fieldFiles.filesToUpload.length; ++i) {
|
||
if (fieldFiles.filesToUpload[i].id === fileId) {
|
||
fieldFiles.filesToUpload.splice(i, 1);
|
||
// Отладочный вывод отключен
|
||
// console.log('File removed from fieldFiles');
|
||
break;
|
||
}
|
||
}
|
||
|
||
elem.parent().remove();
|
||
|
||
if(fieldFiles.filesToUpload.length == 0) {
|
||
elem.closest('.form-item').find('.upload-action').addClass('d-none');
|
||
elem.closest('.form-item').find('.suсcess-upload').text('');
|
||
} else {
|
||
let container = new DataTransfer();
|
||
for (var i = 0, len = fieldFiles.filesToUpload.length; i < len; i++) {
|
||
container.items.add(fieldFiles.filesToUpload[i].file);
|
||
}
|
||
fileInput[0].files = container.files;
|
||
updateSize(fileInput);
|
||
}
|
||
});
|
||
|
||
|
||
|
||
});
|
||
|
||
// End Загрузка файлов
|
||
|
||
});
|