баг-фикс 30/34

This commit is contained in:
Zuev
2026-07-19 14:40:43 +03:00
parent 3d798c13e3
commit bc0e1ab1b4
172 changed files with 13431 additions and 2910 deletions

View File

@@ -1,13 +1,17 @@
// Основной модуль страницы настроек
import { startDropdownAutoObserver, initAllCustomDropdowns } from '../../js/dropdown.js';
import { renderStatusMessage } from '../../js/utils.js';
import { SETTINGS_ROLES, capabilitiesForRole } from '../../js/role-capabilities.js';
import { getToken } from '../../js/api.js';
import { initializeSession } from '../../js/api.js';
// Проверка авторизации
const role = localStorage.getItem('role');
if (!getToken() || !['ADMIN', 'EDUCATION_OFFICE'].includes(role)) {
window.location.href = '/';
async function bootstrap() {
const session = await initializeSession();
if (!session || !SETTINGS_ROLES.includes(session.role)) {
window.location.replace('/');
return;
}
const role = session.role;
// Глобальная инициализация кастомных списков
document.addEventListener('DOMContentLoaded', () => {
@@ -44,12 +48,9 @@ const ROUTES = {
},
};
const ROLE_TABS = {
ADMIN: ['general', 'time-slots', 'database', 'edu-forms'],
EDUCATION_OFFICE: ['time-slots', 'edu-forms']
};
const allowedTabs = new Set(ROLE_TABS[role] || []);
const defaultTab = role === 'EDUCATION_OFFICE' ? 'time-slots' : 'general';
const roleCapabilities = capabilitiesForRole(role);
const allowedTabs = new Set(roleCapabilities.settingsTabs);
const defaultTab = roleCapabilities.defaultSettingsTab;
let currentTab = null;
@@ -129,8 +130,8 @@ async function switchTab(tab) {
currentTab = tab;
} catch (e) {
appContent.innerHTML = `<div style="padding:1rem;color:var(--error);">Ошибка загрузки: ${e.message}</div>`;
console.error(e);
renderStatusMessage(appContent, 'Не удалось загрузить раздел настроек');
console.error('Не удалось загрузить раздел настроек');
}
// Закрываем мобильное меню после перехода
@@ -140,3 +141,6 @@ async function switchTab(tab) {
// Вкладка по умолчанию
switchTab(defaultTab);
}
await bootstrap();

View File

@@ -1,5 +1,5 @@
import { api } from '../../../js/api.js';
import { escapeHtml, showAlert, hideAlert } from '../../../js/utils.js';
import { escapeHtml, showAlert, hideAlert, renderStatusMessage, renderTableMessage } from '../../../js/utils.js';
export async function initDatabase() {
const tenantsTbody = document.getElementById('tenants-tbody');
@@ -12,8 +12,8 @@ export async function initDatabase() {
try {
const data = await api.get('/api/database/status');
const statusBadge = data.connected
? '<span class="badge badge-available">Online</span>'
: '<span class="badge badge-unavailable">Offline</span>';
? '<span class="badge badge-available">Доступно</span>'
: '<span class="badge badge-unavailable">Недоступно</span>';
statusInfo.innerHTML = `
<div style="display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;">
@@ -36,7 +36,7 @@ export async function initDatabase() {
</div>
`;
} catch (e) {
statusInfo.innerHTML = `<div class="form-alert error" style="display:block">Ошибка загрузки статуса: ${e.message}</div>`;
renderStatusMessage(statusInfo, 'Не удалось загрузить статус подключения');
}
}
@@ -46,7 +46,7 @@ export async function initDatabase() {
const tenants = await api.get('/api/database/tenants');
renderTenantsTable(tenants);
} catch (e) {
tenantsTbody.innerHTML = `<tr><td colspan="6" class="loading-row">Ошибка загрузки: ${e.message}</td></tr>`;
renderTableMessage(tenantsTbody, 6, 'Не удалось загрузить список тенантов');
}
}
@@ -58,8 +58,8 @@ export async function initDatabase() {
tenantsTbody.innerHTML = tenants.map(t => {
const statusBadge = t.connected
? '<span class="badge badge-available">Online</span>'
: '<span class="badge badge-unavailable">Offline</span>';
? '<span class="badge badge-available">Доступно</span>'
: '<span class="badge badge-unavailable">Недоступно</span>';
return `
<tr>
@@ -96,7 +96,7 @@ export async function initDatabase() {
showAlert('add-tenant-alert', `${result.message}`, 'error');
}
} catch (e) {
showAlert('add-tenant-alert', `Ошибка: ${e.message}`, 'error');
showAlert('add-tenant-alert', 'Не удалось проверить подключение', 'error');
} finally {
btnTest.textContent = 'Тест';
btnTest.disabled = false;
@@ -122,7 +122,7 @@ export async function initDatabase() {
try {
const result = await api.post('/api/database/tenants', { name, domain, url, username, password });
if (result.success) {
showAlert('add-tenant-alert', `Тенант "${escapeHtml(domain)}" добавлен!`, 'success');
showAlert('add-tenant-alert', `Тенант «${domain}» добавлен`, 'success');
addTenantForm.reset();
loadTenants();
loadStatus();
@@ -130,7 +130,7 @@ export async function initDatabase() {
showAlert('add-tenant-alert', result.message, 'error');
}
} catch (e) {
showAlert('add-tenant-alert', `Ошибка: ${e.message}`, 'error');
showAlert('add-tenant-alert', 'Не удалось добавить тенант', 'error');
}
});
@@ -147,7 +147,7 @@ export async function initDatabase() {
loadTenants();
loadStatus();
} catch (e) {
alert(`Ошибка: ${e.message}`);
alert('Не удалось удалить тенант');
}
});

View File

@@ -8,7 +8,7 @@ export async function fetchEducationForms() {
allEducationForms = await api.get('/api/education-forms');
return allEducationForms;
} catch (e) {
console.error("Failed to fetch education forms", e);
console.error('Не удалось загрузить формы обучения');
return [];
}
}

View File

@@ -62,8 +62,8 @@ export async function initTimeSlotsSettings() {
form?.addEventListener('submit', saveSlot);
resetButton?.addEventListener('click', resetForm);
refreshButton?.addEventListener('click', loadAll);
startInput?.addEventListener('change', fillDurationIfEmpty);
endInput?.addEventListener('change', fillDurationIfEmpty);
startInput?.addEventListener('change', calculateDuration);
endInput?.addEventListener('change', calculateDuration);
tbody?.addEventListener('click', handleSlotTableClick);
await loadAll();
@@ -206,8 +206,7 @@ export async function initTimeSlotsSettings() {
orderNumber: Number(orderInput.value),
scopeId: activeScopeId,
startTime: startInput.value,
endTime: endInput.value,
durationMinutes: durationInput.value ? Number(durationInput.value) : null
endTime: endInput.value
};
try {
@@ -272,8 +271,9 @@ export async function initTimeSlotsSettings() {
}
}
function fillDurationIfEmpty() {
if (durationInput.value || !startInput.value || !endInput.value || startInput.value >= endInput.value) return;
function calculateDuration() {
durationInput.value = '';
if (!startInput.value || !endInput.value || startInput.value >= endInput.value) return;
const [startHour, startMinute] = startInput.value.split(':').map(Number);
const [endHour, endMinute] = endInput.value.split(':').map(Number);
durationInput.value = String((endHour * 60 + endMinute) - (startHour * 60 + startMinute));