Laitetilat: laitelinkit kortteihin + Sijainnit pois yritysasetuksista
Laitetila-laite-yhteys: - Lisätty laitetila_id -sarake devices-tauluun - Laite-lomakkeeseen uusi "Laitetila" dropdown (Tekniikka → Laitteet) - Laitetila-kortit näyttävät laitemäärän ja laitechipit (max 4 + "+N muuta") - Laitetilan detailnäkymässä taulukko tilan laitteista (nimi, tyyppi, malli, IP, ping) - dbLoadLaitetilat palauttaa device_count ja devices-listan per laitetila Yritysasetukset: - Poistettu Sijainnit-osio yrityksen tiedoista (hallitaan Tekniikka → Sijainnit) - Sijainnit sub-tab Tekniikassa pysyy ennallaan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
api.php
1
api.php
@@ -1944,6 +1944,7 @@ switch ($action) {
|
|||||||
'hallintaosoite' => trim($input['hallintaosoite'] ?? ''),
|
'hallintaosoite' => trim($input['hallintaosoite'] ?? ''),
|
||||||
'serial' => trim($input['serial'] ?? ''),
|
'serial' => trim($input['serial'] ?? ''),
|
||||||
'site_id' => $input['site_id'] ?? null,
|
'site_id' => $input['site_id'] ?? null,
|
||||||
|
'laitetila_id' => $input['laitetila_id'] ?? null,
|
||||||
'funktio' => trim($input['funktio'] ?? ''),
|
'funktio' => trim($input['funktio'] ?? ''),
|
||||||
'tyyppi' => trim($input['tyyppi'] ?? ''),
|
'tyyppi' => trim($input['tyyppi'] ?? ''),
|
||||||
'malli' => trim($input['malli'] ?? ''),
|
'malli' => trim($input['malli'] ?? ''),
|
||||||
|
|||||||
13
db.php
13
db.php
@@ -614,6 +614,7 @@ function initDatabase(): void {
|
|||||||
"ALTER TABLE documents ADD COLUMN folder_id VARCHAR(20) DEFAULT NULL AFTER customer_id",
|
"ALTER TABLE documents ADD COLUMN folder_id VARCHAR(20) DEFAULT NULL AFTER customer_id",
|
||||||
"ALTER TABLE documents ADD COLUMN max_versions INT DEFAULT 10 AFTER current_version",
|
"ALTER TABLE documents ADD COLUMN max_versions INT DEFAULT 10 AFTER current_version",
|
||||||
"ALTER TABLE document_versions ADD COLUMN content MEDIUMTEXT DEFAULT NULL AFTER mime_type",
|
"ALTER TABLE document_versions ADD COLUMN content MEDIUMTEXT DEFAULT NULL AFTER mime_type",
|
||||||
|
"ALTER TABLE devices ADD COLUMN laitetila_id VARCHAR(20) DEFAULT NULL AFTER site_id",
|
||||||
];
|
];
|
||||||
foreach ($alters as $sql) {
|
foreach ($alters as $sql) {
|
||||||
try { $db->query($sql); } catch (\Throwable $e) { /* sarake on jo olemassa / jo ajettu */ }
|
try { $db->query($sql); } catch (\Throwable $e) { /* sarake on jo olemassa / jo ajettu */ }
|
||||||
@@ -1070,9 +1071,10 @@ function dbDeleteSite(string $siteId): void {
|
|||||||
|
|
||||||
function dbLoadDevices(string $companyId): array {
|
function dbLoadDevices(string $companyId): array {
|
||||||
$devices = _dbFetchAll("
|
$devices = _dbFetchAll("
|
||||||
SELECT d.*, s.nimi AS site_name
|
SELECT d.*, s.nimi AS site_name, lt.nimi AS laitetila_name
|
||||||
FROM devices d
|
FROM devices d
|
||||||
LEFT JOIN sites s ON d.site_id = s.id
|
LEFT JOIN sites s ON d.site_id = s.id
|
||||||
|
LEFT JOIN laitetilat lt ON d.laitetila_id = lt.id
|
||||||
WHERE d.company_id = ?
|
WHERE d.company_id = ?
|
||||||
ORDER BY d.nimi
|
ORDER BY d.nimi
|
||||||
", [$companyId]);
|
", [$companyId]);
|
||||||
@@ -1085,11 +1087,11 @@ function dbLoadDevices(string $companyId): array {
|
|||||||
|
|
||||||
function dbSaveDevice(string $companyId, array $device): void {
|
function dbSaveDevice(string $companyId, array $device): void {
|
||||||
_dbExecute("
|
_dbExecute("
|
||||||
INSERT INTO devices (id, company_id, nimi, hallintaosoite, serial, site_id, funktio, tyyppi, malli, ping_check, lisatiedot, luotu, muokattu, muokkaaja)
|
INSERT INTO devices (id, company_id, nimi, hallintaosoite, serial, site_id, laitetila_id, funktio, tyyppi, malli, ping_check, lisatiedot, luotu, muokattu, muokkaaja)
|
||||||
VALUES (:id, :company_id, :nimi, :hallintaosoite, :serial, :site_id, :funktio, :tyyppi, :malli, :ping_check, :lisatiedot, :luotu, :muokattu, :muokkaaja)
|
VALUES (:id, :company_id, :nimi, :hallintaosoite, :serial, :site_id, :laitetila_id, :funktio, :tyyppi, :malli, :ping_check, :lisatiedot, :luotu, :muokattu, :muokkaaja)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
nimi = VALUES(nimi), hallintaosoite = VALUES(hallintaosoite), serial = VALUES(serial),
|
nimi = VALUES(nimi), hallintaosoite = VALUES(hallintaosoite), serial = VALUES(serial),
|
||||||
site_id = VALUES(site_id), funktio = VALUES(funktio), tyyppi = VALUES(tyyppi),
|
site_id = VALUES(site_id), laitetila_id = VALUES(laitetila_id), funktio = VALUES(funktio), tyyppi = VALUES(tyyppi),
|
||||||
malli = VALUES(malli), ping_check = VALUES(ping_check), lisatiedot = VALUES(lisatiedot),
|
malli = VALUES(malli), ping_check = VALUES(ping_check), lisatiedot = VALUES(lisatiedot),
|
||||||
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
||||||
", [
|
", [
|
||||||
@@ -1099,6 +1101,7 @@ function dbSaveDevice(string $companyId, array $device): void {
|
|||||||
'hallintaosoite' => $device['hallintaosoite'] ?? '',
|
'hallintaosoite' => $device['hallintaosoite'] ?? '',
|
||||||
'serial' => $device['serial'] ?? '',
|
'serial' => $device['serial'] ?? '',
|
||||||
'site_id' => !empty($device['site_id']) ? $device['site_id'] : null,
|
'site_id' => !empty($device['site_id']) ? $device['site_id'] : null,
|
||||||
|
'laitetila_id' => !empty($device['laitetila_id']) ? $device['laitetila_id'] : null,
|
||||||
'funktio' => $device['funktio'] ?? '',
|
'funktio' => $device['funktio'] ?? '',
|
||||||
'tyyppi' => $device['tyyppi'] ?? '',
|
'tyyppi' => $device['tyyppi'] ?? '',
|
||||||
'malli' => $device['malli'] ?? '',
|
'malli' => $device['malli'] ?? '',
|
||||||
@@ -1950,6 +1953,8 @@ function dbLoadLaitetilat(string $companyId): array {
|
|||||||
$tilat = _dbFetchAll("SELECT * FROM laitetilat WHERE company_id = ? ORDER BY nimi", [$companyId]);
|
$tilat = _dbFetchAll("SELECT * FROM laitetilat WHERE company_id = ? ORDER BY nimi", [$companyId]);
|
||||||
foreach ($tilat as &$t) {
|
foreach ($tilat as &$t) {
|
||||||
$t['file_count'] = (int)_dbFetchScalar("SELECT COUNT(*) FROM laitetila_files WHERE laitetila_id = ?", [$t['id']]);
|
$t['file_count'] = (int)_dbFetchScalar("SELECT COUNT(*) FROM laitetila_files WHERE laitetila_id = ?", [$t['id']]);
|
||||||
|
$t['device_count'] = (int)_dbFetchScalar("SELECT COUNT(*) FROM devices WHERE laitetila_id = ? AND company_id = ?", [$t['id'], $companyId]);
|
||||||
|
$t['devices'] = _dbFetchAll("SELECT id, nimi, tyyppi, malli, hallintaosoite, ping_status FROM devices WHERE laitetila_id = ? AND company_id = ? ORDER BY nimi", [$t['id'], $companyId]);
|
||||||
}
|
}
|
||||||
return $tilat;
|
return $tilat;
|
||||||
}
|
}
|
||||||
|
|||||||
43
index.html
43
index.html
@@ -983,6 +983,12 @@
|
|||||||
<h4 style="color:var(--primary-dark);margin-bottom:0.5rem;">Tiedostot</h4>
|
<h4 style="color:var(--primary-dark);margin-bottom:0.5rem;">Tiedostot</h4>
|
||||||
<div id="laitetila-files-list"></div>
|
<div id="laitetila-files-list"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Laitteet tässä tilassa -->
|
||||||
|
<div id="laitetila-devices-section" style="margin-top:1.5rem;">
|
||||||
|
<h4 style="color:var(--primary-dark);margin-bottom:0.5rem;">🖥 Laitteet</h4>
|
||||||
|
<div id="laitetila-devices-list"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1717,37 +1723,6 @@
|
|||||||
<pre id="smtp-test-result" style="display:none;background:#1a1a2e;color:#0f0;padding:0.75rem;border-radius:6px;font-size:0.8rem;max-height:300px;overflow:auto;margin-top:0.5rem;white-space:pre-wrap;"></pre>
|
<pre id="smtp-test-result" style="display:none;background:#1a1a2e;color:#0f0;padding:0.75rem;border-radius:6px;font-size:0.8rem;max-height:300px;overflow:auto;margin-top:0.5rem;white-space:pre-wrap;"></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Sijainnit (Sites) -->
|
|
||||||
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
|
||||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
|
|
||||||
<h3 style="color:#0f3460;margin:0;">Sijainnit</h3>
|
|
||||||
<button class="btn-primary" id="btn-add-site" style="font-size:0.85rem;">+ Lisää sijainti</button>
|
|
||||||
</div>
|
|
||||||
<p style="color:#888;font-size:0.85rem;margin-bottom:1rem;">Toimipisteet ja konesalit joihin laitteita voidaan sijoittaa.</p>
|
|
||||||
<div id="sites-list"></div>
|
|
||||||
<div id="site-form-container" style="display:none;margin-top:1rem;padding:1rem;background:#f8f9fb;border-radius:8px;">
|
|
||||||
<h4 style="color:#0f3460;margin-bottom:0.75rem;" id="site-form-title">Uusi sijainti</h4>
|
|
||||||
<input type="hidden" id="site-form-id">
|
|
||||||
<div class="form-grid" style="max-width:600px;">
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Nimi *</label>
|
|
||||||
<input type="text" id="site-form-nimi" placeholder="esim. Konesali A">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Osoite</label>
|
|
||||||
<input type="text" id="site-form-osoite" placeholder="esim. Teollisuuskatu 5">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>Kaupunki</label>
|
|
||||||
<input type="text" id="site-form-kaupunki" placeholder="esim. Helsinki">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="display:flex;gap:0.5rem;margin-top:0.75rem;">
|
|
||||||
<button class="btn-primary" id="btn-save-site">Tallenna</button>
|
|
||||||
<button class="btn-secondary" id="btn-cancel-site">Peruuta</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Käyttäjäoikeudet -->
|
<!-- Käyttäjäoikeudet -->
|
||||||
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
||||||
<h3 style="color:#0f3460;margin-bottom:0.5rem;">Käyttäjäoikeudet</h3>
|
<h3 style="color:#0f3460;margin-bottom:0.5rem;">Käyttäjäoikeudet</h3>
|
||||||
@@ -1793,6 +1768,12 @@
|
|||||||
<option value="">— Ei sijaintia —</option>
|
<option value="">— Ei sijaintia —</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="device-form-laitetila">Laitetila</label>
|
||||||
|
<select id="device-form-laitetila">
|
||||||
|
<option value="">— Ei laitetilaa —</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="device-form-tyyppi">Tyyppi</label>
|
<label for="device-form-tyyppi">Tyyppi</label>
|
||||||
<select id="device-form-tyyppi">
|
<select id="device-form-tyyppi">
|
||||||
|
|||||||
127
script.js
127
script.js
@@ -2924,8 +2924,9 @@ async function editDevice(id) {
|
|||||||
document.getElementById('device-form-malli').value = d.malli || '';
|
document.getElementById('device-form-malli').value = d.malli || '';
|
||||||
document.getElementById('device-form-ping-check').checked = d.ping_check || false;
|
document.getElementById('device-form-ping-check').checked = d.ping_check || false;
|
||||||
document.getElementById('device-form-lisatiedot').value = d.lisatiedot || '';
|
document.getElementById('device-form-lisatiedot').value = d.lisatiedot || '';
|
||||||
await loadSitesForDropdown();
|
await loadSitesAndLaitetilatForDropdown();
|
||||||
document.getElementById('device-form-site').value = d.site_id || '';
|
document.getElementById('device-form-site').value = d.site_id || '';
|
||||||
|
document.getElementById('device-form-laitetila').value = d.laitetila_id || '';
|
||||||
document.getElementById('device-modal-title').textContent = 'Muokkaa laitetta';
|
document.getElementById('device-modal-title').textContent = 'Muokkaa laitetta';
|
||||||
document.getElementById('device-modal').style.display = 'flex';
|
document.getElementById('device-modal').style.display = 'flex';
|
||||||
}
|
}
|
||||||
@@ -2938,19 +2939,25 @@ async function deleteDevice(id, name) {
|
|||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadSitesForDropdown() {
|
async function loadSitesForDropdown() { await loadSitesAndLaitetilatForDropdown(); }
|
||||||
|
|
||||||
|
async function loadSitesAndLaitetilatForDropdown() {
|
||||||
try {
|
try {
|
||||||
sitesData = await apiCall('sites');
|
const [sites, tilat] = await Promise.all([apiCall('sites'), apiCall('laitetilat')]);
|
||||||
const sel = document.getElementById('device-form-site');
|
sitesData = sites;
|
||||||
sel.innerHTML = '<option value="">— Ei sijaintia —</option>' +
|
const siteSel = document.getElementById('device-form-site');
|
||||||
|
siteSel.innerHTML = '<option value="">— Ei sijaintia —</option>' +
|
||||||
sitesData.map(s => `<option value="${s.id}">${esc(s.nimi)}${s.kaupunki ? ' (' + esc(s.kaupunki) + ')' : ''}</option>`).join('');
|
sitesData.map(s => `<option value="${s.id}">${esc(s.nimi)}${s.kaupunki ? ' (' + esc(s.kaupunki) + ')' : ''}</option>`).join('');
|
||||||
|
const tilaSel = document.getElementById('device-form-laitetila');
|
||||||
|
tilaSel.innerHTML = '<option value="">— Ei laitetilaa —</option>' +
|
||||||
|
tilat.map(t => `<option value="${t.id}">${esc(t.nimi)}${t.osoite ? ' (' + esc(t.osoite) + ')' : ''}</option>`).join('');
|
||||||
} catch (e) { console.error(e); }
|
} catch (e) { console.error(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('btn-add-device')?.addEventListener('click', async () => {
|
document.getElementById('btn-add-device')?.addEventListener('click', async () => {
|
||||||
document.getElementById('device-form-id').value = '';
|
document.getElementById('device-form-id').value = '';
|
||||||
document.getElementById('device-form').reset();
|
document.getElementById('device-form').reset();
|
||||||
await loadSitesForDropdown();
|
await loadSitesAndLaitetilatForDropdown();
|
||||||
document.getElementById('device-modal-title').textContent = 'Lisää laite';
|
document.getElementById('device-modal-title').textContent = 'Lisää laite';
|
||||||
document.getElementById('device-modal').style.display = 'flex';
|
document.getElementById('device-modal').style.display = 'flex';
|
||||||
});
|
});
|
||||||
@@ -2970,6 +2977,7 @@ document.getElementById('device-form')?.addEventListener('submit', async (e) =>
|
|||||||
hallintaosoite: document.getElementById('device-form-hallintaosoite').value.trim(),
|
hallintaosoite: document.getElementById('device-form-hallintaosoite').value.trim(),
|
||||||
serial: document.getElementById('device-form-serial').value.trim(),
|
serial: document.getElementById('device-form-serial').value.trim(),
|
||||||
site_id: document.getElementById('device-form-site').value || null,
|
site_id: document.getElementById('device-form-site').value || null,
|
||||||
|
laitetila_id: document.getElementById('device-form-laitetila').value || null,
|
||||||
funktio: document.getElementById('device-form-funktio').value.trim(),
|
funktio: document.getElementById('device-form-funktio').value.trim(),
|
||||||
tyyppi: document.getElementById('device-form-tyyppi').value.trim(),
|
tyyppi: document.getElementById('device-form-tyyppi').value.trim(),
|
||||||
malli: document.getElementById('device-form-malli').value.trim(),
|
malli: document.getElementById('device-form-malli').value.trim(),
|
||||||
@@ -3012,7 +3020,6 @@ async function loadSitesTab() {
|
|||||||
sitesData = await apiCall('sites');
|
sitesData = await apiCall('sites');
|
||||||
sitesTabData = sitesData;
|
sitesTabData = sitesData;
|
||||||
renderSitesTab();
|
renderSitesTab();
|
||||||
renderSitesSettings(); // Päivitä myös asetuksissa
|
|
||||||
} catch (e) { console.error(e); }
|
} catch (e) { console.error(e); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3078,64 +3085,13 @@ async function deleteSite(id, name) {
|
|||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renderöi sijainnit myös asetuksissa (company detail)
|
// Alias loadSites (Tekniikka sub-tab kutsuun)
|
||||||
function renderSitesSettings() {
|
|
||||||
const container = document.getElementById('sites-list');
|
|
||||||
if (!container) return;
|
|
||||||
if (sitesData.length === 0) {
|
|
||||||
container.innerHTML = '<p style="color:#888;font-size:0.9rem;">Ei sijainteja. Lisää ensimmäinen sijainti.</p>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
container.innerHTML = sitesData.map(s => `<div style="display:flex;justify-content:space-between;align-items:center;padding:0.75rem;background:#fff;border:1px solid #e0e0e0;border-radius:8px;margin-bottom:0.5rem;">
|
|
||||||
<div>
|
|
||||||
<strong>${esc(s.nimi)}</strong>
|
|
||||||
${s.osoite ? `<span style="color:#888;font-size:0.85rem;margin-left:0.75rem;">${esc(s.osoite)}</span>` : ''}
|
|
||||||
${s.kaupunki ? `<span style="color:#888;font-size:0.85rem;margin-left:0.5rem;">${esc(s.kaupunki)}</span>` : ''}
|
|
||||||
</div>
|
|
||||||
<div style="display:flex;gap:0.5rem;">
|
|
||||||
<button class="btn-link" onclick="editSite('${s.id}')">Muokkaa</button>
|
|
||||||
<button class="btn-link" style="color:#dc2626;" onclick="deleteSite('${s.id}','${esc(s.nimi)}')">Poista</button>
|
|
||||||
</div>
|
|
||||||
</div>`).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alias loadSites asetuksista kutsuun
|
|
||||||
async function loadSites() { await loadSitesTab(); }
|
async function loadSites() { await loadSitesTab(); }
|
||||||
|
|
||||||
function renderSites() { renderSitesSettings(); }
|
function renderSites() {}
|
||||||
|
|
||||||
document.getElementById('site-search-input')?.addEventListener('input', () => renderSitesTab());
|
document.getElementById('site-search-input')?.addEventListener('input', () => renderSitesTab());
|
||||||
|
|
||||||
document.getElementById('btn-add-site')?.addEventListener('click', () => {
|
|
||||||
document.getElementById('site-form-id').value = '';
|
|
||||||
document.getElementById('site-form-nimi').value = '';
|
|
||||||
document.getElementById('site-form-osoite').value = '';
|
|
||||||
document.getElementById('site-form-kaupunki').value = '';
|
|
||||||
document.getElementById('site-form-title').textContent = 'Uusi sijainti';
|
|
||||||
document.getElementById('site-form-container').style.display = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btn-save-site')?.addEventListener('click', async () => {
|
|
||||||
const id = document.getElementById('site-form-id').value;
|
|
||||||
const nimi = document.getElementById('site-form-nimi').value.trim();
|
|
||||||
if (!nimi) return alert('Sijainnin nimi vaaditaan');
|
|
||||||
const data = {
|
|
||||||
nimi,
|
|
||||||
osoite: document.getElementById('site-form-osoite').value.trim(),
|
|
||||||
kaupunki: document.getElementById('site-form-kaupunki').value.trim(),
|
|
||||||
};
|
|
||||||
if (id) data.id = id;
|
|
||||||
try {
|
|
||||||
await apiCall('site_save', 'POST', data);
|
|
||||||
document.getElementById('site-form-container').style.display = 'none';
|
|
||||||
loadSitesTab();
|
|
||||||
} catch (e) { alert(e.message); }
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btn-cancel-site')?.addEventListener('click', () => {
|
|
||||||
document.getElementById('site-form-container').style.display = 'none';
|
|
||||||
});
|
|
||||||
|
|
||||||
// ==================== IPAM ====================
|
// ==================== IPAM ====================
|
||||||
|
|
||||||
let ipamData = [];
|
let ipamData = [];
|
||||||
@@ -5483,18 +5439,33 @@ function renderLaitetilatList() {
|
|||||||
}
|
}
|
||||||
noEl.style.display = 'none';
|
noEl.style.display = 'none';
|
||||||
|
|
||||||
grid.innerHTML = allLaitetilat.map(t => `
|
grid.innerHTML = allLaitetilat.map(t => {
|
||||||
<div class="laitetila-card" onclick="openLaitetilaRead('${t.id}')">
|
const dc = t.device_count || 0;
|
||||||
|
const devList = (t.devices || []).slice(0, 4).map(d => {
|
||||||
|
const ping = d.ping_status === 'up' ? '🟢' : d.ping_status === 'down' ? '🔴' : '⚪';
|
||||||
|
return `<span class="lt-dev-chip">${ping} ${esc(d.nimi)}</span>`;
|
||||||
|
}).join('');
|
||||||
|
const moreCount = dc > 4 ? `<span class="lt-dev-more">+${dc - 4} muuta</span>` : '';
|
||||||
|
return `<div class="laitetila-card" onclick="openLaitetilaRead('${t.id}')">
|
||||||
<h4>${esc(t.nimi)}</h4>
|
<h4>${esc(t.nimi)}</h4>
|
||||||
<p class="laitetila-osoite">${esc(t.osoite || '')}</p>
|
<p class="laitetila-osoite">${esc(t.osoite || '')}</p>
|
||||||
<p class="laitetila-meta">📁 ${t.file_count || 0} tiedostoa</p>
|
<div class="laitetila-stats">
|
||||||
</div>
|
<span>🖥 ${dc} laitetta</span>
|
||||||
`).join('');
|
<span>📁 ${t.file_count || 0} tiedostoa</span>
|
||||||
|
</div>
|
||||||
|
${dc > 0 ? `<div class="lt-dev-list">${devList}${moreCount}</div>` : ''}
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openLaitetilaRead(tilaId) {
|
async function openLaitetilaRead(tilaId) {
|
||||||
try {
|
try {
|
||||||
currentLaitetila = await apiCall(`laitetila&id=${tilaId}`);
|
// Lataa laitetiedot rinnakkain jos ei vielä ladattu
|
||||||
|
const [tila] = await Promise.all([
|
||||||
|
apiCall(`laitetila&id=${tilaId}`),
|
||||||
|
devicesData.length ? Promise.resolve() : apiCall('devices').then(d => { devicesData = d; })
|
||||||
|
]);
|
||||||
|
currentLaitetila = tila;
|
||||||
renderLaitetilaReadView();
|
renderLaitetilaReadView();
|
||||||
showLaitetilaReadView();
|
showLaitetilaReadView();
|
||||||
} catch (e) { alert('Laitetilan avaus epäonnistui: ' + e.message); }
|
} catch (e) { alert('Laitetilan avaus epäonnistui: ' + e.message); }
|
||||||
@@ -5554,6 +5525,30 @@ function renderLaitetilaReadView() {
|
|||||||
} else {
|
} else {
|
||||||
filesSection.style.display = 'none';
|
filesSection.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Laitteet tässä tilassa
|
||||||
|
const devSection = document.getElementById('laitetila-devices-section');
|
||||||
|
const devList = document.getElementById('laitetila-devices-list');
|
||||||
|
// Hae laitteet jotka on linkitetty tähän laitetilaan
|
||||||
|
const tilaDevices = (devicesData || []).filter(d => d.laitetila_id === t.id);
|
||||||
|
if (tilaDevices.length > 0) {
|
||||||
|
devSection.style.display = '';
|
||||||
|
devList.innerHTML = `<table class="lt-devices-table"><thead><tr><th>Laite</th><th>Tyyppi</th><th>Malli</th><th>IP</th><th>Tila</th></tr></thead><tbody>${
|
||||||
|
tilaDevices.map(d => {
|
||||||
|
const ping = d.ping_status === 'up' ? '🟢' : d.ping_status === 'down' ? '🔴' : '⚪';
|
||||||
|
return `<tr>
|
||||||
|
<td><strong>${esc(d.nimi)}</strong></td>
|
||||||
|
<td>${esc(d.tyyppi || '-')}</td>
|
||||||
|
<td>${esc(d.malli || '-')}</td>
|
||||||
|
<td><code>${esc(d.hallintaosoite || '-')}</code></td>
|
||||||
|
<td>${ping}</td>
|
||||||
|
</tr>`;
|
||||||
|
}).join('')
|
||||||
|
}</tbody></table>`;
|
||||||
|
} else {
|
||||||
|
devSection.style.display = '';
|
||||||
|
devList.innerHTML = '<p style="color:#aaa;font-size:0.85rem;">Ei laitteita tässä tilassa. Linkitä laitteita Tekniikka → Laitteet -osiossa.</p>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tiedoston lataus
|
// Tiedoston lataus
|
||||||
|
|||||||
18
style.css
18
style.css
@@ -1694,6 +1694,24 @@ span.empty {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.laitetila-stats {
|
||||||
|
display: flex; gap: 1rem; font-size: 0.8rem; color: #888; margin: 0.35rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lt-dev-list {
|
||||||
|
display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem;
|
||||||
|
border-top: 1px solid #f0f0f0; padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
.lt-dev-chip {
|
||||||
|
font-size: 0.75rem; background: #f3f4f6; padding: 2px 7px; border-radius: 4px; color: #555;
|
||||||
|
}
|
||||||
|
.lt-dev-more { font-size: 0.72rem; color: #aaa; padding: 2px 4px; }
|
||||||
|
|
||||||
|
.lt-devices-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
|
||||||
|
.lt-devices-table th { text-align: left; font-weight: 600; color: #888; padding: 0.4rem 0.5rem; border-bottom: 1px solid #e5e7eb; font-size: 0.8rem; }
|
||||||
|
.lt-devices-table td { padding: 0.4rem 0.5rem; border-bottom: 1px solid #f0f0f0; }
|
||||||
|
.lt-devices-table code { background: #f3f4f6; padding: 1px 5px; border-radius: 3px; font-size: 0.82rem; }
|
||||||
|
|
||||||
/* Kuvagalleria */
|
/* Kuvagalleria */
|
||||||
.gallery-grid {
|
.gallery-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
Reference in New Issue
Block a user