generated from VLADIMIR/template
add pdf
This commit is contained in:
parent
b17599eb39
commit
be8e7fa482
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -5,8 +5,11 @@
|
|||||||
"Точка",
|
"Точка",
|
||||||
"точки",
|
"точки",
|
||||||
"AUTOINCREMENT",
|
"AUTOINCREMENT",
|
||||||
|
"gopdf",
|
||||||
"gwmux",
|
"gwmux",
|
||||||
"localtime",
|
"localtime",
|
||||||
"palces"
|
"palces",
|
||||||
|
"qrcode",
|
||||||
|
"signintech"
|
||||||
]
|
]
|
||||||
}
|
}
|
7
go.mod
7
go.mod
@ -9,6 +9,11 @@ require (
|
|||||||
google.golang.org/grpc v1.64.0
|
google.golang.org/grpc v1.64.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 // indirect
|
||||||
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
@ -20,6 +25,8 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/mattn/go-sqlite3 v1.14.28
|
github.com/mattn/go-sqlite3 v1.14.28
|
||||||
|
github.com/signintech/gopdf v0.32.0
|
||||||
|
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||||
golang.org/x/net v0.23.0 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
golang.org/x/sys v0.26.0 // indirect
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
@ -1,7 +1,49 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
type Team struct {
|
type Team struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string
|
Name string
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Team) GetTeamUrl() (string, error) {
|
||||||
|
ips, err := getLocalIPs()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
ip := ips[0]
|
||||||
|
u := fmt.Sprintf("http://%s:8100?name=%s&password=%s", ip, url.PathEscape(t.Name), t.Password)
|
||||||
|
return u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLocalIPs() ([]string, error) {
|
||||||
|
var ips []string
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipNet, ok := addr.(*net.IPNet)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := ipNet.IP
|
||||||
|
if ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ipv4 := ip.To4(); ipv4 != nil {
|
||||||
|
ips = append(ips, ipv4.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
|
112
internal/services/pdf_service/service.go
Normal file
112
internal/services/pdf_service/service.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package pdf_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"evening_detective/internal/models"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/signintech/gopdf"
|
||||||
|
"github.com/skip2/go-qrcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTeamsPdf(teams []*models.Team) ([]byte, error) {
|
||||||
|
pdf := &gopdf.GoPdf{}
|
||||||
|
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4}) // W: 595, H: 842
|
||||||
|
if err := pdf.AddTTFFont("main", "JetBrainsMono-Medium.ttf"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := pdf.SetFont("main", "", 10); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
padding := 17.
|
||||||
|
xDelta := 187.
|
||||||
|
yDelta := 202.
|
||||||
|
for i, team := range teams {
|
||||||
|
if i%12 == 0 {
|
||||||
|
pdf.AddPage()
|
||||||
|
pdf.SetPage(1 + i/12)
|
||||||
|
}
|
||||||
|
y := (padding + 15) + yDelta*float64(i%12/3)
|
||||||
|
x := padding + xDelta*float64(i%3)
|
||||||
|
|
||||||
|
url, err := team.GetTeamUrl()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := printQR(pdf, url, x+21, y); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := printTextCenter(pdf, team.Name, xDelta-6, x+3, y+150); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
_, err := pdf.WriteTo(buffer)
|
||||||
|
return buffer.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func printQR(pdf *gopdf.GoPdf, url string, x, y float64) error {
|
||||||
|
png, err := qrcode.Encode(url, qrcode.Medium, 256)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imgHolder, err := gopdf.ImageHolderByBytes(png)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = pdf.ImageByHolder(imgHolder, x, y, &gopdf.Rect{W: 145, H: 145})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printTextCenter(pdf *gopdf.GoPdf, text string, pageWidth, x, y float64) error {
|
||||||
|
lines := splitTextByWords(pdf, text, pageWidth)
|
||||||
|
for i, line := range lines {
|
||||||
|
lineWidth, err := pdf.MeasureTextWidth(line)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xLine := x + (pageWidth-lineWidth)/2
|
||||||
|
yLine := y + 15*float64(i)
|
||||||
|
pdf.SetXY(xLine, yLine)
|
||||||
|
|
||||||
|
pdf.Cell(nil, line)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitTextByWords(pdf *gopdf.GoPdf, text string, maxWidth float64) []string {
|
||||||
|
words := strings.Fields(text)
|
||||||
|
var lines []string
|
||||||
|
var currentLine string
|
||||||
|
|
||||||
|
for _, word := range words {
|
||||||
|
testLine := currentLine
|
||||||
|
if testLine != "" {
|
||||||
|
testLine += " " + word
|
||||||
|
} else {
|
||||||
|
testLine = word
|
||||||
|
}
|
||||||
|
|
||||||
|
width, _ := pdf.MeasureTextWidth(testLine)
|
||||||
|
|
||||||
|
if width <= maxWidth {
|
||||||
|
currentLine = testLine
|
||||||
|
} else {
|
||||||
|
if currentLine != "" {
|
||||||
|
lines = append(lines, currentLine)
|
||||||
|
}
|
||||||
|
currentLine = word
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentLine != "" {
|
||||||
|
lines = append(lines, currentLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
@ -9,8 +9,6 @@ import (
|
|||||||
"evening_detective/internal/services/story_service"
|
"evening_detective/internal/services/story_service"
|
||||||
"evening_detective/proto"
|
"evening_detective/proto"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
@ -153,7 +151,7 @@ func (s *Services) GetTeams(ctx context.Context, _ *proto.GetTeamsReq) (*proto.G
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
newTeam.Url, err = getTeamUrl(team)
|
newTeam.Url, err = team.GetTeamUrl()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -220,39 +218,3 @@ func addLog(team *models.Team, action string, v any) {
|
|||||||
fmt.Printf("Team %s: %s %s\n", team.Name, action, string(vJson))
|
fmt.Printf("Team %s: %s %s\n", team.Name, action, string(vJson))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTeamUrl(team *models.Team) (string, error) {
|
|
||||||
ips, err := getLocalIPs()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
ip := ips[0]
|
|
||||||
u := fmt.Sprintf("http://%s:8100?name=%s&password=%s", ip, url.PathEscape(team.Name), team.Password)
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLocalIPs() ([]string, error) {
|
|
||||||
var ips []string
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, addr := range addrs {
|
|
||||||
ipNet, ok := addr.(*net.IPNet)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ip := ipNet.IP
|
|
||||||
if ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ipv4 := ip.To4(); ipv4 != nil {
|
|
||||||
ips = append(ips, ipv4.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ips, nil
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user