const perPage=10
let currentPage=1
let totalPages=1
let regionsCurrentPage=1
let sortField="region_id"
let sortOrder="asc"
let currentFetchController=null
let currentSystemIdToDelete=null
let systemsCurrentPage=1
let systemsTotalPages=1
let systemsSortField="system_id"
let systemsSortOrder="asc"
// Предварительно создаём объекты модалей (чтобы не создавать каждый раз заново)
const editRegionNameModal = new bootstrap.Modal(document.getElementById('editRegionNameModal'));
const deleteRegionModal = new bootstrap.Modal(document.getElementById('deleteRegionModal'));
const regionSubscribersModal = new bootstrap.Modal(document.getElementById('regionSubscribersModal'));
const editSystemNameModal = new bootstrap.Modal(document.getElementById('editSystemNameModal'));
const deleteSystemModal = new bootstrap.Modal(document.getElementById('deleteSystemModal'));
function loadRegions(e){
if(e<1||e>totalPages)return;
currentPage=e;
let t=`/telezab/rest/api/regions?page=${currentPage}&per_page=${perPage}&sort_field=${sortField}&sort_order=${sortOrder}`;
currentFetchController&¤tFetchController.abort(),
safeFetch(t,{signal:(currentFetchController=new AbortController).signal})
.then(e=>e.json())
.then(e=>{
currentFetchController=null,
totalPages=e.total_pages,
updateRegionsTable(e.regions),
updatePagination(e.current_page,e.total_pages,"pagination-regions")
})
.catch(e=>{
"AbortError"===e.name||console.error("Error fetching regions:",e),
currentFetchController=null
})
}
function updateRegionsTable(e){
let t=document.getElementById("regions-table");
if(!t) {
console.error("regions-table element not found!");
return;
}
t.innerHTML="";
e.forEach(e=>{
let n=document.createElement("tr");
n.innerHTML=`
${e.region_id}
${e.name}
${e.active ? "Включен" : "Выключен"}
`;
t.appendChild(n)
});
setupRegionActions();
}
function setupRegionActions(){
// Используем делегирование событий для избежания множественных обработчиков
const regionsTable = document.getElementById("regions-table");
if (!regionsTable) return;
// Удаляем старые обработчики событий с таблицы
const newTable = regionsTable.cloneNode(true);
regionsTable.parentNode.replaceChild(newTable, regionsTable);
// Используем делегирование событий
newTable.addEventListener('click', function(e) {
const target = e.target.closest('button');
if (!target) return;
if (target.classList.contains('delete-btn')) {
e.preventDefault();
deleteRegion(target.dataset.id);
} else if (target.classList.contains('edit-name-btn')) {
e.preventDefault();
handleEditRegionName(target);
} else if (target.classList.contains('subscribers-btn')) {
e.preventDefault();
showRegionSubscribers(target.dataset.id);
}
});
// Обработчик для переключателей статуса
newTable.addEventListener('change', function(e) {
if (e.target.classList.contains('region-status-switch')) {
let id = e.target.dataset.id;
let active = e.target.checked;
toggleRegionStatus(id, active);
document.getElementById(`region-status-label-${id}`).textContent = active ? "Включен" : "Выключен";
}
});
// Обновляем заголовки для сортировки
document.querySelectorAll("th[data-sort]").forEach(e=>{
const newHeader = e.cloneNode(true);
e.parentNode.replaceChild(newHeader, e);
newHeader.addEventListener("click", ()=>{
let field = newHeader.dataset.sort;
if(field === sortField) {
sortOrder = sortOrder === "asc" ? "desc" : "asc";
} else {
sortField = field;
sortOrder = "asc";
}
loadRegions(currentPage);
});
});
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[title]'));
tooltipTriggerList.map(el => new bootstrap.Tooltip(el));
}
function handleEditRegionName(e){
let t = e.dataset.id,
n = e.dataset.name;
document.getElementById("old-region-name").value = n;
document.getElementById("new-region-name").value = n;
editRegionNameModal.show();
let s = 5;
document.getElementById("edit-region-name-timer").textContent = s;
let a = setInterval(() => {
s--;
document.getElementById("edit-region-name-timer").textContent = s;
if (s === 0) {
clearInterval(a);
document.getElementById("save-region-name-btn").removeAttribute("disabled");
}
}, 1000);
let r = document.getElementById("save-region-name-btn"),
o = r.cloneNode(true);
r.parentNode.replaceChild(o, r);
o.addEventListener("click", () => {
updateRegionName(t, document.getElementById("new-region-name").value);
editRegionNameModal.hide();
});
}
function showRegionSubscribers(e){
safeFetch(`/telezab/rest/api/regions/${e}/subscribers`)
.then(res => res.json())
.then(data => {
let t = document.getElementById("regionSubscribersTableBody");
t.innerHTML = "";
if(data.subscribers && data.subscribers.length > 0){
data.subscribers.forEach(sub => {
let n = document.createElement("tr");
n.innerHTML = `
${sub.telegram_id}
${sub.email}
`;
t.appendChild(n);
});
} else {
let n = document.createElement("tr");
n.innerHTML = `
Нет подписчиков для этого региона.
`;
t.appendChild(n);
}
regionSubscribersModal.show();
})
.catch(err => {
console.error("Ошибка при получении подписчиков региона:", err);
toastr.error("Ошибка при получении подписчиков региона. Пожалуйста, попробуйте позже.");
});
}
function updateRegionName(regionId, newName) {
safeFetch("/telezab/rest/api/regions/name", {
method:"PUT",
headers:{"Content-Type":"application/json"},
body:JSON.stringify({region_id:regionId, name:newName})
})
.then(()=>{
loadRegions(currentPage);
toastr.success("Название региона изменено.");
})
.catch(e=>{
console.error("Ошибка при изменении названия региона:",e);
toastr.error("Ошибка при изменении названия региона. Пожалуйста, попробуйте позже.");
});
}
function toggleRegionStatus(e,t){
safeFetch("/telezab/rest/api/regions/status",{
method:"PUT",
headers:{"Content-Type":"application/json"},
body:JSON.stringify({region_id:e,active:t})
})
.then(()=>{
loadRegions(currentPage);
t?toastr.success("Регион активирован."):toastr.success("Регион деактивирован.");
})
.catch(e=>{
console.error("Ошибка при изменении статуса региона:",e);
toastr.error("Ошибка при изменении статуса региона. Пожалуйста, попробуйте позже.");
});
}
function deleteRegion(e){
deleteRegionModal.show();
let t = document.getElementById("deleteConfirmationInput"),
n = document.getElementById("confirmDeleteButton"),
s = document.getElementById("deleteRegionModal"),
a = t.cloneNode(true),
r = n.cloneNode(true);
t.parentNode.replaceChild(a, t);
n.parentNode.replaceChild(r, n);
a.addEventListener("input", function(){
let val = this.value;
r.disabled = val === "УДАЛИТЬ" ? false : true;
});
r.addEventListener("click", function(){
safeFetch(`/telezab/rest/api/regions/${e}`, { method: "DELETE" })
.then(() => {
loadRegions(currentPage);
toastr.success("Регион успешно удален.");
deleteRegionModal.hide();
})
.catch(err => {
console.error("Ошибка при удалении региона:", err);
toastr.error("Ошибка при удалении региона. Пожалуйста, попробуйте позже.");
});
});
s.addEventListener("hidden.bs.modal", function(){
a.value = "";
r.disabled = true;
}, { once: true });
}
function loadSystems(e){
if(e<1||e>systemsTotalPages)return;
systemsCurrentPage=e;
let t=`/telezab/rest/api/systems?page=${systemsCurrentPage}&per_page=10&sort_field=${systemsSortField}&sort_order=${systemsSortOrder}`;
currentFetchController&¤tFetchController.abort(),
safeFetch(t,{signal:(currentFetchController=new AbortController).signal})
.then(e=>e.json())
.then(e=>{
currentFetchController=null,
systemsTotalPages=e.total_pages,
updateSystemsTable(e.systems),
updatePagination(e.current_page,e.total_pages,"pagination-systems")
})
.catch(e=>{
"AbortError"===e.name||console.error("Error fetching systems:",e),
currentFetchController=null
});
}
function updateSystemsTable(e) {
let t = document.getElementById("systems-table");
if (!t) {
console.error("systems-table element not found!");
return;
}
t.innerHTML = "";
e.forEach(e => {
let n = document.createElement("tr");
n.innerHTML = `
${e.system_id}
${e.system_name}
${e.name}
`;
t.appendChild(n);
});
setupSystemActions();
// Инициализация Bootstrap tooltips
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[title]'));
tooltipTriggerList.map(el => new bootstrap.Tooltip(el));
}
function setupSystemActions(){
// Используем делегирование событий для таблицы систем
const systemsTable = document.getElementById("systems-table");
if (!systemsTable) return;
// Удаляем старые обработчики событий с таблицы
const newTable = systemsTable.cloneNode(true);
systemsTable.parentNode.replaceChild(newTable, systemsTable);
// Используем делегирование событий
newTable.addEventListener('click', function(e) {
const target = e.target.closest('button');
if (!target) return;
if (target.classList.contains('delete-btn')) {
e.preventDefault();
deleteSystem(target.dataset.id);
} else if (target.classList.contains('edit-name-btn')) {
e.preventDefault();
handleEditSystemName(target);
}
});
// Обновляем заголовки для сортировки
document.querySelectorAll("th[data-sort]").forEach(e=>{
const newHeader = e.cloneNode(true);
e.parentNode.replaceChild(newHeader, e);
newHeader.addEventListener("click", ()=>{
let field = newHeader.dataset.sort;
if(field === systemsSortField) {
systemsSortOrder = systemsSortOrder === "asc" ? "desc" : "asc";
} else {
systemsSortField = field;
systemsSortOrder = "asc";
}
loadSystems(systemsCurrentPage);
});
});
}
function handleEditSystemName(e){
let t = e.dataset.id,
n = e.dataset.latinName,
s = e.dataset.name;
let a = document.getElementById("edit-system-id"),
r = document.getElementById("edit-system-name-lat"),
o = document.getElementById("old-system-name"),
l = document.getElementById("new-system-name");
if(!a || !r || !o || !l){
console.error("❌ Один или несколько элементов не найдены:");
!a && console.error(" - Не найден элемент #edit-system-id");
!r && console.error(" - Не найден элемент #edit-system-name-lat");
!o && console.error(" - Не найден элемент #old-system-name");
!l && console.error(" - Не найден элемент #new-system-name");
return;
}
a.value = t;
r.value = n;
o.value = s;
l.value = s;
editSystemNameModal.show();
let d = 5,
i = document.getElementById("edit-system-name-timer");
i.textContent = d;
let m = setInterval(() => {
d--;
i.textContent = d;
if(d === 0){
clearInterval(m);
document.getElementById("saveSystemNameBtn").removeAttribute("disabled");
}
}, 1000);
let c = document.getElementById("saveSystemNameBtn"),
g = c.cloneNode(true);
c.parentNode.replaceChild(g, c);
g.addEventListener("click", () => {
let id = a.value,
latinName = r.value,
newName = l.value.trim();
if(!newName){
toastr.error("Введите новое название системы.");
return;
}
updateSystemName(id, latinName, newName);
editSystemNameModal.hide();
});
}
function updateSystemName(systemId, systemNameLat, nameCyr) {
if (!systemId || !systemNameLat || !nameCyr) {
toastr.error("Не все параметры заполнены.");
return;
}
safeFetch("/telezab/rest/api/systems", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
system_id: systemId,
system_name: systemNameLat,
name: nameCyr
})
})
.then(res => res.ok ? res.json() : res.json().then(e => { throw new Error(e.message || "Ошибка сервера") }))
.then(() => {
loadSystems(systemsCurrentPage);
toastr.success("Название системы успешно обновлено.");
})
.catch(e => {
console.error("Ошибка при изменении названия системы:", e);
toastr.error(e.message || "Ошибка при изменении названия системы. Пожалуйста, попробуйте позже.");
});
}
function deleteSystem(e){
deleteSystemModal.show();
let t = document.getElementById("deleteSystemConfirmationInput"),
n = document.getElementById("confirmDeleteSystemButton"),
s = document.getElementById("deleteSystemModal"),
a = t.cloneNode(true),
r = n.cloneNode(true);
t.parentNode.replaceChild(a, t);
n.parentNode.replaceChild(r, n);
a.addEventListener("input", function(){
let val = this.value;
r.disabled = val === "УДАЛИТЬ" ? false : true;
});
r.addEventListener("click", function(){
safeFetch(`/telezab/rest/api/systems/${e}`, { method: "DELETE" })
.then(() => {
loadSystems(systemsCurrentPage);
toastr.success("Система успешно удалена.");
deleteSystemModal.hide();
})
.catch(err => {
console.error("Ошибка при удалении системы:", err);
toastr.error("Ошибка при удалении системы. Пожалуйста, попробуйте позже.");
});
});
s.addEventListener("hidden.bs.modal", function(){
a.value = "";
r.disabled = true;
}, { once: true });
}
function updatePagination(e,t,n){
let s=document.getElementById(n);
if(!s){
console.error(`Container with ID ${n} not found!`);
return;
}
s.innerHTML="";
let a=document.createElement("li");
a.classList.add("page-item");
a.classList.toggle("disabled",1===e);
a.innerHTML=`«`;
s.appendChild(a);
for(let r=1;r<=t;r++){
let o=document.createElement("li");
o.classList.add("page-item");
o.classList.toggle("active",r===e);
let l=document.createElement("a");
l.classList.add("page-link");
l.href="#";
l.textContent=r;
l.onclick=()=>loadPage(r,n);
o.appendChild(l);
s.appendChild(o);
}
let i=document.createElement("li");
i.classList.add("page-item");
i.classList.toggle("disabled",e===t);
i.innerHTML=`»`;
s.appendChild(i);
}
function loadPage(e,t){
"pagination-regions"===t?loadRegions(e):"pagination-systems"===t&&loadSystems(e);
}
// Настройка toastr
toastr.options={
closeButton:!0,
debug:!1,
newestOnTop:!1,
progressBar:!1,
positionClass:"toast-bottom-right",
preventDuplicates:!1,
onclick:null,
showDuration:"300",
hideDuration:"1000",
timeOut:"5000",
extendedTimeOut:"1000",
showEasing:"swing",
hideEasing:"linear",
showMethod:"fadeIn",
hideMethod:"fadeOut"
};
// Обработчики форм
document.getElementById("add-region-form").addEventListener("submit",e=>{
e.preventDefault();
let regionId=document.getElementById("region-id").value;
let regionName=document.getElementById("region-name").value;
let regionActive=document.getElementById("region-active").checked;
if(!/^\d+$/.test(regionId)){
toastr.error("ID региона должен содержать только числа.");
console.log("Ошибка: ID региона не является числом.");
return;
}
safeFetch("/telezab/rest/api/regions",{
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify({region_id:regionId,name:regionName,active:regionActive})
})
.then(e=>e.ok?e.json():e.json().then(e=>{
throw console.error("Ошибка от сервера:",e),new Error(e.message||"Ошибка добавления региона");
}))
.then(e=>{
if("success"===e.status){
console.log("Регион успешно добавлен.");
document.getElementById("region-id").value="";
document.getElementById("region-name").value="";
document.getElementById("region-active").checked=!1;
loadRegions(regionsCurrentPage);
toastr.success(e.message);
$("#addRegionModal").modal("hide");
}else{
throw console.log("Ошибка: Статус ответа не 'success'."),new Error(e.message||"Неизвестная ошибка");
}
})
.catch(e=>{
console.error("Ошибка при добавлении региона:",e);
toastr.error(e.message||"Ошибка при добавлении региона. Пожалуйста, попробуйте позже.");
});
});
document.getElementById("add-system-form").addEventListener("submit",e=>{
e.preventDefault();
let systemId=document.getElementById("system-id").value;
let systemNameLat=document.getElementById("system-name-lat").value;
let systemNameCyr=document.getElementById("system-name-cyr").value;
if(!/^\d+$/.test(systemId)){
toastr.error("ID системы должен содержать только числа.");
return;
}
safeFetch("/telezab/rest/api/systems",{
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify({system_id:systemId,system_name:systemNameLat,name:systemNameCyr})
})
.then(e=>e.ok?e.json():e.json().then(e=>{
throw new Error(e.message||"Ошибка добавления системы");
}))
.then(e=>{
document.getElementById("system-id").value="";
document.getElementById("system-name-lat").value="";
document.getElementById("system-name-cyr").value="";
loadSystems(systemsCurrentPage);
toastr.success("Система успешно добавлена.");
$("#addSystemModal").modal("hide");
})
.catch(e=>{
console.error("Ошибка при добавлении системы:",e);
toastr.error(e.message||"Ошибка при добавлении системы. Пожалуйста, попробуйте позже.");
});
});
// Инициализация при загрузке страницы
document.addEventListener("DOMContentLoaded",()=>{
let regionsTab=document.getElementById("regions-tab");
let systemsTab=document.getElementById("systems-tab");
regionsTab.addEventListener("shown.bs.tab",()=>{
loadRegions(currentPage);
});
systemsTab.addEventListener("shown.bs.tab",()=>{
loadSystems(systemsCurrentPage);
});
regionsTab.classList.contains("active")&&loadRegions(currentPage);
// Очистка форм при закрытии модальных окон
let modalsConfig=[
{modalId:"addRegionModal",formId:"add-region-form"},
{modalId:"addSystemModal",formId:"add-system-form"},
{modalId:"editRegionNameModal",formId:"edit-region-name-form"},
{modalId:"editSystemNameModal",formId:"edit-system-name-form"}
];
modalsConfig.forEach(({modalId,formId})=>{
let modal=document.getElementById(modalId);
let form=document.getElementById(formId);
if(modal&&form){
modal.addEventListener("hidden.bs.modal",()=>{
form.reset();
});
}
});
});