/
killogram
/
E-Analyzer
Обзор
Документация
Войти
/
killogram
/
E-Analyzer
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
frontend/app.js
484 строки
27 KB
Korabliov Kirill
Refactor add purchase feachure
01 июн 2025, 23:54
01 июн 2025, 23:54
9d93c35
Код
Авторство
О чём код?
document.addEventListener('DOMContentLoaded', () => { // Search functionality if (document.getElementById('searchInput')) { const searchInput = document.getElementById('searchInput'); const searchButton = document.getElementById('searchButton'); const purchasesList = document.getElementById('purchasesList'); const trackedPurchasesList = document.createElement('div'); trackedPurchasesList.id = 'trackedPurchasesList'; trackedPurchasesList.innerHTML = '<h2 class="text-xl font-semibold mt-6 mb-2">Отслеживаемые закупки</h2>'; document.getElementById('container').appendChild(trackedPurchasesList); const searchPurchases = async (query) => { if (!query) { purchasesList.innerHTML = '<p class="text-gray-500">Введите запрос</p>'; return; } try { const response = await fetch(`http://localhost:8000/purchases/search/?query=${encodeURIComponent(query)}`); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const purchases = await response.json(); displayPurchases(purchases); } catch (error) { console.error('Ошибка поиска:', error); purchasesList.innerHTML = '<p class="text-red-500">Ошибка поиска закупок</p>'; } }; const displayPurchases = (purchases) => { purchasesList.innerHTML = purchases.length > 0 ? purchases.map(purchase => ` <div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition card"> <a href="purchases.html?registry_number=${encodeURIComponent(purchase.registry_number)}" class="flex-1"> <div> <p class="text-gray-700"><strong>Реестровый номер:</strong> ${purchase.registry_number}</p> <p class="text-gray-700"><strong>Наименование:</strong> ${purchase.name}</p> </div> </a> <select class="status-select p-2 border rounded ml-4" data-purchase-id="${purchase.id}"> <option value="">Выберите статус</option> <option value="Интересно">Интересно</option> <option value="Участвую">Участвую</option> <option value="Выиграл">Выиграл</option> <option value="Проиграл">Проиграл</option> <option value="Анализ">Анализ</option> <option value="Нейинтересно">Нейинтересно</option> </select> </div> `).join('') : '<p class="text-gray-500">Закупки не найдены</p>'; document.querySelectorAll('.status-select').forEach(select => { select.addEventListener('change', async (e) => { e.stopPropagation(); const purchaseId = parseInt(e.target.dataset.purchaseId); const status = e.target.value; if (status) { await trackPurchase(purchaseId, status); e.target.value = ''; loadTrackedPurchases(); } }); select.addEventListener('click', (e) => e.stopPropagation()); }); }; const loadTrackedPurchases = async () => { try { const response = await fetch('http://localhost:8000/tracked/tracked_purchases/'); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const trackedPurchases = await response.json(); displayTrackedPurchases(trackedPurchases); } catch (error) { console.error('Ошибка загрузки отслеживаемых закупок:', error); trackedPurchasesList.innerHTML += '<p class="text-red-500">Ошибка загрузки отслеживаемых закупок</p>'; } }; const displayTrackedPurchases = async (trackedPurchases) => { const list = trackedPurchasesList; list.innerHTML = '<h2 class="text-xl font-semibold mt-6 mb-2">Отслеживаемые закупки</h2>'; if (trackedPurchases.length === 0) { list.innerHTML += '<p class="text-gray-500">Нет отслеживаемых закупок</p>'; return; } for (const tp of trackedPurchases) { try { const response = await fetch(`http://localhost:8000/purchases/by_id/${tp.purchase_id}`); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const purchase = await response.json(); list.innerHTML += ` <div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition card"> <a href="purchases.html?registry_number=${encodeURIComponent(purchase.registry_number)}" class="flex-1"> <div> <p class="text-gray-700"><strong>Наименование:</strong> ${purchase.name}</p> </div> </a> <select class="status-select p-2 border rounded ml-4" data-purchase-id="${tp.purchase_id}"> <option value="">Выберите статус</option> <option value="Интересно" ${tp.status === 'Интересно' ? 'selected' : ''}>Интересно</option> <option value="Участвую" ${tp.status === 'Участвую' ? 'selected' : ''}>Участвую</option> <option value="Выиграл" ${tp.status === 'Выиграл' ? 'selected' : ''}>Выиграл</option> <option value="Проиграл" ${tp.status === 'Проиграл' ? 'selected' : ''}>Проиграл</option> <option value="Анализ" ${tp.status === 'Анализ' ? 'selected' : ''}>Анализ</option> <option value="Нейинтересно" ${tp.status === 'Нейинтересно' ? 'selected' : ''}>Нейинтересно</option> <option value="Скрыто" ${tp.status === 'Скрыто' ? 'selected' : ''}>Скрыть</option> </select> </div> `; } catch (error) { console.error('Ошибка загрузки закупки:', error); } } document.querySelectorAll('.status-select').forEach(select => { select.addEventListener('change', async (e) => { e.stopPropagation(); const purchaseId = parseInt(e.target.dataset.purchaseId); const status = e.target.value; if (status) { await updateTrackedPurchaseStatus(purchaseId, status); e.target.value = status; loadTrackedPurchases(); } }); select.addEventListener('click', (e) => e.stopPropagation()); }); }; const trackPurchase = async (purchaseId, status) => { try { const response = await fetch('http://localhost:8000/tracked/track_purchase/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ purchase_id: purchaseId, status: status }) }); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const data = await response.json(); alert('Закупка добавлена в отслеживаемые!'); } catch (error) { console.error('Ошибка добавления в отслеживаемые:', error); alert('Ошибка добавления в отслеживаемые'); } }; const updateTrackedPurchaseStatus = async (purchaseId, status) => { try { const response = await fetch(`http://localhost:8000/tracked/tracked_purchase/${purchaseId}?status=${encodeURIComponent(status)}`, { method: 'PUT' }); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const data = await response.json(); alert(status === 'Скрыто' ? 'Закупка удалена из отслеживаемых!' : 'Статус обновлен!'); } catch (error) { console.error('Ошибка обновления статуса:', error); alert('Ошибка обновления статуса'); } }; let debounceTimeout; searchInput.addEventListener('input', () => { clearTimeout(debounceTimeout); debounceTimeout = setTimeout(() => { const query = searchInput.value.trim(); searchPurchases(query); }, 300); }); searchButton.addEventListener('click', () => searchPurchases(searchInput.value.trim())); searchInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') searchPurchases(searchInput.value.trim()); }); loadTrackedPurchases(); } // Purchase details functionality if (document.getElementById('purchaseContent')) { const purchaseContent = document.getElementById('purchaseContent'); const pricesContent = document.getElementById('pricesContent'); const datesContent = document.getElementById('datesContent'); const customersContent = document.getElementById('customersContent'); async function loadPurchaseDetails() { const urlParams = new URLSearchParams(window.location.search); const registryNumber = urlParams.get('registry_number'); if (!registryNumber) { purchaseContent.innerHTML = '<p class="text-red-500">Закупка не указана</p>'; return; } purchaseContent.innerHTML = '<p class="text-gray-500">Загрузка закупки...</p>'; pricesContent.innerHTML = '<p class="text-gray-500">Загрузка цен...</p>'; datesContent.innerHTML = '<p class="text-gray-500">Загрузка дат...</p>'; customersContent.innerHTML = '<p class="text-gray-500">Загрузка заказчиков...</p>'; try { const purchaseUrl = `http://localhost:8000/purchases/${encodeURIComponent(registryNumber)}`; const purchaseResponse = await fetch(purchaseUrl); if (!purchaseResponse.ok) throw new Error(`HTTP error ${purchaseResponse.status}`); const purchase = await purchaseResponse.json(); displayPurchaseDetails(purchase); try { const pricesUrl = `http://localhost:8000/prices/${purchase.id}`; const pricesResponse = await fetch(pricesUrl); if (!pricesResponse.ok) throw new Error(`HTTP error ${pricesResponse.status}`); const prices = await pricesResponse.json(); displayPrices(prices); } catch (error) { console.error('Ошибка загрузки цен:', error); pricesContent.innerHTML = '<p class="text-red-500">Цены не найдены</p>'; } try { const datesUrl = `http://localhost:8000/dates/${purchase.id}`; const datesResponse = await fetch(datesUrl); if (!datesResponse.ok) throw new Error(`HTTP error ${datesResponse.status}`); const dates = await datesResponse.json(); displayDates(dates); } catch (error) { console.error('Ошибка загрузки дат:', error); datesContent.innerHTML = '<p class="text-red-500">Даты не найдены</p>'; } try { const customersUrl = `http://localhost:8000/customers/${purchase.id}/customers`; // Исправлено: убран /api const customersResponse = await fetch(customersUrl); console.log('Ответ сервера для заказчиков:', customersResponse); // Отладка if (!customersResponse.ok) throw new Error(`HTTP error ${customersResponse.status}`); const customers = await customersResponse.json(); console.log('Полученные заказчики:', customers); // Отладка displayCustomers(customers, purchase.id); } catch (error) { console.error('Ошибка загрузки заказчиков:', error); customersContent.innerHTML = '<p class="text-red-500">Заказчики не найдены</p>'; } } catch (error) { console.error('Ошибка загрузки закупки:', error); purchaseContent.innerHTML = '<p class="text-red-500">Ошибка загрузки закупки</p>'; } } async function trackPurchase(purchaseId, status) { try { const response = await fetch('http://localhost:8000/tracked/track_purchase/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ purchase_id: purchaseId, status: status }) }); if (!response.ok) throw new Error(`HTTP error ${response.status}`); const data = await response.json(); alert('Закупка добавлена в отслеживаемые!'); } catch (error) { console.error('Ошибка добавления в отслеживаемые:', error); alert('Ошибка добавления в отслеживаемые'); } } function displayPurchaseDetails(purchase) { const extraDataHtml = purchase.extra_data ? `<ul class="list-disc pl-5">${Object.entries(purchase.extra_data) .filter(([_, value]) => value !== null && value !== undefined && !isNaN(value) && value !== '') .map(([key, value]) => `<li><strong>${key}:</strong> ${Array.isArray(value) ? value.join(', ') : value}</li>`).join('')}</ul>` : 'Отсутствуют'; purchaseContent.innerHTML = ` <div class="bg-white p-6 rounded-lg shadow-md mb-6"> <h3 class="text-xl font-semibold mb-4 text-green-500">Основная информация</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div> <p class="text-sm text-gray-600">Реестровый номер</p> <p class="text-gray-900">${purchase.registry_number}</p> </div> <div> <p class="text-sm text-gray-600">Наименование</p> <p class="text-gray-900">${purchase.name}</p> </div> <div> <p class="text-sm text-gray-600">Стадия</p> <p class="text-gray-900">${purchase.stage}</p> </div> <div> <p class="text-sm text-gray-600">Метод</p> <p class="text-gray-900">${purchase.method}</p> </div> <div> <p class="text-sm text-gray-600">Закон</p> <p class="text-gray-900">${purchase.law}</p> </div> <div> <p class="text-sm text-gray-600">ОКПД2</p> <p class="text-gray-900">${purchase.okpd2 || 'Отсутствует'}</p> </div> <div> <p class="text-sm text-gray-600">Дополнительные данные</p> <p class="text-gray-900">${extraDataHtml}</p> </div> <div> <p class="text-sm text-gray-600">Создано</p> <p class="text-gray-900">${purchase.created_at ? new Date(purchase.created_at).toLocaleString('ru-RU') : 'Отсутствует'}</p> </div> <div> <p class="text-sm text-gray-600">Обновлено</p> <p class="text-gray-900">${purchase.updated_at ? new Date(purchase.updated_at).toLocaleString('ru-RU') : 'Отсутствует'}</p> </div> </div> <div class="mt-4"> <label for="statusSelect" class="text-sm text-gray-600">Статус отслеживания:</label> <select id="statusSelect" class="status-select p-2 border rounded"> <option value="">Выберите статус</option> <option value="Интересно">Интересно</option> <option value="Участвую">Участвую</option> <option value="Выиграл">Выиграл</option> <option value="Проиграл">Проиграл</option> <option value="Анализ">Анализ</option> <option value="Нейинтересно">Нейинтересно</option> </select> </div> </div> `; document.getElementById('statusSelect').addEventListener('change', (e) => { const status = e.target.value; if (status) { trackPurchase(purchase.id, status); e.target.value = ''; } }); } function displayPrices(prices) { pricesContent.innerHTML = prices.length > 0 ? prices.map(price => ` <div class="bg-white p-4 rounded-lg shadow-md mb-4"> <p class="text-gray-700"><strong>Начальная цена:</strong> ${price.initial_price} ${price.currency}</p> <p class="text-gray-700"><strong>Контрактная цена:</strong> ${price.contract_price ? `${price.contract_price} ${price.contract_currency}` : 'Отсутствует'}</p> </div> `).join('') : '<p class="text-red-500">Цены не найдены</p>'; } function displayDates(dates) { datesContent.innerHTML = dates.length > 0 ? dates.map(date => ` <div class="bg-white p-4 rounded-lg shadow-md mb-4"> <p class="text-gray-700"><strong>Дата размещения:</strong> ${new Date(date.placement_date).toLocaleString('ru-RU')}</p> <p class="text-gray-700"><strong>Дата обновления:</strong> ${new Date(date.update_date).toLocaleString('ru-RU')}</p> <p class="text-gray-700"><strong>Начало подачи заявок:</strong> ${date.application_start_date ? new Date(date.application_start_date).toLocaleString('ru-RU') : 'Отсутствует'}</p> <p class="text-gray-700"><strong>Окончание подачи заявок:</strong> ${date.application_end_date ? new Date(date.application_end_date).toLocaleString('ru-RU') : 'Отсутствует'}</p> </div> `).join('') : '<p class="text-red-500">Даты не найдены</p>'; } function displayCustomers(customers, purchaseId) { console.log('Отображение заказчиков:', customers); // Отладка customersContent.innerHTML = Array.isArray(customers) && customers.length > 0 ? customers.map(customer => ` <a href="customers.html?customer_id=${customer.id}&purchase_id=${purchaseId}" class="block bg-white p-4 rounded-lg shadow-md mb-4 hover:shadow-lg transition card"> <p class="text-gray-700"><strong>Наименование:</strong> ${customer.name || 'Отсутствует'}</p> </a> `).join('') : '<p class="text-red-500">Заказчики не найдены</p>'; } loadPurchaseDetails(); } // Customer details functionality if (document.getElementById('customerContent')) { const customerContent = document.getElementById('customerContent'); async function loadCustomerDetails() { const urlParams = new URLSearchParams(window.location.search); const customerId = parseInt(urlParams.get('customer_id')); const purchaseId = parseInt(urlParams.get('purchase_id')); if (!customerId || !purchaseId) { customerContent.innerHTML = '<p class="text-red-500">Заказчик или закупка не указаны</p>'; return; } customerContent.innerHTML = '<p class="text-gray-500">Загрузка заказчика...</p>'; try { const customersUrl = `http://localhost:8000/customers/${customerId}`; // Исправлено: убран /api const customersResponse = await fetch(customersUrl); if (!customersResponse.ok) { throw new Error(`HTTP error ${customersResponse.status}`); } const customer = await customersResponse.json(); // Получаем одиночный объект console.log('Полученный заказчик:', customer); // Отладка displayCustomerDetails(customer); // Передаём объект напрямую } catch (error) { console.error('Ошибка загрузки деталей заказчика:', error); customerContent.innerHTML = ` <div class="bg-white p-6 rounded-lg shadow-md"> <p class="text-red-500">Ошибка загрузки заказчика</p> </div> `; } } function displayCustomerDetails(customer) { let filteredExtraData = { ...customer.extra_data }; delete filteredExtraData.organization; const extraDataHtml = filteredExtraData && Object.keys(filteredExtraData).length > 0 ? Object.entries(filteredExtraData) .filter(([_, value]) => value !== null && value !== undefined && value !== '') .map(([key, value]) => ` <div class="mb-2"> <p class="text-sm text-gray-600">${key}</p> <p class="text-gray-900">${Array.isArray(value) ? value.join(', ') : value}</p> </div> `).join('') : '<p class="text-gray-500">Дополнительные данные отсутствуют</p>'; customerContent.innerHTML = ` <div class="bg-white p-6 rounded-lg shadow-md"> <h3 class="text-xl font-semibold mb-4 text-green-500">Информация о заказчике</h3> <div class="space-y-4"> <div> <p class="text-sm text-gray-600">Наименование</p> <p class="text-gray-900">${customer.name || 'Отсутствует'}</p> </div> ${extraDataHtml} </div> </div> `; } loadCustomerDetails(); } // Add purchase functionality document.getElementById('add-purchase-btn')?.addEventListener('click', function() { window.location.href = 'add_purchase.html'; }); document.getElementById('add-purchase-form')?.addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(event.target); const data = { registry_number: formData.get('registry_number'), stage: formData.get('stage'), method: formData.get('method'), name: formData.get('name'), law: formData.get('law'), okpd2: formData.get('okpd2') || null, initial_price: parseFloat(formData.get('initial_price')), currency: formData.get('currency'), contract_price: formData.get('contract_price') ? parseFloat(formData.get('contract_price')) : null, contract_currency: formData.get('contract_currency') || null, placement_date: new Date(formData.get('placement_date')).toISOString(), update_date: new Date(formData.get('update_date')).toISOString(), application_start_date: formData.get('application_start_date') ? new Date(formData.get('application_start_date')).toISOString() : null, application_end_date: formData.get('application_end_date') ? new Date(formData.get('application_end_date')).toISOString() : null, customer_name: formData.get('customer_name') }; try { const response = await fetch('http://localhost:8000/purchases/add_purchase/', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data), }); const result = await response.json(); if (response.ok) { alert('Закупка успешно добавлена!'); window.location.href = 'index.html'; } else { alert(`Ошибка: ${result.detail}`); } } catch (error) { alert(`Ошибка при добавлении закупки: ${error.message}`); } }); });