Servis: tok dijagnostike/popravke, kartice Utvrđeni kvar i Urađeno, cena dijagnostike

- Cena dijagnostike u Podešavanja → Servis; na nalogu se predlaže iz podešavanja
- Odbijanje popravke: status Završeno + naplata samo dijagnostike (popravka_odbijena),
sklanjaju se Radovi/Delovi, Ukupno = dijagnostika
- Kartica Nalaz dijagnostike preimenovana u Utvrđeni kvar; editabilna samo u dijagnostici, kasnije readonly
- Nova kartica Urađeno (polje uradjeno) — upis dok je U popravci/Čeka delove, posle readonly
- Dugmad statusa: Završi u U popravci; promena statusa osvežava ceo sadržaj
- Predračun dostupan od Primljeno; radni nalog u U dijagnostici/Čeka delove
- Dropdown radova izostavlja već dodate usluge; kartica radova se osvežava pri izmeni
- Javni status: badge U dijagnostici, prikaz utvrđenog kvara, wordwrap naziva u tabeli
- Štampa: prelom između stavki, ponavljanje zaglavlja, završni blok bez preloma
This commit is contained in:
2026-06-23 22:21:12 +02:00
parent a8d5b0e9b4
commit f745f043c5
17 changed files with 494 additions and 106 deletions
@@ -34,6 +34,19 @@
</div>
</div>
<div style="max-width:280px;">
<label for="servis_cena_dijagnostike" class="polje-labela">
Cena dijagnostike (din)
</label>
<input type="number" id="servis_cena_dijagnostike" name="servis_cena_dijagnostike"
min="0" step="0.01" value="{{.ServisCenaDijagnostike}}"
style="width:100%;">
<div class="pomocni-tekst" style="margin-top:6px;">
Podrazumevana taksa za pregled/dijagnostiku. Predlaže se na nalogu pri dijagnostici;
naplaćuje se samo ako klijent ne prihvati popravku. 0 znači bez naplate.
</div>
</div>
<div style="max-width:280px;">
<label for="predracun_rok_dana" class="polje-labela">
Rok važenja predračuna (dana)
+141 -19
View File
@@ -47,8 +47,8 @@
{{template "status-badge-detalji" .Nalog.Status}}
{{if eq .Nalog.Status "Primljeno"}}
<!-- serviser preuzima uređaj u rad → status prelazi u „U dijagnostici";
data-refresh osvežava samo zaglavlje (badge i ovo dugme se ponovo renderuju) -->
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#nalog-zaglavlje" style="margin:0;">
promena statusa menja kartice i dugmad, pa osvežavamo ceo sadržaj (#sadrzaj) -->
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#sadrzaj" style="margin:0;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="status" value="U dijagnostici">
<button type="submit" class="btn-sekundarno" style="padding:3px 12px;font-size:12px;">
@@ -56,26 +56,72 @@
</button>
</form>
{{end}}
{{if eq .Nalog.Status "U dijagnostici"}}
<!-- ishod dijagnostike: klijent odobri popravku (→ U popravci) ili ne prihvata (→ Završeno, naplata pregleda) -->
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#sadrzaj" style="margin:0;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="status" value="U popravci">
<button type="submit" class="btn-sekundarno" style="padding:3px 12px;font-size:12px;">
Odobri popravku
</button>
</form>
<form method="POST" action="/servis/{{.Nalog.ID}}/odbij-popravku" style="margin:0;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit" class="btn-sekundarno" style="padding:3px 12px;font-size:12px;"
data-potvrda="Klijent ne prihvata popravku? Nalog ide u „Završeno” i naplaćuje se samo dijagnostika.">
Klijent ne prihvata
</button>
</form>
{{end}}
{{if eq .Nalog.Status "U popravci"}}
<!-- popravka gotova → nalog prelazi u „Završeno" (na preuzimanje) -->
<form method="POST" action="/servis/{{.Nalog.ID}}/status" data-refresh="#sadrzaj" style="margin:0;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<input type="hidden" name="status" value="Završeno">
<button type="submit" class="btn-sekundarno" style="padding:3px 12px;font-size:12px;">
Završi
</button>
</form>
{{end}}
</div>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;">
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
{{/* Revers je potvrda o prijemu — primaran u „Primljeno"; kasnije ostaje samo diskretan reprint */}}
{{if eq .Nalog.Status "Primljeno"}}
<a href="/servis/{{.Nalog.ID}}/revers" target="_blank" class="btn-sekundarno">
Revers
</a>
{{else}}
<a href="/servis/{{.Nalog.ID}}/revers" target="_blank" style="font-size:12px;color:var(--tekst-sporedni);text-decoration:underline;align-self:center;">
Revers (reprint)
</a>
{{end}}
{{/* Predračun je ponuda klijentu sa procenom radova/delova — dostupan od prijema
(dijagnostika je opcioni korak; klijent često traži procenu odmah) */}}
<a href="/servis/{{.Nalog.ID}}/predracun" target="_blank" class="btn-sekundarno">
Predračun
</a>
{{/* Radni nalog je interni papir serviseru — šta treba uraditi; „U dijagnostici" i „Čeka delove" */}}
{{if or (eq .Nalog.Status "U dijagnostici") (eq .Nalog.Status "Čeka delove")}}
<a href="/servis/{{.Nalog.ID}}/radni-nalog" target="_blank" class="btn-sekundarno">
Radni nalog
</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}}
{{/* Nalepnica je primarna pri prijemu (lepi se na uređaj); kasnije ostaje samo diskretan reprint */}}
{{if eq .Nalog.Status "Primljeno"}}
<a href="/servis/{{.Nalog.ID}}/nalepnica" target="_blank" class="btn-sekundarno">
Nalepnica
</a>
{{else}}
<a href="/servis/{{.Nalog.ID}}/nalepnica" target="_blank" style="font-size:12px;color:var(--tekst-sporedni);text-decoration:underline;align-self:center;">
Nalepnica (reprint)
</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>
@@ -244,6 +290,68 @@
</div>
</div>
<!-- nalaz dijagnostike: šta je serviser utvrdio (dijagnoza + predlog) — od „U dijagnostici" nadalje -->
{{if ne .Nalog.Status "Primljeno"}}
<div class="kartica detalji-kartica animiraj" id="nalaz-dijagnostike-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);">Utvrđeni kvar</span>
</div>
{{/* kvar i cena dijagnostike se unose samo dok je nalog „U dijagnostici"; kasnije su readonly */}}
{{if and (index .Dozvole "servis.izmeni") (eq .Nalog.Status "U dijagnostici")}}
<!-- snima se kad textarea izgubi fokus (bez dugmeta); data-refresh osvežava samo ovu karticu -->
<form method="POST" action="/servis/{{.Nalog.ID}}/nalaz-dijagnostike" data-refresh="#nalaz-dijagnostike-kartica">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<textarea name="nalaz_dijagnostike" rows="3"
placeholder="Šta je serviser utvrdio pregledom — dijagnoza kvara i predlog popravke..."
style="width:100%;resize:vertical;"
data-poc="{{.Nalog.NalazDijagnostike}}"
onblur="if(this.value!==this.dataset.poc){this.dataset.poc=this.value;(this.form.requestSubmit?this.form.requestSubmit():this.form.submit());}">{{.Nalog.NalazDijagnostike}}</textarea>
</form>
<!-- cena dijagnostike: naplaćuje se ako klijent ne prihvati popravku; snima se na promenu -->
<form method="POST" action="/servis/{{.Nalog.ID}}/cena-dijagnostike" data-refresh="#nalaz-dijagnostike-kartica, #nalog-ukupno" style="margin-top:12px;">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Cena dijagnostike (din)</label>
{{$cenaDij := .Nalog.CenaDijagnostikeStr}}{{if not $cenaDij}}{{$cenaDij = .CenaDijagnostikePredlog}}{{end}}
<input type="number" name="cena_dijagnostike" min="0" step="0.01" style="max-width:200px;"
placeholder="0"
value="{{$cenaDij}}"
data-poc="{{$cenaDij}}"
onchange="if(this.value!==this.dataset.poc){this.dataset.poc=this.value;(this.form.requestSubmit?this.form.requestSubmit():this.form.submit());}">
<div class="pomocni-tekst" style="margin-top:6px;">Predlog iz podešavanja; naplaćuje se samo ako klijent ne prihvati popravku.</div>
</form>
{{else}}
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.6;white-space:pre-wrap;">
{{if .Nalog.NalazDijagnostike}}{{.Nalog.NalazDijagnostike}}{{else}}<span style="color:var(--tekst-sporedni);font-style:italic;">Nalaz još nije unet.</span>{{end}}
</div>
{{end}}
</div>
{{end}}
<!-- urađeno: šta je serviser stvarno uradio — od „U popravci" nadalje -->
{{if or (eq .Nalog.Status "U popravci") (eq .Nalog.Status "Čeka delove") (eq .Nalog.Status "Završeno") (eq .Nalog.Status "Preuzeto")}}
<div class="kartica detalji-kartica animiraj" id="uradjeno-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);">Urađeno</span>
</div>
{{/* upisuje se dok traje popravka („U popravci" / „Čeka delove"); kasnije readonly */}}
{{if and (index .Dozvole "servis.izmeni") (or (eq .Nalog.Status "U popravci") (eq .Nalog.Status "Čeka delove"))}}
<!-- snima se kad textarea izgubi fokus (bez dugmeta); data-refresh osvežava samo ovu karticu -->
<form method="POST" action="/servis/{{.Nalog.ID}}/uradjeno" data-refresh="#uradjeno-kartica">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<textarea name="uradjeno" rows="3"
placeholder="Šta je serviser uradio na uređaju tokom popravke..."
style="width:100%;resize:vertical;"
data-poc="{{.Nalog.Uradjeno}}"
onblur="if(this.value!==this.dataset.poc){this.dataset.poc=this.value;(this.form.requestSubmit?this.form.requestSubmit():this.form.submit());}">{{.Nalog.Uradjeno}}</textarea>
</form>
{{else}}
<div style="font-size:13px;color:var(--tekst-sporedni);line-height:1.6;white-space:pre-wrap;">
{{if .Nalog.Uradjeno}}{{.Nalog.Uradjeno}}{{else}}<span style="color:var(--tekst-sporedni);font-style:italic;">Još nije uneto šta je urađeno.</span>{{end}}
</div>
{{end}}
</div>
{{end}}
<!-- 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;">
@@ -266,22 +374,24 @@
{{end}}
</div>
{{/* kad je popravka odbijena naplaćuje se samo dijagnostika — radovi i delovi se ne prikazuju */}}
{{if not .Nalog.PopravkaOdbijena}}
<!-- radovi (usluge) -->
<div class="kartica detalji-kartica animiraj">
<div class="kartica detalji-kartica animiraj" id="radovi-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);">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">
<form method="POST" action="/servis/{{.Nalog.ID}}/radovi" style="margin-bottom:16px;" data-refresh="#radovi-kartica, #nalog-ukupno">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<div class="detalji-forma-rad">
<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}}
{{range .Usluge}}{{if not (index $.KorisceneUsluge .ID)}}<option value="{{.ID}}" data-cena="{{.Cena}}">{{.Naziv}}</option>{{end}}{{end}}
</select>
</div>
<div>
@@ -322,7 +432,7 @@
<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">
<form method="POST" action="/servis/{{$.Nalog.ID}}/radovi/{{.ID}}/obrisi" style="display:inline;" data-refresh="#radovi-kartica, #nalog-ukupno">
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
<button type="submit"
data-potvrda="Ukloniti rad '{{.Naziv}}'?"
@@ -353,7 +463,7 @@
<!-- 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">
<form method="POST" action="/servis/{{.Nalog.ID}}/delovi" style="margin-bottom:16px;" data-refresh="#delovi-spisak, #nalog-zaglavlje, #nalog-ukupno">
<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>
@@ -414,7 +524,7 @@
</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">
<form method="POST" action="/servis/{{$.Nalog.ID}}/delovi/{{.ID}}/obrisi" style="display:inline;" data-refresh="#delovi-spisak, #nalog-zaglavlje, #nalog-ukupno">
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
<button type="submit"
data-potvrda="Ukloniti deo '{{.ArtikalNaziv}}'?"
@@ -436,13 +546,21 @@
{{end}}
</div>
</div>
{{end}}
<!-- ukupno: zbir usluga (radova) i ugrađenih delova -->
<div class="kartica detalji-kartica animiraj">
<div id="nalog-ukupno" 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;">
{{if .Nalog.PopravkaOdbijena}}
{{/* klijent odbio popravku — naplaćuje se samo dijagnostika */}}
<div style="display:flex;justify-content:space-between;align-items:center;">
<span style="font-size:14px;color:var(--tekst-sporedni);">Dijagnostika</span>
<span style="font-size:14px;color:var(--tekst-glavni);">{{dinari .Nalog.CenaDijagnostike}} din</span>
</div>
{{else}}
<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>
@@ -451,6 +569,7 @@
<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>
{{end}}
<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>
@@ -459,6 +578,8 @@
</div>
<!-- zona za brisanje -->
{{/* Brisanje je moguće samo dok je „Primljeno" (greška pri unosu); čim uđe u proceduru naplaćuje se dijagnostika */}}
{{if eq .Nalog.Status "Primljeno"}}
<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;">
@@ -475,21 +596,22 @@
</form>
</div>
</div>
{{end}}
</div>
<script>
// Radovi: pri izboru usluge iz <select>-a popuni predloženu cenu (data-cena).
(function () {
var sel = document.getElementById('rad-usluga');
// Delegacija na document — kartica radova se osvežava AJAX-om (data-refresh),
// pa listener vezan za sam <select> ne bi preživeo zamenu elementa.
document.addEventListener('change', function (e) {
if (!e.target || e.target.id !== 'rad-usluga') return;
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';
});
})();
if (!cena) return;
var opt = e.target.options[e.target.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
@@ -69,6 +69,10 @@
.strana { padding: 16px 20px; max-width: 100%; }
.dugme-stampa { display: none !important; }
@page { size: A4; margin: 12mm 14mm; }
/* red tabele se ne sme prelomiti preko granice stranice — prelom pada između stavki */
.tabela tr { break-inside: avoid; }
/* zaglavlje tabele se ponavlja na svakoj stranici kad tabela pređe na novu */
.tabela thead { display: table-header-group; }
}
.dugme-stampa { position: fixed; bottom: 24px; right: 24px; background: #111; color: #fff; border: none; padding: 12px 22px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
.dugme-stampa:hover { background: #333; }
+27 -28
View File
@@ -11,7 +11,7 @@
.strana { max-width: 780px; margin: 0 auto; padding: 32px 40px; }
.zaglavlje { display: flex; align-items: stretch; margin-bottom: 18px; gap: 12px; }
.zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.zg-okvir { flex: 1; padding: 12px 14px; border: 1.5px solid #bbb; border-radius: 12px; }
.firma-naziv { font-size: 18px; font-weight: 700; }
.firma-info { font-size: 11px; color: #555; margin-top: 3px; line-height: 1.5; }
.dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; }
@@ -55,10 +55,13 @@
@page { size: A4; margin: 12mm 14mm; }
/* red tabele se ne sme prelomiti preko granice stranice */
.tabela tr { break-inside: avoid; }
/* „Ukupno radovi/delovi" se ne sme odvojiti od stavki iznad — bez preloma pre njega */
.tabela .ukupno-red { break-before: avoid; }
.tabela .ukupno-red td { break-before: avoid; }
/* zaglavlje tabele se ponavlja na svakoj stranici kad tabela pređe na novu */
.tabela thead { display: table-header-group; }
/* rekapitulacija, klauzula i potpisi ostaju u jednom komadu */
.rekap, .klauzula-blok, .potpisi { break-inside: avoid; }
/* od „Ukupno (procena)" do potpisa sve ostaje na jednoj strani — bez preloma */
.zavrsni-blok { break-inside: avoid; }
}
.dugme-stampa { position: fixed; bottom: 24px; right: 24px; background: #111; color: #fff; border: none; padding: 12px 22px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
.dugme-stampa:hover { background: #333; }
@@ -83,7 +86,19 @@
{{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div>
</div>
<!-- SREDINA: klijent -->
<!-- SREDINA: datumi (levo) + QR (skroz desno) -->
<div class="zg-okvir" style="flex:1.3;">
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;">
<div>
<div class="dok-tip">Predračun (procena)</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.DatumIzdavanja.Format "02.01.2006."}}</div>
<div class="dok-datum">Važi do: {{.VaziDo.Format "02.01.2006."}}</div>
</div>
{{if .QRKod}}<img src="data:image/png;base64,{{.QRKod}}" width="92" height="92" alt="QR {{.Nalog.BrojNaloga}}" style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">{{end}}
</div>
</div>
<!-- DESNO: klijent -->
<div class="zg-okvir">
<div class="strana-tip">Klijent</div>
{{if .KlijentNaziv}}
@@ -100,19 +115,6 @@
<div class="strana-naziv prazno">— klijent nije naveden —</div>
{{end}}
</div>
<!-- DESNO: barkod na vrhu, ispod datumi (levo) + QR (skroz desno) -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:10px;">
<div>
<div class="dok-tip">Predračun (procena)</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum: {{.DatumIzdavanja.Format "02.01.2006."}}</div>
<div class="dok-datum">Važi do: {{.VaziDo.Format "02.01.2006."}}</div>
</div>
{{if .QRKod}}<img src="data:image/png;base64,{{.QRKod}}" width="64" height="64" alt="QR {{.Nalog.BrojNaloga}}" style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;flex-shrink:0;">{{end}}
</div>
</div>
</div>
<!-- uređaj i traženo -->
@@ -144,10 +146,6 @@
<td class="desno">{{dinari .Ukupno}} din</td>
</tr>
{{end}}
<tr class="ukupno-red">
<td colspan="3">Ukupno radovi</td>
<td class="desno">{{dinari .UkupnoRad}} din</td>
</tr>
</tbody>
</table>
</div>
@@ -175,10 +173,6 @@
<td class="desno">{{dinari .Ukupno}} din</td>
</tr>
{{end}}
<tr class="ukupno-red">
<td colspan="3">Ukupno delovi</td>
<td class="desno">{{dinari .UkupnoDelovi}} din</td>
</tr>
</tbody>
</table>
</div>
@@ -190,10 +184,13 @@
</div>
{{end}}
<!-- rekapitulacija -->
<!-- završni blok: od rekapitulacije do potpisa — pri štampi ostaje u jednom komadu -->
<div class="zavrsni-blok">
<!-- rekapitulacija: ponavlja sume po sekciji (korisno kad tabele pređu na prethodnu stranu) -->
<div class="rekap">
{{if .Radovi}}<div class="rekap-red"><span>Radovi</span><span>{{dinari .UkupnoRad}} din</span></div>{{end}}
{{if .ServisniDelovi}}<div class="rekap-red"><span>Delovi i materijal</span><span>{{dinari .UkupnoDelovi}} din</span></div>{{end}}
{{if .Radovi}}<div class="rekap-red" style="font-weight:600;"><span>Ukupno radovi</span><span>{{dinari .UkupnoRad}} din</span></div>{{end}}
{{if .ServisniDelovi}}<div class="rekap-red" style="font-weight:600;"><span>Ukupno delovi</span><span>{{dinari .UkupnoDelovi}} din</span></div>{{end}}
<div class="rekap-ukupno">
<div class="rekap-ukupno-labela">Ukupno (procena):</div>
<div class="rekap-ukupno-iznos">{{dinari .UkupnoSve}} din</div>
@@ -217,6 +214,8 @@
</div>
</div>
</div><!-- /zavrsni-blok -->
</div>
<button class="dugme-stampa" onclick="window.print()">Štampaj</button>
@@ -59,6 +59,10 @@
.strana { padding: 16px 20px; max-width: 100%; }
.dugme-stampa { display: none !important; }
@page { size: A4; margin: 12mm 14mm; }
/* red tabele se ne sme prelomiti preko granice stranice — prelom pada između stavki */
.tabela tr { break-inside: avoid; }
/* zaglavlje tabele se ponavlja na svakoj stranici kad tabela pređe na novu */
.tabela thead { display: table-header-group; }
}
.dugme-stampa { position: fixed; bottom: 24px; right: 24px; background: #111; color: #fff; border: none; padding: 12px 22px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
.dugme-stampa:hover { background: #333; }
+13 -13
View File
@@ -12,7 +12,7 @@
/* zaglavlje: tri okvira (firma · klijent · dokument) */
.zaglavlje { display: flex; align-items: stretch; margin-bottom: 20px; gap: 12px; }
.zg-okvir { flex: 1; padding: 12px 14px; border: 0.5px solid #ddd; border-radius: 6px; }
.zg-okvir { flex: 1; padding: 12px 14px; border: 1.5px solid #bbb; border-radius: 12px; }
.firma-naziv { font-size: 18px; font-weight: 700; }
.firma-info { font-size: 11px; color: #555; margin-top: 4px; line-height: 1.7; }
.dok-tip { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 1px; color: #555; margin-bottom: 4px; }
@@ -83,7 +83,17 @@
{{if .PIB}}PIB: {{.PIB}}{{end}}{{if .MaticniBroj}}{{if .PIB}} &middot; {{end}}MB: {{.MaticniBroj}}{{end}}
</div>
</div>
<!-- SREDINA: klijent -->
<!-- SREDINA: barkod na vrhu, ispod dokument i datumi (QR je u sekciji „Uređaj na servisu") -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div class="dok-tip">Revers — potvrda o prijemu</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum prijema: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.PredvidjenDatum}}
<div class="dok-datum">Predviđen rok: {{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</div>
{{end}}
</div>
<!-- DESNO: klijent -->
<div class="zg-okvir">
<div class="strana-tip">Klijent</div>
{{if .KlijentNaziv}}
@@ -100,16 +110,6 @@
<div class="strana-naziv prazno">— klijent nije naveden —</div>
{{end}}
</div>
<!-- DESNO: barkod na vrhu, ispod dokument i datumi (QR je u sekciji „Uređaj na servisu") -->
<div class="zg-okvir" style="flex:1.3;">
{{if .Barkod}}<img src="data:image/png;base64,{{.Barkod}}" alt="Barkod {{.Nalog.BrojNaloga}}" style="display:block;width:100%;max-height:46px;object-fit:contain;margin-bottom:10px;">{{end}}
<div class="dok-tip">Revers — potvrda o prijemu</div>
<div class="dok-broj">{{.Nalog.BrojNaloga}}</div>
<div class="dok-datum">Datum prijema: {{.Nalog.DatumPrijema.Format "02.01.2006."}}</div>
{{if .Nalog.PredvidjenDatum}}
<div class="dok-datum">Predviđen rok: {{.Nalog.PredvidjenDatum.Format "02.01.2006."}}</div>
{{end}}
</div>
</div>
<!-- uređaj (QR skroz desno — klijent ga skenira da prati status) -->
@@ -154,7 +154,7 @@
</div>
{{if .QRKod}}
<div style="text-align:center;flex-shrink:0;">
<img src="data:image/png;base64,{{.QRKod}}" width="96" height="96" alt="QR {{.Nalog.BrojNaloga}}"
<img src="data:image/png;base64,{{.QRKod}}" width="128" height="128" alt="QR {{.Nalog.BrojNaloga}}"
style="image-rendering:pixelated;border:1px solid #ddd;border-radius:4px;">
<div style="font-size:9px;color:#888;margin-top:3px;">Skenirajte za status</div>
</div>
@@ -55,8 +55,8 @@
/* red podataka */
.red { display: flex; justify-content: space-between; align-items: flex-start; padding: 10px 0; border-bottom: 0.5px solid #f0f0f0; gap: 12px; }
.red:last-child { border-bottom: none; }
.red-labela { font-size: 12px; color: #888; flex-shrink: 0; }
.red-vrednost { font-size: 13px; color: #111; font-weight: 500; text-align: right; }
.red-labela { font-size: 12px; color: #888; min-width: 0; overflow-wrap: anywhere; }
.red-vrednost { font-size: 13px; color: #111; font-weight: 500; text-align: right; flex-shrink: 0; white-space: nowrap; }
/* cena */
.cena-blok { background: #f9fafb; border-radius: 10px; padding: 14px 16px; margin-top: 4px; }
@@ -105,6 +105,8 @@
{{$s := .Nalog.Status}}
{{if eq $s "Primljeno"}}
<span class="status-bedz status-primljeno">Primljeno</span>
{{else if eq $s "U dijagnostici"}}
<span class="status-bedz status-dijagnostika">U dijagnostici</span>
{{else if eq $s "Čeka delove"}}
<span class="status-bedz status-ceka">Čeka delove</span>
{{else if eq $s "U popravci"}}
@@ -153,6 +155,13 @@
<span class="red-vrednost">{{garancijaTekst .Nalog.GarancijaDana}}</span>
</div>
{{if .Nalog.NalazDijagnostike}}
<div style="margin-top:12px;">
<div class="red-labela" style="margin-bottom:6px;">Utvrđeno na dijagnostici</div>
<div class="napomena-blok">{{.Nalog.NalazDijagnostike}}</div>
</div>
{{end}}
{{if .Nalog.NapomenaKlijentu}}
<div style="margin-top:12px;">
<div class="red-labela" style="margin-bottom:6px;">Napomena</div>