Initial
This commit is contained in:
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Секреты и конфиги с ключами
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Логи
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Кэш и временные файлы
|
||||||
|
cache/
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Системные
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Зависимости (если появятся)
|
||||||
|
node_modules/
|
||||||
|
vendor/
|
||||||
21
.htaccess
Normal file
21
.htaccess
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header set Access-Control-Allow-Origin "*"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{HTTPS} off
|
||||||
|
RewriteCond %{HTTP:X-Forwarded-Proto} !https
|
||||||
|
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||||
|
Options -Indexes
|
||||||
|
php_value error_reporting "E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT"
|
||||||
|
php_flag short_open_tag off
|
||||||
|
php_flag display_errors on
|
||||||
|
php_flag log_errors on
|
||||||
|
php_value max_execution_time 0
|
||||||
|
php_value max_input_time 6000
|
||||||
|
php_value max_input_vars 150000
|
||||||
|
php_value max_file_uploads 100
|
||||||
|
php_value upload_max_filesize 400M
|
||||||
|
php_value post_max_size 410M
|
||||||
|
php_value default_socket_timeout 600
|
||||||
|
php_value memory_limit -1
|
||||||
486
API_REFERENCE.md
Normal file
486
API_REFERENCE.md
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
# Справочник API
|
||||||
|
|
||||||
|
## CRM WebService API
|
||||||
|
|
||||||
|
### Базовый URL
|
||||||
|
```
|
||||||
|
https://crm.clientright.ru/webservice.php
|
||||||
|
```
|
||||||
|
|
||||||
|
### Авторизация
|
||||||
|
|
||||||
|
#### 1. Получение токена (getchallenge)
|
||||||
|
```php
|
||||||
|
GET ?operation=getchallenge&username=api
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"token": "временный_токен"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Получение sessionId (login)
|
||||||
|
```php
|
||||||
|
POST
|
||||||
|
operation=login
|
||||||
|
username=api
|
||||||
|
accessKey=md5(challengeToken + userAccessKey)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Где:**
|
||||||
|
- `userAccessKey = '4r9ANex8PT2IuRV'`
|
||||||
|
- `accessKey = md5(challengeToken + userAccessKey)`
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"sessionName": "session_id_для_дальнейших_запросов"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Операции с клиентами
|
||||||
|
|
||||||
|
#### CreateContact - Создание/обновление клиента
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```php
|
||||||
|
operation = CreateContact
|
||||||
|
sessionName = полученный_sessionId
|
||||||
|
firstname = Имя (обязательно)
|
||||||
|
lastname = Фамилия (обязательно)
|
||||||
|
secondname = Отчество
|
||||||
|
mobile = Телефон (обязательно)
|
||||||
|
email = Email
|
||||||
|
tgid = Telegram ID (число)
|
||||||
|
birthday = Дата рождения в формате ГГГГ-ММ-ДД (обязательно)
|
||||||
|
birthplace = Место рождения
|
||||||
|
mailingstreet = Адрес проживания
|
||||||
|
inn = ИНН (обязательно)
|
||||||
|
requisites = Реквизиты для перечисления средств
|
||||||
|
code = СМС код
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример запроса:**
|
||||||
|
```php
|
||||||
|
$params = array(
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'firstname' => 'Василий',
|
||||||
|
'lastname' => 'Пупкинидзе',
|
||||||
|
'secondname' => 'Алибабаевич',
|
||||||
|
'mobile' => '+7(949) 123-45-11',
|
||||||
|
'email' => 'rrrr@mail.ru',
|
||||||
|
'birthday' => '1986-11-15',
|
||||||
|
'mailingstreet' => 'г. Калининград',
|
||||||
|
'inn' => '321654987654',
|
||||||
|
'code' => '4568'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": "83859"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Где `result` - это ID созданного или обновленного клиента.
|
||||||
|
|
||||||
|
### Операции с контрагентами
|
||||||
|
|
||||||
|
#### CreateAccount - Создание/обновление контрагента
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```php
|
||||||
|
operation = CreateAccount
|
||||||
|
sessionName = полученный_sessionId
|
||||||
|
accountname = Наименование юрлица (обязательно)
|
||||||
|
address = Юридический адрес
|
||||||
|
email = Email
|
||||||
|
website = Сайт
|
||||||
|
phone = Телефон
|
||||||
|
inn = ИНН (обязательно)
|
||||||
|
ogrn = ОГРН (обязательно)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример запроса:**
|
||||||
|
```php
|
||||||
|
$params = array(
|
||||||
|
'operation' => 'CreateAccount',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'accountname' => 'ООО "Три бобра"',
|
||||||
|
'address' => 'г. Москва, Кремль',
|
||||||
|
'email' => 'qqqqq@ya.ru',
|
||||||
|
'website' => 'https://pikabu.ru',
|
||||||
|
'phone' => '+7 928 664-66-11',
|
||||||
|
'inn' => '1234567899',
|
||||||
|
'ogrn' => '32165498711'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": "83837"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Где `result` - это ID созданного или обновленного контрагента.
|
||||||
|
|
||||||
|
### Операции с проектами
|
||||||
|
|
||||||
|
#### CreateProject - Создание проекта
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```php
|
||||||
|
operation = CreateProject
|
||||||
|
sessionName = полученный_sessionId
|
||||||
|
contactid = ID клиента (обязательно)
|
||||||
|
offenderid = ID контрагента-обидчика (обязательно)
|
||||||
|
agentid = ID контрагента-посредника (опционально)
|
||||||
|
sms = Код из СМС
|
||||||
|
ip = IP пользователя
|
||||||
|
source = Откуда пришли
|
||||||
|
region = Регион пользователя
|
||||||
|
formid = ID формы
|
||||||
|
category = Категория обращения
|
||||||
|
direction = Направление обращения
|
||||||
|
agrprice = Цена договора (число)
|
||||||
|
subject = Предмет договора
|
||||||
|
agrdate = Дата заключения договора (ГГГГ-ММ-ДД)
|
||||||
|
startdate = Срок начальный (ГГГГ-ММ-ДД)
|
||||||
|
finishdate = Срок конечный (ГГГГ-ММ-ДД)
|
||||||
|
loss = Убыток (число)
|
||||||
|
servicecost = Стоимость услуги (число)
|
||||||
|
progress = Прогресс в % (число)
|
||||||
|
country = Страна путешествия
|
||||||
|
hotel = Средство размещения
|
||||||
|
transport = Транспортные услуги ("да" или "нет")
|
||||||
|
insurance = Страховка ("да" или "нет")
|
||||||
|
other = Прочее
|
||||||
|
description = Описание
|
||||||
|
independently = Самостоятельно соблюден претензионный порядок ("да" или "нет")
|
||||||
|
claimdate = Дата направления претензии (ГГГГ-ММ-ДД)
|
||||||
|
returned = Вернули в претензионном порядке (число)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример запроса:**
|
||||||
|
```php
|
||||||
|
$params = array(
|
||||||
|
'operation' => 'CreateProject',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'contactid' => 83834,
|
||||||
|
'offenderid' => 84675,
|
||||||
|
'sms' => '1234',
|
||||||
|
'ip' => '192.168.0.1',
|
||||||
|
'source' => 'с улицы',
|
||||||
|
'region' => 'Владивосток',
|
||||||
|
'formid' => 1376,
|
||||||
|
'category' => 'Абидили!!',
|
||||||
|
'direction' => 'Путину',
|
||||||
|
'description' => 'какое-то описание'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": "83839"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Где `result` - это ID созданного проекта.
|
||||||
|
|
||||||
|
### Получение списка файлов
|
||||||
|
|
||||||
|
#### GetFilesList - Получение списка файлов клиента
|
||||||
|
|
||||||
|
**Параметры:**
|
||||||
|
```php
|
||||||
|
operation = GetFilesList
|
||||||
|
sessionName = полученный_sessionId
|
||||||
|
inn = ИНН клиента (обязательно)
|
||||||
|
sms = СМС-код (обязательно)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Пример запроса:**
|
||||||
|
```php
|
||||||
|
$params = array(
|
||||||
|
'operation' => 'GetFilesList',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'inn' => '643922466250',
|
||||||
|
'sms' => '795372'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ при успехе:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"status": "ok",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"title": "договор",
|
||||||
|
"path": "storage/2023/December/week4/9e84c3f86209302799f46d0136e93ab6.pdf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "подтверждение оплаты",
|
||||||
|
"path": "storage/2023/December/week4/cf65c58a01e7db0b19c8e1fe119c0e32.pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ при ошибке:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"result": {
|
||||||
|
"status": "failed",
|
||||||
|
"message": "Клиент с указанным СМС-кодом и ИНН не найден"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## WebForms Capture API
|
||||||
|
|
||||||
|
### Базовый URL
|
||||||
|
```
|
||||||
|
https://crm.clientright.ru/modules/Webforms/capture.php
|
||||||
|
```
|
||||||
|
|
||||||
|
### Параметры формы
|
||||||
|
|
||||||
|
**Обязательные системные параметры:**
|
||||||
|
```php
|
||||||
|
__vtrftk = 'sid:ec649134ad232e44c3ad71bbd321cee986f05545,1688385374'
|
||||||
|
publicid = '3ddc71c2d79ef101c09b0d4e9c6bd08b'
|
||||||
|
urlencodeenable = '1'
|
||||||
|
name = 'websiteticket'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Кастомные поля:**
|
||||||
|
Все поля с атрибутом `data-crmname` отправляются как отдельные параметры.
|
||||||
|
|
||||||
|
## File Upload API
|
||||||
|
|
||||||
|
### Базовый URL
|
||||||
|
```
|
||||||
|
https://form.clientright.ru/fileupload_v2.php
|
||||||
|
```
|
||||||
|
|
||||||
|
### Параметры
|
||||||
|
```php
|
||||||
|
POST multipart/form-data
|
||||||
|
lastname = Фамилия клиента
|
||||||
|
sub_dir = ID сессии
|
||||||
|
files_names[] = Массив имен полей для файлов
|
||||||
|
docs_names[] = Массив названий документов
|
||||||
|
field_name-0 = Файл 1
|
||||||
|
field_name-1 = Файл 2
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ответ:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": "true",
|
||||||
|
"empty_file": "путь_к_пустышке",
|
||||||
|
"real_file": "путь_к_реальному_файлу",
|
||||||
|
"message": "Файл успешно загружен"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DaData API
|
||||||
|
|
||||||
|
### Базовый URL
|
||||||
|
```
|
||||||
|
https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/party
|
||||||
|
```
|
||||||
|
|
||||||
|
### Авторизация
|
||||||
|
```
|
||||||
|
Authorization: Token f5d6928d7490cd44124ccae11a08c7fa5625d48c
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Запрос
|
||||||
|
```json
|
||||||
|
POST
|
||||||
|
{
|
||||||
|
"query": "название организации или ИНН"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ответ
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"suggestions": [
|
||||||
|
{
|
||||||
|
"value": "ООО Рога и Копыта",
|
||||||
|
"data": {
|
||||||
|
"inn": "1234567890",
|
||||||
|
"address": {
|
||||||
|
"value": "г. Москва, ул. Ленина, д. 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## IP Geolocation API
|
||||||
|
|
||||||
|
### Базовый URL
|
||||||
|
```
|
||||||
|
http://ip-api.com/json/{IP}?lang=ru
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пример запроса
|
||||||
|
```
|
||||||
|
GET http://ip-api.com/json/192.168.1.1?lang=ru
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ответ
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"country": "Россия",
|
||||||
|
"regionName": "Москва",
|
||||||
|
"city": "Москва",
|
||||||
|
"lat": 55.7558,
|
||||||
|
"lon": 37.6173
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Обработка ошибок
|
||||||
|
|
||||||
|
### Стандартный формат ошибки
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": false,
|
||||||
|
"error": {
|
||||||
|
"code": "ERROR_CODE",
|
||||||
|
"message": "Описание ошибки"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP коды статуса
|
||||||
|
- `200` - Успешный запрос
|
||||||
|
- `400` - Неверные параметры
|
||||||
|
- `401` - Ошибка авторизации
|
||||||
|
- `404` - Ресурс не найден
|
||||||
|
- `500` - Внутренняя ошибка сервера
|
||||||
|
|
||||||
|
### Важные замечания
|
||||||
|
|
||||||
|
1. **SessionId** имеет ограниченное время жизни (15 минут)
|
||||||
|
2. **Поле success** в ответе означает только техническую успешность запроса
|
||||||
|
3. Для проверки бизнес-логики используйте поле **status** внутри **result**
|
||||||
|
4. Все даты должны быть в формате **ГГГГ-ММ-ДД**
|
||||||
|
5. При работе с файлами используйте **multipart/form-data**
|
||||||
|
|
||||||
|
## Примеры использования
|
||||||
|
|
||||||
|
### Полный цикл создания обращения
|
||||||
|
|
||||||
|
```php
|
||||||
|
// 1. Получение токена
|
||||||
|
$ch = curl_init();
|
||||||
|
$url = "https://crm.clientright.ru/webservice.php?operation=getchallenge&username=api";
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$jsonResponse = json_decode($response, true);
|
||||||
|
$challengeToken = $jsonResponse['result']['token'];
|
||||||
|
|
||||||
|
// 2. Получение sessionId
|
||||||
|
$userAccessKey = '4r9ANex8PT2IuRV';
|
||||||
|
$generatedKey = md5($challengeToken . $userAccessKey);
|
||||||
|
curl_setopt_array($ch, array(
|
||||||
|
CURLOPT_RETURNTRANSFER => 1,
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_POST => 1,
|
||||||
|
CURLOPT_POSTFIELDS => array(
|
||||||
|
'operation' => 'login',
|
||||||
|
'username' => 'api',
|
||||||
|
'accessKey' => $generatedKey
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$jsonResponse = json_decode($response, true);
|
||||||
|
$sessionId = $jsonResponse['result']['sessionName'];
|
||||||
|
|
||||||
|
// 3. Создание клиента
|
||||||
|
$clientParams = array(
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'firstname' => 'Иван',
|
||||||
|
'lastname' => 'Иванов',
|
||||||
|
'mobile' => '+79991234567',
|
||||||
|
'email' => 'ivan@example.com',
|
||||||
|
'birthday' => '1990-01-01',
|
||||||
|
'inn' => '123456789012',
|
||||||
|
'code' => '123456'
|
||||||
|
);
|
||||||
|
curl_setopt_array($ch, array(
|
||||||
|
CURLOPT_RETURNTRANSFER => 1,
|
||||||
|
CURLOPT_POST => 1,
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_POSTFIELDS => $clientParams
|
||||||
|
));
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$jsonResponse = json_decode($response, true);
|
||||||
|
$contactId = $jsonResponse['result'];
|
||||||
|
|
||||||
|
// 4. Создание контрагента
|
||||||
|
$accountParams = array(
|
||||||
|
'operation' => 'CreateAccount',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'accountname' => 'ООО "Пример"',
|
||||||
|
'inn' => '9876543210',
|
||||||
|
'ogrn' => '1234567890123'
|
||||||
|
);
|
||||||
|
curl_setopt_array($ch, array(
|
||||||
|
CURLOPT_RETURNTRANSFER => 1,
|
||||||
|
CURLOPT_POST => 1,
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_POSTFIELDS => $accountParams
|
||||||
|
));
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$jsonResponse = json_decode($response, true);
|
||||||
|
$accountId = $jsonResponse['result'];
|
||||||
|
|
||||||
|
// 5. Создание проекта
|
||||||
|
$projectParams = array(
|
||||||
|
'operation' => 'CreateProject',
|
||||||
|
'sessionName' => $sessionId,
|
||||||
|
'contactid' => $contactId,
|
||||||
|
'offenderid' => $accountId,
|
||||||
|
'description' => 'Описание обращения'
|
||||||
|
);
|
||||||
|
curl_setopt_array($ch, array(
|
||||||
|
CURLOPT_RETURNTRANSFER => 1,
|
||||||
|
CURLOPT_POST => 1,
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_POSTFIELDS => $projectParams
|
||||||
|
));
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
$jsonResponse = json_decode($response, true);
|
||||||
|
$projectId = $jsonResponse['result'];
|
||||||
|
|
||||||
|
curl_close($ch);
|
||||||
|
```
|
||||||
|
|
||||||
279
CONFIG.md
Normal file
279
CONFIG.md
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
# Конфигурация проекта
|
||||||
|
|
||||||
|
## Переменные окружения и настройки
|
||||||
|
|
||||||
|
### База данных
|
||||||
|
|
||||||
|
**Файл:** `ticket/database.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
$host = "localhost";
|
||||||
|
$username = "ci20465_erv";
|
||||||
|
$password = "c7vOXbmG";
|
||||||
|
$database = "ci20465_erv";
|
||||||
|
$table = "lexrpiority";
|
||||||
|
```
|
||||||
|
|
||||||
|
### CRM API
|
||||||
|
|
||||||
|
**Endpoint:**
|
||||||
|
```
|
||||||
|
https://crm.clientright.ru/webservice.php
|
||||||
|
```
|
||||||
|
|
||||||
|
**Учетные данные:**
|
||||||
|
```php
|
||||||
|
$username = "api";
|
||||||
|
$userAccessKey = "4r9ANex8PT2IuRV";
|
||||||
|
```
|
||||||
|
|
||||||
|
**WebForms Capture:**
|
||||||
|
```
|
||||||
|
https://crm.clientright.ru/modules/Webforms/capture.php
|
||||||
|
```
|
||||||
|
|
||||||
|
**Параметры формы:**
|
||||||
|
```php
|
||||||
|
$formToken = "sid:ec649134ad232e44c3ad71bbd321cee986f05545,1688385374";
|
||||||
|
$publicId = "3ddc71c2d79ef101c09b0d4e9c6bd08b";
|
||||||
|
$formName = "websiteticket";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Внешние сервисы
|
||||||
|
|
||||||
|
#### DaData API
|
||||||
|
```php
|
||||||
|
$dadataToken = "f5d6928d7490cd44124ccae11a08c7fa5625d48c";
|
||||||
|
$dadataUrl = "https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/party";
|
||||||
|
```
|
||||||
|
|
||||||
|
#### IP Geolocation
|
||||||
|
```php
|
||||||
|
$ipApiUrl = "http://ip-api.com/json/{IP}?lang=ru";
|
||||||
|
```
|
||||||
|
|
||||||
|
#### File Upload
|
||||||
|
```php
|
||||||
|
$fileUploadUrl = "https://form.clientright.ru/fileupload_v2.php";
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Form Processing
|
||||||
|
```php
|
||||||
|
$formProcessingUrl = "https://form.clientright.ru/server_new.php";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Контрагент по умолчанию (ЕРВ)
|
||||||
|
|
||||||
|
**Файл:** `ticket/index.php` (строки 65-72)
|
||||||
|
|
||||||
|
```php
|
||||||
|
$contractor = array(
|
||||||
|
'inn' => '7714312079',
|
||||||
|
'ogrn' => '1037714037426',
|
||||||
|
'accountname' => 'Филиал ООО РСО ЕВРОИНС Туристическое',
|
||||||
|
'address' => '119049 Москва, 4-й Добрынинский пер., д.8, помещ. С 14-I, ком. 21-26',
|
||||||
|
'email' => 'info@erv.ru',
|
||||||
|
'phone' => '84956265800',
|
||||||
|
'website' => 'https://www.erv.ru/'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Валидные тарифы полисов
|
||||||
|
|
||||||
|
**Базовые тарифы:**
|
||||||
|
```php
|
||||||
|
$valid_tariffs_basic = [
|
||||||
|
'STB0048', 'STB1099', 'STB1100', 'STB2099',
|
||||||
|
'AVS21500', 'AVS22500'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
**Дополнительные тарифы:**
|
||||||
|
```php
|
||||||
|
$valid_tariffs_other = [
|
||||||
|
'SPV0001', 'SPV0002', 'SPV0003', 'SPV0004', 'SPV0005',
|
||||||
|
'STV0090',
|
||||||
|
'SPV1001', 'SPV1002', 'SPV1003', 'SPV1004', 'SPV1005',
|
||||||
|
'SPV2001', 'SPV2002', 'SPV2004', 'SPV2005',
|
||||||
|
'OPV1001', 'OPV1002', 'OPV1003', 'OPV1004', 'OPV1005',
|
||||||
|
'OPV2001', 'OPV2002', 'OPV2004', 'OPV2005'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ограничения файлов
|
||||||
|
|
||||||
|
```php
|
||||||
|
$maxFileSize = 5 * 1024 * 1024; // 5 МБ
|
||||||
|
$maxFilesPerField = 10;
|
||||||
|
$allowedFormats = ['pdf', 'jpg', 'png', 'gif', 'jpeg', 'heic', 'HEIC'];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Настройки формы
|
||||||
|
|
||||||
|
**ID формы:**
|
||||||
|
```php
|
||||||
|
$formId = "00001";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Направление обращения:**
|
||||||
|
```php
|
||||||
|
$direction = "ЕРВ Средства размещения";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Маппинг полей формы
|
||||||
|
|
||||||
|
#### Поля клиента (data-ws_type="client")
|
||||||
|
| Поле формы | CRM поле | Описание |
|
||||||
|
|------------|----------|----------|
|
||||||
|
| `lastname` | `lastname` | Фамилия |
|
||||||
|
| `firstname` | `firstname` | Имя |
|
||||||
|
| `patronymic` | `secondname` | Отчество |
|
||||||
|
| `phonenumber` | `mobile` | Телефон |
|
||||||
|
| `email` | `email` | Email |
|
||||||
|
| `birthday` | `birthday` | Дата рождения |
|
||||||
|
| `reg_adres` | `mailingstreet` | Адрес регистрации |
|
||||||
|
| `inn` | `inn` | ИНН |
|
||||||
|
| `code` | `code` | SMS-код |
|
||||||
|
|
||||||
|
#### Поля проекта (data-ws_type="project")
|
||||||
|
| Поле формы | CRM поле | Описание |
|
||||||
|
|------------|----------|----------|
|
||||||
|
| `insured_from` | `cf_1887` | Дата начала страхования |
|
||||||
|
| `insured_to` | `cf_1889` | Дата окончания страхования |
|
||||||
|
| `claim` | `cf_1899` | Код документа |
|
||||||
|
| `doc` | `cf_1804` | Серия и номер документа |
|
||||||
|
| `countryevent` | `cf_1909` | Страна события |
|
||||||
|
| `agree` | `cf_2502` | Согласие на обработку данных |
|
||||||
|
|
||||||
|
#### Поля контрагента (data-ws_type="contractor")
|
||||||
|
| Поле формы | CRM поле | Описание |
|
||||||
|
|------------|----------|----------|
|
||||||
|
| `place_inn` | `inn` | ИНН |
|
||||||
|
| - | `ogrn` | ОГРН |
|
||||||
|
| `place` | `accountname` | Наименование |
|
||||||
|
| `place_adres` | `address` | Адрес |
|
||||||
|
| `place_email` | `email` | Email |
|
||||||
|
| `place_phone` | `phone` | Телефон |
|
||||||
|
| `place_website` | `website` | Сайт |
|
||||||
|
|
||||||
|
#### Другие поля (data-ws_type="other")
|
||||||
|
| Поле формы | CRM поле | Описание |
|
||||||
|
|------------|----------|----------|
|
||||||
|
| - | `cf_2446` | Флаг наличия в базе |
|
||||||
|
| `police_number` | `cf_1885` | Номер полиса |
|
||||||
|
| `event_type` | `cf_1726` | Тип события |
|
||||||
|
| `insurence_date` | `cf_2566` | Дата страхового случая |
|
||||||
|
| `transport_number` | `cf_2568` | Номер рейса/поезда |
|
||||||
|
| `description` | `description` | Описание ситуации |
|
||||||
|
| - | `cf_1945` | ФИО получателя |
|
||||||
|
| - | `cf_1265` | Банк |
|
||||||
|
| - | `cf_1267` | БИК |
|
||||||
|
| - | `cf_1269` | Расчетный счет |
|
||||||
|
| - | `cf_1271` | Корр. счет |
|
||||||
|
| - | `cf_1273` | Иные реквизиты |
|
||||||
|
|
||||||
|
### Типы страховых случаев
|
||||||
|
|
||||||
|
```php
|
||||||
|
$eventTypes = [
|
||||||
|
'delay_flight' => 'Задержка авиарейса (более 3 часов)',
|
||||||
|
'cancel_flight' => 'Отмена авиарейса',
|
||||||
|
'miss_connection' => 'Пропуск (задержка прибытия) стыковочного рейса',
|
||||||
|
'emergency_landing' => 'Посадка воздушного судна на запасной аэродром',
|
||||||
|
'delay_train' => 'Задержка отправки поезда',
|
||||||
|
'cancel_train' => 'Отмена поезда',
|
||||||
|
'delay_ferry' => 'Задержка/отмена отправки парома/круизного судна'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Коды документов
|
||||||
|
|
||||||
|
```php
|
||||||
|
$documentCodes = [
|
||||||
|
'21' => 'Паспорт гражданина Российской Федерации',
|
||||||
|
'07' => 'Военный билет',
|
||||||
|
'24' => 'Удостоверение личности военнослужащего Российской Федерации',
|
||||||
|
'91' => 'Иные документы'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Настройки логирования
|
||||||
|
|
||||||
|
**Путь к логам:**
|
||||||
|
```php
|
||||||
|
$logFile = "logs/logfile.log";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Уровни логирования:**
|
||||||
|
- Информационные сообщения
|
||||||
|
- Ошибки
|
||||||
|
- Отладочная информация
|
||||||
|
|
||||||
|
### Настройки сессии
|
||||||
|
|
||||||
|
```php
|
||||||
|
session_start();
|
||||||
|
$subDir = session_id(); // Используется для изоляции файлов пользователей
|
||||||
|
```
|
||||||
|
|
||||||
|
### URL для редиректа после успешной отправки
|
||||||
|
|
||||||
|
```php
|
||||||
|
$successRedirectUrl = "https://lexpriority.ru/ok";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Политика обработки персональных данных
|
||||||
|
|
||||||
|
```php
|
||||||
|
$privacyPolicyUrl = "https://lexpriority.ru/politics";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Рекомендации по безопасности
|
||||||
|
|
||||||
|
1. **Храните секретные ключи в переменных окружения**
|
||||||
|
2. **Не коммитьте пароли и токены в репозиторий**
|
||||||
|
3. **Используйте HTTPS для всех внешних запросов**
|
||||||
|
4. **Валидируйте все входные данные**
|
||||||
|
5. **Используйте prepared statements для SQL**
|
||||||
|
6. **Ограничьте права доступа к файлам**
|
||||||
|
7. **Регулярно обновляйте зависимости**
|
||||||
|
|
||||||
|
## Переменные для разработки
|
||||||
|
|
||||||
|
### Тестовый режим
|
||||||
|
```php
|
||||||
|
// Добавьте ?demodata=1 к URL для автоматического заполнения формы
|
||||||
|
$demoMode = isset($_GET["demodata"]) ? $_GET["demodata"] : false;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Тестовые данные для API
|
||||||
|
```php
|
||||||
|
$testInn = "643922466250";
|
||||||
|
$testSmsCode = "795372";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Настройки сервера
|
||||||
|
|
||||||
|
### PHP требования
|
||||||
|
- PHP 7.4 или выше
|
||||||
|
- Расширения:
|
||||||
|
- curl
|
||||||
|
- mysqli
|
||||||
|
- gd (для работы с изображениями)
|
||||||
|
- mbstring
|
||||||
|
|
||||||
|
### Права доступа
|
||||||
|
```bash
|
||||||
|
# Для директории загрузки файлов
|
||||||
|
chmod 755 uploads/
|
||||||
|
chmod 755 logs/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Настройки PHP.ini
|
||||||
|
```ini
|
||||||
|
upload_max_filesize = 10M
|
||||||
|
post_max_size = 10M
|
||||||
|
max_execution_time = 300
|
||||||
|
memory_limit = 256M
|
||||||
|
```
|
||||||
|
|
||||||
31
MEMORY.md
Normal file
31
MEMORY.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Ключевые моменты по проекту ERV (формa Багаж, ticket_dev, miniapp)
|
||||||
|
|
||||||
|
## Структура проектов
|
||||||
|
- **miniapp** — основная форма (авиа + отель), эталон рабочей логики СМС и модалок.
|
||||||
|
- **hotels** — форма только по риску «Неполучение услуг размещения (отель)», класс `form-hotels-only`.
|
||||||
|
- **ticket_dev** — копия ticket с проверкой полиса через N8N, ios-оформление, тестовый СМС.
|
||||||
|
- **luggage** — форма «Багаж» (задержка/утрата/повреждение), копия ticket_dev по структуре.
|
||||||
|
|
||||||
|
## Модалка СМС (подтверждение кода)
|
||||||
|
- **Чтобы кнопка «Подтвердить» кликалась:** кнопка должна быть **внутри** элемента с классом `sms-checking` (как в miniapp). Разметка: внутри `.form-item.sms-checking` — инпут кода, затем `<div class="sms-checking sms-action">` с кнопками. Иначе селектор `$('.sms-checking .js-accept-sms')` не находит кнопку.
|
||||||
|
- Открытие через **Fancybox**: `$.fancybox.open({ src: '#confirm_sms', type: 'inline' })`, закрытие `$.fancybox.close()`.
|
||||||
|
- Обработчик — прямой: `$('.sms-checking .js-accept-sms').on('click', ...)` и `var code = $('.sms-checking input[type="text"]').val();`.
|
||||||
|
- **Где правили:** luggage/index.php + luggage/js/common.js; ticket_dev/index.php (разметка по аналогии с miniapp).
|
||||||
|
|
||||||
|
## Куда уходит submit
|
||||||
|
- **miniapp, hotels** → `https://n8n.clientright.pro/webhook/oldform_combine`
|
||||||
|
- **ticket_dev, luggage, ticket** → URL берётся из **.env**: переменная **N8N_SEND_WEBHOOK**. В luggage/ticket_dev в submit.php подключается env_loader.php и `$webhook_url = trim(env('N8N_SEND_WEBHOOK', '...'));`. Пример в luggage/.env: `N8N_SEND_WEBHOOK=https://n8n.clientright.pro/webhook/oldform_combine`.
|
||||||
|
|
||||||
|
## Валидация и форма (luggage)
|
||||||
|
- Форма с пошаговыми шагами: **novalidate** на `<form>`, чтобы браузер не ругался «invalid form control is not focusable» для полей с minlength на скрытых шагах.
|
||||||
|
- Описание: минимум 20 символов, атрибут `data-minlen="20"`, проверка в JS при submit; при ошибке — показ сообщения и прокрутка к полю описания.
|
||||||
|
- Поле «Задержка выдачи багажа (часов)»: обязательно при выборе типа «Задержка», только цифры — класс `js-delay-hours-mask`, inputmask `9{1,4}`, без `notvalidate`.
|
||||||
|
|
||||||
|
## Список файлов (длинные имена)
|
||||||
|
- В .fileList длинное имя не должно наезжать на размер: у `.fileList li strong` — `flex: 1 1 auto`, `min-width: 0`, `overflow: hidden`, `text-overflow: ellipsis`, `white-space: nowrap`. Размер и крестик — `flex-shrink: 0`. Правили luggage, miniapp, ticket_dev, hotels в css/main.css.
|
||||||
|
|
||||||
|
## Тестовый СМС (без реальной отправки)
|
||||||
|
- В .env: `SMS_ENABLED=false`. В sms-verify.php при action=send возвращается `demo_code`, при action=verify проверка локально (Redis/файл). В common.js при успешной отправке показывается код в модалке (`data.demo_code`) и подстановка в поле.
|
||||||
|
|
||||||
|
## Окружение
|
||||||
|
- Ubuntu 22.04. Пользователь — Фёдор. Отвечать на русском.
|
||||||
245
PROJECT_STRUCTURE.md
Normal file
245
PROJECT_STRUCTURE.md
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
# Структура проекта - Детальное описание
|
||||||
|
|
||||||
|
## Обзор архитектуры
|
||||||
|
|
||||||
|
Проект состоит из нескольких версий формы, каждая из которых может иметь свои особенности. Основная рабочая версия находится в директории `/ticket/`.
|
||||||
|
|
||||||
|
## Основные компоненты
|
||||||
|
|
||||||
|
### 1. Frontend (Клиентская часть)
|
||||||
|
|
||||||
|
#### `index.php`
|
||||||
|
Главный файл формы, содержит:
|
||||||
|
- HTML-разметку многошаговой формы
|
||||||
|
- PHP-код для получения IP и региона пользователя
|
||||||
|
- Интеграцию с внешними API (ip-api.com)
|
||||||
|
- Структуру из 3 шагов:
|
||||||
|
- Шаг 1: SMS-подтверждение и проверка полиса
|
||||||
|
- Шаг 2: Информация о страховом случае
|
||||||
|
- Шаг 3: Персональные данные и документы
|
||||||
|
|
||||||
|
#### `js/common.js`
|
||||||
|
Основной JavaScript файл, реализует:
|
||||||
|
- Валидацию форм на каждом шаге
|
||||||
|
- Маски ввода (телефон, ИНН, даты, банковские реквизиты)
|
||||||
|
- Логику переключения между шагами
|
||||||
|
- Отправку SMS-кодов
|
||||||
|
- Загрузку и валидацию файлов
|
||||||
|
- Конвертацию HEIC в JPEG
|
||||||
|
- AJAX-запросы к серверу
|
||||||
|
- Интеграцию с DaData API для автодополнения
|
||||||
|
|
||||||
|
#### `css/main.css` и `css/custom.css`
|
||||||
|
Стили для формы, включая:
|
||||||
|
- Адаптивный дизайн
|
||||||
|
- Стили для шагов формы
|
||||||
|
- Стили для загрузки файлов
|
||||||
|
- Модальные окна
|
||||||
|
|
||||||
|
### 2. Backend (Серверная часть)
|
||||||
|
|
||||||
|
#### `database.php`
|
||||||
|
Проверка полисов в базе данных:
|
||||||
|
- Подключение к MySQL
|
||||||
|
- Проверка номера полиса
|
||||||
|
- Валидация тарифов
|
||||||
|
- Проверка сроков действия полиса
|
||||||
|
- Возврат JSON-ответа с результатами
|
||||||
|
|
||||||
|
#### `sms-test.php`
|
||||||
|
Тестирование отправки SMS:
|
||||||
|
- Генерация кода подтверждения
|
||||||
|
- Отправка SMS на указанный номер
|
||||||
|
- Логирование операций
|
||||||
|
|
||||||
|
#### `file-server.php` (если существует)
|
||||||
|
Обработка загрузки файлов на сервер
|
||||||
|
|
||||||
|
### 3. Интеграция с CRM
|
||||||
|
|
||||||
|
#### Основной endpoint
|
||||||
|
`https://form.clientright.ru/server_new.php`
|
||||||
|
|
||||||
|
Обрабатывает:
|
||||||
|
- Данные формы из POST-запроса
|
||||||
|
- Загруженные файлы
|
||||||
|
- Отправку данных в CRM через `capture.php`
|
||||||
|
- Логирование операций
|
||||||
|
|
||||||
|
#### Веб-сервисы CRM
|
||||||
|
`https://crm.clientright.ru/webservice.php`
|
||||||
|
|
||||||
|
Операции:
|
||||||
|
1. **getchallenge** - получение токена
|
||||||
|
2. **login** - авторизация и получение sessionId
|
||||||
|
3. **CreateContact** - создание/обновление клиента
|
||||||
|
4. **CreateAccount** - создание/обновление контрагента
|
||||||
|
5. **CreateProject** - создание проекта
|
||||||
|
6. **GetFilesList** - получение списка файлов клиента
|
||||||
|
|
||||||
|
### 4. База данных
|
||||||
|
|
||||||
|
#### Структура таблицы `lexrpiority`
|
||||||
|
Поля (предположительно):
|
||||||
|
- `inn` или `police_number` - номер полиса
|
||||||
|
- `birthday` - дата рождения
|
||||||
|
- `insured_from` - дата начала действия
|
||||||
|
- `insured_to` - дата окончания действия
|
||||||
|
- `tariff` - тариф полиса
|
||||||
|
|
||||||
|
#### Валидные тарифы
|
||||||
|
|
||||||
|
**Базовые тарифы:**
|
||||||
|
- STB0048, STB1099, STB1100, STB2099
|
||||||
|
- AVS21500, AVS22500
|
||||||
|
|
||||||
|
**Дополнительные тарифы:**
|
||||||
|
- SPV0001-SPV0005, STV0090
|
||||||
|
- SPV1001-SPV1005, SPV2001-SPV2005
|
||||||
|
- OPV1001-OPV1005, OPV2001-OPV2005
|
||||||
|
|
||||||
|
### 5. Внешние библиотеки
|
||||||
|
|
||||||
|
#### JavaScript библиотеки
|
||||||
|
- **jQuery 3.6.3** - основной фреймворк
|
||||||
|
- **Inputmask** - маски ввода
|
||||||
|
- **Datepicker** - выбор дат
|
||||||
|
- **intl-tel-input** - ввод телефонных номеров
|
||||||
|
- **Fancybox** - модальные окна
|
||||||
|
- **heic2any** - конвертация HEIC в JPEG
|
||||||
|
- **suggestions-jquery** - автодополнение адресов (DaData)
|
||||||
|
|
||||||
|
#### PHP библиотеки (Composer)
|
||||||
|
- **PHPMailer** - отправка email
|
||||||
|
- **FPDF/FPDI** - работа с PDF
|
||||||
|
- **PDF Merger** - объединение PDF
|
||||||
|
|
||||||
|
### 6. Поток данных
|
||||||
|
|
||||||
|
```
|
||||||
|
Пользователь заполняет форму
|
||||||
|
↓
|
||||||
|
Валидация на клиенте (JavaScript)
|
||||||
|
↓
|
||||||
|
Отправка данных на server_new.php
|
||||||
|
↓
|
||||||
|
Обработка файлов и данных
|
||||||
|
↓
|
||||||
|
Отправка в CRM через capture.php
|
||||||
|
↓
|
||||||
|
Получение sessionId через веб-сервисы
|
||||||
|
↓
|
||||||
|
Создание/обновление клиента (CreateContact)
|
||||||
|
↓
|
||||||
|
Создание/обновление контрагента (CreateAccount)
|
||||||
|
↓
|
||||||
|
Создание проекта (CreateProject)
|
||||||
|
↓
|
||||||
|
Загрузка файлов в CRM
|
||||||
|
↓
|
||||||
|
Отправка подтверждающего email
|
||||||
|
↓
|
||||||
|
Возврат результата пользователю
|
||||||
|
```
|
||||||
|
|
||||||
|
## Версии проекта
|
||||||
|
|
||||||
|
### `/ticket/` - Основная рабочая версия
|
||||||
|
Используется в продакшене.
|
||||||
|
|
||||||
|
### `/ticket3/` - Альтернативная версия
|
||||||
|
Возможно, содержит изменения или эксперименты.
|
||||||
|
|
||||||
|
### `/ervws/` - Версия для веб-сервисов
|
||||||
|
Версия с акцентом на веб-сервисы.
|
||||||
|
|
||||||
|
### `/test/` - Тестовая версия
|
||||||
|
Для тестирования новых функций.
|
||||||
|
|
||||||
|
### `/public_html/` - Публичная версия
|
||||||
|
Публичная версия для клиентов.
|
||||||
|
|
||||||
|
## Конфигурация полей формы
|
||||||
|
|
||||||
|
### Поля клиента (data-ws_type="client")
|
||||||
|
- `firstname` - Имя
|
||||||
|
- `lastname` - Фамилия
|
||||||
|
- `secondname` - Отчество
|
||||||
|
- `mobile` - Телефон
|
||||||
|
- `email` - Email
|
||||||
|
- `birthday` - Дата рождения
|
||||||
|
- `mailingstreet` - Адрес регистрации
|
||||||
|
- `inn` - ИНН
|
||||||
|
- `code` - SMS-код
|
||||||
|
|
||||||
|
### Поля проекта (data-ws_type="project")
|
||||||
|
- `cf_1887` - Дата начала страхования (insured_from)
|
||||||
|
- `cf_1889` - Дата окончания страхования (insured_to)
|
||||||
|
- `cf_1899` - Код документа
|
||||||
|
- `cf_1804` - Серия и номер документа
|
||||||
|
- `cf_2502` - Согласие на обработку данных
|
||||||
|
|
||||||
|
### Поля контрагента (data-ws_type="contractor")
|
||||||
|
- `inn` - ИНН
|
||||||
|
- `ogrn` - ОГРН
|
||||||
|
- `accountname` - Наименование
|
||||||
|
- `address` - Адрес
|
||||||
|
- `email` - Email
|
||||||
|
- `phone` - Телефон
|
||||||
|
- `website` - Сайт
|
||||||
|
|
||||||
|
### Другие поля (data-ws_type="other")
|
||||||
|
- `cf_2446` - Флаг наличия в базе
|
||||||
|
- `cf_1885` - Номер полиса
|
||||||
|
- `cf_1726` - Тип события
|
||||||
|
- `cf_2566` - Дата страхового случая
|
||||||
|
- `cf_2568` - Номер рейса/поезда
|
||||||
|
- `description` - Описание ситуации
|
||||||
|
- И другие кастомные поля
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
1. **Валидация файлов:**
|
||||||
|
- Проверка расширений
|
||||||
|
- Проверка MIME-типов
|
||||||
|
- Ограничение размера (5 МБ)
|
||||||
|
- Ограничение количества (10 файлов)
|
||||||
|
|
||||||
|
2. **Валидация данных:**
|
||||||
|
- Проверка обязательных полей
|
||||||
|
- Валидация email
|
||||||
|
- Валидация телефона
|
||||||
|
- Проверка форматов дат
|
||||||
|
|
||||||
|
3. **Защита от атак:**
|
||||||
|
- Экранирование данных
|
||||||
|
- Использование prepared statements (рекомендуется)
|
||||||
|
- Валидация на сервере
|
||||||
|
- CSRF-токены (если реализованы)
|
||||||
|
|
||||||
|
## Логирование
|
||||||
|
|
||||||
|
Логи сохраняются в:
|
||||||
|
- `logs/logfile.log` - общие логи
|
||||||
|
- `formlog/` - логи форм
|
||||||
|
- JSON-файлы с префиксом `resend_log_` - логи повторной отправки
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
### Тестовый режим формы
|
||||||
|
Добавьте `?demodata=1` к URL для автоматического заполнения всех полей.
|
||||||
|
|
||||||
|
### Тестовые данные для API
|
||||||
|
- ИНН: `643922466250`
|
||||||
|
- СМС-код: `795372`
|
||||||
|
|
||||||
|
## Рекомендации по разработке
|
||||||
|
|
||||||
|
1. Всегда тестируйте изменения в `/test/` перед применением в продакшене
|
||||||
|
2. Используйте версионирование для отслеживания изменений
|
||||||
|
3. Логируйте важные операции
|
||||||
|
4. Валидируйте данные на сервере, не только на клиенте
|
||||||
|
5. Используйте prepared statements для SQL-запросов
|
||||||
|
6. Регулярно проверяйте логи на ошибки
|
||||||
|
7. Делайте резервные копии перед крупными изменениями
|
||||||
|
|
||||||
159
README.md
Normal file
159
README.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# Проект ЕРВ - Форма обращений за выплатой страховки
|
||||||
|
|
||||||
|
## Описание проекта
|
||||||
|
|
||||||
|
Веб-приложение для обработки обращений за выплатой страхового возмещения по полисам ЕРВ (Евроинс). Проект представляет собой многошаговую форму с интеграцией в CRM-систему ClientRight.
|
||||||
|
|
||||||
|
## Технологический стек
|
||||||
|
|
||||||
|
- **Backend**: PHP 7.4+
|
||||||
|
- **Frontend**: HTML5, CSS3, JavaScript (jQuery)
|
||||||
|
- **База данных**: MySQL
|
||||||
|
- **Интеграции**:
|
||||||
|
- CRM ClientRight (веб-сервисы)
|
||||||
|
- DaData API (автодополнение адресов и организаций)
|
||||||
|
- SMS-сервис для подтверждения телефона
|
||||||
|
- IP-геолокация (ip-api.com)
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
erv.clientright.ru/
|
||||||
|
├── ticket/ # Основная рабочая версия формы
|
||||||
|
│ ├── index.php # Главная страница формы
|
||||||
|
│ ├── database.php # Проверка полисов в БД
|
||||||
|
│ ├── sms-test.php # Тестирование SMS
|
||||||
|
│ ├── css/ # Стили
|
||||||
|
│ ├── js/ # JavaScript файлы
|
||||||
|
│ └── libs/ # Внешние библиотеки
|
||||||
|
├── ticket3/ # Альтернативная версия
|
||||||
|
├── ervws/ # Версия для веб-сервисов
|
||||||
|
├── test/ # Тестовая версия
|
||||||
|
├── public_html/ # Публичная версия
|
||||||
|
├── vendor/ # PHP зависимости (Composer)
|
||||||
|
├── libs/ # Общие библиотеки
|
||||||
|
└── Документация API.txt # Документация по API CRM
|
||||||
|
```
|
||||||
|
|
||||||
|
## Основные функции
|
||||||
|
|
||||||
|
1. **Многошаговая форма** (3 шага):
|
||||||
|
- Шаг 1: Подтверждение телефона через SMS
|
||||||
|
- Шаг 2: Информация о страховом случае
|
||||||
|
- Шаг 3: Персональные данные и документы
|
||||||
|
|
||||||
|
2. **Проверка полиса**:
|
||||||
|
- Валидация номера полиса в базе данных
|
||||||
|
- Проверка тарифов и сроков действия
|
||||||
|
|
||||||
|
3. **Загрузка файлов**:
|
||||||
|
- Поддержка форматов: PDF, JPG, PNG, GIF, JPEG, HEIC
|
||||||
|
- Конвертация HEIC в JPEG
|
||||||
|
- Максимальный размер файла: 5 МБ
|
||||||
|
- Максимум 10 файлов на поле
|
||||||
|
|
||||||
|
4. **Интеграция с CRM**:
|
||||||
|
- Создание/обновление клиента (CreateContact)
|
||||||
|
- Создание/обновление контрагента (CreateAccount)
|
||||||
|
- Создание проекта (CreateProject)
|
||||||
|
- Загрузка файлов в CRM
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
### База данных
|
||||||
|
- Хост: `localhost`
|
||||||
|
- База: `ci20465_erv`
|
||||||
|
- Таблица для проверки полисов: `lexrpiority`
|
||||||
|
|
||||||
|
### CRM API
|
||||||
|
- Endpoint: `https://crm.clientright.ru/webservice.php`
|
||||||
|
- Username: `api`
|
||||||
|
- Access Key: `4r9ANex8PT2IuRV`
|
||||||
|
|
||||||
|
### Внешние сервисы
|
||||||
|
- **DaData API Token**: `f5d6928d7490cd44124ccae11a08c7fa5625d48c`
|
||||||
|
- **Форма обработки**: `https://form.clientright.ru/server_new.php`
|
||||||
|
- **Загрузка файлов**: `https://form.clientright.ru/fileupload_v2.php`
|
||||||
|
|
||||||
|
## Установка и запуск
|
||||||
|
|
||||||
|
1. Убедитесь, что установлены:
|
||||||
|
- PHP 7.4 или выше
|
||||||
|
- MySQL
|
||||||
|
- Composer (для зависимостей)
|
||||||
|
|
||||||
|
2. Установите зависимости:
|
||||||
|
```bash
|
||||||
|
composer install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Настройте подключение к базе данных в `database.php`
|
||||||
|
|
||||||
|
4. Настройте права доступа для загрузки файлов
|
||||||
|
|
||||||
|
## Рабочие версии
|
||||||
|
|
||||||
|
- **Основная рабочая версия**: `/ticket/`
|
||||||
|
- **Тестовая версия**: `/test/`
|
||||||
|
- **Публичная версия**: `/public_html/`
|
||||||
|
|
||||||
|
## API CRM - Основные операции
|
||||||
|
|
||||||
|
### 1. Авторизация
|
||||||
|
```php
|
||||||
|
operation = getchallenge
|
||||||
|
operation = login
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Работа с клиентами
|
||||||
|
```php
|
||||||
|
operation = CreateContact
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Работа с контрагентами
|
||||||
|
```php
|
||||||
|
operation = CreateAccount
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Работа с проектами
|
||||||
|
```php
|
||||||
|
operation = CreateProject
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Получение списка файлов
|
||||||
|
```php
|
||||||
|
operation = GetFilesList
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробная документация в файле `Документация API.txt`
|
||||||
|
|
||||||
|
## Особенности реализации
|
||||||
|
|
||||||
|
- **Валидация форм**: Проверка обязательных полей на каждом шаге
|
||||||
|
- **Маски ввода**: Телефон, ИНН, даты, банковские реквизиты
|
||||||
|
- **Адаптивность**: Поддержка мобильных устройств
|
||||||
|
- **Логирование**: Логи операций в `logs/logfile.log`
|
||||||
|
- **Обработка ошибок**: Try-catch блоки и валидация ответов
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
|
||||||
|
- Проверка типов файлов при загрузке
|
||||||
|
- Валидация размеров файлов
|
||||||
|
- Защита от XSS через экранирование данных
|
||||||
|
- Использование сессий для изоляции данных пользователей
|
||||||
|
|
||||||
|
## Разработка
|
||||||
|
|
||||||
|
Для разработки используйте версию в директории `/ticket/` или `/test/`.
|
||||||
|
|
||||||
|
### Тестовый режим
|
||||||
|
Добавьте параметр `?demodata=1` к URL для автоматического заполнения формы тестовыми данными.
|
||||||
|
|
||||||
|
## Контакты
|
||||||
|
|
||||||
|
- Разработчик: [TG: @wwdev](https://t.me/wwdev)
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
Проект разработан для ЕРВ (Евроинс).
|
||||||
|
|
||||||
960
common.js
Normal file
960
common.js
Normal file
@@ -0,0 +1,960 @@
|
|||||||
|
$(function() {
|
||||||
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
$(".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\(\)\.\+/ ]"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".js-inndb-mask").inputmask("A9{3,5}-*{6,10}");
|
||||||
|
|
||||||
|
$(".js-inndb-mask").keyup(function(){
|
||||||
|
//if($this)
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".js-bik-mask").inputmask("999999999");
|
||||||
|
$(".js-rs-mask").inputmask("99999999999999999999");
|
||||||
|
$(".js-ks-mask").inputmask("99999999999999999999");
|
||||||
|
|
||||||
|
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(),
|
||||||
|
formatter: (input, date, instance) => {
|
||||||
|
const value = date.toLocaleDateString()
|
||||||
|
input.value = value // => '1/1/2099'
|
||||||
|
},
|
||||||
|
onSelect: function(dateText, inst) {
|
||||||
|
let birthday=$('input[name="birthday"]').val();
|
||||||
|
|
||||||
|
if(getAge(birthday)<18) {
|
||||||
|
$("input[data-enableby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").removeAttr("disabled");
|
||||||
|
} else {
|
||||||
|
$("input[data-enableby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").attr("disabled","disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($('input[name="insurence_date"]').length) {
|
||||||
|
var contract_date = datepicker('input[name="insurence_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 для поля даты рейса отправления
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var phone = document.querySelectorAll('.js-phone-mask');
|
||||||
|
$('.js-phone-mask').inputmask('999 999-99-99');
|
||||||
|
phone.forEach(el => {
|
||||||
|
const iti = window.intlTelInput(el, {
|
||||||
|
initialCountry: 'ru',
|
||||||
|
onlyCountries : ['ru'],
|
||||||
|
separateDialCode: true,
|
||||||
|
customContainer: ".form-item",
|
||||||
|
autoPlaceholder: 'aggressive',
|
||||||
|
utilsScript: "libs/intl-tel-input-master/build/js/utils.js",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.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;
|
||||||
|
|
||||||
|
$('.js-btn-next').on("click",function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.js-btn-prev').on("click",function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
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('Укажите номер рейса прибытия');
|
||||||
|
$('.connection-fields, .connection-date-fields').show();
|
||||||
|
} else if (selectedValue === 'cancel_flight') {
|
||||||
|
$('#transport_number_label').text('Номер рейса/поезда/парома');
|
||||||
|
$('.cancel-flight-docs').show();
|
||||||
|
} else {
|
||||||
|
$('#transport_number_label').text('Номер рейса/поезда/парома');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function validate_step(step_index){
|
||||||
|
let inputs=$('.form-step.active').find('input[type="text"], 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;
|
||||||
|
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'){
|
||||||
|
|
||||||
|
if(validateEmail($(this).val())) {
|
||||||
|
field_fill=true;
|
||||||
|
} else {
|
||||||
|
field_fill=false;
|
||||||
|
$(this).closest('.form-item').find('.form-item__warning').text($(this).data('warmes'));
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
res_array.push(field_fill);
|
||||||
|
});
|
||||||
|
|
||||||
|
if((step_index==3) && $('.form-step[data-step='+step_index+']').find('input[type="checkbox"]:checked').length<1) {
|
||||||
|
$('.form__warning').show();
|
||||||
|
$('.form__warning').text('Выберите хотя 1 страховой случай');
|
||||||
|
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();
|
||||||
|
$(this).closest('.form-item').find('input[type=file]').toggleClass('disabled');
|
||||||
|
$(this).closest('.form-item').find('input[type=file]+label').toggleClass('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
// start sms
|
||||||
|
|
||||||
|
function send_sms(){
|
||||||
|
|
||||||
|
var sended_code = Math.floor(Math.random()*(999999-100000+1)+100000);
|
||||||
|
var smsFormData = new FormData();
|
||||||
|
smsFormData.append('smscode',sended_code);
|
||||||
|
smsFormData.append('phonenumber',$('input[name="phonenumber"]').val());
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// url: 'sms-test.php',
|
||||||
|
// method: 'post',
|
||||||
|
// cache: false,
|
||||||
|
// contentType: false,
|
||||||
|
// processData: false,
|
||||||
|
// data: smsFormData,
|
||||||
|
// dataType : 'json',
|
||||||
|
// success: function(data) {
|
||||||
|
// console.log(data);
|
||||||
|
// return false;
|
||||||
|
// },
|
||||||
|
// error: function (jqXHR, exception) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
alert(sended_code);
|
||||||
|
|
||||||
|
$('.js-code-warning').text('Код отправлен на ваш номер телефона');
|
||||||
|
|
||||||
|
$.fancybox.open({
|
||||||
|
src: '#confirm_sms',
|
||||||
|
type: 'inline'
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.fancybox-close-small').click(function(e) {
|
||||||
|
$('button[type="submit"]').attr("disabled", false);
|
||||||
|
$('button[type="submit"]').attr("disabled", false);
|
||||||
|
$('button[type="submit"]').text("Подать обращение");
|
||||||
|
});
|
||||||
|
|
||||||
|
return sended_code;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function countDown(elm, duration, fn){
|
||||||
|
var countDownDate = new Date().getTime() + (1000 * duration);
|
||||||
|
var x = setInterval(function() {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var distance = countDownDate - now;
|
||||||
|
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||||
|
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
|
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||||
|
elm.innerHTML = minutes + "м " + seconds + "с ";
|
||||||
|
if (distance < 0) {
|
||||||
|
clearInterval(x);
|
||||||
|
fn();
|
||||||
|
elm.innerHTML = "";
|
||||||
|
$('.sms-countdown').hide();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sended_code;
|
||||||
|
|
||||||
|
$('.js-send-sms').on('click', function(e) {
|
||||||
|
// $('.js-send-sms').hide();
|
||||||
|
sended_code=send_sms();
|
||||||
|
$('.sms-countdown').show();
|
||||||
|
$('.modal .js-accept-sms').show();
|
||||||
|
$('.modal .js-send-sms').hide();
|
||||||
|
$('.modal .form-item__warning').text("");
|
||||||
|
countDown(document.querySelector('.sms-countdown .time'), 30, function(){
|
||||||
|
$('.modal .js-send-sms').show();
|
||||||
|
$('.sms-checking button.js-accept-sms').hide();
|
||||||
|
$('.js-code-warning').hide();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.sms-checking .js-accept-sms').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if($('.sms-checking input[type="text"]').val() == sended_code) {
|
||||||
|
$('.sms-success').removeClass('d-none');
|
||||||
|
$('.form-step[data-step=1]').removeClass('disabled');
|
||||||
|
|
||||||
|
$('.modal .js-send-sms').show();
|
||||||
|
$('.sms-check .form-item > .js-send-sms').hide();
|
||||||
|
$.fancybox.close();
|
||||||
|
$.fancybox.close();
|
||||||
|
$('.sms-check').addClass("disabled");
|
||||||
|
$('.sms-check .form-item__warning').text("Вы успешно подтвердили номер");
|
||||||
|
} else {
|
||||||
|
$('.modal .form-item__warning').text("Неверный код");
|
||||||
|
$('.sms-success').addClass('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.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();
|
||||||
|
|
||||||
|
jQuery.each(jQuery('input[type=file].js-attach').not('.disabled'), function(i, file) {
|
||||||
|
|
||||||
|
if(!$(this).hasClass('disabled')) {
|
||||||
|
let field_name=jQuery(this).data('crmname');
|
||||||
|
let docname=jQuery(this).data('docname');
|
||||||
|
let upload_url=jQuery(this).attr('data-uploadurl');
|
||||||
|
let upload_url_real=jQuery(this).attr('data-uploadurl_real');
|
||||||
|
jQuery.each(jQuery(this)[0].files, function(i, file) {
|
||||||
|
formData.append(field_name+'-'+i, file);
|
||||||
|
});
|
||||||
|
if(upload_url) { // Если файл загрузился и получили ответ от upload тогда добавляем в форму
|
||||||
|
formData.append('upload_urls[]',upload_url);
|
||||||
|
formData.append('upload_urls_real[]',upload_url_real);
|
||||||
|
formData.append('files_names[]',field_name);
|
||||||
|
formData.append('docs_names[]',docname);
|
||||||
|
|
||||||
|
if(jQuery(this).data('doctype')=="ticket") {
|
||||||
|
formData.append('docs_ticket_files_ids[]',i);
|
||||||
|
} else {
|
||||||
|
formData.append('docs_ticket_files_ids[]','simple');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (var pair of formData.entries()) {
|
||||||
|
console.log(pair[0]+ ', ' + pair[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'https://form.clientright.ru/server_webservice2.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 f5d6928d7490cd44124ccae11a08c7fa5625d48c",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": "__ddg1_=BoLd7l5yOCjL9tr6qUth"
|
||||||
|
},
|
||||||
|
"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();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// $(document).ready(function(){
|
||||||
|
// setTimeout(function() {
|
||||||
|
// var $form = $(".form form");
|
||||||
|
// createSuggestions($form);
|
||||||
|
// }, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'database.php',
|
||||||
|
method: 'post',
|
||||||
|
data: dbdata,
|
||||||
|
// dataType : 'json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
let res=JSON.parse(data);
|
||||||
|
if(res.success=="true"){
|
||||||
|
|
||||||
|
$('.db-success').removeClass("d-none");
|
||||||
|
$('.js-result').html(res.message);
|
||||||
|
|
||||||
|
$('.js-result').removeClass("danger");
|
||||||
|
|
||||||
|
$('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');
|
||||||
|
$('.form-item--polis').find('input[type=file]').addClass("notvalidate");
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').addClass("disabled");
|
||||||
|
|
||||||
|
|
||||||
|
$('.form-item--polis').addClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$('.db-success').removeClass("d-none");
|
||||||
|
|
||||||
|
$('.js-result').html(res.message);
|
||||||
|
|
||||||
|
$('.js-result').addClass("danger");
|
||||||
|
|
||||||
|
|
||||||
|
$('.js-indatabase').val('0');
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').removeClass("notvalidate");
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').removeClass("disabled");
|
||||||
|
|
||||||
|
$('.form-item--polis').removeClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
error: function (jqXHR, exception) {
|
||||||
|
$('.js-result').html(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) {
|
||||||
|
$("input[data-enableby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").removeAttr("disabled");
|
||||||
|
} else {
|
||||||
|
$("input[data-enableby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").attr("disabled","disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$('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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getAge(dateString) {
|
||||||
|
var today = new Date();
|
||||||
|
var birthDate = new Date(dateString.replace( /(\d{2})-(\d{2})-(\d{4})/, "$2/$1/$3"));
|
||||||
|
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 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','gif','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)) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Доступные форматы: .pdf, .jpg, .png, .gif </div>');
|
||||||
|
elem.addClass('error');
|
||||||
|
file_status.push(false);
|
||||||
|
} else {
|
||||||
|
// elem.closest('.form-item').find('.form-item__warning').text();
|
||||||
|
if((file.size/1024/1024) > 5){
|
||||||
|
file_status.push(false);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 5 Мб. </div>');
|
||||||
|
} else {
|
||||||
|
elem.removeClass('error');
|
||||||
|
file_status.push(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_status.every(val => val === true))
|
||||||
|
{
|
||||||
|
upload_file(elem);
|
||||||
|
$('.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');
|
||||||
|
let docname=thisfile.data('docname');
|
||||||
|
|
||||||
|
console.log(docname);
|
||||||
|
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 filesToUpload = [];
|
||||||
|
|
||||||
|
let filethis=$(this);
|
||||||
|
|
||||||
|
filethis.change(function (evt) {
|
||||||
|
var output = [];
|
||||||
|
let elem= $(this);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').text('');
|
||||||
|
let file_status=[];
|
||||||
|
var formats = ['pdf','jpg','png','gif','jpeg'];
|
||||||
|
|
||||||
|
console.log(evt.target.files);
|
||||||
|
|
||||||
|
if(evt.target.files.length>10) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').text("Разрешено не более 10 файлов");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Доступные форматы: .pdf, .jpg, .png, .gif </div>');
|
||||||
|
elem.addClass('error');
|
||||||
|
file_status.push(false);
|
||||||
|
} else {
|
||||||
|
// elem.closest('.form-item').find('.form-item__warning').text();
|
||||||
|
if((file.size/1024/1024) > 5){
|
||||||
|
file_status.push(false);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 5 Мб. </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> ");
|
||||||
|
|
||||||
|
filesToUpload.push({
|
||||||
|
id: fileId,
|
||||||
|
file: file
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//evt.target.value = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// elem.closest('.form-item').find('.upload-action').removeClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
elem.closest('.form-item').find(".fileList").append(output.join(""));
|
||||||
|
|
||||||
|
let container = new DataTransfer();
|
||||||
|
for (var i = 0, len = filesToUpload.length; i < len; i++) {
|
||||||
|
container.items.add(filesToUpload[i].file);
|
||||||
|
}
|
||||||
|
|
||||||
|
elem[0].files = container.files;
|
||||||
|
|
||||||
|
if(file_status.every(val => val === true))
|
||||||
|
{
|
||||||
|
upload_file(elem);
|
||||||
|
$('.form__action').find('.js-btn-next').removeClass('disabled');
|
||||||
|
} else {
|
||||||
|
$('.form__action').find('.js-btn-next').addClass('disabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).closest('.form-item').on("click", ".removefile", function (e) {
|
||||||
|
let elem= $(this);
|
||||||
|
e.preventDefault();
|
||||||
|
var fileId = elem.parent().children("a").data("fileid");
|
||||||
|
for (var i = 0; i < filesToUpload.length; ++i) {
|
||||||
|
if (filesToUpload[i].id === fileId) filesToUpload.splice(i, 1);
|
||||||
|
}
|
||||||
|
elem.parent().remove();
|
||||||
|
if(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 = filesToUpload.length; i < len; i++) {
|
||||||
|
container.items.add(filesToUpload[i].file);
|
||||||
|
}
|
||||||
|
filethis[0].files = container.files;
|
||||||
|
updateSize(filethis);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// End Загрузка файлов
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
67
css/custom.css
Normal file
67
css/custom.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
form {
|
||||||
|
width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #d1d1d1;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[haserror="yes"] {
|
||||||
|
border: 2px solid tomato !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.constant {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sum_removing {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: tomato;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim_additional {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tour-product,
|
||||||
|
#tour-accomodation,
|
||||||
|
#tour-transportation,
|
||||||
|
#tour-other {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete {
|
||||||
|
padding: 10px 10px 10px 10px;
|
||||||
|
border: 1px solid #f3f3f3;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete__item {
|
||||||
|
padding: 2px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete__item:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.country-select{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
604
css/main.css
Normal file
604
css/main.css
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "r-regular";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Regular.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Regular.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Regular.woff") format("woff"), url("../fonts/Roboto/Roboto-Regular.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-medium";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Medium.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Medium.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Medium.woff") format("woff"), url("../fonts/Roboto/Roboto-Medium.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-bold";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Bold.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Bold.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Bold.woff") format("woff"), url("../fonts/Roboto/Roboto-Bold.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-light";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Light.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Light.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Light.woff") format("woff"), url("../fonts/Roboto/Roboto-Light.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-semibold";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-SemiBold.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-SemiBold.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-SemiBold.woff") format("woff"), url("../fonts/Roboto/Roboto-SemiBold.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-viewport {
|
||||||
|
width: device-width;
|
||||||
|
}
|
||||||
|
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form{
|
||||||
|
padding-top: 100px;
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.form__title{
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.5;
|
||||||
|
max-width: 560px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
.form__title strong{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.form-item .form-item__label {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.55;
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
.form-item .form-item__sublabel {
|
||||||
|
/* font-family: r-light; */
|
||||||
|
margin-bottom: 25px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.55;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.form-item .form-item__sublabel a{
|
||||||
|
color: #ff8562;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.form-item .form-input, .form-item .t-datepicker{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.33;
|
||||||
|
width: 100%;
|
||||||
|
border: 0 none;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 0;
|
||||||
|
color: #000000;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
}
|
||||||
|
input::placeholder{
|
||||||
|
color: #ff000083;
|
||||||
|
}
|
||||||
|
.select-wrap{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.select-wrap:after{
|
||||||
|
content: ' ';
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 6px 5px 0 5px;
|
||||||
|
border-color: #000 transparent transparent transparent;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item .form-input--date{
|
||||||
|
background: url('../img/date.svg') no-repeat right 14px center;
|
||||||
|
background-size: 27px;
|
||||||
|
width: 245px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item .form-input::placeholder{
|
||||||
|
color:#7f7f7f4d;
|
||||||
|
}
|
||||||
|
.form-item .form-item__warning {}
|
||||||
|
|
||||||
|
|
||||||
|
.form-item .form-input--textarea{
|
||||||
|
height: 102px;
|
||||||
|
padding-top: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-step{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-step.active
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__warning{
|
||||||
|
background: #F95D51;
|
||||||
|
padding: 10px;
|
||||||
|
height: 70px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color:#fff;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
.t-check-in, .t-check-out, .t-datepicker{
|
||||||
|
float: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__action{
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.progress-row{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top:-25px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.progress-row .span-progress{
|
||||||
|
transform: translateY(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn{
|
||||||
|
height: 45px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
background: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color:#fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-note {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.55;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.form-note a{
|
||||||
|
color: #ff8562;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.btn span.icon{
|
||||||
|
width: 18px;
|
||||||
|
height: 16px;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn--next{
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.btn--next span.icon{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn--prev span.icon{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn span.icon:after{
|
||||||
|
color:#fff;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: Arial,Helvetica,sans-serif;
|
||||||
|
}
|
||||||
|
.btn--next span.icon:after{
|
||||||
|
content: '→';
|
||||||
|
}
|
||||||
|
.btn--prev span.icon:after{
|
||||||
|
content: '←';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-step__info{
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.form-item input[type="file"]{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-item input[type="file"] +label {
|
||||||
|
height: 45px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
background: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color:#fff;
|
||||||
|
font-family: r-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iti{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-progress {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.span-progress .current {}
|
||||||
|
.span-progress .total {}
|
||||||
|
|
||||||
|
|
||||||
|
.datepicker__header{
|
||||||
|
background: #efefef !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item__warning{
|
||||||
|
color: red;
|
||||||
|
font-size: 13px;
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.datepicker__day.is-today,.qs-current{
|
||||||
|
background: #bdbdbd !important;
|
||||||
|
color:#fff !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item {}
|
||||||
|
.checkbox-item .form-checkbox {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label{
|
||||||
|
padding-left: 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:after{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 20px;
|
||||||
|
top: 0;
|
||||||
|
width: 20px;
|
||||||
|
border: 2px solid #000;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: 10px;
|
||||||
|
-webkit-transition: all 0.2s;
|
||||||
|
transition: all 0.2s;
|
||||||
|
opacity: .6;
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:before{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 20px;
|
||||||
|
top: 0;
|
||||||
|
width: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: 10px;
|
||||||
|
-webkit-transition: all 0.2s;
|
||||||
|
transition: all 0.2s;
|
||||||
|
opacity: .6;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
background: url('../img/check.svg') no-repeat center;
|
||||||
|
background-size: 13px;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:before{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item .form-checkbox:checked + label:before{
|
||||||
|
opacity: 1;
|
||||||
|
background: url('../img/check.svg') no-repeat center;
|
||||||
|
background-size: 13px;
|
||||||
|
}
|
||||||
|
.w-100{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.sms-action{
|
||||||
|
/* display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center; */
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.form-item .form-input--date{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.form__title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.form-item .form-input, .form-item .t-datepicker {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.disabled+label{
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
button[disabled=disabled], button:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-code-warning{
|
||||||
|
color: #88b56d;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.modal{
|
||||||
|
max-width: 400px !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.modal h4.title{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.modal p{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.modal{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.loader-wrap{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(255,255,255,0.5);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1000;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
left: 0;
|
||||||
|
top:0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.loader::after,
|
||||||
|
.loader::before {
|
||||||
|
content: '';
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border: 2px solid rgb(182, 179, 179);
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
animation: rotationBreak 3s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
.loader::after {
|
||||||
|
border-color: #36353e;
|
||||||
|
animation-direction: alternate-reverse;
|
||||||
|
}
|
||||||
|
.loader-info{
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
color: #3d2626;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotationBreak {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-none{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-item{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.form-item__dropdown{
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
box-shadow: 0 0 15px rgba(0,0,0,.05);
|
||||||
|
z-index: 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item input[type="file"] +label{
|
||||||
|
background: none;
|
||||||
|
color:#999999;
|
||||||
|
text-decoration: underline;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.fileList{
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.fileList li{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
border-bottom: 1px solid #f5f2f2;
|
||||||
|
}
|
||||||
|
.fileList li strong{
|
||||||
|
width: 70%;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.fileList li span{
|
||||||
|
width: 20%;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.fileList li .removefile{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: url('../img/close.svg') no-repeat center;
|
||||||
|
background-size: 10px;
|
||||||
|
}
|
||||||
|
.upload-action{
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.country-select{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.form-col{
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-result{
|
||||||
|
color:#30cc11c2;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.js-result.danger{
|
||||||
|
color:#F95D51;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suсcess-upload{
|
||||||
|
margin-bottom: 2px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-text{
|
||||||
|
margin-bottom: 30px;
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
BIN
data/other.pdf
Normal file
BIN
data/other.pdf
Normal file
Binary file not shown.
BIN
data/passport.pdf
Normal file
BIN
data/passport.pdf
Normal file
Binary file not shown.
BIN
data/polis.pdf
Normal file
BIN
data/polis.pdf
Normal file
Binary file not shown.
BIN
data/ticket.pdf
Normal file
BIN
data/ticket.pdf
Normal file
Binary file not shown.
107
database.php
Normal file
107
database.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// База данных: ci20465_erv
|
||||||
|
// Таблица: lexrpiority
|
||||||
|
// Форма: Средства размещения (НУ - неудовлетворительные условия)
|
||||||
|
|
||||||
|
if(isset($_POST['action']) && !empty($_POST['action'])) {
|
||||||
|
$action = $_POST['action'];
|
||||||
|
switch($action) {
|
||||||
|
case 'user_verify' : user_verify(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function user_verify() {
|
||||||
|
|
||||||
|
// Тарифы, которые включают покрытие НУ (Средства размещения)
|
||||||
|
// Только в колонке tariff_code_basic
|
||||||
|
$valid_tariffs_basic = [
|
||||||
|
'STB0027', 'STB0028', 'STB0034', 'STB0037', 'STB0038', 'STB0045',
|
||||||
|
'SPP1023', 'SPP1024', 'SPP1025',
|
||||||
|
'STA1011', 'STA1012',
|
||||||
|
'STB1088', 'STB1089', 'STB1091', 'STB1092', 'STB1100',
|
||||||
|
'STB2088', 'STB2089', 'STB2091', 'STB2092',
|
||||||
|
'OPT1025', 'OPT1026', 'OPT1029', 'OPT1030', 'OPT1032', 'OPT1033', 'OPT1036', 'OPT1037',
|
||||||
|
'OPT2025', 'OPT2026', 'OPT2032', 'OPT2033',
|
||||||
|
'AQS00500', 'AQS60500', 'AQS01500', 'AQS61500', 'AQS02500', 'AQS62500'
|
||||||
|
];
|
||||||
|
|
||||||
|
$link = mysqli_connect("localhost", "ci20465_erv", "c7vOXbmG", "ci20465_erv");
|
||||||
|
|
||||||
|
if (!$link) {
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "false",
|
||||||
|
"message" => "Ошибка подключения к базе данных",
|
||||||
|
"result" => ""
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mysqli_set_charset($link, "utf8");
|
||||||
|
|
||||||
|
$inn = isset($_POST['inn']) ? trim($_POST['inn']) : '';
|
||||||
|
|
||||||
|
if (empty($inn)) {
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "false",
|
||||||
|
"message" => "Номер полиса не указан",
|
||||||
|
"result" => ""
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Экранируем для безопасности
|
||||||
|
$inn_escaped = mysqli_real_escape_string($link, $inn);
|
||||||
|
|
||||||
|
// Ищем полис по номеру voucher
|
||||||
|
$sql = "SELECT * FROM lexrpiority WHERE voucher = '$inn_escaped' LIMIT 1";
|
||||||
|
$result = mysqli_query($link, $sql);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "false",
|
||||||
|
"message" => "Ошибка запроса к базе данных",
|
||||||
|
"result" => ""
|
||||||
|
]);
|
||||||
|
mysqli_close($link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = mysqli_fetch_assoc($result);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
// Полис не найден в базе
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "false",
|
||||||
|
"message" => "Полис не найден",
|
||||||
|
"result" => ""
|
||||||
|
]);
|
||||||
|
mysqli_close($link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Полис найден, проверяем тариф
|
||||||
|
$tariff_basic = isset($row['tariff_code_basic']) ? trim($row['tariff_code_basic']) : '';
|
||||||
|
|
||||||
|
$has_valid_tariff = in_array($tariff_basic, $valid_tariffs_basic);
|
||||||
|
|
||||||
|
if ($has_valid_tariff) {
|
||||||
|
// Полис найден и тариф подходит
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "true",
|
||||||
|
"message" => "Полис найден",
|
||||||
|
"result" => $row
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// Полис найден, но тариф не включает покрытие НУ
|
||||||
|
echo json_encode([
|
||||||
|
"success" => "false",
|
||||||
|
"message" => "Ваш полис не включает покрытие неудовлетворительных условий размещения",
|
||||||
|
"result" => ""
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysqli_close($link);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
59
database_old.php
Normal file
59
database_old.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
// Имя ДБ: turistpr_erv
|
||||||
|
// Пользователь: turistpr_erv
|
||||||
|
// Пароль: c7vOXbmG
|
||||||
|
// Адрес хоста: 141.8.194.131
|
||||||
|
// таблица lexrpiority
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(isset($_POST['action']) && !empty($_POST['action'])) {
|
||||||
|
$action = $_POST['action'];
|
||||||
|
switch($action) {
|
||||||
|
case 'user_verify' : user_verify(); break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function user_verify() {
|
||||||
|
|
||||||
|
$finded_row['success']="false";
|
||||||
|
|
||||||
|
|
||||||
|
//$link = mysqli_connect("141.8.194.131", "turistpr_erv", "c7vOXbmG");
|
||||||
|
$link = mysqli_connect("localhost", "ci20465_erv", "c7vOXbmG");
|
||||||
|
|
||||||
|
if ($link == false){
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$birthday = $_POST['birthday'];
|
||||||
|
$inn = $_POST['inn'];
|
||||||
|
//$sql = "SELECT * FROM turistpr_erv.lexrpiority";
|
||||||
|
$sql = "SELECT * FROM ci20465_erv.lexrpiority";
|
||||||
|
$result = mysqli_query($link, $sql);
|
||||||
|
|
||||||
|
$finded_row=array("success"=>"false","message"=>"Полис не найден", "result" => "");
|
||||||
|
|
||||||
|
if($inn) {
|
||||||
|
while ($row = mysqli_fetch_assoc($result)) {
|
||||||
|
if($inn==$row['voucher']) {
|
||||||
|
$finded_row['success']="true";
|
||||||
|
$finded_row['message']="Полис найден";
|
||||||
|
$finded_row['result']=$row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo json_encode($finded_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
129
database_php_returns.md
Normal file
129
database_php_returns.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Что возвращает database.php и что используется
|
||||||
|
|
||||||
|
## SQL запрос
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT * FROM lexrpiority WHERE voucher = '...' LIMIT 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Возвращает ВСЕ поля строки** из таблицы `lexrpiority`.
|
||||||
|
|
||||||
|
## Что используется в PHP скрипте
|
||||||
|
|
||||||
|
После получения строки из БД (`$row = mysqli_fetch_assoc($result)`), скрипт использует:
|
||||||
|
|
||||||
|
1. **`tariff_code_basic`** - для проверки валидности тарифа
|
||||||
|
2. **`tariff_code_other`** - для проверки валидности тарифа
|
||||||
|
|
||||||
|
## Что возвращается в JSON ответе
|
||||||
|
|
||||||
|
### При успехе (полис найден и валиден):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": "true",
|
||||||
|
"message": "Полис найден",
|
||||||
|
"result": {
|
||||||
|
// ВСЯ строка из БД (все поля таблицы lexrpiority)
|
||||||
|
"id": "35927",
|
||||||
|
"row_no": "893",
|
||||||
|
"agent_code": "E50208",
|
||||||
|
"voucher": "E50208-306083026",
|
||||||
|
"insured_name": "SHAROV IURII",
|
||||||
|
"insured_birth": "10.05.1974",
|
||||||
|
"insured_gender": "U",
|
||||||
|
"status": "NV",
|
||||||
|
"insured_counter": "1",
|
||||||
|
"issued_on": "17.11.2025",
|
||||||
|
"insured_from": "19.11.2025", // ⭐ ИСПОЛЬЗУЕТСЯ на фронтенде
|
||||||
|
"insured_to": "24.11.2025", // ⭐ ИСПОЛЬЗУЕТСЯ на фронтенде
|
||||||
|
"insured_days": "6",
|
||||||
|
"destination": "GEO",
|
||||||
|
"productvariant_code": "10223",
|
||||||
|
"tariff_code_basic": "STB2003",
|
||||||
|
"tariff_code_sport": "",
|
||||||
|
"tariff_code_cancel": "",
|
||||||
|
"tariff_code_other": "SPV2002", // ⭐ ИСПОЛЬЗУЕТСЯ для проверки
|
||||||
|
"premium_cur_basic": "12,48",
|
||||||
|
"premium_cur_sport": "",
|
||||||
|
"premium_cur_cancel": "",
|
||||||
|
"premium_cur_other": "13",
|
||||||
|
"premium_cur": "25,48",
|
||||||
|
"premium_loc": "2067,13",
|
||||||
|
// ... и другие поля
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### При ошибке (полис не найден или не валиден):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": "false",
|
||||||
|
"message": "Полис не найден" или "Ваш полис не включает покрытие задержки рейса",
|
||||||
|
"result": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что используется на фронтенде (JavaScript)
|
||||||
|
|
||||||
|
В `ticket_dev/js/common.js` строки 1227-1228:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Автозаполнение дат из результата проверки полиса
|
||||||
|
$('input[name=insured_from]').val(res.result.insured_from.replace(/\./g, '-'));
|
||||||
|
$('input[name=insured_to]').val(res.result.insured_to.replace(/\./g, '-'));
|
||||||
|
```
|
||||||
|
|
||||||
|
**Используются только 2 поля:**
|
||||||
|
- `result.insured_from` - дата начала действия полиса
|
||||||
|
- `result.insured_to` - дата окончания действия полиса
|
||||||
|
|
||||||
|
## Вывод для вебхука n8n
|
||||||
|
|
||||||
|
Для вебхука нужно возвращать:
|
||||||
|
|
||||||
|
### Минимально необходимое:
|
||||||
|
- `found: 1/0` - для IF Node в n8n
|
||||||
|
- `success: true/false` - для совместимости с PHP
|
||||||
|
- `message` - текстовое сообщение
|
||||||
|
|
||||||
|
### Желательно (для автозаполнения на фронтенде):
|
||||||
|
- `result.insured_from` - дата начала полиса
|
||||||
|
- `result.insured_to` - дата окончания полиса
|
||||||
|
|
||||||
|
### Опционально (для дополнительной информации):
|
||||||
|
- Остальные поля из таблицы `lexrpiority` (если нужны для логирования/аналитики)
|
||||||
|
|
||||||
|
## Рекомендуемый формат ответа вебхука
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"found": 1,
|
||||||
|
"message": "Полис найден",
|
||||||
|
"result": {
|
||||||
|
"insured_from": "19.11.2025",
|
||||||
|
"insured_to": "24.11.2025",
|
||||||
|
"voucher": "E50208-306083026",
|
||||||
|
"insured_name": "SHAROV IURII",
|
||||||
|
"tariff_code_basic": "STB2003",
|
||||||
|
"tariff_code_other": "SPV2002"
|
||||||
|
// Можно добавить другие поля, если нужны
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Или минимальный вариант (если не нужны данные для автозаполнения):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"found": 1,
|
||||||
|
"message": "Полис найден",
|
||||||
|
"result": {
|
||||||
|
"insured_from": "19.11.2025",
|
||||||
|
"insured_to": "24.11.2025"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
114
debug_client_data.php
Normal file
114
debug_client_data.php
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
// Отладочный скрипт для проверки данных клиента
|
||||||
|
// Файл: debug_client_data.php
|
||||||
|
|
||||||
|
echo "<h2>Отладка данных клиента</h2>";
|
||||||
|
echo "<p><strong>Время:</strong> " . date('Y-m-d H:i:s') . "</p>";
|
||||||
|
echo "<hr>";
|
||||||
|
|
||||||
|
// Формируем данные точно как в рабочем скрипте
|
||||||
|
$appends = [
|
||||||
|
'{"ws_type":"client","ws_name":"lastname","field_val":"Козлова"}',
|
||||||
|
'{"ws_type":"client","ws_name":"firstname","field_val":"Александра"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mobile","field_val":"921 862-69-44"}',
|
||||||
|
'{"ws_type":"client","ws_name":"email","field_val":"sashyliakoz@gmail.com"}',
|
||||||
|
'{"ws_type":"client","ws_name":"birthday","field_val":"04-09-1996"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mailingstreet","field_val":"Индекс 188300, Ленинградская область, г. Гатчина, ул. Изотова, д.12, к.2, кв. 38"}',
|
||||||
|
'{"ws_type":"client","ws_name":"inn","field_val":"470519373754"}',
|
||||||
|
'{"ws_type":"ticket","ws_name":"ticket1","field_val":"Отсутствие вида, заявленного и оплаченного в бронировании"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1187","field_val":"ЕРВ Средства размещения"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1590","field_val":"195.175.85.146"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_2296","field_val":"1"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1592","field_val":"Мугла"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1582","field_val":"15-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1584","field_val":"25-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1740","field_val":"E1000-302542604"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1157","field_val":"Алексеевна"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1869","field_val":"Козлова Александра Алексеевна"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1265","field_val":"СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1267","field_val":"044030653"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1271","field_val":"30101810500000000653"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1269","field_val":"40817810755868418791"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1273","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1163","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1161","field_val":"Prime beach hotel"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1165","field_val":"Cumhuriyet Bulv. No 35 Siteler Marmaris / Muğla / Türkiye"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1167","field_val":"info@primebeachhotel.com"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1560","field_val":"0252 417 52 00"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1558","field_val":"https://primebeachhotel.com"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1173","field_val":"16-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1726","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1728","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1730","field_val":"on"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1732","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1734","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1736","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1257","field_val":"470519373754"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1800","field_val":"21"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1802","field_val":"4116"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1804","field_val":"786084"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1798","field_val":"643"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_2000","field_val":"ТУРЦИЯ"}',
|
||||||
|
'{"ws_type":"project","ws_name":"description","field_val":"Заселили в отель 16.09.2025. В ваучере (путевке)указан номер sea view, но при заезде разместили в номере без вида на море. \\nПункт 40.2.1 полиса "}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1738","field_val":"on"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1706","field_val":"105540"}'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<h3>1. Исходные данные appends:</h3>";
|
||||||
|
echo "<pre>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
echo "[" . $key . "] " . $itemjson . "\n";
|
||||||
|
}
|
||||||
|
echo "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>2. Симуляция обработки в server_webservice2.php:</h3>";
|
||||||
|
|
||||||
|
// Симулируем код из server_webservice2.php
|
||||||
|
$client_array = array(
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => 'TEST_SESSION_ID',
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p><strong>Начальный client_array:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Обработка appends:</strong></p>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
$item = json_decode($itemjson);
|
||||||
|
echo "<p>[" . $key . "] ws_type: '" . $item->ws_type . "', ws_name: '" . $item->ws_name . "', field_val: '" . $item->field_val . "'</p>";
|
||||||
|
|
||||||
|
if ($item->ws_type == "client") {
|
||||||
|
$client_array[$item->ws_name] = $item->field_val;
|
||||||
|
echo "<p style='color: green;'>✅ Добавлено в client_array: " . $item->ws_name . " = " . $item->field_val . "</p>";
|
||||||
|
if ($item->ws_name == "code") $sms = $item->field_val;
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: gray;'>⏭️ Пропущено (ws_type != 'client')</p>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<h3>3. Итоговый client_array для отправки в CRM:</h3>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>4. Проверка обязательных полей:</h3>";
|
||||||
|
$required_fields = ['firstname', 'lastname', 'birthday', 'mobile', 'inn'];
|
||||||
|
$missing_fields = [];
|
||||||
|
|
||||||
|
foreach ($required_fields as $field) {
|
||||||
|
if (isset($client_array[$field]) && !empty($client_array[$field])) {
|
||||||
|
echo "<p style='color: green;'>✅ " . $field . ": '" . $client_array[$field] . "'</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ " . $field . ": ОТСУТСТВУЕТ</p>";
|
||||||
|
$missing_fields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($missing_fields)) {
|
||||||
|
echo "<p style='color: green; font-weight: bold;'>✅ Все обязательные поля присутствуют!</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red; font-weight: bold;'>❌ Отсутствуют поля: " . implode(', ', $missing_fields) . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>5. JSON для отправки:</h3>";
|
||||||
|
echo "<pre>" . json_encode($client_array, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
?>
|
||||||
193
debug_crm_responses.php
Normal file
193
debug_crm_responses.php
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<?php
|
||||||
|
// Скрипт для отладки ответов от CRM
|
||||||
|
// Файл: debug_crm_responses.php
|
||||||
|
|
||||||
|
echo "<h2>🔍 ОТЛАДКА ОТВЕТОВ ОТ CRM</h2>";
|
||||||
|
echo "<p><strong>Время:</strong> " . date('Y-m-d H:i:s') . "</p>";
|
||||||
|
echo "<hr>";
|
||||||
|
|
||||||
|
// Тестируем создание клиента напрямую
|
||||||
|
echo "<h3>1. Тест создания клиента напрямую в CRM:</h3>";
|
||||||
|
|
||||||
|
$client_data = [
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => 'TEST_SESSION', // Будет заменен реальным
|
||||||
|
'firstname' => 'Александра',
|
||||||
|
'secondname' => 'Алексеевна',
|
||||||
|
'lastname' => 'Козлова',
|
||||||
|
'mobile' => '921 862-69-44',
|
||||||
|
'email' => 'sashyliakoz@gmail.com',
|
||||||
|
'birthday' => '1996-09-04',
|
||||||
|
'mailingstreet' => 'Индекс 188300, Ленинградская область, г. Гатчина, ул. Изотова, д.12, к.2, кв. 38',
|
||||||
|
'inn' => '470519373754',
|
||||||
|
'code' => '1'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<p><strong>Данные клиента:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($client_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
// Сначала получаем sessionName
|
||||||
|
echo "<h3>2. Получение sessionName:</h3>";
|
||||||
|
|
||||||
|
$challenge_data = [
|
||||||
|
'operation' => 'getchallenge',
|
||||||
|
'username' => 'api'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<p><strong>Данные getchallenge:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($challenge_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
$url = 'https://crm.clientright.ru/webservice.php?operation=getchallenge&username=api';
|
||||||
|
echo "<p><strong>URL getchallenge:</strong> " . $url . "</p>";
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => 2,
|
||||||
|
CURLOPT_TIMEOUT => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
$challenge_response = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>Ответ getchallenge:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($challenge_response) . "</pre>";
|
||||||
|
|
||||||
|
$challenge_result = json_decode($challenge_response, true);
|
||||||
|
if ($challenge_result && isset($challenge_result['result']['token'])) {
|
||||||
|
$token = $challenge_result['result']['token'];
|
||||||
|
echo "<p style='color: green;'>✅ Получен token: " . substr($token, 0, 20) . "...</p>";
|
||||||
|
|
||||||
|
// Логинимся
|
||||||
|
echo "<h3>3. Авторизация:</h3>";
|
||||||
|
|
||||||
|
$generatedKey = md5($token . '4r9ANex8PT2IuRV');
|
||||||
|
$login_data = [
|
||||||
|
'operation' => 'login',
|
||||||
|
'username' => 'api',
|
||||||
|
'accessKey' => $generatedKey
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<p><strong>Данные login:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($login_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
echo "<p><strong>Сгенерированный ключ:</strong> " . $generatedKey . "</p>";
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $login_data,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_TIMEOUT => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
$login_response = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>Ответ login:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($login_response) . "</pre>";
|
||||||
|
|
||||||
|
$login_result = json_decode($login_response, true);
|
||||||
|
if ($login_result && isset($login_result['result']['sessionName'])) {
|
||||||
|
$sessionName = $login_result['result']['sessionName'];
|
||||||
|
echo "<p style='color: green;'>✅ Получен sessionName: " . $sessionName . "</p>";
|
||||||
|
|
||||||
|
// Теперь тестируем создание клиента
|
||||||
|
echo "<h3>4. Тест создания клиента:</h3>";
|
||||||
|
|
||||||
|
$client_data['sessionName'] = $sessionName;
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $client_data,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_TIMEOUT => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
$client_response = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>Ответ CreateContact:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($client_response) . "</pre>";
|
||||||
|
|
||||||
|
$client_result = json_decode($client_response, true);
|
||||||
|
if ($client_result) {
|
||||||
|
if (isset($client_result['result'])) {
|
||||||
|
echo "<p style='color: green;'>✅ Клиент создан с ID: " . $client_result['result'] . "</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ Ошибка создания клиента:</p>";
|
||||||
|
echo "<pre>" . json_encode($client_result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Тестируем создание контрагента
|
||||||
|
echo "<h3>5. Тест создания контрагента:</h3>";
|
||||||
|
|
||||||
|
$contractor_data = [
|
||||||
|
'operation' => 'CreateAccount',
|
||||||
|
'sessionName' => $sessionName,
|
||||||
|
'inn' => '7714312079',
|
||||||
|
'ogrn' => '1037714037426',
|
||||||
|
'accountname' => 'Филиал ООО РСО ЕВРОИНС Туристическое',
|
||||||
|
'address' => '119049 Москва, 4-й Добрынинский пер., д.8, помещ. С 14-I, ком. 21-26',
|
||||||
|
'email' => 'info@erv.ru',
|
||||||
|
'phone' => '84956265800',
|
||||||
|
'website' => 'https://www.erv.ru/'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<p><strong>Данные контрагента:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($contractor_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/webservice.php',
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $contractor_data,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_TIMEOUT => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
$contractor_response = curl_exec($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>Ответ CreateAccount:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($contractor_response) . "</pre>";
|
||||||
|
|
||||||
|
$contractor_result = json_decode($contractor_response, true);
|
||||||
|
if ($contractor_result) {
|
||||||
|
if (isset($contractor_result['result'])) {
|
||||||
|
echo "<p style='color: green;'>✅ Контрагент создан с ID: " . $contractor_result['result'] . "</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ Ошибка создания контрагента:</p>";
|
||||||
|
echo "<pre>" . json_encode($contractor_result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ Не удалось получить sessionName</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ Не удалось получить token</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>6. Сравнение с успешным логом:</h3>";
|
||||||
|
echo "<p><strong>Успешный лог (2025-09-10):</strong></p>";
|
||||||
|
echo "<pre>";
|
||||||
|
echo '{"operation":"CreateContact","sessionName":"61c825a768c1dd749ca62","mobile":"7 (953) 167-38-19","lastname":"Кулагин ","firstname":"Андрей ","secondname":"Викторович ","mailingstreet":"Ленинградская обл...","birthday":"11-05-1967","birthplace":"г Ростов-на-Дону ","inn":"780700202965","requisites":"Реквизиты...","email":"kulaginandrey110567@gmail.com","code":"438138"}';
|
||||||
|
echo "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Наши данные:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($client_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<p><strong>Отладка завершена!</strong></p>";
|
||||||
|
?>
|
||||||
110
debug_exact_data.php
Normal file
110
debug_exact_data.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
// Отладочный скрипт для точного понимания данных
|
||||||
|
// Файл: debug_exact_data.php
|
||||||
|
|
||||||
|
echo "<h2>Точная отладка данных для CRM</h2>";
|
||||||
|
echo "<p><strong>Время:</strong> " . date('Y-m-d H:i:s') . "</p>";
|
||||||
|
echo "<hr>";
|
||||||
|
|
||||||
|
// Симулируем точно как в server_webservice2.php
|
||||||
|
$appends = [
|
||||||
|
'{"ws_type":"client","ws_name":"firstname","field_val":"Александра"}',
|
||||||
|
'{"ws_type":"client","ws_name":"cf_1157","field_val":"Алексеевна"}',
|
||||||
|
'{"ws_type":"client","ws_name":"lastname","field_val":"Козлова"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mobile","field_val":"921 862-69-44"}',
|
||||||
|
'{"ws_type":"client","ws_name":"email","field_val":"sashyliakoz@gmail.com"}',
|
||||||
|
'{"ws_type":"client","ws_name":"phone","field_val":""}',
|
||||||
|
'{"ws_type":"client","ws_name":"birthday","field_val":"04-09-1996"}',
|
||||||
|
'{"ws_type":"client","ws_name":"cf_1263","field_val":"г Гатчина"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mailingstreet","field_val":"Индекс 188300, Ленинградская область, г. Гатчина, ул. Изотова, д.12, к.2, кв. 38"}',
|
||||||
|
'{"ws_type":"client","ws_name":"cf_1257","field_val":"470519373754"}',
|
||||||
|
'{"ws_type":"client","ws_name":"cf_1580","field_val":"105540"}',
|
||||||
|
'{"ws_type":"client","ws_name":"assigned_user_id","field_val":"19x5"}'
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<h3>1. Исходные appends:</h3>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
echo "<p>[" . $key . "] " . $itemjson . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<h3>2. Симуляция кода из server_webservice2.php:</h3>";
|
||||||
|
|
||||||
|
// ТОЧНО как в server_webservice2.php строки 125-136
|
||||||
|
$client_array = array(
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => 'TEST_SESSION_ID',
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p><strong>Начальный client_array:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Обработка foreach:</strong></p>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
$item = json_decode($itemjson);
|
||||||
|
echo "<p>[" . $key . "] ws_type: '" . $item->ws_type . "', ws_name: '" . $item->ws_name . "', field_val: '" . $item->field_val . "'</p>";
|
||||||
|
|
||||||
|
if ($item->ws_type == "client") {
|
||||||
|
$client_array[$item->ws_name] = $item->field_val;
|
||||||
|
echo "<p style='color: green;'>✅ Добавлено: " . $item->ws_name . " = '" . $item->field_val . "'</p>";
|
||||||
|
if ($item->ws_name == "code") $sms = $item->field_val;
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: gray;'>⏭️ Пропущено (ws_type != 'client')</p>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<h3>3. Итоговый client_array для отправки в CRM:</h3>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>4. JSON для отправки в CRM:</h3>";
|
||||||
|
echo "<pre>" . json_encode($client_array, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>5. Проверка обязательных полей:</h3>";
|
||||||
|
$required_fields = ['firstname', 'lastname', 'birthday', 'mobile', 'inn'];
|
||||||
|
$missing_fields = [];
|
||||||
|
|
||||||
|
foreach ($required_fields as $field) {
|
||||||
|
if (isset($client_array[$field]) && !empty($client_array[$field])) {
|
||||||
|
echo "<p style='color: green;'>✅ " . $field . ": '" . $client_array[$field] . "'</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ " . $field . ": ОТСУТСТВУЕТ</p>";
|
||||||
|
$missing_fields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($missing_fields)) {
|
||||||
|
echo "<p style='color: green; font-weight: bold;'>✅ Все обязательные поля присутствуют!</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red; font-weight: bold;'>❌ Отсутствуют поля: " . implode(', ', $missing_fields) . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>6. Сравнение с успешным логом:</h3>";
|
||||||
|
echo "<p><strong>Успешный лог (2025-09-10):</strong></p>";
|
||||||
|
echo "<pre>";
|
||||||
|
echo '{
|
||||||
|
"firstname": "Андрей ",
|
||||||
|
"cf_1157": "Викторович ",
|
||||||
|
"lastname": "Кулагин ",
|
||||||
|
"mobile": "79531673819",
|
||||||
|
"email": "kulaginandrey110567@gmail.com",
|
||||||
|
"phone": "",
|
||||||
|
"birthday": "11-05-1967",
|
||||||
|
"cf_1263": "г Ростов-на-Дону ",
|
||||||
|
"mailingstreet": "Ленинградская обл, Выборгский р-н, поселок Пушное, ул Спортивная, д 6, кв 19",
|
||||||
|
"cf_1257": "780700202965",
|
||||||
|
"cf_1580": "438138",
|
||||||
|
"assigned_user_id": "19x5"
|
||||||
|
}';
|
||||||
|
echo "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Наш массив:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($client_array, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>7. Возможные проблемы:</h3>";
|
||||||
|
echo "<ul>";
|
||||||
|
echo "<li>❓ Возможно, поле ИНН должно называться не 'cf_1257', а 'inn'</li>";
|
||||||
|
echo "<li>❓ Возможно, есть проблема с кодировкой</li>";
|
||||||
|
echo "<li>❓ Возможно, CRM ожидает другие имена полей</li>";
|
||||||
|
echo "</ul>";
|
||||||
|
?>
|
||||||
128
debug_send.php
Normal file
128
debug_send.php
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
// Отладочный скрипт для проверки данных
|
||||||
|
|
||||||
|
echo "<h2>Отладка отправки данных</h2>";
|
||||||
|
|
||||||
|
// Формируем данные точно как в оригинальном JavaScript коде
|
||||||
|
$appends = [
|
||||||
|
'{"crm_name":"lastname","field_val":"Козлова"}',
|
||||||
|
'{"crm_name":"cf_1187","field_val":"ЕРВ Средства размещения"}',
|
||||||
|
'{"crm_name":"cf_1590","field_val":"195.175.85.146"}',
|
||||||
|
'{"crm_name":"cf_2296","field_val":"1"}',
|
||||||
|
'{"crm_name":"cf_1592","field_val":"Мугла"}',
|
||||||
|
'{"crm_name":"cf_1582","field_val":"15-09-2025"}',
|
||||||
|
'{"crm_name":"cf_1584","field_val":"25-09-2025"}',
|
||||||
|
'{"crm_name":"mobile","field_val":"921 862-69-44"}',
|
||||||
|
'{"crm_name":"cf_1740","field_val":"E1000-302542604"}',
|
||||||
|
'{"crm_name":"firstname","field_val":"Александра"}',
|
||||||
|
'{"crm_name":"cf_1157","field_val":"Алексеевна"}',
|
||||||
|
'{"crm_name":"birthday","field_val":"04-09-1996"}',
|
||||||
|
'{"crm_name":"cf_1869","field_val":"Козлова Александра Алексеевна"}',
|
||||||
|
'{"crm_name":"cf_1265","field_val":"СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК"}',
|
||||||
|
'{"crm_name":"cf_1267","field_val":"044030653"}',
|
||||||
|
'{"crm_name":"cf_1271","field_val":"30101810500000000653"}',
|
||||||
|
'{"crm_name":"cf_1269","field_val":"40817810755868418791"}',
|
||||||
|
'{"crm_name":"cf_1273","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1163","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1161","field_val":"Prime beach hotel"}',
|
||||||
|
'{"crm_name":"cf_1165","field_val":"Cumhuriyet Bulv. No 35 Siteler Marmaris / Muğla / Türkiye"}',
|
||||||
|
'{"crm_name":"cf_1167","field_val":"info@primebeachhotel.com"}',
|
||||||
|
'{"crm_name":"cf_1560","field_val":"0252 417 52 00"}',
|
||||||
|
'{"crm_name":"cf_1558","field_val":"https://primebeachhotel.com"}',
|
||||||
|
'{"crm_name":"cf_1173","field_val":"16-09-2025"}',
|
||||||
|
'{"crm_name":"cf_1726","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1728","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1730","field_val":"on"}',
|
||||||
|
'{"crm_name":"cf_1732","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1734","field_val":""}',
|
||||||
|
'{"crm_name":"cf_1736","field_val":""}',
|
||||||
|
'{"crm_name":"mailingstreet","field_val":"Индекс 188300, Ленинградская область, г. Гатчина, ул. Изотова, д.12, к.2, кв. 38"}',
|
||||||
|
'{"crm_name":"cf_1257","field_val":"470519373754"}',
|
||||||
|
'{"crm_name":"cf_1800","field_val":"21"}',
|
||||||
|
'{"crm_name":"cf_1802","field_val":"4116"}',
|
||||||
|
'{"crm_name":"cf_1804","field_val":"786084"}',
|
||||||
|
'{"crm_name":"cf_1798","field_val":"643"}',
|
||||||
|
'{"crm_name":"cf_2000","field_val":"ТУРЦИЯ"}',
|
||||||
|
'{"crm_name":"email","field_val":"sashyliakoz@gmail.com"}',
|
||||||
|
'{"crm_name":"description","field_val":"Заселили в отель 16.09.2025. В ваучере (путевке)указан номер sea view, но при заезде разместили в номере без вида на море. \\nПункт 40.2.1 полиса "}',
|
||||||
|
'{"crm_name":"cf_1738","field_val":"on"}',
|
||||||
|
'{"crm_name":"cf_1706","field_val":"105540"}'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Данные для отправки
|
||||||
|
$data = [
|
||||||
|
'appends' => $appends,
|
||||||
|
'lastname' => 'Козлова',
|
||||||
|
'sub_dir' => session_id(),
|
||||||
|
'upload_urls' => [],
|
||||||
|
'upload_urls_real' => [],
|
||||||
|
'files_names' => [],
|
||||||
|
'docs_names' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<h3>1. Данные которые мы отправляем:</h3>";
|
||||||
|
echo "<pre>" . print_r($data, true) . "</pre>";
|
||||||
|
|
||||||
|
// Симулируем обработку как в server_new.php
|
||||||
|
echo "<h3>2. Симуляция обработки в server_new.php:</h3>";
|
||||||
|
|
||||||
|
$new_post = array(
|
||||||
|
'__vtrftk' => 'sid:ec649134ad232e44c3ad71bbd321cee986f05545,1688385374',
|
||||||
|
'publicid' => '3ddc71c2d79ef101c09b0d4e9c6bd08b',
|
||||||
|
'urlencodeenable' => '1',
|
||||||
|
'name' => 'websiteticket',
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p>Начальный массив new_post:</p>";
|
||||||
|
echo "<pre>" . print_r($new_post, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<p>Обрабатываем appends:</p>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
$item = json_decode($itemjson);
|
||||||
|
echo "<p>Обрабатываем: " . htmlspecialchars($itemjson) . "</p>";
|
||||||
|
echo "<p>crm_name: " . $item->crm_name . ", field_val: " . $item->field_val . "</p>";
|
||||||
|
$new_post[$item->crm_name] = $item->field_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<p>Итоговый массив new_post для отправки в CRM:</p>";
|
||||||
|
echo "<pre>" . print_r($new_post, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>3. Проверяем наличие lastname:</h3>";
|
||||||
|
if (isset($new_post['lastname'])) {
|
||||||
|
echo "<p style='color: green;'>✅ lastname найден: " . $new_post['lastname'] . "</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red;'>❌ lastname НЕ найден!</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<h3>4. Тест отправки в CRM:</h3>";
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => 'https://crm.clientright.ru/modules/Webforms/capture.php',
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $new_post,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_TIMEOUT => 30
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||||
|
$error = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>HTTP код:</strong> " . $httpCode . "</p>";
|
||||||
|
echo "<p><strong>Ответ CRM:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($response) . "</pre>";
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
echo "<p style='color: red;'><strong>Ошибка cURL:</strong> " . $error . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверим JSON ответ
|
||||||
|
$response_data = json_decode($response, true);
|
||||||
|
if ($response_data) {
|
||||||
|
echo "<p><strong>Расшифрованный ответ:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($response_data, true) . "</pre>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
218
debug_webservice2_flow.php
Normal file
218
debug_webservice2_flow.php
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
// Отладочный скрипт для проверки потока данных в server_webservice2.php
|
||||||
|
// Файл: debug_webservice2_flow.php
|
||||||
|
|
||||||
|
echo "<h2>Отладка потока данных в server_webservice2.php</h2>";
|
||||||
|
echo "<p><strong>Время:</strong> " . date('Y-m-d H:i:s') . "</p>";
|
||||||
|
echo "<hr>";
|
||||||
|
|
||||||
|
// Формируем данные точно как в последнем скрипте
|
||||||
|
$appends = [
|
||||||
|
// Поля клиента
|
||||||
|
'{"ws_type":"client","ws_name":"firstname","field_val":"Александра"}',
|
||||||
|
'{"ws_type":"client","ws_name":"secondname","field_val":"Алексеевна"}',
|
||||||
|
'{"ws_type":"client","ws_name":"lastname","field_val":"Козлова"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mobile","field_val":"921 862-69-44"}',
|
||||||
|
'{"ws_type":"client","ws_name":"email","field_val":"sashyliakoz@gmail.com"}',
|
||||||
|
'{"ws_type":"client","ws_name":"birthday","field_val":"1996-09-04"}',
|
||||||
|
'{"ws_type":"client","ws_name":"mailingstreet","field_val":"Индекс 188300, Ленинградская область, г. Гатчина, ул. Изотова, д.12, к.2, кв. 38"}',
|
||||||
|
'{"ws_type":"client","ws_name":"inn","field_val":"470519373754"}',
|
||||||
|
'{"ws_type":"client","ws_name":"code","field_val":"1"}',
|
||||||
|
|
||||||
|
// Поля контрагента
|
||||||
|
'{"ws_type":"contractor","ws_name":"inn","field_val":"7714312079"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"ogrn","field_val":"1037714037426"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"accountname","field_val":"Филиал ООО РСО ЕВРОИНС Туристическое"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"address","field_val":"119049 Москва, 4-й Добрынинский пер., д.8, помещ. С 14-I, ком. 21-26"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"email","field_val":"info@erv.ru"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"phone","field_val":"84956265800"}',
|
||||||
|
'{"ws_type":"contractor","ws_name":"website","field_val":"https://www.erv.ru/"}',
|
||||||
|
|
||||||
|
// Тикеты
|
||||||
|
'{"ws_type":"ticket","ws_name":"ticket1","field_val":"Отсутствие вида, заявленного и оплаченного в бронировании"}',
|
||||||
|
|
||||||
|
// Поля проекта
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1187","field_val":"ЕРВ Средства размещения"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1590","field_val":"195.175.85.146"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_2296","field_val":"1"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1592","field_val":"Мугла"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1582","field_val":"15-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1584","field_val":"25-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1740","field_val":"E1000-302542604"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1157","field_val":"Алексеевна"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1869","field_val":"Козлова Александра Алексеевна"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1265","field_val":"СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1267","field_val":"044030653"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1271","field_val":"30101810500000000653"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1269","field_val":"40817810755868418791"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1273","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1163","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1161","field_val":"Prime beach hotel"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1165","field_val":"Cumhuriyet Bulv. No 35 Siteler Marmaris / Muğla / Türkiye"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1167","field_val":"info@primebeachhotel.com"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1560","field_val":"0252 417 52 00"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1558","field_val":"https://primebeachhotel.com"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1173","field_val":"16-09-2025"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1726","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1728","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1730","field_val":"on"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1732","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1734","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1736","field_val":""}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1257","field_val":"470519373754"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1800","field_val":"21"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1802","field_val":"4116"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1804","field_val":"786084"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1798","field_val":"643"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_2000","field_val":"ТУРЦИЯ"}',
|
||||||
|
'{"ws_type":"project","ws_name":"description","field_val":"Заселили в отель 16.09.2025. В ваучере (путевке)указан номер sea view, но при заезде разместили в номере без вида на море. \\nПункт 40.2.1 полиса "}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1738","field_val":"on"}',
|
||||||
|
'{"ws_type":"project","ws_name":"cf_1706","field_val":"105540"}'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Данные для отправки
|
||||||
|
$data = [
|
||||||
|
'appends' => $appends,
|
||||||
|
'lastname' => 'Козлова',
|
||||||
|
'sub_dir' => session_id(),
|
||||||
|
'upload_urls' => [],
|
||||||
|
'upload_urls_real' => [],
|
||||||
|
'files_names' => [],
|
||||||
|
'docs_names' => [],
|
||||||
|
'docs_ticket_files_ids' => [],
|
||||||
|
'getservice' => ''
|
||||||
|
];
|
||||||
|
|
||||||
|
echo "<h3>1. Что мы отправляем на server_webservice2.php:</h3>";
|
||||||
|
echo "<pre>" . print_r($data, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>2. Симуляция обработки в server_webservice2.php:</h3>";
|
||||||
|
|
||||||
|
// Симулируем код из server_webservice2.php
|
||||||
|
$client_array = array(
|
||||||
|
'operation' => 'CreateContact',
|
||||||
|
'sessionName' => 'TEST_SESSION_ID',
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p><strong>Начальный client_array:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Обработка appends для клиента:</strong></p>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
$item = json_decode($itemjson);
|
||||||
|
echo "<p>[" . $key . "] ws_type: '" . $item->ws_type . "', ws_name: '" . $item->ws_name . "', field_val: '" . $item->field_val . "'</p>";
|
||||||
|
|
||||||
|
if ($item->ws_type == "client") {
|
||||||
|
$client_array[$item->ws_name] = $item->field_val;
|
||||||
|
echo "<p style='color: green;'>✅ Добавлено в client_array: " . $item->ws_name . " = '" . $item->field_val . "'</p>";
|
||||||
|
if ($item->ws_name == "code") $sms = $item->field_val;
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: gray;'>⏭️ Пропущено (ws_type != 'client')</p>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<p><strong>Итоговый client_array для отправки в CRM:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($client_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>3. Симуляция обработки контрагента:</h3>";
|
||||||
|
$contractor_array = array(
|
||||||
|
'operation' => 'CreateAccount',
|
||||||
|
'sessionName' => 'TEST_SESSION_ID',
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p><strong>Начальный contractor_array:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($contractor_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Обработка appends для контрагента:</strong></p>";
|
||||||
|
foreach ($appends as $key => $itemjson) {
|
||||||
|
$item = json_decode($itemjson);
|
||||||
|
|
||||||
|
if ($item->ws_type == "contractor" && $item->field_val != "") {
|
||||||
|
$contractor_array[$item->ws_name] = $item->field_val;
|
||||||
|
echo "<p style='color: green;'>✅ Добавлено в contractor_array: " . $item->ws_name . " = '" . $item->field_val . "'</p>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<p><strong>Итоговый contractor_array для отправки в CRM:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($contractor_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>4. Симуляция обработки проекта:</h3>";
|
||||||
|
$project_array = array(
|
||||||
|
'operation' => 'CreateProject',
|
||||||
|
'sessionName' => 'TEST_SESSION_ID',
|
||||||
|
'contactid' => 'TEST_CLIENT_ID',
|
||||||
|
'offenderid' => 'TEST_CONTRACTOR_ID',
|
||||||
|
'agentid' => '',
|
||||||
|
'sms' => $sms ?? ''
|
||||||
|
);
|
||||||
|
|
||||||
|
echo "<p><strong>Начальный project_array:</strong></p>";
|
||||||
|
echo "<pre>" . print_r($project_array, true) . "</pre>";
|
||||||
|
|
||||||
|
echo "<h3>5. Теперь отправляем реальные данные на server_webservice2.php:</h3>";
|
||||||
|
|
||||||
|
// Отправляем данные
|
||||||
|
$curl = curl_init();
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => 'https://form.clientright.ru/server_webservice2.php',
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $data,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => false,
|
||||||
|
CURLOPT_TIMEOUT => 30,
|
||||||
|
CURLOPT_HTTPHEADER => [
|
||||||
|
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||||
|
$error = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
|
||||||
|
echo "<p><strong>HTTP код:</strong> " . $httpCode . "</p>";
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
echo "<p style='color: red;'><strong>Ошибка cURL:</strong> " . $error . "</p>";
|
||||||
|
} else {
|
||||||
|
echo "<p><strong>Ответ от server_webservice2.php:</strong></p>";
|
||||||
|
echo "<pre>" . htmlspecialchars($response) . "</pre>";
|
||||||
|
|
||||||
|
// Парсим ответ
|
||||||
|
$response_data = json_decode($response, true);
|
||||||
|
if ($response_data) {
|
||||||
|
echo "<h3>Результат:</h3>";
|
||||||
|
|
||||||
|
if (isset($response_data['status']) && $response_data['status'] === 'success') {
|
||||||
|
echo "<p style='color: green; font-weight: bold;'>✅ Статус: Успех!</p>";
|
||||||
|
|
||||||
|
if (isset($response_data['message'])) {
|
||||||
|
echo "<p style='color: green;'><strong>Сообщение:</strong> " . $response_data['message'] . "</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<p style='color: green; font-weight: bold;'>✅ Данные успешно отправлены в CRM!</p>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo "<p style='color: red; font-weight: bold;'>❌ Ошибка при отправке данных</p>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>6. Сравнение с успешным логом:</h3>";
|
||||||
|
echo "<p><strong>Успешный лог (2025-09-10):</strong></p>";
|
||||||
|
echo "<pre>";
|
||||||
|
echo '{"operation":"CreateContact","sessionName":"61c825a768c1dd749ca62","mobile":"7 (953) 167-38-19","lastname":"Кулагин ","firstname":"Андрей ","secondname":"Викторович ","mailingstreet":"Ленинградская обл...","birthday":"11-05-1967","birthplace":"г Ростов-на-Дону ","inn":"780700202965","requisites":"Реквизиты...","email":"kulaginandrey110567@gmail.com","code":"438138"}';
|
||||||
|
echo "</pre>";
|
||||||
|
|
||||||
|
echo "<p><strong>Наш client_array:</strong></p>";
|
||||||
|
echo "<pre>" . json_encode($client_array, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "</pre>";
|
||||||
|
|
||||||
|
echo "<hr>";
|
||||||
|
echo "<h3>7. Возможные проблемы:</h3>";
|
||||||
|
echo "<ul>";
|
||||||
|
echo "<li>❓ Возможно, server_webservice2.php не получает данные appends</li>";
|
||||||
|
echo "<li>❓ Возможно, есть проблема с декодированием JSON</li>";
|
||||||
|
echo "<li>❓ Возможно, поля не попадают в массивы из-за условий</li>";
|
||||||
|
echo "</ul>";
|
||||||
|
?>
|
||||||
21
ervws/.htaccess
Normal file
21
ervws/.htaccess
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header set Access-Control-Allow-Origin "*"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{HTTPS} off
|
||||||
|
RewriteCond %{HTTP:X-Forwarded-Proto} !https
|
||||||
|
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||||
|
Options -Indexes
|
||||||
|
php_value error_reporting "E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT"
|
||||||
|
php_flag short_open_tag off
|
||||||
|
php_flag display_errors on
|
||||||
|
php_flag log_errors on
|
||||||
|
php_value max_execution_time 0
|
||||||
|
php_value max_input_time 6000
|
||||||
|
php_value max_input_vars 150000
|
||||||
|
php_value max_file_uploads 100
|
||||||
|
php_value upload_max_filesize 400M
|
||||||
|
php_value post_max_size 410M
|
||||||
|
php_value default_socket_timeout 600
|
||||||
|
php_value memory_limit -1
|
||||||
67
ervws/css/custom.css
Normal file
67
ervws/css/custom.css
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
form {
|
||||||
|
width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #d1d1d1;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[haserror="yes"] {
|
||||||
|
border: 2px solid tomato !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.constant {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sum_removing {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: tomato;
|
||||||
|
}
|
||||||
|
|
||||||
|
.claim_additional {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tour-product,
|
||||||
|
#tour-accomodation,
|
||||||
|
#tour-transportation,
|
||||||
|
#tour-other {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete {
|
||||||
|
padding: 10px 10px 10px 10px;
|
||||||
|
border: 1px solid #f3f3f3;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete__item {
|
||||||
|
padding: 2px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete__item:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.country-select{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
604
ervws/css/main.css
Normal file
604
ervws/css/main.css
Normal file
@@ -0,0 +1,604 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "r-regular";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Regular.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Regular.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Regular.woff") format("woff"), url("../fonts/Roboto/Roboto-Regular.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-medium";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Medium.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Medium.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Medium.woff") format("woff"), url("../fonts/Roboto/Roboto-Medium.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-bold";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Bold.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Bold.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Bold.woff") format("woff"), url("../fonts/Roboto/Roboto-Bold.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-light";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-Light.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-Light.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-Light.woff") format("woff"), url("../fonts/Roboto/Roboto-Light.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "r-semibold";
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("../fonts/Roboto/Roboto-SemiBold.eot");
|
||||||
|
src: url("../fonts/Roboto/Roboto-SemiBold.eot?#iefix") format("embedded-opentype"), url("../fonts/Roboto/Roboto-SemiBold.woff") format("woff"), url("../fonts/Roboto/Roboto-SemiBold.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||||
|
* Copyright 2011-2018 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2018 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-viewport {
|
||||||
|
width: device-width;
|
||||||
|
}
|
||||||
|
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form{
|
||||||
|
padding-top: 100px;
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.form__title{
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.5;
|
||||||
|
max-width: 560px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
.form__title strong{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.form-item .form-item__label {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.55;
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
.form-item .form-item__sublabel {
|
||||||
|
/* font-family: r-light; */
|
||||||
|
margin-bottom: 25px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.55;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.form-item .form-item__sublabel a{
|
||||||
|
color: #ff8562;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.form-item .form-input, .form-item .t-datepicker{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.33;
|
||||||
|
width: 100%;
|
||||||
|
border: 0 none;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 0;
|
||||||
|
color: #000000;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
}
|
||||||
|
input::placeholder{
|
||||||
|
color: #ff000083;
|
||||||
|
}
|
||||||
|
.select-wrap{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.select-wrap:after{
|
||||||
|
content: ' ';
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 6px 5px 0 5px;
|
||||||
|
border-color: #000 transparent transparent transparent;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item .form-input--date{
|
||||||
|
background: url('../img/date.svg') no-repeat right 14px center;
|
||||||
|
background-size: 27px;
|
||||||
|
width: 245px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item .form-input::placeholder{
|
||||||
|
color:#7f7f7f4d;
|
||||||
|
}
|
||||||
|
.form-item .form-item__warning {}
|
||||||
|
|
||||||
|
|
||||||
|
.form-item .form-input--textarea{
|
||||||
|
height: 102px;
|
||||||
|
padding-top: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-step{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-step.active
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__warning{
|
||||||
|
background: #F95D51;
|
||||||
|
padding: 10px;
|
||||||
|
height: 70px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color:#fff;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
.t-check-in, .t-check-out, .t-datepicker{
|
||||||
|
float: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__action{
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.progress-row{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top:-25px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.progress-row .span-progress{
|
||||||
|
transform: translateY(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn{
|
||||||
|
height: 45px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
background: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color:#fff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-note {
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 1.55;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.form-note a{
|
||||||
|
color: #ff8562;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.btn span.icon{
|
||||||
|
width: 18px;
|
||||||
|
height: 16px;
|
||||||
|
position: relative;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn--next{
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.btn--next span.icon{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn--prev span.icon{
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.btn span.icon:after{
|
||||||
|
color:#fff;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: Arial,Helvetica,sans-serif;
|
||||||
|
}
|
||||||
|
.btn--next span.icon:after{
|
||||||
|
content: '→';
|
||||||
|
}
|
||||||
|
.btn--prev span.icon:after{
|
||||||
|
content: '←';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form-step__info{
|
||||||
|
font-family: 'r-regular',Arial,sans-serif;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.form-item input[type="file"]{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-item input[type="file"] +label {
|
||||||
|
height: 45px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
background: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color:#fff;
|
||||||
|
font-family: r-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iti{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-progress {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.span-progress .current {}
|
||||||
|
.span-progress .total {}
|
||||||
|
|
||||||
|
|
||||||
|
.datepicker__header{
|
||||||
|
background: #efefef !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item__warning{
|
||||||
|
color: red;
|
||||||
|
font-size: 13px;
|
||||||
|
display: block;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.datepicker__day.is-today,.qs-current{
|
||||||
|
background: #bdbdbd !important;
|
||||||
|
color:#fff !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item {}
|
||||||
|
.checkbox-item .form-checkbox {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label{
|
||||||
|
padding-left: 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:after{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 20px;
|
||||||
|
top: 0;
|
||||||
|
width: 20px;
|
||||||
|
border: 2px solid #000;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: 10px;
|
||||||
|
-webkit-transition: all 0.2s;
|
||||||
|
transition: all 0.2s;
|
||||||
|
opacity: .6;
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:before{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 20px;
|
||||||
|
top: 0;
|
||||||
|
width: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: 10px;
|
||||||
|
-webkit-transition: all 0.2s;
|
||||||
|
transition: all 0.2s;
|
||||||
|
opacity: .6;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
background: url('../img/check.svg') no-repeat center;
|
||||||
|
background-size: 13px;
|
||||||
|
}
|
||||||
|
.checkbox-item .form-checkbox + label:before{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item .form-checkbox:checked + label:before{
|
||||||
|
opacity: 1;
|
||||||
|
background: url('../img/check.svg') no-repeat center;
|
||||||
|
background-size: 13px;
|
||||||
|
}
|
||||||
|
.w-100{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.sms-action{
|
||||||
|
/* display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center; */
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.form-item .form-input--date{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.form__title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.form-item .form-input, .form-item .t-datepicker {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.disabled+label{
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
button[disabled=disabled], button:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-code-warning{
|
||||||
|
color: #88b56d;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.modal{
|
||||||
|
max-width: 400px !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
.modal h4.title{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.modal p{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.modal{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.loader-wrap{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(255,255,255,0.5);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1000;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
left: 0;
|
||||||
|
top:0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.loader::after,
|
||||||
|
.loader::before {
|
||||||
|
content: '';
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border: 2px solid rgb(182, 179, 179);
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
animation: rotationBreak 3s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
.loader::after {
|
||||||
|
border-color: #36353e;
|
||||||
|
animation-direction: alternate-reverse;
|
||||||
|
}
|
||||||
|
.loader-info{
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 20px;
|
||||||
|
color: #3d2626;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotationBreak {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-none{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-item{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.form-item__dropdown{
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
font-size: 13px;
|
||||||
|
box-shadow: 0 0 15px rgba(0,0,0,.05);
|
||||||
|
z-index: 123;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item input[type="file"] +label{
|
||||||
|
background: none;
|
||||||
|
color:#999999;
|
||||||
|
text-decoration: underline;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.fileList{
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.fileList li{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
border-bottom: 1px solid #f5f2f2;
|
||||||
|
}
|
||||||
|
.fileList li strong{
|
||||||
|
width: 70%;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.fileList li span{
|
||||||
|
width: 20%;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.fileList li .removefile{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: url('../img/close.svg') no-repeat center;
|
||||||
|
background-size: 10px;
|
||||||
|
}
|
||||||
|
.upload-action{
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.country-select{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.form-col{
|
||||||
|
width: 48%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-result{
|
||||||
|
color:#30cc11c2;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.js-result.danger{
|
||||||
|
color:#F95D51;
|
||||||
|
}
|
||||||
|
|
||||||
|
.suсcess-upload{
|
||||||
|
margin-bottom: 2px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-text{
|
||||||
|
margin-bottom: 30px;
|
||||||
|
margin-top: 30px;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
59
ervws/database.php
Normal file
59
ervws/database.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
// Имя ДБ: turistpr_erv
|
||||||
|
// Пользователь: turistpr_erv
|
||||||
|
// Пароль: c7vOXbmG
|
||||||
|
// Адрес хоста: 141.8.194.131
|
||||||
|
// таблица lexrpiority
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(isset($_POST['action']) && !empty($_POST['action'])) {
|
||||||
|
$action = $_POST['action'];
|
||||||
|
switch($action) {
|
||||||
|
case 'user_verify' : user_verify(); break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function user_verify() {
|
||||||
|
|
||||||
|
$finded_row['success']="false";
|
||||||
|
|
||||||
|
|
||||||
|
//$link = mysqli_connect("141.8.194.131", "turistpr_erv", "c7vOXbmG");
|
||||||
|
$link = mysqli_connect("localhost", "ci20465_erv", "c7vOXbmG");
|
||||||
|
|
||||||
|
if ($link == false){
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$birthday = $_POST['birthday'];
|
||||||
|
$inn = $_POST['inn'];
|
||||||
|
//$sql = "SELECT * FROM turistpr_erv.lexrpiority";
|
||||||
|
$sql = "SELECT * FROM ci20465_erv.lexrpiority";
|
||||||
|
$result = mysqli_query($link, $sql);
|
||||||
|
|
||||||
|
$finded_row=array("success"=>"false","message"=>"Полис не найден", "result" => "");
|
||||||
|
|
||||||
|
if($inn) {
|
||||||
|
while ($row = mysqli_fetch_assoc($result)) {
|
||||||
|
if($inn==$row['voucher']) {
|
||||||
|
$finded_row['success']="true";
|
||||||
|
$finded_row['message']="Полис найден";
|
||||||
|
$finded_row['result']=$row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo json_encode($finded_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
64
ervws/file-server.php
Normal file
64
ervws/file-server.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$input_name = 'file';
|
||||||
|
|
||||||
|
$allow = array();
|
||||||
|
|
||||||
|
$deny = array(
|
||||||
|
'phtml', 'php', 'php3', 'php4', 'php5', 'php6', 'php7', 'phps', 'cgi', 'pl', 'asp',
|
||||||
|
'aspx', 'shtml', 'shtm', 'htaccess', 'htpasswd', 'ini', 'log', 'sh', 'js', 'html',
|
||||||
|
'htm', 'css', 'sql', 'spl', 'scgi', 'fcgi', 'exe'
|
||||||
|
);
|
||||||
|
|
||||||
|
$path = __DIR__ . '/uploads/';
|
||||||
|
|
||||||
|
|
||||||
|
$error = $success = '';
|
||||||
|
if (!isset($_FILES[$input_name])) {
|
||||||
|
$error = 'Файл не загружен.';
|
||||||
|
} else {
|
||||||
|
$file = $_FILES[$input_name];
|
||||||
|
|
||||||
|
if (!empty($file['error']) || empty($file['tmp_name'])) {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
} elseif ($file['tmp_name'] == 'none' || !is_uploaded_file($file['tmp_name'])) {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
} else {
|
||||||
|
$pattern = "[^a-zа-яё0-9,~!@#%^-_\$\?\(\)\{\}\[\]\.]";
|
||||||
|
$name = mb_eregi_replace($pattern, '-', $file['name']);
|
||||||
|
$name = mb_ereg_replace('[-]+', '-', $name);
|
||||||
|
$parts = pathinfo($name);
|
||||||
|
|
||||||
|
if (empty($name) || empty($parts['extension'])) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} elseif (!empty($allow) && !in_array(strtolower($parts['extension']), $allow)) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} elseif (!empty($deny) && in_array(strtolower($parts['extension']), $deny)) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} else {
|
||||||
|
if (move_uploaded_file($file['tmp_name'], $path . $name)) {
|
||||||
|
$fullpath = $_SERVER['HTTP_REFERER']. '/uploads/' . $name;
|
||||||
|
exec("convert uploads/".$name." uploads/".$name.'_'.date('m-d-Y-H-i-s').".pdf");
|
||||||
|
$success = '<p style="color: green">Файл «' . $name . '» успешно загружен.</p><a href="'.$fullpath.'">Скачать</a>';
|
||||||
|
} else {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($error)) {
|
||||||
|
$error = '<p style="color: red">' . $error . '</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'error' => $error,
|
||||||
|
'success' => $success,
|
||||||
|
);
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||||
|
exit();
|
||||||
|
|
||||||
|
//exec("convert banner.png banner.pdf");
|
||||||
|
|
||||||
114
ervws/fileupload.php
Normal file
114
ervws/fileupload.php
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$result=array("success"=>"false","message"=>"asdasd", "result" => "");
|
||||||
|
|
||||||
|
|
||||||
|
$lastname = str_replace(' ', '_',$_POST['lastname']);
|
||||||
|
$inputsArray = $_POST['files_names'];
|
||||||
|
$inputLabel = $_POST['docs_names'];
|
||||||
|
$pdf_page_counts=array();
|
||||||
|
$img_page_counts=0;
|
||||||
|
if($inputsArray) {
|
||||||
|
|
||||||
|
foreach($inputsArray as $index => $inputsArray_item) {
|
||||||
|
for($i=0;$i<10;$i++) {
|
||||||
|
if (!isset($_FILES[$inputsArray_item.'-'.$i])) {
|
||||||
|
$error = 'Файл не загружен.';
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$file = $_FILES[$inputsArray_item.'-'.$i];
|
||||||
|
$allow = array();
|
||||||
|
$deny = array(
|
||||||
|
'phtml', 'php', 'php3', 'php4', 'php5', 'php6', 'php7', 'phps', 'cgi', 'pl', 'asp',
|
||||||
|
'aspx', 'shtml', 'shtm', 'htaccess', 'htpasswd', 'ini', 'log', 'sh', 'js', 'html',
|
||||||
|
'htm', 'css', 'sql', 'spl', 'scgi', 'fcgi', 'exe'
|
||||||
|
);
|
||||||
|
$path = __DIR__ . '/uploads/';
|
||||||
|
$error = $success = '';
|
||||||
|
if (!empty($file['error']) || empty($file['tmp_name'])) {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
} elseif ($file['tmp_name'] == 'none' || !is_uploaded_file($file['tmp_name'])) {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
} else {
|
||||||
|
$pattern = "[^a-zа-яё0-9,~!@#%^-_\$\?\(\)\{\}\[\]\.]";
|
||||||
|
$name = mb_eregi_replace($pattern, '-', $file['name']);
|
||||||
|
$name = mb_ereg_replace('[-]+', '-', $name);
|
||||||
|
$parts = pathinfo($name);
|
||||||
|
if (empty($name) || empty($parts['extension'])) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} elseif (!empty($allow) && !in_array(strtolower($parts['extension']), $allow)) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} elseif (!empty($deny) && in_array(strtolower($parts['extension']), $deny)) {
|
||||||
|
$error = 'Недопустимый тип файла';
|
||||||
|
} else {
|
||||||
|
if (move_uploaded_file($file['tmp_name'], $path . $name)) {
|
||||||
|
$fullpath = $_SERVER['HTTP_REFERER']. '/uploads/' . $name;
|
||||||
|
if(strtolower($parts['extension']) != 'pdf') {
|
||||||
|
$oldfile = 'uploads/'.$name;
|
||||||
|
$name = trim(preg_replace('/\s*\([^)]*\)/', '', $name));
|
||||||
|
$newfile = 'uploads/'.$name.'_'.date('m-d-Y-H-i-s').'.pdf';
|
||||||
|
exec("convert ".$oldfile." ".$newfile." ");
|
||||||
|
$pdfFiles[] = $newfile;
|
||||||
|
$img_page_counts++;
|
||||||
|
} else {
|
||||||
|
$pdfFiles[] = 'uploads/' . $name; // 'uploads/'
|
||||||
|
$pdf_page_counts[]=get_pdf_count('uploads/'.$name);
|
||||||
|
}
|
||||||
|
//exec("convert uploads/".$name." uploads/".$name.'_'.date('m-d-Y-H-i-s').".pdf");
|
||||||
|
//$success = '<p style="color: green">Файл «' . $name . '» успешно загружен.</p><a href="'.$fullpath.'">Скачать</a>';
|
||||||
|
} else {
|
||||||
|
$error = 'Не удалось загрузить файл.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$pages_count=array_sum($pdf_page_counts)+$img_page_counts;
|
||||||
|
$new = 'uploads/'.translit($inputLabel[$index]).'_'.date('d-m-Y').'_'.translit($lastname).'_'.$pages_count.'_CTP.pdf';
|
||||||
|
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $pdfFiles);
|
||||||
|
shell_exec($cmd);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_pdf_count($target_pdf){
|
||||||
|
$cmd = sprintf("identify %s", $target_pdf);
|
||||||
|
exec($cmd, $output);
|
||||||
|
$pages = count($output);
|
||||||
|
return $pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($new) {
|
||||||
|
$result['success']="true";
|
||||||
|
$result['message']=$new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function translit($value)
|
||||||
|
{
|
||||||
|
$converter = array(
|
||||||
|
'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
|
||||||
|
'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i',
|
||||||
|
'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
|
||||||
|
'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
|
||||||
|
'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch',
|
||||||
|
'ш' => 'sh', 'щ' => 'sch', 'ь' => '', 'ы' => 'y', 'ъ' => '',
|
||||||
|
'э' => 'e', 'ю' => 'yu', 'я' => 'ya',
|
||||||
|
|
||||||
|
'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D',
|
||||||
|
'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I',
|
||||||
|
'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N',
|
||||||
|
'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' => 'S', 'Т' => 'T',
|
||||||
|
'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C', 'Ч' => 'Ch',
|
||||||
|
'Ш' => 'Sh', 'Щ' => 'Sch', 'Ь' => '', 'Ы' => 'Y', 'Ъ' => '',
|
||||||
|
'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya',
|
||||||
|
);
|
||||||
|
|
||||||
|
$value = strtr($value, $converter);
|
||||||
|
return preg_replace('/\s+/', '', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
echo json_encode($result);
|
||||||
|
|
||||||
|
?>
|
||||||
BIN
ervws/fonts/Roboto/Roboto-Black.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Black.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Black.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Black.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Black.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Black.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-BlackItalic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Bold.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Bold.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Bold.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Bold.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Bold.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Bold.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-BoldItalic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Italic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Italic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Italic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Italic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Italic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Italic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Light.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Light.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Light.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Light.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Light.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Light.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-LightItalic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-LightItalic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-LightItalic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-LightItalic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-LightItalic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-LightItalic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Medium.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Medium.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Medium.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Medium.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Medium.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Medium.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-MediumItalic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Regular.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Regular.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Regular.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Regular.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Regular.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Regular.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Thin.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-Thin.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Thin.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-Thin.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-Thin.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-Thin.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.eot
Normal file
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.ttf
Normal file
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.woff
Normal file
BIN
ervws/fonts/Roboto/Roboto-ThinItalic.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoBold.eot
Normal file
BIN
ervws/fonts/Roboto/RobotoBold.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoBold.ttf
Normal file
BIN
ervws/fonts/Roboto/RobotoBold.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoBold.woff
Normal file
BIN
ervws/fonts/Roboto/RobotoBold.woff
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoRegular.eot
Normal file
BIN
ervws/fonts/Roboto/RobotoRegular.eot
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoRegular.ttf
Normal file
BIN
ervws/fonts/Roboto/RobotoRegular.ttf
Normal file
Binary file not shown.
BIN
ervws/fonts/Roboto/RobotoRegular.woff
Normal file
BIN
ervws/fonts/Roboto/RobotoRegular.woff
Normal file
Binary file not shown.
133
ervws/fonts/Roboto/stylesheet.css
Normal file
133
ervws/fonts/Roboto/stylesheet.css
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/* This stylesheet generated by Transfonter (https://transfonter.org) on February 25, 2018 4:00 PM */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-MediumItalic.eot');
|
||||||
|
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
|
||||||
|
url('Roboto-MediumItalic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-MediumItalic.woff') format('woff'),
|
||||||
|
url('Roboto-MediumItalic.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Italic.eot');
|
||||||
|
src: local('Roboto Italic'), local('Roboto-Italic'),
|
||||||
|
url('Roboto-Italic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Italic.woff') format('woff'),
|
||||||
|
url('Roboto-Italic.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Bold.eot');
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'),
|
||||||
|
url('Roboto-Bold.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Bold.woff') format('woff'),
|
||||||
|
url('Roboto-Bold.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Regular.eot');
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'),
|
||||||
|
url('Roboto-Regular.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Regular.woff') format('woff'),
|
||||||
|
url('Roboto-Regular.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Medium.eot');
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'),
|
||||||
|
url('Roboto-Medium.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Medium.woff') format('woff'),
|
||||||
|
url('Roboto-Medium.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-BoldItalic.eot');
|
||||||
|
src: local('Roboto Bold Italic'), local('Roboto-BoldItalic'),
|
||||||
|
url('Roboto-BoldItalic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-BoldItalic.woff') format('woff'),
|
||||||
|
url('Roboto-BoldItalic.ttf') format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-ThinItalic.eot');
|
||||||
|
src: local('Roboto Thin Italic'), local('Roboto-ThinItalic'),
|
||||||
|
url('Roboto-ThinItalic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-ThinItalic.woff') format('woff'),
|
||||||
|
url('Roboto-ThinItalic.ttf') format('truetype');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Black.eot');
|
||||||
|
src: local('Roboto Black'), local('Roboto-Black'),
|
||||||
|
url('Roboto-Black.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Black.woff') format('woff'),
|
||||||
|
url('Roboto-Black.ttf') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Light.eot');
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'),
|
||||||
|
url('Roboto-Light.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Light.woff') format('woff'),
|
||||||
|
url('Roboto-Light.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-LightItalic.eot');
|
||||||
|
src: local('Roboto Light Italic'), local('Roboto-LightItalic'),
|
||||||
|
url('Roboto-LightItalic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-LightItalic.woff') format('woff'),
|
||||||
|
url('Roboto-LightItalic.ttf') format('truetype');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-BlackItalic.eot');
|
||||||
|
src: local('Roboto Black Italic'), local('Roboto-BlackItalic'),
|
||||||
|
url('Roboto-BlackItalic.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-BlackItalic.woff') format('woff'),
|
||||||
|
url('Roboto-BlackItalic.ttf') format('truetype');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
src: url('Roboto-Thin.eot');
|
||||||
|
src: local('Roboto Thin'), local('Roboto-Thin'),
|
||||||
|
url('Roboto-Thin.eot?#iefix') format('embedded-opentype'),
|
||||||
|
url('Roboto-Thin.woff') format('woff'),
|
||||||
|
url('Roboto-Thin.ttf') format('truetype');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
42
ervws/img/check.svg
Normal file
42
ervws/img/check.svg
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="405.272px" height="405.272px" viewBox="0 0 405.272 405.272" style="enable-background:new 0 0 405.272 405.272;"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M393.401,124.425L179.603,338.208c-15.832,15.835-41.514,15.835-57.361,0L11.878,227.836
|
||||||
|
c-15.838-15.835-15.838-41.52,0-57.358c15.841-15.841,41.521-15.841,57.355-0.006l81.698,81.699L336.037,67.064
|
||||||
|
c15.841-15.841,41.523-15.829,57.358,0C409.23,82.902,409.23,108.578,393.401,124.425z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 953 B |
1
ervws/img/close.svg
Normal file
1
ervws/img/close.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0"?><svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="30px" height="30px"> <path d="M 7 4 C 6.744125 4 6.4879687 4.0974687 6.2929688 4.2929688 L 4.2929688 6.2929688 C 3.9019687 6.6839688 3.9019687 7.3170313 4.2929688 7.7070312 L 11.585938 15 L 4.2929688 22.292969 C 3.9019687 22.683969 3.9019687 23.317031 4.2929688 23.707031 L 6.2929688 25.707031 C 6.6839688 26.098031 7.3170313 26.098031 7.7070312 25.707031 L 15 18.414062 L 22.292969 25.707031 C 22.682969 26.098031 23.317031 26.098031 23.707031 25.707031 L 25.707031 23.707031 C 26.098031 23.316031 26.098031 22.682969 25.707031 22.292969 L 18.414062 15 L 25.707031 7.7070312 C 26.098031 7.3170312 26.098031 6.6829688 25.707031 6.2929688 L 23.707031 4.2929688 C 23.316031 3.9019687 22.682969 3.9019687 22.292969 4.2929688 L 15 11.585938 L 7.7070312 4.2929688 C 7.5115312 4.0974687 7.255875 4 7 4 z"/></svg>
|
||||||
|
After Width: | Height: | Size: 912 B |
1
ervws/img/date.svg
Normal file
1
ervws/img/date.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg role="presentation" class="t-datepicker__icon " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 69.5 76.2" style="width:25px;"><path d="M9.6 42.9H21V31.6H9.6v11.3zm3-8.3H18v5.3h-5.3v-5.3zm16.5 8.3h11.3V31.6H29.1v11.3zm3-8.3h5.3v5.3h-5.3v-5.3zM48 42.9h11.3V31.6H48v11.3zm3-8.3h5.3v5.3H51v-5.3zM9.6 62H21V50.6H9.6V62zm3-8.4H18V59h-5.3v-5.4zM29.1 62h11.3V50.6H29.1V62zm3-8.4h5.3V59h-5.3v-5.4zM48 62h11.3V50.6H48V62zm3-8.4h5.3V59H51v-5.4z"></path><path d="M59.7 6.8V5.3c0-2.9-2.4-5.3-5.3-5.3s-5.3 2.4-5.3 5.3v1.5H40V5.3C40 2.4 37.6 0 34.7 0s-5.3 2.4-5.3 5.3v1.5h-9.1V5.3C20.3 2.4 18 0 15 0c-2.9 0-5.3 2.4-5.3 5.3v1.5H0v69.5h69.5V6.8h-9.8zm-7.6-1.5c0-1.3 1-2.3 2.3-2.3s2.3 1 2.3 2.3v7.1c0 1.3-1 2.3-2.3 2.3s-2.3-1-2.3-2.3V5.3zm-19.7 0c0-1.3 1-2.3 2.3-2.3S37 4 37 5.3v7.1c0 1.3-1 2.3-2.3 2.3s-2.3-1-2.3-2.3V5.3zm-19.6 0C12.8 4 13.8 3 15 3c1.3 0 2.3 1 2.3 2.3v7.1c0 1.3-1 2.3-2.3 2.3-1.3 0-2.3-1-2.3-2.3V5.3zm53.7 67.9H3V9.8h6.8v2.6c0 2.9 2.4 5.3 5.3 5.3s5.3-2.4 5.3-5.3V9.8h9.1v2.6c0 2.9 2.4 5.3 5.3 5.3s5.3-2.4 5.3-5.3V9.8h9.1v2.6c0 2.9 2.4 5.3 5.3 5.3s5.3-2.4 5.3-5.3V9.8h6.8l-.1 63.4z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ervws/img/favicon/apple-touch-icon-180x180.png
Normal file
BIN
ervws/img/favicon/apple-touch-icon-180x180.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
ervws/img/favicon/favicon.ico
Normal file
BIN
ervws/img/favicon/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
1092
ervws/index.php
Normal file
1092
ervws/index.php
Normal file
File diff suppressed because it is too large
Load Diff
1092
ervws/index.php1
Normal file
1092
ervws/index.php1
Normal file
File diff suppressed because it is too large
Load Diff
927
ervws/js/common.js
Normal file
927
ervws/js/common.js
Normal file
@@ -0,0 +1,927 @@
|
|||||||
|
$(function() {
|
||||||
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
$(".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\(\)\.\+/ ]"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".js-inndb-mask").inputmask("A9{3,5}-*{6,10}");
|
||||||
|
|
||||||
|
$(".js-inndb-mask").keyup(function(){
|
||||||
|
//if($this)
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".js-bik-mask").inputmask("999999999");
|
||||||
|
$(".js-rs-mask").inputmask("99999999999999999999");
|
||||||
|
$(".js-ks-mask").inputmask("99999999999999999999");
|
||||||
|
|
||||||
|
document.querySelector('input').addEventListener('keydown', function (e) {
|
||||||
|
if (e.which == 9) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let month =['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
|
||||||
|
let days = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
|
||||||
|
|
||||||
|
var birthday = datepicker('input[name="birthday"]',
|
||||||
|
{
|
||||||
|
customOverlayMonths: month,
|
||||||
|
customMonths: month,
|
||||||
|
customDays: days,
|
||||||
|
maxDate: new Date(),
|
||||||
|
formatter: (input, date, instance) => {
|
||||||
|
const value = date.toLocaleDateString()
|
||||||
|
input.value = value // => '1/1/2099'
|
||||||
|
},
|
||||||
|
onSelect: function(dateText, inst) {
|
||||||
|
let birthday=$('input[name="birthday"]').val();
|
||||||
|
|
||||||
|
if(getAge(birthday)<18) {
|
||||||
|
$("input[data-enableby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").removeAttr("disabled");
|
||||||
|
} else {
|
||||||
|
$("input[data-enableby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").attr("disabled","disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var contract_date = datepicker('input[name="insurence_date"]',{
|
||||||
|
customOverlayMonths: month,
|
||||||
|
customMonths: month,
|
||||||
|
customDays: days,
|
||||||
|
maxDate: new Date(),
|
||||||
|
formatter: (input, date, instance) => {
|
||||||
|
const value = date.toLocaleDateString()
|
||||||
|
input.value = value // => '1/1/2099'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var phone = document.querySelectorAll('.js-phone-mask');
|
||||||
|
$('.js-phone-mask').inputmask('999 999-99-99');
|
||||||
|
phone.forEach(el => {
|
||||||
|
const iti = window.intlTelInput(el, {
|
||||||
|
initialCountry: 'ru',
|
||||||
|
separateDialCode: true,
|
||||||
|
customContainer: ".form-item",
|
||||||
|
excludeCountries: ["kz"],
|
||||||
|
autoPlaceholder: 'aggressive',
|
||||||
|
geoIpLookup: function(callback) {
|
||||||
|
$.get('https://ipinfo.io', null, 'jsonp').always(resp => callback((resp && resp.country) ? resp.country : ''));
|
||||||
|
},
|
||||||
|
utilsScript: "libs/intl-tel-input-master/build/js/utils.js",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.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;
|
||||||
|
|
||||||
|
$('.js-btn-next').on("click",function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
let isvalid=validate_step(index);
|
||||||
|
|
||||||
|
if(isvalid) {
|
||||||
|
index++;
|
||||||
|
$('.span-progress .current').text(index);
|
||||||
|
if(index==4) {
|
||||||
|
$(this).hide();
|
||||||
|
$('.btn--submit').show();
|
||||||
|
} else {
|
||||||
|
$(this).show();
|
||||||
|
$('.js-btn-prev').show();
|
||||||
|
}
|
||||||
|
$('.form-step').removeClass('active');
|
||||||
|
$('.form-step[data-step='+index+']').addClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.js-btn-prev').on("click",function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
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());
|
||||||
|
});
|
||||||
|
|
||||||
|
function validate_step(step_index){
|
||||||
|
let inputs=$('.form-step.active').find('input[type="text"], 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;
|
||||||
|
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'){
|
||||||
|
|
||||||
|
if(validateEmail($(this).val())) {
|
||||||
|
field_fill=true;
|
||||||
|
} else {
|
||||||
|
field_fill=false;
|
||||||
|
$(this).closest('.form-item').find('.form-item__warning').text($(this).data('warmes'));
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
res_array.push(field_fill);
|
||||||
|
});
|
||||||
|
|
||||||
|
if((step_index==3) && $('.form-step[data-step='+step_index+']').find('input[type="checkbox"]:checked').length<1) {
|
||||||
|
$('.form__warning').show();
|
||||||
|
$('.form__warning').text('Выберите хотя 1 страховой случай');
|
||||||
|
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();
|
||||||
|
$(this).closest('.form-item').find('input[type=file]').toggleClass('disabled');
|
||||||
|
$(this).closest('.form-item').find('input[type=file]+label').toggleClass('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
// start sms
|
||||||
|
|
||||||
|
function send_sms(){
|
||||||
|
|
||||||
|
var sended_code = Math.floor(Math.random()*(999999-100000+1)+100000);
|
||||||
|
var smsFormData = new FormData();
|
||||||
|
smsFormData.append('smscode',sended_code);
|
||||||
|
smsFormData.append('phonenumber',$('input[name="phonenumber"]').val());
|
||||||
|
|
||||||
|
// $.ajax({
|
||||||
|
// url: 'sms-test.php',
|
||||||
|
// method: 'post',
|
||||||
|
// cache: false,
|
||||||
|
// contentType: false,
|
||||||
|
// processData: false,
|
||||||
|
// data: smsFormData,
|
||||||
|
// dataType : 'json',
|
||||||
|
// success: function(data) {
|
||||||
|
// console.log(data);
|
||||||
|
// return false;
|
||||||
|
// },
|
||||||
|
// error: function (jqXHR, exception) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
alert(sended_code);
|
||||||
|
|
||||||
|
$('.js-code-warning').text('Код отправлен на ваш номер телефона');
|
||||||
|
|
||||||
|
$.fancybox.open({
|
||||||
|
src: '#confirm_sms',
|
||||||
|
type: 'inline'
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.fancybox-close-small').click(function(e) {
|
||||||
|
$('button[type="submit"]').attr("disabled", false);
|
||||||
|
$('button[type="submit"]').attr("disabled", false);
|
||||||
|
$('button[type="submit"]').text("Подать обращение");
|
||||||
|
});
|
||||||
|
|
||||||
|
return sended_code;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function countDown(elm, duration, fn){
|
||||||
|
var countDownDate = new Date().getTime() + (1000 * duration);
|
||||||
|
var x = setInterval(function() {
|
||||||
|
var now = new Date().getTime();
|
||||||
|
var distance = countDownDate - now;
|
||||||
|
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||||
|
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
|
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||||
|
elm.innerHTML = minutes + "м " + seconds + "с ";
|
||||||
|
if (distance < 0) {
|
||||||
|
clearInterval(x);
|
||||||
|
fn();
|
||||||
|
elm.innerHTML = "";
|
||||||
|
$('.sms-countdown').hide();
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sended_code;
|
||||||
|
|
||||||
|
$('.js-send-sms').on('click', function(e) {
|
||||||
|
// $('.js-send-sms').hide();
|
||||||
|
sended_code=send_sms();
|
||||||
|
$('.sms-countdown').show();
|
||||||
|
$('.modal .js-accept-sms').show();
|
||||||
|
$('.modal .js-send-sms').hide();
|
||||||
|
$('.modal .form-item__warning').text("");
|
||||||
|
countDown(document.querySelector('.sms-countdown .time'), 30, function(){
|
||||||
|
$('.modal .js-send-sms').show();
|
||||||
|
$('.sms-checking button.js-accept-sms').hide();
|
||||||
|
$('.js-code-warning').hide();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.sms-checking .js-accept-sms').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if($('.sms-checking input[type="text"]').val() == sended_code) {
|
||||||
|
$('.sms-success').removeClass('d-none');
|
||||||
|
$('.form-step[data-step=1]').removeClass('disabled');
|
||||||
|
|
||||||
|
$('.modal .js-send-sms').show();
|
||||||
|
$('.sms-check .form-item > .js-send-sms').hide();
|
||||||
|
$.fancybox.close();
|
||||||
|
$.fancybox.close();
|
||||||
|
$('.sms-check').addClass("disabled");
|
||||||
|
$('.sms-check .form-item__warning').text("Вы успешно подтвердили номер");
|
||||||
|
} else {
|
||||||
|
$('.modal .form-item__warning').text("Неверный код");
|
||||||
|
$('.sms-success').addClass('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.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();
|
||||||
|
|
||||||
|
jQuery.each(jQuery('input[type=file].js-attach').not('.disabled'), function(i, file) {
|
||||||
|
|
||||||
|
if(!$(this).hasClass('disabled')) {
|
||||||
|
let field_name=jQuery(this).data('crmname');
|
||||||
|
let docname=jQuery(this).data('docname');
|
||||||
|
let upload_url=jQuery(this).attr('data-uploadurl');
|
||||||
|
let upload_url_real=jQuery(this).attr('data-uploadurl_real');
|
||||||
|
jQuery.each(jQuery(this)[0].files, function(i, file) {
|
||||||
|
formData.append(field_name+'-'+i, file);
|
||||||
|
});
|
||||||
|
if(upload_url) { // Если файл загрузился и получили ответ от upload тогда добавляем в форму
|
||||||
|
formData.append('upload_urls[]',upload_url);
|
||||||
|
formData.append('upload_urls_real[]',upload_url_real);
|
||||||
|
formData.append('files_names[]',field_name);
|
||||||
|
formData.append('docs_names[]',docname);
|
||||||
|
|
||||||
|
if(jQuery(this).data('doctype')=="ticket") {
|
||||||
|
formData.append('docs_ticket_files_ids[]',i);
|
||||||
|
} else {
|
||||||
|
formData.append('docs_ticket_files_ids[]','simple');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (var pair of formData.entries()) {
|
||||||
|
console.log(pair[0]+ ', ' + pair[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'https://form.clientright.ru/server_webservice2.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 f5d6928d7490cd44124ccae11a08c7fa5625d48c",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Cookie": "__ddg1_=BoLd7l5yOCjL9tr6qUth"
|
||||||
|
},
|
||||||
|
"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();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// $(document).ready(function(){
|
||||||
|
// setTimeout(function() {
|
||||||
|
// var $form = $(".form form");
|
||||||
|
// createSuggestions($form);
|
||||||
|
// }, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: 'database.php',
|
||||||
|
method: 'post',
|
||||||
|
data: dbdata,
|
||||||
|
// dataType : 'json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
let res=JSON.parse(data);
|
||||||
|
if(res.success=="true"){
|
||||||
|
|
||||||
|
$('.db-success').removeClass("d-none");
|
||||||
|
$('.js-result').html(res.message);
|
||||||
|
|
||||||
|
$('.js-result').removeClass("danger");
|
||||||
|
|
||||||
|
$('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');
|
||||||
|
$('.form-item--polis').find('input[type=file]').addClass("notvalidate");
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').addClass("disabled");
|
||||||
|
|
||||||
|
|
||||||
|
$('.form-item--polis').addClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$('.db-success').removeClass("d-none");
|
||||||
|
|
||||||
|
$('.js-result').html(res.message);
|
||||||
|
|
||||||
|
$('.js-result').addClass("danger");
|
||||||
|
|
||||||
|
|
||||||
|
$('.js-indatabase').val('0');
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').removeClass("notvalidate");
|
||||||
|
|
||||||
|
$('.form-item--polis').find('input[type=file]').removeClass("disabled");
|
||||||
|
|
||||||
|
$('.form-item--polis').removeClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
error: function (jqXHR, exception) {
|
||||||
|
$('.js-result').html(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) {
|
||||||
|
$("input[data-enableby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").removeClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").removeAttr("disabled");
|
||||||
|
} else {
|
||||||
|
$("input[data-enableby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-disabledby=birthday]").addClass('disabled');
|
||||||
|
$("input[data-enableby=birthday]").attr("disabled","disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$('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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getAge(dateString) {
|
||||||
|
var today = new Date();
|
||||||
|
var birthDate = new Date(dateString.replace( /(\d{2})-(\d{2})-(\d{4})/, "$2/$1/$3"));
|
||||||
|
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 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','gif','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)) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Доступные форматы: .pdf, .jpg, .png, .gif </div>');
|
||||||
|
elem.addClass('error');
|
||||||
|
file_status.push(false);
|
||||||
|
} else {
|
||||||
|
// elem.closest('.form-item').find('.form-item__warning').text();
|
||||||
|
if((file.size/1024/1024) > 5){
|
||||||
|
file_status.push(false);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 5 Мб. </div>');
|
||||||
|
} else {
|
||||||
|
elem.removeClass('error');
|
||||||
|
file_status.push(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_status.every(val => val === true))
|
||||||
|
{
|
||||||
|
upload_file(elem);
|
||||||
|
$('.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');
|
||||||
|
let docname=thisfile.data('docname');
|
||||||
|
|
||||||
|
console.log(docname);
|
||||||
|
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 filesToUpload = [];
|
||||||
|
|
||||||
|
let filethis=$(this);
|
||||||
|
|
||||||
|
filethis.change(function (evt) {
|
||||||
|
var output = [];
|
||||||
|
let elem= $(this);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').text('');
|
||||||
|
let file_status=[];
|
||||||
|
var formats = ['pdf','jpg','png','gif','jpeg'];
|
||||||
|
|
||||||
|
console.log(evt.target.files);
|
||||||
|
|
||||||
|
if(evt.target.files.length>10) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').text("Разрешено не более 10 файлов");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div> Файл '+file.name+' не подходит по формату. Доступные форматы: .pdf, .jpg, .png, .gif </div>');
|
||||||
|
elem.addClass('error');
|
||||||
|
file_status.push(false);
|
||||||
|
} else {
|
||||||
|
// elem.closest('.form-item').find('.form-item__warning').text();
|
||||||
|
if((file.size/1024/1024) > 5){
|
||||||
|
file_status.push(false);
|
||||||
|
elem.closest('.form-item').find('.form-item__warning').append('<div>Размер файла '+file.name+' превышает 5 Мб. </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> ");
|
||||||
|
|
||||||
|
filesToUpload.push({
|
||||||
|
id: fileId,
|
||||||
|
file: file
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//evt.target.value = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// elem.closest('.form-item').find('.upload-action').removeClass('d-none');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
elem.closest('.form-item').find(".fileList").append(output.join(""));
|
||||||
|
|
||||||
|
let container = new DataTransfer();
|
||||||
|
for (var i = 0, len = filesToUpload.length; i < len; i++) {
|
||||||
|
container.items.add(filesToUpload[i].file);
|
||||||
|
}
|
||||||
|
|
||||||
|
elem[0].files = container.files;
|
||||||
|
|
||||||
|
if(file_status.every(val => val === true))
|
||||||
|
{
|
||||||
|
upload_file(elem);
|
||||||
|
$('.form__action').find('.js-btn-next').removeClass('disabled');
|
||||||
|
} else {
|
||||||
|
$('.form__action').find('.js-btn-next').addClass('disabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(this).closest('.form-item').on("click", ".removefile", function (e) {
|
||||||
|
let elem= $(this);
|
||||||
|
e.preventDefault();
|
||||||
|
var fileId = elem.parent().children("a").data("fileid");
|
||||||
|
for (var i = 0; i < filesToUpload.length; ++i) {
|
||||||
|
if (filesToUpload[i].id === fileId) filesToUpload.splice(i, 1);
|
||||||
|
}
|
||||||
|
elem.parent().remove();
|
||||||
|
if(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 = filesToUpload.length; i < len; i++) {
|
||||||
|
container.items.add(filesToUpload[i].file);
|
||||||
|
}
|
||||||
|
filethis[0].files = container.files;
|
||||||
|
updateSize(filethis);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// End Загрузка файлов
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
ervws/js/it2.png_04-24-2024-11-27-06.pdf
Normal file
BIN
ervws/js/it2.png_04-24-2024-11-27-06.pdf
Normal file
Binary file not shown.
51
ervws/libs/bootstrap/scss/_alert.scss
Normal file
51
ervws/libs/bootstrap/scss/_alert.scss
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Base styles
|
||||||
|
//
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
position: relative;
|
||||||
|
padding: $alert-padding-y $alert-padding-x;
|
||||||
|
margin-bottom: $alert-margin-bottom;
|
||||||
|
border: $alert-border-width solid transparent;
|
||||||
|
@include border-radius($alert-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headings for larger alerts
|
||||||
|
.alert-heading {
|
||||||
|
// Specified to prevent conflicts of changing $headings-color
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide class for links that match alerts
|
||||||
|
.alert-link {
|
||||||
|
font-weight: $alert-link-font-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dismissible alerts
|
||||||
|
//
|
||||||
|
// Expand the right padding and account for the close button's positioning.
|
||||||
|
|
||||||
|
.alert-dismissible {
|
||||||
|
padding-right: ($close-font-size + $alert-padding-x * 2);
|
||||||
|
|
||||||
|
// Adjust close link position
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: $alert-padding-y $alert-padding-x;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Alternate styles
|
||||||
|
//
|
||||||
|
// Generate contextual modifier classes for colorizing the alert.
|
||||||
|
|
||||||
|
@each $color, $value in $theme-colors {
|
||||||
|
.alert-#{$color} {
|
||||||
|
@include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level));
|
||||||
|
}
|
||||||
|
}
|
||||||
47
ervws/libs/bootstrap/scss/_badge.scss
Normal file
47
ervws/libs/bootstrap/scss/_badge.scss
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Base class
|
||||||
|
//
|
||||||
|
// Requires one of the contextual, color modifier classes for `color` and
|
||||||
|
// `background-color`.
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: $badge-padding-y $badge-padding-x;
|
||||||
|
font-size: $badge-font-size;
|
||||||
|
font-weight: $badge-font-weight;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: baseline;
|
||||||
|
@include border-radius($badge-border-radius);
|
||||||
|
|
||||||
|
// Empty badges collapse automatically
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick fix for badges in buttons
|
||||||
|
.btn .badge {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pill badges
|
||||||
|
//
|
||||||
|
// Make them extra rounded with a modifier to replace v3's badges.
|
||||||
|
|
||||||
|
.badge-pill {
|
||||||
|
padding-right: $badge-pill-padding-x;
|
||||||
|
padding-left: $badge-pill-padding-x;
|
||||||
|
@include border-radius($badge-pill-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
//
|
||||||
|
// Contextual variations (linked badges get darker on :hover).
|
||||||
|
|
||||||
|
@each $color, $value in $theme-colors {
|
||||||
|
.badge-#{$color} {
|
||||||
|
@include badge-variant($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
ervws/libs/bootstrap/scss/_breadcrumb.scss
Normal file
38
ervws/libs/bootstrap/scss/_breadcrumb.scss
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
.breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
|
||||||
|
margin-bottom: $breadcrumb-margin-bottom;
|
||||||
|
list-style: none;
|
||||||
|
background-color: $breadcrumb-bg;
|
||||||
|
@include border-radius($border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-item {
|
||||||
|
// The separator between breadcrumbs (by default, a forward-slash: "/")
|
||||||
|
+ .breadcrumb-item::before {
|
||||||
|
display: inline-block; // Suppress underlining of the separator in modern browsers
|
||||||
|
padding-right: $breadcrumb-item-padding;
|
||||||
|
padding-left: $breadcrumb-item-padding;
|
||||||
|
color: $breadcrumb-divider-color;
|
||||||
|
content: "#{$breadcrumb-divider}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built
|
||||||
|
// without `<ul>`s. The `::before` pseudo-element generates an element
|
||||||
|
// *within* the .breadcrumb-item and thereby inherits the `text-decoration`.
|
||||||
|
//
|
||||||
|
// To trick IE into suppressing the underline, we give the pseudo-element an
|
||||||
|
// underline and then immediately remove it.
|
||||||
|
+ .breadcrumb-item:hover::before {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
// stylelint-disable-next-line no-duplicate-selectors
|
||||||
|
+ .breadcrumb-item:hover::before {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $breadcrumb-active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
166
ervws/libs/bootstrap/scss/_button-group.scss
Normal file
166
ervws/libs/bootstrap/scss/_button-group.scss
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
// stylelint-disable selector-no-qualifying-type
|
||||||
|
|
||||||
|
// Make the div behave like a button
|
||||||
|
.btn-group,
|
||||||
|
.btn-group-vertical {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: middle; // match .btn alignment given font-size hack above
|
||||||
|
|
||||||
|
> .btn {
|
||||||
|
position: relative;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
|
||||||
|
// Bring the hover, focused, and "active" buttons to the front to overlay
|
||||||
|
// the borders properly
|
||||||
|
@include hover {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
&:focus,
|
||||||
|
&:active,
|
||||||
|
&.active {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent double borders when buttons are next to each other
|
||||||
|
.btn + .btn,
|
||||||
|
.btn + .btn-group,
|
||||||
|
.btn-group + .btn,
|
||||||
|
.btn-group + .btn-group {
|
||||||
|
margin-left: -$btn-border-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Group multiple button groups together for a toolbar
|
||||||
|
.btn-toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
> .btn:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset rounded corners
|
||||||
|
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||||
|
> .btn-group:not(:last-child) > .btn {
|
||||||
|
@include border-right-radius(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .btn:not(:first-child),
|
||||||
|
> .btn-group:not(:first-child) > .btn {
|
||||||
|
@include border-left-radius(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizing
|
||||||
|
//
|
||||||
|
// Remix the default button sizing classes into new ones for easier manipulation.
|
||||||
|
|
||||||
|
.btn-group-sm > .btn { @extend .btn-sm; }
|
||||||
|
.btn-group-lg > .btn { @extend .btn-lg; }
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Split button dropdowns
|
||||||
|
//
|
||||||
|
|
||||||
|
.dropdown-toggle-split {
|
||||||
|
padding-right: $btn-padding-x * .75;
|
||||||
|
padding-left: $btn-padding-x * .75;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm + .dropdown-toggle-split {
|
||||||
|
padding-right: $btn-padding-x-sm * .75;
|
||||||
|
padding-left: $btn-padding-x-sm * .75;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-lg + .dropdown-toggle-split {
|
||||||
|
padding-right: $btn-padding-x-lg * .75;
|
||||||
|
padding-left: $btn-padding-x-lg * .75;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The clickable button for toggling the menu
|
||||||
|
// Set the same inset shadow as the :active state
|
||||||
|
.btn-group.show .dropdown-toggle {
|
||||||
|
@include box-shadow($btn-active-box-shadow);
|
||||||
|
|
||||||
|
// Show no shadow for `.btn-link` since it has no other button styles.
|
||||||
|
&.btn-link {
|
||||||
|
@include box-shadow(none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Vertical button groups
|
||||||
|
//
|
||||||
|
|
||||||
|
.btn-group-vertical {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.btn,
|
||||||
|
.btn-group {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .btn + .btn,
|
||||||
|
> .btn + .btn-group,
|
||||||
|
> .btn-group + .btn,
|
||||||
|
> .btn-group + .btn-group {
|
||||||
|
margin-top: -$btn-border-width;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset rounded corners
|
||||||
|
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||||
|
> .btn-group:not(:last-child) > .btn {
|
||||||
|
@include border-bottom-radius(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .btn:not(:first-child),
|
||||||
|
> .btn-group:not(:first-child) > .btn {
|
||||||
|
@include border-top-radius(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checkbox and radio options
|
||||||
|
//
|
||||||
|
// In order to support the browser's form validation feedback, powered by the
|
||||||
|
// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use
|
||||||
|
// `display: none;` or `visibility: hidden;` as that also hides the popover.
|
||||||
|
// Simply visually hiding the inputs via `opacity` would leave them clickable in
|
||||||
|
// certain cases which is prevented by using `clip` and `pointer-events`.
|
||||||
|
// This way, we ensure a DOM element is visible to position the popover from.
|
||||||
|
//
|
||||||
|
// See https://github.com/twbs/bootstrap/pull/12794 and
|
||||||
|
// https://github.com/twbs/bootstrap/pull/14559 for more information.
|
||||||
|
|
||||||
|
.btn-group-toggle {
|
||||||
|
> .btn,
|
||||||
|
> .btn-group > .btn {
|
||||||
|
margin-bottom: 0; // Override default `<label>` value
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
position: absolute;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
ervws/libs/bootstrap/scss/_buttons.scss
Normal file
143
ervws/libs/bootstrap/scss/_buttons.scss
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// stylelint-disable selector-no-qualifying-type
|
||||||
|
|
||||||
|
//
|
||||||
|
// Base styles
|
||||||
|
//
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: $btn-font-weight;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: middle;
|
||||||
|
user-select: none;
|
||||||
|
border: $btn-border-width solid transparent;
|
||||||
|
@include button-size($btn-padding-y, $btn-padding-x, $font-size-base, $btn-line-height, $btn-border-radius);
|
||||||
|
@include transition($btn-transition);
|
||||||
|
|
||||||
|
// Share hover and focus styles
|
||||||
|
@include hover-focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&.focus {
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: $btn-focus-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled comes first so active can properly restyle
|
||||||
|
&.disabled,
|
||||||
|
&:disabled {
|
||||||
|
opacity: $btn-disabled-opacity;
|
||||||
|
@include box-shadow(none);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opinionated: add "hand" cursor to non-disabled .btn elements
|
||||||
|
&:not(:disabled):not(.disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):not(.disabled):active,
|
||||||
|
&:not(:disabled):not(.disabled).active {
|
||||||
|
background-image: none;
|
||||||
|
@include box-shadow($btn-active-box-shadow);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
@include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future-proof disabling of clicks on `<a>` elements
|
||||||
|
a.btn.disabled,
|
||||||
|
fieldset:disabled a.btn {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Alternate buttons
|
||||||
|
//
|
||||||
|
|
||||||
|
@each $color, $value in $theme-colors {
|
||||||
|
.btn-#{$color} {
|
||||||
|
@include button-variant($value, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $color, $value in $theme-colors {
|
||||||
|
.btn-outline-#{$color} {
|
||||||
|
@include button-outline-variant($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Link buttons
|
||||||
|
//
|
||||||
|
|
||||||
|
// Make a button look and behave like a link
|
||||||
|
.btn-link {
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
color: $link-color;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
@include hover {
|
||||||
|
color: $link-hover-color;
|
||||||
|
text-decoration: $link-hover-decoration;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&.focus {
|
||||||
|
text-decoration: $link-hover-decoration;
|
||||||
|
border-color: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled,
|
||||||
|
&.disabled {
|
||||||
|
color: $btn-link-disabled-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need for an active state here
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Button Sizes
|
||||||
|
//
|
||||||
|
|
||||||
|
.btn-lg {
|
||||||
|
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-line-height-lg, $btn-border-radius-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-sm {
|
||||||
|
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $font-size-sm, $btn-line-height-sm, $btn-border-radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block button
|
||||||
|
//
|
||||||
|
|
||||||
|
.btn-block {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// Vertically space out multiple block buttons
|
||||||
|
+ .btn-block {
|
||||||
|
margin-top: $btn-block-spacing-y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specificity overrides
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="button"] {
|
||||||
|
&.btn-block {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
270
ervws/libs/bootstrap/scss/_card.scss
Normal file
270
ervws/libs/bootstrap/scss/_card.scss
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
//
|
||||||
|
// Base styles
|
||||||
|
//
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background-color: $card-bg;
|
||||||
|
background-clip: border-box;
|
||||||
|
border: $card-border-width solid $card-border-color;
|
||||||
|
@include border-radius($card-border-radius);
|
||||||
|
|
||||||
|
> hr {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .list-group:first-child {
|
||||||
|
.list-group-item:first-child {
|
||||||
|
@include border-top-radius($card-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .list-group:last-child {
|
||||||
|
.list-group-item:last-child {
|
||||||
|
@include border-bottom-radius($card-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
|
||||||
|
// as much space as possible, ensuring footers are aligned to the bottom.
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: $card-spacer-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
margin-bottom: $card-spacer-y;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-subtitle {
|
||||||
|
margin-top: -($card-spacer-y / 2);
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-text:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-link {
|
||||||
|
@include hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .card-link {
|
||||||
|
margin-left: $card-spacer-x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Optional textual caps
|
||||||
|
//
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
padding: $card-spacer-y $card-spacer-x;
|
||||||
|
margin-bottom: 0; // Removes the default margin-bottom of <hN>
|
||||||
|
background-color: $card-cap-bg;
|
||||||
|
border-bottom: $card-border-width solid $card-border-color;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .list-group {
|
||||||
|
.list-group-item:first-child {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
padding: $card-spacer-y $card-spacer-x;
|
||||||
|
background-color: $card-cap-bg;
|
||||||
|
border-top: $card-border-width solid $card-border-color;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Header navs
|
||||||
|
//
|
||||||
|
|
||||||
|
.card-header-tabs {
|
||||||
|
margin-right: -($card-spacer-x / 2);
|
||||||
|
margin-bottom: -$card-spacer-y;
|
||||||
|
margin-left: -($card-spacer-x / 2);
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header-pills {
|
||||||
|
margin-right: -($card-spacer-x / 2);
|
||||||
|
margin-left: -($card-spacer-x / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card image
|
||||||
|
.card-img-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: $card-img-overlay-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-img {
|
||||||
|
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
|
||||||
|
@include border-radius($card-inner-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card image caps
|
||||||
|
.card-img-top {
|
||||||
|
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
|
||||||
|
@include border-top-radius($card-inner-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-img-bottom {
|
||||||
|
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
|
||||||
|
@include border-bottom-radius($card-inner-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Card deck
|
||||||
|
|
||||||
|
.card-deck {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: $card-deck-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
flex-flow: row wrap;
|
||||||
|
margin-right: -$card-deck-margin;
|
||||||
|
margin-left: -$card-deck-margin;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
// Flexbugs #4: https://github.com/philipwalton/flexbugs#4-flex-shorthand-declarations-with-unitless-flex-basis-values-are-ignored
|
||||||
|
flex: 1 0 0%;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-right: $card-deck-margin;
|
||||||
|
margin-bottom: 0; // Override the default
|
||||||
|
margin-left: $card-deck-margin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Card groups
|
||||||
|
//
|
||||||
|
|
||||||
|
.card-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
// The child selector allows nested `.card` within `.card-group`
|
||||||
|
// to display properly.
|
||||||
|
> .card {
|
||||||
|
margin-bottom: $card-group-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
flex-flow: row wrap;
|
||||||
|
// The child selector allows nested `.card` within `.card-group`
|
||||||
|
// to display properly.
|
||||||
|
> .card {
|
||||||
|
// Flexbugs #4: https://github.com/philipwalton/flexbugs#4-flex-shorthand-declarations-with-unitless-flex-basis-values-are-ignored
|
||||||
|
flex: 1 0 0%;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
+ .card {
|
||||||
|
margin-left: 0;
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle rounded corners
|
||||||
|
@if $enable-rounded {
|
||||||
|
&:first-child {
|
||||||
|
@include border-right-radius(0);
|
||||||
|
|
||||||
|
.card-img-top,
|
||||||
|
.card-header {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
.card-img-bottom,
|
||||||
|
.card-footer {
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@include border-left-radius(0);
|
||||||
|
|
||||||
|
.card-img-top,
|
||||||
|
.card-header {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
}
|
||||||
|
.card-img-bottom,
|
||||||
|
.card-footer {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:only-child {
|
||||||
|
@include border-radius($card-border-radius);
|
||||||
|
|
||||||
|
.card-img-top,
|
||||||
|
.card-header {
|
||||||
|
@include border-top-radius($card-border-radius);
|
||||||
|
}
|
||||||
|
.card-img-bottom,
|
||||||
|
.card-footer {
|
||||||
|
@include border-bottom-radius($card-border-radius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child):not(:last-child):not(:only-child) {
|
||||||
|
@include border-radius(0);
|
||||||
|
|
||||||
|
.card-img-top,
|
||||||
|
.card-img-bottom,
|
||||||
|
.card-header,
|
||||||
|
.card-footer {
|
||||||
|
@include border-radius(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Columns
|
||||||
|
//
|
||||||
|
|
||||||
|
.card-columns {
|
||||||
|
.card {
|
||||||
|
margin-bottom: $card-columns-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
column-count: $card-columns-count;
|
||||||
|
column-gap: $card-columns-gap;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: inline-block; // Don't let them vertically span multiple columns
|
||||||
|
width: 100%; // Don't let their width change
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
191
ervws/libs/bootstrap/scss/_carousel.scss
Normal file
191
ervws/libs/bootstrap/scss/_carousel.scss
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Wrapper for the slide container and indicators
|
||||||
|
.carousel {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-inner {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-item {
|
||||||
|
position: relative;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
@include transition($carousel-transition);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
perspective: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-item.active,
|
||||||
|
.carousel-item-next,
|
||||||
|
.carousel-item-prev {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-item-next,
|
||||||
|
.carousel-item-prev {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS3 transforms when supported by the browser
|
||||||
|
.carousel-item-next.carousel-item-left,
|
||||||
|
.carousel-item-prev.carousel-item-right {
|
||||||
|
transform: translateX(0);
|
||||||
|
|
||||||
|
@supports (transform-style: preserve-3d) {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-item-next,
|
||||||
|
.active.carousel-item-right {
|
||||||
|
transform: translateX(100%);
|
||||||
|
|
||||||
|
@supports (transform-style: preserve-3d) {
|
||||||
|
transform: translate3d(100%, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-item-prev,
|
||||||
|
.active.carousel-item-left {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
|
||||||
|
@supports (transform-style: preserve-3d) {
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Left/right controls for nav
|
||||||
|
//
|
||||||
|
|
||||||
|
.carousel-control-prev,
|
||||||
|
.carousel-control-next {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
// Use flex for alignment (1-3)
|
||||||
|
display: flex; // 1. allow flex styles
|
||||||
|
align-items: center; // 2. vertically center contents
|
||||||
|
justify-content: center; // 3. horizontally center contents
|
||||||
|
width: $carousel-control-width;
|
||||||
|
color: $carousel-control-color;
|
||||||
|
text-align: center;
|
||||||
|
opacity: $carousel-control-opacity;
|
||||||
|
// We can't have a transition here because WebKit cancels the carousel
|
||||||
|
// animation if you trip this while in the middle of another animation.
|
||||||
|
|
||||||
|
// Hover/focus state
|
||||||
|
@include hover-focus {
|
||||||
|
color: $carousel-control-color;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 0;
|
||||||
|
opacity: .9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.carousel-control-prev {
|
||||||
|
left: 0;
|
||||||
|
@if $enable-gradients {
|
||||||
|
background: linear-gradient(90deg, rgba(0, 0, 0, .25), rgba(0, 0, 0, .001));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.carousel-control-next {
|
||||||
|
right: 0;
|
||||||
|
@if $enable-gradients {
|
||||||
|
background: linear-gradient(270deg, rgba(0, 0, 0, .25), rgba(0, 0, 0, .001));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Icons for within
|
||||||
|
.carousel-control-prev-icon,
|
||||||
|
.carousel-control-next-icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: $carousel-control-icon-width;
|
||||||
|
height: $carousel-control-icon-width;
|
||||||
|
background: transparent no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
.carousel-control-prev-icon {
|
||||||
|
background-image: $carousel-control-prev-icon-bg;
|
||||||
|
}
|
||||||
|
.carousel-control-next-icon {
|
||||||
|
background-image: $carousel-control-next-icon-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Optional indicator pips
|
||||||
|
//
|
||||||
|
// Add an ordered list with the following class and add a list item for each
|
||||||
|
// slide your carousel holds.
|
||||||
|
|
||||||
|
.carousel-indicators {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
z-index: 15;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-left: 0; // override <ol> default
|
||||||
|
// Use the .carousel-control's width as margin so we don't overlay those
|
||||||
|
margin-right: $carousel-control-width;
|
||||||
|
margin-left: $carousel-control-width;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
width: $carousel-indicator-width;
|
||||||
|
height: $carousel-indicator-height;
|
||||||
|
margin-right: $carousel-indicator-spacer;
|
||||||
|
margin-left: $carousel-indicator-spacer;
|
||||||
|
text-indent: -999px;
|
||||||
|
background-color: rgba($carousel-indicator-active-bg, .5);
|
||||||
|
|
||||||
|
// Use pseudo classes to increase the hit area by 10px on top and bottom.
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background-color: $carousel-indicator-active-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Optional captions
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
.carousel-caption {
|
||||||
|
position: absolute;
|
||||||
|
right: ((100% - $carousel-caption-width) / 2);
|
||||||
|
bottom: 20px;
|
||||||
|
left: ((100% - $carousel-caption-width) / 2);
|
||||||
|
z-index: 10;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
color: $carousel-caption-color;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
34
ervws/libs/bootstrap/scss/_close.scss
Normal file
34
ervws/libs/bootstrap/scss/_close.scss
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
.close {
|
||||||
|
float: right;
|
||||||
|
font-size: $close-font-size;
|
||||||
|
font-weight: $close-font-weight;
|
||||||
|
line-height: 1;
|
||||||
|
color: $close-color;
|
||||||
|
text-shadow: $close-text-shadow;
|
||||||
|
opacity: .5;
|
||||||
|
|
||||||
|
@include hover-focus {
|
||||||
|
color: $close-color;
|
||||||
|
text-decoration: none;
|
||||||
|
opacity: .75;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opinionated: add "hand" cursor to non-disabled .close elements
|
||||||
|
&:not(:disabled):not(.disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional properties for button version
|
||||||
|
// iOS requires the button element instead of an anchor tag.
|
||||||
|
// If you want the anchor version, it requires `href="#"`.
|
||||||
|
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
|
||||||
|
|
||||||
|
// stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type
|
||||||
|
button.close {
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
// stylelint-enable
|
||||||
56
ervws/libs/bootstrap/scss/_code.scss
Normal file
56
ervws/libs/bootstrap/scss/_code.scss
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Inline and block code styles
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
pre,
|
||||||
|
samp {
|
||||||
|
font-family: $font-family-monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline code
|
||||||
|
code {
|
||||||
|
font-size: $code-font-size;
|
||||||
|
color: $code-color;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
|
// Streamline the style when inside anchors to avoid broken underline and more
|
||||||
|
a > & {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User input typically entered via keyboard
|
||||||
|
kbd {
|
||||||
|
padding: $kbd-padding-y $kbd-padding-x;
|
||||||
|
font-size: $kbd-font-size;
|
||||||
|
color: $kbd-color;
|
||||||
|
background-color: $kbd-bg;
|
||||||
|
@include border-radius($border-radius-sm);
|
||||||
|
@include box-shadow($kbd-box-shadow);
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: $nested-kbd-font-weight;
|
||||||
|
@include box-shadow(none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocks of code
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
font-size: $code-font-size;
|
||||||
|
color: $pre-color;
|
||||||
|
|
||||||
|
// Account for some code outputs that place code tags in pre tags
|
||||||
|
code {
|
||||||
|
font-size: inherit;
|
||||||
|
color: inherit;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable scrollable blocks of code
|
||||||
|
.pre-scrollable {
|
||||||
|
max-height: $pre-scrollable-max-height;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
297
ervws/libs/bootstrap/scss/_custom-forms.scss
Normal file
297
ervws/libs/bootstrap/scss/_custom-forms.scss
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
// Embedded icons from Open Iconic.
|
||||||
|
// Released under MIT and copyright 2014 Waybury.
|
||||||
|
// https://useiconic.com/open
|
||||||
|
|
||||||
|
|
||||||
|
// Checkboxes and radios
|
||||||
|
//
|
||||||
|
// Base class takes care of all the key behavioral aspects.
|
||||||
|
|
||||||
|
.custom-control {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
min-height: (1rem * $line-height-base);
|
||||||
|
padding-left: $custom-control-gutter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-inline {
|
||||||
|
display: inline-flex;
|
||||||
|
margin-right: $custom-control-spacer-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1; // Put the input behind the label so it doesn't overlay text
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
&:checked ~ .custom-control-label::before {
|
||||||
|
color: $custom-control-indicator-checked-color;
|
||||||
|
@include gradient-bg($custom-control-indicator-checked-bg);
|
||||||
|
@include box-shadow($custom-control-indicator-checked-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus ~ .custom-control-label::before {
|
||||||
|
// the mixin is not used here to make sure there is feedback
|
||||||
|
box-shadow: $custom-control-indicator-focus-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active ~ .custom-control-label::before {
|
||||||
|
color: $custom-control-indicator-active-color;
|
||||||
|
background-color: $custom-control-indicator-active-bg;
|
||||||
|
@include box-shadow($custom-control-indicator-active-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
~ .custom-control-label {
|
||||||
|
color: $custom-control-label-disabled-color;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background-color: $custom-control-indicator-disabled-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom control indicators
|
||||||
|
//
|
||||||
|
// Build the custom controls out of psuedo-elements.
|
||||||
|
|
||||||
|
.custom-control-label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
// Background-color and (when enabled) gradient
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
top: (($line-height-base - $custom-control-indicator-size) / 2);
|
||||||
|
left: 0;
|
||||||
|
display: block;
|
||||||
|
width: $custom-control-indicator-size;
|
||||||
|
height: $custom-control-indicator-size;
|
||||||
|
pointer-events: none;
|
||||||
|
content: "";
|
||||||
|
user-select: none;
|
||||||
|
background-color: $custom-control-indicator-bg;
|
||||||
|
@include box-shadow($custom-control-indicator-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foreground (icon)
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: (($line-height-base - $custom-control-indicator-size) / 2);
|
||||||
|
left: 0;
|
||||||
|
display: block;
|
||||||
|
width: $custom-control-indicator-size;
|
||||||
|
height: $custom-control-indicator-size;
|
||||||
|
content: "";
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
background-size: $custom-control-indicator-bg-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checkboxes
|
||||||
|
//
|
||||||
|
// Tweak just a few things for checkboxes.
|
||||||
|
|
||||||
|
.custom-checkbox {
|
||||||
|
.custom-control-label::before {
|
||||||
|
@include border-radius($custom-checkbox-indicator-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input:checked ~ .custom-control-label {
|
||||||
|
&::before {
|
||||||
|
@include gradient-bg($custom-control-indicator-checked-bg);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
background-image: $custom-checkbox-indicator-icon-checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input:indeterminate ~ .custom-control-label {
|
||||||
|
&::before {
|
||||||
|
@include gradient-bg($custom-checkbox-indicator-indeterminate-bg);
|
||||||
|
@include box-shadow($custom-checkbox-indicator-indeterminate-box-shadow);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
background-image: $custom-checkbox-indicator-icon-indeterminate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input:disabled {
|
||||||
|
&:checked ~ .custom-control-label::before {
|
||||||
|
background-color: $custom-control-indicator-checked-disabled-bg;
|
||||||
|
}
|
||||||
|
&:indeterminate ~ .custom-control-label::before {
|
||||||
|
background-color: $custom-control-indicator-checked-disabled-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Radios
|
||||||
|
//
|
||||||
|
// Tweak just a few things for radios.
|
||||||
|
|
||||||
|
.custom-radio {
|
||||||
|
.custom-control-label::before {
|
||||||
|
border-radius: $custom-radio-indicator-border-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input:checked ~ .custom-control-label {
|
||||||
|
&::before {
|
||||||
|
@include gradient-bg($custom-control-indicator-checked-bg);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
background-image: $custom-radio-indicator-icon-checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control-input:disabled {
|
||||||
|
&:checked ~ .custom-control-label::before {
|
||||||
|
background-color: $custom-control-indicator-checked-disabled-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Select
|
||||||
|
//
|
||||||
|
// Replaces the browser default select with a custom one, mostly pulled from
|
||||||
|
// http://primercss.io.
|
||||||
|
//
|
||||||
|
|
||||||
|
.custom-select {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: $custom-select-height;
|
||||||
|
padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x;
|
||||||
|
line-height: $custom-select-line-height;
|
||||||
|
color: $custom-select-color;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: $custom-select-bg $custom-select-indicator no-repeat right $custom-select-padding-x center;
|
||||||
|
background-size: $custom-select-bg-size;
|
||||||
|
border: $custom-select-border-width solid $custom-select-border-color;
|
||||||
|
@if $enable-rounded {
|
||||||
|
border-radius: $custom-select-border-radius;
|
||||||
|
} @else {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
appearance: none;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: $custom-select-focus-border-color;
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: $custom-select-focus-box-shadow;
|
||||||
|
|
||||||
|
&::-ms-value {
|
||||||
|
// For visual consistency with other platforms/browsers,
|
||||||
|
// suppress the default white text on blue background highlight given to
|
||||||
|
// the selected option text when the (still closed) <select> receives focus
|
||||||
|
// in IE and (under certain conditions) Edge.
|
||||||
|
// See https://github.com/twbs/bootstrap/issues/19398.
|
||||||
|
color: $input-color;
|
||||||
|
background-color: $input-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[multiple],
|
||||||
|
&[size]:not([size="1"]) {
|
||||||
|
height: auto;
|
||||||
|
padding-right: $custom-select-padding-x;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: $custom-select-disabled-color;
|
||||||
|
background-color: $custom-select-disabled-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hides the default caret in IE11
|
||||||
|
&::-ms-expand {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-select-sm {
|
||||||
|
height: $custom-select-height-sm;
|
||||||
|
padding-top: $custom-select-padding-y;
|
||||||
|
padding-bottom: $custom-select-padding-y;
|
||||||
|
font-size: $custom-select-font-size-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-select-lg {
|
||||||
|
height: $custom-select-height-lg;
|
||||||
|
padding-top: $custom-select-padding-y;
|
||||||
|
padding-bottom: $custom-select-padding-y;
|
||||||
|
font-size: $custom-select-font-size-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// File
|
||||||
|
//
|
||||||
|
// Custom file input.
|
||||||
|
|
||||||
|
.custom-file {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: $custom-file-height;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-file-input {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100%;
|
||||||
|
height: $custom-file-height;
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
&:focus ~ .custom-file-control {
|
||||||
|
border-color: $custom-file-focus-border-color;
|
||||||
|
box-shadow: $custom-file-focus-box-shadow;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
border-color: $custom-file-focus-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $lang, $value in $custom-file-text {
|
||||||
|
&:lang(#{$lang}) ~ .custom-file-label::after {
|
||||||
|
content: $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-file-label {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
height: $custom-file-height;
|
||||||
|
padding: $custom-file-padding-y $custom-file-padding-x;
|
||||||
|
line-height: $custom-file-line-height;
|
||||||
|
color: $custom-file-color;
|
||||||
|
background-color: $custom-file-bg;
|
||||||
|
border: $custom-file-border-width solid $custom-file-border-color;
|
||||||
|
@include border-radius($custom-file-border-radius);
|
||||||
|
@include box-shadow($custom-file-box-shadow);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 3;
|
||||||
|
display: block;
|
||||||
|
height: calc(#{$custom-file-height} - #{$custom-file-border-width} * 2);
|
||||||
|
padding: $custom-file-padding-y $custom-file-padding-x;
|
||||||
|
line-height: $custom-file-line-height;
|
||||||
|
color: $custom-file-button-color;
|
||||||
|
content: "Browse";
|
||||||
|
@include gradient-bg($custom-file-button-bg);
|
||||||
|
border-left: $custom-file-border-width solid $custom-file-border-color;
|
||||||
|
@include border-radius(0 $custom-file-border-radius $custom-file-border-radius 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
131
ervws/libs/bootstrap/scss/_dropdown.scss
Normal file
131
ervws/libs/bootstrap/scss/_dropdown.scss
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// The dropdown wrapper (`<div>`)
|
||||||
|
.dropup,
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle {
|
||||||
|
// Generate the caret automatically
|
||||||
|
@include caret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The dropdown menu
|
||||||
|
.dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: $zindex-dropdown;
|
||||||
|
display: none; // none by default, but block on "open" of the menu
|
||||||
|
float: left;
|
||||||
|
min-width: $dropdown-min-width;
|
||||||
|
padding: $dropdown-padding-y 0;
|
||||||
|
margin: $dropdown-spacer 0 0; // override default ul
|
||||||
|
font-size: $font-size-base; // Redeclare because nesting can cause inheritance issues
|
||||||
|
color: $body-color;
|
||||||
|
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
|
||||||
|
list-style: none;
|
||||||
|
background-color: $dropdown-bg;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: $dropdown-border-width solid $dropdown-border-color;
|
||||||
|
@include border-radius($dropdown-border-radius);
|
||||||
|
@include box-shadow($dropdown-box-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for dropdowns to go bottom up (aka, dropup-menu)
|
||||||
|
// Just add .dropup after the standard .dropdown class and you're set.
|
||||||
|
.dropup {
|
||||||
|
.dropdown-menu {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: $dropdown-spacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle {
|
||||||
|
@include caret(up);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropright {
|
||||||
|
.dropdown-menu {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-left: $dropdown-spacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle {
|
||||||
|
@include caret(right);
|
||||||
|
&::after {
|
||||||
|
vertical-align: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropleft {
|
||||||
|
.dropdown-menu {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-right: $dropdown-spacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle {
|
||||||
|
@include caret(left);
|
||||||
|
&::before {
|
||||||
|
vertical-align: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dividers (basically an `<hr>`) within the dropdown
|
||||||
|
.dropdown-divider {
|
||||||
|
@include nav-divider($dropdown-divider-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Links, buttons, and more within the dropdown menu
|
||||||
|
//
|
||||||
|
// `<button>`-specific styles are denoted with `// For <button>s`
|
||||||
|
.dropdown-item {
|
||||||
|
display: block;
|
||||||
|
width: 100%; // For `<button>`s
|
||||||
|
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
|
||||||
|
clear: both;
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
color: $dropdown-link-color;
|
||||||
|
text-align: inherit; // For `<button>`s
|
||||||
|
white-space: nowrap; // prevent links from randomly breaking onto new lines
|
||||||
|
background-color: transparent; // For `<button>`s
|
||||||
|
border: 0; // For `<button>`s
|
||||||
|
|
||||||
|
@include hover-focus {
|
||||||
|
color: $dropdown-link-hover-color;
|
||||||
|
text-decoration: none;
|
||||||
|
@include gradient-bg($dropdown-link-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active,
|
||||||
|
&:active {
|
||||||
|
color: $dropdown-link-active-color;
|
||||||
|
text-decoration: none;
|
||||||
|
@include gradient-bg($dropdown-link-active-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled,
|
||||||
|
&:disabled {
|
||||||
|
color: $dropdown-link-disabled-color;
|
||||||
|
background-color: transparent;
|
||||||
|
// Remove CSS gradients if they're enabled
|
||||||
|
@if $enable-gradients {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dropdown section headers
|
||||||
|
.dropdown-header {
|
||||||
|
display: block;
|
||||||
|
padding: $dropdown-padding-y $dropdown-item-padding-x;
|
||||||
|
margin-bottom: 0; // for use with heading elements
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $dropdown-header-color;
|
||||||
|
white-space: nowrap; // as with > li > a
|
||||||
|
}
|
||||||
333
ervws/libs/bootstrap/scss/_forms.scss
Normal file
333
ervws/libs/bootstrap/scss/_forms.scss
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
// stylelint-disable selector-no-qualifying-type
|
||||||
|
|
||||||
|
//
|
||||||
|
// Textual form controls
|
||||||
|
//
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: $input-padding-y $input-padding-x;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
line-height: $input-line-height;
|
||||||
|
color: $input-color;
|
||||||
|
background-color: $input-bg;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: $input-border-width solid $input-border-color;
|
||||||
|
|
||||||
|
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
|
||||||
|
@if $enable-rounded {
|
||||||
|
// Manually use the if/else instead of the mixin to account for iOS override
|
||||||
|
border-radius: $input-border-radius;
|
||||||
|
} @else {
|
||||||
|
// Otherwise undo the iOS default
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include box-shadow($input-box-shadow);
|
||||||
|
@include transition($input-transition);
|
||||||
|
|
||||||
|
// Unstyle the caret on `<select>`s in IE10+.
|
||||||
|
&::-ms-expand {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customize the `:focus` state to imitate native WebKit styles.
|
||||||
|
@include form-control-focus();
|
||||||
|
|
||||||
|
// Placeholder
|
||||||
|
&::placeholder {
|
||||||
|
color: $input-placeholder-color;
|
||||||
|
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled and read-only inputs
|
||||||
|
//
|
||||||
|
// HTML5 says that controls under a fieldset > legend:first-child won't be
|
||||||
|
// disabled if the fieldset is disabled. Due to implementation difficulty, we
|
||||||
|
// don't honor that edge case; we style them as disabled anyway.
|
||||||
|
&:disabled,
|
||||||
|
&[readonly] {
|
||||||
|
background-color: $input-disabled-bg;
|
||||||
|
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-control {
|
||||||
|
&:not([size]):not([multiple]) {
|
||||||
|
height: $input-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus::-ms-value {
|
||||||
|
// Suppress the nested default white text on blue background highlight given to
|
||||||
|
// the selected option text when the (still closed) <select> receives focus
|
||||||
|
// in IE and (under certain conditions) Edge, as it looks bad and cannot be made to
|
||||||
|
// match the appearance of the native widget.
|
||||||
|
// See https://github.com/twbs/bootstrap/issues/19398.
|
||||||
|
color: $input-color;
|
||||||
|
background-color: $input-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make file inputs better match text inputs by forcing them to new lines.
|
||||||
|
.form-control-file,
|
||||||
|
.form-control-range {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Labels
|
||||||
|
//
|
||||||
|
|
||||||
|
// For use with horizontal and inline forms, when you need the label (or legend)
|
||||||
|
// text to align with the form controls.
|
||||||
|
.col-form-label {
|
||||||
|
padding-top: calc(#{$input-padding-y} + #{$input-border-width});
|
||||||
|
padding-bottom: calc(#{$input-padding-y} + #{$input-border-width});
|
||||||
|
margin-bottom: 0; // Override the `<label>/<legend>` default
|
||||||
|
font-size: inherit; // Override the `<legend>` default
|
||||||
|
line-height: $input-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-form-label-lg {
|
||||||
|
padding-top: calc(#{$input-padding-y-lg} + #{$input-border-width});
|
||||||
|
padding-bottom: calc(#{$input-padding-y-lg} + #{$input-border-width});
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
line-height: $input-line-height-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-form-label-sm {
|
||||||
|
padding-top: calc(#{$input-padding-y-sm} + #{$input-border-width});
|
||||||
|
padding-bottom: calc(#{$input-padding-y-sm} + #{$input-border-width});
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
line-height: $input-line-height-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Readonly controls as plain text
|
||||||
|
//
|
||||||
|
// Apply class to a readonly input to make it appear like regular plain
|
||||||
|
// text (without any border, background color, focus indicator)
|
||||||
|
|
||||||
|
.form-control-plaintext {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: $input-padding-y;
|
||||||
|
padding-bottom: $input-padding-y;
|
||||||
|
margin-bottom: 0; // match inputs if this class comes on inputs with default margins
|
||||||
|
line-height: $input-line-height;
|
||||||
|
background-color: transparent;
|
||||||
|
border: solid transparent;
|
||||||
|
border-width: $input-border-width 0;
|
||||||
|
|
||||||
|
&.form-control-sm,
|
||||||
|
&.form-control-lg {
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Form control sizing
|
||||||
|
//
|
||||||
|
// Build on `.form-control` with modifier classes to decrease or increase the
|
||||||
|
// height and font-size of form controls.
|
||||||
|
//
|
||||||
|
// The `.form-group-* form-control` variations are sadly duplicated to avoid the
|
||||||
|
// issue documented in https://github.com/twbs/bootstrap/issues/15074.
|
||||||
|
|
||||||
|
.form-control-sm {
|
||||||
|
padding: $input-padding-y-sm $input-padding-x-sm;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
line-height: $input-line-height-sm;
|
||||||
|
@include border-radius($input-border-radius-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-control-sm {
|
||||||
|
&:not([size]):not([multiple]) {
|
||||||
|
height: $input-height-sm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-lg {
|
||||||
|
padding: $input-padding-y-lg $input-padding-x-lg;
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
line-height: $input-line-height-lg;
|
||||||
|
@include border-radius($input-border-radius-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-control-lg {
|
||||||
|
&:not([size]):not([multiple]) {
|
||||||
|
height: $input-height-lg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Form groups
|
||||||
|
//
|
||||||
|
// Designed to help with the organization and spacing of vertical forms. For
|
||||||
|
// horizontal forms, use the predefined grid classes.
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: $form-group-margin-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-text {
|
||||||
|
display: block;
|
||||||
|
margin-top: $form-text-margin-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Form grid
|
||||||
|
//
|
||||||
|
// Special replacement for our grid system's `.row` for tighter form layouts.
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -5px;
|
||||||
|
margin-left: -5px;
|
||||||
|
|
||||||
|
> .col,
|
||||||
|
> [class*="col-"] {
|
||||||
|
padding-right: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Checkboxes and radios
|
||||||
|
//
|
||||||
|
// Indent the labels to position radios/checkboxes as hanging controls.
|
||||||
|
|
||||||
|
.form-check {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding-left: $form-check-input-gutter;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: $form-check-input-margin-y;
|
||||||
|
margin-left: -$form-check-input-gutter;
|
||||||
|
|
||||||
|
&:disabled ~ .form-check-label {
|
||||||
|
color: $text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-label {
|
||||||
|
margin-bottom: 0; // Override default `<label>` bottom margin
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-inline {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 0; // Override base .form-check
|
||||||
|
margin-right: $form-check-inline-margin-x;
|
||||||
|
|
||||||
|
// Undo .form-check-input defaults and add some `margin-right`.
|
||||||
|
.form-check-input {
|
||||||
|
position: static;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-right: $form-check-inline-input-margin-x;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Form validation
|
||||||
|
//
|
||||||
|
// Provide feedback to users when form field values are valid or invalid. Works
|
||||||
|
// primarily for client-side validation via scoped `:invalid` and `:valid`
|
||||||
|
// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
|
||||||
|
// server side validation.
|
||||||
|
|
||||||
|
@include form-validation-state("valid", $form-feedback-valid-color);
|
||||||
|
@include form-validation-state("invalid", $form-feedback-invalid-color);
|
||||||
|
|
||||||
|
// Inline forms
|
||||||
|
//
|
||||||
|
// Make forms appear inline(-block) by adding the `.form-inline` class. Inline
|
||||||
|
// forms begin stacked on extra small (mobile) devices and then go inline when
|
||||||
|
// viewports reach <768px.
|
||||||
|
//
|
||||||
|
// Requires wrapping inputs and labels with `.form-group` for proper display of
|
||||||
|
// default HTML form controls and our custom form controls (e.g., input groups).
|
||||||
|
|
||||||
|
.form-inline {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
align-items: center; // Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height)
|
||||||
|
|
||||||
|
// Because we use flex, the initial sizing of checkboxes is collapsed and
|
||||||
|
// doesn't occupy the full-width (which is what we want for xs grid tier),
|
||||||
|
// so we force that here.
|
||||||
|
.form-check {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick in the inline
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline-block all the things for "inline"
|
||||||
|
.form-group {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow folks to *not* use `.form-group`
|
||||||
|
.form-control {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto; // Prevent labels from stacking above inputs in `.form-group`
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make static controls behave like regular ones
|
||||||
|
.form-control-plaintext {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove default margin on radios/checkboxes that were used for stacking, and
|
||||||
|
// then undo the floating of radios and checkboxes to match.
|
||||||
|
.form-check {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: auto;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.form-check-input {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-right: $form-check-input-margin-x;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-control {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.custom-control-label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
ervws/libs/bootstrap/scss/_functions.scss
Normal file
86
ervws/libs/bootstrap/scss/_functions.scss
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Bootstrap functions
|
||||||
|
//
|
||||||
|
// Utility mixins and functions for evalutating source code across our variables, maps, and mixins.
|
||||||
|
|
||||||
|
// Ascending
|
||||||
|
// Used to evaluate Sass maps like our grid breakpoints.
|
||||||
|
@mixin _assert-ascending($map, $map-name) {
|
||||||
|
$prev-key: null;
|
||||||
|
$prev-num: null;
|
||||||
|
@each $key, $num in $map {
|
||||||
|
@if $prev-num == null {
|
||||||
|
// Do nothing
|
||||||
|
} @else if not comparable($prev-num, $num) {
|
||||||
|
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||||
|
} @else if $prev-num >= $num {
|
||||||
|
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||||
|
}
|
||||||
|
$prev-key: $key;
|
||||||
|
$prev-num: $num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts at zero
|
||||||
|
// Another grid mixin that ensures the min-width of the lowest breakpoint starts at 0.
|
||||||
|
@mixin _assert-starts-at-zero($map) {
|
||||||
|
$values: map-values($map);
|
||||||
|
$first-value: nth($values, 1);
|
||||||
|
@if $first-value != 0 {
|
||||||
|
@warn "First breakpoint in `$grid-breakpoints` must start at 0, but starts at #{$first-value}.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace `$search` with `$replace` in `$string`
|
||||||
|
// Used on our SVG icon backgrounds for custom forms.
|
||||||
|
//
|
||||||
|
// @author Hugo Giraudel
|
||||||
|
// @param {String} $string - Initial string
|
||||||
|
// @param {String} $search - Substring to replace
|
||||||
|
// @param {String} $replace ('') - New value
|
||||||
|
// @return {String} - Updated string
|
||||||
|
@function str-replace($string, $search, $replace: "") {
|
||||||
|
$index: str-index($string, $search);
|
||||||
|
|
||||||
|
@if $index {
|
||||||
|
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
@return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Color contrast
|
||||||
|
@function color-yiq($color) {
|
||||||
|
$r: red($color);
|
||||||
|
$g: green($color);
|
||||||
|
$b: blue($color);
|
||||||
|
|
||||||
|
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
|
||||||
|
|
||||||
|
@if ($yiq >= $yiq-contrasted-threshold) {
|
||||||
|
@return $yiq-text-dark;
|
||||||
|
} @else {
|
||||||
|
@return $yiq-text-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve color Sass maps
|
||||||
|
@function color($key: "blue") {
|
||||||
|
@return map-get($colors, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@function theme-color($key: "primary") {
|
||||||
|
@return map-get($theme-colors, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@function gray($key: "100") {
|
||||||
|
@return map-get($grays, $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request a theme color level
|
||||||
|
@function theme-color-level($color-name: "primary", $level: 0) {
|
||||||
|
$color: theme-color($color-name);
|
||||||
|
$color-base: if($level > 0, #000, #fff);
|
||||||
|
$level: abs($level);
|
||||||
|
|
||||||
|
@return mix($color-base, $color, $level * $theme-color-interval);
|
||||||
|
}
|
||||||
52
ervws/libs/bootstrap/scss/_grid.scss
Normal file
52
ervws/libs/bootstrap/scss/_grid.scss
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Container widths
|
||||||
|
//
|
||||||
|
// Set the container width, and override it for fixed navbars in media queries.
|
||||||
|
|
||||||
|
@if $enable-grid-classes {
|
||||||
|
.container {
|
||||||
|
@include make-container();
|
||||||
|
@include make-container-max-widths();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fluid container
|
||||||
|
//
|
||||||
|
// Utilizes the mixin meant for fixed width containers, but with 100% width for
|
||||||
|
// fluid, full width layouts.
|
||||||
|
|
||||||
|
@if $enable-grid-classes {
|
||||||
|
.container-fluid {
|
||||||
|
@include make-container();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row
|
||||||
|
//
|
||||||
|
// Rows contain and clear the floats of your columns.
|
||||||
|
|
||||||
|
@if $enable-grid-classes {
|
||||||
|
.row {
|
||||||
|
@include make-row();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the negative margin from default .row, then the horizontal padding
|
||||||
|
// from all immediate children columns (to prevent runaway style inheritance).
|
||||||
|
.no-gutters {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: 0;
|
||||||
|
|
||||||
|
> .col,
|
||||||
|
> [class*="col-"] {
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
//
|
||||||
|
// Common styles for small and large grid columns
|
||||||
|
|
||||||
|
@if $enable-grid-classes {
|
||||||
|
@include make-grid-columns();
|
||||||
|
}
|
||||||
42
ervws/libs/bootstrap/scss/_images.scss
Normal file
42
ervws/libs/bootstrap/scss/_images.scss
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Responsive images (ensure images don't scale beyond their parents)
|
||||||
|
//
|
||||||
|
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
|
||||||
|
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
|
||||||
|
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
|
||||||
|
// which weren't expecting the images within themselves to be involuntarily resized.
|
||||||
|
// See also https://github.com/twbs/bootstrap/issues/18178
|
||||||
|
.img-fluid {
|
||||||
|
@include img-fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Image thumbnails
|
||||||
|
.img-thumbnail {
|
||||||
|
padding: $thumbnail-padding;
|
||||||
|
background-color: $thumbnail-bg;
|
||||||
|
border: $thumbnail-border-width solid $thumbnail-border-color;
|
||||||
|
@include border-radius($thumbnail-border-radius);
|
||||||
|
@include box-shadow($thumbnail-box-shadow);
|
||||||
|
|
||||||
|
// Keep them at most 100% wide
|
||||||
|
@include img-fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Figures
|
||||||
|
//
|
||||||
|
|
||||||
|
.figure {
|
||||||
|
// Ensures the caption's text aligns with the image.
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.figure-img {
|
||||||
|
margin-bottom: ($spacer / 2);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.figure-caption {
|
||||||
|
font-size: $figure-caption-font-size;
|
||||||
|
color: $figure-caption-color;
|
||||||
|
}
|
||||||
159
ervws/libs/bootstrap/scss/_input-group.scss
Normal file
159
ervws/libs/bootstrap/scss/_input-group.scss
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
// stylelint-disable selector-no-qualifying-type
|
||||||
|
|
||||||
|
//
|
||||||
|
// Base styles
|
||||||
|
//
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap; // For form validation feedback
|
||||||
|
align-items: stretch;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> .form-control,
|
||||||
|
> .custom-select,
|
||||||
|
> .custom-file {
|
||||||
|
position: relative; // For focus state's z-index
|
||||||
|
flex: 1 1 auto;
|
||||||
|
// Add width 1% and flex-basis auto to ensure that button will not wrap out
|
||||||
|
// the column. Applies to IE Edge+ and Firefox. Chrome does not require this.
|
||||||
|
width: 1%;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
// Bring the "active" form control to the top of surrounding elements
|
||||||
|
&:focus {
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .form-control,
|
||||||
|
+ .custom-select,
|
||||||
|
+ .custom-file {
|
||||||
|
margin-left: -$input-border-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .form-control,
|
||||||
|
> .custom-select {
|
||||||
|
&:not(:last-child) { @include border-right-radius(0); }
|
||||||
|
&:not(:first-child) { @include border-left-radius(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom file inputs have more complex markup, thus requiring different
|
||||||
|
// border-radius overrides.
|
||||||
|
> .custom-file {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(:last-child) .custom-file-label,
|
||||||
|
&:not(:last-child) .custom-file-label::before { @include border-right-radius(0); }
|
||||||
|
&:not(:first-child) .custom-file-label,
|
||||||
|
&:not(:first-child) .custom-file-label::before { @include border-left-radius(0); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Prepend and append
|
||||||
|
//
|
||||||
|
// While it requires one extra layer of HTML for each, dedicated prepend and
|
||||||
|
// append elements allow us to 1) be less clever, 2) simplify our selectors, and
|
||||||
|
// 3) support HTML5 form validation.
|
||||||
|
|
||||||
|
.input-group-prepend,
|
||||||
|
.input-group-append {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
// Ensure buttons are always above inputs for more visually pleasing borders.
|
||||||
|
// This isn't needed for `.input-group-text` since it shares the same border-color
|
||||||
|
// as our inputs.
|
||||||
|
.btn {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn + .btn,
|
||||||
|
.btn + .input-group-text,
|
||||||
|
.input-group-text + .input-group-text,
|
||||||
|
.input-group-text + .btn {
|
||||||
|
margin-left: -$input-border-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-prepend { margin-right: -$input-border-width; }
|
||||||
|
.input-group-append { margin-left: -$input-border-width; }
|
||||||
|
|
||||||
|
|
||||||
|
// Textual addons
|
||||||
|
//
|
||||||
|
// Serves as a catch-all element for any text or radio/checkbox input you wish
|
||||||
|
// to prepend or append to an input.
|
||||||
|
|
||||||
|
.input-group-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: $input-padding-y $input-padding-x;
|
||||||
|
margin-bottom: 0; // Allow use of <label> elements by overriding our default margin-bottom
|
||||||
|
font-size: $font-size-base; // Match inputs
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
line-height: $input-line-height;
|
||||||
|
color: $input-group-addon-color;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: $input-group-addon-bg;
|
||||||
|
border: $input-border-width solid $input-group-addon-border-color;
|
||||||
|
@include border-radius($input-border-radius);
|
||||||
|
|
||||||
|
// Nuke default margins from checkboxes and radios to vertically center within.
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sizing
|
||||||
|
//
|
||||||
|
// Remix the default form control sizing classes into new ones for easier
|
||||||
|
// manipulation.
|
||||||
|
|
||||||
|
.input-group-lg > .form-control,
|
||||||
|
.input-group-lg > .input-group-prepend > .input-group-text,
|
||||||
|
.input-group-lg > .input-group-append > .input-group-text,
|
||||||
|
.input-group-lg > .input-group-prepend > .btn,
|
||||||
|
.input-group-lg > .input-group-append > .btn {
|
||||||
|
@extend .form-control-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-sm > .form-control,
|
||||||
|
.input-group-sm > .input-group-prepend > .input-group-text,
|
||||||
|
.input-group-sm > .input-group-append > .input-group-text,
|
||||||
|
.input-group-sm > .input-group-prepend > .btn,
|
||||||
|
.input-group-sm > .input-group-append > .btn {
|
||||||
|
@extend .form-control-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Prepend and append rounded corners
|
||||||
|
//
|
||||||
|
// These rulesets must come after the sizing ones to properly override sm and lg
|
||||||
|
// border-radius values when extending. They're more specific than we'd like
|
||||||
|
// with the `.input-group >` part, but without it, we cannot override the sizing.
|
||||||
|
|
||||||
|
|
||||||
|
.input-group > .input-group-prepend > .btn,
|
||||||
|
.input-group > .input-group-prepend > .input-group-text,
|
||||||
|
.input-group > .input-group-append:not(:last-child) > .btn,
|
||||||
|
.input-group > .input-group-append:not(:last-child) > .input-group-text,
|
||||||
|
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
|
||||||
|
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
|
||||||
|
@include border-right-radius(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group > .input-group-append > .btn,
|
||||||
|
.input-group > .input-group-append > .input-group-text,
|
||||||
|
.input-group > .input-group-prepend:not(:first-child) > .btn,
|
||||||
|
.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
|
||||||
|
.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
|
||||||
|
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {
|
||||||
|
@include border-left-radius(0);
|
||||||
|
}
|
||||||
16
ervws/libs/bootstrap/scss/_jumbotron.scss
Normal file
16
ervws/libs/bootstrap/scss/_jumbotron.scss
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
.jumbotron {
|
||||||
|
padding: $jumbotron-padding ($jumbotron-padding / 2);
|
||||||
|
margin-bottom: $jumbotron-padding;
|
||||||
|
background-color: $jumbotron-bg;
|
||||||
|
@include border-radius($border-radius-lg);
|
||||||
|
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
padding: ($jumbotron-padding * 2) $jumbotron-padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.jumbotron-fluid {
|
||||||
|
padding-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
@include border-radius(0);
|
||||||
|
}
|
||||||
115
ervws/libs/bootstrap/scss/_list-group.scss
Normal file
115
ervws/libs/bootstrap/scss/_list-group.scss
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Base class
|
||||||
|
//
|
||||||
|
// Easily usable on <ul>, <ol>, or <div>.
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
// No need to set list-style: none; since .list-group-item is block level
|
||||||
|
padding-left: 0; // reset padding because ul and ol
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Interactive list items
|
||||||
|
//
|
||||||
|
// Use anchor or button elements instead of `li`s or `div`s to create interactive
|
||||||
|
// list items. Includes an extra `.active` modifier class for selected items.
|
||||||
|
|
||||||
|
.list-group-item-action {
|
||||||
|
width: 100%; // For `<button>`s (anchors become 100% by default though)
|
||||||
|
color: $list-group-action-color;
|
||||||
|
text-align: inherit; // For `<button>`s (anchors inherit)
|
||||||
|
|
||||||
|
// Hover state
|
||||||
|
@include hover-focus {
|
||||||
|
color: $list-group-action-hover-color;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: $list-group-hover-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: $list-group-action-active-color;
|
||||||
|
background-color: $list-group-action-active-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Individual list items
|
||||||
|
//
|
||||||
|
// Use on `li`s or `div`s within the `.list-group` parent.
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: $list-group-item-padding-y $list-group-item-padding-x;
|
||||||
|
// Place the border on the list items and negative margin up for better styling
|
||||||
|
margin-bottom: -$list-group-border-width;
|
||||||
|
background-color: $list-group-bg;
|
||||||
|
border: $list-group-border-width solid $list-group-border-color;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
@include border-top-radius($list-group-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
@include border-bottom-radius($list-group-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include hover-focus {
|
||||||
|
z-index: 1; // Place hover/active items above their siblings for proper border styling
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled,
|
||||||
|
&:disabled {
|
||||||
|
color: $list-group-disabled-color;
|
||||||
|
background-color: $list-group-disabled-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include both here for `<a>`s and `<button>`s
|
||||||
|
&.active {
|
||||||
|
z-index: 2; // Place active items above their siblings for proper border styling
|
||||||
|
color: $list-group-active-color;
|
||||||
|
background-color: $list-group-active-bg;
|
||||||
|
border-color: $list-group-active-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Flush list items
|
||||||
|
//
|
||||||
|
// Remove borders and border-radius to keep list group items edge-to-edge. Most
|
||||||
|
// useful within other components (e.g., cards).
|
||||||
|
|
||||||
|
.list-group-flush {
|
||||||
|
.list-group-item {
|
||||||
|
border-right: 0;
|
||||||
|
border-left: 0;
|
||||||
|
@include border-radius(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
.list-group-item:first-child {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
.list-group-item:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Contextual variants
|
||||||
|
//
|
||||||
|
// Add modifier classes to change text and background color on individual items.
|
||||||
|
// Organizationally, this must come after the `:hover` states.
|
||||||
|
|
||||||
|
@each $color, $value in $theme-colors {
|
||||||
|
@include list-group-item-variant($color, theme-color-level($color, -9), theme-color-level($color, 6));
|
||||||
|
}
|
||||||
8
ervws/libs/bootstrap/scss/_media.scss
Normal file
8
ervws/libs/bootstrap/scss/_media.scss
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.media {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user