NetAdmin: liittymän muokkausmodal + nopeusvalikko dropdowniksi

Liittymärivin klikkaus avaa modal-ikkunan jossa voi muokata kaikkia
kenttiä (osoite, nopeus, VLAN, laite, portti, IP). Yhteysnopeus
muutettu dropdown-valikoksi sekä NetAdmin-modalissa että asiakkaan
liittymälomakkeessa. Vakionopeudet: 10/10 - 10000/10000.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 17:26:41 +02:00
parent 517e57c287
commit 9208ab387a
4 changed files with 207 additions and 2 deletions

50
api.php
View File

@@ -4266,6 +4266,56 @@ switch ($action) {
}
break;
case 'netadmin_connection':
requireAuth();
$companyId = requireCompany();
try {
$connId = (int)($_GET['id'] ?? 0);
if (!$connId) {
http_response_code(400);
echo json_encode(['error' => 'Liittymän ID puuttuu']);
break;
}
$conn = dbLoadConnection($connId);
if (!$conn || $conn['company_id'] !== $companyId) {
http_response_code(404);
echo json_encode(['error' => 'Liittymää ei löytynyt']);
break;
}
echo json_encode($conn);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Liittymän haku epäonnistui: ' . $e->getMessage()]);
}
break;
case 'netadmin_connection_update':
requireAuth();
$companyId = requireCompany();
if ($method !== 'POST') break;
try {
$input = json_decode(file_get_contents('php://input'), true);
$connId = (int)($input['id'] ?? 0);
if (!$connId) {
http_response_code(400);
echo json_encode(['error' => 'Liittymän ID puuttuu']);
break;
}
$conn = dbLoadConnection($connId);
if (!$conn || $conn['company_id'] !== $companyId) {
http_response_code(404);
echo json_encode(['error' => 'Liittymää ei löytynyt']);
break;
}
dbUpdateConnection($connId, $input);
$updated = dbLoadConnection($connId);
echo json_encode($updated);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Liittymän päivitys epäonnistui: ' . $e->getMessage()]);
}
break;
// ==================== LAITETILAT ====================
case 'laitetilat':

26
db.php
View File

@@ -1895,3 +1895,29 @@ function dbLoadAllConnections(string $companyId): array {
ORDER BY cc.kaupunki, cc.asennusosoite
", ['companyId' => $companyId]);
}
function dbLoadConnection(int $connectionId): ?array {
return _dbFetchOne("
SELECT cc.*, c.yritys AS customer_name, c.company_id
FROM customer_connections cc
JOIN customers c ON c.id = cc.customer_id
WHERE cc.id = ?
", [$connectionId]);
}
function dbUpdateConnection(int $connectionId, array $data): void {
_dbExecute("UPDATE customer_connections SET
liittymanopeus = ?, vlan = ?, laite = ?, portti = ?, ip = ?,
asennusosoite = ?, postinumero = ?, kaupunki = ?
WHERE id = ?", [
$data['liittymanopeus'] ?? '',
$data['vlan'] ?? '',
$data['laite'] ?? '',
$data['portti'] ?? '',
$data['ip'] ?? '',
$data['asennusosoite'] ?? '',
$data['postinumero'] ?? '',
$data['kaupunki'] ?? '',
$connectionId
]);
}

View File

@@ -1006,6 +1006,73 @@
<p>Ei liittymiä.</p>
</div>
</div>
<!-- Liittymän detaljinäkymä -->
<div id="netadmin-detail-modal" class="modal" style="display:none;">
<div class="modal-content" style="max-width:550px;">
<div style="padding:1.5rem;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
<h3 style="margin:0;color:var(--primary-dark);" id="netadmin-detail-title">Liittymän tiedot</h3>
<button onclick="closeNetadminDetail()" style="background:none;border:none;font-size:1.3rem;cursor:pointer;"></button>
</div>
<div id="netadmin-detail-customer" style="color:#888;font-size:0.85rem;margin-bottom:1rem;"></div>
<form id="netadmin-detail-form">
<input type="hidden" id="na-edit-id">
<div class="form-grid" style="grid-template-columns:1fr 1fr;">
<div class="form-group">
<label>Osoite</label>
<input type="text" id="na-edit-osoite">
</div>
<div class="form-group">
<label>Postinumero</label>
<input type="text" id="na-edit-postinumero">
</div>
<div class="form-group">
<label>Kaupunki</label>
<input type="text" id="na-edit-kaupunki">
</div>
<div class="form-group">
<label>Nopeus</label>
<select id="na-edit-nopeus">
<option value="">-</option>
<option value="10/10">10/10</option>
<option value="50/10">50/10</option>
<option value="50/50">50/50</option>
<option value="100/10">100/10</option>
<option value="100/100">100/100</option>
<option value="200/200">200/200</option>
<option value="300/300">300/300</option>
<option value="500/500">500/500</option>
<option value="1000/1000">1000/1000</option>
<option value="2000/2000">2000/2000</option>
<option value="10000/10000">10000/10000</option>
</select>
</div>
<div class="form-group">
<label>VLAN</label>
<input type="text" id="na-edit-vlan">
</div>
<div class="form-group">
<label>Laite</label>
<input type="text" id="na-edit-laite">
</div>
<div class="form-group">
<label>Portti</label>
<input type="text" id="na-edit-portti">
</div>
<div class="form-group">
<label>IP</label>
<input type="text" id="na-edit-ip">
</div>
</div>
<div style="margin-top:1rem;display:flex;gap:0.5rem;justify-content:flex-end;">
<button type="button" class="btn-secondary" onclick="closeNetadminDetail()">Sulje</button>
<button type="submit" class="btn-primary">Tallenna</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>

View File

@@ -650,7 +650,12 @@ function createLiittymaRow(data = {}, index = 0) {
<div class="form-group"><label>Osoite</label><input type="text" class="l-asennusosoite" value="${esc(data.asennusosoite || '')}" placeholder="esim. Esimerkkikatu 1"></div>
<div class="form-group"><label>Postinumero</label><input type="text" class="l-postinumero" value="${esc(data.postinumero || '')}" placeholder="00100"></div>
<div class="form-group"><label>Kaupunki</label><input type="text" class="l-kaupunki" value="${esc(data.kaupunki || '')}" placeholder="Helsinki"></div>
<div class="form-group"><label>Nopeus</label><input type="text" class="l-liittymanopeus" value="${esc(data.liittymanopeus || '')}" placeholder="esim. 100/100"></div>
<div class="form-group"><label>Nopeus</label><select class="l-liittymanopeus">
<option value="">- Valitse -</option>
${['10/10','50/10','50/50','100/10','100/100','200/200','300/300','500/500','1000/1000','2000/2000','10000/10000'].map(s =>
`<option value="${s}" ${data.liittymanopeus === s ? 'selected' : ''}>${s}</option>`
).join('')}
</select></div>
<div class="form-group"><label>Hinta €/kk</label><input type="number" class="l-hinta" step="0.01" min="0" value="${data.hinta || ''}"></div>
<div class="form-group"><label>Sopimuskausi</label><select class="l-sopimuskausi">
<option value="">- Valitse -</option>
@@ -4476,7 +4481,7 @@ function renderNetadminTable() {
deviceInfo?.ping_status === 'down' ? 'netadmin-status-down' : '';
const deviceDisplay = c.laite ? `<span class="${pingClass}">${esc(c.laite)}</span>` : '-';
return `<tr onclick="editCustomer('${c.customer_id}')" style="cursor:pointer;" title="Avaa asiakas">
return `<tr onclick="openNetadminDetail(${c.id})" style="cursor:pointer;" title="Avaa liittymän tiedot">
<td><strong>${esc(c.customer_name || '-')}</strong></td>
<td>${esc(addr)}</td>
<td>${esc(c.kaupunki || '-')}</td>
@@ -4494,6 +4499,63 @@ document.getElementById('netadmin-filter-city')?.addEventListener('change', rend
document.getElementById('netadmin-filter-speed')?.addEventListener('change', renderNetadminTable);
document.getElementById('netadmin-filter-device')?.addEventListener('change', renderNetadminTable);
async function openNetadminDetail(connId) {
try {
const conn = await apiCall(`netadmin_connection&id=${connId}`);
document.getElementById('na-edit-id').value = conn.id;
document.getElementById('netadmin-detail-title').textContent = conn.asennusosoite || 'Liittymän tiedot';
document.getElementById('netadmin-detail-customer').textContent = '👤 ' + (conn.customer_name || '-');
document.getElementById('na-edit-osoite').value = conn.asennusosoite || '';
document.getElementById('na-edit-postinumero').value = conn.postinumero || '';
document.getElementById('na-edit-kaupunki').value = conn.kaupunki || '';
// Nopeus: aseta dropdown-arvo, tai lisää custom-optio jos ei löydy
const speedSel = document.getElementById('na-edit-nopeus');
const speed = conn.liittymanopeus || '';
if (speed && !Array.from(speedSel.options).some(o => o.value === speed)) {
const opt = document.createElement('option');
opt.value = speed;
opt.textContent = speed;
speedSel.insertBefore(opt, speedSel.lastElementChild);
}
speedSel.value = speed;
document.getElementById('na-edit-vlan').value = conn.vlan || '';
document.getElementById('na-edit-laite').value = conn.laite || '';
document.getElementById('na-edit-portti').value = conn.portti || '';
document.getElementById('na-edit-ip').value = conn.ip || '';
document.getElementById('netadmin-detail-modal').style.display = '';
} catch (e) { alert('Liittymän avaus epäonnistui: ' + e.message); }
}
function closeNetadminDetail() {
document.getElementById('netadmin-detail-modal').style.display = 'none';
}
// Sulje modal klikkaamalla taustaa
document.getElementById('netadmin-detail-modal')?.addEventListener('click', (e) => {
if (e.target.id === 'netadmin-detail-modal') closeNetadminDetail();
});
// Tallenna liittymän muutokset
document.getElementById('netadmin-detail-form')?.addEventListener('submit', async (e) => {
e.preventDefault();
const connId = document.getElementById('na-edit-id').value;
try {
await apiCall('netadmin_connection_update', 'POST', {
id: parseInt(connId),
asennusosoite: document.getElementById('na-edit-osoite').value,
postinumero: document.getElementById('na-edit-postinumero').value,
kaupunki: document.getElementById('na-edit-kaupunki').value,
liittymanopeus: document.getElementById('na-edit-nopeus').value,
vlan: document.getElementById('na-edit-vlan').value,
laite: document.getElementById('na-edit-laite').value,
portti: document.getElementById('na-edit-portti').value,
ip: document.getElementById('na-edit-ip').value
});
closeNetadminDetail();
loadNetadmin();
} catch (e) { alert('Tallennus epäonnistui: ' + e.message); }
});
// ==================== DOKUMENTIT ====================
let allDocuments = [];