作者 yangfu

项目初始化

正在显示 75 个修改的文件 包含 3948 行增加0 行删除
  1 +# Compiled Object codefiles, Static and Dynamic libs (Shared Objects)
  2 +*.o
  3 +*.a
  4 +*.so
  5 +
  6 +# Folders
  7 +_obj
  8 +_test
  9 +
  10 +# Architecture specific extensions/prefixes
  11 +*.[568vq]
  12 +[568vq].out
  13 +
  14 +*.cgo1.go
  15 +*.cgo2.c
  16 +_cgo_defun.c
  17 +_cgo_gotypes.go
  18 +_cgo_export.*
  19 +
  20 +_testmain.go
  21 +
  22 +*.exe
  23 +*.test
  24 +.log
  25 +.idea
  26 +.vscode
  27 +.gitkeep
  28 +
  29 +app.log
  30 +go.sum
  31 +lastupdate.tmp
  32 +*.log
  33 +
  34 +public/*
  35 +logs/
  36 +cmd/discuss/api/etc/core.local.yaml
  1 +.PHONY: bsi-model
  2 +bsi-model:
  3 + goctl model mysql ddl -s .\cmd\bsi\deploy\database\table.sql -d cmd/bsi
  4 +
  5 +.PHONY: bsi-api
  6 +bsi-api:
  7 + goctl api go -api .\cmd\bsi\api\dsl\core.api -dir cmd/bsi/api -style go_zero
  8 +
  9 +.PHONY: bsi-swagger
  10 +bsi-swagger:
  11 + goctl api plugin -plugin goctl-swagger="swagger -filename core.json" -api .\cmd\bsi\api\dsl\core.api -dir .\cmd\discuss\api\dsl
  12 +
  13 +.PHONY: bsi-build
  14 +bsi-build:
  15 + docker build -f cmd/bsi/deploy/docker/Dockerfile -t sumifcc/bsi:1.0.0 .
  1 +package main
  2 +
  3 +import (
  4 + "flag"
  5 + "fmt"
  6 + "github.com/zeromicro/go-zero/core/logx"
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/interanl/pkg/db"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/interanl/pkg/domain"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/xerr"
  11 + "net/http"
  12 + "strings"
  13 +
  14 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/config"
  15 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/handler"
  16 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  17 +
  18 + "github.com/golang-jwt/jwt/v4/request"
  19 + "github.com/zeromicro/go-zero/core/conf"
  20 + "github.com/zeromicro/go-zero/rest"
  21 +)
  22 +
  23 +var configFile = flag.String("f", "etc/core.yaml", "the config file")
  24 +
  25 +func main() {
  26 + flag.Parse()
  27 +
  28 + var c config.Config
  29 + conf.MustLoad(*configFile, &c)
  30 +
  31 + // 系统设置
  32 + systemSetup(c)
  33 +
  34 + // 服务初始化
  35 + opts := make([]rest.RunOption, 0)
  36 + opts = append(opts, rest.WithCustomCors(func(header http.Header) {
  37 + header.Set("Access-Control-Allow-Headers", "*")
  38 + }, func(writer http.ResponseWriter) {
  39 +
  40 + }))
  41 + opts = append(opts, rest.WithUnauthorizedCallback(func(w http.ResponseWriter, r *http.Request, err error) {
  42 + if err != nil {
  43 + logx.Debugf("unauthorized: %s \n", err.Error())
  44 + }
  45 + }))
  46 +
  47 + server := rest.MustNewServer(c.RestConf, opts...)
  48 + defer server.Stop()
  49 +
  50 + ctx := svc.NewServiceContext(c)
  51 + handler.RegisterHandlers(server, ctx)
  52 +
  53 + // 数据迁移
  54 + if c.Migrate {
  55 + db.Migrate(ctx.DB)
  56 + }
  57 +
  58 + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
  59 + server.Start()
  60 +}
  61 +
  62 +func systemSetup(c config.Config) {
  63 + // 初始化Domain里面的配置
  64 + domain.ProjectName = c.Name
  65 +
  66 + // 默认的token头 Authorization 修改为 x-mmm-accesstoken
  67 + request.AuthorizationHeaderExtractor = &request.PostExtractionFilter{
  68 + Extractor: request.HeaderExtractor{"x-mmm-accesstoken"},
  69 + Filter: func(tok string) (string, error) {
  70 + // Should be a bearer token
  71 + if len(tok) > 6 && strings.ToUpper(tok[0:7]) == "BEARER " {
  72 + return tok[7:], nil
  73 + }
  74 + return tok, nil
  75 + },
  76 + }
  77 +
  78 + // 系统错误应答包装
  79 + httpx.SetErrorHandlerCtx(xerr.ErrorHandlerCtx)
  80 +
  81 + // 系统成功应答包装
  82 + httpx.SetOkHandler(xerr.OkHandlerCtx)
  83 +}
  1 +syntax = "v1"
  2 +
  3 +import "core/common.api"
  4 +import "core/screen.api"
  1 + // 通用接口
  2 + @server(
  3 + prefix: v1
  4 + group: common
  5 + )
  6 + service Core {
  7 + @doc "日志查询"
  8 + @handler commonGetLog
  9 + get /log/:module
  10 + }
  11 +
  12 + // 通用接口
  13 + @server(
  14 + prefix: v1
  15 + middleware: LogRequest
  16 + group: common
  17 + )
  18 + service Core {
  19 + @doc "短信验证码"
  20 + @handler commonSmsCode
  21 + post /common/sms/code (CommonSmsCodeRequest) returns (CommonSmsCodeResposne)
  22 +
  23 + @doc "微信二维码"
  24 + @handler miniQrcodeInvite
  25 + post /mini/qrcode (MiniQrCodeRequest)
  26 +
  27 + @doc "清理缓存"
  28 + @handler commonGetClearCache
  29 + get /clear
  30 + }
  31 +
  32 + // 短信验证码
  33 + type(
  34 + CommonSmsCodeRequest{
  35 + Phone string `json:"phone"`
  36 + }
  37 + CommonSmsCodeResposne{
  38 +
  39 + }
  40 + )
  41 +
  42 + type(
  43 + MiniQrCodeRequest{
  44 + Page string `json:"page"` // 微信页面入口
  45 + Scene string `json:"scene"` // 参数
  46 + }
  47 + )
  1 +syntax = "v1"
  2 +
  3 +info(
  4 + title: "易数家显示大屏互动服务"
  5 + desc: "易数家显示大屏互动服务 BSI(Big screen interaction)"
  6 + author: "bsi"
  7 + email: "bsi@gmail.com"
  8 + version: "v1"
  9 +)
  10 +
  11 +// H5接口
  12 +@server(
  13 + prefix: v1/h5
  14 + group: todo
  15 + middleware: LogRequest
  16 + //jwt: MiniAuth
  17 +)
  18 +service Core {
  19 + @doc ""
  20 + @handler H5Todo
  21 + get /todo
  22 + @doc ""
  23 + @handler H5TodoErrorCommon
  24 + get /todo/err1 returns(TodoResonse)
  25 + @doc ""
  26 + @handler H5TodoErrorInternal
  27 + get /todo/err2 returns(TodoResonse)
  28 + @doc ""
  29 + @handler H5TodoErrorGrpc
  30 + get /todo/err3 returns(TodoResonse)
  31 +}
  32 +
  33 +type (
  34 + TodoRequest struct{}
  35 + TodoResonse struct{}
  36 +)
  1 +Name: Core
  2 +Host: 0.0.0.0
  3 +Port: 8080
  4 +
  5 +Verbose: false
  6 +Migrate: true
  7 +Timeout: 30000
  8 +LogRequest: true # 记录详细请求日志
  9 +ContentSecurityCheck: true # 内容安全检查(调用微信接口)
  10 +
  11 +Log:
  12 + #Mode: file
  13 + Encoding: plain
  14 + Level: debug # info
  15 + MaxSize: 1 # 2MB
  16 + TimeFormat: 2006-01-02 15:04:05
  17 + Rotation: size
  18 + MaxContentLength: 10240
  19 +
  20 +SystemAuth:
  21 + AccessSecret: digital-platform
  22 + AccessExpire: 360000
  23 +
  24 +MiniAuth:
  25 + AccessSecret: discuss-secret
  26 + AccessExpire: 360000
  27 +
  28 +Redis:
  29 + Host: 127.0.0.1:6379
  30 + Type: node
  31 + Pass:
  32 +DB:
  33 + DataSource: host=114.55.200.59 user=postgres password=eagle1010 dbname=sumifcc-discuss-dev port=31543 sslmode=disable TimeZone=Asia/Shanghai
  34 +
  35 +ApiAuth:
  36 + Name: ApiAuth
  37 + Host: http://digital-platform-dev.fjmaimaimai.com
  38 + Timeout: 0s
  39 +
  40 +Wechat:
  41 + AppID: wxae5b305849343ec8
  42 + AppSecret: f584adb68f7d784425b60e1ebb2ffd4b
  43 + QrcodeEnv: trial
  1 +package config
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/core/stores/redis"
  5 + "github.com/zeromicro/go-zero/rest"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/config"
  7 + "time"
  8 +)
  9 +
  10 +type Config struct {
  11 + rest.RestConf
  12 + config.Config
  13 + Redis redis.RedisConf `json:",optional"`
  14 + SystemAuth config.Auth
  15 + MiniAuth config.Auth
  16 + Migrate bool `json:",optional,default=true"`
  17 + ApiAuth ApiService
  18 + DebugSmsCode string `json:",optional,default=999512"`
  19 + LogRequest bool `json:",optional,default=true"`
  20 + ContentSecurityCheck bool `json:",optional,default=false"`
  21 +}
  22 +
  23 +type ApiService struct {
  24 + Name string
  25 + Host string
  26 + Timeout time.Duration
  27 +}
  1 +package common
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/common"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +func CommonGetClearCacheHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  12 + return func(w http.ResponseWriter, r *http.Request) {
  13 + l := common.NewCommonGetClearCacheLogic(r.Context(), svcCtx)
  14 + err := l.CommonGetClearCache()
  15 + if err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + } else {
  18 + httpx.Ok(w)
  19 + }
  20 + }
  21 +}
  1 +package common
  2 +
  3 +import (
  4 + "net/http"
  5 + "path/filepath"
  6 + "strings"
  7 +
  8 + "github.com/zeromicro/go-zero/rest/httpx"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  10 +)
  11 +
  12 +func CommonGetLogHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  13 + return func(w http.ResponseWriter, r *http.Request) {
  14 + var req struct {
  15 + Module string `path:"module"`
  16 + }
  17 + if err := httpx.Parse(r, &req); err != nil {
  18 + httpx.ErrorCtx(r.Context(), w, err)
  19 + return
  20 + }
  21 + path := svcCtx.Config.Log.Path
  22 + if svcCtx.Config.Log.Mode != "file" {
  23 + return
  24 + }
  25 + if path == "" {
  26 + path = "logs"
  27 + }
  28 + if !strings.HasSuffix(req.Module, ".log") {
  29 + req.Module += ".log"
  30 + }
  31 + handler := http.FileServer(http.Dir(path))
  32 + r.URL.Path = filepath.Join(req.Module)
  33 + handler.ServeHTTP(w, r)
  34 + }
  35 +}
  1 +package common
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/common"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  10 +)
  11 +
  12 +func CommonSmsCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  13 + return func(w http.ResponseWriter, r *http.Request) {
  14 + var req types.CommonSmsCodeRequest
  15 + if err := httpx.Parse(r, &req); err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + return
  18 + }
  19 +
  20 + l := common.NewCommonSmsCodeLogic(r.Context(), svcCtx)
  21 + resp, err := l.CommonSmsCode(&req)
  22 + if err != nil {
  23 + httpx.ErrorCtx(r.Context(), w, err)
  24 + } else {
  25 + httpx.OkJsonCtx(r.Context(), w, resp)
  26 + }
  27 + }
  28 +}
  1 +package common
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/common"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  10 +)
  11 +
  12 +func MiniQrcodeInviteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  13 + return func(w http.ResponseWriter, r *http.Request) {
  14 + var req types.MiniQrCodeRequest
  15 + if err := httpx.Parse(r, &req); err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + return
  18 + }
  19 +
  20 + l := common.NewMiniQrcodeInviteLogic(r.Context(), svcCtx)
  21 + err := l.MiniQrcodeInvite(&req)
  22 + if err != nil {
  23 + httpx.ErrorCtx(r.Context(), w, err)
  24 + } else {
  25 + httpx.Ok(w)
  26 + }
  27 + }
  28 +}
  1 +// Code generated by goctl. DO NOT EDIT.
  2 +package handler
  3 +
  4 +import (
  5 + "net/http"
  6 +
  7 + common "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/handler/common"
  8 + todo "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/handler/todo"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  10 +
  11 + "github.com/zeromicro/go-zero/rest"
  12 +)
  13 +
  14 +func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
  15 + server.AddRoutes(
  16 + []rest.Route{
  17 + {
  18 + Method: http.MethodGet,
  19 + Path: "/log/:module",
  20 + Handler: common.CommonGetLogHandler(serverCtx),
  21 + },
  22 + },
  23 + rest.WithPrefix("/v1"),
  24 + )
  25 +
  26 + server.AddRoutes(
  27 + rest.WithMiddlewares(
  28 + []rest.Middleware{serverCtx.LogRequest},
  29 + []rest.Route{
  30 + {
  31 + Method: http.MethodPost,
  32 + Path: "/common/sms/code",
  33 + Handler: common.CommonSmsCodeHandler(serverCtx),
  34 + },
  35 + {
  36 + Method: http.MethodPost,
  37 + Path: "/mini/qrcode",
  38 + Handler: common.MiniQrcodeInviteHandler(serverCtx),
  39 + },
  40 + {
  41 + Method: http.MethodGet,
  42 + Path: "/clear",
  43 + Handler: common.CommonGetClearCacheHandler(serverCtx),
  44 + },
  45 + }...,
  46 + ),
  47 + rest.WithPrefix("/v1"),
  48 + )
  49 +
  50 + server.AddRoutes(
  51 + rest.WithMiddlewares(
  52 + []rest.Middleware{serverCtx.LogRequest},
  53 + []rest.Route{
  54 + {
  55 + Method: http.MethodGet,
  56 + Path: "/todo",
  57 + Handler: todo.H5TodoHandler(serverCtx),
  58 + },
  59 + {
  60 + Method: http.MethodGet,
  61 + Path: "/todo/err1",
  62 + Handler: todo.H5TodoErrorCommonHandler(serverCtx),
  63 + },
  64 + {
  65 + Method: http.MethodGet,
  66 + Path: "/todo/err2",
  67 + Handler: todo.H5TodoErrorInternalHandler(serverCtx),
  68 + },
  69 + {
  70 + Method: http.MethodGet,
  71 + Path: "/todo/err3",
  72 + Handler: todo.H5TodoErrorGrpcHandler(serverCtx),
  73 + },
  74 + }...,
  75 + ),
  76 + rest.WithPrefix("/v1/h5"),
  77 + )
  78 +}
  1 +package todo
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/todo"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +func H5TodoErrorCommonHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  12 + return func(w http.ResponseWriter, r *http.Request) {
  13 + l := todo.NewH5TodoErrorCommonLogic(r.Context(), svcCtx)
  14 + resp, err := l.H5TodoErrorCommon()
  15 + if err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + } else {
  18 + httpx.OkJsonCtx(r.Context(), w, resp)
  19 + }
  20 + }
  21 +}
  1 +package todo
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/todo"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +func H5TodoErrorGrpcHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  12 + return func(w http.ResponseWriter, r *http.Request) {
  13 + l := todo.NewH5TodoErrorGrpcLogic(r.Context(), svcCtx)
  14 + resp, err := l.H5TodoErrorGrpc()
  15 + if err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + } else {
  18 + httpx.OkJsonCtx(r.Context(), w, resp)
  19 + }
  20 + }
  21 +}
  1 +package todo
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/todo"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +func H5TodoErrorInternalHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  12 + return func(w http.ResponseWriter, r *http.Request) {
  13 + l := todo.NewH5TodoErrorInternalLogic(r.Context(), svcCtx)
  14 + resp, err := l.H5TodoErrorInternal()
  15 + if err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + } else {
  18 + httpx.OkJsonCtx(r.Context(), w, resp)
  19 + }
  20 + }
  21 +}
  1 +package todo
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/logic/todo"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +func H5TodoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  12 + return func(w http.ResponseWriter, r *http.Request) {
  13 + l := todo.NewH5TodoLogic(r.Context(), svcCtx)
  14 + resp, err := l.H5Todo()
  15 + if err != nil {
  16 + httpx.ErrorCtx(r.Context(), w, err)
  17 + } else {
  18 + httpx.OkJson(w, resp)
  19 + }
  20 + }
  21 +}
  1 +package common
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/xerr"
  7 + "strings"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  11 +)
  12 +
  13 +type CommonGetClearCacheLogic struct {
  14 + logx.Logger
  15 + ctx context.Context
  16 + svcCtx *svc.ServiceContext
  17 +}
  18 +
  19 +func NewCommonGetClearCacheLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CommonGetClearCacheLogic {
  20 + return &CommonGetClearCacheLogic{
  21 + Logger: logx.WithContext(ctx),
  22 + ctx: ctx,
  23 + svcCtx: svcCtx,
  24 + }
  25 +}
  26 +
  27 +func (l *CommonGetClearCacheLogic) CommonGetClearCache() error {
  28 + var (
  29 + appName = l.svcCtx.Config.Name
  30 + success int
  31 + )
  32 + if strings.TrimSpace(appName) == "" {
  33 + return nil
  34 + }
  35 + keyPattern := fmt.Sprintf("%s*", appName)
  36 + list, err := l.svcCtx.Redis.Keys(keyPattern)
  37 + if err != nil {
  38 + return xerr.NewErrMsg(err.Error())
  39 + }
  40 + for _, key := range list {
  41 + if _, err = l.svcCtx.Redis.Del(key); err == nil {
  42 + success++
  43 + }
  44 + }
  45 + logx.Infof("清理缓存:%d/%d", success, len(list))
  46 + return nil
  47 +}
  1 +package common
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "github.com/zeromicro/go-zero/core/logx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  8 +)
  9 +
  10 +type CommonGetLogLogic struct {
  11 + logx.Logger
  12 + ctx context.Context
  13 + svcCtx *svc.ServiceContext
  14 +}
  15 +
  16 +func NewCommonGetLogLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CommonGetLogLogic {
  17 + return &CommonGetLogLogic{
  18 + Logger: logx.WithContext(ctx),
  19 + ctx: ctx,
  20 + svcCtx: svcCtx,
  21 + }
  22 +}
  23 +
  24 +func (l *CommonGetLogLogic) CommonGetLog() error {
  25 + // todo: add your logic here and delete this line
  26 +
  27 + return nil
  28 +}
  1 +package common
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type CommonSmsCodeLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewCommonSmsCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CommonSmsCodeLogic {
  19 + return &CommonSmsCodeLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *CommonSmsCodeLogic) CommonSmsCode(req *types.CommonSmsCodeRequest) (resp *types.CommonSmsCodeResposne, err error) {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return
  30 +}
  1 +package common
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type MiniQrcodeInviteLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewMiniQrcodeInviteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniQrcodeInviteLogic {
  19 + return &MiniQrcodeInviteLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *MiniQrcodeInviteLogic) MiniQrcodeInvite(req *types.MiniQrCodeRequest) error {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return nil
  30 +}
  1 +package todo
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/xerr"
  7 +
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  10 +
  11 + "github.com/zeromicro/go-zero/core/logx"
  12 +)
  13 +
  14 +type H5TodoErrorCommonLogic struct {
  15 + logx.Logger
  16 + ctx context.Context
  17 + svcCtx *svc.ServiceContext
  18 +}
  19 +
  20 +func NewH5TodoErrorCommonLogic(ctx context.Context, svcCtx *svc.ServiceContext) *H5TodoErrorCommonLogic {
  21 + return &H5TodoErrorCommonLogic{
  22 + Logger: logx.WithContext(ctx),
  23 + ctx: ctx,
  24 + svcCtx: svcCtx,
  25 + }
  26 +}
  27 +
  28 +func (l *H5TodoErrorCommonLogic) H5TodoErrorCommon() (resp *types.TodoResonse, err error) {
  29 + // todo: add your logic here and delete this line
  30 + err = xerr.NewCodeErr(xerr.DbError, fmt.Errorf("no result"))
  31 + return
  32 +}
  1 +package todo
  2 +
  3 +import (
  4 + "context"
  5 + "google.golang.org/grpc/codes"
  6 + "google.golang.org/grpc/status"
  7 +
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  10 +
  11 + "github.com/zeromicro/go-zero/core/logx"
  12 +)
  13 +
  14 +type H5TodoErrorGrpcLogic struct {
  15 + logx.Logger
  16 + ctx context.Context
  17 + svcCtx *svc.ServiceContext
  18 +}
  19 +
  20 +func NewH5TodoErrorGrpcLogic(ctx context.Context, svcCtx *svc.ServiceContext) *H5TodoErrorGrpcLogic {
  21 + return &H5TodoErrorGrpcLogic{
  22 + Logger: logx.WithContext(ctx),
  23 + ctx: ctx,
  24 + svcCtx: svcCtx,
  25 + }
  26 +}
  27 +
  28 +func (l *H5TodoErrorGrpcLogic) H5TodoErrorGrpc() (resp *types.TodoResonse, err error) {
  29 + // todo: add your logic here and delete this line
  30 + err = status.Error(codes.DeadlineExceeded, "Grpc deadline...")
  31 + return
  32 +}
  1 +package todo
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/xerr"
  7 +
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
  10 +
  11 + "github.com/zeromicro/go-zero/core/logx"
  12 +)
  13 +
  14 +type H5TodoErrorInternalLogic struct {
  15 + logx.Logger
  16 + ctx context.Context
  17 + svcCtx *svc.ServiceContext
  18 +}
  19 +
  20 +func NewH5TodoErrorInternalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *H5TodoErrorInternalLogic {
  21 + return &H5TodoErrorInternalLogic{
  22 + Logger: logx.WithContext(ctx),
  23 + ctx: ctx,
  24 + svcCtx: svcCtx,
  25 + }
  26 +}
  27 +
  28 +func (l *H5TodoErrorInternalLogic) H5TodoErrorInternal() (resp *types.TodoResonse, err error) {
  29 + // todo: add your logic here and delete this line
  30 + err = xerr.NewErrMsgErr("busy", fmt.Errorf("internal error"))
  31 + return
  32 +}
  1 +package todo
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 +
  7 + "github.com/zeromicro/go-zero/core/logx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
  9 +)
  10 +
  11 +type H5TodoLogic struct {
  12 + logx.Logger
  13 + ctx context.Context
  14 + svcCtx *svc.ServiceContext
  15 +}
  16 +
  17 +func NewH5TodoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *H5TodoLogic {
  18 + return &H5TodoLogic{
  19 + Logger: logx.WithContext(ctx),
  20 + ctx: ctx,
  21 + svcCtx: svcCtx,
  22 + }
  23 +}
  24 +
  25 +func (l *H5TodoLogic) H5Todo() (interface{}, error) {
  26 + // todo: add your logic here and delete this line
  27 +
  28 + return "todo", fmt.Errorf("todo error")
  29 +}
  1 +package middleware
  2 +
  3 +import "net/http"
  4 +
  5 +type LogRequestMiddleware struct {
  6 +}
  7 +
  8 +func NewLogRequestMiddleware() *LogRequestMiddleware {
  9 + return &LogRequestMiddleware{}
  10 +}
  11 +
  12 +func (m *LogRequestMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
  13 + return func(w http.ResponseWriter, r *http.Request) {
  14 + // TODO generate middleware implement function, delete after code implementation
  15 +
  16 + // Passthrough to next handler if need
  17 + next(w, r)
  18 + }
  19 +}
  1 +package svc
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/core/stores/redis"
  5 + "github.com/zeromicro/go-zero/rest"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/config"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/database"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway/authlib"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway/openlib"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway/smslib"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/middleware"
  13 + "gorm.io/gorm"
  14 +)
  15 +
  16 +type ServiceContext struct {
  17 + Config config.Config
  18 + DB *gorm.DB
  19 + Redis *redis.Redis
  20 +
  21 + LogRequest rest.Middleware
  22 + LoginStatusCheck rest.Middleware
  23 +
  24 + ApiAuthService authlib.ApiAuthService
  25 + SmsService smslib.SMSService
  26 + OpenApiService openlib.OpenApiService
  27 +}
  28 +
  29 +func NewServiceContext(c config.Config) *ServiceContext {
  30 + db := database.OpenGormPGDB(c.DB.DataSource, c.Log.Mode)
  31 +
  32 + //mlCache := cache.NewMultiLevelCache([]string{c.Redis.Host}, c.Redis.Pass)
  33 + redis, _ := redis.NewRedis(redis.RedisConf{Host: c.Redis.Host, Pass: c.Redis.Pass, Type: "node"})
  34 + apiAuth := authlib.ApiAuthService{
  35 + Service: gateway.NewService(c.ApiAuth.Name, c.ApiAuth.Host, c.ApiAuth.Timeout),
  36 + }
  37 +
  38 + return &ServiceContext{
  39 + Config: c,
  40 + DB: db,
  41 + Redis: redis,
  42 + ApiAuthService: apiAuth,
  43 + LogRequest: middleware.NewLogRequestMiddleware(c.LogRequest).Handle,
  44 + }
  45 +}
  1 +// Code generated by goctl. DO NOT EDIT.
  2 +package types
  3 +
  4 +type CommonSmsCodeRequest struct {
  5 + Phone string `json:"phone"`
  6 +}
  7 +
  8 +type CommonSmsCodeResposne struct {
  9 +}
  10 +
  11 +type MiniQrCodeRequest struct {
  12 + Page string `json:"page"` // 微信页面入口
  13 + Scene string `json:"scene"` // 参数
  14 +}
  15 +
  16 +type TodoRequest struct {
  17 +}
  18 +
  19 +type TodoResonse struct {
  20 +}
  1 +CREATE TABLE `todo`
  2 +(
  3 + `id` int(0) NOT NULL COMMENT '唯一标识',
  4 + PRIMARY KEY (`id`) USING BTREE
  5 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
  1 +FROM golang:1.19-alpine as builder
  2 +
  3 +# Define the project name | 定义项目名称
  4 +ARG PROJECT=core
  5 +ARG PROJECTCODE=bsi
  6 +
  7 +WORKDIR /build
  8 +COPY . .
  9 +
  10 +RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
  11 +RUN apk update --no-cache && apk add --no-cache tzdata
  12 +RUN go env -w GO111MODULE=on \
  13 + && go env -w GOPROXY=https://goproxy.cn,direct \
  14 + && go env -w CGO_ENABLED=0 \
  15 + && go env \
  16 + && go mod tidy \
  17 + && cd cmd/${PROJECTCODE}/api \
  18 + && go build -ldflags="-s -w" -o /build/api/${PROJECT} ${PROJECT}.go
  19 +
  20 +FROM alpine:latest
  21 +
  22 +# Define the project name | 定义项目名称
  23 +ARG PROJECT=core
  24 +ARG PROJECTCODE=bsi
  25 +# Define the config file name | 定义配置文件名
  26 +ARG CONFIG_FILE=core.yaml
  27 +# Define the author | 定义作者
  28 +ARG AUTHOR=785409885@qq.com
  29 +
  30 +LABEL org.opencontainers.image.authors=${AUTHOR}
  31 +
  32 +WORKDIR /app
  33 +ENV PROJECT=${PROJECT}
  34 +ENV CONFIG_FILE=${CONFIG_FILE}
  35 +ENV TZ Asia/Shanghai
  36 +
  37 +COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
  38 +COPY --from=builder /build/api/${PROJECT} ./
  39 +COPY --from=builder /build/cmd/${PROJECTCODE}/api/etc/${CONFIG_FILE} ./etc/
  40 +
  41 +EXPOSE 8080
  42 +ENTRYPOINT ./${PROJECT} -f etc/${CONFIG_FILE}
  1 +#!/bin/bash
  2 +export PATH=/root/local/bin:$PATH
  3 +kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  4 +if [ "$?" == "1" ];then
  5 + kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
  6 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  7 + if [ "$?" == "0" ];then
  8 + echo "sumifcc-discuss service install success!"
  9 + else
  10 + echo "sumifcc-discuss service install fail!"
  11 + fi
  12 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  13 + if [ "$?" == "0" ];then
  14 + echo "sumifcc-discuss deployment install success!"
  15 + else
  16 + echo "sumifcc-discuss deployment install fail!"
  17 + fi
  18 +else
  19 + kubectl delete -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml
  20 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  21 + while [ "$?" == "0" ]
  22 + do
  23 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  24 + done
  25 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  26 + while [ "$?" == "0" ]
  27 + do
  28 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  29 + done
  30 + kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
  31 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  32 + if [ "$?" == "0" ];then
  33 + echo "sumifcc-discuss service update success!"
  34 + else
  35 + echo "sumifcc-discuss service update fail!"
  36 + fi
  37 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  38 + if [ "$?" == "0" ];then
  39 + echo "sumifcc-discuss deployment update success!"
  40 + else
  41 + echo "sumifcc-discuss deployment update fail!"
  42 + fi
  43 +fi
  1 +#!/bin/bash
  2 +export PATH=/root/local/bin:$PATH
  3 +kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  4 +if [ "$?" == "1" ];then
  5 + kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
  6 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  7 + if [ "$?" == "0" ];then
  8 + echo "sumifcc-discuss service install success!"
  9 + else
  10 + echo "sumifcc-discuss service install fail!"
  11 + fi
  12 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  13 + if [ "$?" == "0" ];then
  14 + echo "sumifcc-discuss deployment install success!"
  15 + else
  16 + echo "sumifcc-discuss deployment install fail!"
  17 + fi
  18 +else
  19 + kubectl delete -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml
  20 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  21 + while [ "$?" == "0" ]
  22 + do
  23 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  24 + done
  25 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  26 + while [ "$?" == "0" ]
  27 + do
  28 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  29 + done
  30 + kubectl create -f /tmp/test/sumifcc-discuss/sumifcc-discuss.yaml --record
  31 + kubectl -n mmm-suplus-test get svc | grep -q sumifcc-discuss
  32 + if [ "$?" == "0" ];then
  33 + echo "sumifcc-discuss service update success!"
  34 + else
  35 + echo "sumifcc-discuss service update fail!"
  36 + fi
  37 + kubectl -n mmm-suplus-test get pods | grep -q sumifcc-discuss
  38 + if [ "$?" == "0" ];then
  39 + echo "sumifcc-discuss deployment update success!"
  40 + else
  41 + echo "sumifcc-discuss deployment update fail!"
  42 + fi
  43 +fi
  1 +apiVersion: v1
  2 +kind: Service
  3 +metadata:
  4 + name: sumifcc-discuss
  5 + namespace: mmm-suplus-test
  6 + labels:
  7 + k8s-app: sumifcc-discuss
  8 +spec:
  9 + ports:
  10 + - name: "http"
  11 + port: 80
  12 + targetPort: 8081
  13 + - name: "https"
  14 + port: 443
  15 + targetPort: 443
  16 + selector:
  17 + k8s-app: sumifcc-discuss
  18 +---
  19 +apiVersion: extensions/v1beta1
  20 +kind: Deployment
  21 +metadata:
  22 + name: sumifcc-discuss
  23 + namespace: mmm-suplus-test
  24 + labels:
  25 + k8s-app: sumifcc-discuss
  26 +spec:
  27 + replicas: 1
  28 + template:
  29 + metadata:
  30 + labels:
  31 + k8s-app: sumifcc-discuss
  32 + spec:
  33 + affinity:
  34 + nodeAffinity:
  35 + preferredDuringSchedulingIgnoredDuringExecution:
  36 + - preference: {}
  37 + weight: 100
  38 + requiredDuringSchedulingIgnoredDuringExecution:
  39 + nodeSelectorTerms:
  40 + - matchExpressions:
  41 + - key: kubernetes.io/hostname
  42 + operator: In
  43 + values:
  44 + - cn-hangzhou.i-bp1djh1xn7taumbue1ze
  45 +
  46 + containers:
  47 + - name: sumifcc-discuss
  48 + image: 192.168.0.243:5000/mmm/sumifcc-discuss:dev
  49 + imagePullPolicy: Always
  50 + ports:
  51 + - containerPort: 8081
  52 + - containerPort: 443
  53 + volumeMounts:
  54 + - mountPath: /opt/logs
  55 + name: accesslogs
  56 + env:
  57 + - name: LOG_LEVEL
  58 + value: "debug"
  59 + - name: LOG_FILE
  60 + value: "true"
  61 + - name: REDIS_HOST
  62 + valueFrom:
  63 + configMapKeyRef:
  64 + name: suplus-config
  65 + key: redis.ip
  66 + - name: REDIS_PORT
  67 + valueFrom:
  68 + configMapKeyRef:
  69 + name: suplus-config
  70 + key: redis.port
  71 + volumes:
  72 + - name: accesslogs
  73 + emptyDir: {}
  1 +
  2 +syntax = "v1"
  3 +
  4 +info(
  5 + title: "xx实例"
  6 + desc: "xx实例"
  7 + author: "author"
  8 + email: "email"
  9 + version: "v1"
  10 +)
  11 +
  12 +@server(
  13 + prefix: todo/v1
  14 + group: todo
  15 + jwt: JwtAuth
  16 +)
  17 +service Core {
  18 + @doc "详情"
  19 + @handler todoGet
  20 + get /todo/:id (TodoGetRequest) returns (TodoGetResponse)
  21 + @doc "保存"
  22 + @handler todoSave
  23 + post /todo (TodoSaveRequest) returns (TodoSaveResponse)
  24 + @doc "删除"
  25 + @handler todoDelete
  26 + delete /todo/:id (TodoDeleteRequest) returns (TodoDeleteResponse)
  27 + @doc "更新"
  28 + @handler todoUpdate
  29 + put /todo/:id (TodoUpdateRequest) returns (TodoUpdateResponse)
  30 + @doc "搜索"
  31 + @handler todoSearch
  32 + post /todo/search (TodoSearchRequest) returns (TodoSearchResponse)
  33 +}
  34 +
  35 +type (
  36 + TodoGetRequest {
  37 + Id int64 `path:"id"`
  38 + }
  39 + TodoGetResponse struct{
  40 + Todo TodoItem `json:"todo"`
  41 + }
  42 +
  43 + TodoSaveRequest struct{
  44 + Todo TodoItem `json:"todo"`
  45 + }
  46 + TodoSaveResponse struct{}
  47 +
  48 + TodoDeleteRequest struct{
  49 + Id int64 `path:"id"`
  50 + }
  51 + TodoDeleteResponse struct{}
  52 +
  53 + TodoUpdateRequest struct{
  54 + Id int64 `path:"id"`
  55 + Todo TodoItem `json:"todo"`
  56 + }
  57 + TodoUpdateResponse struct{}
  58 +
  59 + TodoSearchRequest struct{
  60 + Page int `json:"page"`
  61 + Size int `json:"size"`
  62 + }
  63 + TodoSearchResponse{
  64 + List []TodoItem `json:"list"`
  65 + Total int64 `json:"total"`
  66 + }
  67 + TodoItem struct{
  68 +
  69 + }
  70 +)
  71 +
  72 +// logic CRUD
  73 +// Save
  74 + //var (
  75 + // conn = l.svcCtx.DefaultDBConn()
  76 + // dm *domain.Todo
  77 + //)
  78 + //// 唯一判断
  79 +
  80 + //dm = NewDomainTodo(req.Todo)
  81 + //if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  82 + // dm, err = l.svcCtx.TodoRepository.Insert(l.ctx, conn, dm)
  83 + // return err
  84 + //}, true); err != nil {
  85 + // return nil, xerr.NewErrMsg("保存失败")
  86 + //}
  87 + ////resp = &types.TodoSaveResponse{}
  88 + //return
  89 +
  90 +//func NewDomainTodo(item types.TodoItem) *domain.Todo {
  91 +// return &domain.Todo{
  92 +
  93 +// }
  94 +//}
  95 +//
  96 +//func NewTypesTodo(item *domain.Todo) types.TodoItem {
  97 +// return types.TodoItem{
  98 +// Id: item.Id,
  99 +// }
  100 +//}
  101 +
  102 +// Get
  103 + //var (
  104 + // conn = l.svcCtx.DefaultDBConn()
  105 + // dm *domain.Todo
  106 + //)
  107 + //// 货号唯一
  108 + //if dm, err = l.svcCtx.TodoRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  109 + // return nil, xerr.NewErrMsgErr("不存在", err)
  110 + //}
  111 + //resp = &types.TodoGetResponse{
  112 + // Todo: NewTypesTodo(dm),
  113 + //}
  114 + //return
  115 +
  116 +// Delete
  117 + //var (
  118 + // conn = l.svcCtx.DefaultDBConn()
  119 + // dm *domain.Todo
  120 + //)
  121 + //if dm, err = l.svcCtx.TodoRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  122 + // return nil, xerr.NewErrMsgErr("不存在", err)
  123 + //}
  124 + //if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  125 + // if dm, err = l.svcCtx.TodoRepository.Delete(l.ctx, conn, dm); err != nil {
  126 + // return err
  127 + // }
  128 + // return nil
  129 + //}, true); err != nil {
  130 + // return nil, xerr.NewErrMsgErr("移除失败", err)
  131 + //}
  132 + //return
  133 +
  134 +// Search
  135 + //var (
  136 + // conn = l.svcCtx.DefaultDBConn()
  137 + // dms []*domain.Todo
  138 + // total int64
  139 + //)
  140 + //
  141 + //queryOptions := domain.NewQueryOptions().WithOffsetLimit(req.Page, req.Size).
  142 + // WithKV("", "")
  143 +
  144 + //total, dms, err = l.svcCtx.TodoRepository.Find(l.ctx, conn, queryOptions)
  145 + //list := make([]types.TodoItem, 0)
  146 + //for i := range dms {
  147 + // list = append(list, NewTypesTodo(dms[i]))
  148 + //}
  149 + //resp = &types.TodoSearchResponse{
  150 + // List: list,
  151 + // Total: total,
  152 + //}
  153 + //return
  154 +
  155 +// Update
  156 + //var (
  157 + // conn = l.svcCtx.DefaultDBConn()
  158 + // dm *domain.Todo
  159 + //)
  160 + //if dm, err = l.svcCtx.TodoRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  161 + // return nil, xerr.NewErrMsgErr("不存在", err)
  162 + //}
  163 + //// 不可编辑判断
  164 +
  165 + //// 赋值
  166 +
  167 + //// 更新
  168 + //if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  169 + // dm, err = l.svcCtx.TodoRepository.UpdateWithVersion(l.ctx, conn, dm)
  170 + // return err
  171 + //}, true); err != nil {
  172 + // return nil, xerr.NewErrMsg("更新失败")
  173 + //}
  174 + //resp = &types.TodoUpdateResponse{}
  175 + //return
  1 +
  2 +syntax = "proto3";
  3 +
  4 +option go_package ="./pb";
  5 +
  6 +package pb;
  7 +
  8 +message TodoGetReq {
  9 + int64 Id = 1;
  10 +}
  11 +message TodoGetResp{
  12 + TodoItem User = 1;
  13 +}
  14 +
  15 +message TodoSaveReq {
  16 +
  17 +}
  18 +message TodoSaveResp{
  19 +
  20 +}
  21 +
  22 +message TodoDeleteReq {
  23 + int64 Id = 1;
  24 +}
  25 +message TodoDeleteResp{
  26 +
  27 +}
  28 +
  29 +message TodoUpdateReq {
  30 + int64 Id = 1;
  31 +}
  32 +message TodoUpdateResp{
  33 +
  34 +}
  35 +
  36 +message TodoSearchReq {
  37 + int64 PageNumber = 1;
  38 + int64 PageSize = 2;
  39 +}
  40 +message TodoSearchResp{
  41 + repeated TodoItem List =1;
  42 + int64 Total =2;
  43 +}
  44 +message TodoItem {
  45 +
  46 +}
  47 +
  48 +service TodoService {
  49 + rpc TodoGet(TodoGetReq) returns(TodoGetResp);
  50 + rpc TodoSave(TodoSaveReq) returns(TodoSaveResp);
  51 + rpc TodoDelete(TodoDeleteReq) returns(TodoDeleteResp);
  52 + rpc TodoUpdate(TodoUpdateReq) returns(TodoUpdateResp);
  53 + rpc TodoSearch(TodoSearchReq) returns(TodoSearchResp);
  54 +}
  1 +package db
  2 +
  3 +import (
  4 + "gorm.io/gorm"
  5 +)
  6 +
  7 +func Migrate(db *gorm.DB) {
  8 + db.AutoMigrate()
  9 +}
  1 +package models
  2 +
  3 +import (
  4 + "fmt"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/interanl/pkg/domain"
  6 + "gorm.io/gorm"
  7 + "gorm.io/plugin/soft_delete"
  8 +)
  9 +
  10 +type Todo struct {
  11 + Id int64 // 唯一标识
  12 + CreatedAt int64
  13 + UpdatedAt int64
  14 + IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
  15 + DeletedAt int64
  16 + Version int
  17 +}
  18 +
  19 +func (m *Todo) TableName() string {
  20 + return "todo"
  21 +}
  22 +
  23 +func (m *Todo) BeforeCreate(tx *gorm.DB) (err error) {
  24 + // m.CreatedAt = time.Now().Unix()
  25 + // m.UpdatedAt = time.Now().Unix()
  26 + return
  27 +}
  28 +
  29 +func (m *Todo) BeforeUpdate(tx *gorm.DB) (err error) {
  30 + // m.UpdatedAt = time.Now().Unix()
  31 + return
  32 +}
  33 +
  34 +func (m *Todo) CacheKeyFunc() string {
  35 + if m.Id == 0 {
  36 + return ""
  37 + }
  38 + return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
  39 +}
  40 +
  41 +func (m *Todo) CacheKeyFuncByObject(obj interface{}) string {
  42 + if v, ok := obj.(*Todo); ok {
  43 + return v.CacheKeyFunc()
  44 + }
  45 + return ""
  46 +}
  47 +
  48 +func (m *Todo) CachePrimaryKeyFunc() string {
  49 + if len("") == 0 {
  50 + return ""
  51 + }
  52 + return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
  53 +}
  1 +package repository
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/jinzhu/copier"
  6 + "github.com/pkg/errors"
  7 + "github.com/tiptok/gocomm/pkg/cache"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/interanl/pkg/db/models"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/interanl/pkg/domain"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/transaction"
  11 + "gorm.io/gorm"
  12 +)
  13 +
  14 +type TodoRepository struct {
  15 + *cache.CachedRepository
  16 +}
  17 +
  18 +func (repository *TodoRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.Todo) (*domain.Todo, error) {
  19 + var (
  20 + err error
  21 + m = &models.Todo{}
  22 + tx = conn.DB()
  23 + )
  24 + if m, err = repository.DomainModelToModel(dm); err != nil {
  25 + return nil, err
  26 + }
  27 + if tx = tx.Model(m).Save(m); tx.Error != nil {
  28 + return nil, tx.Error
  29 + }
  30 + dm.Id = m.Id
  31 + return repository.ModelToDomainModel(m)
  32 +
  33 +}
  34 +
  35 +func (repository *TodoRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.Todo) (*domain.Todo, error) {
  36 + var (
  37 + err error
  38 + m *models.Todo
  39 + tx = conn.DB()
  40 + )
  41 + if m, err = repository.DomainModelToModel(dm); err != nil {
  42 + return nil, err
  43 + }
  44 + queryFunc := func() (interface{}, error) {
  45 + tx = tx.Model(m).Updates(m)
  46 + return nil, tx.Error
  47 + }
  48 + if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  49 + return nil, err
  50 + }
  51 + return repository.ModelToDomainModel(m)
  52 +}
  53 +
  54 +func (repository *TodoRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.Todo) (*domain.Todo, error) {
  55 + var (
  56 + err error
  57 + m *models.Todo
  58 + tx = transaction.DB()
  59 + )
  60 + if m, err = repository.DomainModelToModel(dm); err != nil {
  61 + return nil, err
  62 + }
  63 + oldVersion := dm.Version
  64 + m.Version += 1
  65 + queryFunc := func() (interface{}, error) {
  66 + tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
  67 + if tx.RowsAffected == 0 {
  68 + return nil, domain.ErrUpdateFail
  69 + }
  70 + return nil, tx.Error
  71 + }
  72 + if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  73 + return nil, err
  74 + }
  75 + return repository.ModelToDomainModel(m)
  76 +}
  77 +
  78 +func (repository *TodoRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.Todo) (*domain.Todo, error) {
  79 + var (
  80 + tx = conn.DB()
  81 + m = &models.Todo{Id: dm.Identify().(int64)}
  82 + )
  83 + queryFunc := func() (interface{}, error) {
  84 + tx = tx.Where("id = ?", m.Id).Delete(m)
  85 + return m, tx.Error
  86 + }
  87 + if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  88 + return dm, err
  89 + }
  90 + return repository.ModelToDomainModel(m)
  91 +}
  92 +
  93 +func (repository *TodoRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.Todo, error) {
  94 + var (
  95 + err error
  96 + tx = conn.DB()
  97 + m = new(models.Todo)
  98 + )
  99 + queryFunc := func() (interface{}, error) {
  100 + tx = tx.Model(m).Where("id = ?", id).First(m)
  101 + if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
  102 + return nil, domain.ErrNotFound
  103 + }
  104 + return m, tx.Error
  105 + }
  106 + cacheModel := new(models.Todo)
  107 + cacheModel.Id = id
  108 + if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
  109 + return nil, err
  110 + }
  111 + return repository.ModelToDomainModel(m)
  112 +}
  113 +
  114 +func (repository *TodoRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.Todo, error) {
  115 + var (
  116 + tx = conn.DB()
  117 + ms []*models.Todo
  118 + dms = make([]*domain.Todo, 0)
  119 + total int64
  120 + )
  121 + queryFunc := func() (interface{}, error) {
  122 + tx = tx.Model(&ms).Order("id desc")
  123 + if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
  124 + return dms, tx.Error
  125 + }
  126 + return dms, nil
  127 + }
  128 +
  129 + if _, err := repository.Query(queryFunc); err != nil {
  130 + return 0, nil, err
  131 + }
  132 +
  133 + for _, item := range ms {
  134 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  135 + return 0, dms, err
  136 + } else {
  137 + dms = append(dms, dm)
  138 + }
  139 + }
  140 + return total, dms, nil
  141 +}
  142 +
  143 +func (repository *TodoRepository) ModelToDomainModel(from *models.Todo) (*domain.Todo, error) {
  144 + to := &domain.Todo{}
  145 + err := copier.Copy(to, from)
  146 + return to, err
  147 +}
  148 +
  149 +func (repository *TodoRepository) DomainModelToModel(from *domain.Todo) (*models.Todo, error) {
  150 + to := &models.Todo{}
  151 + err := copier.Copy(to, from)
  152 + return to, err
  153 +}
  154 +
  155 +func NewTodoRepository(cache *cache.CachedRepository) domain.TodoRepository {
  156 + return &TodoRepository{CachedRepository: cache}
  157 +}
  1 +package domain
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/transaction"
  6 + "reflect"
  7 +)
  8 +
  9 +func OffsetLimit(page, size int) (offset int, limit int) {
  10 + if page == 0 {
  11 + page = 1
  12 + }
  13 + if size == 0 {
  14 + size = 20
  15 + }
  16 + offset = (page - 1) * size
  17 + limit = size
  18 + return
  19 +}
  20 +
  21 +type QueryOptions map[string]interface{}
  22 +
  23 +func NewQueryOptions() QueryOptions {
  24 + options := make(map[string]interface{})
  25 + return options
  26 +}
  27 +func (options QueryOptions) WithOffsetLimit(page, size int) QueryOptions {
  28 + offset, limit := OffsetLimit(page, size)
  29 + options["offset"] = offset
  30 + options["limit"] = limit
  31 + return options
  32 +}
  33 +
  34 +func (options QueryOptions) WithKV(key string, value interface{}) QueryOptions {
  35 + if reflect.ValueOf(value).IsZero() {
  36 + return options
  37 + }
  38 + options[key] = value
  39 + return options
  40 +}
  41 +
  42 +func (options QueryOptions) MustWithKV(key string, value interface{}) QueryOptions {
  43 + options[key] = value
  44 + return options
  45 +}
  46 +
  47 +func (options QueryOptions) Copy() QueryOptions {
  48 + newOptions := NewQueryOptions()
  49 + for k, v := range options {
  50 + newOptions[k] = v
  51 + }
  52 + return newOptions
  53 +}
  54 +
  55 +type IndexQueryOptionFunc func() QueryOptions
  56 +
  57 +// 自定义的一些查询条件
  58 +
  59 +func (options QueryOptions) WithCountOnly() QueryOptions {
  60 + options["countOnly"] = true
  61 + return options
  62 +}
  63 +func (options QueryOptions) WithFindOnly() QueryOptions {
  64 + options["findOnly"] = true
  65 + return options
  66 +}
  67 +
  68 +func LazyLoad[K comparable, T any](source map[K]T, ctx context.Context, conn transaction.Conn, k K, load func(context.Context, transaction.Conn, K) (T, error)) (T, error) {
  69 + if v, ok := source[k]; ok {
  70 + return v, nil
  71 + }
  72 + if v, err := load(ctx, conn, k); err != nil {
  73 + return v, err
  74 + } else {
  75 + source[k] = v
  76 + return v, nil
  77 + }
  78 +}
  79 +
  80 +func Values[T any, V any](list []T, each func(item T) V) []V {
  81 + var result []V
  82 + for _, item := range list {
  83 + value := each(item)
  84 + result = append(result, value)
  85 + }
  86 + return result
  87 +}
  1 +package domain
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/transaction"
  6 +)
  7 +
  8 +type Todo struct {
  9 + Id int64 // 唯一标识
  10 + CreatedAt int64
  11 + UpdatedAt int64
  12 + DeletedAt int64
  13 + Version int
  14 +}
  15 +
  16 +type TodoRepository interface {
  17 + Insert(ctx context.Context, conn transaction.Conn, dm *Todo) (*Todo, error)
  18 + Update(ctx context.Context, conn transaction.Conn, dm *Todo) (*Todo, error)
  19 + UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Todo) (*Todo, error)
  20 + Delete(ctx context.Context, conn transaction.Conn, dm *Todo) (*Todo, error)
  21 + FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Todo, error)
  22 + Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*Todo, error)
  23 +}
  24 +
  25 +func (m *Todo) Identify() interface{} {
  26 + if m.Id == 0 {
  27 + return nil
  28 + }
  29 + return m.Id
  30 +}
  1 +package domain
  2 +
  3 +import (
  4 + "errors"
  5 + "github.com/zeromicro/go-zero/core/stores/sqlx"
  6 +)
  7 +
  8 +var (
  9 + ErrNotFound = sqlx.ErrNotFound
  10 + ErrUpdateFail = errors.New("sql: no rows affected")
  11 +)
  12 +
  13 +var ProjectName = "bsi"
  1 +module gitlab.fjmaimaimai.com/allied-creation/sumifcc
  2 +
  3 +go 1.19
  4 +
  5 +require (
  6 + github.com/golang-jwt/jwt/v4 v4.5.0
  7 + github.com/jinzhu/copier v0.4.0
  8 + github.com/jinzhu/now v1.1.5
  9 + github.com/mozillazg/go-pinyin v0.20.0
  10 + github.com/pkg/errors v0.9.1
  11 + github.com/stretchr/testify v1.8.4
  12 + github.com/tiptok/gocomm v1.0.14
  13 + github.com/zeromicro/go-zero v1.5.5
  14 + google.golang.org/grpc v1.57.0
  15 + gorm.io/driver/mysql v1.5.1
  16 + gorm.io/driver/postgres v1.5.2
  17 + gorm.io/gorm v1.25.4
  18 + gorm.io/plugin/soft_delete v1.2.1
  19 +)
  20 +
  21 +require (
  22 + github.com/Shopify/sarama v1.37.2 // indirect
  23 + github.com/beego/beego/v2 v2.0.1 // indirect
  24 + github.com/beorn7/perks v1.0.1 // indirect
  25 + github.com/cenkalti/backoff/v4 v4.2.0 // indirect
  26 + github.com/cespare/xxhash/v2 v2.2.0 // indirect
  27 + github.com/davecgh/go-spew v1.1.1 // indirect
  28 + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
  29 + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
  30 + github.com/eapache/go-resiliency v1.3.0 // indirect
  31 + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
  32 + github.com/eapache/queue v1.1.0 // indirect
  33 + github.com/fatih/color v1.15.0 // indirect
  34 + github.com/fsnotify/fsnotify v1.4.9 // indirect
  35 + github.com/garyburd/redigo v1.6.3 // indirect
  36 + github.com/gin-contrib/sse v0.1.0 // indirect
  37 + github.com/gin-gonic/gin v1.5.0 // indirect
  38 + github.com/go-logr/logr v1.2.3 // indirect
  39 + github.com/go-logr/stdr v1.2.2 // indirect
  40 + github.com/go-playground/locales v0.12.1 // indirect
  41 + github.com/go-playground/universal-translator v0.16.0 // indirect
  42 + github.com/go-redis/redis/v8 v8.11.5 // indirect
  43 + github.com/go-sql-driver/mysql v1.7.1 // indirect
  44 + github.com/golang/protobuf v1.5.3 // indirect
  45 + github.com/golang/snappy v0.0.4 // indirect
  46 + github.com/google/uuid v1.3.0 // indirect
  47 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
  48 + github.com/hashicorp/errwrap v1.1.0 // indirect
  49 + github.com/hashicorp/go-multierror v1.1.1 // indirect
  50 + github.com/hashicorp/go-uuid v1.0.3 // indirect
  51 + github.com/hashicorp/hcl v1.0.0 // indirect
  52 + github.com/jackc/pgpassfile v1.0.0 // indirect
  53 + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
  54 + github.com/jackc/pgx/v5 v5.4.3 // indirect
  55 + github.com/jcmturner/aescts/v2 v2.0.0 // indirect
  56 + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
  57 + github.com/jcmturner/gofork v1.7.6 // indirect
  58 + github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect
  59 + github.com/jcmturner/rpc/v2 v2.0.3 // indirect
  60 + github.com/jinzhu/inflection v1.0.0 // indirect
  61 + github.com/json-iterator/go v1.1.12 // indirect
  62 + github.com/klauspost/compress v1.15.15 // indirect
  63 + github.com/leodido/go-urn v1.1.0 // indirect
  64 + github.com/magiconair/properties v1.8.0 // indirect
  65 + github.com/mattn/go-colorable v0.1.13 // indirect
  66 + github.com/mattn/go-isatty v0.0.17 // indirect
  67 + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
  68 + github.com/mitchellh/mapstructure v1.3.3 // indirect
  69 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
  70 + github.com/modern-go/reflect2 v1.0.2 // indirect
  71 + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
  72 + github.com/onsi/gomega v1.26.0 // indirect
  73 + github.com/openzipkin/zipkin-go v0.4.1 // indirect
  74 + github.com/pelletier/go-toml v1.8.1 // indirect
  75 + github.com/pelletier/go-toml/v2 v2.0.9 // indirect
  76 + github.com/pierrec/lz4/v4 v4.1.17 // indirect
  77 + github.com/pmezard/go-difflib v1.0.0 // indirect
  78 + github.com/prometheus/client_golang v1.16.0 // indirect
  79 + github.com/prometheus/client_model v0.3.0 // indirect
  80 + github.com/prometheus/common v0.42.0 // indirect
  81 + github.com/prometheus/procfs v0.10.1 // indirect
  82 + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
  83 + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
  84 + github.com/spaolacci/murmur3 v1.1.0 // indirect
  85 + github.com/spf13/afero v1.2.2 // indirect
  86 + github.com/spf13/cast v1.4.1 // indirect
  87 + github.com/spf13/jwalterweatherman v1.0.0 // indirect
  88 + github.com/spf13/pflag v1.0.5 // indirect
  89 + github.com/spf13/viper v1.4.0 // indirect
  90 + github.com/ugorji/go/codec v1.1.7 // indirect
  91 + go.opentelemetry.io/otel v1.14.0 // indirect
  92 + go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect
  93 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
  94 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
  95 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
  96 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
  97 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
  98 + go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect
  99 + go.opentelemetry.io/otel/sdk v1.14.0 // indirect
  100 + go.opentelemetry.io/otel/trace v1.14.0 // indirect
  101 + go.opentelemetry.io/proto/otlp v0.19.0 // indirect
  102 + go.uber.org/automaxprocs v1.5.3 // indirect
  103 + golang.org/x/crypto v0.12.0 // indirect
  104 + golang.org/x/net v0.14.0 // indirect
  105 + golang.org/x/sys v0.11.0 // indirect
  106 + golang.org/x/text v0.12.0 // indirect
  107 + google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
  108 + google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
  109 + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
  110 + google.golang.org/protobuf v1.31.0 // indirect
  111 + gopkg.in/go-playground/validator.v9 v9.29.1 // indirect
  112 + gopkg.in/yaml.v2 v2.4.0 // indirect
  113 + gopkg.in/yaml.v3 v3.0.1 // indirect
  114 +)
  1 +package cache
  2 +
  3 +import (
  4 + "github.com/tiptok/gocomm/pkg/cache"
  5 + "github.com/tiptok/gocomm/pkg/cache/gzcache"
  6 + "github.com/tiptok/gocomm/pkg/log"
  7 + "github.com/zeromicro/go-zero/core/logx"
  8 +)
  9 +
  10 +func NewMultiLevelCache(hosts []string, password string) *cache.MultiLevelCache {
  11 + logx.Infof("starting multi level cache...")
  12 + mlCache := cache.NewMultiLevelCacheNew(cache.WithDebugLog(true, func() log.Log {
  13 + return log.DefaultLog
  14 + }))
  15 + mlCache.RegisterCache(gzcache.NewClusterCache(hosts, password))
  16 + return mlCache
  17 +}
  18 +
  19 +func NewCachedRepository(c *cache.MultiLevelCache, options ...cache.QueryOption) *cache.CachedRepository {
  20 + return cache.NewCachedRepository(c, options...)
  21 +}
  1 +package config
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/core/stores/cache"
  5 +)
  6 +
  7 +type Auth struct {
  8 + AccessSecret string
  9 + AccessExpire int64
  10 +}
  11 +type Config struct {
  12 + DB struct {
  13 + DataSource string `json:",env=DataSource"`
  14 + } `json:",optional"`
  15 + Cache cache.CacheConf `json:",optional"`
  16 + DTM DTM `json:",optional"`
  17 + Sms Sms `json:",optional"`
  18 + Oss Oss `json:",optional"`
  19 + Wechat Wechat `json:",optional"`
  20 +}
  21 +
  22 +type DTM struct {
  23 + Server Server `json:",optional"`
  24 +}
  25 +
  26 +type Server struct {
  27 + Name string `json:",optional"`
  28 + Host string `json:",optional"`
  29 + GRPC GRPC `json:",optional"`
  30 + HTTP HTTP `json:",optional"`
  31 + Metrics Metrics `json:",optional"`
  32 +}
  33 +
  34 +type HTTP struct {
  35 + Port string
  36 +}
  37 +
  38 +type GRPC struct {
  39 + Port string
  40 +}
  41 +
  42 +type Metrics struct {
  43 + Port string
  44 +}
  45 +
  46 +type Sms struct {
  47 + Debug bool
  48 + DebugCode string
  49 + Expire int `json:",default=180"`
  50 + MaxSendTime int `json:",default=5"`
  51 + CompanyName string
  52 + SecretId string
  53 + SecretKey string
  54 + SmsAppId string
  55 + Sign string
  56 + TemplateId string
  57 +}
  58 +
  59 +type Oss struct {
  60 + OssEndPoint string
  61 + AccessKeyID string
  62 + AccessKeySecret string
  63 + BuckName string
  64 +
  65 + RegionID string
  66 + RoleArn string
  67 +
  68 + CDN CDN
  69 +}
  70 +
  71 +type Wechat struct {
  72 + AppName string `json:",optional"`
  73 + AppID string
  74 + AppSecret string
  75 + QrcodeEnv string `json:",optional,default=release"`
  76 + MsgTemplates []Template `json:",optional"`
  77 +}
  78 +
  79 +func (wx Wechat) GetTemplate(code string) (Template, bool) {
  80 + for _, temp := range wx.MsgTemplates {
  81 + if temp.Code == code {
  82 + return temp, true
  83 + }
  84 + }
  85 + return Template{}, false
  86 +}
  87 +
  88 +type CDN struct {
  89 + HostPairs []string
  90 +}
  91 +
  92 +type Template struct {
  93 + ID string // 模板ID
  94 + Name string // 模板名称
  95 + Code string // 模板编码
  96 +}
  1 +package contextdata
  2 +
  3 +import (
  4 + "context"
  5 + "encoding/json"
  6 + "github.com/golang-jwt/jwt/v4"
  7 + "github.com/zeromicro/go-zero/core/logx"
  8 + "time"
  9 +)
  10 +
  11 +var (
  12 + CtxKeyJwtUserId = "userId"
  13 + CtxKeyJwtCompanyId = "companyId"
  14 +)
  15 +
  16 +func GetInt64FromCtx(ctx context.Context, key string) int64 {
  17 + var uid int64
  18 + if jsonUid, ok := ctx.Value(key).(json.Number); ok {
  19 + if int64Uid, err := jsonUid.Int64(); err == nil {
  20 + uid = int64Uid
  21 + } else {
  22 + logx.WithContext(ctx).Errorf("GetUidFromCtx err : %+v", err)
  23 + }
  24 + }
  25 + return uid
  26 +}
  27 +
  28 +func getStringFromCtx(ctx context.Context, key string) string {
  29 + var uid string
  30 + if jsonUid, ok := ctx.Value(key).(string); ok {
  31 + return jsonUid
  32 + }
  33 + return uid
  34 +}
  35 +
  36 +func getArrayInt64FromCtx(ctx context.Context, key string) []int64 {
  37 + values := ctx.Value(key)
  38 + var ids = make([]int64, 0)
  39 + if values == nil {
  40 + return ids
  41 + }
  42 + if list, ok := values.([]interface{}); ok {
  43 + for _, item := range list {
  44 + if jsonId, ok := item.(json.Number); ok {
  45 + id, _ := jsonId.Int64()
  46 + ids = append(ids, id)
  47 + }
  48 + }
  49 + }
  50 + return ids
  51 +}
  52 +
  53 +func GetUserTokenFromCtx(ctx context.Context) UserToken {
  54 + return UserToken{
  55 + UserId: GetInt64FromCtx(ctx, CtxKeyJwtUserId),
  56 + CompanyId: GetInt64FromCtx(ctx, CtxKeyJwtCompanyId),
  57 + }
  58 +}
  59 +
  60 +type UserToken struct {
  61 + UserId int64
  62 + CompanyId int64
  63 +}
  64 +
  65 +func (tk UserToken) GenerateToken(secret string, expire int64) (string, error) {
  66 + claims := make(jwt.MapClaims)
  67 + claims["exp"] = time.Now().Unix() + expire
  68 + claims["iat"] = time.Now().Unix()
  69 + claims["UserId"] = tk.UserId
  70 + token := jwt.New(jwt.SigningMethodHS256)
  71 + token.Claims = claims
  72 +
  73 + return token.SignedString([]byte(secret))
  74 +}
  1 +package database
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 + "log"
  7 + "os"
  8 + "time"
  9 +
  10 + "github.com/zeromicro/go-zero/core/logx"
  11 + "gorm.io/driver/mysql"
  12 + "gorm.io/driver/postgres"
  13 + "gorm.io/gorm"
  14 + "gorm.io/gorm/logger"
  15 +)
  16 +
  17 +func OpenGormDB(source string) *gorm.DB {
  18 + newLogger := logger.New(
  19 + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
  20 + logger.Config{
  21 + SlowThreshold: time.Second, // Slow SQL threshold
  22 + LogLevel: logger.Info, // Log level
  23 + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
  24 + Colorful: false, // Disable color
  25 + },
  26 + )
  27 + fmt.Println("starting db...")
  28 + db, err := gorm.Open(mysql.Open(source), &gorm.Config{
  29 + Logger: newLogger,
  30 + })
  31 + if err != nil {
  32 + panic(err)
  33 + }
  34 + return db
  35 +}
  36 +
  37 +func OpenGormPGDB(source string, logMode string) *gorm.DB {
  38 + logx.Infof("starting db...")
  39 + db, err := gorm.Open(postgres.New(postgres.Config{
  40 + DSN: source,
  41 + PreferSimpleProtocol: true, // disables implicit prepared statement usage
  42 + }), &gorm.Config{
  43 + Logger: NewLogger(logMode), //newLogger,
  44 + })
  45 + if err != nil {
  46 + panic(err)
  47 + }
  48 +
  49 + return db
  50 +}
  51 +
  52 +func NewLogger(logType string) logger.Interface {
  53 + if logType == "console" {
  54 + return logger.New(
  55 + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
  56 + logger.Config{
  57 + SlowThreshold: time.Second, // Slow SQL threshold
  58 + LogLevel: logger.Info, // Log level
  59 + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
  60 + Colorful: false, // Disable color
  61 + },
  62 + )
  63 + }
  64 + return ZeroLog{}
  65 +}
  66 +
  67 +type ZeroLog struct {
  68 +}
  69 +
  70 +func (l ZeroLog) LogMode(logger.LogLevel) logger.Interface {
  71 + return l
  72 +}
  73 +func (l ZeroLog) Info(ctx context.Context, s string, values ...interface{}) {
  74 + logx.Infof(s, values...)
  75 +}
  76 +func (l ZeroLog) Warn(ctx context.Context, s string, values ...interface{}) {
  77 + logx.Errorf(s, values...)
  78 +}
  79 +func (l ZeroLog) Error(ctx context.Context, s string, values ...interface{}) {
  80 + logx.Errorf(s, values...)
  81 +}
  82 +func (l ZeroLog) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
  83 + now := time.Now()
  84 + sql, rows := fc()
  85 + logx.Infof("[%v] [rows:%v] %s", now.Sub(begin).String(), rows, sql)
  86 +}
  1 +package database
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/jinzhu/now"
  6 + "github.com/zeromicro/go-zero/core/stores/redis"
  7 + "gorm.io/gorm"
  8 + "gorm.io/gorm/clause"
  9 + "gorm.io/gorm/migrator"
  10 + "gorm.io/gorm/schema"
  11 + "strings"
  12 + "time"
  13 +)
  14 +
  15 +var (
  16 + // PartitionByRangeTime 按unix时间戳分区
  17 + PartitionByRangeTime = 1
  18 + // PartitionByHash 按系统的hash值分区
  19 + PartitionByHash = 2
  20 + // PartitionByList 按List包含值分区
  21 + PartitionByList = 3
  22 +)
  23 +
  24 +type PartitionTable interface {
  25 + TableName() string
  26 +}
  27 +
  28 +type PartitionMigrator struct {
  29 + ServiceName string
  30 + DB *gorm.DB
  31 + Redis *redis.Redis
  32 +}
  33 +
  34 +func NewPartitionMigrator(serviceName string, db *gorm.DB, redis *redis.Redis) *PartitionMigrator {
  35 + return &PartitionMigrator{
  36 + DB: db,
  37 + ServiceName: serviceName,
  38 + Redis: redis,
  39 + }
  40 +}
  41 +
  42 +func (c *PartitionMigrator) AutoMigrate(t PartitionTable, option ...PartitionOptionFunc) error {
  43 + options := NewPartitionOptions()
  44 + for i := range option {
  45 + option[i](options)
  46 + }
  47 +
  48 + tableName := t.TableName()
  49 + if !c.DB.Migrator().HasTable(tableName) {
  50 + migrator := Migrator{migrator.Migrator{
  51 + migrator.Config{
  52 + CreateIndexAfterCreateTable: true,
  53 + DB: c.DB,
  54 + Dialector: c.DB.Dialector,
  55 + },
  56 + }}
  57 + if err := migrator.CreatePartitionTable(options, t); err != nil {
  58 + panic(err)
  59 + }
  60 + }
  61 +
  62 + rk := fmt.Sprintf("%s:auto-partition:%s", c.ServiceName, tableName)
  63 + lock := redis.NewRedisLock(c.Redis, rk)
  64 + ok, err := lock.Acquire()
  65 + if !ok || err != nil {
  66 + return nil
  67 + }
  68 + defer lock.Release()
  69 + switch options.Type {
  70 + case PartitionByRangeTime:
  71 + begin := options.TimeBegin
  72 + end := options.TimeEnd
  73 + for {
  74 + if begin.Unix() > end.Unix() {
  75 + break
  76 + }
  77 + pTable := fmt.Sprintf("%s_%s", tableName, options.FormatTimeSubFunc(begin))
  78 + sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s PARTITION OF %s FOR VALUES FROM (%d) TO (%d);",
  79 + pTable, tableName, begin.Unix(), begin.AddDate(0, options.TimeSpanMonth, 0).Unix())
  80 + tx := c.DB.Exec(sql)
  81 + if tx.Error != nil {
  82 + return tx.Error
  83 + }
  84 + c.log(t, pTable)
  85 + begin = begin.AddDate(0, options.TimeSpanMonth, 0)
  86 + }
  87 + break
  88 + case PartitionByHash:
  89 + for i := 0; i < options.Modulus; i++ {
  90 + pTable := fmt.Sprintf("%s_%d", tableName, i)
  91 + sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s PARTITION OF %s FOR VALUES WITH (MODULUS %d, REMAINDER %d);",
  92 + pTable, tableName, options.Modulus, i)
  93 + tx := c.DB.Exec(sql)
  94 + if tx.Error != nil {
  95 + return tx.Error
  96 + }
  97 + c.log(t, pTable)
  98 + }
  99 + break
  100 + case PartitionByList:
  101 + for i := 0; i < len(options.ListRange); i++ {
  102 + pTable := fmt.Sprintf("%s_%d", tableName, i)
  103 + sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s PARTITION OF %s FOR VALUES IN %s;",
  104 + pTable, tableName, InArgs(options.ListRange[i]))
  105 + tx := c.DB.Exec(sql)
  106 + if tx.Error != nil {
  107 + return tx.Error
  108 + }
  109 + c.log(t, pTable)
  110 + }
  111 + break
  112 + default:
  113 + return nil
  114 + }
  115 +
  116 + return nil
  117 +}
  118 +
  119 +func (c *PartitionMigrator) log(t PartitionTable, pTable string) {
  120 + fmt.Println("【自动分区】 create partition table", pTable, "on table", t.TableName())
  121 +}
  122 +
  123 +type PartitionOptions struct {
  124 + // 分区类型 1:Hash 2:RangeTime
  125 + Type int
  126 + // 分区列
  127 + Column string
  128 +
  129 + // Hash分区
  130 + Modulus int
  131 +
  132 + // List 范围
  133 + ListRange []interface{}
  134 +
  135 + // Range时间分区
  136 + TimeBegin time.Time
  137 + TimeEnd time.Time
  138 + TimeSpanMonth int
  139 + FormatTimeSubFunc func(time.Time) string
  140 +
  141 + // 禁用PrimaryKey生成
  142 + // 分区字段有函数表达式的,需要禁用掉PrimaryKey,使用自定义的唯一ID生成规则
  143 + DisablePrimaryKey bool
  144 +}
  145 +
  146 +func NewPartitionOptions() *PartitionOptions {
  147 + return &PartitionOptions{
  148 + Type: PartitionByRangeTime,
  149 + FormatTimeSubFunc: func(t time.Time) string {
  150 + return t.Format("200601")
  151 + },
  152 + }
  153 +}
  154 +
  155 +func (c *PartitionOptions) Sql() string {
  156 + if c.Type == PartitionByHash {
  157 + return fmt.Sprintf("PARTITION BY HASH(%s)", c.Column)
  158 + }
  159 + if c.Type == PartitionByRangeTime {
  160 + return fmt.Sprintf("PARTITION BY RANGE(%s)", c.Column)
  161 + }
  162 + if c.Type == PartitionByList {
  163 + return fmt.Sprintf("PARTITION BY LIST(%s)", c.Column)
  164 + }
  165 + return ""
  166 +}
  167 +
  168 +type PartitionOptionFunc func(*PartitionOptions)
  169 +
  170 +func WithPartitionType(t int) PartitionOptionFunc {
  171 + return func(options *PartitionOptions) {
  172 + options.Type = t
  173 + }
  174 +}
  175 +
  176 +func WithPartitionColumn(c string) PartitionOptionFunc {
  177 + return func(options *PartitionOptions) {
  178 + options.Column = c
  179 + }
  180 +}
  181 +
  182 +func WithPartitionHash(modulus int) PartitionOptionFunc {
  183 + return func(options *PartitionOptions) {
  184 + options.Modulus = modulus
  185 + }
  186 +}
  187 +
  188 +func WithPartitionRangeTime(begin, end time.Time, spanMonth int) PartitionOptionFunc {
  189 + return func(options *PartitionOptions) {
  190 + options.TimeBegin = begin
  191 + options.TimeEnd = end
  192 + options.TimeSpanMonth = spanMonth
  193 + }
  194 +}
  195 +
  196 +func WithPartitionList(list ...interface{}) PartitionOptionFunc {
  197 + return func(options *PartitionOptions) {
  198 + options.ListRange = list
  199 + }
  200 +}
  201 +
  202 +func WithDisablePrimaryKey(disablePrimaryKey bool) PartitionOptionFunc {
  203 + return func(options *PartitionOptions) {
  204 + options.DisablePrimaryKey = disablePrimaryKey
  205 + }
  206 +}
  207 +
  208 +func Date(date string) time.Time {
  209 + return now.MustParse(date)
  210 +}
  211 +
  212 +type Migrator struct {
  213 + migrator.Migrator
  214 +}
  215 +
  216 +// CreatePartitionTable create table in database for values
  217 +func (m Migrator) CreatePartitionTable(options *PartitionOptions, values ...interface{}) error {
  218 + for _, value := range m.ReorderModels(values, false) {
  219 + tx := m.DB.Session(&gorm.Session{})
  220 + if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) {
  221 + var (
  222 + createTableSQL = "CREATE TABLE ? ("
  223 + values = []interface{}{m.CurrentTable(stmt)}
  224 + hasPrimaryKeyInDataType bool
  225 + )
  226 +
  227 + for _, dbName := range stmt.Schema.DBNames {
  228 + field := stmt.Schema.FieldsByDBName[dbName]
  229 + if !field.IgnoreMigration {
  230 + createTableSQL += "? ?"
  231 + hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(string(field.DataType)), "PRIMARY KEY")
  232 + values = append(values, clause.Column{Name: dbName}, m.DB.Migrator().FullDataTypeOf(field))
  233 + createTableSQL += ","
  234 + }
  235 + }
  236 +
  237 + if !hasPrimaryKeyInDataType && len(stmt.Schema.PrimaryFields) > 0 && !options.DisablePrimaryKey {
  238 + createTableSQL += "PRIMARY KEY ?,"
  239 + primaryKeys := []interface{}{}
  240 + for _, field := range stmt.Schema.PrimaryFields {
  241 + primaryKeys = append(primaryKeys, clause.Column{Name: field.DBName})
  242 + }
  243 +
  244 + values = append(values, primaryKeys)
  245 + }
  246 +
  247 + for _, idx := range stmt.Schema.ParseIndexes() {
  248 + if m.CreateIndexAfterCreateTable {
  249 + defer func(value interface{}, name string) {
  250 + if errr == nil {
  251 + errr = tx.Migrator().CreateIndex(value, name)
  252 + }
  253 + }(value, idx.Name)
  254 + } else {
  255 + if idx.Class != "" {
  256 + createTableSQL += idx.Class + " "
  257 + }
  258 + createTableSQL += "INDEX ? ?"
  259 +
  260 + if idx.Comment != "" {
  261 + createTableSQL += fmt.Sprintf(" COMMENT '%s'", idx.Comment)
  262 + }
  263 +
  264 + if idx.Option != "" {
  265 + createTableSQL += " " + idx.Option
  266 + }
  267 +
  268 + createTableSQL += ","
  269 + values = append(values, clause.Column{Name: idx.Name}, tx.Migrator().(migrator.BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt))
  270 + }
  271 + }
  272 +
  273 + if !m.DB.DisableForeignKeyConstraintWhenMigrating && !m.DB.IgnoreRelationshipsWhenMigrating {
  274 + for _, rel := range stmt.Schema.Relationships.Relations {
  275 + if rel.Field.IgnoreMigration {
  276 + continue
  277 + }
  278 + if constraint := rel.ParseConstraint(); constraint != nil {
  279 + if constraint.Schema == stmt.Schema {
  280 + sql, vars := buildConstraint(constraint)
  281 + createTableSQL += sql + ","
  282 + values = append(values, vars...)
  283 + }
  284 + }
  285 + }
  286 + }
  287 +
  288 + for _, chk := range stmt.Schema.ParseCheckConstraints() {
  289 + createTableSQL += "CONSTRAINT ? CHECK (?),"
  290 + values = append(values, clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint})
  291 + }
  292 +
  293 + createTableSQL = strings.TrimSuffix(createTableSQL, ",")
  294 +
  295 + createTableSQL += ")"
  296 +
  297 + if options != nil {
  298 + createTableSQL += options.Sql()
  299 + }
  300 +
  301 + if tableOption, ok := m.DB.Get("gorm:table_options"); ok {
  302 + createTableSQL += fmt.Sprint(tableOption)
  303 + }
  304 +
  305 + errr = tx.Exec(createTableSQL, values...).Error
  306 + return errr
  307 + }); err != nil {
  308 + return err
  309 + }
  310 + }
  311 + return nil
  312 +}
  313 +
  314 +func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) {
  315 + sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??"
  316 + if constraint.OnDelete != "" {
  317 + sql += " ON DELETE " + constraint.OnDelete
  318 + }
  319 +
  320 + if constraint.OnUpdate != "" {
  321 + sql += " ON UPDATE " + constraint.OnUpdate
  322 + }
  323 +
  324 + var foreignKeys, references []interface{}
  325 + for _, field := range constraint.ForeignKeys {
  326 + foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName})
  327 + }
  328 +
  329 + for _, field := range constraint.References {
  330 + references = append(references, clause.Column{Name: field.DBName})
  331 + }
  332 + results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references)
  333 + return
  334 +}
  1 +package database
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/core/mapping"
  5 + "reflect"
  6 +)
  7 +
  8 +func InArgs(args interface{}) string {
  9 + bytes := make([]byte, 0)
  10 + bytes = appendIn(bytes, reflect.ValueOf(args))
  11 + return string(bytes)
  12 +}
  13 +
  14 +func Arg(args interface{}) string {
  15 + bytes := make([]byte, 0)
  16 + v := reflect.ValueOf(args)
  17 + bytes = appendValue(bytes, v)
  18 + return string(bytes)
  19 +}
  20 +
  21 +func appendIn(b []byte, slice reflect.Value) []byte {
  22 + sliceLen := slice.Len()
  23 + b = append(b, '(')
  24 + for i := 0; i < sliceLen; i++ {
  25 + if i > 0 {
  26 + b = append(b, ',')
  27 + }
  28 +
  29 + elem := slice.Index(i)
  30 + if elem.Kind() == reflect.Interface {
  31 + elem = elem.Elem()
  32 + }
  33 + if elem.Kind() == reflect.Slice {
  34 + //b = appendIn(b, elem)
  35 + } else {
  36 + b = appendValue(b, elem)
  37 + }
  38 + }
  39 + b = append(b, ')')
  40 + return b
  41 +}
  42 +
  43 +func appendValue(b []byte, v reflect.Value) []byte {
  44 + if v.Kind() == reflect.Ptr && v.IsNil() {
  45 +
  46 + return append(b, "NULL"...)
  47 + }
  48 + if v.Kind() == reflect.Int || v.Kind() == reflect.Int64 || v.Kind() == reflect.Float64 {
  49 + return append(b, []byte(mapping.Repr(v.Interface()))...)
  50 + }
  51 + b = append(b, []byte("'")...)
  52 + b = append(b, []byte(mapping.Repr(v.Interface()))...)
  53 + b = append(b, []byte("'")...)
  54 + return b
  55 +}
  1 +package authlib
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway"
  6 + "net/http"
  7 +)
  8 +
  9 +type ApiAuthService struct {
  10 + gateway.Service
  11 +}
  12 +
  13 +func (svc *ApiAuthService) MeInfo(ctx context.Context, request RequestUserMeQuery) (*DataUserMe, error) {
  14 + var result DataUserMe
  15 + if err := svc.Do(ctx, "/v1/user/me", http.MethodGet, request, &result); err != nil {
  16 + return nil, err
  17 + }
  18 + return &result, nil
  19 +}
  20 +
  21 +func (svc *ApiAuthService) MeAppInfo(ctx context.Context, request RequestUserMeQuery) (*DataUserAppInfo, error) {
  22 + var result DataUserAppInfo
  23 + if err := svc.Do(ctx, "/v1/user/me-app-info", http.MethodGet, request, &result); err != nil {
  24 + return nil, err
  25 + }
  26 + return &result, nil
  27 +}
  28 +
  29 +func (svc *ApiAuthService) LoginCheck(ctx context.Context, request RequestLoginCheck) (*DataLoginCheck, error) {
  30 + var (
  31 + result DataLoginCheck
  32 + err error
  33 + )
  34 + if err = svc.Do(ctx, "/v1/login/check?token="+request.Token, http.MethodGet, request, &result); err != nil {
  35 + return nil, err
  36 + }
  37 + if errCodeMsg, ok := err.(gateway.HttpError); ok {
  38 + return &DataLoginCheck{
  39 + Code: errCodeMsg.Base.Code,
  40 + Msg: errCodeMsg.Base.Msg,
  41 + }, nil
  42 + }
  43 + return &result, nil
  44 +}
  45 +
  46 +func (svc *ApiAuthService) AppLogin(ctx context.Context, request RequestAppLogin) (*DataAppLogin, error) {
  47 + var result DataAppLogin
  48 + if err := svc.Do(ctx, "/v1/login/check?token="+request.Token, http.MethodGet, request, &result); err != nil {
  49 + return nil, err
  50 + }
  51 + return &result, nil
  52 +}
  1 +package authlib
  2 +
  3 +type RequestUserMeQuery struct {
  4 + Token string `header:"x-mmm-accesstoken"`
  5 + //UserId int
  6 + //CompanyId int
  7 +}
  8 +
  9 +type DataUserMe struct {
  10 + User *struct {
  11 + ID string `json:"id"`
  12 + Phone string `json:"phone"`
  13 + NickName string `json:"nickName"`
  14 + Avatar string `json:"avatar"`
  15 + } `json:"user,optional"`
  16 + CompanyList []*struct {
  17 + ID string `json:"id"`
  18 + Name string `json:"name"`
  19 + Logo string `json:"logo"`
  20 + DefaultLogin int `json:"defaultLogin"`
  21 + Types int `json:"types"`
  22 + } `json:"companyList,optional"`
  23 + CurrentCompany *struct {
  24 + ID string `json:"id"`
  25 + Name string `json:"name"`
  26 + Logo string `json:"logo"`
  27 + DefaultLogin int `json:"defaultLogin"`
  28 + Types int `json:"types"`
  29 + } `json:"currentCompany,optional"`
  30 + Workbench []*struct {
  31 + ID int `json:"id"`
  32 + Name string `json:"name"`
  33 + Code string `json:"code"`
  34 + CoverImage string `json:"coverImage"`
  35 + URL string `json:"url"`
  36 + } `json:"workbench,optional"`
  37 + Menus []*struct {
  38 + MenuID int `json:"menuId"`
  39 + ParentID int `json:"parentId"`
  40 + MenuName string `json:"menuName"`
  41 + Code string `json:"code"`
  42 + Types string `json:"types"`
  43 + } `json:"menus,optional"`
  44 +}
  45 +
  46 +type RequestLoginCheck struct {
  47 + Token string
  48 +}
  49 +type DataLoginCheck struct {
  50 + Code int `json:"code,optional"`
  51 + Msg string `json:"msg,optional"`
  52 +}
  53 +
  54 +type (
  55 + RequestAppLogin struct {
  56 + AppKey string `json:"appKey" valid:"Required"` // 应用键值
  57 + Token string `json:"token" valid:"Required"` // 凭证
  58 + }
  59 + DataAppLogin struct {
  60 + AppEnabled bool `json:"appEnabled"`
  61 + }
  62 +)
  63 +
  64 +type (
  65 + DataUserAppInfo struct {
  66 + Apps []AppItem `json:"apps"`
  67 + }
  68 + AppItem struct {
  69 + AppId int64
  70 + AppKey string
  71 + AppName string
  72 + }
  73 +)
  1 +package gateway
  2 +
  3 +import (
  4 + "encoding/json"
  5 + "fmt"
  6 +)
  7 +
  8 +// Response 统一消息返回格式
  9 +type Response struct {
  10 + Code int `json:"code,optional"`
  11 + Msg string `json:"msg,optional"`
  12 + Data json.RawMessage `json:"data,optional"`
  13 +}
  14 +
  15 +//
  16 +//type Request struct {
  17 +// Url string
  18 +// Method string
  19 +// Param interface{}
  20 +//}
  21 +
  22 +type HttpError struct {
  23 + Base Response
  24 +}
  25 +
  26 +func (e HttpError) Error() string {
  27 + if e.Base.Code > 0 && e.Base.Msg != "" {
  28 + return e.Base.Msg
  29 + }
  30 + return fmt.Sprintf("HttpError code:%d msg:%s", e.Base.Code, e.Base.Msg)
  31 +}
  1 +package gateway
  2 +
  3 +import (
  4 + "context"
  5 + "encoding/json"
  6 + "fmt"
  7 + "github.com/zeromicro/go-zero/core/mapping"
  8 + "github.com/zeromicro/go-zero/rest/httpc"
  9 + "io/ioutil"
  10 + "net/http"
  11 + "strings"
  12 + "time"
  13 +)
  14 +
  15 +type Service struct {
  16 + Timeout time.Duration
  17 + Host string
  18 + Interceptor func(msg string)
  19 + ServiceName string
  20 + service httpc.Service
  21 +}
  22 +
  23 +func NewService(name string, host string, timeout time.Duration, opts ...httpc.Option) Service {
  24 + client := &http.Client{}
  25 + //client.Timeout = timeout
  26 +
  27 + service := Service{
  28 + Host: host,
  29 + service: httpc.NewServiceWithClient(name, client, opts...),
  30 + }
  31 + return service
  32 +}
  33 +
  34 +func (gateway Service) Do(ctx context.Context, url string, method string, val interface{}, result interface{}) error {
  35 + var (
  36 + baseResponse = Response{}
  37 + begin = time.Now()
  38 + body []byte
  39 + )
  40 + response, err := gateway.service.Do(ctx, method, gateway.Host+url, val)
  41 + defer func() {
  42 + jsonParam, _ := json.Marshal(val)
  43 + jsonData, _ := json.Marshal(result)
  44 + if err != nil {
  45 + result = err.Error()
  46 + }
  47 + if gateway.Interceptor != nil {
  48 + gateway.Interceptor(fmt.Sprintf("【网关】%v | %v%v | %v : %v \n-->> %v \n<<-- %v", time.Since(begin), gateway.Host, url, strings.ToUpper(method),
  49 + result,
  50 + string(jsonParam),
  51 + string(jsonData),
  52 + ))
  53 + }
  54 + }()
  55 + if err != nil {
  56 + return err
  57 + }
  58 + if response.StatusCode != http.StatusOK {
  59 + return HttpError{
  60 + Base: Response{
  61 + Code: response.StatusCode,
  62 + Msg: response.Status,
  63 + },
  64 + }
  65 + }
  66 + body, err = Bytes(response)
  67 + if err != nil {
  68 + return err
  69 + }
  70 + if err = json.Unmarshal(body, &baseResponse); err != nil {
  71 + return err
  72 + }
  73 + if baseResponse.Code != 0 {
  74 + return HttpError{
  75 + Base: Response{
  76 + Code: baseResponse.Code,
  77 + Msg: baseResponse.Msg,
  78 + },
  79 + }
  80 + }
  81 + if err = mapping.UnmarshalJsonBytes(baseResponse.Data, result); err != nil {
  82 + return err
  83 + }
  84 + return nil
  85 +}
  86 +
  87 +func (gateway Service) HandlerResponse(ctx context.Context, request *http.Request, response *http.Response, val, result interface{}) error {
  88 + var (
  89 + baseResponse = Response{}
  90 + begin = time.Now()
  91 + body []byte
  92 + err error
  93 + )
  94 + defer func() {
  95 + jsonParam, _ := json.Marshal(val)
  96 + jsonData, _ := json.Marshal(result)
  97 + if err != nil {
  98 + result = err.Error()
  99 + }
  100 + if gateway.Interceptor != nil {
  101 + gateway.Interceptor(fmt.Sprintf("【网关】%v | %v%v | %v : %v \n-->> %v \n<<-- %v", time.Since(begin), gateway.Host, request.URL.Path, request.Method,
  102 + result,
  103 + string(jsonParam),
  104 + string(jsonData),
  105 + ))
  106 + }
  107 + }()
  108 + if err != nil {
  109 + return err
  110 + }
  111 + if response.StatusCode != http.StatusOK {
  112 + return HttpError{
  113 + Base: Response{
  114 + Code: response.StatusCode,
  115 + Msg: response.Status,
  116 + },
  117 + }
  118 + }
  119 + body, err = Bytes(response)
  120 + if err != nil {
  121 + return err
  122 + }
  123 + if err = json.Unmarshal(body, &baseResponse); err != nil {
  124 + return err
  125 + }
  126 + if baseResponse.Code != 0 {
  127 + return HttpError{
  128 + Base: Response{
  129 + Code: baseResponse.Code,
  130 + Msg: baseResponse.Msg,
  131 + },
  132 + }
  133 + }
  134 + if err = mapping.UnmarshalJsonBytes(baseResponse.Data, result); err != nil {
  135 + return err
  136 + }
  137 + return nil
  138 +}
  139 +
  140 +func (gateway Service) GetService() httpc.Service {
  141 + return gateway.service
  142 +}
  143 +func Bytes(resp *http.Response) ([]byte, error) {
  144 + var body []byte
  145 + if resp.Body == nil {
  146 + return nil, nil
  147 + }
  148 + defer resp.Body.Close()
  149 +
  150 + body, err := ioutil.ReadAll(resp.Body)
  151 + return body, err
  152 +}
  1 +package openlib
  2 +
  3 +import (
  4 + "bytes"
  5 + "context"
  6 + "encoding/json"
  7 + "github.com/zeromicro/go-zero/core/mapping"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway"
  9 + "io"
  10 + "io/ioutil"
  11 + "mime/multipart"
  12 + "net/http"
  13 + "net/url"
  14 +)
  15 +
  16 +type OpenApiService struct {
  17 + gateway.Service
  18 +}
  19 +
  20 +func (svc *OpenApiService) PutFile(ctx context.Context, request RequestPutFile) (*DataPutFile, error) {
  21 + var result DataPutFile
  22 + r, _ := buildRequest(ctx, http.MethodPost, svc.Host+"/v1/vod/putObject", request)
  23 + response, err := svc.GetService().DoRequest(r)
  24 + if err != nil {
  25 + return nil, err
  26 + }
  27 + if err := svc.HandlerResponse(ctx, r, response, nil, &result); err != nil {
  28 + return nil, err
  29 + }
  30 + return &result, nil
  31 +}
  32 +
  33 +func buildRequest(ctx context.Context, method, tmpUrl string, data any) (*http.Request, error) {
  34 + u, err := url.Parse(tmpUrl)
  35 + if err != nil {
  36 + return nil, err
  37 + }
  38 +
  39 + var val map[string]map[string]any
  40 + if data != nil {
  41 + val, err = mapping.Marshal(data)
  42 + if err != nil {
  43 + return nil, err
  44 + }
  45 + }
  46 +
  47 + var reader io.Reader
  48 + jsonVars, hasJsonBody := val["json"]
  49 + if hasJsonBody {
  50 + var buf bytes.Buffer
  51 + enc := json.NewEncoder(&buf)
  52 + if err := enc.Encode(jsonVars); err != nil {
  53 + return nil, err
  54 + }
  55 +
  56 + reader = &buf
  57 + }
  58 +
  59 + req, err := http.NewRequestWithContext(ctx, method, u.String(), reader)
  60 + if err != nil {
  61 + return nil, err
  62 + }
  63 + fileVars, hasFile := val["file"]
  64 + if hasFile {
  65 + if err = fillFile(req, fileVars); err != nil {
  66 + return nil, err
  67 + }
  68 + }
  69 + if hasJsonBody {
  70 + req.Header.Set("Content-Type", "application/json; charset=utf-8")
  71 + }
  72 +
  73 + return req, nil
  74 +}
  75 +
  76 +func fillFile(req *http.Request, val map[string]any) error {
  77 + if len(val) == 0 {
  78 + return nil
  79 + }
  80 + pr, pw := io.Pipe()
  81 + bodyWriter := multipart.NewWriter(pw)
  82 + go func() {
  83 + for k, v := range val {
  84 + fileWriter, err := bodyWriter.CreateFormFile(k, k)
  85 + if err != nil {
  86 + return
  87 + }
  88 + //fh, err := os.Open(v.(string))
  89 + //if err != nil {
  90 + // return err
  91 + //}
  92 + fh := bytes.NewBuffer(v.([]byte))
  93 + // iocopy
  94 + _, err = io.Copy(fileWriter, fh)
  95 + if err != nil {
  96 + return
  97 + }
  98 + }
  99 + bodyWriter.Close()
  100 + pw.Close()
  101 + }()
  102 + req.Header.Set("Content-Type", bodyWriter.FormDataContentType())
  103 + req.Body = ioutil.NopCloser(pr)
  104 + req.Header.Set("Transfer-Encoding", "chunked")
  105 + return nil
  106 +}
  1 +package openlib
  2 +
  3 +type (
  4 + RequestPutFile struct {
  5 + File []byte `file:"file.png"`
  6 + }
  7 + DataPutFile []*DataUploadItem
  8 +
  9 + DataUploadItem struct {
  10 + Host string `json:"host"`
  11 + Key string `json:"key"`
  12 + Path string `json:"path"`
  13 + FileName string `json:"fileName"`
  14 + }
  15 +)
  1 +package gateway
  2 +
  3 +import "net/http"
  4 +
  5 +type RequestOptions struct {
  6 + Header http.Header
  7 + // key:form key value:path
  8 + FileMap map[string]string
  9 +}
  10 +
  11 +type Option func(o *RequestOptions)
  12 +
  13 +func WithHeader(header http.Header) Option {
  14 + return func(o *RequestOptions) {
  15 + o.Header = header
  16 + }
  17 +}
  18 +
  19 +func WithFileMap(v map[string]string) Option {
  20 + return func(o *RequestOptions) {
  21 + o.FileMap = v
  22 + }
  23 +}
  1 +package smslib
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway"
  6 + "net/http"
  7 +)
  8 +
  9 +type SMSService struct {
  10 + gateway.Service
  11 +}
  12 +
  13 +func (svc *SMSService) SendSmsCode(ctx context.Context, request RequestSendSmsCode) (*DataSendSmsCode, error) {
  14 + var result DataSendSmsCode
  15 + if err := svc.Do(ctx, "/service/sendSms", http.MethodPost, request, &result); err != nil {
  16 + return nil, err
  17 + }
  18 + return &result, nil
  19 +}
  20 +
  21 +func (svc *SMSService) CheckSmsCode(ctx context.Context, request RequestCheckSmsCode) (*DataCheckSmsCode, error) {
  22 + var result DataCheckSmsCode
  23 + if err := svc.Do(ctx, "/service/checkSmsCode", http.MethodPost, request, &result); err != nil {
  24 + return nil, err
  25 + }
  26 + return &result, nil
  27 +}
  1 +package smslib
  2 +
  3 +type (
  4 + RequestSendSmsCode struct {
  5 + Phone string `json:"phone"`
  6 + }
  7 + DataSendSmsCode struct {
  8 + }
  9 +)
  10 +
  11 +type (
  12 + RequestCheckSmsCode struct {
  13 + Phone string `json:"phone"`
  14 + Code string `json:"code"`
  15 + }
  16 + DataCheckSmsCode struct {
  17 + }
  18 +)
  1 +package middleware
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/rest/httpx"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/gateway/authlib"
  7 + "net/http"
  8 +)
  9 +
  10 +type LoginStatusCheckMiddleware struct {
  11 + apiAuth authlib.ApiAuthService
  12 +}
  13 +
  14 +func NewLoginStatusCheckMiddleware(apiAuth authlib.ApiAuthService) *LoginStatusCheckMiddleware {
  15 + return &LoginStatusCheckMiddleware{
  16 + apiAuth: apiAuth,
  17 + }
  18 +}
  19 +
  20 +func (m *LoginStatusCheckMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
  21 + return func(w http.ResponseWriter, r *http.Request) {
  22 + token := r.Header.Get("x-mmm-accesstoken")
  23 + if len(token) > 0 {
  24 + _, err := m.apiAuth.LoginCheck(r.Context(), authlib.RequestLoginCheck{
  25 + Token: token,
  26 + })
  27 + if err != nil {
  28 + gatewayError, ok := err.(gateway.HttpError)
  29 + if ok {
  30 + unAuthResponse(w, gatewayError.Base.Code, gatewayError.Base.Msg)
  31 + return
  32 + }
  33 + httpx.ErrorCtx(r.Context(), w, err)
  34 + return
  35 + }
  36 + }
  37 + next(w, r)
  38 + }
  39 +}
  40 +
  41 +func unAuthResponse(w http.ResponseWriter, code int, msg string) {
  42 + data := map[string]interface{}{
  43 + "msg": msg,
  44 + "code": code,
  45 + "data": struct{}{},
  46 + }
  47 + httpx.WriteJson(w, http.StatusUnauthorized, data)
  48 +}
  1 +package middleware
  2 +
  3 +import (
  4 + "github.com/zeromicro/go-zero/rest/handler"
  5 + "net/http"
  6 +)
  7 +
  8 +type LogRequestMiddleware struct {
  9 + logRequest bool
  10 +}
  11 +
  12 +// NewLogRequestMiddleware 记录请求
  13 +// logRequest true开启记录,false关闭记录
  14 +func NewLogRequestMiddleware(logRequest bool) *LogRequestMiddleware {
  15 + return &LogRequestMiddleware{
  16 + logRequest: logRequest,
  17 + }
  18 +}
  19 +func (m *LogRequestMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
  20 + if !m.logRequest {
  21 + return func(writer http.ResponseWriter, request *http.Request) {
  22 + next(writer, request)
  23 + }
  24 + }
  25 + return handler.DetailedLogHandler(next).(http.HandlerFunc)
  26 +}
  1 +package tool
  2 +
  3 +import (
  4 + "crypto/md5"
  5 + "fmt"
  6 + "io"
  7 +)
  8 +
  9 +/** 加密方式 **/
  10 +
  11 +func Md5ByString(str string) string {
  12 + m := md5.New()
  13 + _, err := io.WriteString(m, str)
  14 + if err != nil {
  15 + panic(err)
  16 + }
  17 + arr := m.Sum(nil)
  18 + return fmt.Sprintf("%x", arr)
  19 +}
  20 +
  21 +func Md5ByBytes(b []byte) string {
  22 + return fmt.Sprintf("%x", md5.Sum(b))
  23 +}
  1 +package tool
  2 +
  3 +import (
  4 + "path/filepath"
  5 + "strings"
  6 +)
  7 +
  8 +const (
  9 + Image = "image"
  10 + Video = "video"
  11 +)
  12 +
  13 +var TypeMap = map[string]string{
  14 + "jpg": Image,
  15 + "png": Image,
  16 + "gif": Image,
  17 + "webp": Image,
  18 + "cr2": Image,
  19 + "tif": Image,
  20 + "bmp": Image,
  21 + "heif": Image,
  22 + "jxr": Image,
  23 + "psd": Image,
  24 + "ico": Image,
  25 + "dwg": Image,
  26 + "avif": Image,
  27 +
  28 + "mp4": Video,
  29 + "m4v": Video,
  30 + "mkv": Video,
  31 + "webm": Video,
  32 + "mov": Video,
  33 + "avi": Video,
  34 + "wmv": Video,
  35 + "mpg": Video,
  36 + "flv": Video,
  37 + "3gp": Video,
  38 +}
  39 +var DefaultFileTypeDetector = FileTypeDetector{}
  40 +
  41 +type FileTypeDetector struct {
  42 +}
  43 +
  44 +func (c FileTypeDetector) Classify(medias []string, mediaType string) []string {
  45 + result := make([]string, 0)
  46 + for _, media := range medias {
  47 + v, ok := TypeMap[strings.Trim(filepath.Ext(media), ".")]
  48 + if !ok {
  49 + continue
  50 + }
  51 + if v == mediaType {
  52 + result = append(result, media)
  53 + }
  54 + }
  55 + return result
  56 +}
  1 +package tool
  2 +
  3 +import (
  4 + jwt "github.com/golang-jwt/jwt/v4"
  5 + "time"
  6 +)
  7 +
  8 +type UserToken struct {
  9 + UserId int64 `json:"userId"`
  10 + AdminId int64 `json:"adminId"`
  11 + CompanyId int64 `json:"companyId"`
  12 + ClientType string `json:"clientType"`
  13 +}
  14 +
  15 +func (tk UserToken) GenerateToken(secret string, expire int64) (string, error) {
  16 + claims := make(jwt.MapClaims)
  17 + claims["exp"] = time.Now().Unix() + expire
  18 + claims["iat"] = time.Now().Unix()
  19 + claims["userId"] = tk.UserId
  20 + claims["adminId"] = tk.AdminId
  21 + claims["companyId"] = tk.CompanyId
  22 + claims["clientType"] = tk.ClientType
  23 + token := jwt.New(jwt.SigningMethodHS256)
  24 + token.Claims = claims
  25 +
  26 + return token.SignedString([]byte(secret))
  27 +}
  1 +package tool
  2 +
  3 +import (
  4 + "math/rand"
  5 + "time"
  6 +)
  7 +
  8 +const (
  9 + KC_RAND_KIND_NUM = 0 // 纯数字
  10 + KC_RAND_KIND_LOWER = 1 // 小写字母
  11 + KC_RAND_KIND_UPPER = 2 // 大写字母
  12 + KC_RAND_KIND_ALL = 3 // 数字、大小写字母
  13 +)
  14 +
  15 +// 随机字符串
  16 +func Krand(size int, kind int) string {
  17 + ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
  18 + is_all := kind > 2 || kind < 0
  19 + rand.Seed(time.Now().UnixNano())
  20 + for i := 0; i < size; i++ {
  21 + if is_all { // random ikind
  22 + ikind = rand.Intn(3)
  23 + }
  24 + scope, base := kinds[ikind][0], kinds[ikind][1]
  25 + result[i] = uint8(base + rand.Intn(scope))
  26 + }
  27 + return string(result)
  28 +}
  1 +package oss
  2 +
  3 +import (
  4 + "encoding/json"
  5 + "fmt"
  6 + "image"
  7 + _ "image/jpeg"
  8 + "net/http"
  9 + "strings"
  10 + "time"
  11 +)
  12 +
  13 +type FileInfo struct {
  14 + FileSize struct {
  15 + Value string
  16 + }
  17 + Format struct {
  18 + Value string
  19 + }
  20 + ImageHeight struct {
  21 + Value string
  22 + }
  23 + ImageWidth struct {
  24 + Value string
  25 + }
  26 +}
  27 +
  28 +func GetImageInfo(url string) (info FileInfo, err error) {
  29 + //ok := strings.HasPrefix(url, "https://timeless-world.oss-cn-shenzhen.aliyuncs.com")
  30 + ok := strings.HasPrefix(url, "http")
  31 + if !ok {
  32 + return
  33 + }
  34 + ok = strings.Contains(url, "aliyuncs")
  35 + if !ok {
  36 + return
  37 + }
  38 + apiUrl := url + `?x-oss-process=image/info`
  39 + req, err := http.NewRequest(http.MethodGet, apiUrl, nil)
  40 + if err != nil {
  41 + return info, err
  42 + }
  43 + httpclient := http.Client{
  44 + Timeout: 5 * time.Second,
  45 + }
  46 + resp, err := httpclient.Do(req)
  47 + if err != nil {
  48 + return info, err
  49 + }
  50 + defer resp.Body.Close()
  51 + if resp.StatusCode != http.StatusOK {
  52 + return
  53 + }
  54 + jDecoder := json.NewDecoder(resp.Body)
  55 + err = jDecoder.Decode(&info)
  56 + if err != nil {
  57 + return info, err
  58 + }
  59 + return info, nil
  60 +}
  61 +
  62 +// 获取视频封面图
  63 +func GetVideoCover(videoUrl string) (coverUrl string, w int, h int, err error) {
  64 + ok := strings.HasPrefix(videoUrl, "http")
  65 + if !ok {
  66 + return
  67 + }
  68 + ok = strings.Contains(videoUrl, "aliyuncs")
  69 + if !ok {
  70 + return
  71 + }
  72 + videoUrl = videoUrl + "?x-oss-process=video/snapshot,t_100,f_jpg,m_fast"
  73 + httpclient := http.Client{
  74 + Timeout: 5 * time.Second,
  75 + }
  76 + res, err := httpclient.Get(videoUrl)
  77 + if err != nil || res.StatusCode != http.StatusOK {
  78 + return videoUrl, 600, 600, fmt.Errorf("获取图片失败:%s", err)
  79 + }
  80 + defer res.Body.Close()
  81 + m, _, err := image.Decode(res.Body)
  82 + if err != nil {
  83 + return videoUrl, 600, 600, fmt.Errorf("获取图片失败:%s", err)
  84 + }
  85 + return videoUrl, m.Bounds().Dx(), m.Bounds().Dy(), nil
  86 +}
  1 +package oss
  2 +
  3 +import "testing"
  4 +
  5 +func TestGetVideoCover(t *testing.T) {
  6 +
  7 + cover, w, h, err := GetVideoCover("https://timeless-world.oss-cn-shenzhen.aliyuncs.com/open-api/dev_online/20230913/object/1694587897_yYfG6TYTsGMCKETxdnTEhAQjXpYGD3MB.mp4")
  8 + t.Logf("cover=%v, w=%v, h=%v, err=%v", cover, w, h, err)
  9 +}
  1 +package tool
  2 +
  3 +import (
  4 + "strings"
  5 +
  6 + "github.com/mozillazg/go-pinyin"
  7 +)
  8 +
  9 +func ToPinYin(hans string, sep string) string {
  10 + a := pinyin.NewArgs()
  11 + tmp := pinyin.Pinyin(hans, a)
  12 + result := make([]string, 0)
  13 + for i := range tmp {
  14 + result = append(result, tmp[i]...)
  15 + }
  16 + py := strings.Join(result, sep)
  17 + if len(py) == 0 {
  18 + return strings.ToLower(hans)
  19 + }
  20 + return py
  21 +}
  1 +package transaction
  2 +
  3 +import (
  4 + "context"
  5 + "fmt"
  6 + "gorm.io/gorm"
  7 + "sync"
  8 +)
  9 +
  10 +type Context struct {
  11 + //启用事务标识
  12 + beginTransFlag bool
  13 + db *gorm.DB
  14 + session *gorm.DB
  15 + lock sync.Mutex
  16 +}
  17 +
  18 +func (transactionContext *Context) Begin() error {
  19 + transactionContext.lock.Lock()
  20 + defer transactionContext.lock.Unlock()
  21 + transactionContext.beginTransFlag = true
  22 + tx := transactionContext.db.Begin()
  23 + transactionContext.session = tx
  24 + return nil
  25 +}
  26 +
  27 +func (transactionContext *Context) Commit() error {
  28 + transactionContext.lock.Lock()
  29 + defer transactionContext.lock.Unlock()
  30 + if !transactionContext.beginTransFlag {
  31 + return nil
  32 + }
  33 + tx := transactionContext.session.Commit()
  34 + return tx.Error
  35 +}
  36 +
  37 +func (transactionContext *Context) Rollback() error {
  38 + transactionContext.lock.Lock()
  39 + defer transactionContext.lock.Unlock()
  40 + if !transactionContext.beginTransFlag {
  41 + return nil
  42 + }
  43 + tx := transactionContext.session.Rollback()
  44 + return tx.Error
  45 +}
  46 +
  47 +func (transactionContext *Context) DB() *gorm.DB {
  48 + if transactionContext.beginTransFlag && transactionContext.session != nil {
  49 + return transactionContext.session
  50 + }
  51 + return transactionContext.db
  52 +}
  53 +
  54 +func NewTransactionContext(db *gorm.DB) *Context {
  55 + return &Context{
  56 + db: db,
  57 + }
  58 +}
  59 +
  60 +type Conn interface {
  61 + Begin() error
  62 + Commit() error
  63 + Rollback() error
  64 + DB() *gorm.DB
  65 +}
  66 +
  67 +// UseTrans when beginTrans is true , it will begin a new transaction
  68 +// to execute the function, recover when panic happen
  69 +func UseTrans(ctx context.Context,
  70 + db *gorm.DB,
  71 + fn func(context.Context, Conn) error, beginTrans bool) (err error) {
  72 + var tx Conn
  73 + tx = NewTransactionContext(db)
  74 + if beginTrans {
  75 + if err = tx.Begin(); err != nil {
  76 + return
  77 + }
  78 + }
  79 + defer func() {
  80 + if p := recover(); p != nil {
  81 + if e := tx.Rollback(); e != nil {
  82 + err = fmt.Errorf("recover from %#v, rollback failed: %w", p, e)
  83 + } else {
  84 + err = fmt.Errorf("recoveer from %#v", p)
  85 + }
  86 + } else if err != nil {
  87 + if e := tx.Rollback(); e != nil {
  88 + err = fmt.Errorf("transaction failed: %s, rollback failed: %w", err, e)
  89 + }
  90 + } else {
  91 + err = tx.Commit()
  92 + }
  93 + }()
  94 +
  95 + return fn(ctx, tx)
  96 +}
  97 +
  98 +func PaginationAndCount(ctx context.Context, tx *gorm.DB, params map[string]interface{}, dst interface{}) (int64, *gorm.DB) {
  99 + var total int64
  100 + // 只返回数量
  101 + if v, ok := params["countOnly"]; ok && v.(bool) {
  102 + tx = tx.Count(&total)
  103 + return total, tx
  104 + }
  105 + // 只返回记录
  106 + if v, ok := params["findOnly"]; ok && v.(bool) {
  107 + if v, ok := params["offset"]; ok {
  108 + tx.Offset(v.(int))
  109 + }
  110 + if v, ok := params["limit"]; ok {
  111 + tx.Limit(v.(int))
  112 + }
  113 + if tx = tx.Find(dst); tx.Error != nil {
  114 + return 0, tx
  115 + }
  116 + return total, tx
  117 + }
  118 + // 数量跟记录都返回
  119 + tx = tx.Count(&total)
  120 + if tx.Error != nil {
  121 + return total, tx
  122 + }
  123 + if v, ok := params["offset"]; ok {
  124 + tx.Offset(v.(int))
  125 + }
  126 + if v, ok := params["limit"]; ok {
  127 + tx.Limit(v.(int))
  128 + }
  129 + if tx = tx.Find(dst); tx.Error != nil {
  130 + return 0, tx
  131 + }
  132 + return total, tx
  133 +}
  1 +package xcollection
  2 +
  3 +type TreeNode interface {
  4 + PID() string
  5 + ID() string
  6 +}
  7 +
  8 +type Tree struct {
  9 + Node TreeNode `json:"chart"`
  10 + Nodes []*Tree `json:"charts"`
  11 +}
  12 +
  13 +func NewTree(nodes []TreeNode) *Tree {
  14 + var tree = &Tree{
  15 + Node: nil,
  16 + Nodes: make([]*Tree, 0),
  17 + }
  18 + for i := range nodes {
  19 + match := traverseAdd(tree, nodes[i])
  20 + if !match {
  21 + tree.Nodes = append(tree.Nodes, newTree(nodes[i]))
  22 + }
  23 + }
  24 + return tree
  25 +}
  26 +
  27 +func newTree(node TreeNode) *Tree {
  28 + return &Tree{
  29 + Node: node,
  30 + Nodes: make([]*Tree, 0),
  31 + }
  32 +}
  33 +
  34 +func (tree *Tree) Root() TreeNode {
  35 + if tree.Node != nil {
  36 + return tree.Node
  37 + }
  38 + if len(tree.Nodes) > 0 {
  39 + return tree.Nodes[0].Node
  40 + }
  41 + return nil
  42 +}
  43 +
  44 +// TreeNodePaths returns all the parents of the current node 1->5->7 , use time n*O(n)(need performance optimization)
  45 +func (tree *Tree) TreeNodePaths(node TreeNode) []TreeNode {
  46 + treeNode := node
  47 + result := make([]TreeNode, 0)
  48 + for {
  49 + if treeNode == nil {
  50 + break
  51 + }
  52 + tmp := tree.find(treeNode, func(a, b TreeNode) bool {
  53 + if a.ID() == b.PID() {
  54 + return true
  55 + }
  56 + return false
  57 + })
  58 + result = append(result, treeNode)
  59 + if tmp == nil {
  60 + break
  61 + }
  62 + treeNode = tmp.Node
  63 + }
  64 + reserveResult := make([]TreeNode, 0)
  65 + for i := len(result) - 1; i >= 0; i-- {
  66 + reserveResult = append(reserveResult, result[i])
  67 + }
  68 + return reserveResult
  69 +}
  70 +
  71 +// Add adds a node to the first matching parent tree if add success it return true
  72 +func (tree *Tree) Add(node TreeNode) bool {
  73 + return traverseAdd(tree, node)
  74 +}
  75 +
  76 +// AllChildNode returns all child nodes under Node, including itself
  77 +func (tree *Tree) AllChildNode(node TreeNode) []TreeNode {
  78 + treeNode := tree.find(node, nil)
  79 + if treeNode == nil {
  80 + return []TreeNode{}
  81 + }
  82 + return tree.allChildNode(treeNode, nil)
  83 +}
  84 +
  85 +// AllLeafNode returns all leaf node under Node ,if node is nil returns all leaf node under tree
  86 +func (tree *Tree) AllLeafNode(node TreeNode) []TreeNode {
  87 + treeNode := tree
  88 + if node != nil {
  89 + treeNode = tree.find(node, nil)
  90 + }
  91 + if treeNode == nil {
  92 + return []TreeNode{}
  93 + }
  94 + return tree.allChildNode(treeNode, func(node *Tree) bool {
  95 + if len(node.Nodes) == 0 {
  96 + return true
  97 + }
  98 + return false
  99 + })
  100 +}
  101 +
  102 +// Depth returns all child nodes under depth depth=[1:n]
  103 +func (tree *Tree) Depth(depth int) []TreeNode {
  104 + treeNode := tree.find(tree.Root(), nil)
  105 + if treeNode == nil {
  106 + return []TreeNode{}
  107 + }
  108 + return tree.allChildByDepth(treeNode, depth)
  109 +}
  110 +
  111 +// AllChildNodeByDepth returns all child nodes under depth Node
  112 +func (tree *Tree) AllChildNodeByDepth(node TreeNode, depth int) []TreeNode {
  113 + treeNode := tree.find(node, nil)
  114 + if treeNode == nil {
  115 + return []TreeNode{}
  116 + }
  117 + return tree.allChildByDepth(treeNode, depth)
  118 +}
  119 +
  120 +// Find query the node in this tree
  121 +func (tree *Tree) Find(node TreeNode, compared func(a, b TreeNode) bool) *Tree {
  122 + return tree.find(node, compared)
  123 +}
  124 +
  125 +// find query the node in this tree
  126 +func (tree *Tree) find(node TreeNode, compared func(a, b TreeNode) bool) *Tree {
  127 + var stack []*Tree
  128 + stack = append(stack, tree)
  129 + var find *Tree
  130 + for {
  131 + if len(stack) == 0 {
  132 + break
  133 + }
  134 + pop := stack[0]
  135 + stack = stack[1:]
  136 + stack = append(stack, pop.Nodes...)
  137 + if pop == nil || pop.Node == nil {
  138 + continue
  139 + }
  140 + if compared != nil {
  141 + if compared(pop.Node, node) {
  142 + find = pop
  143 + break
  144 + }
  145 + continue
  146 + }
  147 + if pop.Node.ID() == node.ID() {
  148 + find = pop
  149 + break
  150 + }
  151 + }
  152 + return find
  153 +}
  154 +
  155 +// allChildNode 返回treeNode下所有子节点
  156 +func (tree *Tree) allChildNode(treeNode *Tree, filter func(node *Tree) bool) []TreeNode {
  157 + var stack []*Tree
  158 + stack = append(stack, treeNode)
  159 + var res []TreeNode
  160 + for {
  161 + if len(stack) == 0 {
  162 + break
  163 + }
  164 + pop := stack[0]
  165 + stack = stack[1:]
  166 + stack = append(stack, pop.Nodes...)
  167 + if filter != nil && !filter(pop) {
  168 + continue
  169 + }
  170 + res = append(res, pop.Node)
  171 + }
  172 + return res
  173 +}
  174 +
  175 +// traverseAdd 递归添加
  176 +//
  177 +// tree 当前树
  178 +// node 判断的节点
  179 +func traverseAdd(tree *Tree, node TreeNode) bool {
  180 + list := tree.Nodes
  181 + var match bool = false
  182 + for i := range list {
  183 + id, pid := list[i].Node.ID(), node.PID()
  184 + if pid == id {
  185 + list[i].Nodes = append(list[i].Nodes, newTree(node))
  186 + return true
  187 + }
  188 + if match || traverseAdd(list[i], node) {
  189 + match = true
  190 + break
  191 + }
  192 + }
  193 + return match
  194 +}
  195 +
  196 +// allChildByDepth 返回treeNode下指定深度的所有子节点 depth=[1:n]
  197 +func (tree *Tree) allChildByDepth(treeNode *Tree, depth int) []TreeNode {
  198 + var stack []*Tree
  199 + stack = append(stack, treeNode)
  200 + var res []TreeNode
  201 + if depth <= 0 {
  202 + return res
  203 + }
  204 + if treeNode.Root() != nil && depth == 1 {
  205 + return []TreeNode{treeNode.Root()}
  206 + }
  207 + curDepth := 1
  208 + var depthStack []*Tree
  209 + for {
  210 + if len(stack) == 0 {
  211 + break
  212 + }
  213 + pop := stack[0]
  214 + stack = stack[1:]
  215 + depthStack = append(depthStack, pop.Nodes...)
  216 + if len(stack) == 0 {
  217 + curDepth++
  218 + stack = depthStack[:]
  219 + depthStack = []*Tree{}
  220 + if curDepth == depth {
  221 + for i := range stack {
  222 + res = append(res, stack[i].Node)
  223 + }
  224 + break
  225 + }
  226 + }
  227 + }
  228 + return res
  229 +}
  1 +package xcollection
  2 +
  3 +import (
  4 + "github.com/stretchr/testify/assert"
  5 + "strconv"
  6 + "testing"
  7 +)
  8 +
  9 +func prepare() []struct {
  10 + Input []TreeNode
  11 + Text string
  12 + Except []string
  13 + Except2 []string
  14 +} {
  15 + return []struct {
  16 + Input []TreeNode
  17 + Text string
  18 + Except []string
  19 + Except2 []string
  20 + }{
  21 + {
  22 + Input: []TreeNode{
  23 + &st{Id: 1, Pid: 0},
  24 + &st{Id: 2, Pid: 1}, &st{Id: 3, Pid: 1}, &st{Id: 4, Pid: 1},
  25 + &st{Id: 5, Pid: 3},
  26 + &st{Id: 6, Pid: 5}, &st{Id: 7, Pid: 5}},
  27 + Text: `
  28 +树形结构:
  29 + 1
  30 +2 3 4
  31 + 5
  32 + 6 7
  33 +`,
  34 + Except: []string{"5", "6", "7"},
  35 + Except2: []string{"2", "4", "6", "7"},
  36 + },
  37 + }
  38 +}
  39 +
  40 +func Test_Tree(t *testing.T) {
  41 + table := prepare()
  42 + for i := range table {
  43 + tree := NewTree(table[i].Input)
  44 + out := tree.AllChildNode(&st{Id: 5, Pid: 3})
  45 + var res []string = treeNodeResults(out)
  46 + assert.Equal(t, res, table[i].Except)
  47 +
  48 + out = tree.AllLeafNode(nil) //tree.Root()
  49 + res = treeNodeResults(out)
  50 + assert.Equal(t, res, table[i].Except2)
  51 +
  52 + root := tree.Root()
  53 + assert.Equal(t, root.ID(), "1")
  54 +
  55 + //tree.Add(&st{Id:10,Pid: 7})
  56 + //
  57 + //out = tree.AllLeafNode(tree.Root())
  58 + //res = treeNodeResults(out)
  59 + //assert.Equal(t, res, []string{"2", "4", "6", "10"})
  60 +
  61 + out = tree.TreeNodePaths(&st{Id: 7, Pid: 5})
  62 + res = treeNodeResults(out)
  63 + assert.Equal(t, res, []string{"1", "3", "5", "7"})
  64 +
  65 + }
  66 +}
  67 +
  68 +func Test_TreeNodeByDepth(t *testing.T) {
  69 + input := []TreeNode{
  70 + &st{Id: 1, Pid: 0},
  71 + &st{Id: 2, Pid: 1}, &st{Id: 3, Pid: 1}, &st{Id: 4, Pid: 1},
  72 + &st{Id: 5, Pid: 3},
  73 + &st{Id: 6, Pid: 5}, &st{Id: 7, Pid: 5},
  74 + &st{Id: 8, Pid: 6}, &st{Id: 9, Pid: 6}, &st{Id: 10, Pid: 6}, &st{Id: 11, Pid: 7}, &st{Id: 12, Pid: 7},
  75 + }
  76 +
  77 + tree := NewTree(input)
  78 + /*
  79 + 树形结构:
  80 + 1
  81 + 2 3 4
  82 + 5
  83 + 6 7
  84 + 8 9 10 11 12
  85 + */
  86 + var out []TreeNode
  87 + var res []string
  88 + out = tree.AllChildNodeByDepth(&st{Id: 5, Pid: 3}, 2)
  89 + res = treeNodeResults(out)
  90 + assert.Equal(t, []string{"6", "7"}, res)
  91 + out = tree.AllChildNodeByDepth(tree.Root(), 1)
  92 + res = treeNodeResults(out)
  93 + assert.Equal(t, []string{"1"}, res)
  94 + out = tree.AllChildNodeByDepth(tree.Root(), 2)
  95 + res = treeNodeResults(out)
  96 + assert.Equal(t, []string{"2", "3", "4"}, res)
  97 + out = tree.AllChildNodeByDepth(tree.Root(), 3)
  98 + res = treeNodeResults(out)
  99 + assert.Equal(t, []string{"5"}, res)
  100 + out = tree.AllChildNodeByDepth(tree.Root(), 4)
  101 + res = treeNodeResults(out)
  102 + assert.Equal(t, []string{"6", "7"}, res)
  103 + out = tree.AllChildNodeByDepth(tree.Root(), 5)
  104 + res = treeNodeResults(out)
  105 + assert.Equal(t, []string{"8", "9", "10", "11", "12"}, res)
  106 +}
  107 +
  108 +type st struct {
  109 + Id int
  110 + Pid int
  111 +}
  112 +
  113 +func (t *st) PID() string {
  114 + return strconv.Itoa(t.Pid)
  115 +}
  116 +func (t *st) ID() string {
  117 + return strconv.Itoa(t.Id)
  118 +}
  119 +
  120 +func treeNodeResults(nodes []TreeNode) []string {
  121 + var res []string
  122 + for i := range nodes {
  123 + res = append(res, nodes[i].ID())
  124 + }
  125 + return res
  126 +}
  1 +package xerr
  2 +
  3 +/**默认的服务错误**/
  4 +
  5 +func NewErr(err error) *CodeError {
  6 + return &CodeError{errCode: ServerCommonError, InternalError: err}
  7 +}
  8 +
  9 +func NewErrMsg(errMsg string) *CodeError {
  10 + return &CodeError{errCode: ServerCommonError, errMsg: errMsg}
  11 +}
  12 +
  13 +func NewErrMsgErr(errMsg string, internalError error) *CodeError {
  14 + return &CodeError{errCode: ServerCommonError, errMsg: errMsg, InternalError: internalError}
  15 +}
  16 +
  17 +/**指定错误码的错误**/
  18 +
  19 +func NewCodeErr(errCode int, err error) *CodeError {
  20 + return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode), InternalError: err}
  21 +}
  22 +
  23 +func NewCodeErrMsg(errCode int, err error, msg string) *CodeError {
  24 + return &CodeError{errCode: errCode, errMsg: msg, InternalError: err}
  25 +}
  1 +package xerr
  2 +
  3 +import "fmt"
  4 +
  5 +const (
  6 + // OK 成功返回
  7 + OK int = 200
  8 +)
  9 +
  10 +// 全局错误码
  11 +// 系统错误前3位代表业务,后三位代表具体功能
  12 +const (
  13 + ServerCommonError int = 100001 // 系统错误
  14 + RequestParamError int = 100002 // 参数请求错误
  15 + TokenExpireError int = 100003 // token失效
  16 + TokenGenerateError int = 100004 // 生成token失败
  17 + DbError int = 100005 // 数据库错误
  18 + DbUpdateAffectedZeroError int = 100006 // 数据库更新错误
  19 +)
  20 +
  21 +/**微信模块**/
  22 +const (
  23 + ErrWxMiniAuthFailError int = 500001
  24 + ErrUserNoAuth int = 500002
  25 +)
  26 +
  27 +type CodeError struct {
  28 + errCode int
  29 + errMsg string
  30 + InternalError error
  31 +}
  32 +
  33 +// GetErrCode 返回给前端的错误码
  34 +func (e *CodeError) GetErrCode() int {
  35 + return e.errCode
  36 +}
  37 +
  38 +// GetErrMsg 返回给前端显示端错误信息
  39 +func (e *CodeError) GetErrMsg() string {
  40 + if e.errMsg == "" {
  41 + return MapErrMsg(e.errCode)
  42 + }
  43 + return e.errMsg
  44 +}
  45 +
  46 +func (e *CodeError) Error() string {
  47 + if e.InternalError != nil {
  48 + return fmt.Sprintf("code error: code=%d msg:%s error:%s", e.errCode, e.errMsg, e.InternalError.Error())
  49 + }
  50 + return fmt.Sprintf("code error: code=%d msg:%s", e.errCode, e.errMsg)
  51 +}
  1 +package xerr
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/zeromicro/go-zero/core/logx"
  6 + "google.golang.org/grpc/status"
  7 + "net/http"
  8 +)
  9 +
  10 +func ErrorHandlerCtx(ctx context.Context, err error) (int, any) {
  11 + //错误返回
  12 + var (
  13 + errCode = ServerCommonError
  14 + )
  15 + // 自定义错误类型
  16 + if codeError, ok := err.(*CodeError); ok {
  17 + errCode = codeError.GetErrCode()
  18 + } else {
  19 + // grpc err错误
  20 + var grpcStatus *status.Status
  21 + if grpcStatus, ok = status.FromError(err); ok {
  22 + grpcCode := int(grpcStatus.Code())
  23 + if IsCodeErr(grpcCode) {
  24 + errCode = grpcCode
  25 + }
  26 + }
  27 + }
  28 + logx.WithContext(ctx).Errorf("【ERROR-HANDLER】 : %+v ", err)
  29 + response := Error(errCode, MapErrMsg(errCode))
  30 + response.Error = err.Error()
  31 + return http.StatusOK, response
  32 +}
  33 +
  34 +func OkHandlerCtx(ctx context.Context, a any) any {
  35 + return Success(a)
  36 +}
  37 +
  38 +func Success(data interface{}) *ResponseSuccessBean {
  39 + return &ResponseSuccessBean{Code: 0, Msg: "OK", Data: data}
  40 +}
  41 +
  42 +type ResponseSuccessBean struct {
  43 + Code uint32 `json:"code"`
  44 + Msg string `json:"msg"`
  45 + Data interface{} `json:"data"`
  46 +}
  47 +
  48 +type ResponseErrorBean struct {
  49 + Code int `json:"code"`
  50 + Msg string `json:"msg"`
  51 + Error string `json:"err"`
  52 +}
  53 +
  54 +func Error(errCode int, errMsg string) *ResponseErrorBean {
  55 + return &ResponseErrorBean{Code: errCode, Msg: errMsg}
  56 +}
  1 +package xerr
  2 +
  3 +var message map[int]string
  4 +
  5 +func init() {
  6 + message = make(map[int]string)
  7 + message[OK] = "SUCCESS"
  8 + message[ServerCommonError] = "服务器开小差啦,稍后再来试一试"
  9 + message[RequestParamError] = "参数错误"
  10 + message[TokenExpireError] = "token失效,请重新登陆"
  11 + message[TokenGenerateError] = "生成token失败"
  12 + message[DbError] = "数据库繁忙,请稍后再试"
  13 + message[DbUpdateAffectedZeroError] = "更新数据影响行数为0"
  14 + message[ErrUserNoAuth] = "无权限"
  15 + message[ErrWxMiniAuthFailError] = "微信授权失败"
  16 +}
  17 +
  18 +func MapErrMsg(errCode int) string {
  19 + if msg, ok := message[errCode]; ok {
  20 + return msg
  21 + } else {
  22 + return "服务器开小差啦,稍后再来试一试"
  23 + }
  24 +}
  25 +
  26 +func IsCodeErr(errCode int) bool {
  27 + if _, ok := message[errCode]; ok {
  28 + return true
  29 + } else {
  30 + return false
  31 + }
  32 +}