Servis: Code128 barkod na vrhu nalepnice (laserski skener)
This commit is contained in:
@@ -3,21 +3,21 @@ module ntech
|
|||||||
go 1.26.3
|
go 1.26.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/boombuler/barcode v1.1.0
|
||||||
github.com/go-chi/chi/v5 v5.3.0
|
github.com/go-chi/chi/v5 v5.3.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/pquerna/otp v1.5.0
|
github.com/pquerna/otp v1.5.0
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
golang.org/x/crypto v0.52.0
|
golang.org/x/crypto v0.52.0
|
||||||
modernc.org/sqlite v1.51.0
|
modernc.org/sqlite v1.51.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/boombuler/barcode v1.1.0 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
|
||||||
github.com/stretchr/testify v1.11.1 // indirect
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
golang.org/x/sys v0.45.0 // indirect
|
golang.org/x/sys v0.45.0 // indirect
|
||||||
golang.org/x/tools v0.44.0 // indirect
|
golang.org/x/tools v0.44.0 // indirect
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image/png"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -15,6 +17,8 @@ import (
|
|||||||
"ntech/internal/middleware"
|
"ntech/internal/middleware"
|
||||||
"ntech/internal/model"
|
"ntech/internal/model"
|
||||||
|
|
||||||
|
"github.com/boombuler/barcode"
|
||||||
|
"github.com/boombuler/barcode/code128"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
qrcode "github.com/skip2/go-qrcode"
|
qrcode "github.com/skip2/go-qrcode"
|
||||||
)
|
)
|
||||||
@@ -1303,6 +1307,25 @@ type PodaciNalepnice struct {
|
|||||||
Nalog model.ServisniNalog
|
Nalog model.ServisniNalog
|
||||||
KlijentNaziv string
|
KlijentNaziv string
|
||||||
QRKod string // base64 PNG QR koda sa URL-om naloga
|
QRKod string // base64 PNG QR koda sa URL-om naloga
|
||||||
|
Barkod string // base64 PNG Code128 barkoda sa brojem naloga (za laserski skener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// barkodNaloga generiše Code128 barkod broja naloga kao base64 PNG; prazan string ako ne uspe
|
||||||
|
func barkodNaloga(broj string) string {
|
||||||
|
kod, err := code128.Encode(broj)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// razvuci na fiksnu širinu/visinu radi oštrog otiska na nalepnici
|
||||||
|
skaliran, err := barcode.Scale(kod, 480, 90)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := png.Encode(&buf, skaliran); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// StampaNalepnice renderuje malu nalepnicu sa brojem naloga, klijentom, uređajem i QR kodom
|
// StampaNalepnice renderuje malu nalepnicu sa brojem naloga, klijentom, uređajem i QR kodom
|
||||||
@@ -1341,6 +1364,7 @@ func (h *Handler) StampaNalepnice(w http.ResponseWriter, r *http.Request) {
|
|||||||
Nalog: *nalog,
|
Nalog: *nalog,
|
||||||
KlijentNaziv: klijentNaziv,
|
KlijentNaziv: klijentNaziv,
|
||||||
QRKod: qrKod,
|
QRKod: qrKod,
|
||||||
|
Barkod: barkodNaloga(nalog.BrojNaloga),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
width: 70mm;
|
width: 70mm;
|
||||||
height: 40mm;
|
height: 40mm;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 3mm;
|
padding: 2.5mm 3mm;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
gap: 3mm;
|
gap: 1.5mm;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
/* na ekranu — centrirano sa okvirom radi pregleda */
|
/* na ekranu — centrirano sa okvirom radi pregleda */
|
||||||
@@ -25,6 +25,12 @@
|
|||||||
.nalepnica { margin: 24px auto; border: 1px dashed #bbb; box-shadow: 0 1px 4px rgba(0,0,0,.1); }
|
.nalepnica { margin: 24px auto; border: 1px dashed #bbb; box-shadow: 0 1px 4px rgba(0,0,0,.1); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* barkod na vrhu — preko cele širine, za laserski skener */
|
||||||
|
.barkod { flex: 0 0 auto; text-align: center; }
|
||||||
|
.barkod img { display: block; width: 100%; height: 9mm; object-fit: fill; }
|
||||||
|
|
||||||
|
.donji-red { flex: 1; min-width: 0; display: flex; align-items: center; gap: 3mm; }
|
||||||
|
|
||||||
.podaci { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 1.5mm; }
|
.podaci { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 1.5mm; }
|
||||||
.broj { font-family: monospace; font-size: 14pt; font-weight: 700; line-height: 1.1; }
|
.broj { font-family: monospace; font-size: 14pt; font-weight: 700; line-height: 1.1; }
|
||||||
.red { font-size: 8pt; line-height: 1.25; }
|
.red { font-size: 8pt; line-height: 1.25; }
|
||||||
@@ -33,7 +39,7 @@
|
|||||||
.prazno { color: #aaa; font-style: italic; font-weight: 400; }
|
.prazno { color: #aaa; font-style: italic; font-weight: 400; }
|
||||||
|
|
||||||
.qr { flex: 0 0 auto; }
|
.qr { flex: 0 0 auto; }
|
||||||
.qr img { display: block; width: 26mm; height: 26mm; }
|
.qr img { display: block; width: 22mm; height: 22mm; }
|
||||||
|
|
||||||
@page { size: 70mm 40mm; margin: 0; }
|
@page { size: 70mm 40mm; margin: 0; }
|
||||||
@media print {
|
@media print {
|
||||||
@@ -44,6 +50,10 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="nalepnica">
|
<div class="nalepnica">
|
||||||
|
{{if .Barkod}}
|
||||||
|
<div class="barkod"><img src="data:image/png;base64,{{.Barkod}}" alt="Barkod"></div>
|
||||||
|
{{end}}
|
||||||
|
<div class="donji-red">
|
||||||
<div class="podaci">
|
<div class="podaci">
|
||||||
<div class="broj">{{.Nalog.BrojNaloga}}</div>
|
<div class="broj">{{.Nalog.BrojNaloga}}</div>
|
||||||
<div class="red">
|
<div class="red">
|
||||||
@@ -59,6 +69,7 @@
|
|||||||
<div class="qr"><img src="data:image/png;base64,{{.QRKod}}" alt="QR"></div>
|
<div class="qr"><img src="data:image/png;base64,{{.QRKod}}" alt="QR"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<script>window.addEventListener('load', function(){ window.print(); });</script>
|
<script>window.addEventListener('load', function(){ window.print(); });</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user