Files
Sheep-Service/web/lib/pages/territory/manager/script.js
Rozenrod 4b96ef0806 Додана сторінка "Розклад зібрань"
Перероблен генератор карточок територій APІ
2025-11-22 20:17:50 +02:00

496 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
let map_territory, type_territory;
const Territory_Manager = {
init: async (type, id) => {
let html = await fetch('/lib/pages/territory/manager/index.html').then((response) => response.text());
app.innerHTML = html;
type_territory = type;
let sheeps_list = [];
if (Sheeps.sheeps_list.list.length == 0) {
sheeps_list = await Sheeps.sheeps_list.loadAPI();
} else {
sheeps_list = Sheeps.sheeps_list.list;
}
let editor_button = document.getElementById('editor_button');
if (USER.possibilities.can_add_territory) {
editor_button.style.display = "";
editor_button.setAttribute("href", `/territory/editor/${type}/${id}`)
}
await Territory_Manager.info.setHTML(type, id);
Territory_Manager.entrances.setHTML(type, id);
for (let i = 0; i < sheeps_list.length; i++) {
const element = sheeps_list[i];
document.getElementById('list_sheeps').innerHTML += `
<option value="${element.name}">${element.name}</option>
`;
}
const card = document.getElementById('territory-new');
const mess = card.querySelector('.mess');
if (!card.dataset.listenerAdded) {
card.addEventListener('click', function (event) {
if (!mess.contains(event.target)) {
Territory_Manager.mess.close();
}
});
card.dataset.listenerAdded = 'true';
}
},
info: {
list: {},
loadAPI: async (url) => {
const uuid = localStorage.getItem("uuid");
const response = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
});
Territory_Manager.info.list = await response.json();
return Territory_Manager.info.list;
},
setHTML: async (type, id) => {
const url = `${CONFIG.api}${type}/${id}`;
const data = await Territory_Manager.info.loadAPI(url);
Territory_Manager.map(type, data);
const info_picture = document.getElementById('info-picture');
const info_title = document.getElementById('info-title');
const info_number = document.getElementById('info-number');
const info_settlement = document.getElementById('info-settlement');
const info_description = document.getElementById('info-description');
if (!info_picture.dataset.listener) {
info_picture.addEventListener("click", () => {
const state = info_picture.getAttribute('data-state');
info_picture.setAttribute('data-state', state === 'active' ? '' : 'active');
});
info_picture.dataset.listener = "true";
}
info_picture.setAttribute("src", "");
info_title.textContent = data.title;
info_number.textContent = data.number;
info_settlement.textContent = data.settlement;
info_description.value = data.description;
const urlImage = `https://sheep-service.com/cards/${type}/${type === "house" ? "T" : "H"}${id}.webp`;
try {
const checkImage = await fetch(urlImage, { method: 'GET' });
const showOk = checkImage.ok;
document.getElementById('menu-picture-ok').style.display = showOk ? '' : 'none';
document.getElementById('menu-picture-error').style.display = showOk ? 'none' : '';
if (showOk) {
document.getElementById('menu-picture-ok').setAttribute("href", urlImage);
}
} catch (err) {
document.getElementById('menu-picture-error').style.display = '';
document.getElementById('menu-picture-ok').style.display = 'none';
}
},
update: async () => {
const uuid = localStorage.getItem('uuid');
const data = Territory_Manager.info.list;
data.description = document.getElementById('info-description').value;
const url = `${CONFIG.api}${type_territory}/${data.id}`;
try {
const response = await fetch(url, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify(data)
});
if (response.ok) {
console.log('ok');
await response.json();
} else {
console.log('err');
}
} catch (e) {
console.log('update error', e);
}
}
},
entrances: {
list: [],
loadAPI: async (url) => {
const uuid = localStorage.getItem("uuid");
const response = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
});
Territory_Manager.entrances.list = await response.json();
return Territory_Manager.entrances.list;
},
setHTML: async (type, id) => {
const container = document.getElementById('territory-entrance');
container.innerHTML = "";
const sheeps_list = Sheeps.sheeps_list.list;
const renderName = (history) => {
if (history.name === "Групова") return `<p>${history.name} ${history.group_id}</p>`;
const sheep = sheeps_list.find(item => item.name === history.name);
return sheep ? `<a href="/sheeps/${sheep.id}" data-route>${history.name}</a>` : `<a>${history.name}</a>`;
};
const renderWorking = (element, i = 0) => `
<div class="entrance" data-state="working">
<div id="title">
<h1>${element.title ?? ''}</h1>
<a href="/territory/card/${type}/${id}" title="Редактор квартир" data-route>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M 12.5 6 C 8.9280619 6 6 8.9280619 6 12.5 L 6 35.5 C 6 39.071938 8.9280619 42 12.5 42 L 35.5 42 C 39.071938 42 42 39.071938 42 35.5 L 42 12.5 C 42 8.9280619 39.071938 6 35.5 6 L 12.5 6 z M 12.5 9 L 14 9 L 14 15 L 9 15 L 9 12.5 C 9 10.549938 10.549938 9 12.5 9 z M 17 9 L 35.5 9 C 37.450062 9 39 10.549938 39 12.5 L 39 15 L 17 15 L 17 9 z M 9 18 L 14 18 L 14 23 L 9 23 L 9 18 z M 17 18 L 39 18 L 39 23 L 17 23 L 17 18 z M 9 26 L 14 26 L 14 31 L 9 31 L 9 26 z M 17 26 L 39 26 L 39 31 L 17 31 L 17 26 z M 9 34 L 14 34 L 14 39 L 12.5 39 C 10.549938 39 9 37.450062 9 35.5 L 9 34 z M 17 34 L 39 34 L 39 35.5 C 39 37.450062 37.450062 39 35.5 39 L 17 39 L 17 34 z"/></svg>
</a>
</div>
<div><h1>Територію опрацьовує:</h1>${renderName(element.history)}</div>
<div><h1>Територія видана:</h1><h2>${formattedDate(element.history.date.start)}</h2></div>
<div><h1>Варто забрати:</h1><h2>${formattedDate(element.history.date.end) ?? formattedDate(element.history.date.start + (1000 * 2629743 * 4))}</h2></div>
<div class="edit_working">
<button onclick="Territory_Manager.endWorker('${type}', ${id}, ${element.history.id})" style="color: #121214;background: #c14d4d;">Забрати</button>
<button onclick="Territory_Manager.share('${type}'${type === "house" ? `, ${i}` : ""})">Відправити посилання</button>
</div>
</div>
`;
const renderFree = (element, i = 0) => {
let name = () => {
if(element.history.name == "Групова") return `Групова №${element.history.group_id}`
else return element.history.name ?? "..."
}
return `
<div class="entrance">
<div id="title">
<h1>${element.title ?? ''}</h1>
<a href="/territory/card/${type}/${id}" title="Редактор квартир" data-route>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path d="M 12.5 6 C 8.9280619 6 6 8.9280619 6 12.5 L 6 35.5 C 6 39.071938 8.9280619 42 12.5 42 L 35.5 42 C 39.071938 42 42 39.071938 42 35.5 L 42 12.5 C 42 8.9280619 39.071938 6 35.5 6 L 12.5 6 z M 12.5 9 L 14 9 L 14 15 L 9 15 L 9 12.5 C 9 10.549938 10.549938 9 12.5 9 z M 17 9 L 35.5 9 C 37.450062 9 39 10.549938 39 12.5 L 39 15 L 17 15 L 17 9 z M 9 18 L 14 18 L 14 23 L 9 23 L 9 18 z M 17 18 L 39 18 L 39 23 L 17 23 L 17 18 z M 9 26 L 14 26 L 14 31 L 9 31 L 9 26 z M 17 26 L 39 26 L 39 31 L 17 31 L 17 26 z M 9 34 L 14 34 L 14 39 L 12.5 39 C 10.549938 39 9 37.450062 9 35.5 L 9 34 z M 17 34 L 39 34 L 39 35.5 C 39 37.450062 37.450062 39 35.5 39 L 17 39 L 17 34 z"/></svg>
</a>
</div>
<div><h1>Територія не опрацьовується</h1></div>
<div><h1>Останнє опрацювання:</h1><h2>${formattedDate(element.history.date.end) ?? "..."} (${name()})</h2></div>
<div class="edit">
<button onclick="Territory_Manager.mess.open({type: '${type}', id: ${id}, number: ${i}, mode: false})" style="color: var(--ColorThemes0);background: var(--ColorThemes3);">Призначити груповою</button>
<button onclick="Territory_Manager.mess.open({type: '${type}', id: ${id}, number: ${i}, mode: true})">Призначити вісника</button>
</div>
</div>
`
};
let html = "";
if (type === "house") {
const url = `${CONFIG.api}house/${id}/entrances`;
const list = await Territory_Manager.entrances.loadAPI(url);
for (let i = 0; i < list.length; i++) {
const el = list[i];
html += el.working ? renderWorking(el, i) : renderFree(el, i);
}
} else if (type === "homestead") {
const url = `${CONFIG.api}homestead/${id}`;
const el = await Territory_Manager.entrances.loadAPI(url);
html += el.working ? renderWorking(el) : renderFree(el);
}
container.innerHTML = html;
}
},
map: (type, data) => {
let lat = data.geo?.lat ?? data.points?.[0]?.[0]?.[0]?.lat ?? 49.5629016;
let lng = data.geo?.lng ?? data.points?.[0]?.[0]?.[0]?.lng ?? 25.6145625;
if (map_territory && map_territory.remove) map_territory.remove();
const mapElement = document.getElementById('map_territory_manager');
if (!mapElement) return;
let googleHybrid = L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
maxZoom: 20,
minZoom: 15,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
});
let osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
});
let mytile = L.tileLayer('https://sheep-service.com/map/{z}/{x}/{y}.webp', {
maxZoom: 20,
minZoom: 15,
tms: true
});
map_territory = L.map(mapElement, {
renderer: L.canvas(),
center: [lat, lng],
zoom: 0,
zoomControl: false,
layers: [
googleHybrid,
osm,
mytile
]
});
map_territory.setZoom((data.zoom - 1));
let baseMaps = {
"Google Hybrid": googleHybrid,
"OpenStreetMap": osm,
"Sheep Service Map": mytile,
};
let layerControl = L.control.layers(baseMaps, [], { position: 'bottomright' }).addTo(map_territory);
map_territory.pm.setLang("ua");
const polygonOptions = type === "homestead" ? {
color: "#f2bd53",
radius: 500,
fillOpacity: 0.3,
dashArray: '20,15',
dashOffset: '20',
} : {
color: "#585858",
fillColor: "#f2bd53",
fillOpacity: 0.8
};
L.polygon(data.points, polygonOptions).addTo(map_territory);
console.log(data.zoom);
// setTimeout(() => {
// map_territory.setZoom(data.zoom);
// }, 200)
},
mess: {
open: ({ type, id, number, mode }) => {
const block = document.getElementById('territory-new');
const groupInput = document.getElementById('new-worker-group');
const nameInput = document.getElementById('new-worker-name');
const button = document.getElementById('new-worker-button');
// Показуємо блок
block.style.display = "";
requestAnimationFrame(() => block.style.opacity = "1");
groupInput.style.display = mode ? 'none' : 'flex';
nameInput.style.display = mode ? 'flex' : 'none';
button.onclick = () => Territory_Manager.newWorker({ type, id, number, mode });
},
close: () => {
// Робимо плавне зникнення
const block = document.getElementById('territory-new');
block.style.opacity = "0";
const onTransitionEnd = () => {
block.style.display = "none";
block.removeEventListener("transitionend", onTransitionEnd);
};
block.addEventListener("transitionend", onTransitionEnd);
}
},
newWorker: async ({ type, id, number, mode }) => {
const uuid = localStorage.getItem('uuid');
const sheepName = document.getElementById('new-worker-name').value;
const groupId = Number(document.getElementById('new-worker-group').value);
const newButton = document.getElementById('new-worker-button');
const groupButton = document.getElementById('group-working-button');
let territory_id;
let URL;
const sheep = Sheeps.sheeps_list.list.find(e => e.name === sheepName);
if (type === "house") {
territory_id = Territory_Manager.entrances.list[number]?.id;
URL = `${CONFIG.api}history/entrance/${territory_id}`;
} else if (type === "homestead") {
territory_id = Territory_Manager.info.list.id;
URL = `${CONFIG.api}history/homestead/${territory_id}`;
}
if (!territory_id || !URL) {
console.warn("Невірні дані для призначення.");
return;
}
const data = {
name: mode ? sheepName : "Групова",
group_id: mode ? sheep?.group_id : groupId,
sheep_id: mode ? sheep?.id : null
};
try {
const response = await fetch(URL, {
method: 'POST',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify(data)
});
if (!response.ok) throw new Error("Failed to assign");
Territory_Manager.mess.close();
Territory_Manager.entrances.list = [];
await Territory_Manager.entrances.setHTML(type, id);
} catch (err) {
console.error('❌ Error:', err);
const errorText = "Помилка";
if (newButton) newButton.innerText = errorText;
if (groupButton) groupButton.innerText = errorText;
}
},
endWorker: async (type, id, territory_id) => {
const button = document.getElementById('end-working-button');
const uuid = localStorage.getItem('uuid');
const URL = type === "house"
? `${CONFIG.api}history/entrance/${territory_id}`
: `${CONFIG.api}history/homestead/${territory_id}`;
try {
const response = await fetch(URL, {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
},
body: JSON.stringify({})
});
if (!response.ok) throw new Error("Запит не успішний");
Territory_Manager.entrances.list = [];
await Territory_Manager.entrances.setHTML(type, id);
} catch (error) {
console.error("❌ Помилка зняття призначення:", error);
if (button) button.innerText = "Помилка";
}
},
share: async (type, number) => {
const isHouse = type === "house";
const territory = isHouse ? Territory_Manager.entrances.list[number] : Territory_Manager.info.list;
const id = territory.id;
const pos = Sheeps.sheeps_list.list.map(e => e.id).indexOf(territory.history.sheep_id);
let sheep = Sheeps.sheeps_list.list[pos];
console.log(pos);
const shareUrl = pos > 0
? `\n\nПосилання на програму:\n • https://sheep-service.com/?uuid=${sheep.uuid}`
: '';
const description = Territory_Manager.info.list.description?.length > 0
? `\n\nДодатково:\n${Territory_Manager.info.list.description}`
: '';
if (!navigator.share) {
console.log("Sorry! Your browser does not support Web Share API");
return;
}
try {
const baseUrl = "https://sheep-service.com/cards";
const url = isHouse
? `${baseUrl}/house/T${Territory_Manager.info.list.id}.webp`
: `${baseUrl}/homestead/H${Territory_Manager.info.list.id}.webp`;
const response = await fetch(url);
if (!response.ok) throw new Error('Image not found');
const blob = await response.blob();
const fileName = `${isHouse ? "E" + id : "H" + id}.webp`;
const file = new File([blob], fileName, { type: blob.type });
const shareText = `Територія:\n${isHouse ? "E" + id : "H" + id}\n\nНаселений пункт:\n${Territory_Manager.info.list.settlement}\n\nВулиця:\n${Territory_Manager.info.list.title} ${Territory_Manager.info.list.number} (${territory.title})${description}\n\nПризначення:\nЗ ${formattedDate(territory.history.date.start)}\n • До ${formattedDate(territory.history.date.end) ?? formattedDate(territory.history.date.start + (1000 * 2629743 * 4))}${shareUrl}`;
console.log(shareText);
await navigator.share({
text: shareText,
files: [file]
});
console.log('Успешно отправлено!');
} catch (error) {
console.error('Ошибка при отправке:', error);
}
},
getScreen: async () => {
const center = map_territory.getCenter();
const zoom = (map_territory.getZoom() + 2) || 17;
const info = Territory_Manager.info.list;
const params = new URLSearchParams({
lat: center.lat,
lng: center.lng,
type: type_territory,
wayId: info.osm_id,
zoom,
address: info.title,
number: info.number,
id: info.id
});
const url = `https://sheep-service.com/api/generator/cards?${params.toString()}`;
const uuid = localStorage.getItem("uuid");
try {
const response = await fetch(url, {
method: 'GET',
headers: {
"Content-Type": "application/json",
"Authorization": uuid
}
});
const result = await response.json();
const urlImage = `https://sheep-service.com/cards/${type_territory}/${type_territory === "house" ? "T" : "H"}${info.id}.webp`;
const errorElem = document.getElementById('menu-picture-error');
const okElem = document.getElementById('menu-picture-ok');
if (result) {
errorElem.style.display = 'none';
okElem.style.display = '';
okElem.setAttribute("href", urlImage);
} else {
errorElem.style.display = '';
okElem.style.display = 'none';
}
} catch (err) {
console.error('Ошибка при получении скрина:', err);
}
}
}