作者 yangfu

init

正在显示 76 个修改的文件 包含 4664 行增加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 +
  28 +app.log
  29 +go.sum
  30 +lastupdate.tmp
  31 +*.log
  32 +
  33 +public/*
  34 +logs/
  1 +FROM golang:1.19-alpine as builder
  2 +
  3 +# Define the project name | 定义项目名称
  4 +ARG PROJECT=core
  5 +
  6 +WORKDIR /build
  7 +COPY . .
  8 +
  9 +RUN go env -w GO111MODULE=on \
  10 + && go env -w GOPROXY=https://goproxy.cn,direct \
  11 + && go env -w CGO_ENABLED=0 \
  12 + && go env \
  13 + && go mod tidy \
  14 + && cd cmd/chart-server/api \
  15 + && go build -ldflags="-s -w" -o /build/api/${PROJECT} ${PROJECT}.go
  16 +
  17 +FROM alpine:latest
  18 +
  19 +# Define the project name | 定义项目名称
  20 +ARG PROJECT=core
  21 +# Define the config file name | 定义配置文件名
  22 +ARG CONFIG_FILE=core.yaml
  23 +# Define the author | 定义作者
  24 +ARG AUTHOR=785409885@qq.com
  25 +
  26 +LABEL org.opencontainers.image.authors=${AUTHOR}
  27 +
  28 +WORKDIR /app
  29 +ENV PROJECT=${PROJECT}
  30 +ENV CONFIG_FILE=${CONFIG_FILE}
  31 +
  32 +COPY --from=builder /build/api/${PROJECT} ./
  33 +COPY --from=builder /build/cmd/chart-server/api/etc/${CONFIG_FILE} ./etc/
  34 +
  35 +EXPOSE 8080
  36 +ENTRYPOINT ./${PROJECT} -f etc/${CONFIG_FILE}
  1 +package main
  2 +
  3 +import (
  4 + "flag"
  5 + "fmt"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  8 + "net/http"
  9 + "strings"
  10 +
  11 + "github.com/golang-jwt/jwt/v4/request"
  12 +
  13 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/config"
  14 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/handler"
  15 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  16 +
  17 + "github.com/zeromicro/go-zero/core/conf"
  18 + "github.com/zeromicro/go-zero/rest"
  19 +)
  20 +
  21 +var configFile = flag.String("f", "etc/core.yaml", "the config file")
  22 +
  23 +func main() {
  24 + flag.Parse()
  25 +
  26 + var c config.Config
  27 + conf.MustLoad(*configFile, &c)
  28 +
  29 + // 默认的token头 Authorization 修改未 x-token
  30 + request.AuthorizationHeaderExtractor = &request.PostExtractionFilter{
  31 + request.HeaderExtractor{"x-mmm-accesstoken"}, func(tok string) (string, error) {
  32 + // Should be a bearer token
  33 + if len(tok) > 6 && strings.ToUpper(tok[0:7]) == "BEARER " {
  34 + return tok[7:], nil
  35 + }
  36 + return tok, nil
  37 + },
  38 + }
  39 +
  40 + // 初始化Domain里面的配置
  41 + domain.ProjectName = c.Name
  42 +
  43 + opts := make([]rest.RunOption, 0)
  44 + // cors
  45 + opt := rest.WithCustomCors(func(header http.Header) {
  46 + header.Set("Access-Control-Allow-Headers", "*")
  47 + }, func(writer http.ResponseWriter) {
  48 +
  49 + })
  50 + opts = append(opts, opt)
  51 +
  52 + server := rest.MustNewServer(c.RestConf, opts...)
  53 + defer server.Stop()
  54 +
  55 + ctx := svc.NewServiceContext(c)
  56 + handler.RegisterHandlers(server, ctx)
  57 +
  58 + db.Migrate(ctx.DB)
  59 +
  60 + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
  61 + server.Start()
  62 +}
  1 +Name: Core
  2 +Host: 0.0.0.0
  3 +Port: 8080
  4 +
  5 +Verbose: false
  6 +
  7 +JwtAuth:
  8 + AccessSecret: digital-platform
  9 + Expire: 360000
  10 +
  11 +Redis:
  12 + Host: 127.0.0.1:6379
  13 + Type: node
  14 + Pass:
  15 +DB:
  16 + DataSource: host=106.52.103.187 user=postgres password=UYXN134KUm8TeE7 dbname=skateboard-test port=25431 sslmode=disable TimeZone=Asia/Shanghai
  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-bchart/pkg/config"
  7 +)
  8 +
  9 +type Config struct {
  10 + rest.RestConf
  11 + config.Config
  12 + Redis redis.RedisConf `json:",optional"`
  13 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func DeleteChartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartDeleteRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewDeleteChartLogic(r.Context(), svcCtx)
  22 + resp, err := l.DeleteChart(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func GetChartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartGetRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewGetChartLogic(r.Context(), svcCtx)
  22 + resp, err := l.GetChart(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func RenameChartSortHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartRenameRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewRenameChartSortLogic(r.Context(), svcCtx)
  22 + resp, err := l.RenameChartSort(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func SaveChartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartSaveRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewSaveChartLogic(r.Context(), svcCtx)
  22 + resp, err := l.SaveChart(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func SearchChartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartSearchRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewSearchChartLogic(r.Context(), svcCtx)
  22 + resp, err := l.SearchChart(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func UpdateChartHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartUpdateRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewUpdateChartLogic(r.Context(), svcCtx)
  22 + resp, err := l.UpdateChart(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package chart
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/logic/chart"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +)
  12 +
  13 +func UpdateChartSortHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.ChartUpdateSortRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := chart.NewUpdateChartSortLogic(r.Context(), svcCtx)
  22 + resp, err := l.UpdateChartSort(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +// Code generated by goctl. DO NOT EDIT.
  2 +package handler
  3 +
  4 +import (
  5 + "net/http"
  6 +
  7 + chart "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/handler/chart"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  9 +
  10 + "github.com/zeromicro/go-zero/rest"
  11 +)
  12 +
  13 +func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
  14 + server.AddRoutes(
  15 + []rest.Route{
  16 + {
  17 + Method: http.MethodGet,
  18 + Path: "/chart/:id",
  19 + Handler: chart.GetChartHandler(serverCtx),
  20 + },
  21 + {
  22 + Method: http.MethodPost,
  23 + Path: "/chart",
  24 + Handler: chart.SaveChartHandler(serverCtx),
  25 + },
  26 + {
  27 + Method: http.MethodDelete,
  28 + Path: "/chart/:id",
  29 + Handler: chart.DeleteChartHandler(serverCtx),
  30 + },
  31 + {
  32 + Method: http.MethodPut,
  33 + Path: "/chart/:id",
  34 + Handler: chart.UpdateChartHandler(serverCtx),
  35 + },
  36 + {
  37 + Method: http.MethodPost,
  38 + Path: "/chart/search",
  39 + Handler: chart.SearchChartHandler(serverCtx),
  40 + },
  41 + {
  42 + Method: http.MethodPost,
  43 + Path: "/chart/move",
  44 + Handler: chart.UpdateChartSortHandler(serverCtx),
  45 + },
  46 + {
  47 + Method: http.MethodPost,
  48 + Path: "/chart/rename",
  49 + Handler: chart.RenameChartSortHandler(serverCtx),
  50 + },
  51 + },
  52 + rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
  53 + rest.WithPrefix("/v1"),
  54 + )
  55 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/contextdata"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  8 +
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +
  12 + "github.com/zeromicro/go-zero/core/logx"
  13 +)
  14 +
  15 +type DeleteChartLogic struct {
  16 + logx.Logger
  17 + ctx context.Context
  18 + svcCtx *svc.ServiceContext
  19 +}
  20 +
  21 +func NewDeleteChartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteChartLogic {
  22 + return &DeleteChartLogic{
  23 + Logger: logx.WithContext(ctx),
  24 + ctx: ctx,
  25 + svcCtx: svcCtx,
  26 + }
  27 +}
  28 +
  29 +func (l *DeleteChartLogic) DeleteChart(req *types.ChartDeleteRequest) (resp *types.ChartDeleteResponse, err error) {
  30 + var (
  31 + conn = l.svcCtx.DefaultDBConn()
  32 + chart *domain.Chart
  33 + tenantId = contextdata.GetTenantFromCtx(l.ctx)
  34 + )
  35 + resp = &types.ChartDeleteResponse{}
  36 + if chart, err = l.svcCtx.ChartRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  37 + return nil, xerr.NewErrMsgErr("不存在", err)
  38 + }
  39 + if chart.TenantId != tenantId {
  40 + return nil, xerr.NewErrMsgErr("无权限", nil)
  41 + }
  42 + // TODO:图表被引用不能删除
  43 + // TODO:删除下级图表
  44 + if chart, err = l.svcCtx.ChartRepository.Delete(l.ctx, conn, chart); err != nil {
  45 + return nil, xerr.NewErrMsgErr("删除失败", err)
  46 + }
  47 +
  48 + resp = &types.ChartDeleteResponse{}
  49 + return
  50 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type GetChartLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewGetChartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChartLogic {
  19 + return &GetChartLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *GetChartLogic) GetChart(req *types.ChartGetRequest) (resp *types.ChartGetResponse, err error) {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return
  30 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/contextdata"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  8 +
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  11 +
  12 + "github.com/zeromicro/go-zero/core/logx"
  13 +)
  14 +
  15 +type RenameChartSortLogic struct {
  16 + logx.Logger
  17 + ctx context.Context
  18 + svcCtx *svc.ServiceContext
  19 +}
  20 +
  21 +func NewRenameChartSortLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RenameChartSortLogic {
  22 + return &RenameChartSortLogic{
  23 + Logger: logx.WithContext(ctx),
  24 + ctx: ctx,
  25 + svcCtx: svcCtx,
  26 + }
  27 +}
  28 +
  29 +func (l *RenameChartSortLogic) RenameChartSort(req *types.ChartRenameRequest) (resp *types.ChartRenameResponse, err error) {
  30 + var (
  31 + conn = l.svcCtx.DefaultDBConn()
  32 + chart *domain.Chart
  33 + tenantId = contextdata.GetTenantFromCtx(l.ctx)
  34 + charts []*domain.Chart
  35 + )
  36 + resp = &types.ChartRenameResponse{}
  37 + if chart, err = l.svcCtx.ChartRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  38 + return nil, xerr.NewErrMsgErr("不存在", err)
  39 + }
  40 + if chart.Name == req.Name {
  41 + return
  42 + }
  43 + if chart.TenantId != tenantId {
  44 + return nil, xerr.NewErrMsgErr("无权限", nil)
  45 + }
  46 + _, charts, err = l.svcCtx.ChartRepository.Find(l.ctx, conn, domain.IndexChartPid(tenantId, chart.Pid)())
  47 + if err != nil {
  48 + return nil, xerr.NewErr(err)
  49 + }
  50 + for i := range charts {
  51 + if charts[i].Name == req.Name {
  52 + return nil, xerr.NewErrMsgErr("名称已存在", nil)
  53 + }
  54 + }
  55 + chart.Name = req.Name
  56 + chart, err = l.svcCtx.ChartRepository.UpdateWithVersion(l.ctx, conn, chart)
  57 + if err != nil {
  58 + return nil, xerr.NewErr(err)
  59 + }
  60 + return
  61 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/contextdata"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/tool"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  10 +
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  13 +
  14 + "github.com/zeromicro/go-zero/core/logx"
  15 +)
  16 +
  17 +type SaveChartLogic struct {
  18 + logx.Logger
  19 + ctx context.Context
  20 + svcCtx *svc.ServiceContext
  21 +}
  22 +
  23 +func NewSaveChartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SaveChartLogic {
  24 + return &SaveChartLogic{
  25 + Logger: logx.WithContext(ctx),
  26 + ctx: ctx,
  27 + svcCtx: svcCtx,
  28 + }
  29 +}
  30 +
  31 +func (l *SaveChartLogic) SaveChart(req *types.ChartSaveRequest) (resp *types.ChartSaveResponse, err error) {
  32 + var (
  33 + conn = l.svcCtx.DefaultDBConn()
  34 + parentChart *domain.Chart
  35 + tenantId = contextdata.GetTenantFromCtx(l.ctx)
  36 + )
  37 + if !domain.ChartTypeContain(req.Type) {
  38 + return nil, xerr.NewErrMsgErr("未知类型:"+req.Type, err)
  39 + }
  40 + chart := &domain.Chart{
  41 + Name: req.Name,
  42 + Type: req.Type,
  43 + Pid: req.Pid,
  44 + Sort: 1,
  45 + Group: tool.Krand(10, tool.KC_RAND_KIND_UPPER),
  46 + TenantId: tenantId,
  47 + }
  48 + if chart.Name == "" {
  49 + chart.Name = chart.RandName()
  50 + }
  51 + if req.Pid > 0 {
  52 + if parentChart, err = l.svcCtx.ChartRepository.FindOne(l.ctx, conn, req.Pid); err != nil {
  53 + return nil, xerr.NewErrMsgErr("父级不存在", err)
  54 + }
  55 + chart.Group = parentChart.Group
  56 + }
  57 + // current sort
  58 + if currentSortChart, _ := l.svcCtx.ChartRepository.FindOneByGroup(l.ctx, conn, tenantId, req.Pid); currentSortChart != nil {
  59 + chart.Sort = currentSortChart.Sort + 1
  60 + }
  61 + if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  62 + if chart, err = l.svcCtx.ChartRepository.Insert(ctx, conn, chart); err != nil {
  63 + return err
  64 + }
  65 + return nil
  66 + }, true); err != nil {
  67 + return nil, xerr.NewErrMsgErr("创建失败", err)
  68 + }
  69 + resp = &types.ChartSaveResponse{
  70 + Chart: types.NewChartItem(chart),
  71 + }
  72 + return
  73 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/samber/lo"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/contextdata"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xcollection"
  9 +
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  12 +
  13 + "github.com/zeromicro/go-zero/core/logx"
  14 +)
  15 +
  16 +type SearchChartLogic struct {
  17 + logx.Logger
  18 + ctx context.Context
  19 + svcCtx *svc.ServiceContext
  20 +}
  21 +
  22 +func NewSearchChartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchChartLogic {
  23 + return &SearchChartLogic{
  24 + Logger: logx.WithContext(ctx),
  25 + ctx: ctx,
  26 + svcCtx: svcCtx,
  27 + }
  28 +}
  29 +
  30 +func (l *SearchChartLogic) SearchChart(req *types.ChartSearchRequest) (resp interface{}, err error) {
  31 + var (
  32 + conn = l.svcCtx.DefaultDBConn()
  33 + tenantId = contextdata.GetTenantFromCtx(l.ctx)
  34 + charts []*domain.Chart
  35 + )
  36 + _, charts, err = l.svcCtx.ChartRepository.Find(l.ctx, conn, domain.IndexTenantId(tenantId)())
  37 + var chartItems = make([]xcollection.TreeNode, 0)
  38 + lo.EveryBy(charts, func(chart *domain.Chart) bool {
  39 + // 按类型过滤
  40 + if len(req.IncludeTypes) > 0 {
  41 + if !lo.Contains(req.IncludeTypes, chart.Type) {
  42 + return true
  43 + }
  44 + }
  45 + chartItems = append(chartItems, types.NewChartItem(chart))
  46 + return true
  47 + })
  48 + if req.DataStyle == "tree" {
  49 + resp = xcollection.NewTree(chartItems).Nodes
  50 + } else if req.DataStyle == "flat" {
  51 + resp = chartItems
  52 + } else {
  53 + resp = chartItems
  54 + }
  55 + return map[string]interface{}{
  56 + "list": resp,
  57 + }, nil
  58 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type UpdateChartLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewUpdateChartLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateChartLogic {
  19 + return &UpdateChartLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *UpdateChartLogic) UpdateChart(req *types.ChartUpdateRequest) (resp *types.ChartUpdateResponse, err error) {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return
  30 +}
  1 +package chart
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/zeromicro/go-zero/core/logx"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/types"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/contextdata"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  12 +)
  13 +
  14 +type UpdateChartSortLogic struct {
  15 + logx.Logger
  16 + ctx context.Context
  17 + svcCtx *svc.ServiceContext
  18 +}
  19 +
  20 +func NewUpdateChartSortLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateChartSortLogic {
  21 + return &UpdateChartSortLogic{
  22 + Logger: logx.WithContext(ctx),
  23 + ctx: ctx,
  24 + svcCtx: svcCtx,
  25 + }
  26 +}
  27 +
  28 +func (l *UpdateChartSortLogic) UpdateChartSort(req *types.ChartUpdateSortRequest) (resp *types.ChartUpdateSortResponse, err error) {
  29 + var (
  30 + conn = l.svcCtx.DefaultDBConn()
  31 + chart *domain.Chart
  32 + chartGroupBefore []*domain.Chart
  33 + chartGroupAfter []*domain.Chart
  34 + tenantId = contextdata.GetTenantFromCtx(l.ctx)
  35 + )
  36 + if chart, err = l.svcCtx.ChartRepository.FindOne(l.ctx, conn, req.Id); err != nil {
  37 + return nil, xerr.NewErrMsgErr("不存在", err)
  38 + }
  39 + var (
  40 + oldPid = chart.Pid
  41 + inSameGroup = req.Pid == chart.Pid // 同一分组
  42 + )
  43 + chart.Sort = req.Index + 1
  44 + chart.Pid = req.Pid
  45 + resp = &types.ChartUpdateSortResponse{}
  46 + // TODO:图表被引用不能移动
  47 +
  48 + // 移动到同一个分组某个位置
  49 + if inSameGroup {
  50 + if _, chartGroupBefore, err = l.svcCtx.ChartRepository.Find(l.ctx, conn, domain.IndexChartPid(tenantId, req.Pid)()); err != nil {
  51 + return nil, xerr.NewErr(err)
  52 + }
  53 + if err = l.updateSort(domain.Reorder(chartGroupBefore, chart, true)); err != nil {
  54 + return nil, xerr.NewErrMsgErr("更新失败", err)
  55 + }
  56 + return
  57 + }
  58 + // 移动到不同分组的某个位置
  59 + if _, chartGroupBefore, err = l.svcCtx.ChartRepository.Find(l.ctx, conn, domain.IndexChartPid(tenantId, oldPid)()); err != nil {
  60 + return nil, xerr.NewErr(err)
  61 + }
  62 + if _, chartGroupAfter, err = l.svcCtx.ChartRepository.Find(l.ctx, conn, domain.IndexChartPid(tenantId, req.Pid)()); err != nil {
  63 + return nil, xerr.NewErr(err)
  64 + }
  65 + list := domain.Reorder(chartGroupBefore, chart, false)
  66 + list = append(list, domain.Reorder(chartGroupAfter, chart, true)...)
  67 + if err = l.updateSort(list); err != nil {
  68 + return nil, xerr.NewErrMsgErr("更新失败", err)
  69 + }
  70 + return
  71 +}
  72 +
  73 +func (l *UpdateChartSortLogic) updateSort(charts []*domain.Chart) error {
  74 + if err := transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  75 + for i := range charts {
  76 + if charts[i].Id == 0 {
  77 + continue
  78 + }
  79 + if _, err := l.svcCtx.ChartRepository.Update(l.ctx, conn, charts[i]); err != nil {
  80 + return err
  81 + }
  82 + }
  83 + return nil
  84 + }, true); err != nil {
  85 + return err
  86 + }
  87 + return nil
  88 +}
  1 +package svc
  2 +
  3 +import (
  4 + "github.com/tiptok/gocomm/pkg/cache/gzcache"
  5 + "github.com/zeromicro/go-zero/core/stores/redis"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/api/internal/config"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/repository"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/cache"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/database"
  12 + "gorm.io/gorm"
  13 +)
  14 +
  15 +type ServiceContext struct {
  16 + Config config.Config
  17 + DB *gorm.DB
  18 + Redis *redis.Redis
  19 + RedisCache gzcache.GZCache
  20 + ChartRepository domain.ChartRepository
  21 +}
  22 +
  23 +func NewServiceContext(c config.Config) *ServiceContext {
  24 + db := database.OpenGormPGDB(c.DB.DataSource)
  25 + mlCache := cache.NewMultiLevelCache([]string{c.Redis.Host}, c.Redis.Pass)
  26 + redisCache := gzcache.NewClusterCache([]string{c.Redis.Host}, c.Redis.Pass)
  27 + redis, _ := redis.NewRedis(redis.RedisConf{Host: c.Redis.Host, Pass: c.Redis.Pass, Type: "node"})
  28 +
  29 + return &ServiceContext{
  30 + Config: c,
  31 + DB: db,
  32 + RedisCache: redisCache,
  33 + Redis: redis,
  34 + ChartRepository: repository.NewChartRepository(cache.NewCachedRepository(mlCache)),
  35 + }
  36 +}
  37 +
  38 +func (svc *ServiceContext) DefaultDBConn() transaction.Conn {
  39 + return transaction.NewTransactionContext(svc.DB)
  40 +}
  1 +package types
  2 +
  3 +import "strconv"
  4 +
  5 +func (item ChartItem) PID() string {
  6 + return strconv.Itoa(int(item.Pid))
  7 +}
  8 +
  9 +func (item ChartItem) ID() string {
  10 + return strconv.Itoa(int(item.Id))
  11 +}
  1 +package types
  2 +
  3 +import (
  4 + "github.com/jinzhu/copier"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  6 +)
  7 +
  8 +func NewChartItem(chart *domain.Chart) ChartItem {
  9 + item := ChartItem{}
  10 + copier.Copy(&item, chart)
  11 + //item.Charts = make([]ChartItem, 0)
  12 + return item
  13 +}
  1 +// Code generated by goctl. DO NOT EDIT.
  2 +package types
  3 +
  4 +type ChartGetRequest struct {
  5 + Id int64 `path:"id"`
  6 +}
  7 +
  8 +type ChartGetResponse struct {
  9 + Chart ChartItem `json:"chart"`
  10 +}
  11 +
  12 +type ChartSaveRequest struct {
  13 + Pid int64 `json:"pid,optional"` // 父级ID
  14 + Type string `json:"type"` // 类型 report:报表 group:分组 chart:图表
  15 + Name string `json:"name,optional"` // 名称
  16 +}
  17 +
  18 +type ChartSaveResponse struct {
  19 + Chart ChartItem `json:"chart"`
  20 +}
  21 +
  22 +type ChartDeleteRequest struct {
  23 + Id int64 `path:"id"`
  24 +}
  25 +
  26 +type ChartDeleteResponse struct {
  27 +}
  28 +
  29 +type ChartUpdateRequest struct {
  30 + Id int64 `path:"id"`
  31 +}
  32 +
  33 +type ChartUpdateResponse struct {
  34 +}
  35 +
  36 +type ChartSearchRequest struct {
  37 + IncludeTypes []string `json:"includeTypes,optional"` //包含的类型: 类型 report:报表 group:分组 chart:图表(未指定返回所有)
  38 + DataStyle string `json:"dataStyle,optional"` // 数据样式 tree:树形 flat:平铺
  39 +}
  40 +
  41 +type ChartSearchResponse struct {
  42 + List []ChartItem `json:"list"`
  43 + Total int64 `json:"total"`
  44 +}
  45 +
  46 +type ChartUpdateSortRequest struct {
  47 + Id int64 `json:"id"`
  48 + Pid int64 `json:"pid"`
  49 + Index int `json:"index"` // 元素下标,从0开始
  50 +}
  51 +
  52 +type ChartUpdateSortResponse struct {
  53 +}
  54 +
  55 +type ChartRenameRequest struct {
  56 + Id int64 `json:"id"`
  57 + Name string `json:"name"` // 名称
  58 +}
  59 +
  60 +type ChartRenameResponse struct {
  61 +}
  62 +
  63 +type ChartItem struct {
  64 + Id int64 `json:"id,optional"` // ID
  65 + Pid int64 `json:"pid,optional"` // 父级ID
  66 + Type string `json:"type,optional"` // 类型 report:报表 group:分组 chart:图表
  67 + Sort int64 `json:"sort,optional"` // 排序
  68 + Name string `json:"name,optional"` // 名称
  69 + //Charts []ChartItem `json:"charts,optional"`
  70 +}
  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: v1
  14 + group: chart
  15 + jwt: JwtAuth
  16 +)
  17 +service Core {
  18 + @handler getChart
  19 + post /chart/:id (ChartGetRequest) returns (ChartGetResponse)
  20 + @handler saveChart
  21 + post /chart (ChartSaveRequest) returns (ChartSaveResponse)
  22 + @handler deleteChart
  23 + delete /chart/:id (ChartDeleteRequest) returns (ChartDeleteResponse)
  24 + @handler updateChart
  25 + put /chart/:id (ChartUpdateRequest) returns (ChartUpdateResponse)
  26 + @handler searchChart
  27 + post /chart/search (ChartSearchRequest) returns (ChartSearchResponse)
  28 +}
  29 +
  30 +type (
  31 + ChartGetRequest {
  32 + Id int64 `path:"id"`
  33 + }
  34 + ChartGetResponse struct{
  35 + Chart ChartItem `json:"chart"`
  36 + }
  37 +
  38 + ChartSaveRequest struct{
  39 + Chart ChartItem `json:"chart"`
  40 + }
  41 + ChartSaveResponse struct{}
  42 +
  43 + ChartDeleteRequest struct{
  44 + Id int64 `path:"id"`
  45 + }
  46 + ChartDeleteResponse struct{}
  47 +
  48 + ChartUpdateRequest struct{
  49 + Id int64 `path:"id"`
  50 + Chart ChartItem `json:"chart"`
  51 + }
  52 + ChartUpdateResponse struct{}
  53 +
  54 + ChartSearchRequest struct{
  55 + Page int `json:"page"`
  56 + Size int `json:"size"`
  57 + }
  58 + ChartSearchResponse{
  59 + List []ChartItem `json:"list"`
  60 + Total int64 `json:"total"`
  61 + }
  62 + ChartItem struct{
  63 +
  64 + }
  65 +)
  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: v1
  14 + group: chart-setting
  15 + jwt: JwtAuth
  16 +)
  17 +service Core {
  18 + @handler getChartSetting
  19 + post /chart-setting/:id (ChartSettingGetRequest) returns (ChartSettingGetResponse)
  20 + @handler saveChartSetting
  21 + post /chart-setting (ChartSettingSaveRequest) returns (ChartSettingSaveResponse)
  22 + @handler deleteChartSetting
  23 + delete /chart-setting/:id (ChartSettingDeleteRequest) returns (ChartSettingDeleteResponse)
  24 + @handler updateChartSetting
  25 + put /chart-setting/:id (ChartSettingUpdateRequest) returns (ChartSettingUpdateResponse)
  26 + @handler searchChartSetting
  27 + post /chart-setting/search (ChartSettingSearchRequest) returns (ChartSettingSearchResponse)
  28 +}
  29 +
  30 +type (
  31 + ChartSettingGetRequest {
  32 + Id int64 `path:"id"`
  33 + }
  34 + ChartSettingGetResponse struct{
  35 + ChartSetting ChartSettingItem `json:"chartSetting"`
  36 + }
  37 +
  38 + ChartSettingSaveRequest struct{
  39 + ChartSetting ChartSettingItem `json:"chartSetting"`
  40 + }
  41 + ChartSettingSaveResponse struct{}
  42 +
  43 + ChartSettingDeleteRequest struct{
  44 + Id int64 `path:"id"`
  45 + }
  46 + ChartSettingDeleteResponse struct{}
  47 +
  48 + ChartSettingUpdateRequest struct{
  49 + Id int64 `path:"id"`
  50 + ChartSetting ChartSettingItem `json:"chartSetting"`
  51 + }
  52 + ChartSettingUpdateResponse struct{}
  53 +
  54 + ChartSettingSearchRequest struct{
  55 + Page int `json:"page"`
  56 + Size int `json:"size"`
  57 + }
  58 + ChartSettingSearchResponse{
  59 + List []ChartSettingItem `json:"list"`
  60 + Total int64 `json:"total"`
  61 + }
  62 + ChartSettingItem struct{
  63 +
  64 + }
  65 +)
  1 +
  2 +syntax = "proto3";
  3 +
  4 +option go_package ="./pb";
  5 +
  6 +package pb;
  7 +
  8 +message ChartGetReq {
  9 + int64 Id = 1;
  10 +}
  11 +message ChartGetResp{
  12 + ChartItem User = 1;
  13 +}
  14 +
  15 +message ChartSaveReq {
  16 +
  17 +}
  18 +message ChartSaveResp{
  19 +
  20 +}
  21 +
  22 +message ChartDeleteReq {
  23 + int64 Id = 1;
  24 +}
  25 +message ChartDeleteResp{
  26 +
  27 +}
  28 +
  29 +message ChartUpdateReq {
  30 + int64 Id = 1;
  31 +}
  32 +message ChartUpdateResp{
  33 +
  34 +}
  35 +
  36 +message ChartSearchReq {
  37 + int64 PageNumber = 1;
  38 + int64 PageSize = 2;
  39 +}
  40 +message ChartSearchResp{
  41 + repeated ChartItem List =1;
  42 + int64 Total =2;
  43 +}
  44 +message ChartItem {
  45 +
  46 +}
  47 +
  48 +service ChartService {
  49 + rpc ChartGet(ChartGetReq) returns(ChartGetResp);
  50 + rpc ChartSave(ChartSaveReq) returns(ChartSaveResp);
  51 + rpc ChartDelete(ChartDeleteReq) returns(ChartDeleteResp);
  52 + rpc ChartUpdate(ChartUpdateReq) returns(ChartUpdateResp);
  53 + rpc ChartSearch(ChartSearchReq) returns(ChartSearchResp);
  54 +}
  1 +
  2 +syntax = "proto3";
  3 +
  4 +option go_package ="./pb";
  5 +
  6 +package pb;
  7 +
  8 +message ChartSettingGetReq {
  9 + int64 Id = 1;
  10 +}
  11 +message ChartSettingGetResp{
  12 + ChartSettingItem User = 1;
  13 +}
  14 +
  15 +message ChartSettingSaveReq {
  16 +
  17 +}
  18 +message ChartSettingSaveResp{
  19 +
  20 +}
  21 +
  22 +message ChartSettingDeleteReq {
  23 + int64 Id = 1;
  24 +}
  25 +message ChartSettingDeleteResp{
  26 +
  27 +}
  28 +
  29 +message ChartSettingUpdateReq {
  30 + int64 Id = 1;
  31 +}
  32 +message ChartSettingUpdateResp{
  33 +
  34 +}
  35 +
  36 +message ChartSettingSearchReq {
  37 + int64 PageNumber = 1;
  38 + int64 PageSize = 2;
  39 +}
  40 +message ChartSettingSearchResp{
  41 + repeated ChartSettingItem List =1;
  42 + int64 Total =2;
  43 +}
  44 +message ChartSettingItem {
  45 +
  46 +}
  47 +
  48 +service ChartSettingService {
  49 + rpc ChartSettingGet(ChartSettingGetReq) returns(ChartSettingGetResp);
  50 + rpc ChartSettingSave(ChartSettingSaveReq) returns(ChartSettingSaveResp);
  51 + rpc ChartSettingDelete(ChartSettingDeleteReq) returns(ChartSettingDeleteResp);
  52 + rpc ChartSettingUpdate(ChartSettingUpdateReq) returns(ChartSettingUpdateResp);
  53 + rpc ChartSettingSearch(ChartSettingSearchReq) returns(ChartSettingSearchResp);
  54 +}
  1 +package db
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/models"
  5 + "gorm.io/gorm"
  6 +)
  7 +
  8 +func Migrate(db *gorm.DB) {
  9 + db.AutoMigrate(&models.Chart{})
  10 +}
  1 +package models
  2 +
  3 +import (
  4 + "fmt"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  6 + "gorm.io/gorm"
  7 + "gorm.io/plugin/soft_delete"
  8 +)
  9 +
  10 +type Chart struct {
  11 + Id int64 // ID
  12 + Pid int64 `gorm:"index:idx_chart_t_pid_sort"` // 父级ID
  13 + Type string // 类型
  14 + Sort int `gorm:"index:idx_chart_t_pid_sort"` // 排序
  15 + Name string // 名称
  16 + Group string `gorm:"index:idx_chart_group"` // 分组
  17 + TenantId int64 `gorm:"index:idx_chart_t_pid_sort"` // 租户ID
  18 +
  19 + CreatedAt int64 `json:",omitempty"`
  20 + UpdatedAt int64 `json:",omitempty"`
  21 + DeletedAt int64 `json:",omitempty"`
  22 + Version int `json:",omitempty"`
  23 + IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"`
  24 +}
  25 +
  26 +func (m *Chart) TableName() string {
  27 + return "chart"
  28 +}
  29 +
  30 +func (m *Chart) BeforeCreate(tx *gorm.DB) (err error) {
  31 + // m.CreatedAt = time.Now().Unix()
  32 + // m.UpdatedAt = time.Now().Unix()
  33 + return
  34 +}
  35 +
  36 +func (m *Chart) BeforeUpdate(tx *gorm.DB) (err error) {
  37 + // m.UpdatedAt = time.Now().Unix()
  38 + return
  39 +}
  40 +
  41 +func (m *Chart) CacheKeyFunc() string {
  42 + if m.Id == 0 {
  43 + return ""
  44 + }
  45 + return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
  46 +}
  47 +
  48 +func (m *Chart) CacheKeyFuncByObject(obj interface{}) string {
  49 + if v, ok := obj.(*Chart); ok {
  50 + return v.CacheKeyFunc()
  51 + }
  52 + return ""
  53 +}
  54 +
  55 +func (m *Chart) CachePrimaryKeyFunc() string {
  56 + if len("") == 0 {
  57 + return ""
  58 + }
  59 + return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
  60 +}
  1 +package models
  2 +
  3 +import (
  4 + "fmt"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  6 + "gorm.io/gorm"
  7 +)
  8 +
  9 +type ChartSetting struct {
  10 + Id int64 // ID
  11 + ChartId int64 // 图表ID
  12 + Property string // 属性
  13 + Style string // 样式
  14 + Series string // 系列值-数据绑定
  15 +
  16 + CreatedAt int64 `json:",omitempty"`
  17 + UpdatedAt int64 `json:",omitempty"`
  18 + DeletedAt int64 `json:",omitempty"`
  19 + Version int `json:",omitempty"`
  20 +}
  21 +
  22 +func (m *ChartSetting) TableName() string {
  23 + return "chart_setting"
  24 +}
  25 +
  26 +func (m *ChartSetting) BeforeCreate(tx *gorm.DB) (err error) {
  27 + // m.CreatedAt = time.Now().Unix()
  28 + // m.UpdatedAt = time.Now().Unix()
  29 + return
  30 +}
  31 +
  32 +func (m *ChartSetting) BeforeUpdate(tx *gorm.DB) (err error) {
  33 + // m.UpdatedAt = time.Now().Unix()
  34 + return
  35 +}
  36 +
  37 +func (m *ChartSetting) CacheKeyFunc() string {
  38 + if m.Id == 0 {
  39 + return ""
  40 + }
  41 + return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
  42 +}
  43 +
  44 +func (m *ChartSetting) CacheKeyFuncByObject(obj interface{}) string {
  45 + if v, ok := obj.(*ChartSetting); ok {
  46 + return v.CacheKeyFunc()
  47 + }
  48 + return ""
  49 +}
  50 +
  51 +func (m *ChartSetting) CachePrimaryKeyFunc() string {
  52 + if len("") == 0 {
  53 + return ""
  54 + }
  55 + return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
  56 +}
  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-bchart/cmd/chart-server/interanl/pkg/db/models"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  11 + "gorm.io/gorm"
  12 +)
  13 +
  14 +type ChartRepository struct {
  15 + *cache.CachedRepository
  16 +}
  17 +
  18 +func (repository *ChartRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.Chart) (*domain.Chart, error) {
  19 + var (
  20 + err error
  21 + m = &models.Chart{}
  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 *ChartRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.Chart) (*domain.Chart, error) {
  36 + var (
  37 + err error
  38 + m *models.Chart
  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 *ChartRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.Chart) (*domain.Chart, error) {
  55 + var (
  56 + err error
  57 + m *models.Chart
  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 *ChartRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.Chart) (*domain.Chart, error) {
  79 + var (
  80 + tx = conn.DB()
  81 + m = &models.Chart{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 *ChartRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.Chart, error) {
  94 + var (
  95 + err error
  96 + tx = conn.DB()
  97 + m = new(models.Chart)
  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.Chart)
  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 *ChartRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.Chart, error) {
  115 + var (
  116 + tx = conn.DB()
  117 + ms []*models.Chart
  118 + dms = make([]*domain.Chart, 0)
  119 + total int64
  120 + )
  121 + queryFunc := func() (interface{}, error) {
  122 + tx = tx.Model(&ms).Order("pid asc").Order("sort asc")
  123 + if v, ok := queryOptions["tenantId"]; ok {
  124 + tx.Where("tenant_id = ?", v)
  125 + }
  126 + if v, ok := queryOptions["pid"]; ok {
  127 + tx.Where("pid = ?", v)
  128 + }
  129 + if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
  130 + return dms, tx.Error
  131 + }
  132 + return dms, nil
  133 + }
  134 +
  135 + if _, err := repository.Query(queryFunc); err != nil {
  136 + return 0, nil, err
  137 + }
  138 +
  139 + for _, item := range ms {
  140 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  141 + return 0, dms, err
  142 + } else {
  143 + dms = append(dms, dm)
  144 + }
  145 + }
  146 + return total, dms, nil
  147 +}
  148 +
  149 +func (repository *ChartRepository) FindOneByGroup(ctx context.Context, conn transaction.Conn, tenantId, pid int64) (*domain.Chart, error) {
  150 + var (
  151 + err error
  152 + tx = conn.DB()
  153 + m = new(models.Chart)
  154 + )
  155 + queryFunc := func() (interface{}, error) {
  156 + tx = tx.Model(m).Where("tenant_id = ?", tenantId).Where("pid = ?", pid).Order("sort desc").Limit(1).First(m)
  157 + if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
  158 + return nil, domain.ErrNotFound
  159 + }
  160 + return m, tx.Error
  161 + }
  162 + if _, err = repository.Query(queryFunc); err != nil {
  163 + return nil, err
  164 + }
  165 + return repository.ModelToDomainModel(m)
  166 +}
  167 +
  168 +func (repository *ChartRepository) ModelToDomainModel(from *models.Chart) (*domain.Chart, error) {
  169 + to := &domain.Chart{}
  170 + err := copier.Copy(to, from)
  171 + return to, err
  172 +}
  173 +
  174 +func (repository *ChartRepository) DomainModelToModel(from *domain.Chart) (*models.Chart, error) {
  175 + to := &models.Chart{}
  176 + err := copier.Copy(to, from)
  177 + return to, err
  178 +}
  179 +
  180 +func NewChartRepository(cache *cache.CachedRepository) domain.ChartRepository {
  181 + return &ChartRepository{CachedRepository: cache}
  182 +}
  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-bchart/cmd/chart-server/interanl/pkg/db/models"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/domain"
  11 + "gorm.io/gorm"
  12 +)
  13 +
  14 +type ChartSettingRepository struct {
  15 + *cache.CachedRepository
  16 +}
  17 +
  18 +func (repository *ChartSettingRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.ChartSetting) (*domain.ChartSetting, error) {
  19 + var (
  20 + err error
  21 + m = &models.ChartSetting{}
  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 *ChartSettingRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.ChartSetting) (*domain.ChartSetting, error) {
  36 + var (
  37 + err error
  38 + m *models.ChartSetting
  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 *ChartSettingRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.ChartSetting) (*domain.ChartSetting, error) {
  55 + var (
  56 + err error
  57 + m *models.ChartSetting
  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 *ChartSettingRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.ChartSetting) (*domain.ChartSetting, error) {
  79 + var (
  80 + tx = conn.DB()
  81 + m = &models.ChartSetting{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 *ChartSettingRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.ChartSetting, error) {
  94 + var (
  95 + err error
  96 + tx = conn.DB()
  97 + m = new(models.ChartSetting)
  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.ChartSetting)
  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 *ChartSettingRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.ChartSetting, error) {
  115 + var (
  116 + tx = conn.DB()
  117 + ms []*models.ChartSetting
  118 + dms = make([]*domain.ChartSetting, 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 *ChartSettingRepository) ModelToDomainModel(from *models.ChartSetting) (*domain.ChartSetting, error) {
  144 + to := &domain.ChartSetting{}
  145 + err := copier.Copy(to, from)
  146 + return to, err
  147 +}
  148 +
  149 +func (repository *ChartSettingRepository) DomainModelToModel(from *domain.ChartSetting) (*models.ChartSetting, error) {
  150 + to := &models.ChartSetting{}
  151 + err := copier.Copy(to, from)
  152 + return to, err
  153 +}
  154 +
  155 +func NewChartSettingRepository(cache *cache.CachedRepository) domain.ChartSettingRepository {
  156 + return &ChartSettingRepository{CachedRepository: cache}
  157 +}
  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{}, v interface{}) (int64, *gorm.DB) {
  99 + var total int64
  100 + var enableCounter bool = false
  101 + if v, ok := params["enableCounter"]; ok {
  102 + enableCounter = v.(bool)
  103 + }
  104 + if enableCounter {
  105 + tx = tx.Count(&total)
  106 + return total, tx
  107 + }
  108 + tx = tx.Count(&total)
  109 + if tx.Error != nil {
  110 + return total, tx
  111 + }
  112 + if v, ok := params["offset"]; ok {
  113 + tx.Offset(v.(int))
  114 + }
  115 + if v, ok := params["limit"]; ok {
  116 + tx.Limit(v.(int))
  117 + }
  118 + if tx = tx.Find(v); tx.Error != nil {
  119 + return 0, tx
  120 + }
  121 + return total, tx
  122 +}
  1 +package domain
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/tool"
  7 + "golang.org/x/exp/slices"
  8 + "sort"
  9 + "strings"
  10 +)
  11 +
  12 +type Chart struct {
  13 + Id int64 // ID
  14 + Pid int64 // 父级ID
  15 + Type string // 类型
  16 + Sort int // 排序
  17 + Name string // 名称
  18 + Group string // 分组
  19 + TenantId int64 // 租户ID
  20 +
  21 + CreatedAt int64 `json:",omitempty"`
  22 + UpdatedAt int64 `json:",omitempty"`
  23 + DeletedAt int64 `json:",omitempty"`
  24 + Version int `json:",omitempty"`
  25 +}
  26 +
  27 +type ChartRepository interface {
  28 + Insert(ctx context.Context, conn transaction.Conn, dm *Chart) (*Chart, error)
  29 + Update(ctx context.Context, conn transaction.Conn, dm *Chart) (*Chart, error)
  30 + UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Chart) (*Chart, error)
  31 + Delete(ctx context.Context, conn transaction.Conn, dm *Chart) (*Chart, error)
  32 + FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Chart, error)
  33 + Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*Chart, error)
  34 + FindOneByGroup(ctx context.Context, conn transaction.Conn, tenantId, pid int64) (*Chart, error)
  35 +}
  36 +
  37 +/*************** 索引函数 开始****************/
  38 +
  39 +func IndexTenantId(tenantId int64) IndexQueryOptionFunc {
  40 + return func() QueryOptions {
  41 + return NewQueryOptions().WithKV("tenantId", tenantId)
  42 + }
  43 +}
  44 +
  45 +func IndexChartPid(tenantId, pid int64) IndexQueryOptionFunc {
  46 + return func() QueryOptions {
  47 + return NewQueryOptions().WithKV("tenantId", tenantId).WithKV("pid", pid)
  48 + }
  49 +}
  50 +
  51 +func (m *Chart) Identify() interface{} {
  52 + if m.Id == 0 {
  53 + return nil
  54 + }
  55 + return m.Id
  56 +}
  57 +
  58 +func (m *Chart) RandName() string {
  59 + randNumber := tool.Krand(6, tool.KC_RAND_KIND_NUM)
  60 + var result strings.Builder
  61 + switch m.Type {
  62 + case ChartTypeReport:
  63 + result.WriteString("未命名报表")
  64 + case ChartTypeGroup:
  65 + result.WriteString("未命名分组")
  66 + case ChartTypeChart:
  67 + result.WriteString("未命名图表")
  68 + }
  69 + result.WriteString(randNumber)
  70 + return result.String()
  71 +}
  72 +
  73 +// Reorder 重新排序charts
  74 +// appendFlag:true 追加 target 到 charts
  75 +// appendFlag:false 不追加
  76 +func Reorder(charts []*Chart, target *Chart, appendFlag bool) []*Chart {
  77 + // 重排序
  78 + var result = make([]*Chart, 0)
  79 + sort.SliceStable(charts, func(i, j int) bool {
  80 + return charts[i].Sort < charts[j].Sort
  81 + })
  82 + for index, c := range charts {
  83 + c.Sort = index + 1
  84 + if c.Id == target.Id {
  85 + result = append(result, &Chart{Sort: c.Sort}) // 旧节点继续追击啊,ID设置为0,后面跳过更新
  86 + continue
  87 + }
  88 + result = append(result, c)
  89 + }
  90 + // 插入新的节点
  91 + if appendFlag {
  92 + index := slices.IndexFunc(result, func(c *Chart) bool {
  93 + if float64(c.Sort) > float64(target.Sort)-0.5 {
  94 + return true
  95 + }
  96 + return false
  97 + })
  98 + if index == -1 {
  99 + index = len(result)
  100 + }
  101 + result = slices.Insert(result, index, target)
  102 + }
  103 + // 重排序
  104 + var index = 1
  105 + for i := range result {
  106 + if result[i].Id == 0 {
  107 + continue
  108 + }
  109 + result[i].Sort = index
  110 + index++
  111 + }
  112 + return result
  113 +}
  1 +package domain
  2 +
  3 +type ChartProperty struct {
  4 + Title *Title `json:"title,optional"` // 标题
  5 + FilterRule *FilterRule `json:"filterRule,optional"` // 过滤规则
  6 + Series []*Series `json:"series,optional"` // 系列
  7 + Cover string `json:"cover,optional"` // 封面
  8 +
  9 + //XAxis interface{} `json:"xAxis"` // X轴
  10 + //YAxis interface{} `json:"yAxis"` // Y轴
  11 +}
  12 +
  13 +type Series struct {
  14 + Type string `json:"type"` // 图表类型 (记录型表格:RecordTable-1 总体指标:MetricsCard-1 容器卡片:ContainerCard-1 四分图:QuarterChart-1)
  15 + Name string `json:"name"` // 名称
  16 + Data interface{} `json:"data"` // 保存配置的时候置空
  17 + Config *DataConfig `json:"config"` // 配置
  18 +}
  19 +
  20 +type Title struct {
  21 + MainTitle *TitleInfo `json:"main,optional"` // 主标题
  22 + SubTitle *TitleInfo `json:"sub,optional"` // 副标题
  23 +}
  24 +
  25 +type TitleInfo struct {
  26 + Content string `json:"content,optional"` // 标题内容
  27 + Description *Description `json:"description,optional"` // 描述
  28 +}
  29 +
  30 +type Description struct {
  31 + Type string `json:"type"` // text:文字 attachment:附件
  32 + Remark string `json:"remark,optional"` // 备注说明
  33 + Attachment *File `json:"attachment,optional"` // 附件
  34 +}
  35 +
  36 +type File struct {
  37 + FileName string `json:"name"`
  38 + Url string `json:"url"`
  39 +}
  40 +
  41 +type FilterRule struct {
  42 + FilterItems []*FilterItem `json:"items"`
  43 +}
  44 +
  45 +type FilterItem struct {
  46 + FieldItem
  47 +}
  48 +
  49 +// FieldItem 字段项
  50 +type FieldItem struct {
  51 + Source
  52 + Field string `json:"field"`
  53 +}
  54 +
  55 +type Source struct {
  56 + From string `json:"from"` // 数据源类型 ByteBank:字库 User:用户自定义
  57 + SourceId int64 `json:"id"` // 数据源ID(from值为ByteBank时有值)
  58 + CustomData interface{} `json:"customData"` // 自定义数据(from值为User时有值)
  59 +}
  60 +
  61 +type DataConfig struct {
  62 + Source Source `json:"source"`
  63 +}
  1 +package domain
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/db/transaction"
  6 +)
  7 +
  8 +type ChartSetting struct {
  9 + Id int64 // ID
  10 + ChartId int64 // 图表ID
  11 + Property string // 属性
  12 + Style string // 样式
  13 + Series string // 系列值-数据绑定
  14 +
  15 + CreatedAt int64 `json:",omitempty"`
  16 + UpdatedAt int64 `json:",omitempty"`
  17 + DeletedAt int64 `json:",omitempty"`
  18 + Version int `json:",omitempty"`
  19 +}
  20 +
  21 +type ChartSettingRepository interface {
  22 + Insert(ctx context.Context, conn transaction.Conn, dm *ChartSetting) (*ChartSetting, error)
  23 + Update(ctx context.Context, conn transaction.Conn, dm *ChartSetting) (*ChartSetting, error)
  24 + UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *ChartSetting) (*ChartSetting, error)
  25 + Delete(ctx context.Context, conn transaction.Conn, dm *ChartSetting) (*ChartSetting, error)
  26 + FindOne(ctx context.Context, conn transaction.Conn, id int64) (*ChartSetting, error)
  27 + Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*ChartSetting, error)
  28 +}
  29 +
  30 +func (m *ChartSetting) Identify() interface{} {
  31 + if m.Id == 0 {
  32 + return nil
  33 + }
  34 + return m.Id
  35 +}
  1 +package domain
  2 +
  3 +import (
  4 + "github.com/magiconair/properties/assert"
  5 + "testing"
  6 +)
  7 +
  8 +func TestReorder(t *testing.T) {
  9 + //chartsAfter:
  10 + //target := &Chart{Id: 3, Pid: 0, Sort: 3}
  11 + inputs := []struct {
  12 + charts []*Chart
  13 + targetId int64
  14 + sortIndex int
  15 + pid int64
  16 + appendFlag bool
  17 + want []int64
  18 + }{
  19 + {createChartsBefore(), 3, 1, 0, true, []int64{3, 1, 2}},
  20 + {createChartsBefore(), 3, 2, 0, true, []int64{1, 3, 2}},
  21 + {createChartsBefore(), 3, 3, 0, true, []int64{1, 2, 3}},
  22 + {createChartsBefore(), 3, 4, 0, true, []int64{1, 2, 3}},
  23 + {createChartsBefore(), 3, 1, 1, false, []int64{1, 2}},
  24 + }
  25 + for _, input := range inputs {
  26 + assert.Equal(t, chartIds(Reorder(input.charts, &Chart{Id: input.targetId, Pid: input.pid, Sort: input.sortIndex}, input.appendFlag)), input.want)
  27 + }
  28 +}
  29 +func chartIds(charts []*Chart) []int64 {
  30 + var idList = make([]int64, 0)
  31 + for _, c := range charts {
  32 + if c.Id == 0 {
  33 + continue
  34 + }
  35 + idList = append(idList, c.Id)
  36 + }
  37 + return idList
  38 +}
  39 +
  40 +func createChartsBefore() []*Chart {
  41 + return []*Chart{
  42 + {Id: 1, Pid: 0, Sort: 1},
  43 + {Id: 2, Pid: 0, Sort: 2},
  44 + {Id: 3, Pid: 0, Sort: 3},
  45 + }
  46 +}
  47 +
  48 +func createChartsAfter() []*Chart {
  49 + return []*Chart{
  50 + {Id: 5, Pid: 1, Sort: 1},
  51 + {Id: 6, Pid: 1, Sort: 2},
  52 + {Id: 7, Pid: 1, Sort: 3},
  53 + }
  54 +}
  1 +package domain
  2 +
  3 +import "github.com/samber/lo"
  4 +
  5 +const (
  6 + ChartTypeReport = "report" // 报表
  7 + ChartTypeGroup = "group" // 分组
  8 + ChartTypeChart = "chart" // 图表
  9 +)
  10 +
  11 +func ChartTypeContain(t string) bool {
  12 + return lo.Contains([]string{ChartTypeReport, ChartTypeGroup, ChartTypeChart}, t)
  13 +}
  1 +package domain
  2 +
  3 +import "reflect"
  4 +
  5 +func OffsetLimit(page, size int) (offset int, limit int) {
  6 + if page == 0 {
  7 + page = 1
  8 + }
  9 + if size == 0 {
  10 + size = 20
  11 + }
  12 + offset = (page - 1) * size
  13 + limit = size
  14 + return
  15 +}
  16 +
  17 +type QueryOptions map[string]interface{}
  18 +
  19 +func NewQueryOptions() QueryOptions {
  20 + options := make(map[string]interface{})
  21 + return options
  22 +}
  23 +func (options QueryOptions) WithOffsetLimit(page, size int) QueryOptions {
  24 + offset, limit := OffsetLimit(page, size)
  25 + options["offset"] = offset
  26 + options["limit"] = limit
  27 + return options
  28 +}
  29 +
  30 +func (options QueryOptions) WithKV(key string, value interface{}) QueryOptions {
  31 + if reflect.ValueOf(value).IsZero() {
  32 + return options
  33 + }
  34 + options[key] = value
  35 + return options
  36 +}
  37 +
  38 +func (options QueryOptions) EnableCounter() QueryOptions {
  39 + return options.WithKV("enableCounter", true)
  40 +}
  41 +
  42 +func (options QueryOptions) Copy() QueryOptions {
  43 + newOptions := NewQueryOptions()
  44 + for k, v := range options {
  45 + newOptions[k] = v
  46 + }
  47 + return newOptions
  48 +}
  49 +
  50 +type IndexQueryOptionFunc func() QueryOptions
  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 = "project"
  1 +package gateway
  2 +
  3 +import (
  4 + "encoding/json"
  5 + "fmt"
  6 +)
  7 +
  8 +type MessageCode struct {
  9 + Code int `json:"code"`
  10 + Msg string `json:"msg"`
  11 +}
  12 +
  13 +// Response 统一消息返回格式
  14 +type Response struct {
  15 + MessageCode
  16 + Data json.RawMessage `json:"data"`
  17 +}
  18 +
  19 +//
  20 +//type Request struct {
  21 +// Url string
  22 +// Method string
  23 +// Param interface{}
  24 +//}
  25 +
  26 +type HttpError struct {
  27 + Base Response
  28 +}
  29 +
  30 +func (e HttpError) Error() string {
  31 + return fmt.Sprintf("HttpError code:%d msg:%s", e.Base.Code, e.Base.Msg)
  32 +}
  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 + "net/http"
  10 + "strings"
  11 + "time"
  12 +)
  13 +
  14 +type Service struct {
  15 + Timeout time.Duration
  16 + host string
  17 + Interceptor func(msg string)
  18 + ServiceName string
  19 + service httpc.Service
  20 +}
  21 +
  22 +func NewService(name string, host string, timeout time.Duration, opts ...httpc.Option) Service {
  23 + client := &http.Client{}
  24 + client.Timeout = timeout
  25 +
  26 + service := Service{
  27 + service: httpc.NewServiceWithClient(name, client, opts...),
  28 + }
  29 + return service
  30 +}
  31 +
  32 +func (gateway Service) Do(ctx context.Context, url string, method string, val interface{}, result interface{}) error {
  33 + var (
  34 + baseResponse = &Response{}
  35 + begin = time.Now()
  36 + )
  37 + response, err := gateway.service.Do(ctx, gateway.host+url, method, val)
  38 + defer func() {
  39 + jsonParam, _ := json.Marshal(val)
  40 + jsonData, _ := json.Marshal(result)
  41 + if err != nil {
  42 + result = err.Error()
  43 + }
  44 + if gateway.Interceptor != nil {
  45 + gateway.Interceptor(fmt.Sprintf("【网关】%v | %v%v | %v : %v \n-->> %v \n<<-- %v", time.Since(begin), gateway.host, url, strings.ToUpper(method),
  46 + result,
  47 + string(jsonParam),
  48 + string(jsonData),
  49 + ))
  50 + }
  51 + }()
  52 + if err != nil {
  53 + return err
  54 + }
  55 + if response.StatusCode != http.StatusOK {
  56 + return HttpError{
  57 + Base: Response{
  58 + MessageCode: MessageCode{
  59 + Code: response.StatusCode,
  60 + Msg: response.Status,
  61 + },
  62 + },
  63 + }
  64 + }
  65 + if err = httpc.ParseJsonBody(response, baseResponse); err != nil {
  66 + return err
  67 + }
  68 + if err = mapping.UnmarshalJsonBytes(baseResponse.Data, result); err != nil {
  69 + return err
  70 + }
  71 +
  72 + return nil
  73 +}
  1 +package bytelib
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/cmd/chart-server/interanl/pkg/gateway"
  5 +)
  6 +
  7 +type ByteMetadataService struct {
  8 + gateway.Service
  9 +}
  1 +package bytelib
  2 +
  3 +import (
  4 + "context"
  5 + "net/http"
  6 +)
  7 +
  8 +func (gateway *ByteMetadataService) TableDataPreview(ctx context.Context, request *TableDataPreviewRequest) (TablePreviewResponse, error) {
  9 + var result TablePreviewResponse
  10 + if err := gateway.Do(ctx, "/data/table-preview", http.MethodPost, request, &result); err != nil {
  11 + return result, err
  12 + }
  13 + return result, nil
  14 +}
  15 +
  16 +type TableDataPreviewRequest struct {
  17 + ObjectId int64 `json:"objectId"` //表ID
  18 + ObjectType string `json:"objectType"` //表类型 File:文件 MetaTable:元表 DBTable:数据库表 ;当对象类型为DBTable时 objectId 1:表操作日志 2.拆解模块日志
  19 + Where *TableQueryWhere `json:"where"` //查询条件
  20 + UseCache bool `json:"useCache"`
  21 + HiddenData bool `json:"hiddenData"` // 隐藏数据,只返回结构
  22 +}
  23 +
  24 +type TableQueryWhere struct {
  25 + PageNumber int64 `json:"pageNumber"`
  26 + PageSize int64 `json:"pageSize"`
  27 + Conditions []*TableQueryCondition `json:"conditions"`
  28 +}
  29 +
  30 +type TableQueryCondition struct {
  31 + Field *Field `json:"field"` //字段
  32 + Like string `json:"like"` //模糊匹配
  33 + In []string `json:"in"` //包含项
  34 + Ex []string `json:"ex"` //排除项
  35 + Order string `json:"order"` //排序 ASC正序 DESC降序
  36 +}
  37 +
  38 +type TablePreviewResponse TableData
  39 +
  40 +type TablePreview struct {
  41 + Code int `json:"code"`
  42 + Msg string `json:"msg"`
  43 + Data *TableData `json:"data"`
  44 +}
  45 +
  46 +type TableData struct {
  47 + //表ID
  48 + ObjectId int64 `json:"objectId"`
  49 + //表名
  50 + Name string `json:"name"`
  51 + //数据
  52 + Grid *TableDataGrid `json:"grid"`
  53 + //字段
  54 + Fields []*Field `json:"fields"`
  55 +}
  56 +
  57 +type TableDataGrid struct {
  58 + //数据列表
  59 + List []interface{} `json:"list"`
  60 + //总记录数
  61 + Total int64 `json:"total"`
  62 +}
  1 +package bytelib
  2 +
  3 +import (
  4 + "context"
  5 + "net/http"
  6 +)
  7 +
  8 +func (gateway *ByteMetadataService) TableInfo(ctx context.Context, request *TableInfoRequest) (TableInfoResponse, error) {
  9 + var result TableInfoResponse
  10 + if err := gateway.Do(ctx, "/tables/:tableId", http.MethodGet, request, &result); err != nil {
  11 + return result, err
  12 + }
  13 + return result, nil
  14 +}
  15 +
  16 +type TableInfoRequest struct {
  17 + TableId int `path:"tableId"`
  18 +}
  19 +type TableInfoResponse struct {
  20 + // 表Id
  21 + TableId int `json:"tableId"`
  22 + // 表类型 MainTable:主表 SideTable:副表 SubTable:分表 ExcelTable:Excel表
  23 + TableType string `json:"tableType"`
  24 + // 名称
  25 + Name string `json:"name"`
  26 + // 父级ID
  27 + ParentId int `json:"parentId"`
  28 + // 主表字段
  29 + //MainTableFields []*Field `json:"mainTableFields"`
  30 + // 手动添加字段
  31 + //ManualFields []*Field `json:"manualFields"`
  32 + // 数据列
  33 + Fields []*Field `json:"fields"`
  34 + // 模块 应用于模块 1:数控中心 2:拆解模块 4:计算模块
  35 + Module int `json:"module"`
  36 +}
  1 +package bytelib
  2 +
  3 +import (
  4 + "context"
  5 + "net/http"
  6 +)
  7 +
  8 +func (gateway *ByteMetadataService) ObjectTableSearch(ctx context.Context, request ObjectTableSearchRequest) (ObjectTableSearchResponse, error) {
  9 + result := ObjectTableSearchResponse{}
  10 + if err := gateway.Do(ctx, "/data/table-object-search", http.MethodPost, request, &result); err != nil {
  11 + return result, err
  12 + }
  13 + return result, nil
  14 +}
  15 +
  16 +type ObjectTableSearchRequest struct {
  17 + // 表名称
  18 + Name string `cname:"表名称" json:"name"`
  19 + //ViewType string `cname:"视图类型 full:完整 main:主表关系" json:"viewType"`
  20 + // 表类型 MainTable:主表 SideTable:副表 SubTable:分表 ExcelTable:Excel表 SubProcess:子过程 Schema:方案
  21 + TableTypes []string `cname:"表类型 MainTable:主表 SideTable:副表 SubTable:分表 ExcelTable:Excel表" json:"tableTypes" valid:"Required"`
  22 + // 父级ID
  23 + ParentId int `cname:"父级ID" json:"parentId"`
  24 + // 模块 应用于模块 1:数控中心 2:拆解模块 4:计算模块
  25 + Module int `json:"module"`
  26 + // 父级ID
  27 + ParentTableId int `cname:"父级ID" json:"parentTableId"`
  28 + // 返回结构信息
  29 + ReturnDetailStructInfo bool `cname:"返回具体的结构信息 默认不返回" json:"returnDetailStructInfo"`
  30 + // 排除分组项,只返回一级列表;默认 false 不排除,连分组也返回
  31 + ReturnGroupItem bool `cname:"排除分组" json:"returnGroupItem"`
  32 + // 排除指定表
  33 + ExcludeTables []int `cname:"排除指定表" json:"excludeTables"`
  34 + FilterRules []*FilterRule `json:"filterRules"`
  35 + TableId int `cname:"ID" json:"tableId"`
  36 +}
  37 +
  38 +type ObjectTableSearchResponse struct {
  39 + Count int `json:"count"`
  40 + List []*Table `json:"list"`
  41 +}
  42 +
  43 +type FilterRule struct {
  44 + // *:匹配所有
  45 + TableType string `json:"tableType"`
  46 + Status int `json:"status"`
  47 +}
  48 +
  49 +type Table struct {
  50 + // 序号
  51 + Id int `json:"id"`
  52 + // 表Id
  53 + TableId int `json:"tableId"`
  54 + // 表类型 MainTable:主表 SideTable:副表 SubTable:分表 ExcelTable:Excel表
  55 + TableType string `json:"tableType"`
  56 + // 名称
  57 + Name string `json:"name"`
  58 + // 对应数据库名称
  59 + SQLName string `json:"sqlName,omitempty"`
  60 + // 父级ID
  61 + ParentId int `json:"parentId"`
  62 + // 模块 应用于模块 1:数控中心 2:拆解模块 4:计算模块
  63 + Module int `json:"module"`
  64 + // 标识
  65 + Flag string `json:"flag,omitempty"`
  66 + // 启用状态
  67 + Status int `json:"status"`
  68 + // 冲突状态
  69 + InConflict bool `json:"inConflict"`
  70 + // 表字段
  71 + Fields []*Field `json:"fields"`
  72 +}
  73 +
  74 +// Field 字段
  75 +type Field struct {
  76 + // 名称
  77 + Name string `json:"name"`
  78 + // 对应数据库名称
  79 + SQLName string `json:"sqlName"`
  80 + // 对应数据库类型
  81 + SQLType string `json:"sqlType"`
  82 + // 标识 1.主键 2:主表字段 3:手动添加
  83 + Flag int `json:"flag"`
  84 +}
  1 +package bytelib
  2 +
  3 +var (
  4 + MainTable TableType = "MainTable" // 主表
  5 + SideTable TableType = "SideTable" // 副表
  6 + SubTable TableType = "SubTable" // 分表
  7 + SchemaTable TableType = "Schema" // 方案
  8 + SubProcessTable TableType = "SubProcess" // 子过程
  9 + CalculateItem TableType = "CalculateItem" // 计算项
  10 + CalculateTable TableType = "CalculateTable" // 计算表
  11 + CalculateSet TableType = "CalculateSet" // 计算集
  12 +)
  13 +
  14 +type TableType string
  15 +
  16 +func (t TableType) ToString() string {
  17 + return string(t)
  18 +}
  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 +## 生成模型
  2 +
  3 +```
  4 +goctl model mysql ddl -s .\doc\dsl\model\table.sql -d cmd/chart-server
  5 +```
  6 +
  7 +## api生成
  8 +
  9 +```
  10 +goctl api go -api .\doc\dsl\api\core.api -dir cmd/chart-server/api -style go_zero
  11 +```
  12 +
  13 +## swagger 生成
  14 +
  15 +```
  16 +goctl api plugin -plugin goctl-swagger="swagger -filename core.json" -api .\doc\dsl\api\core.api -dir .\doc\dsl\api
  17 +```
  18 +
  19 +## 镜像生成
  20 +
  21 +```
  22 +docker build -f Dockerfile -t tiptok/sumifcc-bchart:1.0.0 .
  23 +```
  1 +import "core/chart.api"
  2 +// import "./core/chart_stting.api"
  1 +{
  2 + "swagger": "2.0",
  3 + "info": {
  4 + "title": "",
  5 + "version": ""
  6 + },
  7 + "schemes": [
  8 + "http",
  9 + "https"
  10 + ],
  11 + "consumes": [
  12 + "application/json"
  13 + ],
  14 + "produces": [
  15 + "application/json"
  16 + ],
  17 + "paths": {
  18 + "v1/chart": {
  19 + "post": {
  20 + "summary": "保存图表",
  21 + "operationId": "saveChart",
  22 + "responses": {
  23 + "200": {
  24 + "description": "A successful response.",
  25 + "schema": {
  26 + "$ref": "#/definitions/ChartSaveResponse"
  27 + }
  28 + }
  29 + },
  30 + "parameters": [
  31 + {
  32 + "name": "body",
  33 + "in": "body",
  34 + "required": true,
  35 + "schema": {
  36 + "$ref": "#/definitions/ChartSaveRequest"
  37 + }
  38 + }
  39 + ],
  40 + "requestBody": {},
  41 + "tags": [
  42 + "chart"
  43 + ]
  44 + }
  45 + },
  46 + "v1/chart/rename": {
  47 + "post": {
  48 + "summary": "更新图表排序",
  49 + "operationId": "renameChartSort",
  50 + "responses": {
  51 + "200": {
  52 + "description": "A successful response.",
  53 + "schema": {
  54 + "$ref": "#/definitions/ChartUpdateSortResponse"
  55 + }
  56 + }
  57 + },
  58 + "parameters": [
  59 + {
  60 + "name": "body",
  61 + "in": "body",
  62 + "required": true,
  63 + "schema": {
  64 + "$ref": "#/definitions/ChartUpdateSortRequest"
  65 + }
  66 + }
  67 + ],
  68 + "requestBody": {},
  69 + "tags": [
  70 + "chart"
  71 + ]
  72 + }
  73 + },
  74 + "v1/chart/search": {
  75 + "post": {
  76 + "summary": "搜索图表",
  77 + "operationId": "searchChart",
  78 + "responses": {
  79 + "200": {
  80 + "description": "A successful response.",
  81 + "schema": {
  82 + "$ref": "#/definitions/ChartSearchResponse"
  83 + }
  84 + }
  85 + },
  86 + "parameters": [
  87 + {
  88 + "name": "body",
  89 + "in": "body",
  90 + "required": true,
  91 + "schema": {
  92 + "$ref": "#/definitions/ChartSearchRequest"
  93 + }
  94 + }
  95 + ],
  96 + "requestBody": {},
  97 + "tags": [
  98 + "chart"
  99 + ]
  100 + }
  101 + },
  102 + "v1/chart/sort": {
  103 + "post": {
  104 + "summary": "更新图表排序",
  105 + "operationId": "updateChartSort",
  106 + "responses": {
  107 + "200": {
  108 + "description": "A successful response.",
  109 + "schema": {
  110 + "$ref": "#/definitions/ChartUpdateSortResponse"
  111 + }
  112 + }
  113 + },
  114 + "parameters": [
  115 + {
  116 + "name": "body",
  117 + "in": "body",
  118 + "required": true,
  119 + "schema": {
  120 + "$ref": "#/definitions/ChartUpdateSortRequest"
  121 + }
  122 + }
  123 + ],
  124 + "requestBody": {},
  125 + "tags": [
  126 + "chart"
  127 + ]
  128 + }
  129 + },
  130 + "v1/chart/{id}": {
  131 + "get": {
  132 + "summary": "获取图表详情",
  133 + "operationId": "getChart",
  134 + "responses": {
  135 + "200": {
  136 + "description": "A successful response.",
  137 + "schema": {
  138 + "$ref": "#/definitions/ChartGetResponse"
  139 + }
  140 + }
  141 + },
  142 + "parameters": [
  143 + {
  144 + "name": "id",
  145 + "in": "path",
  146 + "required": true,
  147 + "type": "string"
  148 + }
  149 + ],
  150 + "requestBody": {},
  151 + "tags": [
  152 + "chart"
  153 + ]
  154 + },
  155 + "delete": {
  156 + "summary": "删除图表",
  157 + "operationId": "deleteChart",
  158 + "responses": {
  159 + "200": {
  160 + "description": "A successful response.",
  161 + "schema": {
  162 + "$ref": "#/definitions/ChartDeleteResponse"
  163 + }
  164 + }
  165 + },
  166 + "parameters": [
  167 + {
  168 + "name": "id",
  169 + "in": "path",
  170 + "required": true,
  171 + "type": "string"
  172 + },
  173 + {
  174 + "name": "body",
  175 + "in": "body",
  176 + "required": true,
  177 + "schema": {
  178 + "$ref": "#/definitions/ChartDeleteRequest"
  179 + }
  180 + }
  181 + ],
  182 + "requestBody": {},
  183 + "tags": [
  184 + "chart"
  185 + ]
  186 + },
  187 + "put": {
  188 + "summary": "更新图表(配置)",
  189 + "operationId": "updateChart",
  190 + "responses": {
  191 + "200": {
  192 + "description": "A successful response.",
  193 + "schema": {
  194 + "$ref": "#/definitions/ChartUpdateResponse"
  195 + }
  196 + }
  197 + },
  198 + "parameters": [
  199 + {
  200 + "name": "id",
  201 + "in": "path",
  202 + "required": true,
  203 + "type": "string"
  204 + },
  205 + {
  206 + "name": "body",
  207 + "in": "body",
  208 + "required": true,
  209 + "schema": {
  210 + "$ref": "#/definitions/ChartUpdateRequest"
  211 + }
  212 + }
  213 + ],
  214 + "requestBody": {},
  215 + "tags": [
  216 + "chart"
  217 + ]
  218 + }
  219 + }
  220 + },
  221 + "definitions": {
  222 + "ChartDeleteRequest": {
  223 + "type": "object",
  224 + "properties": {
  225 + "id": {
  226 + "type": "integer",
  227 + "format": "int64"
  228 + }
  229 + },
  230 + "title": "ChartDeleteRequest",
  231 + "required": [
  232 + "id"
  233 + ]
  234 + },
  235 + "ChartDeleteResponse": {
  236 + "type": "object",
  237 + "title": "ChartDeleteResponse"
  238 + },
  239 + "ChartGetRequest": {
  240 + "type": "object",
  241 + "properties": {
  242 + "id": {
  243 + "type": "integer",
  244 + "format": "int64"
  245 + }
  246 + },
  247 + "title": "ChartGetRequest",
  248 + "required": [
  249 + "id"
  250 + ]
  251 + },
  252 + "ChartGetResponse": {
  253 + "type": "object",
  254 + "properties": {
  255 + "chart": {
  256 + "$ref": "#/definitions/ChartItem"
  257 + }
  258 + },
  259 + "title": "ChartGetResponse",
  260 + "required": [
  261 + "chart"
  262 + ]
  263 + },
  264 + "ChartItem": {
  265 + "type": "object",
  266 + "properties": {
  267 + "id": {
  268 + "type": "integer",
  269 + "format": "int64",
  270 + "description": " ID"
  271 + },
  272 + "pid": {
  273 + "type": "integer",
  274 + "format": "int64",
  275 + "description": " 父级ID"
  276 + },
  277 + "type": {
  278 + "type": "string",
  279 + "description": " 类型 report:报表 group:分组 chart:图表"
  280 + },
  281 + "sort": {
  282 + "type": "integer",
  283 + "format": "int64",
  284 + "description": " 排序"
  285 + },
  286 + "name": {
  287 + "type": "string",
  288 + "description": " 名称"
  289 + },
  290 + "charts": {
  291 + "type": "array",
  292 + "items": {
  293 + "$ref": "#/definitions/ChartItem"
  294 + }
  295 + }
  296 + },
  297 + "title": "ChartItem"
  298 + },
  299 + "ChartRenameRequest": {
  300 + "type": "object",
  301 + "properties": {
  302 + "id": {
  303 + "type": "integer",
  304 + "format": "int64"
  305 + },
  306 + "name": {
  307 + "type": "string",
  308 + "description": " 名称"
  309 + }
  310 + },
  311 + "title": "ChartRenameRequest",
  312 + "required": [
  313 + "id",
  314 + "name"
  315 + ]
  316 + },
  317 + "ChartRenameResponse": {
  318 + "type": "object",
  319 + "title": "ChartRenameResponse"
  320 + },
  321 + "ChartSaveRequest": {
  322 + "type": "object",
  323 + "properties": {
  324 + "pid": {
  325 + "type": "integer",
  326 + "format": "int64",
  327 + "description": " 父级ID"
  328 + },
  329 + "type": {
  330 + "type": "string",
  331 + "description": " 类型 report:报表 group:分组 chart:图表"
  332 + },
  333 + "name": {
  334 + "type": "string",
  335 + "description": " 名称"
  336 + }
  337 + },
  338 + "title": "ChartSaveRequest",
  339 + "required": [
  340 + "type"
  341 + ]
  342 + },
  343 + "ChartSaveResponse": {
  344 + "type": "object",
  345 + "properties": {
  346 + "chart": {
  347 + "$ref": "#/definitions/ChartItem"
  348 + }
  349 + },
  350 + "title": "ChartSaveResponse",
  351 + "required": [
  352 + "chart"
  353 + ]
  354 + },
  355 + "ChartSearchRequest": {
  356 + "type": "object",
  357 + "properties": {
  358 + "page": {
  359 + "type": "integer",
  360 + "format": "int32"
  361 + },
  362 + "size": {
  363 + "type": "integer",
  364 + "format": "int32"
  365 + }
  366 + },
  367 + "title": "ChartSearchRequest",
  368 + "required": [
  369 + "page",
  370 + "size"
  371 + ]
  372 + },
  373 + "ChartSearchResponse": {
  374 + "type": "object",
  375 + "properties": {
  376 + "list": {
  377 + "type": "array",
  378 + "items": {
  379 + "$ref": "#/definitions/ChartItem"
  380 + }
  381 + },
  382 + "total": {
  383 + "type": "integer",
  384 + "format": "int64"
  385 + }
  386 + },
  387 + "title": "ChartSearchResponse",
  388 + "required": [
  389 + "list",
  390 + "total"
  391 + ]
  392 + },
  393 + "ChartUpdateRequest": {
  394 + "type": "object",
  395 + "properties": {
  396 + "id": {
  397 + "type": "integer",
  398 + "format": "int64"
  399 + }
  400 + },
  401 + "title": "ChartUpdateRequest",
  402 + "required": [
  403 + "id"
  404 + ]
  405 + },
  406 + "ChartUpdateResponse": {
  407 + "type": "object",
  408 + "title": "ChartUpdateResponse"
  409 + },
  410 + "ChartUpdateSortRequest": {
  411 + "type": "object",
  412 + "properties": {
  413 + "id": {
  414 + "type": "integer",
  415 + "format": "int64"
  416 + },
  417 + "sort": {
  418 + "type": "integer",
  419 + "format": "int32"
  420 + },
  421 + "pid": {
  422 + "type": "integer",
  423 + "format": "int32"
  424 + }
  425 + },
  426 + "title": "ChartUpdateSortRequest",
  427 + "required": [
  428 + "id",
  429 + "sort",
  430 + "pid"
  431 + ]
  432 + },
  433 + "ChartUpdateSortResponse": {
  434 + "type": "object",
  435 + "title": "ChartUpdateSortResponse"
  436 + }
  437 + },
  438 + "securityDefinitions": {
  439 + "apiKey": {
  440 + "type": "apiKey",
  441 + "description": "Enter JWT Bearer token **_only_**",
  442 + "name": "Authorization",
  443 + "in": "header"
  444 + }
  445 + },
  446 + "security": [
  447 + {
  448 + "apiKey": []
  449 + }
  450 + ]
  451 +}
  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: v1
  14 + group: chart
  15 + jwt: JwtAuth
  16 + //middleware: Authority
  17 +)
  18 +service Core {
  19 + @doc "获取图表详情"
  20 + @handler getChart
  21 + get /chart/:id (ChartGetRequest) returns (ChartGetResponse)
  22 + @doc "保存图表"
  23 + @handler saveChart
  24 + post /chart (ChartSaveRequest) returns (ChartSaveResponse)
  25 + @doc "删除图表"
  26 + @handler deleteChart
  27 + delete /chart/:id (ChartDeleteRequest) returns (ChartDeleteResponse)
  28 + @doc "更新图表(配置)"
  29 + @handler updateChart
  30 + put /chart/:id (ChartUpdateRequest) returns (ChartUpdateResponse)
  31 + @doc "搜索图表"
  32 + @handler searchChart
  33 + post /chart/search (ChartSearchRequest) returns (ChartSearchResponse)
  34 + @doc "移动图表"
  35 + @handler updateChartSort
  36 + post /chart/move (ChartUpdateSortRequest) returns (ChartUpdateSortResponse)
  37 + @doc "重命名图表"
  38 + @handler renameChartSort
  39 + post /chart/rename (ChartRenameRequest) returns (ChartRenameResponse)
  40 +}
  41 +
  42 +type (
  43 + ChartGetRequest {
  44 + Id int64 `path:"id"`
  45 + }
  46 + ChartGetResponse struct{
  47 + Chart ChartItem `json:"chart"`
  48 + }
  49 +
  50 + ChartSaveRequest struct{
  51 + Pid int64 `json:"pid,optional"`// 父级ID
  52 + Type string `json:"type"`// 类型 report:报表 group:分组 chart:图表
  53 + Name string `json:"name,optional"`// 名称
  54 + }
  55 + ChartSaveResponse struct{
  56 + Chart ChartItem `json:"chart"`
  57 + }
  58 +
  59 + ChartDeleteRequest struct{
  60 + Id int64 `path:"id"`
  61 + }
  62 + ChartDeleteResponse struct{}
  63 +
  64 + ChartUpdateRequest struct{
  65 + Id int64 `path:"id"`
  66 + }
  67 + ChartUpdateResponse struct{}
  68 +
  69 + ChartSearchRequest struct {
  70 + IncludeTypes []string `json:"includeTypes,optional"` //包含的类型: 类型 report:报表 group:分组 chart:图表(未指定返回所有)
  71 + DataStyle string `json:"dataStyle,optional"` // 数据样式 tree:树形 flat:平铺
  72 + }
  73 + ChartSearchResponse{
  74 + List []ChartItem `json:"list"`
  75 + Total int64 `json:"total"`
  76 + }
  77 + ChartUpdateSortRequest struct{
  78 + Id int64 `json:"id"`
  79 + Pid int64 `json:"pid"`
  80 + Index int `json:"index"` // 元素下标
  81 + }
  82 + ChartUpdateSortResponse struct{}
  83 + ChartRenameRequest struct{
  84 + Id int64 `json:"id"`
  85 + Name string `json:"name"`// 名称
  86 + }
  87 + ChartRenameResponse struct{}
  88 + ChartItem struct{
  89 + Id int64 `json:"id,optional"`// ID
  90 + Pid int64 `json:"pid,optional"`// 父级ID
  91 + Type string `json:"type,optional"`// 类型 report:报表 group:分组 chart:图表
  92 + Sort int64 `json:"sort,optional"`// 排序
  93 + Name string `json:"name,optional"`// 名称
  94 + Charts []ChartItem `json:"charts,optional"`
  95 + }
  96 +)
  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: v1
  14 + group: chart-setting
  15 + jwt: JwtAuth
  16 +)
  17 +service Core {
  18 + @handler getChartSetting
  19 + post /chart-setting/:id (ChartSettingGetRequest) returns (ChartSettingGetResponse)
  20 + @handler saveChartSetting
  21 + post /chart-setting (ChartSettingSaveRequest) returns (ChartSettingSaveResponse)
  22 + @handler deleteChartSetting
  23 + delete /chart-setting/:id (ChartSettingDeleteRequest) returns (ChartSettingDeleteResponse)
  24 + @handler updateChartSetting
  25 + put /chart-setting/:id (ChartSettingUpdateRequest) returns (ChartSettingUpdateResponse)
  26 + @handler searchChartSetting
  27 + post /chart-setting/search (ChartSettingSearchRequest) returns (ChartSettingSearchResponse)
  28 +}
  29 +
  30 +type (
  31 + ChartSettingGetRequest {
  32 + Id int64 `path:"id"`
  33 + }
  34 + ChartSettingGetResponse struct{
  35 + ChartSetting ChartSettingItem `json:"chartSetting"`
  36 + }
  37 +
  38 + ChartSettingSaveRequest struct{
  39 + ChartSetting ChartSettingItem `json:"chartSetting"`
  40 + }
  41 + ChartSettingSaveResponse struct{}
  42 +
  43 + ChartSettingDeleteRequest struct{
  44 + Id int64 `path:"id"`
  45 + }
  46 + ChartSettingDeleteResponse struct{}
  47 +
  48 + ChartSettingUpdateRequest struct{
  49 + Id int64 `path:"id"`
  50 + ChartSetting ChartSettingItem `json:"chartSetting"`
  51 + }
  52 + ChartSettingUpdateResponse struct{}
  53 +
  54 + ChartSettingSearchRequest struct{
  55 + Page int `json:"page"`
  56 + Size int `json:"size"`
  57 + }
  58 + ChartSettingSearchResponse{
  59 + List []ChartSettingItem `json:"list"`
  60 + Total int64 `json:"total"`
  61 + }
  62 + ChartSettingItem struct{
  63 +
  64 + }
  65 +)
  1 +
  2 +CREATE TABLE `chart` (
  3 + `id` bigint(0) NOT NULL COMMENT 'ID',
  4 + `pid` bigint(0) NOT NULL COMMENT '父级ID',
  5 + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '类型',
  6 + `sort` int(0) NOT NULL COMMENT '排序',
  7 + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
  8 + PRIMARY KEY (`id`) USING BTREE
  9 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
  10 +
  11 +CREATE TABLE `chart_setting` (
  12 + `id` bigint(0) NOT NULL COMMENT 'ID ',
  13 + `chart_id` bigint(0) NOT NULL COMMENT '图表ID',
  14 + `property` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '属性',
  15 + `style` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '样式',
  16 + `series` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '系列值-数据绑定',
  17 + PRIMARY KEY (`id`) USING BTREE
  18 +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
  1 +module gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart
  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/pkg/errors v0.9.1
  10 + github.com/stretchr/testify v1.8.4
  11 + github.com/tiptok/gocomm v1.0.14
  12 + github.com/zeromicro/go-zero v1.5.5
  13 + google.golang.org/grpc v1.57.0
  14 + gorm.io/driver/mysql v1.5.1
  15 + gorm.io/driver/postgres v1.5.2
  16 + gorm.io/gorm v1.25.4
  17 + gorm.io/plugin/soft_delete v1.2.1
  18 +)
  19 +
  20 +require (
  21 + github.com/Shopify/sarama v1.37.2 // indirect
  22 + github.com/beego/beego/v2 v2.0.1 // indirect
  23 + github.com/beorn7/perks v1.0.1 // indirect
  24 + github.com/cenkalti/backoff/v4 v4.2.0 // indirect
  25 + github.com/cespare/xxhash/v2 v2.2.0 // indirect
  26 + github.com/coreos/go-semver v0.3.1 // indirect
  27 + github.com/coreos/go-systemd/v22 v22.5.0 // indirect
  28 + github.com/davecgh/go-spew v1.1.1 // indirect
  29 + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
  30 + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
  31 + github.com/eapache/go-resiliency v1.3.0 // indirect
  32 + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
  33 + github.com/eapache/queue v1.1.0 // indirect
  34 + github.com/emicklei/go-restful/v3 v3.9.0 // indirect
  35 + github.com/fatih/color v1.15.0 // indirect
  36 + github.com/fsnotify/fsnotify v1.4.9 // indirect
  37 + github.com/garyburd/redigo v1.6.3 // indirect
  38 + github.com/gin-contrib/sse v0.1.0 // indirect
  39 + github.com/gin-gonic/gin v1.5.0 // indirect
  40 + github.com/go-logr/logr v1.2.3 // indirect
  41 + github.com/go-logr/stdr v1.2.2 // indirect
  42 + github.com/go-openapi/jsonpointer v0.19.6 // indirect
  43 + github.com/go-openapi/jsonreference v0.20.1 // indirect
  44 + github.com/go-openapi/swag v0.22.3 // indirect
  45 + github.com/go-playground/locales v0.12.1 // indirect
  46 + github.com/go-playground/universal-translator v0.16.0 // indirect
  47 + github.com/go-redis/redis/v8 v8.11.5 // indirect
  48 + github.com/go-sql-driver/mysql v1.7.1 // indirect
  49 + github.com/gogo/protobuf v1.3.2 // indirect
  50 + github.com/golang/mock v1.6.0 // indirect
  51 + github.com/golang/protobuf v1.5.3 // indirect
  52 + github.com/golang/snappy v0.0.4 // indirect
  53 + github.com/google/gnostic v0.5.7-v3refs // indirect
  54 + github.com/google/go-cmp v0.5.9 // indirect
  55 + github.com/google/gofuzz v1.2.0 // indirect
  56 + github.com/google/uuid v1.3.0 // indirect
  57 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 // indirect
  58 + github.com/hashicorp/errwrap v1.1.0 // indirect
  59 + github.com/hashicorp/go-multierror v1.1.1 // indirect
  60 + github.com/hashicorp/go-uuid v1.0.3 // indirect
  61 + github.com/hashicorp/hcl v1.0.0 // indirect
  62 + github.com/jackc/pgpassfile v1.0.0 // indirect
  63 + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
  64 + github.com/jackc/pgx/v5 v5.4.3 // indirect
  65 + github.com/jcmturner/aescts/v2 v2.0.0 // indirect
  66 + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
  67 + github.com/jcmturner/gofork v1.7.6 // indirect
  68 + github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect
  69 + github.com/jcmturner/rpc/v2 v2.0.3 // indirect
  70 + github.com/jinzhu/inflection v1.0.0 // indirect
  71 + github.com/josharian/intern v1.0.0 // indirect
  72 + github.com/json-iterator/go v1.1.12 // indirect
  73 + github.com/klauspost/compress v1.15.15 // indirect
  74 + github.com/leodido/go-urn v1.1.0 // indirect
  75 + github.com/magiconair/properties v1.8.0 // indirect
  76 + github.com/mailru/easyjson v0.7.7 // indirect
  77 + github.com/mattn/go-colorable v0.1.13 // indirect
  78 + github.com/mattn/go-isatty v0.0.17 // indirect
  79 + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
  80 + github.com/mitchellh/mapstructure v1.3.3 // indirect
  81 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
  82 + github.com/modern-go/reflect2 v1.0.2 // indirect
  83 + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
  84 + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
  85 + github.com/openzipkin/zipkin-go v0.4.1 // indirect
  86 + github.com/pelletier/go-toml v1.8.1 // indirect
  87 + github.com/pelletier/go-toml/v2 v2.0.9 // indirect
  88 + github.com/pierrec/lz4/v4 v4.1.17 // indirect
  89 + github.com/pmezard/go-difflib v1.0.0 // indirect
  90 + github.com/prometheus/client_golang v1.16.0 // indirect
  91 + github.com/prometheus/client_model v0.3.0 // indirect
  92 + github.com/prometheus/common v0.42.0 // indirect
  93 + github.com/prometheus/procfs v0.10.1 // indirect
  94 + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
  95 + github.com/samber/lo v1.38.1 // indirect
  96 + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
  97 + github.com/spaolacci/murmur3 v1.1.0 // indirect
  98 + github.com/spf13/afero v1.2.2 // indirect
  99 + github.com/spf13/cast v1.3.0 // indirect
  100 + github.com/spf13/jwalterweatherman v1.0.0 // indirect
  101 + github.com/spf13/pflag v1.0.5 // indirect
  102 + github.com/spf13/viper v1.4.0 // indirect
  103 + github.com/ugorji/go/codec v1.1.7 // indirect
  104 + go.etcd.io/etcd/api/v3 v3.5.9 // indirect
  105 + go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
  106 + go.etcd.io/etcd/client/v3 v3.5.9 // indirect
  107 + go.opentelemetry.io/otel v1.14.0 // indirect
  108 + go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect
  109 + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect
  110 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect
  111 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // indirect
  112 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.14.0 // indirect
  113 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.14.0 // indirect
  114 + go.opentelemetry.io/otel/exporters/zipkin v1.14.0 // indirect
  115 + go.opentelemetry.io/otel/sdk v1.14.0 // indirect
  116 + go.opentelemetry.io/otel/trace v1.14.0 // indirect
  117 + go.opentelemetry.io/proto/otlp v0.19.0 // indirect
  118 + go.uber.org/atomic v1.10.0 // indirect
  119 + go.uber.org/automaxprocs v1.5.3 // indirect
  120 + go.uber.org/multierr v1.9.0 // indirect
  121 + go.uber.org/zap v1.24.0 // indirect
  122 + golang.org/x/crypto v0.12.0 // indirect
  123 + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
  124 + golang.org/x/net v0.14.0 // indirect
  125 + golang.org/x/oauth2 v0.7.0 // indirect
  126 + golang.org/x/sys v0.11.0 // indirect
  127 + golang.org/x/term v0.11.0 // indirect
  128 + golang.org/x/text v0.12.0 // indirect
  129 + golang.org/x/time v0.3.0 // indirect
  130 + google.golang.org/appengine v1.6.7 // indirect
  131 + google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54 // indirect
  132 + google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
  133 + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
  134 + google.golang.org/protobuf v1.31.0 // indirect
  135 + gopkg.in/go-playground/validator.v9 v9.29.1 // indirect
  136 + gopkg.in/inf.v0 v0.9.1 // indirect
  137 + gopkg.in/yaml.v2 v2.4.0 // indirect
  138 + gopkg.in/yaml.v3 v3.0.1 // indirect
  139 + k8s.io/api v0.26.3 // indirect
  140 + k8s.io/apimachinery v0.27.0-alpha.3 // indirect
  141 + k8s.io/client-go v0.26.3 // indirect
  142 + k8s.io/klog/v2 v2.90.1 // indirect
  143 + k8s.io/kube-openapi v0.0.0-20230307230338-69ee2d25a840 // indirect
  144 + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
  145 + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
  146 + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
  147 + sigs.k8s.io/yaml v1.3.0 // indirect
  148 +)
  1 +package cache
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/tiptok/gocomm/pkg/cache"
  6 + "github.com/tiptok/gocomm/pkg/cache/gzcache"
  7 + "github.com/tiptok/gocomm/pkg/log"
  8 +)
  9 +
  10 +func NewMultiLevelCache(hosts []string, password string) *cache.MultiLevelCache {
  11 + fmt.Println("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 + "github.com/zeromicro/go-zero/zrpc"
  6 + "time"
  7 +)
  8 +
  9 +type JWT struct {
  10 + Secret string `json:",optional"`
  11 + Expires time.Duration `json:",optional"`
  12 +}
  13 +type JwtAuth struct {
  14 + AccessSecret string
  15 + Expire int64
  16 +}
  17 +type Config struct {
  18 + JwtAuth JwtAuth `json:",optional"`
  19 + UserRpc zrpc.RpcClientConf `json:",optional"`
  20 + AuthRpc zrpc.RpcClientConf `json:",optional"`
  21 + PostRpc zrpc.RpcClientConf `json:",optional"`
  22 + CommentRpc zrpc.RpcClientConf `json:",optional"`
  23 + JWT JWT `json:",optional"`
  24 + DB struct {
  25 + DataSource string
  26 + } `json:",optional"`
  27 + Cache cache.CacheConf `json:",optional"`
  28 + DTM DTM `json:",optional"`
  29 + Sms Sms `json:",optional"`
  30 + Oss Oss `json:",optional"`
  31 + Wechat Wechat `json:",optional"` // 学员端微信
  32 + CoachClient Wechat `json:",optional"` // 教练端微信
  33 + OfficialAccount Wechat `json:",optional"`
  34 + ThirdWechatApps []Wechat `json:",optional"`
  35 +}
  36 +
  37 +type DTM struct {
  38 + Server Server `json:",optional"`
  39 +}
  40 +
  41 +type Server struct {
  42 + Name string `json:",optional"`
  43 + Host string `json:",optional"`
  44 + GRPC GRPC `json:",optional"`
  45 + HTTP HTTP `json:",optional"`
  46 + Metrics Metrics `json:",optional"`
  47 +}
  48 +
  49 +type HTTP struct {
  50 + Port string
  51 +}
  52 +
  53 +type GRPC struct {
  54 + Port string
  55 +}
  56 +
  57 +type Metrics struct {
  58 + Port string
  59 +}
  60 +
  61 +type Sms struct {
  62 + Debug bool
  63 + DebugCode string
  64 + Expire int `json:",default=180"`
  65 + MaxSendTime int `json:",default=5"`
  66 + CompanyName string
  67 + SecretId string
  68 + SecretKey string
  69 + SmsAppId string
  70 + Sign string
  71 + TemplateId string
  72 +}
  73 +
  74 +type Oss struct {
  75 + OssEndPoint string
  76 + AccessKeyID string
  77 + AccessKeySecret string
  78 + BuckName string
  79 +
  80 + RegionID string
  81 + RoleArn string
  82 +
  83 + CDN CDN
  84 +}
  85 +
  86 +type Wechat struct {
  87 + AppName string `json:",optional"`
  88 + AppID string
  89 + AppSecret string
  90 + MsgTemplates []Template `json:",optional"`
  91 +}
  92 +
  93 +func (wx Wechat) GetTemplate(code string) (Template, bool) {
  94 + for _, temp := range wx.MsgTemplates {
  95 + if temp.Code == code {
  96 + return temp, true
  97 + }
  98 + }
  99 + return Template{}, false
  100 +}
  101 +
  102 +type CDN struct {
  103 + HostPairs []string
  104 +}
  105 +
  106 +type Template struct {
  107 + ID string // 模板ID
  108 + Name string // 模板名称
  109 + Code string // 模板编码
  110 +}
  1 +package contextdata
  2 +
  3 +import (
  4 + "context"
  5 +)
  6 +
  7 +func GetTenantFromCtx(ctx context.Context) int64 {
  8 + return 1
  9 +}
  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 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/config"
  9 + "time"
  10 +)
  11 +
  12 +var (
  13 + CtxKeyJwtUserId = "UserId"
  14 +)
  15 +
  16 +func GetUserIdFromCtx(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: GetUserIdFromCtx(ctx, CtxKeyJwtUserId),
  56 + }
  57 +}
  58 +
  59 +type UserToken struct {
  60 + UserId int64 `json:"userId"`
  61 +}
  62 +
  63 +func (tk UserToken) GenerateToken(jwtConfig config.JwtAuth) (string, error) {
  64 + claims := make(jwt.MapClaims)
  65 + claims["exp"] = time.Now().Unix() + jwtConfig.Expire
  66 + claims["iat"] = time.Now().Unix()
  67 + claims["UserId"] = tk.UserId
  68 + token := jwt.New(jwt.SigningMethodHS256)
  69 + token.Claims = claims
  70 +
  71 + return token.SignedString([]byte(jwtConfig.AccessSecret))
  72 +}
  73 +
  74 +func (tk *UserToken) ParseToken(jwtConfig config.JWT, str string) error {
  75 + return nil
  76 +}
  77 +
  78 +// CheckUserInfo 如果UserToken有效 返回:true 否则返回false
  79 +func (tk *UserToken) CheckUserInfo() bool {
  80 + return !(tk.UserId > 100000000 || tk.UserId <= 0)
  81 +}
  1 +package database
  2 +
  3 +import (
  4 + "fmt"
  5 + "gorm.io/driver/mysql"
  6 + "gorm.io/driver/postgres"
  7 + "gorm.io/gorm"
  8 + "gorm.io/gorm/logger"
  9 + "log"
  10 + "os"
  11 + "time"
  12 +)
  13 +
  14 +func OpenGormDB(source string) *gorm.DB {
  15 + newLogger := logger.New(
  16 + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
  17 + logger.Config{
  18 + SlowThreshold: time.Second, // Slow SQL threshold
  19 + LogLevel: logger.Info, // Log level
  20 + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
  21 + Colorful: false, // Disable color
  22 + },
  23 + )
  24 + fmt.Println("starting db...")
  25 + db, err := gorm.Open(mysql.Open(source), &gorm.Config{
  26 + Logger: newLogger,
  27 + })
  28 + if err != nil {
  29 + panic(err)
  30 + }
  31 + return db
  32 +}
  33 +
  34 +func OpenGormPGDB(source string) *gorm.DB {
  35 + newLogger := logger.New(
  36 + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
  37 + logger.Config{
  38 + SlowThreshold: time.Second, // Slow SQL threshold
  39 + LogLevel: logger.Info, // Log level
  40 + IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger
  41 + Colorful: false, // Disable color
  42 + },
  43 + )
  44 + fmt.Println("starting db...")
  45 + db, err := gorm.Open(postgres.Open(source), &gorm.Config{
  46 + Logger: newLogger,
  47 + })
  48 + if err != nil {
  49 + panic(err)
  50 + }
  51 + return db
  52 +}
  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 result
  2 +
  3 +import (
  4 + "fmt"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  6 + "net/http"
  7 +
  8 + "github.com/pkg/errors"
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 + "github.com/zeromicro/go-zero/rest/httpx"
  11 + "google.golang.org/grpc/status"
  12 +)
  13 +
  14 +// http返回
  15 +func HttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, err error) {
  16 +
  17 + if err == nil {
  18 + //成功返回
  19 + r := Success(resp)
  20 + httpx.WriteJson(w, http.StatusOK, r)
  21 + } else {
  22 + //错误返回
  23 + errcode := xerr.SERVER_COMMON_ERROR
  24 + errmsg := "服务器开小差啦,稍后再来试一试"
  25 + internalErr := ""
  26 + causeErr := errors.Cause(err) // err类型
  27 + if e, ok := causeErr.(*xerr.CodeError); ok { //自定义错误类型
  28 + //自定义CodeError
  29 + errcode = e.GetErrCode()
  30 + errmsg = e.GetErrMsg()
  31 + if e.InternalError != nil {
  32 + internalErr = e.InternalError.Error()
  33 + }
  34 + } else {
  35 + if gstatus, ok := status.FromError(causeErr); ok { // grpc err错误
  36 + grpcCode := uint32(gstatus.Code())
  37 + if xerr.IsCodeErr(grpcCode) { //区分自定义错误跟系统底层、db等错误,底层、db错误不能返回给前端
  38 + errcode = grpcCode
  39 + errmsg = gstatus.Message()
  40 + }
  41 + }
  42 + }
  43 +
  44 + logx.WithContext(r.Context()).Errorf("【API-ERR】 : %+v ", err)
  45 + response := Error(errcode, errmsg)
  46 + response.Error = internalErr
  47 + httpx.WriteJson(w, http.StatusBadRequest, response)
  48 + }
  49 +}
  50 +
  51 +// 授权的http方法
  52 +func AuthHttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, err error) {
  53 +
  54 + if err == nil {
  55 + //成功返回
  56 + r := Success(resp)
  57 + httpx.WriteJson(w, http.StatusOK, r)
  58 + } else {
  59 + //错误返回
  60 + errcode := xerr.SERVER_COMMON_ERROR
  61 + errmsg := "服务器开小差啦,稍后再来试一试"
  62 +
  63 + causeErr := errors.Cause(err) // err类型
  64 + if e, ok := causeErr.(*xerr.CodeError); ok { //自定义错误类型
  65 + //自定义CodeError
  66 + errcode = e.GetErrCode()
  67 + errmsg = e.GetErrMsg()
  68 + } else {
  69 + if gstatus, ok := status.FromError(causeErr); ok { // grpc err错误
  70 + grpcCode := uint32(gstatus.Code())
  71 + if xerr.IsCodeErr(grpcCode) { //区分自定义错误跟系统底层、db等错误,底层、db错误不能返回给前端
  72 + errcode = grpcCode
  73 + errmsg = gstatus.Message()
  74 + }
  75 + }
  76 + }
  77 +
  78 + logx.WithContext(r.Context()).Errorf("【GATEWAY-ERR】 : %+v ", err)
  79 +
  80 + httpx.WriteJson(w, http.StatusUnauthorized, Error(errcode, errmsg))
  81 + }
  82 +}
  83 +
  84 +// http 参数错误返回
  85 +func ParamErrorResult(r *http.Request, w http.ResponseWriter, err error) {
  86 + errMsg := fmt.Sprintf("%s ,%s", xerr.MapErrMsg(xerr.REUQEST_PARAM_ERROR), err.Error())
  87 + httpx.WriteJson(w, http.StatusBadRequest, Error(xerr.REUQEST_PARAM_ERROR, errMsg))
  88 +}
  1 +package result
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/xerr"
  6 +
  7 + "github.com/pkg/errors"
  8 + "github.com/zeromicro/go-zero/core/logx"
  9 + "google.golang.org/grpc/status"
  10 +)
  11 +
  12 +// job返回
  13 +func JobResult(ctx context.Context, resp interface{}, err error) {
  14 + if err == nil {
  15 + // 成功返回 ,只有dev环境下才会打印info,线上不显示
  16 + if resp != nil {
  17 + logx.Infof("resp: %+v", resp)
  18 + }
  19 + return
  20 + } else {
  21 + errCode := xerr.SERVER_COMMON_ERROR
  22 + errMsg := "服务器开小差啦,稍后再来试一试"
  23 +
  24 + // 错误返回
  25 + causeErr := errors.Cause(err) // err类型
  26 + if e, ok := causeErr.(*xerr.CodeError); ok { // 自定义错误类型
  27 + // 自定义CodeError
  28 + errCode = e.GetErrCode()
  29 + errMsg = e.GetErrMsg()
  30 + } else {
  31 + if gstatus, ok := status.FromError(causeErr); ok { // grpc err错误
  32 + grpcCode := uint32(gstatus.Code())
  33 + if xerr.IsCodeErr(grpcCode) { // 区分自定义错误跟系统底层、db等错误,底层、db错误不能返回给前端
  34 + errCode = grpcCode
  35 + errMsg = gstatus.Message()
  36 + }
  37 + }
  38 + }
  39 +
  40 + logx.WithContext(ctx).Errorf("【JOB-ERR】 : %+v ,errCode:%d , errMsg:%s ", err, errCode, errMsg)
  41 + return
  42 + }
  43 +}
  1 +package result
  2 +
  3 +type ResponseSuccessBean struct {
  4 + Code uint32 `json:"code"`
  5 + Msg string `json:"msg"`
  6 + Data interface{} `json:"data"`
  7 +}
  8 +type NullJson struct{}
  9 +
  10 +func Success(data interface{}) *ResponseSuccessBean {
  11 + return &ResponseSuccessBean{Code: 0, Msg: "OK", Data: data}
  12 +}
  13 +
  14 +type ResponseErrorBean struct {
  15 + Code uint32 `json:"code"`
  16 + Msg string `json:"msg"`
  17 + Error string `json:"err"`
  18 +}
  19 +
  20 +func Error(errCode uint32, errMsg string) *ResponseErrorBean {
  21 + return &ResponseErrorBean{Code: errCode, Msg: errMsg}
  22 +}
  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 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-bchart/pkg/config"
  6 + "time"
  7 +)
  8 +
  9 +type UserToken struct {
  10 + UserId int64 `json:"userId"`
  11 + CoachId int64 `json:"coach_id"`
  12 + AdminId int64 `json:"adminId"`
  13 + ClientType string `json:"clientType"`
  14 + AccessShops []int64 `json:"accessShops"`
  15 +}
  16 +
  17 +func (tk UserToken) GenerateToken(jwtConfig config.JwtAuth) (string, error) {
  18 + claims := make(jwt.MapClaims)
  19 + claims["exp"] = time.Now().Unix() + jwtConfig.Expire
  20 + claims["iat"] = time.Now().Unix()
  21 + claims["UserId"] = tk.UserId
  22 + claims["CoachId"] = tk.CoachId
  23 + claims["AdminId"] = tk.AdminId
  24 + claims["ClientType"] = tk.ClientType
  25 + claims["AccessShops"] = tk.AccessShops
  26 + token := jwt.New(jwt.SigningMethodHS256)
  27 + token.Claims = claims
  28 +
  29 + return token.SignedString([]byte(jwtConfig.AccessSecret))
  30 +}
  31 +
  32 +func (tk *UserToken) ParseToken(jwtConfig config.JWT, str string) error {
  33 + //tokenClaims, err := jwt.ParseWithClaims(
  34 + // str,
  35 + // tk,
  36 + // func(token *jwt.Token) (interface{}, error) {
  37 + // return []byte(jwtConfig.Secret), nil
  38 + // })
  39 + //if err != nil {
  40 + // return err
  41 + //}
  42 + //if claim, ok := tokenClaims.Claims.(*UserToken); ok && tokenClaims.Valid {
  43 + // *tk = *claim
  44 + // return nil
  45 + //}
  46 + //return errors.New("token 解析失败")
  47 + return nil
  48 +}
  49 +
  50 +// CheckUserInfo 如果UserToken有效 返回:true 否则返回false
  51 +func (tk *UserToken) CheckUserInfo() bool {
  52 + return !(tk.UserId > 100000000 || tk.UserId <= 0)
  53 +}
  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 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 +const OK uint32 = 200
  5 +
  6 +/**(前3位代表业务,后三位代表具体功能)**/
  7 +
  8 +// 全局错误码
  9 +const SERVER_COMMON_ERROR uint32 = 100001
  10 +const REUQEST_PARAM_ERROR uint32 = 100002
  11 +const TOKEN_EXPIRE_ERROR uint32 = 100003
  12 +const TOKEN_GENERATE_ERROR uint32 = 100004
  13 +const DB_ERROR uint32 = 100005
  14 +const DB_UPDATE_AFFECTED_ZERO_ERROR uint32 = 100006
  15 +
  16 +const REQUEST_ARGS_ERROR = 200001
  17 +
  18 +// 微信模块
  19 +const ErrWxMiniAuthFailError uint32 = 500001
  20 +const ErrUserNoAuth uint32 = 500002
  1 +package xerr
  2 +
  3 +var message map[uint32]string
  4 +
  5 +func init() {
  6 + message = make(map[uint32]string)
  7 + message[OK] = "SUCCESS"
  8 + message[SERVER_COMMON_ERROR] = "服务器开小差啦,稍后再来试一试"
  9 + message[REUQEST_PARAM_ERROR] = "参数错误"
  10 + message[TOKEN_EXPIRE_ERROR] = "token失效,请重新登陆"
  11 + message[TOKEN_GENERATE_ERROR] = "生成token失败"
  12 + message[DB_ERROR] = "数据库繁忙,请稍后再试"
  13 + message[DB_UPDATE_AFFECTED_ZERO_ERROR] = "更新数据影响行数为0"
  14 + message[ErrUserNoAuth] = "无权限"
  15 + message[ErrWxMiniAuthFailError] = "微信授权失败"
  16 +}
  17 +
  18 +func MapErrMsg(errcode uint32) string {
  19 + if msg, ok := message[errcode]; ok {
  20 + return msg
  21 + } else {
  22 + return "服务器开小差啦,稍后再来试一试"
  23 + }
  24 +}
  25 +
  26 +func IsCodeErr(errcode uint32) bool {
  27 + if _, ok := message[errcode]; ok {
  28 + return true
  29 + } else {
  30 + return false
  31 + }
  32 +}
  1 +package xerr
  2 +
  3 +import (
  4 + "fmt"
  5 +)
  6 +
  7 +/**
  8 +常用通用固定错误
  9 +*/
  10 +
  11 +type CodeError struct {
  12 + errCode uint32
  13 + errMsg string
  14 + InternalError error
  15 +}
  16 +
  17 +// GetErrCode 返回给前端的错误码
  18 +func (e *CodeError) GetErrCode() uint32 {
  19 + return e.errCode
  20 +}
  21 +
  22 +// GetErrMsg 返回给前端显示端错误信息
  23 +func (e *CodeError) GetErrMsg() string {
  24 + return e.errMsg
  25 +}
  26 +
  27 +func (e *CodeError) Error() string {
  28 + if e.InternalError != nil {
  29 + return fmt.Sprintf("ErrCode:%d,ErrMsg:%s InternalError:%s", e.errCode, e.errMsg, e.InternalError.Error())
  30 + }
  31 + return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg)
  32 +}
  33 +
  34 +/*
  35 + 指定错误码的错误
  36 +*/
  37 +
  38 +func NewCodeErr(errCode uint32, err error) *CodeError {
  39 + return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode), InternalError: err}
  40 +}
  41 +
  42 +func NewCodeErrMsg(errCode uint32, err error, msg string) *CodeError {
  43 + return &CodeError{errCode: errCode, errMsg: msg, InternalError: err}
  44 +}
  45 +
  46 +/*
  47 + 默认的服务错误
  48 +*/
  49 +
  50 +func NewErr(err error) *CodeError {
  51 + return &CodeError{errCode: SERVER_COMMON_ERROR, InternalError: err}
  52 +}
  53 +
  54 +func NewErrMsg(errMsg string) *CodeError {
  55 + return &CodeError{errCode: SERVER_COMMON_ERROR, errMsg: errMsg}
  56 +}
  57 +
  58 +func NewErrMsgErr(errMsg string, err error) *CodeError {
  59 + return &CodeError{errCode: SERVER_COMMON_ERROR, errMsg: errMsg, InternalError: err}
  60 +}