- Garancija se u detaljima prikazuje kao trajanje na srpskom (npr. „1 mesec i 15 dana", „2 meseca", „20 dana"); helper garancijaTekst + srpska deklinacija - Nova kolona garancija_dana (trajanje od završetka); garancija_do ostaje za fazu Završeno - Modal: textbox „Trajanje garancije (dana)" umesto kalendara; Podrazumevano i Bez garancije - Nova ruta/handler AzurirajGarancijaDana; forma izmene čuva trajanje (ne briše) - Podešavanja → Servis: rok garancije prebačen iz meseci u dane (servis_garancija_dana, default 60) - „Garancija do" uklonjena iz forme Izmeni nalog (kod arhiviran u docs/); SacuvajIzmenaNaloga čuva garanciju iz baze da je auto-snimanje ne pregazi - Prikazni tekst „Tehničar" → „Serviser" svuda (identifikatori Tehnicar/tehnicar_id netaknuti)
583 lines
34 KiB
HTML
583 lines
34 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "naslov"}}Detalji naloga — NTech{{end}}
|
|
|
|
{{define "dodatni-css"}}
|
|
<style>
|
|
.detalji-kartica:nth-child(1) { animation-delay: 0.04s; }
|
|
.detalji-kartica:nth-child(2) { animation-delay: 0.12s; }
|
|
.detalji-kartica:nth-child(3) { animation-delay: 0.20s; }
|
|
.detalji-kartica:nth-child(4) { animation-delay: 0.28s; }
|
|
.detalji-kartica:nth-child(5) { animation-delay: 0.36s; }
|
|
</style>
|
|
{{end}}
|
|
|
|
{{define "status-badge-detalji"}}
|
|
{{if eq . "Primljeno"}}<span class="status-badge status-primljeno">{{.}}</span>
|
|
{{else if eq . "Čeka delove"}}<span class="status-badge status-ceka">{{.}}</span>
|
|
{{else if eq . "U popravci"}}<span class="status-badge status-popravka">{{.}}</span>
|
|
{{else if eq . "Završeno"}}<span class="status-badge status-zavrseno">{{.}}</span>
|
|
{{else if eq . "Preuzeto"}}<span class="status-badge status-preuzeto">{{.}}</span>
|
|
{{else}}<span class="status-badge status-primljeno">{{.}}</span>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{define "sadrzaj"}}
|
|
<div class="kolona" style="gap:16px;">
|
|
|
|
{{if .Sacuvano}}
|
|
<div class="poruka-uspeh poruka-animacija">Nalog je uspešno sačuvan.</div>
|
|
{{end}}
|
|
|
|
<!-- nazad dugme -->
|
|
<a href="/servis" class="nazad-link" hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
Nazad na servis
|
|
</a>
|
|
|
|
<!-- zaglavlje naloga -->
|
|
<div class="kartica detalji-kartica animiraj" id="nalog-zaglavlje">
|
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:12px;margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);">
|
|
<div class="kolona" style="gap:8px;">
|
|
<span style="font-size:20px;font-weight:600;color:var(--tekst-glavni);font-family:monospace;">
|
|
{{.Nalog.BrojNaloga}}
|
|
</span>
|
|
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
|
{{template "status-badge-detalji" .Nalog.Status}}
|
|
</div>
|
|
</div>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap;">
|
|
{{if not (or (eq .Nalog.Status "Završeno") (eq .Nalog.Status "Preuzeto"))}}
|
|
<a href="/servis/{{.Nalog.ID}}/stampa" target="_blank" class="btn-sekundarno">
|
|
Radni nalog
|
|
</a>
|
|
<a href="/servis/{{.Nalog.ID}}/predracun" target="_blank" class="btn-sekundarno">
|
|
Predračun
|
|
</a>
|
|
{{end}}
|
|
{{if or (eq .Nalog.Status "Završeno") (eq .Nalog.Status "Preuzeto")}}
|
|
<a href="/servis/{{.Nalog.ID}}/otpremnica" target="_blank" class="btn-sekundarno">
|
|
Otpremnica
|
|
</a>
|
|
{{end}}
|
|
<a href="/servis/izmeni/{{.Nalog.ID}}" class="btn-primarno" hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML">
|
|
Izmeni nalog
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:16px;">
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Datum prijema</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);">{{.Nalog.DatumPrijema.Format "02.01.2006. u 15:04"}}</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Predviđen datum popravke</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);">
|
|
{{if .Nalog.PredvidjenDatum}}{{.Nalog.PredvidjenDatum.Format "02.01.2006."}}{{else}}—{{end}}
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<button type="button" class="izmeni-polje" onclick="ntechOtvoriModal(this)">Promeni</button>
|
|
<dialog class="premesti-modal" onclick="if(event.target===this)this.close()">
|
|
<form method="dialog" class="premesti-zaglavlje">
|
|
<h3>Predviđen datum popravke</h3>
|
|
<button type="submit" class="premesti-zatvori" aria-label="Zatvori">×</button>
|
|
</form>
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/predvidjen-datum" data-refresh="#nalog-zaglavlje" style="display:flex;flex-direction:column;gap:12px;padding:16px;">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div>
|
|
<label class="polje-labela">Datum</label>
|
|
<input type="date" name="predvidjen_datum"
|
|
value="{{if .Nalog.PredvidjenDatum}}{{.Nalog.PredvidjenDatum.Format "2006-01-02"}}{{end}}"
|
|
style="width:100%;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;">
|
|
<div class="pomocni-tekst" style="margin-top:6px;">Podrazumevano = automatski (datum prijema + rok iz podešavanja).</div>
|
|
</div>
|
|
<button type="button" class="btn-sekundarno" style="align-self:flex-start;"
|
|
onclick="var f=this.closest('form'); f.querySelector('[name=predvidjen_datum]').value=''; f.requestSubmit();">Podrazumevano</button>
|
|
</form>
|
|
</dialog>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Garancija</div>
|
|
<div style="font-size:14px;{{if not .BezGarancije}}color:#16a34a;font-weight:500;{{else}}color:var(--tekst-sporedni);{{end}}">
|
|
{{garancijaTekst .Nalog.GarancijaDana}}
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<button type="button" class="izmeni-polje" onclick="ntechOtvoriModal(this)">Promeni</button>
|
|
<dialog class="premesti-modal" onclick="if(event.target===this)this.close()">
|
|
<form method="dialog" class="premesti-zaglavlje">
|
|
<h3>Garancija</h3>
|
|
<button type="submit" class="premesti-zatvori" aria-label="Zatvori">×</button>
|
|
</form>
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/garancija-dana" data-refresh="#nalog-zaglavlje" style="display:flex;flex-direction:column;gap:12px;padding:16px;">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div>
|
|
<label class="polje-labela">Trajanje garancije (dana)</label>
|
|
<div style="display:flex;align-items:center;gap:10px;">
|
|
<input type="number" name="garancija_dana" min="0" step="1"
|
|
value="{{if .BezGarancije}}{{.GarancijaDefault}}{{else}}{{.Nalog.GarancijaDana}}{{end}}"
|
|
{{if .BezGarancije}}disabled{{end}}
|
|
style="flex:1;min-width:0;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;{{if .BezGarancije}}opacity:.5;{{end}}">
|
|
<label class="tip-opcija{{if .BezGarancije}} tip-opcija-akt{{end}}" style="white-space:nowrap;">
|
|
<input type="checkbox" name="bez_garancije" value="1"{{if .BezGarancije}} checked{{end}} style="margin:0;width:auto;"
|
|
onchange="var d=this.closest('div').querySelector('[name=garancija_dana]'); d.disabled=this.checked; d.style.opacity=this.checked?'.5':''; this.closest('label').classList.toggle('tip-opcija-akt',this.checked);">
|
|
Bez garancije
|
|
</label>
|
|
</div>
|
|
<div class="pomocni-tekst" style="margin-top:6px;">Računa se od datuma završetka radova.</div>
|
|
</div>
|
|
<button type="button" class="btn-sekundarno" style="align-self:flex-start;"
|
|
onclick="var f=this.closest('form'); var d=f.querySelector('[name=garancija_dana]'); d.disabled=false; d.style.opacity=''; d.value='{{.GarancijaDefault}}'; var c=f.querySelector('[name=bez_garancije]'); c.checked=false; c.closest('label').classList.remove('tip-opcija-akt'); f.requestSubmit();">Podrazumevano</button>
|
|
</form>
|
|
</dialog>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Klijent</div>
|
|
<div style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
|
{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}—{{end}}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Serviser</div>
|
|
<div style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
|
{{if .TehnicarNaziv}}{{.TehnicarNaziv}}{{else}}<span style="color:var(--tekst-sporedni);font-weight:normal;">— nedodeljen —</span>{{end}}
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<button type="button" class="izmeni-polje" onclick="ntechOtvoriModal(this)">Promeni</button>
|
|
<dialog class="premesti-modal" onclick="if(event.target===this)this.close()">
|
|
<form method="dialog" class="premesti-zaglavlje">
|
|
<h3>Serviser</h3>
|
|
<button type="submit" class="premesti-zatvori" aria-label="Zatvori">×</button>
|
|
</form>
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/tehnicar" data-refresh="#nalog-zaglavlje" style="display:flex;flex-direction:column;gap:12px;padding:16px;">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div>
|
|
<label class="polje-labela">Serviser</label>
|
|
<select name="tehnicar_id"
|
|
style="width:100%;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;">
|
|
<option value="">— nedodeljen —</option>
|
|
{{range .Tehnicari}}
|
|
<option value="{{.ID}}"{{if eq .ID $.Nalog.TehnicarIDVrednost}} selected{{end}}>{{.KorisnickoIme}}</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</form>
|
|
</dialog>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- podaci o uređaju -->
|
|
<div class="kartica detalji-kartica animiraj">
|
|
<div style="margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);">
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Uređaj</span>
|
|
</div>
|
|
<div class="kolona" style="gap:14px;">
|
|
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(160px, 1fr));gap:16px;">
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Naziv uređaja</div>
|
|
<div style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">{{.Nalog.Uredjaj}}</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Serijski broj</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);">
|
|
{{if .Nalog.SerijskiBroj}}{{.Nalog.SerijskiBroj}}{{else}}—{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:6px;">Opis kvara</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);line-height:1.6;white-space:pre-wrap;">{{.Nalog.OpisKvara}}</div>
|
|
</div>
|
|
{{if .Nalog.TrazeneNadogradnje}}
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:6px;">Tražene nadogradnje</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);line-height:1.6;white-space:pre-wrap;">{{.Nalog.TrazeneNadogradnje}}</div>
|
|
</div>
|
|
{{end}}
|
|
{{if or .Nalog.Ostecenja .Nalog.PinUredjaja .Nalog.Pribor}}
|
|
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(160px, 1fr));gap:16px;">
|
|
{{if .Nalog.Ostecenja}}
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Oštećenja pri prijemu</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);">{{.Nalog.Ostecenja}}</div>
|
|
</div>
|
|
{{end}}
|
|
{{if .Nalog.PinUredjaja}}
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">PIN / lozinka uređaja</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);font-family:monospace;">{{.Nalog.PinUredjaja}}</div>
|
|
</div>
|
|
{{end}}
|
|
{{if .Nalog.Pribor}}
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Pribor i oprema</div>
|
|
<div style="font-size:14px;color:var(--tekst-glavni);">{{.Nalog.Pribor}}</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{if .Nalog.Napomena}}
|
|
<div>
|
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:6px;">Napomena</div>
|
|
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.6;white-space:pre-wrap;">{{.Nalog.Napomena}}</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- napomena klijentu -->
|
|
<div class="kartica detalji-kartica animiraj" id="napomena-klijentu-kartica">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);flex-wrap:wrap;gap:10px;">
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Napomena klijentu</span>
|
|
</div>
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<!-- forma se sama snima kad textarea izgubi fokus (bez dugmeta); data-refresh osvežava samo ovu karticu -->
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/napomena-klijentu" data-refresh="#napomena-klijentu-kartica">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<textarea name="napomena_klijentu" rows="3"
|
|
placeholder="Poruka koju ostavljate klijentu uz nalog..."
|
|
style="width:100%;resize:vertical;"
|
|
data-poc="{{.Nalog.NapomenaKlijentu}}"
|
|
onblur="if(this.value!==this.dataset.poc){this.dataset.poc=this.value;(this.form.requestSubmit?this.form.requestSubmit():this.form.submit());}">{{.Nalog.NapomenaKlijentu}}</textarea>
|
|
</form>
|
|
{{else}}
|
|
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.6;white-space:pre-wrap;">
|
|
{{if .Nalog.NapomenaKlijentu}}{{.Nalog.NapomenaKlijentu}}{{else}}<span style="color:var(--tekst-sporedni);font-style:italic;">Nema napomene.</span>{{end}}
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<!-- radovi (usluge) -->
|
|
<div class="kartica detalji-kartica animiraj">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);flex-wrap:wrap;gap:10px;">
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Radovi (usluge)</span>
|
|
</div>
|
|
|
|
<!-- forma za dodavanje rada iz cenovnika usluga -->
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/radovi" style="margin-bottom:16px;" data-refresh="#radovi-spisak">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div style="display:grid;grid-template-columns:1fr 80px 120px auto;gap:10px;align-items:flex-end;">
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Usluga</label>
|
|
<select name="usluga_id" id="rad-usluga" style="width:100%;" required>
|
|
<option value="">— odaberi uslugu —</option>
|
|
{{range .Usluge}}<option value="{{.ID}}" data-cena="{{.Cena}}">{{.Naziv}}</option>{{end}}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Kol.</label>
|
|
<input type="number" name="kolicina" id="rad-kolicina" min="0.01" step="0.01" value="1" style="width:100%;" required>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Cena/kom (din)</label>
|
|
<input type="number" name="cena_komada" id="rad-cena" min="0" step="0.01" value="0" style="width:100%;" required>
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="btn-primarno" style="font-size:13px;padding:8px 14px;white-space:nowrap;">+ Dodaj</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
{{end}}
|
|
|
|
<!-- lista radova -->
|
|
<div id="radovi-spisak">
|
|
{{if .ServisniRadovi}}
|
|
<table class="tabela">
|
|
<thead>
|
|
<tr style="border-bottom:0.5px solid var(--ivica);">
|
|
<th style="padding:8px 10px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Usluga</th>
|
|
<th style="padding:8px 10px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:80px;">Kol.</th>
|
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Cena/kom</th>
|
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Ukupno</th>
|
|
<th style="width:50px;"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .ServisniRadovi}}
|
|
<tr style="border-bottom:0.5px solid var(--ivica);">
|
|
<td style="padding:9px 10px;font-size:14px;color:var(--tekst-glavni);">{{.Naziv}}</td>
|
|
<td style="padding:9px 10px;text-align:center;font-size:14px;color:var(--tekst-glavni);">{{.Kolicina}}</td>
|
|
<td style="padding:9px 10px;text-align:right;font-size:14px;color:var(--tekst-glavni);">{{dinari .CenaKomada}} din</td>
|
|
<td style="padding:9px 10px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">{{dinari .Ukupno}} din</td>
|
|
<td style="padding:9px 10px;text-align:center;">
|
|
{{if index $.Dozvole "servis.izmeni"}}
|
|
<form method="POST" action="/servis/{{$.Nalog.ID}}/radovi/{{.ID}}/obrisi" style="display:inline;" data-refresh="#radovi-spisak">
|
|
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
|
|
<button type="submit"
|
|
data-potvrda="Ukloniti rad '{{.Naziv}}'?"
|
|
style="background:none;border:none;cursor:pointer;color:#dc2626;font-size:16px;padding:2px 6px;border-radius:4px;">
|
|
×
|
|
</button>
|
|
</form>
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{else}}
|
|
<div style="font-size:13px;color:var(--tekst-sporedni);text-align:center;padding:16px 0;">
|
|
Nema unetih radova. Dodaj uslugu iz cenovnika.
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ugrađeni delovi -->
|
|
<div class="kartica detalji-kartica animiraj">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);flex-wrap:wrap;gap:10px;">
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Ugrađeni delovi</span>
|
|
</div>
|
|
|
|
<!-- forma za dodavanje dela -->
|
|
{{if index .Dozvole "servis.izmeni"}}
|
|
<form method="POST" action="/servis/{{.Nalog.ID}}/delovi" style="margin-bottom:16px;" data-refresh="#delovi-spisak, #nalog-zaglavlje">
|
|
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
|
|
<div style="margin-bottom:10px;">
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Kategorija</label>
|
|
<select id="deo-kategorija" style="width:100%;"></select>
|
|
</div>
|
|
<div style="display:grid;grid-template-columns:1fr 70px 80px 120px auto;gap:10px;align-items:flex-end;">
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Artikal</label>
|
|
<select name="artikal_id" id="deo-artikal" style="width:100%;" required>
|
|
<option value="">— odaberi artikal —</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">U magacinu</label>
|
|
<div id="deo-umagacinu" style="width:100%;box-sizing:border-box;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;font-weight:500;text-align:center;background:var(--pozadina);color:var(--tekst-glavni);">—</div>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Kol.</label>
|
|
<input type="number" name="kolicina" id="deo-kol" min="1" value="1" style="width:100%;box-sizing:border-box;" required>
|
|
</div>
|
|
<div>
|
|
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Cena/kom (din)</label>
|
|
<input type="number" name="cena_komada" id="deo-cena" min="0" step="0.01" value="0" style="width:100%;" required>
|
|
</div>
|
|
<div>
|
|
<button type="submit" class="btn-primarno" style="font-size:13px;padding:8px 14px;white-space:nowrap;">+ Dodaj</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
{{end}}
|
|
|
|
<!-- lista delova -->
|
|
<div id="delovi-spisak">
|
|
{{if .ServisniDelovi}}
|
|
<table class="tabela">
|
|
<thead>
|
|
<tr style="border-bottom:0.5px solid var(--ivica);">
|
|
<th style="padding:8px 10px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Artikal</th>
|
|
<th style="padding:8px 10px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:80px;">Kol.</th>
|
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Cena/kom</th>
|
|
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:130px;">Ukupno</th>
|
|
<th style="width:50px;"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .ServisniDelovi}}
|
|
<tr data-artikal-id="{{.ArtikalID}}" data-kolicina="{{.Kolicina}}" data-potrazivano="{{.Potrazivano}}" style="border-bottom:0.5px solid var(--ivica);{{if .Potrazivano}}background:rgba(220,38,38,0.06);{{end}}">
|
|
<td style="padding:9px 10px;font-size:14px;color:var(--tekst-glavni);">{{.ArtikalNaziv}}</td>
|
|
<td style="padding:9px 10px;text-align:center;font-size:14px;{{if .Potrazivano}}color:#dc2626;font-weight:600;{{else}}color:var(--tekst-glavni);{{end}}">
|
|
{{.Kolicina}}{{if .Potrazivano}}<span style="font-weight:400;"> + {{.Potrazivano}} na čekanju</span>{{end}}
|
|
</td>
|
|
<td style="padding:9px 10px;text-align:right;font-size:14px;color:var(--tekst-glavni);">
|
|
{{if .Kolicina}}{{dinari .CenaKomada}} din{{else}}—{{end}}
|
|
</td>
|
|
<td style="padding:9px 10px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
|
|
{{if .Kolicina}}{{dinari .Ukupno}} din{{else}}—{{end}}
|
|
</td>
|
|
<td style="padding:9px 10px;text-align:center;">
|
|
{{if and .ID (index $.Dozvole "servis.izmeni")}}
|
|
<form method="POST" action="/servis/{{$.Nalog.ID}}/delovi/{{.ID}}/obrisi" style="display:inline;" data-refresh="#delovi-spisak, #nalog-zaglavlje">
|
|
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
|
|
<button type="submit"
|
|
data-potvrda="Ukloniti deo '{{.ArtikalNaziv}}'?"
|
|
style="background:none;border:none;cursor:pointer;color:#dc2626;font-size:16px;padding:2px 6px;border-radius:4px;">
|
|
×
|
|
</button>
|
|
</form>
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{else}}
|
|
<div style="font-size:13px;color:var(--tekst-sporedni);text-align:center;padding:16px 0;">
|
|
Nema ugrađenih delova za ovaj nalog.
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ukupno: zbir usluga (radova) i ugrađenih delova -->
|
|
<div class="kartica detalji-kartica animiraj">
|
|
<div style="margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);">
|
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Ukupno</span>
|
|
</div>
|
|
<div class="kolona" style="gap:10px;">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
|
<span style="font-size:14px;color:var(--tekst-sporedni);">Usluge (rad)</span>
|
|
<span style="font-size:14px;color:var(--tekst-glavni);">{{dinari .UkupnoRadovi}} din</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
|
<span style="font-size:14px;color:var(--tekst-sporedni);">Ugrađeni delovi</span>
|
|
<span style="font-size:14px;color:var(--tekst-glavni);">{{dinari .UkupnoDelovi}} din</span>
|
|
</div>
|
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:6px;padding-top:12px;border-top:0.5px solid var(--ivica);">
|
|
<span style="font-size:16px;font-weight:600;color:var(--tekst-glavni);">Ukupno</span>
|
|
<span style="font-size:18px;font-weight:600;color:var(--tekst-glavni);">{{dinari .UkupnoSve}} din</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- zona za brisanje -->
|
|
<div class="kartica detalji-kartica animiraj" style="border-color:#dc262633;">
|
|
<div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;">
|
|
<div style="flex:1;min-width:200px;">
|
|
<div style="font-size:14px;font-weight:500;color:#dc2626;margin-bottom:4px;">Brisanje naloga</div>
|
|
<div class="pomocni-tekst">
|
|
Brisanje je trajno. Nalog i svi vezani podaci biće trajno uklonjeni.
|
|
</div>
|
|
</div>
|
|
<form method="POST" action="/servis/obrisi/{{.Nalog.ID}}">
|
|
<button type="submit" class="btn-opasno"
|
|
data-potvrda="Da li ste sigurni da želite da obrišete nalog {{.Nalog.BrojNaloga}}?">
|
|
Obriši nalog
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
// Radovi: pri izboru usluge iz <select>-a popuni predloženu cenu (data-cena).
|
|
(function () {
|
|
var sel = document.getElementById('rad-usluga');
|
|
var cena = document.getElementById('rad-cena');
|
|
if (!sel || !cena) return;
|
|
sel.addEventListener('change', function () {
|
|
var opt = sel.options[sel.selectedIndex];
|
|
var c = parseFloat(opt.getAttribute('data-cena'));
|
|
cena.value = (!isNaN(c) && c > 0) ? c.toFixed(2) : '0';
|
|
});
|
|
})();
|
|
|
|
// Delovi: kategorija filtrira <select> artikala; izborom artikla popunjavamo
|
|
// cenu i prikaz „U magacinu". Običan <select> ima native pretragu kucanjem
|
|
// i otvara se jednim klikom (za razliku od datalist-a).
|
|
(function () {
|
|
var ARTIKLI = {{json .Artikli}} || [];
|
|
var kategSel = document.getElementById('deo-kategorija');
|
|
var artikalSel = document.getElementById('deo-artikal');
|
|
var cena = document.getElementById('deo-cena');
|
|
var umagacinu = document.getElementById('deo-umagacinu');
|
|
var kol = document.getElementById('deo-kol');
|
|
var stanjeIzabrano = 0;
|
|
if (!artikalSel) return;
|
|
|
|
// boji „U magacinu" i polje količine crveno kada ukupno (postojeće u tabeli
|
|
// + nova količina) prelazi stanje; čita direktno iz DOM-a tabele jer se ona
|
|
// osvežava AJAX-om, pa JSON varijabla zastareva
|
|
function osveziPrekoracenje() {
|
|
var novaKol = parseInt(kol && kol.value, 10) || 0;
|
|
var postojeciKol = 0;
|
|
if (artikalSel.value) {
|
|
var aid = artikalSel.value;
|
|
var redovi = document.querySelectorAll('#delovi-spisak tr[data-artikal-id="' + aid + '"]');
|
|
redovi.forEach(function (tr) {
|
|
postojeciKol += (parseInt(tr.getAttribute('data-kolicina'), 10) || 0) +
|
|
(parseInt(tr.getAttribute('data-potrazivano'), 10) || 0);
|
|
});
|
|
}
|
|
var preko = (postojeciKol + novaKol) > stanjeIzabrano && artikalSel.value;
|
|
if (umagacinu) umagacinu.classList.toggle('prekoraceno', preko);
|
|
if (kol) kol.classList.toggle('prekoraceno', preko);
|
|
}
|
|
|
|
if (kategSel) {
|
|
var kategs = [];
|
|
ARTIKLI.forEach(function (a) {
|
|
var k = a.KategorijaNaziv || '';
|
|
if (k && kategs.indexOf(k) < 0) kategs.push(k);
|
|
});
|
|
kategs.sort();
|
|
kategSel.innerHTML = '<option value="">Sve kategorije</option>' +
|
|
kategs.map(function (k) { return '<option value="' + k + '">' + k + '</option>'; }).join('');
|
|
}
|
|
|
|
function popuniArtikle() {
|
|
var izabrana = kategSel ? kategSel.value : '';
|
|
artikalSel.innerHTML = '<option value="">— odaberi artikal —</option>' +
|
|
ARTIKLI.filter(function (a) { return !izabrana || (a.KategorijaNaziv || '') === izabrana; })
|
|
.map(function (a) {
|
|
return '<option value="' + a.ID + '" data-cena="' + a.ProdajnaCena +
|
|
'" data-stanje="' + a.Kolicina + '">' + a.Naziv + '</option>';
|
|
}).join('');
|
|
if (umagacinu) umagacinu.textContent = '—';
|
|
}
|
|
popuniArtikle();
|
|
if (kategSel) kategSel.addEventListener('change', popuniArtikle);
|
|
|
|
artikalSel.addEventListener('change', function () {
|
|
var opt = artikalSel.options[artikalSel.selectedIndex];
|
|
var c = parseFloat(opt.getAttribute('data-cena'));
|
|
if (cena) cena.value = (!isNaN(c) && c > 0) ? c.toFixed(2) : '0';
|
|
var st = parseInt(opt.getAttribute('data-stanje'), 10);
|
|
stanjeIzabrano = isNaN(st) ? 0 : st;
|
|
if (umagacinu) umagacinu.textContent = artikalSel.value ? stanjeIzabrano : '—';
|
|
osveziPrekoracenje();
|
|
});
|
|
if (kol) kol.addEventListener('input', osveziPrekoracenje);
|
|
|
|
// resetuj prikaz „U magacinu" nakon dodavanja dela — base.html poziva
|
|
// f.reset() posle AJAX osvežavanja tabele, ali .reset() ne dira <div>
|
|
var formaDelovi = document.querySelector('form[action$="/delovi"]');
|
|
if (formaDelovi) {
|
|
formaDelovi.addEventListener('reset', function () {
|
|
if (umagacinu) {
|
|
umagacinu.textContent = '—';
|
|
umagacinu.classList.remove('prekoraceno');
|
|
}
|
|
stanjeIzabrano = 0;
|
|
if (kol) kol.classList.remove('prekoraceno');
|
|
});
|
|
}
|
|
})();
|
|
|
|
// Popup polja (predviđen datum, garancija, serviser): nema dugmeta „Sačuvaj" —
|
|
// snima se na zatvaranje modala, i to samo ako je vrednost promenjena.
|
|
// Početno stanje forme pamtimo pri otvaranju; na „close" upoređujemo i, ako se
|
|
// razlikuje, šaljemo formu (ntech AJAX presretač osveži #nalog-zaglavlje).
|
|
window.ntechOtvoriModal = function (btn) {
|
|
var d = btn.nextElementSibling;
|
|
if (!d || d.tagName !== 'DIALOG') return;
|
|
var forma = d.querySelector('form[method="POST"], form[method="post"]');
|
|
if (forma) forma.dataset.poc = new URLSearchParams(new FormData(forma)).toString();
|
|
d.showModal();
|
|
};
|
|
if (!window._ntechModalSaveDodato) {
|
|
window._ntechModalSaveDodato = true;
|
|
// 'close' ne baburi — slušamo u capture fazi na dokumentu (hvata i modale ubačene swap-om)
|
|
document.addEventListener('close', function (e) {
|
|
var d = e.target;
|
|
if (!d || d.tagName !== 'DIALOG') return;
|
|
var forma = d.querySelector('form[method="POST"], form[method="post"]');
|
|
if (!forma || forma.dataset.poc === undefined) return;
|
|
var sad = new URLSearchParams(new FormData(forma)).toString();
|
|
if (sad !== forma.dataset.poc) {
|
|
if (forma.requestSubmit) forma.requestSubmit(); else forma.submit();
|
|
}
|
|
}, true);
|
|
}
|
|
</script>
|
|
{{end}}
|