Dashboard — pravi podaci, prihod meseca, poslednje prodaje, datum umesto badge
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"ntech/internal/db/sqlite"
|
"ntech/internal/db/sqlite"
|
||||||
"ntech/internal/model"
|
"ntech/internal/model"
|
||||||
@@ -19,7 +20,8 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var brojArtikala, aktivniServisi, prodajaOvogMeseca, kriticnaZaliha int
|
var brojArtikala, aktivniServisi, kriticnaZaliha int
|
||||||
|
var prihodOvogMeseca float64
|
||||||
|
|
||||||
if err := h.DB.QueryRowContext(ctx,
|
if err := h.DB.QueryRowContext(ctx,
|
||||||
"SELECT COUNT(*) FROM artikli",
|
"SELECT COUNT(*) FROM artikli",
|
||||||
@@ -35,10 +37,10 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := h.DB.QueryRowContext(ctx, `
|
if err := h.DB.QueryRowContext(ctx, `
|
||||||
SELECT COUNT(*) FROM prodajni_nalozi
|
SELECT COALESCE(SUM(ukupno), 0) FROM prodajni_nalozi
|
||||||
WHERE strftime('%Y-%m', datum) = strftime('%Y-%m', 'now', 'localtime')`,
|
WHERE strftime('%Y-%m', datum) = strftime('%Y-%m', 'now', 'localtime')`,
|
||||||
).Scan(&prodajaOvogMeseca); err != nil {
|
).Scan(&prihodOvogMeseca); err != nil {
|
||||||
log.Printf("dashboard: prodaja ovog meseca: %v", err)
|
log.Printf("dashboard: prihod ovog meseca: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.DB.QueryRowContext(ctx,
|
if err := h.DB.QueryRowContext(ctx,
|
||||||
@@ -47,9 +49,9 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Printf("dashboard: kriticna zaliha: %v", err)
|
log.Printf("dashboard: kriticna zaliha: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// poslednjih 5 servisnih naloga
|
// poslednjih 5 servisnih naloga sa datumom prijema
|
||||||
servisRedovi, err := h.DB.QueryContext(ctx, `
|
servisRedovi, err := h.DB.QueryContext(ctx, `
|
||||||
SELECT uredjaj, status FROM servisni_nalozi
|
SELECT uredjaj, status, datum_prijema FROM servisni_nalozi
|
||||||
ORDER BY datum_prijema DESC LIMIT 5`)
|
ORDER BY datum_prijema DESC LIMIT 5`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("dashboard: poslednji servisi: %v", err)
|
log.Printf("dashboard: poslednji servisi: %v", err)
|
||||||
@@ -60,8 +62,10 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
defer servisRedovi.Close()
|
defer servisRedovi.Close()
|
||||||
for servisRedovi.Next() {
|
for servisRedovi.Next() {
|
||||||
var s model.StavkaServisa
|
var s model.StavkaServisa
|
||||||
if err := servisRedovi.Scan(&s.Uredjaj, &s.Status); err == nil {
|
var datum time.Time
|
||||||
|
if err := servisRedovi.Scan(&s.Uredjaj, &s.Status, &datum); err == nil {
|
||||||
s.BojaTacke = bojaTackeServisa(s.Status)
|
s.BojaTacke = bojaTackeServisa(s.Status)
|
||||||
|
s.DatumPrijema = datum.Format("02.01.")
|
||||||
poslednjiServisi = append(poslednjiServisi, s)
|
poslednjiServisi = append(poslednjiServisi, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +96,31 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// poslednjih 5 prodajnih naloga sa nazivom klijenta
|
||||||
|
prodajaRedovi, err := h.DB.QueryContext(ctx, `
|
||||||
|
SELECT
|
||||||
|
pn.broj_naloga, pn.ukupno, pn.datum,
|
||||||
|
COALESCE(NULLIF(k.naziv_firme, ''), TRIM(COALESCE(k.ime, '') || ' ' || COALESCE(k.prezime, '')), '') AS klijent_naziv
|
||||||
|
FROM prodajni_nalozi pn
|
||||||
|
LEFT JOIN klijenti k ON k.id = pn.klijent_id
|
||||||
|
ORDER BY pn.datum DESC LIMIT 5`)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("dashboard: poslednje prodaje: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var poslednjeProdaje []model.StavkaProdajePregled
|
||||||
|
if prodajaRedovi != nil {
|
||||||
|
defer prodajaRedovi.Close()
|
||||||
|
for prodajaRedovi.Next() {
|
||||||
|
var p model.StavkaProdajePregled
|
||||||
|
var datum time.Time
|
||||||
|
if err := prodajaRedovi.Scan(&p.BrojNaloga, &p.Ukupno, &datum, &p.KlijentNaziv); err == nil {
|
||||||
|
p.Datum = datum.Format("02.01.")
|
||||||
|
poslednjeProdaje = append(poslednjeProdaje, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
podaci := model.PodaciDashboarda{
|
podaci := model.PodaciDashboarda{
|
||||||
PodaciStranice: model.PodaciStranice{
|
PodaciStranice: model.PodaciStranice{
|
||||||
Stranica: "dashboard",
|
Stranica: "dashboard",
|
||||||
@@ -105,10 +134,11 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
},
|
},
|
||||||
BrojArtikala: brojArtikala,
|
BrojArtikala: brojArtikala,
|
||||||
AktivniServisi: aktivniServisi,
|
AktivniServisi: aktivniServisi,
|
||||||
ProdajaOvogMeseca: prodajaOvogMeseca,
|
PrihodOvogMeseca: prihodOvogMeseca,
|
||||||
KriticnaZaliha: kriticnaZaliha,
|
KriticnaZaliha: kriticnaZaliha,
|
||||||
PoslednjiServisi: poslednjiServisi,
|
PoslednjiServisi: poslednjiServisi,
|
||||||
KriticneZalihe: kriticneZalihe,
|
KriticneZalihe: kriticneZalihe,
|
||||||
|
PoslednjeProdaje: poslednjeProdaje,
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(
|
tmpl, err := template.ParseFiles(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ type StavkaServisa struct {
|
|||||||
Uredjaj string
|
Uredjaj string
|
||||||
Status string
|
Status string
|
||||||
BojaTacke string
|
BojaTacke string
|
||||||
|
DatumPrijema string // kratki format, npr. "01.06."
|
||||||
}
|
}
|
||||||
|
|
||||||
// StavkaZalihe prikazuje jedan artikal sa kritičnom zalihom
|
// StavkaZalihe prikazuje jedan artikal sa kritičnom zalihom
|
||||||
@@ -14,6 +15,14 @@ type StavkaZalihe struct {
|
|||||||
BojaTacke string
|
BojaTacke string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StavkaProdajePregled prikazuje jedan prodajni nalog na dashboardu
|
||||||
|
type StavkaProdajePregled struct {
|
||||||
|
BrojNaloga string
|
||||||
|
KlijentNaziv string
|
||||||
|
Ukupno float64
|
||||||
|
Datum string // kratki format, npr. "01.06."
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
Stranica string
|
||||||
@@ -31,8 +40,9 @@ type PodaciDashboarda struct {
|
|||||||
PodaciStranice
|
PodaciStranice
|
||||||
BrojArtikala int
|
BrojArtikala int
|
||||||
AktivniServisi int
|
AktivniServisi int
|
||||||
ProdajaOvogMeseca int
|
PrihodOvogMeseca float64
|
||||||
KriticnaZaliha int
|
KriticnaZaliha int
|
||||||
PoslednjiServisi []StavkaServisa
|
PoslednjiServisi []StavkaServisa
|
||||||
KriticneZalihe []StavkaZalihe
|
KriticneZalihe []StavkaZalihe
|
||||||
|
PoslednjeProdaje []StavkaProdajePregled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
<div style="width:36px;height:36px;border-radius:8px;background:#fff7ed;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
|
<div style="width:36px;height:36px;border-radius:8px;background:#fff7ed;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ea580c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ea580c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{.ProdajaOvogMeseca}}</div>
|
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{printf "%.0f" .PrihodOvogMeseca}} din</div>
|
||||||
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Prodaja ovog meseca</div>
|
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Prihod ovog meseca</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="kartica">
|
<div class="kartica">
|
||||||
@@ -38,18 +38,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<!-- poslednji servisi -->
|
<!-- poslednji servisi -->
|
||||||
<div class="kartica">
|
<div class="kartica">
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
|
||||||
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednji servisi</span>
|
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednji servisi</span>
|
||||||
<span style="font-size:11px;padding:2px 8px;border-radius:20px;background:#eff2ff;color:#4f7ef8;font-weight:500;">Danas</span>
|
|
||||||
</div>
|
</div>
|
||||||
{{range .PoslednjiServisi}}
|
{{range .PoslednjiServisi}}
|
||||||
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
|
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
|
||||||
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{.BojaTacke}};"></div>
|
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{.BojaTacke}};"></div>
|
||||||
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;">{{.Uredjaj}}</span>
|
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{.Uredjaj}}</span>
|
||||||
<span style="font-size:12px;color:var(--tekst-sporedni);">{{.Status}}</span>
|
<span style="font-size:11px;color:var(--tekst-sporedni);white-space:nowrap;">{{.DatumPrijema}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema servisnih naloga.</div>
|
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema servisnih naloga.</div>
|
||||||
@@ -72,5 +71,28 @@
|
|||||||
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Sve zalihe su uredne.</div>
|
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Sve zalihe su uredne.</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- poslednje prodaje -->
|
||||||
|
<div class="kartica">
|
||||||
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
|
||||||
|
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednje prodaje</span>
|
||||||
|
</div>
|
||||||
|
{{range .PoslednjeProdaje}}
|
||||||
|
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
|
||||||
|
<div style="flex:1;min-width:0;">
|
||||||
|
<div style="font-size:13px;color:var(--tekst-glavni);font-family:monospace;">{{.BrojNaloga}}</div>
|
||||||
|
{{if .KlijentNaziv}}
|
||||||
|
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{.KlijentNaziv}}</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div style="text-align:right;flex-shrink:0;">
|
||||||
|
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);">{{printf "%.0f" .Ukupno}} din</div>
|
||||||
|
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;">{{.Datum}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema prodajnih naloga.</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user