Uvoz/vraćanje baze: čuvanje lokalnih podešavanja i naloga, novi korisnik ime/prezime, custom potvrda umesto confirm(), ispravka prefiksa šifre artikla po kategoriji

This commit is contained in:
2026-07-05 11:16:22 +02:00
parent ffbcbd6fd7
commit 1ff572dd77
15 changed files with 460 additions and 74 deletions
+15 -5
View File
@@ -14,7 +14,7 @@
<div class="kolona" style="gap:16px;">
<!-- lista korisnika -->
<div class="kartica animiraj" style="padding:0;overflow:hidden;">
<div id="lista-korisnika-kartica" class="kartica animiraj" style="padding:0;overflow:hidden;">
<div style="padding:16px 20px;border-bottom:0.5px solid var(--ivica);">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Korisnici sistema</span>
</div>
@@ -81,10 +81,10 @@
</button>
</form>
{{if eq .Uloga "radnik"}}
<form method="POST" action="/admin/korisnici/{{.ID}}/obrisi" style="display:inline;"
onsubmit="return confirm('Obrisati korisnika {{.KorisnickoIme}}? Ova radnja je trajna.')">
<form method="POST" action="/admin/korisnici/{{.ID}}/obrisi" style="display:inline;">
<button type="submit"
class="btn-obrisi-ghost">
class="btn-obrisi-ghost"
data-potvrda="Obrisati korisnika {{.KorisnickoIme}}? Ova radnja je trajna.">
Obriši
</button>
</form>
@@ -103,8 +103,18 @@
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
Novi korisnik
</div>
<form method="POST" action="/admin/korisnici/novi">
<form method="POST" action="/admin/korisnici/novi" data-refresh="#lista-korisnika-kartica">
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));gap:14px;margin-bottom:16px;">
<div>
<label class="polje-labela">Ime</label>
<input type="text" name="ime" required autocomplete="off"
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>
<div>
<label class="polje-labela">Prezime</label>
<input type="text" name="prezime" required autocomplete="off"
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>
<div>
<label class="polje-labela">Korisničko ime</label>
<input type="text" name="korisnicko_ime" required minlength="3" autocomplete="off"
+4 -4
View File
@@ -88,8 +88,8 @@
<div style="font-size: 14px; color: #16a34a; margin-bottom: 4px; font-weight: 500">✓ Dvostepena verifikacija je uključena</div>
<div style="font-size: 13px; color: var(--tekst-sporedni)">Prijava zahteva TOTP kod pored lozinke.</div>
</div>
<form method="POST" action="/admin/profil/totp/deaktiviraj" onsubmit="return confirm('Da li ste sigurni? Ovo će isključiti dvostepenu verifikaciju.');">
<button type="submit" class="btn-opasno">Deaktiviraj 2FA</button>
<form method="POST" action="/admin/profil/totp/deaktiviraj">
<button type="submit" class="btn-opasno" data-potvrda="Da li ste sigurni? Ovo će isključiti dvostepenu verifikaciju.">Deaktiviraj 2FA</button>
</form>
</div>
@@ -105,8 +105,8 @@
{{ else }}
<div style="font-size: 13px; color: var(--tekst-sporedni); margin-bottom: 10px">Rezervni kodovi: preostalo <strong>{{ .BrojRezervnih }}</strong>. Koriste se za prijavu kada nemate pristup aplikaciji sa kodovima.</div>
{{ end }}
<form method="POST" action="/admin/profil/totp/kodovi" onsubmit="return confirm('Generisati nove rezervne kodove? Stari kodovi više neće važiti.');">
<button type="submit" class="btn-sekundarno">Regeneriši rezervne kodove</button>
<form method="POST" action="/admin/profil/totp/kodovi">
<button type="submit" class="btn-sekundarno" data-potvrda="Generisati nove rezervne kodove? Stari kodovi više neće važiti.">Regeneriši rezervne kodove</button>
</form>
</div>
+3 -3
View File
@@ -30,11 +30,11 @@
<td style="padding: 10px 20px; font-size: 13px; color: var(--tekst-sporedni); white-space: nowrap">{{.PoslednjiPokusaj.Format "02.01.2006. 15:04:05"}}</td>
<td style="padding: 10px 20px; font-size: 13px; color: var(--tekst-sporedni)">{{.Preostalo}}</td>
<td style="padding: 10px 20px; text-align: right">
<form method="POST" action="/admin/blokirane-ip/odblokiraj" style="display:inline;" data-full-reload
onsubmit="return confirm('Odblokirati IP adresu {{.IP}}? Ovo odmah briše sve neuspele pokušaje prijave za nju.')">
<form method="POST" action="/admin/blokirane-ip/odblokiraj" style="display:inline;" data-full-reload>
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
<input type="hidden" name="ip" value="{{.IP}}">
<button type="submit" class="btn-sekundarno" style="font-size: 13px; padding: 6px 14px">Odblokiraj</button>
<button type="submit" class="btn-sekundarno" style="font-size: 13px; padding: 6px 14px"
data-potvrda="Odblokirati IP adresu {{.IP}}? Ovo odmah briše sve neuspele pokušaje prijave za nju.">Odblokiraj</button>
</form>
</td>
</tr>
+3 -3
View File
@@ -93,10 +93,10 @@
<a hx-boost="true" hx-target="#glavni-sadrzaj" hx-select="#glavni-sadrzaj" hx-swap="outerHTML" href="/fiskal/pazar" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;">Osveži</a>
{{if index .Dozvole "fiskal.zakljucenje"}}
<form method="POST" action="/fiskal/pazar/zakljuci" style="display:inline;" data-full-reload
onsubmit="return confirm('Resetovati brojače na ekranu? Ovo NIJE zakonska obaveza — izveštaj po periodu radi nezavisno od ovoga. Samo svodi prikaz Promet od poslednjeg preseka na nulu.')">
<form method="POST" action="/fiskal/pazar/zakljuci" style="display:inline;" data-full-reload>
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;color:var(--tekst-sporedni);">Resetuj brojače (opciono)</button>
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;color:var(--tekst-sporedni);"
data-potvrda="Resetovati brojače na ekranu? Ovo NIJE zakonska obaveza — izveštaj po periodu radi nezavisno od ovoga. Samo svodi prikaz Promet od poslednjeg preseka na nulu.">Resetuj brojače (opciono)</button>
</form>
{{end}}
</div>
+19 -4
View File
@@ -25,12 +25,27 @@
{{if .Obrisana}}
<div class="poruka-uspeh poruka-animacija">Kategorija je uspešno obrisana.</div>
{{end}}
{{if .PrikaziSifreDod}}
<div class="poruka-uspeh poruka-animacija">
{{if eq .SifreDodeljene 0}}Svi artikli već imaju šifru.{{else}}Dodeljena šifra za {{.SifreDodeljene}} artikal(a).{{end}}
</div>
{{end}}
<!-- nazad dugme -->
<a href="/magacin" 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"><polyline points="15 18 9 12 15 6"/></svg>
Nazad na magacin
</a>
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;">
<a href="/magacin" 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"><polyline points="15 18 9 12 15 6"/></svg>
Nazad na magacin
</a>
{{if index $.Dozvole "artikal.izmeni"}}
<form method="POST" action="/magacin/kategorije/dodeli-sifre">
<button type="submit" class="btn-sekundarno" style="font-size:13px;padding:8px 16px;"
data-potvrda="Proći kroz sve artikle bez šifre i dodeliti im šifru na osnovu prefiksa njihove kategorije?">
Dodeli šifre artiklima bez šifre
</button>
</form>
{{end}}
</div>
{{if index $.Dozvole "kategorija.dodaj"}}
<!-- forma za novu kategoriju -->
+1 -1
View File
@@ -30,7 +30,7 @@
<div>
<label class="polje-labela">Šifra artikla</label>
<input type="text" name="sifra" id="sifra-input" value="{{.Artikal.Sifra}}"
placeholder="npr. KOMP-0001"
placeholder="{{if .PredlogSifre}}{{.PredlogSifre}}{{else}}npr. KOMP-0001{{end}}"
style="width:100%;font-family:monospace;">
<div style="font-size:11px;color:var(--tekst-slabi);margin-top:4px;">Ako ostaviš prazno, šifra se automatski dodeljuje.</div>
</div>
+3 -3
View File
@@ -303,11 +303,11 @@
<td style="padding:8px 12px;color:var(--tekst-sporedni);">{{.Datum}}</td>
<td style="padding:8px 12px;text-align:right;color:var(--tekst-sporedni);">{{.Velicina}}</td>
<td style="padding:8px 12px;text-align:right;">
<form method="POST" action="/podesavanja/backup/vrati"
onsubmit="return confirm('Vratiti bazu na stanje od: {{.Datum}}?\n\nTrenutna baza će biti automatski sačuvana pre obnove.')">
<form method="POST" action="/podesavanja/backup/vrati">
<input type="hidden" name="ime" value="{{.Ime}}">
<button type="submit"
class="btn-obrisi-ghost">
class="btn-obrisi-ghost"
data-potvrda="Vratiti bazu na stanje od: {{.Datum}}? Trenutna baza će biti automatski sačuvana pre obnove.">
Vrati
</button>
</form>
+13 -3
View File
@@ -26,6 +26,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><polyline points="7 5 12 10 17 5"/></svg>
Vrati backup baze
</button>
<button type="button" onclick="document.getElementById('uvezi-bazu-input').click()"
style="display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:var(--kartica);border:0.5px solid var(--ivica);border-radius:8px;font-size:13px;color:var(--tekst-sporedni);cursor:pointer;transition:background 0.2s;"
onmouseover="this.style.background='var(--pozadina)'" onmouseout="this.style.background='var(--kartica)'">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
Uvezi bazu
</button>
<form id="uvezi-bazu-forma" method="POST" action="/podesavanja/uvezi-bazu" enctype="multipart/form-data" style="display:none;">
<input type="file" id="uvezi-bazu-input" name="baza" accept=".db" required
onchange="window._ntechPotvrdi('Uvoz će zameniti CELU trenutnu bazu podataka fajlom koji ste izabrali.\n\nTrenutna baza će automatski biti sačuvana pre zamene.\n\nNastaviti?').then((ok) => { if (ok) { document.getElementById('uvezi-bazu-forma').requestSubmit(); } else { this.value = ''; } })">
</form>
</div>
</div>
@@ -77,11 +87,11 @@
<td style="padding:8px 12px;color:var(--tekst-sporedni);">{{.Datum}}</td>
<td style="padding:8px 12px;text-align:right;color:var(--tekst-sporedni);">{{.Velicina}}</td>
<td style="padding:8px 12px;text-align:right;">
<form method="POST" action="/podesavanja/backup/vrati"
onsubmit="return confirm('Vratiti bazu na stanje od: {{.Datum}}?\n\nTrenutna baza će biti automatski sačuvana pre obnove.')">
<form method="POST" action="/podesavanja/backup/vrati">
<input type="hidden" name="ime" value="{{.Ime}}">
<button type="submit"
class="btn-obrisi-ghost">
class="btn-obrisi-ghost"
data-potvrda="Vratiti bazu na stanje od: {{.Datum}}? Trenutna baza će biti automatski sačuvana pre obnove.">
Vrati
</button>
</form>