/
delphin
/
CatRW
Обзор
Документация
Войти
/
delphin
/
CatRW
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/model_types.js
275 строк
10 KB
delphin
start project
02 мар 2026, 09:14
Верифицирован
02 мар 2026, 09:14
4b0ee03
Код
Авторство
О чём код?
// /js/model_types.js - УПРОЩЁННАЯ ВЕРСИЯ с новыми уведомлениями try { let allTypes = []; let isEditMode = false; let currentlyEditingCode = null; const API_BASE = '/api/model_types'; console.log('✅ model_types.js загружен'); // 1. Загрузить типы async function loadTypes() { const tbody = document.getElementById('typesList'); if (!tbody) return; showLoading(tbody, 'Загрузка типов...'); try { const response = await fetch(API_BASE); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); if (data.success) { allTypes = data.data || []; renderTypesTable(); Notifications.success(`Загружено: ${allTypes.length} типов`); } else { showError(tbody, data.error || 'Ошибка загрузки'); } } catch (error) { console.error('❌ Ошибка загрузки:', error); showError(tbody, 'Ошибка: ' + error.message); } } // 2. Отрисовать таблицу function renderTypesTable() { const tbody = document.getElementById('typesList'); if (!tbody) return; if (!allTypes.length) { tbody.innerHTML = ` <tr><td colspan="5" style="text-align: center; padding: 40px; color: #7f8c8d;"> Нет типов моделей </td></tr> `; return; } let html = ''; // Предзагружаем счётчики const promises = allTypes.map(type => getTypeStats(type.code)); Promise.all(promises).then(statsArray => { allTypes.forEach((type, index) => { const stats = statsArray[index]; const localeTypes = window.Locales ? window.Locales.getCategory('model_types') : {}; html += ` <tr id="type-${type.code}"> <td><strong>${escapeHtml(type.code)}</strong></td> <td>${localeTypes[type.code] || '—'}</td> <td>${stats.subtypes || 0}</td> <td>${stats.models || 0}</td> <td> <div class="action-buttons"> <button onclick="openEditForm('${type.code}')" class="btn btn-warning btn-small">✏️</button> <button onclick="deleteType('${type.code}')" class="btn btn-danger btn-small">🗑️</button> </div> </td> </tr> `; }); tbody.innerHTML = html; }); } // 3. Получить статистику по типу async function getTypeStats(typeCode) { try { const [subtypesRes, modelsRes] = await Promise.all([ fetch(`/api/model_subtypes?type_code=${typeCode}`).then(r => r.json()), fetch(`/api/models?type_code=${typeCode}&limit=1`).then(r => r.json()) ]); return { subtypes: subtypesRes.success ? (subtypesRes.data?.length || 0) : 0, models: modelsRes.success ? (modelsRes.total || 0) : 0 }; } catch (error) { return { subtypes: 0, models: 0 }; } } // 4. Показать/скрыть форму function toggleAddForm() { const form = document.getElementById('addFormContainer'); if (!form) return; const isVisible = form.style.display === 'block'; form.style.display = isVisible ? 'none' : 'block'; if (!isVisible && !isEditMode) { clearForm(); document.getElementById('typeCode').focus(); } } // 5. Очистить форму function clearForm() { document.getElementById('typeCode').value = ''; document.getElementById('addResult').innerHTML = ''; isEditMode = false; currentlyEditingCode = null; const formTitle = document.getElementById('formTitle'); const saveButton = document.getElementById('saveButton'); const cancelBtn = document.getElementById('cancelEditBtn'); if (formTitle) formTitle.textContent = 'Новый тип модели'; if (saveButton) saveButton.textContent = '➕ Добавить'; if (cancelBtn) cancelBtn.style.display = 'none'; } // 6. Открыть форму редактирования async function openEditForm(code) { const type = allTypes.find(t => t.code === code); if (!type) return; isEditMode = true; currentlyEditingCode = code; document.getElementById('typeCode').value = type.code; const formTitle = document.getElementById('formTitle'); const saveButton = document.getElementById('saveButton'); const cancelBtn = document.getElementById('cancelEditBtn'); if (formTitle) formTitle.textContent = `Редактирование: ${type.code}`; if (saveButton) saveButton.textContent = '💾 Сохранить'; if (cancelBtn) cancelBtn.style.display = 'inline-block'; const form = document.getElementById('addFormContainer'); if (form) form.style.display = 'block'; document.getElementById('typeCode').focus(); Notifications.info('📝 Режим редактирования'); } // 7. Сохранить тип async function saveType() { const codeInput = document.getElementById('typeCode'); if (!codeInput) return; const code = codeInput.value.trim(); if (!code) { Notifications.error('Введите код типа'); return; } // Валидация... if (!/^[a-z][a-z0-9_]*$/.test(code)) { Notifications.error('Код должен содержать только английские буквы в нижнем регистре, цифры и подчёркивание'); return; } const method = isEditMode ? 'PUT' : 'POST'; const url = isEditMode ? `${API_BASE}/${currentlyEditingCode}` : API_BASE; Notifications.info('Сохранение...'); try { const response = await fetch(url, { method: method, headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ code: code }) }); const result = await response.json(); if (result.success) { Notifications.success(result.message); clearForm(); toggleAddForm(); setTimeout(loadTypes, 1000); } else { Notifications.error(result.error || 'Ошибка'); } } catch (error) { Notifications.error(error.message); } } // 8. Удалить тип async function deleteType(code) { const type = allTypes.find(t => t.code === code); if (!type) return; if (!confirm(`Удалить тип "${code}"?\nВсе подтипы этого типа также будут удалены.`)) return; try { const response = await fetch(`${API_BASE}/${code}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { Notifications.success(result.message); if (currentlyEditingCode === code) { clearForm(); } loadTypes(); } else { Notifications.error(result.error); } } catch (error) { Notifications.error(error.message); } } // 9. Отменить редактирование function cancelEdit() { clearForm(); toggleAddForm(); Notifications.info('Редактирование отменено'); } // Вспомогательные функции function showLoading(element, message) { if (!element) return; element.innerHTML = ` <tr><td colspan="5" style="text-align: center; padding: 30px; color: #7f8c8d;"> <div style="display: inline-block; animation: spin 1s linear infinite; margin-right: 10px;">⟳</div> ${escapeHtml(message)} </td></tr> `; } function showError(element, message) { if (!element) return; element.innerHTML = ` <tr><td colspan="5" style="text-align: center; padding: 30px; color: #e74c3c;"> ❌ ${escapeHtml(message)} </td></tr> `; } function escapeHtml(text) { if (!text) return ''; return text.toString() .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // Экспортируем функции window.loadTypes = loadTypes; window.toggleAddForm = toggleAddForm; window.openEditForm = openEditForm; window.saveType = saveType; window.deleteType = deleteType; window.cancelEdit = cancelEdit; console.log('✅ model_types.js инициализирован'); setTimeout(loadTypes, 100); } catch (error) { console.error('❌ Критическая ошибка в model_types.js:', error); alert('Ошибка загрузки скрипта типов моделей: ' + error.message); }