feat(master): Add login interface, add pdma, format part of the code, and change mysql connection parse Time to True - [添加登录接口,增加pdma,格式化部分代码、mysql连接parseTime改为True]

This commit is contained in:
刘欢
2024-07-11 11:26:46 +08:00
parent 9c6e04be13
commit fa1a270e95
90 changed files with 12854 additions and 321 deletions

3
.gitignore vendored
View File

@@ -28,6 +28,7 @@ tmp/*
# Project runtime log
logs/*.log
docs
docs/docs.go
docs/swagger.*
INSTALL.lock

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -9,23 +9,23 @@ connmaxlifetime = 60
host = '127.0.0.1'
maxidleconn = 60
maxopenconn = 1
name = 'gin-template'
name = 'gin_template'
pass = 'root'
port = 3306
user = 'root'
[database.mysql.read]
database = 'gin-template'
database = 'gin_template'
host = '127.0.0.1'
name = 'gin-template'
name = 'gin_template'
pass = 'root'
port = 3306
user = 'root'
[database.mysql.write]
database = 'gin-template'
database = 'gin_template'
host = '127.0.0.1'
name = 'gin-template'
name = 'gin_template'
pass = 'root'
port = 3306
user = 'root'

View File

@@ -1,8 +1,9 @@
// Package configs
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:32
// @description: 常量配置
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:32
// @description: 常量配置
package configs
import (

View File

@@ -1,8 +1,9 @@
// Package configs
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:32
// @description: 数据库配置
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:32
// @description: 数据库配置
package configs
type DataBase struct {

View File

@@ -1,8 +1,9 @@
// Package configs
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:33
// @description: 报警配置
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:33
// @description: 报警配置
package configs
type Notify struct {

View File

@@ -1,8 +1,9 @@
// Package configs
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:33
// @description: redis配置
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:33
// @description: redis配置
package configs
type Redis struct {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

16
go.mod
View File

@@ -11,21 +11,24 @@ require (
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.22.0
github.com/gorilla/websocket v1.5.3
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.1
github.com/redis/go-redis/v9 v9.5.3
github.com/robfig/cron/v3 v3.0.1
github.com/rs/cors/wrapper/gin v0.0.0-20240515105523-1562b1715b35
github.com/shirou/gopsutil/v4 v4.24.6
github.com/spf13/cast v1.6.0
github.com/spf13/viper v1.19.0
github.com/sqids/sqids-go v0.4.1
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
go.uber.org/multierr v1.10.0
go.uber.org/zap v1.27.0
golang.org/x/text v0.16.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.22.0
golang.org/x/tools v0.23.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gorm.io/driver/mysql v1.5.7
@@ -55,7 +58,6 @@ require (
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
@@ -83,25 +85,23 @@ require (
github.com/rs/cors v1.11.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shirou/gopsutil/v4 v4.24.6 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/swaggo/swag v1.16.3 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/sys v0.22.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect

24
go.sum
View File

@@ -199,6 +199,8 @@ github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckyS
github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
@@ -260,16 +262,14 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -281,8 +281,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -303,8 +303,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -326,8 +326,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=

View File

@@ -1,8 +1,9 @@
// Package alert
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:40
// @description: 告警通知
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:40
// @description: 告警通知
package alert
import (

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type createRequest struct{}
type createResponse struct{}
// Create 新增管理员
//
// @Summary 新增管理员
// @Description 新增管理员
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin [post]
func (h *handler) Create() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type createAdminMenuRequest struct{}
type createAdminMenuResponse struct{}
// CreateAdminMenu 提交菜单授权
//
// @Summary 提交菜单授权
// @Description 提交菜单授权
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body createAdminMenuRequest true "请求信息"
// @Success 200 {object} createAdminMenuResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/menu [post]
func (h *handler) CreateAdminMenu() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type deleteRequest struct{}
type deleteResponse struct{}
// Delete 删除管理员
//
// @Summary 删除管理员
// @Description 删除管理员
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body deleteRequest true "请求信息"
// @Success 200 {object} deleteResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/{id} [delete]
func (h *handler) Delete() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type detailRequest struct{}
type detailResponse struct{}
// Detail 个人信息
//
// @Summary 个人信息
// @Description 个人信息
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body detailRequest true "请求信息"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/info [get]
func (h *handler) Detail() core.HandlerFunc {
return func(ctx core.Context) {
}
}

26
internal/api/admin/func_list.go Executable file
View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type listRequest struct{}
type listResponse struct{}
// List 管理员列表
//
// @Summary 管理员列表
// @Description 管理员列表
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body listRequest true "请求信息"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin [get]
func (h *handler) List() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type listAdminMenuRequest struct{}
type listAdminMenuResponse struct{}
// ListAdminMenu 菜单授权列表
//
// @Summary 菜单授权列表
// @Description 菜单授权列表
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body listAdminMenuRequest true "请求信息"
// @Success 200 {object} listAdminMenuResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/menu/{id} [get]
func (h *handler) ListAdminMenu() core.HandlerFunc {
return func(ctx core.Context) {
}
}

154
internal/api/admin/func_login.go Executable file
View File

@@ -0,0 +1,154 @@
package admin
import (
"encoding/json"
"fmt"
"github.com/LLiuHuan/gin-template/configs"
"github.com/LLiuHuan/gin-template/internal/code"
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/pkg/password"
"github.com/LLiuHuan/gin-template/internal/pkg/validation"
"github.com/LLiuHuan/gin-template/internal/proposal"
"github.com/LLiuHuan/gin-template/internal/repository/redis"
"github.com/LLiuHuan/gin-template/internal/services/admin"
"github.com/LLiuHuan/gin-template/pkg/errors"
"net/http"
)
type loginRequest struct {
Username string `form:"username" json:"username" binding:"required"` // 用户名
Password string `form:"password" json:"password" binding:"min=4,max=16,required"` // 密码
}
type loginResponse struct {
Token string `json:"token"` // 用户身份标识
RefreshToken string `json:"refreshToken"` // 刷新token
}
// Login 管理员登录
//
// @Summary 管理员登录
// @Description 管理员登录
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body loginRequest true "请求信息"
// @Success 200 {object} loginResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/login [post]
//
// @Security LoginToken
func (h *handler) Login() core.HandlerFunc {
return func(ctx core.Context) {
req := new(loginRequest)
res := new(loginResponse)
if err := ctx.ShouldBindJSON(req); err != nil {
fmt.Println(err)
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).
WithError(validation.ErrorE(err)),
)
return
}
searchOneData := new(admin.SearchOneData)
searchOneData.Username = req.Username
searchOneData.Password = password.GeneratePassword(req.Password)
searchOneData.IsUsed = 1
info, err := h.adminService.Detail(ctx, searchOneData)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
if info == nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(errors.New("未查询出符合条件的用户")),
)
return
}
token := password.GenerateLoginToken(info.Id)
// 用户信息
sessionUserInfo := &proposal.SessionUserInfo{
UserID: info.Id,
UserName: info.Username,
}
// 将用户信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token, string(sessionUserInfo.Marshal()), configs.LoginSessionTTL, redis.WithTrace(ctx.Trace()))
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
searchMenuData := new(admin.SearchMyMenuData)
searchMenuData.AdminId = info.Id
menu, err := h.adminService.MyMenu(ctx, searchMenuData)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
// 菜单栏信息
menuJsonInfo, _ := json.Marshal(menu)
// 将菜单栏信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":menu", string(menuJsonInfo), configs.LoginSessionTTL, redis.WithTrace(ctx.Trace()))
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
searchActionData := new(admin.SearchMyActionData)
searchActionData.AdminId = info.Id
action, err := h.adminService.MyAction(ctx, searchActionData)
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
// 可访问接口信息
actionJsonInfo, _ := json.Marshal(action)
// 将可访问接口信息记录到 Redis 中
err = h.cache.Set(configs.RedisKeyPrefixLoginUser+token+":action", string(actionJsonInfo), configs.LoginSessionTTL, redis.WithTrace(ctx.Trace()))
if err != nil {
ctx.AbortWithError(core.Error(
http.StatusBadRequest,
code.AdminLoginError,
code.Text(code.AdminLoginError)).WithError(err),
)
return
}
res.Token = token
ctx.Payload(res)
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type logoutRequest struct{}
type logoutResponse struct{}
// Logout 管理员登出
//
// @Summary 管理员登出
// @Description 管理员登出
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body logoutRequest true "请求信息"
// @Success 200 {object} logoutResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/logout [post]
func (h *handler) Logout() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type modifyPasswordRequest struct{}
type modifyPasswordResponse struct{}
// ModifyPassword 修改密码
//
// @Summary 修改密码
// @Description 修改密码
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body modifyPasswordRequest true "请求信息"
// @Success 200 {object} modifyPasswordResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/modify_password [patch]
func (h *handler) ModifyPassword() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type modifyPersonalInfoRequest struct{}
type modifyPersonalInfoResponse struct{}
// ModifyPersonalInfo 修改个人信息
//
// @Summary 修改个人信息
// @Description 修改个人信息
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body modifyPersonalInfoRequest true "请求信息"
// @Success 200 {object} modifyPersonalInfoResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/modify_personal_info [patch]
func (h *handler) ModifyPersonalInfo() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type offlineRequest struct{}
type offlineResponse struct{}
// Offline 下线管理员
//
// @Summary 下线管理员
// @Description 下线管理员
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body offlineRequest true "请求信息"
// @Success 200 {object} offlineResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/offline [patch]
func (h *handler) Offline() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type resetPasswordRequest struct{}
type resetPasswordResponse struct{}
// ResetPassword 重置密码
//
// @Summary 重置密码
// @Description 重置密码
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body resetPasswordRequest true "请求信息"
// @Success 200 {object} resetPasswordResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/reset_password/{id} [patch]
func (h *handler) ResetPassword() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type updateUsedRequest struct{}
type updateUsedResponse struct{}
// UpdateUsed 更新管理员为启用/禁用
//
// @Summary 更新管理员为启用/禁用
// @Description 更新管理员为启用/禁用
// @Tags API.admin
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body updateUsedRequest true "请求信息"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/admin/used [patch]
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,105 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 09:47
package admin
import (
"github.com/LLiuHuan/gin-template/configs"
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/repository/database"
"github.com/LLiuHuan/gin-template/internal/repository/redis"
"github.com/LLiuHuan/gin-template/internal/services/admin"
"github.com/LLiuHuan/gin-template/pkg/hash"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
// Login 管理员登录
// @Tags API.admin
// @Router /api/v1/login [post]
Login() core.HandlerFunc
// Logout 管理员登出
// @Tags API.admin
// @Router /api/v1/admin/logout [post]
Logout() core.HandlerFunc
// ModifyPassword 修改密码
// @Tags API.admin
// @Router /api/v1/admin/modify_password [patch]
ModifyPassword() core.HandlerFunc
// Detail 个人信息
// @Tags API.admin
// @Router /api/v1/admin/info [get]
Detail() core.HandlerFunc
// ModifyPersonalInfo 修改个人信息
// @Tags API.admin
// @Router /api/v1/admin/modify_personal_info [patch]
ModifyPersonalInfo() core.HandlerFunc
// Create 新增管理员
// @Tags API.admin
// @Router /api/v1/admin [post]
Create() core.HandlerFunc
// List 管理员列表
// @Tags API.admin
// @Router /api/v1/admin [get]
List() core.HandlerFunc
// Delete 删除管理员
// @Tags API.admin
// @Router /api/v1/admin/{id} [delete]
Delete() core.HandlerFunc
// Offline 下线管理员
// @Tags API.admin
// @Router /api/v1/admin/offline [patch]
Offline() core.HandlerFunc
// UpdateUsed 更新管理员为启用/禁用
// @Tags API.admin
// @Router /api/v1/admin/used [patch]
UpdateUsed() core.HandlerFunc
// ResetPassword 重置密码
// @Tags API.admin
// @Router /api/v1/admin/reset_password/{id} [patch]
ResetPassword() core.HandlerFunc
// CreateAdminMenu 提交菜单授权
// @Tags API.admin
// @Router /api/v1/admin/menu [post]
CreateAdminMenu() core.HandlerFunc
// ListAdminMenu 菜单授权列表
// @Tags API.admin
// @Router /api/v1/admin/menu/{id} [get]
ListAdminMenu() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache redis.Repo
hashids hash.Hash
adminService admin.Service
}
func New(logger *zap.Logger, db database.Repo, cache redis.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
hashids: hash.New(configs.Get().HashIds.Alphabet, configs.Get().HashIds.MinLength, configs.Get().HashIds.BlockList),
adminService: admin.New(db, cache),
}
}
func (h *handler) i() {}

View File

@@ -31,15 +31,16 @@ type createResponse struct {
}
// Create 创建任务
// @Summary 创建任务
// @Description 创建任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [post]
//
// @Summary 创建任务
// @Description 创建任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [post]
func (h *handler) Create() core.HandlerFunc {
return func(ctx core.Context) {
req := new(createRequest)

View File

@@ -33,15 +33,16 @@ type detailResponse struct {
}
// Detail 获取单条任务详情
// @Summary 获取单条任务详情
// @Description 获取单条任务详情
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body detailRequest true "请求信息"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/{id} [get]
//
// @Summary 获取单条任务详情
// @Description 获取单条任务详情
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body detailRequest true "请求信息"
// @Success 200 {object} detailResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/{id} [get]
func (h *handler) Detail() core.HandlerFunc {
return func(ctx core.Context) {
req := new(detailRequest)

View File

@@ -19,15 +19,16 @@ type executeResponse struct {
}
// Execute 手动执行任务
// @Summary 手动执行任务
// @Description 手动执行任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body executeRequest true "请求信息"
// @Success 200 {object} executeResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/exec/{id} [patch]
//
// @Summary 手动执行任务
// @Description 手动执行任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body executeRequest true "请求信息"
// @Success 200 {object} executeResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/exec/{id} [patch]
func (h *handler) Execute() core.HandlerFunc {
return func(ctx core.Context) {
req := new(executeRequest)

View File

@@ -54,15 +54,16 @@ type listResponse struct {
}
// List 任务列表
// @Summary 任务列表
// @Description 任务列表
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body listRequest true "请求信息"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [get]
//
// @Summary 任务列表
// @Description 任务列表
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body listRequest true "请求信息"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron [get]
func (h *handler) List() core.HandlerFunc {
return func(ctx core.Context) {
req := new(listRequest)

View File

@@ -28,19 +28,20 @@ type modifyRequest struct {
}
type modifyResponse struct {
Id int32 `json:"id"` // 主键ID
Id int `json:"id"` // 主键ID
}
// Modify 编辑任务
// @Summary 编辑任务
// @Description 编辑任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body modifyRequest true "请求信息"
// @Success 200 {object} modifyResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/{id} [post]
//
// @Summary 编辑任务
// @Description 编辑任务
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body modifyRequest true "请求信息"
// @Success 200 {object} modifyResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/{id} [post]
func (h *handler) Modify() core.HandlerFunc {
return func(ctx core.Context) {
req := new(modifyRequest)
@@ -64,7 +65,7 @@ func (h *handler) Modify() core.HandlerFunc {
return
}
id := int32(ids[0])
id := int(ids[0])
modifyData := new(cron.ModifyCronTaskData)
modifyData.Name = req.Name

View File

@@ -18,15 +18,16 @@ type updateUsedResponse struct {
}
// UpdateUsed 更新任务为启用/禁用
// @Summary 更新任务为启用/禁用
// @Description 更新任务为启用/禁用
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body updateUsedRequest true "请求信息"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/used [patch]
//
// @Summary 更新任务为启用/禁用
// @Description 更新任务为启用/禁用
// @Tags API.cron
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body updateUsedRequest true "请求信息"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/cron/used [patch]
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(ctx core.Context) {
req := new(updateUsedRequest)

View File

@@ -20,15 +20,16 @@ type md5Response struct {
}
// Md5 加密
// @Summary 加密
// @Description 加密
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body md5Request true "请求信息"
// @Success 200 {object} md5Response
// @Failure 400 {object} code.Failure
// @Router /helper/md5/{str} [get]
//
// @Summary 加密
// @Description 加密
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body md5Request true "请求信息"
// @Success 200 {object} md5Response
// @Failure 400 {object} code.Failure
// @Router /helper/md5/{str} [get]
func (h *handler) Md5() core.HandlerFunc {
return func(ctx core.Context) {
req := new(md5Request)

View File

@@ -25,15 +25,16 @@ type signResponse struct {
}
// Sign 签名
// @Summary 签名
// @Description 签名
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body signRequest true "请求信息"
// @Success 200 {object} signResponse
// @Failure 400 {object} code.Failure
// @Router /helper/sign [post]
//
// @Summary 签名
// @Description 签名
// @Tags Helper
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body signRequest true "请求信息"
// @Success 200 {object} signResponse
// @Failure 400 {object} code.Failure
// @Router /helper/sign [post]
func (h *handler) Sign() core.HandlerFunc {
return func(ctx core.Context) {
req := new(signRequest)

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type clearCacheRequest struct{}
type clearCacheResponse struct{}
// ClearCache 清空缓存
//
// @Summary 清空缓存
// @Description 清空缓存
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body clearCacheRequest true "请求信息"
// @Success 200 {object} clearCacheResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/cache/clear [patch]
func (h *handler) ClearCache() core.HandlerFunc {
return func(ctx core.Context) {
}
}

26
internal/api/tool/func_dbs.go Executable file
View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type dbsRequest struct{}
type dbsResponse struct{}
// Dbs 查询 DB
//
// @Summary 查询 DB
// @Description 查询 DB
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body dbsRequest true "请求信息"
// @Success 200 {object} dbsResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/data/dbs [get]
func (h *handler) Dbs() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type hashIdsDecodeRequest struct{}
type hashIdsDecodeResponse struct{}
// HashIdsDecode HashIds 解密
//
// @Summary HashIds 解密
// @Description HashIds 解密
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body hashIdsDecodeRequest true "请求信息"
// @Success 200 {object} hashIdsDecodeResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/hashids/decode/{id} [get]
func (h *handler) HashIdsDecode() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type hashIdsEncodeRequest struct{}
type hashIdsEncodeResponse struct{}
// HashIdsEncode HashIds 加密
//
// @Summary HashIds 加密
// @Description HashIds 加密
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body hashIdsEncodeRequest true "请求信息"
// @Success 200 {object} hashIdsEncodeResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/hashids/encode/{id} [get]
func (h *handler) HashIdsEncode() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,123 @@
package tool
import (
"fmt"
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/LLiuHuan/gin-template/configs"
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/pkg/currency"
"github.com/LLiuHuan/gin-template/pkg/env"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v4/host"
"github.com/shirou/gopsutil/v4/mem"
"github.com/spf13/cast"
)
type projectInfoRequest struct{}
type projectInfoResponse struct {
MemTotal string // 内存总量
MemUsed string // 内存使用量
MemUsedPercent float64 // 内存使用率
DiskTotal string // 磁盘总量
DiskUsed string // 磁盘使用量
DiskUsedPercent float64 // 磁盘使用率
HostOS string // 操作系统
HostName string // 主机名
CpuName string // CPU 名称
CpuCores int32 // CPU 核数
CpuUsedPercent float64 // CPU 使用率
GoPath string // GoPath
GoVersion string // Go 版本
Goroutine int // Goroutine 数量
ProjectPath string // 项目路径
Env string // 运行环境
Host string // 主机地址
GoOS string // GoOS
GoArch string // GoArch
ProjectVersion string // 项目版本
DatabaseVersion string // 数据库版本
RedisVersion string // Redis 版本
}
// ProjectInfo 项目基础信息
//
// @Summary 项目基础信息
// @Description 项目基础信息
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body projectInfoRequest true "请求信息"
// @Success 200 {object} projectInfoResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/project/info [get]
func (h *handler) ProjectInfo() core.HandlerFunc {
type mysqlVersion struct {
Ver string
}
databaseVer := new(mysqlVersion)
if h.db != nil {
h.db.GetDB().Raw("SELECT version() as ver").Scan(databaseVer)
}
redisVer := ""
if h.cache != nil {
redisVer = h.cache.Version()
}
return func(ctx core.Context) {
memInfo, _ := mem.VirtualMemory()
diskInfo, _ := disk.Usage("/")
hostInfo, _ := host.Info()
cpuInfo, _ := cpu.Info()
cpuPercent, _ := cpu.Percent(time.Microsecond, false)
obj := new(projectInfoResponse)
obj.MemTotal = currency.FormatFileSize(cast.ToInt64(memInfo.Total))
obj.MemUsed = currency.FormatFileSize(cast.ToInt64(memInfo.Used))
obj.MemUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", memInfo.UsedPercent), 64)
obj.DiskTotal = currency.FormatFileSize(cast.ToInt64(diskInfo.Total))
obj.DiskUsed = currency.FormatFileSize(cast.ToInt64(diskInfo.Used))
obj.DiskUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", diskInfo.UsedPercent), 64)
obj.HostOS = fmt.Sprintf("%s(%s) %s", hostInfo.Platform, hostInfo.PlatformFamily, hostInfo.PlatformVersion)
obj.HostName = hostInfo.Hostname
if len(cpuInfo) > 0 {
obj.CpuName = cpuInfo[0].ModelName
obj.CpuCores = cpuInfo[0].Cores
}
if len(cpuPercent) > 0 {
obj.CpuUsedPercent, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", cpuPercent[0]), 64)
}
obj.GoPath = runtime.GOROOT()
obj.GoVersion = runtime.Version()
obj.Goroutine = runtime.NumGoroutine()
dir, _ := os.Getwd()
obj.ProjectPath = strings.Replace(dir, "\\", "/", -1)
obj.Host = ctx.Host()
obj.Env = env.Active().Value()
obj.GoOS = runtime.GOOS
obj.GoArch = runtime.GOARCH
obj.ProjectVersion = configs.ProjectVersion
obj.DatabaseVersion = databaseVer.Ver
obj.RedisVersion = redisVer
ctx.Payload(obj)
}
}

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type searchCacheRequest struct{}
type searchCacheResponse struct{}
// SearchCache 查询缓存
//
// @Summary 查询缓存
// @Description 查询缓存
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body searchCacheRequest true "请求信息"
// @Success 200 {object} searchCacheResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/cache/search [post]
func (h *handler) SearchCache() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type searchMySQLRequest struct{}
type searchMySQLResponse struct{}
// SearchMySQL 执行 SQL 语句
//
// @Summary 执行 SQL 语句
// @Description 执行 SQL 语句
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body searchMySQLRequest true "请求信息"
// @Success 200 {object} searchMySQLResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/data/mysql [post]
func (h *handler) SearchMySQL() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -0,0 +1,26 @@
package tool
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
)
type tablesRequest struct{}
type tablesResponse struct{}
// Tables 查询 Table
//
// @Summary 查询 Table
// @Description 查询 Table
// @Tags API.tool
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body tablesRequest true "请求信息"
// @Success 200 {object} tablesResponse
// @Failure 400 {object} code.Failure
// @Router /api/v1/tool/data/tables [post]
func (h *handler) Tables() core.HandlerFunc {
return func(ctx core.Context) {
}
}

View File

@@ -1,8 +1,9 @@
// Package code
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:43
// @description: 英文错误码
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:43
// @description: 英文错误码
package code
var enUSText = map[int]string{

View File

@@ -1,8 +1,9 @@
// Package code
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:43
// @description: 中文错误码
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:43
// @description: 中文错误码
package code
var zhCNText = map[int]string{

View File

@@ -1,8 +1,9 @@
// Package metrics
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:45
// @description: 指标
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 22:45
// @description: 指标
package metrics
import (

View File

@@ -1,8 +1,9 @@
// Package core
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:28
// @description: 跨域请求处理
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:28
// @description: 跨域请求处理
package core
import (

View File

@@ -1,8 +1,9 @@
// Package core
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:31
// @description: 恢复panic
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:31
// @description: 恢复panic
package core
import (

View File

@@ -1,8 +1,9 @@
// Package core
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:34
// @description: 链路追踪
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 17:34
// @description: 链路追踪
package core
import (

View File

@@ -1,8 +1,9 @@
// Package core
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 14:36
// @description: 多路复用器
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 14:36
// @description: 多路复用器
package core
import (

View File

@@ -14,6 +14,7 @@ import (
"github.com/LLiuHuan/gin-template/pkg/env"
"github.com/LLiuHuan/gin-template/pkg/errors"
_ "github.com/LLiuHuan/gin-template/docs"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus/promhttp"

View File

@@ -27,7 +27,6 @@ func GeneratePassword(str string) (password string) {
h := hmac.New(sha256.New, []byte(saltPassword))
h.Write(mByte)
password = hex.EncodeToString(h.Sum(nil))
return
}
@@ -41,7 +40,7 @@ func ResetPassword() (password string) {
return
}
func GenerateLoginToken(id int32) (token string) {
func GenerateLoginToken(id int) (token string) {
m := md5.New()
m.Write([]byte(fmt.Sprintf("%d%s", id, saltPassword)))
token = hex.EncodeToString(m.Sum(nil))

View File

@@ -5,6 +5,7 @@
package validation
import (
"errors"
"fmt"
"github.com/LLiuHuan/gin-template/configs"
@@ -22,7 +23,6 @@ var trans ut.Translator
func init() {
lang := configs.Get().Project.Local
fmt.Println(lang, lang == configs.ZhCN)
if lang == configs.ZhCN {
trans, _ = ut.New(zh.New()).GetTranslator("zh")
if err := zhTranslation.RegisterDefaultTranslations(binding.Validator.Engine().(*validator.Validate), trans); err != nil {
@@ -38,13 +38,22 @@ func init() {
}
}
func Error(err error) (message string) {
if validationErrors, ok := err.(validator.ValidationErrors); !ok {
func validationError(err error) string {
var message string
var validationErrors validator.ValidationErrors
if !errors.As(err, &validationErrors) {
return err.Error()
} else {
for _, e := range validationErrors {
message += e.Translate(trans) + ";"
}
}
for _, e := range validationErrors {
message += e.Translate(trans) + ";"
}
return message
}
func ErrorE(err error) error {
return errors.New(validationError(err))
}
func Error(err error) (message string) {
return validationError(err)
}

View File

@@ -1,8 +1,9 @@
// Package proposal
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:40
// @description: 告警信息
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:40
// @description: 告警信息
package proposal
import (

View File

@@ -1,8 +1,9 @@
// Package proposal
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:41
// @description: 指标信息
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:41
// @description: 指标信息
package proposal
import "encoding/json"

View File

@@ -1,8 +1,9 @@
// Package proposal
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:41
// @description: 用户会话信息
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:41
// @description: 用户会话信息
package proposal
import "encoding/json"

View File

@@ -6,6 +6,7 @@ package database
import (
"fmt"
"gorm.io/gorm/schema"
"strings"
"time"
@@ -110,6 +111,9 @@ func getDBDriver(mode string, isOpenReadDB int) (*gorm.DB, error) {
gormDB, err := gorm.Open(dialector, &gorm.Config{
SkipDefaultTransaction: true,
PrepareStmt: true,
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
return nil, err
@@ -183,7 +187,7 @@ func getDsn(sqlType string, readWrite string) string {
if Charset == "" {
Charset = "utf8mb4"
}
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=false&loc=Local", User, Pass, Host, Port, DataBase, Charset)
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=Local", User, Pass, Host, Port, DataBase, Charset)
case "sqlserver", "mssql":
return fmt.Sprintf("server=%s;port=%d;database=%s;user id=%s;password=%s;encrypt=disable", Host, Port, DataBase, User, Pass)
case "postgresql", "postgre", "postgres":

View File

@@ -1,7 +1,8 @@
// Package database
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 10:19
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 10:19
package database
import (
@@ -231,8 +232,9 @@ func structHasSpecialField(fieldName string, anyStructPtr interface{}) (bool, st
}
// getColumnNameFromGormTag 从 gorm 标签中获取字段名
// @defaultColumn 如果没有 gormcolumn 标签为字段重命名,则使用默认字段名
// @TagValue 字段中含有的gorm"column:created_at" 标签值可能的格式1. column:created_at 、2. default:null; column:created_at 、3. column:created_at; default:null
//
// @defaultColumn 如果没有 gormcolumn 标签为字段重命名,则使用默认字段名
// @TagValue 字段中含有的gorm"column:created_at" 标签值可能的格式1. column:created_at 、2. default:null; column:created_at 、3. column:created_at; default:null
func getColumnNameFromGormTag(defaultColumn, TagValue string) (str string) {
pos1 := strings.Index(TagValue, "column:")
if pos1 == -1 {

View File

@@ -1,8 +1,9 @@
// Package interceptor
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 登录拦截器
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 登录拦截器
package interceptor
import (

View File

@@ -1,8 +1,9 @@
// Package interceptor
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 校验用户权限
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 校验用户权限
package interceptor
import (

View File

@@ -1,8 +1,9 @@
// Package interceptor
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 校验签名
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:00
// @description: 校验签名
package interceptor
import (

View File

@@ -5,6 +5,7 @@
package router
import (
"github.com/LLiuHuan/gin-template/internal/api/admin"
"github.com/LLiuHuan/gin-template/internal/api/helper"
"github.com/LLiuHuan/gin-template/internal/api/tool"
"github.com/LLiuHuan/gin-template/internal/pkg/core"
@@ -14,6 +15,7 @@ func setApiV1Router(r *resource) {
// helper
helperHandler := helper.New(r.logger, r.db, r.cache)
toolHandler := tool.New(r.logger, r.db, r.cache)
adminHandler := admin.New(r.logger, r.db, r.cache)
apiRouter := r.mux.Group("/api/v1")
{
@@ -41,16 +43,12 @@ func setApiV1Router(r *resource) {
// }
//}
}
// 需要签名验证,无需登录验证,无需 RBAC 权限验证
login := r.mux.Group("/api/v1", r.interceptors.CheckSignature())
{
login.POST("/login", adminHandler.Login())
}
//// admin
//adminHandler := admin.New(r.logger, r.db, r.cache)
//
//// 需要签名验证,无需登录验证,无需 RBAC 权限验证
//login := r.mux.Group("/api", r.interceptors.CheckSignature())
//{
// login.POST("/login", adminHandler.Login())
//}
//
//// 需要签名验证、登录验证,无需 RBAC 权限验证
//notRBAC := r.mux.Group("/api", core.WrapAuthHandler(r.interceptors.CheckLogin), r.interceptors.CheckSignature())
//{

View File

@@ -0,0 +1,47 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 09:47
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/repository/database"
"github.com/LLiuHuan/gin-template/internal/repository/database/admin"
"github.com/LLiuHuan/gin-template/internal/repository/redis"
)
var _ Service = (*service)(nil)
type Service interface {
i()
//Create(ctx core.Context, adminData *CreateAdminData) (id int32, err error)
//PageList(ctx core.Context, searchData *SearchData) (listData []*admin.Admin, err error)
//PageListCount(ctx core.Context, searchData *SearchData) (total int64, err error)
//UpdateUsed(ctx core.Context, id int32, used int32) (err error)
//Delete(ctx core.Context, id int32) (err error)
Detail(ctx core.Context, searchOneData *SearchOneData) (info *admin.Admin, err error)
//ResetPassword(ctx core.Context, id int32) (err error)
//ModifyPassword(ctx core.Context, id int32, newPassword string) (err error)
//ModifyPersonalInfo(ctx core.Context, id int32, modifyData *ModifyData) (err error)
//CreateMenu(ctx core.Context, menuData *CreateMenuData) (err error)
//ListMenu(ctx core.Context, searchData *SearchListMenuData) (menuData []ListMenuData, err error)
MyMenu(ctx core.Context, searchData *SearchMyMenuData) (menuData []ListMyMenuData, err error)
MyAction(ctx core.Context, searchData *SearchMyActionData) (actionData []MyActionData, err error)
}
type service struct {
db database.Repo
cache redis.Repo
}
func New(db database.Repo, cache redis.Repo) Service {
return &service{
db: db,
cache: cache,
}
}
func (s *service) i() {}

View File

@@ -0,0 +1,57 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 10:03
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/repository/database"
"github.com/LLiuHuan/gin-template/internal/repository/database/admin"
)
type SearchOneData struct {
Id int // 用户ID
Username string // 用户名
Nickname string // 昵称
Mobile string // 手机号
Password string // 密码
IsUsed int32 // 是否启用 1:是 -1:否
}
func (s *service) Detail(ctx core.Context, searchOneData *SearchOneData) (info *admin.Admin, err error) {
qb := admin.NewQueryBuilder()
qb.WhereIsDeleted(database.EqualPredicate, -1)
if searchOneData.Id != 0 {
qb.WhereId(database.EqualPredicate, searchOneData.Id)
}
if searchOneData.Username != "" {
qb.WhereUsername(database.EqualPredicate, searchOneData.Username)
}
if searchOneData.Nickname != "" {
qb.WhereNickname(database.EqualPredicate, searchOneData.Nickname)
}
if searchOneData.Mobile != "" {
qb.WhereMobile(database.EqualPredicate, searchOneData.Mobile)
}
if searchOneData.Password != "" {
qb.WherePassword(database.EqualPredicate, searchOneData.Password)
}
if searchOneData.IsUsed != 0 {
qb.WhereIsUsed(database.EqualPredicate, searchOneData.IsUsed)
}
info, err = qb.QueryOne(s.db.GetDB().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
return
}

View File

@@ -0,0 +1,73 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 10:00
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/repository/database"
"github.com/LLiuHuan/gin-template/internal/repository/database/admin_menu"
"github.com/LLiuHuan/gin-template/internal/repository/database/menu_action"
)
type SearchMyActionData struct {
AdminId int `json:"admin_id"` // 管理员ID
}
type MyActionData struct {
Id int // 主键
MenuId int // 菜单栏ID
Method string // 请求方式
Api string // 请求地址
}
func (s *service) MyAction(ctx core.Context, searchData *SearchMyActionData) (actionData []MyActionData, err error) {
adminMenuQb := admin_menu.NewQueryBuilder()
if searchData.AdminId != 0 {
adminMenuQb.WhereAdminId(database.EqualPredicate, searchData.AdminId)
}
adminMenuListData, err := adminMenuQb.
OrderById(false).
QueryAll(s.db.GetDB().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
if len(adminMenuListData) <= 0 {
return
}
var menuIds []int
for _, v := range adminMenuListData {
menuIds = append(menuIds, v.MenuId)
}
actionQb := menu_action.NewQueryBuilder()
actionQb.WhereIsDeleted(database.EqualPredicate, -1)
actionQb.WhereMenuIdIn(menuIds)
actionListData, err := actionQb.QueryAll(s.db.GetDB().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
if len(actionListData) <= 0 {
return
}
actionData = make([]MyActionData, len(actionListData))
for k, v := range actionListData {
data := MyActionData{
Id: v.Id,
MenuId: v.MenuId,
Method: v.Method,
Api: v.Api,
}
actionData[k] = data
}
return
}

View File

@@ -1,16 +0,0 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-03 15:02
package admin
type SearchMyActionData struct {
AdminId int `json:"admin_id"` // 管理员ID
}
type MyActionData struct {
Id int // 主键
MenuId int // 菜单栏ID
Method string // 请求方式
Api string // 请求地址
}

View File

@@ -0,0 +1,73 @@
// Package admin
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 15:07
package admin
import (
"github.com/LLiuHuan/gin-template/internal/pkg/core"
"github.com/LLiuHuan/gin-template/internal/repository/database"
"github.com/LLiuHuan/gin-template/internal/repository/database/admin_menu"
"github.com/LLiuHuan/gin-template/internal/repository/database/menu"
)
type SearchMyMenuData struct {
AdminId int `json:"admin_id"` // 管理员ID
}
type ListMyMenuData struct {
Id int `json:"id"` // ID
Pid int `json:"pid"` // 父类ID
Name string `json:"name"` // 菜单名称
Link string `json:"link"` // 链接地址
Icon string `json:"icon"` // 图标
}
func (s *service) MyMenu(ctx core.Context, searchData *SearchMyMenuData) (menuData []ListMyMenuData, err error) {
adminMenuQb := admin_menu.NewQueryBuilder()
if searchData.AdminId != 0 {
adminMenuQb.WhereAdminId(database.EqualPredicate, searchData.AdminId)
}
adminMenuListData, err := adminMenuQb.
OrderById(false).
QueryAll(s.db.GetDB().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
if len(adminMenuListData) <= 0 {
return
}
menuQb := menu.NewQueryBuilder()
menuQb.WhereIsDeleted(database.EqualPredicate, -1)
menuListData, err := menuQb.
OrderBySort(true).
QueryAll(s.db.GetDB().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
if len(menuListData) <= 0 {
return
}
for _, menuAllV := range menuListData {
for _, v := range adminMenuListData {
if menuAllV.Id == v.MenuId {
data := ListMyMenuData{
Id: menuAllV.Id,
Pid: menuAllV.Pid,
Name: menuAllV.Name,
Link: menuAllV.Link,
Icon: menuAllV.Icon,
}
menuData = append(menuData, data)
}
}
}
return
}

View File

@@ -40,15 +40,16 @@ type installRequest struct {
type installResponse struct{}
// Install 安装
// @Summary 安装
// @Description 安装
// @Tags API.install
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body installRequest true "请求信息"
// @Success 200 {object} installResponse
// @Failure 400 {object} code.Failure
// @Router /v1/api/install [post]
//
// @Summary 安装
// @Description 安装
// @Tags API.install
// @Accept application/x-www-form-urlencoded
// @Produce json
// @Param Request body installRequest true "请求信息"
// @Success 200 {object} installResponse
// @Failure 400 {object} code.Failure
// @Router /v1/api/install [post]
func (h *handler) Install() core.HandlerFunc {
installTableList := map[string]map[string]string{
"authorized": {

29
main.go
View File

@@ -1,7 +1,8 @@
// Package gin_template
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 18:07
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 18:07
package main
import (
@@ -25,20 +26,20 @@ func init() {
}
// @title swagger 接口文档
// @version 2.0
// @description
// @title swagger 接口文档
// @version 2.0
// @description
// @contact.name
// @contact.url
// @contact.email
// @contact.name
// @contact.url
// @contact.email
// @license.name MIT
// @license.url https://github.com/LLiuHuan/gin-template/blob/master/LICENSE
// @license.name MIT
// @license.url https://github.com/LLiuHuan/gin-template/blob/master/LICENSE
// @securityDefinitions.apikey LoginToken
// @in header
// @name token
// @securityDefinitions.apikey LoginToken
// @in header
// @name token
func main() {
accessLogger, err := logger.NewJSONLogger(
logger.WithDisableConsole(),

View File

@@ -1,8 +1,9 @@
// Package browser
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:53
// @description: 使用浏览器打开指定的 URL
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:53
// @description: 使用浏览器打开指定的 URL
package browser
import (

View File

@@ -1,10 +1,11 @@
//go:build darwin
// Package color
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:54
// @description: Darwin颜色
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:54
// @description: Darwin颜色
package color
import (

View File

@@ -1,10 +1,11 @@
//go:build linux
// Package color
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:54
// @description: Linux颜色
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:54
// @description: Linux颜色
package color
import (

View File

@@ -1,10 +1,11 @@
//go:build windows
// Package color
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:55
// @description: Windows颜色
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:55
// @description: Windows颜色
package color
import (

View File

@@ -6,74 +6,171 @@ package currency
import (
"fmt"
"math"
"strconv"
"strings"
)
// FormatFileSize 字节的单位转换 保留两位小数
func FormatFileSize(fileSize int64) (size string) {
if fileSize < 1<<10 {
//return strconv.FormatInt(fileSize, 10) + "B"
return fmt.Sprintf("%.2f B", float64(fileSize)/float64(1))
} else if fileSize < 1<<20 {
return fmt.Sprintf("%.2f KB", float64(fileSize)/float64(1<<10))
} else if fileSize < 1<<30 {
return fmt.Sprintf("%.2f MB", float64(fileSize)/float64(1<<20))
} else if fileSize < 1<<40 {
return fmt.Sprintf("%.2f GB", float64(fileSize)/float64(1<<30))
} else if fileSize < 1<<50 {
return fmt.Sprintf("%.2f TB", float64(fileSize)/float64(1<<40))
} else if fileSize < 1<<60 {
return fmt.Sprintf("%.2f EB", float64(fileSize)/float64(1<<50))
} else { //if fileSize < (1000 * 1000 * 1000 * 1000 * 1000 * 1000)
return fmt.Sprintf("%.2f ZB", float64(fileSize)/float64(1<<60))
// FormatFileSize 字节的单位转换 保留两位小数, 基数是1024
func FormatFileSize(fileSize int64) string {
units := []struct {
threshold int64
format string
}{
{1 << 10, "%.2f B"},
{1 << 20, "%.2f KB"},
{1 << 30, "%.2f MB"},
{1 << 40, "%.2f GB"},
{1 << 50, "%.2f TB"},
{1 << 60, "%.2f EB"},
{math.MaxInt64, "%.2f ZB"},
}
var unit string
var value float64
for _, u := range units {
if fileSize < u.threshold {
unit = u.format
value = float64(fileSize) / float64(u.threshold>>10)
break
}
}
return strings.ReplaceAll(fmt.Sprintf(unit, value), ".00", "")
}
// ReversalFileSize 字节的单位转换 保留两位小数
func ReversalFileSize(fileSize string) (size float64) {
if strings.HasSuffix(fileSize, "KB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "KB", "", -1), 64)
if err != nil {
return 0
units := []struct {
suffix string
multiplier float64
}{
{"KB", float64(1 << 10)},
{"MB", float64(1 << 20)},
{"GB", float64(1 << 30)},
{"TB", float64(1 << 40)},
{"EB", float64(1 << 50)},
{"ZB", float64(1 << 60)},
{"B", float64(1)},
}
for _, unit := range units {
if strings.HasSuffix(fileSize, unit.suffix) {
value, err := strconv.ParseFloat(strings.TrimSpace(strings.TrimSuffix(fileSize, unit.suffix)), 64)
if err != nil {
return 0
}
size = value * unit.multiplier
break
}
size = float * float64(1<<10)
} else if strings.HasSuffix(fileSize, "MB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "MB", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1<<20)
} else if strings.HasSuffix(fileSize, "GB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "GB", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1<<30)
} else if strings.HasSuffix(fileSize, "TB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "TB", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1<<40)
} else if strings.HasSuffix(fileSize, "EB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "EB", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1<<50)
} else if strings.HasSuffix(fileSize, "ZB") {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "ZB", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1<<60)
} else {
float, err := strconv.ParseFloat(strings.Replace(fileSize, "B", "", -1), 64)
if err != nil {
return 0
}
size = float * float64(1)
}
return size / float64(1<<20)
}
// ReversalFileSize 字节的单位转换 保留两位小数
//func ReversalFileSize(fileSize string) (size float64) {
// if strings.HasSuffix(fileSize, "KB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "KB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<10)
// } else if strings.HasSuffix(fileSize, "MB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "MB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<20)
// } else if strings.HasSuffix(fileSize, "GB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "GB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<30)
// } else if strings.HasSuffix(fileSize, "TB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "TB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<40)
// } else if strings.HasSuffix(fileSize, "EB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "EB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<50)
// } else if strings.HasSuffix(fileSize, "ZB") {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "ZB", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1<<60)
// } else {
// float, err := strconv.ParseFloat(strings.Replace(fileSize, "B", "", -1), 64)
// if err != nil {
// return 0
// }
// size = float * float64(1)
// }
// return size / float64(1<<20)
//}
const (
UnitWan = "万"
UnitQianWan = "千万"
UnitYi = "亿"
UnitBaiYi = "百亿"
UnitQianYi = "千亿"
UnitWanYi = "万亿"
)
func SimplifyNum(num float64, suffix string) string {
units := []struct {
threshold float64
unit string
}{
{1e12, UnitWanYi},
{1e11, UnitQianYi},
{1e10, UnitBaiYi},
{1e8, UnitYi},
{1e7, UnitQianWan},
{1e4, UnitWan},
}
num = math.Round(num*100) / 100
if num == 0 {
return "0"
}
for _, u := range units {
if num >= u.threshold {
return strings.ReplaceAll(fmt.Sprintf("%.3f %s%s", num/u.threshold, u.unit, suffix), ".000", "")
}
}
return strings.ReplaceAll(fmt.Sprintf("%.3f %s", num, suffix), ".000", "")
}
//func SimplifyNum(num float64, suffix string) string {
// // 保留两位小数
// num = math.Round(num*100) / 100
// if num <= 0 {
// return "0"
// } else if num >= 1000 && num < 1000000 {
// return fmt.Sprintf("%.3f 万%s", num/10000, suffix)
// } else if num >= 10000000 && num < 100000000 {
// return fmt.Sprintf("%.3f 千万%s", num/10000000, suffix)
// } else if num >= 100000000 && num < 10000000000 {
// return fmt.Sprintf("%.3f 亿%s", num/100000000, suffix)
// } else if num >= 10000000000 && num < 100000000000 {
// return fmt.Sprintf("%.3f 百亿%s", num/10000000000, suffix)
// } else if num >= 100000000000 && num < 1000000000000 {
// return fmt.Sprintf("%.3f 千亿%s", num/100000000000, suffix)
// } else if num >= 1000000000000 && num < 10000000000000 {
// return fmt.Sprintf("%.3f 万亿%s", num/1000000000000, suffix)
// } else {
// return fmt.Sprintf("%f%s", num, suffix)
// }
//}

View File

@@ -0,0 +1,73 @@
// Package currency
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-09 11:04
package currency
import (
"testing"
)
func TestSimplifyNum(t *testing.T) {
// 生成一个单元测试
if num := SimplifyNum(1, "元"); num != "1 元" {
t.Errorf("Expected 1 元, but got %s", num)
}
if num := SimplifyNum(100, "元"); num != "100 元" {
t.Errorf("Expected 100 元, but got %s", num)
}
if num := SimplifyNum(1000, "元"); num != "1000 元" {
t.Errorf("Expected 1000 元, but got %s", num)
}
if num := SimplifyNum(10000, "元"); num != "1 万元" {
t.Errorf("Expected 1 万元, but got %s", num)
}
if num := SimplifyNum(100000, "元"); num != "10 万元" {
t.Errorf("Expected 10 万元, but got %s", num)
}
if num := SimplifyNum(140312310, "元"); num != " 1.403 亿元" {
t.Errorf("Expected 1.403 亿元, but got %s", num)
}
if num := SimplifyNum(10000000, "元"); num != "1 千万元" {
t.Errorf("Expected 1 千万元, but got %s", num)
}
}
func TestFormatFileSize(t *testing.T) {
result := FormatFileSize(1)
if result != "1 B" {
t.Errorf("Expected 1B, but got %s", result)
}
result = FormatFileSize(1 << 10)
if result != "1 KB" {
t.Errorf("Expected 1KB, but got %s", result)
}
result = FormatFileSize(1 << 20)
if result != "1 MB" {
t.Errorf("Expected 1MB, but got %s", result)
}
result = FormatFileSize(1 << 30)
if result != "1 GB" {
t.Errorf("Expected 1GB, but got %s", result)
}
result = FormatFileSize(1 << 40)
if result != "1 TB" {
t.Errorf("Expected 1TB, but got %s", result)
}
//result = FormatFileSize(48712831672)
//t.Log(result)
}
func TestReversalFileSize(t *testing.T) {
result := ReversalFileSize("100 GB")
t.Log(result)
//if result != 5000 {
// t.Errorf("Expected 5000, but got %f", result)
//}
}

View File

@@ -1,8 +1,9 @@
// Package database
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:56
// @description: 数据库
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:56
// @description: 数据库
package database
import (

View File

@@ -1,8 +1,9 @@
// Package file
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:57
// @description: 文件操作
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:57
// @description: 文件操作
package file
import (

View File

@@ -1,8 +1,9 @@
// Package trace
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:40
// @description: 链路追踪
//
// @program: gin-template
// @author: [lliuhuan](https://github.com/lliuhuan)
// @create: 2024-07-02 21:40
// @description: 链路追踪
package trace
import (