Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de562d164c | |||
| 2c1f1b2a20 |
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-telemetria.php';
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/libs/leaflet/leaflet.css" />
|
||||
|
||||
<style>
|
||||
#installationsMap {
|
||||
height: calc(100vh - 220px);
|
||||
min-height: 480px;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.map-sidebar-list {
|
||||
max-height: calc(100vh - 420px);
|
||||
min-height: 220px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.map-marker-pin {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50% 50% 50% 0;
|
||||
transform: rotate(-45deg);
|
||||
border: 2px solid #fff;
|
||||
box-shadow: 0 2px 6px rgba(67, 89, 113, 0.35);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #696cff;
|
||||
}
|
||||
|
||||
.map-marker-pin i {
|
||||
transform: rotate(45deg);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.map-marker-pin.is-alert {
|
||||
background-color: #ff3e1d;
|
||||
}
|
||||
|
||||
.map-list-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.map-list-item:hover,
|
||||
.map-list-item.is-focused {
|
||||
background-color: rgba(105, 108, 255, 0.08);
|
||||
}
|
||||
|
||||
.map-list-item.is-hidden-on-map {
|
||||
opacity: 0.55;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
Telemetria <span class="text-muted fw-light">/ Mapa instalacji</span>
|
||||
</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-8 col-xl-9">
|
||||
<div class="card shadow-sm border-0 overflow-hidden">
|
||||
<div id="installationsMap"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card shadow-sm border-0 h-100">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Instalacje na mapie</h5>
|
||||
<small class="text-muted">Wyszukaj, filtruj i zarządzaj widocznością</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3 mt-3">
|
||||
<label class="form-label" for="mapSearchInput">Szukaj</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="bx bx-search"></i></span>
|
||||
<input type="text" id="mapSearchInput" class="form-control" placeholder="Nazwa lub lokalizacja...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="mapTypeFilter">Typ</label>
|
||||
<select id="mapTypeFilter" class="form-select">
|
||||
<option value="">Wszystkie typy</option>
|
||||
<option value="gas">Zbiornik Gazu</option>
|
||||
<option value="farm">Kurnik / Farma</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="mapStatusFilter">Status</label>
|
||||
<select id="mapStatusFilter" class="form-select">
|
||||
<option value="">Każdy status</option>
|
||||
<option value="online">Online</option>
|
||||
<option value="alert">Alert</option>
|
||||
<option value="offline">Offline</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="fw-medium">Widoczność</span>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="button" class="btn btn-outline-primary" id="showAllInstallationsBtn">Wszystkie</button>
|
||||
<button type="button" class="btn btn-outline-secondary" id="hideAllInstallationsBtn">Ukryj</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mapInstallationsList" class="map-sidebar-list border rounded"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script src="<?= $basePath ?>/assets/vendor/libs/leaflet/leaflet.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const installations = [
|
||||
{
|
||||
id: 'inst-1',
|
||||
name: 'Zbiornik LPG #1',
|
||||
location: 'Stalowa Wola, ul. Przemysłowa 5',
|
||||
type: 'gas',
|
||||
typeLabel: 'Zbiornik Gazu',
|
||||
status: 'online',
|
||||
statusLabel: 'Online',
|
||||
lat: 50.5826,
|
||||
lng: 22.0534,
|
||||
alert: null,
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-2',
|
||||
name: 'Kurnik B (Sektor 2)',
|
||||
location: 'Farma Wola, Obiekt Główny',
|
||||
type: 'farm',
|
||||
typeLabel: 'Sterownik Kurnika',
|
||||
status: 'online',
|
||||
statusLabel: 'Online',
|
||||
lat: 50.6012,
|
||||
lng: 22.0918,
|
||||
alert: null,
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-3',
|
||||
name: 'Zbiornik LPG #2',
|
||||
location: 'Rzeszów, Baza Północ',
|
||||
type: 'gas',
|
||||
typeLabel: 'Zbiornik Gazu',
|
||||
status: 'offline',
|
||||
statusLabel: 'Offline',
|
||||
lat: 50.0578,
|
||||
lng: 22.0048,
|
||||
alert: 'Brak łączności — brak sygnału od ponad 3 dni.',
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-4',
|
||||
name: 'Zbiornik LPG #3',
|
||||
location: 'Lublin, ul. Metalurgiczna 12',
|
||||
type: 'gas',
|
||||
typeLabel: 'Zbiornik Gazu',
|
||||
status: 'alert',
|
||||
statusLabel: 'Alert',
|
||||
lat: 51.2354,
|
||||
lng: 22.5489,
|
||||
alert: 'Niski poziom gazu — poziom poniżej 15%.',
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-5',
|
||||
name: 'Zbiornik LPG #4',
|
||||
location: 'Tarnobrzeg, Stacja Przeładunkowa',
|
||||
type: 'gas',
|
||||
typeLabel: 'Zbiornik Gazu',
|
||||
status: 'online',
|
||||
statusLabel: 'Online',
|
||||
lat: 50.5731,
|
||||
lng: 21.6794,
|
||||
alert: null,
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-6',
|
||||
name: 'Sterownik Farma Alpha',
|
||||
location: 'Nisko, Sektor A',
|
||||
type: 'farm',
|
||||
typeLabel: 'Sterownik Kurnika',
|
||||
status: 'online',
|
||||
statusLabel: 'Online',
|
||||
lat: 50.5198,
|
||||
lng: 22.1396,
|
||||
alert: null,
|
||||
url: 'installation-live.php'
|
||||
},
|
||||
{
|
||||
id: 'inst-7',
|
||||
name: 'Zbiornik LPG #5',
|
||||
location: 'Przemyśl, Baza Południe',
|
||||
type: 'gas',
|
||||
typeLabel: 'Zbiornik Gazu',
|
||||
status: 'online',
|
||||
statusLabel: 'Online',
|
||||
lat: 49.7837,
|
||||
lng: 22.7673,
|
||||
alert: null,
|
||||
url: 'installation-live.php'
|
||||
}
|
||||
];
|
||||
|
||||
const mapEl = document.getElementById('installationsMap');
|
||||
if (!mapEl || typeof L === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
const map = L.map(mapEl).setView([50.45, 22.15], 8);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||
maxZoom: 18
|
||||
}).addTo(map);
|
||||
|
||||
const markersById = {};
|
||||
let closePopupTimer = null;
|
||||
|
||||
function createMarkerIcon(hasAlert) {
|
||||
const pinClass = hasAlert ? ' is-alert' : '';
|
||||
const iconHtml = hasAlert
|
||||
? '<i class="bx bx-error"></i>'
|
||||
: '<i class="bx bx-buildings"></i>';
|
||||
|
||||
return L.divIcon({
|
||||
className: '',
|
||||
html: '<div class="map-marker-pin' + pinClass + '">' + iconHtml + '</div>',
|
||||
iconSize: [32, 32],
|
||||
iconAnchor: [16, 32],
|
||||
popupAnchor: [0, -28]
|
||||
});
|
||||
}
|
||||
|
||||
function buildPopupHtml(item) {
|
||||
const alertBlock = item.alert
|
||||
? '<div class="alert alert-danger py-2 px-3 mb-2 small">' +
|
||||
'<i class="bx bx-error-circle me-1"></i>' + item.alert +
|
||||
'</div>'
|
||||
: '<p class="text-muted small mb-2">Brak aktywnych alertów</p>';
|
||||
|
||||
return (
|
||||
'<div>' +
|
||||
'<h6 class="mb-1 fw-bold">' + item.name + '</h6>' +
|
||||
'<small class="text-muted d-block mb-2"><i class="bx bx-map me-1"></i>' + item.location + '</small>' +
|
||||
alertBlock +
|
||||
'<button type="button" class="btn btn-sm btn-primary w-100" onclick="window.location.href=\'' + item.url + '\'">' +
|
||||
'<i class="bx bx-right-arrow-alt me-1"></i> Przejdź do instalacji' +
|
||||
'</button>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
|
||||
function statusBadgeClass(status) {
|
||||
if (status === 'online') return 'bg-success';
|
||||
if (status === 'alert') return 'bg-danger';
|
||||
return 'bg-secondary';
|
||||
}
|
||||
|
||||
installations.forEach(function (item) {
|
||||
const marker = L.marker([item.lat, item.lng], {
|
||||
icon: createMarkerIcon(Boolean(item.alert)),
|
||||
title: item.name
|
||||
});
|
||||
|
||||
marker.bindPopup(buildPopupHtml(item));
|
||||
|
||||
marker.on('mouseover', function () {
|
||||
if (closePopupTimer) {
|
||||
clearTimeout(closePopupTimer);
|
||||
closePopupTimer = null;
|
||||
}
|
||||
marker.openPopup();
|
||||
});
|
||||
|
||||
marker.on('mouseout', function () {
|
||||
closePopupTimer = setTimeout(function () {
|
||||
marker.closePopup();
|
||||
}, 280);
|
||||
});
|
||||
|
||||
marker.on('popupopen', function () {
|
||||
const popupEl = marker.getPopup().getElement();
|
||||
if (!popupEl) return;
|
||||
|
||||
popupEl.addEventListener('mouseenter', function () {
|
||||
if (closePopupTimer) {
|
||||
clearTimeout(closePopupTimer);
|
||||
closePopupTimer = null;
|
||||
}
|
||||
});
|
||||
|
||||
popupEl.addEventListener('mouseleave', function () {
|
||||
closePopupTimer = setTimeout(function () {
|
||||
marker.closePopup();
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
markersById[item.id] = {
|
||||
item: item,
|
||||
marker: marker,
|
||||
visible: true,
|
||||
matchesFilter: true
|
||||
};
|
||||
|
||||
marker.addTo(map);
|
||||
});
|
||||
|
||||
const listEl = document.getElementById('mapInstallationsList');
|
||||
const searchInput = document.getElementById('mapSearchInput');
|
||||
const typeFilter = document.getElementById('mapTypeFilter');
|
||||
const statusFilter = document.getElementById('mapStatusFilter');
|
||||
|
||||
function renderList() {
|
||||
const fragments = installations.map(function (item) {
|
||||
const state = markersById[item.id];
|
||||
if (!state.matchesFilter) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const hiddenClass = state.visible ? '' : ' is-hidden-on-map';
|
||||
const alertIcon = item.alert
|
||||
? '<i class="bx bx-error-circle text-danger ms-1" title="Alert"></i>'
|
||||
: '';
|
||||
|
||||
return (
|
||||
'<div class="map-list-item border-bottom px-3 py-2' + hiddenClass + '" data-id="' + item.id + '">' +
|
||||
'<div class="d-flex align-items-start gap-2">' +
|
||||
'<div class="form-check form-switch mb-0 mt-1">' +
|
||||
'<input class="form-check-input map-visibility-toggle" type="checkbox" role="switch" ' +
|
||||
'data-id="' + item.id + '" ' + (state.visible ? 'checked' : '') + ' ' +
|
||||
'aria-label="Widoczność ' + item.name + '">' +
|
||||
'</div>' +
|
||||
'<div class="flex-grow-1 min-w-0">' +
|
||||
'<div class="d-flex justify-content-between align-items-start gap-2">' +
|
||||
'<div class="min-w-0">' +
|
||||
'<div class="fw-semibold text-truncate">' + item.name + alertIcon + '</div>' +
|
||||
'<small class="text-muted text-truncate d-block">' + item.location + '</small>' +
|
||||
'</div>' +
|
||||
'<span class="badge ' + statusBadgeClass(item.status) + '">' + item.statusLabel + '</span>' +
|
||||
'</div>' +
|
||||
'<small class="text-muted">' + item.typeLabel + '</small>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}).join('');
|
||||
|
||||
listEl.innerHTML = fragments ||
|
||||
'<div class="text-center text-muted py-4 px-3 small">Brak instalacji spełniających kryteria</div>';
|
||||
}
|
||||
|
||||
function applyFilters() {
|
||||
const query = (searchInput.value || '').trim().toLowerCase();
|
||||
const type = typeFilter.value;
|
||||
const status = statusFilter.value;
|
||||
|
||||
installations.forEach(function (item) {
|
||||
const state = markersById[item.id];
|
||||
const haystack = (item.name + ' ' + item.location).toLowerCase();
|
||||
const matchesQuery = !query || haystack.indexOf(query) !== -1;
|
||||
const matchesType = !type || item.type === type;
|
||||
const matchesStatus = !status || item.status === status;
|
||||
state.matchesFilter = matchesQuery && matchesType && matchesStatus;
|
||||
|
||||
const shouldShow = state.matchesFilter && state.visible;
|
||||
if (shouldShow) {
|
||||
if (!map.hasLayer(state.marker)) {
|
||||
state.marker.addTo(map);
|
||||
}
|
||||
} else if (map.hasLayer(state.marker)) {
|
||||
map.removeLayer(state.marker);
|
||||
}
|
||||
});
|
||||
|
||||
renderList();
|
||||
}
|
||||
|
||||
function setAllVisibility(visible) {
|
||||
installations.forEach(function (item) {
|
||||
markersById[item.id].visible = visible;
|
||||
});
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
function focusInstallation(id) {
|
||||
const state = markersById[id];
|
||||
if (!state || !state.matchesFilter) return;
|
||||
|
||||
if (!state.visible) {
|
||||
state.visible = true;
|
||||
applyFilters();
|
||||
}
|
||||
|
||||
map.flyTo([state.item.lat, state.item.lng], 12, { duration: 0.6 });
|
||||
state.marker.openPopup();
|
||||
|
||||
listEl.querySelectorAll('.map-list-item').forEach(function (el) {
|
||||
el.classList.toggle('is-focused', el.getAttribute('data-id') === id);
|
||||
});
|
||||
}
|
||||
|
||||
listEl.addEventListener('change', function (event) {
|
||||
const toggle = event.target.closest('.map-visibility-toggle');
|
||||
if (!toggle) return;
|
||||
|
||||
const id = toggle.getAttribute('data-id');
|
||||
markersById[id].visible = toggle.checked;
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
listEl.addEventListener('click', function (event) {
|
||||
if (event.target.closest('.map-visibility-toggle')) return;
|
||||
const row = event.target.closest('.map-list-item');
|
||||
if (!row) return;
|
||||
focusInstallation(row.getAttribute('data-id'));
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', applyFilters);
|
||||
typeFilter.addEventListener('change', applyFilters);
|
||||
statusFilter.addEventListener('change', applyFilters);
|
||||
|
||||
document.getElementById('showAllInstallationsBtn').addEventListener('click', function () {
|
||||
setAllVisibility(true);
|
||||
});
|
||||
|
||||
document.getElementById('hideAllInstallationsBtn').addEventListener('click', function () {
|
||||
setAllVisibility(false);
|
||||
});
|
||||
|
||||
applyFilters();
|
||||
|
||||
setTimeout(function () {
|
||||
map.invalidateSize();
|
||||
}, 200);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-telemetria.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
Telemetria <span class="text-muted fw-light">/ Logi systemowe</span>
|
||||
</h4>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Dziennik zdarzeń (Logi modułu)</h5>
|
||||
</div>
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data</th>
|
||||
<th>Użytkownik</th>
|
||||
<th>Operacja</th>
|
||||
<th>Szczegóły</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
<tr>
|
||||
<td>2026-06-19 16:30</td>
|
||||
<td><span class="badge bg-label-primary"><i class="bx bx-user me-1"></i> Jan Kowalski</span></td>
|
||||
<td><span class="fw-bold text-danger">Usunięcie urządzenia</span></td>
|
||||
<td>ID: 1024</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-06-19 16:20</td>
|
||||
<td><span class="badge bg-label-secondary"><i class="bx bx-cog me-1"></i> System</span></td>
|
||||
<td><span class="fw-bold text-warning">Zmiana statusu</span></td>
|
||||
<td>ID: 1024, Status: Online → Offline (utrata łączności)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-06-19 16:15</td>
|
||||
<td><span class="badge bg-label-primary"><i class="bx bx-user me-1"></i> Jan Kowalski</span></td>
|
||||
<td><span class="fw-bold text-info">Edycja danych</span></td>
|
||||
<td>ID: 1024, Edycja danych urządzenia.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2026-06-19 16:10</td>
|
||||
<td><span class="badge bg-label-primary"><i class="bx bx-user me-1"></i> Jan Kowalski</span></td>
|
||||
<td><span class="fw-bold text-success">Dodanie urządzenia</span></td>
|
||||
<td>MAC: AA:BB:CC:DD:EE:FF, Nazwa: "Sterownik Klimatu Alpha"</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -42,11 +42,23 @@ $currentPage = basename($_SERVER['PHP_SELF']);
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'installations.php') ? 'active' : ''; ?>">
|
||||
<a href="installations.php" class="menu-link">
|
||||
<li class="menu-item <?php echo in_array($currentPage, ['installations.php', 'installations-map.php'], true) ? 'active open' : ''; ?>">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<i class="menu-icon tf-icons bx bx-buildings"></i>
|
||||
<div class="text-truncate" data-i18n="Instalacje">Instalacje</div>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item <?php echo ($currentPage == 'installations.php') ? 'active' : ''; ?>">
|
||||
<a href="installations.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Lista">Lista instalacji</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'installations-map.php') ? 'active' : ''; ?>">
|
||||
<a href="installations-map.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Mapa instalacji">Mapa instalacji</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'devices.php') ? 'active' : ''; ?>">
|
||||
<a href="devices.php" class="menu-link">
|
||||
@@ -60,5 +72,23 @@ $currentPage = basename($_SERVER['PHP_SELF']);
|
||||
<div class="text-truncate" data-i18n="Raporty">Raporty</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'settings.php' || $currentPage == 'logs.php') ? 'active open' : ''; ?>">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<i class="menu-icon tf-icons bx bx-server"></i>
|
||||
<div class="text-truncate" data-i18n="System">System</div>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item <?php echo ($currentPage == 'settings.php') ? 'active' : ''; ?>">
|
||||
<a href="settings.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Ustawienia">Ustawienia</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'logs.php') ? 'active' : ''; ?>">
|
||||
<a href="logs.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Logi">Logi systemowe</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-telemetria.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
Telemetria <span class="text-muted fw-light">/ Ustawienia</span>
|
||||
</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-12 mb-4">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Powiadomienia i Alerty</h5>
|
||||
</div>
|
||||
<div class="card-body pt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h6 class="mb-1">Aktywny moduł alertów</h6>
|
||||
<small class="text-muted">Pozwala na ustawianie zaawansowanych wyzwalaczy i powiadomień SMS/Email po przekroczeniu progów alarmowych w instalacjach.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch form-switch-lg ms-3 mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="alertsModuleSwitch">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary mt-3" onclick="saveSettings()">Zapisz ustawienia</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal potwierdzenia włączenia -->
|
||||
<div class="modal fade" id="confirmPaymentModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-warning border-2">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title text-warning"><i class="bx bx-error-circle me-1"></i> Potwierdzenie subskrypcji</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" onclick="cancelSwitch()"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Uruchomienie modułu <strong>Powiadomienia i Alerty</strong> wiąże się z dodatkową opłatą abonamentową w wysokości <strong>50 zł / msc</strong> doliczaną do Twojej faktury.</p>
|
||||
<p class="mb-0 text-dark fw-bold">Czy na pewno chcesz włączyć ten moduł?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal" onclick="cancelSwitch()">Anuluj</button>
|
||||
<button type="button" class="btn btn-success" data-bs-dismiss="modal" onclick="confirmSave()">Tak, włączam moduł</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let isCurrentlyEnabled = false; // Zakładamy że na start jest wyłączone
|
||||
|
||||
function saveSettings() {
|
||||
const switchEl = document.getElementById('alertsModuleSwitch');
|
||||
|
||||
// Jeśli chcemy włączyć, a wcześniej było wyłączone
|
||||
if (switchEl.checked && !isCurrentlyEnabled) {
|
||||
var paymentModal = new bootstrap.Modal(document.getElementById('confirmPaymentModal'));
|
||||
paymentModal.show();
|
||||
} else if (!switchEl.checked && isCurrentlyEnabled) {
|
||||
alert('Moduł został pomyślnie wyłączony. Opłata nie będzie naliczana od następnego okresu rozliczeniowego.');
|
||||
isCurrentlyEnabled = false;
|
||||
} else {
|
||||
alert('Ustawienia zapisane bez zmian.');
|
||||
}
|
||||
}
|
||||
|
||||
function confirmSave() {
|
||||
isCurrentlyEnabled = true;
|
||||
document.getElementById('alertsModuleSwitch').checked = true;
|
||||
alert('Moduł został włączony! Doliczono 50 zł/msc do Twojego abonamentu. Możesz teraz konfigurować alerty w instalacjach.');
|
||||
}
|
||||
|
||||
function cancelSwitch() {
|
||||
// Jeśli anulowano modal, przywracamy przełącznik do stanu wylączonego
|
||||
document.getElementById('alertsModuleSwitch').checked = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user