Dodavanje podešavanja u bazu, logo zona sa tri opcije
This commit is contained in:
+5
-2
@@ -47,16 +47,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Println("Migracije uspešno izvršene")
|
log.Println("Migracije uspešno izvršene")
|
||||||
|
|
||||||
|
// kreiramo handler sa bazom
|
||||||
|
h := handler.Novi(db)
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
// statični fajlovi — CSS, JS, slike
|
// statični fajlovi
|
||||||
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("web/static"))))
|
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("web/static"))))
|
||||||
|
|
||||||
// rute
|
// rute
|
||||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
||||||
})
|
})
|
||||||
r.Get("/dashboard", handler.Dashboard)
|
r.Get("/dashboard", h.Dashboard)
|
||||||
|
|
||||||
log.Printf("NTech pokrenut na portu %s", port)
|
log.Printf("NTech pokrenut na portu %s", port)
|
||||||
err = http.ListenAndServe(":"+port, r)
|
err = http.ListenAndServe(":"+port, r)
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DohvatiPodesavanje čita jednu vrednost iz tabele podešavanja
|
||||||
|
func DohvatiPodesavanje(ctx context.Context, db *sql.DB, kljuc string) (string, error) {
|
||||||
|
var vrednost string
|
||||||
|
err := db.QueryRowContext(ctx, "SELECT vrednost FROM podesavanja WHERE kljuc = ?", kljuc).Scan(&vrednost)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("ntech: DohvatiPodesavanje: %s: %w", kljuc, err)
|
||||||
|
}
|
||||||
|
return vrednost, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SacuvajPodesavanje upisuje ili menja vrednost u tabeli podešavanja
|
||||||
|
func SacuvajPodesavanje(ctx context.Context, db *sql.DB, kljuc, vrednost string) error {
|
||||||
|
_, err := db.ExecContext(ctx,
|
||||||
|
"INSERT INTO podesavanja (kljuc, vrednost) VALUES (?, ?) ON CONFLICT(kljuc) DO UPDATE SET vrednost = excluded.vrednost",
|
||||||
|
kljuc, vrednost,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ntech: SacuvajPodesavanje: %s: %w", kljuc, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DohvatiSvaPodesavanja čita sva podešavanja i vraća ih kao mapu
|
||||||
|
func DohvatiSvaPodesavanja(ctx context.Context, db *sql.DB) (map[string]string, error) {
|
||||||
|
redovi, err := db.QueryContext(ctx, "SELECT kljuc, vrednost FROM podesavanja")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ntech: DohvatiSvaPodesavanja: %w", err)
|
||||||
|
}
|
||||||
|
defer redovi.Close()
|
||||||
|
|
||||||
|
rezultat := make(map[string]string)
|
||||||
|
for redovi.Next() {
|
||||||
|
var kljuc, vrednost string
|
||||||
|
if err := redovi.Scan(&kljuc, &vrednost); err != nil {
|
||||||
|
return nil, fmt.Errorf("ntech: DohvatiSvaPodesavanja: scan: %w", err)
|
||||||
|
}
|
||||||
|
rezultat[kljuc] = vrednost
|
||||||
|
}
|
||||||
|
return rezultat, nil
|
||||||
|
}
|
||||||
@@ -4,18 +4,28 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"ntech/internal/db/sqlite"
|
||||||
"ntech/internal/model"
|
"ntech/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Dashboard renderuje početnu stranicu
|
// Dashboard renderuje početnu stranicu
|
||||||
func Dashboard(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
// za sad koristimo testne podatke — kasnije će ići iz baze
|
// čitamo sva podešavanja iz baze
|
||||||
|
podesavanja, err := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
podaci := model.PodaciDashboarda{
|
podaci := model.PodaciDashboarda{
|
||||||
PodaciStranice: model.PodaciStranice{
|
PodaciStranice: model.PodaciStranice{
|
||||||
Stranica: "dashboard",
|
Stranica: "dashboard",
|
||||||
NaslovStranice: "Dashboard",
|
NaslovStranice: "Dashboard",
|
||||||
Tema: "tamna",
|
Tema: podesavanja["tema"],
|
||||||
NazivFirme: "NTech",
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
|
Podnazlov: podesavanja["podnazlov"],
|
||||||
|
LogoTip: podesavanja["logo_tip"],
|
||||||
|
LogoPutanja: podesavanja["logo_putanja"],
|
||||||
Korisnik: "Admin",
|
Korisnik: "Admin",
|
||||||
},
|
},
|
||||||
BrojArtikala: 0,
|
BrojArtikala: 0,
|
||||||
@@ -26,7 +36,6 @@ func Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
KriticneZalihe: []model.StavkaZalihe{},
|
KriticneZalihe: []model.StavkaZalihe{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// učitavamo sve potrebne šablone zajedno
|
|
||||||
tmpl, err := template.ParseFiles(
|
tmpl, err := template.ParseFiles(
|
||||||
"web/templates/teme/podrazumevana/base.html",
|
"web/templates/teme/podrazumevana/base.html",
|
||||||
"web/templates/komponente/sidebar.html",
|
"web/templates/komponente/sidebar.html",
|
||||||
@@ -38,7 +47,6 @@ func Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderujemo base šablon sa podacima
|
|
||||||
if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil {
|
if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil {
|
||||||
http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError)
|
http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
|
// Handler drži zavisnosti koje su potrebne svim handlerima
|
||||||
|
type Handler struct {
|
||||||
|
DB *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Novi kreira novi Handler sa datom bazom
|
||||||
|
func Novi(db *sql.DB) *Handler {
|
||||||
|
return &Handler{DB: db}
|
||||||
|
}
|
||||||
+15
-13
@@ -4,7 +4,7 @@ package model
|
|||||||
type StavkaServisa struct {
|
type StavkaServisa struct {
|
||||||
Uredjaj string
|
Uredjaj string
|
||||||
Status string
|
Status string
|
||||||
BojaTacke string // "#16a34a" zelena, "#f59e0b" žuta, "#dc2626" crvena
|
BojaTacke string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StavkaZalihe prikazuje jedan artikal sa kritičnom zalihom
|
// StavkaZalihe prikazuje jedan artikal sa kritičnom zalihom
|
||||||
@@ -16,21 +16,23 @@ type StavkaZalihe struct {
|
|||||||
|
|
||||||
// PodaciStranice su zajednički podaci koje svaka stranica prima
|
// PodaciStranice su zajednički podaci koje svaka stranica prima
|
||||||
type PodaciStranice struct {
|
type PodaciStranice struct {
|
||||||
Stranica string // naziv aktivne stranice za sidebar
|
Stranica string
|
||||||
NaslovStranice string // naslov u topbaru
|
NaslovStranice string
|
||||||
Tema string // aktivna tema: "tamna", "svetla", "zelena", "ljubicasta"
|
Tema string
|
||||||
NazivFirme string // naziv firme za logo zonu
|
NazivFirme string
|
||||||
Logo string // putanja do logo fajla, opciono
|
Podnazlov string
|
||||||
Korisnik string // ime korisnika za avatar
|
LogoTip string // "ikonica", "tekst", "slika"
|
||||||
|
LogoPutanja string // putanja do slike, koristi se samo kada je LogoTip "slika"
|
||||||
|
Korisnik string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodaciDashboarda su podaci specifični za dashboard stranicu
|
// PodaciDashboarda su podaci specifični za dashboard stranicu
|
||||||
type PodaciDashboarda struct {
|
type PodaciDashboarda struct {
|
||||||
PodaciStranice
|
PodaciStranice
|
||||||
BrojArtikala int
|
BrojArtikala int
|
||||||
AktivniServisi int
|
AktivniServisi int
|
||||||
ProdajaOvogMeseca int
|
ProdajaOvogMeseca int
|
||||||
KriticnaZaliha int
|
KriticnaZaliha int
|
||||||
PoslednjiServisi []StavkaServisa
|
PoslednjiServisi []StavkaServisa
|
||||||
KriticneZalihe []StavkaZalihe
|
KriticneZalihe []StavkaZalihe
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS podesavanja (
|
||||||
|
kljuc TEXT PRIMARY KEY,
|
||||||
|
vrednost TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- podrazumevane vrednosti
|
||||||
|
INSERT OR IGNORE INTO podesavanja (kljuc, vrednost) VALUES
|
||||||
|
('naziv_firme', 'NTech'),
|
||||||
|
('podnazlov', 'Servis računara'),
|
||||||
|
('logo_tip', 'ikonica'),
|
||||||
|
('logo_putanja', ''),
|
||||||
|
('tema', 'tamna');
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{{define "sidebar"}}
|
{{define "sidebar"}}
|
||||||
<aside class="sidebar" id="sidebar">
|
<aside class="sidebar" id="sidebar">
|
||||||
<!-- vrh sidebara — hamburger i logo -->
|
|
||||||
<div class="sidebar-vrh">
|
<div class="sidebar-vrh">
|
||||||
<button class="hamburger" id="hamburger" aria-label="Otvori/zatvori meni">
|
<button class="hamburger" id="hamburger" aria-label="Otvori/zatvori meni">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -10,19 +9,27 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="logo-zona">
|
<div class="logo-zona">
|
||||||
{{if .Logo}}
|
{{if eq .LogoTip "slika"}}
|
||||||
<img src="/static/{{.Logo}}" alt="Logo" style="width:36px;height:36px;object-fit:contain;border-radius:6px;">
|
<img src="/static/{{.LogoPutanja}}" alt="Logo" style="width:36px;height:36px;object-fit:contain;border-radius:6px;flex-shrink:0;">
|
||||||
|
<div>
|
||||||
|
<div class="logo-naziv">{{.NazivFirme}}</div>
|
||||||
|
<div class="logo-podnazlov">{{.Podnazlov}}</div>
|
||||||
|
</div>
|
||||||
|
{{else if eq .LogoTip "tekst"}}
|
||||||
|
<div>
|
||||||
|
<div class="logo-naziv">{{.NazivFirme}}</div>
|
||||||
|
<div class="logo-podnazlov">{{.Podnazlov}}</div>
|
||||||
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div style="width:36px;height:36px;border-radius:8px;background:rgba(255,255,255,0.1);border:1.5px dashed rgba(255,255,255,0.25);flex-shrink:0;"></div>
|
<div style="width:36px;height:36px;border-radius:8px;background:rgba(255,255,255,0.1);border:1.5px dashed rgba(255,255,255,0.25);flex-shrink:0;"></div>
|
||||||
|
<div>
|
||||||
|
<div class="logo-naziv">{{.NazivFirme}}</div>
|
||||||
|
<div class="logo-podnazlov">{{.Podnazlov}}</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div>
|
|
||||||
<div class="logo-naziv">{{if .NazivFirme}}{{.NazivFirme}}{{else}}NTech{{end}}</div>
|
|
||||||
<div class="logo-podnazlov">Servis računara</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- navigacija -->
|
|
||||||
<nav class="sidebar-nav" aria-label="Glavna navigacija">
|
<nav class="sidebar-nav" aria-label="Glavna navigacija">
|
||||||
<div class="nav-oznaka">Glavni meni</div>
|
<div class="nav-oznaka">Glavni meni</div>
|
||||||
|
|
||||||
@@ -66,13 +73,12 @@
|
|||||||
<div class="nav-oznaka">Sistem</div>
|
<div class="nav-oznaka">Sistem</div>
|
||||||
|
|
||||||
<a href="/podesavanja" class="nav-stavka {{if eq .Stranica "podesavanja"}}aktivan{{end}}">
|
<a href="/podesavanja" class="nav-stavka {{if eq .Stranica "podesavanja"}}aktivan{{end}}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||||
<span>Podešavanja</span>
|
<span>Podešavanja</span>
|
||||||
<span class="nav-tooltip">Podešavanja</span>
|
<span class="nav-tooltip">Podešavanja</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- dno sidebara -->
|
|
||||||
<div class="sidebar-dno">
|
<div class="sidebar-dno">
|
||||||
<a href="/odjava" class="nav-stavka">
|
<a href="/odjava" class="nav-stavka">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
||||||
|
|||||||
Reference in New Issue
Block a user