feat(forms): автоподстановка банков и улучшенная обработка телефона
- Step1Phone: добавлена обработка вставки телефона с автоматической очисткой от +7 и обрезкой до 10 цифр - Step3Payment: заменён Select на AutoComplete для выбора банка с автоподстановкой - generateConfirmationFormHTML: заменён select на input с datalist для автоподстановки банков в форме подтверждения - Добавлены скрытые поля bank_id для сохранения ID банка отдельно от названия - Добавлены файлы для проверки заявки 226564ce Улучшения UX: - Пользователь может вводить название банка вместо прокрутки длинного списка - Автоматическая фильтрация списка банков при вводе - Предупреждение при обрезке номера телефона при вставке
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
2025-12-01 14:55:09
|
||||
2025-12-02 15:00:08
|
||||
133
ticket_form/check_claim_226564ce.py
Normal file
133
ticket_form/check_claim_226564ce.py
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Проверка заявки 226564ce-d7cf-48ee-a820-690e8f5ec8e5
|
||||
"""
|
||||
import asyncio
|
||||
import asyncpg
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
POSTGRES_HOST = "147.45.189.234"
|
||||
POSTGRES_PORT = 5432
|
||||
POSTGRES_DB = "default_db"
|
||||
POSTGRES_USER = "gen_user"
|
||||
POSTGRES_PASSWORD = "2~~9_^kVsU?2\\S"
|
||||
|
||||
CLAIM_ID = "226564ce-d7cf-48ee-a820-690e8f5ec8e5"
|
||||
|
||||
async def check_claim():
|
||||
conn = await asyncpg.connect(
|
||||
host=POSTGRES_HOST,
|
||||
port=POSTGRES_PORT,
|
||||
database=POSTGRES_DB,
|
||||
user=POSTGRES_USER,
|
||||
password=POSTGRES_PASSWORD
|
||||
)
|
||||
|
||||
try:
|
||||
# 1. Проверяем заявку
|
||||
claim_row = await conn.fetchrow("""
|
||||
SELECT
|
||||
id,
|
||||
status_code,
|
||||
created_at,
|
||||
updated_at,
|
||||
expires_at,
|
||||
payload
|
||||
FROM clpr_claims
|
||||
WHERE id::text = $1 OR payload->>'claim_id' = $1
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1
|
||||
""", CLAIM_ID)
|
||||
|
||||
if not claim_row:
|
||||
print(f"❌ Заявка {CLAIM_ID} не найдена!")
|
||||
return
|
||||
|
||||
print(f"✅ Заявка найдена:")
|
||||
print(f" ID: {claim_row['id']}")
|
||||
print(f" Status: {claim_row['status_code']}")
|
||||
print(f" Created: {claim_row['created_at']}")
|
||||
print(f" Updated: {claim_row['updated_at']}")
|
||||
print(f" Expires: {claim_row['expires_at']}")
|
||||
|
||||
payload = claim_row['payload'] if isinstance(claim_row['payload'], dict) else json.loads(claim_row['payload'])
|
||||
|
||||
# 2. Проверяем documents_meta
|
||||
documents_meta = payload.get('documents_meta', [])
|
||||
print(f"\n📋 documents_meta: {len(documents_meta)} записей")
|
||||
|
||||
if documents_meta:
|
||||
# Проверяем на дубликаты
|
||||
field_names = [doc.get('field_name') for doc in documents_meta]
|
||||
duplicates = [name for name in field_names if field_names.count(name) > 1]
|
||||
|
||||
if duplicates:
|
||||
print(f" ⚠️ Найдены дубликаты field_name: {set(duplicates)}")
|
||||
|
||||
for i, doc in enumerate(documents_meta):
|
||||
print(f"\n {i+1}. field_name: {doc.get('field_name', 'N/A')}")
|
||||
print(f" field_label: {doc.get('field_label', 'N/A')}")
|
||||
print(f" file_id: {doc.get('file_id', 'N/A')}")
|
||||
print(f" file_name: {doc.get('file_name', 'N/A')}")
|
||||
print(f" uploaded_at: {doc.get('uploaded_at', 'N/A')}")
|
||||
else:
|
||||
print(" ⚠️ documents_meta пуст!")
|
||||
|
||||
# 3. Проверяем документы в таблице
|
||||
claim_uuid = claim_row['id']
|
||||
docs_rows = await conn.fetch("""
|
||||
SELECT
|
||||
id,
|
||||
claim_id,
|
||||
field_name,
|
||||
file_id,
|
||||
file_name,
|
||||
original_file_name,
|
||||
uploaded_at,
|
||||
file_hash
|
||||
FROM clpr_claim_documents
|
||||
WHERE claim_id = $1
|
||||
ORDER BY uploaded_at DESC
|
||||
""", str(claim_uuid))
|
||||
|
||||
print(f"\n📄 Документы в clpr_claim_documents: {len(docs_rows)} записей")
|
||||
for i, row in enumerate(docs_rows):
|
||||
print(f"\n {i+1}. field_name: {row['field_name']}")
|
||||
print(f" file_id: {row['file_id']}")
|
||||
print(f" file_name: {row['file_name']}")
|
||||
print(f" file_hash: {row['file_hash'] or 'NULL'}")
|
||||
print(f" uploaded_at: {row['uploaded_at']}")
|
||||
|
||||
# 4. Сравниваем documents_meta и clpr_claim_documents
|
||||
print(f"\n🔍 Сравнение:")
|
||||
meta_field_names = set(doc.get('field_name') for doc in documents_meta)
|
||||
table_field_names = set(row['field_name'] for row in docs_rows)
|
||||
|
||||
only_in_meta = meta_field_names - table_field_names
|
||||
only_in_table = table_field_names - meta_field_names
|
||||
|
||||
if only_in_meta:
|
||||
print(f" ⚠️ Только в documents_meta: {only_in_meta}")
|
||||
if only_in_table:
|
||||
print(f" ⚠️ Только в clpr_claim_documents: {only_in_table}")
|
||||
if not only_in_meta and not only_in_table:
|
||||
print(f" ✅ Все field_name совпадают")
|
||||
|
||||
# 5. Проверяем поле upload_description
|
||||
upload_description = payload.get('upload_description')
|
||||
print(f"\n📝 upload_description: {upload_description}")
|
||||
|
||||
# 6. Проверяем answers
|
||||
answers = payload.get('answers', {})
|
||||
print(f"\n💬 answers: {len(answers)} полей")
|
||||
if answers:
|
||||
for key, value in list(answers.items())[:5]: # Первые 5
|
||||
print(f" {key}: {str(value)[:50]}...")
|
||||
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(check_claim())
|
||||
|
||||
94
ticket_form/docs/CLAIM_226564ce_STATUS.md
Normal file
94
ticket_form/docs/CLAIM_226564ce_STATUS.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Статус заявки 226564ce-d7cf-48ee-a820-690e8f5ec8e5
|
||||
|
||||
## ✅ Общая информация
|
||||
|
||||
- **ID**: `226564ce-d7cf-48ee-a820-690e8f5ec8e5`
|
||||
- **Status**: `draft_docs_complete`
|
||||
- **Unified ID**: `usr_b1fbffa0-477b-4abb-95d6-8d6f849ddc71`
|
||||
- **Session Token**: `sess_c278abf8-1603-484d-af98-8b93843e5253`
|
||||
- **Phone**: `71234543212`
|
||||
- **Channel**: `web_form`
|
||||
- **Is Confirmed**: `false` (должна отображаться в списке)
|
||||
- **Created**: `2025-12-01 14:38:11`
|
||||
- **Updated**: `2025-12-01 20:06:18`
|
||||
- **Expires**: `2025-12-15 19:35:30`
|
||||
|
||||
## ✅ Документы
|
||||
|
||||
### documents_meta (2 записи)
|
||||
|
||||
1. **uploads[1][0]**
|
||||
- `field_label`: "Чек или подтверждение оплаты" ✅ (правильно, не "group-2")
|
||||
- `file_id`: `/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/crm2/CRM_Active_Files/Documents/Project/ERV_3212_КлиентПрав_399543/e34f2f9e-e48d-47f4-9c2d-6957012c0800__chek-ili-podtverzhdenie-oplaty.pdf`
|
||||
- `file_name`: `e34f2f9e-e48d-47f4-9c2d-6957012c0800__chek-ili-podtverzhdenie-oplaty.pdf`
|
||||
- `uploaded_at`: `2025-12-01T14:15:54.122Z`
|
||||
|
||||
2. **uploads[0][0]**
|
||||
- `field_label`: "Договор или заказ" ✅ (правильно)
|
||||
- `file_id`: `/f9825c87-4e3558f6-f9b6-405c-ad3d-d1535c49b61c/crm2/CRM_Active_Files/Documents/Project/ERV_3212_КлиентПрав_399543/344deab2-1a3a-46ce-931b-5a29bb2c40a3__dogovor-ili-zakaz.pdf`
|
||||
- `file_name`: `344deab2-1a3a-46ce-931b-5a29bb2c40a3__dogovor-ili-zakaz.pdf`
|
||||
- `uploaded_at`: `2025-12-01T13:47:15.772Z`
|
||||
|
||||
### clpr_claim_documents (2 записи)
|
||||
|
||||
1. **uploads[1][0]**
|
||||
- `id`: `e34f2f9e-e48d-47f4-9c2d-6957012c0800`
|
||||
- `file_hash`: `3e1f1332a76b7f26df1628c49579f30a873de9170f3b8007b0bac5e4a439ca67` ✅
|
||||
|
||||
2. **uploads[0][0]**
|
||||
- `id`: `344deab2-1a3a-46ce-931b-5a29bb2c40a3`
|
||||
- `file_hash`: `83822e59662aa2037977dc5a8661d8a057ae6572e6f99936a31c6cdd7d66f1d9` ✅
|
||||
|
||||
## ✅ Проверки
|
||||
|
||||
- ✅ **Дубликатов нет** — все `field_name` уникальны
|
||||
- ✅ **field_label правильные** — не "group-2", а реальные названия
|
||||
- ✅ **Синхронизация** — `documents_meta` и `clpr_claim_documents` совпадают
|
||||
- ✅ **file_hash заполнен** — оба документа имеют хеш
|
||||
- ✅ **Заявка должна отображаться** — `is_confirmed = false`, `status_code != 'approved'`
|
||||
|
||||
## 📋 Payload структура
|
||||
|
||||
Заявка содержит следующие ключи в `payload`:
|
||||
- `body`
|
||||
- `email`
|
||||
- `phone`
|
||||
- `tg_id`
|
||||
- `answers`
|
||||
- `claim_id`
|
||||
- `applicant`
|
||||
- `contact_id`
|
||||
- `form_draft`
|
||||
- `ai_analysis`
|
||||
- `claim_ready`
|
||||
- `wizard_plan`
|
||||
- `wizard_ready`
|
||||
- `ai_agent13_rag`
|
||||
- `documents_meta` ✅
|
||||
- `ai_agent1_facts`
|
||||
- `answers_prefill`
|
||||
- `current_doc_index`
|
||||
- `documents_skipped`
|
||||
- `documents_required`
|
||||
- `documents_uploaded`
|
||||
- `problem_description`
|
||||
|
||||
## 🔍 Возможные проблемы с отображением
|
||||
|
||||
Если заявка не отображается или отображается неправильно, проверьте:
|
||||
|
||||
1. **API endpoint `/drafts/list`** — должен находить заявку по `unified_id`, `phone` или `session_token`
|
||||
2. **Фронтенд фильтрация** — возможно, фильтруется по `status_code`
|
||||
3. **Отображение `field_label`** — должно использовать `documents_meta[].field_label`, а не вычислять из `field_name`
|
||||
|
||||
## ✅ Вывод
|
||||
|
||||
**Заявка в порядке!** Все данные корректны:
|
||||
- ✅ Нет дубликатов в `documents_meta`
|
||||
- ✅ `field_label` правильные
|
||||
- ✅ Документы синхронизированы
|
||||
- ✅ `file_hash` заполнен
|
||||
- ✅ Заявка должна отображаться в списке
|
||||
|
||||
Если есть проблемы с отображением, они скорее всего на стороне фронтенда или API фильтрации.
|
||||
|
||||
@@ -278,6 +278,25 @@ export default function Step1Phone({
|
||||
maxLength={10}
|
||||
size="large"
|
||||
style={{ flex: 1 }}
|
||||
onPaste={(e) => {
|
||||
// Обработка вставки: очищаем от +7, пробелов и других символов
|
||||
e.preventDefault();
|
||||
const pastedText = (e.clipboardData || (window as any).clipboardData).getData('text');
|
||||
// Убираем все нецифровые символы
|
||||
let cleanText = pastedText.replace(/\D/g, '');
|
||||
// Если начинается с 7 или 8, убираем первую цифру (код страны)
|
||||
if (cleanText.length === 11 && (cleanText.startsWith('7') || cleanText.startsWith('8'))) {
|
||||
cleanText = cleanText.substring(1);
|
||||
}
|
||||
// Оставляем только первые 10 цифр
|
||||
cleanText = cleanText.substring(0, 10);
|
||||
// Устанавливаем очищенное значение
|
||||
form.setFieldValue('phone', cleanText);
|
||||
// Показываем предупреждение, если номер был обрезан
|
||||
if (pastedText.replace(/\D/g, '').length > 10) {
|
||||
message.warning('Номер автоматически обрезан до 10 цифр');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Space.Compact>
|
||||
</Form.Item>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Form, Input, Button, Select, message, Space, Divider } from 'antd';
|
||||
import { Form, Input, Button, AutoComplete, message, Space, Divider } from 'antd';
|
||||
import { PhoneOutlined, SafetyOutlined, QrcodeOutlined, MailOutlined, CopyOutlined } from '@ant-design/icons';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8200';
|
||||
const NSPK_BANKS_API = 'http://212.193.27.93/api/payouts/dictionaries/nspk-banks';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
interface Bank {
|
||||
bankid: string;
|
||||
bankname: string;
|
||||
@@ -61,15 +59,34 @@ export default function Step3Payment({
|
||||
setBanks(banksData);
|
||||
addDebugEvent?.('banks', 'success', `✅ Загружено ${banksData.length} банков`, { count: banksData.length });
|
||||
|
||||
// Если есть сохранённый bankName, но нет bankId - пытаемся найти по названию
|
||||
if (formData.bankName && !formData.bankId) {
|
||||
// Если есть сохранённый bankName или bankId - восстанавливаем значения
|
||||
if (formData.bankName) {
|
||||
const foundBank = banksData.find(b =>
|
||||
b.bankname.toLowerCase() === formData.bankName.toLowerCase() ||
|
||||
b.bankname.toLowerCase().includes(formData.bankName.toLowerCase())
|
||||
);
|
||||
if (foundBank) {
|
||||
updateFormData({ bankId: foundBank.bankid });
|
||||
form.setFieldsValue({ bankId: foundBank.bankid });
|
||||
updateFormData({
|
||||
bankId: foundBank.bankid,
|
||||
bankName: foundBank.bankname
|
||||
});
|
||||
form.setFieldsValue({
|
||||
bankId: foundBank.bankid,
|
||||
bankName: foundBank.bankname
|
||||
});
|
||||
}
|
||||
} else if (formData.bankId) {
|
||||
// Если есть только bankId, находим по ID
|
||||
const foundBank = banksData.find(b => b.bankid === formData.bankId);
|
||||
if (foundBank) {
|
||||
updateFormData({
|
||||
bankId: foundBank.bankid,
|
||||
bankName: foundBank.bankname
|
||||
});
|
||||
form.setFieldsValue({
|
||||
bankId: foundBank.bankid,
|
||||
bankName: foundBank.bankname
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
@@ -189,12 +206,15 @@ export default function Step3Payment({
|
||||
}
|
||||
};
|
||||
|
||||
// Инициализация формы с bankId если есть
|
||||
// Инициализация формы с bankId и bankName если есть
|
||||
useEffect(() => {
|
||||
if (formData.bankId) {
|
||||
form.setFieldsValue({ bankId: formData.bankId });
|
||||
if (formData.bankId || formData.bankName) {
|
||||
form.setFieldsValue({
|
||||
bankId: formData.bankId,
|
||||
bankName: formData.bankName
|
||||
});
|
||||
}
|
||||
}, [formData.bankId, form]);
|
||||
}, [formData.bankId, formData.bankName, form]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
@@ -202,7 +222,8 @@ export default function Step3Payment({
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
...formData,
|
||||
bankId: formData.bankId || formData.bankName, // Fallback на bankName для совместимости
|
||||
bankId: formData.bankId,
|
||||
bankName: formData.bankName,
|
||||
}}
|
||||
style={{ marginTop: 24 }}
|
||||
>
|
||||
@@ -377,40 +398,78 @@ export default function Step3Payment({
|
||||
</div>
|
||||
</Form.Item>
|
||||
|
||||
{/* Скрытое поле для bankId */}
|
||||
<Form.Item name="bankId" hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Выберите ваш банк"
|
||||
name="bankId"
|
||||
rules={[{ required: true, message: 'Выберите банк для получения выплаты' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder={banksLoading ? "Загрузка списка банков..." : "Выберите банк"}
|
||||
size="large"
|
||||
showSearch
|
||||
loading={banksLoading}
|
||||
notFoundContent={banksLoading ? "Загрузка..." : "Банк не найден"}
|
||||
filterOption={(input: string, option: any) => {
|
||||
const label = option?.label || option?.children;
|
||||
if (typeof label === 'string') {
|
||||
return label.toLowerCase().includes(input.toLowerCase());
|
||||
label="Банк для получения выплаты"
|
||||
name="bankName"
|
||||
rules={[
|
||||
{ required: true, message: 'Выберите банк для получения выплаты' },
|
||||
{
|
||||
validator: (_, value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const foundBank = banks.find(b =>
|
||||
b.bankname.toLowerCase() === value.toLowerCase()
|
||||
);
|
||||
if (!foundBank) {
|
||||
return Promise.reject(new Error('Выберите банк из списка'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
]}
|
||||
>
|
||||
<AutoComplete
|
||||
placeholder={banksLoading ? "Загрузка списка банков..." : "Начните вводить название банка"}
|
||||
size="large"
|
||||
loading={banksLoading}
|
||||
notFoundContent={banksLoading ? "Загрузка..." : "Банк не найден. Попробуйте ввести другое название"}
|
||||
options={banks.map((bank) => ({
|
||||
value: bank.bankname,
|
||||
label: bank.bankname,
|
||||
}))}
|
||||
filterOption={(inputValue, option) => {
|
||||
if (!option?.label) return false;
|
||||
return option.label.toLowerCase().includes(inputValue.toLowerCase());
|
||||
}}
|
||||
onChange={(value) => {
|
||||
const selectedBank = banks.find(b => b.bankid === value);
|
||||
onSelect={(value) => {
|
||||
// При выборе из списка находим банк и сохраняем оба поля
|
||||
const selectedBank = banks.find(b => b.bankname === value);
|
||||
if (selectedBank) {
|
||||
updateFormData({
|
||||
bankId: selectedBank.bankid,
|
||||
bankName: selectedBank.bankname
|
||||
});
|
||||
// Устанавливаем bankId в скрытое поле
|
||||
form.setFieldsValue({ bankId: selectedBank.bankid });
|
||||
}
|
||||
}}
|
||||
>
|
||||
{banks.map((bank) => (
|
||||
<Option key={bank.bankid} value={bank.bankid} label={bank.bankname}>
|
||||
{bank.bankname}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
onChange={(value) => {
|
||||
// При вводе текста ищем точное совпадение по названию
|
||||
if (typeof value === 'string') {
|
||||
const foundBank = banks.find(b =>
|
||||
b.bankname.toLowerCase() === value.toLowerCase()
|
||||
);
|
||||
if (foundBank) {
|
||||
updateFormData({
|
||||
bankId: foundBank.bankid,
|
||||
bankName: foundBank.bankname
|
||||
});
|
||||
form.setFieldsValue({ bankId: foundBank.bankid });
|
||||
} else if (value === '') {
|
||||
// Если поле очищено, очищаем и bankId
|
||||
updateFormData({ bankId: undefined, bankName: undefined });
|
||||
form.setFieldsValue({ bankId: undefined });
|
||||
}
|
||||
}
|
||||
}}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
|
||||
@@ -775,10 +775,16 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
|
||||
function createBankSelect(root, key, value) {
|
||||
var id = 'field_' + root + '_' + key + '_' + Math.random().toString(36).slice(2);
|
||||
var selectHtml = '<select class="inline-field bind bank-select" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '">';
|
||||
selectHtml += '<option value="">Загрузка списка банков...</option>';
|
||||
selectHtml += '</select>';
|
||||
return selectHtml;
|
||||
var datalistId = 'bank-datalist-' + id;
|
||||
// Создаём input с datalist для автоподстановки
|
||||
var inputHtml = '<input type="text" class="inline-field bind bank-select" data-root="' + esc(root) + '" data-key="' + esc(key) + '" id="' + id + '" list="' + datalistId + '" placeholder="Начните вводить название банка" autocomplete="off" />';
|
||||
inputHtml += '<datalist id="' + datalistId + '" class="bank-datalist">';
|
||||
inputHtml += '<option value="">Загрузка списка банков...</option>';
|
||||
inputHtml += '</datalist>';
|
||||
// Скрытое поле для bank_id
|
||||
var hiddenId = id + '_id';
|
||||
inputHtml += '<input type="hidden" class="bank-id-field" data-root="' + esc(root) + '" data-key="bank_id" id="' + hiddenId + '" />';
|
||||
return inputHtml;
|
||||
}
|
||||
|
||||
function createCheckbox(root, key, checked, labelText, required) {
|
||||
@@ -1240,6 +1246,19 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
var fields = document.querySelectorAll('.bind');
|
||||
console.log('Found fields:', fields.length);
|
||||
|
||||
// Обработка скрытых полей bank_id
|
||||
var bankIdFields = document.querySelectorAll('.bank-id-field');
|
||||
Array.prototype.forEach.call(bankIdFields, function(field) {
|
||||
field.addEventListener('change', function() {
|
||||
var root = this.getAttribute('data-root');
|
||||
var value = this.value;
|
||||
if (root === 'user') {
|
||||
state.user = state.user || {};
|
||||
state.user.bank_id = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ✅ Устанавливаем начальный стиль для всех полей и форматируем телефоны
|
||||
Array.prototype.forEach.call(fields, function(field) {
|
||||
var key = field.getAttribute('data-key');
|
||||
@@ -1335,6 +1354,12 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
// Обновляем состояние
|
||||
if (root === 'user') {
|
||||
state.user = state.user || {};
|
||||
// Для bank_id не сохраняем название банка, только ID из скрытого поля
|
||||
if (key === 'bank_id' && this.classList.contains('bank-select')) {
|
||||
// Это текстовое поле для названия банка - не сохраняем в state
|
||||
// bank_id будет сохранён из скрытого поля
|
||||
return;
|
||||
}
|
||||
state.user[key] = value;
|
||||
|
||||
// Обновляем телефон в СБП
|
||||
@@ -1437,8 +1462,8 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
|
||||
// Загрузка списка банков СБП
|
||||
function loadBanks() {
|
||||
var bankSelects = document.querySelectorAll('.bank-select');
|
||||
if (bankSelects.length === 0) {
|
||||
var bankInputs = document.querySelectorAll('.bank-select');
|
||||
if (bankInputs.length === 0) {
|
||||
console.log('Bank select fields not found');
|
||||
return;
|
||||
}
|
||||
@@ -1458,32 +1483,109 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
return a.bankname.localeCompare(b.bankname, 'ru');
|
||||
});
|
||||
|
||||
// Заполняем все bank-select элементы
|
||||
Array.prototype.forEach.call(bankSelects, function(select) {
|
||||
var currentValue = select.getAttribute('data-selected') || state.user?.bank_id || '';
|
||||
select.innerHTML = '<option value="">Выберите банк</option>';
|
||||
// Сохраняем список банков глобально для поиска
|
||||
window.__banksList = banks;
|
||||
|
||||
// Заполняем все datalist элементы
|
||||
Array.prototype.forEach.call(bankInputs, function(input) {
|
||||
var datalistId = input.getAttribute('list');
|
||||
var datalist = document.getElementById(datalistId);
|
||||
var hiddenId = input.id + '_id';
|
||||
var hiddenField = document.getElementById(hiddenId);
|
||||
var currentBankId = state.user?.bank_id || '';
|
||||
var currentBankName = '';
|
||||
|
||||
if (!datalist) {
|
||||
console.error('Datalist not found for input:', input.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Очищаем datalist
|
||||
datalist.innerHTML = '';
|
||||
|
||||
// Заполняем datalist опциями
|
||||
banks.forEach(function(bank) {
|
||||
var option = document.createElement('option');
|
||||
option.value = bank.bankid;
|
||||
option.textContent = bank.bankname;
|
||||
if (bank.bankid === currentValue) {
|
||||
option.selected = true;
|
||||
option.value = bank.bankname;
|
||||
option.setAttribute('data-bank-id', bank.bankid);
|
||||
datalist.appendChild(option);
|
||||
|
||||
// Если это текущий банк, устанавливаем значение
|
||||
if (bank.bankid === currentBankId) {
|
||||
currentBankName = bank.bankname;
|
||||
}
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
// Если выбран банк, обновляем стиль
|
||||
if (currentValue && select.value) {
|
||||
select.classList.add('filled');
|
||||
updateFieldStyle(select);
|
||||
// Устанавливаем текущее значение если есть
|
||||
if (currentBankName) {
|
||||
input.value = currentBankName;
|
||||
if (hiddenField) {
|
||||
hiddenField.value = currentBankId;
|
||||
}
|
||||
input.classList.add('filled');
|
||||
updateFieldStyle(input);
|
||||
}
|
||||
|
||||
// Обработчик изменения для поиска банка по названию
|
||||
input.addEventListener('input', function() {
|
||||
var inputValue = this.value.trim();
|
||||
var foundBank = null;
|
||||
|
||||
// Ищем точное совпадение
|
||||
if (inputValue) {
|
||||
foundBank = banks.find(function(b) {
|
||||
return b.bankname.toLowerCase() === inputValue.toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
if (foundBank) {
|
||||
// Найден банк - сохраняем ID
|
||||
if (hiddenField) {
|
||||
hiddenField.value = foundBank.bankid;
|
||||
}
|
||||
state.user = state.user || {};
|
||||
state.user.bank_id = foundBank.bankid;
|
||||
this.classList.add('filled');
|
||||
} else {
|
||||
// Банк не найден - очищаем ID
|
||||
if (hiddenField) {
|
||||
hiddenField.value = '';
|
||||
}
|
||||
state.user = state.user || {};
|
||||
state.user.bank_id = '';
|
||||
this.classList.remove('filled');
|
||||
}
|
||||
updateFieldStyle(this);
|
||||
updateSubmitButton();
|
||||
});
|
||||
|
||||
// Обработчик выбора из списка
|
||||
input.addEventListener('change', function() {
|
||||
var inputValue = this.value.trim();
|
||||
var foundBank = banks.find(function(b) {
|
||||
return b.bankname.toLowerCase() === inputValue.toLowerCase();
|
||||
});
|
||||
|
||||
if (foundBank) {
|
||||
if (hiddenField) {
|
||||
hiddenField.value = foundBank.bankid;
|
||||
}
|
||||
state.user = state.user || {};
|
||||
state.user.bank_id = foundBank.bankid;
|
||||
this.classList.add('filled');
|
||||
updateFieldStyle(this);
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error('Error loading banks:', error);
|
||||
Array.prototype.forEach.call(bankSelects, function(select) {
|
||||
select.innerHTML = '<option value="">Ошибка загрузки банков. Обновите страницу.</option>';
|
||||
Array.prototype.forEach.call(bankInputs, function(input) {
|
||||
var datalistId = input.getAttribute('list');
|
||||
var datalist = document.getElementById(datalistId);
|
||||
if (datalist) {
|
||||
datalist.innerHTML = '<option value="">Ошибка загрузки банков. Обновите страницу.</option>';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1552,6 +1654,17 @@ export function generateConfirmationFormHTML(data: any): string {
|
||||
return;
|
||||
}
|
||||
|
||||
// Собираем bank_id из скрытых полей перед отправкой
|
||||
var bankIdFields = document.querySelectorAll('.bank-id-field');
|
||||
Array.prototype.forEach.call(bankIdFields, function(field) {
|
||||
var root = field.getAttribute('data-root');
|
||||
var bankId = field.value;
|
||||
if (root === 'user' && bankId) {
|
||||
state.user = state.user || {};
|
||||
state.user.bank_id = bankId;
|
||||
}
|
||||
});
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'claim_confirmed',
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user