commit c4548fe498d931fa74853dda950ebfb1a2efbc8b Author: Echo <1711788888@qq.com> Date: Thu Nov 2 04:34:46 2023 +0800 :sparkles: Init diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fbd90b4 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/server.iml b/.idea/server.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/server.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d564ad8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:alpine as builder + +WORKDIR /go/src/miniapp +COPY . . + +RUN go env -w GO111MODULE=on \ + && go env -w GOPROXY=https://goproxy.cn,direct \ + && go env -w CGO_ENABLED=0 \ + && go env \ + && go mod tidy \ + && go build -o server.exe.exe . + +FROM alpine:latest + +LABEL MAINTAINER="SliverHorn@sliver_horn@qq.com" + +WORKDIR /go/src/miniapp + +COPY --from=0 /go/src/miniapp/server ./ +COPY --from=0 /go/src/miniapp/resource ./resource/ +COPY --from=0 /go/src/miniapp/config.docker.yaml ./ + +EXPOSE 8888 +ENTRYPOINT ./server -c config.docker.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a34870 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +## server项目结构 + +```shell +├── api +│   └── v1 +├── config +├── core +├── docs +├── global +├── initialize +│   └── internal +├── middleware +├── model +│   ├── request +│   └── response +├── packfile +├── resource +│   ├── excel +│   ├── page +│   └── template +├── router +├── service +├── source +└── utils + ├── timer + └── upload +``` + +| 文件夹 | 说明 | 描述 | +| ------------ | ----------------------- | --------------------------- | +| `api` | api层 | api层 | +| `--v1` | v1版本接口 | v1版本接口 | +| `config` | 配置包 | config.yaml对应的配置结构体 | +| `core` | 核心文件 | 核心组件(zap, viper, server)的初始化 | +| `docs` | swagger文档目录 | swagger文档目录 | +| `global` | 全局对象 | 全局对象 | +| `initialize` | 初始化 | router,redis,gorm,validator, timer的初始化 | +| `--internal` | 初始化内部函数 | gorm 的 longger 自定义,在此文件夹的函数只能由 `initialize` 层进行调用 | +| `middleware` | 中间件层 | 用于存放 `gin` 中间件代码 | +| `model` | 模型层 | 模型对应数据表 | +| `--request` | 入参结构体 | 接收前端发送到后端的数据。 | +| `--response` | 出参结构体 | 返回给前端的数据结构体 | +| `packfile` | 静态文件打包 | 静态文件打包 | +| `resource` | 静态资源文件夹 | 负责存放静态文件 | +| `--excel` | excel导入导出默认路径 | excel导入导出默认路径 | +| `--page` | 表单生成器 | 表单生成器 打包后的dist | +| `--template` | 模板 | 模板文件夹,存放的是代码生成器的模板 | +| `router` | 路由层 | 路由层 | +| `service` | service层 | 存放业务逻辑问题 | +| `source` | source层 | 存放初始化数据的函数 | +| `utils` | 工具包 | 工具函数封装 | +| `--timer` | timer | 定时器接口封装 | +| `--upload` | oss | oss接口封装 | + diff --git a/api/base.go b/api/base.go new file mode 100644 index 0000000..9cf0aca --- /dev/null +++ b/api/base.go @@ -0,0 +1,43 @@ +package api + +import ( + "git.echol.cn/loser/logger/log" + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/common/response" + "strconv" +) + +func GetUser(ctx *gin.Context, u *app.User, dontResponse, dontCheck bool) { + userId := ctx.Request.Header.Get("userId") + if userId == "" { + if !dontResponse { + ctx.Abort() + response.FailWithMessage("未授权操作", ctx) + } + return + } + id, _ := strconv.Atoi(userId) + u.ID = uint(id) + + // 查询 + err := global.GVA_DB.Take(&u).Error + if err != nil { + log.Errorf("获取用户信息失败:%s", err.Error()) + ctx.Abort() + if !dontResponse { + response.FailWithMessage("用户状态异常", ctx) + } + return + } + // 需要跳过微信绑定检验 + if !dontCheck { + // 检查微信绑定 + if u.WechatOpenId == nil || *u.WechatOpenId == "" { + log.Errorf("%v 未绑定微信", u.Nickname) + response.FailWithMessage("请先绑定微信", ctx) + ctx.Abort() + } + } +} diff --git a/api/v1/app/enter.go b/api/v1/app/enter.go new file mode 100644 index 0000000..b4238e0 --- /dev/null +++ b/api/v1/app/enter.go @@ -0,0 +1,18 @@ +package app + +import "miniapp/service" + +type ApiGroup struct { + UserApi + LoginApi + FavoriteApi + VisionApi + TodosApi +} + +var ( + userService = service.ServiceGroupApp.AppServiceGroup.UserService + favoriteService = service.ServiceGroupApp.AppServiceGroup.FavoriteService + visionService = service.ServiceGroupApp.AppServiceGroup.VisionService + todosService = service.ServiceGroupApp.AppServiceGroup.TodesService +) diff --git a/api/v1/app/favorite.go b/api/v1/app/favorite.go new file mode 100644 index 0000000..a3cb536 --- /dev/null +++ b/api/v1/app/favorite.go @@ -0,0 +1,80 @@ +package app + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" + r "miniapp/model/common/response" +) + +type FavoriteApi struct{} + +// GetList 获取收藏列表 +func (f *FavoriteApi) GetList(ctx *gin.Context) { + var p request.GetFavoriteList + + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("获取收藏列表失败", zap.Error(err)) + return + } + + // 获取收藏列表 + err, list, total := favoriteService.GetFavoriteList(p) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("获取收藏列表失败", zap.Error(err)) + return + } + + r.OkWithData(r.PageResult{ + List: list, + Total: total, + Page: p.Page, + PageSize: p.PageSize, + }, ctx) +} + +// Create 创建收藏 +func (f *FavoriteApi) Create(ctx *gin.Context) { + var p app.Favorite + + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("创建收藏失败", zap.Error(err)) + return + } + + // 创建收藏 + err := favoriteService.CreateFavorite(&p) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("创建收藏失败", zap.Error(err)) + return + } + + r.Ok(ctx) +} + +// Delete 删除收藏 +func (f *FavoriteApi) Delete(ctx *gin.Context) { + var p app.Favorite + + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("删除收藏失败", zap.Error(err)) + return + } + + // 删除收藏 + err := favoriteService.DeleteFavorite(&p) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("删除收藏失败", zap.Error(err)) + return + } + + r.Ok(ctx) +} diff --git a/api/v1/app/login.go b/api/v1/app/login.go new file mode 100644 index 0000000..551fd17 --- /dev/null +++ b/api/v1/app/login.go @@ -0,0 +1,120 @@ +package app + +import ( + "context" + "encoding/json" + "fmt" + "git.echol.cn/loser/logger/log" + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/app/request" + "miniapp/model/common/constant" + r "miniapp/model/common/response" + "miniapp/oauth2" + "miniapp/service" + "net/http" + "net/url" + "strconv" +) + +type LoginApi struct{} + +// Login 登录 +func (l *LoginApi) Login(ctx *gin.Context) { + var p request.Login + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + return + } + // 获取用户基础账号信息 + + userId, err := oauth2.OAuthServer.UserAuthorizationHandler(ctx.Writer, ctx.Request) + if err != nil { + log.Errorf("获取用户基础账号信息失败: %v", err) + r.FailWithMessage(err.Error(), ctx) + return + } + // 重新组装登录参数 + ctx.Request.Form = url.Values{ + "username": {userId}, + "password": {p.Password}, + "scope": {"ALL"}, + "grant_type": {"password"}, + "nickName": {p.NickName}, + "avatarUrl": {p.AvatarUrl}, + } + + // 参数解析成功,进行登录 + if err = oauth2.OAuthServer.HandleTokenRequest(ctx.Writer, ctx.Request); err != nil { + log.Errorf("登录失败:%s", err.Error()) + r.FailWithMessage(err.Error(), ctx) + return + } + // 登录成功才更新登录时间 + if ctx.Writer.Status() == http.StatusOK { + // 登录成功,更新登录时间和IP + uid, _ := strconv.Atoi(userId) + go service.ServiceGroupApp.AppServiceGroup.UserService.UpdateLastLoginInfo(uid) + } + +} + +// Refresh 刷新登录Token +func (l *LoginApi) Refresh(ctx *gin.Context) { + var p request.RefreshToken + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误: "+err.Error(), ctx) + return + } + + // 刷新Token + if err := oauth2.OAuthServer.HandleTokenRequest(ctx.Writer, ctx.Request); err != nil { + log.Errorf("Token数据返回失败: %v", err.Error()) + + r.FailWithMessage(err.Error(), ctx) + } +} + +// Logout 退出登录 +func (l *LoginApi) Logout(ctx *gin.Context) { + log.Debug("退出登录啦") + // Token字符串前缀 + const bearerSchema string = "Bearer " + // 取出Token + tokenHeader := ctx.Request.Header.Get("Authorization") + tokenStr := tokenHeader[len(bearerSchema):] + // 取出原始RedisKey + baseDataId, err := global.GVA_REDIS.Get(context.Background(), constant.OAuth2RedisKey+tokenStr).Result() + if err != nil { + r.FailWithMessage("Token信息获取失败", ctx) + return + } + baseDataStr, err := global.GVA_REDIS.Get(context.Background(), constant.OAuth2RedisKey+baseDataId).Result() + if err != nil { + r.FailWithMessage("Token信息获取失败", ctx) + return + } + // 转换数据为Map + tokenData := make(map[string]any) + if err = json.Unmarshal([]byte(baseDataStr), &tokenData); err != nil { + r.FailWithMessage("系统错误: "+err.Error(), ctx) + return + } + // 删除Redis缓存的数据 + global.GVA_REDIS.Del(context.Background(), constant.OAuth2RedisKey+baseDataId) + global.GVA_REDIS.Del(context.Background(), fmt.Sprintf("%v%v", constant.OAuth2RedisKey, tokenData["Access"])) + global.GVA_REDIS.Del(context.Background(), fmt.Sprintf("%v%v", constant.OAuth2RedisKey, tokenData["Refresh"])) + + r.Ok(ctx) +} + +func (l *LoginApi) GetWeChatToken(c *gin.Context) { + wechaetToken, err := http.Get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx3d38ce1103a82225&secret=3c41ca428b4d0f43cfaef6f567a1cc06") + if err != nil { + log.Errorf("获取微信Token失败: %v", err) + r.FailWithMessage(err.Error(), c) + return + } + + r.OkWithData(wechaetToken, c) +} diff --git a/api/v1/app/todos.go b/api/v1/app/todos.go new file mode 100644 index 0000000..9ffa583 --- /dev/null +++ b/api/v1/app/todos.go @@ -0,0 +1,49 @@ +package app + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/api" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/common" + r "miniapp/model/common/response" +) + +type TodosApi struct{} + +func (t TodosApi) GetUserTodos(ctx *gin.Context) { + + var ue app.User + if api.GetUser(ctx, &ue, false, true); ctx.IsAborted() { + return + } + + list, err := todosService.GetUserTodos(ue.ID) + if err != nil { + r.FailWithMessage("获取Todo列表失败:"+err.Error(), ctx) + global.GVA_LOG.Error("获取Todo列表失败", zap.Error(err)) + return + } + + r.OkWithData(list, ctx) +} + +// UpdateTodo 更新Todo +func (t TodosApi) UpdateTodo(ctx *gin.Context) { + var todo common.UserTodo + if err := ctx.ShouldBind(&todo); err != nil { + r.FailWithMessage("参数错误:"+err.Error(), ctx) + global.GVA_LOG.Error("参数错误", zap.Error(err)) + return + } + + // 更新 + err := todosService.UpdateTodoById(&todo) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("更新失败", zap.Error(err)) + return + } + r.Ok(ctx) +} diff --git a/api/v1/app/user.go b/api/v1/app/user.go new file mode 100644 index 0000000..ca35748 --- /dev/null +++ b/api/v1/app/user.go @@ -0,0 +1,134 @@ +package app + +import ( + "git.echol.cn/loser/logger/log" + "github.com/gin-gonic/gin" + "miniapp/api" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" + "miniapp/model/app/response" + r "miniapp/model/common/response" + "miniapp/utils" + "strings" +) + +type UserApi struct { +} + +// GetUser 获取当前登录用户信息 +func (u *UserApi) GetUser(ctx *gin.Context) { + // 取出当前登录用户 + var ue app.User + if api.GetUser(ctx, &ue, false, true); ctx.IsAborted() { + return + } + // 转换为VO + var v response.UserVO + v.ParseOrdinary(ue) + + r.OkWithData(v, ctx) +} + +// BindingWeChat 绑定微信 +func (u *UserApi) BindingWeChat(ctx *gin.Context) { + var p request.BindingWeChat + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + // 取出当前登录用户 + var loginUser app.User + if api.GetUser(ctx, &loginUser, true, true); ctx.IsAborted() { + return + } + + // 解析出UnionId和OpenId + unionId, openId, _, err := utils.WeChatUtils().GetWechatUnionId(p.Code) + if err != nil { + log.Errorf("获取微信UnionId失败:%s", err.Error()) + r.FailWithMessage("系统错误,请稍后再试", ctx) + return + } + + // 解析成功,修改用户信息 + loginUser.WechatUnionId = &unionId + loginUser.WechatOpenId = &openId + if err = userService.UpdateUserInfo(&loginUser); err != nil { + log.Errorf("修改用户信息失败:%s", err.Error()) + r.FailWithMessage("系统错误,请稍后再试", ctx) + return + } + r.Ok(ctx) +} + +// UpdateUser 修改用户信息 +func (u *UserApi) UpdateUser(ctx *gin.Context) { + var p request.ChangeUserInfo + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误: "+err.Error(), ctx) + return + } + // 获取当前登录用户 + var loginUser app.User + if api.GetUser(ctx, &loginUser, false, true); ctx.IsAborted() { + return + } + // 修改资料 + + if p.Nickname != "" { + loginUser.Nickname = p.Nickname + } + if p.Avatar != "" && strings.HasPrefix(p.Avatar, "http") { + loginUser.Avatar = p.Avatar + } + if p.Phone != "" { + loginUser.Phone = p.Phone + } + // 修改数据 + if err := userService.UpdateUserInfo(&loginUser); err != nil { + log.Errorf("修改用户信息失败:%s", err.Error()) + r.FailWithMessage("修改用户信息失败"+err.Error(), ctx) + return + } + // 操作成功,更新头像和昵称 + r.Ok(ctx) +} + +// UpdateUserHospital 修改用户医院信息 +func (u *UserApi) UpdateUserHospital(ctx *gin.Context) { + var p request.ChangeUserHospital + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误: "+err.Error(), ctx) + return + } + + // 修改数据 + if err := userService.UpdateUserHospital(&p); err != nil { + log.Errorf("修改用户信息失败:%s", err.Error()) + r.FailWithMessage("修改用户信息失败"+err.Error(), ctx) + return + } + // 操作成功,更新头像和昵称 + r.Ok(ctx) +} + +// GetInfo 获取用户信息 +func (u *UserApi) GetInfo(ctx *gin.Context) { + id := ctx.Param("id") + if id == "" { + global.GVA_LOG.Error("参数错误") + r.FailWithMessage("参数错误", ctx) + return + } + + // 获取用户信息 + userInfo, err := userService.GetUserInfo(id) + if err != nil { + log.Errorf("获取用户信息失败:%s", err.Error()) + r.FailWithMessage("获取用户信息失败"+err.Error(), ctx) + return + } + r.OkWithData(userInfo, ctx) +} diff --git a/api/v1/app/vision.go b/api/v1/app/vision.go new file mode 100644 index 0000000..c62b78b --- /dev/null +++ b/api/v1/app/vision.go @@ -0,0 +1,56 @@ +package app + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" + r "miniapp/model/common/response" +) + +type VisionApi struct{} + +func (VisionApi) GetList(ctx *gin.Context) { + var p request.VisionListRequest + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误:"+err.Error(), ctx) + global.GVA_LOG.Error("参数错误", zap.Error(err)) + return + } + + // 获取列表 + list, total, err := visionService.GetVisionList(p) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("获取列表失败", zap.Error(err)) + return + } + + r.OkWithData(r.PageResult{ + List: list, + Total: total, + Page: p.Page, + PageSize: p.PageSize, + }, ctx) +} + +func (VisionApi) Create(ctx *gin.Context) { + var p app.Vision + + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("参数错误", zap.Error(err)) + return + } + + // 创建 + err := visionService.CreateVision(&p) + if err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("创建失败", zap.Error(err)) + return + } + + r.Ok(ctx) +} diff --git a/api/v1/enter.go b/api/v1/enter.go new file mode 100644 index 0000000..2fc3782 --- /dev/null +++ b/api/v1/enter.go @@ -0,0 +1,15 @@ +package v1 + +import ( + "miniapp/api/v1/app" + "miniapp/api/v1/example" + "miniapp/api/v1/system" +) + +type ApiGroup struct { + SystemApiGroup system.ApiGroup + ExampleApiGroup example.ApiGroup + AppApiGroup app.ApiGroup +} + +var ApiGroupApp = new(ApiGroup) diff --git a/api/v1/example/enter.go b/api/v1/example/enter.go new file mode 100644 index 0000000..2c572dd --- /dev/null +++ b/api/v1/example/enter.go @@ -0,0 +1,13 @@ +package example + +import "miniapp/service" + +type ApiGroup struct { + CustomerApi + FileUploadAndDownloadApi +} + +var ( + customerService = service.ServiceGroupApp.ExampleServiceGroup.CustomerService + fileUploadAndDownloadService = service.ServiceGroupApp.ExampleServiceGroup.FileUploadAndDownloadService +) diff --git a/api/v1/example/exa_breakpoint_continue.go b/api/v1/example/exa_breakpoint_continue.go new file mode 100644 index 0000000..32447c5 --- /dev/null +++ b/api/v1/example/exa_breakpoint_continue.go @@ -0,0 +1,150 @@ +package example + +import ( + "fmt" + "io" + "mime/multipart" + "strconv" + + "miniapp/model/example" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + exampleRes "miniapp/model/example/response" + "miniapp/utils" +) + +// BreakpointContinue +// @Tags ExaFileUploadAndDownload +// @Summary 断点续传到服务器 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param file formData file true "an example for breakpoint resume, 断点续传示例" +// @Success 200 {object} response.Response{msg=string} "断点续传到服务器" +// @Router /fileUploadAndDownload/breakpointContinue [post] +func (b *FileUploadAndDownloadApi) BreakpointContinue(c *gin.Context) { + fileMd5 := c.Request.FormValue("fileMd5") + fileName := c.Request.FormValue("fileName") + chunkMd5 := c.Request.FormValue("chunkMd5") + chunkNumber, _ := strconv.Atoi(c.Request.FormValue("chunkNumber")) + chunkTotal, _ := strconv.Atoi(c.Request.FormValue("chunkTotal")) + _, FileHeader, err := c.Request.FormFile("file") + if err != nil { + global.GVA_LOG.Error("接收文件失败!", zap.Error(err)) + response.FailWithMessage("接收文件失败", c) + return + } + f, err := FileHeader.Open() + if err != nil { + global.GVA_LOG.Error("文件读取失败!", zap.Error(err)) + response.FailWithMessage("文件读取失败", c) + return + } + defer func(f multipart.File) { + err := f.Close() + if err != nil { + fmt.Println(err) + } + }(f) + cen, _ := io.ReadAll(f) + if !utils.CheckMd5(cen, chunkMd5) { + global.GVA_LOG.Error("检查md5失败!", zap.Error(err)) + response.FailWithMessage("检查md5失败", c) + return + } + file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal) + if err != nil { + global.GVA_LOG.Error("查找或创建记录失败!", zap.Error(err)) + response.FailWithMessage("查找或创建记录失败", c) + return + } + pathC, err := utils.BreakPointContinue(cen, fileName, chunkNumber, chunkTotal, fileMd5) + if err != nil { + global.GVA_LOG.Error("断点续传失败!", zap.Error(err)) + response.FailWithMessage("断点续传失败", c) + return + } + + if err = fileUploadAndDownloadService.CreateFileChunk(file.ID, pathC, chunkNumber); err != nil { + global.GVA_LOG.Error("创建文件记录失败!", zap.Error(err)) + response.FailWithMessage("创建文件记录失败", c) + return + } + response.OkWithMessage("切片创建成功", c) +} + +// FindFile +// @Tags ExaFileUploadAndDownload +// @Summary 查找文件 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param file formData file true "Find the file, 查找文件" +// @Success 200 {object} response.Response{data=exampleRes.FileResponse,msg=string} "查找文件,返回包括文件详情" +// @Router /fileUploadAndDownload/findFile [post] +func (b *FileUploadAndDownloadApi) FindFile(c *gin.Context) { + fileMd5 := c.Query("fileMd5") + fileName := c.Query("fileName") + chunkTotal, _ := strconv.Atoi(c.Query("chunkTotal")) + file, err := fileUploadAndDownloadService.FindOrCreateFile(fileMd5, fileName, chunkTotal) + if err != nil { + global.GVA_LOG.Error("查找失败!", zap.Error(err)) + response.FailWithMessage("查找失败", c) + } else { + response.OkWithDetailed(exampleRes.FileResponse{File: file}, "查找成功", c) + } +} + +// BreakpointContinueFinish +// @Tags ExaFileUploadAndDownload +// @Summary 创建文件 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param file formData file true "上传文件完成" +// @Success 200 {object} response.Response{data=exampleRes.FilePathResponse,msg=string} "创建文件,返回包括文件路径" +// @Router /fileUploadAndDownload/findFile [post] +func (b *FileUploadAndDownloadApi) BreakpointContinueFinish(c *gin.Context) { + fileMd5 := c.Query("fileMd5") + fileName := c.Query("fileName") + filePath, err := utils.MakeFile(fileName, fileMd5) + if err != nil { + global.GVA_LOG.Error("文件创建失败!", zap.Error(err)) + response.FailWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建失败", c) + } else { + response.OkWithDetailed(exampleRes.FilePathResponse{FilePath: filePath}, "文件创建成功", c) + } +} + +// RemoveChunk +// @Tags ExaFileUploadAndDownload +// @Summary 删除切片 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param file formData file true "删除缓存切片" +// @Success 200 {object} response.Response{msg=string} "删除切片" +// @Router /fileUploadAndDownload/removeChunk [post] +func (b *FileUploadAndDownloadApi) RemoveChunk(c *gin.Context) { + var file example.ExaFile + err := c.ShouldBindJSON(&file) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.RemoveChunk(file.FileMd5) + if err != nil { + global.GVA_LOG.Error("缓存切片删除失败!", zap.Error(err)) + return + } + err = fileUploadAndDownloadService.DeleteFileChunk(file.FileMd5, file.FilePath) + if err != nil { + global.GVA_LOG.Error(err.Error(), zap.Error(err)) + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithMessage("缓存切片删除成功", c) +} diff --git a/api/v1/example/exa_customer.go b/api/v1/example/exa_customer.go new file mode 100644 index 0000000..1b81e59 --- /dev/null +++ b/api/v1/example/exa_customer.go @@ -0,0 +1,176 @@ +package example + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/example" + exampleRes "miniapp/model/example/response" + "miniapp/utils" +) + +type CustomerApi struct{} + +// CreateExaCustomer +// @Tags ExaCustomer +// @Summary 创建客户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body example.ExaCustomer true "客户用户名, 客户手机号码" +// @Success 200 {object} response.Response{msg=string} "创建客户" +// @Router /customer/customer [post] +func (e *CustomerApi) CreateExaCustomer(c *gin.Context) { + var customer example.ExaCustomer + err := c.ShouldBindJSON(&customer) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(customer, utils.CustomerVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + customer.SysUserID = utils.GetUserID(c) + customer.SysUserAuthorityID = utils.GetUserAuthorityId(c) + err = customerService.CreateExaCustomer(customer) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + return + } + response.OkWithMessage("创建成功", c) +} + +// DeleteExaCustomer +// @Tags ExaCustomer +// @Summary 删除客户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body example.ExaCustomer true "客户ID" +// @Success 200 {object} response.Response{msg=string} "删除客户" +// @Router /customer/customer [delete] +func (e *CustomerApi) DeleteExaCustomer(c *gin.Context) { + var customer example.ExaCustomer + err := c.ShouldBindJSON(&customer) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(customer.GVA_MODEL, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = customerService.DeleteExaCustomer(customer) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// UpdateExaCustomer +// @Tags ExaCustomer +// @Summary 更新客户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body example.ExaCustomer true "客户ID, 客户信息" +// @Success 200 {object} response.Response{msg=string} "更新客户信息" +// @Router /customer/customer [put] +func (e *CustomerApi) UpdateExaCustomer(c *gin.Context) { + var customer example.ExaCustomer + err := c.ShouldBindJSON(&customer) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(customer.GVA_MODEL, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(customer, utils.CustomerVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = customerService.UpdateExaCustomer(&customer) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + return + } + response.OkWithMessage("更新成功", c) +} + +// GetExaCustomer +// @Tags ExaCustomer +// @Summary 获取单一客户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query example.ExaCustomer true "客户ID" +// @Success 200 {object} response.Response{data=exampleRes.ExaCustomerResponse,msg=string} "获取单一客户信息,返回包括客户详情" +// @Router /customer/customer [get] +func (e *CustomerApi) GetExaCustomer(c *gin.Context) { + var customer example.ExaCustomer + err := c.ShouldBindQuery(&customer) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(customer.GVA_MODEL, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + data, err := customerService.GetExaCustomer(customer.ID) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(exampleRes.ExaCustomerResponse{Customer: data}, "获取成功", c) +} + +// GetExaCustomerList +// @Tags ExaCustomer +// @Summary 分页获取权限客户列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "页码, 每页大小" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取权限客户列表,返回包括列表,总数,页码,每页数量" +// @Router /customer/customerList [get] +func (e *CustomerApi) GetExaCustomerList(c *gin.Context) { + var pageInfo request.PageInfo + err := c.ShouldBindQuery(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + customerList, total, err := customerService.GetCustomerInfoList(utils.GetUserAuthorityId(c), pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败"+err.Error(), c) + return + } + response.OkWithDetailed(response.PageResult{ + List: customerList, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/example/exa_file_upload_download.go b/api/v1/example/exa_file_upload_download.go new file mode 100644 index 0000000..52bbe90 --- /dev/null +++ b/api/v1/example/exa_file_upload_download.go @@ -0,0 +1,110 @@ +package example + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/example" + exampleRes "miniapp/model/example/response" +) + +type FileUploadAndDownloadApi struct{} + +// UploadFile +// @Tags ExaFileUploadAndDownload +// @Summary 上传文件示例 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param file formData file true "上传文件示例" +// @Success 200 {object} response.Response{data=exampleRes.ExaFileResponse,msg=string} "上传文件示例,返回包括文件详情" +// @Router /fileUploadAndDownload/upload [post] +func (b *FileUploadAndDownloadApi) UploadFile(c *gin.Context) { + var file example.ExaFileUploadAndDownload + noSave := c.DefaultQuery("noSave", "0") + _, header, err := c.Request.FormFile("file") + if err != nil { + global.GVA_LOG.Error("接收文件失败!", zap.Error(err)) + response.FailWithMessage("接收文件失败", c) + return + } + file, err = fileUploadAndDownloadService.UploadFile(header, noSave) // 文件上传后拿到文件路径 + if err != nil { + global.GVA_LOG.Error("修改数据库链接失败!", zap.Error(err)) + response.FailWithMessage("修改数据库链接失败", c) + return + } + response.OkWithDetailed(exampleRes.ExaFileResponse{File: file}, "上传成功", c) +} + +// EditFileName 编辑文件名或者备注 +func (b *FileUploadAndDownloadApi) EditFileName(c *gin.Context) { + var file example.ExaFileUploadAndDownload + err := c.ShouldBindJSON(&file) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = fileUploadAndDownloadService.EditFileName(file) + if err != nil { + global.GVA_LOG.Error("编辑失败!", zap.Error(err)) + response.FailWithMessage("编辑失败", c) + return + } + response.OkWithMessage("编辑成功", c) +} + +// DeleteFile +// @Tags ExaFileUploadAndDownload +// @Summary 删除文件 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body example.ExaFileUploadAndDownload true "传入文件里面id即可" +// @Success 200 {object} response.Response{msg=string} "删除文件" +// @Router /fileUploadAndDownload/deleteFile [post] +func (b *FileUploadAndDownloadApi) DeleteFile(c *gin.Context) { + var file example.ExaFileUploadAndDownload + err := c.ShouldBindJSON(&file) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if err := fileUploadAndDownloadService.DeleteFile(file); err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// GetFileList +// @Tags ExaFileUploadAndDownload +// @Summary 分页文件列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "页码, 每页大小" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页文件列表,返回包括列表,总数,页码,每页数量" +// @Router /fileUploadAndDownload/getFileList [post] +func (b *FileUploadAndDownloadApi) GetFileList(c *gin.Context) { + var pageInfo request.PageInfo + err := c.ShouldBindJSON(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := fileUploadAndDownloadService.GetFileRecordInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/article.go b/api/v1/system/article.go new file mode 100644 index 0000000..b438b9a --- /dev/null +++ b/api/v1/system/article.go @@ -0,0 +1,106 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/common" + "miniapp/model/common/request" + r "miniapp/model/common/response" +) + +type ArticleApi struct{} + +// GetArticleList 获取文章列表 +func (a ArticleApi) GetArticleList(ctx *gin.Context) { + var p request.PageInfo + if err := ctx.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + list, total, err := articleService.GetArticleList(p) + if err != nil { + global.GVA_LOG.Error("获取文章列表失败" + err.Error()) + r.FailWithMessage("获取文章列表失败", ctx) + return + } + + r.OkWithDetailed(r.PageResult{List: list, Total: total, Page: p.Page, PageSize: p.PageSize}, "获取成功", ctx) +} + +// CreateArticle 创建文章 +func (a ArticleApi) CreateArticle(ctx *gin.Context) { + var article common.Article + if err := ctx.ShouldBindJSON(&article); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := articleService.CreateArticle(&article) + if err != nil { + global.GVA_LOG.Error("创建失败" + err.Error()) + r.FailWithMessage("创建失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("创建成功", ctx) +} + +// UpdateArticle 更新文章 +func (a ArticleApi) UpdateArticle(ctx *gin.Context) { + var article common.Article + if err := ctx.ShouldBindJSON(&article); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := articleService.UpdateArticle(&article) + if err != nil { + global.GVA_LOG.Error("更新失败" + err.Error()) + r.FailWithMessage("更新失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("更新成功", ctx) +} + +// DeleteArticle 删除文章 +func (a ArticleApi) DeleteArticle(ctx *gin.Context) { + var article common.Article + if err := ctx.ShouldBind(&article); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := articleService.DeleteArticle(&article) + if err != nil { + global.GVA_LOG.Error("删除失败" + err.Error()) + r.FailWithMessage("删除失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("删除成功", ctx) +} + +// GetArticleById 根据id获取文章 +func (a ArticleApi) GetArticleById(ctx *gin.Context) { + Id := ctx.Param("id") + if Id == "" { + global.GVA_LOG.Error("参数错误") + r.FailWithMessage("参数错误", ctx) + return + } + + article, err := articleService.GetArticleById(Id) + if err != nil { + global.GVA_LOG.Error("获取失败" + err.Error()) + r.FailWithMessage("获取失败"+err.Error(), ctx) + return + } + + r.OkWithDetailed(article, "获取成功", ctx) +} diff --git a/api/v1/system/banner.go b/api/v1/system/banner.go new file mode 100644 index 0000000..1c5e632 --- /dev/null +++ b/api/v1/system/banner.go @@ -0,0 +1,108 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/common" + "miniapp/model/common/request" + r "miniapp/model/common/response" +) + +type BannerApi struct { +} + +// GetBannerList 获取轮播图列表 +func (b *BannerApi) GetBannerList(ctx *gin.Context) { + var p request.PageInfo + + if err := ctx.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + list, total, err := bannerService.GetBannerList(p) + if err != nil { + global.GVA_LOG.Error("获取轮播图列表失败" + err.Error()) + r.FailWithMessage("获取轮播图列表失败", ctx) + return + } + + r.OkWithDetailed(r.PageResult{List: list, Total: total, Page: p.Page, PageSize: p.PageSize}, "获取成功", ctx) +} + +// CreateBanner 创建轮播图 +func (b *BannerApi) CreateBanner(ctx *gin.Context) { + var banner common.Banner + if err := ctx.ShouldBindJSON(&banner); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := bannerService.CreateBanner(&banner) + if err != nil { + global.GVA_LOG.Error("创建失败" + err.Error()) + r.FailWithMessage("创建失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("创建成功", ctx) +} + +// UpdateBanner 更新轮播图 +func (b *BannerApi) UpdateBanner(ctx *gin.Context) { + var banner common.Banner + if err := ctx.ShouldBindJSON(&banner); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := bannerService.UpdateBanner(&banner) + if err != nil { + global.GVA_LOG.Error("更新失败" + err.Error()) + r.FailWithMessage("更新失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("更新成功", ctx) +} + +// DeleteBanner 删除轮播图 +func (b *BannerApi) DeleteBanner(ctx *gin.Context) { + var banner common.Banner + if err := ctx.ShouldBind(&banner); err != nil { + global.GVA_LOG.Error("参数错误" + err.Error()) + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := bannerService.DeleteBanner(&banner) + if err != nil { + global.GVA_LOG.Error("删除失败" + err.Error()) + r.FailWithMessage("删除失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("删除成功", ctx) +} + +// GetBannerById 根据id获取轮播图 +func (b *BannerApi) GetBannerById(ctx *gin.Context) { + Id := ctx.Param("id") + if Id == "" { + global.GVA_LOG.Error("参数错误") + r.FailWithMessage("参数错误", ctx) + return + } + + banner, err := bannerService.GetBannerById(Id) + if err != nil { + global.GVA_LOG.Error("获取失败" + err.Error()) + r.FailWithMessage("获取失败"+err.Error(), ctx) + return + } + + r.OkWithDetailed(banner, "获取成功", ctx) +} diff --git a/api/v1/system/enter.go b/api/v1/system/enter.go new file mode 100644 index 0000000..ed60af7 --- /dev/null +++ b/api/v1/system/enter.go @@ -0,0 +1,46 @@ +package system + +import "miniapp/service" + +type ApiGroup struct { + DBApi + JwtApi + BaseApi + SystemApi + CasbinApi + AutoCodeApi + SystemApiApi + AuthorityApi + DictionaryApi + AuthorityMenuApi + OperationRecordApi + AutoCodeHistoryApi + DictionaryDetailApi + AuthorityBtnApi + ChatGptApi + BannerApi + HospitalApi + ArticleApi +} + +var ( + apiService = service.ServiceGroupApp.SystemServiceGroup.ApiService + jwtService = service.ServiceGroupApp.SystemServiceGroup.JwtService + menuService = service.ServiceGroupApp.SystemServiceGroup.MenuService + userService = service.ServiceGroupApp.SystemServiceGroup.UserService + initDBService = service.ServiceGroupApp.SystemServiceGroup.InitDBService + casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService + autoCodeService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeService + baseMenuService = service.ServiceGroupApp.SystemServiceGroup.BaseMenuService + authorityService = service.ServiceGroupApp.SystemServiceGroup.AuthorityService + dictionaryService = service.ServiceGroupApp.SystemServiceGroup.DictionaryService + systemConfigService = service.ServiceGroupApp.SystemServiceGroup.SystemConfigService + operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService + autoCodeHistoryService = service.ServiceGroupApp.SystemServiceGroup.AutoCodeHistoryService + dictionaryDetailService = service.ServiceGroupApp.SystemServiceGroup.DictionaryDetailService + authorityBtnService = service.ServiceGroupApp.SystemServiceGroup.AuthorityBtnService + chatGptService = service.ServiceGroupApp.SystemServiceGroup.ChatGptService + hospitalService = service.ServiceGroupApp.SystemServiceGroup.HospitalService + bannerService = service.ServiceGroupApp.SystemServiceGroup.BannerService + articleService = service.ServiceGroupApp.SystemServiceGroup.ArticleService +) diff --git a/api/v1/system/hospital.go b/api/v1/system/hospital.go new file mode 100644 index 0000000..20af3d6 --- /dev/null +++ b/api/v1/system/hospital.go @@ -0,0 +1,100 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "miniapp/model/common" + "miniapp/model/common/request" + r "miniapp/model/common/response" + systemService "miniapp/service/system" + "strconv" +) + +type HospitalApi struct { +} + +// GetHospitalList 获取医院列表 +func (h HospitalApi) GetHospitalList(ctx *gin.Context) { + var p request.PageInfo + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + list, total, err := systemService.HospitalService{}.GetHospitalList(p) + if err != nil { + r.FailWithMessage("获取医院列表失败", ctx) + return + } + + r.OkWithDetailed(r.PageResult{List: list, Total: total, Page: p.Page, PageSize: p.PageSize}, "获取成功", ctx) +} + +// CreateHospital 创建医院 +func (h HospitalApi) CreateHospital(ctx *gin.Context) { + var hospital common.Hospital + if err := ctx.ShouldBindJSON(&hospital); err != nil { + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := systemService.HospitalService{}.CreateHospital(&hospital) + if err != nil { + r.FailWithMessage("创建失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("创建成功", ctx) +} + +// UpdateHospital 更新医院 +func (h HospitalApi) UpdateHospital(ctx *gin.Context) { + var hospital common.Hospital + if err := ctx.ShouldBindJSON(&hospital); err != nil { + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := systemService.HospitalService{}.UpdateHospital(&hospital) + if err != nil { + r.FailWithMessage("更新失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("更新成功", ctx) +} + +// DeleteHospital 删除医院 +func (h HospitalApi) DeleteHospital(ctx *gin.Context) { + var hospital common.Hospital + if err := ctx.ShouldBind(&hospital); err != nil { + r.FailWithMessage("参数错误"+err.Error(), ctx) + return + } + + err := hospitalService.DeleteHospital(&hospital) + if err != nil { + r.FailWithMessage("删除失败"+err.Error(), ctx) + return + } + + r.OkWithMessage("删除成功", ctx) +} + +// GetHospitalById 根据id获取医院 +func (h HospitalApi) GetHospitalById(ctx *gin.Context) { + Id := ctx.Param("id") + if Id == "" { + r.FailWithMessage("参数错误", ctx) + return + } + + // 参数转换 string -> int + id, _ := strconv.Atoi(Id) + hospitalResult, err := systemService.HospitalService{}.GetHospitalById(uint(id)) + if err != nil { + r.FailWithMessage("获取失败"+err.Error(), ctx) + return + } + + r.OkWithDetailed(hospitalResult, "获取成功", ctx) +} diff --git a/api/v1/system/sys_api.go b/api/v1/system/sys_api.go new file mode 100644 index 0000000..f0e208e --- /dev/null +++ b/api/v1/system/sys_api.go @@ -0,0 +1,231 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/system" + systemReq "miniapp/model/system/request" + systemRes "miniapp/model/system/response" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type SystemApiApi struct{} + +// CreateApi +// @Tags SysApi +// @Summary 创建基础api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法" +// @Success 200 {object} response.Response{msg=string} "创建基础api" +// @Router /api/createApi [post] +func (s *SystemApiApi) CreateApi(c *gin.Context) { + var api system.SysApi + err := c.ShouldBindJSON(&api) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(api, utils.ApiVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = apiService.CreateApi(api) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + return + } + response.OkWithMessage("创建成功", c) +} + +// DeleteApi +// @Tags SysApi +// @Summary 删除api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysApi true "ID" +// @Success 200 {object} response.Response{msg=string} "删除api" +// @Router /api/deleteApi [post] +func (s *SystemApiApi) DeleteApi(c *gin.Context) { + var api system.SysApi + err := c.ShouldBindJSON(&api) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(api.GVA_MODEL, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = apiService.DeleteApi(api) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// GetApiList +// @Tags SysApi +// @Summary 分页获取API列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.SearchApiParams true "分页获取API列表" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取API列表,返回包括列表,总数,页码,每页数量" +// @Router /api/getApiList [post] +func (s *SystemApiApi) GetApiList(c *gin.Context) { + var pageInfo systemReq.SearchApiParams + err := c.ShouldBindJSON(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := apiService.GetAPIInfoList(pageInfo.SysApi, pageInfo.PageInfo, pageInfo.OrderKey, pageInfo.Desc) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} + +// GetApiById +// @Tags SysApi +// @Summary 根据id获取api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "根据id获取api" +// @Success 200 {object} response.Response{data=systemRes.SysAPIResponse} "根据id获取api,返回包括api详情" +// @Router /api/getApiById [post] +func (s *SystemApiApi) GetApiById(c *gin.Context) { + var idInfo request.GetById + err := c.ShouldBindJSON(&idInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(idInfo, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + api, err := apiService.GetApiById(idInfo.ID) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysAPIResponse{Api: api}, "获取成功", c) +} + +// UpdateApi +// @Tags SysApi +// @Summary 修改基础api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysApi true "api路径, api中文描述, api组, 方法" +// @Success 200 {object} response.Response{msg=string} "修改基础api" +// @Router /api/updateApi [post] +func (s *SystemApiApi) UpdateApi(c *gin.Context) { + var api system.SysApi + err := c.ShouldBindJSON(&api) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(api, utils.ApiVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = apiService.UpdateApi(api) + if err != nil { + global.GVA_LOG.Error("修改失败!", zap.Error(err)) + response.FailWithMessage("修改失败", c) + return + } + response.OkWithMessage("修改成功", c) +} + +// GetAllApis +// @Tags SysApi +// @Summary 获取所有的Api 不分页 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=systemRes.SysAPIListResponse,msg=string} "获取所有的Api 不分页,返回包括api列表" +// @Router /api/getAllApis [post] +func (s *SystemApiApi) GetAllApis(c *gin.Context) { + apis, err := apiService.GetAllApis() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysAPIListResponse{Apis: apis}, "获取成功", c) +} + +// DeleteApisByIds +// @Tags SysApi +// @Summary 删除选中Api +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "ID" +// @Success 200 {object} response.Response{msg=string} "删除选中Api" +// @Router /api/deleteApisByIds [delete] +func (s *SystemApiApi) DeleteApisByIds(c *gin.Context) { + var ids request.IdsReq + err := c.ShouldBindJSON(&ids) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = apiService.DeleteApisByIds(ids) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// FreshCasbin +// @Tags SysApi +// @Summary 刷新casbin缓存 +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{msg=string} "刷新成功" +// @Router /api/freshCasbin [get] +func (s *SystemApiApi) FreshCasbin(c *gin.Context) { + err := apiService.FreshCasbin() + if err != nil { + global.GVA_LOG.Error("刷新失败!", zap.Error(err)) + response.FailWithMessage("刷新失败", c) + return + } + response.OkWithMessage("刷新成功", c) +} diff --git a/api/v1/system/sys_authority.go b/api/v1/system/sys_authority.go new file mode 100644 index 0000000..fee9d7b --- /dev/null +++ b/api/v1/system/sys_authority.go @@ -0,0 +1,208 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/system" + systemReq "miniapp/model/system/request" + systemRes "miniapp/model/system/response" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type AuthorityApi struct{} + +// CreateAuthority +// @Tags Authority +// @Summary 创建角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id" +// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "创建角色,返回包括系统角色详情" +// @Router /authority/createAuthority [post] +func (a *AuthorityApi) CreateAuthority(c *gin.Context) { + var authority system.SysAuthority + err := c.ShouldBindJSON(&authority) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + + err = utils.Verify(authority, utils.AuthorityVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if authBack, err := authorityService.CreateAuthority(authority); err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败"+err.Error(), c) + } else { + _ = menuService.AddMenuAuthority(systemReq.DefaultMenu(), authority.AuthorityId) + _ = casbinService.UpdateCasbin(authority.AuthorityId, systemReq.DefaultCasbin()) + response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "创建成功", c) + } +} + +// CopyAuthority +// @Tags Authority +// @Summary 拷贝角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body response.SysAuthorityCopyResponse true "旧角色id, 新权限id, 新权限名, 新父角色id" +// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "拷贝角色,返回包括系统角色详情" +// @Router /authority/copyAuthority [post] +func (a *AuthorityApi) CopyAuthority(c *gin.Context) { + var copyInfo systemRes.SysAuthorityCopyResponse + err := c.ShouldBindJSON(©Info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(copyInfo, utils.OldAuthorityVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(copyInfo.Authority, utils.AuthorityVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + authBack, err := authorityService.CopyAuthority(copyInfo) + if err != nil { + global.GVA_LOG.Error("拷贝失败!", zap.Error(err)) + response.FailWithMessage("拷贝失败"+err.Error(), c) + return + } + response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authBack}, "拷贝成功", c) +} + +// DeleteAuthority +// @Tags Authority +// @Summary 删除角色 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAuthority true "删除角色" +// @Success 200 {object} response.Response{msg=string} "删除角色" +// @Router /authority/deleteAuthority [post] +func (a *AuthorityApi) DeleteAuthority(c *gin.Context) { + var authority system.SysAuthority + err := c.ShouldBindJSON(&authority) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(authority, utils.AuthorityIdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = authorityService.DeleteAuthority(&authority) + if err != nil { // 删除角色之前需要判断是否有用户正在使用此角色 + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败"+err.Error(), c) + return + } + response.OkWithMessage("删除成功", c) +} + +// UpdateAuthority +// @Tags Authority +// @Summary 更新角色信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAuthority true "权限id, 权限名, 父角色id" +// @Success 200 {object} response.Response{data=systemRes.SysAuthorityResponse,msg=string} "更新角色信息,返回包括系统角色详情" +// @Router /authority/updateAuthority [post] +func (a *AuthorityApi) UpdateAuthority(c *gin.Context) { + var auth system.SysAuthority + err := c.ShouldBindJSON(&auth) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(auth, utils.AuthorityVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + authority, err := authorityService.UpdateAuthority(auth) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败"+err.Error(), c) + return + } + response.OkWithDetailed(systemRes.SysAuthorityResponse{Authority: authority}, "更新成功", c) +} + +// GetAuthorityList +// @Tags Authority +// @Summary 分页获取角色列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "页码, 每页大小" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取角色列表,返回包括列表,总数,页码,每页数量" +// @Router /authority/getAuthorityList [post] +func (a *AuthorityApi) GetAuthorityList(c *gin.Context) { + var pageInfo request.PageInfo + err := c.ShouldBindJSON(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := authorityService.GetAuthorityInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败"+err.Error(), c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} + +// SetDataAuthority +// @Tags Authority +// @Summary 设置角色资源权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAuthority true "设置角色资源权限" +// @Success 200 {object} response.Response{msg=string} "设置角色资源权限" +// @Router /authority/setDataAuthority [post] +func (a *AuthorityApi) SetDataAuthority(c *gin.Context) { + var auth system.SysAuthority + err := c.ShouldBindJSON(&auth) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(auth, utils.AuthorityIdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = authorityService.SetDataAuthority(auth) + if err != nil { + global.GVA_LOG.Error("设置失败!", zap.Error(err)) + response.FailWithMessage("设置失败"+err.Error(), c) + return + } + response.OkWithMessage("设置成功", c) +} diff --git a/api/v1/system/sys_authority_btn.go b/api/v1/system/sys_authority_btn.go new file mode 100644 index 0000000..380f6c9 --- /dev/null +++ b/api/v1/system/sys_authority_btn.go @@ -0,0 +1,80 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system/request" +) + +type AuthorityBtnApi struct{} + +// GetAuthorityBtn +// @Tags AuthorityBtn +// @Summary 获取权限按钮 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.SysAuthorityBtnReq true "菜单id, 角色id, 选中的按钮id" +// @Success 200 {object} response.Response{data=response.SysAuthorityBtnRes,msg=string} "返回列表成功" +// @Router /authorityBtn/getAuthorityBtn [post] +func (a *AuthorityBtnApi) GetAuthorityBtn(c *gin.Context) { + var req request.SysAuthorityBtnReq + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + res, err := authorityBtnService.GetAuthorityBtn(req) + if err != nil { + global.GVA_LOG.Error("查询失败!", zap.Error(err)) + response.FailWithMessage("查询失败", c) + return + } + response.OkWithDetailed(res, "查询成功", c) +} + +// SetAuthorityBtn +// @Tags AuthorityBtn +// @Summary 设置权限按钮 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.SysAuthorityBtnReq true "菜单id, 角色id, 选中的按钮id" +// @Success 200 {object} response.Response{msg=string} "返回列表成功" +// @Router /authorityBtn/setAuthorityBtn [post] +func (a *AuthorityBtnApi) SetAuthorityBtn(c *gin.Context) { + var req request.SysAuthorityBtnReq + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = authorityBtnService.SetAuthorityBtn(req) + if err != nil { + global.GVA_LOG.Error("分配失败!", zap.Error(err)) + response.FailWithMessage("分配失败", c) + return + } + response.OkWithMessage("分配成功", c) +} + +// CanRemoveAuthorityBtn +// @Tags AuthorityBtn +// @Summary 设置权限按钮 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{msg=string} "删除成功" +// @Router /authorityBtn/canRemoveAuthorityBtn [post] +func (a *AuthorityBtnApi) CanRemoveAuthorityBtn(c *gin.Context) { + id := c.Query("id") + err := authorityBtnService.CanRemoveAuthorityBtn(id) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithMessage("删除成功", c) +} diff --git a/api/v1/system/sys_auto_code.go b/api/v1/system/sys_auto_code.go new file mode 100644 index 0000000..9a368be --- /dev/null +++ b/api/v1/system/sys_auto_code.go @@ -0,0 +1,315 @@ +package system + +import ( + "errors" + "fmt" + "net/url" + "os" + "strings" + + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type AutoCodeApi struct{} + +// PreviewTemp +// @Tags AutoCode +// @Summary 预览创建后的代码 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.AutoCodeStruct true "预览创建代码" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "预览创建后的代码" +// @Router /autoCode/preview [post] +func (autoApi *AutoCodeApi) PreviewTemp(c *gin.Context) { + var a system.AutoCodeStruct + _ = c.ShouldBindJSON(&a) + if err := utils.Verify(a, utils.AutoCodeVerify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + a.Pretreatment() // 处理go关键字 + a.PackageT = utils.FirstUpper(a.Package) + autoCode, err := autoCodeService.PreviewTemp(a) + if err != nil { + global.GVA_LOG.Error("预览失败!", zap.Error(err)) + response.FailWithMessage("预览失败", c) + } else { + response.OkWithDetailed(gin.H{"autoCode": autoCode}, "预览成功", c) + } +} + +// CreateTemp +// @Tags AutoCode +// @Summary 自动代码模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.AutoCodeStruct true "创建自动代码" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /autoCode/createTemp [post] +func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) { + var a system.AutoCodeStruct + _ = c.ShouldBindJSON(&a) + if err := utils.Verify(a, utils.AutoCodeVerify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + a.Pretreatment() + var apiIds []uint + if a.AutoCreateApiToSql { + if ids, err := autoCodeService.AutoCreateApi(&a); err != nil { + global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Error(err)) + c.Writer.Header().Add("success", "false") + c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!")) + return + } else { + apiIds = ids + } + } + a.PackageT = utils.FirstUpper(a.Package) + err := autoCodeService.CreateTemp(a, apiIds...) + if err != nil { + if errors.Is(err, system.ErrAutoMove) { + c.Writer.Header().Add("success", "true") + c.Writer.Header().Add("msg", url.QueryEscape(err.Error())) + } else { + c.Writer.Header().Add("success", "false") + c.Writer.Header().Add("msg", url.QueryEscape(err.Error())) + _ = os.Remove("./ginvueadmin.zip") + } + } else { + c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", "ginvueadmin.zip")) // fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名 + c.Writer.Header().Add("Content-Type", "application/json") + c.Writer.Header().Add("success", "true") + c.File("./ginvueadmin.zip") + _ = os.Remove("./ginvueadmin.zip") + } +} + +// GetDB +// @Tags AutoCode +// @Summary 获取当前所有数据库 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前所有数据库" +// @Router /autoCode/getDatabase [get] +func (autoApi *AutoCodeApi) GetDB(c *gin.Context) { + businessDB := c.Query("businessDB") + dbs, err := autoCodeService.Database(businessDB).GetDB(businessDB) + var dbList []map[string]interface{} + for _, db := range global.GVA_CONFIG.DBList { + var item = make(map[string]interface{}) + item["aliasName"] = db.AliasName + item["dbName"] = db.Dbname + item["disable"] = db.Disable + item["dbtype"] = db.Type + dbList = append(dbList, item) + } + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + } else { + response.OkWithDetailed(gin.H{"dbs": dbs, "dbList": dbList}, "获取成功", c) + } +} + +// GetTables +// @Tags AutoCode +// @Summary 获取当前数据库所有表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前数据库所有表" +// @Router /autoCode/getTables [get] +func (autoApi *AutoCodeApi) GetTables(c *gin.Context) { + dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname) + businessDB := c.Query("businessDB") + tables, err := autoCodeService.Database(businessDB).GetTables(businessDB, dbName) + if err != nil { + global.GVA_LOG.Error("查询table失败!", zap.Error(err)) + response.FailWithMessage("查询table失败", c) + } else { + response.OkWithDetailed(gin.H{"tables": tables}, "获取成功", c) + } +} + +// GetColumn +// @Tags AutoCode +// @Summary 获取当前表所有字段 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取当前表所有字段" +// @Router /autoCode/getColumn [get] +func (autoApi *AutoCodeApi) GetColumn(c *gin.Context) { + businessDB := c.Query("businessDB") + dbName := c.DefaultQuery("dbName", global.GVA_CONFIG.Mysql.Dbname) + tableName := c.Query("tableName") + columns, err := autoCodeService.Database(businessDB).GetColumn(businessDB, tableName, dbName) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + } else { + response.OkWithDetailed(gin.H{"columns": columns}, "获取成功", c) + } +} + +// CreatePackage +// @Tags AutoCode +// @Summary 创建package +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAutoCode true "创建package" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建package成功" +// @Router /autoCode/createPackage [post] +func (autoApi *AutoCodeApi) CreatePackage(c *gin.Context) { + var a system.SysAutoCode + _ = c.ShouldBindJSON(&a) + if err := utils.Verify(a, utils.AutoPackageVerify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err := autoCodeService.CreateAutoCode(&a) + if err != nil { + + global.GVA_LOG.Error("创建成功!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + } else { + response.OkWithMessage("创建成功", c) + } +} + +// GetPackage +// @Tags AutoCode +// @Summary 获取package +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建package成功" +// @Router /autoCode/getPackage [post] +func (autoApi *AutoCodeApi) GetPackage(c *gin.Context) { + pkgs, err := autoCodeService.GetPackage() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + } else { + response.OkWithDetailed(gin.H{"pkgs": pkgs}, "获取成功", c) + } +} + +// DelPackage +// @Tags AutoCode +// @Summary 删除package +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAutoCode true "创建package" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "删除package成功" +// @Router /autoCode/delPackage [post] +func (autoApi *AutoCodeApi) DelPackage(c *gin.Context) { + var a system.SysAutoCode + _ = c.ShouldBindJSON(&a) + err := autoCodeService.DelPackage(a) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + } else { + response.OkWithMessage("删除成功", c) + } +} + +// AutoPlug +// @Tags AutoCode +// @Summary 创建插件模板 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAutoCode true "创建插件模板" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "创建插件模板成功" +// @Router /autoCode/createPlug [post] +func (autoApi *AutoCodeApi) AutoPlug(c *gin.Context) { + var a system.AutoPlugReq + err := c.ShouldBindJSON(&a) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + a.Snake = strings.ToLower(a.PlugName) + a.NeedModel = a.HasRequest || a.HasResponse + err = autoCodeService.CreatePlug(a) + if err != nil { + global.GVA_LOG.Error("预览失败!", zap.Error(err)) + response.FailWithMessage("预览失败", c) + return + } + response.Ok(c) +} + +// InstallPlugin +// @Tags AutoCode +// @Summary 安装插件 +// @Security ApiKeyAuth +// @accept multipart/form-data +// @Produce application/json +// @Param plug formData file true "this is a test file" +// @Success 200 {object} response.Response{data=[]interface{},msg=string} "安装插件成功" +// @Router /autoCode/installPlugin [post] +func (autoApi *AutoCodeApi) InstallPlugin(c *gin.Context) { + header, err := c.FormFile("plug") + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + web, server, err := autoCodeService.InstallPlugin(header) + webStr := "web插件安装成功" + serverStr := "server插件安装成功" + if web == -1 { + webStr = "web端插件未成功安装,请按照文档自行解压安装,如果为纯后端插件请忽略此条提示" + } + if server == -1 { + serverStr = "server端插件未成功安装,请按照文档自行解压安装,如果为纯前端插件请忽略此条提示" + } + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithData([]interface{}{ + gin.H{ + "code": web, + "msg": webStr, + }, + gin.H{ + "code": server, + "msg": serverStr, + }}, c) +} + +// PubPlug +// @Tags AutoCode +// @Summary 打包插件 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysAutoCode true "打包插件" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "打包插件成功" +// @Router /autoCode/pubPlug [get] +func (autoApi *AutoCodeApi) PubPlug(c *gin.Context) { + plugName := c.Query("plugName") + snake := strings.ToLower(plugName) + zipPath, err := autoCodeService.PubPlug(snake) + if err != nil { + global.GVA_LOG.Error("打包失败!", zap.Error(err)) + response.FailWithMessage("打包失败"+err.Error(), c) + return + } + response.OkWithMessage(fmt.Sprintf("打包成功,文件路径为:%s", zipPath), c) +} diff --git a/api/v1/system/sys_auto_code_history.go b/api/v1/system/sys_auto_code_history.go new file mode 100644 index 0000000..fdb59fb --- /dev/null +++ b/api/v1/system/sys_auto_code_history.go @@ -0,0 +1,115 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + systemReq "miniapp/model/system/request" +) + +type AutoCodeHistoryApi struct{} + +// First +// @Tags AutoCode +// @Summary 获取meta信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "请求参数" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取meta信息" +// @Router /autoCode/getMeta [post] +func (a *AutoCodeHistoryApi) First(c *gin.Context) { + var info request.GetById + err := c.ShouldBindJSON(&info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + data, err := autoCodeHistoryService.First(&info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithDetailed(gin.H{"meta": data}, "获取成功", c) +} + +// Delete +// @Tags AutoCode +// @Summary 删除回滚记录 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "请求参数" +// @Success 200 {object} response.Response{msg=string} "删除回滚记录" +// @Router /autoCode/delSysHistory [post] +func (a *AutoCodeHistoryApi) Delete(c *gin.Context) { + var info request.GetById + err := c.ShouldBindJSON(&info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = autoCodeHistoryService.Delete(&info) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// RollBack +// @Tags AutoCode +// @Summary 回滚自动生成代码 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.RollBack true "请求参数" +// @Success 200 {object} response.Response{msg=string} "回滚自动生成代码" +// @Router /autoCode/rollback [post] +func (a *AutoCodeHistoryApi) RollBack(c *gin.Context) { + var info systemReq.RollBack + err := c.ShouldBindJSON(&info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = autoCodeHistoryService.RollBack(&info) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + response.OkWithMessage("回滚成功", c) +} + +// GetList +// @Tags AutoCode +// @Summary 查询回滚记录 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.SysAutoHistory true "请求参数" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "查询回滚记录,返回包括列表,总数,页码,每页数量" +// @Router /autoCode/getSysHistory [post] +func (a *AutoCodeHistoryApi) GetList(c *gin.Context) { + var search systemReq.SysAutoHistory + err := c.ShouldBindJSON(&search) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := autoCodeHistoryService.GetList(search.PageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: search.Page, + PageSize: search.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/sys_captcha.go b/api/v1/system/sys_captcha.go new file mode 100644 index 0000000..5d7d263 --- /dev/null +++ b/api/v1/system/sys_captcha.go @@ -0,0 +1,70 @@ +package system + +import ( + "time" + + "github.com/gin-gonic/gin" + "github.com/mojocn/base64Captcha" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + systemRes "miniapp/model/system/response" +) + +// 当开启多服务器部署时,替换下面的配置,使用redis共享存储验证码 +// var store = captcha.NewDefaultRedisStore() +var store = base64Captcha.DefaultMemStore + +type BaseApi struct{} + +// Captcha +// @Tags Base +// @Summary 生成验证码 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=systemRes.SysCaptchaResponse,msg=string} "生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码" +// @Router /base/captcha [post] +func (b *BaseApi) Captcha(c *gin.Context) { + // 判断验证码是否开启 + openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数 + openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间 + key := c.ClientIP() + v, ok := global.BlackCache.Get(key) + if !ok { + global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut)) + } + + var oc bool + if openCaptcha == 0 || openCaptcha < interfaceToInt(v) { + oc = true + } + // 字符,公式,验证码配置 + // 生成默认数字的driver + driver := base64Captcha.NewDriverDigit(global.GVA_CONFIG.Captcha.ImgHeight, global.GVA_CONFIG.Captcha.ImgWidth, global.GVA_CONFIG.Captcha.KeyLong, 0.7, 80) + // cp := base64Captcha.NewCaptcha(driver, store.UseWithCtx(c)) // v8下使用redis + cp := base64Captcha.NewCaptcha(driver, store) + id, b64s, err := cp.Generate() + if err != nil { + global.GVA_LOG.Error("验证码获取失败!", zap.Error(err)) + response.FailWithMessage("验证码获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysCaptchaResponse{ + CaptchaId: id, + PicPath: b64s, + CaptchaLength: global.GVA_CONFIG.Captcha.KeyLong, + OpenCaptcha: oc, + }, "验证码获取成功", c) +} + +// 类型转换 +func interfaceToInt(v interface{}) (i int) { + switch v := v.(type) { + case int: + i = v + default: + i = 0 + } + return +} diff --git a/api/v1/system/sys_casbin.go b/api/v1/system/sys_casbin.go new file mode 100644 index 0000000..6f684b6 --- /dev/null +++ b/api/v1/system/sys_casbin.go @@ -0,0 +1,68 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system/request" + systemRes "miniapp/model/system/response" + "miniapp/utils" +) + +type CasbinApi struct{} + +// UpdateCasbin +// @Tags Casbin +// @Summary 更新角色api权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.CasbinInReceive true "权限id, 权限模型列表" +// @Success 200 {object} response.Response{msg=string} "更新角色api权限" +// @Router /casbin/UpdateCasbin [post] +func (cas *CasbinApi) UpdateCasbin(c *gin.Context) { + var cmr request.CasbinInReceive + err := c.ShouldBindJSON(&cmr) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(cmr, utils.AuthorityIdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = casbinService.UpdateCasbin(cmr.AuthorityId, cmr.CasbinInfos) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + return + } + response.OkWithMessage("更新成功", c) +} + +// GetPolicyPathByAuthorityId +// @Tags Casbin +// @Summary 获取权限列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.CasbinInReceive true "权限id, 权限模型列表" +// @Success 200 {object} response.Response{data=systemRes.PolicyPathResponse,msg=string} "获取权限列表,返回包括casbin详情列表" +// @Router /casbin/getPolicyPathByAuthorityId [post] +func (cas *CasbinApi) GetPolicyPathByAuthorityId(c *gin.Context) { + var casbin request.CasbinInReceive + err := c.ShouldBindJSON(&casbin) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(casbin, utils.AuthorityIdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + paths := casbinService.GetPolicyPathByAuthorityId(casbin.AuthorityId) + response.OkWithDetailed(systemRes.PolicyPathResponse{Paths: paths}, "获取成功", c) +} diff --git a/api/v1/system/sys_chatgpt.go b/api/v1/system/sys_chatgpt.go new file mode 100644 index 0000000..8621343 --- /dev/null +++ b/api/v1/system/sys_chatgpt.go @@ -0,0 +1,71 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + sysModel "miniapp/model/system" + "miniapp/model/system/request" +) + +type ChatGptApi struct{} + +func (chat *ChatGptApi) CreateSK(c *gin.Context) { + var option sysModel.SysChatGptOption + c.ShouldBindJSON(&option) + err := chatGptService.CreateSK(option) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败"+err.Error(), c) + return + } + response.OkWithMessage("创建成功", c) +} + +func (chat *ChatGptApi) GetSK(c *gin.Context) { + var option sysModel.SysChatGptOption + c.ShouldBindJSON(&option) + _, err := chatGptService.GetSK() + if err != nil { + response.OkWithDetailed(gin.H{ + "ok": false, + }, "无sk或获取失败", c) + return + } + response.OkWithDetailed(gin.H{ + "ok": true, + }, "获取成功", c) +} + +func (chat *ChatGptApi) DeleteSK(c *gin.Context) { + err := chatGptService.DeleteSK() + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败"+err.Error(), c) + return + } + response.OkWithMessage("删除成功", c) +} + +func (chat *ChatGptApi) GetTable(c *gin.Context) { + var req request.ChatGptRequest + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + sql, results, err := chatGptService.GetTable(req) + if err != nil { + global.GVA_LOG.Error("查询失败!", zap.Error(err)) + response.FailWithDetailed(gin.H{ + "sql": sql, + "results": results, + }, "生成失败"+err.Error(), c) + return + } + response.OkWithDetailed(gin.H{ + "sql": sql, + "results": results, + }, "ChatGpt生成完成", c) +} diff --git a/api/v1/system/sys_dictionary.go b/api/v1/system/sys_dictionary.go new file mode 100644 index 0000000..48115a9 --- /dev/null +++ b/api/v1/system/sys_dictionary.go @@ -0,0 +1,148 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" + "miniapp/model/system/request" + "miniapp/utils" +) + +type DictionaryApi struct{} + +// CreateSysDictionary +// @Tags SysDictionary +// @Summary 创建SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionary true "SysDictionary模型" +// @Success 200 {object} response.Response{msg=string} "创建SysDictionary" +// @Router /sysDictionary/createSysDictionary [post] +func (s *DictionaryApi) CreateSysDictionary(c *gin.Context) { + var dictionary system.SysDictionary + err := c.ShouldBindJSON(&dictionary) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryService.CreateSysDictionary(dictionary) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + return + } + response.OkWithMessage("创建成功", c) +} + +// DeleteSysDictionary +// @Tags SysDictionary +// @Summary 删除SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionary true "SysDictionary模型" +// @Success 200 {object} response.Response{msg=string} "删除SysDictionary" +// @Router /sysDictionary/deleteSysDictionary [delete] +func (s *DictionaryApi) DeleteSysDictionary(c *gin.Context) { + var dictionary system.SysDictionary + err := c.ShouldBindJSON(&dictionary) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryService.DeleteSysDictionary(dictionary) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// UpdateSysDictionary +// @Tags SysDictionary +// @Summary 更新SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionary true "SysDictionary模型" +// @Success 200 {object} response.Response{msg=string} "更新SysDictionary" +// @Router /sysDictionary/updateSysDictionary [put] +func (s *DictionaryApi) UpdateSysDictionary(c *gin.Context) { + var dictionary system.SysDictionary + err := c.ShouldBindJSON(&dictionary) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryService.UpdateSysDictionary(&dictionary) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + return + } + response.OkWithMessage("更新成功", c) +} + +// FindSysDictionary +// @Tags SysDictionary +// @Summary 用id查询SysDictionary +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query system.SysDictionary true "ID或字典英名" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysDictionary" +// @Router /sysDictionary/findSysDictionary [get] +func (s *DictionaryApi) FindSysDictionary(c *gin.Context) { + var dictionary system.SysDictionary + err := c.ShouldBindQuery(&dictionary) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + sysDictionary, err := dictionaryService.GetSysDictionary(dictionary.Type, dictionary.ID, dictionary.Status) + if err != nil { + global.GVA_LOG.Error("字典未创建或未开启!", zap.Error(err)) + response.FailWithMessage("字典未创建或未开启", c) + return + } + response.OkWithDetailed(gin.H{"resysDictionary": sysDictionary}, "查询成功", c) +} + +// GetSysDictionaryList +// @Tags SysDictionary +// @Summary 分页获取SysDictionary列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.SysDictionarySearch true "页码, 每页大小, 搜索条件" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量" +// @Router /sysDictionary/getSysDictionaryList [get] +func (s *DictionaryApi) GetSysDictionaryList(c *gin.Context) { + var pageInfo request.SysDictionarySearch + err := c.ShouldBindQuery(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo.PageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := dictionaryService.GetSysDictionaryInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/sys_dictionary_detail.go b/api/v1/system/sys_dictionary_detail.go new file mode 100644 index 0000000..9b8dfbc --- /dev/null +++ b/api/v1/system/sys_dictionary_detail.go @@ -0,0 +1,148 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" + "miniapp/model/system/request" + "miniapp/utils" +) + +type DictionaryDetailApi struct{} + +// CreateSysDictionaryDetail +// @Tags SysDictionaryDetail +// @Summary 创建SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型" +// @Success 200 {object} response.Response{msg=string} "创建SysDictionaryDetail" +// @Router /sysDictionaryDetail/createSysDictionaryDetail [post] +func (s *DictionaryDetailApi) CreateSysDictionaryDetail(c *gin.Context) { + var detail system.SysDictionaryDetail + err := c.ShouldBindJSON(&detail) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryDetailService.CreateSysDictionaryDetail(detail) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + return + } + response.OkWithMessage("创建成功", c) +} + +// DeleteSysDictionaryDetail +// @Tags SysDictionaryDetail +// @Summary 删除SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionaryDetail true "SysDictionaryDetail模型" +// @Success 200 {object} response.Response{msg=string} "删除SysDictionaryDetail" +// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete] +func (s *DictionaryDetailApi) DeleteSysDictionaryDetail(c *gin.Context) { + var detail system.SysDictionaryDetail + err := c.ShouldBindJSON(&detail) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryDetailService.DeleteSysDictionaryDetail(detail) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// UpdateSysDictionaryDetail +// @Tags SysDictionaryDetail +// @Summary 更新SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysDictionaryDetail true "更新SysDictionaryDetail" +// @Success 200 {object} response.Response{msg=string} "更新SysDictionaryDetail" +// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put] +func (s *DictionaryDetailApi) UpdateSysDictionaryDetail(c *gin.Context) { + var detail system.SysDictionaryDetail + err := c.ShouldBindJSON(&detail) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = dictionaryDetailService.UpdateSysDictionaryDetail(&detail) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + return + } + response.OkWithMessage("更新成功", c) +} + +// FindSysDictionaryDetail +// @Tags SysDictionaryDetail +// @Summary 用id查询SysDictionaryDetail +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query system.SysDictionaryDetail true "用id查询SysDictionaryDetail" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysDictionaryDetail" +// @Router /sysDictionaryDetail/findSysDictionaryDetail [get] +func (s *DictionaryDetailApi) FindSysDictionaryDetail(c *gin.Context) { + var detail system.SysDictionaryDetail + err := c.ShouldBindQuery(&detail) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(detail, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + reSysDictionaryDetail, err := dictionaryDetailService.GetSysDictionaryDetail(detail.ID) + if err != nil { + global.GVA_LOG.Error("查询失败!", zap.Error(err)) + response.FailWithMessage("查询失败", c) + return + } + response.OkWithDetailed(gin.H{"reSysDictionaryDetail": reSysDictionaryDetail}, "查询成功", c) +} + +// GetSysDictionaryDetailList +// @Tags SysDictionaryDetail +// @Summary 分页获取SysDictionaryDetail列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.SysDictionaryDetailSearch true "页码, 每页大小, 搜索条件" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysDictionaryDetail列表,返回包括列表,总数,页码,每页数量" +// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get] +func (s *DictionaryDetailApi) GetSysDictionaryDetailList(c *gin.Context) { + var pageInfo request.SysDictionaryDetailSearch + err := c.ShouldBindQuery(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := dictionaryDetailService.GetSysDictionaryDetailInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/sys_initdb.go b/api/v1/system/sys_initdb.go new file mode 100644 index 0000000..9b205c9 --- /dev/null +++ b/api/v1/system/sys_initdb.go @@ -0,0 +1,59 @@ +package system + +import ( + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system/request" + + "github.com/gin-gonic/gin" +) + +type DBApi struct{} + +// InitDB +// @Tags InitDB +// @Summary 初始化用户数据库 +// @Produce application/json +// @Param data body request.InitDB true "初始化数据库参数" +// @Success 200 {object} response.Response{data=string} "初始化用户数据库" +// @Router /init/initdb [post] +func (i *DBApi) InitDB(c *gin.Context) { + if global.GVA_DB != nil { + global.GVA_LOG.Error("已存在数据库配置!") + response.FailWithMessage("已存在数据库配置", c) + return + } + var dbInfo request.InitDB + if err := c.ShouldBindJSON(&dbInfo); err != nil { + global.GVA_LOG.Error("参数校验不通过!", zap.Error(err)) + response.FailWithMessage("参数校验不通过", c) + return + } + if err := initDBService.InitDB(dbInfo); err != nil { + global.GVA_LOG.Error("自动创建数据库失败!", zap.Error(err)) + response.FailWithMessage("自动创建数据库失败,请查看后台日志,检查后在进行初始化", c) + return + } + response.OkWithMessage("自动创建数据库成功", c) +} + +// CheckDB +// @Tags CheckDB +// @Summary 初始化用户数据库 +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "初始化用户数据库" +// @Router /init/checkdb [post] +func (i *DBApi) CheckDB(c *gin.Context) { + var ( + message = "前往初始化数据库" + needInit = true + ) + + if global.GVA_DB != nil { + message = "数据库无需初始化" + needInit = false + } + global.GVA_LOG.Info(message) + response.OkWithDetailed(gin.H{"needInit": needInit}, message, c) +} diff --git a/api/v1/system/sys_jwt_blacklist.go b/api/v1/system/sys_jwt_blacklist.go new file mode 100644 index 0000000..eae5889 --- /dev/null +++ b/api/v1/system/sys_jwt_blacklist.go @@ -0,0 +1,31 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" +) + +type JwtApi struct{} + +// JsonInBlacklist +// @Tags Jwt +// @Summary jwt加入黑名单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{msg=string} "jwt加入黑名单" +// @Router /jwt/jsonInBlacklist [post] +func (j *JwtApi) JsonInBlacklist(c *gin.Context) { + token := c.Request.Header.Get("x-token") + jwt := system.JwtBlacklist{Jwt: token} + err := jwtService.JsonInBlacklist(jwt) + if err != nil { + global.GVA_LOG.Error("jwt作废失败!", zap.Error(err)) + response.FailWithMessage("jwt作废失败", c) + return + } + response.OkWithMessage("jwt作废成功", c) +} diff --git a/api/v1/system/sys_menu.go b/api/v1/system/sys_menu.go new file mode 100644 index 0000000..6ddbdd4 --- /dev/null +++ b/api/v1/system/sys_menu.go @@ -0,0 +1,278 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/system" + systemReq "miniapp/model/system/request" + systemRes "miniapp/model/system/response" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type AuthorityMenuApi struct{} + +// GetMenu +// @Tags AuthorityMenu +// @Summary 获取用户动态路由 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body request.Empty true "空" +// @Success 200 {object} response.Response{data=systemRes.SysMenusResponse,msg=string} "获取用户动态路由,返回包括系统菜单详情列表" +// @Router /menu/getMenu [post] +func (a *AuthorityMenuApi) GetMenu(c *gin.Context) { + menus, err := menuService.GetMenuTree(utils.GetUserAuthorityId(c)) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + if menus == nil { + menus = []system.SysMenu{} + } + response.OkWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取成功", c) +} + +// GetBaseMenuTree +// @Tags AuthorityMenu +// @Summary 获取用户动态路由 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body request.Empty true "空" +// @Success 200 {object} response.Response{data=systemRes.SysBaseMenusResponse,msg=string} "获取用户动态路由,返回包括系统菜单列表" +// @Router /menu/getBaseMenuTree [post] +func (a *AuthorityMenuApi) GetBaseMenuTree(c *gin.Context) { + menus, err := menuService.GetBaseMenuTree() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysBaseMenusResponse{Menus: menus}, "获取成功", c) +} + +// AddMenuAuthority +// @Tags AuthorityMenu +// @Summary 增加menu和角色关联关系 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.AddMenuAuthorityInfo true "角色ID" +// @Success 200 {object} response.Response{msg=string} "增加menu和角色关联关系" +// @Router /menu/addMenuAuthority [post] +func (a *AuthorityMenuApi) AddMenuAuthority(c *gin.Context) { + var authorityMenu systemReq.AddMenuAuthorityInfo + err := c.ShouldBindJSON(&authorityMenu) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if err := utils.Verify(authorityMenu, utils.AuthorityIdVerify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if err := menuService.AddMenuAuthority(authorityMenu.Menus, authorityMenu.AuthorityId); err != nil { + global.GVA_LOG.Error("添加失败!", zap.Error(err)) + response.FailWithMessage("添加失败", c) + } else { + response.OkWithMessage("添加成功", c) + } +} + +// GetMenuAuthority +// @Tags AuthorityMenu +// @Summary 获取指定角色menu +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetAuthorityId true "角色ID" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取指定角色menu" +// @Router /menu/getMenuAuthority [post] +func (a *AuthorityMenuApi) GetMenuAuthority(c *gin.Context) { + var param request.GetAuthorityId + err := c.ShouldBindJSON(¶m) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(param, utils.AuthorityIdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + menus, err := menuService.GetMenuAuthority(¶m) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取失败", c) + return + } + response.OkWithDetailed(gin.H{"menus": menus}, "获取成功", c) +} + +// AddBaseMenu +// @Tags Menu +// @Summary 新增菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记" +// @Success 200 {object} response.Response{msg=string} "新增菜单" +// @Router /menu/addBaseMenu [post] +func (a *AuthorityMenuApi) AddBaseMenu(c *gin.Context) { + var menu system.SysBaseMenu + err := c.ShouldBindJSON(&menu) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(menu, utils.MenuVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(menu.Meta, utils.MenuMetaVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = menuService.AddBaseMenu(menu) + if err != nil { + global.GVA_LOG.Error("添加失败!", zap.Error(err)) + response.FailWithMessage("添加失败", c) + return + } + response.OkWithMessage("添加成功", c) +} + +// DeleteBaseMenu +// @Tags Menu +// @Summary 删除菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "菜单id" +// @Success 200 {object} response.Response{msg=string} "删除菜单" +// @Router /menu/deleteBaseMenu [post] +func (a *AuthorityMenuApi) DeleteBaseMenu(c *gin.Context) { + var menu request.GetById + err := c.ShouldBindJSON(&menu) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(menu, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = baseMenuService.DeleteBaseMenu(menu.ID) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// UpdateBaseMenu +// @Tags Menu +// @Summary 更新菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记" +// @Success 200 {object} response.Response{msg=string} "更新菜单" +// @Router /menu/updateBaseMenu [post] +func (a *AuthorityMenuApi) UpdateBaseMenu(c *gin.Context) { + var menu system.SysBaseMenu + err := c.ShouldBindJSON(&menu) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(menu, utils.MenuVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(menu.Meta, utils.MenuMetaVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = baseMenuService.UpdateBaseMenu(menu) + if err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + return + } + response.OkWithMessage("更新成功", c) +} + +// GetBaseMenuById +// @Tags Menu +// @Summary 根据id获取菜单 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "菜单id" +// @Success 200 {object} response.Response{data=systemRes.SysBaseMenuResponse,msg=string} "根据id获取菜单,返回包括系统菜单列表" +// @Router /menu/getBaseMenuById [post] +func (a *AuthorityMenuApi) GetBaseMenuById(c *gin.Context) { + var idInfo request.GetById + err := c.ShouldBindJSON(&idInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(idInfo, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + menu, err := baseMenuService.GetBaseMenuById(idInfo.ID) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysBaseMenuResponse{Menu: menu}, "获取成功", c) +} + +// GetMenuList +// @Tags Menu +// @Summary 分页获取基础menu列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "页码, 每页大小" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取基础menu列表,返回包括列表,总数,页码,每页数量" +// @Router /menu/getMenuList [post] +func (a *AuthorityMenuApi) GetMenuList(c *gin.Context) { + var pageInfo request.PageInfo + err := c.ShouldBindJSON(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + menuList, total, err := menuService.GetInfoList() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: menuList, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/sys_operation_record.go b/api/v1/system/sys_operation_record.go new file mode 100644 index 0000000..ee8ddc0 --- /dev/null +++ b/api/v1/system/sys_operation_record.go @@ -0,0 +1,149 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/system" + systemReq "miniapp/model/system/request" + "miniapp/utils" +) + +type OperationRecordApi struct{} + +// CreateSysOperationRecord +// @Tags SysOperationRecord +// @Summary 创建SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysOperationRecord true "创建SysOperationRecord" +// @Success 200 {object} response.Response{msg=string} "创建SysOperationRecord" +// @Router /sysOperationRecord/createSysOperationRecord [post] +func (s *OperationRecordApi) CreateSysOperationRecord(c *gin.Context) { + var sysOperationRecord system.SysOperationRecord + err := c.ShouldBindJSON(&sysOperationRecord) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = operationRecordService.CreateSysOperationRecord(sysOperationRecord) + if err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + return + } + response.OkWithMessage("创建成功", c) +} + +// DeleteSysOperationRecord +// @Tags SysOperationRecord +// @Summary 删除SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysOperationRecord true "SysOperationRecord模型" +// @Success 200 {object} response.Response{msg=string} "删除SysOperationRecord" +// @Router /sysOperationRecord/deleteSysOperationRecord [delete] +func (s *OperationRecordApi) DeleteSysOperationRecord(c *gin.Context) { + var sysOperationRecord system.SysOperationRecord + err := c.ShouldBindJSON(&sysOperationRecord) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = operationRecordService.DeleteSysOperationRecord(sysOperationRecord) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// DeleteSysOperationRecordByIds +// @Tags SysOperationRecord +// @Summary 批量删除SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除SysOperationRecord" +// @Success 200 {object} response.Response{msg=string} "批量删除SysOperationRecord" +// @Router /sysOperationRecord/deleteSysOperationRecordByIds [delete] +func (s *OperationRecordApi) DeleteSysOperationRecordByIds(c *gin.Context) { + var IDS request.IdsReq + err := c.ShouldBindJSON(&IDS) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = operationRecordService.DeleteSysOperationRecordByIds(IDS) + if err != nil { + global.GVA_LOG.Error("批量删除失败!", zap.Error(err)) + response.FailWithMessage("批量删除失败", c) + return + } + response.OkWithMessage("批量删除成功", c) +} + +// FindSysOperationRecord +// @Tags SysOperationRecord +// @Summary 用id查询SysOperationRecord +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query system.SysOperationRecord true "Id" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "用id查询SysOperationRecord" +// @Router /sysOperationRecord/findSysOperationRecord [get] +func (s *OperationRecordApi) FindSysOperationRecord(c *gin.Context) { + var sysOperationRecord system.SysOperationRecord + err := c.ShouldBindQuery(&sysOperationRecord) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(sysOperationRecord, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + reSysOperationRecord, err := operationRecordService.GetSysOperationRecord(sysOperationRecord.ID) + if err != nil { + global.GVA_LOG.Error("查询失败!", zap.Error(err)) + response.FailWithMessage("查询失败", c) + return + } + response.OkWithDetailed(gin.H{"reSysOperationRecord": reSysOperationRecord}, "查询成功", c) +} + +// GetSysOperationRecordList +// @Tags SysOperationRecord +// @Summary 分页获取SysOperationRecord列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.SysOperationRecordSearch true "页码, 每页大小, 搜索条件" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量" +// @Router /sysOperationRecord/getSysOperationRecordList [get] +func (s *OperationRecordApi) GetSysOperationRecordList(c *gin.Context) { + var pageInfo systemReq.SysOperationRecordSearch + err := c.ShouldBindQuery(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := operationRecordService.GetSysOperationRecordInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} diff --git a/api/v1/system/sys_system.go b/api/v1/system/sys_system.go new file mode 100644 index 0000000..14fd5ab --- /dev/null +++ b/api/v1/system/sys_system.go @@ -0,0 +1,89 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" + systemRes "miniapp/model/system/response" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type SystemApi struct{} + +// GetSystemConfig +// @Tags System +// @Summary 获取配置文件内容 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {object} response.Response{data=systemRes.SysConfigResponse,msg=string} "获取配置文件内容,返回包括系统配置" +// @Router /system/getSystemConfig [post] +func (s *SystemApi) GetSystemConfig(c *gin.Context) { + config, err := systemConfigService.GetSystemConfig() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(systemRes.SysConfigResponse{Config: config}, "获取成功", c) +} + +// SetSystemConfig +// @Tags System +// @Summary 设置配置文件内容 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body system.System true "设置配置文件内容" +// @Success 200 {object} response.Response{data=string} "设置配置文件内容" +// @Router /system/setSystemConfig [post] +func (s *SystemApi) SetSystemConfig(c *gin.Context) { + var sys system.System + err := c.ShouldBindJSON(&sys) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = systemConfigService.SetSystemConfig(sys) + if err != nil { + global.GVA_LOG.Error("设置失败!", zap.Error(err)) + response.FailWithMessage("设置失败", c) + return + } + response.OkWithMessage("设置成功", c) +} + +// ReloadSystem +// @Tags System +// @Summary 重启系统 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {object} response.Response{msg=string} "重启系统" +// @Router /system/reloadSystem [post] +func (s *SystemApi) ReloadSystem(c *gin.Context) { + err := utils.Reload() + if err != nil { + global.GVA_LOG.Error("重启系统失败!", zap.Error(err)) + response.FailWithMessage("重启系统失败", c) + return + } + response.OkWithMessage("重启系统成功", c) +} + +// GetServerInfo +// @Tags System +// @Summary 获取服务器信息 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取服务器信息" +// @Router /system/getServerInfo [post] +func (s *SystemApi) GetServerInfo(c *gin.Context) { + server, err := systemConfigService.GetServerInfo() + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(gin.H{"server.exe.exe": server}, "获取成功", c) +} diff --git a/api/v1/system/sys_user.go b/api/v1/system/sys_user.go new file mode 100644 index 0000000..1c12de4 --- /dev/null +++ b/api/v1/system/sys_user.go @@ -0,0 +1,462 @@ +package system + +import ( + "strconv" + "time" + + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/common/response" + "miniapp/model/system" + systemReq "miniapp/model/system/request" + systemRes "miniapp/model/system/response" + "miniapp/utils" + + "github.com/gin-gonic/gin" + "github.com/redis/go-redis/v9" + "go.uber.org/zap" +) + +// Login +// @Tags Base +// @Summary 用户登录 +// @Produce application/json +// @Param data body systemReq.Login true "用户名, 密码, 验证码" +// @Success 200 {object} response.Response{data=systemRes.LoginResponse,msg=string} "返回包括用户信息,token,过期时间" +// @Router /base/login [post] +func (b *BaseApi) Login(c *gin.Context) { + var l systemReq.Login + err := c.ShouldBindJSON(&l) + key := c.ClientIP() + + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(l, utils.LoginVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + + // 判断验证码是否开启 + openCaptcha := global.GVA_CONFIG.Captcha.OpenCaptcha // 是否开启防爆次数 + openCaptchaTimeOut := global.GVA_CONFIG.Captcha.OpenCaptchaTimeOut // 缓存超时时间 + v, ok := global.BlackCache.Get(key) + if !ok { + global.BlackCache.Set(key, 1, time.Second*time.Duration(openCaptchaTimeOut)) + } + + var oc bool = openCaptcha == 0 || openCaptcha < interfaceToInt(v) + + if !oc || (l.CaptchaId != "" && l.Captcha != "" && store.Verify(l.CaptchaId, l.Captcha, true)) { + u := &system.SysUser{Username: l.Username, Password: l.Password} + user, err := userService.Login(u) + if err != nil { + global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err)) + // 验证码次数+1 + global.BlackCache.Increment(key, 1) + response.FailWithMessage("用户名不存在或者密码错误", c) + return + } + if user.Enable != 1 { + global.GVA_LOG.Error("登陆失败! 用户被禁止登录!") + // 验证码次数+1 + global.BlackCache.Increment(key, 1) + response.FailWithMessage("用户被禁止登录", c) + return + } + b.TokenNext(c, *user) + return + } + // 验证码次数+1 + global.BlackCache.Increment(key, 1) + response.FailWithMessage("验证码错误", c) +} + +// TokenNext 登录以后签发jwt +func (b *BaseApi) TokenNext(c *gin.Context, user system.SysUser) { + j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名 + claims := j.CreateClaims(systemReq.BaseClaims{ + UUID: user.UUID, + ID: user.ID, + NickName: user.NickName, + Username: user.Username, + AuthorityId: user.AuthorityId, + }) + token, err := j.CreateToken(claims) + if err != nil { + global.GVA_LOG.Error("获取token失败!", zap.Error(err)) + response.FailWithMessage("获取token失败", c) + return + } + if !global.GVA_CONFIG.System.UseMultipoint { + response.OkWithDetailed(systemRes.LoginResponse{ + User: user, + Token: token, + ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000, + }, "登录成功", c) + return + } + + if jwtStr, err := jwtService.GetRedisJWT(user.Username); err == redis.Nil { + if err := jwtService.SetRedisJWT(token, user.Username); err != nil { + global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) + response.FailWithMessage("设置登录状态失败", c) + return + } + response.OkWithDetailed(systemRes.LoginResponse{ + User: user, + Token: token, + ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000, + }, "登录成功", c) + } else if err != nil { + global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) + response.FailWithMessage("设置登录状态失败", c) + } else { + var blackJWT system.JwtBlacklist + blackJWT.Jwt = jwtStr + if err := jwtService.JsonInBlacklist(blackJWT); err != nil { + response.FailWithMessage("jwt作废失败", c) + return + } + if err := jwtService.SetRedisJWT(token, user.Username); err != nil { + response.FailWithMessage("设置登录状态失败", c) + return + } + response.OkWithDetailed(systemRes.LoginResponse{ + User: user, + Token: token, + ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000, + }, "登录成功", c) + } +} + +// Register +// @Tags SysUser +// @Summary 用户注册账号 +// @Produce application/json +// @Param data body systemReq.Register true "用户名, 昵称, 密码, 角色ID" +// @Success 200 {object} response.Response{data=systemRes.SysUserResponse,msg=string} "用户注册账号,返回包括用户信息" +// @Router /user/admin_register [post] +func (b *BaseApi) Register(c *gin.Context) { + var r systemReq.Register + err := c.ShouldBindJSON(&r) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(r, utils.RegisterVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + var authorities []system.SysAuthority + for _, v := range r.AuthorityIds { + authorities = append(authorities, system.SysAuthority{ + AuthorityId: v, + }) + } + user := &system.SysUser{Username: r.Username, NickName: r.NickName, Password: r.Password, HeaderImg: r.HeaderImg, AuthorityId: r.AuthorityId, Authorities: authorities, Enable: r.Enable, Phone: r.Phone, Email: r.Email} + userReturn, err := userService.Register(*user) + if err != nil { + global.GVA_LOG.Error("注册失败!", zap.Error(err)) + response.FailWithDetailed(systemRes.SysUserResponse{User: userReturn}, "注册失败", c) + return + } + response.OkWithDetailed(systemRes.SysUserResponse{User: userReturn}, "注册成功", c) +} + +// ChangePassword +// @Tags SysUser +// @Summary 用户修改密码 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body systemReq.ChangePasswordReq true "用户名, 原密码, 新密码" +// @Success 200 {object} response.Response{msg=string} "用户修改密码" +// @Router /user/changePassword [post] +func (b *BaseApi) ChangePassword(c *gin.Context) { + var req systemReq.ChangePasswordReq + err := c.ShouldBindJSON(&req) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(req, utils.ChangePasswordVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + uid := utils.GetUserID(c) + u := &system.SysUser{GVA_MODEL: global.GVA_MODEL{ID: uid}, Password: req.Password} + _, err = userService.ChangePassword(u, req.NewPassword) + if err != nil { + global.GVA_LOG.Error("修改失败!", zap.Error(err)) + response.FailWithMessage("修改失败,原密码与当前账户不符", c) + return + } + response.OkWithMessage("修改成功", c) +} + +// GetUserList +// @Tags SysUser +// @Summary 分页获取用户列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.PageInfo true "页码, 每页大小" +// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "分页获取用户列表,返回包括列表,总数,页码,每页数量" +// @Router /user/getUserList [post] +func (b *BaseApi) GetUserList(c *gin.Context) { + var pageInfo request.PageInfo + err := c.ShouldBindJSON(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(pageInfo, utils.PageInfoVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + list, total, err := userService.GetUserInfoList(pageInfo) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) +} + +// SetUserAuthority +// @Tags SysUser +// @Summary 更改用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.SetUserAuth true "用户UUID, 角色ID" +// @Success 200 {object} response.Response{msg=string} "设置用户权限" +// @Router /user/setUserAuthority [post] +func (b *BaseApi) SetUserAuthority(c *gin.Context) { + var sua systemReq.SetUserAuth + err := c.ShouldBindJSON(&sua) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if UserVerifyErr := utils.Verify(sua, utils.SetUserAuthorityVerify); UserVerifyErr != nil { + response.FailWithMessage(UserVerifyErr.Error(), c) + return + } + userID := utils.GetUserID(c) + err = userService.SetUserAuthority(userID, sua.AuthorityId) + if err != nil { + global.GVA_LOG.Error("修改失败!", zap.Error(err)) + response.FailWithMessage(err.Error(), c) + return + } + claims := utils.GetUserInfo(c) + j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名 + claims.AuthorityId = sua.AuthorityId + if token, err := j.CreateToken(*claims); err != nil { + global.GVA_LOG.Error("修改失败!", zap.Error(err)) + response.FailWithMessage(err.Error(), c) + } else { + c.Header("new-token", token) + c.Header("new-expires-at", strconv.FormatInt(claims.ExpiresAt.Unix(), 10)) + response.OkWithMessage("修改成功", c) + } +} + +// SetUserAuthorities +// @Tags SysUser +// @Summary 设置用户权限 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body systemReq.SetUserAuthorities true "用户UUID, 角色ID" +// @Success 200 {object} response.Response{msg=string} "设置用户权限" +// @Router /user/setUserAuthorities [post] +func (b *BaseApi) SetUserAuthorities(c *gin.Context) { + var sua systemReq.SetUserAuthorities + err := c.ShouldBindJSON(&sua) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = userService.SetUserAuthorities(sua.ID, sua.AuthorityIds) + if err != nil { + global.GVA_LOG.Error("修改失败!", zap.Error(err)) + response.FailWithMessage("修改失败", c) + return + } + response.OkWithMessage("修改成功", c) +} + +// DeleteUser +// @Tags SysUser +// @Summary 删除用户 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.GetById true "用户ID" +// @Success 200 {object} response.Response{msg=string} "删除用户" +// @Router /user/deleteUser [delete] +func (b *BaseApi) DeleteUser(c *gin.Context) { + var reqId request.GetById + err := c.ShouldBindJSON(&reqId) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(reqId, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + jwtId := utils.GetUserID(c) + if jwtId == uint(reqId.ID) { + response.FailWithMessage("删除失败, 自杀失败", c) + return + } + err = userService.DeleteUser(reqId.ID) + if err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + return + } + response.OkWithMessage("删除成功", c) +} + +// SetUserInfo +// @Tags SysUser +// @Summary 设置用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户信息" +// @Router /user/setUserInfo [put] +func (b *BaseApi) SetUserInfo(c *gin.Context) { + var user systemReq.ChangeUserInfo + err := c.ShouldBindJSON(&user) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = utils.Verify(user, utils.IdVerify) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + + if len(user.AuthorityIds) != 0 { + err = userService.SetUserAuthorities(user.ID, user.AuthorityIds) + if err != nil { + global.GVA_LOG.Error("设置失败!", zap.Error(err)) + response.FailWithMessage("设置失败", c) + return + } + } + err = userService.SetUserInfo(system.SysUser{ + GVA_MODEL: global.GVA_MODEL{ + ID: user.ID, + }, + NickName: user.NickName, + HeaderImg: user.HeaderImg, + Phone: user.Phone, + Email: user.Email, + SideMode: user.SideMode, + Enable: user.Enable, + }) + if err != nil { + global.GVA_LOG.Error("设置失败!", zap.Error(err)) + response.FailWithMessage("设置失败", c) + return + } + response.OkWithMessage("设置成功", c) +} + +// SetSelfInfo +// @Tags SysUser +// @Summary 设置用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接" +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "设置用户信息" +// @Router /user/SetSelfInfo [put] +func (b *BaseApi) SetSelfInfo(c *gin.Context) { + var user systemReq.ChangeUserInfo + err := c.ShouldBindJSON(&user) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + user.ID = utils.GetUserID(c) + err = userService.SetSelfInfo(system.SysUser{ + GVA_MODEL: global.GVA_MODEL{ + ID: user.ID, + }, + NickName: user.NickName, + HeaderImg: user.HeaderImg, + Phone: user.Phone, + Email: user.Email, + SideMode: user.SideMode, + Enable: user.Enable, + }) + if err != nil { + global.GVA_LOG.Error("设置失败!", zap.Error(err)) + response.FailWithMessage("设置失败", c) + return + } + response.OkWithMessage("设置成功", c) +} + +// GetUserInfo +// @Tags SysUser +// @Summary 获取用户信息 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Success 200 {object} response.Response{data=map[string]interface{},msg=string} "获取用户信息" +// @Router /user/getUserInfo [get] +func (b *BaseApi) GetUserInfo(c *gin.Context) { + uuid := utils.GetUserUuid(c) + ReqUser, err := userService.GetUserInfo(uuid) + if err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + return + } + response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "获取成功", c) +} + +// ResetPassword +// @Tags SysUser +// @Summary 重置用户密码 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body system.SysUser true "ID" +// @Success 200 {object} response.Response{msg=string} "重置用户密码" +// @Router /user/resetPassword [post] +func (b *BaseApi) ResetPassword(c *gin.Context) { + var user system.SysUser + err := c.ShouldBindJSON(&user) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = userService.ResetPassword(user.ID) + if err != nil { + global.GVA_LOG.Error("重置失败!", zap.Error(err)) + response.FailWithMessage("重置失败"+err.Error(), c) + return + } + response.OkWithMessage("重置成功", c) +} diff --git a/client/redis.go b/client/redis.go new file mode 100644 index 0000000..b81dfaa --- /dev/null +++ b/client/redis.go @@ -0,0 +1,25 @@ +package client + +import ( + "context" + "git.echol.cn/loser/logger/log" + "github.com/go-redis/redis/v8" + "miniapp/global" +) + +var Redis *redis.Client + +func InitRedisClient() { + // 初始化连接 + conn := redis.NewClient(&redis.Options{ + Addr: global.GVA_CONFIG.Redis.Addr, + Password: global.GVA_CONFIG.Redis.Password, + DB: global.GVA_CONFIG.Redis.DB, + }) + if err := conn.Ping(context.Background()).Err(); err != nil { + log.Panicf("Redis连接初始化失败: %v", err) + } else { + log.Debug("Redis连接初始化成功") + } + Redis = conn +} diff --git a/config.docker.yaml b/config.docker.yaml new file mode 100644 index 0000000..c24676c --- /dev/null +++ b/config.docker.yaml @@ -0,0 +1,203 @@ +# miniapp Global Configuration + +# jwt configuration +jwt: + signing-key: qmPlus + expires-time: 7d + buffer-time: 1d + issuer: qmPlus +# zap logger configuration +zap: + level: info + format: console + prefix: "[miniapp]" + director: log + show-line: true + encode-level: LowercaseColorLevelEncoder + stacktrace-key: stacktrace + log-in-console: true + +# redis configuration +redis: + db: 0 + addr: 177.7.0.14:6379 + password: "" + +# email configuration +email: + to: xxx@qq.com + port: 465 + from: xxx@163.com + host: smtp.163.com + is-ssl: true + secret: xxx + nickname: test + +# system configuration +system: + env: public # Change to "develop" to skip authentication for development mode + addr: 8888 + db-type: mysql + oss-type: local # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server.exe.exe/utils/upload/upload.go 中 NewOss函数配置 + use-redis: false # 使用redis + use-multipoint: false + # IP限制次数 一个小时15000次 + iplimit-count: 15000 + # IP限制一个小时 + iplimit-time: 3600 + +# captcha configuration +captcha: + key-long: 6 + img-width: 240 + img-height: 80 + open-captcha: 0 # 0代表一直开启,大于0代表限制次数 + open-captcha-timeout: 3600 # open-captcha大于0时才生效 + +# mysql connect configuration +# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master) +mysql: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false + +# pgsql connect configuration +# 未初始化之前请勿手动修改数据库信息!!!如果一定要手动初始化请看(https://gin-vue-admin.com/docs/first_master) +pgsql: + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false + +db-list: + - disable: true # 是否禁用 + type: "" # 数据库的类型,目前支持mysql、pgsql + alias-name: "" # 数据库的名称,注意: alias-name 需要在db-list中唯一 + path: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + max-idle-conns: 10 + max-open-conns: 100 + log-mode: "" + log-zap: false + + +# local configuration +local: + path: uploads/file + store-path: uploads/file + +# autocode configuration +autocode: + transfer-restart: true + # root 自动适配项目根目录 + # 请不要手动配置,他会在项目加载的时候识别出根路径 + root: "" + server: /server.exe.exe + server-plug: /plugin/%s + server-api: /api/v1/%s + server-initialize: /initialize + server-model: /model/%s + server-request: /model/%s/request/ + server-router: /router/%s + server-service: /service/%s + web: /web/src + web-api: /api + web-form: /view + web-table: /view + +# qiniu configuration (请自行七牛申请对应的 公钥 私钥 bucket 和 域名地址) +qiniu: + zone: ZoneHuaDong + bucket: "" + img-path: "" + use-https: false + access-key: "" + secret-key: "" + use-cdn-domains: false + +# aliyun oss configuration +aliyun-oss: + endpoint: yourEndpoint + access-key-id: yourAccessKeyId + access-key-secret: yourAccessKeySecret + bucket-name: yourBucketName + bucket-url: yourBucketUrl + base-path: yourBasePath + +# tencent cos configuration +tencent-cos: + bucket: xxxxx-10005608 + region: ap-shanghai + secret-id: your-secret-id + secret-key: your-secret-key + base-url: https://gin.vue.admin + path-prefix: miniapp + +# aws s3 configuration (minio compatible) +aws-s3: + bucket: xxxxx-10005608 + region: ap-shanghai + endpoint: "" + s3-force-path-style: false + disable-ssl: false + secret-id: your-secret-id + secret-key: your-secret-key + base-url: https://gin.vue.admin + path-prefix: miniapp + +# huawei obs configuration +hua-wei-obs: + path: you-path + bucket: you-bucket + endpoint: you-endpoint + access-key: you-access-key + secret-key: you-secret-key + +# excel configuration +excel: + dir: ./resource/excel/ + +# timer task db clear table +Timer: + start: true + spec: "@daily" # 定时任务详细配置参考 https://pkg.go.dev/github.com/robfig/cron/v3 + detail: + - tableName: sys_operation_records + compareField: created_at + interval: 2160h + - tableName: jwt_blacklists + compareField: created_at + interval: 168h + +# 跨域配置 +# 需要配合 server.exe.exe/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用 +cors: + mode: whitelist # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 + whitelist: + - allow-origin: example1.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 + - allow-origin: example2.com + allow-headers: content-type + allow-methods: GET, POST + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true # 布尔值 \ No newline at end of file diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..08eed26 --- /dev/null +++ b/config.yaml @@ -0,0 +1,128 @@ +aliyun-oss: + endpoint: oss-cn-chengdu.aliyuncs.com + access-key-id: LTAI5tFHes6HBWJFUjuPwHso + access-key-secret: qXuWtEJvYEQvj9yhkmLYfRxHShheYa + bucket-name: jmyl-app + bucket-url: https://jmyl-app.oss-cn-chengdu.aliyuncs.com + base-path: miniapp +autocode: + server-model: /model/%s + server-router: /router/%s + server: /server.exe.exe + server-api: /api/v1/%s + server-plug: /plugin/%s + server-initialize: /initialize + root: C:\Users\Administrator\Desktop + web-table: /view + web: /web/src + server-service: /service/%s + server-request: /model/%s/request/ + web-api: /api + web-form: /view + transfer-restart: true +captcha: + key-long: 4 + img-width: 240 + img-height: 80 + open-captcha: 0 + open-captcha-timeout: 3600 +cors: + mode: strict-whitelist + whitelist: + - allow-origin: example1.com + allow-methods: POST, GET + allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true + - allow-origin: example2.com + allow-methods: GET, POST + allow-headers: content-type + expose-headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type + allow-credentials: true +db-list: + - type: "" + alias-name: "" + prefix: "" + port: "" + config: "" + db-name: "" + username: "" + password: "" + path: "" + engine: "" + log-mode: "" + max-idle-conns: 10 + max-open-conns: 100 + singular: false + log-zap: false + disable: true +email: + to: xxx@qq.com + from: xxx@163.com + host: smtp.163.com + secret: xxx + nickname: test + port: 465 + is-ssl: true +excel: + dir: ./resource/excel/ +jwt: + signing-key: f2b1b2af-c8f1-43cf-88e4-40b0a64b5487 + expires-time: 7d + buffer-time: 1d + issuer: qmPlus +local: + path: uploads/file + store-path: uploads/file +mini-app: + app-id: wxaaf66dbb5c3983b3 + app-secret: 0abba24dbff43febba1e551651f693b4 +mysql: + prefix: "" + port: "3307" + config: charset=utf8mb4&parseTime=True&loc=Local + db-name: jm_wechat2 + username: root + password: loser7659 + path: 192.168.123.120 + engine: "" + log-mode: error + max-idle-conns: 10 + max-open-conns: 100 + singular: false + log-zap: false +redis: + addr: 192.168.123.120:6378 + password: "" + db: 0 +system: + env: public + db-type: mysql + oss-type: aliyun-oss + router-prefix: "" + addr: 8888 + iplimit-count: 15000 + iplimit-time: 3600 + use-multipoint: false + use-redis: true +timer: + spec: '@daily' + detail: + - tableName: sys_operation_records + compareField: created_at + interval: 2160h + - tableName: jwt_blacklists + compareField: created_at + interval: 168h + start: true + with_seconds: false +zap: + level: info + prefix: '[miniapp]' + format: console + director: log + encode-level: LowercaseColorLevelEncoder + stacktrace-key: stacktrace + max-age: 0 + show-line: true + log-in-console: true diff --git a/config/auto_code.go b/config/auto_code.go new file mode 100644 index 0000000..ffad28f --- /dev/null +++ b/config/auto_code.go @@ -0,0 +1,18 @@ +package config + +type Autocode struct { + SModel string `mapstructure:"server.exe.exe-model" json:"server.exe.exe-model" yaml:"server.exe.exe-model"` + SRouter string `mapstructure:"server.exe.exe-router" json:"server.exe.exe-router" yaml:"server.exe.exe-router"` + Server string `mapstructure:"server.exe.exe" json:"server.exe.exe" yaml:"server.exe.exe"` + SApi string `mapstructure:"server.exe.exe-api" json:"server.exe.exe-api" yaml:"server.exe.exe-api"` + SPlug string `mapstructure:"server.exe.exe-plug" json:"server.exe.exe-plug" yaml:"server.exe.exe-plug"` + SInitialize string `mapstructure:"server.exe.exe-initialize" json:"server.exe.exe-initialize" yaml:"server.exe.exe-initialize"` + Root string `mapstructure:"root" json:"root" yaml:"root"` + WTable string `mapstructure:"web-table" json:"web-table" yaml:"web-table"` + Web string `mapstructure:"web" json:"web" yaml:"web"` + SService string `mapstructure:"server.exe.exe-service" json:"server.exe.exe-service" yaml:"server.exe.exe-service"` + SRequest string `mapstructure:"server.exe.exe-request" json:"server.exe.exe-request" yaml:"server.exe.exe-request"` + WApi string `mapstructure:"web-api" json:"web-api" yaml:"web-api"` + WForm string `mapstructure:"web-form" json:"web-form" yaml:"web-form"` + TransferRestart bool `mapstructure:"transfer-restart" json:"transfer-restart" yaml:"transfer-restart"` +} diff --git a/config/captcha.go b/config/captcha.go new file mode 100644 index 0000000..074a9bf --- /dev/null +++ b/config/captcha.go @@ -0,0 +1,9 @@ +package config + +type Captcha struct { + KeyLong int `mapstructure:"key-long" json:"key-long" yaml:"key-long"` // 验证码长度 + ImgWidth int `mapstructure:"img-width" json:"img-width" yaml:"img-width"` // 验证码宽度 + ImgHeight int `mapstructure:"img-height" json:"img-height" yaml:"img-height"` // 验证码高度 + OpenCaptcha int `mapstructure:"open-captcha" json:"open-captcha" yaml:"open-captcha"` // 防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码 + OpenCaptchaTimeOut int `mapstructure:"open-captcha-timeout" json:"open-captcha-timeout" yaml:"open-captcha-timeout"` // 防爆破验证码超时时间,单位:s(秒) +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..ff396d9 --- /dev/null +++ b/config/config.go @@ -0,0 +1,34 @@ +package config + +type Server struct { + JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"` + Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"` + Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"` + Email Email `mapstructure:"email" json:"email" yaml:"email"` + System System `mapstructure:"system" json:"system" yaml:"system"` + Captcha Captcha `mapstructure:"captcha" json:"captcha" yaml:"captcha"` + // auto + AutoCode Autocode `mapstructure:"autocode" json:"autocode" yaml:"autocode"` + // gorm + Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"` + Mssql Mssql `mapstructure:"mssql" json:"mssql" yaml:"mssql"` + Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"` + Oracle Oracle `mapstructure:"oracle" json:"oracle" yaml:"oracle"` + Sqlite Sqlite `mapstructure:"sqlite" json:"sqlite" yaml:"sqlite"` + DBList []SpecializedDB `mapstructure:"db-list" json:"db-list" yaml:"db-list"` + // oss + Local Local `mapstructure:"local" json:"local" yaml:"local"` + Qiniu Qiniu `mapstructure:"qiniu" json:"qiniu" yaml:"qiniu"` + AliyunOSS AliyunOSS `mapstructure:"aliyun-oss" json:"aliyun-oss" yaml:"aliyun-oss"` + HuaWeiObs HuaWeiObs `mapstructure:"hua-wei-obs" json:"hua-wei-obs" yaml:"hua-wei-obs"` + TencentCOS TencentCOS `mapstructure:"tencent-cos" json:"tencent-cos" yaml:"tencent-cos"` + AwsS3 AwsS3 `mapstructure:"aws-s3" json:"aws-s3" yaml:"aws-s3"` + + Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"` + Timer Timer `mapstructure:"timer" json:"timer" yaml:"timer"` + + // 跨域配置 + Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"` + + MiniApp MiniApp `mapstructure:"mini-app" json:"mini-app" yaml:"mini-app"` +} diff --git a/config/cors.go b/config/cors.go new file mode 100644 index 0000000..7fba993 --- /dev/null +++ b/config/cors.go @@ -0,0 +1,14 @@ +package config + +type CORS struct { + Mode string `mapstructure:"mode" json:"mode" yaml:"mode"` + Whitelist []CORSWhitelist `mapstructure:"whitelist" json:"whitelist" yaml:"whitelist"` +} + +type CORSWhitelist struct { + AllowOrigin string `mapstructure:"allow-origin" json:"allow-origin" yaml:"allow-origin"` + AllowMethods string `mapstructure:"allow-methods" json:"allow-methods" yaml:"allow-methods"` + AllowHeaders string `mapstructure:"allow-headers" json:"allow-headers" yaml:"allow-headers"` + ExposeHeaders string `mapstructure:"expose-headers" json:"expose-headers" yaml:"expose-headers"` + AllowCredentials bool `mapstructure:"allow-credentials" json:"allow-credentials" yaml:"allow-credentials"` +} diff --git a/config/db_list.go b/config/db_list.go new file mode 100644 index 0000000..17eaac9 --- /dev/null +++ b/config/db_list.go @@ -0,0 +1,32 @@ +package config + +type DsnProvider interface { + Dsn() string +} + +// Embeded 结构体可以压平到上一层,从而保持 config 文件的结构和原来一样 +// 见 playground: https://go.dev/play/p/KIcuhqEoxmY + +// GeneralDB 也被 Pgsql 和 Mysql 原样使用 +type GeneralDB struct { + Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` + Port string `mapstructure:"port" json:"port" yaml:"port"` + Config string `mapstructure:"config" json:"config" yaml:"config"` // 高级配置 + Dbname string `mapstructure:"db-name" json:"db-name" yaml:"db-name"` // 数据库名 + Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库密码 + Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码 + Path string `mapstructure:"path" json:"path" yaml:"path"` + Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` //数据库引擎,默认InnoDB + LogMode string `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"` // 是否开启Gorm全局日志 + MaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"` // 空闲中的最大连接数 + MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"` // 打开到数据库的最大连接数 + Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` //是否开启全局禁用复数,true表示开启 + LogZap bool `mapstructure:"log-zap" json:"log-zap" yaml:"log-zap"` // 是否通过zap写入日志文件 +} + +type SpecializedDB struct { + Type string `mapstructure:"type" json:"type" yaml:"type"` + AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"` + GeneralDB `yaml:",inline" mapstructure:",squash"` + Disable bool `mapstructure:"disable" json:"disable" yaml:"disable"` +} diff --git a/config/email.go b/config/email.go new file mode 100644 index 0000000..0984616 --- /dev/null +++ b/config/email.go @@ -0,0 +1,11 @@ +package config + +type Email struct { + To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用 + From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱 + Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议 + Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥 + Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱 + Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465 + IsSSL bool `mapstructure:"is-ssl" json:"is-ssl" yaml:"is-ssl"` // 是否SSL 是否开启SSL +} diff --git a/config/excel.go b/config/excel.go new file mode 100644 index 0000000..13caab7 --- /dev/null +++ b/config/excel.go @@ -0,0 +1,5 @@ +package config + +type Excel struct { + Dir string `mapstructure:"dir" json:"dir" yaml:"dir"` +} diff --git a/config/gorm_mssql.go b/config/gorm_mssql.go new file mode 100644 index 0000000..8278576 --- /dev/null +++ b/config/gorm_mssql.go @@ -0,0 +1,14 @@ +package config + +type Mssql struct { + GeneralDB `yaml:",inline" mapstructure:",squash"` +} + +// dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" +func (m *Mssql) Dsn() string { + return "sqlserver://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "?database=" + m.Dbname + "&encrypt=disable" +} + +func (m *Mssql) GetLogMode() string { + return m.LogMode +} diff --git a/config/gorm_mysql.go b/config/gorm_mysql.go new file mode 100644 index 0000000..86911f3 --- /dev/null +++ b/config/gorm_mysql.go @@ -0,0 +1,13 @@ +package config + +type Mysql struct { + GeneralDB `yaml:",inline" mapstructure:",squash"` +} + +func (m *Mysql) Dsn() string { + return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config +} + +func (m *Mysql) GetLogMode() string { + return m.LogMode +} diff --git a/config/gorm_oracle.go b/config/gorm_oracle.go new file mode 100644 index 0000000..44f9051 --- /dev/null +++ b/config/gorm_oracle.go @@ -0,0 +1,14 @@ +package config + +type Oracle struct { + GeneralDB `yaml:",inline" mapstructure:",squash"` +} + +func (m *Oracle) Dsn() string { + return "oracle://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "/" + m.Dbname + "?" + m.Config + +} + +func (m *Oracle) GetLogMode() string { + return m.LogMode +} diff --git a/config/gorm_pgsql.go b/config/gorm_pgsql.go new file mode 100644 index 0000000..17c5f5e --- /dev/null +++ b/config/gorm_pgsql.go @@ -0,0 +1,21 @@ +package config + +type Pgsql struct { + GeneralDB `yaml:",inline" mapstructure:",squash"` +} + +// Dsn 基于配置文件获取 dsn +// Author [SliverHorn](https://github.com/SliverHorn) +func (p *Pgsql) Dsn() string { + return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + p.Dbname + " port=" + p.Port + " " + p.Config +} + +// LinkDsn 根据 dbname 生成 dsn +// Author [SliverHorn](https://github.com/SliverHorn) +func (p *Pgsql) LinkDsn(dbname string) string { + return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + dbname + " port=" + p.Port + " " + p.Config +} + +func (m *Pgsql) GetLogMode() string { + return m.LogMode +} diff --git a/config/gorm_sqlite.go b/config/gorm_sqlite.go new file mode 100644 index 0000000..5eebcae --- /dev/null +++ b/config/gorm_sqlite.go @@ -0,0 +1,17 @@ +package config + +import ( + "path/filepath" +) + +type Sqlite struct { + GeneralDB `yaml:",inline" mapstructure:",squash"` +} + +func (s *Sqlite) Dsn() string { + return filepath.Join(s.Path, s.Dbname+".db") +} + +func (s *Sqlite) GetLogMode() string { + return s.LogMode +} diff --git a/config/jwt.go b/config/jwt.go new file mode 100644 index 0000000..c95d30d --- /dev/null +++ b/config/jwt.go @@ -0,0 +1,8 @@ +package config + +type JWT struct { + SigningKey string `mapstructure:"signing-key" json:"signing-key" yaml:"signing-key"` // jwt签名 + ExpiresTime string `mapstructure:"expires-time" json:"expires-time" yaml:"expires-time"` // 过期时间 + BufferTime string `mapstructure:"buffer-time" json:"buffer-time" yaml:"buffer-time"` // 缓冲时间 + Issuer string `mapstructure:"issuer" json:"issuer" yaml:"issuer"` // 签发者 +} diff --git a/config/oss_aliyun.go b/config/oss_aliyun.go new file mode 100644 index 0000000..934bd78 --- /dev/null +++ b/config/oss_aliyun.go @@ -0,0 +1,10 @@ +package config + +type AliyunOSS struct { + Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"` + AccessKeyId string `mapstructure:"access-key-id" json:"access-key-id" yaml:"access-key-id"` + AccessKeySecret string `mapstructure:"access-key-secret" json:"access-key-secret" yaml:"access-key-secret"` + BucketName string `mapstructure:"bucket-name" json:"bucket-name" yaml:"bucket-name"` + BucketUrl string `mapstructure:"bucket-url" json:"bucket-url" yaml:"bucket-url"` + BasePath string `mapstructure:"base-path" json:"base-path" yaml:"base-path"` +} diff --git a/config/oss_aws.go b/config/oss_aws.go new file mode 100644 index 0000000..7ec6acc --- /dev/null +++ b/config/oss_aws.go @@ -0,0 +1,13 @@ +package config + +type AwsS3 struct { + Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` + Region string `mapstructure:"region" json:"region" yaml:"region"` + Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"` + SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"` + SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` + BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"` + PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"` + S3ForcePathStyle bool `mapstructure:"s3-force-path-style" json:"s3-force-path-style" yaml:"s3-force-path-style"` + DisableSSL bool `mapstructure:"disable-ssl" json:"disable-ssl" yaml:"disable-ssl"` +} diff --git a/config/oss_huawei.go b/config/oss_huawei.go new file mode 100644 index 0000000..45dfbcd --- /dev/null +++ b/config/oss_huawei.go @@ -0,0 +1,9 @@ +package config + +type HuaWeiObs struct { + Path string `mapstructure:"path" json:"path" yaml:"path"` + Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` + Endpoint string `mapstructure:"endpoint" json:"endpoint" yaml:"endpoint"` + AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"` + SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` +} diff --git a/config/oss_local.go b/config/oss_local.go new file mode 100644 index 0000000..7038d4a --- /dev/null +++ b/config/oss_local.go @@ -0,0 +1,6 @@ +package config + +type Local struct { + Path string `mapstructure:"path" json:"path" yaml:"path"` // 本地文件访问路径 + StorePath string `mapstructure:"store-path" json:"store-path" yaml:"store-path"` // 本地文件存储路径 +} diff --git a/config/oss_qiniu.go b/config/oss_qiniu.go new file mode 100644 index 0000000..298fe2d --- /dev/null +++ b/config/oss_qiniu.go @@ -0,0 +1,11 @@ +package config + +type Qiniu struct { + Zone string `mapstructure:"zone" json:"zone" yaml:"zone"` // 存储区域 + Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` // 空间名称 + ImgPath string `mapstructure:"img-path" json:"img-path" yaml:"img-path"` // CDN加速域名 + AccessKey string `mapstructure:"access-key" json:"access-key" yaml:"access-key"` // 秘钥AK + SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` // 秘钥SK + UseHTTPS bool `mapstructure:"use-https" json:"use-https" yaml:"use-https"` // 是否使用https + UseCdnDomains bool `mapstructure:"use-cdn-domains" json:"use-cdn-domains" yaml:"use-cdn-domains"` // 上传是否使用CDN上传加速 +} diff --git a/config/oss_tencent.go b/config/oss_tencent.go new file mode 100644 index 0000000..39a29d1 --- /dev/null +++ b/config/oss_tencent.go @@ -0,0 +1,10 @@ +package config + +type TencentCOS struct { + Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` + Region string `mapstructure:"region" json:"region" yaml:"region"` + SecretID string `mapstructure:"secret-id" json:"secret-id" yaml:"secret-id"` + SecretKey string `mapstructure:"secret-key" json:"secret-key" yaml:"secret-key"` + BaseURL string `mapstructure:"base-url" json:"base-url" yaml:"base-url"` + PathPrefix string `mapstructure:"path-prefix" json:"path-prefix" yaml:"path-prefix"` +} diff --git a/config/redis.go b/config/redis.go new file mode 100644 index 0000000..60dbb1e --- /dev/null +++ b/config/redis.go @@ -0,0 +1,7 @@ +package config + +type Redis struct { + Addr string `mapstructure:"addr" json:"addr" yaml:"addr"` // 服务器地址:端口 + Password string `mapstructure:"password" json:"password" yaml:"password"` // 密码 + DB int `mapstructure:"db" json:"db" yaml:"db"` // redis的哪个数据库 +} diff --git a/config/system.go b/config/system.go new file mode 100644 index 0000000..bb1cfce --- /dev/null +++ b/config/system.go @@ -0,0 +1,13 @@ +package config + +type System struct { + Env string `mapstructure:"env" json:"env" yaml:"env"` // 环境值 + DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql + OssType string `mapstructure:"oss-type" json:"oss-type" yaml:"oss-type"` // Oss类型 + RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"` + Addr int `mapstructure:"addr" json:"addr" yaml:"addr"` // 端口值 + LimitCountIP int `mapstructure:"iplimit-count" json:"iplimit-count" yaml:"iplimit-count"` + LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimit-time" yaml:"iplimit-time"` + UseMultipoint bool `mapstructure:"use-multipoint" json:"use-multipoint" yaml:"use-multipoint"` // 多点登录拦截 + UseRedis bool `mapstructure:"use-redis" json:"use-redis" yaml:"use-redis"` // 使用redis +} diff --git a/config/timer.go b/config/timer.go new file mode 100644 index 0000000..5057e50 --- /dev/null +++ b/config/timer.go @@ -0,0 +1,15 @@ +package config + +type Timer struct { + Spec string `mapstructure:"spec" json:"spec" yaml:"spec"` // CRON表达式 + Detail []Detail `mapstructure:"detail" json:"detail" yaml:"detail"` + Start bool `mapstructure:"start" json:"start" yaml:"start"` // 是否启用 + WithSeconds bool `mapstructure:"with_seconds" json:"with_seconds" yaml:"with_seconds"` // 是否精确到秒 + +} + +type Detail struct { + TableName string `mapstructure:"tableName" json:"tableName" yaml:"tableName"` // 需要清理的表名 + CompareField string `mapstructure:"compareField" json:"compareField" yaml:"compareField"` // 需要比较时间的字段 + Interval string `mapstructure:"interval" json:"interval" yaml:"interval"` // 时间间隔 +} diff --git a/config/wechat.go b/config/wechat.go new file mode 100644 index 0000000..a11f242 --- /dev/null +++ b/config/wechat.go @@ -0,0 +1,23 @@ +package config + +type MiniApp struct { + AppId string `mapstructure:"app-id" yaml:"app-id"` + AppSecret string `mapstructure:"app-secret" yaml:"app-secret"` +} + +// 微信小程序配置 + +// 微信支付配置 +type wechatPayConfig struct { + MchId string `mapstructure:"mchId" yaml:"mchId"` // 商户号 + SerialNo string `mapstructure:"serialNo" yaml:"serialNo"` // 商户API证书的证书序列号 + ApiV3Key string `mapstructure:"apiV3Key" yaml:"apiV3Key"` // 支付key + PrivateKey string `mapstructure:"privateKey" yaml:"privateKey"` // 支付私钥绝对路径 +} + +// api密钥配置 +type CapiConfig struct { + AppId string `mapstructure:"app-id" yaml:"app-id"` // APP ID + SecretId string `mapstructure:"secret-id" yaml:"secret-id"` // Secret ID + SecretKey string `mapstructure:"secret-key" yaml:"secret-key"` // Secret Key +} diff --git a/config/zap.go b/config/zap.go new file mode 100644 index 0000000..2872219 --- /dev/null +++ b/config/zap.go @@ -0,0 +1,60 @@ +package config + +import ( + "go.uber.org/zap/zapcore" + "strings" +) + +type Zap struct { + Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别 + Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀 + Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出 + Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹 + EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` // 编码级 + StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` // 栈名 + + MaxAge int `mapstructure:"max-age" json:"max-age" yaml:"max-age"` // 日志留存时间 + ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行 + LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台 +} + +// ZapEncodeLevel 根据 EncodeLevel 返回 zapcore.LevelEncoder +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *Zap) ZapEncodeLevel() zapcore.LevelEncoder { + switch { + case z.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认) + return zapcore.LowercaseLevelEncoder + case z.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色 + return zapcore.LowercaseColorLevelEncoder + case z.EncodeLevel == "CapitalLevelEncoder": // 大写编码器 + return zapcore.CapitalLevelEncoder + case z.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色 + return zapcore.CapitalColorLevelEncoder + default: + return zapcore.LowercaseLevelEncoder + } +} + +// TransportLevel 根据字符串转化为 zapcore.Level +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *Zap) TransportLevel() zapcore.Level { + z.Level = strings.ToLower(z.Level) + switch z.Level { + case "debug": + return zapcore.DebugLevel + case "info": + return zapcore.InfoLevel + case "warn": + return zapcore.WarnLevel + case "error": + return zapcore.WarnLevel + case "dpanic": + return zapcore.DPanicLevel + case "panic": + return zapcore.PanicLevel + case "fatal": + return zapcore.FatalLevel + default: + return zapcore.DebugLevel + } +} diff --git a/core/internal/constant.go b/core/internal/constant.go new file mode 100644 index 0000000..b22362c --- /dev/null +++ b/core/internal/constant.go @@ -0,0 +1,9 @@ +package internal + +const ( + ConfigEnv = "GVA_CONFIG" + ConfigDefaultFile = "config.yaml" + ConfigTestFile = "config.test.yaml" + ConfigDebugFile = "config.debug.yaml" + ConfigReleaseFile = "config.release.yaml" +) diff --git a/core/internal/cutter.go b/core/internal/cutter.go new file mode 100644 index 0000000..721a94b --- /dev/null +++ b/core/internal/cutter.go @@ -0,0 +1,97 @@ +package internal + +import ( + "os" + "path/filepath" + "regexp" + "strings" + "sync" + "time" +) + +type Cutter struct { + level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal) + format string // 时间格式(2006-01-02) + Director string // 日志文件夹 + file *os.File // 文件句柄 + mutex *sync.RWMutex // 读写锁 +} + +type CutterOption func(*Cutter) + +// WithCutterFormat 设置时间格式 +func WithCutterFormat(format string) CutterOption { + return func(c *Cutter) { + c.format = format + } +} + +func NewCutter(director string, level string, options ...CutterOption) *Cutter { + rotate := &Cutter{ + level: level, + Director: director, + mutex: new(sync.RWMutex), + } + for i := 0; i < len(options); i++ { + options[i](rotate) + } + return rotate +} + +// Write satisfies the io.Writer interface. It writes to the +// appropriate file handle that is currently being used. +// If we have reached rotation time, the target file gets +// automatically rotated, and also purged if necessary. +func (c *Cutter) Write(bytes []byte) (n int, err error) { + c.mutex.Lock() + defer func() { + if c.file != nil { + _ = c.file.Close() + c.file = nil + } + c.mutex.Unlock() + }() + var business string + if strings.Contains(string(bytes), "business") { + var compile *regexp.Regexp + compile, err = regexp.Compile(`{"business": "([^,]+)"}`) + if err != nil { + return 0, err + } + if compile.Match(bytes) { + finds := compile.FindSubmatch(bytes) + business = string(finds[len(finds)-1]) + bytes = compile.ReplaceAll(bytes, []byte("")) + } + compile, err = regexp.Compile(`"business": "([^,]+)"`) + if err != nil { + return 0, err + } + if compile.Match(bytes) { + finds := compile.FindSubmatch(bytes) + business = string(finds[len(finds)-1]) + bytes = compile.ReplaceAll(bytes, []byte("")) + } + } + format := time.Now().Format(c.format) + formats := make([]string, 0, 4) + formats = append(formats, c.Director) + if format != "" { + formats = append(formats, format) + } + if business != "" { + formats = append(formats, business) + } + formats = append(formats, c.level+".log") + filename := filepath.Join(formats...) + dirname := filepath.Dir(filename) + err = os.MkdirAll(dirname, 0755) + if err != nil { + return 0, err + } + c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return 0, err + } + return c.file.Write(bytes) +} diff --git a/core/internal/file_rotatelogs.go b/core/internal/file_rotatelogs.go new file mode 100644 index 0000000..7ae7688 --- /dev/null +++ b/core/internal/file_rotatelogs.go @@ -0,0 +1,21 @@ +package internal + +import ( + "go.uber.org/zap/zapcore" + "miniapp/global" + "os" +) + +var FileRotatelogs = new(fileRotatelogs) + +type fileRotatelogs struct{} + +// GetWriteSyncer 获取 zapcore.WriteSyncer +// Author [SliverHorn](https://github.com/SliverHorn) +func (r *fileRotatelogs) GetWriteSyncer(level string) zapcore.WriteSyncer { + fileWriter := NewCutter(global.GVA_CONFIG.Zap.Director, level, WithCutterFormat("2006-01-02")) + if global.GVA_CONFIG.Zap.LogInConsole { + return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter)) + } + return zapcore.AddSync(fileWriter) +} diff --git a/core/internal/zap.go b/core/internal/zap.go new file mode 100644 index 0000000..fcfcb58 --- /dev/null +++ b/core/internal/zap.go @@ -0,0 +1,101 @@ +package internal + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "miniapp/global" + "time" +) + +var Zap = new(_zap) + +type _zap struct{} + +// GetEncoder 获取 zapcore.Encoder +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) GetEncoder() zapcore.Encoder { + if global.GVA_CONFIG.Zap.Format == "json" { + return zapcore.NewJSONEncoder(z.GetEncoderConfig()) + } + return zapcore.NewConsoleEncoder(z.GetEncoderConfig()) +} + +// GetEncoderConfig 获取zapcore.EncoderConfig +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) GetEncoderConfig() zapcore.EncoderConfig { + return zapcore.EncoderConfig{ + MessageKey: "message", + LevelKey: "level", + TimeKey: "time", + NameKey: "logger", + CallerKey: "caller", + StacktraceKey: global.GVA_CONFIG.Zap.StacktraceKey, + LineEnding: zapcore.DefaultLineEnding, + EncodeLevel: global.GVA_CONFIG.Zap.ZapEncodeLevel(), + EncodeTime: z.CustomTimeEncoder, + EncodeDuration: zapcore.SecondsDurationEncoder, + EncodeCaller: zapcore.FullCallerEncoder, + } +} + +// GetEncoderCore 获取Encoder的 zapcore.Core +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) GetEncoderCore(l zapcore.Level, level zap.LevelEnablerFunc) zapcore.Core { + writer := FileRotatelogs.GetWriteSyncer(l.String()) // 日志分割 + return zapcore.NewCore(z.GetEncoder(), writer, level) +} + +// CustomTimeEncoder 自定义日志输出时间格式 +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) CustomTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) { + encoder.AppendString(global.GVA_CONFIG.Zap.Prefix + t.Format("2006/01/02 - 15:04:05.000")) +} + +// GetZapCores 根据配置文件的Level获取 []zapcore.Core +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) GetZapCores() []zapcore.Core { + cores := make([]zapcore.Core, 0, 7) + for level := global.GVA_CONFIG.Zap.TransportLevel(); level <= zapcore.FatalLevel; level++ { + cores = append(cores, z.GetEncoderCore(level, z.GetLevelPriority(level))) + } + return cores +} + +// GetLevelPriority 根据 zapcore.Level 获取 zap.LevelEnablerFunc +// Author [SliverHorn](https://github.com/SliverHorn) +func (z *_zap) GetLevelPriority(level zapcore.Level) zap.LevelEnablerFunc { + switch level { + case zapcore.DebugLevel: + return func(level zapcore.Level) bool { // 调试级别 + return level == zap.DebugLevel + } + case zapcore.InfoLevel: + return func(level zapcore.Level) bool { // 日志级别 + return level == zap.InfoLevel + } + case zapcore.WarnLevel: + return func(level zapcore.Level) bool { // 警告级别 + return level == zap.WarnLevel + } + case zapcore.ErrorLevel: + return func(level zapcore.Level) bool { // 错误级别 + return level == zap.ErrorLevel + } + case zapcore.DPanicLevel: + return func(level zapcore.Level) bool { // dpanic级别 + return level == zap.DPanicLevel + } + case zapcore.PanicLevel: + return func(level zapcore.Level) bool { // panic级别 + return level == zap.PanicLevel + } + case zapcore.FatalLevel: + return func(level zapcore.Level) bool { // 终止级别 + return level == zap.FatalLevel + } + default: + return func(level zapcore.Level) bool { // 调试级别 + return level == zap.DebugLevel + } + } +} diff --git a/core/server.go b/core/server.go new file mode 100644 index 0000000..1d2cc5e --- /dev/null +++ b/core/server.go @@ -0,0 +1,39 @@ +package core + +import ( + "fmt" + "time" + + "go.uber.org/zap" + "miniapp/global" + "miniapp/initialize" + "miniapp/service/system" +) + +type server interface { + ListenAndServe() error +} + +func RunWindowsServer() { + if global.GVA_CONFIG.System.UseMultipoint || global.GVA_CONFIG.System.UseRedis { + // 初始化redis服务 + initialize.Redis() + } + + // 从db加载jwt数据 + if global.GVA_DB != nil { + system.LoadAll() + } + + Router := initialize.Routers() + Router.Static("/form-generator", "./resource/page") + + address := fmt.Sprintf(":%d", global.GVA_CONFIG.System.Addr) + s := initServer(address, Router) + // 保证文本顺序输出 + // In order to ensure that the text order output can be deleted + time.Sleep(10 * time.Microsecond) + global.GVA_LOG.Info("server.exe.exe run success on ", zap.String("address", address)) + + global.GVA_LOG.Error(s.ListenAndServe().Error()) +} diff --git a/core/server_other.go b/core/server_other.go new file mode 100644 index 0000000..b95e901 --- /dev/null +++ b/core/server_other.go @@ -0,0 +1,19 @@ +//go:build !windows +// +build !windows + +package core + +import ( + "time" + + "github.com/fvbock/endless" + "github.com/gin-gonic/gin" +) + +func initServer(address string, router *gin.Engine) server { + s := endless.NewServer(address, router) + s.ReadHeaderTimeout = 20 * time.Second + s.WriteTimeout = 20 * time.Second + s.MaxHeaderBytes = 1 << 20 + return s +} diff --git a/core/server_win.go b/core/server_win.go new file mode 100644 index 0000000..54c4c07 --- /dev/null +++ b/core/server_win.go @@ -0,0 +1,21 @@ +//go:build windows +// +build windows + +package core + +import ( + "net/http" + "time" + + "github.com/gin-gonic/gin" +) + +func initServer(address string, router *gin.Engine) server { + return &http.Server{ + Addr: address, + Handler: router, + ReadTimeout: 20 * time.Second, + WriteTimeout: 20 * time.Second, + MaxHeaderBytes: 1 << 20, + } +} diff --git a/core/viper.go b/core/viper.go new file mode 100644 index 0000000..b2f828b --- /dev/null +++ b/core/viper.go @@ -0,0 +1,74 @@ +package core + +import ( + "flag" + "fmt" + "github.com/gin-gonic/gin" + "miniapp/core/internal" + "os" + "path/filepath" + + "github.com/fsnotify/fsnotify" + "github.com/spf13/viper" + + "miniapp/global" + _ "miniapp/packfile" +) + +// Viper // +// 优先级: 命令行 > 环境变量 > 默认值 +// Author [SliverHorn](https://github.com/SliverHorn) +func Viper(path ...string) *viper.Viper { + var config string + + if len(path) == 0 { + flag.StringVar(&config, "c", "", "choose config file.") + flag.Parse() + if config == "" { // 判断命令行参数是否为空 + if configEnv := os.Getenv(internal.ConfigEnv); configEnv == "" { // 判断 internal.ConfigEnv 常量存储的环境变量是否为空 + switch gin.Mode() { + case gin.DebugMode: + config = internal.ConfigDefaultFile + fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigDefaultFile) + case gin.ReleaseMode: + config = internal.ConfigReleaseFile + fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigReleaseFile) + case gin.TestMode: + config = internal.ConfigTestFile + fmt.Printf("您正在使用gin模式的%s环境名称,config的路径为%s\n", gin.EnvGinMode, internal.ConfigTestFile) + } + } else { // internal.ConfigEnv 常量存储的环境变量不为空 将值赋值于config + config = configEnv + fmt.Printf("您正在使用%s环境变量,config的路径为%s\n", internal.ConfigEnv, config) + } + } else { // 命令行参数不为空 将值赋值于config + fmt.Printf("您正在使用命令行的-c参数传递的值,config的路径为%s\n", config) + } + } else { // 函数传递的可变参数的第一个值赋值于config + config = path[0] + fmt.Printf("您正在使用func Viper()传递的值,config的路径为%s\n", config) + } + + v := viper.New() + v.SetConfigFile(config) + v.SetConfigType("yaml") + err := v.ReadInConfig() + if err != nil { + panic(fmt.Errorf("Fatal error config file: %s \n", err)) + } + v.WatchConfig() + + v.OnConfigChange(func(e fsnotify.Event) { + fmt.Println("config file changed:", e.Name) + if err = v.Unmarshal(&global.GVA_CONFIG); err != nil { + fmt.Println(err) + } + }) + if err = v.Unmarshal(&global.GVA_CONFIG); err != nil { + fmt.Println(err) + } + + // root 适配性 根据root位置去找到对应迁移位置,保证root路径有效 + global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..") + return v +} diff --git a/core/zap.go b/core/zap.go new file mode 100644 index 0000000..277dcf1 --- /dev/null +++ b/core/zap.go @@ -0,0 +1,28 @@ +package core + +import ( + "fmt" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "miniapp/core/internal" + "miniapp/global" + "miniapp/utils" + "os" +) + +// Zap 获取 zap.Logger +// Author [SliverHorn](https://github.com/SliverHorn) +func Zap() (logger *zap.Logger) { + if ok, _ := utils.PathExists(global.GVA_CONFIG.Zap.Director); !ok { // 判断是否有Director文件夹 + fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director) + _ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm) + } + + cores := internal.Zap.GetZapCores() + logger = zap.New(zapcore.NewTee(cores...)) + + if global.GVA_CONFIG.Zap.ShowLine { + logger = logger.WithOptions(zap.AddCaller()) + } + return logger +} diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..83dd0f5 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,6882 @@ +// Code generated by swaggo/swag. DO NOT EDIT. + +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/createApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "创建基础api", + "parameters": [ + { + "description": "api路径, api中文描述, api组, 方法", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "创建基础api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/deleteApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "删除api", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "删除api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/deleteApisByIds": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "删除选中Api", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.IdsReq" + } + } + ], + "responses": { + "200": { + "description": "删除选中Api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/freshCasbin": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "刷新casbin缓存", + "responses": { + "200": { + "description": "刷新成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/getAllApis": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "获取所有的Api 不分页", + "responses": { + "200": { + "description": "获取所有的Api 不分页,返回包括api列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAPIListResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/getApiById": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "根据id获取api", + "parameters": [ + { + "description": "根据id获取api", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "根据id获取api,返回包括api详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAPIResponse" + } + } + } + ] + } + } + } + } + }, + "/api/getApiList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "分页获取API列表", + "parameters": [ + { + "description": "分页获取API列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SearchApiParams" + } + } + ], + "responses": { + "200": { + "description": "分页获取API列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/updateApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "修改基础api", + "parameters": [ + { + "description": "api路径, api中文描述, api组, 方法", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "修改基础api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/copyAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "拷贝角色", + "parameters": [ + { + "description": "旧角色id, 新权限id, 新权限名, 新父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/response.SysAuthorityCopyResponse" + } + } + ], + "responses": { + "200": { + "description": "拷贝角色,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/createAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "权限id, 权限名, 父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "创建角色,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/deleteAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "删除角色", + "parameters": [ + { + "description": "删除角色", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "删除角色", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/getAuthorityList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "分页获取角色列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取角色列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/setDataAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "设置角色资源权限", + "parameters": [ + { + "description": "设置角色资源权限", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "设置角色资源权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/updateAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "更新角色信息", + "parameters": [ + { + "description": "权限id, 权限名, 父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "更新角色信息,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/canRemoveAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "设置权限按钮", + "responses": { + "200": { + "description": "删除成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/getAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "获取权限按钮", + "parameters": [ + { + "description": "菜单id, 角色id, 选中的按钮id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAuthorityBtnReq" + } + } + ], + "responses": { + "200": { + "description": "返回列表成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityBtnRes" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/setAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "设置权限按钮", + "parameters": [ + { + "description": "菜单id, 角色id, 选中的按钮id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAuthorityBtnReq" + } + } + ], + "responses": { + "200": { + "description": "返回列表成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "创建package", + "parameters": [ + { + "description": "创建package", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAutoCode" + } + } + ], + "responses": { + "200": { + "description": "创建package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createPlug": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "安装插件", + "parameters": [ + { + "type": "file", + "description": "this is a test file", + "name": "plug", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "安装插件成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createTemp": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "自动代码模板", + "parameters": [ + { + "description": "创建自动代码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.AutoCodeStruct" + } + } + ], + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"创建成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/autoCode/delPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "删除package", + "parameters": [ + { + "description": "创建package", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAutoCode" + } + } + ], + "responses": { + "200": { + "description": "删除package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/delSysHistory": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "删除回滚记录", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除回滚记录", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getColumn": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前表所有字段", + "responses": { + "200": { + "description": "获取当前表所有字段", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getDatabase": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前所有数据库", + "responses": { + "200": { + "description": "获取当前所有数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getMeta": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取meta信息", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "获取meta信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取package", + "responses": { + "200": { + "description": "创建package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getSysHistory": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "查询回滚记录", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAutoHistory" + } + } + ], + "responses": { + "200": { + "description": "查询回滚记录,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getTables": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前数据库所有表", + "responses": { + "200": { + "description": "获取当前数据库所有表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/preview": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "预览创建后的代码", + "parameters": [ + { + "description": "预览创建代码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.AutoCodeStruct" + } + } + ], + "responses": { + "200": { + "description": "预览创建后的代码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/rollback": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "回滚自动生成代码", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.RollBack" + } + } + ], + "responses": { + "200": { + "description": "回滚自动生成代码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/base/captcha": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Base" + ], + "summary": "生成验证码", + "responses": { + "200": { + "description": "生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysCaptchaResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/base/login": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Base" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "用户名, 密码, 验证码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Login" + } + } + ], + "responses": { + "200": { + "description": "返回包括用户信息,token,过期时间", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.LoginResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/casbin/UpdateCasbin": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Casbin" + ], + "summary": "更新角色api权限", + "parameters": [ + { + "description": "权限id, 权限模型列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.CasbinInReceive" + } + } + ], + "responses": { + "200": { + "description": "更新角色api权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/casbin/getPolicyPathByAuthorityId": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Casbin" + ], + "summary": "获取权限列表", + "parameters": [ + { + "description": "权限id, 权限模型列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.CasbinInReceive" + } + } + ], + "responses": { + "200": { + "description": "获取权限列表,返回包括casbin详情列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PolicyPathResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/customer/customer": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "获取单一客户信息", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "客户名", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "description": "客户手机号", + "name": "customerPhoneData", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "integer", + "description": "管理角色ID", + "name": "sysUserAuthorityID", + "in": "query" + }, + { + "type": "integer", + "description": "管理ID", + "name": "sysUserId", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "获取单一客户信息,返回包括客户详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.ExaCustomerResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "更新客户信息", + "parameters": [ + { + "description": "客户ID, 客户信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "更新客户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "创建客户", + "parameters": [ + { + "description": "客户用户名, 客户手机号码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "创建客户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "删除客户", + "parameters": [ + { + "description": "客户ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "删除客户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/customer/customerList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "分页获取权限客户列表", + "parameters": [ + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取权限客户列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/email/emailTest": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "发送测试邮件", + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"发送成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/email/sendEmail": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "发送邮件", + "parameters": [ + { + "description": "发送邮件必须的参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/response.Email" + } + } + ], + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"发送成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/fileUploadAndDownload/breakpointContinue": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "断点续传到服务器", + "parameters": [ + { + "type": "file", + "description": "an example for breakpoint resume, 断点续传示例", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "断点续传到服务器", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/deleteFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "删除文件", + "parameters": [ + { + "description": "传入文件里面id即可", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaFileUploadAndDownload" + } + } + ], + "responses": { + "200": { + "description": "删除文件", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/findFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "创建文件", + "parameters": [ + { + "type": "file", + "description": "上传文件完成", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "创建文件,返回包括文件路径", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.FilePathResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/getFileList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "分页文件列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页文件列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/removeChunk": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "删除切片", + "parameters": [ + { + "type": "file", + "description": "删除缓存切片", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "删除切片", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/upload": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "上传文件示例", + "parameters": [ + { + "type": "file", + "description": "上传文件示例", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "上传文件示例,返回包括文件详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.ExaFileResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/init/checkdb": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "CheckDB" + ], + "summary": "初始化用户数据库", + "responses": { + "200": { + "description": "初始化用户数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/init/initdb": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "InitDB" + ], + "summary": "初始化用户数据库", + "parameters": [ + { + "description": "初始化数据库参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.InitDB" + } + } + ], + "responses": { + "200": { + "description": "初始化用户数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/jwt/jsonInBlacklist": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Jwt" + ], + "summary": "jwt加入黑名单", + "responses": { + "200": { + "description": "jwt加入黑名单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/addBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "新增菜单", + "parameters": [ + { + "description": "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + ], + "responses": { + "200": { + "description": "新增菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/addMenuAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "增加menu和角色关联关系", + "parameters": [ + { + "description": "角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AddMenuAuthorityInfo" + } + } + ], + "responses": { + "200": { + "description": "增加menu和角色关联关系", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/deleteBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "删除菜单", + "parameters": [ + { + "description": "菜单id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getBaseMenuById": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "根据id获取菜单", + "parameters": [ + { + "description": "菜单id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "根据id获取菜单,返回包括系统菜单列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysBaseMenuResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getBaseMenuTree": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取用户动态路由", + "parameters": [ + { + "description": "空", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Empty" + } + } + ], + "responses": { + "200": { + "description": "获取用户动态路由,返回包括系统菜单列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysBaseMenusResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取用户动态路由", + "parameters": [ + { + "description": "空", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Empty" + } + } + ], + "responses": { + "200": { + "description": "获取用户动态路由,返回包括系统菜单详情列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysMenusResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenuAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取指定角色menu", + "parameters": [ + { + "description": "角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetAuthorityId" + } + } + ], + "responses": { + "200": { + "description": "获取指定角色menu", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenuList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "分页获取基础menu列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取基础menu列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/updateBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "更新菜单", + "parameters": [ + { + "description": "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + ], + "responses": { + "200": { + "description": "更新菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/createSysDictionary": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "创建SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "创建SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/deleteSysDictionary": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "删除SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "删除SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/findSysDictionary": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "用id查询SysDictionary", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "描述", + "name": "desc", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "字典名(中)", + "name": "name", + "in": "query" + }, + { + "type": "boolean", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "字典名(英)", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/getSysDictionaryList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "分页获取SysDictionary列表", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "描述", + "name": "desc", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "字典名(中)", + "name": "name", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "boolean", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "字典名(英)", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/updateSysDictionary": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "更新SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "更新SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/createSysDictionaryDetail": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "创建SysDictionaryDetail", + "parameters": [ + { + "description": "SysDictionaryDetail模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "创建SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/deleteSysDictionaryDetail": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "删除SysDictionaryDetail", + "parameters": [ + { + "description": "SysDictionaryDetail模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "删除SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/findSysDictionaryDetail": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "用id查询SysDictionaryDetail", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "展示值", + "name": "label", + "in": "query" + }, + { + "type": "integer", + "description": "排序标记", + "name": "sort", + "in": "query" + }, + { + "type": "boolean", + "description": "启用状态", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "description": "关联标记", + "name": "sysDictionaryID", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "字典值", + "name": "value", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/getSysDictionaryDetailList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "分页获取SysDictionaryDetail列表", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "展示值", + "name": "label", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "排序标记", + "name": "sort", + "in": "query" + }, + { + "type": "boolean", + "description": "启用状态", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "description": "关联标记", + "name": "sysDictionaryID", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "字典值", + "name": "value", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysDictionaryDetail列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/updateSysDictionaryDetail": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "更新SysDictionaryDetail", + "parameters": [ + { + "description": "更新SysDictionaryDetail", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "更新SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/createSysOperationRecord": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "创建SysOperationRecord", + "parameters": [ + { + "description": "创建SysOperationRecord", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysOperationRecord" + } + } + ], + "responses": { + "200": { + "description": "创建SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/deleteSysOperationRecord": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "删除SysOperationRecord", + "parameters": [ + { + "description": "SysOperationRecord模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysOperationRecord" + } + } + ], + "responses": { + "200": { + "description": "删除SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/deleteSysOperationRecordByIds": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "批量删除SysOperationRecord", + "parameters": [ + { + "description": "批量删除SysOperationRecord", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.IdsReq" + } + } + ], + "responses": { + "200": { + "description": "批量删除SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/findSysOperationRecord": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "用id查询SysOperationRecord", + "parameters": [ + { + "type": "string", + "description": "代理", + "name": "agent", + "in": "query" + }, + { + "type": "string", + "description": "请求Body", + "name": "body", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "错误信息", + "name": "error_message", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "请求ip", + "name": "ip", + "in": "query" + }, + { + "type": "string", + "description": "延迟", + "name": "latency", + "in": "query" + }, + { + "type": "string", + "description": "请求方法", + "name": "method", + "in": "query" + }, + { + "type": "string", + "description": "请求路径", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "响应Body", + "name": "resp", + "in": "query" + }, + { + "type": "integer", + "description": "请求状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "用户id", + "name": "user_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/getSysOperationRecordList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "分页获取SysOperationRecord列表", + "parameters": [ + { + "type": "string", + "description": "代理", + "name": "agent", + "in": "query" + }, + { + "type": "string", + "description": "请求Body", + "name": "body", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "错误信息", + "name": "error_message", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "请求ip", + "name": "ip", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "延迟", + "name": "latency", + "in": "query" + }, + { + "type": "string", + "description": "请求方法", + "name": "method", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "string", + "description": "请求路径", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "响应Body", + "name": "resp", + "in": "query" + }, + { + "type": "integer", + "description": "请求状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "用户id", + "name": "user_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/getServerInfo": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "获取服务器信息", + "responses": { + "200": { + "description": "获取服务器信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/getSystemConfig": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "获取配置文件内容", + "responses": { + "200": { + "description": "获取配置文件内容,返回包括系统配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysConfigResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/reloadSystem": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "重启系统", + "responses": { + "200": { + "description": "重启系统", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/setSystemConfig": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "设置配置文件内容", + "parameters": [ + { + "description": "设置配置文件内容", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.System" + } + } + ], + "responses": { + "200": { + "description": "设置配置文件内容", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/SetSelfInfo": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户信息", + "parameters": [ + { + "description": "ID, 用户名, 昵称, 头像链接", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "设置用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/admin_register": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "用户注册账号", + "parameters": [ + { + "description": "用户名, 昵称, 密码, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Register" + } + } + ], + "responses": { + "200": { + "description": "用户注册账号,返回包括用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysUserResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/changePassword": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "用户修改密码", + "parameters": [ + { + "description": "用户名, 原密码, 新密码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChangePasswordReq" + } + } + ], + "responses": { + "200": { + "description": "用户修改密码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/deleteUser": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "删除用户", + "parameters": [ + { + "description": "用户ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除用户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/getUserInfo": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "获取用户信息", + "responses": { + "200": { + "description": "获取用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/getUserList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "分页获取用户列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取用户列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/resetPassword": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "重置用户密码", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "重置用户密码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserAuthorities": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户权限", + "parameters": [ + { + "description": "用户UUID, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SetUserAuthorities" + } + } + ], + "responses": { + "200": { + "description": "设置用户权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "更改用户权限", + "parameters": [ + { + "description": "用户UUID, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SetUserAuth" + } + } + ], + "responses": { + "200": { + "description": "设置用户权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserInfo": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户信息", + "parameters": [ + { + "description": "ID, 用户名, 昵称, 头像链接", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "设置用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + } + }, + "definitions": { + "config.AliyunOSS": { + "type": "object", + "properties": { + "access-key-id": { + "type": "string" + }, + "access-key-secret": { + "type": "string" + }, + "base-path": { + "type": "string" + }, + "bucket-name": { + "type": "string" + }, + "bucket-url": { + "type": "string" + }, + "endpoint": { + "type": "string" + } + } + }, + "config.Autocode": { + "type": "object", + "properties": { + "root": { + "type": "string" + }, + "server.exe.exe": { + "type": "string" + }, + "server.exe.exe-api": { + "type": "string" + }, + "server.exe.exe-initialize": { + "type": "string" + }, + "server.exe.exe-model": { + "type": "string" + }, + "server.exe.exe-plug": { + "type": "string" + }, + "server.exe.exe-request": { + "type": "string" + }, + "server.exe.exe-router": { + "type": "string" + }, + "server.exe.exe-service": { + "type": "string" + }, + "transfer-restart": { + "type": "boolean" + }, + "web": { + "type": "string" + }, + "web-api": { + "type": "string" + }, + "web-form": { + "type": "string" + }, + "web-table": { + "type": "string" + } + } + }, + "config.AwsS3": { + "type": "object", + "properties": { + "base-url": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "disable-ssl": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "path-prefix": { + "type": "string" + }, + "region": { + "type": "string" + }, + "s3-force-path-style": { + "type": "boolean" + }, + "secret-id": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.CORS": { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "whitelist": { + "type": "array", + "items": { + "$ref": "#/definitions/config.CORSWhitelist" + } + } + } + }, + "config.CORSWhitelist": { + "type": "object", + "properties": { + "allow-credentials": { + "type": "boolean" + }, + "allow-headers": { + "type": "string" + }, + "allow-methods": { + "type": "string" + }, + "allow-origin": { + "type": "string" + }, + "expose-headers": { + "type": "string" + } + } + }, + "config.Captcha": { + "type": "object", + "properties": { + "img-height": { + "description": "验证码高度", + "type": "integer" + }, + "img-width": { + "description": "验证码宽度", + "type": "integer" + }, + "key-long": { + "description": "验证码长度", + "type": "integer" + }, + "open-captcha": { + "description": "防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码", + "type": "integer" + }, + "open-captcha-timeout": { + "description": "防爆破验证码超时时间,单位:s(秒)", + "type": "integer" + } + } + }, + "config.Detail": { + "type": "object", + "properties": { + "compareField": { + "description": "需要比较时间的字段", + "type": "string" + }, + "interval": { + "description": "时间间隔", + "type": "string" + }, + "tableName": { + "description": "需要清理的表名", + "type": "string" + } + } + }, + "config.Excel": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "config.HuaWeiObs": { + "type": "object", + "properties": { + "access-key": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "path": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.JWT": { + "type": "object", + "properties": { + "buffer-time": { + "description": "缓冲时间", + "type": "string" + }, + "expires-time": { + "description": "过期时间", + "type": "string" + }, + "issuer": { + "description": "签发者", + "type": "string" + }, + "signing-key": { + "description": "jwt签名", + "type": "string" + } + } + }, + "config.Local": { + "type": "object", + "properties": { + "path": { + "description": "本地文件访问路径", + "type": "string" + }, + "store-path": { + "description": "本地文件存储路径", + "type": "string" + } + } + }, + "config.Mssql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Mysql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Oracle": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Pgsql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Qiniu": { + "type": "object", + "properties": { + "access-key": { + "description": "秘钥AK", + "type": "string" + }, + "bucket": { + "description": "空间名称", + "type": "string" + }, + "img-path": { + "description": "CDN加速域名", + "type": "string" + }, + "secret-key": { + "description": "秘钥SK", + "type": "string" + }, + "use-cdn-domains": { + "description": "上传是否使用CDN上传加速", + "type": "boolean" + }, + "use-https": { + "description": "是否使用https", + "type": "boolean" + }, + "zone": { + "description": "存储区域", + "type": "string" + } + } + }, + "config.Redis": { + "type": "object", + "properties": { + "addr": { + "description": "服务器地址:端口", + "type": "string" + }, + "db": { + "description": "redis的哪个数据库", + "type": "integer" + }, + "password": { + "description": "密码", + "type": "string" + } + } + }, + "config.Server": { + "type": "object", + "properties": { + "aliyun-oss": { + "$ref": "#/definitions/config.AliyunOSS" + }, + "autocode": { + "description": "auto", + "allOf": [ + { + "$ref": "#/definitions/config.Autocode" + } + ] + }, + "aws-s3": { + "$ref": "#/definitions/config.AwsS3" + }, + "captcha": { + "$ref": "#/definitions/config.Captcha" + }, + "cors": { + "description": "跨域配置", + "allOf": [ + { + "$ref": "#/definitions/config.CORS" + } + ] + }, + "db-list": { + "type": "array", + "items": { + "$ref": "#/definitions/config.SpecializedDB" + } + }, + "email": { + "$ref": "#/definitions/github_com_flipped-aurora_gin-vue-admin_server_config.Email" + }, + "excel": { + "$ref": "#/definitions/config.Excel" + }, + "hua-wei-obs": { + "$ref": "#/definitions/config.HuaWeiObs" + }, + "jwt": { + "$ref": "#/definitions/config.JWT" + }, + "local": { + "description": "oss", + "allOf": [ + { + "$ref": "#/definitions/config.Local" + } + ] + }, + "mssql": { + "$ref": "#/definitions/config.Mssql" + }, + "mysql": { + "description": "gorm", + "allOf": [ + { + "$ref": "#/definitions/config.Mysql" + } + ] + }, + "oracle": { + "$ref": "#/definitions/config.Oracle" + }, + "pgsql": { + "$ref": "#/definitions/config.Pgsql" + }, + "qiniu": { + "$ref": "#/definitions/config.Qiniu" + }, + "redis": { + "$ref": "#/definitions/config.Redis" + }, + "system": { + "$ref": "#/definitions/config.System" + }, + "tencent-cos": { + "$ref": "#/definitions/config.TencentCOS" + }, + "timer": { + "$ref": "#/definitions/config.Timer" + }, + "zap": { + "$ref": "#/definitions/config.Zap" + } + } + }, + "config.SpecializedDB": { + "type": "object", + "properties": { + "alias-name": { + "type": "string" + }, + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "disable": { + "type": "boolean" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "type": { + "type": "string" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.System": { + "type": "object", + "properties": { + "addr": { + "description": "端口值", + "type": "integer" + }, + "db-type": { + "description": "数据库类型:mysql(默认)|sqlite|sqlserver|postgresql", + "type": "string" + }, + "env": { + "description": "环境值", + "type": "string" + }, + "iplimit-count": { + "type": "integer" + }, + "iplimit-time": { + "type": "integer" + }, + "oss-type": { + "description": "Oss类型", + "type": "string" + }, + "router-prefix": { + "type": "string" + }, + "use-multipoint": { + "description": "多点登录拦截", + "type": "boolean" + }, + "use-redis": { + "description": "使用redis", + "type": "boolean" + } + } + }, + "config.TencentCOS": { + "type": "object", + "properties": { + "base-url": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "path-prefix": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret-id": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.Timer": { + "type": "object", + "properties": { + "detail": { + "type": "array", + "items": { + "$ref": "#/definitions/config.Detail" + } + }, + "spec": { + "description": "CRON表达式", + "type": "string" + }, + "start": { + "description": "是否启用", + "type": "boolean" + }, + "with_seconds": { + "description": "是否精确到秒", + "type": "boolean" + } + } + }, + "config.Zap": { + "type": "object", + "properties": { + "director": { + "description": "日志文件夹", + "type": "string" + }, + "encode-level": { + "description": "编码级", + "type": "string" + }, + "format": { + "description": "输出", + "type": "string" + }, + "level": { + "description": "级别", + "type": "string" + }, + "log-in-console": { + "description": "输出控制台", + "type": "boolean" + }, + "max-age": { + "description": "日志留存时间", + "type": "integer" + }, + "prefix": { + "description": "日志前缀", + "type": "string" + }, + "show-line": { + "description": "显示行", + "type": "boolean" + }, + "stacktrace-key": { + "description": "栈名", + "type": "string" + } + } + }, + "example.ExaCustomer": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "customerName": { + "description": "客户名", + "type": "string" + }, + "customerPhoneData": { + "description": "客户手机号", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "sysUser": { + "description": "管理详情", + "allOf": [ + { + "$ref": "#/definitions/system.SysUser" + } + ] + }, + "sysUserAuthorityID": { + "description": "管理角色ID", + "type": "integer" + }, + "sysUserId": { + "description": "管理ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFile": { + "type": "object", + "properties": { + "chunkTotal": { + "type": "integer" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "exaFileChunk": { + "type": "array", + "items": { + "$ref": "#/definitions/example.ExaFileChunk" + } + }, + "fileMd5": { + "type": "string" + }, + "fileName": { + "type": "string" + }, + "filePath": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "isFinish": { + "type": "boolean" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFileChunk": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "exaFileID": { + "type": "integer" + }, + "fileChunkNumber": { + "type": "integer" + }, + "fileChunkPath": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFileUploadAndDownload": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "key": { + "description": "编号", + "type": "string" + }, + "name": { + "description": "文件名", + "type": "string" + }, + "tag": { + "description": "文件标签", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "url": { + "description": "文件地址", + "type": "string" + } + } + }, + "github_com_flipped-aurora_gin-vue-admin_server_config.Email": { + "type": "object", + "properties": { + "from": { + "description": "收件人", + "type": "string" + }, + "host": { + "description": "服务器地址", + "type": "string" + }, + "is-ssl": { + "description": "是否SSL", + "type": "boolean" + }, + "nickname": { + "description": "昵称", + "type": "string" + }, + "port": { + "description": "端口", + "type": "integer" + }, + "secret": { + "description": "密钥", + "type": "string" + }, + "to": { + "description": "收件人:多个以英文逗号分隔", + "type": "string" + } + } + }, + "request.AddMenuAuthorityInfo": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + }, + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + } + }, + "request.CasbinInReceive": { + "type": "object", + "properties": { + "authorityId": { + "description": "权限id", + "type": "integer" + }, + "casbinInfos": { + "type": "array", + "items": { + "$ref": "#/definitions/request.CasbinInfo" + } + } + } + }, + "request.CasbinInfo": { + "type": "object", + "properties": { + "method": { + "description": "方法", + "type": "string" + }, + "path": { + "description": "路径", + "type": "string" + } + } + }, + "request.ChangePasswordReq": { + "type": "object", + "properties": { + "newPassword": { + "description": "新密码", + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + } + } + }, + "request.Empty": { + "type": "object" + }, + "request.GetAuthorityId": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + } + } + }, + "request.GetById": { + "type": "object", + "properties": { + "id": { + "description": "主键ID", + "type": "integer" + } + } + }, + "request.IdsReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "request.InitDB": { + "type": "object", + "required": [ + "dbName", + "userName" + ], + "properties": { + "dbName": { + "description": "数据库名", + "type": "string" + }, + "dbType": { + "description": "数据库类型", + "type": "string" + }, + "host": { + "description": "服务器地址", + "type": "string" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "port": { + "description": "数据库连接端口", + "type": "string" + }, + "userName": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "request.Login": { + "type": "object", + "properties": { + "captcha": { + "description": "验证码", + "type": "string" + }, + "captchaId": { + "description": "验证码ID", + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, + "request.PageInfo": { + "type": "object", + "properties": { + "keyword": { + "description": "关键字", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + } + } + }, + "request.Register": { + "type": "object", + "properties": { + "authorityId": { + "type": "string", + "example": "int 角色id" + }, + "authorityIds": { + "type": "string", + "example": "[]uint 角色id" + }, + "email": { + "type": "string", + "example": "电子邮箱" + }, + "enable": { + "type": "string", + "example": "int 是否启用" + }, + "headerImg": { + "type": "string", + "example": "头像链接" + }, + "nickName": { + "type": "string", + "example": "昵称" + }, + "passWord": { + "type": "string", + "example": "密码" + }, + "phone": { + "type": "string", + "example": "电话号码" + }, + "userName": { + "type": "string", + "example": "用户名" + } + } + }, + "request.RollBack": { + "type": "object", + "properties": { + "deleteTable": { + "description": "是否删除表", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + } + } + }, + "request.SearchApiParams": { + "type": "object", + "properties": { + "apiGroup": { + "description": "api组", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "description": "排序方式:升序false(默认)|降序true", + "type": "boolean" + }, + "description": { + "description": "api中文描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "keyword": { + "description": "关键字", + "type": "string" + }, + "method": { + "description": "方法:创建POST(默认)|查看GET|更新PUT|删除DELETE", + "type": "string" + }, + "orderKey": { + "description": "排序", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + }, + "path": { + "description": "api路径", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "request.SetUserAuth": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + } + } + }, + "request.SetUserAuthorities": { + "type": "object", + "properties": { + "authorityIds": { + "description": "角色ID", + "type": "array", + "items": { + "type": "integer" + } + }, + "id": { + "type": "integer" + } + } + }, + "request.SysAuthorityBtnReq": { + "type": "object", + "properties": { + "authorityId": { + "type": "integer" + }, + "menuID": { + "type": "integer" + }, + "selected": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "request.SysAutoHistory": { + "type": "object", + "properties": { + "keyword": { + "description": "关键字", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + } + } + }, + "response.Email": { + "type": "object", + "properties": { + "body": { + "description": "邮件内容", + "type": "string" + }, + "subject": { + "description": "邮件标题", + "type": "string" + }, + "to": { + "description": "邮件发送给谁", + "type": "string" + } + } + }, + "response.ExaCustomerResponse": { + "type": "object", + "properties": { + "customer": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + }, + "response.ExaFileResponse": { + "type": "object", + "properties": { + "file": { + "$ref": "#/definitions/example.ExaFileUploadAndDownload" + } + } + }, + "response.FilePathResponse": { + "type": "object", + "properties": { + "filePath": { + "type": "string" + } + } + }, + "response.FileResponse": { + "type": "object", + "properties": { + "file": { + "$ref": "#/definitions/example.ExaFile" + } + } + }, + "response.LoginResponse": { + "type": "object", + "properties": { + "expiresAt": { + "type": "integer" + }, + "token": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/system.SysUser" + } + } + }, + "response.PageResult": { + "type": "object", + "properties": { + "list": {}, + "page": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "response.PolicyPathResponse": { + "type": "object", + "properties": { + "paths": { + "type": "array", + "items": { + "$ref": "#/definitions/request.CasbinInfo" + } + } + } + }, + "response.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "msg": { + "type": "string" + } + } + }, + "response.SysAPIListResponse": { + "type": "object", + "properties": { + "apis": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysApi" + } + } + } + }, + "response.SysAPIResponse": { + "type": "object", + "properties": { + "api": { + "$ref": "#/definitions/system.SysApi" + } + } + }, + "response.SysAuthorityBtnRes": { + "type": "object", + "properties": { + "selected": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "response.SysAuthorityCopyResponse": { + "type": "object", + "properties": { + "authority": { + "$ref": "#/definitions/system.SysAuthority" + }, + "oldAuthorityId": { + "description": "旧角色ID", + "type": "integer" + } + } + }, + "response.SysAuthorityResponse": { + "type": "object", + "properties": { + "authority": { + "$ref": "#/definitions/system.SysAuthority" + } + } + }, + "response.SysBaseMenuResponse": { + "type": "object", + "properties": { + "menu": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + }, + "response.SysBaseMenusResponse": { + "type": "object", + "properties": { + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + } + }, + "response.SysCaptchaResponse": { + "type": "object", + "properties": { + "captchaId": { + "type": "string" + }, + "captchaLength": { + "type": "integer" + }, + "openCaptcha": { + "type": "boolean" + }, + "picPath": { + "type": "string" + } + } + }, + "response.SysConfigResponse": { + "type": "object", + "properties": { + "config": { + "$ref": "#/definitions/config.Server" + } + } + }, + "response.SysMenusResponse": { + "type": "object", + "properties": { + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysMenu" + } + } + } + }, + "response.SysUserResponse": { + "type": "object", + "properties": { + "user": { + "$ref": "#/definitions/system.SysUser" + } + } + }, + "system.AutoCodeStruct": { + "type": "object", + "properties": { + "abbreviation": { + "description": "Struct简称", + "type": "string" + }, + "autoCreateApiToSql": { + "description": "是否自动创建api", + "type": "boolean" + }, + "autoCreateResource": { + "description": "是否自动创建资源标识", + "type": "boolean" + }, + "autoMoveFile": { + "description": "是否自动移动文件", + "type": "boolean" + }, + "businessDB": { + "description": "业务数据库", + "type": "string" + }, + "description": { + "description": "Struct中文名称", + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/definitions/system.Field" + } + }, + "hasTimer": { + "type": "boolean" + }, + "humpPackageName": { + "description": "go文件名称", + "type": "string" + }, + "package": { + "type": "string" + }, + "packageName": { + "description": "文件名称", + "type": "string" + }, + "structName": { + "description": "Struct名称", + "type": "string" + }, + "tableName": { + "description": "表名", + "type": "string" + } + } + }, + "system.Field": { + "type": "object", + "properties": { + "clearable": { + "description": "是否可清空", + "type": "boolean" + }, + "columnName": { + "description": "数据库字段", + "type": "string" + }, + "comment": { + "description": "数据库字段描述", + "type": "string" + }, + "dataTypeLong": { + "description": "数据库字段长度", + "type": "string" + }, + "dictType": { + "description": "字典", + "type": "string" + }, + "errorText": { + "description": "校验失败文字", + "type": "string" + }, + "fieldDesc": { + "description": "中文名", + "type": "string" + }, + "fieldJson": { + "description": "FieldJson", + "type": "string" + }, + "fieldName": { + "description": "Field名", + "type": "string" + }, + "fieldSearchType": { + "description": "搜索条件", + "type": "string" + }, + "fieldType": { + "description": "Field数据类型", + "type": "string" + }, + "require": { + "description": "是否必填", + "type": "boolean" + }, + "sort": { + "description": "是否增加排序", + "type": "boolean" + } + } + }, + "system.Meta": { + "type": "object", + "properties": { + "activeName": { + "type": "string" + }, + "closeTab": { + "description": "自动关闭tab", + "type": "boolean" + }, + "defaultMenu": { + "description": "是否是基础路由(开发中)", + "type": "boolean" + }, + "icon": { + "description": "菜单图标", + "type": "string" + }, + "keepAlive": { + "description": "是否缓存", + "type": "boolean" + }, + "title": { + "description": "菜单名", + "type": "string" + } + } + }, + "system.SysApi": { + "type": "object", + "properties": { + "apiGroup": { + "description": "api组", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "description": { + "description": "api中文描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "method": { + "description": "方法:创建POST(默认)|查看GET|更新PUT|删除DELETE", + "type": "string" + }, + "path": { + "description": "api路径", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysAuthority": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + }, + "authorityName": { + "description": "角色名", + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "dataAuthorityId": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "defaultRouter": { + "description": "默认菜单(默认dashboard)", + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + }, + "parentId": { + "description": "父角色ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysAutoCode": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "label": { + "type": "string" + }, + "packageName": { + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenu": { + "type": "object", + "properties": { + "authoritys": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + }, + "component": { + "description": "对应前端文件路径", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "hidden": { + "description": "是否在列表隐藏", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "menuBtn": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuBtn" + } + }, + "meta": { + "description": "附加属性", + "allOf": [ + { + "$ref": "#/definitions/system.Meta" + } + ] + }, + "name": { + "description": "路由name", + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuParameter" + } + }, + "parentId": { + "description": "父菜单ID", + "type": "string" + }, + "path": { + "description": "路由path", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenuBtn": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "name": { + "type": "string" + }, + "sysBaseMenuID": { + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenuParameter": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "key": { + "description": "地址栏携带参数的key", + "type": "string" + }, + "sysBaseMenuID": { + "type": "integer" + }, + "type": { + "description": "地址栏携带参数为params还是query", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "value": { + "description": "地址栏携带参数的值", + "type": "string" + } + } + }, + "system.SysDictionary": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "description": "描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "name": { + "description": "字典名(中)", + "type": "string" + }, + "status": { + "description": "状态", + "type": "boolean" + }, + "sysDictionaryDetails": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + }, + "type": { + "description": "字典名(英)", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysDictionaryDetail": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "label": { + "description": "展示值", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "status": { + "description": "启用状态", + "type": "boolean" + }, + "sysDictionaryID": { + "description": "关联标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "value": { + "description": "字典值", + "type": "integer" + } + } + }, + "system.SysMenu": { + "type": "object", + "properties": { + "authoritys": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "btns": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysMenu" + } + }, + "component": { + "description": "对应前端文件路径", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "hidden": { + "description": "是否在列表隐藏", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "menuBtn": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuBtn" + } + }, + "menuId": { + "type": "string" + }, + "meta": { + "description": "附加属性", + "allOf": [ + { + "$ref": "#/definitions/system.Meta" + } + ] + }, + "name": { + "description": "路由name", + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuParameter" + } + }, + "parentId": { + "description": "父菜单ID", + "type": "string" + }, + "path": { + "description": "路由path", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysOperationRecord": { + "type": "object", + "properties": { + "agent": { + "description": "代理", + "type": "string" + }, + "body": { + "description": "请求Body", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "error_message": { + "description": "错误信息", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "ip": { + "description": "请求ip", + "type": "string" + }, + "latency": { + "description": "延迟", + "type": "string" + }, + "method": { + "description": "请求方法", + "type": "string" + }, + "path": { + "description": "请求路径", + "type": "string" + }, + "resp": { + "description": "响应Body", + "type": "string" + }, + "status": { + "description": "请求状态", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "user": { + "$ref": "#/definitions/system.SysUser" + }, + "user_id": { + "description": "用户id", + "type": "integer" + } + } + }, + "system.SysUser": { + "type": "object", + "properties": { + "activeColor": { + "description": "活跃颜色", + "type": "string" + }, + "authorities": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "authority": { + "$ref": "#/definitions/system.SysAuthority" + }, + "authorityId": { + "description": "用户角色ID", + "type": "integer" + }, + "baseColor": { + "description": "基础颜色", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "email": { + "description": "用户邮箱", + "type": "string" + }, + "enable": { + "description": "用户是否被冻结 1正常 2冻结", + "type": "integer" + }, + "headerImg": { + "description": "用户头像", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "nickName": { + "description": "用户昵称", + "type": "string" + }, + "phone": { + "description": "用户手机号", + "type": "string" + }, + "sideMode": { + "description": "用户侧边主题", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "userName": { + "description": "用户登录名", + "type": "string" + }, + "uuid": { + "description": "用户UUID", + "type": "string" + } + } + }, + "system.System": { + "type": "object", + "properties": { + "config": { + "$ref": "#/definitions/config.Server" + } + } + } + }, + "securityDefinitions": { + "ApiKeyAuth": { + "type": "apiKey", + "name": "x-token", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "0.0.1", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "Swagger Example API", + Description: "This is a sample Server pets", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..3e5cb93 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,6916 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a sample Server pets", + "title": "Swagger Example API", + "contact": {}, + "version": "0.0.1" + }, + "paths": { + "/api/createApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "创建基础api", + "parameters": [ + { + "description": "api路径, api中文描述, api组, 方法", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "创建基础api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/deleteApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "删除api", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "删除api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/deleteApisByIds": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "删除选中Api", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.IdsReq" + } + } + ], + "responses": { + "200": { + "description": "删除选中Api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/freshCasbin": { + "get": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "刷新casbin缓存", + "responses": { + "200": { + "description": "刷新成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/getAllApis": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "获取所有的Api 不分页", + "responses": { + "200": { + "description": "获取所有的Api 不分页,返回包括api列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAPIListResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/getApiById": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "根据id获取api", + "parameters": [ + { + "description": "根据id获取api", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "根据id获取api,返回包括api详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAPIResponse" + } + } + } + ] + } + } + } + } + }, + "/api/getApiList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "分页获取API列表", + "parameters": [ + { + "description": "分页获取API列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SearchApiParams" + } + } + ], + "responses": { + "200": { + "description": "分页获取API列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/api/updateApi": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysApi" + ], + "summary": "修改基础api", + "parameters": [ + { + "description": "api路径, api中文描述, api组, 方法", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysApi" + } + } + ], + "responses": { + "200": { + "description": "修改基础api", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/copyAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "拷贝角色", + "parameters": [ + { + "description": "旧角色id, 新权限id, 新权限名, 新父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/response.SysAuthorityCopyResponse" + } + } + ], + "responses": { + "200": { + "description": "拷贝角色,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/createAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "创建角色", + "parameters": [ + { + "description": "权限id, 权限名, 父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "创建角色,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/deleteAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "删除角色", + "parameters": [ + { + "description": "删除角色", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "删除角色", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/getAuthorityList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "分页获取角色列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取角色列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/setDataAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "设置角色资源权限", + "parameters": [ + { + "description": "设置角色资源权限", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "设置角色资源权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authority/updateAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Authority" + ], + "summary": "更新角色信息", + "parameters": [ + { + "description": "权限id, 权限名, 父角色id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAuthority" + } + } + ], + "responses": { + "200": { + "description": "更新角色信息,返回包括系统角色详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/canRemoveAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "设置权限按钮", + "responses": { + "200": { + "description": "删除成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/getAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "获取权限按钮", + "parameters": [ + { + "description": "菜单id, 角色id, 选中的按钮id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAuthorityBtnReq" + } + } + ], + "responses": { + "200": { + "description": "返回列表成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysAuthorityBtnRes" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/authorityBtn/setAuthorityBtn": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityBtn" + ], + "summary": "设置权限按钮", + "parameters": [ + { + "description": "菜单id, 角色id, 选中的按钮id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAuthorityBtnReq" + } + } + ], + "responses": { + "200": { + "description": "返回列表成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "创建package", + "parameters": [ + { + "description": "创建package", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAutoCode" + } + } + ], + "responses": { + "200": { + "description": "创建package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createPlug": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "安装插件", + "parameters": [ + { + "type": "file", + "description": "this is a test file", + "name": "plug", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "安装插件成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/createTemp": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "自动代码模板", + "parameters": [ + { + "description": "创建自动代码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.AutoCodeStruct" + } + } + ], + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"创建成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/autoCode/delPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "删除package", + "parameters": [ + { + "description": "创建package", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysAutoCode" + } + } + ], + "responses": { + "200": { + "description": "删除package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/delSysHistory": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "删除回滚记录", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除回滚记录", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getColumn": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前表所有字段", + "responses": { + "200": { + "description": "获取当前表所有字段", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getDatabase": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前所有数据库", + "responses": { + "200": { + "description": "获取当前所有数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getMeta": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取meta信息", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "获取meta信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getPackage": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取package", + "responses": { + "200": { + "description": "创建package成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getSysHistory": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "查询回滚记录", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SysAutoHistory" + } + } + ], + "responses": { + "200": { + "description": "查询回滚记录,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/getTables": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "获取当前数据库所有表", + "responses": { + "200": { + "description": "获取当前数据库所有表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/preview": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "预览创建后的代码", + "parameters": [ + { + "description": "预览创建代码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.AutoCodeStruct" + } + } + ], + "responses": { + "200": { + "description": "预览创建后的代码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/autoCode/rollback": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AutoCode" + ], + "summary": "回滚自动生成代码", + "parameters": [ + { + "description": "请求参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.RollBack" + } + } + ], + "responses": { + "200": { + "description": "回滚自动生成代码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/base/captcha": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Base" + ], + "summary": "生成验证码", + "responses": { + "200": { + "description": "生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysCaptchaResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/base/login": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "Base" + ], + "summary": "用户登录", + "parameters": [ + { + "description": "用户名, 密码, 验证码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Login" + } + } + ], + "responses": { + "200": { + "description": "返回包括用户信息,token,过期时间", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.LoginResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/casbin/UpdateCasbin": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Casbin" + ], + "summary": "更新角色api权限", + "parameters": [ + { + "description": "权限id, 权限模型列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.CasbinInReceive" + } + } + ], + "responses": { + "200": { + "description": "更新角色api权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/casbin/getPolicyPathByAuthorityId": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Casbin" + ], + "summary": "获取权限列表", + "parameters": [ + { + "description": "权限id, 权限模型列表", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.CasbinInReceive" + } + } + ], + "responses": { + "200": { + "description": "获取权限列表,返回包括casbin详情列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PolicyPathResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/customer/customer": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "获取单一客户信息", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "客户名", + "name": "customerName", + "in": "query" + }, + { + "type": "string", + "description": "客户手机号", + "name": "customerPhoneData", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "integer", + "description": "管理角色ID", + "name": "sysUserAuthorityID", + "in": "query" + }, + { + "type": "integer", + "description": "管理ID", + "name": "sysUserId", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "获取单一客户信息,返回包括客户详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.ExaCustomerResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "更新客户信息", + "parameters": [ + { + "description": "客户ID, 客户信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "更新客户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "创建客户", + "parameters": [ + { + "description": "客户用户名, 客户手机号码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "创建客户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + }, + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "删除客户", + "parameters": [ + { + "description": "客户ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + ], + "responses": { + "200": { + "description": "删除客户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/customer/customerList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaCustomer" + ], + "summary": "分页获取权限客户列表", + "parameters": [ + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取权限客户列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/email/emailTest": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "发送测试邮件", + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"发送成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/email/sendEmail": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "发送邮件", + "parameters": [ + { + "description": "发送邮件必须的参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/response.Email" + } + } + ], + "responses": { + "200": { + "description": "{\"success\":true,\"data\":{},\"msg\":\"发送成功\"}", + "schema": { + "type": "string" + } + } + } + } + }, + "/fileUploadAndDownload/breakpointContinue": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "断点续传到服务器", + "parameters": [ + { + "type": "file", + "description": "an example for breakpoint resume, 断点续传示例", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "断点续传到服务器", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/deleteFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "删除文件", + "parameters": [ + { + "description": "传入文件里面id即可", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/example.ExaFileUploadAndDownload" + } + } + ], + "responses": { + "200": { + "description": "删除文件", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/findFile": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "创建文件", + "parameters": [ + { + "type": "file", + "description": "上传文件完成", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "创建文件,返回包括文件路径", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.FilePathResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/getFileList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "分页文件列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页文件列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/removeChunk": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "删除切片", + "parameters": [ + { + "type": "file", + "description": "删除缓存切片", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "删除切片", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/fileUploadAndDownload/upload": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ExaFileUploadAndDownload" + ], + "summary": "上传文件示例", + "parameters": [ + { + "type": "file", + "description": "上传文件示例", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "上传文件示例,返回包括文件详情", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.ExaFileResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/init/checkdb": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "CheckDB" + ], + "summary": "初始化用户数据库", + "responses": { + "200": { + "description": "初始化用户数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/init/initdb": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "InitDB" + ], + "summary": "初始化用户数据库", + "parameters": [ + { + "description": "初始化数据库参数", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.InitDB" + } + } + ], + "responses": { + "200": { + "description": "初始化用户数据库", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/jwt/jsonInBlacklist": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Jwt" + ], + "summary": "jwt加入黑名单", + "responses": { + "200": { + "description": "jwt加入黑名单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/addBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "新增菜单", + "parameters": [ + { + "description": "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + ], + "responses": { + "200": { + "description": "新增菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/addMenuAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "增加menu和角色关联关系", + "parameters": [ + { + "description": "角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AddMenuAuthorityInfo" + } + } + ], + "responses": { + "200": { + "description": "增加menu和角色关联关系", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/deleteBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "删除菜单", + "parameters": [ + { + "description": "菜单id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getBaseMenuById": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "根据id获取菜单", + "parameters": [ + { + "description": "菜单id", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "根据id获取菜单,返回包括系统菜单列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysBaseMenuResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getBaseMenuTree": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取用户动态路由", + "parameters": [ + { + "description": "空", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Empty" + } + } + ], + "responses": { + "200": { + "description": "获取用户动态路由,返回包括系统菜单列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysBaseMenusResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取用户动态路由", + "parameters": [ + { + "description": "空", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Empty" + } + } + ], + "responses": { + "200": { + "description": "获取用户动态路由,返回包括系统菜单详情列表", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysMenusResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenuAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AuthorityMenu" + ], + "summary": "获取指定角色menu", + "parameters": [ + { + "description": "角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetAuthorityId" + } + } + ], + "responses": { + "200": { + "description": "获取指定角色menu", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/getMenuList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "分页获取基础menu列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取基础menu列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/menu/updateBaseMenu": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Menu" + ], + "summary": "更新菜单", + "parameters": [ + { + "description": "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + ], + "responses": { + "200": { + "description": "更新菜单", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/createSysDictionary": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "创建SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "创建SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/deleteSysDictionary": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "删除SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "删除SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/findSysDictionary": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "用id查询SysDictionary", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "描述", + "name": "desc", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "字典名(中)", + "name": "name", + "in": "query" + }, + { + "type": "boolean", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "字典名(英)", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/getSysDictionaryList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "分页获取SysDictionary列表", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "描述", + "name": "desc", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "字典名(中)", + "name": "name", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "boolean", + "description": "状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "字典名(英)", + "name": "type", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionary/updateSysDictionary": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionary" + ], + "summary": "更新SysDictionary", + "parameters": [ + { + "description": "SysDictionary模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionary" + } + } + ], + "responses": { + "200": { + "description": "更新SysDictionary", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/createSysDictionaryDetail": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "创建SysDictionaryDetail", + "parameters": [ + { + "description": "SysDictionaryDetail模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "创建SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/deleteSysDictionaryDetail": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "删除SysDictionaryDetail", + "parameters": [ + { + "description": "SysDictionaryDetail模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "删除SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/findSysDictionaryDetail": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "用id查询SysDictionaryDetail", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "展示值", + "name": "label", + "in": "query" + }, + { + "type": "integer", + "description": "排序标记", + "name": "sort", + "in": "query" + }, + { + "type": "boolean", + "description": "启用状态", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "description": "关联标记", + "name": "sysDictionaryID", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "字典值", + "name": "value", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/getSysDictionaryDetailList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "分页获取SysDictionaryDetail列表", + "parameters": [ + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "展示值", + "name": "label", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "integer", + "description": "排序标记", + "name": "sort", + "in": "query" + }, + { + "type": "boolean", + "description": "启用状态", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "description": "关联标记", + "name": "sysDictionaryID", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "字典值", + "name": "value", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysDictionaryDetail列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysDictionaryDetail/updateSysDictionaryDetail": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysDictionaryDetail" + ], + "summary": "更新SysDictionaryDetail", + "parameters": [ + { + "description": "更新SysDictionaryDetail", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + } + ], + "responses": { + "200": { + "description": "更新SysDictionaryDetail", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/createSysOperationRecord": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "创建SysOperationRecord", + "parameters": [ + { + "description": "创建SysOperationRecord", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysOperationRecord" + } + } + ], + "responses": { + "200": { + "description": "创建SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/deleteSysOperationRecord": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "删除SysOperationRecord", + "parameters": [ + { + "description": "SysOperationRecord模型", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysOperationRecord" + } + } + ], + "responses": { + "200": { + "description": "删除SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/deleteSysOperationRecordByIds": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "批量删除SysOperationRecord", + "parameters": [ + { + "description": "批量删除SysOperationRecord", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.IdsReq" + } + } + ], + "responses": { + "200": { + "description": "批量删除SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/findSysOperationRecord": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "用id查询SysOperationRecord", + "parameters": [ + { + "type": "string", + "description": "代理", + "name": "agent", + "in": "query" + }, + { + "type": "string", + "description": "请求Body", + "name": "body", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "错误信息", + "name": "error_message", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "请求ip", + "name": "ip", + "in": "query" + }, + { + "type": "string", + "description": "延迟", + "name": "latency", + "in": "query" + }, + { + "type": "string", + "description": "请求方法", + "name": "method", + "in": "query" + }, + { + "type": "string", + "description": "请求路径", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "响应Body", + "name": "resp", + "in": "query" + }, + { + "type": "integer", + "description": "请求状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "用户id", + "name": "user_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "用id查询SysOperationRecord", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/sysOperationRecord/getSysOperationRecordList": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysOperationRecord" + ], + "summary": "分页获取SysOperationRecord列表", + "parameters": [ + { + "type": "string", + "description": "代理", + "name": "agent", + "in": "query" + }, + { + "type": "string", + "description": "请求Body", + "name": "body", + "in": "query" + }, + { + "type": "string", + "description": "创建时间", + "name": "createdAt", + "in": "query" + }, + { + "type": "string", + "description": "错误信息", + "name": "error_message", + "in": "query" + }, + { + "type": "integer", + "description": "主键ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "请求ip", + "name": "ip", + "in": "query" + }, + { + "type": "string", + "description": "关键字", + "name": "keyword", + "in": "query" + }, + { + "type": "string", + "description": "延迟", + "name": "latency", + "in": "query" + }, + { + "type": "string", + "description": "请求方法", + "name": "method", + "in": "query" + }, + { + "type": "integer", + "description": "页码", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "每页大小", + "name": "pageSize", + "in": "query" + }, + { + "type": "string", + "description": "请求路径", + "name": "path", + "in": "query" + }, + { + "type": "string", + "description": "响应Body", + "name": "resp", + "in": "query" + }, + { + "type": "integer", + "description": "请求状态", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "更新时间", + "name": "updatedAt", + "in": "query" + }, + { + "type": "integer", + "description": "用户id", + "name": "user_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/getServerInfo": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "获取服务器信息", + "responses": { + "200": { + "description": "获取服务器信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/getSystemConfig": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "获取配置文件内容", + "responses": { + "200": { + "description": "获取配置文件内容,返回包括系统配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysConfigResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/reloadSystem": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "重启系统", + "responses": { + "200": { + "description": "重启系统", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/system/setSystemConfig": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "设置配置文件内容", + "parameters": [ + { + "description": "设置配置文件内容", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.System" + } + } + ], + "responses": { + "200": { + "description": "设置配置文件内容", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/SetSelfInfo": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户信息", + "parameters": [ + { + "description": "ID, 用户名, 昵称, 头像链接", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "设置用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/admin_register": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "用户注册账号", + "parameters": [ + { + "description": "用户名, 昵称, 密码, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.Register" + } + } + ], + "responses": { + "200": { + "description": "用户注册账号,返回包括用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.SysUserResponse" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/changePassword": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "用户修改密码", + "parameters": [ + { + "description": "用户名, 原密码, 新密码", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChangePasswordReq" + } + } + ], + "responses": { + "200": { + "description": "用户修改密码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/deleteUser": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "删除用户", + "parameters": [ + { + "description": "用户ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.GetById" + } + } + ], + "responses": { + "200": { + "description": "删除用户", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/getUserInfo": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "获取用户信息", + "responses": { + "200": { + "description": "获取用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/getUserList": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "分页获取用户列表", + "parameters": [ + { + "description": "页码, 每页大小", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.PageInfo" + } + } + ], + "responses": { + "200": { + "description": "分页获取用户列表,返回包括列表,总数,页码,每页数量", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/response.PageResult" + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/resetPassword": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "重置用户密码", + "parameters": [ + { + "description": "ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "重置用户密码", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserAuthorities": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户权限", + "parameters": [ + { + "description": "用户UUID, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SetUserAuthorities" + } + } + ], + "responses": { + "200": { + "description": "设置用户权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserAuthority": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "更改用户权限", + "parameters": [ + { + "description": "用户UUID, 角色ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.SetUserAuth" + } + } + ], + "responses": { + "200": { + "description": "设置用户权限", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + }, + "/user/setUserInfo": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "SysUser" + ], + "summary": "设置用户信息", + "parameters": [ + { + "description": "ID, 用户名, 昵称, 头像链接", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/system.SysUser" + } + } + ], + "responses": { + "200": { + "description": "设置用户信息", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + }, + "msg": { + "type": "string" + } + } + } + ] + } + } + } + } + } + }, + "definitions": { + "config.AliyunOSS": { + "type": "object", + "properties": { + "access-key-id": { + "type": "string" + }, + "access-key-secret": { + "type": "string" + }, + "base-path": { + "type": "string" + }, + "bucket-name": { + "type": "string" + }, + "bucket-url": { + "type": "string" + }, + "endpoint": { + "type": "string" + } + } + }, + "config.Autocode": { + "type": "object", + "properties": { + "root": { + "type": "string" + }, + "server": { + "type": "string" + }, + "server-api": { + "type": "string" + }, + "server-initialize": { + "type": "string" + }, + "server-model": { + "type": "string" + }, + "server-plug": { + "type": "string" + }, + "server-request": { + "type": "string" + }, + "server-router": { + "type": "string" + }, + "server-service": { + "type": "string" + }, + "transfer-restart": { + "type": "boolean" + }, + "web": { + "type": "string" + }, + "web-api": { + "type": "string" + }, + "web-form": { + "type": "string" + }, + "web-table": { + "type": "string" + } + } + }, + "config.AwsS3": { + "type": "object", + "properties": { + "base-url": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "disable-ssl": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "path-prefix": { + "type": "string" + }, + "region": { + "type": "string" + }, + "s3-force-path-style": { + "type": "boolean" + }, + "secret-id": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.CORS": { + "type": "object", + "properties": { + "mode": { + "type": "string" + }, + "whitelist": { + "type": "array", + "items": { + "$ref": "#/definitions/config.CORSWhitelist" + } + } + } + }, + "config.CORSWhitelist": { + "type": "object", + "properties": { + "allow-credentials": { + "type": "boolean" + }, + "allow-headers": { + "type": "string" + }, + "allow-methods": { + "type": "string" + }, + "allow-origin": { + "type": "string" + }, + "expose-headers": { + "type": "string" + } + } + }, + "config.Captcha": { + "type": "object", + "properties": { + "img-height": { + "description": "验证码高度", + "type": "integer" + }, + "img-width": { + "description": "验证码宽度", + "type": "integer" + }, + "key-long": { + "description": "验证码长度", + "type": "integer" + }, + "open-captcha": { + "description": "防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码", + "type": "integer" + }, + "open-captcha-timeout": { + "description": "防爆破验证码超时时间,单位:s(秒)", + "type": "integer" + } + } + }, + "config.Detail": { + "type": "object", + "properties": { + "compareField": { + "description": "需要比较时间的字段", + "type": "string" + }, + "interval": { + "description": "时间间隔", + "type": "string" + }, + "tableName": { + "description": "需要清理的表名", + "type": "string" + } + } + }, + "config.Excel": { + "type": "object", + "properties": { + "dir": { + "type": "string" + } + } + }, + "config.HuaWeiObs": { + "type": "object", + "properties": { + "access-key": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "path": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.JWT": { + "type": "object", + "properties": { + "buffer-time": { + "description": "缓冲时间", + "type": "string" + }, + "expires-time": { + "description": "过期时间", + "type": "string" + }, + "issuer": { + "description": "签发者", + "type": "string" + }, + "signing-key": { + "description": "jwt签名", + "type": "string" + } + } + }, + "config.Local": { + "type": "object", + "properties": { + "path": { + "description": "本地文件访问路径", + "type": "string" + }, + "store-path": { + "description": "本地文件存储路径", + "type": "string" + } + } + }, + "config.Mssql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Mysql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Oracle": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Pgsql": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Sqlite": { + "type": "object", + "properties": { + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.Qiniu": { + "type": "object", + "properties": { + "access-key": { + "description": "秘钥AK", + "type": "string" + }, + "bucket": { + "description": "空间名称", + "type": "string" + }, + "img-path": { + "description": "CDN加速域名", + "type": "string" + }, + "secret-key": { + "description": "秘钥SK", + "type": "string" + }, + "use-cdn-domains": { + "description": "上传是否使用CDN上传加速", + "type": "boolean" + }, + "use-https": { + "description": "是否使用https", + "type": "boolean" + }, + "zone": { + "description": "存储区域", + "type": "string" + } + } + }, + "config.Redis": { + "type": "object", + "properties": { + "addr": { + "description": "服务器地址:端口", + "type": "string" + }, + "db": { + "description": "redis的哪个数据库", + "type": "integer" + }, + "password": { + "description": "密码", + "type": "string" + } + } + }, + "config.Server": { + "type": "object", + "properties": { + "aliyun-oss": { + "$ref": "#/definitions/config.AliyunOSS" + }, + "autocode": { + "description": "auto", + "allOf": [ + { + "$ref": "#/definitions/config.Autocode" + } + ] + }, + "aws-s3": { + "$ref": "#/definitions/config.AwsS3" + }, + "captcha": { + "$ref": "#/definitions/config.Captcha" + }, + "cors": { + "description": "跨域配置", + "allOf": [ + { + "$ref": "#/definitions/config.CORS" + } + ] + }, + "db-list": { + "type": "array", + "items": { + "$ref": "#/definitions/config.SpecializedDB" + } + }, + "email": { + "$ref": "#/definitions/github_com_flipped-aurora_gin-vue-admin_server_config.Email" + }, + "excel": { + "$ref": "#/definitions/config.Excel" + }, + "hua-wei-obs": { + "$ref": "#/definitions/config.HuaWeiObs" + }, + "jwt": { + "$ref": "#/definitions/config.JWT" + }, + "local": { + "description": "oss", + "allOf": [ + { + "$ref": "#/definitions/config.Local" + } + ] + }, + "mssql": { + "$ref": "#/definitions/config.Mssql" + }, + "mysql": { + "description": "gorm", + "allOf": [ + { + "$ref": "#/definitions/config.Mysql" + } + ] + }, + "oracle": { + "$ref": "#/definitions/config.Oracle" + }, + "pgsql": { + "$ref": "#/definitions/config.Pgsql" + }, + "sqlite": { + "$ref": "#/definitions/config.Sqlite" + }, + "qiniu": { + "$ref": "#/definitions/config.Qiniu" + }, + "redis": { + "$ref": "#/definitions/config.Redis" + }, + "system": { + "$ref": "#/definitions/config.System" + }, + "tencent-cos": { + "$ref": "#/definitions/config.TencentCOS" + }, + "timer": { + "$ref": "#/definitions/config.Timer" + }, + "zap": { + "$ref": "#/definitions/config.Zap" + } + } + }, + "config.SpecializedDB": { + "type": "object", + "properties": { + "alias-name": { + "type": "string" + }, + "config": { + "description": "高级配置", + "type": "string" + }, + "db-name": { + "description": "数据库名", + "type": "string" + }, + "disable": { + "type": "boolean" + }, + "engine": { + "description": "数据库引擎,默认InnoDB", + "type": "string", + "default": "InnoDB" + }, + "log-mode": { + "description": "是否开启Gorm全局日志", + "type": "string" + }, + "log-zap": { + "description": "是否通过zap写入日志文件", + "type": "boolean" + }, + "max-idle-conns": { + "description": "空闲中的最大连接数", + "type": "integer" + }, + "max-open-conns": { + "description": "打开到数据库的最大连接数", + "type": "integer" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "path": { + "description": "服务器地址:端口", + "type": "string" + }, + "port": { + "description": ":端口", + "type": "string" + }, + "prefix": { + "description": "全局表前缀,单独定义TableName则不生效", + "type": "string" + }, + "singular": { + "description": "是否开启全局禁用复数,true表示开启", + "type": "boolean" + }, + "type": { + "type": "string" + }, + "username": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "config.System": { + "type": "object", + "properties": { + "addr": { + "description": "端口值", + "type": "integer" + }, + "db-type": { + "description": "数据库类型:mysql(默认)|sqlite|sqlserver|postgresql", + "type": "string" + }, + "env": { + "description": "环境值", + "type": "string" + }, + "iplimit-count": { + "type": "integer" + }, + "iplimit-time": { + "type": "integer" + }, + "oss-type": { + "description": "Oss类型", + "type": "string" + }, + "router-prefix": { + "type": "string" + }, + "use-multipoint": { + "description": "多点登录拦截", + "type": "boolean" + }, + "use-redis": { + "description": "使用redis", + "type": "boolean" + } + } + }, + "config.TencentCOS": { + "type": "object", + "properties": { + "base-url": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "path-prefix": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secret-id": { + "type": "string" + }, + "secret-key": { + "type": "string" + } + } + }, + "config.Timer": { + "type": "object", + "properties": { + "detail": { + "type": "array", + "items": { + "$ref": "#/definitions/config.Detail" + } + }, + "spec": { + "description": "CRON表达式", + "type": "string" + }, + "start": { + "description": "是否启用", + "type": "boolean" + }, + "with_seconds": { + "description": "是否精确到秒", + "type": "boolean" + } + } + }, + "config.Zap": { + "type": "object", + "properties": { + "director": { + "description": "日志文件夹", + "type": "string" + }, + "encode-level": { + "description": "编码级", + "type": "string" + }, + "format": { + "description": "输出", + "type": "string" + }, + "level": { + "description": "级别", + "type": "string" + }, + "log-in-console": { + "description": "输出控制台", + "type": "boolean" + }, + "max-age": { + "description": "日志留存时间", + "type": "integer" + }, + "prefix": { + "description": "日志前缀", + "type": "string" + }, + "show-line": { + "description": "显示行", + "type": "boolean" + }, + "stacktrace-key": { + "description": "栈名", + "type": "string" + } + } + }, + "example.ExaCustomer": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "customerName": { + "description": "客户名", + "type": "string" + }, + "customerPhoneData": { + "description": "客户手机号", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "sysUser": { + "description": "管理详情", + "allOf": [ + { + "$ref": "#/definitions/system.SysUser" + } + ] + }, + "sysUserAuthorityID": { + "description": "管理角色ID", + "type": "integer" + }, + "sysUserId": { + "description": "管理ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFile": { + "type": "object", + "properties": { + "chunkTotal": { + "type": "integer" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "exaFileChunk": { + "type": "array", + "items": { + "$ref": "#/definitions/example.ExaFileChunk" + } + }, + "fileMd5": { + "type": "string" + }, + "fileName": { + "type": "string" + }, + "filePath": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "isFinish": { + "type": "boolean" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFileChunk": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "exaFileID": { + "type": "integer" + }, + "fileChunkNumber": { + "type": "integer" + }, + "fileChunkPath": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "example.ExaFileUploadAndDownload": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "key": { + "description": "编号", + "type": "string" + }, + "name": { + "description": "文件名", + "type": "string" + }, + "tag": { + "description": "文件标签", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "url": { + "description": "文件地址", + "type": "string" + } + } + }, + "github_com_flipped-aurora_gin-vue-admin_server_config.Email": { + "type": "object", + "properties": { + "from": { + "description": "收件人", + "type": "string" + }, + "host": { + "description": "服务器地址", + "type": "string" + }, + "is-ssl": { + "description": "是否SSL", + "type": "boolean" + }, + "nickname": { + "description": "昵称", + "type": "string" + }, + "port": { + "description": "端口", + "type": "integer" + }, + "secret": { + "description": "密钥", + "type": "string" + }, + "to": { + "description": "收件人:多个以英文逗号分隔", + "type": "string" + } + } + }, + "request.AddMenuAuthorityInfo": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + }, + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + } + }, + "request.CasbinInReceive": { + "type": "object", + "properties": { + "authorityId": { + "description": "权限id", + "type": "integer" + }, + "casbinInfos": { + "type": "array", + "items": { + "$ref": "#/definitions/request.CasbinInfo" + } + } + } + }, + "request.CasbinInfo": { + "type": "object", + "properties": { + "method": { + "description": "方法", + "type": "string" + }, + "path": { + "description": "路径", + "type": "string" + } + } + }, + "request.ChangePasswordReq": { + "type": "object", + "properties": { + "newPassword": { + "description": "新密码", + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + } + } + }, + "request.Empty": { + "type": "object" + }, + "request.GetAuthorityId": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + } + } + }, + "request.GetById": { + "type": "object", + "properties": { + "id": { + "description": "主键ID", + "type": "integer" + } + } + }, + "request.IdsReq": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "request.InitDB": { + "type": "object", + "required": [ + "dbName", + "userName" + ], + "properties": { + "dbName": { + "description": "数据库名", + "type": "string" + }, + "dbType": { + "description": "数据库类型", + "type": "string" + }, + "host": { + "description": "服务器地址", + "type": "string" + }, + "password": { + "description": "数据库密码", + "type": "string" + }, + "port": { + "description": "数据库连接端口", + "type": "string" + }, + "userName": { + "description": "数据库用户名", + "type": "string" + } + } + }, + "request.Login": { + "type": "object", + "properties": { + "captcha": { + "description": "验证码", + "type": "string" + }, + "captchaId": { + "description": "验证码ID", + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, + "request.PageInfo": { + "type": "object", + "properties": { + "keyword": { + "description": "关键字", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + } + } + }, + "request.Register": { + "type": "object", + "properties": { + "authorityId": { + "type": "string", + "example": "int 角色id" + }, + "authorityIds": { + "type": "string", + "example": "[]uint 角色id" + }, + "email": { + "type": "string", + "example": "电子邮箱" + }, + "enable": { + "type": "string", + "example": "int 是否启用" + }, + "headerImg": { + "type": "string", + "example": "头像链接" + }, + "nickName": { + "type": "string", + "example": "昵称" + }, + "passWord": { + "type": "string", + "example": "密码" + }, + "phone": { + "type": "string", + "example": "电话号码" + }, + "userName": { + "type": "string", + "example": "用户名" + } + } + }, + "request.RollBack": { + "type": "object", + "properties": { + "deleteTable": { + "description": "是否删除表", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + } + } + }, + "request.SearchApiParams": { + "type": "object", + "properties": { + "apiGroup": { + "description": "api组", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "description": "排序方式:升序false(默认)|降序true", + "type": "boolean" + }, + "description": { + "description": "api中文描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "keyword": { + "description": "关键字", + "type": "string" + }, + "method": { + "description": "方法:创建POST(默认)|查看GET|更新PUT|删除DELETE", + "type": "string" + }, + "orderKey": { + "description": "排序", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + }, + "path": { + "description": "api路径", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "request.SetUserAuth": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + } + } + }, + "request.SetUserAuthorities": { + "type": "object", + "properties": { + "authorityIds": { + "description": "角色ID", + "type": "array", + "items": { + "type": "integer" + } + }, + "id": { + "type": "integer" + } + } + }, + "request.SysAuthorityBtnReq": { + "type": "object", + "properties": { + "authorityId": { + "type": "integer" + }, + "menuID": { + "type": "integer" + }, + "selected": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "request.SysAutoHistory": { + "type": "object", + "properties": { + "keyword": { + "description": "关键字", + "type": "string" + }, + "page": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页大小", + "type": "integer" + } + } + }, + "response.Email": { + "type": "object", + "properties": { + "body": { + "description": "邮件内容", + "type": "string" + }, + "subject": { + "description": "邮件标题", + "type": "string" + }, + "to": { + "description": "邮件发送给谁", + "type": "string" + } + } + }, + "response.ExaCustomerResponse": { + "type": "object", + "properties": { + "customer": { + "$ref": "#/definitions/example.ExaCustomer" + } + } + }, + "response.ExaFileResponse": { + "type": "object", + "properties": { + "file": { + "$ref": "#/definitions/example.ExaFileUploadAndDownload" + } + } + }, + "response.FilePathResponse": { + "type": "object", + "properties": { + "filePath": { + "type": "string" + } + } + }, + "response.FileResponse": { + "type": "object", + "properties": { + "file": { + "$ref": "#/definitions/example.ExaFile" + } + } + }, + "response.LoginResponse": { + "type": "object", + "properties": { + "expiresAt": { + "type": "integer" + }, + "token": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/system.SysUser" + } + } + }, + "response.PageResult": { + "type": "object", + "properties": { + "list": {}, + "page": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + }, + "total": { + "type": "integer" + } + } + }, + "response.PolicyPathResponse": { + "type": "object", + "properties": { + "paths": { + "type": "array", + "items": { + "$ref": "#/definitions/request.CasbinInfo" + } + } + } + }, + "response.Response": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": {}, + "msg": { + "type": "string" + } + } + }, + "response.SysAPIListResponse": { + "type": "object", + "properties": { + "apis": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysApi" + } + } + } + }, + "response.SysAPIResponse": { + "type": "object", + "properties": { + "api": { + "$ref": "#/definitions/system.SysApi" + } + } + }, + "response.SysAuthorityBtnRes": { + "type": "object", + "properties": { + "selected": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "response.SysAuthorityCopyResponse": { + "type": "object", + "properties": { + "authority": { + "$ref": "#/definitions/system.SysAuthority" + }, + "oldAuthorityId": { + "description": "旧角色ID", + "type": "integer" + } + } + }, + "response.SysAuthorityResponse": { + "type": "object", + "properties": { + "authority": { + "$ref": "#/definitions/system.SysAuthority" + } + } + }, + "response.SysBaseMenuResponse": { + "type": "object", + "properties": { + "menu": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + }, + "response.SysBaseMenusResponse": { + "type": "object", + "properties": { + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + } + } + }, + "response.SysCaptchaResponse": { + "type": "object", + "properties": { + "captchaId": { + "type": "string" + }, + "captchaLength": { + "type": "integer" + }, + "openCaptcha": { + "type": "boolean" + }, + "picPath": { + "type": "string" + } + } + }, + "response.SysConfigResponse": { + "type": "object", + "properties": { + "config": { + "$ref": "#/definitions/config.Server" + } + } + }, + "response.SysMenusResponse": { + "type": "object", + "properties": { + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysMenu" + } + } + } + }, + "response.SysUserResponse": { + "type": "object", + "properties": { + "user": { + "$ref": "#/definitions/system.SysUser" + } + } + }, + "system.AutoCodeStruct": { + "type": "object", + "properties": { + "abbreviation": { + "description": "Struct简称", + "type": "string" + }, + "autoCreateApiToSql": { + "description": "是否自动创建api", + "type": "boolean" + }, + "autoCreateResource": { + "description": "是否自动创建资源标识", + "type": "boolean" + }, + "autoMoveFile": { + "description": "是否自动移动文件", + "type": "boolean" + }, + "businessDB": { + "description": "业务数据库", + "type": "string" + }, + "description": { + "description": "Struct中文名称", + "type": "string" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/definitions/system.Field" + } + }, + "hasTimer": { + "type": "boolean" + }, + "humpPackageName": { + "description": "go文件名称", + "type": "string" + }, + "package": { + "type": "string" + }, + "packageName": { + "description": "文件名称", + "type": "string" + }, + "structName": { + "description": "Struct名称", + "type": "string" + }, + "tableName": { + "description": "表名", + "type": "string" + } + } + }, + "system.Field": { + "type": "object", + "properties": { + "clearable": { + "description": "是否可清空", + "type": "boolean" + }, + "columnName": { + "description": "数据库字段", + "type": "string" + }, + "comment": { + "description": "数据库字段描述", + "type": "string" + }, + "dataTypeLong": { + "description": "数据库字段长度", + "type": "string" + }, + "dictType": { + "description": "字典", + "type": "string" + }, + "errorText": { + "description": "校验失败文字", + "type": "string" + }, + "fieldDesc": { + "description": "中文名", + "type": "string" + }, + "fieldJson": { + "description": "FieldJson", + "type": "string" + }, + "fieldName": { + "description": "Field名", + "type": "string" + }, + "fieldSearchType": { + "description": "搜索条件", + "type": "string" + }, + "fieldType": { + "description": "Field数据类型", + "type": "string" + }, + "require": { + "description": "是否必填", + "type": "boolean" + }, + "sort": { + "description": "是否增加排序", + "type": "boolean" + } + } + }, + "system.Meta": { + "type": "object", + "properties": { + "activeName": { + "type": "string" + }, + "closeTab": { + "description": "自动关闭tab", + "type": "boolean" + }, + "defaultMenu": { + "description": "是否是基础路由(开发中)", + "type": "boolean" + }, + "icon": { + "description": "菜单图标", + "type": "string" + }, + "keepAlive": { + "description": "是否缓存", + "type": "boolean" + }, + "title": { + "description": "菜单名", + "type": "string" + } + } + }, + "system.SysApi": { + "type": "object", + "properties": { + "apiGroup": { + "description": "api组", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "description": { + "description": "api中文描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "method": { + "description": "方法:创建POST(默认)|查看GET|更新PUT|删除DELETE", + "type": "string" + }, + "path": { + "description": "api路径", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysAuthority": { + "type": "object", + "properties": { + "authorityId": { + "description": "角色ID", + "type": "integer" + }, + "authorityName": { + "description": "角色名", + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "dataAuthorityId": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "defaultRouter": { + "description": "默认菜单(默认dashboard)", + "type": "string" + }, + "deletedAt": { + "type": "string" + }, + "menus": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + }, + "parentId": { + "description": "父角色ID", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysAutoCode": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "label": { + "type": "string" + }, + "packageName": { + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenu": { + "type": "object", + "properties": { + "authoritys": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenu" + } + }, + "component": { + "description": "对应前端文件路径", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "hidden": { + "description": "是否在列表隐藏", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "menuBtn": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuBtn" + } + }, + "meta": { + "description": "附加属性", + "allOf": [ + { + "$ref": "#/definitions/system.Meta" + } + ] + }, + "name": { + "description": "路由name", + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuParameter" + } + }, + "parentId": { + "description": "父菜单ID", + "type": "string" + }, + "path": { + "description": "路由path", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenuBtn": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "name": { + "type": "string" + }, + "sysBaseMenuID": { + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysBaseMenuParameter": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "key": { + "description": "地址栏携带参数的key", + "type": "string" + }, + "sysBaseMenuID": { + "type": "integer" + }, + "type": { + "description": "地址栏携带参数为params还是query", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "value": { + "description": "地址栏携带参数的值", + "type": "string" + } + } + }, + "system.SysDictionary": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "desc": { + "description": "描述", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "name": { + "description": "字典名(中)", + "type": "string" + }, + "status": { + "description": "状态", + "type": "boolean" + }, + "sysDictionaryDetails": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysDictionaryDetail" + } + }, + "type": { + "description": "字典名(英)", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysDictionaryDetail": { + "type": "object", + "properties": { + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "label": { + "description": "展示值", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "status": { + "description": "启用状态", + "type": "boolean" + }, + "sysDictionaryID": { + "description": "关联标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "value": { + "description": "字典值", + "type": "integer" + } + } + }, + "system.SysMenu": { + "type": "object", + "properties": { + "authoritys": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "btns": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysMenu" + } + }, + "component": { + "description": "对应前端文件路径", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "hidden": { + "description": "是否在列表隐藏", + "type": "boolean" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "menuBtn": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuBtn" + } + }, + "menuId": { + "type": "string" + }, + "meta": { + "description": "附加属性", + "allOf": [ + { + "$ref": "#/definitions/system.Meta" + } + ] + }, + "name": { + "description": "路由name", + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysBaseMenuParameter" + } + }, + "parentId": { + "description": "父菜单ID", + "type": "string" + }, + "path": { + "description": "路由path", + "type": "string" + }, + "sort": { + "description": "排序标记", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + } + } + }, + "system.SysOperationRecord": { + "type": "object", + "properties": { + "agent": { + "description": "代理", + "type": "string" + }, + "body": { + "description": "请求Body", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "error_message": { + "description": "错误信息", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "ip": { + "description": "请求ip", + "type": "string" + }, + "latency": { + "description": "延迟", + "type": "string" + }, + "method": { + "description": "请求方法", + "type": "string" + }, + "path": { + "description": "请求路径", + "type": "string" + }, + "resp": { + "description": "响应Body", + "type": "string" + }, + "status": { + "description": "请求状态", + "type": "integer" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "user": { + "$ref": "#/definitions/system.SysUser" + }, + "user_id": { + "description": "用户id", + "type": "integer" + } + } + }, + "system.SysUser": { + "type": "object", + "properties": { + "activeColor": { + "description": "活跃颜色", + "type": "string" + }, + "authorities": { + "type": "array", + "items": { + "$ref": "#/definitions/system.SysAuthority" + } + }, + "authority": { + "$ref": "#/definitions/system.SysAuthority" + }, + "authorityId": { + "description": "用户角色ID", + "type": "integer" + }, + "baseColor": { + "description": "基础颜色", + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "email": { + "description": "用户邮箱", + "type": "string" + }, + "enable": { + "description": "用户是否被冻结 1正常 2冻结", + "type": "integer" + }, + "headerImg": { + "description": "用户头像", + "type": "string" + }, + "id": { + "description": "主键ID", + "type": "integer" + }, + "nickName": { + "description": "用户昵称", + "type": "string" + }, + "phone": { + "description": "用户手机号", + "type": "string" + }, + "sideMode": { + "description": "用户侧边主题", + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "userName": { + "description": "用户登录名", + "type": "string" + }, + "uuid": { + "description": "用户UUID", + "type": "string" + } + } + }, + "system.System": { + "type": "object", + "properties": { + "config": { + "$ref": "#/definitions/config.Server" + } + } + } + }, + "securityDefinitions": { + "ApiKeyAuth": { + "type": "apiKey", + "name": "x-token", + "in": "header" + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..4f1a697 --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,4196 @@ +definitions: + config.AliyunOSS: + properties: + access-key-id: + type: string + access-key-secret: + type: string + base-path: + type: string + bucket-name: + type: string + bucket-url: + type: string + endpoint: + type: string + type: object + config.Autocode: + properties: + root: + type: string + server: + type: string + server-api: + type: string + server-initialize: + type: string + server-model: + type: string + server-plug: + type: string + server-request: + type: string + server-router: + type: string + server-service: + type: string + transfer-restart: + type: boolean + web: + type: string + web-api: + type: string + web-form: + type: string + web-table: + type: string + type: object + config.AwsS3: + properties: + base-url: + type: string + bucket: + type: string + disable-ssl: + type: boolean + endpoint: + type: string + path-prefix: + type: string + region: + type: string + s3-force-path-style: + type: boolean + secret-id: + type: string + secret-key: + type: string + type: object + config.CORS: + properties: + mode: + type: string + whitelist: + items: + $ref: '#/definitions/config.CORSWhitelist' + type: array + type: object + config.CORSWhitelist: + properties: + allow-credentials: + type: boolean + allow-headers: + type: string + allow-methods: + type: string + allow-origin: + type: string + expose-headers: + type: string + type: object + config.Captcha: + properties: + img-height: + description: 验证码高度 + type: integer + img-width: + description: 验证码宽度 + type: integer + key-long: + description: 验证码长度 + type: integer + open-captcha: + description: 防爆破验证码开启此数,0代表每次登录都需要验证码,其他数字代表错误密码此数,如3代表错误三次后出现验证码 + type: integer + open-captcha-timeout: + description: 防爆破验证码超时时间,单位:s(秒) + type: integer + type: object + config.Detail: + properties: + compareField: + description: 需要比较时间的字段 + type: string + interval: + description: 时间间隔 + type: string + tableName: + description: 需要清理的表名 + type: string + type: object + config.Excel: + properties: + dir: + type: string + type: object + config.HuaWeiObs: + properties: + access-key: + type: string + bucket: + type: string + endpoint: + type: string + path: + type: string + secret-key: + type: string + type: object + config.JWT: + properties: + buffer-time: + description: 缓冲时间 + type: string + expires-time: + description: 过期时间 + type: string + issuer: + description: 签发者 + type: string + signing-key: + description: jwt签名 + type: string + type: object + config.Local: + properties: + path: + description: 本地文件访问路径 + type: string + store-path: + description: 本地文件存储路径 + type: string + type: object + config.Mssql: + properties: + config: + description: 高级配置 + type: string + db-name: + description: 数据库名 + type: string + engine: + default: InnoDB + description: 数据库引擎,默认InnoDB + type: string + log-mode: + description: 是否开启Gorm全局日志 + type: string + log-zap: + description: 是否通过zap写入日志文件 + type: boolean + max-idle-conns: + description: 空闲中的最大连接数 + type: integer + max-open-conns: + description: 打开到数据库的最大连接数 + type: integer + password: + description: 数据库密码 + type: string + path: + description: 服务器地址:端口 + type: string + port: + description: :端口 + type: string + prefix: + description: 全局表前缀,单独定义TableName则不生效 + type: string + singular: + description: 是否开启全局禁用复数,true表示开启 + type: boolean + username: + description: 数据库用户名 + type: string + type: object + config.Mysql: + properties: + config: + description: 高级配置 + type: string + db-name: + description: 数据库名 + type: string + engine: + default: InnoDB + description: 数据库引擎,默认InnoDB + type: string + log-mode: + description: 是否开启Gorm全局日志 + type: string + log-zap: + description: 是否通过zap写入日志文件 + type: boolean + max-idle-conns: + description: 空闲中的最大连接数 + type: integer + max-open-conns: + description: 打开到数据库的最大连接数 + type: integer + password: + description: 数据库密码 + type: string + path: + description: 服务器地址:端口 + type: string + port: + description: :端口 + type: string + prefix: + description: 全局表前缀,单独定义TableName则不生效 + type: string + singular: + description: 是否开启全局禁用复数,true表示开启 + type: boolean + username: + description: 数据库用户名 + type: string + type: object + config.Oracle: + properties: + config: + description: 高级配置 + type: string + db-name: + description: 数据库名 + type: string + engine: + default: InnoDB + description: 数据库引擎,默认InnoDB + type: string + log-mode: + description: 是否开启Gorm全局日志 + type: string + log-zap: + description: 是否通过zap写入日志文件 + type: boolean + max-idle-conns: + description: 空闲中的最大连接数 + type: integer + max-open-conns: + description: 打开到数据库的最大连接数 + type: integer + password: + description: 数据库密码 + type: string + path: + description: 服务器地址:端口 + type: string + port: + description: :端口 + type: string + prefix: + description: 全局表前缀,单独定义TableName则不生效 + type: string + singular: + description: 是否开启全局禁用复数,true表示开启 + type: boolean + username: + description: 数据库用户名 + type: string + type: object + config.Pgsql: + properties: + config: + description: 高级配置 + type: string + db-name: + description: 数据库名 + type: string + engine: + default: InnoDB + description: 数据库引擎,默认InnoDB + type: string + log-mode: + description: 是否开启Gorm全局日志 + type: string + log-zap: + description: 是否通过zap写入日志文件 + type: boolean + max-idle-conns: + description: 空闲中的最大连接数 + type: integer + max-open-conns: + description: 打开到数据库的最大连接数 + type: integer + password: + description: 数据库密码 + type: string + path: + description: 服务器地址:端口 + type: string + port: + description: :端口 + type: string + prefix: + description: 全局表前缀,单独定义TableName则不生效 + type: string + singular: + description: 是否开启全局禁用复数,true表示开启 + type: boolean + username: + description: 数据库用户名 + type: string + type: object + config.Qiniu: + properties: + access-key: + description: 秘钥AK + type: string + bucket: + description: 空间名称 + type: string + img-path: + description: CDN加速域名 + type: string + secret-key: + description: 秘钥SK + type: string + use-cdn-domains: + description: 上传是否使用CDN上传加速 + type: boolean + use-https: + description: 是否使用https + type: boolean + zone: + description: 存储区域 + type: string + type: object + config.Redis: + properties: + addr: + description: 服务器地址:端口 + type: string + db: + description: redis的哪个数据库 + type: integer + password: + description: 密码 + type: string + type: object + config.Server: + properties: + aliyun-oss: + $ref: '#/definitions/config.AliyunOSS' + autocode: + allOf: + - $ref: '#/definitions/config.Autocode' + description: auto + aws-s3: + $ref: '#/definitions/config.AwsS3' + captcha: + $ref: '#/definitions/config.Captcha' + cors: + allOf: + - $ref: '#/definitions/config.CORS' + description: 跨域配置 + db-list: + items: + $ref: '#/definitions/config.SpecializedDB' + type: array + email: + $ref: '#/definitions/github_com_flipped-aurora_gin-vue-admin_server_config.Email' + excel: + $ref: '#/definitions/config.Excel' + hua-wei-obs: + $ref: '#/definitions/config.HuaWeiObs' + jwt: + $ref: '#/definitions/config.JWT' + local: + allOf: + - $ref: '#/definitions/config.Local' + description: oss + mssql: + $ref: '#/definitions/config.Mssql' + mysql: + allOf: + - $ref: '#/definitions/config.Mysql' + description: gorm + oracle: + $ref: '#/definitions/config.Oracle' + pgsql: + $ref: '#/definitions/config.Pgsql' + qiniu: + $ref: '#/definitions/config.Qiniu' + redis: + $ref: '#/definitions/config.Redis' + system: + $ref: '#/definitions/config.System' + tencent-cos: + $ref: '#/definitions/config.TencentCOS' + timer: + $ref: '#/definitions/config.Timer' + zap: + $ref: '#/definitions/config.Zap' + type: object + config.SpecializedDB: + properties: + alias-name: + type: string + config: + description: 高级配置 + type: string + db-name: + description: 数据库名 + type: string + disable: + type: boolean + engine: + default: InnoDB + description: 数据库引擎,默认InnoDB + type: string + log-mode: + description: 是否开启Gorm全局日志 + type: string + log-zap: + description: 是否通过zap写入日志文件 + type: boolean + max-idle-conns: + description: 空闲中的最大连接数 + type: integer + max-open-conns: + description: 打开到数据库的最大连接数 + type: integer + password: + description: 数据库密码 + type: string + path: + description: 服务器地址:端口 + type: string + port: + description: :端口 + type: string + prefix: + description: 全局表前缀,单独定义TableName则不生效 + type: string + singular: + description: 是否开启全局禁用复数,true表示开启 + type: boolean + type: + type: string + username: + description: 数据库用户名 + type: string + type: object + config.System: + properties: + addr: + description: 端口值 + type: integer + db-type: + description: 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql + type: string + env: + description: 环境值 + type: string + iplimit-count: + type: integer + iplimit-time: + type: integer + oss-type: + description: Oss类型 + type: string + router-prefix: + type: string + use-multipoint: + description: 多点登录拦截 + type: boolean + use-redis: + description: 使用redis + type: boolean + type: object + config.TencentCOS: + properties: + base-url: + type: string + bucket: + type: string + path-prefix: + type: string + region: + type: string + secret-id: + type: string + secret-key: + type: string + type: object + config.Timer: + properties: + detail: + items: + $ref: '#/definitions/config.Detail' + type: array + spec: + description: CRON表达式 + type: string + start: + description: 是否启用 + type: boolean + with_seconds: + description: 是否精确到秒 + type: boolean + type: object + config.Zap: + properties: + director: + description: 日志文件夹 + type: string + encode-level: + description: 编码级 + type: string + format: + description: 输出 + type: string + level: + description: 级别 + type: string + log-in-console: + description: 输出控制台 + type: boolean + max-age: + description: 日志留存时间 + type: integer + prefix: + description: 日志前缀 + type: string + show-line: + description: 显示行 + type: boolean + stacktrace-key: + description: 栈名 + type: string + type: object + example.ExaCustomer: + properties: + createdAt: + description: 创建时间 + type: string + customerName: + description: 客户名 + type: string + customerPhoneData: + description: 客户手机号 + type: string + id: + description: 主键ID + type: integer + sysUser: + allOf: + - $ref: '#/definitions/system.SysUser' + description: 管理详情 + sysUserAuthorityID: + description: 管理角色ID + type: integer + sysUserId: + description: 管理ID + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + example.ExaFile: + properties: + chunkTotal: + type: integer + createdAt: + description: 创建时间 + type: string + exaFileChunk: + items: + $ref: '#/definitions/example.ExaFileChunk' + type: array + fileMd5: + type: string + fileName: + type: string + filePath: + type: string + id: + description: 主键ID + type: integer + isFinish: + type: boolean + updatedAt: + description: 更新时间 + type: string + type: object + example.ExaFileChunk: + properties: + createdAt: + description: 创建时间 + type: string + exaFileID: + type: integer + fileChunkNumber: + type: integer + fileChunkPath: + type: string + id: + description: 主键ID + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + example.ExaFileUploadAndDownload: + properties: + createdAt: + description: 创建时间 + type: string + id: + description: 主键ID + type: integer + key: + description: 编号 + type: string + name: + description: 文件名 + type: string + tag: + description: 文件标签 + type: string + updatedAt: + description: 更新时间 + type: string + url: + description: 文件地址 + type: string + type: object + github_com_flipped-aurora_gin-vue-admin_server_config.Email: + properties: + from: + description: 收件人 + type: string + host: + description: 服务器地址 + type: string + is-ssl: + description: 是否SSL + type: boolean + nickname: + description: 昵称 + type: string + port: + description: 端口 + type: integer + secret: + description: 密钥 + type: string + to: + description: 收件人:多个以英文逗号分隔 + type: string + type: object + request.AddMenuAuthorityInfo: + properties: + authorityId: + description: 角色ID + type: integer + menus: + items: + $ref: '#/definitions/system.SysBaseMenu' + type: array + type: object + request.CasbinInReceive: + properties: + authorityId: + description: 权限id + type: integer + casbinInfos: + items: + $ref: '#/definitions/request.CasbinInfo' + type: array + type: object + request.CasbinInfo: + properties: + method: + description: 方法 + type: string + path: + description: 路径 + type: string + type: object + request.ChangePasswordReq: + properties: + newPassword: + description: 新密码 + type: string + password: + description: 密码 + type: string + type: object + request.Empty: + type: object + request.GetAuthorityId: + properties: + authorityId: + description: 角色ID + type: integer + type: object + request.GetById: + properties: + id: + description: 主键ID + type: integer + type: object + request.IdsReq: + properties: + ids: + items: + type: integer + type: array + type: object + request.InitDB: + properties: + dbName: + description: 数据库名 + type: string + dbType: + description: 数据库类型 + type: string + host: + description: 服务器地址 + type: string + password: + description: 数据库密码 + type: string + port: + description: 数据库连接端口 + type: string + userName: + description: 数据库用户名 + type: string + required: + - dbName + - userName + type: object + request.Login: + properties: + captcha: + description: 验证码 + type: string + captchaId: + description: 验证码ID + type: string + password: + description: 密码 + type: string + username: + description: 用户名 + type: string + type: object + request.PageInfo: + properties: + keyword: + description: 关键字 + type: string + page: + description: 页码 + type: integer + pageSize: + description: 每页大小 + type: integer + type: object + request.Register: + properties: + authorityId: + example: int 角色id + type: string + authorityIds: + example: '[]uint 角色id' + type: string + email: + example: 电子邮箱 + type: string + enable: + example: int 是否启用 + type: string + headerImg: + example: 头像链接 + type: string + nickName: + example: 昵称 + type: string + passWord: + example: 密码 + type: string + phone: + example: 电话号码 + type: string + userName: + example: 用户名 + type: string + type: object + request.RollBack: + properties: + deleteTable: + description: 是否删除表 + type: boolean + id: + description: 主键ID + type: integer + type: object + request.SearchApiParams: + properties: + apiGroup: + description: api组 + type: string + createdAt: + description: 创建时间 + type: string + desc: + description: 排序方式:升序false(默认)|降序true + type: boolean + description: + description: api中文描述 + type: string + id: + description: 主键ID + type: integer + keyword: + description: 关键字 + type: string + method: + description: 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE + type: string + orderKey: + description: 排序 + type: string + page: + description: 页码 + type: integer + pageSize: + description: 每页大小 + type: integer + path: + description: api路径 + type: string + updatedAt: + description: 更新时间 + type: string + type: object + request.SetUserAuth: + properties: + authorityId: + description: 角色ID + type: integer + type: object + request.SetUserAuthorities: + properties: + authorityIds: + description: 角色ID + items: + type: integer + type: array + id: + type: integer + type: object + request.SysAuthorityBtnReq: + properties: + authorityId: + type: integer + menuID: + type: integer + selected: + items: + type: integer + type: array + type: object + request.SysAutoHistory: + properties: + keyword: + description: 关键字 + type: string + page: + description: 页码 + type: integer + pageSize: + description: 每页大小 + type: integer + type: object + response.Email: + properties: + body: + description: 邮件内容 + type: string + subject: + description: 邮件标题 + type: string + to: + description: 邮件发送给谁 + type: string + type: object + response.ExaCustomerResponse: + properties: + customer: + $ref: '#/definitions/example.ExaCustomer' + type: object + response.ExaFileResponse: + properties: + file: + $ref: '#/definitions/example.ExaFileUploadAndDownload' + type: object + response.FilePathResponse: + properties: + filePath: + type: string + type: object + response.FileResponse: + properties: + file: + $ref: '#/definitions/example.ExaFile' + type: object + response.LoginResponse: + properties: + expiresAt: + type: integer + token: + type: string + user: + $ref: '#/definitions/system.SysUser' + type: object + response.PageResult: + properties: + list: {} + page: + type: integer + pageSize: + type: integer + total: + type: integer + type: object + response.PolicyPathResponse: + properties: + paths: + items: + $ref: '#/definitions/request.CasbinInfo' + type: array + type: object + response.Response: + properties: + code: + type: integer + data: {} + msg: + type: string + type: object + response.SysAPIListResponse: + properties: + apis: + items: + $ref: '#/definitions/system.SysApi' + type: array + type: object + response.SysAPIResponse: + properties: + api: + $ref: '#/definitions/system.SysApi' + type: object + response.SysAuthorityBtnRes: + properties: + selected: + items: + type: integer + type: array + type: object + response.SysAuthorityCopyResponse: + properties: + authority: + $ref: '#/definitions/system.SysAuthority' + oldAuthorityId: + description: 旧角色ID + type: integer + type: object + response.SysAuthorityResponse: + properties: + authority: + $ref: '#/definitions/system.SysAuthority' + type: object + response.SysBaseMenuResponse: + properties: + menu: + $ref: '#/definitions/system.SysBaseMenu' + type: object + response.SysBaseMenusResponse: + properties: + menus: + items: + $ref: '#/definitions/system.SysBaseMenu' + type: array + type: object + response.SysCaptchaResponse: + properties: + captchaId: + type: string + captchaLength: + type: integer + openCaptcha: + type: boolean + picPath: + type: string + type: object + response.SysConfigResponse: + properties: + config: + $ref: '#/definitions/config.Server' + type: object + response.SysMenusResponse: + properties: + menus: + items: + $ref: '#/definitions/system.SysMenu' + type: array + type: object + response.SysUserResponse: + properties: + user: + $ref: '#/definitions/system.SysUser' + type: object + system.AutoCodeStruct: + properties: + abbreviation: + description: Struct简称 + type: string + autoCreateApiToSql: + description: 是否自动创建api + type: boolean + autoCreateResource: + description: 是否自动创建资源标识 + type: boolean + autoMoveFile: + description: 是否自动移动文件 + type: boolean + businessDB: + description: 业务数据库 + type: string + description: + description: Struct中文名称 + type: string + fields: + items: + $ref: '#/definitions/system.Field' + type: array + hasTimer: + type: boolean + humpPackageName: + description: go文件名称 + type: string + package: + type: string + packageName: + description: 文件名称 + type: string + structName: + description: Struct名称 + type: string + tableName: + description: 表名 + type: string + type: object + system.Field: + properties: + clearable: + description: 是否可清空 + type: boolean + columnName: + description: 数据库字段 + type: string + comment: + description: 数据库字段描述 + type: string + dataTypeLong: + description: 数据库字段长度 + type: string + dictType: + description: 字典 + type: string + errorText: + description: 校验失败文字 + type: string + fieldDesc: + description: 中文名 + type: string + fieldJson: + description: FieldJson + type: string + fieldName: + description: Field名 + type: string + fieldSearchType: + description: 搜索条件 + type: string + fieldType: + description: Field数据类型 + type: string + require: + description: 是否必填 + type: boolean + sort: + description: 是否增加排序 + type: boolean + type: object + system.Meta: + properties: + activeName: + type: string + closeTab: + description: 自动关闭tab + type: boolean + defaultMenu: + description: 是否是基础路由(开发中) + type: boolean + icon: + description: 菜单图标 + type: string + keepAlive: + description: 是否缓存 + type: boolean + title: + description: 菜单名 + type: string + type: object + system.SysApi: + properties: + apiGroup: + description: api组 + type: string + createdAt: + description: 创建时间 + type: string + description: + description: api中文描述 + type: string + id: + description: 主键ID + type: integer + method: + description: 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE + type: string + path: + description: api路径 + type: string + updatedAt: + description: 更新时间 + type: string + type: object + system.SysAuthority: + properties: + authorityId: + description: 角色ID + type: integer + authorityName: + description: 角色名 + type: string + children: + items: + $ref: '#/definitions/system.SysAuthority' + type: array + createdAt: + description: 创建时间 + type: string + dataAuthorityId: + items: + $ref: '#/definitions/system.SysAuthority' + type: array + defaultRouter: + description: 默认菜单(默认dashboard) + type: string + deletedAt: + type: string + menus: + items: + $ref: '#/definitions/system.SysBaseMenu' + type: array + parentId: + description: 父角色ID + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + system.SysAutoCode: + properties: + createdAt: + description: 创建时间 + type: string + desc: + type: string + id: + description: 主键ID + type: integer + label: + type: string + packageName: + type: string + updatedAt: + description: 更新时间 + type: string + type: object + system.SysBaseMenu: + properties: + authoritys: + items: + $ref: '#/definitions/system.SysAuthority' + type: array + children: + items: + $ref: '#/definitions/system.SysBaseMenu' + type: array + component: + description: 对应前端文件路径 + type: string + createdAt: + description: 创建时间 + type: string + hidden: + description: 是否在列表隐藏 + type: boolean + id: + description: 主键ID + type: integer + menuBtn: + items: + $ref: '#/definitions/system.SysBaseMenuBtn' + type: array + meta: + allOf: + - $ref: '#/definitions/system.Meta' + description: 附加属性 + name: + description: 路由name + type: string + parameters: + items: + $ref: '#/definitions/system.SysBaseMenuParameter' + type: array + parentId: + description: 父菜单ID + type: string + path: + description: 路由path + type: string + sort: + description: 排序标记 + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + system.SysBaseMenuBtn: + properties: + createdAt: + description: 创建时间 + type: string + desc: + type: string + id: + description: 主键ID + type: integer + name: + type: string + sysBaseMenuID: + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + system.SysBaseMenuParameter: + properties: + createdAt: + description: 创建时间 + type: string + id: + description: 主键ID + type: integer + key: + description: 地址栏携带参数的key + type: string + sysBaseMenuID: + type: integer + type: + description: 地址栏携带参数为params还是query + type: string + updatedAt: + description: 更新时间 + type: string + value: + description: 地址栏携带参数的值 + type: string + type: object + system.SysDictionary: + properties: + createdAt: + description: 创建时间 + type: string + desc: + description: 描述 + type: string + id: + description: 主键ID + type: integer + name: + description: 字典名(中) + type: string + status: + description: 状态 + type: boolean + sysDictionaryDetails: + items: + $ref: '#/definitions/system.SysDictionaryDetail' + type: array + type: + description: 字典名(英) + type: string + updatedAt: + description: 更新时间 + type: string + type: object + system.SysDictionaryDetail: + properties: + createdAt: + description: 创建时间 + type: string + id: + description: 主键ID + type: integer + label: + description: 展示值 + type: string + sort: + description: 排序标记 + type: integer + status: + description: 启用状态 + type: boolean + sysDictionaryID: + description: 关联标记 + type: integer + updatedAt: + description: 更新时间 + type: string + value: + description: 字典值 + type: integer + type: object + system.SysMenu: + properties: + authoritys: + items: + $ref: '#/definitions/system.SysAuthority' + type: array + btns: + additionalProperties: + type: integer + type: object + children: + items: + $ref: '#/definitions/system.SysMenu' + type: array + component: + description: 对应前端文件路径 + type: string + createdAt: + description: 创建时间 + type: string + hidden: + description: 是否在列表隐藏 + type: boolean + id: + description: 主键ID + type: integer + menuBtn: + items: + $ref: '#/definitions/system.SysBaseMenuBtn' + type: array + menuId: + type: string + meta: + allOf: + - $ref: '#/definitions/system.Meta' + description: 附加属性 + name: + description: 路由name + type: string + parameters: + items: + $ref: '#/definitions/system.SysBaseMenuParameter' + type: array + parentId: + description: 父菜单ID + type: string + path: + description: 路由path + type: string + sort: + description: 排序标记 + type: integer + updatedAt: + description: 更新时间 + type: string + type: object + system.SysOperationRecord: + properties: + agent: + description: 代理 + type: string + body: + description: 请求Body + type: string + createdAt: + description: 创建时间 + type: string + error_message: + description: 错误信息 + type: string + id: + description: 主键ID + type: integer + ip: + description: 请求ip + type: string + latency: + description: 延迟 + type: string + method: + description: 请求方法 + type: string + path: + description: 请求路径 + type: string + resp: + description: 响应Body + type: string + status: + description: 请求状态 + type: integer + updatedAt: + description: 更新时间 + type: string + user: + $ref: '#/definitions/system.SysUser' + user_id: + description: 用户id + type: integer + type: object + system.SysUser: + properties: + activeColor: + description: 活跃颜色 + type: string + authorities: + items: + $ref: '#/definitions/system.SysAuthority' + type: array + authority: + $ref: '#/definitions/system.SysAuthority' + authorityId: + description: 用户角色ID + type: integer + baseColor: + description: 基础颜色 + type: string + createdAt: + description: 创建时间 + type: string + email: + description: 用户邮箱 + type: string + enable: + description: 用户是否被冻结 1正常 2冻结 + type: integer + headerImg: + description: 用户头像 + type: string + id: + description: 主键ID + type: integer + nickName: + description: 用户昵称 + type: string + phone: + description: 用户手机号 + type: string + sideMode: + description: 用户侧边主题 + type: string + updatedAt: + description: 更新时间 + type: string + userName: + description: 用户登录名 + type: string + uuid: + description: 用户UUID + type: string + type: object + system.System: + properties: + config: + $ref: '#/definitions/config.Server' + type: object +info: + contact: {} + description: This is a sample Server pets + title: Swagger Example API + version: 0.0.1 +paths: + /api/createApi: + post: + consumes: + - application/json + parameters: + - description: api路径, api中文描述, api组, 方法 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysApi' + produces: + - application/json + responses: + "200": + description: 创建基础api + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建基础api + tags: + - SysApi + /api/deleteApi: + post: + consumes: + - application/json + parameters: + - description: ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysApi' + produces: + - application/json + responses: + "200": + description: 删除api + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除api + tags: + - SysApi + /api/deleteApisByIds: + delete: + consumes: + - application/json + parameters: + - description: ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.IdsReq' + produces: + - application/json + responses: + "200": + description: 删除选中Api + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除选中Api + tags: + - SysApi + /api/freshCasbin: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 刷新成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + summary: 刷新casbin缓存 + tags: + - SysApi + /api/getAllApis: + post: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 获取所有的Api 不分页,返回包括api列表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAPIListResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取所有的Api 不分页 + tags: + - SysApi + /api/getApiById: + post: + consumes: + - application/json + parameters: + - description: 根据id获取api + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 根据id获取api,返回包括api详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAPIResponse' + type: object + security: + - ApiKeyAuth: [] + summary: 根据id获取api + tags: + - SysApi + /api/getApiList: + post: + consumes: + - application/json + parameters: + - description: 分页获取API列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SearchApiParams' + produces: + - application/json + responses: + "200": + description: 分页获取API列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取API列表 + tags: + - SysApi + /api/updateApi: + post: + consumes: + - application/json + parameters: + - description: api路径, api中文描述, api组, 方法 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysApi' + produces: + - application/json + responses: + "200": + description: 修改基础api + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 修改基础api + tags: + - SysApi + /authority/copyAuthority: + post: + consumes: + - application/json + parameters: + - description: 旧角色id, 新权限id, 新权限名, 新父角色id + in: body + name: data + required: true + schema: + $ref: '#/definitions/response.SysAuthorityCopyResponse' + produces: + - application/json + responses: + "200": + description: 拷贝角色,返回包括系统角色详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAuthorityResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 拷贝角色 + tags: + - Authority + /authority/createAuthority: + post: + consumes: + - application/json + parameters: + - description: 权限id, 权限名, 父角色id + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAuthority' + produces: + - application/json + responses: + "200": + description: 创建角色,返回包括系统角色详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAuthorityResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建角色 + tags: + - Authority + /authority/deleteAuthority: + post: + consumes: + - application/json + parameters: + - description: 删除角色 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAuthority' + produces: + - application/json + responses: + "200": + description: 删除角色 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除角色 + tags: + - Authority + /authority/getAuthorityList: + post: + consumes: + - application/json + parameters: + - description: 页码, 每页大小 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.PageInfo' + produces: + - application/json + responses: + "200": + description: 分页获取角色列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取角色列表 + tags: + - Authority + /authority/setDataAuthority: + post: + consumes: + - application/json + parameters: + - description: 设置角色资源权限 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAuthority' + produces: + - application/json + responses: + "200": + description: 设置角色资源权限 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置角色资源权限 + tags: + - Authority + /authority/updateAuthority: + post: + consumes: + - application/json + parameters: + - description: 权限id, 权限名, 父角色id + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAuthority' + produces: + - application/json + responses: + "200": + description: 更新角色信息,返回包括系统角色详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAuthorityResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新角色信息 + tags: + - Authority + /authorityBtn/canRemoveAuthorityBtn: + post: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 删除成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置权限按钮 + tags: + - AuthorityBtn + /authorityBtn/getAuthorityBtn: + post: + consumes: + - application/json + parameters: + - description: 菜单id, 角色id, 选中的按钮id + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SysAuthorityBtnReq' + produces: + - application/json + responses: + "200": + description: 返回列表成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysAuthorityBtnRes' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取权限按钮 + tags: + - AuthorityBtn + /authorityBtn/setAuthorityBtn: + post: + consumes: + - application/json + parameters: + - description: 菜单id, 角色id, 选中的按钮id + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SysAuthorityBtnReq' + produces: + - application/json + responses: + "200": + description: 返回列表成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置权限按钮 + tags: + - AuthorityBtn + /autoCode/createPackage: + post: + consumes: + - application/json + parameters: + - description: 创建package + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAutoCode' + produces: + - application/json + responses: + "200": + description: 创建package成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建package + tags: + - AutoCode + /autoCode/createPlug: + post: + consumes: + - multipart/form-data + parameters: + - description: this is a test file + in: formData + name: plug + required: true + type: file + produces: + - application/json + responses: + "200": + description: 安装插件成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + items: + type: object + type: array + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 安装插件 + tags: + - AutoCode + /autoCode/createTemp: + post: + consumes: + - application/json + parameters: + - description: 创建自动代码 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.AutoCodeStruct' + produces: + - application/json + responses: + "200": + description: '{"success":true,"data":{},"msg":"创建成功"}' + schema: + type: string + security: + - ApiKeyAuth: [] + summary: 自动代码模板 + tags: + - AutoCode + /autoCode/delPackage: + post: + consumes: + - application/json + parameters: + - description: 创建package + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysAutoCode' + produces: + - application/json + responses: + "200": + description: 删除package成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除package + tags: + - AutoCode + /autoCode/delSysHistory: + post: + consumes: + - application/json + parameters: + - description: 请求参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 删除回滚记录 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除回滚记录 + tags: + - AutoCode + /autoCode/getColumn: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 获取当前表所有字段 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取当前表所有字段 + tags: + - AutoCode + /autoCode/getDatabase: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 获取当前所有数据库 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取当前所有数据库 + tags: + - AutoCode + /autoCode/getMeta: + post: + consumes: + - application/json + parameters: + - description: 请求参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 获取meta信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取meta信息 + tags: + - AutoCode + /autoCode/getPackage: + post: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 创建package成功 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取package + tags: + - AutoCode + /autoCode/getSysHistory: + post: + consumes: + - application/json + parameters: + - description: 请求参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SysAutoHistory' + produces: + - application/json + responses: + "200": + description: 查询回滚记录,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 查询回滚记录 + tags: + - AutoCode + /autoCode/getTables: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 获取当前数据库所有表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取当前数据库所有表 + tags: + - AutoCode + /autoCode/preview: + post: + consumes: + - application/json + parameters: + - description: 预览创建代码 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.AutoCodeStruct' + produces: + - application/json + responses: + "200": + description: 预览创建后的代码 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 预览创建后的代码 + tags: + - AutoCode + /autoCode/rollback: + post: + consumes: + - application/json + parameters: + - description: 请求参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.RollBack' + produces: + - application/json + responses: + "200": + description: 回滚自动生成代码 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 回滚自动生成代码 + tags: + - AutoCode + /base/captcha: + post: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 生成验证码,返回包括随机数id,base64,验证码长度,是否开启验证码 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysCaptchaResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 生成验证码 + tags: + - Base + /base/login: + post: + parameters: + - description: 用户名, 密码, 验证码 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.Login' + produces: + - application/json + responses: + "200": + description: 返回包括用户信息,token,过期时间 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.LoginResponse' + msg: + type: string + type: object + summary: 用户登录 + tags: + - Base + /casbin/UpdateCasbin: + post: + consumes: + - application/json + parameters: + - description: 权限id, 权限模型列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.CasbinInReceive' + produces: + - application/json + responses: + "200": + description: 更新角色api权限 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新角色api权限 + tags: + - Casbin + /casbin/getPolicyPathByAuthorityId: + post: + consumes: + - application/json + parameters: + - description: 权限id, 权限模型列表 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.CasbinInReceive' + produces: + - application/json + responses: + "200": + description: 获取权限列表,返回包括casbin详情列表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PolicyPathResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取权限列表 + tags: + - Casbin + /customer/customer: + delete: + consumes: + - application/json + parameters: + - description: 客户ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/example.ExaCustomer' + produces: + - application/json + responses: + "200": + description: 删除客户 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除客户 + tags: + - ExaCustomer + get: + consumes: + - application/json + parameters: + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 客户名 + in: query + name: customerName + type: string + - description: 客户手机号 + in: query + name: customerPhoneData + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 管理角色ID + in: query + name: sysUserAuthorityID + type: integer + - description: 管理ID + in: query + name: sysUserId + type: integer + - description: 更新时间 + in: query + name: updatedAt + type: string + produces: + - application/json + responses: + "200": + description: 获取单一客户信息,返回包括客户详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.ExaCustomerResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取单一客户信息 + tags: + - ExaCustomer + post: + consumes: + - application/json + parameters: + - description: 客户用户名, 客户手机号码 + in: body + name: data + required: true + schema: + $ref: '#/definitions/example.ExaCustomer' + produces: + - application/json + responses: + "200": + description: 创建客户 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建客户 + tags: + - ExaCustomer + put: + consumes: + - application/json + parameters: + - description: 客户ID, 客户信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/example.ExaCustomer' + produces: + - application/json + responses: + "200": + description: 更新客户信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新客户信息 + tags: + - ExaCustomer + /customer/customerList: + get: + consumes: + - application/json + parameters: + - description: 关键字 + in: query + name: keyword + type: string + - description: 页码 + in: query + name: page + type: integer + - description: 每页大小 + in: query + name: pageSize + type: integer + produces: + - application/json + responses: + "200": + description: 分页获取权限客户列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取权限客户列表 + tags: + - ExaCustomer + /email/emailTest: + post: + produces: + - application/json + responses: + "200": + description: '{"success":true,"data":{},"msg":"发送成功"}' + schema: + type: string + security: + - ApiKeyAuth: [] + summary: 发送测试邮件 + tags: + - System + /email/sendEmail: + post: + parameters: + - description: 发送邮件必须的参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/response.Email' + produces: + - application/json + responses: + "200": + description: '{"success":true,"data":{},"msg":"发送成功"}' + schema: + type: string + security: + - ApiKeyAuth: [] + summary: 发送邮件 + tags: + - System + /fileUploadAndDownload/breakpointContinue: + post: + consumes: + - multipart/form-data + parameters: + - description: an example for breakpoint resume, 断点续传示例 + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: 断点续传到服务器 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 断点续传到服务器 + tags: + - ExaFileUploadAndDownload + /fileUploadAndDownload/deleteFile: + post: + parameters: + - description: 传入文件里面id即可 + in: body + name: data + required: true + schema: + $ref: '#/definitions/example.ExaFileUploadAndDownload' + produces: + - application/json + responses: + "200": + description: 删除文件 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除文件 + tags: + - ExaFileUploadAndDownload + /fileUploadAndDownload/findFile: + post: + consumes: + - multipart/form-data + parameters: + - description: 上传文件完成 + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: 创建文件,返回包括文件路径 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.FilePathResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建文件 + tags: + - ExaFileUploadAndDownload + /fileUploadAndDownload/getFileList: + post: + consumes: + - application/json + parameters: + - description: 页码, 每页大小 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.PageInfo' + produces: + - application/json + responses: + "200": + description: 分页文件列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页文件列表 + tags: + - ExaFileUploadAndDownload + /fileUploadAndDownload/removeChunk: + post: + consumes: + - multipart/form-data + parameters: + - description: 删除缓存切片 + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: 删除切片 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除切片 + tags: + - ExaFileUploadAndDownload + /fileUploadAndDownload/upload: + post: + consumes: + - multipart/form-data + parameters: + - description: 上传文件示例 + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: 上传文件示例,返回包括文件详情 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.ExaFileResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 上传文件示例 + tags: + - ExaFileUploadAndDownload + /init/checkdb: + post: + produces: + - application/json + responses: + "200": + description: 初始化用户数据库 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + summary: 初始化用户数据库 + tags: + - CheckDB + /init/initdb: + post: + parameters: + - description: 初始化数据库参数 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.InitDB' + produces: + - application/json + responses: + "200": + description: 初始化用户数据库 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + type: string + type: object + summary: 初始化用户数据库 + tags: + - InitDB + /jwt/jsonInBlacklist: + post: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: jwt加入黑名单 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: jwt加入黑名单 + tags: + - Jwt + /menu/addBaseMenu: + post: + consumes: + - application/json + parameters: + - description: 路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysBaseMenu' + produces: + - application/json + responses: + "200": + description: 新增菜单 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 新增菜单 + tags: + - Menu + /menu/addMenuAuthority: + post: + consumes: + - application/json + parameters: + - description: 角色ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.AddMenuAuthorityInfo' + produces: + - application/json + responses: + "200": + description: 增加menu和角色关联关系 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 增加menu和角色关联关系 + tags: + - AuthorityMenu + /menu/deleteBaseMenu: + post: + consumes: + - application/json + parameters: + - description: 菜单id + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 删除菜单 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除菜单 + tags: + - Menu + /menu/getBaseMenuById: + post: + consumes: + - application/json + parameters: + - description: 菜单id + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 根据id获取菜单,返回包括系统菜单列表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysBaseMenuResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 根据id获取菜单 + tags: + - Menu + /menu/getBaseMenuTree: + post: + parameters: + - description: 空 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.Empty' + produces: + - application/json + responses: + "200": + description: 获取用户动态路由,返回包括系统菜单列表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysBaseMenusResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取用户动态路由 + tags: + - AuthorityMenu + /menu/getMenu: + post: + parameters: + - description: 空 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.Empty' + produces: + - application/json + responses: + "200": + description: 获取用户动态路由,返回包括系统菜单详情列表 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysMenusResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取用户动态路由 + tags: + - AuthorityMenu + /menu/getMenuAuthority: + post: + consumes: + - application/json + parameters: + - description: 角色ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetAuthorityId' + produces: + - application/json + responses: + "200": + description: 获取指定角色menu + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取指定角色menu + tags: + - AuthorityMenu + /menu/getMenuList: + post: + consumes: + - application/json + parameters: + - description: 页码, 每页大小 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.PageInfo' + produces: + - application/json + responses: + "200": + description: 分页获取基础menu列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取基础menu列表 + tags: + - Menu + /menu/updateBaseMenu: + post: + consumes: + - application/json + parameters: + - description: 路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysBaseMenu' + produces: + - application/json + responses: + "200": + description: 更新菜单 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新菜单 + tags: + - Menu + /sysDictionary/createSysDictionary: + post: + consumes: + - application/json + parameters: + - description: SysDictionary模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionary' + produces: + - application/json + responses: + "200": + description: 创建SysDictionary + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建SysDictionary + tags: + - SysDictionary + /sysDictionary/deleteSysDictionary: + delete: + consumes: + - application/json + parameters: + - description: SysDictionary模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionary' + produces: + - application/json + responses: + "200": + description: 删除SysDictionary + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除SysDictionary + tags: + - SysDictionary + /sysDictionary/findSysDictionary: + get: + consumes: + - application/json + parameters: + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 描述 + in: query + name: desc + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 字典名(中) + in: query + name: name + type: string + - description: 状态 + in: query + name: status + type: boolean + - description: 字典名(英) + in: query + name: type + type: string + - description: 更新时间 + in: query + name: updatedAt + type: string + produces: + - application/json + responses: + "200": + description: 用id查询SysDictionary + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 用id查询SysDictionary + tags: + - SysDictionary + /sysDictionary/getSysDictionaryList: + get: + consumes: + - application/json + parameters: + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 描述 + in: query + name: desc + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 关键字 + in: query + name: keyword + type: string + - description: 字典名(中) + in: query + name: name + type: string + - description: 页码 + in: query + name: page + type: integer + - description: 每页大小 + in: query + name: pageSize + type: integer + - description: 状态 + in: query + name: status + type: boolean + - description: 字典名(英) + in: query + name: type + type: string + - description: 更新时间 + in: query + name: updatedAt + type: string + produces: + - application/json + responses: + "200": + description: 分页获取SysDictionary列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取SysDictionary列表 + tags: + - SysDictionary + /sysDictionary/updateSysDictionary: + put: + consumes: + - application/json + parameters: + - description: SysDictionary模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionary' + produces: + - application/json + responses: + "200": + description: 更新SysDictionary + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新SysDictionary + tags: + - SysDictionary + /sysDictionaryDetail/createSysDictionaryDetail: + post: + consumes: + - application/json + parameters: + - description: SysDictionaryDetail模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionaryDetail' + produces: + - application/json + responses: + "200": + description: 创建SysDictionaryDetail + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建SysDictionaryDetail + tags: + - SysDictionaryDetail + /sysDictionaryDetail/deleteSysDictionaryDetail: + delete: + consumes: + - application/json + parameters: + - description: SysDictionaryDetail模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionaryDetail' + produces: + - application/json + responses: + "200": + description: 删除SysDictionaryDetail + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除SysDictionaryDetail + tags: + - SysDictionaryDetail + /sysDictionaryDetail/findSysDictionaryDetail: + get: + consumes: + - application/json + parameters: + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 展示值 + in: query + name: label + type: string + - description: 排序标记 + in: query + name: sort + type: integer + - description: 启用状态 + in: query + name: status + type: boolean + - description: 关联标记 + in: query + name: sysDictionaryID + type: integer + - description: 更新时间 + in: query + name: updatedAt + type: string + - description: 字典值 + in: query + name: value + type: integer + produces: + - application/json + responses: + "200": + description: 用id查询SysDictionaryDetail + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 用id查询SysDictionaryDetail + tags: + - SysDictionaryDetail + /sysDictionaryDetail/getSysDictionaryDetailList: + get: + consumes: + - application/json + parameters: + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 关键字 + in: query + name: keyword + type: string + - description: 展示值 + in: query + name: label + type: string + - description: 页码 + in: query + name: page + type: integer + - description: 每页大小 + in: query + name: pageSize + type: integer + - description: 排序标记 + in: query + name: sort + type: integer + - description: 启用状态 + in: query + name: status + type: boolean + - description: 关联标记 + in: query + name: sysDictionaryID + type: integer + - description: 更新时间 + in: query + name: updatedAt + type: string + - description: 字典值 + in: query + name: value + type: integer + produces: + - application/json + responses: + "200": + description: 分页获取SysDictionaryDetail列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取SysDictionaryDetail列表 + tags: + - SysDictionaryDetail + /sysDictionaryDetail/updateSysDictionaryDetail: + put: + consumes: + - application/json + parameters: + - description: 更新SysDictionaryDetail + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysDictionaryDetail' + produces: + - application/json + responses: + "200": + description: 更新SysDictionaryDetail + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更新SysDictionaryDetail + tags: + - SysDictionaryDetail + /sysOperationRecord/createSysOperationRecord: + post: + consumes: + - application/json + parameters: + - description: 创建SysOperationRecord + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysOperationRecord' + produces: + - application/json + responses: + "200": + description: 创建SysOperationRecord + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 创建SysOperationRecord + tags: + - SysOperationRecord + /sysOperationRecord/deleteSysOperationRecord: + delete: + consumes: + - application/json + parameters: + - description: SysOperationRecord模型 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysOperationRecord' + produces: + - application/json + responses: + "200": + description: 删除SysOperationRecord + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除SysOperationRecord + tags: + - SysOperationRecord + /sysOperationRecord/deleteSysOperationRecordByIds: + delete: + consumes: + - application/json + parameters: + - description: 批量删除SysOperationRecord + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.IdsReq' + produces: + - application/json + responses: + "200": + description: 批量删除SysOperationRecord + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 批量删除SysOperationRecord + tags: + - SysOperationRecord + /sysOperationRecord/findSysOperationRecord: + get: + consumes: + - application/json + parameters: + - description: 代理 + in: query + name: agent + type: string + - description: 请求Body + in: query + name: body + type: string + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 错误信息 + in: query + name: error_message + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 请求ip + in: query + name: ip + type: string + - description: 延迟 + in: query + name: latency + type: string + - description: 请求方法 + in: query + name: method + type: string + - description: 请求路径 + in: query + name: path + type: string + - description: 响应Body + in: query + name: resp + type: string + - description: 请求状态 + in: query + name: status + type: integer + - description: 更新时间 + in: query + name: updatedAt + type: string + - description: 用户id + in: query + name: user_id + type: integer + produces: + - application/json + responses: + "200": + description: 用id查询SysOperationRecord + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 用id查询SysOperationRecord + tags: + - SysOperationRecord + /sysOperationRecord/getSysOperationRecordList: + get: + consumes: + - application/json + parameters: + - description: 代理 + in: query + name: agent + type: string + - description: 请求Body + in: query + name: body + type: string + - description: 创建时间 + in: query + name: createdAt + type: string + - description: 错误信息 + in: query + name: error_message + type: string + - description: 主键ID + in: query + name: id + type: integer + - description: 请求ip + in: query + name: ip + type: string + - description: 关键字 + in: query + name: keyword + type: string + - description: 延迟 + in: query + name: latency + type: string + - description: 请求方法 + in: query + name: method + type: string + - description: 页码 + in: query + name: page + type: integer + - description: 每页大小 + in: query + name: pageSize + type: integer + - description: 请求路径 + in: query + name: path + type: string + - description: 响应Body + in: query + name: resp + type: string + - description: 请求状态 + in: query + name: status + type: integer + - description: 更新时间 + in: query + name: updatedAt + type: string + - description: 用户id + in: query + name: user_id + type: integer + produces: + - application/json + responses: + "200": + description: 分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取SysOperationRecord列表 + tags: + - SysOperationRecord + /system/getServerInfo: + post: + produces: + - application/json + responses: + "200": + description: 获取服务器信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取服务器信息 + tags: + - System + /system/getSystemConfig: + post: + produces: + - application/json + responses: + "200": + description: 获取配置文件内容,返回包括系统配置 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysConfigResponse' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取配置文件内容 + tags: + - System + /system/reloadSystem: + post: + produces: + - application/json + responses: + "200": + description: 重启系统 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 重启系统 + tags: + - System + /system/setSystemConfig: + post: + parameters: + - description: 设置配置文件内容 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.System' + produces: + - application/json + responses: + "200": + description: 设置配置文件内容 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置配置文件内容 + tags: + - System + /user/SetSelfInfo: + put: + consumes: + - application/json + parameters: + - description: ID, 用户名, 昵称, 头像链接 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysUser' + produces: + - application/json + responses: + "200": + description: 设置用户信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置用户信息 + tags: + - SysUser + /user/admin_register: + post: + parameters: + - description: 用户名, 昵称, 密码, 角色ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.Register' + produces: + - application/json + responses: + "200": + description: 用户注册账号,返回包括用户信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.SysUserResponse' + msg: + type: string + type: object + summary: 用户注册账号 + tags: + - SysUser + /user/changePassword: + post: + parameters: + - description: 用户名, 原密码, 新密码 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.ChangePasswordReq' + produces: + - application/json + responses: + "200": + description: 用户修改密码 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 用户修改密码 + tags: + - SysUser + /user/deleteUser: + delete: + consumes: + - application/json + parameters: + - description: 用户ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.GetById' + produces: + - application/json + responses: + "200": + description: 删除用户 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 删除用户 + tags: + - SysUser + /user/getUserInfo: + get: + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: 获取用户信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 获取用户信息 + tags: + - SysUser + /user/getUserList: + post: + consumes: + - application/json + parameters: + - description: 页码, 每页大小 + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.PageInfo' + produces: + - application/json + responses: + "200": + description: 分页获取用户列表,返回包括列表,总数,页码,每页数量 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/response.PageResult' + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 分页获取用户列表 + tags: + - SysUser + /user/resetPassword: + post: + parameters: + - description: ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysUser' + produces: + - application/json + responses: + "200": + description: 重置用户密码 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 重置用户密码 + tags: + - SysUser + /user/setUserAuthorities: + post: + consumes: + - application/json + parameters: + - description: 用户UUID, 角色ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SetUserAuthorities' + produces: + - application/json + responses: + "200": + description: 设置用户权限 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置用户权限 + tags: + - SysUser + /user/setUserAuthority: + post: + consumes: + - application/json + parameters: + - description: 用户UUID, 角色ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/request.SetUserAuth' + produces: + - application/json + responses: + "200": + description: 设置用户权限 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 更改用户权限 + tags: + - SysUser + /user/setUserInfo: + put: + consumes: + - application/json + parameters: + - description: ID, 用户名, 昵称, 头像链接 + in: body + name: data + required: true + schema: + $ref: '#/definitions/system.SysUser' + produces: + - application/json + responses: + "200": + description: 设置用户信息 + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + additionalProperties: true + type: object + msg: + type: string + type: object + security: + - ApiKeyAuth: [] + summary: 设置用户信息 + tags: + - SysUser +securityDefinitions: + ApiKeyAuth: + in: header + name: x-token + type: apiKey +swagger: "2.0" diff --git a/global/global.go b/global/global.go new file mode 100644 index 0000000..85ac83c --- /dev/null +++ b/global/global.go @@ -0,0 +1,51 @@ +package global + +import ( + "sync" + + "github.com/songzhibin97/gkit/cache/local_cache" + "miniapp/utils/timer" + + "golang.org/x/sync/singleflight" + + "go.uber.org/zap" + + "miniapp/config" + + "github.com/redis/go-redis/v9" + "github.com/spf13/viper" + "gorm.io/gorm" +) + +var ( + GVA_DB *gorm.DB + GVA_DBList map[string]*gorm.DB + GVA_REDIS *redis.Client + GVA_CONFIG config.Server + GVA_VP *viper.Viper + // GVA_LOG *oplogging.Logger + GVA_LOG *zap.Logger + GVA_Timer timer.Timer = timer.NewTimerTask() + GVA_Concurrency_Control = &singleflight.Group{} + + BlackCache local_cache.Cache + lock sync.RWMutex +) + +// GetGlobalDBByDBName 通过名称获取db list中的db +func GetGlobalDBByDBName(dbname string) *gorm.DB { + lock.RLock() + defer lock.RUnlock() + return GVA_DBList[dbname] +} + +// MustGetGlobalDBByDBName 通过名称获取db 如果不存在则panic +func MustGetGlobalDBByDBName(dbname string) *gorm.DB { + lock.RLock() + defer lock.RUnlock() + db, ok := GVA_DBList[dbname] + if !ok || db == nil { + panic("db no init") + } + return db +} diff --git a/global/model.go b/global/model.go new file mode 100644 index 0000000..2a497bd --- /dev/null +++ b/global/model.go @@ -0,0 +1,14 @@ +package global + +import ( + "time" + + "gorm.io/gorm" +) + +type GVA_MODEL struct { + ID uint `gorm:"primarykey"` // 主键ID + CreatedAt time.Time // 创建时间 + UpdatedAt time.Time // 更新时间 + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间 +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8827a23 --- /dev/null +++ b/go.mod @@ -0,0 +1,145 @@ +module miniapp + +go 1.20 + +require ( + git.echol.cn/loser/logger v1.0.15 + github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible + github.com/aws/aws-sdk-go v1.44.307 + github.com/casbin/casbin/v2 v2.71.1 + github.com/casbin/gorm-adapter/v3 v3.18.0 + github.com/duke-git/lancet/v2 v2.2.7 + github.com/flipped-aurora/ws v1.0.2 + github.com/fsnotify/fsnotify v1.6.0 + github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 + github.com/gin-gonic/gin v1.9.1 + github.com/glebarez/sqlite v1.8.0 + github.com/go-oauth2/oauth2/v4 v4.5.2 + github.com/go-oauth2/redis/v4 v4.1.1 + github.com/go-redis/redis/v8 v8.11.4 + github.com/go-sql-driver/mysql v1.7.1 + github.com/gofrs/uuid/v5 v5.0.0 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/google/uuid v1.3.0 + github.com/gookit/color v1.5.4 + github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible + github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84 + github.com/medivhzhan/weapp/v3 v3.6.19 + github.com/mojocn/base64Captcha v1.3.5 + github.com/otiai10/copy v1.7.0 + github.com/pkg/errors v0.9.1 + github.com/qiniu/api.v7/v7 v7.4.1 + github.com/redis/go-redis/v9 v9.0.5 + github.com/robfig/cron/v3 v3.0.1 + github.com/sashabaranov/go-openai v1.14.1 + github.com/shirou/gopsutil/v3 v3.23.6 + github.com/songzhibin97/gkit v1.2.11 + github.com/spf13/viper v1.16.0 + github.com/stretchr/testify v1.8.4 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.1 + github.com/tencentyun/cos-go-sdk-v5 v0.7.42 + github.com/unrolled/secure v1.13.0 + go.uber.org/zap v1.24.0 + golang.org/x/crypto v0.10.0 + golang.org/x/sync v0.3.0 + golang.org/x/text v0.11.0 + gorm.io/driver/mysql v1.5.1 + gorm.io/driver/postgres v1.5.2 + gorm.io/driver/sqlserver v1.5.1 + gorm.io/gorm v1.25.2 + nhooyr.io/websocket v1.8.7 +) + +require ( + github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/clbanning/mxj v1.8.4 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/glebarez/go-sqlite v1.21.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt v3.2.1+incompatible // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.3.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/microsoft/go-mssqldb v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mozillazg/go-httpheader v0.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.4.2 // indirect + github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 // indirect + github.com/tidwall/buntdb v1.1.2 // indirect + github.com/tidwall/gjson v1.12.1 // indirect + github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e // indirect + github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 // indirect + github.com/tklauser/go-sysconf v0.3.11 // indirect + github.com/tklauser/numcpus v0.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/image v0.5.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/time v0.1.0 // indirect + golang.org/x/tools v0.9.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/plugin/dbresolver v1.4.1 // indirect + modernc.org/libc v1.24.1 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.6.0 // indirect + modernc.org/sqlite v1.23.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c34165c --- /dev/null +++ b/go.sum @@ -0,0 +1,997 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +git.echol.cn/loser/logger v1.0.15 h1:paD2Lz4WzNKs1QezLbavqdxo+/zb9cW0YRQ7/mSglgo= +git.echol.cn/loser/logger v1.0.15/go.mod h1:tc96/GAMirPcVTT/Rs6qPXrnGq9buiAR0cyL37j4ZuA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible h1:KpbJFXwhVeuxNtBJ74MCGbIoaBok2uZvkD7QXp2+Wis= +github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/aws/aws-sdk-go v1.44.307 h1:2R0/EPgpZcFSUwZhYImq/srjaOrOfLv5MNRzrFyAM38= +github.com/aws/aws-sdk-go v1.44.307/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/casbin/casbin/v2 v2.71.1 h1:LRHyqM0S1LzM/K59PmfUIN0ZJfLgcOjL4OhOQI/FNXU= +github.com/casbin/casbin/v2 v2.71.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/casbin/gorm-adapter/v3 v3.18.0 h1:0td7v030eK3H5ftXRHx1d5wVPbuYEJP2ObMSUHtA0Ek= +github.com/casbin/gorm-adapter/v3 v3.18.0/go.mod h1:ekufPNBgVIQvv9JffVGsg7KUv4DjnevTh6AQnBNkoK8= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-rendezvous v0.0.0-20200609043717-5ab96a526299/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/duke-git/lancet/v2 v2.2.7 h1:u9zr6HR+MDUvZEtTlAFtSTIgZfEFsN7cKi27n5weZsw= +github.com/duke-git/lancet/v2 v2.2.7/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +miniapp v0.0.0-20231010105746-b3dbb8d4be1f h1:sbAmzjFAivP+AJI8GK4hE/5XS99uW1BoVNRgN6TVbtM= +miniapp v0.0.0-20231010105746-b3dbb8d4be1f/go.mod h1:+F/ve48KKaHY2PUejjziInYtC7VKMafUrd7KomJuw5c= +github.com/flipped-aurora/ws v1.0.2 h1:oEUz7sgrbPENvgli7Q4QpC0NIEbJucgR4yjcDMg/AjY= +github.com/flipped-aurora/ws v1.0.2/go.mod h1:RdyM2Fnvxx7f7A6WSmU1aAhDrQIAVW7LS/0LsAUE5mE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc= +github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY= +github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E= +github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc= +github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-oauth2/oauth2/v4 v4.1.0/go.mod h1:+rsyi0o/ZbSfhL/3Xr/sAtL4brS+IdGj86PHVlPjE+4= +github.com/go-oauth2/oauth2/v4 v4.5.2 h1:CuZhD3lhGuI6aNLyUbRHXsgG2RwGRBOuCBfd4WQKqBQ= +github.com/go-oauth2/oauth2/v4 v4.5.2/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ= +github.com/go-oauth2/redis/v4 v4.1.1 h1:uYLGPbAEZ3tb2Qg+BHzrtMHbJ7NeX6S9Ol0+iYyBF5E= +github.com/go-oauth2/redis/v4 v4.1.1/go.mod h1:cYNT5bLEwCnrFXqSbWDvxXzfTaF/fKMf1XoRVFwBPrc= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redis/v8 v8.0.0-beta.5/go.mod h1:Mm9EH/5UMRx680UIryN6rd5XFn/L7zORPqLV+1D5thQ= +github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= +github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible h1:3kDd8PIWAdU+qGs/+0QUgsMI2ZSiJPt45Xn0su+x/Q0= +github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.8+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84 h1:pS0A6cr4aHYZnYwC7Uw+rwgb39+nzkm2QhwZ+S6Gn5I= +github.com/jordan-wright/email v0.0.0-20200824153738-3f5bafa1cd84/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/medivhzhan/weapp/v3 v3.6.19 h1:SXY1H1AdX4RvRyuCTb5+sJxEMisyoxHLL87aIwuos/g= +github.com/medivhzhan/weapp/v3 v3.6.19/go.mod h1:DBlnuMNGIcDYSDaM8JnBIT14I+OqMaMNm9QU8HvhhMU= +github.com/microsoft/go-mssqldb v1.1.0 h1:jsV+tpvcPTbNNKW0o3kiCD69kOHICsfjZ2VcVu2lKYc= +github.com/microsoft/go-mssqldb v1.1.0/go.mod h1:LzkFdl4z2Ck+Hi+ycGOTbL56VEfgoyA2DvYejrNGbRk= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0= +github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= +github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI= +github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/qiniu/api.v7/v7 v7.4.1 h1:BnNUBimLk6nrA/mIwsww9yJRupmViSsb1ndLMC7a9OY= +github.com/qiniu/api.v7/v7 v7.4.1/go.mod h1:VE5oC5rkE1xul0u1S2N0b2Uxq9/6hZzhyqjgK25XDcM= +github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/sashabaranov/go-openai v1.14.1 h1:jqfkdj8XHnBF84oi2aNtT8Ktp3EJ0MfuVjvcMkfI0LA= +github.com/sashabaranov/go-openai v1.14.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08= +github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/songzhibin97/gkit v1.2.11 h1:O8+l6eLMrZ2yNbT6Vohc6ggWnH5zt4P8/3ZEkf8jUL4= +github.com/songzhibin97/gkit v1.2.11/go.mod h1:axjYsiJWnn/kf/uGiUr9JPHRlt2CQrqfq/fPZ3xIY+M= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= +github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= +github.com/tencentyun/cos-go-sdk-v5 v0.7.42 h1:Up1704BJjI5orycXKjpVpvuOInt9GC5pqY4knyE9Uds= +github.com/tencentyun/cos-go-sdk-v5 v0.7.42/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= +github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo= +github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI= +github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e h1:+NL1GDIUOKxVfbp2KoJQD9cTQ6dyP2co9q4yzmT9FZo= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ3KKDyCkxapfufrqDqwmGjcHfAyXRrE= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk= +github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE= +github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4= +github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= +gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= +gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/sqlserver v1.5.1 h1:wpyW/pR26U94uaujltiFGXY7fd2Jw5hC9PB1ZF/Y5s4= +gorm.io/driver/sqlserver v1.5.1/go.mod h1:AYHzzte2msKTmYBYsSIq8ZUsznLJwBdkB2wpI+kt0nM= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= +gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/plugin/dbresolver v1.4.1 h1:Ug4LcoPhrvqq71UhxtF346f+skTYoCa/nEsdjvHwEzk= +gorm.io/plugin/dbresolver v1.4.1/go.mod h1:CTbCtMWhsjXSiJqiW2R8POvJ2cq18RVOl4WGyT5nhNc= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= +modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= +modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.0 h1:MWTFBI5H1WLnXpNBh/BTruBVqzzoh28DA0iOnlkkRaM= +modernc.org/sqlite v1.23.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/initialize/db_list.go b/initialize/db_list.go new file mode 100644 index 0000000..8fef27d --- /dev/null +++ b/initialize/db_list.go @@ -0,0 +1,36 @@ +package initialize + +import ( + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" +) + +const sys = "system" + +func DBList() { + dbMap := make(map[string]*gorm.DB) + for _, info := range global.GVA_CONFIG.DBList { + if info.Disable { + continue + } + switch info.Type { + case "mysql": + dbMap[info.AliasName] = GormMysqlByConfig(config.Mysql{GeneralDB: info.GeneralDB}) + case "mssql": + dbMap[info.AliasName] = GormMssqlByConfig(config.Mssql{GeneralDB: info.GeneralDB}) + case "pgsql": + dbMap[info.AliasName] = GormPgSqlByConfig(config.Pgsql{GeneralDB: info.GeneralDB}) + case "oracle": + dbMap[info.AliasName] = GormOracleByConfig(config.Oracle{GeneralDB: info.GeneralDB}) + default: + continue + } + } + // 做特殊判断,是否有迁移 + // 适配低版本迁移多数据库版本 + if sysDB, ok := dbMap[sys]; ok { + global.GVA_DB = sysDB + } + global.GVA_DBList = dbMap +} diff --git a/initialize/ensure_tables.go b/initialize/ensure_tables.go new file mode 100644 index 0000000..7bab0e3 --- /dev/null +++ b/initialize/ensure_tables.go @@ -0,0 +1,100 @@ +package initialize + +import ( + "context" + adapter "github.com/casbin/gorm-adapter/v3" + "gorm.io/gorm" + "miniapp/model/example" + sysModel "miniapp/model/system" + "miniapp/service/system" +) + +const initOrderEnsureTables = system.InitOrderExternal - 1 + +type ensureTables struct{} + +// auto run +func init() { + system.RegisterInit(initOrderEnsureTables, &ensureTables{}) +} + +func (ensureTables) InitializerName() string { + return "ensure_tables_created" +} +func (e *ensureTables) InitializeData(ctx context.Context) (next context.Context, err error) { + return ctx, nil +} + +func (e *ensureTables) DataInserted(ctx context.Context) bool { + return true +} + +func (e *ensureTables) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + tables := []interface{}{ + sysModel.SysApi{}, + sysModel.SysUser{}, + sysModel.SysBaseMenu{}, + sysModel.SysAuthority{}, + sysModel.JwtBlacklist{}, + sysModel.SysDictionary{}, + sysModel.SysAutoCodeHistory{}, + sysModel.SysOperationRecord{}, + sysModel.SysDictionaryDetail{}, + sysModel.SysBaseMenuParameter{}, + sysModel.SysBaseMenuBtn{}, + sysModel.SysAuthorityBtn{}, + sysModel.SysAutoCode{}, + sysModel.SysChatGptOption{}, + + adapter.CasbinRule{}, + + example.ExaFile{}, + example.ExaCustomer{}, + example.ExaFileChunk{}, + example.ExaFileUploadAndDownload{}, + } + for _, t := range tables { + _ = db.AutoMigrate(&t) + // 视图 authority_menu 会被当成表来创建,引发冲突错误(更新版本的gorm似乎不会) + // 由于 AutoMigrate() 基本无需考虑错误,因此显式忽略 + } + return ctx, nil +} + +func (e *ensureTables) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + tables := []interface{}{ + sysModel.SysApi{}, + sysModel.SysUser{}, + sysModel.SysBaseMenu{}, + sysModel.SysAuthority{}, + sysModel.JwtBlacklist{}, + sysModel.SysDictionary{}, + sysModel.SysAutoCodeHistory{}, + sysModel.SysOperationRecord{}, + sysModel.SysDictionaryDetail{}, + sysModel.SysBaseMenuParameter{}, + sysModel.SysBaseMenuBtn{}, + sysModel.SysAuthorityBtn{}, + sysModel.SysAutoCode{}, + sysModel.SysChatGptOption{}, + adapter.CasbinRule{}, + + example.ExaFile{}, + example.ExaCustomer{}, + example.ExaFileChunk{}, + example.ExaFileUploadAndDownload{}, + } + yes := true + for _, t := range tables { + yes = yes && db.Migrator().HasTable(t) + } + return yes +} diff --git a/initialize/gorm.go b/initialize/gorm.go new file mode 100644 index 0000000..549e772 --- /dev/null +++ b/initialize/gorm.go @@ -0,0 +1,78 @@ +package initialize + +import ( + "miniapp/model/app" + "miniapp/model/common" + "os" + + "miniapp/global" + "miniapp/model/example" + "miniapp/model/system" + + "go.uber.org/zap" + "gorm.io/gorm" +) + +// Gorm 初始化数据库并产生数据库全局变量 +// Author SliverHorn +func Gorm() *gorm.DB { + switch global.GVA_CONFIG.System.DbType { + case "mysql": + return GormMysql() + case "pgsql": + return GormPgSql() + case "oracle": + return GormOracle() + case "mssql": + return GormMssql() + case "sqlite": + return GormSqlite() + default: + return GormMysql() + } +} + +// RegisterTables 注册数据库表专用 +// Author SliverHorn +func RegisterTables() { + db := global.GVA_DB + err := db.AutoMigrate( + // 系统模块表 + system.SysApi{}, + system.SysUser{}, + system.SysBaseMenu{}, + system.JwtBlacklist{}, + system.SysAuthority{}, + system.SysDictionary{}, + system.SysOperationRecord{}, + system.SysAutoCodeHistory{}, + system.SysDictionaryDetail{}, + system.SysBaseMenuParameter{}, + system.SysBaseMenuBtn{}, + system.SysAuthorityBtn{}, + system.SysAutoCode{}, + system.SysChatGptOption{}, + + example.ExaFile{}, + example.ExaCustomer{}, + example.ExaFileChunk{}, + example.ExaFileUploadAndDownload{}, + + app.User{}, + app.OAuth2Client{}, + app.Favorite{}, + app.Vision{}, + + common.Hospital{}, + common.Notes{}, + common.Todos{}, + common.Article{}, + common.Banner{}, + common.UserTodo{}, + ) + if err != nil { + global.GVA_LOG.Error("register table failed", zap.Error(err)) + os.Exit(0) + } + global.GVA_LOG.Info("register table success") +} diff --git a/initialize/gorm_mssql.go b/initialize/gorm_mssql.go new file mode 100644 index 0000000..529bde0 --- /dev/null +++ b/initialize/gorm_mssql.go @@ -0,0 +1,59 @@ +/* + * @Author: 逆光飞翔 191180776@qq.com + * @Date: 2022-12-08 17:25:49 + * @LastEditors: 逆光飞翔 191180776@qq.com + * @LastEditTime: 2022-12-08 18:00:00 + * @FilePath: \server.exe.exe\initialize\gorm_mssql.go + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +package initialize + +import ( + "gorm.io/driver/sqlserver" + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" + "miniapp/initialize/internal" +) + +// GormMssql 初始化Mssql数据库 +// Author [LouisZhang](191180776@qq.com) +func GormMssql() *gorm.DB { + m := global.GVA_CONFIG.Mssql + if m.Dbname == "" { + return nil + } + mssqlConfig := sqlserver.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + } + if db, err := gorm.Open(sqlserver.New(mssqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + return nil + } else { + db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine) + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} + +// GormMssqlByConfig 初始化Mysql数据库用过传入配置 +func GormMssqlByConfig(m config.Mssql) *gorm.DB { + if m.Dbname == "" { + return nil + } + mssqlConfig := sqlserver.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + } + if db, err := gorm.Open(sqlserver.New(mssqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + panic(err) + } else { + db.InstanceSet("gorm:table_options", "ENGINE=InnoDB") + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} diff --git a/initialize/gorm_mysql.go b/initialize/gorm_mysql.go new file mode 100644 index 0000000..d04afd0 --- /dev/null +++ b/initialize/gorm_mysql.go @@ -0,0 +1,55 @@ +package initialize + +import ( + _ "github.com/go-sql-driver/mysql" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" + "miniapp/initialize/internal" +) + +// GormMysql 初始化Mysql数据库 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func GormMysql() *gorm.DB { + m := global.GVA_CONFIG.Mysql + if m.Dbname == "" { + return nil + } + mysqlConfig := mysql.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + SkipInitializeWithVersion: false, // 根据版本自动配置 + } + if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + return nil + } else { + db.InstanceSet("gorm:table_options", "ENGINE="+m.Engine) + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} + +// GormMysqlByConfig 初始化Mysql数据库用过传入配置 +func GormMysqlByConfig(m config.Mysql) *gorm.DB { + if m.Dbname == "" { + return nil + } + mysqlConfig := mysql.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + SkipInitializeWithVersion: false, // 根据版本自动配置 + } + if db, err := gorm.Open(mysql.New(mysqlConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + panic(err) + } else { + db.InstanceSet("gorm:table_options", "ENGINE=InnoDB") + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} diff --git a/initialize/gorm_oracle.go b/initialize/gorm_oracle.go new file mode 100644 index 0000000..1fb659e --- /dev/null +++ b/initialize/gorm_oracle.go @@ -0,0 +1,52 @@ +package initialize + +import ( + //"github.com/dzwvip/oracle" + "miniapp/config" + "miniapp/global" + "miniapp/initialize/internal" + + //_ "github.com/godror/godror" + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +// GormOracle 初始化oracle数据库 +// 如果需要Oracle库 放开import里的注释 把下方 mysql.Config 改为 oracle.Config ; mysql.New 改为 oracle.New +func GormOracle() *gorm.DB { + m := global.GVA_CONFIG.Oracle + if m.Dbname == "" { + return nil + } + oracleConfig := mysql.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + } + if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + panic(err) + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} + +// GormOracleByConfig 初始化Oracle数据库用过传入配置 +func GormOracleByConfig(m config.Oracle) *gorm.DB { + if m.Dbname == "" { + return nil + } + oracleConfig := mysql.Config{ + DSN: m.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + } + if db, err := gorm.Open(mysql.New(oracleConfig), internal.Gorm.Config(m.Prefix, m.Singular)); err != nil { + panic(err) + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(m.MaxIdleConns) + sqlDB.SetMaxOpenConns(m.MaxOpenConns) + return db + } +} diff --git a/initialize/gorm_pgsql.go b/initialize/gorm_pgsql.go new file mode 100644 index 0000000..98cfdf6 --- /dev/null +++ b/initialize/gorm_pgsql.go @@ -0,0 +1,50 @@ +package initialize + +import ( + "gorm.io/driver/postgres" + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" + "miniapp/initialize/internal" +) + +// GormPgSql 初始化 Postgresql 数据库 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func GormPgSql() *gorm.DB { + p := global.GVA_CONFIG.Pgsql + if p.Dbname == "" { + return nil + } + pgsqlConfig := postgres.Config{ + DSN: p.Dsn(), // DSN data source name + PreferSimpleProtocol: false, + } + if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil { + return nil + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(p.MaxIdleConns) + sqlDB.SetMaxOpenConns(p.MaxOpenConns) + return db + } +} + +// GormPgSqlByConfig 初始化 Postgresql 数据库 通过参数 +func GormPgSqlByConfig(p config.Pgsql) *gorm.DB { + if p.Dbname == "" { + return nil + } + pgsqlConfig := postgres.Config{ + DSN: p.Dsn(), // DSN data source name + PreferSimpleProtocol: false, + } + if db, err := gorm.Open(postgres.New(pgsqlConfig), internal.Gorm.Config(p.Prefix, p.Singular)); err != nil { + panic(err) + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(p.MaxIdleConns) + sqlDB.SetMaxOpenConns(p.MaxOpenConns) + return db + } +} diff --git a/initialize/gorm_sqlite.go b/initialize/gorm_sqlite.go new file mode 100644 index 0000000..699389b --- /dev/null +++ b/initialize/gorm_sqlite.go @@ -0,0 +1,42 @@ +package initialize + +import ( + "github.com/glebarez/sqlite" + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" + "miniapp/initialize/internal" +) + +// GormSqlite 初始化Sqlite数据库 +func GormSqlite() *gorm.DB { + s := global.GVA_CONFIG.Sqlite + if s.Dbname == "" { + return nil + } + + if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil { + panic(err) + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(s.MaxIdleConns) + sqlDB.SetMaxOpenConns(s.MaxOpenConns) + return db + } +} + +// GormSqliteByConfig 初始化Sqlite数据库用过传入配置 +func GormSqliteByConfig(s config.Sqlite) *gorm.DB { + if s.Dbname == "" { + return nil + } + + if db, err := gorm.Open(sqlite.Open(s.Dsn()), internal.Gorm.Config(s.Prefix, s.Singular)); err != nil { + panic(err) + } else { + sqlDB, _ := db.DB() + sqlDB.SetMaxIdleConns(s.MaxIdleConns) + sqlDB.SetMaxOpenConns(s.MaxOpenConns) + return db + } +} diff --git a/initialize/internal/gorm.go b/initialize/internal/gorm.go new file mode 100644 index 0000000..eaadddc --- /dev/null +++ b/initialize/internal/gorm.go @@ -0,0 +1,62 @@ +package internal + +import ( + "gorm.io/gorm/schema" + "log" + "os" + "time" + + "gorm.io/gorm" + "gorm.io/gorm/logger" + "miniapp/global" +) + +type DBBASE interface { + GetLogMode() string +} + +var Gorm = new(_gorm) + +type _gorm struct{} + +// Config gorm 自定义配置 +// Author [SliverHorn](https://github.com/SliverHorn) +func (g *_gorm) Config(prefix string, singular bool) *gorm.Config { + config := &gorm.Config{ + NamingStrategy: schema.NamingStrategy{ + TablePrefix: prefix, + SingularTable: singular, + }, + DisableForeignKeyConstraintWhenMigrating: true, + } + _default := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{ + SlowThreshold: 200 * time.Millisecond, + LogLevel: logger.Warn, + Colorful: true, + }) + var logMode DBBASE + switch global.GVA_CONFIG.System.DbType { + case "mysql": + logMode = &global.GVA_CONFIG.Mysql + case "pgsql": + logMode = &global.GVA_CONFIG.Pgsql + case "oracle": + logMode = &global.GVA_CONFIG.Oracle + default: + logMode = &global.GVA_CONFIG.Mysql + } + + switch logMode.GetLogMode() { + case "silent", "Silent": + config.Logger = _default.LogMode(logger.Silent) + case "error", "Error": + config.Logger = _default.LogMode(logger.Error) + case "warn", "Warn": + config.Logger = _default.LogMode(logger.Warn) + case "info", "Info": + config.Logger = _default.LogMode(logger.Info) + default: + config.Logger = _default.LogMode(logger.Info) + } + return config +} diff --git a/initialize/internal/logger.go b/initialize/internal/logger.go new file mode 100644 index 0000000..871f216 --- /dev/null +++ b/initialize/internal/logger.go @@ -0,0 +1,35 @@ +package internal + +import ( + "fmt" + + "gorm.io/gorm/logger" + "miniapp/global" +) + +type writer struct { + logger.Writer +} + +// NewWriter writer 构造函数 +// Author [SliverHorn](https://github.com/SliverHorn) +func NewWriter(w logger.Writer) *writer { + return &writer{Writer: w} +} + +// Printf 格式化打印日志 +// Author [SliverHorn](https://github.com/SliverHorn) +func (w *writer) Printf(message string, data ...interface{}) { + var logZap bool + switch global.GVA_CONFIG.System.DbType { + case "mysql": + logZap = global.GVA_CONFIG.Mysql.LogZap + case "pgsql": + logZap = global.GVA_CONFIG.Pgsql.LogZap + } + if logZap { + global.GVA_LOG.Info(fmt.Sprintf(message+"\n", data...)) + } else { + w.Writer.Printf(message, data...) + } +} diff --git a/initialize/other.go b/initialize/other.go new file mode 100644 index 0000000..7e89990 --- /dev/null +++ b/initialize/other.go @@ -0,0 +1,23 @@ +package initialize + +import ( + "github.com/songzhibin97/gkit/cache/local_cache" + + "miniapp/global" + "miniapp/utils" +) + +func OtherInit() { + dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) + if err != nil { + panic(err) + } + _, err = utils.ParseDuration(global.GVA_CONFIG.JWT.BufferTime) + if err != nil { + panic(err) + } + + global.BlackCache = local_cache.NewCache( + local_cache.SetDefaultExpire(dr), + ) +} diff --git a/initialize/plugin.go b/initialize/plugin.go new file mode 100644 index 0000000..372aada --- /dev/null +++ b/initialize/plugin.go @@ -0,0 +1,36 @@ +package initialize + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/middleware" + "miniapp/plugin/email" + "miniapp/utils/plugin" +) + +func PluginInit(group *gin.RouterGroup, Plugin ...plugin.Plugin) { + for i := range Plugin { + PluginGroup := group.Group(Plugin[i].RouterPath()) + Plugin[i].Register(PluginGroup) + } +} + +func InstallPlugin(Router *gin.Engine) { + PublicGroup := Router.Group("") + fmt.Println("无鉴权插件安装==》", PublicGroup) + PrivateGroup := Router.Group("") + fmt.Println("鉴权插件安装==》", PrivateGroup) + PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()) + // 添加跟角色挂钩权限的插件 示例 本地示例模式于在线仓库模式注意上方的import 可以自行切换 效果相同 + PluginInit(PrivateGroup, email.CreateEmailPlug( + global.GVA_CONFIG.Email.To, + global.GVA_CONFIG.Email.From, + global.GVA_CONFIG.Email.Host, + global.GVA_CONFIG.Email.Secret, + global.GVA_CONFIG.Email.Nickname, + global.GVA_CONFIG.Email.Port, + global.GVA_CONFIG.Email.IsSSL, + )) +} diff --git a/initialize/redis.go b/initialize/redis.go new file mode 100644 index 0000000..2c11b05 --- /dev/null +++ b/initialize/redis.go @@ -0,0 +1,26 @@ +package initialize + +import ( + "context" + + "miniapp/global" + + "github.com/redis/go-redis/v9" + "go.uber.org/zap" +) + +func Redis() { + redisCfg := global.GVA_CONFIG.Redis + client := redis.NewClient(&redis.Options{ + Addr: redisCfg.Addr, + Password: redisCfg.Password, // no password set + DB: redisCfg.DB, // use default DB + }) + pong, err := client.Ping(context.Background()).Result() + if err != nil { + global.GVA_LOG.Error("redis connect ping failed, err:", zap.Error(err)) + } else { + global.GVA_LOG.Info("redis connect ping response:", zap.String("pong", pong)) + global.GVA_REDIS = client + } +} diff --git a/initialize/register_init.go b/initialize/register_init.go new file mode 100644 index 0000000..afdaa0a --- /dev/null +++ b/initialize/register_init.go @@ -0,0 +1,10 @@ +package initialize + +import ( + _ "miniapp/source/example" + _ "miniapp/source/system" +) + +func init() { + // do nothing,only import source package so that inits can be registered +} diff --git a/initialize/router.go b/initialize/router.go new file mode 100644 index 0000000..d8027de --- /dev/null +++ b/initialize/router.go @@ -0,0 +1,90 @@ +package initialize + +import ( + swaggerFiles "github.com/swaggo/files" + "net/http" + + "github.com/gin-gonic/gin" + ginSwagger "github.com/swaggo/gin-swagger" + + "miniapp/global" + "miniapp/middleware" + "miniapp/router" +) + +// 初始化总路由 + +func Routers() *gin.Engine { + Router := gin.Default() + InstallPlugin(Router) // 安装插件 + systemRouter := router.RouterGroupApp.System + exampleRouter := router.RouterGroupApp.Example + appRouter := router.RouterGroupApp.App + // 如果想要不使用nginx代理前端网页,可以修改 web/.env.production 下的 + // VUE_APP_BASE_API = / + // VUE_APP_BASE_PATH = http://localhost + // 然后执行打包命令 npm run build。在打开下面3行注释 + // Router.Static("/favicon.ico", "./dist/favicon.ico") + // Router.Static("/assets", "./dist/assets") // dist里面的静态资源 + // Router.StaticFile("/", "./dist/index.html") // 前端网页入口页面 + + Router.StaticFS(global.GVA_CONFIG.Local.StorePath, http.Dir(global.GVA_CONFIG.Local.StorePath)) // 为用户头像和文件提供静态地址 + // Router.Use(middleware.LoadTls()) // 如果需要使用https 请打开此中间件 然后前往 core/server.exe.exe.go 将启动模式 更变为 Router.RunTLS("端口","你的cre/pem文件","你的key文件") + // 跨域,如需跨域可以打开下面的注释 + // Router.Use(middleware.Cors()) // 直接放行全部跨域请求 + // Router.Use(middleware.CorsByRules()) // 按照配置的规则放行跨域请求 + //global.GVA_LOG.Info("use middleware cors") + + Router.GET(global.GVA_CONFIG.System.RouterPrefix+"/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + global.GVA_LOG.Info("register swagger handler") + // 方便统一添加路由组前缀 多服务器上线使用 + + PublicGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix) + { + // 健康监测 + PublicGroup.GET("/health", func(c *gin.Context) { + c.JSON(http.StatusOK, "ok") + }) + } + { + systemRouter.InitBaseRouter(PublicGroup) // 注册基础功能路由 不做鉴权 + systemRouter.InitInitRouter(PublicGroup) // 自动初始化相关 + } + //用户端路由 无需鉴权 + { + appRouter.InitLoginRouter(PublicGroup) // 登陆路由 + appRouter.InitUserRouter(PublicGroup) // 注册用户路由 + appRouter.InitFavoriteRouter(PublicGroup) // 收藏路由 + appRouter.InitVisionRouter(PublicGroup) // 视力路由 + + } + PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix) + PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler()) + { + systemRouter.InitApiRouter(PrivateGroup, PublicGroup) // 注册功能api路由 + systemRouter.InitJwtRouter(PrivateGroup) // jwt相关路由 + systemRouter.InitUserRouter(PrivateGroup) // 注册用户路由 + systemRouter.InitMenuRouter(PrivateGroup) // 注册menu路由 + systemRouter.InitSystemRouter(PrivateGroup) // system相关路由 + systemRouter.InitCasbinRouter(PrivateGroup) // 权限相关路由 + systemRouter.InitAutoCodeRouter(PrivateGroup) // 创建自动化代码 + systemRouter.InitAuthorityRouter(PrivateGroup) // 注册角色路由 + systemRouter.InitSysDictionaryRouter(PrivateGroup) // 字典管理 + systemRouter.InitAutoCodeHistoryRouter(PrivateGroup) // 自动化代码历史 + systemRouter.InitSysOperationRecordRouter(PrivateGroup) // 操作记录 + systemRouter.InitSysDictionaryDetailRouter(PrivateGroup) // 字典详情管理 + systemRouter.InitAuthorityBtnRouterRouter(PrivateGroup) // 字典详情管理 + systemRouter.InitChatGptRouter(PrivateGroup) // chatGpt接口 + + exampleRouter.InitCustomerRouter(PrivateGroup) // 客户路由 + exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由 + + systemRouter.InitHospitalRouter(PublicGroup) // 医院路由 + systemRouter.InitBannerRouter(PublicGroup) // banner路由 + systemRouter.InitArticleRouter(PublicGroup) // 文章路由 + + } + + global.GVA_LOG.Info("router register success") + return Router +} diff --git a/initialize/timer.go b/initialize/timer.go new file mode 100644 index 0000000..19517f1 --- /dev/null +++ b/initialize/timer.go @@ -0,0 +1,33 @@ +package initialize + +import ( + "fmt" + + "github.com/robfig/cron/v3" + + "miniapp/config" + "miniapp/global" + "miniapp/utils" +) + +func Timer() { + if global.GVA_CONFIG.Timer.Start { + for i := range global.GVA_CONFIG.Timer.Detail { + go func(detail config.Detail) { + var option []cron.Option + if global.GVA_CONFIG.Timer.WithSeconds { + option = append(option, cron.WithSeconds()) + } + _, err := global.GVA_Timer.AddTaskByFunc("ClearDB", global.GVA_CONFIG.Timer.Spec, func() { + err := utils.ClearTable(global.GVA_DB, detail.TableName, detail.CompareField, detail.Interval) + if err != nil { + fmt.Println("timer error:", err) + } + }, option...) + if err != nil { + fmt.Println("add timer error:", err) + } + }(global.GVA_CONFIG.Timer.Detail[i]) + } + } +} diff --git a/initialize/validator.go b/initialize/validator.go new file mode 100644 index 0000000..ca45cdc --- /dev/null +++ b/initialize/validator.go @@ -0,0 +1,22 @@ +package initialize + +import "miniapp/utils" + +func init() { + _ = utils.RegisterRule("PageVerify", + utils.Rules{ + "Page": {utils.NotEmpty()}, + "PageSize": {utils.NotEmpty()}, + }, + ) + _ = utils.RegisterRule("IdVerify", + utils.Rules{ + "Id": {utils.NotEmpty()}, + }, + ) + _ = utils.RegisterRule("AuthorityIdVerify", + utils.Rules{ + "AuthorityId": {utils.NotEmpty()}, + }, + ) +} diff --git a/log/2023-10-11/error.log b/log/2023-10-11/error.log new file mode 100644 index 0000000..113e13e --- /dev/null +++ b/log/2023-10-11/error.log @@ -0,0 +1,60 @@ +[miniapp]2023/10/11 - 12:17:48.633 error C:/Users/Administrator/Desktop/server/api/v1/system/sys_user.go:56 登陆失败! 用户名不存在或者密码错误! {"error": "db not init"} +[miniapp]2023/10/11 - 12:49:14.470 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 12:49:32.985 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 14:32:21.261 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 14:32:27.921 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 15:44:36.062 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=652652648915C63137533C77, Ec=0016-00000005"} +[miniapp]2023/10/11 - 15:45:18.933 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=6526528FB6896C32324B0C23, Ec=0016-00000005"} +[miniapp]2023/10/11 - 21:30:35.072 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 21:30:35.762 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 21:30:35.765 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 21:49:13.118 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 21:49:14.248 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 21:49:14.250 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 21:51:29.980 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 21:51:29.985 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 21:54:28.032 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 21:54:28.659 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 21:54:28.661 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 21:57:19.306 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 21:57:19.306 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 21:57:19.308 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:03:03.529 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:03:49.141 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:03:49.777 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:03:49.780 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:04:26.159 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:04:26.818 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:04:26.820 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:08:39.077 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:08:45.745 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:08:45.745 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:08:45.745 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:08:45.748 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:08:45.749 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:08:46.369 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:08:46.371 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:11:23.107 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:11:23.110 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:13:36.214 error C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构 +[miniapp]2023/10/11 - 22:13:36.216 error C:/Users/Administrator/Desktop/server/middleware/operation.go:123 create operation record error: {"error": "Error 1406 (22001): Data too long for column 'agent' at row 1"} +[miniapp]2023/10/11 - 22:14:59.957 error C:/Users/Administrator/Desktop/server/initialize/gorm.go:70 register table failed {"error": "Error 1069 (42000): Too many keys specified; max 64 keys allowed"} +[miniapp]2023/10/11 - 22:15:41.382 error C:/Users/Administrator/Desktop/server/initialize/gorm.go:70 register table failed {"error": "Error 1069 (42000): Too many keys specified; max 64 keys allowed"} +[miniapp]2023/10/11 - 22:36:29.260 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 清理失败,跳过清理 +[miniapp]2023/10/11 - 22:36:29.261 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: context canceled +[miniapp]2023/10/11 - 22:41:42.786 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 22:47:14.886 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:00:58.398 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 23:00:59.633 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 23:00:59.633 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/10/11 - 23:01:00.334 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:01:14.971 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:01:25.497 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:04:12.045 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:15:08.506 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:15:16.620 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:17:51.189 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:18:17.252 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:18:51.753 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:19:55.688 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed +[miniapp]2023/10/11 - 23:24:59.675 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: Client authentication failed diff --git a/log/2023-10-11/info.log b/log/2023-10-11/info.log new file mode 100644 index 0000000..c40bf76 --- /dev/null +++ b/log/2023-10-11/info.log @@ -0,0 +1,95 @@ +[miniapp]2023/10/11 - 12:17:24.308 info C:/Users/Administrator/Desktop/server/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:17:24.316 info C:/Users/Administrator/Desktop/server/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:17:24.318 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:17:59.631 info C:/Users/Administrator/Desktop/server/api/v1/system/sys_initdb.go:57 前往初始化数据库 +[miniapp]2023/10/11 - 12:22:36.247 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:22:36.248 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:22:36.249 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:22:36.249 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:22:36.257 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:26:26.104 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:26:26.105 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:26:26.106 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:26:26.106 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:26:26.120 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:28:21.674 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/api/v1/system/sys_initdb.go:57 数据库无需初始化 +[miniapp]2023/10/11 - 12:28:42.802 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/api/v1/system/sys_initdb.go:57 数据库无需初始化 +[miniapp]2023/10/11 - 12:29:07.498 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:29:07.505 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:29:07.505 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:29:07.515 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:29:15.197 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/api/v1/system/sys_initdb.go:57 前往初始化数据库 +[miniapp]2023/10/11 - 12:31:44.363 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:31:44.365 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:31:44.365 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:31:44.366 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:31:44.380 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:36:28.127 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:36:28.128 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:36:28.128 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:44 register swagger handler +[miniapp]2023/10/11 - 12:36:28.129 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/initialize/router.go:81 router register success +[miniapp]2023/10/11 - 12:36:28.139 info D:/GOPATH/pkg/mod/miniapp@v0.0.0-20231010105746-b3dbb8d4be1f/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:40:59.510 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:41:36.502 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:41:36.504 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:41:36.505 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 12:41:36.505 info C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success +[miniapp]2023/10/11 - 12:41:36.518 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:47:37.733 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:47:37.735 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:47:37.736 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 12:47:37.736 info C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success +[miniapp]2023/10/11 - 12:47:37.745 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:48:02.622 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:48:02.624 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:48:02.625 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 12:48:02.626 info C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success +[miniapp]2023/10/11 - 12:48:02.633 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:48:47.654 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:48:47.659 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:48:47.660 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 12:48:47.660 info C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success +[miniapp]2023/10/11 - 12:48:47.676 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 12:51:25.617 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 12:51:25.619 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 12:51:25.620 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 12:51:25.621 info C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success +[miniapp]2023/10/11 - 12:51:25.631 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 14:46:18.358 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 14:46:18.361 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 14:46:18.362 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 14:47:00.201 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success +[miniapp]2023/10/11 - 14:47:00.204 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 14:47:00.205 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 14:47:00.205 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 14:47:00.219 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 14:53:02.134 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 14:53:02.137 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 14:53:02.137 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 14:53:02.138 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 14:53:02.150 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 15:00:11.005 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 15:00:11.008 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 15:00:11.008 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 15:00:11.009 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 15:00:11.023 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 15:41:43.799 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 15:41:43.802 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 15:41:43.802 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 15:41:43.803 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 15:41:43.814 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 22:16:48.448 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 22:16:48.451 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 22:16:48.451 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 22:16:48.452 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 22:16:48.456 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 23:23:50.878 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 23:23:50.880 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 23:23:50.881 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 23:23:50.881 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 23:23:50.890 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/11 - 23:24:18.312 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/11 - 23:24:18.315 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/11 - 23:24:18.315 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/11 - 23:24:18.316 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/11 - 23:24:18.321 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} diff --git a/log/2023-10-11/panic.log b/log/2023-10-11/panic.log new file mode 100644 index 0000000..be36152 --- /dev/null +++ b/log/2023-10-11/panic.log @@ -0,0 +1 @@ +[miniapp]2023/10/11 - 12:40:59.513 panic D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:71 OAuth2服务启动失败[Client信息拉取失败]: Error 1146 (42S02): Table 'jm_wechat2.t_oauth2_client' doesn't exist diff --git a/log/2023-10-12/error.log b/log/2023-10-12/error.log new file mode 100644 index 0000000..02f3752 --- /dev/null +++ b/log/2023-10-12/error.log @@ -0,0 +1,17 @@ +[miniapp]2023/10/12 - 20:49:24.766 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.798 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.842 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.849 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.856 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.863 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/12 - 20:49:24.893 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 清理失败,跳过清理 +[miniapp]2023/10/12 - 20:49:24.894 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 收到未定义的登录错误: context canceled +[miniapp]2023/10/12 - 21:12:02.597 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=6527F0A3A3A9C63939913609, Ec=0016-00000005"} +[miniapp]2023/10/12 - 21:12:50.260 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=6527F0D3A3A9C63230926B09, Ec=0016-00000005"} +[miniapp]2023/10/12 - 21:12:52.879 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=6527F0D5F299AF3531A6044D, Ec=0016-00000005"} +[miniapp]2023/10/12 - 21:13:56.794 error C:/Users/Administrator/Desktop/server/utils/upload/aliyun_oss.go:36 function formUploader.Put() Failed {"err": "oss: service returned error: StatusCode=400, ErrorCode=InvalidObjectName, ErrorMessage=\"The specified object is not valid.\", RequestId=6527F1158915C63033347E5F, Ec=0016-00000005"} +[miniapp]2023/10/12 - 22:04:57.489 error C:/Users/Administrator/Desktop/server/api/v1/example/exa_file_upload_download.go:29 接收文件失败! {"error": "http: no such file"} +[miniapp]2023/10/12 - 22:08:48.459 error C:/Users/Administrator/Desktop/server/api/v1/example/exa_file_upload_download.go:29 接收文件失败! {"error": "http: no such file"} +[miniapp]2023/10/12 - 22:12:55.105 error C:/Users/Administrator/Desktop/server/api/v1/example/exa_file_upload_download.go:29 接收文件失败! {"error": "http: no such file"} +[miniapp]2023/10/12 - 22:17:38.420 error C:/Users/Administrator/Desktop/server/api/v1/example/exa_file_upload_download.go:29 接收文件失败! {"error": "http: no such file"} +[miniapp]2023/10/12 - 22:22:22.968 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token diff --git a/log/2023-10-12/info.log b/log/2023-10-12/info.log new file mode 100644 index 0000000..b4184d5 --- /dev/null +++ b/log/2023-10-12/info.log @@ -0,0 +1,40 @@ +[miniapp]2023/10/12 - 14:46:11.064 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/12 - 14:46:11.067 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 14:46:11.068 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 14:46:11.068 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/12 - 14:46:11.071 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 14:47:42.187 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/12 - 14:47:42.203 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 14:47:42.204 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 14:47:42.204 info C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success +[miniapp]2023/10/12 - 14:47:42.217 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 17:28:23.736 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/12 - 17:28:23.739 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 17:28:23.739 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 17:28:23.740 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 17:28:23.756 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 17:29:04.795 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success +[miniapp]2023/10/12 - 17:29:04.798 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 17:29:04.798 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 17:29:04.799 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 17:29:04.804 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 17:32:13.919 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:74 register table success +[miniapp]2023/10/12 - 17:32:13.922 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 17:32:13.922 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 17:32:13.923 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 17:32:13.937 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 21:07:08.230 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success +[miniapp]2023/10/12 - 21:07:08.233 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 21:07:08.233 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 21:07:08.234 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 21:07:08.235 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 21:13:51.791 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success +[miniapp]2023/10/12 - 21:13:51.803 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 21:13:51.804 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 21:13:51.804 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 21:13:51.812 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/12 - 21:43:51.654 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success +[miniapp]2023/10/12 - 21:43:51.657 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/12 - 21:43:51.658 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/12 - 21:43:51.658 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/12 - 21:43:51.667 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} diff --git a/log/2023-10-17/error.log b/log/2023-10-17/error.log new file mode 100644 index 0000000..52eccde --- /dev/null +++ b/log/2023-10-17/error.log @@ -0,0 +1,16 @@ +[miniapp]2023/10/17 - 08:17:20.513 error C:/Users/Administrator/Desktop/server/initialize/gorm.go:72 register table failed {"error": "Error 1069 (42000): Too many keys specified; max 64 keys allowed"} +[miniapp]2023/10/17 - 08:18:09.291 error C:/Users/Administrator/Desktop/server/initialize/gorm.go:72 register table failed {"error": "Error 1069 (42000): Too many keys specified; max 64 keys allowed"} +[miniapp]2023/10/17 - 09:04:37.076 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:09:12.484 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:09:26.157 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:09:40.307 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:11:26.648 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:11:31.255 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:11:59.129 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:12:31.958 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 09:14:05.958 error C:/Users/Administrator/Desktop/server/initialize/gorm.go:74 register table failed {"error": "Error 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key"} +[miniapp]2023/10/17 - 09:24:07.298 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/17 - 09:24:07.298 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/17 - 19:02:13.384 error C:/Users/Administrator/Desktop/server/core/server.go:38 listen tcp :8888: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted. +[miniapp]2023/10/17 - 21:48:55.926 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/17 - 21:49:14.534 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token diff --git a/log/2023-10-17/info.log b/log/2023-10-17/info.log new file mode 100644 index 0000000..00fb288 --- /dev/null +++ b/log/2023-10-17/info.log @@ -0,0 +1,60 @@ +[miniapp]2023/10/17 - 08:18:29.954 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success +[miniapp]2023/10/17 - 08:18:29.957 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 08:18:29.957 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 08:18:29.958 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 08:18:29.965 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 08:28:22.029 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:76 register table success +[miniapp]2023/10/17 - 08:28:22.032 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 08:28:22.032 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 08:28:22.033 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 08:28:22.049 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 08:43:13.963 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:76 register table success +[miniapp]2023/10/17 - 08:43:13.966 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 08:43:13.966 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 08:43:13.967 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 08:43:13.975 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 08:48:32.173 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 08:48:32.176 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 08:48:32.177 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 08:48:32.177 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 08:48:32.189 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:00:52.809 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:00:52.811 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:00:52.811 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:00:52.812 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:00:52.818 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:13:20.930 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:13:20.932 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:13:20.932 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:13:20.933 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:13:20.937 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:15:05.736 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:15:05.739 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:15:05.739 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:15:05.740 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:15:05.752 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:16:26.672 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:16:26.674 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:16:26.675 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:16:26.675 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:16:26.688 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:23:41.666 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:23:41.669 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:23:41.669 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:23:41.670 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:23:41.674 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 09:26:05.699 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 09:26:05.702 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 09:26:05.702 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 09:26:05.703 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 09:26:05.706 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 19:02:13.365 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 19:02:13.368 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 19:02:13.369 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 19:02:13.373 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 19:02:13.383 info C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"} +[miniapp]2023/10/17 - 21:48:19.564 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/17 - 21:48:19.567 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/17 - 21:48:19.568 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/17 - 21:48:19.568 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/17 - 21:48:19.577 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} diff --git a/log/2023-10-20/info.log b/log/2023-10-20/info.log new file mode 100644 index 0000000..485d9ac --- /dev/null +++ b/log/2023-10-20/info.log @@ -0,0 +1,5 @@ +[miniapp]2023/10/20 - 07:53:58.443 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/20 - 07:54:00.942 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/20 - 07:54:00.943 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/20 - 07:54:00.944 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/20 - 07:54:00.952 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} diff --git a/log/2023-10-23/error.log b/log/2023-10-23/error.log new file mode 100644 index 0000000..4a6bcb2 --- /dev/null +++ b/log/2023-10-23/error.log @@ -0,0 +1,11 @@ +[miniapp]2023/10/23 - 12:44:57.260 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/23 - 12:45:09.157 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/23 - 12:45:40.239 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/23 - 12:45:53.047 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/23 - 12:46:19.752 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:0]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:46:52.038 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:0]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:47:50.862 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:0]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:48:12.650 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:1]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:48:29.039 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:1]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:49:43.463 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "unsupported data type: map[is_finish:1]: Table not set, please set it like: db.Model(&user) or db.Table(\"users\")"} +[miniapp]2023/10/23 - 12:50:36.829 error C:/Users/Administrator/Desktop/server/api/v1/app/todos.go:45 更新失败 {"error": "WHERE conditions required"} diff --git a/log/2023-10-23/info.log b/log/2023-10-23/info.log new file mode 100644 index 0000000..4218841 --- /dev/null +++ b/log/2023-10-23/info.log @@ -0,0 +1,20 @@ +[miniapp]2023/10/23 - 12:03:11.274 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/23 - 12:03:11.277 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/23 - 12:03:11.278 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/23 - 12:03:11.279 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/23 - 12:03:11.292 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} +[miniapp]2023/10/23 - 12:43:49.800 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/23 - 12:43:49.803 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/23 - 12:43:49.804 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/23 - 12:43:49.804 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/23 - 12:43:49.813 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} +[miniapp]2023/10/23 - 12:50:34.031 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/23 - 12:50:34.033 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/23 - 12:50:34.034 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/23 - 12:50:34.035 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/23 - 12:50:34.049 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} +[miniapp]2023/10/23 - 12:52:29.098 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/23 - 12:52:29.100 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/23 - 12:52:29.101 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/23 - 12:52:29.102 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/23 - 12:52:29.115 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"} diff --git a/log/2023-10-24/info.log b/log/2023-10-24/info.log new file mode 100644 index 0000000..0a0d179 --- /dev/null +++ b/log/2023-10-24/info.log @@ -0,0 +1,5 @@ +[miniapp]2023/10/24 - 19:58:03.150 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/24 - 19:58:03.153 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/24 - 19:58:03.153 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/24 - 19:58:03.154 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/24 - 19:58:03.157 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/log/2023-10-25/error.log b/log/2023-10-25/error.log new file mode 100644 index 0000000..62b1caa --- /dev/null +++ b/log/2023-10-25/error.log @@ -0,0 +1,11 @@ +[miniapp]2023/10/25 - 18:36:37.534 error C:/Users/Administrator/Desktop/server/service/app/user.go:33 账号创建失败: %v {"error": "Error 1062 (23000): Duplicate entry '17754945397' for key 't_user.deleted'"} +[miniapp]2023/10/25 - 18:36:37.534 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户信息或创建用户失败,错误信息:登录失败 +[miniapp]2023/10/25 - 18:36:37.534 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 登录失败,请联系管理员 +[miniapp]2023/10/25 - 18:36:59.107 error C:/Users/Administrator/Desktop/server/service/app/user.go:33 账号创建失败: %v {"error": "Error 1062 (23000): Duplicate entry '17754945397' for key 't_user.deleted'"} +[miniapp]2023/10/25 - 18:36:59.111 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户信息或创建用户失败,错误信息:登录失败 +[miniapp]2023/10/25 - 18:36:59.111 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 登录失败,请联系管理员 +[miniapp]2023/10/25 - 22:33:30.865 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/25 - 22:39:31.822 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/25 - 22:48:41.964 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/25 - 22:49:04.522 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/25 - 23:51:51.256 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") diff --git a/log/2023-10-25/info.log b/log/2023-10-25/info.log new file mode 100644 index 0000000..ce43db3 --- /dev/null +++ b/log/2023-10-25/info.log @@ -0,0 +1,5 @@ +[miniapp]2023/10/25 - 18:29:32.387 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/25 - 18:29:32.390 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/25 - 18:29:32.390 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/25 - 18:29:32.391 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/25 - 18:29:32.405 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/log/2023-10-27/info.log b/log/2023-10-27/info.log new file mode 100644 index 0000000..96596ad --- /dev/null +++ b/log/2023-10-27/info.log @@ -0,0 +1,15 @@ +[miniapp]2023/10/27 - 11:45:32.628 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/27 - 11:45:32.630 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/27 - 11:45:32.631 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/27 - 11:45:32.632 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/27 - 11:45:32.637 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/27 - 12:10:35.736 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/27 - 12:10:35.739 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/27 - 12:10:35.739 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/27 - 12:10:35.740 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/27 - 12:10:35.749 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/27 - 12:47:41.062 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/27 - 12:47:41.064 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/27 - 12:47:41.066 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/27 - 12:47:41.067 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/27 - 12:47:41.081 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/log/2023-10-31/error.log b/log/2023-10-31/error.log new file mode 100644 index 0000000..ab48fc4 --- /dev/null +++ b/log/2023-10-31/error.log @@ -0,0 +1,46 @@ +[miniapp]2023/10/31 - 20:49:30.974 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/31 - 20:49:57.444 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 20:50:56.668 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/31 - 20:54:19.255 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/31 - 20:54:22.325 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/10/31 - 20:55:06.699 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/31 - 20:55:09.937 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/31 - 20:55:09.978 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/31 - 20:55:17.840 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/31 - 20:56:13.511 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败 +[miniapp]2023/10/31 - 20:57:16.209 error C:/Users/Administrator/Desktop/server/api/v1/app/favorite.go:20 获取收藏列表失败 {"error": "Key: 'GetFavoriteList.UserId' Error:Field validation for 'UserId' failed on the 'required' tag"} +[miniapp]2023/10/31 - 21:02:24.186 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:02:35.331 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:03:50.010 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:04:56.284 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:06:04.107 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:07:00.827 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:07:16.492 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:07:46.859 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 21:08:31.311 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败record not found +[miniapp]2023/10/31 - 21:10:01.493 error C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败unsupported data type: map[reading_num:{SQL:reading_num + ? Vars:[1] WithoutParentheses:false}]: Table not set, please set it like: db.Model(&user) or db.Table("users") +[miniapp]2023/10/31 - 22:28:37.154 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:28:37.154 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:28:39.405 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:28:39.406 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:28:39.533 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:28:39.533 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:28:39.617 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:28:39.617 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:28:42.450 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:28:42.450 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:29:42.352 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:29:42.352 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:29:46.792 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:29:46.792 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:33:00.380 error C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:33:00.380 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 22:47:43.125 error C:/Users/Administrator/Desktop/server/service/app/user.go:138 创建用户Todo列表失败 {"error": "empty slice found"} +[miniapp]2023/10/31 - 22:47:43.126 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 修改用户信息失败:empty slice found +[miniapp]2023/10/31 - 23:36:47.050 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 创建失败 {"error": "invalid character 'l' looking for beginning of value"} +[miniapp]2023/10/31 - 23:36:47.714 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 创建失败 {"error": "invalid character 'l' looking for beginning of value"} +[miniapp]2023/10/31 - 23:36:50.662 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 创建失败 {"error": "invalid character 'l' looking for beginning of value"} +[miniapp]2023/10/31 - 23:39:27.412 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 创建失败 {"error": "invalid character 'l' looking for beginning of value"} +[miniapp]2023/10/31 - 23:40:00.946 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 创建失败 {"error": "json: cannot unmarshal string into Go struct field Vision.userId of type int"} +[miniapp]2023/10/31 - 23:42:42.975 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 参数错误 {"error": "json: cannot unmarshal number into Go struct field Vision.leftEyeVision of type string"} +[miniapp]2023/10/31 - 23:43:21.416 error C:/Users/Administrator/Desktop/server/api/v1/app/vision.go:43 参数错误 {"error": "json: cannot unmarshal number into Go struct field Vision.leftEyeVision of type string"} diff --git a/log/2023-10-31/info.log b/log/2023-10-31/info.log new file mode 100644 index 0000000..c157e39 --- /dev/null +++ b/log/2023-10-31/info.log @@ -0,0 +1,60 @@ +[miniapp]2023/10/31 - 20:24:51.191 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 20:24:53.732 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 20:24:53.733 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 20:24:53.733 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 20:24:53.742 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 20:54:05.435 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 20:54:05.441 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 20:54:05.441 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 20:54:05.442 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 20:54:05.444 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 21:07:42.771 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 21:07:42.774 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 21:07:42.775 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 21:07:42.775 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 21:07:42.789 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 21:08:25.715 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 21:08:25.718 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 21:08:25.718 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 21:08:25.719 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 21:08:25.728 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 21:09:59.776 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 21:09:59.779 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 21:09:59.779 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 21:09:59.780 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 21:09:59.792 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 21:10:45.446 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 21:10:45.448 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 21:10:45.449 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 21:10:45.450 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 21:10:45.455 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 22:39:24.366 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 22:39:24.368 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 22:39:24.369 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 22:39:24.369 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 22:39:24.385 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 23:12:22.869 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 23:12:22.876 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 23:12:22.877 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 23:12:22.878 info C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success +[miniapp]2023/10/31 - 23:12:22.893 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 23:13:39.015 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 23:13:39.018 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 23:13:39.018 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 23:13:39.019 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/10/31 - 23:13:39.022 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 23:35:11.076 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 23:35:11.078 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 23:35:11.079 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 23:35:11.079 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/10/31 - 23:35:11.091 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 23:42:07.185 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 23:42:07.187 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 23:42:07.188 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 23:42:07.188 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/10/31 - 23:42:07.201 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} +[miniapp]2023/10/31 - 23:43:16.970 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/10/31 - 23:43:16.973 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/10/31 - 23:43:16.973 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/10/31 - 23:43:16.974 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/10/31 - 23:43:16.975 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/log/2023-11-01/error.log b/log/2023-11-01/error.log new file mode 100644 index 0000000..0d982e3 --- /dev/null +++ b/log/2023-11-01/error.log @@ -0,0 +1,11 @@ +[miniapp]2023/11/01 - 00:13:11.882 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/01 - 00:13:45.594 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/01 - 00:14:15.126 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/01 - 00:14:23.191 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/01 - 00:14:28.535 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/01 - 00:15:23.979 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/11/01 - 00:15:40.724 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/11/01 - 00:17:03.179 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/11/01 - 00:17:12.790 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/11/01 - 00:17:42.207 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 +[miniapp]2023/11/01 - 00:20:44.193 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型 diff --git a/log/2023-11-01/info.log b/log/2023-11-01/info.log new file mode 100644 index 0000000..e1f7641 --- /dev/null +++ b/log/2023-11-01/info.log @@ -0,0 +1,5 @@ +[miniapp]2023/11/01 - 00:16:23.519 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/11/01 - 00:16:23.521 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/11/01 - 00:16:23.522 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/11/01 - 00:16:23.522 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/11/01 - 00:16:23.528 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/log/2023-11-02/error.log b/log/2023-11-02/error.log new file mode 100644 index 0000000..f640aee --- /dev/null +++ b/log/2023-11-02/error.log @@ -0,0 +1,3 @@ +[miniapp]2023/11/02 - 04:28:58.518 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/02 - 04:29:12.614 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token +[miniapp]2023/11/02 - 04:29:13.638 error D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取Token失败,错误:invalid access token diff --git a/log/2023-11-02/info.log b/log/2023-11-02/info.log new file mode 100644 index 0000000..68e3d5d --- /dev/null +++ b/log/2023-11-02/info.log @@ -0,0 +1,5 @@ +[miniapp]2023/11/02 - 04:09:23.247 info C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success +[miniapp]2023/11/02 - 04:09:23.251 info C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"} +[miniapp]2023/11/02 - 04:09:23.252 info C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler +[miniapp]2023/11/02 - 04:09:23.252 info C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success +[miniapp]2023/11/02 - 04:09:23.267 info C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe.exe run success on {"address": ":8888"} diff --git a/main.go b/main.go new file mode 100644 index 0000000..31e2dd3 --- /dev/null +++ b/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "go.uber.org/zap" + "miniapp/client" + "miniapp/oauth2" + + "miniapp/core" + "miniapp/global" + "miniapp/initialize" +) + +//go:generate go env -w GO111MODULE=on +//go:generate go env -w GOPROXY=https://goproxy.cn,direct +//go:generate go mod tidy +//go:generate go mod download + +// @title Swagger Example API +// @version 0.0.1 +// @description This is a sample Server pets +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name x-token +// @BasePath / +func main() { + global.GVA_VP = core.Viper() // 初始化Viper + initialize.OtherInit() + global.GVA_LOG = core.Zap() // 初始化zap日志库 + zap.ReplaceGlobals(global.GVA_LOG) + global.GVA_DB = initialize.Gorm() // gorm连接数据库 + initialize.Timer() + initialize.DBList() + if global.GVA_DB != nil { + initialize.RegisterTables() // 初始化表 + // 程序结束前关闭数据库链接 + db, _ := global.GVA_DB.DB() + defer db.Close() + } + + client.InitRedisClient() + oauth2.InitOAuth2Server() // 初始化OAuth2服务 + core.RunWindowsServer() +} diff --git a/middleware/auth.go b/middleware/auth.go new file mode 100644 index 0000000..44ad320 --- /dev/null +++ b/middleware/auth.go @@ -0,0 +1,69 @@ +package middleware + +import ( + "git.echol.cn/loser/logger/log" + "github.com/gin-gonic/gin" + r "miniapp/model/common/response" + "miniapp/oauth2" + "strings" +) + +// AuthorizeToken 验证OAuth2生成的Token +func AuthorizeToken() gin.HandlerFunc { + return func(ctx *gin.Context) { + // 判断有无token + tokenStr := ctx.GetHeader("Authorization") + if tokenStr == "" || !strings.HasPrefix(tokenStr, "Bearer ") { + r.FailWithMessage("请先登录", ctx) + ctx.Abort() + return + } + // 先取出用户Token + token, err := oauth2.OAuthServer.ValidationBearerToken(ctx.Request) + if err != nil { + log.Errorf("获取Token失败,错误:%s", err.Error()) + r.FailWithMessage("登录已失效或已在其他地方登录", ctx) + ctx.Abort() + return + } + // 把UserId字段反序列化成map + //info := make(map[string]string) + //if err = json.Unmarshal([]byte(token.GetUserID()), &info); err != nil { + // core.R(ctx).FailWithMessageAndCode("Token数据解析失败", http.StatusUnauthorized) + // ctx.Abort() + // return + //} + //go func() { + // // 异步记录用户在线情况,十分钟没操作就是不在线了 + // rdsKey := "oauth:online:" + info["userId"] + // global.RedisConn.Set(context.Background(), rdsKey, "1", 10*time.Minute) + //}() + // 判断通过,允许放行 + ctx.Request.Header.Add("userId", token.GetUserID()) + ctx.Set("userId", token.GetUserID()) + ctx.Next() + } +} + +// DealLoginUserId 处理登录用户Id +func DealLoginUserId() gin.HandlerFunc { + return func(ctx *gin.Context) { + // 判断有无token + tokenStr := ctx.GetHeader("Authorization") + if tokenStr == "" || !strings.HasPrefix(tokenStr, "Bearer ") { + //ctx.Next() + return + } + // 先取出用户Token + token, err := oauth2.OAuthServer.ValidationBearerToken(ctx.Request) + if err != nil { + //ctx.Next() + return + } + //log.Debugf("本次请求存在正常Token: %v", tokenStr) + // 判断通过,允许放行 + ctx.Request.Header.Add("userId", token.GetUserID()) + ctx.Set("userId", token.GetUserID()) + //ctx.Next() + } +} diff --git a/middleware/casbin_rbac.go b/middleware/casbin_rbac.go new file mode 100644 index 0000000..c182789 --- /dev/null +++ b/middleware/casbin_rbac.go @@ -0,0 +1,38 @@ +package middleware + +import ( + "strconv" + "strings" + + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/common/response" + "miniapp/service" + "miniapp/utils" +) + +var casbinService = service.ServiceGroupApp.SystemServiceGroup.CasbinService + +// CasbinHandler 拦截器 +func CasbinHandler() gin.HandlerFunc { + return func(c *gin.Context) { + if global.GVA_CONFIG.System.Env != "develop" { + waitUse, _ := utils.GetClaims(c) + //获取请求的PATH + path := c.Request.URL.Path + obj := strings.TrimPrefix(path, global.GVA_CONFIG.System.RouterPrefix) + // 获取请求方法 + act := c.Request.Method + // 获取用户的角色 + sub := strconv.Itoa(int(waitUse.AuthorityId)) + e := casbinService.Casbin() // 判断策略中是否存在 + success, _ := e.Enforce(sub, obj, act) + if !success { + response.FailWithDetailed(gin.H{}, "权限不足", c) + c.Abort() + return + } + } + c.Next() + } +} diff --git a/middleware/cors.go b/middleware/cors.go new file mode 100644 index 0000000..2bcaae7 --- /dev/null +++ b/middleware/cors.go @@ -0,0 +1,73 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" + "miniapp/config" + "miniapp/global" + "net/http" +) + +// Cors 直接放行所有跨域请求并放行所有 OPTIONS 方法 +func Cors() gin.HandlerFunc { + return func(c *gin.Context) { + method := c.Request.Method + origin := c.Request.Header.Get("Origin") + c.Header("Access-Control-Allow-Origin", origin) + c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id") + c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT") + c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type, New-Token, New-Expires-At") + c.Header("Access-Control-Allow-Credentials", "true") + + // 放行所有OPTIONS方法 + if method == "OPTIONS" { + c.AbortWithStatus(http.StatusNoContent) + } + // 处理请求 + c.Next() + } +} + +// CorsByRules 按照配置处理跨域请求 +func CorsByRules() gin.HandlerFunc { + // 放行全部 + if global.GVA_CONFIG.Cors.Mode == "allow-all" { + return Cors() + } + return func(c *gin.Context) { + whitelist := checkCors(c.GetHeader("origin")) + + // 通过检查, 添加请求头 + if whitelist != nil { + c.Header("Access-Control-Allow-Origin", whitelist.AllowOrigin) + c.Header("Access-Control-Allow-Headers", whitelist.AllowHeaders) + c.Header("Access-Control-Allow-Methods", whitelist.AllowMethods) + c.Header("Access-Control-Expose-Headers", whitelist.ExposeHeaders) + if whitelist.AllowCredentials { + c.Header("Access-Control-Allow-Credentials", "true") + } + } + + // 严格白名单模式且未通过检查,直接拒绝处理请求 + if whitelist == nil && global.GVA_CONFIG.Cors.Mode == "strict-whitelist" && !(c.Request.Method == "GET" && c.Request.URL.Path == "/health") { + c.AbortWithStatus(http.StatusForbidden) + } else { + // 非严格白名单模式,无论是否通过检查均放行所有 OPTIONS 方法 + if c.Request.Method == http.MethodOptions { + c.AbortWithStatus(http.StatusNoContent) + } + } + + // 处理请求 + c.Next() + } +} + +func checkCors(currentOrigin string) *config.CORSWhitelist { + for _, whitelist := range global.GVA_CONFIG.Cors.Whitelist { + // 遍历配置中的跨域头,寻找匹配项 + if currentOrigin == whitelist.AllowOrigin { + return &whitelist + } + } + return nil +} diff --git a/middleware/email.go b/middleware/email.go new file mode 100644 index 0000000..16b8ba8 --- /dev/null +++ b/middleware/email.go @@ -0,0 +1,60 @@ +package middleware + +import ( + "bytes" + "io" + "strconv" + "time" + + "miniapp/plugin/email/utils" + utils2 "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/system" + "miniapp/service" +) + +var userService = service.ServiceGroupApp.SystemServiceGroup.UserService + +func ErrorToEmail() gin.HandlerFunc { + return func(c *gin.Context) { + var username string + claims, _ := utils2.GetClaims(c) + if claims.Username != "" { + username = claims.Username + } else { + id, _ := strconv.Atoi(c.Request.Header.Get("x-user-id")) + user, err := userService.FindUserById(id) + if err != nil { + username = "Unknown" + } + username = user.Username + } + body, _ := io.ReadAll(c.Request.Body) + // 再重新写回请求体body中,ioutil.ReadAll会清空c.Request.Body中的数据 + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + record := system.SysOperationRecord{ + Ip: c.ClientIP(), + Method: c.Request.Method, + Path: c.Request.URL.Path, + Agent: c.Request.UserAgent(), + Body: string(body), + } + now := time.Now() + + c.Next() + + latency := time.Since(now) + status := c.Writer.Status() + record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String() + str := "接收到的请求为" + record.Body + "\n" + "请求方式为" + record.Method + "\n" + "报错信息如下" + record.ErrorMessage + "\n" + "耗时" + latency.String() + "\n" + if status != 200 { + subject := username + "" + record.Ip + "调用了" + record.Path + "报错了" + if err := utils.ErrorToEmail(subject, str); err != nil { + global.GVA_LOG.Error("ErrorToEmail Failed, err:", zap.Error(err)) + } + } + } +} diff --git a/middleware/error.go b/middleware/error.go new file mode 100644 index 0000000..881cb3c --- /dev/null +++ b/middleware/error.go @@ -0,0 +1,61 @@ +package middleware + +import ( + "net" + "net/http" + "net/http/httputil" + "os" + "runtime/debug" + "strings" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" +) + +// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志 +func GinRecovery(stack bool) gin.HandlerFunc { + return func(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + // Check for a broken connection, as it is not really a + // condition that warrants a panic stack trace. + var brokenPipe bool + if ne, ok := err.(*net.OpError); ok { + if se, ok := ne.Err.(*os.SyscallError); ok { + if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { + brokenPipe = true + } + } + } + + httpRequest, _ := httputil.DumpRequest(c.Request, false) + if brokenPipe { + global.GVA_LOG.Error(c.Request.URL.Path, + zap.Any("error", err), + zap.String("request", string(httpRequest)), + ) + // If the connection is dead, we can't write a status to it. + _ = c.Error(err.(error)) // nolint: errcheck + c.Abort() + return + } + + if stack { + global.GVA_LOG.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + zap.String("stack", string(debug.Stack())), + ) + } else { + global.GVA_LOG.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + ) + } + c.AbortWithStatus(http.StatusInternalServerError) + } + }() + c.Next() + } +} diff --git a/middleware/jwt.go b/middleware/jwt.go new file mode 100644 index 0000000..6c03560 --- /dev/null +++ b/middleware/jwt.go @@ -0,0 +1,79 @@ +package middleware + +import ( + "errors" + "github.com/golang-jwt/jwt/v4" + "strconv" + "time" + + "miniapp/utils" + + "miniapp/global" + "miniapp/model/common/response" + "miniapp/model/system" + "miniapp/service" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +var jwtService = service.ServiceGroupApp.SystemServiceGroup.JwtService + +func JWTAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录 + token := c.Request.Header.Get("x-token") + if token == "" { + response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c) + c.Abort() + return + } + if jwtService.IsBlacklist(token) { + response.FailWithDetailed(gin.H{"reload": true}, "您的帐户异地登陆或令牌失效", c) + c.Abort() + return + } + j := utils.NewJWT() + // parseToken 解析token包含的信息 + claims, err := j.ParseToken(token) + if err != nil { + if errors.Is(err, utils.TokenExpired) { + response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) + c.Abort() + return + } + response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c) + c.Abort() + return + } + + // 已登录用户被管理员禁用 需要使该用户的jwt失效 此处比较消耗性能 如果需要 请自行打开 + // 用户被删除的逻辑 需要优化 此处比较消耗性能 如果需要 请自行打开 + + //if user, err := userService.FindUserByUuid(claims.UUID.String()); err != nil || user.Enable == 2 { + // _ = jwtService.JsonInBlacklist(system.JwtBlacklist{Jwt: token}) + // response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c) + // c.Abort() + //} + if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime { + dr, _ := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) + claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(dr)) + newToken, _ := j.CreateTokenByOldToken(token, *claims) + newClaims, _ := j.ParseToken(newToken) + c.Header("new-token", newToken) + c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10)) + if global.GVA_CONFIG.System.UseMultipoint { + RedisJwtToken, err := jwtService.GetRedisJWT(newClaims.Username) + if err != nil { + global.GVA_LOG.Error("get redis jwt failed", zap.Error(err)) + } else { // 当之前的取成功时才进行拉黑操作 + _ = jwtService.JsonInBlacklist(system.JwtBlacklist{Jwt: RedisJwtToken}) + } + // 无论如何都要记录当前的活跃状态 + _ = jwtService.SetRedisJWT(newToken, newClaims.Username) + } + } + c.Set("claims", claims) + c.Next() + } +} diff --git a/middleware/limit_ip.go b/middleware/limit_ip.go new file mode 100644 index 0000000..fc4542e --- /dev/null +++ b/middleware/limit_ip.go @@ -0,0 +1,92 @@ +package middleware + +import ( + "context" + "errors" + "net/http" + "time" + + "go.uber.org/zap" + + "github.com/gin-gonic/gin" + "miniapp/global" + "miniapp/model/common/response" +) + +type LimitConfig struct { + // GenerationKey 根据业务生成key 下面CheckOrMark查询生成 + GenerationKey func(c *gin.Context) string + // 检查函数,用户可修改具体逻辑,更加灵活 + CheckOrMark func(key string, expire int, limit int) error + // Expire key 过期时间 + Expire int + // Limit 周期时间 + Limit int +} + +func (l LimitConfig) LimitWithTime() gin.HandlerFunc { + return func(c *gin.Context) { + if err := l.CheckOrMark(l.GenerationKey(c), l.Expire, l.Limit); err != nil { + c.JSON(http.StatusOK, gin.H{"code": response.ERROR, "msg": err}) + c.Abort() + return + } else { + c.Next() + } + } +} + +// DefaultGenerationKey 默认生成key +func DefaultGenerationKey(c *gin.Context) string { + return "GVA_Limit" + c.ClientIP() +} + +func DefaultCheckOrMark(key string, expire int, limit int) (err error) { + // 判断是否开启redis + if global.GVA_REDIS == nil { + return err + } + if err = SetLimitWithTime(key, limit, time.Duration(expire)*time.Second); err != nil { + global.GVA_LOG.Error("limit", zap.Error(err)) + } + return err +} + +func DefaultLimit() gin.HandlerFunc { + return LimitConfig{ + GenerationKey: DefaultGenerationKey, + CheckOrMark: DefaultCheckOrMark, + Expire: global.GVA_CONFIG.System.LimitTimeIP, + Limit: global.GVA_CONFIG.System.LimitCountIP, + }.LimitWithTime() +} + +// SetLimitWithTime 设置访问次数 +func SetLimitWithTime(key string, limit int, expiration time.Duration) error { + count, err := global.GVA_REDIS.Exists(context.Background(), key).Result() + if err != nil { + return err + } + if count == 0 { + pipe := global.GVA_REDIS.TxPipeline() + pipe.Incr(context.Background(), key) + pipe.Expire(context.Background(), key, expiration) + _, err = pipe.Exec(context.Background()) + return err + } else { + // 次数 + if times, err := global.GVA_REDIS.Get(context.Background(), key).Int(); err != nil { + return err + } else { + if times >= limit { + if t, err := global.GVA_REDIS.PTTL(context.Background(), key).Result(); err != nil { + return errors.New("请求太过频繁,请稍后再试") + } else { + return errors.New("请求太过频繁, 请 " + t.String() + " 秒后尝试") + } + } else { + return global.GVA_REDIS.Incr(context.Background(), key).Err() + } + } + } +} diff --git a/middleware/loadtls.go b/middleware/loadtls.go new file mode 100644 index 0000000..a17cf65 --- /dev/null +++ b/middleware/loadtls.go @@ -0,0 +1,27 @@ +package middleware + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/unrolled/secure" +) + +// 用https把这个中间件在router里面use一下就好 + +func LoadTls() gin.HandlerFunc { + return func(c *gin.Context) { + middleware := secure.New(secure.Options{ + SSLRedirect: true, + SSLHost: "localhost:443", + }) + err := middleware.Process(c.Writer, c.Request) + if err != nil { + // 如果出现错误,请不要继续 + fmt.Println(err) + return + } + // 继续往下处理 + c.Next() + } +} diff --git a/middleware/logger.go b/middleware/logger.go new file mode 100644 index 0000000..fabc334 --- /dev/null +++ b/middleware/logger.go @@ -0,0 +1,89 @@ +package middleware + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +// LogLayout 日志layout +type LogLayout struct { + Time time.Time + Metadata map[string]interface{} // 存储自定义原数据 + Path string // 访问路径 + Query string // 携带query + Body string // 携带body数据 + IP string // ip地址 + UserAgent string // 代理 + Error string // 错误 + Cost time.Duration // 花费时间 + Source string // 来源 +} + +type Logger struct { + // Filter 用户自定义过滤 + Filter func(c *gin.Context) bool + // FilterKeyword 关键字过滤(key) + FilterKeyword func(layout *LogLayout) bool + // AuthProcess 鉴权处理 + AuthProcess func(c *gin.Context, layout *LogLayout) + // 日志处理 + Print func(LogLayout) + // Source 服务唯一标识 + Source string +} + +func (l Logger) SetLoggerMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + path := c.Request.URL.Path + query := c.Request.URL.RawQuery + var body []byte + if l.Filter != nil && !l.Filter(c) { + body, _ = c.GetRawData() + // 将原body塞回去 + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + } + c.Next() + cost := time.Since(start) + layout := LogLayout{ + Time: time.Now(), + Path: path, + Query: query, + IP: c.ClientIP(), + UserAgent: c.Request.UserAgent(), + Error: strings.TrimRight(c.Errors.ByType(gin.ErrorTypePrivate).String(), "\n"), + Cost: cost, + Source: l.Source, + } + if l.Filter != nil && !l.Filter(c) { + layout.Body = string(body) + } + if l.AuthProcess != nil { + // 处理鉴权需要的信息 + l.AuthProcess(c, &layout) + } + if l.FilterKeyword != nil { + // 自行判断key/value 脱敏等 + l.FilterKeyword(&layout) + } + // 自行处理日志 + l.Print(layout) + } +} + +func DefaultLogger() gin.HandlerFunc { + return Logger{ + Print: func(layout LogLayout) { + // 标准输出,k8s做收集 + v, _ := json.Marshal(layout) + fmt.Println(string(v)) + }, + Source: "GVA", + }.SetLoggerMiddleware() +} diff --git a/middleware/operation.go b/middleware/operation.go new file mode 100644 index 0000000..c247d18 --- /dev/null +++ b/middleware/operation.go @@ -0,0 +1,136 @@ +package middleware + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "miniapp/utils" + + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/system" + "miniapp/service" +) + +var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService + +var respPool sync.Pool +var bufferSize = 1024 + +func init() { + respPool.New = func() interface{} { + return make([]byte, bufferSize) + } +} + +func OperationRecord() gin.HandlerFunc { + return func(c *gin.Context) { + var body []byte + var userId int + if c.Request.Method != http.MethodGet { + var err error + body, err = io.ReadAll(c.Request.Body) + if err != nil { + global.GVA_LOG.Error("read body from request error:", zap.Error(err)) + } else { + c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) + } + } else { + query := c.Request.URL.RawQuery + query, _ = url.QueryUnescape(query) + split := strings.Split(query, "&") + m := make(map[string]string) + for _, v := range split { + kv := strings.Split(v, "=") + if len(kv) == 2 { + m[kv[0]] = kv[1] + } + } + body, _ = json.Marshal(&m) + } + claims, _ := utils.GetClaims(c) + if claims != nil && claims.BaseClaims.ID != 0 { + userId = int(claims.BaseClaims.ID) + } else { + id, err := strconv.Atoi(c.Request.Header.Get("x-user-id")) + if err != nil { + userId = 0 + } + userId = id + } + record := system.SysOperationRecord{ + Ip: c.ClientIP(), + Method: c.Request.Method, + Path: c.Request.URL.Path, + Agent: c.Request.UserAgent(), + Body: string(body), + UserID: userId, + } + + // 上传文件时候 中间件日志进行裁断操作 + if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") { + if len(record.Body) > bufferSize { + // 截断 + newBody := respPool.Get().([]byte) + copy(newBody, record.Body) + record.Body = string(newBody) + defer respPool.Put(newBody) + } + } + + writer := responseBodyWriter{ + ResponseWriter: c.Writer, + body: &bytes.Buffer{}, + } + c.Writer = writer + now := time.Now() + + c.Next() + + latency := time.Since(now) + record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String() + record.Status = c.Writer.Status() + record.Latency = latency + record.Resp = writer.body.String() + + if strings.Contains(c.Writer.Header().Get("Pragma"), "public") || + strings.Contains(c.Writer.Header().Get("Expires"), "0") || + strings.Contains(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") || + strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") || + strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") || + strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") || + strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") || + strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") || + strings.Contains(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") { + if len(record.Resp) > bufferSize { + // 截断 + newBody := respPool.Get().([]byte) + copy(newBody, record.Resp) + record.Resp = string(newBody) + defer respPool.Put(newBody) + } + } + + if err := operationRecordService.CreateSysOperationRecord(record); err != nil { + global.GVA_LOG.Error("create operation record error:", zap.Error(err)) + } + } +} + +type responseBodyWriter struct { + gin.ResponseWriter + body *bytes.Buffer +} + +func (r responseBodyWriter) Write(b []byte) (int, error) { + r.body.Write(b) + return r.ResponseWriter.Write(b) +} diff --git a/model/app/favorite.go b/model/app/favorite.go new file mode 100644 index 0000000..3035f11 --- /dev/null +++ b/model/app/favorite.go @@ -0,0 +1,18 @@ +package app + +import "miniapp/global" + +type Favorite struct { + global.GVA_MODEL + UserId int `json:"userId" gorm:"not null;column:user_id;comment:'用户id'"` // 用户id + FavoriteId int `json:"favoriteId" gorm:"not null;comment:收藏id"` // 收藏id + Cover string `json:"cover" gorm:"size:50;comment:封面"` + Titte string `json:"title" comment:"收藏商品名称"` // 收藏商品名称 + Introduction string `json:"introduction" comment:"简介"` // 简介 + +} + +// TableName 表名 +func (Favorite) TableName() string { + return "sys_favorite" +} diff --git a/model/app/oauth2_client.go b/model/app/oauth2_client.go new file mode 100644 index 0000000..68c4fe4 --- /dev/null +++ b/model/app/oauth2_client.go @@ -0,0 +1,18 @@ +package app + +import ( + "miniapp/global" +) + +// OAuth2Client OAuth2客户端信息 +type OAuth2Client struct { + global.GVA_MODEL + ClientId string `gorm:"type:varchar(255) not null"` + ClientSecret string `gorm:"type:varchar(255) not null"` + Grant string `gorm:"type:varchar(255) not null"` // 允许的授权范围,支持类型: oauth2.GrantType + Domain string `gorm:"type:varchar(255)"` +} + +func (OAuth2Client) TableName() string { + return "t_oauth2_client" +} diff --git a/model/app/request/favorite.go b/model/app/request/favorite.go new file mode 100644 index 0000000..63f4816 --- /dev/null +++ b/model/app/request/favorite.go @@ -0,0 +1,8 @@ +package request + +import "miniapp/model/common/request" + +type GetFavoriteList struct { + request.PageInfo + UserId int `json:"userId" form:"userId" binding:"required"` +} diff --git a/model/app/request/login.go b/model/app/request/login.go new file mode 100644 index 0000000..d6243e8 --- /dev/null +++ b/model/app/request/login.go @@ -0,0 +1,25 @@ +package request + +import "miniapp/model/common/constant" + +type Login struct { + Username string `json:"username" form:"username" binding:"required"` // 邮箱或手机号 + Password string `json:"password" form:"password"` // 密码 + TypeCode constant.LoginType `json:"type" form:"type" binding:"required"` // 登录方式,默认为空,可选值参见自定义类型 + UserIdentity constant.UserIdentity `json:"identity" form:"identity" binding:"required"` // 用户身份,默认为空,可选值参见自定义类型 + NickName string `json:"nickName" form:"nickName"` // 微信昵称 + AvatarUrl string `json:"avatarUrl" form:"avatarUrl"` // 微信头像 +} + +// RefreshToken 刷新Token入参 +type RefreshToken struct { + RefreshToken string `json:"refresh_token" form:"refresh_token" binding:"required"` // 刷新Token + GrantType string `json:"grant_type" form:"grant_type" binding:"required"` // 授权类型,写refresh_token +} + +// DecryptMobile 解密用户手机号入参 +type DecryptMobile struct { + SessionKey string `json:"sessionKey" form:"sessionKey"` // sessionKey + EncryptedData string `json:"encryptedData" form:"encryptedData" binding:"required"` // 加密数据 + Iv string `json:"iv" form:"iv" binding:"required"` // 加密算法的初始向量 +} diff --git a/model/app/request/user.go b/model/app/request/user.go new file mode 100644 index 0000000..f502e13 --- /dev/null +++ b/model/app/request/user.go @@ -0,0 +1,54 @@ +package request + +import ( + "miniapp/model/common/constant" + "miniapp/model/common/request" + "miniapp/model/types" +) + +type BindingWeChat struct { + Code string `json:"code" form:"code" binding:"required"` // 微信code +} + +// GetUserList 获取普通用户 +type GetUserList struct { + request.PageInfo + Phone string `json:"phone" form:"phone"` // 手机号 + Status string `json:"status" form:"status" binding:"oneof='' NORMAL DISABLE"` // 用户状态 + StartAt string `json:"startAt" form:"startAt"` // 开始时间 + EndAt string `json:"endAt" form:"endAt"` // 结束时间 + Name string `json:"name" form:"name"` //用户名 +} + +// ChangeUserInfo 修改普通用户信息 +type ChangeUserInfo struct { + Nickname string `json:"nickname" form:"nickname"` // 昵称 + Avatar string `json:"avatar" form:"avatar"` // 头像 + Phone string `json:"phone" form:"phone"` // 手机号 +} + +// ChangePassword 修改密码 +type ChangePassword struct { + OldPassword string `json:"oldPassword" form:"oldPassword" binding:"required"` // 旧密码 + NewPassword string `json:"newPassword" form:"oldPassword" binding:"required"` // 新密码 + ConfirmPassword string `json:"confirmPassword" form:"oldPassword" binding:"required,eqcsfield=NewPassword"` // 确认新密码 +} + +// SaveUser 保存用户信息 +type SaveUser struct { + Id int `json:"id" form:"id"` // 用户ID + Username string `json:"username" form:"username"` // 用户名 + Nickname string `json:"nickname" form:"nickname"` // 昵称 + Password string `json:"password" form:"password"` // 密码 + Email string `json:"email" form:"email"` // 邮箱 + Phone string `json:"phone" form:"phone"` + Status constant.UserStatus `json:"status" form:"status" binding:"oneof=NORMAL DISABLE"` // 用户状态 + RoleId string `json:"role_id" form:"role_id"` //角色id +} + +type ChangeUserHospital struct { + UserId int `json:"userId" form:"userId" binding:"required"` // 用户ID + HospitalId int `json:"hospitalId" form:"hospitalId" binding:"required"` // 医院ID + IsSurgery int `json:"isSurgery" form:"isSurgery"` // 是否已经手术 0未手术 1已手术 + SurgeryTime *types.DateTime `json:"surgeryTime" form:"surgeryTime"` // 手术时间 +} diff --git a/model/app/request/vision.go b/model/app/request/vision.go new file mode 100644 index 0000000..ab217e1 --- /dev/null +++ b/model/app/request/vision.go @@ -0,0 +1,8 @@ +package request + +import "miniapp/model/common/request" + +type VisionListRequest struct { + request.PageInfo + UserId int `json:"userId" form:"userId"` +} diff --git a/model/app/response/user.go b/model/app/response/user.go new file mode 100644 index 0000000..93519b5 --- /dev/null +++ b/model/app/response/user.go @@ -0,0 +1,50 @@ +package response + +import ( + "miniapp/model/app" + "miniapp/model/common/constant" + "miniapp/model/types" + "miniapp/utils" + "strconv" +) + +type UserItem struct { + Id string `json:"id"` + Phone string `json:"phone"` // 手机号 + Nickname string `json:"nickname"` // 用户名 + CreateAt string `json:"createAt"` // 创建时间 + Avatar string `json:"avatar"` // 头像 + LastLoginAt string `json:"lastLoginAt"` // 最后登录时间 + Status constant.UserStatus `json:"status"` // 状态:1-正常,2-禁用 +} + +type UserVO struct { + Id string `json:"id"` + Nickname string `json:"nickname"` + Email string `json:"email"` + Username string `json:"username"` + Phone string `json:"phone"` + Status constant.UserStatus `json:"status"` + Birthday string `json:"birthday"` + Avatar string `json:"avatar"` + LastLoginAt *types.DateTime `json:"lastLoginAt"` + LastLoginIp *string `json:"lastLoginIp"` + CreatedAt types.DateTime `json:"createdAt"` + TimeNote string `json:"timeNote"` +} + +func (auv *UserVO) ParseOrdinary(u app.User) { + auv.Id = strconv.Itoa(int(u.ID)) + auv.Phone = utils.Desensitization().Phone(u.Phone) + auv.Nickname = u.Nickname + auv.Status = u.Status + auv.LastLoginAt = u.LastLoginAt + auv.Avatar = u.Avatar + auv.CreatedAt = types.DateTime(u.CreatedAt) + + if u.IsSurgery == 1 { + auv.TimeNote = "距离下次复查时间还剩:" + } else { + auv.TimeNote = "距离手术时间还剩:" + } +} diff --git a/model/app/user.go b/model/app/user.go new file mode 100644 index 0000000..74e9a7b --- /dev/null +++ b/model/app/user.go @@ -0,0 +1,26 @@ +package app + +import ( + "miniapp/global" + "miniapp/model/common/constant" + "miniapp/model/types" +) + +type User struct { + global.GVA_MODEL + Phone string `json:"phone" gorm:"index:deleted;type:varchar(255) not null comment '手机号'"` + WechatUnionId *string `json:"wechat_union_id" gorm:"type:varchar(255) comment '微信UnionId'"` + WechatOpenId *string `json:"wechat_open_id" gorm:"type:varchar(255) comment '微信OpenId'"` + Nickname string `json:"nickname" gorm:"type:varchar(255) comment '昵称'"` + Avatar string `json:"avatar" gorm:"type:varchar(255) comment '头像'"` + Status constant.UserStatus `json:"status" gorm:"type:enum('NORMAL','DISABLE'); default:'NORMAL'; not null; comment:'状态 NORMAL-正常;DISABLE-禁用'"` + IsSurgery int `json:"isSurgery" gorm:"default:0;comment:是否已经手术 0未手术 1已手术"` + IsInfo int `json:"isInfo" gorm:"default:0;comment:是否已经填写信息 0未填写 1已填写"` + HospitalId int `json:"hospital_id" gorm:"comment:手术医院"` + SurgeryTime *types.DateTime `json:"surgery_time" gorm:"comment:手术时间"` + LastLoginAt *types.DateTime `json:"last_login_at" gorm:"comment:'最后登录时间'"` +} + +func (User) TableName() string { + return "t_user" +} diff --git a/model/app/vision.go b/model/app/vision.go new file mode 100644 index 0000000..f2a2ffe --- /dev/null +++ b/model/app/vision.go @@ -0,0 +1,16 @@ +package app + +import "miniapp/global" + +type Vision struct { + global.GVA_MODEL + UserId int `json:"userId" form:"userId" gorm:"not null;column:user_id;comment:'用户id'"` // 用户id + //左眼视力 + LeftEyeVision string `json:"leftEyeVision" from:"leftEyeVision" gorm:"not null;comment:左眼视力"` // 左眼视力 + //右眼视力 + RightEyeVision string `json:"rightEyeVision" from:"rightEyeVision" gorm:"not null;comment:右眼视力"` // 右眼视力 +} + +func (v Vision) TableName() string { + return "t_vision" +} diff --git a/model/cache/user.go b/model/cache/user.go new file mode 100644 index 0000000..7534269 --- /dev/null +++ b/model/cache/user.go @@ -0,0 +1,19 @@ +package cache + +import "encoding/json" + +// UserInfo 登录用的用户信息结构体 +type UserInfo struct { + UserType string `json:"userType"` // 用户类型 + RoleCodes string `json:"roleCodes"` // 角色代码 + UserId string `json:"userId"` // 用户Id +} + +// String 实现Stringer接口 +func (i UserInfo) String() (string, error) { + b, err := json.Marshal(i) + if err != nil { + return "", err + } + return string(b), nil +} diff --git a/model/common/article.go b/model/common/article.go new file mode 100644 index 0000000..7a30b40 --- /dev/null +++ b/model/common/article.go @@ -0,0 +1,15 @@ +package common + +import "miniapp/global" + +type Article struct { + global.GVA_MODEL + Title string `json:"title" form:"title" gorm:"column:title;comment:标题;type:varchar(255);size:255;"` + Content string `json:"content" form:"content" gorm:"column:content;comment:内容;type:longtext;"` + CoverImg string `json:"cover_img" form:"coverImg" gorm:"column:cover_img;comment:封面图;type:varchar(255);size:255;"` + ReadingNum int `json:"reading_num" form:"reading_num" gorm:"column:reading_num;comment:阅读量;type:int;size:10;"` +} + +func (Article) TableName() string { + return "articles" +} diff --git a/model/common/banner.go b/model/common/banner.go new file mode 100644 index 0000000..5ed016b --- /dev/null +++ b/model/common/banner.go @@ -0,0 +1,12 @@ +package common + +import ( + "miniapp/global" +) + +type Banner struct { + global.GVA_MODEL + ImgUrl string `json:"imgUrl" gorm:"type:varchar(255) comment '图片地址'"` + Link string `json:"link" gorm:"type:varchar(255) comment '跳转链接'"` + Status int `json:"status" gorm:"type:tinyint(1) comment '是否显示 0-不显示 1-显示'"` +} diff --git a/model/common/constant/login.go b/model/common/constant/login.go new file mode 100644 index 0000000..872622d --- /dev/null +++ b/model/common/constant/login.go @@ -0,0 +1,16 @@ +package constant + +// LoginType 自定义登录类型 +type LoginType string + +// 登录类型 +const ( + LoginTypeWeChatMiniApp LoginType = "wechat_mini_app" // 微信小程序登录 + LoginTypeSms LoginType = "sms" // 短信验证码登录 + LoginTypePassword LoginType = "password" // 密码登录 +) + +// String 转换为字符串 +func (t LoginType) String() string { + return string(t) +} diff --git a/model/common/constant/order.go b/model/common/constant/order.go new file mode 100644 index 0000000..439074c --- /dev/null +++ b/model/common/constant/order.go @@ -0,0 +1,133 @@ +package constant + +import "fmt" + +// PaymentType 支付方式 +type PaymentType int + +const ( + PaymentTypeNone PaymentType = iota // 未知 0 + PaymentTypeWeChatMiniApp // 微信小程序 1 + PaymentTypeWeChatH5 // 微信H5 2 + PaymentTypeWeChatAPP // 微信APP 3 + PaymentTypeExchangeCode // 兑换码白嫖 4 +) + +// 支付渠道描述 +var paymentTypeMap = map[PaymentType]string{ + PaymentTypeNone: "未知", + PaymentTypeWeChatMiniApp: "微信小程序", + PaymentTypeWeChatH5: "微信H5", + PaymentTypeWeChatAPP: "微信APP", + PaymentTypeExchangeCode: "兑换码", +} + +// 处理为看得懂的状态 +func (pt PaymentType) String() string { + if str, ok := paymentTypeMap[pt]; ok { + return str + } + return fmt.Sprintf("未知状态(%d)", pt) +} + +// MarshalJSON JSON序列化的时候转换为中文 +func (pt PaymentType) MarshalJSON() ([]byte, error) { + return []byte(`"` + pt.String() + `"`), nil +} + +// ===================================================================================================================== + +type PayStatus int + +const ( + PayStatusNot PayStatus = iota // 未支付 + PayStatusSuccess // 支付成功 + PayStatusFail // 支付失败 + PayStatusRefunded // 已退款 +) + +var payStatusMap = map[PayStatus]string{ + PayStatusNot: "未支付", + PayStatusSuccess: "支付成功", + PayStatusFail: "支付失败", + PayStatusRefunded: "已退款", +} + +// 处理为看得懂的状态 +func (ps PayStatus) String() string { + if str, ok := payStatusMap[ps]; ok { + return str + } + return fmt.Sprintf("未知状态(%d)", ps) +} + +// MarshalJSON JSON序列化的时候转换为中文 +func (ps PayStatus) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, ps.String())), nil +} + +// ===================================================================================================================== + +type OrderStatus int + +const ( + OrderStatusWait OrderStatus = iota // 待支付 0 + OrderStatusUsing // 生效中 1 + OrderStatusFailure // 已失效 2 + OrderStatusApplicationRefund // 已申请退款 3 + OrderStatusRefunding // 退款中 4 + OrderStatusRefunded // 已退款 5 + OrderStatusCanceled // 已取消 6 + OrderStatusEnd // 已完成 7 +) + +var orderStatusMap = map[OrderStatus]string{ + OrderStatusWait: "待支付", + OrderStatusUsing: "生效中", + OrderStatusFailure: "已失效", + OrderStatusApplicationRefund: "已申请退款", + OrderStatusRefunding: "退款中", + OrderStatusRefunded: "已退款", + OrderStatusCanceled: "已取消", + OrderStatusEnd: "已完成", +} + +// 处理为看得懂的状态 +func (os OrderStatus) String() string { + if str, ok := orderStatusMap[os]; ok { + return str + } + return fmt.Sprintf("未知状态(%d)", os) +} + +// MarshalJSON JSON序列化的时候转换为中文 +func (os OrderStatus) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, os.String())), nil +} + +// ===================================================================================================================== + +type OrderServiceType int + +const ( + OrderServiceTypeProduct OrderServiceType = iota + 1 // 普通商品 + OrderServiceTypeActivity // 活动 +) + +var orderServiceTypeMap = map[OrderServiceType]string{ + OrderServiceTypeProduct: "服务", + OrderServiceTypeActivity: "活动", +} + +// 处理为看得懂的状态 +func (os OrderServiceType) String() string { + if str, ok := orderServiceTypeMap[os]; ok { + return str + } + return fmt.Sprintf("未知状态(%d)", os) +} + +// MarshalJSON JSON序列化的时候转换为中文 +func (os OrderServiceType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%s"`, os.String())), nil +} diff --git a/model/common/constant/rds_key.go b/model/common/constant/rds_key.go new file mode 100644 index 0000000..cb798c6 --- /dev/null +++ b/model/common/constant/rds_key.go @@ -0,0 +1,8 @@ +package constant + +const ( + OAuth2RedisKey = "oauth:token:" // Token缓存前缀 + OAuth2UserCacheKey = "oauth:user:" // 用户缓存前缀 + ApiAntiShakeKey = "api:antishake:" // 防抖锁 + WeChatSessionKey = "wechat:session:" // 小程序用户SessionKey前缀 +) diff --git a/model/common/constant/user.go b/model/common/constant/user.go new file mode 100644 index 0000000..2484ad8 --- /dev/null +++ b/model/common/constant/user.go @@ -0,0 +1,88 @@ +package constant + +import ( + "fmt" +) + +// UserStatus 用户状态 +type UserStatus string + +const ( + UserStatusActive UserStatus = "NORMAL" // 用户状态正常 + UserStatusDisabled UserStatus = "DISABLE" // 已禁用用户 +) + +// 状态对应的描述 +var userStatusMap = map[UserStatus]string{ + UserStatusActive: "正常", + UserStatusDisabled: "已禁用", +} + +// 处理为看得懂的状态 +func (s UserStatus) String() string { + if str, ok := userStatusMap[s]; ok { + return str + } + return string(s) +} + +// ===================================================================================================================== + +// UserSex 性别 +type UserSex int + +const ( + UserSexNone UserSex = iota // 不知道是啥 + UserSexMale // 男 + UserSexFemale // 女 + UserSexOther // 其他性别 +) + +// 状态对应的描述 +var userSexMap = map[UserSex]string{ + UserSexNone: "无性别", + UserSexMale: "男", + UserSexFemale: "女", + UserSexOther: "其他", +} + +// FromString 中文取性别 +func (s UserSex) FromString(sex string) UserSex { + result := UserSexNone + for key, value := range userSexMap { + if sex == value { + result = key + break + } + } + return result +} + +// 处理为看得懂的状态 +func (s UserSex) String() string { + if str, ok := userSexMap[s]; ok { + return str + } + //return strconv.Itoa(int(s)) + return fmt.Sprintf("UserSex(%d)", int(s)) +} + +// MarshalJSON JSON序列化的时候转换为中文 +func (s UserSex) MarshalJSON() ([]byte, error) { + return []byte(`"` + s.String() + `"`), nil +} + +// ===================================================================================================================== + +// UserIdentity 用户身份 +type UserIdentity string + +const ( + UserIdentityAdmin UserIdentity = "admin" // 管理员 + UserIdentityUser UserIdentity = "user" // 普通用户 +) + +// String implements the Stringer interface. +func (t UserIdentity) String() string { + return string(t) +} diff --git a/model/common/hospital.go b/model/common/hospital.go new file mode 100644 index 0000000..828ae6d --- /dev/null +++ b/model/common/hospital.go @@ -0,0 +1,16 @@ +package common + +import "miniapp/global" + +type Hospital struct { + global.GVA_MODEL + Name string `json:"name" form:"name" gorm:"comment:医院名称;"` + Addr string `json:"addr" form:"addr" gorm:"comment:医院地址;"` + Phone string `json:"phone" form:"phone" gorm:"comment:医院电话;"` + Notes []Notes `json:"notes" form:"notes" gorm:"many2many:hospital_notes;comment:注意事项;"` + Todos []Todos `json:"todos" form:"todos" gorm:"many2many:hospital_todos;comment:任务列表;"` +} + +func (h Hospital) TableName() string { + return "sys_hospital" +} diff --git a/model/common/notes.go b/model/common/notes.go new file mode 100644 index 0000000..1aa9f99 --- /dev/null +++ b/model/common/notes.go @@ -0,0 +1,13 @@ +package common + +import "miniapp/global" + +type Notes struct { + global.GVA_MODEL + Content string `json:"content" form:"content" gorm:"comment:注意事项内容;"` + NotesTime string `json:"notes_time" form:"notes_time" gorm:"comment:注意事项时间;"` //手术前、手术后、术中 +} + +func (n Notes) TableName() string { + return "sys_notes" +} diff --git a/model/common/request/common.go b/model/common/request/common.go new file mode 100644 index 0000000..22007e9 --- /dev/null +++ b/model/common/request/common.go @@ -0,0 +1,28 @@ +package request + +// PageInfo Paging common input parameter structure +type PageInfo struct { + Page int `json:"page" form:"page"` // 页码 + PageSize int `json:"pageSize" form:"pageSize"` // 每页大小 + Keyword string `json:"keyword" form:"keyword"` //关键字 +} + +// GetById Find by id structure +type GetById struct { + ID int `json:"id" form:"id"` // 主键ID +} + +func (r *GetById) Uint() uint { + return uint(r.ID) +} + +type IdsReq struct { + Ids []int `json:"ids" form:"ids"` +} + +// GetAuthorityId Get role by id structure +type GetAuthorityId struct { + AuthorityId int `json:"authorityId" form:"authorityId"` // 角色ID +} + +type Empty struct{} diff --git a/model/common/response/common.go b/model/common/response/common.go new file mode 100644 index 0000000..7461096 --- /dev/null +++ b/model/common/response/common.go @@ -0,0 +1,8 @@ +package response + +type PageResult struct { + List interface{} `json:"list"` + Total int64 `json:"total"` + Page int `json:"page"` + PageSize int `json:"pageSize"` +} diff --git a/model/common/response/response.go b/model/common/response/response.go new file mode 100644 index 0000000..733f757 --- /dev/null +++ b/model/common/response/response.go @@ -0,0 +1,55 @@ +package response + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +type Response struct { + Code int `json:"code"` + Data interface{} `json:"data"` + Msg string `json:"msg"` +} + +const ( + ERROR = 7 + SUCCESS = 0 +) + +func Result(code int, data interface{}, msg string, c *gin.Context) { + // 开始时间 + c.JSON(http.StatusOK, Response{ + code, + data, + msg, + }) +} + +func Ok(c *gin.Context) { + Result(SUCCESS, map[string]interface{}{}, "操作成功", c) +} + +func OkWithMessage(message string, c *gin.Context) { + Result(SUCCESS, map[string]interface{}{}, message, c) +} + +func OkWithData(data interface{}, c *gin.Context) { + Result(SUCCESS, data, "查询成功", c) +} + +func OkWithDetailed(data interface{}, message string, c *gin.Context) { + Result(SUCCESS, data, message, c) +} + +func Fail(c *gin.Context) { + Result(ERROR, map[string]interface{}{}, "操作失败", c) +} + +func FailWithMessage(message string, c *gin.Context) { + Result(ERROR, map[string]interface{}{}, message, c) +} + +func FailWithDetailed(data interface{}, message string, c *gin.Context) { + Result(ERROR, data, message, c) +} diff --git a/model/common/todos.go b/model/common/todos.go new file mode 100644 index 0000000..353b84a --- /dev/null +++ b/model/common/todos.go @@ -0,0 +1,13 @@ +package common + +import "miniapp/global" + +type Todos struct { + // 任务列表 + global.GVA_MODEL + Content string `json:"content" form:"content" gorm:"comment:任务内容;"` +} + +func (t Todos) TableName() string { + return "sys_todos" +} diff --git a/model/common/user_todo.go b/model/common/user_todo.go new file mode 100644 index 0000000..2663a2b --- /dev/null +++ b/model/common/user_todo.go @@ -0,0 +1,14 @@ +package common + +import "miniapp/global" + +type UserTodo struct { + global.GVA_MODEL + UserId int `json:"userId" form:"userId" gorm:"comment:用户id;"` + Content string `json:"content" form:"content" gorm:"comment:任务内容;"` + IsFinish int `json:"isFinish" form:"isFinish" gorm:"comment:是否完成;"` +} + +func (u UserTodo) TableName() string { + return "t_user_todo" +} diff --git a/model/example/exa_breakpoint_continue.go b/model/example/exa_breakpoint_continue.go new file mode 100644 index 0000000..d811f81 --- /dev/null +++ b/model/example/exa_breakpoint_continue.go @@ -0,0 +1,24 @@ +package example + +import ( + "miniapp/global" +) + +// file struct, 文件结构体 +type ExaFile struct { + global.GVA_MODEL + FileName string + FileMd5 string + FilePath string + ExaFileChunk []ExaFileChunk + ChunkTotal int + IsFinish bool +} + +// file chunk struct, 切片结构体 +type ExaFileChunk struct { + global.GVA_MODEL + ExaFileID uint + FileChunkNumber int + FileChunkPath string +} diff --git a/model/example/exa_customer.go b/model/example/exa_customer.go new file mode 100644 index 0000000..734e144 --- /dev/null +++ b/model/example/exa_customer.go @@ -0,0 +1,15 @@ +package example + +import ( + "miniapp/global" + "miniapp/model/system" +) + +type ExaCustomer struct { + global.GVA_MODEL + CustomerName string `json:"customerName" form:"customerName" gorm:"comment:客户名"` // 客户名 + CustomerPhoneData string `json:"customerPhoneData" form:"customerPhoneData" gorm:"comment:客户手机号"` // 客户手机号 + SysUserID uint `json:"sysUserId" form:"sysUserId" gorm:"comment:管理ID"` // 管理ID + SysUserAuthorityID uint `json:"sysUserAuthorityID" form:"sysUserAuthorityID" gorm:"comment:管理角色ID"` // 管理角色ID + SysUser system.SysUser `json:"sysUser" form:"sysUser" gorm:"comment:管理详情"` // 管理详情 +} diff --git a/model/example/exa_file_upload_download.go b/model/example/exa_file_upload_download.go new file mode 100644 index 0000000..72b44a1 --- /dev/null +++ b/model/example/exa_file_upload_download.go @@ -0,0 +1,17 @@ +package example + +import ( + "miniapp/global" +) + +type ExaFileUploadAndDownload struct { + global.GVA_MODEL + Name string `json:"name" gorm:"comment:文件名"` // 文件名 + Url string `json:"url" gorm:"comment:文件地址"` // 文件地址 + Tag string `json:"tag" gorm:"comment:文件标签"` // 文件标签 + Key string `json:"key" gorm:"comment:编号"` // 编号 +} + +func (ExaFileUploadAndDownload) TableName() string { + return "exa_file_upload_and_downloads" +} diff --git a/model/example/response/exa_breakpoint_continue.go b/model/example/response/exa_breakpoint_continue.go new file mode 100644 index 0000000..fffb933 --- /dev/null +++ b/model/example/response/exa_breakpoint_continue.go @@ -0,0 +1,11 @@ +package response + +import "miniapp/model/example" + +type FilePathResponse struct { + FilePath string `json:"filePath"` +} + +type FileResponse struct { + File example.ExaFile `json:"file"` +} diff --git a/model/example/response/exa_customer.go b/model/example/response/exa_customer.go new file mode 100644 index 0000000..22cb599 --- /dev/null +++ b/model/example/response/exa_customer.go @@ -0,0 +1,7 @@ +package response + +import "miniapp/model/example" + +type ExaCustomerResponse struct { + Customer example.ExaCustomer `json:"customer"` +} diff --git a/model/example/response/exa_file_upload_download.go b/model/example/response/exa_file_upload_download.go new file mode 100644 index 0000000..b47f2c7 --- /dev/null +++ b/model/example/response/exa_file_upload_download.go @@ -0,0 +1,7 @@ +package response + +import "miniapp/model/example" + +type ExaFileResponse struct { + File example.ExaFileUploadAndDownload `json:"file"` +} diff --git a/model/system/request/jwt.go b/model/system/request/jwt.go new file mode 100644 index 0000000..6388202 --- /dev/null +++ b/model/system/request/jwt.go @@ -0,0 +1,21 @@ +package request + +import ( + "github.com/gofrs/uuid/v5" + jwt "github.com/golang-jwt/jwt/v4" +) + +// Custom claims structure +type CustomClaims struct { + BaseClaims + BufferTime int64 + jwt.RegisteredClaims +} + +type BaseClaims struct { + UUID uuid.UUID + ID uint + Username string + NickName string + AuthorityId uint +} diff --git a/model/system/request/sys_api.go b/model/system/request/sys_api.go new file mode 100644 index 0000000..41516f9 --- /dev/null +++ b/model/system/request/sys_api.go @@ -0,0 +1,14 @@ +package request + +import ( + "miniapp/model/common/request" + "miniapp/model/system" +) + +// api分页条件查询及排序结构体 +type SearchApiParams struct { + system.SysApi + request.PageInfo + OrderKey string `json:"orderKey"` // 排序 + Desc bool `json:"desc"` // 排序方式:升序false(默认)|降序true +} diff --git a/model/system/request/sys_authority_btn.go b/model/system/request/sys_authority_btn.go new file mode 100644 index 0000000..98493ff --- /dev/null +++ b/model/system/request/sys_authority_btn.go @@ -0,0 +1,7 @@ +package request + +type SysAuthorityBtnReq struct { + MenuID uint `json:"menuID"` + AuthorityId uint `json:"authorityId"` + Selected []uint `json:"selected"` +} diff --git a/model/system/request/sys_auto_history.go b/model/system/request/sys_auto_history.go new file mode 100644 index 0000000..cc6e6ae --- /dev/null +++ b/model/system/request/sys_auto_history.go @@ -0,0 +1,13 @@ +package request + +import "miniapp/model/common/request" + +type SysAutoHistory struct { + request.PageInfo +} + +// GetById Find by id structure +type RollBack struct { + ID int `json:"id" form:"id"` // 主键ID + DeleteTable bool `json:"deleteTable" form:"deleteTable"` // 是否删除表 +} diff --git a/model/system/request/sys_casbin.go b/model/system/request/sys_casbin.go new file mode 100644 index 0000000..0c07ae6 --- /dev/null +++ b/model/system/request/sys_casbin.go @@ -0,0 +1,26 @@ +package request + +// Casbin info structure +type CasbinInfo struct { + Path string `json:"path"` // 路径 + Method string `json:"method"` // 方法 +} + +// Casbin structure for input parameters +type CasbinInReceive struct { + AuthorityId uint `json:"authorityId"` // 权限id + CasbinInfos []CasbinInfo `json:"casbinInfos"` +} + +func DefaultCasbin() []CasbinInfo { + return []CasbinInfo{ + {Path: "/menu/getMenu", Method: "POST"}, + {Path: "/jwt/jsonInBlacklist", Method: "POST"}, + {Path: "/base/login", Method: "POST"}, + {Path: "/user/admin_register", Method: "POST"}, + {Path: "/user/changePassword", Method: "POST"}, + {Path: "/user/setUserAuthority", Method: "POST"}, + {Path: "/user/setUserInfo", Method: "PUT"}, + {Path: "/user/getUserInfo", Method: "GET"}, + } +} diff --git a/model/system/request/sys_chatgpt.go b/model/system/request/sys_chatgpt.go new file mode 100644 index 0000000..19d00db --- /dev/null +++ b/model/system/request/sys_chatgpt.go @@ -0,0 +1,11 @@ +package request + +import ( + "miniapp/model/common/request" + "miniapp/model/system" +) + +type ChatGptRequest struct { + system.ChatGpt + request.PageInfo +} diff --git a/model/system/request/sys_dictionary.go b/model/system/request/sys_dictionary.go new file mode 100644 index 0000000..07ff3e9 --- /dev/null +++ b/model/system/request/sys_dictionary.go @@ -0,0 +1,11 @@ +package request + +import ( + "miniapp/model/common/request" + "miniapp/model/system" +) + +type SysDictionarySearch struct { + system.SysDictionary + request.PageInfo +} diff --git a/model/system/request/sys_dictionary_detail.go b/model/system/request/sys_dictionary_detail.go new file mode 100644 index 0000000..e4bacda --- /dev/null +++ b/model/system/request/sys_dictionary_detail.go @@ -0,0 +1,11 @@ +package request + +import ( + "miniapp/model/common/request" + "miniapp/model/system" +) + +type SysDictionaryDetailSearch struct { + system.SysDictionaryDetail + request.PageInfo +} diff --git a/model/system/request/sys_init.go b/model/system/request/sys_init.go new file mode 100644 index 0000000..9a97755 --- /dev/null +++ b/model/system/request/sys_init.go @@ -0,0 +1,102 @@ +package request + +import ( + "fmt" + "miniapp/config" + "os" +) + +type InitDB struct { + DBType string `json:"dbType"` // 数据库类型 + Host string `json:"host"` // 服务器地址 + Port string `json:"port"` // 数据库连接端口 + UserName string `json:"userName"` // 数据库用户名 + Password string `json:"password"` // 数据库密码 + DBName string `json:"dbName" binding:"required"` // 数据库名 + DBPath string `json:"dbPath"` // sqlite数据库文件路径 +} + +// MysqlEmptyDsn msyql 空数据库 建库链接 +// Author SliverHorn +func (i *InitDB) MysqlEmptyDsn() string { + if i.Host == "" { + i.Host = "127.0.0.1" + } + if i.Port == "" { + i.Port = "3306" + } + return fmt.Sprintf("%s:%s@tcp(%s:%s)/", i.UserName, i.Password, i.Host, i.Port) +} + +// PgsqlEmptyDsn pgsql 空数据库 建库链接 +// Author SliverHorn +func (i *InitDB) PgsqlEmptyDsn() string { + if i.Host == "" { + i.Host = "127.0.0.1" + } + if i.Port == "" { + i.Port = "5432" + } + return "host=" + i.Host + " user=" + i.UserName + " password=" + i.Password + " port=" + i.Port + " dbname=" + "postgres" + " " + "sslmode=disable TimeZone=Asia/Shanghai" +} + +// SqliteEmptyDsn sqlite 空数据库 建库链接 +// Author Kafumio +func (i *InitDB) SqliteEmptyDsn() string { + separator := string(os.PathSeparator) + return i.DBPath + separator + i.DBName + ".db" +} + +// ToMysqlConfig 转换 config.Mysql +// Author [SliverHorn](https://github.com/SliverHorn) +func (i *InitDB) ToMysqlConfig() config.Mysql { + return config.Mysql{ + GeneralDB: config.GeneralDB{ + Path: i.Host, + Port: i.Port, + Dbname: i.DBName, + Username: i.UserName, + Password: i.Password, + MaxIdleConns: 10, + MaxOpenConns: 100, + LogMode: "error", + Config: "charset=utf8mb4&parseTime=True&loc=Local", + }, + } +} + +// ToPgsqlConfig 转换 config.Pgsql +// Author [SliverHorn](https://github.com/SliverHorn) +func (i *InitDB) ToPgsqlConfig() config.Pgsql { + return config.Pgsql{ + GeneralDB: config.GeneralDB{ + Path: i.Host, + Port: i.Port, + Dbname: i.DBName, + Username: i.UserName, + Password: i.Password, + MaxIdleConns: 10, + MaxOpenConns: 100, + LogMode: "error", + Config: "sslmode=disable TimeZone=Asia/Shanghai", + }, + } +} + +// ToSqliteConfig 转换 config.Sqlite +// Author [Kafumio](https://github.com/Kafumio) +func (i *InitDB) ToSqliteConfig() config.Sqlite { + return config.Sqlite{ + GeneralDB: config.GeneralDB{ + Path: i.DBPath, + Port: i.Port, + Dbname: i.DBName, + Username: i.UserName, + Password: i.Password, + MaxIdleConns: 10, + MaxOpenConns: 100, + LogMode: "error", + Config: "", + }, + } +} diff --git a/model/system/request/sys_menu.go b/model/system/request/sys_menu.go new file mode 100644 index 0000000..06d7f6b --- /dev/null +++ b/model/system/request/sys_menu.go @@ -0,0 +1,27 @@ +package request + +import ( + "miniapp/global" + "miniapp/model/system" +) + +// Add menu authority info structure +type AddMenuAuthorityInfo struct { + Menus []system.SysBaseMenu `json:"menus"` + AuthorityId uint `json:"authorityId"` // 角色ID +} + +func DefaultMenu() []system.SysBaseMenu { + return []system.SysBaseMenu{{ + GVA_MODEL: global.GVA_MODEL{ID: 1}, + ParentId: "0", + Path: "dashboard", + Name: "dashboard", + Component: "view/dashboard/index.vue", + Sort: 1, + Meta: system.Meta{ + Title: "仪表盘", + Icon: "setting", + }, + }} +} diff --git a/model/system/request/sys_operation_record.go b/model/system/request/sys_operation_record.go new file mode 100644 index 0000000..f0cc2fc --- /dev/null +++ b/model/system/request/sys_operation_record.go @@ -0,0 +1,11 @@ +package request + +import ( + "miniapp/model/common/request" + "miniapp/model/system" +) + +type SysOperationRecordSearch struct { + system.SysOperationRecord + request.PageInfo +} diff --git a/model/system/request/sys_user.go b/model/system/request/sys_user.go new file mode 100644 index 0000000..df0d911 --- /dev/null +++ b/model/system/request/sys_user.go @@ -0,0 +1,56 @@ +package request + +import ( + "miniapp/model/system" +) + +// Register User register structure +type Register struct { + Username string `json:"userName" example:"用户名"` + Password string `json:"passWord" example:"密码"` + NickName string `json:"nickName" example:"昵称"` + HeaderImg string `json:"headerImg" example:"头像链接"` + AuthorityId uint `json:"authorityId" swaggertype:"string" example:"int 角色id"` + Enable int `json:"enable" swaggertype:"string" example:"int 是否启用"` + AuthorityIds []uint `json:"authorityIds" swaggertype:"string" example:"[]uint 角色id"` + Phone string `json:"phone" example:"电话号码"` + Email string `json:"email" example:"电子邮箱"` +} + +// User login structure +type Login struct { + Username string `json:"username"` // 用户名 + Password string `json:"password"` // 密码 + Captcha string `json:"captcha"` // 验证码 + CaptchaId string `json:"captchaId"` // 验证码ID +} + +// Modify password structure +type ChangePasswordReq struct { + ID uint `json:"-"` // 从 JWT 中提取 user id,避免越权 + Password string `json:"password"` // 密码 + NewPassword string `json:"newPassword"` // 新密码 +} + +// Modify user's auth structure +type SetUserAuth struct { + AuthorityId uint `json:"authorityId"` // 角色ID +} + +// Modify user's auth structure +type SetUserAuthorities struct { + ID uint + AuthorityIds []uint `json:"authorityIds"` // 角色ID +} + +type ChangeUserInfo struct { + ID uint `gorm:"primarykey"` // 主键ID + NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称 + Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号 + AuthorityIds []uint `json:"authorityIds" gorm:"-"` // 角色ID + Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱 + HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像 + SideMode string `json:"sideMode" gorm:"comment:用户侧边主题"` // 用户侧边主题 + Enable int `json:"enable" gorm:"comment:冻结用户"` //冻结用户 + Authorities []system.SysAuthority `json:"-" gorm:"many2many:sys_user_authority;"` +} diff --git a/model/system/response/sys_api.go b/model/system/response/sys_api.go new file mode 100644 index 0000000..5c22eae --- /dev/null +++ b/model/system/response/sys_api.go @@ -0,0 +1,11 @@ +package response + +import "miniapp/model/system" + +type SysAPIResponse struct { + Api system.SysApi `json:"api"` +} + +type SysAPIListResponse struct { + Apis []system.SysApi `json:"apis"` +} diff --git a/model/system/response/sys_authority.go b/model/system/response/sys_authority.go new file mode 100644 index 0000000..4fa99fb --- /dev/null +++ b/model/system/response/sys_authority.go @@ -0,0 +1,12 @@ +package response + +import "miniapp/model/system" + +type SysAuthorityResponse struct { + Authority system.SysAuthority `json:"authority"` +} + +type SysAuthorityCopyResponse struct { + Authority system.SysAuthority `json:"authority"` + OldAuthorityId uint `json:"oldAuthorityId"` // 旧角色ID +} diff --git a/model/system/response/sys_authority_btn.go b/model/system/response/sys_authority_btn.go new file mode 100644 index 0000000..2f772cf --- /dev/null +++ b/model/system/response/sys_authority_btn.go @@ -0,0 +1,5 @@ +package response + +type SysAuthorityBtnRes struct { + Selected []uint `json:"selected"` +} diff --git a/model/system/response/sys_auto_code.go b/model/system/response/sys_auto_code.go new file mode 100644 index 0000000..1e44005 --- /dev/null +++ b/model/system/response/sys_auto_code.go @@ -0,0 +1,16 @@ +package response + +type Db struct { + Database string `json:"database" gorm:"column:database"` +} + +type Table struct { + TableName string `json:"tableName" gorm:"column:table_name"` +} + +type Column struct { + DataType string `json:"dataType" gorm:"column:data_type"` + ColumnName string `json:"columnName" gorm:"column:column_name"` + DataTypeLong string `json:"dataTypeLong" gorm:"column:data_type_long"` + ColumnComment string `json:"columnComment" gorm:"column:column_comment"` +} diff --git a/model/system/response/sys_auto_code_history.go b/model/system/response/sys_auto_code_history.go new file mode 100644 index 0000000..071844c --- /dev/null +++ b/model/system/response/sys_auto_code_history.go @@ -0,0 +1,14 @@ +package response + +import "time" + +type AutoCodeHistory struct { + ID uint `json:"ID" gorm:"column:id"` + CreatedAt time.Time `json:"CreatedAt" gorm:"column:created_at"` + UpdatedAt time.Time `json:"UpdatedAt" gorm:"column:updated_at"` + BusinessDB string `json:"businessDB" gorm:"column:business_db"` + TableName string `json:"tableName" gorm:"column:table_name"` + StructName string `json:"structName" gorm:"column:struct_name"` + StructCNName string `json:"structCNName" gorm:"column:struct_cn_name"` + Flag int `json:"flag" gorm:"column:flag"` +} diff --git a/model/system/response/sys_captcha.go b/model/system/response/sys_captcha.go new file mode 100644 index 0000000..0c3995a --- /dev/null +++ b/model/system/response/sys_captcha.go @@ -0,0 +1,8 @@ +package response + +type SysCaptchaResponse struct { + CaptchaId string `json:"captchaId"` + PicPath string `json:"picPath"` + CaptchaLength int `json:"captchaLength"` + OpenCaptcha bool `json:"openCaptcha"` +} diff --git a/model/system/response/sys_casbin.go b/model/system/response/sys_casbin.go new file mode 100644 index 0000000..da53122 --- /dev/null +++ b/model/system/response/sys_casbin.go @@ -0,0 +1,9 @@ +package response + +import ( + "miniapp/model/system/request" +) + +type PolicyPathResponse struct { + Paths []request.CasbinInfo `json:"paths"` +} diff --git a/model/system/response/sys_chatgpt.go b/model/system/response/sys_chatgpt.go new file mode 100644 index 0000000..693a92a --- /dev/null +++ b/model/system/response/sys_chatgpt.go @@ -0,0 +1,4 @@ +package response + +type ChatGptResponse struct { +} diff --git a/model/system/response/sys_menu.go b/model/system/response/sys_menu.go new file mode 100644 index 0000000..b57ac51 --- /dev/null +++ b/model/system/response/sys_menu.go @@ -0,0 +1,15 @@ +package response + +import "miniapp/model/system" + +type SysMenusResponse struct { + Menus []system.SysMenu `json:"menus"` +} + +type SysBaseMenusResponse struct { + Menus []system.SysBaseMenu `json:"menus"` +} + +type SysBaseMenuResponse struct { + Menu system.SysBaseMenu `json:"menu"` +} diff --git a/model/system/response/sys_system.go b/model/system/response/sys_system.go new file mode 100644 index 0000000..d1e98ad --- /dev/null +++ b/model/system/response/sys_system.go @@ -0,0 +1,7 @@ +package response + +import "miniapp/config" + +type SysConfigResponse struct { + Config config.Server `json:"config"` +} diff --git a/model/system/response/sys_user.go b/model/system/response/sys_user.go new file mode 100644 index 0000000..835fe97 --- /dev/null +++ b/model/system/response/sys_user.go @@ -0,0 +1,15 @@ +package response + +import ( + "miniapp/model/system" +) + +type SysUserResponse struct { + User system.SysUser `json:"user"` +} + +type LoginResponse struct { + User system.SysUser `json:"user"` + Token string `json:"token"` + ExpiresAt int64 `json:"expiresAt"` +} diff --git a/model/system/sys_api.go b/model/system/sys_api.go new file mode 100644 index 0000000..ee38c75 --- /dev/null +++ b/model/system/sys_api.go @@ -0,0 +1,17 @@ +package system + +import ( + "miniapp/global" +) + +type SysApi struct { + global.GVA_MODEL + Path string `json:"path" gorm:"comment:api路径"` // api路径 + Description string `json:"description" gorm:"comment:api中文描述"` // api中文描述 + ApiGroup string `json:"apiGroup" gorm:"comment:api组"` // api组 + Method string `json:"method" gorm:"default:POST;comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE +} + +func (SysApi) TableName() string { + return "sys_apis" +} diff --git a/model/system/sys_authority.go b/model/system/sys_authority.go new file mode 100644 index 0000000..01c5efa --- /dev/null +++ b/model/system/sys_authority.go @@ -0,0 +1,23 @@ +package system + +import ( + "time" +) + +type SysAuthority struct { + CreatedAt time.Time // 创建时间 + UpdatedAt time.Time // 更新时间 + DeletedAt *time.Time `sql:"index"` + AuthorityId uint `json:"authorityId" gorm:"not null;unique;primary_key;comment:角色ID;size:90"` // 角色ID + AuthorityName string `json:"authorityName" gorm:"comment:角色名"` // 角色名 + ParentId *uint `json:"parentId" gorm:"comment:父角色ID"` // 父角色ID + DataAuthorityId []*SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id;"` + Children []SysAuthority `json:"children" gorm:"-"` + SysBaseMenus []SysBaseMenu `json:"menus" gorm:"many2many:sys_authority_menus;"` + Users []SysUser `json:"-" gorm:"many2many:sys_user_authority;"` + DefaultRouter string `json:"defaultRouter" gorm:"comment:默认菜单;default:dashboard"` // 默认菜单(默认dashboard) +} + +func (SysAuthority) TableName() string { + return "sys_authorities" +} diff --git a/model/system/sys_authority_btn.go b/model/system/sys_authority_btn.go new file mode 100644 index 0000000..e005984 --- /dev/null +++ b/model/system/sys_authority_btn.go @@ -0,0 +1,8 @@ +package system + +type SysAuthorityBtn struct { + AuthorityId uint `gorm:"comment:角色ID"` + SysMenuID uint `gorm:"comment:菜单ID"` + SysBaseMenuBtnID uint `gorm:"comment:菜单按钮ID"` + SysBaseMenuBtn SysBaseMenuBtn ` gorm:"comment:按钮详情"` +} diff --git a/model/system/sys_authority_menu.go b/model/system/sys_authority_menu.go new file mode 100644 index 0000000..ae39063 --- /dev/null +++ b/model/system/sys_authority_menu.go @@ -0,0 +1,19 @@ +package system + +type SysMenu struct { + SysBaseMenu + MenuId string `json:"menuId" gorm:"comment:菜单ID"` + AuthorityId uint `json:"-" gorm:"comment:角色ID"` + Children []SysMenu `json:"children" gorm:"-"` + Parameters []SysBaseMenuParameter `json:"parameters" gorm:"foreignKey:SysBaseMenuID;references:MenuId"` + Btns map[string]uint `json:"btns" gorm:"-"` +} + +type SysAuthorityMenu struct { + MenuId string `json:"menuId" gorm:"comment:菜单ID;column:sys_base_menu_id"` + AuthorityId string `json:"-" gorm:"comment:角色ID;column:sys_authority_authority_id"` +} + +func (s SysAuthorityMenu) TableName() string { + return "sys_authority_menus" +} diff --git a/model/system/sys_auto_code.go b/model/system/sys_auto_code.go new file mode 100644 index 0000000..34af7a5 --- /dev/null +++ b/model/system/sys_auto_code.go @@ -0,0 +1,119 @@ +package system + +import ( + "errors" + "go/token" + "strings" + + "miniapp/global" +) + +// AutoCodeStruct 初始版本自动化代码工具 +type AutoCodeStruct struct { + StructName string `json:"structName"` // Struct名称 + TableName string `json:"tableName"` // 表名 + PackageName string `json:"packageName"` // 文件名称 + HumpPackageName string `json:"humpPackageName"` // go文件名称 + Abbreviation string `json:"abbreviation"` // Struct简称 + Description string `json:"description"` // Struct中文名称 + AutoCreateApiToSql bool `json:"autoCreateApiToSql"` // 是否自动创建api + AutoCreateResource bool `json:"autoCreateResource"` // 是否自动创建资源标识 + AutoMoveFile bool `json:"autoMoveFile"` // 是否自动移动文件 + BusinessDB string `json:"businessDB"` // 业务数据库 + Fields []*Field `json:"fields,omitempty"` + HasTimer bool + DictTypes []string `json:"-"` + Package string `json:"package"` + PackageT string `json:"-"` + NeedValid bool `json:"-"` + NeedSort bool `json:"-"` + HasPic bool `json:"-"` + HasRichText bool `json:"-"` + HasFile bool `json:"-"` + NeedJSON bool `json:"-"` +} + +func (a *AutoCodeStruct) Pretreatment() { + a.KeyWord() + a.SuffixTest() +} + +// KeyWord 是go关键字的处理加上 _ ,防止编译报错 +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *AutoCodeStruct) KeyWord() { + if token.IsKeyword(a.Abbreviation) { + a.Abbreviation = a.Abbreviation + "_" + } +} + +// SuffixTest 处理_test 后缀 +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *AutoCodeStruct) SuffixTest() { + if strings.HasSuffix(a.HumpPackageName, "test") { + a.HumpPackageName = a.HumpPackageName + "_" + } +} + +type Field struct { + FieldName string `json:"fieldName"` // Field名 + FieldDesc string `json:"fieldDesc"` // 中文名 + FieldType string `json:"fieldType"` // Field数据类型 + FieldJson string `json:"fieldJson"` // FieldJson + DataTypeLong string `json:"dataTypeLong"` // 数据库字段长度 + Comment string `json:"comment"` // 数据库字段描述 + ColumnName string `json:"columnName"` // 数据库字段 + FieldSearchType string `json:"fieldSearchType"` // 搜索条件 + DictType string `json:"dictType"` // 字典 + Require bool `json:"require"` // 是否必填 + ErrorText string `json:"errorText"` // 校验失败文字 + Clearable bool `json:"clearable"` // 是否可清空 + Sort bool `json:"sort"` // 是否增加排序 +} + +var ErrAutoMove error = errors.New("创建代码成功并移动文件成功") + +type SysAutoCode struct { + global.GVA_MODEL + PackageName string `json:"packageName" gorm:"comment:包名"` + Label string `json:"label" gorm:"comment:展示名"` + Desc string `json:"desc" gorm:"comment:描述"` +} + +type AutoPlugReq struct { + PlugName string `json:"plugName"` // 必然大写开头 + Snake string `json:"snake"` // 后端自动转为 snake + RouterGroup string `json:"routerGroup"` + HasGlobal bool `json:"hasGlobal"` + HasRequest bool `json:"hasRequest"` + HasResponse bool `json:"hasResponse"` + NeedModel bool `json:"needModel"` + Global []AutoPlugInfo `json:"global,omitempty"` + Request []AutoPlugInfo `json:"request,omitempty"` + Response []AutoPlugInfo `json:"response,omitempty"` +} + +func (a *AutoPlugReq) CheckList() { + a.Global = bind(a.Global) + a.Request = bind(a.Request) + a.Response = bind(a.Response) + +} +func bind(req []AutoPlugInfo) []AutoPlugInfo { + var r []AutoPlugInfo + for _, info := range req { + if info.Effective() { + r = append(r, info) + } + } + return r +} + +type AutoPlugInfo struct { + Key string `json:"key"` + Type string `json:"type"` + Desc string `json:"desc"` +} + +func (a AutoPlugInfo) Effective() bool { + return a.Key != "" && a.Type != "" && a.Desc != "" +} diff --git a/model/system/sys_autocode_history.go b/model/system/sys_autocode_history.go new file mode 100644 index 0000000..5bb6d4e --- /dev/null +++ b/model/system/sys_autocode_history.go @@ -0,0 +1,40 @@ +package system + +import ( + "strconv" + "strings" + + "miniapp/global" + "miniapp/model/common/request" +) + +// SysAutoCodeHistory 自动迁移代码记录,用于回滚,重放使用 +type SysAutoCodeHistory struct { + global.GVA_MODEL + Package string `json:"package"` + BusinessDB string `json:"businessDB"` + TableName string `json:"tableName"` + RequestMeta string `gorm:"type:text" json:"requestMeta,omitempty"` // 前端传入的结构化信息 + AutoCodePath string `gorm:"type:text" json:"autoCodePath,omitempty"` // 其他meta信息 path;path + InjectionMeta string `gorm:"type:text" json:"injectionMeta,omitempty"` // 注入的内容 RouterPath@functionName@RouterString; + StructName string `json:"structName"` + StructCNName string `json:"structCNName"` + ApiIDs string `json:"apiIDs,omitempty"` // api表注册内容 + Flag int `json:"flag"` // 表示对应状态 0 代表创建, 1 代表回滚 ... +} + +// ToRequestIds ApiIDs 转换 request.IdsReq +// Author [SliverHorn](https://github.com/SliverHorn) +func (m *SysAutoCodeHistory) ToRequestIds() request.IdsReq { + if m.ApiIDs == "" { + return request.IdsReq{} + } + slice := strings.Split(m.ApiIDs, ";") + ids := make([]int, 0, len(slice)) + length := len(slice) + for i := 0; i < length; i++ { + id, _ := strconv.ParseInt(slice[i], 10, 32) + ids = append(ids, int(id)) + } + return request.IdsReq{Ids: ids} +} diff --git a/model/system/sys_base_menu.go b/model/system/sys_base_menu.go new file mode 100644 index 0000000..33fc7af --- /dev/null +++ b/model/system/sys_base_menu.go @@ -0,0 +1,42 @@ +package system + +import ( + "miniapp/global" +) + +type SysBaseMenu struct { + global.GVA_MODEL + MenuLevel uint `json:"-"` + ParentId string `json:"parentId" gorm:"comment:父菜单ID"` // 父菜单ID + Path string `json:"path" gorm:"comment:路由path"` // 路由path + Name string `json:"name" gorm:"comment:路由name"` // 路由name + Hidden bool `json:"hidden" gorm:"comment:是否在列表隐藏"` // 是否在列表隐藏 + Component string `json:"component" gorm:"comment:对应前端文件路径"` // 对应前端文件路径 + Sort int `json:"sort" gorm:"comment:排序标记"` // 排序标记 + Meta `json:"meta" gorm:"embedded;comment:附加属性"` // 附加属性 + SysAuthoritys []SysAuthority `json:"authoritys" gorm:"many2many:sys_authority_menus;"` + Children []SysBaseMenu `json:"children" gorm:"-"` + Parameters []SysBaseMenuParameter `json:"parameters"` + MenuBtn []SysBaseMenuBtn `json:"menuBtn"` +} + +type Meta struct { + ActiveName string `json:"activeName" gorm:"comment:高亮菜单"` + KeepAlive bool `json:"keepAlive" gorm:"comment:是否缓存"` // 是否缓存 + DefaultMenu bool `json:"defaultMenu" gorm:"comment:是否是基础路由(开发中)"` // 是否是基础路由(开发中) + Title string `json:"title" gorm:"comment:菜单名"` // 菜单名 + Icon string `json:"icon" gorm:"comment:菜单图标"` // 菜单图标 + CloseTab bool `json:"closeTab" gorm:"comment:自动关闭tab"` // 自动关闭tab +} + +type SysBaseMenuParameter struct { + global.GVA_MODEL + SysBaseMenuID uint + Type string `json:"type" gorm:"comment:地址栏携带参数为params还是query"` // 地址栏携带参数为params还是query + Key string `json:"key" gorm:"comment:地址栏携带参数的key"` // 地址栏携带参数的key + Value string `json:"value" gorm:"comment:地址栏携带参数的值"` // 地址栏携带参数的值 +} + +func (SysBaseMenu) TableName() string { + return "sys_base_menus" +} diff --git a/model/system/sys_chatgpt.go b/model/system/sys_chatgpt.go new file mode 100644 index 0000000..97e83ae --- /dev/null +++ b/model/system/sys_chatgpt.go @@ -0,0 +1,22 @@ +package system + +type ChatGpt struct { + DBName string `json:"dbname,omitempty"` + Chat string `json:"chat,omitempty"` + ChatID string `json:"chatID,omitempty"` +} + +type SysChatGptOption struct { + SK string `json:"sk"` +} + +type ChatField struct { + TABLE_NAME string + COLUMN_NAME string + COLUMN_COMMENT string +} + +type ChatFieldNoTable struct { + COLUMN_NAME string + COLUMN_COMMENT string +} diff --git a/model/system/sys_dictionary.go b/model/system/sys_dictionary.go new file mode 100644 index 0000000..2943432 --- /dev/null +++ b/model/system/sys_dictionary.go @@ -0,0 +1,20 @@ +// 自动生成模板SysDictionary +package system + +import ( + "miniapp/global" +) + +// 如果含有time.Time 请自行import time包 +type SysDictionary struct { + global.GVA_MODEL + Name string `json:"name" form:"name" gorm:"column:name;comment:字典名(中)"` // 字典名(中) + Type string `json:"type" form:"type" gorm:"column:type;comment:字典名(英)"` // 字典名(英) + Status *bool `json:"status" form:"status" gorm:"column:status;comment:状态"` // 状态 + Desc string `json:"desc" form:"desc" gorm:"column:desc;comment:描述"` // 描述 + SysDictionaryDetails []SysDictionaryDetail `json:"sysDictionaryDetails" form:"sysDictionaryDetails"` +} + +func (SysDictionary) TableName() string { + return "sys_dictionaries" +} diff --git a/model/system/sys_dictionary_detail.go b/model/system/sys_dictionary_detail.go new file mode 100644 index 0000000..e9ef656 --- /dev/null +++ b/model/system/sys_dictionary_detail.go @@ -0,0 +1,21 @@ +// 自动生成模板SysDictionaryDetail +package system + +import ( + "miniapp/global" +) + +// 如果含有time.Time 请自行import time包 +type SysDictionaryDetail struct { + global.GVA_MODEL + Label string `json:"label" form:"label" gorm:"column:label;comment:展示值"` // 展示值 + Value int `json:"value" form:"value" gorm:"column:value;comment:字典值"` // 字典值 + Extend string `json:"extend" form:"extend" gorm:"column:extend;comment:扩展值"` // 扩展值 + Status *bool `json:"status" form:"status" gorm:"column:status;comment:启用状态"` // 启用状态 + Sort int `json:"sort" form:"sort" gorm:"column:sort;comment:排序标记"` // 排序标记 + SysDictionaryID int `json:"sysDictionaryID" form:"sysDictionaryID" gorm:"column:sys_dictionary_id;comment:关联标记"` // 关联标记 +} + +func (SysDictionaryDetail) TableName() string { + return "sys_dictionary_details" +} diff --git a/model/system/sys_jwt_blacklist.go b/model/system/sys_jwt_blacklist.go new file mode 100644 index 0000000..4dd3316 --- /dev/null +++ b/model/system/sys_jwt_blacklist.go @@ -0,0 +1,10 @@ +package system + +import ( + "miniapp/global" +) + +type JwtBlacklist struct { + global.GVA_MODEL + Jwt string `gorm:"type:text;comment:jwt"` +} diff --git a/model/system/sys_menu_btn.go b/model/system/sys_menu_btn.go new file mode 100644 index 0000000..16a141e --- /dev/null +++ b/model/system/sys_menu_btn.go @@ -0,0 +1,10 @@ +package system + +import "miniapp/global" + +type SysBaseMenuBtn struct { + global.GVA_MODEL + Name string `json:"name" gorm:"comment:按钮关键key"` + Desc string `json:"desc" gorm:"按钮备注"` + SysBaseMenuID uint `json:"sysBaseMenuID" gorm:"comment:菜单ID"` +} diff --git a/model/system/sys_operation_record.go b/model/system/sys_operation_record.go new file mode 100644 index 0000000..314ef9c --- /dev/null +++ b/model/system/sys_operation_record.go @@ -0,0 +1,24 @@ +// 自动生成模板SysOperationRecord +package system + +import ( + "time" + + "miniapp/global" +) + +// 如果含有time.Time 请自行import time包 +type SysOperationRecord struct { + global.GVA_MODEL + Ip string `json:"ip" form:"ip" gorm:"column:ip;comment:请求ip"` // 请求ip + Method string `json:"method" form:"method" gorm:"column:method;comment:请求方法"` // 请求方法 + Path string `json:"path" form:"path" gorm:"column:path;comment:请求路径"` // 请求路径 + Status int `json:"status" form:"status" gorm:"column:status;comment:请求状态"` // 请求状态 + Latency time.Duration `json:"latency" form:"latency" gorm:"column:latency;comment:延迟" swaggertype:"string"` // 延迟 + Agent string `json:"agent" form:"agent" gorm:"column:agent;comment:代理"` // 代理 + ErrorMessage string `json:"error_message" form:"error_message" gorm:"column:error_message;comment:错误信息"` // 错误信息 + Body string `json:"body" form:"body" gorm:"type:text;column:body;comment:请求Body"` // 请求Body + Resp string `json:"resp" form:"resp" gorm:"type:text;column:resp;comment:响应Body"` // 响应Body + UserID int `json:"user_id" form:"user_id" gorm:"column:user_id;comment:用户id"` // 用户id + User SysUser `json:"user"` +} diff --git a/model/system/sys_system.go b/model/system/sys_system.go new file mode 100644 index 0000000..055659f --- /dev/null +++ b/model/system/sys_system.go @@ -0,0 +1,10 @@ +package system + +import ( + "miniapp/config" +) + +// 配置文件结构体 +type System struct { + Config config.Server `json:"config"` +} diff --git a/model/system/sys_user.go b/model/system/sys_user.go new file mode 100644 index 0000000..a6667ff --- /dev/null +++ b/model/system/sys_user.go @@ -0,0 +1,28 @@ +package system + +import ( + "github.com/gofrs/uuid/v5" + "miniapp/global" +) + +type SysUser struct { + global.GVA_MODEL + UUID uuid.UUID `json:"uuid" gorm:"index;comment:用户UUID"` // 用户UUID + Username string `json:"userName" gorm:"index;comment:用户登录名"` // 用户登录名 + Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码 + NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称 + SideMode string `json:"sideMode" gorm:"default:dark;comment:用户侧边主题"` // 用户侧边主题 + HeaderImg string `json:"headerImg" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像 + BaseColor string `json:"baseColor" gorm:"default:#fff;comment:基础颜色"` // 基础颜色 + ActiveColor string `json:"activeColor" gorm:"default:#1890ff;comment:活跃颜色"` // 活跃颜色 + AuthorityId uint `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID + Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"` + Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"` + Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号 + Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱 + Enable int `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` //用户是否被冻结 1正常 2冻结 +} + +func (SysUser) TableName() string { + return "sys_users" +} diff --git a/model/system/sys_user_authority.go b/model/system/sys_user_authority.go new file mode 100644 index 0000000..1aa83cb --- /dev/null +++ b/model/system/sys_user_authority.go @@ -0,0 +1,11 @@ +package system + +// SysUserAuthority 是 sysUser 和 sysAuthority 的连接表 +type SysUserAuthority struct { + SysUserId uint `gorm:"column:sys_user_id"` + SysAuthorityAuthorityId uint `gorm:"column:sys_authority_authority_id"` +} + +func (s *SysUserAuthority) TableName() string { + return "sys_user_authority" +} diff --git a/model/types/date.go b/model/types/date.go new file mode 100644 index 0000000..edcb82c --- /dev/null +++ b/model/types/date.go @@ -0,0 +1,111 @@ +package types + +import ( + "database/sql/driver" + "fmt" + "time" +) + +// 默认时间格式 +const dateFormat = "2006-01-02 15:04:05.000" + +// DateTime 自定义时间类型 +type DateTime time.Time + +// Scan implements the Scanner interface. +func (dt *DateTime) Scan(value any) error { + // mysql 内部日期的格式可能是 2006-01-02 15:04:05 +0800 CST 格式,所以检出的时候还需要进行一次格式化 + tTime, _ := time.ParseInLocation("2006-01-02 15:04:05 +0800 CST", value.(time.Time).String(), time.Local) + *dt = DateTime(tTime) + return nil +} + +// Value implements the driver Valuer interface. +func (dt DateTime) Value() (driver.Value, error) { + // 0001-01-01 00:00:00 属于空值,遇到空值解析成 null 即可 + if dt.String() == "0001-01-01 00:00:00.000" { + return nil, nil + } + return []byte(dt.Format(dateFormat)), nil +} + +// 用于 fmt.Println 和后续验证场景 +func (dt DateTime) String() string { + return dt.Format(dateFormat) +} + +// Format 格式化 +func (dt DateTime) Format(fm string) string { + return time.Time(dt).Format(fm) +} + +// After 时间比较 +func (dt *DateTime) After(now time.Time) bool { + return time.Time(*dt).After(now) +} + +// Before 时间比较 +func (dt *DateTime) Before(now time.Time) bool { + return time.Time(*dt).Before(now) +} + +// IBefore 时间比较 +func (dt *DateTime) IBefore(now DateTime) bool { + return dt.Before(time.Time(now)) +} + +// SubTime 对比 +func (dt DateTime) SubTime(t time.Time) time.Duration { + return dt.ToTime().Sub(t) +} + +// Sub 对比 +func (dt DateTime) Sub(t DateTime) time.Duration { + return dt.ToTime().Sub(t.ToTime()) +} + +// ToTime 转换为golang的时间类型 +func (dt DateTime) ToTime() time.Time { + return time.Time(dt).Local() +} + +// IsNil 是否为空值 +func (dt DateTime) IsNil() bool { + return dt.Format(dateFormat) == "0001-01-01 00:00:00.000" +} + +// Unix 实现Unix函数 +func (dt DateTime) Unix() int64 { + return dt.ToTime().Unix() +} + +// EndOfCentury 获取本世纪最后时间 +func (dt DateTime) EndOfCentury() DateTime { + yearEnd := time.Now().Local().Year()/100*100 + 99 + return DateTime(time.Date(yearEnd, 12, 31, 23, 59, 59, 999999999, time.Local)) +} + +// ======== 序列化 ======== + +// MarshalJSON 时间到字符串 +func (dt DateTime) MarshalJSON() ([]byte, error) { + // 过滤掉空数据 + if dt.IsNil() { + return []byte("\"\""), nil + } + output := fmt.Sprintf(`"%s"`, dt.Format("2006-01-02 15:04:05")) + return []byte(output), nil +} + +// UnmarshalJSON 字符串到时间 +func (dt *DateTime) UnmarshalJSON(b []byte) error { + if len(b) == 2 { + *dt = DateTime{} + return nil + } + // 解析指定的格式 + //now, err := time.ParseInLocation(`"`+dateFormat+`"`, string(b), time.Local) + now, err := time.ParseInLocation(dateFormat, string(b), time.Local) + *dt = DateTime(now) + return err +} diff --git a/oauth2/handle/oauth2.go b/oauth2/handle/oauth2.go new file mode 100644 index 0000000..2dd0a95 --- /dev/null +++ b/oauth2/handle/oauth2.go @@ -0,0 +1,178 @@ +package handle + +import ( + "context" + "encoding/json" + er "errors" + "fmt" + "git.echol.cn/loser/logger/log" + "github.com/go-oauth2/oauth2/v4" + "github.com/go-oauth2/oauth2/v4/errors" + "miniapp/client" + "miniapp/model/app" + "miniapp/model/cache" + "miniapp/model/common/constant" + "miniapp/service" + "net/http" + "strconv" + "strings" + "time" +) + +// UserAuthorizationHandler 获取用户Id +func UserAuthorizationHandler(w http.ResponseWriter, r *http.Request) (userId string, err error) { + loginType := constant.LoginType(r.FormValue("type")) // 登录类型 + userIdentity := constant.UserIdentity(r.FormValue("identity")) // 身份类型 + account := r.FormValue("username") // 用户传入账号(或者授权Code) + nikeName := r.FormValue("nickName") // 昵称 + avatarUrl := r.FormValue("avatarUrl") // 头像 + + log.Debugf("预处理用户登录请求,身份类型: %v => 登录类型: %s => 账号: %v", userIdentity, loginType, account) + + var roleCode []string + // 处理用户Id + switch userIdentity { + case constant.UserIdentityAdmin: + // 管理员 + case constant.UserIdentityUser: + // 普通用户 + userId, err = getUser(account, loginType, nikeName, avatarUrl) + default: + err = er.New("未知的用户身份类型") + } + + if err != nil { + return + } + + // 组装缓存用户信息 + m := cache.UserInfo{ + RoleCodes: strings.Join(roleCode, ","), + UserId: userId, + UserType: userIdentity.String(), + } + userInfo, err := m.String() + if err != nil { + err = errors.New("登录失败,请联系管理员") + return + } + if err = client.Redis.Set(context.Background(), fmt.Sprintf("%s%v", constant.OAuth2UserCacheKey, userId), userInfo, time.Hour*24*7).Err(); err != nil { + log.Errorf("缓存用户信息失败,用户ID:%v,错误信息:%s", userId, err.Error()) + err = errors.New("登录失败,请联系管理员") + return + } + + return +} + +// LoginWithPassword 账号密码登录模式 +func LoginWithPassword(ctx context.Context, clientId, userId, password string) (userID string, err error) { + log.Debugf("[%v]处理登录请求,用户Id:%s --> %s", clientId, userId, password) + + userID = userId + return +} + +// CheckClient 检查是否允许该客户端通过该授权模式请求令牌 +func CheckClient(clientID string, grant oauth2.GrantType) (allowed bool, err error) { + // 解出租户Id和传入的客户端Id + c := app.OAuth2Client{ClientId: clientID} + + // 查询客户端配置信息 + if err = service.ServiceGroupApp.AppServiceGroup.Oauth2ClientService.FindOne(&c); err != nil { + log.Errorf("客户端信息查询失败: %v", err.Error()) + err = errors.New("客户端信息查询失败: " + err.Error()) + allowed = false + return + } + // 判断是否包含授权范围 + allowed = strings.Contains(c.Grant, string(grant)) + if !allowed { + err = errors.New("不受允许的grant_type") + } + return +} + +// ExtensionFields 自定义响应Token的扩展字段 +func ExtensionFields(ti oauth2.TokenInfo) (fieldsValue map[string]any) { + fieldsValue = map[string]any{} + fieldsValue["license"] = "Made By Lee" + + // 取出用户信息 + var userInfo app.User + tid, _ := strconv.Atoi(ti.GetUserID()) + userInfo.ID = uint(tid) + //if err := repository.User().GetUser(&userInfo); err != nil { + // return + //} + service.ServiceGroupApp.AppServiceGroup.UserService.GetUser(&userInfo) + fieldsValue["newUser"] = time.Now().Sub(userInfo.CreatedAt).Minutes() <= 1 + + fieldsValue["nickname"] = userInfo.Nickname + fieldsValue["phone"] = userInfo.Phone + fieldsValue["userId"] = userInfo.ID + fieldsValue["avatar"] = userInfo.Avatar + fieldsValue["TimeNote"] = userInfo.Avatar + + return +} + +// ResponseToken 返回Token生成结果 +func ResponseToken(w http.ResponseWriter, data map[string]any, header http.Header, statusCode ...int) error { + log.Debugf("返回Token原始数据: %+v", data) + type response struct { + Code int `json:"code"` + Data map[string]any `json:"data"` + Msg string `json:"message"` + } + + status := http.StatusOK + msg := "login success" + if len(statusCode) > 0 && statusCode[0] > 0 { + status = statusCode[0] + msg = fmt.Sprintf("%v", data["error_description"]) + // 处理特殊返回 - 刷新Token到期了 + switch data["error"] { + case "invalid_grant": + msg = "登录已过期,请重新授权登录" + case "invalid_request": + msg = "登录参数错误" + default: + log.Errorf("收到未定义的登录错误: %v", data["error_description"]) + } + data = nil + } + + res := response{ + Code: status, + Msg: msg, + Data: data, + } + + jsonBytes, err := json.Marshal(res) + if err != nil { + return err + } + w.Header().Set("Content-Type", "application/json;charset=UTF-8") + w.Header().Set("Cache-Control", "no-store") + w.Header().Set("Pragma", "no-cache") + + for key := range header { + w.Header().Set(key, header.Get(key)) + } + + w.WriteHeader(status) + _, err = w.Write(jsonBytes) + if err != nil { + log.Errorf("返回Token失败: %v", err.Error()) + return err + } + return err +} + +// InternalErrorHandler 自定义内部错误处理 +func InternalErrorHandler(err error) (re *errors.Response) { + re = errors.NewResponse(err, http.StatusUnauthorized) + re.Description = err.Error() + return +} diff --git a/oauth2/handle/token_gen.go b/oauth2/handle/token_gen.go new file mode 100644 index 0000000..1cb6945 --- /dev/null +++ b/oauth2/handle/token_gen.go @@ -0,0 +1,65 @@ +package handle + +import ( + "context" + "encoding/json" + "fmt" + "git.echol.cn/loser/logger/log" + "github.com/go-oauth2/oauth2/v4" + "github.com/google/uuid" + "miniapp/client" + "miniapp/model/common/constant" + "strings" +) + +func NewAccessGenerate() *AccessGenerate { + return &AccessGenerate{} +} + +type AccessGenerate struct { +} + +// Token 手动实现Token生成,直接生成UUID,替换掉自带的那个憨得一批的长长的字符串 +func (ag *AccessGenerate) Token(ctx context.Context, data *oauth2.GenerateBasic, isGenRefresh bool) (string, string, error) { + u, _ := uuid.NewUUID() + access := strings.ReplaceAll(u.String(), "-", "") + + refresh := "" + if isGenRefresh { + u, _ = uuid.NewUUID() + refresh = strings.ReplaceAll(u.String(), "-", "") + } + // 生成新的,清理掉旧的 + ag.clearOldToken(ctx, data.UserID) + // 返回结果 + return access, refresh, nil +} + +// 清理掉旧的Token和RefreshToken +func (ag *AccessGenerate) clearOldToken(ctx context.Context, userId string) { + rdsKey := constant.OAuth2RedisKey + "*-*" + // 获取所有符合条件的Key + keys, err := client.Redis.Keys(ctx, rdsKey).Result() + if err != nil { + log.Errorf("清理失败,跳过清理") + return + } + for _, key := range keys { + dataStr, err := client.Redis.Get(ctx, key).Result() + if err != nil { + continue + } + var m map[string]any + if err = json.Unmarshal([]byte(dataStr), &m); err != nil { + continue + } + // 找到匹配的数据 + if m["UserID"] == userId { + // 删除AccessToken + client.Redis.Del(ctx, fmt.Sprintf("%v%v", constant.OAuth2RedisKey, m["Access"])) + client.Redis.Del(ctx, fmt.Sprintf("%v%v", constant.OAuth2RedisKey, m["Refresh"])) + client.Redis.Del(ctx, key) + continue + } + } +} diff --git a/oauth2/handle/user.go b/oauth2/handle/user.go new file mode 100644 index 0000000..c655fc2 --- /dev/null +++ b/oauth2/handle/user.go @@ -0,0 +1,69 @@ +package handle + +import ( + "errors" + "git.echol.cn/loser/logger/log" + "miniapp/model/app" + "miniapp/model/common/constant" + "miniapp/service" + "miniapp/utils" + "strconv" +) + +// 获取普通用户信息 +func getUser(account string, loginType constant.LoginType, nikeName string, avatarUrl string) (userId string, err error) { + // 根据登录类型获取用户信息 + + // 定义微信小程序信息 + //var unionId, openId, sessionKey string + var mobile string + // 定义用户信息 + var user app.User + //user.InviteCode = &inviteCode + switch loginType { + case constant.LoginTypeWeChatMiniApp: + mobile, err = utils.WeChatUtils().GetPhoneNumber(account) + if err != nil { + return + } + if mobile == "" { + err = errors.New("获取手机号失败") + return + } + user.Phone = mobile + user.Nickname = nikeName + user.Avatar = avatarUrl + default: + user.Phone = account + user.Nickname = nikeName + user.Avatar = avatarUrl + } + + // 查询用户信息 + if err = service.ServiceGroupApp.AppServiceGroup.UserService.GetOrCreate(&user); err != nil { + log.Errorf("获取用户信息或创建用户失败,错误信息:%s", err.Error()) + err = errors.New("登录失败,请联系管理员") + return + } + + // 校验用户状态 + if user.Status == constant.UserStatusDisabled { + err = errors.New("账户已被禁用") + return + } + + // 异步缓存小程序SessionKey + //go func() { + // if loginType == constant.LoginTypeWeChatMiniApp { + // // 缓存SessionKey + // if client.Redis.Set(context.Background(), constant.WeChatSessionKey+user.Id, sessionKey, 3*24*time.Hour).Err() != nil { + // log.Errorf("缓存SessionKey失败,用户Id:%s", user.Id) + // } + // } + //}() + + // 返回用户Id + userId = strconv.Itoa(int(user.ID)) + + return +} diff --git a/oauth2/server.go b/oauth2/server.go new file mode 100644 index 0000000..3a8cb90 --- /dev/null +++ b/oauth2/server.go @@ -0,0 +1,76 @@ +package oauth2 + +import ( + "git.echol.cn/loser/logger/log" + "github.com/go-oauth2/oauth2/v4" + "github.com/go-oauth2/oauth2/v4/manage" + "github.com/go-oauth2/oauth2/v4/models" + "github.com/go-oauth2/oauth2/v4/server" + "github.com/go-oauth2/oauth2/v4/store" + od "github.com/go-oauth2/redis/v4" + "miniapp/client" + "miniapp/model/app" + "miniapp/model/common/constant" + "miniapp/oauth2/handle" + "miniapp/service" + "time" +) + +var OAuthServer *server.Server // Oauth服务 + +// InitOAuth2Server 初始化OAuth2服务端 +func InitOAuth2Server() { + manager := manage.NewDefaultManager() + // 配置信息 + cfg := &manage.Config{ + AccessTokenExp: time.Hour * 3, // 访问令牌过期时间,三小时 + RefreshTokenExp: time.Hour * 24 * 7, // 更新令牌过期时间,一周 + IsGenerateRefresh: true, // 是否生成新的更新令牌 + } + // 设置密码模式的配置参数 + manager.SetPasswordTokenCfg(cfg) + + manager.MapTokenStorage(od.NewRedisStoreWithCli(client.Redis, constant.OAuth2RedisKey)) + // 生成Token方式 + manager.MapAccessGenerate(handle.NewAccessGenerate()) + + // 配置客户端 + clientStore := store.NewClientStore() + // 从数据库查询所有client信息 + var clients []app.OAuth2Client + if err := service.ServiceGroupApp.AppServiceGroup.Oauth2ClientService.FinAll(&clients); err != nil { + log.Panicf("OAuth2服务启动失败[Client信息拉取失败]: %v", err.Error()) + } + if len(clients) == 0 { + log.Panic("未配置OAuth2客户端信息") + } + // 组装数据 + for _, c := range clients { + _ = clientStore.Set(c.ClientId, &models.Client{ + ID: c.ClientId, + Secret: c.ClientSecret, + }) + } + log.Debug("客户端信息初始化完成") + manager.MapClientStorage(clientStore) + + srv := server.NewServer(server.NewConfig(), manager) + // 设置密码登录模式处理逻辑 + srv.SetPasswordAuthorizationHandler(handle.LoginWithPassword) + // 允许密码模式、刷新Token + srv.SetAllowedGrantType(oauth2.PasswordCredentials, oauth2.Refreshing) + // 客户端ID和授权模式检查 + srv.SetClientAuthorizedHandler(handle.CheckClient) + // 自定义响应Token的扩展字段 + srv.SetExtensionFieldsHandler(handle.ExtensionFields) + // 自定义返回数据接口 + srv.SetResponseTokenHandler(handle.ResponseToken) + // 自定义内部错误处理 + srv.SetInternalErrorHandler(handle.InternalErrorHandler) + // 响应错误处理(支持自定义URI及错误明细) + //srv.SetResponseErrorHandler(handle.ResponseErrorHandler) + // 自定义解析用户Id函数 + srv.SetUserAuthorizationHandler(handle.UserAuthorizationHandler) + + OAuthServer = srv +} diff --git a/packfile/notUsePackFile.go b/packfile/notUsePackFile.go new file mode 100644 index 0000000..53871d6 --- /dev/null +++ b/packfile/notUsePackFile.go @@ -0,0 +1,4 @@ +//go:build !packfile +// +build !packfile + +package packfile diff --git a/packfile/usePackFile.go b/packfile/usePackFile.go new file mode 100644 index 0000000..7820af9 --- /dev/null +++ b/packfile/usePackFile.go @@ -0,0 +1,45 @@ +//go:build packfile +// +build packfile + +package packfile + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +//go:generate go-bindata -o=staticFile.go -pkg=packfile -tags=packfile ../resource/... ../config.yaml + +func writeFile(path string, data []byte) { + // 如果文件夹不存在,预先创建文件夹 + if lastSeparator := strings.LastIndex(path, "/"); lastSeparator != -1 { + dirPath := path[:lastSeparator] + if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { + os.MkdirAll(dirPath, os.ModePerm) + } + } + + // 已存在的文件,不应该覆盖重写,可能在前端更改了配置文件等 + if _, err := os.Stat(path); os.IsNotExist(err) { + if err2 := os.WriteFile(path, data, os.ModePerm); err2 != nil { + fmt.Printf("Write file failed: %s\n", path) + } + } else { + fmt.Printf("File exist, skip: %s\n", path) + } +} + +func init() { + for key := range _bindata { + filePath, _ := filepath.Abs(strings.TrimPrefix(key, ".")) + data, err := Asset(key) + if err != nil { + // Asset was not found. + fmt.Printf("Fail to find: %s\n", filePath) + } else { + writeFile(filePath, data) + } + } +} diff --git a/plugin/email/README.MD b/plugin/email/README.MD new file mode 100644 index 0000000..1720283 --- /dev/null +++ b/plugin/email/README.MD @@ -0,0 +1,75 @@ +## GVA 邮件发送功能插件 +#### 开发者:GIN-VUE-ADMIN 官方 + +### 使用步骤 + +#### 1. 前往GVA主程序下的initialize/router.go 在Routers 方法最末尾按照你需要的及安全模式添加本插件 + 例: + 本插件可以采用gva的配置文件 也可以直接写死内容作为配置 建议为gva添加配置文件结构 然后将配置传入 + PluginInit(PrivateGroup, email.CreateEmailPlug( + global.GVA_CONFIG.Email.To, + global.GVA_CONFIG.Email.From, + global.GVA_CONFIG.Email.Host, + global.GVA_CONFIG.Email.Secret, + global.GVA_CONFIG.Email.Nickname, + global.GVA_CONFIG.Email.Port, + global.GVA_CONFIG.Email.IsSSL, + )) + + 同样也可以再传入时写死 + + PluginInit(PrivateGroup, email.CreateEmailPlug( + "a@qq.com", + "b@qq.com", + "smtp.qq.com", + "global.GVA_CONFIG.Email.Secret", + "登录密钥", + 465, + true, + )) + +### 2. 配置说明 + +#### 2-1 全局配置结构体说明 + //其中 Form 和 Secret 通常来说就是用户名和密码 + + type Email struct { + To string // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用 此处配置主要用于发送错误监控邮件 + From string // 发件人 你自己要发邮件的邮箱 + Host string // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议 + Secret string // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥 + Nickname string // 昵称 发件人昵称 自定义即可 可以不填 + Port int // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465 + IsSSL bool // 是否SSL 是否开启SSL + } +#### 2-2 入参结构说明 + //其中 Form 和 Secret 通常来说就是用户名和密码 + + type Email struct { + To string `json:"to"` // 邮件发送给谁 + Subject string `json:"subject"` // 邮件标题 + Body string `json:"body"` // 邮件内容 + } + + +### 3. 方法API + + utils.EmailTest(邮件标题,邮件主体) 发送测试邮件 + 例:utils.EmailTest("测试邮件","测试邮件") + utils.ErrorToEmail(邮件标题,邮件主体) 错误监控 + 例:utils.ErrorToEmail("测试邮件","测试邮件") + utils.Email(目标邮箱多个的话用逗号分隔,邮件标题,邮件主体) 发送测试邮件 + 例:utils.Email(”a.qq.com,b.qq.com“,"测试邮件","测试邮件") + +### 4. 可直接调用的接口 + + 测试接口: /email/emailTest [post] 已配置swagger + + 发送邮件接口接口: /email/emailSend [post] 已配置swagger + 入参: + type Email struct { + To string `json:"to"` // 邮件发送给谁 + Subject string `json:"subject"` // 邮件标题 + Body string `json:"body"` // 邮件内容 + } + diff --git a/plugin/email/api/enter.go b/plugin/email/api/enter.go new file mode 100644 index 0000000..353404d --- /dev/null +++ b/plugin/email/api/enter.go @@ -0,0 +1,7 @@ +package api + +type ApiGroup struct { + EmailApi +} + +var ApiGroupApp = new(ApiGroup) diff --git a/plugin/email/api/sys_email.go b/plugin/email/api/sys_email.go new file mode 100644 index 0000000..b63c413 --- /dev/null +++ b/plugin/email/api/sys_email.go @@ -0,0 +1,53 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/common/response" + email_response "miniapp/plugin/email/model/response" + "miniapp/plugin/email/service" +) + +type EmailApi struct{} + +// EmailTest +// @Tags System +// @Summary 发送测试邮件 +// @Security ApiKeyAuth +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}" +// @Router /email/emailTest [post] +func (s *EmailApi) EmailTest(c *gin.Context) { + err := service.ServiceGroupApp.EmailTest() + if err != nil { + global.GVA_LOG.Error("发送失败!", zap.Error(err)) + response.FailWithMessage("发送失败", c) + return + } + response.OkWithMessage("发送成功", c) +} + +// SendEmail +// @Tags System +// @Summary 发送邮件 +// @Security ApiKeyAuth +// @Produce application/json +// @Param data body email_response.Email true "发送邮件必须的参数" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}" +// @Router /email/sendEmail [post] +func (s *EmailApi) SendEmail(c *gin.Context) { + var email email_response.Email + err := c.ShouldBindJSON(&email) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + err = service.ServiceGroupApp.SendEmail(email.To, email.Subject, email.Body) + if err != nil { + global.GVA_LOG.Error("发送失败!", zap.Error(err)) + response.FailWithMessage("发送失败", c) + return + } + response.OkWithMessage("发送成功", c) +} diff --git a/plugin/email/config/email.go b/plugin/email/config/email.go new file mode 100644 index 0000000..c535348 --- /dev/null +++ b/plugin/email/config/email.go @@ -0,0 +1,11 @@ +package config + +type Email struct { + To string `mapstructure:"to" json:"to" yaml:"to"` // 收件人:多个以英文逗号分隔 例:a@qq.com b@qq.com 正式开发中请把此项目作为参数使用 + From string `mapstructure:"from" json:"from" yaml:"from"` // 发件人 你自己要发邮件的邮箱 + Host string `mapstructure:"host" json:"host" yaml:"host"` // 服务器地址 例如 smtp.qq.com 请前往QQ或者你要发邮件的邮箱查看其smtp协议 + Secret string `mapstructure:"secret" json:"secret" yaml:"secret"` // 密钥 用于登录的密钥 最好不要用邮箱密码 去邮箱smtp申请一个用于登录的密钥 + Nickname string `mapstructure:"nickname" json:"nickname" yaml:"nickname"` // 昵称 发件人昵称 通常为自己的邮箱 + Port int `mapstructure:"port" json:"port" yaml:"port"` // 端口 请前往QQ或者你要发邮件的邮箱查看其smtp协议 大多为 465 + IsSSL bool `mapstructure:"is-ssl" json:"isSSL" yaml:"is-ssl"` // 是否SSL 是否开启SSL +} diff --git a/plugin/email/global/gloabl.go b/plugin/email/global/gloabl.go new file mode 100644 index 0000000..d2f6c3e --- /dev/null +++ b/plugin/email/global/gloabl.go @@ -0,0 +1,5 @@ +package global + +import "miniapp/plugin/email/config" + +var GlobalConfig = new(config.Email) diff --git a/plugin/email/main.go b/plugin/email/main.go new file mode 100644 index 0000000..3cc134d --- /dev/null +++ b/plugin/email/main.go @@ -0,0 +1,28 @@ +package email + +import ( + "github.com/gin-gonic/gin" + "miniapp/plugin/email/global" + "miniapp/plugin/email/router" +) + +type emailPlugin struct{} + +func CreateEmailPlug(To, From, Host, Secret, Nickname string, Port int, IsSSL bool) *emailPlugin { + global.GlobalConfig.To = To + global.GlobalConfig.From = From + global.GlobalConfig.Host = Host + global.GlobalConfig.Secret = Secret + global.GlobalConfig.Nickname = Nickname + global.GlobalConfig.Port = Port + global.GlobalConfig.IsSSL = IsSSL + return &emailPlugin{} +} + +func (*emailPlugin) Register(group *gin.RouterGroup) { + router.RouterGroupApp.InitEmailRouter(group) +} + +func (*emailPlugin) RouterPath() string { + return "email" +} diff --git a/plugin/email/model/response/email.go b/plugin/email/model/response/email.go new file mode 100644 index 0000000..ed25475 --- /dev/null +++ b/plugin/email/model/response/email.go @@ -0,0 +1,7 @@ +package response + +type Email struct { + To string `json:"to"` // 邮件发送给谁 + Subject string `json:"subject"` // 邮件标题 + Body string `json:"body"` // 邮件内容 +} diff --git a/plugin/email/router/enter.go b/plugin/email/router/enter.go new file mode 100644 index 0000000..e081a54 --- /dev/null +++ b/plugin/email/router/enter.go @@ -0,0 +1,7 @@ +package router + +type RouterGroup struct { + EmailRouter +} + +var RouterGroupApp = new(RouterGroup) diff --git a/plugin/email/router/sys_email.go b/plugin/email/router/sys_email.go new file mode 100644 index 0000000..74b3c36 --- /dev/null +++ b/plugin/email/router/sys_email.go @@ -0,0 +1,19 @@ +package router + +import ( + "github.com/gin-gonic/gin" + "miniapp/middleware" + "miniapp/plugin/email/api" +) + +type EmailRouter struct{} + +func (s *EmailRouter) InitEmailRouter(Router *gin.RouterGroup) { + emailRouter := Router.Use(middleware.OperationRecord()) + EmailApi := api.ApiGroupApp.EmailApi.EmailTest + SendEmail := api.ApiGroupApp.EmailApi.SendEmail + { + emailRouter.POST("emailTest", EmailApi) // 发送测试邮件 + emailRouter.POST("sendEmail", SendEmail) // 发送邮件 + } +} diff --git a/plugin/email/service/enter.go b/plugin/email/service/enter.go new file mode 100644 index 0000000..e96e267 --- /dev/null +++ b/plugin/email/service/enter.go @@ -0,0 +1,7 @@ +package service + +type ServiceGroup struct { + EmailService +} + +var ServiceGroupApp = new(ServiceGroup) diff --git a/plugin/email/service/sys_email.go b/plugin/email/service/sys_email.go new file mode 100644 index 0000000..882196a --- /dev/null +++ b/plugin/email/service/sys_email.go @@ -0,0 +1,32 @@ +package service + +import ( + "miniapp/plugin/email/utils" +) + +type EmailService struct{} + +//@author: [maplepie](https://github.com/maplepie) +//@function: EmailTest +//@description: 发送邮件测试 +//@return: err error + +func (e *EmailService) EmailTest() (err error) { + subject := "test" + body := "test" + err = utils.EmailTest(subject, body) + return err +} + +//@author: [maplepie](https://github.com/maplepie) +//@function: EmailTest +//@description: 发送邮件测试 +//@return: err error +//@params to string 收件人 +//@params subject string 标题(主题) +//@params body string 邮件内容 + +func (e *EmailService) SendEmail(to, subject, body string) (err error) { + err = utils.Email(to, subject, body) + return err +} diff --git a/plugin/email/utils/email.go b/plugin/email/utils/email.go new file mode 100644 index 0000000..d1a77c7 --- /dev/null +++ b/plugin/email/utils/email.go @@ -0,0 +1,82 @@ +package utils + +import ( + "crypto/tls" + "fmt" + "net/smtp" + "strings" + + "miniapp/plugin/email/global" + + "github.com/jordan-wright/email" +) + +//@author: [maplepie](https://github.com/maplepie) +//@function: Email +//@description: Email发送方法 +//@param: subject string, body string +//@return: error + +func Email(To, subject string, body string) error { + to := strings.Split(To, ",") + return send(to, subject, body) +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: ErrorToEmail +//@description: 给email中间件错误发送邮件到指定邮箱 +//@param: subject string, body string +//@return: error + +func ErrorToEmail(subject string, body string) error { + to := strings.Split(global.GlobalConfig.To, ",") + if to[len(to)-1] == "" { // 判断切片的最后一个元素是否为空,为空则移除 + to = to[:len(to)-1] + } + return send(to, subject, body) +} + +//@author: [maplepie](https://github.com/maplepie) +//@function: EmailTest +//@description: Email测试方法 +//@param: subject string, body string +//@return: error + +func EmailTest(subject string, body string) error { + to := []string{global.GlobalConfig.To} + return send(to, subject, body) +} + +//@author: [maplepie](https://github.com/maplepie) +//@function: send +//@description: Email发送方法 +//@param: subject string, body string +//@return: error + +func send(to []string, subject string, body string) error { + from := global.GlobalConfig.From + nickname := global.GlobalConfig.Nickname + secret := global.GlobalConfig.Secret + host := global.GlobalConfig.Host + port := global.GlobalConfig.Port + isSSL := global.GlobalConfig.IsSSL + + auth := smtp.PlainAuth("", from, secret, host) + e := email.NewEmail() + if nickname != "" { + e.From = fmt.Sprintf("%s <%s>", nickname, from) + } else { + e.From = from + } + e.To = to + e.Subject = subject + e.HTML = []byte(body) + var err error + hostAddr := fmt.Sprintf("%s:%d", host, port) + if isSSL { + err = e.SendWithTLS(hostAddr, auth, &tls.Config{ServerName: host}) + } else { + err = e.Send(hostAddr, auth) + } + return err +} diff --git a/plugin/plugin-tool/utils/check.go b/plugin/plugin-tool/utils/check.go new file mode 100644 index 0000000..b36b579 --- /dev/null +++ b/plugin/plugin-tool/utils/check.go @@ -0,0 +1,53 @@ +package utils + +import ( + "fmt" + "miniapp/global" + "miniapp/model/system" + "strconv" +) + +func RegisterApis(apis ...system.SysApi) { + var count int64 + var apiPaths []string + for i := range apis { + apiPaths = append(apiPaths, apis[i].Path) + } + global.GVA_DB.Find(&[]system.SysApi{}, "path in (?)", apiPaths).Count(&count) + if count > 0 { + fmt.Println("插件已安装或存在同名路由") + return + } + err := global.GVA_DB.Create(&apis).Error + if err != nil { + fmt.Println(err) + } +} + +func RegisterMenus(menus ...system.SysBaseMenu) { + var count int64 + var menuNames []string + parentMenu := menus[0] + otherMenus := menus[1:] + for i := range menus { + menuNames = append(menuNames, menus[i].Name) + } + global.GVA_DB.Find(&[]system.SysBaseMenu{}, "name in (?)", menuNames).Count(&count) + if count > 0 { + fmt.Println("插件已安装或存在同名菜单") + return + } + parentMenu.ParentId = "0" + err := global.GVA_DB.Create(&parentMenu).Error + if err != nil { + fmt.Println(err) + } + for i := range otherMenus { + pid := strconv.Itoa(int(parentMenu.ID)) + otherMenus[i].ParentId = pid + } + err = global.GVA_DB.Create(&otherMenus).Error + if err != nil { + fmt.Println(err) + } +} diff --git a/plugin/ws/ws.go b/plugin/ws/ws.go new file mode 100644 index 0000000..bd6926e --- /dev/null +++ b/plugin/ws/ws.go @@ -0,0 +1,84 @@ +package ws + +import ( + "github.com/flipped-aurora/ws/core/biz" + "github.com/flipped-aurora/ws/core/data" + "github.com/gin-gonic/gin" + "go.uber.org/zap" + "nhooyr.io/websocket" +) + +type wsPlugin struct { + logger *zap.Logger // 日志输出对象 + manageBuf int64 // buffer + registeredMsgHandler map[int32]func(biz.IMessage) bool // 消息处理 + checkMap map[string]biz.CheckFunc // 用户校验 + + admin biz.IManage + adminCase *biz.AdminCase +} + +func DefaultRegisteredMsgHandler(admin biz.IManage, logger *zap.Logger) map[int32]func(biz.IMessage) bool { + return map[int32]func(msg biz.IMessage) bool{ + 1: func(msg biz.IMessage) bool { + // w.admin 里面找到注册客户端的方法 + client, ok := admin.FindClient(msg.GetTo()) + if !ok { + logger.Info("没有找到该用户") + return false + } + return client.SendMes(msg) + }, + } +} + +func DefaultCheckMap() map[string]biz.CheckFunc { + return map[string]biz.CheckFunc{ + "gva_ws": func(c interface{}) (string, bool) { + // 先断言是gin.content + cc, ok := c.(*gin.Context) + if !ok { + return "", false + } + token := cc.Query("jwt") + // 可以携带jwt + if len(token) == 0 { + return "", false + } + // 解析 jwt... + + return token, true + }, + } +} + +func (w *wsPlugin) Register(g *gin.RouterGroup) { + // gva_ws 为身份校验函数 + g.GET("/ws", w.adminCase.HandlerWS("gva_ws", &websocket.AcceptOptions{ + InsecureSkipVerify: true, + })) + g.POST("/sendMsg", w.adminCase.SendMsg("gva_ws")) +} + +func (w *wsPlugin) RouterPath() string { + return "gva_ws" +} + +func GenerateWs(logger *zap.Logger, manageBuf int64, checkMap map[string]biz.CheckFunc) *wsPlugin { + m := data.NewManage(manageBuf) + t := data.NewTopic() + h := data.NewHandle() + admin := data.NewAdmin(m, t, h, logger) + for s, checkFunc := range checkMap { + admin.AddCheckFunc(s, checkFunc) + } + registeredMsgHandler := DefaultRegisteredMsgHandler(admin, logger) + + for key, handler := range registeredMsgHandler { + admin.RegisteredMsgHandler(key, handler) + } + return &wsPlugin{ + logger: logger, manageBuf: manageBuf, + registeredMsgHandler: registeredMsgHandler, checkMap: checkMap, admin: admin, adminCase: biz.NewAdmin(admin), + } +} diff --git a/resource/autocode_template/readme.txt.tpl b/resource/autocode_template/readme.txt.tpl new file mode 100644 index 0000000..33a0603 --- /dev/null +++ b/resource/autocode_template/readme.txt.tpl @@ -0,0 +1,7 @@ +代码解压后把fe的api文件内容粘贴进前端api文件夹下并修改为自己想要的名字即可 + +后端代码解压后同理,放到自己想要的 mvc对应路径 并且到 initRouter中注册自动生成的路由 到registerTable中注册自动生成的model + +项目github:"https://github.com/piexlmax/miniapp" + +希望大家给个star多多鼓励 diff --git a/resource/autocode_template/server/api.go.tpl b/resource/autocode_template/server/api.go.tpl new file mode 100644 index 0000000..1168429 --- /dev/null +++ b/resource/autocode_template/server/api.go.tpl @@ -0,0 +1,210 @@ +package {{.Package}} + +import ( + "miniapp/global" + "miniapp/model/{{.Package}}" + "miniapp/model/common/request" + {{.Package}}Req "miniapp/model/{{.Package}}/request" + "miniapp/model/common/response" + "miniapp/service" + "github.com/gin-gonic/gin" + "go.uber.org/zap" + {{- if .NeedValid }} + "miniapp/utils" + {{- else if .AutoCreateResource}} + "miniapp/utils" + {{- end }} +) + +type {{.StructName}}Api struct { +} + +var {{.Abbreviation}}Service = service.ServiceGroupApp.{{.PackageT}}ServiceGroup.{{.StructName}}Service + + +// Create{{.StructName}} 创建{{.Description}} +// @Tags {{.StructName}} +// @Summary 创建{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body {{.Package}}.{{.StructName}} true "创建{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /{{.Abbreviation}}/create{{.StructName}} [post] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Context) { + var {{.Abbreviation}} {{.Package}}.{{.StructName}} + err := c.ShouldBindJSON(&{{.Abbreviation}}) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- if .AutoCreateResource }} + {{.Abbreviation}}.CreatedBy = utils.GetUserID(c) + {{- end }} + {{- if .NeedValid }} + verify := utils.Rules{ + {{- range $index,$element := .Fields }} + {{- if $element.Require }} + "{{$element.FieldName}}":{utils.NotEmpty()}, + {{- end }} + {{- end }} + } + if err := utils.Verify({{.Abbreviation}}, verify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- end }} + if err := {{.Abbreviation}}Service.Create{{.StructName}}(&{{.Abbreviation}}); err != nil { + global.GVA_LOG.Error("创建失败!", zap.Error(err)) + response.FailWithMessage("创建失败", c) + } else { + response.OkWithMessage("创建成功", c) + } +} + +// Delete{{.StructName}} 删除{{.Description}} +// @Tags {{.StructName}} +// @Summary 删除{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body {{.Package}}.{{.StructName}} true "删除{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}(c *gin.Context) { + var {{.Abbreviation}} {{.Package}}.{{.StructName}} + err := c.ShouldBindJSON(&{{.Abbreviation}}) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- if .AutoCreateResource }} + {{.Abbreviation}}.DeletedBy = utils.GetUserID(c) + {{- end }} + if err := {{.Abbreviation}}Service.Delete{{.StructName}}({{.Abbreviation}}); err != nil { + global.GVA_LOG.Error("删除失败!", zap.Error(err)) + response.FailWithMessage("删除失败", c) + } else { + response.OkWithMessage("删除成功", c) + } +} + +// Delete{{.StructName}}ByIds 批量删除{{.Description}} +// @Tags {{.StructName}} +// @Summary 批量删除{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}" +// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gin.Context) { + var IDS request.IdsReq + err := c.ShouldBindJSON(&IDS) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- if .AutoCreateResource }} + deletedBy := utils.GetUserID(c) + {{- end }} + if err := {{.Abbreviation}}Service.Delete{{.StructName}}ByIds(IDS{{- if .AutoCreateResource }},deletedBy{{- end }}); err != nil { + global.GVA_LOG.Error("批量删除失败!", zap.Error(err)) + response.FailWithMessage("批量删除失败", c) + } else { + response.OkWithMessage("批量删除成功", c) + } +} + +// Update{{.StructName}} 更新{{.Description}} +// @Tags {{.StructName}} +// @Summary 更新{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body {{.Package}}.{{.StructName}} true "更新{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /{{.Abbreviation}}/update{{.StructName}} [put] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Context) { + var {{.Abbreviation}} {{.Package}}.{{.StructName}} + err := c.ShouldBindJSON(&{{.Abbreviation}}) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- if .AutoCreateResource }} + {{.Abbreviation}}.UpdatedBy = utils.GetUserID(c) + {{- end }} + {{- if .NeedValid }} + verify := utils.Rules{ + {{- range $index,$element := .Fields }} + {{- if $element.Require }} + "{{$element.FieldName}}":{utils.NotEmpty()}, + {{- end }} + {{- end }} + } + if err := utils.Verify({{.Abbreviation}}, verify); err != nil { + response.FailWithMessage(err.Error(), c) + return + } + {{- end }} + if err := {{.Abbreviation}}Service.Update{{.StructName}}({{.Abbreviation}}); err != nil { + global.GVA_LOG.Error("更新失败!", zap.Error(err)) + response.FailWithMessage("更新失败", c) + } else { + response.OkWithMessage("更新成功", c) + } +} + +// Find{{.StructName}} 用id查询{{.Description}} +// @Tags {{.StructName}} +// @Summary 用id查询{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query {{.Package}}.{{.StructName}} true "用id查询{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /{{.Abbreviation}}/find{{.StructName}} [get] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Context) { + var {{.Abbreviation}} {{.Package}}.{{.StructName}} + err := c.ShouldBindQuery(&{{.Abbreviation}}) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if re{{.Abbreviation}}, err := {{.Abbreviation}}Service.Get{{.StructName}}({{.Abbreviation}}.ID); err != nil { + global.GVA_LOG.Error("查询失败!", zap.Error(err)) + response.FailWithMessage("查询失败", c) + } else { + response.OkWithData(gin.H{"re{{.Abbreviation}}": re{{.Abbreviation}}}, c) + } +} + +// Get{{.StructName}}List 分页获取{{.Description}}列表 +// @Tags {{.StructName}} +// @Summary 分页获取{{.Description}}列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /{{.Abbreviation}}/get{{.StructName}}List [get] +func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Context) { + var pageInfo {{.Package}}Req.{{.StructName}}Search + err := c.ShouldBindQuery(&pageInfo) + if err != nil { + response.FailWithMessage(err.Error(), c) + return + } + if list, total, err := {{.Abbreviation}}Service.Get{{.StructName}}InfoList(pageInfo); err != nil { + global.GVA_LOG.Error("获取失败!", zap.Error(err)) + response.FailWithMessage("获取失败", c) + } else { + response.OkWithDetailed(response.PageResult{ + List: list, + Total: total, + Page: pageInfo.Page, + PageSize: pageInfo.PageSize, + }, "获取成功", c) + } +} diff --git a/resource/autocode_template/server/model.go.tpl b/resource/autocode_template/server/model.go.tpl new file mode 100644 index 0000000..43808c9 --- /dev/null +++ b/resource/autocode_template/server/model.go.tpl @@ -0,0 +1,42 @@ +// 自动生成模板{{.StructName}} +package {{.Package}} + +import ( + "miniapp/global" + {{ if .HasTimer }}"time"{{ end }} + {{ if .NeedJSON }}"gorm.io/datatypes"{{ end }} +) + +// {{.Description}} 结构体 {{.StructName}} +type {{.StructName}} struct { + global.GVA_MODEL {{- range .Fields}} + {{- if eq .FieldType "enum" }} + {{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};type:enum({{.DataTypeLong}});comment:{{.Comment}};"` + {{- else if eq .FieldType "picture" }} + {{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- else if eq .FieldType "video" }} + {{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- else if eq .FieldType "file" }} + {{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- else if eq .FieldType "pictures" }} + {{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- else if eq .FieldType "richtext" }} + {{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}type:text;"` + {{- else if ne .FieldType "string" }} + {{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- else }} + {{.FieldName}} {{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}"` + {{- end }} {{ if .FieldDesc }}//{{.FieldDesc}} {{ end }} {{- end }} + {{- if .AutoCreateResource }} + CreatedBy uint `gorm:"column:created_by;comment:创建者"` + UpdatedBy uint `gorm:"column:updated_by;comment:更新者"` + DeletedBy uint `gorm:"column:deleted_by;comment:删除者"` + {{- end}} +} + +{{ if .TableName }} +// TableName {{.Description}} {{.StructName}}自定义表名 {{.TableName}} +func ({{.StructName}}) TableName() string { + return "{{.TableName}}" +} +{{ end }} diff --git a/resource/autocode_template/server/request.go.tpl b/resource/autocode_template/server/request.go.tpl new file mode 100644 index 0000000..4d9725f --- /dev/null +++ b/resource/autocode_template/server/request.go.tpl @@ -0,0 +1,24 @@ +package request + +import ( + "miniapp/model/{{.Package}}" + "miniapp/model/common/request" + "time" +) + +type {{.StructName}}Search struct{ + {{.Package}}.{{.StructName}} + StartCreatedAt *time.Time `json:"startCreatedAt" form:"startCreatedAt"` + EndCreatedAt *time.Time `json:"endCreatedAt" form:"endCreatedAt"` + {{- range .Fields}} + {{- if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}} + Start{{.FieldName}} *{{.FieldType}} `json:"start{{.FieldName}}" form:"start{{.FieldName}}"` + End{{.FieldName}} *{{.FieldType}} `json:"end{{.FieldName}}" form:"end{{.FieldName}}"` + {{- end }} + {{- end }} + request.PageInfo + {{- if .NeedSort}} + Sort string `json:"sort" form:"sort"` + Order string `json:"order" form:"order"` + {{- end}} +} diff --git a/resource/autocode_template/server/router.go.tpl b/resource/autocode_template/server/router.go.tpl new file mode 100644 index 0000000..463bfbf --- /dev/null +++ b/resource/autocode_template/server/router.go.tpl @@ -0,0 +1,27 @@ +package {{.Package}} + +import ( + "miniapp/api/v1" + "miniapp/middleware" + "github.com/gin-gonic/gin" +) + +type {{.StructName}}Router struct { +} + +// Init{{.StructName}}Router 初始化 {{.Description}} 路由信息 +func (s *{{.StructName}}Router) Init{{.StructName}}Router(Router *gin.RouterGroup) { + {{.Abbreviation}}Router := Router.Group("{{.Abbreviation}}").Use(middleware.OperationRecord()) + {{.Abbreviation}}RouterWithoutRecord := Router.Group("{{.Abbreviation}}") + var {{.Abbreviation}}Api = v1.ApiGroupApp.{{.PackageT}}ApiGroup.{{.StructName}}Api + { + {{.Abbreviation}}Router.POST("create{{.StructName}}", {{.Abbreviation}}Api.Create{{.StructName}}) // 新建{{.Description}} + {{.Abbreviation}}Router.DELETE("delete{{.StructName}}", {{.Abbreviation}}Api.Delete{{.StructName}}) // 删除{{.Description}} + {{.Abbreviation}}Router.DELETE("delete{{.StructName}}ByIds", {{.Abbreviation}}Api.Delete{{.StructName}}ByIds) // 批量删除{{.Description}} + {{.Abbreviation}}Router.PUT("update{{.StructName}}", {{.Abbreviation}}Api.Update{{.StructName}}) // 更新{{.Description}} + } + { + {{.Abbreviation}}RouterWithoutRecord.GET("find{{.StructName}}", {{.Abbreviation}}Api.Find{{.StructName}}) // 根据ID获取{{.Description}} + {{.Abbreviation}}RouterWithoutRecord.GET("get{{.StructName}}List", {{.Abbreviation}}Api.Get{{.StructName}}List) // 获取{{.Description}}列表 + } +} diff --git a/resource/autocode_template/server/service.go.tpl b/resource/autocode_template/server/service.go.tpl new file mode 100644 index 0000000..0e3dec4 --- /dev/null +++ b/resource/autocode_template/server/service.go.tpl @@ -0,0 +1,138 @@ +package {{.Package}} + +import ( + "miniapp/global" + "miniapp/model/{{.Package}}" + "miniapp/model/common/request" + {{.Package}}Req "miniapp/model/{{.Package}}/request" + {{- if .AutoCreateResource }} + "gorm.io/gorm" + {{- end}} +) + +type {{.StructName}}Service struct { +} + +{{- $db := "" }} +{{- if eq .BusinessDB "" }} + {{- $db = "global.GVA_DB" }} +{{- else}} + {{- $db = printf "global.MustGetGlobalDBByDBName(\"%s\")" .BusinessDB }} +{{- end}} + +// Create{{.StructName}} 创建{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service) Create{{.StructName}}({{.Abbreviation}} *{{.Package}}.{{.StructName}}) (err error) { + err = {{$db}}.Create({{.Abbreviation}}).Error + return err +} + +// Delete{{.StructName}} 删除{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}({{.Abbreviation}} {{.Package}}.{{.StructName}}) (err error) { + {{- if .AutoCreateResource }} + err = {{$db}}.Transaction(func(tx *gorm.DB) error { + if err := tx.Model(&{{.Package}}.{{.StructName}}{}).Where("id = ?", {{.Abbreviation}}.ID).Update("deleted_by", {{.Abbreviation}}.DeletedBy).Error; err != nil { + return err + } + if err = tx.Delete(&{{.Abbreviation}}).Error; err != nil { + return err + } + return nil + }) + {{- else }} + err = {{$db}}.Delete(&{{.Abbreviation}}).Error + {{- end }} + return err +} + +// Delete{{.StructName}}ByIds 批量删除{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service)Delete{{.StructName}}ByIds(ids request.IdsReq{{- if .AutoCreateResource }},deleted_by uint{{- end}}) (err error) { + {{- if .AutoCreateResource }} + err = {{$db}}.Transaction(func(tx *gorm.DB) error { + if err := tx.Model(&{{.Package}}.{{.StructName}}{}).Where("id in ?", ids.Ids).Update("deleted_by", deleted_by).Error; err != nil { + return err + } + if err := tx.Where("id in ?", ids.Ids).Delete(&{{.Package}}.{{.StructName}}{}).Error; err != nil { + return err + } + return nil + }) + {{- else}} + err = {{$db}}.Delete(&[]{{.Package}}.{{.StructName}}{},"id in ?",ids.Ids).Error + {{- end}} + return err +} + +// Update{{.StructName}} 更新{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service)Update{{.StructName}}({{.Abbreviation}} {{.Package}}.{{.StructName}}) (err error) { + err = {{$db}}.Save(&{{.Abbreviation}}).Error + return err +} + +// Get{{.StructName}} 根据id获取{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}(id uint) ({{.Abbreviation}} {{.Package}}.{{.StructName}}, err error) { + err = {{$db}}.Where("id = ?", id).First(&{{.Abbreviation}}).Error + return +} + +// Get{{.StructName}}InfoList 分页获取{{.Description}}记录 +// Author [piexlmax](https://github.com/piexlmax) +func ({{.Abbreviation}}Service *{{.StructName}}Service)Get{{.StructName}}InfoList(info {{.Package}}Req.{{.StructName}}Search) (list []{{.Package}}.{{.StructName}}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + // 创建db + db := {{$db}}.Model(&{{.Package}}.{{.StructName}}{}) + var {{.Abbreviation}}s []{{.Package}}.{{.StructName}} + // 如果有条件搜索 下方会自动创建搜索语句 + if info.StartCreatedAt !=nil && info.EndCreatedAt !=nil { + db = db.Where("created_at BETWEEN ? AND ?", info.StartCreatedAt, info.EndCreatedAt) + } + {{- range .Fields}} + {{- if .FieldSearchType}} + {{- if or (eq .FieldType "string") (eq .FieldType "enum") }} + if info.{{.FieldName}} != "" { + db = db.Where("{{.ColumnName}} {{.FieldSearchType}} ?",{{if eq .FieldSearchType "LIKE"}}"%"+ {{ end }}info.{{.FieldName}}{{if eq .FieldSearchType "LIKE"}}+"%"{{ end }}) + } + {{- else if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}} + if info.Start{{.FieldName}} != nil && info.End{{.FieldName}} != nil { + db = db.Where("{{.ColumnName}} {{.FieldSearchType}} ? AND ? ",info.Start{{.FieldName}},info.End{{.FieldName}}) + } + {{- else}} + if info.{{.FieldName}} != nil { + db = db.Where("{{.ColumnName}} {{.FieldSearchType}} ?",{{if eq .FieldSearchType "LIKE"}}"%"+{{ end }}info.{{.FieldName}}{{if eq .FieldSearchType "LIKE"}}+"%"{{ end }}) + } + {{- end }} + {{- end }} + {{- end }} + err = db.Count(&total).Error + if err!=nil { + return + } + {{- if .NeedSort}} + var OrderStr string + orderMap := make(map[string]bool) + {{- range .Fields}} + {{- if .Sort}} + orderMap["{{.ColumnName}}"] = true + {{- end}} + {{- end}} + if orderMap[info.Sort] { + OrderStr = info.Sort + if info.Order == "descending" { + OrderStr = OrderStr + " desc" + } + db = db.Order(OrderStr) + } + {{- end}} + + if limit != 0 { + db = db.Limit(limit).Offset(offset) + } + + err = db.Find(&{{.Abbreviation}}s).Error + return {{.Abbreviation}}s, total, err +} diff --git a/resource/autocode_template/subcontract/api_enter.go.tpl b/resource/autocode_template/subcontract/api_enter.go.tpl new file mode 100644 index 0000000..d94193b --- /dev/null +++ b/resource/autocode_template/subcontract/api_enter.go.tpl @@ -0,0 +1,4 @@ +package {{ .PackageName }} + +type ApiGroup struct { +} diff --git a/resource/autocode_template/subcontract/data.go b/resource/autocode_template/subcontract/data.go new file mode 100644 index 0000000..cb445a5 --- /dev/null +++ b/resource/autocode_template/subcontract/data.go @@ -0,0 +1,14 @@ +package subcontract + +import ( + _ "embed" +) + +//go:embed api_enter.go.tpl +var API []byte + +//go:embed router_enter.go.tpl +var Router []byte + +//go:embed service_enter.go.tpl +var Server []byte diff --git a/resource/autocode_template/subcontract/router_enter.go.tpl b/resource/autocode_template/subcontract/router_enter.go.tpl new file mode 100644 index 0000000..24dec19 --- /dev/null +++ b/resource/autocode_template/subcontract/router_enter.go.tpl @@ -0,0 +1,4 @@ +package {{ .PackageName }} + +type RouterGroup struct { +} diff --git a/resource/autocode_template/subcontract/service_enter.go.tpl b/resource/autocode_template/subcontract/service_enter.go.tpl new file mode 100644 index 0000000..c8d82a4 --- /dev/null +++ b/resource/autocode_template/subcontract/service_enter.go.tpl @@ -0,0 +1,6 @@ +package {{ .PackageName }} + + +type ServiceGroup struct { +} + diff --git a/resource/autocode_template/web/api.js.tpl b/resource/autocode_template/web/api.js.tpl new file mode 100644 index 0000000..99f51c1 --- /dev/null +++ b/resource/autocode_template/web/api.js.tpl @@ -0,0 +1,97 @@ +import service from '@/utils/request' + +// @Tags {{.StructName}} +// @Summary 创建{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.{{.StructName}} true "创建{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}" +// @Router /{{.Abbreviation}}/create{{.StructName}} [post] +export const create{{.StructName}} = (data) => { + return service({ + url: '/{{.Abbreviation}}/create{{.StructName}}', + method: 'post', + data + }) +} + +// @Tags {{.StructName}} +// @Summary 删除{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.{{.StructName}} true "删除{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete] +export const delete{{.StructName}} = (data) => { + return service({ + url: '/{{.Abbreviation}}/delete{{.StructName}}', + method: 'delete', + data + }) +} + +// @Tags {{.StructName}} +// @Summary 批量删除{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body request.IdsReq true "批量删除{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" +// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete] +export const delete{{.StructName}}ByIds = (data) => { + return service({ + url: '/{{.Abbreviation}}/delete{{.StructName}}ByIds', + method: 'delete', + data + }) +} + +// @Tags {{.StructName}} +// @Summary 更新{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data body model.{{.StructName}} true "更新{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}" +// @Router /{{.Abbreviation}}/update{{.StructName}} [put] +export const update{{.StructName}} = (data) => { + return service({ + url: '/{{.Abbreviation}}/update{{.StructName}}', + method: 'put', + data + }) +} + +// @Tags {{.StructName}} +// @Summary 用id查询{{.Description}} +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query model.{{.StructName}} true "用id查询{{.Description}}" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}" +// @Router /{{.Abbreviation}}/find{{.StructName}} [get] +export const find{{.StructName}} = (params) => { + return service({ + url: '/{{.Abbreviation}}/find{{.StructName}}', + method: 'get', + params + }) +} + +// @Tags {{.StructName}} +// @Summary 分页获取{{.Description}}列表 +// @Security ApiKeyAuth +// @accept application/json +// @Produce application/json +// @Param data query request.PageInfo true "分页获取{{.Description}}列表" +// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}" +// @Router /{{.Abbreviation}}/get{{.StructName}}List [get] +export const get{{.StructName}}List = (params) => { + return service({ + url: '/{{.Abbreviation}}/get{{.StructName}}List', + method: 'get', + params + }) +} diff --git a/resource/autocode_template/web/form.vue.tpl b/resource/autocode_template/web/form.vue.tpl new file mode 100644 index 0000000..ed22874 --- /dev/null +++ b/resource/autocode_template/web/form.vue.tpl @@ -0,0 +1,194 @@ + + + + + diff --git a/resource/autocode_template/web/table.vue.tpl b/resource/autocode_template/web/table.vue.tpl new file mode 100644 index 0000000..dd3db22 --- /dev/null +++ b/resource/autocode_template/web/table.vue.tpl @@ -0,0 +1,722 @@ + + + + + diff --git a/resource/page/css/app.7832f89c.css b/resource/page/css/app.7832f89c.css new file mode 100644 index 0000000..39a4456 --- /dev/null +++ b/resource/page/css/app.7832f89c.css @@ -0,0 +1 @@ +.primary-color[data-v-c59cf5f6]{color:#409eff}.background-opacity[data-v-c59cf5f6]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-c59cf5f6]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-c59cf5f6]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-c59cf5f6]{margin-top:8px}.el-form-item--small .el-radio[data-v-c59cf5f6]{line-height:32px!important}.el-form-item--small .el-rate[data-v-c59cf5f6]{margin-top:6px}.el-form-item--mini .el-radio[data-v-c59cf5f6]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-c59cf5f6]{margin-top:4px}.el-card[data-v-c59cf5f6]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-c59cf5f6]::-ms-reveal{display:none}[data-v-c59cf5f6]::-webkit-scrollbar{width:8px;height:8px}[data-v-c59cf5f6]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-c59cf5f6]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-c59cf5f6]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-c59cf5f6]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.color-svg-icon[data-v-c59cf5f6]{color:#409eff}.side-scroll-bar[data-v-c59cf5f6] .el-scrollbar__wrap{overflow-x:hidden}div.panel-container[data-v-c59cf5f6]{padding-bottom:10px}.no-bottom-margin[data-v-c59cf5f6] .el-tabs__header{margin-bottom:0}.indent-left-margin[data-v-c59cf5f6] .el-tabs__nav{margin-left:20px}.el-collapse-item[data-v-c59cf5f6] ul>li{list-style:none}.widget-collapse[data-v-c59cf5f6]{border-top-width:0}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__header{margin-left:8px;font-style:italic;font-weight:700}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content{padding-bottom:6px}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul{padding-left:10px;margin:0;-webkit-margin-before:0;margin-block-start:0;-webkit-margin-after:.25em;margin-block-end:.25em;-webkit-padding-start:10px;padding-inline-start:10px}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul:after{content:"";display:block;clear:both}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul .container-widget-item,.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul .field-widget-item{display:inline-block;height:28px;line-height:28px;width:115px;float:left;margin:2px 6px 6px 0;cursor:move;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;background:#f1f2f3}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul .container-widget-item:hover,.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul .field-widget-item:hover{background:#ebeef5;outline:1px solid #409eff}.widget-collapse[data-v-c59cf5f6] .el-collapse-item__content ul .drag-handler{position:absolute;top:0;left:160px;background-color:#ddd;border-radius:5px;padding-right:5px;font-size:11px;color:#666}.el-card.ft-card[data-v-c59cf5f6]{border:1px solid #8896b3}.ft-card[data-v-c59cf5f6]{margin-bottom:10px}.ft-card .bottom[data-v-c59cf5f6]{margin-top:10px;line-height:12px}.ft-card .ft-title[data-v-c59cf5f6]{font-size:13px;font-weight:700}.ft-card .right-button[data-v-c59cf5f6]{padding:0;float:right}.ft-card .clear-fix[data-v-c59cf5f6]:after,.ft-card .clear-fix[data-v-c59cf5f6]:before{display:table;content:""}.ft-card .clear-fix[data-v-c59cf5f6]:after{clear:both}.primary-color[data-v-c1251358]{color:#409eff}.background-opacity[data-v-c1251358]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-c1251358]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-c1251358]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-c1251358]{margin-top:8px}.el-form-item--small .el-radio[data-v-c1251358]{line-height:32px!important}.el-form-item--small .el-rate[data-v-c1251358]{margin-top:6px}.el-form-item--mini .el-radio[data-v-c1251358]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-c1251358]{margin-top:4px}.el-card[data-v-c1251358]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-c1251358]::-ms-reveal{display:none}[data-v-c1251358]::-webkit-scrollbar{width:8px;height:8px}[data-v-c1251358]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-c1251358]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-c1251358]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-c1251358]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.design-time-bottom-margin[data-v-c1251358]{margin-bottom:5px}.field-wrapper[data-v-c1251358]{position:relative}.field-wrapper .field-action[data-v-c1251358]{position:absolute;bottom:0;right:-2px;height:22px;line-height:22px;background:#409eff;z-index:9}.field-wrapper .field-action i[data-v-c1251358]{font-size:14px;color:#fff;margin:0 5px;cursor:pointer}.field-wrapper .drag-handler[data-v-c1251358]{position:absolute;top:0;left:-1px;height:20px;line-height:20px;z-index:9}.field-wrapper .drag-handler i[data-v-c1251358]{font-size:12px;font-style:normal;color:#fff;margin:4px;cursor:move}.field-wrapper .drag-handler[data-v-c1251358]:hover{background:#409eff}.static-content-item[data-v-c1251358]{min-height:20px;display:flex;align-items:center}.static-content-item[data-v-c1251358] .el-divider--horizontal{margin:0}.el-form-item.selected[data-v-c1251358],.static-content-item.selected[data-v-c1251358]{outline:2px solid #409eff}.primary-color[data-v-1293f105]{color:#409eff}.background-opacity[data-v-1293f105]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-1293f105]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-1293f105]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-1293f105]{margin-top:8px}.el-form-item--small .el-radio[data-v-1293f105]{line-height:32px!important}.el-form-item--small .el-rate[data-v-1293f105]{margin-top:6px}.el-form-item--mini .el-radio[data-v-1293f105]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-1293f105]{margin-top:4px}.el-card[data-v-1293f105]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-1293f105]::-ms-reveal{display:none}[data-v-1293f105]::-webkit-scrollbar{width:8px;height:8px}[data-v-1293f105]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-1293f105]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-1293f105]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-1293f105]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-0bf26fd2]{color:#409eff}.background-opacity[data-v-0bf26fd2]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-0bf26fd2]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-0bf26fd2]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-0bf26fd2]{margin-top:8px}.el-form-item--small .el-radio[data-v-0bf26fd2]{line-height:32px!important}.el-form-item--small .el-rate[data-v-0bf26fd2]{margin-top:6px}.el-form-item--mini .el-radio[data-v-0bf26fd2]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-0bf26fd2]{margin-top:4px}.el-card[data-v-0bf26fd2]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-0bf26fd2]::-ms-reveal{display:none}[data-v-0bf26fd2]::-webkit-scrollbar{width:8px;height:8px}[data-v-0bf26fd2]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-0bf26fd2]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-0bf26fd2]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-0bf26fd2]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.design-time-bottom-margin[data-v-0bf26fd2]{margin-bottom:5px}.field-wrapper[data-v-0bf26fd2]{position:relative}.field-wrapper .field-action[data-v-0bf26fd2]{position:absolute;bottom:0;right:-2px;height:22px;line-height:22px;background:#409eff;z-index:9}.field-wrapper .field-action i[data-v-0bf26fd2]{font-size:14px;color:#fff;margin:0 5px;cursor:pointer}.field-wrapper .drag-handler[data-v-0bf26fd2]{position:absolute;top:0;left:-1px;height:20px;line-height:20px;z-index:9}.field-wrapper .drag-handler i[data-v-0bf26fd2]{font-size:12px;font-style:normal;color:#fff;margin:4px;cursor:move}.field-wrapper .drag-handler[data-v-0bf26fd2]:hover{background:#409eff}.el-form-item[data-v-0bf26fd2]{position:relative}.el-form-item[data-v-0bf26fd2] .el-form-item__label{white-space:nowrap;text-overflow:ellipsis}.el-form-item span.custom-label i[data-v-0bf26fd2]{margin:0 3px}.el-form-item[data-v-0bf26fd2] .hide-spin-button input::-webkit-inner-spin-button,.el-form-item[data-v-0bf26fd2] .hide-spin-button input::-webkit-outer-spin-button{-webkit-appearance:none!important}.el-form-item[data-v-0bf26fd2] .hide-spin-button input[type=number]{-moz-appearance:textfield}.required[data-v-0bf26fd2] .el-form-item__label:before{content:"*";color:#f56c6c;margin-right:4px}.static-content-item[data-v-0bf26fd2]{min-height:20px;display:flex;align-items:center}.static-content-item[data-v-0bf26fd2] .el-divider--horizontal{margin:0}.el-form-item.selected[data-v-0bf26fd2],.static-content-item.selected[data-v-0bf26fd2]{outline:2px solid #409eff}[data-v-0bf26fd2] .label-left-align .el-form-item__label{text-align:left}[data-v-0bf26fd2] .label-center-align .el-form-item__label{text-align:center}[data-v-0bf26fd2] .label-right-align .el-form-item__label{text-align:right}.primary-color[data-v-40c2df66]{color:#409eff}.background-opacity[data-v-40c2df66]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-40c2df66]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-40c2df66]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-40c2df66]{margin-top:8px}.el-form-item--small .el-radio[data-v-40c2df66]{line-height:32px!important}.el-form-item--small .el-rate[data-v-40c2df66]{margin-top:6px}.el-form-item--mini .el-radio[data-v-40c2df66]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-40c2df66]{margin-top:4px}.el-card[data-v-40c2df66]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-40c2df66]::-ms-reveal{display:none}[data-v-40c2df66]::-webkit-scrollbar{width:8px;height:8px}[data-v-40c2df66]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-40c2df66]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-40c2df66]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-40c2df66]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-40c2df66]{width:100%!important}.primary-color[data-v-608e81d3]{color:#409eff}.background-opacity[data-v-608e81d3]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-608e81d3]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-608e81d3]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-608e81d3]{margin-top:8px}.el-form-item--small .el-radio[data-v-608e81d3]{line-height:32px!important}.el-form-item--small .el-rate[data-v-608e81d3]{margin-top:6px}.el-form-item--mini .el-radio[data-v-608e81d3]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-608e81d3]{margin-top:4px}.el-card[data-v-608e81d3]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-608e81d3]::-ms-reveal{display:none}[data-v-608e81d3]::-webkit-scrollbar{width:8px;height:8px}[data-v-608e81d3]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-608e81d3]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-608e81d3]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-608e81d3]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-53ad0c08]{color:#409eff}.background-opacity[data-v-53ad0c08]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-53ad0c08]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-53ad0c08]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-53ad0c08]{margin-top:8px}.el-form-item--small .el-radio[data-v-53ad0c08]{line-height:32px!important}.el-form-item--small .el-rate[data-v-53ad0c08]{margin-top:6px}.el-form-item--mini .el-radio[data-v-53ad0c08]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-53ad0c08]{margin-top:4px}.el-card[data-v-53ad0c08]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-53ad0c08]::-ms-reveal{display:none}[data-v-53ad0c08]::-webkit-scrollbar{width:8px;height:8px}[data-v-53ad0c08]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-53ad0c08]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-53ad0c08]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-53ad0c08]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-53ad0c08]{width:100%!important}.primary-color[data-v-76c3fdc8]{color:#409eff}.background-opacity[data-v-76c3fdc8]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-76c3fdc8]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-76c3fdc8]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-76c3fdc8]{margin-top:8px}.el-form-item--small .el-radio[data-v-76c3fdc8]{line-height:32px!important}.el-form-item--small .el-rate[data-v-76c3fdc8]{margin-top:6px}.el-form-item--mini .el-radio[data-v-76c3fdc8]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-76c3fdc8]{margin-top:4px}.el-card[data-v-76c3fdc8]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-76c3fdc8]::-ms-reveal{display:none}[data-v-76c3fdc8]::-webkit-scrollbar{width:8px;height:8px}[data-v-76c3fdc8]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-76c3fdc8]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-76c3fdc8]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-76c3fdc8]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-76c3fdc8]{width:100%!important}.primary-color[data-v-ea728dba]{color:#409eff}.background-opacity[data-v-ea728dba]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-ea728dba]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-ea728dba]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-ea728dba]{margin-top:8px}.el-form-item--small .el-radio[data-v-ea728dba]{line-height:32px!important}.el-form-item--small .el-rate[data-v-ea728dba]{margin-top:6px}.el-form-item--mini .el-radio[data-v-ea728dba]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-ea728dba]{margin-top:4px}.el-card[data-v-ea728dba]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-ea728dba]::-ms-reveal{display:none}[data-v-ea728dba]::-webkit-scrollbar{width:8px;height:8px}[data-v-ea728dba]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-ea728dba]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-ea728dba]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-ea728dba]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-ea728dba]{width:100%!important}.primary-color[data-v-0faf59b2]{color:#409eff}.background-opacity[data-v-0faf59b2]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-0faf59b2]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-0faf59b2]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-0faf59b2]{margin-top:8px}.el-form-item--small .el-radio[data-v-0faf59b2]{line-height:32px!important}.el-form-item--small .el-rate[data-v-0faf59b2]{margin-top:6px}.el-form-item--mini .el-radio[data-v-0faf59b2]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-0faf59b2]{margin-top:4px}.el-card[data-v-0faf59b2]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-0faf59b2]::-ms-reveal{display:none}[data-v-0faf59b2]::-webkit-scrollbar{width:8px;height:8px}[data-v-0faf59b2]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-0faf59b2]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-0faf59b2]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-0faf59b2]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-3f51f292]{color:#409eff}.background-opacity[data-v-3f51f292]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-3f51f292]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-3f51f292]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-3f51f292]{margin-top:8px}.el-form-item--small .el-radio[data-v-3f51f292]{line-height:32px!important}.el-form-item--small .el-rate[data-v-3f51f292]{margin-top:6px}.el-form-item--mini .el-radio[data-v-3f51f292]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-3f51f292]{margin-top:4px}.el-card[data-v-3f51f292]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-3f51f292]::-ms-reveal{display:none}[data-v-3f51f292]::-webkit-scrollbar{width:8px;height:8px}[data-v-3f51f292]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-3f51f292]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-3f51f292]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-3f51f292]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-3f51f292]{width:100%!important}.dynamicPseudoAfter[data-v-3f51f292] .el-upload.el-upload--text{color:#409eff;font-size:12px}.dynamicPseudoAfter[data-v-3f51f292] .el-upload.el-upload--text .el-icon-plus:after{content:var(--select-file-action)}.hideUploadDiv[data-v-3f51f292] div.el-upload--picture-card,.hideUploadDiv[data-v-3f51f292] div.el-upload--text,.hideUploadDiv[data-v-3f51f292] div.el-upload__tip{display:none}.upload-file-list[data-v-3f51f292]{font-size:12px}.upload-file-list .file-action[data-v-3f51f292]{color:#409eff;margin-left:5px;margin-right:5px;cursor:pointer}.primary-color[data-v-5b64c2ea]{color:#409eff}.background-opacity[data-v-5b64c2ea]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-5b64c2ea]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-5b64c2ea]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-5b64c2ea]{margin-top:8px}.el-form-item--small .el-radio[data-v-5b64c2ea]{line-height:32px!important}.el-form-item--small .el-rate[data-v-5b64c2ea]{margin-top:6px}.el-form-item--mini .el-radio[data-v-5b64c2ea]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-5b64c2ea]{margin-top:4px}.el-card[data-v-5b64c2ea]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-5b64c2ea]::-ms-reveal{display:none}[data-v-5b64c2ea]::-webkit-scrollbar{width:8px;height:8px}[data-v-5b64c2ea]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-5b64c2ea]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-5b64c2ea]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-5b64c2ea]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-97099720]{color:#409eff}.background-opacity[data-v-97099720]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-97099720]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-97099720]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-97099720]{margin-top:8px}.el-form-item--small .el-radio[data-v-97099720]{line-height:32px!important}.el-form-item--small .el-rate[data-v-97099720]{margin-top:6px}.el-form-item--mini .el-radio[data-v-97099720]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-97099720]{margin-top:4px}.el-card[data-v-97099720]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-97099720]::-ms-reveal{display:none}[data-v-97099720]::-webkit-scrollbar{width:8px;height:8px}[data-v-97099720]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-97099720]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-97099720]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-97099720]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-a039267e]{color:#409eff}.background-opacity[data-v-a039267e]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-a039267e]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-a039267e]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-a039267e]{margin-top:8px}.el-form-item--small .el-radio[data-v-a039267e]{line-height:32px!important}.el-form-item--small .el-rate[data-v-a039267e]{margin-top:6px}.el-form-item--mini .el-radio[data-v-a039267e]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-a039267e]{margin-top:4px}.el-card[data-v-a039267e]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-a039267e]::-ms-reveal{display:none}[data-v-a039267e]::-webkit-scrollbar{width:8px;height:8px}[data-v-a039267e]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-a039267e]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-a039267e]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-a039267e]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-a039267e]{width:100%!important}.primary-color[data-v-7aa66af0]{color:#409eff}.background-opacity[data-v-7aa66af0]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-7aa66af0]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-7aa66af0]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-7aa66af0]{margin-top:8px}.el-form-item--small .el-radio[data-v-7aa66af0]{line-height:32px!important}.el-form-item--small .el-rate[data-v-7aa66af0]{margin-top:6px}.el-form-item--mini .el-radio[data-v-7aa66af0]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-7aa66af0]{margin-top:4px}.el-card[data-v-7aa66af0]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-7aa66af0]::-ms-reveal{display:none}[data-v-7aa66af0]::-webkit-scrollbar{width:8px;height:8px}[data-v-7aa66af0]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-7aa66af0]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-7aa66af0]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-7aa66af0]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-7aa66af0]{width:100%!important}.hideUploadDiv[data-v-7aa66af0] div.el-upload--picture-card,.hideUploadDiv[data-v-7aa66af0] div.el-upload--text,.hideUploadDiv[data-v-7aa66af0] div.el-upload__tip{display:none}.primary-color[data-v-ef35f5b6]{color:#409eff}.background-opacity[data-v-ef35f5b6]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-ef35f5b6]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-ef35f5b6]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-ef35f5b6]{margin-top:8px}.el-form-item--small .el-radio[data-v-ef35f5b6]{line-height:32px!important}.el-form-item--small .el-rate[data-v-ef35f5b6]{margin-top:6px}.el-form-item--mini .el-radio[data-v-ef35f5b6]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-ef35f5b6]{margin-top:4px}.el-card[data-v-ef35f5b6]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-ef35f5b6]::-ms-reveal{display:none}[data-v-ef35f5b6]::-webkit-scrollbar{width:8px;height:8px}[data-v-ef35f5b6]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-ef35f5b6]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-ef35f5b6]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-ef35f5b6]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-02bf17e4]{color:#409eff}.background-opacity[data-v-02bf17e4]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-02bf17e4]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-02bf17e4]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-02bf17e4]{margin-top:8px}.el-form-item--small .el-radio[data-v-02bf17e4]{line-height:32px!important}.el-form-item--small .el-rate[data-v-02bf17e4]{margin-top:6px}.el-form-item--mini .el-radio[data-v-02bf17e4]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-02bf17e4]{margin-top:4px}.el-card[data-v-02bf17e4]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-02bf17e4]::-ms-reveal{display:none}[data-v-02bf17e4]::-webkit-scrollbar{width:8px;height:8px}[data-v-02bf17e4]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-02bf17e4]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-02bf17e4]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-02bf17e4]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-02bf17e4]{width:100%!important}.primary-color[data-v-29731672]{color:#409eff}.background-opacity[data-v-29731672]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-29731672]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-29731672]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-29731672]{margin-top:8px}.el-form-item--small .el-radio[data-v-29731672]{line-height:32px!important}.el-form-item--small .el-rate[data-v-29731672]{margin-top:6px}.el-form-item--mini .el-radio[data-v-29731672]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-29731672]{margin-top:4px}.el-card[data-v-29731672]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-29731672]::-ms-reveal{display:none}[data-v-29731672]::-webkit-scrollbar{width:8px;height:8px}[data-v-29731672]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-29731672]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-29731672]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-29731672]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-29731672]{width:100%!important}.primary-color[data-v-19724718]{color:#409eff}.background-opacity[data-v-19724718]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-19724718]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-19724718]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-19724718]{margin-top:8px}.el-form-item--small .el-radio[data-v-19724718]{line-height:32px!important}.el-form-item--small .el-rate[data-v-19724718]{margin-top:6px}.el-form-item--mini .el-radio[data-v-19724718]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-19724718]{margin-top:4px}.el-card[data-v-19724718]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-19724718]::-ms-reveal{display:none}[data-v-19724718]::-webkit-scrollbar{width:8px;height:8px}[data-v-19724718]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-19724718]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-19724718]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-19724718]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-19724718]{width:100%!important}.primary-color[data-v-ddcdb608]{color:#409eff}.background-opacity[data-v-ddcdb608]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-ddcdb608]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-ddcdb608]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-ddcdb608]{margin-top:8px}.el-form-item--small .el-radio[data-v-ddcdb608]{line-height:32px!important}.el-form-item--small .el-rate[data-v-ddcdb608]{margin-top:6px}.el-form-item--mini .el-radio[data-v-ddcdb608]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-ddcdb608]{margin-top:4px}.el-card[data-v-ddcdb608]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-ddcdb608]::-ms-reveal{display:none}[data-v-ddcdb608]::-webkit-scrollbar{width:8px;height:8px}[data-v-ddcdb608]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-ddcdb608]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-ddcdb608]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-ddcdb608]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-ddcdb608]{width:100%!important}.primary-color[data-v-856e2df6]{color:#409eff}.background-opacity[data-v-856e2df6]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-856e2df6]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-856e2df6]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-856e2df6]{margin-top:8px}.el-form-item--small .el-radio[data-v-856e2df6]{line-height:32px!important}.el-form-item--small .el-rate[data-v-856e2df6]{margin-top:6px}.el-form-item--mini .el-radio[data-v-856e2df6]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-856e2df6]{margin-top:4px}.el-card[data-v-856e2df6]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-856e2df6]::-ms-reveal{display:none}[data-v-856e2df6]::-webkit-scrollbar{width:8px;height:8px}[data-v-856e2df6]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-856e2df6]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-856e2df6]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-856e2df6]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.slot-wrapper-design[data-v-856e2df6]{width:100%;min-height:26px;background:linear-gradient(45deg,#ccc 25%,#eee 0,#eee 50%,#ccc 0,#ccc 75%,#eee 0);background-size:20px 20px;text-align:center}.slot-wrapper-design .slot-title[data-v-856e2df6]{font-size:13px}.primary-color[data-v-15a81133]{color:#409eff}.background-opacity[data-v-15a81133]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-15a81133]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-15a81133]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-15a81133]{margin-top:8px}.el-form-item--small .el-radio[data-v-15a81133]{line-height:32px!important}.el-form-item--small .el-rate[data-v-15a81133]{margin-top:6px}.el-form-item--mini .el-radio[data-v-15a81133]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-15a81133]{margin-top:4px}.el-card[data-v-15a81133]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-15a81133]::-ms-reveal{display:none}[data-v-15a81133]::-webkit-scrollbar{width:8px;height:8px}[data-v-15a81133]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-15a81133]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-15a81133]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-15a81133]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-88bb0ad8]{color:#409eff}.background-opacity[data-v-88bb0ad8]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-88bb0ad8]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-88bb0ad8]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-88bb0ad8]{margin-top:8px}.el-form-item--small .el-radio[data-v-88bb0ad8]{line-height:32px!important}.el-form-item--small .el-rate[data-v-88bb0ad8]{margin-top:6px}.el-form-item--mini .el-radio[data-v-88bb0ad8]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-88bb0ad8]{margin-top:4px}.el-card[data-v-88bb0ad8]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-88bb0ad8]::-ms-reveal{display:none}[data-v-88bb0ad8]::-webkit-scrollbar{width:8px;height:8px}[data-v-88bb0ad8]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-88bb0ad8]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-88bb0ad8]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-88bb0ad8]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-88bb0ad8]{width:100%!important}.primary-color[data-v-90e01c78]{color:#409eff}.background-opacity[data-v-90e01c78]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-90e01c78]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-90e01c78]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-90e01c78]{margin-top:8px}.el-form-item--small .el-radio[data-v-90e01c78]{line-height:32px!important}.el-form-item--small .el-rate[data-v-90e01c78]{margin-top:6px}.el-form-item--mini .el-radio[data-v-90e01c78]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-90e01c78]{margin-top:4px}.el-card[data-v-90e01c78]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-90e01c78]::-ms-reveal{display:none}[data-v-90e01c78]::-webkit-scrollbar{width:8px;height:8px}[data-v-90e01c78]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-90e01c78]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-90e01c78]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-90e01c78]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.primary-color[data-v-68ea79e5]{color:#409eff}.background-opacity[data-v-68ea79e5]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-68ea79e5]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-68ea79e5]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-68ea79e5]{margin-top:8px}.el-form-item--small .el-radio[data-v-68ea79e5]{line-height:32px!important}.el-form-item--small .el-rate[data-v-68ea79e5]{margin-top:6px}.el-form-item--mini .el-radio[data-v-68ea79e5]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-68ea79e5]{margin-top:4px}.el-card[data-v-68ea79e5]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-68ea79e5]::-ms-reveal{display:none}[data-v-68ea79e5]::-webkit-scrollbar{width:8px;height:8px}[data-v-68ea79e5]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-68ea79e5]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-68ea79e5]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-68ea79e5]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-68ea79e5]{width:100%!important}.primary-color[data-v-0761446e]{color:#409eff}.background-opacity[data-v-0761446e]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-0761446e]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-0761446e]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-0761446e]{margin-top:8px}.el-form-item--small .el-radio[data-v-0761446e]{line-height:32px!important}.el-form-item--small .el-rate[data-v-0761446e]{margin-top:6px}.el-form-item--mini .el-radio[data-v-0761446e]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-0761446e]{margin-top:4px}.el-card[data-v-0761446e]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-0761446e]::-ms-reveal{display:none}[data-v-0761446e]::-webkit-scrollbar{width:8px;height:8px}[data-v-0761446e]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-0761446e]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-0761446e]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-0761446e]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.full-width-input[data-v-0761446e]{width:100%!important}.primary-color[data-v-943e926a]{color:#409eff}.background-opacity[data-v-943e926a]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-943e926a]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-943e926a]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-943e926a]{margin-top:8px}.el-form-item--small .el-radio[data-v-943e926a]{line-height:32px!important}.el-form-item--small .el-rate[data-v-943e926a]{margin-top:6px}.el-form-item--mini .el-radio[data-v-943e926a]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-943e926a]{margin-top:4px}.el-card[data-v-943e926a]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-943e926a]::-ms-reveal{display:none}[data-v-943e926a]::-webkit-scrollbar{width:8px;height:8px}[data-v-943e926a]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-943e926a]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-943e926a]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-943e926a]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.blank-cell[data-v-943e926a]{font-style:italic;color:#ccc}.blank-cell span.invisible-content[data-v-943e926a]{opacity:0}.primary-color[data-v-0cc705e0]{color:#409eff}.background-opacity[data-v-0cc705e0]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-0cc705e0]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-0cc705e0]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-0cc705e0]{margin-top:8px}.el-form-item--small .el-radio[data-v-0cc705e0]{line-height:32px!important}.el-form-item--small .el-rate[data-v-0cc705e0]{margin-top:6px}.el-form-item--mini .el-radio[data-v-0cc705e0]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-0cc705e0]{margin-top:4px}.el-card[data-v-0cc705e0]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-0cc705e0]::-ms-reveal{display:none}[data-v-0cc705e0]::-webkit-scrollbar{width:8px;height:8px}[data-v-0cc705e0]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-0cc705e0]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-0cc705e0]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-0cc705e0]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.sub-form-container[data-v-0cc705e0]{margin-bottom:8px;text-align:left}.sub-form-container[data-v-0cc705e0] .el-row.header-row{padding-bottom:0}.sub-form-container[data-v-0cc705e0] .el-row.sub-form-row{padding-top:3px;padding-bottom:3px}.sub-form-container[data-v-0cc705e0] .el-row.sub-form-row .row-number-span{margin-left:16px}div.action-header-column[data-v-0cc705e0]{display:inline-block;width:120px}div.action-header-column .action-label[data-v-0cc705e0]{margin-right:12px}div.action-header-column .action-button[data-v-0cc705e0]{padding-left:8px;padding-right:8px}div.field-header-column[data-v-0cc705e0]{display:inline-block}div.field-header-column span.custom-label i[data-v-0cc705e0]{margin:0 3px}div.field-header-column.is-required[data-v-0cc705e0]:before{content:"*";color:#f56c6c;margin-right:4px}div.label-center-left[data-v-0cc705e0]{text-align:left}div.label-center-align[data-v-0cc705e0]{text-align:center}div.label-right-align[data-v-0cc705e0]{text-align:right}div.sub-form-action-column[data-v-0cc705e0]{display:inline-block;width:120px}div.sub-form-action-column[data-v-0cc705e0] .el-form-item{margin-bottom:0}div.sub-form-action-column[data-v-0cc705e0] .el-button{font-size:18px;padding:0;background:#dcdfe6;border:4px solid #dcdfe6}div.sub-form-action-column.hide-label[data-v-0cc705e0] .el-form-item__label{display:none}div.sub-form-table-column[data-v-0cc705e0]{display:inline-block}div.sub-form-table-column[data-v-0cc705e0] .el-form-item{margin-left:4px;margin-right:4px;margin-bottom:0}div.sub-form-table-column[data-v-0cc705e0] .el-form-item__content{margin-left:0!important}div.sub-form-table-column.hide-label[data-v-0cc705e0] .el-form-item__label{display:none}.primary-color[data-v-79b5d9f8]{color:#409eff}.background-opacity[data-v-79b5d9f8]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-79b5d9f8]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-79b5d9f8]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-79b5d9f8]{margin-top:8px}.el-form-item--small .el-radio[data-v-79b5d9f8]{line-height:32px!important}.el-form-item--small .el-rate[data-v-79b5d9f8]{margin-top:6px}.el-form-item--mini .el-radio[data-v-79b5d9f8]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-79b5d9f8]{margin-top:4px}.el-card[data-v-79b5d9f8]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-79b5d9f8]::-ms-reveal{display:none}[data-v-79b5d9f8]::-webkit-scrollbar{width:8px;height:8px}[data-v-79b5d9f8]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-79b5d9f8]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-79b5d9f8]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-79b5d9f8]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}td.table-cell[data-v-79b5d9f8]{display:table-cell;height:36px;border:1px solid #e5e5e5}.primary-color[data-v-5a8d7072]{color:#409eff}.background-opacity[data-v-5a8d7072]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-5a8d7072]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-5a8d7072]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-5a8d7072]{margin-top:8px}.el-form-item--small .el-radio[data-v-5a8d7072]{line-height:32px!important}.el-form-item--small .el-rate[data-v-5a8d7072]{margin-top:6px}.el-form-item--mini .el-radio[data-v-5a8d7072]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-5a8d7072]{margin-top:4px}.el-card[data-v-5a8d7072]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-5a8d7072]::-ms-reveal{display:none}[data-v-5a8d7072]::-webkit-scrollbar{width:8px;height:8px}[data-v-5a8d7072]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-5a8d7072]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-5a8d7072]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-5a8d7072]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}div.table-container table.table-layout[data-v-5a8d7072]{width:100%;table-layout:fixed;border-collapse:collapse}.primary-color[data-v-70ce788c]{color:#409eff}.background-opacity[data-v-70ce788c]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-70ce788c]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-70ce788c]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-70ce788c]{margin-top:8px}.el-form-item--small .el-radio[data-v-70ce788c]{line-height:32px!important}.el-form-item--small .el-rate[data-v-70ce788c]{margin-top:6px}.el-form-item--mini .el-radio[data-v-70ce788c]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-70ce788c]{margin-top:4px}.el-card[data-v-70ce788c]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-70ce788c]::-ms-reveal{display:none}[data-v-70ce788c]::-webkit-scrollbar{width:8px;height:8px}[data-v-70ce788c]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-70ce788c]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-70ce788c]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-70ce788c]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.el-form[data-v-70ce788c] .el-row{padding:8px}.primary-color[data-v-d13460f4]{color:#409eff}.background-opacity[data-v-d13460f4]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-d13460f4]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-d13460f4]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-d13460f4]{margin-top:8px}.el-form-item--small .el-radio[data-v-d13460f4]{line-height:32px!important}.el-form-item--small .el-rate[data-v-d13460f4]{margin-top:6px}.el-form-item--mini .el-radio[data-v-d13460f4]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-d13460f4]{margin-top:4px}.el-card[data-v-d13460f4]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-d13460f4]::-ms-reveal{display:none}[data-v-d13460f4]::-webkit-scrollbar{width:8px;height:8px}[data-v-d13460f4]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-d13460f4]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-d13460f4]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-d13460f4]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.ace-editor[data-v-d13460f4]{min-height:300px}.primary-color[data-v-a010c82e]{color:#409eff}.background-opacity[data-v-a010c82e]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-a010c82e]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-a010c82e]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-a010c82e]{margin-top:8px}.el-form-item--small .el-radio[data-v-a010c82e]{line-height:32px!important}.el-form-item--small .el-rate[data-v-a010c82e]{margin-top:6px}.el-form-item--mini .el-radio[data-v-a010c82e]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-a010c82e]{margin-top:4px}.el-card[data-v-a010c82e]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-a010c82e]::-ms-reveal{display:none}[data-v-a010c82e]::-webkit-scrollbar{width:8px;height:8px}[data-v-a010c82e]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-a010c82e]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-a010c82e]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-a010c82e]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.left-toolbar[data-v-a010c82e]{float:left;font-size:16px}.right-toolbar[data-v-a010c82e]{float:right;text-align:right;overflow:hidden}.right-toolbar .right-toolbar-con[data-v-a010c82e]{text-align:left;width:600px}.right-toolbar[data-v-a010c82e] .el-button--text{font-size:14px!important}.el-button i[data-v-a010c82e]{margin-right:3px}.small-padding-dialog[data-v-a010c82e] .el-dialog__header{background:#f1f2f3}.small-padding-dialog[data-v-a010c82e] .el-dialog__body{padding:12px 15px 12px 15px}.small-padding-dialog[data-v-a010c82e] .el-dialog__body .el-alert.alert-padding{padding:0 10px}.small-padding-dialog[data-v-a010c82e] .ace-container{border:1px solid #dcdfe6}.dialog-title-light-bg[data-v-a010c82e] .el-dialog__header{background:#f1f2f3}.no-box-shadow[data-v-a010c82e]{box-shadow:none}.no-padding.el-tabs--border-card[data-v-a010c82e] .el-tabs__content{padding:0}.form-render-wrapper.h5-layout[data-v-a010c82e]{width:420px}.form-render-wrapper.h5-layout[data-v-a010c82e],.form-render-wrapper.pad-layout[data-v-a010c82e]{margin:0 auto;border-radius:15px;box-shadow:0 0 1px 10px #495060;height:calc(100vh - 142px);overflow-y:auto;overflow-x:hidden}.form-render-wrapper.pad-layout[data-v-a010c82e]{width:960px}.node-tree-drawer[data-v-a010c82e] .el-drawer{padding:10px;overflow:auto}.node-tree-drawer[data-v-a010c82e] .el-drawer__header{margin-bottom:12px;padding:5px 5px 0}.node-tree-drawer[data-v-a010c82e] .el-drawer__body{padding-left:5px}.node-tree[data-v-a010c82e] .el-tree-node{position:relative;padding-left:12px}.node-tree[data-v-a010c82e] .el-tree-node__content{padding-left:0!important}.node-tree[data-v-a010c82e] .el-tree-node__expand-icon.is-leaf{display:none}.node-tree[data-v-a010c82e] .el-tree-node__children{padding-left:12px;overflow:visible!important}.node-tree[data-v-a010c82e] .el-tree-node :last-child:before{height:38px}.node-tree[data-v-a010c82e] .el-tree>.el-tree-node:before{border-left:none}.node-tree[data-v-a010c82e] .el-tree>.el-tree-node:after{border-top:none}.node-tree[data-v-a010c82e] .el-tree-node:after,.node-tree[data-v-a010c82e] .el-tree-node:before{content:"";left:-4px;position:absolute;right:auto;border-width:1px}.node-tree[data-v-a010c82e] .el-tree-node:before{border-left:1px dashed #4386c6;bottom:0;height:100%;top:-10px;width:1px}.node-tree[data-v-a010c82e] .el-tree-node:after{border-top:1px dashed #4386c6;height:20px;top:12px;width:16px}.node-tree[data-v-a010c82e] .el-tree-node.is-current>.el-tree-node__content{background:#c2d6ea!important}.node-tree[data-v-a010c82e] .el-tree-node__expand-icon{margin-left:-3px;padding:6px 6px 6px 0;font-size:16px}.primary-color[data-v-ebfa1f06]{color:#409eff}.background-opacity[data-v-ebfa1f06]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-ebfa1f06]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-ebfa1f06]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-ebfa1f06]{margin-top:8px}.el-form-item--small .el-radio[data-v-ebfa1f06]{line-height:32px!important}.el-form-item--small .el-rate[data-v-ebfa1f06]{margin-top:6px}.el-form-item--mini .el-radio[data-v-ebfa1f06]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-ebfa1f06]{margin-top:4px}.el-card[data-v-ebfa1f06]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-ebfa1f06]::-ms-reveal{display:none}[data-v-ebfa1f06]::-webkit-scrollbar{width:8px;height:8px}[data-v-ebfa1f06]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-ebfa1f06]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-ebfa1f06]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-ebfa1f06]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}li.col-item[data-v-ebfa1f06]{list-style:none}li.col-item span.col-span-title[data-v-ebfa1f06]{display:inline-block;font-size:13px;width:120px}li.col-item .col-delete-button[data-v-ebfa1f06]{margin-left:6px}.primary-color[data-v-66fb0270]{color:#409eff}.background-opacity[data-v-66fb0270]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-66fb0270]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-66fb0270]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-66fb0270]{margin-top:8px}.el-form-item--small .el-radio[data-v-66fb0270]{line-height:32px!important}.el-form-item--small .el-rate[data-v-66fb0270]{margin-top:6px}.el-form-item--mini .el-radio[data-v-66fb0270]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-66fb0270]{margin-top:4px}.el-card[data-v-66fb0270]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-66fb0270]::-ms-reveal{display:none}[data-v-66fb0270]::-webkit-scrollbar{width:8px;height:8px}[data-v-66fb0270]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-66fb0270]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-66fb0270]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-66fb0270]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.radio-group-custom[data-v-66fb0270] .el-radio-button__inner{padding-left:12px;padding-right:12px}.primary-color[data-v-6ddd24c1]{color:#409eff}.background-opacity[data-v-6ddd24c1]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-6ddd24c1]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-6ddd24c1]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-6ddd24c1]{margin-top:8px}.el-form-item--small .el-radio[data-v-6ddd24c1]{line-height:32px!important}.el-form-item--small .el-rate[data-v-6ddd24c1]{margin-top:6px}.el-form-item--mini .el-radio[data-v-6ddd24c1]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-6ddd24c1]{margin-top:4px}.el-card[data-v-6ddd24c1]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-6ddd24c1]::-ms-reveal{display:none}[data-v-6ddd24c1]::-webkit-scrollbar{width:8px;height:8px}[data-v-6ddd24c1]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-6ddd24c1]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-6ddd24c1]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-6ddd24c1]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}li.col-item[data-v-6ddd24c1]{list-style:none}li.col-item span.col-span-title[data-v-6ddd24c1]{display:inline-block;font-size:13px;width:120px}li.col-item .col-delete-button[data-v-6ddd24c1]{margin-left:6px}.panes-setting ul[data-v-6ddd24c1]{-webkit-padding-start:0;padding-inline-start:0;padding-left:0;margin:0}.panes-setting .drag-option[data-v-6ddd24c1]{cursor:move}.panes-setting li.ghost[data-v-6ddd24c1]{background:#fff;border:2px dotted #409eff}.html-content-editor[data-v-a3fcc8ba]{font-size:13px}.primary-color[data-v-3312ca7f]{color:#409eff}.background-opacity[data-v-3312ca7f]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-3312ca7f]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-3312ca7f]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-3312ca7f]{margin-top:8px}.el-form-item--small .el-radio[data-v-3312ca7f]{line-height:32px!important}.el-form-item--small .el-rate[data-v-3312ca7f]{margin-top:6px}.el-form-item--mini .el-radio[data-v-3312ca7f]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-3312ca7f]{margin-top:4px}.el-card[data-v-3312ca7f]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-3312ca7f]::-ms-reveal{display:none}[data-v-3312ca7f]::-webkit-scrollbar{width:8px;height:8px}[data-v-3312ca7f]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-3312ca7f]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-3312ca7f]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-3312ca7f]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.radio-group-custom[data-v-3312ca7f] .el-radio-button__inner{padding-left:12px;padding-right:12px}.primary-color[data-v-7202e5fc]{color:#409eff}.background-opacity[data-v-7202e5fc]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-7202e5fc]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-7202e5fc]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-7202e5fc]{margin-top:8px}.el-form-item--small .el-radio[data-v-7202e5fc]{line-height:32px!important}.el-form-item--small .el-rate[data-v-7202e5fc]{margin-top:6px}.el-form-item--mini .el-radio[data-v-7202e5fc]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-7202e5fc]{margin-top:4px}.el-card[data-v-7202e5fc]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-7202e5fc]::-ms-reveal{display:none}[data-v-7202e5fc]::-webkit-scrollbar{width:8px;height:8px}[data-v-7202e5fc]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-7202e5fc]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-7202e5fc]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-7202e5fc]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.option-items-pane ul[data-v-7202e5fc]{-webkit-padding-start:6px;padding-inline-start:6px;padding-left:6px}li.ghost[data-v-7202e5fc]{background:#fff;border:2px dotted #409eff}.drag-option[data-v-7202e5fc]{cursor:move}.small-padding-dialog[data-v-7202e5fc] .el-dialog__body{padding:10px 15px}.dialog-footer .el-button[data-v-7202e5fc]{width:100px}.primary-color[data-v-c9642832]{color:#409eff}.background-opacity[data-v-c9642832]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-c9642832]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-c9642832]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-c9642832]{margin-top:8px}.el-form-item--small .el-radio[data-v-c9642832]{line-height:32px!important}.el-form-item--small .el-rate[data-v-c9642832]{margin-top:6px}.el-form-item--mini .el-radio[data-v-c9642832]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-c9642832]{margin-top:4px}.el-card[data-v-c9642832]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-c9642832]::-ms-reveal{display:none}[data-v-c9642832]::-webkit-scrollbar{width:8px;height:8px}[data-v-c9642832]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-c9642832]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-c9642832]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-c9642832]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.setting-form[data-v-c9642832] .el-form-item__label{font-size:13px;overflow:hidden;white-space:nowrap}.setting-form[data-v-c9642832] .el-form-item--mini.el-form-item{margin-bottom:6px}.setting-form .radio-group-custom[data-v-c9642832] .el-radio-button__inner{padding-left:12px;padding-right:12px}.setting-form .custom-divider.el-divider--horizontal[data-v-c9642832]{margin:10px 0}.setting-collapse[data-v-c9642832] .el-collapse-item__content{padding-bottom:6px}.setting-collapse[data-v-c9642832] .el-collapse-item__header{font-style:italic;font-weight:700}.small-padding-dialog[data-v-c9642832] .el-dialog__body{padding:6px 15px 12px 15px}.primary-color[data-v-c0de647a]{color:#409eff}.background-opacity[data-v-c0de647a]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-c0de647a]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-c0de647a]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-c0de647a]{margin-top:8px}.el-form-item--small .el-radio[data-v-c0de647a]{line-height:32px!important}.el-form-item--small .el-rate[data-v-c0de647a]{margin-top:6px}.el-form-item--mini .el-radio[data-v-c0de647a]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-c0de647a]{margin-top:4px}.el-card[data-v-c0de647a]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-c0de647a]::-ms-reveal{display:none}[data-v-c0de647a]::-webkit-scrollbar{width:8px;height:8px}[data-v-c0de647a]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-c0de647a]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-c0de647a]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-c0de647a]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.panel-container[data-v-c0de647a]{padding:0 8px}.setting-scrollbar[data-v-c0de647a] .el-scrollbar__wrap{overflow-x:hidden}.setting-collapse[data-v-c0de647a] .el-collapse-item__content{padding-bottom:6px}.setting-collapse[data-v-c0de647a] .el-collapse-item__header{font-style:italic;font-weight:700}.setting-form[data-v-c0de647a] .el-form-item__label{font-size:13px;overflow:hidden;white-space:nowrap}.setting-form[data-v-c0de647a] .el-form-item--mini.el-form-item{margin-bottom:6px}[data-v-c0de647a] .hide-spin-button input::-webkit-inner-spin-button,[data-v-c0de647a] .hide-spin-button input::-webkit-outer-spin-button{-webkit-appearance:none!important}[data-v-c0de647a] .hide-spin-button input[type=number]{-moz-appearance:textfield}[data-v-c0de647a] .custom-divider.el-divider--horizontal{margin:10px 0}[data-v-c0de647a] .custom-divider-margin-top.el-divider--horizontal{margin:20px 0}.small-padding-dialog[data-v-c0de647a] .el-dialog__body{padding:6px 15px 12px 15px}.primary-color[data-v-b98cf8dc]{color:#409eff}.background-opacity[data-v-b98cf8dc]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-b98cf8dc]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-b98cf8dc]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-b98cf8dc]{margin-top:8px}.el-form-item--small .el-radio[data-v-b98cf8dc]{line-height:32px!important}.el-form-item--small .el-rate[data-v-b98cf8dc]{margin-top:6px}.el-form-item--mini .el-radio[data-v-b98cf8dc]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-b98cf8dc]{margin-top:4px}.el-card[data-v-b98cf8dc]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-b98cf8dc]::-ms-reveal{display:none}[data-v-b98cf8dc]::-webkit-scrollbar{width:8px;height:8px}[data-v-b98cf8dc]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-b98cf8dc]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-b98cf8dc]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-b98cf8dc]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.container-wrapper[data-v-b98cf8dc]{position:relative;margin-bottom:5px}.container-wrapper .container-action[data-v-b98cf8dc]{position:absolute;bottom:0;right:-2px;height:28px;line-height:28px;background:#409eff;z-index:999}.container-wrapper .container-action i[data-v-b98cf8dc]{font-size:14px;color:#fff;margin:0 5px;cursor:pointer}.container-wrapper .drag-handler[data-v-b98cf8dc]{position:absolute;top:-2px;left:-2px;height:22px;line-height:22px;background:#409eff;z-index:9}.container-wrapper .drag-handler i[data-v-b98cf8dc]{font-size:14px;font-style:normal;color:#fff;margin:4px;cursor:move}.primary-color[data-v-07e1e7bf]{color:#409eff}.background-opacity[data-v-07e1e7bf]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-07e1e7bf]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-07e1e7bf]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-07e1e7bf]{margin-top:8px}.el-form-item--small .el-radio[data-v-07e1e7bf]{line-height:32px!important}.el-form-item--small .el-rate[data-v-07e1e7bf]{margin-top:6px}.el-form-item--mini .el-radio[data-v-07e1e7bf]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-07e1e7bf]{margin-top:4px}.el-card[data-v-07e1e7bf]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-07e1e7bf]::-ms-reveal{display:none}[data-v-07e1e7bf]::-webkit-scrollbar{width:8px;height:8px}[data-v-07e1e7bf]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-07e1e7bf]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-07e1e7bf]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-07e1e7bf]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.grid-cell[data-v-07e1e7bf]{min-height:38px;padding:3px;outline:1px dashed #369;position:relative}.grid-cell .form-widget-list[data-v-07e1e7bf]{min-height:28px}.grid-cell .grid-col-action[data-v-07e1e7bf]{position:absolute;bottom:0;right:-2px;height:28px;line-height:28px;background:#409eff;z-index:999}.grid-cell .grid-col-action i[data-v-07e1e7bf]{font-size:14px;color:#fff;margin:0 5px;cursor:pointer}.grid-cell .grid-col-handler[data-v-07e1e7bf]{position:absolute;top:-2px;left:-2px;height:22px;line-height:22px;background:#409eff;z-index:9}.grid-cell .grid-col-handler i[data-v-07e1e7bf]{font-size:14px;font-style:normal;color:#fff;margin:4px;cursor:default}.primary-color[data-v-ec57838c]{color:#409eff}.background-opacity[data-v-ec57838c]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-ec57838c]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-ec57838c]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-ec57838c]{margin-top:8px}.el-form-item--small .el-radio[data-v-ec57838c]{line-height:32px!important}.el-form-item--small .el-rate[data-v-ec57838c]{margin-top:6px}.el-form-item--mini .el-radio[data-v-ec57838c]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-ec57838c]{margin-top:4px}.el-card[data-v-ec57838c]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-ec57838c]::-ms-reveal{display:none}[data-v-ec57838c]::-webkit-scrollbar{width:8px;height:8px}[data-v-ec57838c]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-ec57838c]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-ec57838c]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-ec57838c]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.el-row.grid-container[data-v-ec57838c]{min-height:50px;outline:1px dashed #369}.el-row.grid-container .form-widget-list[data-v-ec57838c]{min-height:28px}.grid-cell.selected[data-v-ec57838c],.grid-container.selected[data-v-ec57838c]{outline:2px solid #409eff!important}.primary-color[data-v-5a6a2ce9]{color:#409eff}.background-opacity[data-v-5a6a2ce9]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-5a6a2ce9]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-5a6a2ce9]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-5a6a2ce9]{margin-top:8px}.el-form-item--small .el-radio[data-v-5a6a2ce9]{line-height:32px!important}.el-form-item--small .el-rate[data-v-5a6a2ce9]{margin-top:6px}.el-form-item--mini .el-radio[data-v-5a6a2ce9]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-5a6a2ce9]{margin-top:4px}.el-card[data-v-5a6a2ce9]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-5a6a2ce9]::-ms-reveal{display:none}[data-v-5a6a2ce9]::-webkit-scrollbar{width:8px;height:8px}[data-v-5a6a2ce9]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-5a6a2ce9]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-5a6a2ce9]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-5a6a2ce9]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.tab-container[data-v-5a6a2ce9]{margin:2px}.tab-container .form-widget-list[data-v-5a6a2ce9]{min-height:28px}.tab-container.selected[data-v-5a6a2ce9]{outline:2px solid #409eff!important}.primary-color[data-v-5f7bc992]{color:#409eff}.background-opacity[data-v-5f7bc992]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-5f7bc992]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-5f7bc992]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-5f7bc992]{margin-top:8px}.el-form-item--small .el-radio[data-v-5f7bc992]{line-height:32px!important}.el-form-item--small .el-rate[data-v-5f7bc992]{margin-top:6px}.el-form-item--mini .el-radio[data-v-5f7bc992]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-5f7bc992]{margin-top:4px}.el-card[data-v-5f7bc992]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-5f7bc992]::-ms-reveal{display:none}[data-v-5f7bc992]::-webkit-scrollbar{width:8px;height:8px}[data-v-5f7bc992]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-5f7bc992]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-5f7bc992]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-5f7bc992]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.table-cell[data-v-5f7bc992]{border:1px dashed #369;display:table-cell;position:relative}.table-cell .draggable-div[data-v-5f7bc992]{position:relative;height:100%}.table-cell .form-widget-list[data-v-5f7bc992]{border:1px dashed #369;margin:3px;height:100%}.table-cell .table-cell-action[data-v-5f7bc992]{position:absolute;bottom:0;right:-2px;height:28px;line-height:28px;background:#409eff;z-index:999}.table-cell .table-cell-action i[data-v-5f7bc992]{font-size:14px;color:#fff;margin:0 5px;cursor:pointer}.table-cell .table-cell-handler[data-v-5f7bc992]{position:absolute;top:-2px;left:-2px;height:22px;line-height:22px;background:#409eff;z-index:9}.table-cell .table-cell-handler i[data-v-5f7bc992]{font-size:14px;font-style:normal;color:#fff;margin:4px;cursor:default}.table-cell.selected[data-v-5f7bc992]{outline:2px solid #409eff!important}.primary-color[data-v-37d3c0b7]{color:#409eff}.background-opacity[data-v-37d3c0b7]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-37d3c0b7]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-37d3c0b7]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-37d3c0b7]{margin-top:8px}.el-form-item--small .el-radio[data-v-37d3c0b7]{line-height:32px!important}.el-form-item--small .el-rate[data-v-37d3c0b7]{margin-top:6px}.el-form-item--mini .el-radio[data-v-37d3c0b7]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-37d3c0b7]{margin-top:4px}.el-card[data-v-37d3c0b7]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-37d3c0b7]::-ms-reveal{display:none}[data-v-37d3c0b7]::-webkit-scrollbar{width:8px;height:8px}[data-v-37d3c0b7]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-37d3c0b7]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-37d3c0b7]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-37d3c0b7]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}div.table-container[data-v-37d3c0b7]{padding:5px;border:1px dashed #369;box-sizing:border-box}div.table-container table.table-layout[data-v-37d3c0b7]{width:100%;text-align:center;border-collapse:collapse;table-layout:fixed}div.table-container table.table-layout[data-v-37d3c0b7] td{height:48px;border:1px dashed #369;padding:3px;display:table-cell}div.table-container table.table-layout .form-widget-list[data-v-37d3c0b7]{border:1px dashed #369;min-height:36px}.table-container.selected[data-v-37d3c0b7]{outline:2px solid #409eff!important}.primary-color[data-v-7372c190]{color:#409eff}.background-opacity[data-v-7372c190]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-7372c190]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-7372c190]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-7372c190]{margin-top:8px}.el-form-item--small .el-radio[data-v-7372c190]{line-height:32px!important}.el-form-item--small .el-rate[data-v-7372c190]{margin-top:6px}.el-form-item--mini .el-radio[data-v-7372c190]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-7372c190]{margin-top:4px}.el-card[data-v-7372c190]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-7372c190]::-ms-reveal{display:none}[data-v-7372c190]::-webkit-scrollbar{width:8px;height:8px}[data-v-7372c190]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-7372c190]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-7372c190]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-7372c190]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.container-scroll-bar[data-v-7372c190] .el-scrollbar__view,.container-scroll-bar[data-v-7372c190] .el-scrollbar__wrap{overflow-x:hidden}.form-widget-container[data-v-7372c190]{padding:10px;background:#f1f2f3;overflow-x:hidden;overflow-y:auto}.form-widget-container .el-form.full-height-width[data-v-7372c190]{height:100%;padding:3px;background:#fff}.form-widget-container .el-form.full-height-width .no-widget-hint[data-v-7372c190]{position:absolute;left:0;right:0;top:0;bottom:0;height:100%;display:flex;align-items:center;justify-content:center;text-align:center;font-size:18px;color:#999}.form-widget-container .el-form.full-height-width .form-widget-list[data-v-7372c190]{min-height:calc(100vh - 124px);padding:3px}.form-widget-container .el-form.Pad-layout[data-v-7372c190]{margin:0 auto;max-width:960px;border-radius:15px;box-shadow:0 0 1px 10px #495060}.form-widget-container .el-form.H5-layout[data-v-7372c190]{margin:0 auto;width:420px;border-radius:15px;box-shadow:0 0 1px 10px #495060}.form-widget-container .el-form.widget-form[data-v-7372c190] .el-row{padding:2px;border:1px dashed hsla(0,0%,66.7%,.75)}.grid-cell[data-v-7372c190]{min-height:30px;border-right:1px dotted #ccc}.fade-enter-active[data-v-7372c190],.fade-leave-active[data-v-7372c190]{transition:opacity .5s}.fade-enter[data-v-7372c190],.fade-leave-to[data-v-7372c190]{opacity:0}.primary-color[data-v-7e9e197b]{color:#409eff}.background-opacity[data-v-7e9e197b]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-7e9e197b]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-7e9e197b]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-7e9e197b]{margin-top:8px}.el-form-item--small .el-radio[data-v-7e9e197b]{line-height:32px!important}.el-form-item--small .el-rate[data-v-7e9e197b]{margin-top:6px}.el-form-item--mini .el-radio[data-v-7e9e197b]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-7e9e197b]{margin-top:4px}.el-card[data-v-7e9e197b]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-7e9e197b]::-ms-reveal{display:none}[data-v-7e9e197b]::-webkit-scrollbar{width:8px;height:8px}[data-v-7e9e197b]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-7e9e197b]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-7e9e197b]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-7e9e197b]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.el-container.main-container[data-v-7e9e197b]{background:#fff}.el-container.main-container[data-v-7e9e197b] aside{margin:0;padding:0;background:inherit}.el-container.full-height[data-v-7e9e197b]{height:100%;overflow-y:hidden}.el-container.center-layout-container[data-v-7e9e197b]{min-width:680px;border-left:2px dotted #ebeef5;border-right:2px dotted #ebeef5}.el-header.main-header[data-v-7e9e197b]{border-bottom:2px dotted #ebeef5;height:48px!important;line-height:48px!important;min-width:800px}div.main-title[data-v-7e9e197b]{font-size:18px;color:#242424;display:flex;align-items:center;justify-items:center}div.main-title img[data-v-7e9e197b]{cursor:pointer;width:36px;height:36px}div.main-title span.bold[data-v-7e9e197b]{font-size:20px;font-weight:700;margin:0 6px 0 6px}div.main-title span.version-span[data-v-7e9e197b]{font-size:14px;color:#101f1c;margin-left:6px}.float-left[data-v-7e9e197b]{float:left}.float-right[data-v-7e9e197b]{float:right}.el-dropdown-link[data-v-7e9e197b]{margin-right:12px;cursor:pointer}div.external-link a[data-v-7e9e197b]{font-size:13px;text-decoration:none;margin-right:10px;color:#606266}.el-header.toolbar-header[data-v-7e9e197b]{font-size:14px;border-bottom:1px dotted #ccc;height:42px!important}.el-aside.side-panel[data-v-7e9e197b]{width:260px!important;overflow-y:hidden}.el-main.form-widget-main[data-v-7e9e197b]{padding:0;position:relative;overflow-x:hidden}.container-scroll-bar[data-v-7e9e197b] .el-scrollbar__view,.container-scroll-bar[data-v-7e9e197b] .el-scrollbar__wrap{overflow-x:hidden}#app{height:100%}.primary-color[data-v-1a7581a2]{color:#409eff}.background-opacity[data-v-1a7581a2]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-1a7581a2]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-1a7581a2]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-1a7581a2]{margin-top:8px}.el-form-item--small .el-radio[data-v-1a7581a2]{line-height:32px!important}.el-form-item--small .el-rate[data-v-1a7581a2]{margin-top:6px}.el-form-item--mini .el-radio[data-v-1a7581a2]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-1a7581a2]{margin-top:4px}.el-card[data-v-1a7581a2]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-1a7581a2]::-ms-reveal{display:none}[data-v-1a7581a2]::-webkit-scrollbar{width:8px;height:8px}[data-v-1a7581a2]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-1a7581a2]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-1a7581a2]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-1a7581a2]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.svg-icon[data-v-1a7581a2]{width:1.1em;height:1.1em;margin-left:.35em;margin-right:.35em;vertical-align:-.15em;fill:currentColor;overflow:hidden}.primary-color{color:#409eff}.background-opacity{background:rgba(64,158,255,.6)}.form-widget-list .ghost{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio{line-height:36px!important}.el-form-item--medium .el-rate{margin-top:8px}.el-form-item--small .el-radio{line-height:32px!important}.el-form-item--small .el-rate{margin-top:6px}.el-form-item--mini .el-radio{line-height:28px!important}.el-form-item--mini .el-rate{margin-top:4px}.el-card{margin-top:3px;margin-bottom:3px}input[type=password]::-ms-reveal{display:none}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}*{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}html{box-sizing:border-box}body,html{height:100%}body{margin:0;background-color:#fff;text-rendering:optimizeLegibility;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif}@font-face{font-family:iconfont;src:url(data:font/ttf;base64,AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzI8i0leAAABjAAAAFZjbWFw7bW54gAAAfgAAAGqZ2x5Zpkon+wAAAOwAAADNGhlYWQcnMJsAAAA4AAAADZoaGVhB4IDhgAAALwAAAAkaG10eBQAAAAAAAHkAAAAFGxvY2EBeAI2AAADpAAAAAxtYXhwARcAagAAARgAAAAgbmFtZT5U/n0AAAbkAAACbXBvc3T0IfeLAAAJVAAAAFAAAQAAA4D/gAAABAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAUAAQAAAAEAALwRH5pfDzz1AAsEAAAAAADcvr83AAAAANy+vzcAAP+ABAADgQAAAAgAAgAAAAAAAAABAAAABQBeAAgAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAEEAAGQAAUAAAKJAswAAACPAokCzAAAAesAMgEIAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAQOYd52sDgP+AAFwDgQCAAAAAAQAAAAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAABQAAAAMAAAAsAAAABAAAAWoAAQAAAAAAZAADAAEAAAAsAAMACgAAAWoABAA4AAAACAAIAAIAAOYd51Tna///AADmHedT52v//wAAAAAAAAABAAgACAAKAAAABAABAAIAAwAAAQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAQAAAAAAAAAAEAADmHQAA5h0AAAAEAADnUwAA51MAAAABAADnVAAA51QAAAACAADnawAA52sAAAADAAAAAAAAAE4AnAEqAZoABAAA/8AEAANAABoAHgAmAC4AACU2MhcWDwEUDwEGDwEiFAcjIiYvASY+ATIfAQMRIREBESMRIREjAyERIxEhESMDAo0KGwoFAQEJfQIJAgICAwQJBYwJBRQbCmmlAUD9wEABAD8BAkBAAQA/AbYKCgUMBg0KfwIEAQEBBASACRsUCmQC7v3AAkD9gP8AAUD+wAEA/wABQP7AAQAABAAA/4ADwANAABoAHgAmAC4AACUWFAcGLwEiLwEmLwE0Iic1NDY/ATYeARQPASUhESEBITUhESE1JREhNSERITUlATYKCgUMBg0KfwIEAQEBBASACRsUCmQC7v3AAkD9gP8AAUD+wAEA/wABQP7AAQDzChsKBQEBCX0CCQICAgMECQWMCQUUGwpppf7AAkBA/wA/Af3AQP8APwEABQAAAAADwgL9ACYAOQBBAEkAXQAAASYnNzY0JiIPASYjIgcGBwYUFxYXFhcHBhQXFjI/ARYzMjY3Njc2BTY3NjMyFwcuASMiDgEVFBcHJiUUBiMiJzcWBzQ2MzIXByYXIic3HgEzMj4BNTQnNxYXDgEHBgO9TWNpChMaCXRdeZF9XlEFBSIqMDRtCQkPGAl0YHZcs0RHIwX8xEZSanhcSlAQLRksSSsaWlIBkjcpFhSACsA3KRYUgApgXEpQEC0ZLEkrGlpUSSF6SkwBkINKaQoaEwpzQGRLgQcSBzkyOSltCRoJCgpzPU9FR1gPAm5AUi1QDg8rSSwxKVlBcik3CoAUFik3CoAU6i1QDg8rSSwxKVlAc0l1ICIAAAAIAAD/gANBA4EACAARABoAIwAsADUAPgBHAAABIiY0NjIWFAYDIiY0NjIWFAYDIiY0NjIWFAYDIiY0NjIWFAYBIiY0NjIWFAYDIiY0NjIWFAYDIiY0NjIWFAYDIiY0NjIWFAYBICg4OFA4OCgoODhQODgoKDg4UDg4KCg4OFA4OAGYKDg4UDg4KCg4OFA4OCgoODhQODgoKDg4UDg4AsA4UDg4UDj+6zhPOTlPOP7qOU84OE85/us4UDg4UDgDQDhQODhQOP7rOE85OU84/uo5Tzg4Tzn+6zhQODhQOAAAAAAAEgDeAAEAAAAAAAAAFQAAAAEAAAAAAAEACAAVAAEAAAAAAAIABwAdAAEAAAAAAAMACAAkAAEAAAAAAAQACAAsAAEAAAAAAAUACwA0AAEAAAAAAAYACAA/AAEAAAAAAAoAKwBHAAEAAAAAAAsAEwByAAMAAQQJAAAAKgCFAAMAAQQJAAEAEACvAAMAAQQJAAIADgC/AAMAAQQJAAMAEADNAAMAAQQJAAQAEADdAAMAAQQJAAUAFgDtAAMAAQQJAAYAEAEDAAMAAQQJAAoAVgETAAMAAQQJAAsAJgFpCkNyZWF0ZWQgYnkgaWNvbmZvbnQKaWNvbmZvbnRSZWd1bGFyaWNvbmZvbnRpY29uZm9udFZlcnNpb24gMS4waWNvbmZvbnRHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuaHR0cDovL2ZvbnRlbGxvLmNvbQAKAEMAcgBlAGEAdABlAGQAIABiAHkAIABpAGMAbwBuAGYAbwBuAHQACgBpAGMAbwBuAGYAbwBuAHQAUgBlAGcAdQBsAGEAcgBpAGMAbwBuAGYAbwBuAHQAaQBjAG8AbgBmAG8AbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABpAGMAbwBuAGYAbwBuAHQARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQECAQMBBAEFAQYADGluc2VydGNvbHVtbglpbnNlcnRyb3cEaGlkZQRkcmFnAAA=) format("truetype")}.iconfont,body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal}.icon-insertcolumn:before{content:"\e753"}.icon-insertrow:before{content:"\e754"}.icon-hide:before{content:"\e76b"}.icon-drag:before{content:"\e61d"}.primary-color[data-v-228afde5]{color:#409eff}.background-opacity[data-v-228afde5]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-228afde5]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-228afde5]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-228afde5]{margin-top:8px}.el-form-item--small .el-radio[data-v-228afde5]{line-height:32px!important}.el-form-item--small .el-rate[data-v-228afde5]{margin-top:6px}.el-form-item--mini .el-radio[data-v-228afde5]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-228afde5]{margin-top:4px}.el-card[data-v-228afde5]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-228afde5]::-ms-reveal{display:none}[data-v-228afde5]::-webkit-scrollbar{width:8px;height:8px}[data-v-228afde5]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-228afde5]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-228afde5]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-228afde5]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}.card-container.selected[data-v-228afde5]{outline:2px solid #409eff!important}.card-container[data-v-228afde5]{margin:3px}.card-container .form-widget-list[data-v-228afde5]{min-height:28px}[data-v-228afde5] .el-card__header{padding:10px 12px}.folded[data-v-228afde5] .el-card__body{display:none}.clear-fix[data-v-228afde5]:after,.clear-fix[data-v-228afde5]:before{display:table;content:""}.clear-fix[data-v-228afde5]:after{clear:both}.float-right[data-v-228afde5]{float:right}.primary-color[data-v-159d5068]{color:#409eff}.background-opacity[data-v-159d5068]{background:rgba(64,158,255,.6)}.form-widget-list .ghost[data-v-159d5068]{content:"";font-size:0;height:3px;box-sizing:border-box;background:#409eff;border:2px solid #409eff;outline-width:0;padding:0;overflow:hidden}.el-form-item--medium .el-radio[data-v-159d5068]{line-height:36px!important}.el-form-item--medium .el-rate[data-v-159d5068]{margin-top:8px}.el-form-item--small .el-radio[data-v-159d5068]{line-height:32px!important}.el-form-item--small .el-rate[data-v-159d5068]{margin-top:6px}.el-form-item--mini .el-radio[data-v-159d5068]{line-height:28px!important}.el-form-item--mini .el-rate[data-v-159d5068]{margin-top:4px}.el-card[data-v-159d5068]{margin-top:3px;margin-bottom:3px}input[type=password][data-v-159d5068]::-ms-reveal{display:none}[data-v-159d5068]::-webkit-scrollbar{width:8px;height:8px}[data-v-159d5068]::-webkit-scrollbar-track{width:8px;background:rgba(16,31,28,.1);border-radius:2em}[data-v-159d5068]::-webkit-scrollbar-thumb{background-color:rgba(16,31,28,.35);background-clip:padding-box;min-height:28px;border-radius:2em}[data-v-159d5068]::-webkit-scrollbar-thumb:hover{background-color:rgba(16,31,28,.85)}[data-v-159d5068]{scrollbar-color:#e5e5e5 #f7f7f9;scrollbar-width:thin}[data-v-159d5068] .el-card__header{padding:10px 12px}.folded[data-v-159d5068] .el-card__body{display:none}.clear-fix[data-v-159d5068]:after,.clear-fix[data-v-159d5068]:before{display:table;content:""}.clear-fix[data-v-159d5068]:after{clear:both}.float-right[data-v-159d5068]{float:right} \ No newline at end of file diff --git a/resource/page/css/chunk-vendors.a16c4353.css b/resource/page/css/chunk-vendors.a16c4353.css new file mode 100644 index 0000000..c7a0f01 --- /dev/null +++ b/resource/page/css/chunk-vendors.a16c4353.css @@ -0,0 +1 @@ +.el-pagination--small .arrow.disabled,.el-table--hidden,.el-table .el-table__cell.is-hidden>*,.el-table .hidden-columns{visibility:hidden}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}@font-face{font-family:element-icons;src:url(../fonts/element-icons.535877f5.woff) format("woff"),url(../fonts/element-icons.732389de.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{transform:rotate(0)}to{transform:rotate(1turn)}}@keyframes rotating{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination:after,.el-pagination:before{display:table;content:""}.el-pagination:after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409eff}.el-pagination button:disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:50% no-repeat #fff;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#c0c4cc;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more:before,.el-pagination--small li.more:before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409eff}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#c0c4cc}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409eff}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409eff;color:#fff}.el-dialog,.el-pager li{background:#fff;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-date-table,.el-pager,.el-table th.el-table__cell{-webkit-user-select:none;-moz-user-select:none}.el-pager .more:before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#c0c4cc}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409eff}.el-pager li.active{color:#409eff;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{to{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409eff}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@keyframes dialog-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #e4e7ed;box-sizing:border-box;background-color:#fff}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#f5f7fa}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#fff}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button:before{content:"";position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:hsla(0,0%,100%,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default:before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover:not(.is-disabled):before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown [disabled]{cursor:not-allowed;color:#bbb}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #ebeef5}.el-dropdown-menu__item--divided:before{content:"";height:6px;display:block;margin:0 -20px;background-color:#fff}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:1px solid #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0}.el-menu,.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu:after,.el-menu:before{display:table;content:""}.el-menu:after{clear:both}.el-menu.el-menu--horizontal{border-bottom:1px solid #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409eff;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409eff;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #e4e7ed;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409eff}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;transition:transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409eff}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{transform:rotate(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#fff;border:1px solid #dcdfe6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409eff}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;box-shadow:-1px 0 0 0 #409eff}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#f2f6fc}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){box-shadow:0 0 2px 2px #409eff}.el-switch{display:inline-flex;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409eff}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #dcdfe6;outline:0;border-radius:10px;box-sizing:border-box;background:#dcdfe6;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;transition:all .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#409eff;background-color:#409eff}.el-switch.is-checked .el-switch__core:after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item{padding-right:40px}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409eff;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected:after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#409eff;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type):after{content:"";position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#e4e7ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#c0c4cc}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409eff}.el-select .el-input .el-select__caret{color:#c0c4cc;font-size:14px;transition:transform .3s;transform:rotate(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{transform:rotate(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;transform:rotate(180deg);border-radius:100%;color:#c0c4cc;transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#e4e7ed}.el-select .el-input.is-focus .el-input__inner{border-color:#409eff}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#c0c4cc;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;transform:translateY(-50%);display:flex;align-items:center;flex-wrap:wrap}.el-select__tags-text{overflow:hidden;text-overflow:ellipsis}.el-select .el-tag{box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5;display:flex;max-width:100%;align-items:center}.el-select .el-tag__close.el-icon-close{background-color:#c0c4cc;top:0;color:#fff;flex-shrink:0}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#fff}.el-select .el-tag__close.el-icon-close:before{display:block;transform:translateY(.5px)}.el-table{position:relative;overflow:hidden;box-sizing:border-box;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:flex;justify-content:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;transition:transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit .el-table__cell.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th.el-table__cell{background:#f5f7fa}.el-table .el-table__cell{padding:12px 0;min-width:0;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table .el-table__cell.is-center{text-align:center}.el-table .el-table__cell.is-right{text-align:right}.el-table .el-table__cell.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium .el-table__cell{padding:10px 0}.el-table--small .el-table__cell{padding:8px 0}.el-table--mini .el-table__cell{padding:6px 0}.el-table--border .el-table__cell:first-child .cell,.el-table .cell{padding-left:10px}.el-table tr{background-color:#fff}.el-table tr input[type=checkbox]{margin:0}.el-table td.el-table__cell,.el-table th.el-table__cell.is-leaf{border-bottom:1px solid #ebeef5}.el-table th.el-table__cell.is-sortable{cursor:pointer}.el-table th.el-table__cell{overflow:hidden;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:#fff}.el-table th.el-table__cell>.cell{display:inline-block;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th.el-table__cell>.cell.highlight{color:#409eff}.el-table th.el-table__cell.required>div:before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td.el-table__cell div{box-sizing:border-box}.el-table td.el-table__cell.gutter{width:0}.el-table .cell{box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #ebeef5}.el-table--border:after,.el-table--group:after,.el-table:before{content:"";position:absolute;background-color:#ebeef5;z-index:1}.el-table--border:after,.el-table--group:after{top:0;right:0;width:1px;height:100%}.el-table:before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border .el-table__cell,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #ebeef5}.el-table--border th.el-table__cell.gutter:last-of-type{border-bottom:1px solid #ebeef5;border-bottom-width:1px}.el-table--border th.el-table__cell,.el-table__fixed-right-patch{border-bottom:1px solid #ebeef5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right:before,.el-table__fixed:before{content:"";position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#ebeef5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#fff}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td.el-table__cell{border-top:1px solid #ebeef5;background-color:#f5f7fa;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td.el-table__cell{border-top:1px solid #ebeef5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td.el-table__cell,.el-table__header-wrapper tbody td.el-table__cell{background-color:#f5f7fa;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #ebeef5}.el-table .caret-wrapper{display:inline-flex;flex-direction:column;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#c0c4cc;top:5px}.el-table .sort-caret.descending{border-top-color:#c0c4cc;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409eff}.el-table .descending .sort-caret.descending{border-top-color:#409eff}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell{background:#fafafa}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td.el-table__cell{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped>td.el-table__cell,.el-table__body tr.hover-row>td.el-table__cell{background-color:#f5f7fa}.el-table__body tr.current-row>td.el-table__cell{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #ebeef5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;transform:scale(.75)}.el-table--enable-row-transition .el-table__body td.el-table__cell{transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell{background-color:#f5f7fa}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #ebeef5;border-radius:2px;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409eff;color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #ebeef5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div,.el-date-table td.in-range div,.el-date-table td.in-range div:hover{background-color:#f2f6fc}.el-table-filter__bottom button:hover{color:#409eff}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{padding:3px 0;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#c0c4cc}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409eff;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#fff}.el-date-table td.available:hover{color:#409eff}.el-date-table td.current:not(.disabled) span{color:#fff;background-color:#409eff}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#fff}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409eff}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#f5f7fa;opacity:1;cursor:not-allowed;color:#c0c4cc}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#f2f6fc;border-radius:15px}.el-date-table td.selected div:hover{background-color:#f2f6fc}.el-date-table td.selected span{background-color:#409eff;color:#fff;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:1px solid #ebeef5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;box-sizing:border-box}.el-month-table td.today .cell{color:#409eff;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#fff}.el-month-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-month-table td.disabled .cell:hover{color:#c0c4cc}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409eff}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#f2f6fc}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#fff}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#fff;background-color:#409eff}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409eff}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409eff;font-weight:700}.el-year-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-year-table td.disabled .cell:hover{color:#c0c4cc}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409eff}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#fff}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:1px solid #ebeef5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409eff}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409eff;font-weight:700}.time-select-item.disabled{color:#e4e7ed;cursor:not-allowed}.time-select-item:hover{background-color:#f5f7fa;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#c0c4cc;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input:-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::-moz-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::placeholder{color:#c0c4cc}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#c0c4cc;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:inline-flex;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409eff}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#e4e7ed}.el-range-editor.is-disabled input{background-color:#f5f7fa;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::-moz-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::placeholder{color:#c0c4cc}.el-range-editor.is-disabled .el-range-separator{color:#c0c4cc}.el-picker-panel{color:#606266;border:1px solid #e4e7ed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#fff;border-radius:4px;line-height:30px;margin:5px 0}.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper:after,.el-picker-panel__body:after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#fff;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409eff}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409eff}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409eff}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;box-sizing:border-box;padding-top:6px;background-color:#fff;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#fff;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409eff}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list:after,.el-time-spinner__list:before{content:"";display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#f5f7fa;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#c0c4cc;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #e4e7ed;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;user-select:none;box-sizing:content-box}.el-slider__button,.el-slider__button-wrapper,.el-time-panel{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content:after,.el-time-panel__content:before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #e4e7ed;border-bottom:1px solid #e4e7ed}.el-time-panel__content:after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content:before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds:after{left:66.66667%}.el-time-panel__content.has-seconds:before{padding-left:33.33333%}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409eff}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #e4e7ed}.el-popover{position:absolute;background:#fff;min-width:150px;border:1px solid #ebeef5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{to{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#fff;border-radius:4px;border:1px solid #ebeef5;font-size:18px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper:after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#f56c6c}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409eff}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;transform:translateY(-50%);font-size:24px!important}.el-message-box__status:before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67c23a}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#e6a23c}.el-message-box__status.el-icon-error{color:#f56c6c}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#f56c6c;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:flex;align-items:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@keyframes msgbox-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb:after,.el-breadcrumb:before{display:table;content:""}.el-breadcrumb:after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#c0c4cc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner.is-link,.el-breadcrumb__inner a{font-weight:700;text-decoration:none;transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner.is-link:hover,.el-breadcrumb__inner a:hover{color:#409eff;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item:after,.el-form-item:before{display:table;content:""}.el-form-item:after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content:after,.el-form-item__content:before{display:table;content:""}.el-form-item__content:after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#f56c6c;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:"*";color:#f56c6c;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#f56c6c}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409eff;z-index:1;transition:transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;transition:all .15s}.el-collapse-item__arrow,.el-tabs__nav{-webkit-transition:-webkit-transform .3s}.el-tabs__new-tab .el-icon-plus{transform:scale(.8)}.el-tabs__new-tab:hover{color:#409eff}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap:after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#e4e7ed;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap:after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap:after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;transition:transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:flex}.el-tabs__nav.is-stretch>*{flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){box-shadow:inset 0 0 2px 2px #409eff;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#c0c4cc;color:#fff}.el-tabs__item.is-active{color:#409eff}.el-tabs__item:hover{color:#409eff;cursor:pointer}.el-tabs__item.is-disabled{color:#c0c4cc;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #e4e7ed}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #e4e7ed;border-bottom:none;border-radius:4px 4px 0 0;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #e4e7ed;transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#fff}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#fff;border:1px solid #dcdfe6;box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#f5f7fa;border-bottom:1px solid #e4e7ed;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409eff;background-color:#fff;border-right-color:#dcdfe6;border-left-color:#dcdfe6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409eff}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#c0c4cc}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #dcdfe6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{transform:rotate(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left:after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left:after,.el-tabs--left .el-tabs__nav-wrap.is-right:after,.el-tabs--right .el-tabs__nav-wrap.is-left:after,.el-tabs--right .el-tabs__nav-wrap.is-right:after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #e4e7ed;border-bottom:none;border-top:1px solid #e4e7ed;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #e4e7ed;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #e4e7ed;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #e4e7ed;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right:after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #e4e7ed;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #e4e7ed;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #e4e7ed;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;transform-origin:0 0;transform:translateX(100%)}to{opacity:1;transform-origin:0 0;transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;transform-origin:0 0;transform:translateX(100%)}to{opacity:1;transform-origin:0 0;transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{transform-origin:0 0;transform:translateX(0);opacity:1}to{transform-origin:0 0;transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{transform-origin:0 0;transform:translateX(0);opacity:1}to{transform-origin:0 0;transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;transform-origin:0 0;transform:translateX(-100%)}to{opacity:1;transform-origin:0 0;transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;transform-origin:0 0;transform:translateX(-100%)}to{opacity:1;transform-origin:0 0;transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{transform-origin:0 0;transform:translateX(0);opacity:1}to{transform-origin:0 0;transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{transform-origin:0 0;transform:translateX(0);opacity:1}to{transform-origin:0 0;transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#fff;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409eff}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#f5f7fa}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409eff;color:#fff}.el-tree-node__content{display:flex;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#c0c4cc;font-size:12px;transform:rotate(0);transition:transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#c0c4cc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:flex;align-items:center;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#c0c4cc}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#fff}.el-alert.is-center{justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67c23a}.el-alert--success.is-light .el-alert__description{color:#67c23a}.el-alert--success.is-dark{background-color:#67c23a;color:#fff}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#fff}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#e6a23c}.el-alert--warning.is-light .el-alert__description{color:#e6a23c}.el-alert--warning.is-dark{background-color:#e6a23c;color:#fff}.el-alert--error.is-light{background-color:#fef0f0;color:#f56c6c}.el-alert--error.is-light .el-alert__description{color:#f56c6c}.el-alert--error.is-dark{background-color:#f56c6c;color:#fff}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#f56c6c}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#e6a23c}.el-notification-fade-enter.right{right:0;transform:translateX(100%)}.el-notification-fade-enter.left{left:0;transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409eff}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409eff}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #dcdfe6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #dcdfe6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#e4e7ed;color:#e4e7ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#e4e7ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #dcdfe6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #dcdfe6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow:after{content:" ";border-width:5px}.el-progress-bar__inner:after,.el-row:after,.el-row:before,.el-slider:after,.el-slider:before,.el-slider__button-wrapper:after,.el-upload-cover:after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow:after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow:after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow:after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow:after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow:after{border-right-color:#fff}.el-slider:after,.el-slider:before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper:after{vertical-align:middle;display:inline-block}.el-slider:after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#e4e7ed;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button{border-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409eff;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal}.el-slider__button-wrapper:after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409eff;background-color:#fff;border-radius:50%;transition:.2s;user-select:none}.el-image-viewer__btn,.el-slider__button,.el-step__icon-inner{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#fff;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #dcdfe6;line-height:20px;box-sizing:border-box;transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#c0c4cc}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409eff}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:hsla(0,0%,100%,.9);margin:0;top:0;right:0;bottom:0;left:0;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-2,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-push-0,.el-col-push-1,.el-col-push-2,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409eff;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409eff;stroke-linecap:round}.el-loading-spinner i{color:#409eff}@-webkit-keyframes loading-rotate{to{transform:rotate(1turn)}}@keyframes loading-rotate{to{transform:rotate(1turn)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}to{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{box-sizing:border-box}.el-row:after,.el-row:before{display:table}.el-row:after{clear:both}.el-row--flex{display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{justify-content:center}.el-row--flex.is-justify-end{justify-content:flex-end}.el-row--flex.is-justify-space-between{justify-content:space-between}.el-row--flex.is-justify-space-around{justify-content:space-around}.el-row--flex.is-align-top{align-items:flex-start}.el-row--flex.is-align-middle{align-items:center}.el-row--flex.is-align-bottom{align-items:flex-end}[class*=el-col-]{float:left;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409eff;color:#409eff}.el-upload:focus .el-upload-dragger{border-color:#409eff}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#c0c4cc;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #dcdfe6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409eff;font-style:normal}.el-upload-dragger:hover{border-color:#409eff}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409eff}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67c23a}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409eff}.el-upload-list__item:hover{background-color:#f5f7fa}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409eff;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409eff}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;transform:rotate(45deg);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#fff}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;transform:rotate(45deg);box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover:after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;transform:rotate(45deg);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#fff;font-size:14px;cursor:pointer;vertical-align:middle;transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#fff;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;transform:translateY(-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner:after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-warning .el-progress-bar__inner{background-color:#e6a23c}.el-progress.is-warning .el-progress__text{color:#e6a23c}.el-progress.is-exception .el-progress-bar__inner{background-color:#f56c6c}.el-progress.is-exception .el-progress__text{color:#f56c6c}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#ebeef5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409eff;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner:after{height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}to{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{to{transform:rotate(1turn)}}@keyframes rotate{to{transform:rotate(1turn)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#ebeef5;position:fixed;left:50%;top:20px;transform:translateX(-50%);background-color:#edf2fc;transition:opacity .3s,transform .4s,top .4s;padding:15px 15px 15px 20px;display:flex;align-items:center}.el-message.is-center{justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#e6a23c}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#f56c6c}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;transform:translateY(-50%);cursor:pointer;color:#c0c4cc;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#f56c6c}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#e6a23c}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#f56c6c;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409eff}.el-badge__content--success{background-color:#67c23a}.el-badge__content--warning{background-color:#e6a23c}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#f56c6c}.el-card{border:1px solid #ebeef5;background-color:#fff;color:#303133;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #ebeef5;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#c0c4cc;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;flex-flow:column}.el-step{position:relative;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{flex-basis:auto!important;flex-shrink:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#c0c4cc;border-color:#c0c4cc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#f56c6c;border-color:#f56c6c}.el-step__head.is-finish{color:#409eff;border-color:#409eff}.el-step__icon{position:relative;z-index:1;display:inline-flex;justify-content:center;align-items:center;width:24px;height:24px;font-size:14px;box-sizing:border-box;background:#fff;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#c0c4cc}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;transition:.15s ease-out;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#c0c4cc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#f56c6c}.el-step__title.is-finish{color:#409eff}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#c0c4cc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#f56c6c}.el-step__description.is-finish{color:#409eff}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:flex;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:flex;align-items:stretch;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{flex-grow:1;display:flex;align-items:center;justify-content:center}.el-step.is-simple .el-step__arrow:after,.el-step.is-simple .el-step__arrow:before{content:"";display:inline-block;position:absolute;height:15px;width:1px;background:#c0c4cc}.el-step.is-simple .el-step__arrow:before{transform:rotate(-45deg) translateY(-4px);transform-origin:0 0}.el-step.is-simple .el-step__arrow:after{transform:rotate(45deg) translateY(4px);transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#c0c4cc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item--card,.el-carousel__item.is-animating{transition:transform .4s ease-in-out}.el-carousel__item--card{width:50%}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#fff;opacity:.24;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active,.fade-in-linear-enter-active,.fade-in-linear-leave-active{transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active,.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;transform:scaleY(1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;transform:scaleY(1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;transform:scale(1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;transform:scale(.45)}.collapse-transition{transition:height .3s ease-in-out,padding-top .3s ease-in-out,padding-bottom .3s ease-in-out}.horizontal-collapse-transition{transition:width .3s ease-in-out,padding-left .3s ease-in-out,padding-right .3s ease-in-out}.el-list-enter-active,.el-list-leave-active{transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;transform:translateY(-30px)}.el-opacity-transition{transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #ebeef5;border-bottom:1px solid #ebeef5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:flex;align-items:center;height:48px;line-height:48px;background-color:#fff;color:#303133;cursor:pointer;border-bottom:1px solid #ebeef5;font-size:13px;font-weight:500;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;transition:transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409eff}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#fff;overflow:hidden;box-sizing:border-box;border-bottom:1px solid #ebeef5}.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;filter:drop-shadow(0 2px 12px rgba(0,0,0,.03))}.el-popper .popper__arrow:after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#ebeef5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow:after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#ebeef5}.el-popper[x-placement^=bottom] .popper__arrow:after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#ebeef5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow:after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#ebeef5}.el-popper[x-placement^=left] .popper__arrow:after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-tag{background-color:#ecf5ff;border-color:#d9ecff;display:inline-block;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#409eff;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409eff}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#fff;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#fff;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67c23a}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#fff;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close:before{display:block}.el-tag--dark{background-color:#409eff;color:#fff}.el-tag--dark,.el-tag--dark.is-hit{border-color:#409eff}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#fff;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#fff;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67c23a}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#fff;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409eff}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#fff;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#fff;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#fff;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#fff;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#fff;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;transform:scale(.7)}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#c0c4cc}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409eff}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{transition:transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{transform:rotate(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#fff;border:1px solid #e4e7ed;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;transform:translateY(-50%);display:flex;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:inline-flex;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{flex:none;background-color:#c0c4cc;color:#fff}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:flex;justify-content:space-between;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#f5f7fa}.el-cascader__suggestion-item.is-checked{color:#409eff;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#c0c4cc}.el-cascader__search-input{flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;box-sizing:border-box}.el-cascader__search-input:-ms-input-placeholder{color:#c0c4cc}.el-cascader__search-input::-moz-placeholder{color:#c0c4cc}.el-cascader__search-input::placeholder{color:#c0c4cc}.el-color-predefine{display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:flex;flex:1;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{box-shadow:0 0 3px 2px #409eff}.el-color-predefine__color-selector>div{display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:linear-gradient(180deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.el-color-svpanel__black{background:linear-gradient(0deg,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,#fff);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,#fff)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper:after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409eff;border-color:#409eff}.el-color-dropdown__link-btn{cursor:pointer;color:#409eff;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409eff,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:hsla(0,0%,100%,.7)}.el-color-picker__trigger{display:inline-block;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;transform:translate3d(-50%,-50%,0);color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;box-sizing:content-box;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#fff;background-image:none;border:1px solid #dcdfe6;border-radius:4px;transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::-moz-placeholder{color:#c0c4cc}.el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea__inner:hover{border-color:#c0c4cc}.el-textarea__inner:focus{outline:0;border-color:#409eff}.el-textarea .el-input__count{color:#909399;background:#fff;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::-moz-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea.is-exceed .el-textarea__inner{border-color:#f56c6c}.el-textarea.is-exceed .el-input__count{color:#f56c6c}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner,.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;cursor:pointer;transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:inline-flex;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#fff;line-height:normal;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#c0c4cc;text-align:center}.el-input__inner::-ms-reveal{display:none}.el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input__inner::-moz-placeholder{color:#c0c4cc}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409eff;outline:0}.el-input__suffix{right:5px;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;transition:all .3s;line-height:40px}.el-input__icon:after{content:"";height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::-moz-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#f56c6c}.el-input.is-exceed .el-input__suffix .el-input__count{color:#f56c6c}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#fff;background-color:#409eff;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #dcdfe6;background-color:#f5f7fa;color:#c0c4cc}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #ebeef5;border-radius:4px;overflow:hidden;background:#fff;display:inline-block;vertical-align:middle;width:200px;max-height:100%;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409eff}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#f5f7fa;margin:0;padding-left:15px;border-bottom:1px solid #ebeef5;box-sizing:border-box;color:#000}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-divider__text,.el-link{font-weight:500;font-size:14px}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#fff;margin:0;padding:0;border-top:1px solid #ebeef5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer:after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner:after{height:6px;width:3px;left:4px}.el-container{display:flex;flex-direction:row;flex:1;flex-basis:auto;box-sizing:border-box;min-width:0}.el-aside,.el-header{-webkit-box-sizing:border-box}.el-container.is-vertical{flex-direction:column}.el-header{padding:0 20px}.el-aside,.el-header{box-sizing:border-box;flex-shrink:0}.el-aside{overflow:auto}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;flex:1;flex-basis:auto;overflow:auto;padding:20px}.el-footer,.el-main{box-sizing:border-box}.el-footer{padding:0 20px;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #e4e7ed}.el-timeline-item__icon{color:#fff;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#e4e7ed;border-radius:50%;display:flex;justify-content:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409eff}.el-timeline-item__node--success{background-color:#67c23a}.el-timeline-item__node--warning{background-color:#e6a23c}.el-timeline-item__node--danger{background-color:#f56c6c}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;justify-content:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:inline-flex;flex-direction:row;align-items:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0}.el-drawer,.el-empty,.el-result{-webkit-box-orient:vertical}.el-link.is-underline:hover:after{content:"";position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409eff}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409eff}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409eff}.el-link.el-link--default.is-disabled{color:#c0c4cc}.el-link.el-link--primary{color:#409eff}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#f56c6c}.el-link.el-link--danger{color:#f56c6c}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67c23a}.el-link.el-link--success{color:#67c23a}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#e6a23c}.el-link.el-link--warning{color:#e6a23c}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#dcdfe6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#fff;padding:0 20px;color:#303133}.el-image__error,.el-image__placeholder{background:#f5f7fa}.el-divider__text.is-left{left:20px;transform:translateY(-50%)}.el-divider__text.is-center{left:50%;transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;justify-content:center;align-items:center;font-size:14px;color:#c0c4cc;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:flex;align-items:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;box-sizing:border-box;user-select:none}.el-button,.el-checkbox,.el-image-viewer__btn{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:24px;color:#fff;background-color:#606266}.el-image-viewer__canvas{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:flex;align-items:center;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{top:50%;width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff}.el-image-viewer__prev{transform:translateY(-50%);left:40px}.el-image-viewer__next{transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@keyframes viewer-fade-in{0%{transform:translate3d(0,-20px,0);opacity:0}to{transform:translateZ(0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{transform:translateZ(0);opacity:1}to{transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;border:1px solid #dcdfe6;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409eff;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#fff;border-color:#409eff;color:#409eff}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#fff;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#fff;border-color:#ebeef5;color:#c0c4cc}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:"";position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:hsla(0,0%,100%,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#fff;background-color:#409eff;border-color:#409eff}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#fff}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#fff;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409eff;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409eff;border-color:#409eff;color:#fff}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#fff;background-color:#67c23a;border-color:#67c23a}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#fff}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#fff}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#fff;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67c23a;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67c23a;border-color:#67c23a;color:#fff}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#fff;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#fff;background-color:#e6a23c;border-color:#e6a23c}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#fff}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#fff}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#fff;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#e6a23c;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#e6a23c;border-color:#e6a23c;color:#fff}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#fff;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#fff;background-color:#f56c6c;border-color:#f56c6c}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#fff}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#fff}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#fff;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#f56c6c;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#f56c6c;border-color:#f56c6c;color:#fff}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#fff;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#fff;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#fff}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#fff}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#fff;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#fff}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#fff;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409eff;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group:after,.el-button-group:before{display:table;content:""}.el-button-group:after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-button.is-active,.el-button-group>.el-button:not(.is-disabled):active,.el-button-group>.el-button:not(.is-disabled):focus,.el-button-group>.el-button:not(.is-disabled):hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:first-child{border-right-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:last-child{border-left-color:hsla(0,0%,100%,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:hsla(0,0%,100%,.5);border-right-color:hsla(0,0%,100%,.5)}.el-calendar{background-color:#fff}.el-calendar__header{display:flex;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #ebeef5}.el-backtop,.el-page-header{display:-ms-flexbox}.el-calendar__title{color:#000;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#c0c4cc}.el-backtop,.el-calendar-table td.is-today{color:#409eff}.el-calendar-table td{border-bottom:1px solid #ebeef5;border-right:1px solid #ebeef5;vertical-align:top;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#f2f8fe}.el-calendar-table tr:first-child td{border-top:1px solid #ebeef5}.el-calendar-table tr td:first-child{border-left:1px solid #ebeef5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#f2f8fe}.el-backtop{position:fixed;background-color:#fff;width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#f2f6fc}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left:after{content:"";position:absolute;width:1px;height:16px;right:-20px;top:50%;transform:translateY(-50%);background-color:#dcdfe6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox,.el-checkbox-button__inner,.el-empty__image img,.el-radio{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #dcdfe6;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409eff}.el-checkbox.is-bordered.is-disabled{border-color:#ebeef5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner:after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#dcdfe6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner:after{cursor:not-allowed;border-color:#c0c4cc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after{border-color:#c0c4cc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner:before{background-color:#c0c4cc;border-color:#c0c4cc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409eff;border-color:#409eff}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#c0c4cc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner:after{transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409eff}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409eff}.el-checkbox__input.is-indeterminate .el-checkbox__inner:before{content:"";position:absolute;display:block;background-color:#fff;height:2px;transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner:after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #dcdfe6;border-radius:2px;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409eff}.el-checkbox__inner:after{box-sizing:content-box;content:"";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;transform:rotate(45deg) scaleY(0);width:3px;transition:transform .15s ease-in .05s;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#fff;border:1px solid #dcdfe6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409eff}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-radio,.el-radio__input{line-height:1;white-space:nowrap;outline:0}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#409eff;border-color:#409eff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409eff}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#ebeef5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409eff}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio{color:#606266;font-weight:500;cursor:pointer;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #dcdfe6;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409eff}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#ebeef5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#e4e7ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner:after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner:after{background-color:#c0c4cc}.el-radio__input.is-disabled+span.el-radio__label{color:#c0c4cc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409eff;background:#409eff}.el-radio__input.is-checked .el-radio__inner:after{transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409eff}.el-radio__input.is-focus .el-radio__inner{border-color:#409eff}.el-radio__inner{border:1px solid #dcdfe6;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;box-sizing:border-box}.el-radio__inner:hover{border-color:#409eff}.el-radio__inner:after{width:4px;height:4px;border-radius:100%;background-color:#fff;content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) scale(0);transition:transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{box-shadow:0 0 2px 2px #409eff}.el-radio__label{font-size:14px;padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;transition:opacity .34s ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);transition:background-color .3s}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;transition:opacity .12s ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #e4e7ed;border-radius:4px}.el-cascader-menu{min-width:180px;box-sizing:border-box;color:#606266;border-right:1px solid #e4e7ed}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;box-sizing:border-box}.el-avatar,.el-drawer{-webkit-box-sizing:border-box;overflow:hidden}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:#c0c4cc}.el-cascader-node{position:relative;display:flex;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409eff;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#f5f7fa}.el-cascader-node.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;box-sizing:border-box;text-align:center;color:#fff;background:#c0c4cc;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-drawer,.el-drawer__header{display:-ms-flexbox}.el-empty__image img,.el-empty__image svg{vertical-align:top;height:100%;width:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}.el-drawer.ltr,.el-drawer.rtl,.el-drawer__container{top:0;bottom:0;height:100%}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}to{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}to{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes rtl-drawer-in{0%{transform:translate(100%)}to{transform:translate(0)}}@-webkit-keyframes rtl-drawer-out{0%{transform:translate(0)}to{transform:translate(100%)}}@keyframes rtl-drawer-out{0%{transform:translate(0)}to{transform:translate(100%)}}@-webkit-keyframes ltr-drawer-in{0%{transform:translate(-100%)}to{transform:translate(0)}}@keyframes ltr-drawer-in{0%{transform:translate(-100%)}to{transform:translate(0)}}@-webkit-keyframes ltr-drawer-out{0%{transform:translate(0)}to{transform:translate(-100%)}}@keyframes ltr-drawer-out{0%{transform:translate(0)}to{transform:translate(-100%)}}@-webkit-keyframes ttb-drawer-in{0%{transform:translateY(-100%)}to{transform:translate(0)}}@keyframes ttb-drawer-in{0%{transform:translateY(-100%)}to{transform:translate(0)}}@-webkit-keyframes ttb-drawer-out{0%{transform:translate(0)}to{transform:translateY(-100%)}}@keyframes ttb-drawer-out{0%{transform:translate(0)}to{transform:translateY(-100%)}}@-webkit-keyframes btt-drawer-in{0%{transform:translateY(100%)}to{transform:translate(0)}}@keyframes btt-drawer-in{0%{transform:translateY(100%)}to{transform:translate(0)}}@-webkit-keyframes btt-drawer-out{0%{transform:translate(0)}to{transform:translateY(100%)}}@keyframes btt-drawer-out{0%{transform:translate(0)}to{transform:translateY(100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#fff;display:flex;flex-direction:column;box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);outline:0}.el-drawer__body>*,.el-empty{-webkit-box-sizing:border-box}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{align-items:center;color:#72767b;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{flex:1}.el-drawer__title{margin:0;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{flex:1;overflow:auto}.el-drawer__body>*{box-sizing:border-box}.el-drawer.btt,.el-drawer.ttb,.el-drawer__container{width:100%;left:0;right:0}.el-drawer__container{position:relative}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-popconfirm__main{display:flex;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0}@-webkit-keyframes el-skeleton-loading{0%{background-position:100% 50%}to{background-position:0 50%}}@keyframes el-skeleton-loading{0%{background-position:100% 50%}to{background-position:0 50%}}.el-skeleton{width:100%}.el-skeleton__first-line,.el-skeleton__paragraph{height:16px;margin-top:16px;background:#f2f2f2}.el-skeleton.is-animated .el-skeleton__item{background:linear-gradient(90deg,#f2f2f2 25%,#e6e6e6 37%,#f2f2f2 63%);background-size:400% 100%;-webkit-animation:el-skeleton-loading 1.4s ease infinite;animation:el-skeleton-loading 1.4s ease infinite}.el-skeleton__item{background:#f2f2f2;display:inline-block;height:16px;border-radius:4px;width:100%}.el-empty,.el-skeleton__image{display:-ms-flexbox}.el-skeleton__circle{border-radius:50%;width:36px;height:36px;line-height:36px}.el-skeleton__circle--lg{width:40px;height:40px;line-height:40px}.el-skeleton__circle--md{width:28px;height:28px;line-height:28px}.el-skeleton__button{height:40px;width:64px;border-radius:4px}.el-skeleton__p{width:100%}.el-skeleton__p.is-last{width:61%}.el-skeleton__p.is-first{width:33%}.el-skeleton__text{width:100%;height:13px}.el-skeleton__caption{height:12px}.el-skeleton__h1{height:20px}.el-skeleton__h3{height:18px}.el-skeleton__h5{height:16px}.el-skeleton__image{width:unset;display:flex;align-items:center;justify-content:center;border-radius:0}.el-skeleton__image svg{fill:#dcdde0;width:22%;height:22%}.el-empty{display:flex;justify-content:center;align-items:center;flex-direction:column;text-align:center;box-sizing:border-box;padding:40px 0}.el-empty__image{width:160px}.el-empty__image img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-o-object-fit:contain;object-fit:contain}.el-empty__image svg{fill:#dcdde0}.el-empty__description{margin-top:20px}.el-empty__description p{margin:0;font-size:14px;color:#909399}.el-empty__bottom,.el-result__title{margin-top:20px}.el-descriptions{box-sizing:border-box;font-size:14px;color:#303133}.el-descriptions__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.el-descriptions__title{font-size:16px;font-weight:700}.el-descriptions--mini,.el-descriptions--small{font-size:12px}.el-descriptions__body{color:#606266;background-color:#fff}.el-descriptions__body .el-descriptions__table{border-collapse:collapse;width:100%;table-layout:fixed}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell{box-sizing:border-box;text-align:left;font-weight:400;line-height:1.5}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left{text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center{text-align:center}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right{text-align:right}.el-descriptions .is-bordered{table-layout:auto}.el-descriptions .is-bordered .el-descriptions-item__cell{border:1px solid #ebeef5;padding:12px 10px}.el-descriptions :not(.is-bordered) .el-descriptions-item__cell{padding-bottom:12px}.el-descriptions--medium.is-bordered .el-descriptions-item__cell{padding:10px}.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:10px}.el-descriptions--small.is-bordered .el-descriptions-item__cell{padding:8px 10px}.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:8px}.el-descriptions--mini.is-bordered .el-descriptions-item__cell{padding:6px 10px}.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:6px}.el-descriptions-item__container{display:flex}.el-descriptions-item__label.has-colon:after{content:":";position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}.el-result{display:flex;justify-content:center;align-items:center;flex-direction:column;text-align:center;box-sizing:border-box;padding:40px 30px}.el-result__icon svg{width:64px;height:64px}.el-result__title p{margin:0;font-size:20px;color:#303133;line-height:1.3}.el-result__subtitle{margin-top:10px}.el-result__subtitle p{margin:0;font-size:14px;color:#606266;line-height:1.3}.el-result__extra{margin-top:30px}.el-result .icon-success{fill:#67c23a}.el-result .icon-error{fill:#f56c6c}.el-result .icon-info{fill:#909399}.el-result .icon-warning{fill:#e6a23c} \ No newline at end of file diff --git a/resource/page/fonts/element-icons.535877f5.woff b/resource/page/fonts/element-icons.535877f5.woff new file mode 100644 index 0000000..02b9a25 Binary files /dev/null and b/resource/page/fonts/element-icons.535877f5.woff differ diff --git a/resource/page/fonts/element-icons.732389de.ttf b/resource/page/fonts/element-icons.732389de.ttf new file mode 100644 index 0000000..91b74de Binary files /dev/null and b/resource/page/fonts/element-icons.732389de.ttf differ diff --git a/resource/page/index.html b/resource/page/index.html new file mode 100644 index 0000000..a193235 --- /dev/null +++ b/resource/page/index.html @@ -0,0 +1 @@ +variant-form
\ No newline at end of file diff --git a/resource/page/js/app.9fe02340.js b/resource/page/js/app.9fe02340.js new file mode 100644 index 0000000..334033b --- /dev/null +++ b/resource/page/js/app.9fe02340.js @@ -0,0 +1 @@ +(function(e){function t(t){for(var n,s,a=t[0],r=t[1],d=t[2],u=0,f=[];u=this.colLength-1||e>this.colLength-1||this.colArray[e].options.rowspan!==this.widget.options.rowspan},mergeWholeRowDisabled:function(){return this.colLength<=1||this.colLength===this.widget.options.colspan},mergeAboveRowDisabled:function(){return this.rowIndex<=0||this.rowArray[this.rowIndex-1].cols[this.colIndex].options.colspan!==this.widget.options.colspan},mergeBelowRowDisabled:function(){var e=this.rowIndex+this.widget.options.rowspan;return this.rowIndex>=this.rowLength-1||e>this.rowLength-1||this.rowArray[e].cols[this.colIndex].options.colspan!==this.widget.options.colspan},mergeWholeColDisabled:function(){return this.rowLength<=1||this.rowLength===this.widget.options.rowspan},undoMergeColDisabled:function(){return this.widget.merged||this.widget.options.colspan<=1},undoMergeRowDisabled:function(){return this.widget.merged||this.widget.options.rowspan<=1},deleteWholeColDisabled:function(){return 1===this.colLength||this.widget.options.colspan===this.colLength},deleteWholeRowDisabled:function(){return 1===this.rowLength||this.widget.options.rowspan===this.rowLength}},watch:{},created:function(){this.initRefList()},methods:{selectWidget:function(e){this.designer.setSelected(e)},checkContainerMove:function(e){return this.designer.checkWidgetMove(e)},onTableDragEnd:function(e,t){},onTableDragAdd:function(e,t){var i=e.newIndex;t[i]&&this.designer.setSelected(t[i]),this.designer.emitHistoryChange(),this.designer.emitEvent("field-selected",this.widget)},onTableDragUpdate:function(){this.designer.emitHistoryChange()},selectParentWidget:function(){this.parentWidget?this.designer.setSelected(this.parentWidget):this.designer.clearSelected()},handleTableCellCommand:function(e){"insertLeftCol"===e?this.insertLeftCol():"insertRightCol"===e?this.insertRightCol():"insertAboveRow"===e?this.insertAboveRow():"insertBelowRow"===e?this.insertBelowRow():"mergeLeftCol"===e?this.mergeLeftCol():"mergeRightCol"===e?this.mergeRightCol():"mergeWholeCol"===e?this.mergeWholeCol():"mergeAboveRow"===e?this.mergeAboveRow():"mergeBelowRow"===e?this.mergeBelowRow():"mergeWholeRow"===e?this.mergeWholeRow():"undoMergeCol"===e?this.undoMergeCol():"undoMergeRow"===e?this.undoMergeRow():"deleteWholeCol"===e?this.deleteWholeCol():"deleteWholeRow"===e&&this.deleteWholeRow()},insertLeftCol:function(){this.designer.insertTableCol(this.parentWidget,this.colIndex,this.rowIndex,!0)},insertRightCol:function(){this.designer.insertTableCol(this.parentWidget,this.colIndex,this.rowIndex,!1)},insertAboveRow:function(){this.designer.insertTableRow(this.parentWidget,this.rowIndex,this.rowIndex,this.colIndex,!0)},insertBelowRow:function(){this.designer.insertTableRow(this.parentWidget,this.rowIndex,this.rowIndex,this.colIndex,!1)},mergeLeftCol:function(){this.designer.mergeTableCol(this.rowArray,this.colArray,this.rowIndex,this.colIndex,!0,this.widget)},mergeRightCol:function(){this.designer.mergeTableCol(this.rowArray,this.colArray,this.rowIndex,this.colIndex,!1,this.widget)},mergeWholeRow:function(){this.designer.mergeTableWholeRow(this.rowArray,this.colArray,this.rowIndex,this.colIndex)},mergeAboveRow:function(){this.designer.mergeTableRow(this.rowArray,this.rowIndex,this.colIndex,!0,this.widget)},mergeBelowRow:function(){this.designer.mergeTableRow(this.rowArray,this.rowIndex,this.colIndex,!1,this.widget)},mergeWholeCol:function(){this.designer.mergeTableWholeCol(this.rowArray,this.colArray,this.rowIndex,this.colIndex)},undoMergeCol:function(){this.designer.undoMergeTableCol(this.rowArray,this.rowIndex,this.colIndex,this.widget.options.colspan,this.widget.options.rowspan)},undoMergeRow:function(){this.designer.undoMergeTableRow(this.rowArray,this.rowIndex,this.colIndex,this.widget.options.colspan,this.widget.options.rowspan)},deleteWholeCol:function(){this.designer.deleteTableWholeCol(this.rowArray,this.colIndex)},deleteWholeRow:function(){this.designer.deleteTableWholeRow(this.rowArray,this.rowIndex)}}},f=u,p=(i("6e5c"),i("2877")),m=Object(p["a"])(f,n,o,!1,null,"5f7bc992",null);t["default"]=m.exports},"15c6":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-picture-upload-field",use:"icon-picture-upload-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"16f3":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.prefixIcon")}},[i("el-input",{attrs:{type:"text"},model:{value:e.optionModel.prefixIcon,callback:function(t){e.$set(e.optionModel,"prefixIcon",t)},expression:"optionModel.prefixIcon"}})],1)},o=[],l=i("79fa"),s={name:"prefixIcon-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"28d62b7a",null);t["default"]=d.exports},1795:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.inactiveColor")}},[i("el-color-picker",{model:{value:e.optionModel.inactiveColor,callback:function(t){e.$set(e.optionModel,"inactiveColor",t)},expression:"optionModel.inactiveColor"}})],1)},o=[],l=i("79fa"),s={name:"inactiveColor-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"03b49a61",null);t["default"]=d.exports},"17f0":function(e,t,i){},1895:function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-switch-field",use:"icon-switch-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"18ba":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-redo",use:"icon-redo-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},1973:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:"onSubFormRowChange","label-width":"150px"}},[i("el-button",{attrs:{type:"info",icon:"el-icon-edit",plain:"",round:""},on:{click:function(t){return e.editEventHandler("onSubFormRowChange",e.eventParams)}}},[e._v(" "+e._s(e.i18nt("designer.setting.addEventHandler")))])],1)},o=[],l=i("79fa"),s=i("7d6c"),a={name:"onSubFormRowChange-editor",mixins:[l["b"],s["a"]],props:{designer:Object,selectedWidget:Object,optionModel:Object},data:function(){return{eventParams:["subFormData"]}}},r=a,d=i("2877"),c=Object(d["a"])(r,n,o,!1,null,"7109dd9a",null);t["default"]=c.exports},"19fd":function(e,t,i){"use strict";i("554e")},"1bdc":function(e,t,i){},"1d42":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-time-field",use:"icon-time-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"1e67":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.clearable")}},[i("el-switch",{model:{value:e.optionModel.clearable,callback:function(t){e.$set(e.optionModel,"clearable",t)},expression:"optionModel.clearable"}})],1)},o=[],l=i("79fa"),s={name:"clearable-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"5534f7e5",null);t["default"]=d.exports},"20c0":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("form-item-wrapper",{attrs:{designer:e.designer,field:e.field,rules:e.rules,"design-state":e.designState,"parent-widget":e.parentWidget,"parent-list":e.parentList,"index-of-parent-list":e.indexOfParentList,"sub-form-row-index":e.subFormRowIndex,"sub-form-col-index":e.subFormColIndex,"sub-form-row-id":e.subFormRowId}},[i("el-time-picker",{ref:"fieldEditor",staticClass:"full-width-input",attrs:{disabled:e.field.options.disabled,readonly:e.field.options.readonly,size:e.field.options.size,clearable:e.field.options.clearable,editable:e.field.options.editable,format:e.field.options.format,"value-format":"HH:mm:ss",placeholder:e.field.options.placeholder||e.i18nt("render.hint.timePlaceholder")},on:{focus:e.handleFocusCustomEvent,blur:e.handleBlurCustomEvent,change:e.handleChangeEvent},model:{value:e.fieldModel,callback:function(t){e.fieldModel=t},expression:"fieldModel"}})],1)},o=[],l=(i("a9e3"),i("9eeb")),s=i("c6e3"),a=i("79fa"),r=i("2d11"),d={name:"time-widget",componentName:"FieldWidget",mixins:[s["a"],r["a"],a["b"]],props:{field:Object,parentWidget:Object,parentList:Array,indexOfParentList:Number,designer:Object,designState:{type:Boolean,default:!1},subFormRowIndex:{type:Number,default:-1},subFormColIndex:{type:Number,default:-1},subFormRowId:{type:String,default:""}},components:{FormItemWrapper:l["default"]},inject:["refList","formConfig","globalOptionData","globalModel"],data:function(){return{oldFieldValue:null,fieldModel:null,rules:[]}},computed:{},beforeCreate:function(){},created:function(){this.initFieldModel(),this.registerToRefList(),this.initEventHandler(),this.buildFieldRules(),this.handleOnCreated()},mounted:function(){this.handleOnMounted()},beforeDestroy:function(){this.unregisterFromRefList()},methods:{}},c=d,u=(i("9ebd"),i("2877")),f=Object(u["a"])(c,n,o,!1,null,"0761446e",null);t["default"]=f.exports},"20e0":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-slot-component",use:"icon-slot-component-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"22a7":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.buttonStyle")}},[i("el-switch",{model:{value:e.optionModel.buttonStyle,callback:function(t){e.$set(e.optionModel,"buttonStyle",t)},expression:"optionModel.buttonStyle"}})],1)},o=[],l=i("79fa"),s={name:"buttonStyle-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"e14fae56",null);t["default"]=d.exports},2305:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",[i("span",{attrs:{slot:"label"},slot:"label"},[e._v(e._s(e.i18nt("designer.setting.fileTypes"))+" "),i("el-tooltip",{attrs:{effect:"light",content:e.i18nt("designer.setting.fileTypesHelp")}},[i("i",{staticClass:"el-icon-info"})])],1),i("el-select",{staticStyle:{width:"100%"},attrs:{multiple:"","allow-create":"",filterable:"","default-first-option":""},model:{value:e.optionModel.fileTypes,callback:function(t){e.$set(e.optionModel,"fileTypes",t)},expression:"optionModel.fileTypes"}},e._l(e.uploadPictureTypes,(function(e,t){return i("el-option",{key:t,attrs:{label:e.label,value:e.value}})})),1)],1)},o=[],l=i("79fa"),s={name:"picture-upload-fileTypes-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object},data:function(){return{uploadPictureTypes:[{value:"jpg",label:"jpg"},{value:"jpeg",label:"jpeg"},{value:"png",label:"png"},{value:"gif",label:"gif"}]}}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"651805a2",null);t["default"]=d.exports},2445:function(e,t,i){"use strict";i("e905")},"25e2":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-radio-field",use:"icon-radio-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"26a6":function(e,t,i){"use strict";i("b0c0");t["a"]={methods:{initRefList:function(){null!==this.refList&&this.widget.options.name&&(this.refList[this.widget.options.name]=this)},getWidgetRef:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=this.refList[e];return!i&&t&&this.$message.error(this.i18nt("render.hint.refNotFound")+e),i},registerToRefList:function(e){null!==this.refList&&this.widget.options.name&&(e&&delete this.refList[e],this.refList[this.widget.options.name]=this)}}}},"26cb":function(e,t,i){},"27a8":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-date-field",use:"icon-date-field-usage",viewBox:"0 0 1132 1024",content:''});s.a.add(a);t["default"]=a},"28ed":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.showScore")}},[i("el-switch",{model:{value:e.optionModel.showScore,callback:function(t){e.$set(e.optionModel,"showScore",t)},expression:"optionModel.showScore"}})],1)},o=[],l=i("79fa"),s={name:"showScore-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"1bb4aaaf",null);t["default"]=d.exports},"28f2":function(e,t,i){},"29a3":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.checkStrictly")}},[i("el-switch",{model:{value:e.optionModel.checkStrictly,callback:function(t){e.$set(e.optionModel,"checkStrictly",t)},expression:"optionModel.checkStrictly"}})],1)},o=[],l=i("79fa"),s={name:"checkStrictly-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"615c8dbf",null);t["default"]=d.exports},"2b13":function(e,t,i){"use strict";i("eed3")},"2b47":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.showRowNumber")}},[i("el-switch",{model:{value:e.optionModel.showRowNumber,callback:function(t){e.$set(e.optionModel,"showRowNumber",t)},expression:"optionModel.showRowNumber"}})],1)},o=[],l=i("79fa"),s={name:"showRowNumber-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"148dc69b",null);t["default"]=d.exports},"2c6d":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.hidden")}},[i("el-switch",{model:{value:e.optionModel.hidden,callback:function(t){e.$set(e.optionModel,"hidden",t)},expression:"optionModel.hidden"}})],1)},o=[],l=i("79fa"),s={name:"hidden-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"d798e8e2",null);t["default"]=d.exports},"2d11":function(e,t,i){"use strict";i("b0c0"),i("a434"),i("d3b7"),i("159b"),i("d81d");var n=i("ca00"),o=i("a00a");t["a"]={inject:["refList","formConfig","globalOptionData","globalModel","getOptionData"],computed:{subFormName:function(){return this.parentWidget?this.parentWidget.options.name:""},subFormItemFlag:function(){return!!this.parentWidget&&"sub-form"===this.parentWidget.type},formModel:{cache:!1,get:function(){return this.globalModel.formModel}}},methods:{getPropName:function(){return this.subFormItemFlag&&!this.designState?this.subFormName+"."+this.subFormRowIndex+"."+this.field.options.name:this.field.options.name},initFieldModel:function(){var e=this;if(this.field.formItemFlag){if(this.subFormItemFlag&&!this.designState){var t=this.formModel[this.subFormName];return void 0!==t&&void 0!==t[this.subFormRowIndex]&&void 0!==t[this.subFormRowIndex][this.field.options.name]||void 0===this.field.options.defaultValue?void 0===t[this.subFormRowIndex][this.field.options.name]?(this.fieldModel=null,t[this.subFormRowIndex][this.field.options.name]=null):this.fieldModel=t[this.subFormRowIndex][this.field.options.name]:(this.fieldModel=this.field.options.defaultValue,t[this.subFormRowIndex][this.field.options.name]=this.field.options.defaultValue),setTimeout((function(){e.handleOnChangeForSubForm(e.fieldModel,e.oldFieldValue,t,e.subFormRowId)}),800),this.oldFieldValue=Object(n["d"])(this.fieldModel),void this.initFileList()}void 0===this.formModel[this.field.options.name]&&void 0!==this.field.options.defaultValue?this.fieldModel=this.field.options.defaultValue:void 0===this.formModel[this.field.options.name]?this.formModel[this.field.options.name]=null:this.fieldModel=this.formModel[this.field.options.name],this.oldFieldValue=Object(n["d"])(this.fieldModel),this.initFileList()}},initFileList:function(){"picture-upload"!==this.field.type&&"file-upload"!==this.field.type||!0===this.designState||this.fieldModel&&(Array.isArray(this.fieldModel)?this.fileList=Object(n["d"])(this.fieldModel):this.fileList.splice(0,0,Object(n["d"])(this.fieldModel)))},initEventHandler:function(){this.$on("setFormData",(function(e){this.subFormItemFlag||this.setValue(e[this.field.options.name])})),this.$on("field-value-changed",(function(e){if(this.subFormItemFlag){var t=this.formModel[this.subFormName];this.handleOnChangeForSubForm(e[0],e[1],t,this.subFormRowId)}else this.handleOnChange(e[0],e[1])})),this.$on("reloadOptionItems",(function(e){(0===e.length||e.indexOf(this.field.options.name)>-1)&&this.initOptionItems(!0)}))},handleOnCreated:function(){if(this.field.options.onCreated){var e=new Function(this.field.options.onCreated);e.call(this)}},handleOnMounted:function(){if(this.field.options.onMounted){var e=new Function(this.field.options.onMounted);e.call(this)}},registerToRefList:function(e){null!==this.refList&&this.field.options.name&&(this.subFormItemFlag&&!this.designState?(e&&delete this.refList[e+"@row"+this.subFormRowId],this.refList[this.field.options.name+"@row"+this.subFormRowId]=this):(e&&delete this.refList[e],this.refList[this.field.options.name]=this))},unregisterFromRefList:function(){if(null!==this.refList&&this.field.options.name){var e=this.field.options.name;this.subFormItemFlag&&!this.designState?delete this.refList[e+"@row"+this.subFormRowId]:delete this.refList[e]}},initOptionItems:function(e){if(!this.designState&&("radio"===this.field.type||"checkbox"===this.field.type||"select"===this.field.type||"cascader"===this.field.type)){var t=this.getOptionData();t&&t.hasOwnProperty(this.field.options.name)&&(e?this.reloadOptions(t[this.field.options.name]):this.loadOptions(t[this.field.options.name]))}},refreshDefaultValue:function(){!0===this.designState&&void 0!==this.field.options.defaultValue&&(this.fieldModel=this.field.options.defaultValue)},clearFieldRules:function(){this.field.formItemFlag&&this.rules.splice(0,this.rules.length)},buildFieldRules:function(){var e=this;if(this.field.formItemFlag){if(this.rules.splice(0,this.rules.length),this.field.options.required&&this.rules.push({required:!0,trigger:["blur"],message:this.field.options.requiredHint||this.i18nt("render.hint.fieldRequired")}),this.field.options.validation){var t=this.field.options.validation;o["a"][t]?this.rules.push({validator:o["a"][t],trigger:["blur","change"],label:this.field.options.label,errorMsg:this.field.options.validationHint}):this.rules.push({validator:o["a"]["regExp"],trigger:["blur","change"],regExp:t,label:this.field.options.label,errorMsg:this.field.options.validationHint})}if(this.field.options.onValidate){var i=function(t,i,n){var o=new Function("rule","value","callback",e.field.options.onValidate);return o.call(e,t,i,n)};this.rules.push({validator:i,trigger:["blur","change"],label:this.field.options.label})}}},disableChangeValidate:function(){this.rules&&this.rules.forEach((function(e){e.trigger&&e.trigger.splice(0,e.trigger.length)}))},enableChangeValidate:function(){this.rules&&this.rules.forEach((function(e){e.trigger&&(e.trigger.push("blur"),e.trigger.push("change"))}))},disableOptionOfList:function(e,t){e&&e.length>0&&e.forEach((function(e){e.value===t&&(e.disabled=!0)}))},enableOptionOfList:function(e,t){e&&e.length>0&&e.forEach((function(e){e.value===t&&(e.disabled=!1)}))},emitFieldDataChange:function(e,t){this.$emit("field-value-changed",[e,t]),this.dispatch("VFormRender","fieldChange",[this.field.options.name,e,t,this.subFormName,this.subFormRowIndex])},syncUpdateFormModel:function(e){if(!this.designState)if(this.subFormItemFlag){var t=this.formModel[this.subFormName]||[{}],i=t[this.subFormRowIndex];i[this.field.options.name]=e}else this.formModel[this.field.options.name]=e},handleChangeEvent:function(e){this.syncUpdateFormModel(e),this.emitFieldDataChange(e,this.oldFieldValue),this.oldFieldValue=Object(n["d"])(e),this.dispatch("VFormRender","fieldValidation",[this.getPropName()])},handleFocusCustomEvent:function(e){if(this.oldFieldValue=Object(n["d"])(this.fieldModel),this.field.options.onFocus){var t=new Function("event",this.field.options.onFocus);t.call(this,e)}},handleBlurCustomEvent:function(e){if(this.field.options.onBlur){var t=new Function("event",this.field.options.onBlur);t.call(this,e)}},handleInputCustomEvent:function(e){if(this.syncUpdateFormModel(e),this.dispatch("VFormRender","fieldValidation",[this.getPropName()]),this.field.options.onInput){var t=new Function("value",this.field.options.onInput);t.call(this,e)}},emitAppendButtonClick:function(){if(!this.designState)if(this.field.options.onAppendButtonClick){var e=new Function(this.field.options.onAppendButtonClick);e.call(this)}else this.dispatch("VFormRender","appendButtonClick",[this])},handleOnChange:function(e,t){if(this.field.options.onChange){var i=new Function("value","oldValue",this.field.options.onChange);i.call(this,e,t)}},handleOnChangeForSubForm:function(e,t,i,n){if(this.field.options.onChange){var o=new Function("value","oldValue","subFormData","rowId",this.field.options.onChange);o.call(this,e,t,i,n)}},handleButtonWidgetClick:function(){if(!this.designState)if(this.field.options.onClick){var e=new Function(this.field.options.onClick);e.call(this)}else this.dispatch("VFormRender","buttonClick",[this])},remoteQuery:function(e){if(this.field.options.onRemoteQuery){var t=new Function("keyword",this.field.options.onRemoteQuery);t.call(this,e)}},getFormRef:function(){return this.refList["v_form_ref"]},getWidgetRef:function(e,t){var i=this.refList[e];return!i&&t&&this.$message.error(this.i18nt("render.hint.refNotFound")+e),i},getFieldEditor:function(){return this.$refs["fieldEditor"]},setValue:function(e){if(this.field.formItemFlag){var t=Object(n["d"])(this.fieldModel);this.fieldModel=e,this.initFileList(),this.syncUpdateFormModel(e),this.emitFieldDataChange(e,t)}},getValue:function(){return this.fieldModel},resetField:function(){if(!this.subFormItemFlag){var e=this.field.options.defaultValue;this.setValue(e),"picture-upload"!==this.field.type&&"file-upload"!==this.field.type||(this.$refs["fieldEditor"].clearFiles(),this.fileList.splice(0,this.fileList.length))}},setWidgetOption:function(e,t){this.field.options.hasOwnProperty(e)&&(this.field.options[e]=t)},setReadonly:function(e){this.field.options.readonly=e},setDisabled:function(e){this.field.options.disabled=e},setAppendButtonVisible:function(e){this.field.options.appendButton=e},setAppendButtonDisabled:function(e){this.field.options.appendButtonDisabled=e},setHidden:function(e){this.field.options.hidden=e,e?this.clearFieldRules():this.buildFieldRules()},setRequired:function(e){this.field.options.required=e,this.buildFieldRules()},setLabel:function(e){this.field.options.label=e},focus:function(){this.getFieldEditor()&&this.getFieldEditor().focus&&this.getFieldEditor().focus()},clearSelectedOptions:function(){"checkbox"!==this.field.type&&"radio"!==this.field.type&&"select"!==this.field.type||("checkbox"===this.field.type||"select"===this.field.type&&this.field.options.multiple?this.fieldModel=[]:this.fieldModel="")},loadOptions:function(e){this.field.options.optionItems=Object(n["d"])(e)},reloadOptions:function(e){this.field.options.optionItems=Object(n["d"])(e)},getOptions:function(){return this.field.options.optionItems},disableOption:function(e){this.disableOptionOfList(this.field.options.optionItems,e)},enableOption:function(e){this.enableOptionOfList(this.field.options.optionItems,e)},setUploadHeader:function(e,t){this.$set(this.uploadHeaders,e,t)},setUploadData:function(e,t){this.$set(this.uploadData,e,t)},setToolbar:function(e){this.customToolbar=e},isSubFormItem:function(){return!!this.parentWidget&&"sub-form"===this.parentWidget.type},addCssClass:function(e){this.field.options.customClass?this.field.options.customClass.push(e):this.field.options.customClass=[e]},removeCssClass:function(e){if(this.field.options.customClass){var t=-1;this.field.options.customClass.map((function(i,n){i===e&&(t=n)})),t>-1&&this.field.options.customClass.splice(t,1)}}}}},"2d13":function(e,t,i){},"2d9e":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-card",use:"icon-card-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"2dc5":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.limit")}},[i("el-input-number",{staticClass:"hide-spin-button",staticStyle:{width:"100%"},attrs:{min:1},model:{value:e.optionModel.limit,callback:function(t){e.$set(e.optionModel,"limit",t)},expression:"optionModel.limit"}})],1)},o=[],l=i("79fa"),s={name:"limit-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"41408032",null);t["default"]=d.exports},"2dd9":function(e,t,i){},"2ec9":function(e,t,i){"use strict";i("04fd")},"2faa":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("form-item-wrapper",{attrs:{designer:e.designer,field:e.field,rules:e.rules,"design-state":e.designState,"parent-widget":e.parentWidget,"parent-list":e.parentList,"index-of-parent-list":e.indexOfParentList,"sub-form-row-index":e.subFormRowIndex,"sub-form-col-index":e.subFormColIndex,"sub-form-row-id":e.subFormRowId}},[i("el-rate",{ref:"fieldEditor",attrs:{disabled:e.field.options.disabled,max:e.field.options.max,"low-threshold":e.field.options.lowThreshold,"high-threshold":e.field.options.highThreshold,"allow-half":e.field.options.allowHalf,"show-text":e.field.options.showText,"show-score":e.field.options.showScore},on:{change:e.handleChangeEvent},model:{value:e.fieldModel,callback:function(t){e.fieldModel=t},expression:"fieldModel"}})],1)},o=[],l=(i("a9e3"),i("9eeb")),s=i("c6e3"),a=i("79fa"),r=i("2d11"),d={name:"rate-widget",componentName:"FieldWidget",mixins:[s["a"],r["a"],a["b"]],props:{field:Object,parentWidget:Object,parentList:Array,indexOfParentList:Number,designer:Object,designState:{type:Boolean,default:!1},subFormRowIndex:{type:Number,default:-1},subFormColIndex:{type:Number,default:-1},subFormRowId:{type:String,default:""}},components:{FormItemWrapper:l["default"]},inject:["refList","formConfig","globalOptionData","globalModel"],data:function(){return{oldFieldValue:null,fieldModel:null,rules:[]}},computed:{},beforeCreate:function(){},created:function(){this.initFieldModel(),this.registerToRefList(),this.initEventHandler(),this.buildFieldRules(),this.handleOnCreated()},mounted:function(){this.handleOnMounted()},beforeDestroy:function(){this.unregisterFromRefList()},methods:{}},c=d,u=(i("623d"),i("2877")),f=Object(u["a"])(c,n,o,!1,null,"02bf17e4",null);t["default"]=f.exports},"30ac":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.automaticDropdown")}},[i("el-switch",{model:{value:e.optionModel.automaticDropdown,callback:function(t){e.$set(e.optionModel,"automaticDropdown",t)},expression:"optionModel.automaticDropdown"}})],1)},o=[],l=i("79fa"),s={name:"automaticDropdown-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"82662fa2",null);t["default"]=d.exports},"31ab":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.inactiveText")}},[i("el-input",{model:{value:e.optionModel.inactiveText,callback:function(t){e.$set(e.optionModel,"inactiveText",t)},expression:"optionModel.inactiveText"}})],1)},o=[],l=i("79fa"),s={name:"inactiveText-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"03f5012d",null);t["default"]=d.exports},"31b7":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",[i("el-form-item",{attrs:{"label-width":"0"}},[i("el-divider",{staticClass:"custom-divider"},[e._v(e._s(e.i18nt("designer.setting.uploadSetting")))])],1),i("el-form-item",{attrs:{label:e.i18nt("designer.setting.uploadURL")}},[i("el-input",{attrs:{type:"text"},model:{value:e.optionModel.uploadURL,callback:function(t){e.$set(e.optionModel,"uploadURL",t)},expression:"optionModel.uploadURL"}})],1)],1)},o=[],l=i("79fa"),s={name:"uploadURL-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"2b299867",null);t["default"]=d.exports},"329d":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.colOffsetTitle")}},[i("el-input-number",{staticStyle:{width:"100%"},attrs:{min:0,max:24},model:{value:e.optionModel.offset,callback:function(t){e.$set(e.optionModel,"offset",e._n(t))},expression:"optionModel.offset"}})],1)},o=[],l=i("79fa"),s={name:"grid-col-offset-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"b3fd22fe",null);t["default"]=d.exports},"333d":function(e,t,i){"use strict";i("5660")},"345a":function(e,t,i){"use strict";i("c372")},"34c5":function(e,t,i){"use strict";i("baf1")},"34f0":function(e,t,i){"use strict";i("b0c0"),i("d3b7"),i("159b"),i("a434"),i("d81d");var n=i("ca00");t["a"]={computed:{customClass:function(){return this.widget.options.customClass||""},formModel:{cache:!1,get:function(){return this.globalModel.formModel}}},mounted:function(){this.callSetHidden()},methods:{unregisterFromRefList:function(){if(null!==this.refList&&this.widget.options.name){var e=this.widget.options.name;delete this.refList[e]}},callSetHidden:function(){!0===this.widget.options.hidden&&this.setHidden(!0)},setHidden:function(e){var t=this;this.widget.options.hidden=e;var i=function(i){var n=i.options.name,o=t.getWidgetRef(n);e&&o&&o.clearFieldRules&&o.clearFieldRules(),!e&&o&&o.buildFieldRules&&o.buildFieldRules()};Object(n["t"])(this.widget,i)},activeTab:function(e){var t=this;e>=0&&e=0&&e=0&&e=0&&e=0&&e0&&this.rowIdData.forEach((function(t,i){e.disableSubFormRow(i)})),this.actionDisabled=!0},enableSubForm:function(){var e=this;this.rowIdData.length>0&&this.rowIdData.forEach((function(t,i){e.enableSubFormRow(i)})),this.actionDisabled=!1},resetSubForm:function(){if("sub-form"===this.widget.type){var e=this.formModel[this.widget.options.name];e&&(e.splice(0,e.length),this.rowIdData.splice(0,this.rowIdData.length)),this.widget.options.showBlankRow&&this.addSubFormRow()}},getSubFormValues:function(){if("sub-form"===this.widget.type)return this.formModel[this.widget.options.name];this.$message.error(this.i18nt("render.hint.nonSubFormType"))},setSubFormValues:function(e){},addCssClass:function(e){this.widget.options.customClass?this.widget.options.customClass.push(e):this.widget.options.customClass=[e]},removeCssClass:function(e){if(this.widget.options.customClass){var t=-1;this.widget.options.customClass.map((function(i,n){i===e&&(t=n)})),t>-1&&this.widget.options.customClass.splice(t,1)}}}}},3559:function(e,t,i){},"35c2":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.contentPosition")}},[i("el-select",{model:{value:e.optionModel.contentPosition,callback:function(t){e.$set(e.optionModel,"contentPosition",t)},expression:"optionModel.contentPosition"}},[i("el-option",{attrs:{label:"center",value:"center"}}),i("el-option",{attrs:{label:"left",value:"left"}}),i("el-option",{attrs:{label:"right",value:"right"}})],1)],1)},o=[],l=i("79fa"),s={name:"contentPosition-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"d4bc4820",null);t["default"]=d.exports},"36ad":function(e,t,i){},"36c7":function(e,t,i){},"36f6":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.labelHidden")}},[i("el-switch",{model:{value:e.optionModel.labelHidden,callback:function(t){e.$set(e.optionModel,"labelHidden",t)},expression:"optionModel.labelHidden"}})],1)},o=[],l=i("79fa"),s={name:"labelHidden-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"086f4433",null);t["default"]=d.exports},"37ab":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticStyle:{display:"none"}})},o=[],l={name:"checkbox-defaultValue-editor",props:{designer:Object,selectedWidget:Object,optionModel:Object}},s=l,a=i("2877"),r=Object(a["a"])(s,n,o,!1,null,"b77e89ba",null);t["default"]=r.exports},"38b9":function(e,t,i){"use strict";i("d6e6")},"390e":function(e,t,i){"use strict";i("d85f")},3918:function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-time-range-field",use:"icon-time-range-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},3952:function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-rich-editor-field",use:"icon-rich-editor-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"3ad3":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("form-item-wrapper",{attrs:{designer:e.designer,field:e.field,rules:e.rules,"design-state":e.designState,"parent-widget":e.parentWidget,"parent-list":e.parentList,"index-of-parent-list":e.indexOfParentList,"sub-form-row-index":e.subFormRowIndex,"sub-form-col-index":e.subFormColIndex,"sub-form-row-id":e.subFormRowId}},[i("el-color-picker",{ref:"fieldEditor",attrs:{size:e.field.options.size,disabled:e.field.options.disabled},on:{change:e.handleChangeEvent},model:{value:e.fieldModel,callback:function(t){e.fieldModel=t},expression:"fieldModel"}})],1)},o=[],l=(i("a9e3"),i("9eeb")),s=i("c6e3"),a=i("79fa"),r=i("2d11"),d={name:"color-widget",componentName:"FieldWidget",mixins:[s["a"],r["a"],a["b"]],props:{field:Object,parentWidget:Object,parentList:Array,indexOfParentList:Number,designer:Object,designState:{type:Boolean,default:!1},subFormRowIndex:{type:Number,default:-1},subFormColIndex:{type:Number,default:-1},subFormRowId:{type:String,default:""}},components:{FormItemWrapper:l["default"]},inject:["refList","formConfig","globalOptionData","globalModel"],data:function(){return{oldFieldValue:null,fieldModel:null,rules:[]}},computed:{},beforeCreate:function(){},created:function(){this.initFieldModel(),this.registerToRefList(),this.initEventHandler(),this.buildFieldRules(),this.handleOnCreated()},mounted:function(){this.handleOnMounted()},beforeDestroy:function(){this.unregisterFromRefList()},methods:{}},c=d,u=(i("a906"),i("2877")),f=Object(u["a"])(c,n,o,!1,null,"53ad0c08",null);t["default"]=f.exports},"3bc5":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.maxStars")}},[i("el-input-number",{staticClass:"hide-spin-button",staticStyle:{width:"100%"},attrs:{min:1,max:10},model:{value:e.optionModel.max,callback:function(t){e.$set(e.optionModel,"max",t)},expression:"optionModel.max"}})],1)},o=[],l=i("79fa"),s={name:"rate-max-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"59c5a4f2",null);t["default"]=d.exports},"3c10":function(e,t,i){"use strict";i("848c")},"3e10":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.labelAlign")}},[i("el-radio-group",{staticClass:"radio-group-custom",model:{value:e.optionModel.labelAlign,callback:function(t){e.$set(e.optionModel,"labelAlign",t)},expression:"optionModel.labelAlign"}},[i("el-radio-button",{attrs:{label:"label-left-align"}},[e._v(" "+e._s(e.i18nt("designer.setting.leftAlign")))]),i("el-radio-button",{attrs:{label:"label-center-align"}},[e._v(" "+e._s(e.i18nt("designer.setting.centerAlign")))]),i("el-radio-button",{attrs:{label:"label-right-align"}},[e._v(" "+e._s(e.i18nt("designer.setting.rightAlign")))])],1)],1)},o=[],l=i("79fa"),s={name:"sub-form-labelAlign-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=(i("0dee"),i("2877")),d=Object(r["a"])(a,n,o,!1,null,"66fb0270",null);t["default"]=d.exports},"3f28":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:"onUploadError","label-width":"150px"}},[i("el-button",{attrs:{type:"info",icon:"el-icon-edit",plain:"",round:""},on:{click:function(t){return e.editEventHandler("onUploadError",e.eventParams)}}},[e._v(" "+e._s(e.i18nt("designer.setting.addEventHandler")))])],1)},o=[],l=i("79fa"),s=i("7d6c"),a={name:"onUploadError-editor",mixins:[l["b"],s["a"]],props:{designer:Object,selectedWidget:Object,optionModel:Object},data:function(){return{eventParams:["error","file","fileList"]}}},r=a,d=i("2877"),c=Object(d["a"])(r,n,o,!1,null,"a1332e98",null);t["default"]=c.exports},"401c":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.showFileList")}},[i("el-switch",{model:{value:e.optionModel.showFileList,callback:function(t){e.$set(e.optionModel,"showFileList",t)},expression:"optionModel.showFileList"}})],1)},o=[],l=i("79fa"),s={name:"showFileList-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"6901fcd5",null);t["default"]=d.exports},"40fa":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-text-field",use:"icon-text-field-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},4120:function(e,t,i){"use strict";i("1bdc")},"423c":function(e,t,i){},"43b3":function(e,t,i){},"447a":function(e,t,i){"use strict";i("6043")},"44fb":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.showText")}},[i("el-switch",{model:{value:e.optionModel.showText,callback:function(t){e.$set(e.optionModel,"showText",t)},expression:"optionModel.showText"}})],1)},o=[],l=i("79fa"),s={name:"showText-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"ed97a906",null);t["default"]=d.exports},4595:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.placeholder")}},[i("el-input",{attrs:{type:"text"},model:{value:e.optionModel.placeholder,callback:function(t){e.$set(e.optionModel,"placeholder",t)},expression:"optionModel.placeholder"}})],1)},o=[],l=i("79fa"),s=i("b2bf"),a={name:"placeholder-editor",mixins:[l["b"],s["a"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},r=a,d=i("2877"),c=Object(d["a"])(r,n,o,!1,null,"03f971ba",null);t["default"]=c.exports},"47f1":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-table",use:"icon-table-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"491c":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-divider",use:"icon-divider-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"4a70":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("form-item-wrapper",{attrs:{designer:e.designer,field:e.field,rules:e.rules,"design-state":e.designState,"parent-widget":e.parentWidget,"parent-list":e.parentList,"index-of-parent-list":e.indexOfParentList,"sub-form-row-index":e.subFormRowIndex,"sub-form-col-index":e.subFormColIndex,"sub-form-row-id":e.subFormRowId}},[i("el-upload",{ref:"fieldEditor",staticClass:"dynamicPseudoAfter",class:{hideUploadDiv:e.uploadBtnHidden},style:e.styleVariables,attrs:{disabled:e.field.options.disabled,action:e.field.options.uploadURL,headers:e.uploadHeaders,data:e.uploadData,"with-credentials":e.field.options.withCredentials,multiple:e.field.options.multipleSelect,"file-list":e.fileList,"show-file-list":e.field.options.showFileList,limit:e.field.options.limit,"on-exceed":e.handleFileExceed,"before-upload":e.beforeFileUpload,"on-success":e.handleFileUpload,"on-error":e.handelUploadError,"on-remove":e.handleFileRemove},scopedSlots:e._u([{key:"file",fn:function(t){var n=t.file;return[i("div",{staticClass:"upload-file-list"},[i("span",{staticClass:"upload-file-name",attrs:{title:n.name}},[e._v(e._s(n.name))]),i("a",{attrs:{href:n.url,download:""}},[i("i",{staticClass:"el-icon-download file-action",attrs:{title:e.i18nt("render.hint.downloadFile")}})]),e.field.options.disabled?e._e():i("i",{staticClass:"el-icon-delete file-action",attrs:{title:e.i18nt("render.hint.removeFile")},on:{click:function(t){return e.removeUploadFile(n.name)}}})])]}}])},[e.field.options.uploadTip?i("div",{staticClass:"el-upload__tip",attrs:{slot:"tip"},slot:"tip"},[e._v(e._s(e.field.options.uploadTip))]):e._e(),i("i",{staticClass:"el-icon-plus avatar-uploader-icon",attrs:{slot:"default"},slot:"default"})])],1)},o=[],l=(i("a9e3"),i("ac1f"),i("5319"),i("b0c0"),i("d3b7"),i("159b"),i("a434"),i("9eeb")),s=i("c6e3"),a=i("79fa"),r=i("ca00"),d=i("2d11"),c="'"+Object(a["c"])("render.hint.selectFile")+"'",u={name:"file-upload-widget",componentName:"FieldWidget",mixins:[s["a"],d["a"],a["b"]],props:{field:Object,parentWidget:Object,parentList:Array,indexOfParentList:Number,designer:Object,designState:{type:Boolean,default:!1},subFormRowIndex:{type:Number,default:-1},subFormColIndex:{type:Number,default:-1},subFormRowId:{type:String,default:""}},components:{FormItemWrapper:l["default"]},inject:["refList","formConfig","globalOptionData","globalModel"],data:function(){return{oldFieldValue:null,fieldModel:null,rules:[],uploadHeaders:{},uploadData:{key:""},fileList:[],uploadBtnHidden:!1,styleVariables:{"--select-file-action":c}}},computed:{},beforeCreate:function(){},created:function(){this.initFieldModel(),this.registerToRefList(),this.initEventHandler(),this.buildFieldRules(),this.handleOnCreated()},mounted:function(){this.handleOnMounted()},beforeDestroy:function(){this.unregisterFromRefList()},methods:{handleFileExceed:function(){var e=this.field.options.limit;this.$message.warning(this.i18nt("render.hint.uploadExceed").replace("${uploadLimit}",e))},updateUploadFieldModelAndEmitDataChange:function(e){var t=Object(r["d"])(this.fieldModel);this.fieldModel=Object(r["d"])(e),this.syncUpdateFormModel(this.fieldModel),this.emitFieldDataChange(this.fieldModel,t)},beforeFileUpload:function(e){var t=!1,i=e.name.substring(e.name.lastIndexOf(".")+1);if(this.field.options&&this.field.options.fileTypes){var n=this.field.options.fileTypes;n.length>0&&(t=n.some((function(e){return i.toLowerCase()===e.toLowerCase()})))}if(!t)return this.$message.error(this.i18nt("render.hint.unsupportedFileType")+i),!1;var o=!1,l=5;return this.field.options&&this.field.options.fileMaxSize&&(l=this.field.options.fileMaxSize),o=e.size/1024/1024<=l,o?(this.uploadData.key=e.name,this.handleOnBeforeUpload(e)):(this.$message.error(this.i18nt("render.hint.fileSizeExceed")+l+"MB"),!1)},handleOnBeforeUpload:function(e){if(this.field.options.onBeforeUpload){var t=new Function("file",this.field.options.onBeforeUpload),i=t.call(this,e);return"boolean"!==typeof i||i}return!0},handleFileUpload:function(e,t,i){if("success"===t.status&&(this.updateUploadFieldModelAndEmitDataChange(i),this.fileList=Object(r["d"])(i),this.uploadBtnHidden=i.length>=this.field.options.limit,this.field.options.onUploadSuccess)){var n=new Function("result","file","fileList",this.field.options.onUploadSuccess);n.call(this,e,t,i)}},handleFileRemove:function(e,t){if(this.fileList=Object(r["d"])(t),this.updateUploadFieldModelAndEmitDataChange(t),this.uploadBtnHidden=t.length>=this.field.options.limit,this.field.options.onFileRemove){var i=new Function("file","fileList",this.field.options.onFileRemove);i.call(this,e,t)}},removeUploadFile:function(e){var t=-1,i=null;if(this.fileList.forEach((function(n,o){n.name===e&&(t=o,i=n)})),t>=0&&(this.fileList.splice(t,1),this.updateUploadFieldModelAndEmitDataChange(this.fileList),this.uploadBtnHidden=this.fileList.length>=this.field.options.limit,this.field.options.onFileRemove)){var n=new Function("file","fileList",this.field.options.onFileRemove);n.call(this,i,this.fileList)}},handelUploadError:function(e,t,i){if(this.field.options.onUploadError){var n=new Function("error","file","fileList",this.field.options.onUploadError);n.call(this,e,t,i)}else this.$message({message:this.i18nt("render.hint.uploadError")+e,duration:3e3,type:"error"})}}},f=u,p=(i("390e"),i("2877")),m=Object(p["a"])(f,n,o,!1,null,"3f51f292",null);t["default"]=m.exports},"4be5":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.valueFormat")}},[i("el-select",{attrs:{filterable:"","allow-create":""},model:{value:e.optionModel.valueFormat,callback:function(t){e.$set(e.optionModel,"valueFormat",t)},expression:"optionModel.valueFormat"}},[i("el-option",{attrs:{label:"yyyy-MM-dd",value:"yyyy-MM-dd"}}),i("el-option",{attrs:{label:"yyyy-MM-dd HH:mm:ss",value:"yyyy-MM-dd HH:mm:ss"}})],1)],1)},o=[],l=i("79fa"),s={name:"date-range-valueFormat-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"584a5ccb",null);t["default"]=d.exports},"4cde":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-static-text",use:"icon-static-text-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"4e3d":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:"onBlur","label-width":"150px"}},[i("el-button",{attrs:{type:"info",icon:"el-icon-edit",plain:"",round:""},on:{click:function(t){return e.editEventHandler("onBlur",e.eventParams)}}},[e._v(" "+e._s(e.i18nt("designer.setting.addEventHandler")))])],1)},o=[],l=i("79fa"),s=i("7d6c"),a={name:"onBlur-editor",mixins:[l["b"],s["a"]],props:{designer:Object,selectedWidget:Object,optionModel:Object},data:function(){return{eventParams:["event"]}}},r=a,d=i("2877"),c=Object(d["a"])(r,n,o,!1,null,"ab3f95fc",null);t["default"]=c.exports},"4e94":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.format")}},[i("el-select",{attrs:{filterable:"","allow-create":""},model:{value:e.optionModel.format,callback:function(t){e.$set(e.optionModel,"format",t)},expression:"optionModel.format"}},[i("el-option",{attrs:{label:"yyyy-MM-dd",value:"yyyy-MM-dd"}}),i("el-option",{attrs:{label:"yyyy/MM/dd",value:"yyyy/MM/dd"}}),i("el-option",{attrs:{label:"yyyy年MM月dd日",value:"yyyy年MM月dd日"}}),i("el-option",{attrs:{label:"yyyy-MM-dd HH:mm:ss",value:"yyyy-MM-dd HH:mm:ss"}}),i("el-option",{attrs:{label:"yyyy-MM-dd hh:mm:ss",value:"yyyy-MM-dd hh:mm:ss"}})],1)],1)},o=[],l=i("79fa"),s={name:"date-range-format-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"04dfb3ed",null);t["default"]=d.exports},"4ebe":function(e,t,i){},"4ed4":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-button",use:"icon-button-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},"4eff":function(e,t,i){},5112:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.remote")}},[i("el-switch",{on:{change:e.onRemoteChange},model:{value:e.optionModel.remote,callback:function(t){e.$set(e.optionModel,"remote",t)},expression:"optionModel.remote"}})],1)},o=[],l=i("79fa"),s=i("b2bf"),a={name:"remote-editor",mixins:[l["b"],s["a"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},r=a,d=i("2877"),c=Object(d["a"])(r,n,o,!1,null,"83c35cae",null);t["default"]=c.exports},"51ff":function(e,t,i){var n={"./alert.svg":"f2db","./button.svg":"4ed4","./card.svg":"2d9e","./cascader-field.svg":"5fe5","./checkbox-field.svg":"f582","./color-field.svg":"5bc5","./custom-component.svg":"c885","./data-table.svg":"6592","./date-field.svg":"27a8","./date-range-field.svg":"6947","./divider.svg":"491c","./document.svg":"fd28","./drag.svg":"9bbf","./file-upload-field.svg":"d119","./github.svg":"558d","./grid.svg":"d8ec","./html-text.svg":"89ef","./node-tree.svg":"e486","./number-field.svg":"9b6e","./picture-upload-field.svg":"15c6","./radio-field.svg":"25e2","./rate-field.svg":"f250","./redo.svg":"18ba","./rich-editor-field.svg":"3952","./section.svg":"e934","./select-field.svg":"b8d7","./slider-field.svg":"7007","./slot-component.svg":"20e0","./slot-field.svg":"ecf2","./static-text.svg":"4cde","./sub-form.svg":"db13","./switch-field.svg":"1895","./tab.svg":"8fb7","./table.svg":"47f1","./text-field.svg":"40fa","./textarea-field.svg":"d2e4","./time-field.svg":"1d42","./time-range-field.svg":"3918","./undo.svg":"612b","./vue-sfc.svg":"8740"};function o(e){var t=l(e);return i(t)}function l(e){if(!i.o(n,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return n[e]}o.keys=function(){return Object.keys(n)},o.resolve=l,e.exports=o,o.id="51ff"},5479:function(e,t,i){"use strict";i("f355")},"54cf":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.rows")}},[i("el-input-number",{staticStyle:{width:"100%"},model:{value:e.optionModel.rows,callback:function(t){e.$set(e.optionModel,"rows",t)},expression:"optionModel.rows"}})],1)},o=[],l=i("79fa"),s={name:"rows-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"99e99dee",null);t["default"]=d.exports},"54d3":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.controlsPosition")}},[i("el-select",{model:{value:e.optionModel.controlsPosition,callback:function(t){e.$set(e.optionModel,"controlsPosition",t)},expression:"optionModel.controlsPosition"}},[i("el-option",{attrs:{label:"default",value:""}}),i("el-option",{attrs:{label:"right",value:"right"}})],1)],1)},o=[],l=i("79fa"),s={name:"controlsPosition-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"320a7676",null);t["default"]=d.exports},"554e":function(e,t,i){},"558d":function(e,t,i){"use strict";i.r(t);var n=i("e017"),o=i.n(n),l=i("21a1"),s=i.n(l),a=new o.a({id:"icon-github",use:"icon-github-usage",viewBox:"0 0 1024 1024",content:''});s.a.add(a);t["default"]=a},5660:function(e,t,i){},"566c":function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.step")}},[i("el-input-number",{staticClass:"hide-spin-button",staticStyle:{width:"100%"},model:{value:e.optionModel.step,callback:function(t){e.$set(e.optionModel,"step",t)},expression:"optionModel.step"}})],1)},o=[],l=i("79fa"),s={name:"step-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"3dde34f4",null);t["default"]=d.exports},5674:function(e,t,i){"use strict";i.r(t);var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form-item",{attrs:{label:e.i18nt("designer.setting.cellWidth")}},[i("el-input",{attrs:{type:"text"},model:{value:e.optionModel.cellWidth,callback:function(t){e.$set(e.optionModel,"cellWidth",t)},expression:"optionModel.cellWidth"}})],1)},o=[],l=i("79fa"),s={name:"cellWidth-editor",mixins:[l["b"]],props:{designer:Object,selectedWidget:Object,optionModel:Object}},a=s,r=i("2877"),d=Object(r["a"])(a,n,o,!1,null,"8ddfb426",null);t["default"]=d.exports},"56d7":function(e,t,i){"use strict";i.r(t);i("e260"),i("e6cf"),i("cca6"),i("a79d"),i("db4d"),i("768f");var n=i("a026"),o=i("bc3a"),l=i.n(o),s=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{attrs:{id:"app"}},[i("VFormDesigner",{ref:"vfDesignerRef",attrs:{"designer-config":e.designerConfig}})],1)},a=[],r=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-container",{staticClass:"main-container full-height"},[i("el-header",{staticClass:"main-header"},[i("div",{staticClass:"float-left main-title"},[i("span",{staticClass:"bold"},[e._v("GVA")]),e._v(" "+e._s(e.i18nt("application.productTitle"))+" ")]),i("div",{staticClass:"float-right external-link"},[e.showLink("languageMenu")?i("el-dropdown",{attrs:{"hide-timeout":2e3},on:{command:e.handleLanguageChanged}},[i("span",{staticClass:"el-dropdown-link"},[e._v(e._s(e.curLangName)),i("i",{staticClass:"el-icon-arrow-down el-icon--right"})]),i("el-dropdown-menu",{attrs:{slot:"dropdown"},slot:"dropdown"},[i("el-dropdown-item",{attrs:{command:"zh-CN"}},[e._v(e._s(e.i18nt("application.zh-CN")))]),i("el-dropdown-item",{attrs:{command:"en-US"}},[e._v(e._s(e.i18nt("application.en-US")))])],1)],1):e._e()],1)]),i("el-container",[i("el-aside",{staticClass:"side-panel"},[i("widget-panel",{attrs:{designer:e.designer}})],1),i("el-container",{staticClass:"center-layout-container"},[i("el-header",{staticClass:"toolbar-header"},[i("toolbar-panel",{ref:"toolbarRef",attrs:{designer:e.designer},scopedSlots:e._u([e._l(e.$slots,(function(t,i){return{key:i,fn:function(){return[e._t(i)]},proxy:!0}}))],null,!0)})],1),i("el-main",{staticClass:"form-widget-main"},[i("el-scrollbar",{staticClass:"container-scroll-bar",style:{height:e.scrollerHeight}},[i("v-form-widget",{ref:"formRef",attrs:{designer:e.designer,"form-config":e.designer.formConfig}})],1)],1)],1),i("el-aside",[i("setting-panel",{attrs:{designer:e.designer,"selected-widget":e.designer.selectedWidget,"form-config":e.designer.formConfig}})],1)],1)],1)},d=[],c=(i("a434"),i("d3b7"),i("159b"),function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-scrollbar",{staticClass:"side-scroll-bar",style:{height:e.scrollerHeight}},[i("div",{staticClass:"panel-container"},[i("el-tabs",{staticClass:"no-bottom-margin indent-left-margin",model:{value:e.firstTab,callback:function(t){e.firstTab=t},expression:"firstTab"}},[i("el-tab-pane",{attrs:{name:"componentLib"}},[i("span",{attrs:{slot:"label"},slot:"label"},[i("i",{staticClass:"el-icon-set-up"}),e._v(" "+e._s(e.i18nt("designer.componentLib")))]),i("el-collapse",{staticClass:"widget-collapse",model:{value:e.activeNames,callback:function(t){e.activeNames=t},expression:"activeNames"}},[i("el-collapse-item",{attrs:{name:"1",title:e.i18nt("designer.containerTitle")}},[i("draggable",{attrs:{tag:"ul",list:e.containers,group:{name:"dragGroup",pull:"clone",put:!1},clone:e.handleContainerWidgetClone,"ghost-class":"ghost",sort:!1,move:e.checkContainerMove},on:{end:e.onContainerDragEnd}},e._l(e.containers,(function(t,n){return i("li",{key:n,staticClass:"container-widget-item",attrs:{title:t.displayName},on:{dblclick:function(i){return e.addContainerByDbClick(t)}}},[i("span",[i("svg-icon",{attrs:{"icon-class":t.icon,"class-name":"color-svg-icon"}}),e._v(e._s(e.i18n2t("designer.widgetLabel."+t.type,"extension.widgetLabel."+t.type)))],1)])})),0)],1),i("el-collapse-item",{attrs:{name:"2",title:e.i18nt("designer.basicFieldTitle")}},[i("draggable",{attrs:{tag:"ul",list:e.basicFields,group:{name:"dragGroup",pull:"clone",put:!1},move:e.checkFieldMove,clone:e.handleFieldWidgetClone,"ghost-class":"ghost",sort:!1}},e._l(e.basicFields,(function(t,n){return i("li",{key:n,staticClass:"field-widget-item",attrs:{title:t.displayName},on:{dblclick:function(i){return e.addFieldByDbClick(t)}}},[i("span",[i("svg-icon",{attrs:{"icon-class":t.icon,"class-name":"color-svg-icon"}}),e._v(e._s(e.i18n2t("designer.widgetLabel."+t.type,"extension.widgetLabel."+t.type)))],1)])})),0)],1),i("el-collapse-item",{attrs:{name:"3",title:e.i18nt("designer.advancedFieldTitle")}},[i("draggable",{attrs:{tag:"ul",list:e.advancedFields,group:{name:"dragGroup",pull:"clone",put:!1},move:e.checkFieldMove,clone:e.handleFieldWidgetClone,"ghost-class":"ghost",sort:!1}},e._l(e.advancedFields,(function(t,n){return i("li",{key:n,staticClass:"field-widget-item",attrs:{title:t.displayName},on:{dblclick:function(i){return e.addFieldByDbClick(t)}}},[i("span",[i("svg-icon",{attrs:{"icon-class":t.icon,"class-name":"color-svg-icon"}}),e._v(e._s(e.i18n2t("designer.widgetLabel."+t.type,"extension.widgetLabel."+t.type)))],1)])})),0)],1),i("el-collapse-item",{attrs:{name:"4",title:e.i18nt("designer.customFieldTitle")}},[i("draggable",{attrs:{tag:"ul",list:e.customFields,group:{name:"dragGroup",pull:"clone",put:!1},move:e.checkFieldMove,clone:e.handleFieldWidgetClone,"ghost-class":"ghost",sort:!1}},e._l(e.customFields,(function(t,n){return i("li",{key:n,staticClass:"field-widget-item",attrs:{title:t.displayName},on:{dblclick:function(i){return e.addFieldByDbClick(t)}}},[i("span",[i("svg-icon",{attrs:{"icon-class":t.icon,"class-name":"color-svg-icon"}}),e._v(e._s(e.i18n2t("designer.widgetLabel."+t.type,"extension.widgetLabel."+t.type)))],1)])})),0)],1)],1)],1),e.showFormTemplates()?i("el-tab-pane",{staticStyle:{padding:"8px"},attrs:{name:"formLib"}},[i("span",{attrs:{slot:"label"},slot:"label"},[i("i",{staticClass:"el-icon-c-scale-to-original"}),e._v(" "+e._s(e.i18nt("designer.formLib")))]),e._l(e.formTemplates,(function(t,n){return[i("el-card",{key:n,staticClass:"ft-card",attrs:{"bord-style":{padding:"0"},shadow:"hover"}},[i("el-popover",{attrs:{placement:"right",trigger:"hover"}},[i("img",{staticStyle:{width:"200px"},attrs:{slot:"reference",src:t.imgUrl},slot:"reference"}),i("img",{staticStyle:{height:"600px",width:"720px"},attrs:{src:t.imgUrl}})]),i("div",{staticClass:"bottom clear-fix"},[i("span",{staticClass:"ft-title"},[e._v("#"+e._s(n+1)+" "+e._s(t.title))]),i("el-button",{staticClass:"right-button",attrs:{type:"text"},on:{click:function(i){return e.loadFormTemplate(t.jsonUrl)}}},[e._v(" "+e._s(e.i18nt("designer.hint.loadFormTemplate")))])],1)],1)]}))],2):e._e()],1)],1)])}),u=[],f=i("5530"),p=(i("4de4"),i("d81d"),i("b76a")),m=i.n(p),g=[{type:"grid",category:"container",icon:"grid",cols:[],options:{name:"",hidden:!1,gutter:12,colHeight:null,customClass:""}},{type:"table",category:"container",icon:"table",rows:[],options:{name:"",hidden:!1,customClass:""}},{type:"tab",category:"container",icon:"tab",displayType:"border-card",tabs:[],options:{name:"",hidden:!1,customClass:""}},{type:"grid-col",category:"container",icon:"grid-col",internal:!0,widgetList:[],options:{name:"",hidden:!1,span:12,offset:0,push:0,pull:0,responsive:!1,md:12,sm:12,xs:12,customClass:""}},{type:"table-cell",category:"container",icon:"table-cell",internal:!0,widgetList:[],merged:!1,options:{name:"",cellWidth:"",cellHeight:"",colspan:1,rowspan:1,customClass:""}},{type:"tab-pane",category:"container",icon:"tab-pane",internal:!0,widgetList:[],options:{name:"",label:"",hidden:!1,active:!1,disabled:!1,customClass:""}}],h=[{type:"input",icon:"text-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",type:"text",defaultValue:"",placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,clearable:!0,showPassword:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,minLength:null,maxLength:null,showWordLimit:!1,prefixIcon:"",suffixIcon:"",appendButton:!1,appendButtonDisabled:!1,buttonIcon:"el-icon-search",onCreated:"",onMounted:"",onInput:"",onChange:"",onFocus:"",onBlur:"",onValidate:"",onAppendButtonClick:""}},{type:"textarea",icon:"textarea-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",rows:3,defaultValue:"",placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,minLength:null,maxLength:null,showWordLimit:!1,onCreated:"",onMounted:"",onInput:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"number",icon:"number-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:0,placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,min:-1e11,max:1e11,precision:0,step:1,controlsPosition:"right",onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"radio",icon:"radio-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,columnWidth:"200px",size:"",displayStyle:"inline",buttonStyle:!1,border:!1,labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,optionItems:[{label:"radio 1",value:1},{label:"radio 2",value:2},{label:"radio 3",value:3}],required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"checkbox",icon:"checkbox-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:[],columnWidth:"200px",size:"",displayStyle:"inline",buttonStyle:!1,border:!1,labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,optionItems:[{label:"check 1",value:1},{label:"check 2",value:2},{label:"check 3",value:3}],required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"select",icon:"select-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:"",placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,clearable:!0,filterable:!1,allowCreate:!1,remote:!1,automaticDropdown:!1,multiple:!1,multipleLimit:0,optionItems:[{label:"select 1",value:1},{label:"select 2",value:2},{label:"select 3",value:3}],required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onRemoteQuery:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"time",icon:"time-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,clearable:!0,editable:!1,format:"HH:mm:ss",required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"time-range",icon:"time-range-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,startPlaceholder:"",endPlaceholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,clearable:!0,editable:!1,format:"HH:mm:ss",required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"date",icon:"date-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",type:"date",defaultValue:null,placeholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,clearable:!0,editable:!1,format:"yyyy-MM-dd",valueFormat:"yyyy-MM-dd",required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"date-range",icon:"date-range-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",type:"daterange",defaultValue:null,startPlaceholder:"",endPlaceholder:"",columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,readonly:!1,disabled:!1,hidden:!1,clearable:!0,editable:!1,format:"yyyy-MM-dd",valueFormat:"yyyy-MM-dd",required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}},{type:"switch",icon:"switch-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,columnWidth:"200px",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,switchWidth:40,activeText:"",inactiveText:"",activeColor:null,inactiveColor:null,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"rate",icon:"rate-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,columnWidth:"200px",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,max:5,lowThreshold:2,highThreshold:4,allowHalf:!1,showText:!1,showScore:!1,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"color",icon:"color-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:null,columnWidth:"200px",size:"",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"slider",icon:"slider-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",columnWidth:"200px",showStops:!0,size:"",labelWidth:null,labelHidden:!1,disabled:!1,hidden:!1,required:!1,requiredHint:"",validation:"",validationHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,min:0,max:100,step:10,range:!1,height:null,onCreated:"",onMounted:"",onChange:"",onValidate:""}},{type:"static-text",icon:"static-text",formItemFlag:!1,options:{name:"",columnWidth:"200px",hidden:!1,textContent:"static text",fontSize:"13px",customClass:"",onCreated:"",onMounted:""}},{type:"html-text",icon:"html-text",formItemFlag:!1,options:{name:"",columnWidth:"200px",hidden:!1,htmlContent:"html text",customClass:"",onCreated:"",onMounted:""}},{type:"button",icon:"button",formItemFlag:!1,options:{name:"",label:"",columnWidth:"200px",size:"",displayStyle:"block",disabled:!1,hidden:!1,type:"",plain:!1,round:!1,circle:!1,icon:null,customClass:"",onCreated:"",onMounted:"",onClick:""}},{type:"divider",icon:"divider",formItemFlag:!1,options:{name:"",label:"",columnWidth:"200px",direction:"horizontal",contentPosition:"center",hidden:!1,customClass:"",onCreated:"",onMounted:""}}],b=[{type:"picture-upload",icon:"picture-upload-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",labelWidth:null,labelHidden:!1,columnWidth:"200px",disabled:!1,hidden:!1,required:!1,requiredHint:"",customRule:"",customRuleHint:"",uploadURL:"",uploadTip:"",withCredentials:!1,multipleSelect:!1,showFileList:!0,limit:3,fileMaxSize:5,fileTypes:["jpg","jpeg","png"],customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onBeforeUpload:"",onUploadSuccess:"",onUploadError:"",onFileRemove:"",onValidate:""}},{type:"file-upload",icon:"file-upload-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",labelWidth:null,labelHidden:!1,columnWidth:"200px",disabled:!1,hidden:!1,required:!1,requiredHint:"",customRule:"",customRuleHint:"",uploadURL:"",uploadTip:"",withCredentials:!1,multipleSelect:!1,showFileList:!0,limit:3,fileMaxSize:5,fileTypes:["doc","docx","xls","xlsx"],customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onBeforeUpload:"",onUploadSuccess:"",onUploadError:"",onFileRemove:"",onValidate:""}},{type:"rich-editor",icon:"rich-editor-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",placeholder:"",labelWidth:null,labelHidden:!1,columnWidth:"200px",disabled:!1,hidden:!1,required:!1,requiredHint:"",customRule:"",customRuleHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,minLength:null,maxLength:null,showWordLimit:!1,onCreated:"",onMounted:"",onValidate:""}},{type:"cascader",icon:"cascader-field",formItemFlag:!0,options:{name:"",label:"",labelAlign:"",defaultValue:"",placeholder:"",size:"",labelWidth:null,labelHidden:!1,columnWidth:"200px",disabled:!1,hidden:!1,clearable:!0,filterable:!1,multiple:!1,checkStrictly:!1,optionItems:[{label:"select 1",value:1,children:[{label:"child 1",value:11}]},{label:"select 2",value:2},{label:"select 3",value:3}],required:!1,requiredHint:"",customRule:"",customRuleHint:"",customClass:"",labelIconClass:null,labelIconPosition:"rear",labelTooltip:null,onCreated:"",onMounted:"",onChange:"",onFocus:"",onBlur:"",onValidate:""}}],v=[];function w(e){g.push(e)}function y(e){v.push(e)}var C=[{title:"单列表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t1.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json1.txt",description:"表单模板详细说明..."},{title:"多列表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t2.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json2.txt",description:"表单模板详细说明..."},{title:"分组表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t3.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json3.txt",description:"表单模板详细说明..."},{title:"标签页表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t4.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json4.txt",description:"表单模板详细说明..."},{title:"主从表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t5.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json5.txt",description:"表单模板详细说明..."},{title:"响应式表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t6.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json6.txt",description:"表单模板详细说明..."},{title:"问卷调查表",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t7.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json7.txt",description:"表单模板详细说明..."},{title:"固定表格表单",imgUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t8.png",jsonUrl:"https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json8.txt",description:"表单模板详细说明..."}],x=i("ca00"),_=i("79fa"),O={name:"FieldPanel",mixins:[_["b"]],components:{Draggable:m.a},props:{designer:Object},inject:["getBannedWidgets","getDesignerConfig"],data:function(){return{designerConfig:this.getDesignerConfig(),firstTab:"componentLib",scrollerHeight:0,activeNames:["1","2","3","4"],containers:g,basicFields:h,advancedFields:b,customFields:v,formTemplates:C}},computed:{},mounted:function(){var e=this;this.loadWidgets(),this.scrollerHeight=window.innerHeight-56+"px",Object(x["a"])((function(){e.$nextTick((function(){e.scrollerHeight=window.innerHeight-56+"px"}))}))},methods:{isBanned:function(e){return this.getBannedWidgets().indexOf(e)>-1},showFormTemplates:function(){return void 0===this.designerConfig["formTemplates"]||!!this.designerConfig["formTemplates"]},loadWidgets:function(){var e=this;this.containers=this.containers.map((function(t){return Object(f["a"])(Object(f["a"])({},t),{},{displayName:e.i18n2t("designer.widgetLabel.".concat(t.type),"extension.widgetLabel.".concat(t.type))})})).filter((function(t){return!t.internal&&!e.isBanned(t.type)})),this.basicFields=this.basicFields.map((function(t){return Object(f["a"])(Object(f["a"])({},t),{},{displayName:e.i18n2t("designer.widgetLabel.".concat(t.type),"extension.widgetLabel.".concat(t.type))})})).filter((function(t){return!e.isBanned(t.type)})),this.advancedFields=this.advancedFields.map((function(t){return Object(f["a"])(Object(f["a"])({},t),{},{displayName:e.i18n2t("designer.widgetLabel.".concat(t.type),"extension.widgetLabel.".concat(t.type))})})).filter((function(t){return!e.isBanned(t.type)})),this.customFields=this.customFields.map((function(t){return Object(f["a"])(Object(f["a"])({},t),{},{displayName:e.i18n2t("designer.widgetLabel.".concat(t.type),"extension.widgetLabel.".concat(t.type))})})).filter((function(t){return!e.isBanned(t.type)}))},handleContainerWidgetClone:function(e){return this.designer.copyNewContainerWidget(e)},handleFieldWidgetClone:function(e){return this.designer.copyNewFieldWidget(e)},checkContainerMove:function(e){return this.designer.checkWidgetMove(e)},checkFieldMove:function(e){return this.designer.checkFieldMove(e)},onContainerDragEnd:function(e){},addContainerByDbClick:function(e){this.designer.addContainerByDbClick(e)},addFieldByDbClick:function(e){this.designer.addFieldByDbClick(e)},loadFormTemplate:function(e){var t=this;this.$confirm(this.i18nt("designer.hint.loadFormTemplateHint"),this.i18nt("render.hint.prompt"),{confirmButtonText:this.i18nt("render.hint.confirm"),cancelButtonText:this.i18nt("render.hint.cancel")}).then((function(){l.a.get(e).then((function(e){var i=!1;"string"===typeof e.data?i=t.designer.loadFormJson(JSON.parse(e.data)):e.data.constructor===Object&&(i=t.designer.loadFormJson(e.data)),i&&t.designer.emitHistoryChange(),t.$message.success(t.i18nt("designer.hint.loadFormTemplateSuccess"))})).catch((function(e){t.$message.error(t.i18nt("designer.hint.loadFormTemplateFailed")+":"+e)}))})).catch((function(e){console.error(e)}))}}},F=O,M=(i("d43b"),i("2877")),j=Object(M["a"])(F,c,u,!1,null,"c59cf5f6",null),L=j.exports,S=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("div",{staticClass:"toolbar-container"},[i("div",{staticClass:"left-toolbar"},[i("el-button",{attrs:{type:"text",disabled:e.undoDisabled,title:e.i18nt("designer.toolbar.undoHint")},on:{click:e.undoHistory}},[i("svg-icon",{attrs:{"icon-class":"undo"}})],1),i("el-button",{attrs:{type:"text",disabled:e.redoDisabled,title:e.i18nt("designer.toolbar.redoHint")},on:{click:e.redoHistory}},[i("svg-icon",{attrs:{"icon-class":"redo"}})],1),i("el-button-group",{staticStyle:{"margin-left":"20px"}},[i("el-button",{attrs:{type:"PC"===e.layoutType?"info":""},on:{click:function(t){return e.changeLayoutType("PC")}}},[e._v(" "+e._s(e.i18nt("designer.toolbar.pcLayout")))]),i("el-button",{attrs:{type:"Pad"===e.layoutType?"info":""},on:{click:function(t){return e.changeLayoutType("Pad")}}},[e._v(" "+e._s(e.i18nt("designer.toolbar.padLayout")))]),i("el-button",{attrs:{type:"H5"===e.layoutType?"info":""},on:{click:function(t){return e.changeLayoutType("H5")}}},[e._v(" "+e._s(e.i18nt("designer.toolbar.mobileLayout")))])],1),i("el-button",{staticStyle:{"margin-left":"20px"},attrs:{type:"",title:e.i18nt("designer.toolbar.nodeTreeHint")},on:{click:e.showNodeTreeDrawer}},[i("svg-icon",{attrs:{"icon-class":"node-tree"}})],1)],1),i("el-drawer",{staticClass:"node-tree-drawer",attrs:{title:e.i18nt("designer.toolbar.nodeTreeTitle"),direction:"ltr",visible:e.showNodeTreeDrawerFlag,modal:!1,size:280,"destroy-on-close":!0},on:{"update:visible":function(t){e.showNodeTreeDrawerFlag=t}}},[i("el-tree",{ref:"nodeTree",staticClass:"node-tree",attrs:{data:e.nodeTreeData,"node-key":"id","default-expand-all":"","highlight-current":"","icon-class":"el-icon-arrow-right"},on:{"node-click":e.onNodeTreeClick}})],1),i("div",{staticClass:"right-toolbar",style:{width:e.toolbarWidth+"px"}},[i("div",{staticClass:"right-toolbar-con"},[e.showToolButton("clearDesignerButton")?i("el-button",{attrs:{type:"text"},on:{click:e.clearFormWidget}},[i("i",{staticClass:"el-icon-delete"}),e._v(e._s(e.i18nt("designer.toolbar.clear")))]):e._e(),e.showToolButton("previewFormButton")?i("el-button",{attrs:{type:"text"},on:{click:e.previewForm}},[i("i",{staticClass:"el-icon-view"}),e._v(e._s(e.i18nt("designer.toolbar.preview")))]):e._e(),e.showToolButton("generateSFCButton")?i("el-button",{attrs:{type:"text"},on:{click:e.generateSFC}},[i("svg-icon",{attrs:{"icon-class":"vue-sfc"}}),e._v(e._s(e.i18nt("designer.toolbar.generateSFC")))],1):e._e(),e._l(e.$slots,(function(t,i){return[e._t(i)]}))],2)]),e.showPreviewDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"small-padding-dialog",attrs:{title:e.i18nt("designer.toolbar.preview"),visible:e.showPreviewDialogFlag,"show-close":!0,"close-on-click-modal":!1,"close-on-press-escape":!1,center:"","destroy-on-close":!0,"append-to-body":!0,width:"75%",fullscreen:"H5"===e.layoutType||"Pad"===e.layoutType},on:{"update:visible":function(t){e.showPreviewDialogFlag=t}}},[i("div",[i("div",{staticClass:"form-render-wrapper",class:["H5"===e.layoutType?"h5-layout":"Pad"===e.layoutType?"pad-layout":""]},[i("VFormRender",{ref:"preForm",attrs:{"form-json":e.formJson,"form-data":e.testFormData,"preview-state":!0,"option-data":e.testOptionData},on:{appendButtonClick:e.testOnAppendButtonClick,buttonClick:e.testOnButtonClick,formChange:e.handleFormChange}})],1)]),i("code-editor",{staticStyle:{display:"none"},model:{value:e.testFunc,callback:function(t){e.testFunc=t},expression:"testFunc"}}),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{attrs:{type:"primary"},on:{click:e.getFormData}},[e._v(e._s(e.i18nt("designer.hint.getFormData")))]),i("el-button",{attrs:{type:"primary"},on:{click:e.resetForm}},[e._v(e._s(e.i18nt("designer.hint.resetForm")))]),i("el-button",{attrs:{type:"primary"},on:{click:e.setFormDisabled}},[e._v(e._s(e.i18nt("designer.hint.disableForm")))]),i("el-button",{attrs:{type:"primary"},on:{click:e.setFormEnabled}},[e._v(e._s(e.i18nt("designer.hint.enableForm")))]),i("el-button",{attrs:{type:""},on:{click:function(t){e.showPreviewDialogFlag=!1}}},[e._v(e._s(e.i18nt("designer.hint.closePreview")))]),e._e(),e._e(),e._e()],1)],1):e._e(),e.showImportJsonDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"small-padding-dialog",attrs:{title:e.i18nt("designer.toolbar.importJson"),visible:e.showImportJsonDialogFlag,"show-close":!0,center:"","close-on-click-modal":!1,"close-on-press-escape":!1,"destroy-on-close":!0},on:{"update:visible":function(t){e.showImportJsonDialogFlag=t}}},[i("el-alert",{staticClass:"alert-padding",attrs:{type:"info",title:e.i18nt("designer.hint.importJsonHint"),"show-icon":""}}),i("code-editor",{attrs:{mode:"json",readonly:!1},model:{value:e.importTemplate,callback:function(t){e.importTemplate=t},expression:"importTemplate"}}),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{attrs:{type:"primary"},on:{click:e.doJsonImport}},[e._v(" "+e._s(e.i18nt("designer.hint.import")))]),i("el-button",{on:{click:function(t){e.showImportJsonDialogFlag=!1}}},[e._v(" "+e._s(e.i18nt("designer.hint.cancel")))])],1)],1):e._e(),e.showExportJsonDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"small-padding-dialog",attrs:{title:e.i18nt("designer.toolbar.exportJson"),visible:e.showExportJsonDialogFlag,"show-close":!0,center:"","close-on-click-modal":!1,"close-on-press-escape":!1,"destroy-on-close":!0},on:{"update:visible":function(t){e.showExportJsonDialogFlag=t}}},[i("code-editor",{attrs:{mode:"json",readonly:!0},model:{value:e.jsonContent,callback:function(t){e.jsonContent=t},expression:"jsonContent"}}),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{staticClass:"copy-json-btn",attrs:{type:"primary","data-clipboard-text":e.jsonRawContent},on:{click:e.copyFormJson}},[e._v(" "+e._s(e.i18nt("designer.hint.copyJson")))]),i("el-button",{on:{click:e.saveFormJson}},[e._v(e._s(e.i18nt("designer.hint.saveFormJson")))]),i("el-button",{attrs:{type:""},on:{click:function(t){e.showExportJsonDialogFlag=!1}}},[e._v(" "+e._s(e.i18nt("designer.hint.closePreview")))])],1)],1):e._e(),e.showExportCodeDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"small-padding-dialog",attrs:{title:e.i18nt("designer.toolbar.exportCode"),visible:e.showExportCodeDialogFlag,"show-close":!0,center:"",width:"65%","close-on-click-modal":!1,"close-on-press-escape":!1,"destroy-on-close":!0},on:{"update:visible":function(t){e.showExportCodeDialogFlag=t}}},[i("el-tabs",{staticClass:"no-box-shadow no-padding",attrs:{type:"border-card"},model:{value:e.activeCodeTab,callback:function(t){e.activeCodeTab=t},expression:"activeCodeTab"}},[i("el-tab-pane",{attrs:{label:"Vue",name:"vue"}},[i("code-editor",{attrs:{mode:"html",readonly:!0,"user-worker":!1},model:{value:e.vueCode,callback:function(t){e.vueCode=t},expression:"vueCode"}})],1),i("el-tab-pane",{attrs:{label:"HTML",name:"html"}},[i("code-editor",{attrs:{mode:"html",readonly:!0,"user-worker":!1},model:{value:e.htmlCode,callback:function(t){e.htmlCode=t},expression:"htmlCode"}})],1)],1),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{staticClass:"copy-vue-btn",attrs:{type:"primary","data-clipboard-text":e.vueCode},on:{click:e.copyVueCode}},[e._v(" "+e._s(e.i18nt("designer.hint.copyVueCode")))]),i("el-button",{staticClass:"copy-html-btn",attrs:{type:"primary","data-clipboard-text":e.htmlCode},on:{click:e.copyHtmlCode}},[e._v(" "+e._s(e.i18nt("designer.hint.copyHtmlCode")))]),i("el-button",{on:{click:e.saveVueCode}},[e._v(e._s(e.i18nt("designer.hint.saveVueCode")))]),i("el-button",{on:{click:e.saveHtmlCode}},[e._v(e._s(e.i18nt("designer.hint.saveHtmlCode")))]),i("el-button",{attrs:{type:""},on:{click:function(t){e.showExportCodeDialogFlag=!1}}},[e._v(" "+e._s(e.i18nt("designer.hint.closePreview")))])],1)],1):e._e(),e.showFormDataDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"dialog-title-light-bg",attrs:{title:e.i18nt("designer.hint.exportFormData"),visible:e.showFormDataDialogFlag,"show-close":!0,center:"","close-on-click-modal":!1,"close-on-press-escape":!1,"destroy-on-close":!0,"append-to-body":!0},on:{"update:visible":function(t){e.showFormDataDialogFlag=t}}},[i("div",{staticStyle:{border:"1px solid #DCDFE6"}},[i("code-editor",{attrs:{mode:"json",readonly:!0},model:{value:e.formDataJson,callback:function(t){e.formDataJson=t},expression:"formDataJson"}})],1),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{staticClass:"copy-form-data-json-btn",attrs:{type:"primary","data-clipboard-text":e.formDataRawJson},on:{click:e.copyFormDataJson}},[e._v(" "+e._s(e.i18nt("designer.hint.copyFormData")))]),i("el-button",{on:{click:e.saveFormData}},[e._v(e._s(e.i18nt("designer.hint.saveFormData")))]),i("el-button",{attrs:{type:""},on:{click:function(t){e.showFormDataDialogFlag=!1}}},[e._v(" "+e._s(e.i18nt("designer.hint.closePreview")))])],1)]):e._e(),e.showExportSFCDialogFlag?i("el-dialog",{directives:[{name:"dialog-drag",rawName:"v-dialog-drag"}],staticClass:"small-padding-dialog",attrs:{title:e.i18nt("designer.toolbar.generateSFC"),visible:e.showExportSFCDialogFlag,"show-close":!0,center:"",width:"65%","close-on-click-modal":!1,"close-on-press-escape":!1,"destroy-on-close":!0},on:{"update:visible":function(t){e.showExportSFCDialogFlag=t}}},[i("el-tabs",{staticClass:"no-box-shadow no-padding",attrs:{type:"border-card"},model:{value:e.activeSFCTab,callback:function(t){e.activeSFCTab=t},expression:"activeSFCTab"}},[i("el-tab-pane",{attrs:{label:"Vue2",name:"vue2"}},[i("code-editor",{attrs:{mode:"html",readonly:!0,"user-worker":!1},model:{value:e.sfcCode,callback:function(t){e.sfcCode=t},expression:"sfcCode"}})],1),i("el-tab-pane",{attrs:{label:"Vue3",name:"vue3"}},[i("code-editor",{attrs:{mode:"html",readonly:!0,"user-worker":!1},model:{value:e.sfcCodeV3,callback:function(t){e.sfcCodeV3=t},expression:"sfcCodeV3"}})],1)],1),i("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[i("el-button",{staticClass:"copy-vue2-sfc-btn",attrs:{type:"primary","data-clipboard-text":e.sfcCode},on:{click:e.copyV2SFC}},[e._v(" "+e._s(e.i18nt("designer.hint.copyVue2SFC")))]),i("el-button",{staticClass:"copy-vue3-sfc-btn",attrs:{type:"primary","data-clipboard-text":e.sfcCodeV3},on:{click:e.copyV3SFC}},[e._v(" "+e._s(e.i18nt("designer.hint.copyVue3SFC")))]),i("el-button",{on:{click:e.saveV2SFC}},[e._v(e._s(e.i18nt("designer.hint.saveVue2SFC")))]),i("el-button",{on:{click:e.saveV3SFC}},[e._v(e._s(e.i18nt("designer.hint.saveVue3SFC")))]),i("el-button",{attrs:{type:""},on:{click:function(t){e.showExportSFCDialogFlag=!1}}},[e._v(" "+e._s(e.i18nt("designer.hint.closePreview")))])],1)],1):e._e()],1)},k=[],W=(i("b0c0"),i("e9c4"),function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("el-form",{ref:"renderForm",staticClass:"render-form",class:[e.customClass],attrs:{"label-position":e.labelPosition,size:e.size,"label-width":e.labelWidth,"validate-on-rule-change":!1,model:e.formDataModel},nativeOn:{submit:function(e){e.preventDefault()}}},[e._l(e.widgetList,(function(t,n){return["container"===t.category?[i(e.getContainerWidgetName(t),{key:t.id,tag:"component",attrs:{widget:t,"parent-list":e.widgetList,"index-of-parent-list":n,"parent-widget":null},scopedSlots:e._u([e._l(Object.keys(e.$scopedSlots),(function(t){return{key:t,fn:function(i){return[e._t(t,null,null,i)]}}}))],null,!0)})]:[i(e.getWidgetName(t),{key:t.id,tag:"component",attrs:{field:t,"form-model":e.formDataModel,designer:null,"parent-list":e.widgetList,"index-of-parent-list":n,"parent-widget":null},scopedSlots:e._u([e._l(Object.keys(e.$scopedSlots),(function(t){return{key:t,fn:function(i){return[e._t(t,null,null,i)]}}}))],null,!0)})]]}))],2)}),E=[],D=i("2909"),I=(i("b64b"),i("c6e3")),R=(i("ddb0"),i("10ae"));R.keys().map((function(e){var t=R(e).default;n["default"].component(t.name,t)}));var T,P=i("c029"),H={name:"VFormRender",componentName:"VFormRender",mixins:[I["a"],_["b"]],components:Object(f["a"])({},P["a"]),props:{formJson:{type:Object,default:function(){return Object(x["b"])()}},formData:{type:Object,default:function(){return{}}},optionData:{type:Object,default:function(){return{}}},previewState:{type:Boolean,default:!1}},provide:function(){var e=this;return{refList:this.widgetRefList,sfRefList:this.subFormRefList,formConfig:this.formConfig,globalOptionData:this.optionData,getOptionData:function(){return e.optionData},globalModel:{formModel:this.formDataModel},previewState:this.previewState}},data:function(){return{formJsonObj:this.formJson,formDataModel:{},widgetRefList:{},subFormRefList:{},formId:null,externalComponents:{}}},computed:{formConfig:function(){return this.formJsonObj.formConfig},widgetList:function(){return this.formJsonObj.widgetList},labelPosition:function(){return this.formConfig&&this.formConfig.labelPosition?this.formConfig.labelPosition:"left"},labelWidth:function(){return this.formConfig&&this.formConfig.labelWidth?this.formConfig.labelWidth+"px":"80px"},size:function(){return this.formConfig&&this.formConfig.size?this.formConfig.size:"medium"},customClass:function(){return this.formConfig&&this.formConfig.customClass?this.formConfig.customClass:""}},watch:{},created:function(){this.buildFormModel(this.formJsonObj?this.formJsonObj.widgetList:null),this.initFormObject()},mounted:function(){this.initLocale(),this.handleOnMounted()},methods:{initFormObject:function(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.formId="vfRender"+Object(x["e"])(),e&&this.insertCustomStyleAndScriptNode(),this.addFieldChangeEventHandler(),this.addFieldValidateEventHandler(),this.registerFormToRefList(),this.handleOnCreated()},getContainerWidgetName:function(e){return e.type+"-item"},getWidgetName:function(e){return e.type+"-widget"},initLocale:function(){var e=localStorage.getItem("v_form_locale")||"zh-CN";this.changeLanguage(e)},insertCustomStyleAndScriptNode:function(){this.formConfig&&this.formConfig.cssCode&&Object(x["j"])(this.formConfig.cssCode,this.previewState?"":this.formId),this.formConfig&&this.formConfig.functions&&Object(x["k"])(this.formConfig.functions,this.previewState?"":this.formId)},buildFormModel:function(e){var t=this;e&&e.length>0&&e.forEach((function(e){t.buildDataFromWidget(e)}))},buildDataFromWidget:function(e){var t=this;if("container"===e.category)if("grid"===e.type)e.cols&&e.cols.length>0&&e.cols.forEach((function(e){t.buildDataFromWidget(e)}));else if("table"===e.type)e.rows&&e.rows.length>0&&e.rows.forEach((function(e){e.cols&&e.cols.length>0&&e.cols.forEach((function(e){t.buildDataFromWidget(e)}))}));else if("tab"===e.type)e.tabs&&e.tabs.length>0&&e.tabs.forEach((function(e){e.widgetList&&e.widgetList.length>0&&e.widgetList.forEach((function(e){t.buildDataFromWidget(e)}))}));else if("sub-form"===e.type){var i=e.options.name;if(this.formData.hasOwnProperty(i)){var n=this.formData[i];this.$set(this.formDataModel,i,Object(x["d"])(n))}else{var o={};e.options.showBlankRow?(e.widgetList.forEach((function(e){e.formItemFlag&&(o[e.options.name]=e.options.defaultValue)})),this.$set(this.formDataModel,i,[o])):this.$set(this.formDataModel,i,[])}}else"grid-col"===e.type||e.type,e.widgetList&&e.widgetList.length>0&&e.widgetList.forEach((function(e){t.buildDataFromWidget(e)}));else if(e.formItemFlag)if(this.formData.hasOwnProperty(e.options.name)){var l=this.formData[e.options.name];this.$set(this.formDataModel,e.options.name,Object(x["d"])(l))}else this.$set(this.formDataModel,e.options.name,e.options.defaultValue)},addFieldChangeEventHandler:function(){var e=this;this.$off("fieldChange"),this.$on("fieldChange",(function(t,i,n,o,l){e.handleFieldDataChange(t,i,n,o,l),e.$emit("formChange",t,i,n,e.formDataModel,o,l)}))},addFieldValidateEventHandler:function(){var e=this;this.$off("fieldValidation"),this.$on("fieldValidation",(function(t){e.$refs.renderForm.validateField(t)}))},registerFormToRefList:function(){this.widgetRefList["v_form_ref"]=this},handleFieldDataChange:function(e,t,i,n,o){if(this.formConfig&&this.formConfig.onFormDataChange){var l=new Function("fieldName","newValue","oldValue","formModel","subFormName","subFormRowIndex",this.formConfig.onFormDataChange);l.call(this,e,t,i,this.formDataModel,n,o)}},handleOnCreated:function(){if(this.formConfig&&this.formConfig.onFormCreated){var e=new Function(this.formConfig.onFormCreated);e.call(this)}},handleOnMounted:function(){if(this.formConfig&&this.formConfig.onFormMounted){var e=new Function(this.formConfig.onFormMounted);e.call(this)}},findWidgetAndSetDisabled:function(e,t){var i=this.getWidgetRef(e);i?i.setDisabled(t):this.findWidgetOfSubFormAndSetDisabled(e,t)},findWidgetOfSubFormAndSetDisabled:function(e,t){var i=this;this.findWidgetNameInSubForm(e).forEach((function(e){var n=i.getWidgetRef(e);n&&n.setDisabled(t)}))},findWidgetAndSetHidden:function(e,t){var i=this.getWidgetRef(e);i?i.setHidden(t):this.findWidgetOfSubFormAndSetHidden(e,t)},findWidgetOfSubFormAndSetHidden:function(e,t){var i=this;this.findWidgetNameInSubForm(e).forEach((function(e){var n=i.getWidgetRef(e);n&&n.setHidden(t)}))},findWidgetNameInSubForm:function(e){var t=[],i=null,n=function(t,n){t.options&&t.options.name===e&&(i=n.options.name)};if(Object(x["s"])(this.widgetList,n),i){var o=this.getWidgetRef(i);if(o){var l=o.getRowIdData();l&&l.length>0&&l.forEach((function(i){t.push(e+"@row"+i)}))}}return t},changeLanguage:function(e){Object(_["a"])(e)},getNativeForm:function(){return this.$refs["renderForm"]},getWidgetRef:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=this.widgetRefList[e];return!i&&t&&this.$message.error(this.i18nt("render.hint.refNotFound")+e),i},clearFormDataModel:function(){for(var e in this.formDataModel)delete this.formDataModel[e]},setFormJson:function(e){var t=this;if(e)if("string"===typeof e||e.constructor===Object){var i=null;if(i="string"===typeof e?JSON.parse(e):e,!i.formConfig||!i.widgetList)return void this.$message.error("Invalid format of form json.");this.clearFormDataModel(),this.buildFormModel(i.widgetList),this.$set(this.formJsonObj,"formConfig",i.formConfig),this._provided.formConfig=i.formConfig,this.$set(this.formJsonObj,"widgetList",i.widgetList),this.insertCustomStyleAndScriptNode(),this.$nextTick((function(){t.initFormObject(!1),t.handleOnMounted()}))}else this.$message.error("Set form json failed.")},reloadOptionData:function(e){var t=[];e&&"string"===typeof e?t=[e]:e&&Array.isArray(e)&&(t=Object(D["a"])(e)),this.broadcast("FieldWidget","reloadOptionItems",[t])},getFormData:function(){var e=this,t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(!t)return this.formDataModel;var i=function(){},n=new window.Promise((function(e,t){i=function(i,n){n?t(n):e(i)}}));return this.$refs["renderForm"].validate((function(t){t?i(e.formDataModel):i(e.formDataModel,e.i18nt("render.hint.validationFailed"))})),n},setFormData:function(e){var t=this;Object.keys(this.formDataModel).forEach((function(i){e&&e.hasOwnProperty(i)&&(t.formDataModel[i]=Object(x["d"])(e[i]))})),this.broadcast("ContainerItem","setFormData",this.formDataModel),this.broadcast("FieldWidget","setFormData",this.formDataModel)},getFieldValue:function(e){var t=this,i=this.getWidgetRef(e);if(i&&i.getValue)return i.getValue();if(!i){var n=[];return this.findWidgetNameInSubForm(e).forEach((function(e){var i=t.getWidgetRef(e);i&&i.getValue&&n.push(i.getValue())})),n}},setFieldValue:function(e,t){var i=this,n=this.getWidgetRef(e);n&&n.setValue&&n.setValue(t),n||this.findWidgetNameInSubForm(e).forEach((function(e){var n=i.getWidgetRef(e);n&&n.setValue&&n.setValue(t)}))},getSubFormValues:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=this.subFormRefList[e];return i.getSubFormValues(t)},setSubFormValues:function(e,t){},disableForm:function(){var e=this,t=Object.keys(this.widgetRefList);t.forEach((function(t){var i=e.getWidgetRef(t);i&&(i.widget&&"sub-form"===i.widget.type?i.disableSubForm():i.setDisabled&&i.setDisabled(!0))}))},enableForm:function(){var e=this,t=Object.keys(this.widgetRefList);t.forEach((function(t){var i=e.getWidgetRef(t);i&&(i.widget&&"sub-form"===i.widget.type?i.enableSubForm():i.setDisabled&&i.setDisabled(!1))}))},resetForm:function(){var e=this,t=Object.keys(this.subFormRefList);t.forEach((function(t){e.subFormRefList[t].resetSubForm&&e.subFormRefList[t].resetSubForm()}));var i=Object.keys(this.widgetRefList);i.forEach((function(t){var i=e.getWidgetRef(t);i&&!i.subFormItemFlag&&i.resetField&&i.resetField()})),this.$nextTick((function(){e.clearValidate()}))},clearValidate:function(e){this.$refs.renderForm.clearValidate(e)},validateForm:function(e){this.$refs["renderForm"].validate((function(t){e(t)}))},validateFields:function(){},disableWidgets:function(e){var t=this;e&&("string"===typeof e?this.findWidgetAndSetDisabled(e,!0):Array.isArray(e)&&e.forEach((function(e){t.findWidgetAndSetDisabled(e,!0)})))},enableWidgets:function(e){var t=this;e&&("string"===typeof e?this.findWidgetAndSetDisabled(e,!1):Array.isArray(e)&&e.forEach((function(e){t.findWidgetAndSetDisabled(e,!1)})))},hideWidgets:function(e){var t=this;e&&("string"===typeof e?this.findWidgetAndSetHidden(e,!0):Array.isArray(e)&&e.forEach((function(e){t.findWidgetAndSetHidden(e,!0)})))},showWidgets:function(e){var t=this;e&&("string"===typeof e?this.findWidgetAndSetHidden(e,!1):Array.isArray(e)&&e.forEach((function(e){t.findWidgetAndSetHidden(e,!1)})))},getFieldWidgets:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return e?Object(x["g"])(e):Object(x["g"])(this.formJsonObj.widgetList)},getContainerWidgets:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return e?Object(x["f"])(e):Object(x["f"])(this.formJsonObj.widgetList)},addEC:function(e,t){this.externalComponents[e]=t},hasEC:function(e){return this.externalComponents.hasOwnProperty(e)},getEC:function(e){return this.externalComponents[e]}}},N=H,$=(i("5a4b"),Object(M["a"])(N,W,E,!1,null,"70ce788c",null)),V=$.exports,A=i("9470"),B=i("b311"),z=i.n(B),U=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"vue",i=JSON.stringify(e);return"html"===t?'\n\n\n\t\n\t\n\tVForm Demo\n\t\n\t\n\t\n\n\n\n
\n\t \n \n\t Submit\n
\n\n + + + + + + + + +
+ + + diff --git a/resource/plug_template/api/api.go.tpl b/resource/plug_template/api/api.go.tpl new file mode 100644 index 0000000..dacaafc --- /dev/null +++ b/resource/plug_template/api/api.go.tpl @@ -0,0 +1,35 @@ +package api + +import ( + "miniapp/global" + "miniapp/model/common/response" +{{ if .NeedModel }} "miniapp/plugin/{{ .Snake}}/model" {{ end }} + "miniapp/plugin/{{ .Snake}}/service" + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type {{ .PlugName}}Api struct{} + +// @Tags {{ .PlugName}} +// @Summary 请手动填写接口功能 +// @Produce application/json +// @Success 200 {string} string "{"success":true,"data":{},"msg":"发送成功"}" +// @Router /{{ .RouterGroup}}/routerName [post] +func (p *{{ .PlugName}}Api) ApiName(c *gin.Context) { + {{ if .HasRequest}} + var plug model.Request + _ = c.ShouldBindJSON(&plug) + {{ end }} + if {{ if .HasResponse }} res, {{ end }} err:= service.ServiceGroupApp.PlugService({{ if .HasRequest }}plug{{ end -}}); err != nil { + global.GVA_LOG.Error("失败!", zap.Error(err)) + response.FailWithMessage("失败", c) + } else { + {{if .HasResponse }} + response.OkWithDetailed(res,"成功",c) + {{else}} + response.OkWithData("成功", c) + {{ end -}} + + } +} diff --git a/resource/plug_template/api/enter.go.tpl b/resource/plug_template/api/enter.go.tpl new file mode 100644 index 0000000..ca5687c --- /dev/null +++ b/resource/plug_template/api/enter.go.tpl @@ -0,0 +1,7 @@ +package api + +type ApiGroup struct { + {{ .PlugName}}Api +} + +var ApiGroupApp = new(ApiGroup) diff --git a/resource/plug_template/config/config.go.tpl b/resource/plug_template/config/config.go.tpl new file mode 100644 index 0000000..0bd87bc --- /dev/null +++ b/resource/plug_template/config/config.go.tpl @@ -0,0 +1,9 @@ +package config + +{{- if .HasGlobal }} +type {{ .PlugName }} struct { + {{- range .Global }} + {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}} + {{- end }} +} +{{ end -}} \ No newline at end of file diff --git a/resource/plug_template/global/global.go.tpl b/resource/plug_template/global/global.go.tpl new file mode 100644 index 0000000..82822e8 --- /dev/null +++ b/resource/plug_template/global/global.go.tpl @@ -0,0 +1,8 @@ +package global + +{{- if .HasGlobal }} + +import "miniapp/plugin/{{ .Snake}}/config" + +var GlobalConfig = new(config.{{ .PlugName}}) +{{ end -}} \ No newline at end of file diff --git a/resource/plug_template/main.go.tpl b/resource/plug_template/main.go.tpl new file mode 100644 index 0000000..dd899c0 --- /dev/null +++ b/resource/plug_template/main.go.tpl @@ -0,0 +1,29 @@ +package {{ .Snake}} + +import ( +{{- if .HasGlobal }} + "miniapp/plugin/{{ .Snake}}/global" +{{- end }} + "miniapp/plugin/{{ .Snake}}/router" + "github.com/gin-gonic/gin" +) + +type {{ .PlugName}}Plugin struct { +} + +func Create{{ .PlugName}}Plug({{- range .Global}} {{.Key}} {{.Type}}, {{- end }})*{{ .PlugName}}Plugin { +{{- if .HasGlobal }} + {{- range .Global}} + global.GlobalConfig.{{.Key}} = {{.Key}} + {{- end }} +{{ end }} + return &{{ .PlugName}}Plugin{} +} + +func (*{{ .PlugName}}Plugin) Register(group *gin.RouterGroup) { + router.RouterGroupApp.Init{{ .PlugName}}Router(group) +} + +func (*{{ .PlugName}}Plugin) RouterPath() string { + return "{{ .RouterGroup}}" +} diff --git a/resource/plug_template/model/model.go.tpl b/resource/plug_template/model/model.go.tpl new file mode 100644 index 0000000..137f147 --- /dev/null +++ b/resource/plug_template/model/model.go.tpl @@ -0,0 +1,17 @@ +package model + +{{- if .HasRequest }} +type Request struct { + {{- range .Request }} + {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}} + {{- end }} +} +{{ end -}} + +{{- if .HasResponse }} +type Response struct { + {{- range .Response }} + {{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}} + {{- end }} +} +{{ end -}} diff --git a/resource/plug_template/router/enter.go.tpl b/resource/plug_template/router/enter.go.tpl new file mode 100644 index 0000000..70a9d6c --- /dev/null +++ b/resource/plug_template/router/enter.go.tpl @@ -0,0 +1,7 @@ +package router + +type RouterGroup struct { + {{ .PlugName}}Router +} + +var RouterGroupApp = new(RouterGroup) diff --git a/resource/plug_template/router/router.go.tpl b/resource/plug_template/router/router.go.tpl new file mode 100644 index 0000000..fb93bc8 --- /dev/null +++ b/resource/plug_template/router/router.go.tpl @@ -0,0 +1,17 @@ +package router + +import ( + "miniapp/plugin/{{ .Snake}}/api" + "github.com/gin-gonic/gin" +) + +type {{ .PlugName}}Router struct { +} + +func (s *{{ .PlugName}}Router) Init{{ .PlugName}}Router(Router *gin.RouterGroup) { + plugRouter := Router + plugApi := api.ApiGroupApp.{{ .PlugName}}Api + { + plugRouter.POST("routerName", plugApi.ApiName) + } +} diff --git a/resource/plug_template/service/enter.go.tpl b/resource/plug_template/service/enter.go.tpl new file mode 100644 index 0000000..5f9e425 --- /dev/null +++ b/resource/plug_template/service/enter.go.tpl @@ -0,0 +1,7 @@ +package service + +type ServiceGroup struct { + {{ .PlugName}}Service +} + +var ServiceGroupApp = new(ServiceGroup) diff --git a/resource/plug_template/service/service.go.tpl b/resource/plug_template/service/service.go.tpl new file mode 100644 index 0000000..13de626 --- /dev/null +++ b/resource/plug_template/service/service.go.tpl @@ -0,0 +1,14 @@ +package service + + {{- if .NeedModel }} +import ( + "miniapp/plugin/{{ .Snake}}/model" +) +{{ end }} + +type {{ .PlugName}}Service struct{} + +func (e *{{ .PlugName}}Service) PlugService({{- if .HasRequest }}req model.Request {{ end -}}) ({{- if .HasResponse }}res model.Response,{{ end -}} err error) { + // 写你的业务逻辑 + return {{- if .HasResponse }} res,{{ end }} nil +} diff --git a/router/app/enter.go b/router/app/enter.go new file mode 100644 index 0000000..2cedc36 --- /dev/null +++ b/router/app/enter.go @@ -0,0 +1,8 @@ +package app + +type RouterGroup struct { + UserRouter + LoginRouter + FavoriteRouter + VisionRouter +} diff --git a/router/app/favorite.go b/router/app/favorite.go new file mode 100644 index 0000000..e24e438 --- /dev/null +++ b/router/app/favorite.go @@ -0,0 +1,21 @@ +package app + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type FavoriteRouter struct{} + +func (s *FavoriteRouter) InitFavoriteRouter(Router *gin.RouterGroup) { + favoriteRouter := Router.Group("favorite").Use(middleware.AuthorizeToken()) + //publicRouter := Router.Group("user") + baseApi := v1.ApiGroupApp.AppApiGroup.FavoriteApi + { + favoriteRouter.POST("", baseApi.Create) + favoriteRouter.DELETE("", baseApi.Delete) + favoriteRouter.GET("list", baseApi.GetList) + } + +} diff --git a/router/app/login.go b/router/app/login.go new file mode 100644 index 0000000..6133de0 --- /dev/null +++ b/router/app/login.go @@ -0,0 +1,20 @@ +package app + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type LoginRouter struct{} + +func (s *LoginRouter) InitLoginRouter(Router *gin.RouterGroup) { + loginRouter := Router.Group("login") + baseApi := v1.ApiGroupApp.AppApiGroup.LoginApi + { + loginRouter.GET("wechat/token", baseApi.GetWeChatToken) + loginRouter.POST("token", baseApi.Login) + loginRouter.POST("token/refresh", baseApi.Refresh) + loginRouter.POST("token/logout", baseApi.Logout) + } + +} diff --git a/router/app/user.go b/router/app/user.go new file mode 100644 index 0000000..2b197ab --- /dev/null +++ b/router/app/user.go @@ -0,0 +1,30 @@ +package app + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type UserRouter struct { +} + +func (s *LoginRouter) InitUserRouter(Router *gin.RouterGroup) { + userRouter := Router.Group("user").Use(middleware.AuthorizeToken()) + //publicRouter := Router.Group("user") + baseApi := v1.ApiGroupApp.AppApiGroup.UserApi + filrApi := v1.ApiGroupApp.ExampleApiGroup.FileUploadAndDownloadApi + todoApi := v1.ApiGroupApp.AppApiGroup.TodosApi + { + userRouter.POST("upload", filrApi.UploadFile) + userRouter.POST("binding/wechat", baseApi.BindingWeChat) + userRouter.PUT("info", baseApi.UpdateUser) + userRouter.GET("info", baseApi.GetInfo) + userRouter.PUT("hospital", baseApi.UpdateUserHospital) + userRouter.GET("", baseApi.GetUser) + userRouter.GET("todo", todoApi.GetUserTodos) + userRouter.PUT("todo", todoApi.UpdateTodo) + + } + +} diff --git a/router/app/vision.go b/router/app/vision.go new file mode 100644 index 0000000..9e24e39 --- /dev/null +++ b/router/app/vision.go @@ -0,0 +1,21 @@ +package app + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type VisionRouter struct{} + +func (s *VisionRouter) InitVisionRouter(Router *gin.RouterGroup) { + userRouter := Router.Group("vision").Use(middleware.AuthorizeToken()) + //publicRouter := Router.Group("user") + baseApi := v1.ApiGroupApp.AppApiGroup.VisionApi + { + userRouter.GET("", baseApi.GetList) + userRouter.POST("", baseApi.Create) + + } + +} diff --git a/router/enter.go b/router/enter.go new file mode 100644 index 0000000..b838a5c --- /dev/null +++ b/router/enter.go @@ -0,0 +1,15 @@ +package router + +import ( + "miniapp/router/app" + "miniapp/router/example" + "miniapp/router/system" +) + +type RouterGroup struct { + System system.RouterGroup + Example example.RouterGroup + App app.RouterGroup +} + +var RouterGroupApp = new(RouterGroup) diff --git a/router/example/enter.go b/router/example/enter.go new file mode 100644 index 0000000..b1798c9 --- /dev/null +++ b/router/example/enter.go @@ -0,0 +1,6 @@ +package example + +type RouterGroup struct { + CustomerRouter + FileUploadAndDownloadRouter +} diff --git a/router/example/exa_customer.go b/router/example/exa_customer.go new file mode 100644 index 0000000..a9dc9cc --- /dev/null +++ b/router/example/exa_customer.go @@ -0,0 +1,24 @@ +package example + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type CustomerRouter struct{} + +func (e *CustomerRouter) InitCustomerRouter(Router *gin.RouterGroup) { + customerRouter := Router.Group("customer").Use(middleware.OperationRecord()) + customerRouterWithoutRecord := Router.Group("customer") + exaCustomerApi := v1.ApiGroupApp.ExampleApiGroup.CustomerApi + { + customerRouter.POST("customer", exaCustomerApi.CreateExaCustomer) // 创建客户 + customerRouter.PUT("customer", exaCustomerApi.UpdateExaCustomer) // 更新客户 + customerRouter.DELETE("customer", exaCustomerApi.DeleteExaCustomer) // 删除客户 + } + { + customerRouterWithoutRecord.GET("customer", exaCustomerApi.GetExaCustomer) // 获取单一客户信息 + customerRouterWithoutRecord.GET("customerList", exaCustomerApi.GetExaCustomerList) // 获取客户列表 + } +} diff --git a/router/example/exa_file_upload_and_download.go b/router/example/exa_file_upload_and_download.go new file mode 100644 index 0000000..2eb2b0d --- /dev/null +++ b/router/example/exa_file_upload_and_download.go @@ -0,0 +1,23 @@ +package example + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type FileUploadAndDownloadRouter struct{} + +func (e *FileUploadAndDownloadRouter) InitFileUploadAndDownloadRouter(Router *gin.RouterGroup) { + fileUploadAndDownloadRouter := Router.Group("fileUploadAndDownload") + exaFileUploadAndDownloadApi := v1.ApiGroupApp.ExampleApiGroup.FileUploadAndDownloadApi + { + fileUploadAndDownloadRouter.POST("upload", exaFileUploadAndDownloadApi.UploadFile) // 上传文件 + fileUploadAndDownloadRouter.POST("getFileList", exaFileUploadAndDownloadApi.GetFileList) // 获取上传文件列表 + fileUploadAndDownloadRouter.POST("deleteFile", exaFileUploadAndDownloadApi.DeleteFile) // 删除指定文件 + fileUploadAndDownloadRouter.POST("editFileName", exaFileUploadAndDownloadApi.EditFileName) // 编辑文件名或者备注 + fileUploadAndDownloadRouter.POST("breakpointContinue", exaFileUploadAndDownloadApi.BreakpointContinue) // 断点续传 + fileUploadAndDownloadRouter.GET("findFile", exaFileUploadAndDownloadApi.FindFile) // 查询当前文件成功的切片 + fileUploadAndDownloadRouter.POST("breakpointContinueFinish", exaFileUploadAndDownloadApi.BreakpointContinueFinish) // 切片传输完成 + fileUploadAndDownloadRouter.POST("removeChunk", exaFileUploadAndDownloadApi.RemoveChunk) // 删除切片 + } +} diff --git a/router/system/article.go b/router/system/article.go new file mode 100644 index 0000000..36ddda5 --- /dev/null +++ b/router/system/article.go @@ -0,0 +1,28 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type ArticleRouter struct { +} + +// InitArticleRouter 注册Banner路由 +func (s *BannerRouter) InitArticleRouter(Router *gin.RouterGroup) { + articleRouter := Router.Group("article").Use(middleware.OperationRecord()).Use(middleware.JWTAuth()) + publicRouter := Router.Group("article") + bannerApi := v1.ApiGroupApp.SystemApiGroup.ArticleApi + + { + articleRouter.POST("", bannerApi.CreateArticle) // 新建文章 + articleRouter.DELETE("", bannerApi.DeleteArticle) // 删除文章 + articleRouter.PUT("", bannerApi.UpdateArticle) // 更新文章 + + } + { + publicRouter.GET("list", bannerApi.GetArticleList) // 获取医院列表 + publicRouter.GET(":id", bannerApi.GetArticleById) // 获取单条医院消息 + } +} diff --git a/router/system/banner.go b/router/system/banner.go new file mode 100644 index 0000000..2c90647 --- /dev/null +++ b/router/system/banner.go @@ -0,0 +1,28 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type BannerRouter struct { +} + +// InitBannerRouter 注册Banner路由 +func (s *BannerRouter) InitBannerRouter(Router *gin.RouterGroup) { + hospitalRouter := Router.Group("banner").Use(middleware.OperationRecord()).Use(middleware.JWTAuth()) + publicRouter := Router.Group("banner") + bannerApi := v1.ApiGroupApp.SystemApiGroup.BannerApi + + { + hospitalRouter.POST("", bannerApi.CreateBanner) // 创建医院 + hospitalRouter.DELETE("", bannerApi.DeleteBanner) // 删除医院 + hospitalRouter.PUT("", bannerApi.UpdateBanner) // 更新医院 + + } + { + publicRouter.GET("list", bannerApi.GetBannerList) // 获取医院列表 + publicRouter.GET(":id", bannerApi.GetBannerById) // 获取单条医院消息 + } +} diff --git a/router/system/enter.go b/router/system/enter.go new file mode 100644 index 0000000..257128e --- /dev/null +++ b/router/system/enter.go @@ -0,0 +1,22 @@ +package system + +type RouterGroup struct { + ApiRouter + JwtRouter + SysRouter + BaseRouter + InitRouter + MenuRouter + UserRouter + CasbinRouter + AutoCodeRouter + AuthorityRouter + DictionaryRouter + OperationRecordRouter + DictionaryDetailRouter + AuthorityBtnRouter + ChatGptRouter + HospitalRouter + BannerRouter + ArticleRouter +} diff --git a/router/system/hospital.go b/router/system/hospital.go new file mode 100644 index 0000000..a47c5b1 --- /dev/null +++ b/router/system/hospital.go @@ -0,0 +1,28 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type HospitalRouter struct { +} + +// InitHospitalRouter 注册医院路由 +func (s *RouterGroup) InitHospitalRouter(Router *gin.RouterGroup) { + hospitalRouter := Router.Group("hospital").Use(middleware.OperationRecord()).Use(middleware.JWTAuth()) + publicRouter := Router.Group("hospital") + hospitalApi := v1.ApiGroupApp.SystemApiGroup.HospitalApi + + { + hospitalRouter.POST("", hospitalApi.CreateHospital) // 创建医院 + hospitalRouter.DELETE("", hospitalApi.DeleteHospital) // 删除医院 + hospitalRouter.PUT("", hospitalApi.UpdateHospital) // 更新医院 + + } + { + publicRouter.GET("list", hospitalApi.GetHospitalList) // 获取医院列表 + publicRouter.GET(":id", hospitalApi.GetHospitalById) // 获取单条医院消息 + } +} diff --git a/router/system/sys_api.go b/router/system/sys_api.go new file mode 100644 index 0000000..a0ed203 --- /dev/null +++ b/router/system/sys_api.go @@ -0,0 +1,31 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type ApiRouter struct{} + +func (s *ApiRouter) InitApiRouter(Router *gin.RouterGroup, RouterPub *gin.RouterGroup) { + apiRouter := Router.Group("api").Use(middleware.OperationRecord()) + apiRouterWithoutRecord := Router.Group("api") + + apiPublicRouterWithoutRecord := RouterPub.Group("api") + apiRouterApi := v1.ApiGroupApp.SystemApiGroup.SystemApiApi + { + apiRouter.POST("createApi", apiRouterApi.CreateApi) // 创建Api + apiRouter.POST("deleteApi", apiRouterApi.DeleteApi) // 删除Api + apiRouter.POST("getApiById", apiRouterApi.GetApiById) // 获取单条Api消息 + apiRouter.POST("updateApi", apiRouterApi.UpdateApi) // 更新api + apiRouter.DELETE("deleteApisByIds", apiRouterApi.DeleteApisByIds) // 删除选中api + } + { + apiRouterWithoutRecord.POST("getAllApis", apiRouterApi.GetAllApis) // 获取所有api + apiRouterWithoutRecord.POST("getApiList", apiRouterApi.GetApiList) // 获取Api列表 + } + { + apiPublicRouterWithoutRecord.GET("freshCasbin", apiRouterApi.FreshCasbin) // 刷新casbin权限 + } +} diff --git a/router/system/sys_authority.go b/router/system/sys_authority.go new file mode 100644 index 0000000..d8f527e --- /dev/null +++ b/router/system/sys_authority.go @@ -0,0 +1,25 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type AuthorityRouter struct{} + +func (s *AuthorityRouter) InitAuthorityRouter(Router *gin.RouterGroup) { + authorityRouter := Router.Group("authority").Use(middleware.OperationRecord()) + authorityRouterWithoutRecord := Router.Group("authority") + authorityApi := v1.ApiGroupApp.SystemApiGroup.AuthorityApi + { + authorityRouter.POST("createAuthority", authorityApi.CreateAuthority) // 创建角色 + authorityRouter.POST("deleteAuthority", authorityApi.DeleteAuthority) // 删除角色 + authorityRouter.PUT("updateAuthority", authorityApi.UpdateAuthority) // 更新角色 + authorityRouter.POST("copyAuthority", authorityApi.CopyAuthority) // 拷贝角色 + authorityRouter.POST("setDataAuthority", authorityApi.SetDataAuthority) // 设置角色资源权限 + } + { + authorityRouterWithoutRecord.POST("getAuthorityList", authorityApi.GetAuthorityList) // 获取角色列表 + } +} diff --git a/router/system/sys_authority_btn.go b/router/system/sys_authority_btn.go new file mode 100644 index 0000000..31f179a --- /dev/null +++ b/router/system/sys_authority_btn.go @@ -0,0 +1,19 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type AuthorityBtnRouter struct{} + +func (s *AuthorityBtnRouter) InitAuthorityBtnRouterRouter(Router *gin.RouterGroup) { + //authorityRouter := Router.Group("authorityBtn").Use(middleware.OperationRecord()) + authorityRouterWithoutRecord := Router.Group("authorityBtn") + authorityBtnApi := v1.ApiGroupApp.SystemApiGroup.AuthorityBtnApi + { + authorityRouterWithoutRecord.POST("getAuthorityBtn", authorityBtnApi.GetAuthorityBtn) + authorityRouterWithoutRecord.POST("setAuthorityBtn", authorityBtnApi.SetAuthorityBtn) + authorityRouterWithoutRecord.POST("canRemoveAuthorityBtn", authorityBtnApi.CanRemoveAuthorityBtn) + } +} diff --git a/router/system/sys_auto_code.go b/router/system/sys_auto_code.go new file mode 100644 index 0000000..fe3ca3c --- /dev/null +++ b/router/system/sys_auto_code.go @@ -0,0 +1,26 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type AutoCodeRouter struct{} + +func (s *AutoCodeRouter) InitAutoCodeRouter(Router *gin.RouterGroup) { + autoCodeRouter := Router.Group("autoCode") + autoCodeApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeApi + { + autoCodeRouter.GET("getDB", autoCodeApi.GetDB) // 获取数据库 + autoCodeRouter.GET("getTables", autoCodeApi.GetTables) // 获取对应数据库的表 + autoCodeRouter.GET("getColumn", autoCodeApi.GetColumn) // 获取指定表所有字段信息 + autoCodeRouter.POST("preview", autoCodeApi.PreviewTemp) // 获取自动创建代码预览 + autoCodeRouter.POST("createTemp", autoCodeApi.CreateTemp) // 创建自动化代码 + autoCodeRouter.POST("createPackage", autoCodeApi.CreatePackage) // 创建package包 + autoCodeRouter.POST("getPackage", autoCodeApi.GetPackage) // 获取package包 + autoCodeRouter.POST("delPackage", autoCodeApi.DelPackage) // 删除package包 + autoCodeRouter.POST("createPlug", autoCodeApi.AutoPlug) // 自动插件包模板 + autoCodeRouter.POST("installPlugin", autoCodeApi.InstallPlugin) // 自动安装插件 + autoCodeRouter.POST("pubPlug", autoCodeApi.PubPlug) // 打包插件 + } +} diff --git a/router/system/sys_auto_code_history.go b/router/system/sys_auto_code_history.go new file mode 100644 index 0000000..a715226 --- /dev/null +++ b/router/system/sys_auto_code_history.go @@ -0,0 +1,19 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type AutoCodeHistoryRouter struct{} + +func (s *AutoCodeRouter) InitAutoCodeHistoryRouter(Router *gin.RouterGroup) { + autoCodeHistoryRouter := Router.Group("autoCode") + autoCodeHistoryApi := v1.ApiGroupApp.SystemApiGroup.AutoCodeHistoryApi + { + autoCodeHistoryRouter.POST("getMeta", autoCodeHistoryApi.First) // 根据id获取meta信息 + autoCodeHistoryRouter.POST("rollback", autoCodeHistoryApi.RollBack) // 回滚 + autoCodeHistoryRouter.POST("delSysHistory", autoCodeHistoryApi.Delete) // 删除回滚记录 + autoCodeHistoryRouter.POST("getSysHistory", autoCodeHistoryApi.GetList) // 获取回滚记录分页 + } +} diff --git a/router/system/sys_base.go b/router/system/sys_base.go new file mode 100644 index 0000000..65e424b --- /dev/null +++ b/router/system/sys_base.go @@ -0,0 +1,18 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type BaseRouter struct{} + +func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) (R gin.IRoutes) { + baseRouter := Router.Group("base") + baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi + { + baseRouter.POST("login", baseApi.Login) + baseRouter.POST("captcha", baseApi.Captcha) + } + return baseRouter +} diff --git a/router/system/sys_casbin.go b/router/system/sys_casbin.go new file mode 100644 index 0000000..db4b24d --- /dev/null +++ b/router/system/sys_casbin.go @@ -0,0 +1,21 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type CasbinRouter struct{} + +func (s *CasbinRouter) InitCasbinRouter(Router *gin.RouterGroup) { + casbinRouter := Router.Group("casbin").Use(middleware.OperationRecord()) + casbinRouterWithoutRecord := Router.Group("casbin") + casbinApi := v1.ApiGroupApp.SystemApiGroup.CasbinApi + { + casbinRouter.POST("updateCasbin", casbinApi.UpdateCasbin) + } + { + casbinRouterWithoutRecord.POST("getPolicyPathByAuthorityId", casbinApi.GetPolicyPathByAuthorityId) + } +} diff --git a/router/system/sys_chatgpt.go b/router/system/sys_chatgpt.go new file mode 100644 index 0000000..378b668 --- /dev/null +++ b/router/system/sys_chatgpt.go @@ -0,0 +1,20 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type ChatGptRouter struct{} + +func (s *ChatGptRouter) InitChatGptRouter(Router *gin.RouterGroup) { + chatGptRouter := Router.Group("chatGpt").Use(middleware.OperationRecord()) + chatGptApi := v1.ApiGroupApp.SystemApiGroup.ChatGptApi + { + chatGptRouter.POST("createSK", chatGptApi.CreateSK) + chatGptRouter.GET("getSK", chatGptApi.GetSK) + chatGptRouter.DELETE("deleteSK", chatGptApi.DeleteSK) + chatGptRouter.POST("getTable", chatGptApi.GetTable) + } +} diff --git a/router/system/sys_dictionary.go b/router/system/sys_dictionary.go new file mode 100644 index 0000000..7e54309 --- /dev/null +++ b/router/system/sys_dictionary.go @@ -0,0 +1,24 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type DictionaryRouter struct{} + +func (s *DictionaryRouter) InitSysDictionaryRouter(Router *gin.RouterGroup) { + sysDictionaryRouter := Router.Group("sysDictionary").Use(middleware.OperationRecord()) + sysDictionaryRouterWithoutRecord := Router.Group("sysDictionary") + sysDictionaryApi := v1.ApiGroupApp.SystemApiGroup.DictionaryApi + { + sysDictionaryRouter.POST("createSysDictionary", sysDictionaryApi.CreateSysDictionary) // 新建SysDictionary + sysDictionaryRouter.DELETE("deleteSysDictionary", sysDictionaryApi.DeleteSysDictionary) // 删除SysDictionary + sysDictionaryRouter.PUT("updateSysDictionary", sysDictionaryApi.UpdateSysDictionary) // 更新SysDictionary + } + { + sysDictionaryRouterWithoutRecord.GET("findSysDictionary", sysDictionaryApi.FindSysDictionary) // 根据ID获取SysDictionary + sysDictionaryRouterWithoutRecord.GET("getSysDictionaryList", sysDictionaryApi.GetSysDictionaryList) // 获取SysDictionary列表 + } +} diff --git a/router/system/sys_dictionary_detail.go b/router/system/sys_dictionary_detail.go new file mode 100644 index 0000000..1d39b0d --- /dev/null +++ b/router/system/sys_dictionary_detail.go @@ -0,0 +1,24 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type DictionaryDetailRouter struct{} + +func (s *DictionaryDetailRouter) InitSysDictionaryDetailRouter(Router *gin.RouterGroup) { + dictionaryDetailRouter := Router.Group("sysDictionaryDetail").Use(middleware.OperationRecord()) + dictionaryDetailRouterWithoutRecord := Router.Group("sysDictionaryDetail") + sysDictionaryDetailApi := v1.ApiGroupApp.SystemApiGroup.DictionaryDetailApi + { + dictionaryDetailRouter.POST("createSysDictionaryDetail", sysDictionaryDetailApi.CreateSysDictionaryDetail) // 新建SysDictionaryDetail + dictionaryDetailRouter.DELETE("deleteSysDictionaryDetail", sysDictionaryDetailApi.DeleteSysDictionaryDetail) // 删除SysDictionaryDetail + dictionaryDetailRouter.PUT("updateSysDictionaryDetail", sysDictionaryDetailApi.UpdateSysDictionaryDetail) // 更新SysDictionaryDetail + } + { + dictionaryDetailRouterWithoutRecord.GET("findSysDictionaryDetail", sysDictionaryDetailApi.FindSysDictionaryDetail) // 根据ID获取SysDictionaryDetail + dictionaryDetailRouterWithoutRecord.GET("getSysDictionaryDetailList", sysDictionaryDetailApi.GetSysDictionaryDetailList) // 获取SysDictionaryDetail列表 + } +} diff --git a/router/system/sys_initdb.go b/router/system/sys_initdb.go new file mode 100644 index 0000000..2074602 --- /dev/null +++ b/router/system/sys_initdb.go @@ -0,0 +1,17 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type InitRouter struct{} + +func (s *InitRouter) InitInitRouter(Router *gin.RouterGroup) { + initRouter := Router.Group("init") + dbApi := v1.ApiGroupApp.SystemApiGroup.DBApi + { + initRouter.POST("initdb", dbApi.InitDB) // 初始化数据库 + initRouter.POST("checkdb", dbApi.CheckDB) // 检测是否需要初始化数据库 + } +} diff --git a/router/system/sys_jwt.go b/router/system/sys_jwt.go new file mode 100644 index 0000000..e4a0a2f --- /dev/null +++ b/router/system/sys_jwt.go @@ -0,0 +1,16 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type JwtRouter struct{} + +func (s *JwtRouter) InitJwtRouter(Router *gin.RouterGroup) { + jwtRouter := Router.Group("jwt") + jwtApi := v1.ApiGroupApp.SystemApiGroup.JwtApi + { + jwtRouter.POST("jsonInBlacklist", jwtApi.JsonInBlacklist) // jwt加入黑名单 + } +} diff --git a/router/system/sys_menu.go b/router/system/sys_menu.go new file mode 100644 index 0000000..2a84407 --- /dev/null +++ b/router/system/sys_menu.go @@ -0,0 +1,29 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type MenuRouter struct{} + +func (s *MenuRouter) InitMenuRouter(Router *gin.RouterGroup) (R gin.IRoutes) { + menuRouter := Router.Group("menu").Use(middleware.OperationRecord()) + menuRouterWithoutRecord := Router.Group("menu") + authorityMenuApi := v1.ApiGroupApp.SystemApiGroup.AuthorityMenuApi + { + menuRouter.POST("addBaseMenu", authorityMenuApi.AddBaseMenu) // 新增菜单 + menuRouter.POST("addMenuAuthority", authorityMenuApi.AddMenuAuthority) // 增加menu和角色关联关系 + menuRouter.POST("deleteBaseMenu", authorityMenuApi.DeleteBaseMenu) // 删除菜单 + menuRouter.POST("updateBaseMenu", authorityMenuApi.UpdateBaseMenu) // 更新菜单 + } + { + menuRouterWithoutRecord.POST("getMenu", authorityMenuApi.GetMenu) // 获取菜单树 + menuRouterWithoutRecord.POST("getMenuList", authorityMenuApi.GetMenuList) // 分页获取基础menu列表 + menuRouterWithoutRecord.POST("getBaseMenuTree", authorityMenuApi.GetBaseMenuTree) // 获取用户动态路由 + menuRouterWithoutRecord.POST("getMenuAuthority", authorityMenuApi.GetMenuAuthority) // 获取指定角色menu + menuRouterWithoutRecord.POST("getBaseMenuById", authorityMenuApi.GetBaseMenuById) // 根据id获取菜单 + } + return menuRouter +} diff --git a/router/system/sys_operation_record.go b/router/system/sys_operation_record.go new file mode 100644 index 0000000..d355bf3 --- /dev/null +++ b/router/system/sys_operation_record.go @@ -0,0 +1,21 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" +) + +type OperationRecordRouter struct{} + +func (s *OperationRecordRouter) InitSysOperationRecordRouter(Router *gin.RouterGroup) { + operationRecordRouter := Router.Group("sysOperationRecord") + authorityMenuApi := v1.ApiGroupApp.SystemApiGroup.OperationRecordApi + { + operationRecordRouter.POST("createSysOperationRecord", authorityMenuApi.CreateSysOperationRecord) // 新建SysOperationRecord + operationRecordRouter.DELETE("deleteSysOperationRecord", authorityMenuApi.DeleteSysOperationRecord) // 删除SysOperationRecord + operationRecordRouter.DELETE("deleteSysOperationRecordByIds", authorityMenuApi.DeleteSysOperationRecordByIds) // 批量删除SysOperationRecord + operationRecordRouter.GET("findSysOperationRecord", authorityMenuApi.FindSysOperationRecord) // 根据ID获取SysOperationRecord + operationRecordRouter.GET("getSysOperationRecordList", authorityMenuApi.GetSysOperationRecordList) // 获取SysOperationRecord列表 + + } +} diff --git a/router/system/sys_system.go b/router/system/sys_system.go new file mode 100644 index 0000000..ffb8b63 --- /dev/null +++ b/router/system/sys_system.go @@ -0,0 +1,20 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type SysRouter struct{} + +func (s *SysRouter) InitSystemRouter(Router *gin.RouterGroup) { + sysRouter := Router.Group("system").Use(middleware.OperationRecord()) + systemApi := v1.ApiGroupApp.SystemApiGroup.SystemApi + { + sysRouter.POST("getSystemConfig", systemApi.GetSystemConfig) // 获取配置文件内容 + sysRouter.POST("setSystemConfig", systemApi.SetSystemConfig) // 设置配置文件内容 + sysRouter.POST("getServerInfo", systemApi.GetServerInfo) // 获取服务器信息 + sysRouter.POST("reloadSystem", systemApi.ReloadSystem) // 重启服务 + } +} diff --git a/router/system/sys_user.go b/router/system/sys_user.go new file mode 100644 index 0000000..94d57e0 --- /dev/null +++ b/router/system/sys_user.go @@ -0,0 +1,29 @@ +package system + +import ( + "github.com/gin-gonic/gin" + v1 "miniapp/api/v1" + "miniapp/middleware" +) + +type UserRouter struct{} + +func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) { + userRouter := Router.Group("user").Use(middleware.OperationRecord()) + userRouterWithoutRecord := Router.Group("user") + baseApi := v1.ApiGroupApp.SystemApiGroup.BaseApi + { + userRouter.POST("admin_register", baseApi.Register) // 管理员注册账号 + userRouter.POST("changePassword", baseApi.ChangePassword) // 用户修改密码 + userRouter.POST("setUserAuthority", baseApi.SetUserAuthority) // 设置用户权限 + userRouter.DELETE("deleteUser", baseApi.DeleteUser) // 删除用户 + userRouter.PUT("setUserInfo", baseApi.SetUserInfo) // 设置用户信息 + userRouter.PUT("setSelfInfo", baseApi.SetSelfInfo) // 设置自身信息 + userRouter.POST("setUserAuthorities", baseApi.SetUserAuthorities) // 设置用户权限组 + userRouter.POST("resetPassword", baseApi.ResetPassword) // 设置用户权限组 + } + { + userRouterWithoutRecord.POST("getUserList", baseApi.GetUserList) // 分页获取用户列表 + userRouterWithoutRecord.GET("getUserInfo", baseApi.GetUserInfo) // 获取自身信息 + } +} diff --git a/service/app/base.go b/service/app/base.go new file mode 100644 index 0000000..edcd5f6 --- /dev/null +++ b/service/app/base.go @@ -0,0 +1,104 @@ +package app + +import ( + "fmt" + "go.uber.org/zap" + "gorm.io/gorm" + "miniapp/global" +) + +// 分页组件 +func Page(current, size int) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + if current == 0 { + current = 1 + } + if size < 1 { + size = 10 + } + // 计算偏移量 + offset := (current - 1) * size + // 返回组装结果 + return db.Offset(offset).Limit(size) + } +} + +// @title updateSortBefore +// @description 更新之前处理序号 +// @param tx *gorm.DB "已开启的事务对象" +// @param model any "模型对象" +// @return error "错误信息" +func updateSortBefore(tx *gorm.DB, tableName, id string, sort int, param string) (err error) { + // 查出原来的排序号 + var oldSort int + err = tx.Table(tableName).Select("sort").Where("id = ?", id).Scan(&oldSort).Error + if err != nil { + global.GVA_LOG.Error("查询老数据失败: %v", zap.Error(err)) + return + } + // 如果相等,啥都不干 + if oldSort == sort { + return nil + } + // 处理排序 + // 如果老的排序号小于新的,(老, 新]之间的排序号都要-1 + // 如果老的大于新的,[老, 新)排序号-1 + if oldSort < sort { + // 老的小于新的,[老, 新) + 1 + sel := tx.Table(tableName). + Where("sort <= ? AND sort > ?", sort, oldSort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) // 自定义条件 + } + err = sel.Update("sort", gorm.Expr("sort - 1")).Error + } else { + // 老的大于新的,[新, 老) + 1 + sel := tx.Table(tableName). + Where("sort >= ? AND sort < ?", sort, oldSort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) // 自定义条件 + } + err = sel.Update("sort", gorm.Expr("sort + 1")).Error + } + return +} + +// @title createSortBefore +// @description 新建之前处理序号 +// @param tx *gorm.DB "已开启的事务对象" +// @param model any "模型对象" +// @return error "错误信息" +func createSortBefore(tx *gorm.DB, tableName string, sort int, param string) (err error) { + // 处理排序,如果没有传,就会是在最前面 + sel := tx.Table(tableName).Where("sort >= ?", sort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) + } + err = sel.Update("sort", gorm.Expr("sort + 1")).Error + if err != nil { + global.GVA_LOG.Error("处理前置排序失败:%v", zap.Error(err)) + } + return +} + +// @title dealSortAfter +// @description 处理序号之后 +// @param tx *gorm.DB "已开启的事务对象" +// @param modelName string "表名" +// @return error "错误信息" +func dealSortAfter(tx *gorm.DB, modelName, param string) (err error) { + // 保存成功,刷新排序 + if param != "" { + param += " AND " + } + sql := fmt.Sprintf("UPDATE %s a, (SELECT (@i := @i + 1) i, id FROM %s WHERE %s deleted_at IS NULL order by sort ASC) i, "+ + "(SELECT @i := 0) ir SET a.sort = i.i, updated_at=now() WHERE a.id = i.id", modelName, modelName, param) + err = tx.Exec(sql).Error + if err != nil { + global.GVA_LOG.Error("刷新排序失败: %v", zap.Error(err)) + } + return +} diff --git a/service/app/enter.go b/service/app/enter.go new file mode 100644 index 0000000..edd0427 --- /dev/null +++ b/service/app/enter.go @@ -0,0 +1,9 @@ +package app + +type ServiceGroup struct { + Oauth2ClientService + UserService + FavoriteService + VisionService + TodesService +} diff --git a/service/app/favorite.go b/service/app/favorite.go new file mode 100644 index 0000000..1df7ca4 --- /dev/null +++ b/service/app/favorite.go @@ -0,0 +1,34 @@ +package app + +import ( + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" +) + +type FavoriteService struct{} + +// GetFavoriteList 获取收藏列表 +func (f *FavoriteService) GetFavoriteList(p request.GetFavoriteList) (err error, list []app.Favorite, total int64) { + limit := p.PageSize + offset := p.PageSize * (p.Page - 1) + db := global.GVA_DB.Model(&app.Favorite{}).Where("user_id = ?", p.UserId) + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Find(&list).Error + return +} + +// CreateFavorite 创建收藏 +func (f *FavoriteService) CreateFavorite(favorite *app.Favorite) (err error) { + err = global.GVA_DB.Create(&favorite).Error + return +} + +// DeleteFavorite 删除收藏 +func (f *FavoriteService) DeleteFavorite(favorite *app.Favorite) (err error) { + err = global.GVA_DB.Delete(&favorite).Error + return +} diff --git a/service/app/oauth2_client.go b/service/app/oauth2_client.go new file mode 100644 index 0000000..5ff0796 --- /dev/null +++ b/service/app/oauth2_client.go @@ -0,0 +1,18 @@ +package app + +import ( + "miniapp/global" + "miniapp/model/app" +) + +type Oauth2ClientService struct{} + +// FinAll 查询所有客户端 +func (o *Oauth2ClientService) FinAll(clients *[]app.OAuth2Client) error { + return global.GVA_DB.Find(&clients).Error +} + +// FindOne 查询某一个 +func (o *Oauth2ClientService) FindOne(c *app.OAuth2Client) error { + return global.GVA_DB.Take(&c, c).Error +} diff --git a/service/app/todes.go b/service/app/todes.go new file mode 100644 index 0000000..398904d --- /dev/null +++ b/service/app/todes.go @@ -0,0 +1,19 @@ +package app + +import ( + "miniapp/global" + "miniapp/model/common" +) + +type TodesService struct{} + +func (t TodesService) GetUserTodos(userId uint) (list []common.UserTodo, err error) { + err = global.GVA_DB.Where("user_id = ?", userId).Find(&list).Error + return + +} + +func (t TodesService) UpdateTodoById(c *common.UserTodo) error { + + return global.GVA_DB.Table("t_user_todo").Where("id = ?", c.ID).Update("is_finish", c.IsFinish).Error +} diff --git a/service/app/user.go b/service/app/user.go new file mode 100644 index 0000000..b44d287 --- /dev/null +++ b/service/app/user.go @@ -0,0 +1,156 @@ +package app + +import ( + "errors" + "github.com/duke-git/lancet/v2/datetime" + "go.uber.org/zap" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" + "miniapp/model/app/response" + "miniapp/model/common" + "miniapp/model/types" + "time" +) + +type UserService struct{} + +func (UserService) GetUser(user *app.User) (err error) { + return global.GVA_DB.Take(&user, user).Error +} + +func (UserService) GetOrCreate(user *app.User) (err error) { + //err = global.GVA_DB.Take(&user, user).Error + err = global.GVA_DB.Model(&user).Where("phone = ?", user.Phone).First(&user).Error + if err == nil { + return + } + // 如果是没查询到记录,则创建用户 + if err == gorm.ErrRecordNotFound { + // 用户不存在,创建用户 + if err = global.GVA_DB.Create(&user).Error; err != nil { + global.GVA_LOG.Error("账号创建失败: %v", zap.Error(err)) + err = errors.New("登录失败") + return + } + } + return +} + +// CheckUnionIdIsExist 检查UnionId和OpenId是否存在 +func (UserService) CheckUnionIdIsExist(unionId, openId string) bool { + var count int64 + err := global.GVA_DB.Model(&app.User{}).Where("wechat_union_id = ? and wechat_open_id = ?", unionId, openId).Count(&count).Error + if err != nil { + return false + } + return count > 0 +} + +// UpdateUserInfo 更新普通用户信息 +func (UserService) UpdateUserInfo(e *app.User) (err error) { + return global.GVA_DB.Updates(&e).Error +} + +// GetAverageUserList 查询普通用户列表 +func (UserService) GetAverageUserList(p request.GetUserList) (records []response.UserItem, count int64, err error) { + tx := global.GVA_DB.Scopes(Page(p.Page, p.PageSize)). + Table("`t_user` AS tu"). + Select("tu.id AS id,tu.avatar AS avatar,tu.phone AS phone,tu.nickname AS nickname,tu.sex AS sex,tu.created_at AS created_at,tu.last_login_at AS last_login_at,tu.`status` AS `status`"). + Order("tu.last_login_at DESC") + + if p.Phone != "" { + tx = tx.Where("tu.phone LIKE ?", "%"+p.Phone+"%") + } + //加一个姓名的模糊查询 + if p.Name != "" { + tx = tx.Where("tu.nickname LIKE ?", "&"+p.Name+"%") + } + if p.Status != "" { + tx = tx.Where("tu.`status` = ?", p.Status) + } + + if p.StartAt != "" || p.EndAt != "" { + start := time.Date(2021, 1, 1, 0, 0, 0, 0, time.Local) + end := time.Now() + // 处理数据 + if p.StartAt != "" { + st, err := datetime.FormatStrToTime(p.StartAt, "yyyy-mm-dd") + if err != nil { + global.GVA_LOG.Error("解析开始时间异常") + return nil, 0, errors.New("解析开始时间异常") + } + start = datetime.BeginOfDay(st) + } + if p.EndAt != "" { + et, err := datetime.FormatStrToTime(p.EndAt, "yyyy-mm-dd") + if err != nil { + global.GVA_LOG.Error("解析结束时间异常") + return nil, 0, errors.New("解析结束时间异常") + } + end = datetime.EndOfDay(et) + } + // 处理查询条件 + tx.Where("tor.pay_at BETWEEN ? AND ?", start, end) + } + + err = tx.Offset(-1).Limit(-1).Count(&count).Find(&records).Error + return +} + +func (UserService) UpdateLastLoginInfo(username int) { + now := time.Now().Local() + + global.GVA_DB.Model(&app.User{}). + Where("id = ?", username). + Updates(app.User{LastLoginAt: (*types.DateTime)(&now)}) + +} + +// UpdateUserHospital 更新用户医院信息 +func (UserService) UpdateUserHospital(r *request.ChangeUserHospital) (err error) { + + err = global.GVA_DB.Delete(&common.UserTodo{}, "user_id = ?", r.UserId).Error + if err != nil { + global.GVA_LOG.Error("清除用户Todo列表失败", zap.Error(err)) + return + } + + var hospital common.Hospital + err = global.GVA_DB.Where("id = ?", r.HospitalId).Preload("Todos").First(&hospital).Error + if err != nil { + global.GVA_LOG.Error("获取医院信息失败", zap.Error(err)) + return + } + + if hospital.Todos != nil { + var userTodos []common.UserTodo + for _, todo := range hospital.Todos { + userTodos = append(userTodos, common.UserTodo{ + Content: todo.Content, + UserId: r.UserId, + IsFinish: 0, + }) + } + err = global.GVA_DB.Create(&userTodos).Error + if err != nil { + global.GVA_LOG.Error("创建用户Todo列表失败", zap.Error(err)) + return + } + } + return +} + +func (s UserService) GetUserInfo(id string) (user response.UserVO, err error) { + var u app.User + err = global.GVA_DB.Where("id = ?", id).First(&u).Error + user.ParseOrdinary(u) + + if u.IsSurgery == 1 { + user.TimeNote = "距离下次复查时间还剩:" + } else { + user.TimeNote = "距离手术时间还剩:" + } + return +} diff --git a/service/app/vision.go b/service/app/vision.go new file mode 100644 index 0000000..5d11869 --- /dev/null +++ b/service/app/vision.go @@ -0,0 +1,26 @@ +package app + +import ( + "miniapp/global" + "miniapp/model/app" + "miniapp/model/app/request" +) + +type VisionService struct{} + +func (s *VisionService) GetVisionList(p request.VisionListRequest) (list *[]app.Vision, total int64, err error) { + limit := p.PageSize + offset := p.PageSize * (p.Page - 1) + db := global.GVA_DB.Model(&app.Vision{}).Where("user_id = ?", p.UserId) + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Find(&list).Error + return +} + +func (s *VisionService) CreateVision(vision *app.Vision) (err error) { + err = global.GVA_DB.Create(&vision).Error + return +} diff --git a/service/enter.go b/service/enter.go new file mode 100644 index 0000000..21d80ce --- /dev/null +++ b/service/enter.go @@ -0,0 +1,15 @@ +package service + +import ( + "miniapp/service/app" + "miniapp/service/example" + "miniapp/service/system" +) + +type ServiceGroup struct { + SystemServiceGroup system.ServiceGroup + ExampleServiceGroup example.ServiceGroup + AppServiceGroup app.ServiceGroup +} + +var ServiceGroupApp = new(ServiceGroup) diff --git a/service/example/enter.go b/service/example/enter.go new file mode 100644 index 0000000..c5a7dda --- /dev/null +++ b/service/example/enter.go @@ -0,0 +1,6 @@ +package example + +type ServiceGroup struct { + CustomerService + FileUploadAndDownloadService +} diff --git a/service/example/exa_breakpoint_continue.go b/service/example/exa_breakpoint_continue.go new file mode 100644 index 0000000..c56ca6b --- /dev/null +++ b/service/example/exa_breakpoint_continue.go @@ -0,0 +1,69 @@ +package example + +import ( + "errors" + + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/example" +) + +type FileUploadAndDownloadService struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: FindOrCreateFile +//@description: 上传文件时检测当前文件属性,如果没有文件则创建,有则返回文件的当前切片 +//@param: fileMd5 string, fileName string, chunkTotal int +//@return: file model.ExaFile, err error + +func (e *FileUploadAndDownloadService) FindOrCreateFile(fileMd5 string, fileName string, chunkTotal int) (file example.ExaFile, err error) { + var cfile example.ExaFile + cfile.FileMd5 = fileMd5 + cfile.FileName = fileName + cfile.ChunkTotal = chunkTotal + + if errors.Is(global.GVA_DB.Where("file_md5 = ? AND is_finish = ?", fileMd5, true).First(&file).Error, gorm.ErrRecordNotFound) { + err = global.GVA_DB.Where("file_md5 = ? AND file_name = ?", fileMd5, fileName).Preload("ExaFileChunk").FirstOrCreate(&file, cfile).Error + return file, err + } + cfile.IsFinish = true + cfile.FilePath = file.FilePath + err = global.GVA_DB.Create(&cfile).Error + return cfile, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateFileChunk +//@description: 创建文件切片记录 +//@param: id uint, fileChunkPath string, fileChunkNumber int +//@return: error + +func (e *FileUploadAndDownloadService) CreateFileChunk(id uint, fileChunkPath string, fileChunkNumber int) error { + var chunk example.ExaFileChunk + chunk.FileChunkPath = fileChunkPath + chunk.ExaFileID = id + chunk.FileChunkNumber = fileChunkNumber + err := global.GVA_DB.Create(&chunk).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteFileChunk +//@description: 删除文件切片记录 +//@param: fileMd5 string, fileName string, filePath string +//@return: error + +func (e *FileUploadAndDownloadService) DeleteFileChunk(fileMd5 string, filePath string) error { + var chunks []example.ExaFileChunk + var file example.ExaFile + err := global.GVA_DB.Where("file_md5 = ? ", fileMd5).First(&file). + Updates(map[string]interface{}{ + "IsFinish": true, + "file_path": filePath, + }).Error + if err != nil { + return err + } + err = global.GVA_DB.Where("exa_file_id = ?", file.ID).Delete(&chunks).Unscoped().Error + return err +} diff --git a/service/example/exa_customer.go b/service/example/exa_customer.go new file mode 100644 index 0000000..252f31a --- /dev/null +++ b/service/example/exa_customer.go @@ -0,0 +1,85 @@ +package example + +import ( + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/example" + "miniapp/model/system" + systemService "miniapp/service/system" +) + +type CustomerService struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateExaCustomer +//@description: 创建客户 +//@param: e model.ExaCustomer +//@return: err error + +func (exa *CustomerService) CreateExaCustomer(e example.ExaCustomer) (err error) { + err = global.GVA_DB.Create(&e).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteFileChunk +//@description: 删除客户 +//@param: e model.ExaCustomer +//@return: err error + +func (exa *CustomerService) DeleteExaCustomer(e example.ExaCustomer) (err error) { + err = global.GVA_DB.Delete(&e).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateExaCustomer +//@description: 更新客户 +//@param: e *model.ExaCustomer +//@return: err error + +func (exa *CustomerService) UpdateExaCustomer(e *example.ExaCustomer) (err error) { + err = global.GVA_DB.Save(e).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetExaCustomer +//@description: 获取客户信息 +//@param: id uint +//@return: customer model.ExaCustomer, err error + +func (exa *CustomerService) GetExaCustomer(id uint) (customer example.ExaCustomer, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&customer).Error + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetCustomerInfoList +//@description: 分页获取客户列表 +//@param: sysUserAuthorityID string, info request.PageInfo +//@return: list interface{}, total int64, err error + +func (exa *CustomerService) GetCustomerInfoList(sysUserAuthorityID uint, info request.PageInfo) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + db := global.GVA_DB.Model(&example.ExaCustomer{}) + var a system.SysAuthority + a.AuthorityId = sysUserAuthorityID + auth, err := systemService.AuthorityServiceApp.GetAuthorityInfo(a) + if err != nil { + return + } + var dataId []uint + for _, v := range auth.DataAuthorityId { + dataId = append(dataId, v.AuthorityId) + } + var CustomerList []example.ExaCustomer + err = db.Where("sys_user_authority_id in ?", dataId).Count(&total).Error + if err != nil { + return CustomerList, total, err + } else { + err = db.Limit(limit).Offset(offset).Preload("SysUser").Where("sys_user_authority_id in ?", dataId).Find(&CustomerList).Error + } + return CustomerList, total, err +} diff --git a/service/example/exa_file_upload_download.go b/service/example/exa_file_upload_download.go new file mode 100644 index 0000000..01bf170 --- /dev/null +++ b/service/example/exa_file_upload_download.go @@ -0,0 +1,108 @@ +package example + +import ( + "errors" + "mime/multipart" + "strings" + + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/example" + "miniapp/utils/upload" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Upload +//@description: 创建文件上传记录 +//@param: file model.ExaFileUploadAndDownload +//@return: error + +func (e *FileUploadAndDownloadService) Upload(file example.ExaFileUploadAndDownload) error { + return global.GVA_DB.Create(&file).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: FindFile +//@description: 查询文件记录 +//@param: id uint +//@return: model.ExaFileUploadAndDownload, error + +func (e *FileUploadAndDownloadService) FindFile(id uint) (example.ExaFileUploadAndDownload, error) { + var file example.ExaFileUploadAndDownload + err := global.GVA_DB.Where("id = ?", id).First(&file).Error + return file, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteFile +//@description: 删除文件记录 +//@param: file model.ExaFileUploadAndDownload +//@return: err error + +func (e *FileUploadAndDownloadService) DeleteFile(file example.ExaFileUploadAndDownload) (err error) { + var fileFromDb example.ExaFileUploadAndDownload + fileFromDb, err = e.FindFile(file.ID) + if err != nil { + return + } + oss := upload.NewOss() + if err = oss.DeleteFile(fileFromDb.Key); err != nil { + return errors.New("文件删除失败") + } + err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error + return err +} + +// EditFileName 编辑文件名或者备注 +func (e *FileUploadAndDownloadService) EditFileName(file example.ExaFileUploadAndDownload) (err error) { + var fileFromDb example.ExaFileUploadAndDownload + return global.GVA_DB.Where("id = ?", file.ID).First(&fileFromDb).Update("name", file.Name).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetFileRecordInfoList +//@description: 分页获取数据 +//@param: info request.PageInfo +//@return: list interface{}, total int64, err error + +func (e *FileUploadAndDownloadService) GetFileRecordInfoList(info request.PageInfo) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + keyword := info.Keyword + db := global.GVA_DB.Model(&example.ExaFileUploadAndDownload{}) + var fileLists []example.ExaFileUploadAndDownload + if len(keyword) > 0 { + db = db.Where("name LIKE ?", "%"+keyword+"%") + } + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&fileLists).Error + return fileLists, total, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UploadFile +//@description: 根据配置文件判断是文件上传到本地或者七牛云 +//@param: header *multipart.FileHeader, noSave string +//@return: file model.ExaFileUploadAndDownload, err error + +func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader, noSave string) (file example.ExaFileUploadAndDownload, err error) { + oss := upload.NewOss() + filePath, key, uploadErr := oss.UploadFile(header) + if uploadErr != nil { + panic(uploadErr) + } + s := strings.Split(header.Filename, ".") + f := example.ExaFileUploadAndDownload{ + Url: filePath, + Name: header.Filename, + Tag: s[len(s)-1], + Key: key, + } + if noSave == "0" { + return f, e.Upload(f) + } + return f, nil +} diff --git a/service/system/article.go b/service/system/article.go new file mode 100644 index 0000000..f50f897 --- /dev/null +++ b/service/system/article.go @@ -0,0 +1,38 @@ +package system + +import ( + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/common" + "miniapp/model/common/request" +) + +type ArticleService struct{} + +// GetArticleList 获取文章列表 +func (a ArticleService) GetArticleList(p request.PageInfo) (list []common.Article, total int64, err error) { + err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Find(&list).Offset(-1).Limit(-1).Count(&total).Error + return +} + +// CreateArticle 创建文章 +func (a ArticleService) CreateArticle(article *common.Article) (err error) { + return global.GVA_DB.Create(&article).Error +} + +// UpdateArticle 更新文章 +func (a ArticleService) UpdateArticle(article *common.Article) (err error) { + return global.GVA_DB.Updates(&article).Error +} + +// DeleteArticle 删除文章 +func (a ArticleService) DeleteArticle(article *common.Article) (err error) { + return global.GVA_DB.Delete(&article).Error +} + +// GetArticleById 根据id获取文章 +func (a ArticleService) GetArticleById(id string) (article *common.Article, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&article).Error + err = global.GVA_DB.Table("articles").Where("id = ?", id).Update("reading_num", gorm.Expr("reading_num + ?", 1)).Error + return +} diff --git a/service/system/banner.go b/service/system/banner.go new file mode 100644 index 0000000..022ea9c --- /dev/null +++ b/service/system/banner.go @@ -0,0 +1,37 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common" + "miniapp/model/common/request" +) + +type BannerService struct { +} + +// GetBannerList 获取轮播图列表 +func (b BannerService) GetBannerList(p request.PageInfo) (list []common.Banner, total int64, err error) { + err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Find(&list).Limit(-1).Offset(-1).Count(&total).Error + return +} + +// CreateBanner 创建轮播图 +func (b BannerService) CreateBanner(banner *common.Banner) (err error) { + return global.GVA_DB.Create(&banner).Error +} + +// UpdateBanner 更新轮播图 +func (b BannerService) UpdateBanner(banner *common.Banner) (err error) { + return global.GVA_DB.Updates(&banner).Error +} + +// DeleteBanner 删除轮播图 +func (b BannerService) DeleteBanner(banner *common.Banner) (err error) { + return global.GVA_DB.Delete(&banner).Error +} + +// GetBannerById 根据id获取轮播图 +func (b BannerService) GetBannerById(id string) (banner *common.Banner, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&banner).Error + return +} diff --git a/service/system/base.go b/service/system/base.go new file mode 100644 index 0000000..8a5ed3c --- /dev/null +++ b/service/system/base.go @@ -0,0 +1,104 @@ +package system + +import ( + "fmt" + "go.uber.org/zap" + "gorm.io/gorm" + "miniapp/global" +) + +// 分页组件 +func Page(current, size int) func(db *gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + if current == 0 { + current = 1 + } + if size < 1 { + size = 10 + } + // 计算偏移量 + offset := (current - 1) * size + // 返回组装结果 + return db.Offset(offset).Limit(size) + } +} + +// @title updateSortBefore +// @description 更新之前处理序号 +// @param tx *gorm.DB "已开启的事务对象" +// @param model any "模型对象" +// @return error "错误信息" +func updateSortBefore(tx *gorm.DB, tableName, id string, sort int, param string) (err error) { + // 查出原来的排序号 + var oldSort int + err = tx.Table(tableName).Select("sort").Where("id = ?", id).Scan(&oldSort).Error + if err != nil { + global.GVA_LOG.Error("查询老数据失败: %v", zap.Error(err)) + return + } + // 如果相等,啥都不干 + if oldSort == sort { + return nil + } + // 处理排序 + // 如果老的排序号小于新的,(老, 新]之间的排序号都要-1 + // 如果老的大于新的,[老, 新)排序号-1 + if oldSort < sort { + // 老的小于新的,[老, 新) + 1 + sel := tx.Table(tableName). + Where("sort <= ? AND sort > ?", sort, oldSort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) // 自定义条件 + } + err = sel.Update("sort", gorm.Expr("sort - 1")).Error + } else { + // 老的大于新的,[新, 老) + 1 + sel := tx.Table(tableName). + Where("sort >= ? AND sort < ?", sort, oldSort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) // 自定义条件 + } + err = sel.Update("sort", gorm.Expr("sort + 1")).Error + } + return +} + +// @title createSortBefore +// @description 新建之前处理序号 +// @param tx *gorm.DB "已开启的事务对象" +// @param model any "模型对象" +// @return error "错误信息" +func createSortBefore(tx *gorm.DB, tableName string, sort int, param string) (err error) { + // 处理排序,如果没有传,就会是在最前面 + sel := tx.Table(tableName).Where("sort >= ?", sort). + Where("deleted_at IS NULL") + if param != "" { + sel.Where(param) + } + err = sel.Update("sort", gorm.Expr("sort + 1")).Error + if err != nil { + global.GVA_LOG.Error("处理前置排序失败:%v", zap.Error(err)) + } + return +} + +// @title dealSortAfter +// @description 处理序号之后 +// @param tx *gorm.DB "已开启的事务对象" +// @param modelName string "表名" +// @return error "错误信息" +func dealSortAfter(tx *gorm.DB, modelName, param string) (err error) { + // 保存成功,刷新排序 + if param != "" { + param += " AND " + } + sql := fmt.Sprintf("UPDATE %s a, (SELECT (@i := @i + 1) i, id FROM %s WHERE %s deleted_at IS NULL order by sort ASC) i, "+ + "(SELECT @i := 0) ir SET a.sort = i.i, updated_at=now() WHERE a.id = i.id", modelName, modelName, param) + err = tx.Exec(sql).Error + if err != nil { + global.GVA_LOG.Error("刷新排序失败: %v", zap.Error(err)) + } + return +} diff --git a/service/system/enter.go b/service/system/enter.go new file mode 100644 index 0000000..028a2ad --- /dev/null +++ b/service/system/enter.go @@ -0,0 +1,23 @@ +package system + +type ServiceGroup struct { + JwtService + ApiService + MenuService + UserService + CasbinService + InitDBService + AutoCodeService + BaseMenuService + AuthorityService + DictionaryService + SystemConfigService + AutoCodeHistoryService + OperationRecordService + DictionaryDetailService + AuthorityBtnService + ChatGptService + HospitalService + BannerService + ArticleService +} diff --git a/service/system/hospital.go b/service/system/hospital.go new file mode 100644 index 0000000..56c488a --- /dev/null +++ b/service/system/hospital.go @@ -0,0 +1,37 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common" + "miniapp/model/common/request" +) + +type HospitalService struct { +} + +// GetHospitalList 获取医院列表 +func (h HospitalService) GetHospitalList(p request.PageInfo) (list []common.Hospital, total int64, err error) { + err = global.GVA_DB.Scopes(Page(p.Page, p.PageSize)).Preload("Notes").Preload("Todos").Find(&list).Offset(-1).Limit(-1).Count(&total).Error + return +} + +// CreateHospital 创建医院 +func (h HospitalService) CreateHospital(hospital *common.Hospital) (err error) { + return global.GVA_DB.Create(&hospital).Error +} + +// UpdateHospital 更新医院 +func (h HospitalService) UpdateHospital(hospital *common.Hospital) (err error) { + return global.GVA_DB.Updates(&hospital).Error +} + +// DeleteHospital 删除医院 +func (h HospitalService) DeleteHospital(hospital *common.Hospital) (err error) { + return global.GVA_DB.Select("Notes").Delete(&hospital).Error +} + +// GetHospitalById 根据id获取医院 +func (h HospitalService) GetHospitalById(id uint) (hospital *common.Hospital, err error) { + err = global.GVA_DB.Where("id = ?", id).Preload("Notes").Preload("Todos").First(&hospital).Error + return +} diff --git a/service/system/jwt_black_list.go b/service/system/jwt_black_list.go new file mode 100644 index 0000000..7639f18 --- /dev/null +++ b/service/system/jwt_black_list.go @@ -0,0 +1,82 @@ +package system + +import ( + "context" + + "go.uber.org/zap" + + "miniapp/global" + "miniapp/model/system" + "miniapp/utils" +) + +type JwtService struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: JsonInBlacklist +//@description: 拉黑jwt +//@param: jwtList model.JwtBlacklist +//@return: err error + +func (jwtService *JwtService) JsonInBlacklist(jwtList system.JwtBlacklist) (err error) { + err = global.GVA_DB.Create(&jwtList).Error + if err != nil { + return + } + global.BlackCache.SetDefault(jwtList.Jwt, struct{}{}) + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: IsBlacklist +//@description: 判断JWT是否在黑名单内部 +//@param: jwt string +//@return: bool + +func (jwtService *JwtService) IsBlacklist(jwt string) bool { + _, ok := global.BlackCache.Get(jwt) + return ok + // err := global.GVA_DB.Where("jwt = ?", jwt).First(&system.JwtBlacklist{}).Error + // isNotFound := errors.Is(err, gorm.ErrRecordNotFound) + // return !isNotFound +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetRedisJWT +//@description: 从redis取jwt +//@param: userName string +//@return: redisJWT string, err error + +func (jwtService *JwtService) GetRedisJWT(userName string) (redisJWT string, err error) { + redisJWT, err = global.GVA_REDIS.Get(context.Background(), userName).Result() + return redisJWT, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetRedisJWT +//@description: jwt存入redis并设置过期时间 +//@param: jwt string, userName string +//@return: err error + +func (jwtService *JwtService) SetRedisJWT(jwt string, userName string) (err error) { + // 此处过期时间等于jwt过期时间 + dr, err := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) + if err != nil { + return err + } + timer := dr + err = global.GVA_REDIS.Set(context.Background(), userName, jwt, timer).Err() + return err +} + +func LoadAll() { + var data []string + err := global.GVA_DB.Model(&system.JwtBlacklist{}).Select("jwt").Find(&data).Error + if err != nil { + global.GVA_LOG.Error("加载数据库jwt黑名单失败!", zap.Error(err)) + return + } + for i := 0; i < len(data); i++ { + global.BlackCache.SetDefault(data[i], struct{}{}) + } // jwt黑名单 加入 BlackCache 中 +} diff --git a/service/system/sys_api.go b/service/system/sys_api.go new file mode 100644 index 0000000..2d0844f --- /dev/null +++ b/service/system/sys_api.go @@ -0,0 +1,196 @@ +package system + +import ( + "errors" + "fmt" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" + + "gorm.io/gorm" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateApi +//@description: 新增基础api +//@param: api model.SysApi +//@return: err error + +type ApiService struct{} + +var ApiServiceApp = new(ApiService) + +func (apiService *ApiService) CreateApi(api system.SysApi) (err error) { + if !errors.Is(global.GVA_DB.Where("path = ? AND method = ?", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) { + return errors.New("存在相同api") + } + return global.GVA_DB.Create(&api).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteApi +//@description: 删除基础api +//@param: api model.SysApi +//@return: err error + +func (apiService *ApiService) DeleteApi(api system.SysApi) (err error) { + var entity system.SysApi + err = global.GVA_DB.Where("id = ?", api.ID).First(&entity).Error // 根据id查询api记录 + if errors.Is(err, gorm.ErrRecordNotFound) { // api记录不存在 + return err + } + err = global.GVA_DB.Delete(&entity).Error + if err != nil { + return err + } + CasbinServiceApp.ClearCasbin(1, entity.Path, entity.Method) + if err != nil { + return err + } + return nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetAPIInfoList +//@description: 分页获取数据, +//@param: api model.SysApi, info request.PageInfo, order string, desc bool +//@return: list interface{}, total int64, err error + +func (apiService *ApiService) GetAPIInfoList(api system.SysApi, info request.PageInfo, order string, desc bool) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + db := global.GVA_DB.Model(&system.SysApi{}) + var apiList []system.SysApi + + if api.Path != "" { + db = db.Where("path LIKE ?", "%"+api.Path+"%") + } + + if api.Description != "" { + db = db.Where("description LIKE ?", "%"+api.Description+"%") + } + + if api.Method != "" { + db = db.Where("method = ?", api.Method) + } + + if api.ApiGroup != "" { + db = db.Where("api_group = ?", api.ApiGroup) + } + + err = db.Count(&total).Error + + if err != nil { + return apiList, total, err + } else { + db = db.Limit(limit).Offset(offset) + if order != "" { + var OrderStr string + // 设置有效排序key 防止sql注入 + // 感谢 Tom4t0 提交漏洞信息 + orderMap := make(map[string]bool, 5) + orderMap["id"] = true + orderMap["path"] = true + orderMap["api_group"] = true + orderMap["description"] = true + orderMap["method"] = true + if orderMap[order] { + if desc { + OrderStr = order + " desc" + } else { + OrderStr = order + } + } else { // didn't match any order key in `orderMap` + err = fmt.Errorf("非法的排序字段: %v", order) + return apiList, total, err + } + + err = db.Order(OrderStr).Find(&apiList).Error + } else { + err = db.Order("api_group").Find(&apiList).Error + } + } + return apiList, total, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetAllApis +//@description: 获取所有的api +//@return: apis []model.SysApi, err error + +func (apiService *ApiService) GetAllApis() (apis []system.SysApi, err error) { + err = global.GVA_DB.Find(&apis).Error + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetApiById +//@description: 根据id获取api +//@param: id float64 +//@return: api model.SysApi, err error + +func (apiService *ApiService) GetApiById(id int) (api system.SysApi, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&api).Error + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateApi +//@description: 根据id更新api +//@param: api model.SysApi +//@return: err error + +func (apiService *ApiService) UpdateApi(api system.SysApi) (err error) { + var oldA system.SysApi + err = global.GVA_DB.Where("id = ?", api.ID).First(&oldA).Error + if oldA.Path != api.Path || oldA.Method != api.Method { + if !errors.Is(global.GVA_DB.Where("path = ? AND method = ?", api.Path, api.Method).First(&system.SysApi{}).Error, gorm.ErrRecordNotFound) { + return errors.New("存在相同api路径") + } + } + if err != nil { + return err + } else { + err = CasbinServiceApp.UpdateCasbinApi(oldA.Path, api.Path, oldA.Method, api.Method) + if err != nil { + return err + } else { + err = global.GVA_DB.Save(&api).Error + } + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteApis +//@description: 删除选中API +//@param: apis []model.SysApi +//@return: err error + +func (apiService *ApiService) DeleteApisByIds(ids request.IdsReq) (err error) { + var apis []system.SysApi + err = global.GVA_DB.Find(&apis, "id in ?", ids.Ids).Delete(&apis).Error + if err != nil { + return err + } else { + for _, sysApi := range apis { + CasbinServiceApp.ClearCasbin(1, sysApi.Path, sysApi.Method) + } + if err != nil { + return err + } + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteApis +//@description: 删除选中API +//@param: apis []model.SysApi +//@return: err error + +func (apiService *ApiService) FreshCasbin() (err error) { + e := CasbinServiceApp.Casbin() + err = e.LoadPolicy() + return err +} diff --git a/service/system/sys_authority.go b/service/system/sys_authority.go new file mode 100644 index 0000000..9db3888 --- /dev/null +++ b/service/system/sys_authority.go @@ -0,0 +1,220 @@ +package system + +import ( + "errors" + "strconv" + + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" + "miniapp/model/system/response" +) + +var ErrRoleExistence = errors.New("存在相同角色id") + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateAuthority +//@description: 创建一个角色 +//@param: auth model.SysAuthority +//@return: authority system.SysAuthority, err error + +type AuthorityService struct{} + +var AuthorityServiceApp = new(AuthorityService) + +func (authorityService *AuthorityService) CreateAuthority(auth system.SysAuthority) (authority system.SysAuthority, err error) { + var authorityBox system.SysAuthority + if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) { + return auth, ErrRoleExistence + } + err = global.GVA_DB.Create(&auth).Error + return auth, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CopyAuthority +//@description: 复制一个角色 +//@param: copyInfo response.SysAuthorityCopyResponse +//@return: authority system.SysAuthority, err error + +func (authorityService *AuthorityService) CopyAuthority(copyInfo response.SysAuthorityCopyResponse) (authority system.SysAuthority, err error) { + var authorityBox system.SysAuthority + if !errors.Is(global.GVA_DB.Where("authority_id = ?", copyInfo.Authority.AuthorityId).First(&authorityBox).Error, gorm.ErrRecordNotFound) { + return authority, ErrRoleExistence + } + copyInfo.Authority.Children = []system.SysAuthority{} + menus, err := MenuServiceApp.GetMenuAuthority(&request.GetAuthorityId{AuthorityId: int(copyInfo.OldAuthorityId)}) + if err != nil { + return + } + var baseMenu []system.SysBaseMenu + for _, v := range menus { + intNum, _ := strconv.Atoi(v.MenuId) + v.SysBaseMenu.ID = uint(intNum) + baseMenu = append(baseMenu, v.SysBaseMenu) + } + copyInfo.Authority.SysBaseMenus = baseMenu + err = global.GVA_DB.Create(©Info.Authority).Error + if err != nil { + return + } + + var btns []system.SysAuthorityBtn + + err = global.GVA_DB.Find(&btns, "authority_id = ?", copyInfo.OldAuthorityId).Error + if err != nil { + return + } + if len(btns) > 0 { + for i := range btns { + btns[i].AuthorityId = copyInfo.Authority.AuthorityId + } + err = global.GVA_DB.Create(&btns).Error + + if err != nil { + return + } + } + paths := CasbinServiceApp.GetPolicyPathByAuthorityId(copyInfo.OldAuthorityId) + err = CasbinServiceApp.UpdateCasbin(copyInfo.Authority.AuthorityId, paths) + if err != nil { + _ = authorityService.DeleteAuthority(©Info.Authority) + } + return copyInfo.Authority, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateAuthority +//@description: 更改一个角色 +//@param: auth model.SysAuthority +//@return: authority system.SysAuthority, err error + +func (authorityService *AuthorityService) UpdateAuthority(auth system.SysAuthority) (authority system.SysAuthority, err error) { + err = global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Updates(&auth).Error + return auth, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteAuthority +//@description: 删除角色 +//@param: auth *model.SysAuthority +//@return: err error + +func (authorityService *AuthorityService) DeleteAuthority(auth *system.SysAuthority) (err error) { + if errors.Is(global.GVA_DB.Debug().Preload("Users").First(&auth).Error, gorm.ErrRecordNotFound) { + return errors.New("该角色不存在") + } + if len(auth.Users) != 0 { + return errors.New("此角色有用户正在使用禁止删除") + } + if !errors.Is(global.GVA_DB.Where("authority_id = ?", auth.AuthorityId).First(&system.SysUser{}).Error, gorm.ErrRecordNotFound) { + return errors.New("此角色有用户正在使用禁止删除") + } + if !errors.Is(global.GVA_DB.Where("parent_id = ?", auth.AuthorityId).First(&system.SysAuthority{}).Error, gorm.ErrRecordNotFound) { + return errors.New("此角色存在子角色不允许删除") + } + db := global.GVA_DB.Preload("SysBaseMenus").Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(auth) + err = db.Unscoped().Delete(auth).Error + if err != nil { + return + } + if len(auth.SysBaseMenus) > 0 { + err = global.GVA_DB.Model(auth).Association("SysBaseMenus").Delete(auth.SysBaseMenus) + if err != nil { + return + } + // err = db.Association("SysBaseMenus").Delete(&auth) + } + if len(auth.DataAuthorityId) > 0 { + err = global.GVA_DB.Model(auth).Association("DataAuthorityId").Delete(auth.DataAuthorityId) + if err != nil { + return + } + } + err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_authority_authority_id = ?", auth.AuthorityId).Error + if err != nil { + return + } + err = global.GVA_DB.Delete(&[]system.SysAuthorityBtn{}, "authority_id = ?", auth.AuthorityId).Error + if err != nil { + return + } + authorityId := strconv.Itoa(int(auth.AuthorityId)) + CasbinServiceApp.ClearCasbin(0, authorityId) + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetAuthorityInfoList +//@description: 分页获取数据 +//@param: info request.PageInfo +//@return: list interface{}, total int64, err error + +func (authorityService *AuthorityService) GetAuthorityInfoList(info request.PageInfo) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + db := global.GVA_DB.Model(&system.SysAuthority{}) + if err = db.Where("parent_id = ?", "0").Count(&total).Error; total == 0 || err != nil { + return + } + var authority []system.SysAuthority + err = db.Limit(limit).Offset(offset).Preload("DataAuthorityId").Where("parent_id = ?", "0").Find(&authority).Error + for k := range authority { + err = authorityService.findChildrenAuthority(&authority[k]) + } + return authority, total, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetAuthorityInfo +//@description: 获取所有角色信息 +//@param: auth model.SysAuthority +//@return: sa system.SysAuthority, err error + +func (authorityService *AuthorityService) GetAuthorityInfo(auth system.SysAuthority) (sa system.SysAuthority, err error) { + err = global.GVA_DB.Preload("DataAuthorityId").Where("authority_id = ?", auth.AuthorityId).First(&sa).Error + return sa, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetDataAuthority +//@description: 设置角色资源权限 +//@param: auth model.SysAuthority +//@return: error + +func (authorityService *AuthorityService) SetDataAuthority(auth system.SysAuthority) error { + var s system.SysAuthority + global.GVA_DB.Preload("DataAuthorityId").First(&s, "authority_id = ?", auth.AuthorityId) + err := global.GVA_DB.Model(&s).Association("DataAuthorityId").Replace(&auth.DataAuthorityId) + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetMenuAuthority +//@description: 菜单与角色绑定 +//@param: auth *model.SysAuthority +//@return: error + +func (authorityService *AuthorityService) SetMenuAuthority(auth *system.SysAuthority) error { + var s system.SysAuthority + global.GVA_DB.Preload("SysBaseMenus").First(&s, "authority_id = ?", auth.AuthorityId) + err := global.GVA_DB.Model(&s).Association("SysBaseMenus").Replace(&auth.SysBaseMenus) + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: findChildrenAuthority +//@description: 查询子角色 +//@param: authority *model.SysAuthority +//@return: err error + +func (authorityService *AuthorityService) findChildrenAuthority(authority *system.SysAuthority) (err error) { + err = global.GVA_DB.Preload("DataAuthorityId").Where("parent_id = ?", authority.AuthorityId).Find(&authority.Children).Error + if len(authority.Children) > 0 { + for k := range authority.Children { + err = authorityService.findChildrenAuthority(&authority.Children[k]) + } + } + return err +} diff --git a/service/system/sys_authority_btn.go b/service/system/sys_authority_btn.go new file mode 100644 index 0000000..4034599 --- /dev/null +++ b/service/system/sys_authority_btn.go @@ -0,0 +1,58 @@ +package system + +import ( + "errors" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system" + "miniapp/model/system/request" + "miniapp/model/system/response" +) + +type AuthorityBtnService struct{} + +func (a *AuthorityBtnService) GetAuthorityBtn(req request.SysAuthorityBtnReq) (res response.SysAuthorityBtnRes, err error) { + var authorityBtn []system.SysAuthorityBtn + err = global.GVA_DB.Find(&authorityBtn, "authority_id = ? and sys_menu_id = ?", req.AuthorityId, req.MenuID).Error + if err != nil { + return + } + var selected []uint + for _, v := range authorityBtn { + selected = append(selected, v.SysBaseMenuBtnID) + } + res.Selected = selected + return res, err +} + +func (a *AuthorityBtnService) SetAuthorityBtn(req request.SysAuthorityBtnReq) (err error) { + return global.GVA_DB.Transaction(func(tx *gorm.DB) error { + var authorityBtn []system.SysAuthorityBtn + err = tx.Delete(&[]system.SysAuthorityBtn{}, "authority_id = ? and sys_menu_id = ?", req.AuthorityId, req.MenuID).Error + if err != nil { + return err + } + for _, v := range req.Selected { + authorityBtn = append(authorityBtn, system.SysAuthorityBtn{ + AuthorityId: req.AuthorityId, + SysMenuID: req.MenuID, + SysBaseMenuBtnID: v, + }) + } + if len(authorityBtn) > 0 { + err = tx.Create(&authorityBtn).Error + } + if err != nil { + return err + } + return err + }) +} + +func (a *AuthorityBtnService) CanRemoveAuthorityBtn(ID string) (err error) { + fErr := global.GVA_DB.First(&system.SysAuthorityBtn{}, "sys_base_menu_btn_id = ?", ID).Error + if errors.Is(fErr, gorm.ErrRecordNotFound) { + return nil + } + return errors.New("此按钮正在被使用无法删除") +} diff --git a/service/system/sys_auto_code.go b/service/system/sys_auto_code.go new file mode 100644 index 0000000..9bea314 --- /dev/null +++ b/service/system/sys_auto_code.go @@ -0,0 +1,958 @@ +package system + +import ( + "archive/zip" + "encoding/json" + "errors" + "fmt" + "io" + "mime/multipart" + "os" + "path/filepath" + "strconv" + "strings" + "text/template" + + ast2 "miniapp/utils/ast" + + cp "github.com/otiai10/copy" + "go.uber.org/zap" + "miniapp/resource/autocode_template/subcontract" + + "miniapp/global" + "miniapp/model/system" + "miniapp/utils" + + "gorm.io/gorm" +) + +const ( + autoPath = "autocode_template/" + autocodePath = "resource/autocode_template" + plugPath = "resource/plug_template" + packageService = "service/%s/enter.go" + packageServiceName = "service" + packageRouter = "router/%s/enter.go" + packageRouterName = "router" + packageAPI = "api/v1/%s/enter.go" + packageAPIName = "api/v1" +) + +type autoPackage struct { + path string + temp string + name string +} + +var ( + packageInjectionMap map[string]astInjectionMeta + injectionPaths []injectionMeta +) + +func Init(Package string) { + injectionPaths = []injectionMeta{ + { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SApi, Package), "enter.go"), + funcName: "ApiGroup", + structNameF: "%sApi", + }, + { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRouter, Package), "enter.go"), + funcName: "RouterGroup", + structNameF: "%sRouter", + }, + { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SService, Package), "enter.go"), + funcName: "ServiceGroup", + structNameF: "%sService", + }, + } + + packageInjectionMap = map[string]astInjectionMeta{ + packageServiceName: { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, "service", "enter.go"), + importCodeF: "miniapp/%s/%s", + packageNameF: "%s", + groupName: "ServiceGroup", + structNameF: "%sServiceGroup", + }, + packageRouterName: { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, "router", "enter.go"), + importCodeF: "miniapp/%s/%s", + packageNameF: "%s", + groupName: "RouterGroup", + structNameF: "%s", + }, + packageAPIName: { + path: filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, "api/v1", "enter.go"), + importCodeF: "miniapp/%s/%s", + packageNameF: "%s", + groupName: "ApiGroup", + structNameF: "%sApiGroup", + }, + } +} + +type injectionMeta struct { + path string + funcName string + structNameF string // 带格式化的 +} + +type astInjectionMeta struct { + path string + importCodeF string + structNameF string + packageNameF string + groupName string +} + +type tplData struct { + template *template.Template + autoPackage string + locationPath string + autoCodePath string + autoMoveFilePath string +} + +type AutoCodeService struct{} + +var AutoCodeServiceApp = new(AutoCodeService) + +// @author: [songzhibin97](https://github.com/songzhibin97) +// @function: PreviewTemp +// @description: 预览创建代码 +// @param: model.AutoCodeStruct +// @return: map[string]string, error + +func (autoCodeService *AutoCodeService) PreviewTemp(autoCode system.AutoCodeStruct) (map[string]string, error) { + makeDictTypes(&autoCode) + for i := range autoCode.Fields { + if autoCode.Fields[i].FieldType == "time.Time" { + autoCode.HasTimer = true + } + if autoCode.Fields[i].Require { + autoCode.NeedValid = true + } + if autoCode.Fields[i].Sort { + autoCode.NeedSort = true + } + if autoCode.Fields[i].FieldType == "picture" { + autoCode.HasPic = true + } + if autoCode.Fields[i].FieldType == "video" { + autoCode.HasPic = true + } + if autoCode.Fields[i].FieldType == "richtext" { + autoCode.HasRichText = true + } + if autoCode.Fields[i].FieldType == "pictures" { + autoCode.HasPic = true + autoCode.NeedJSON = true + } + if autoCode.Fields[i].FieldType == "file" { + autoCode.HasFile = true + autoCode.NeedJSON = true + } + } + dataList, _, needMkdir, err := autoCodeService.getNeedList(&autoCode) + if err != nil { + return nil, err + } + + // 写入文件前,先创建文件夹 + if err = utils.CreateDir(needMkdir...); err != nil { + return nil, err + } + + // 创建map + ret := make(map[string]string) + + // 生成map + for _, value := range dataList { + ext := "" + if ext = filepath.Ext(value.autoCodePath); ext == ".txt" { + continue + } + f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0o755) + if err != nil { + return nil, err + } + if err = value.template.Execute(f, autoCode); err != nil { + return nil, err + } + _ = f.Close() + f, err = os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_RDONLY, 0o755) + if err != nil { + return nil, err + } + builder := strings.Builder{} + builder.WriteString("```") + + if ext != "" && strings.Contains(ext, ".") { + builder.WriteString(strings.Replace(ext, ".", "", -1)) + } + builder.WriteString("\n\n") + data, err := io.ReadAll(f) + if err != nil { + return nil, err + } + builder.Write(data) + builder.WriteString("\n\n```") + + pathArr := strings.Split(value.autoCodePath, string(os.PathSeparator)) + ret[pathArr[1]+"-"+pathArr[3]] = builder.String() + _ = f.Close() + + } + defer func() { // 移除中间文件 + if err := os.RemoveAll(autoPath); err != nil { + return + } + }() + return ret, nil +} + +func makeDictTypes(autoCode *system.AutoCodeStruct) { + DictTypeM := make(map[string]string) + for _, v := range autoCode.Fields { + if v.DictType != "" { + DictTypeM[v.DictType] = "" + } + } + + for k := range DictTypeM { + autoCode.DictTypes = append(autoCode.DictTypes, k) + } +} + +// @author: [piexlmax](https://github.com/piexlmax) +// @function: CreateTemp +// @description: 创建代码 +// @param: model.AutoCodeStruct +// @return: err error + +func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruct, ids ...uint) (err error) { + makeDictTypes(&autoCode) + for i := range autoCode.Fields { + if autoCode.Fields[i].FieldType == "time.Time" { + autoCode.HasTimer = true + } + if autoCode.Fields[i].Require { + autoCode.NeedValid = true + } + if autoCode.Fields[i].Sort { + autoCode.NeedSort = true + } + if autoCode.Fields[i].FieldType == "picture" { + autoCode.HasPic = true + } + if autoCode.Fields[i].FieldType == "video" { + autoCode.HasPic = true + } + if autoCode.Fields[i].FieldType == "richtext" { + autoCode.HasRichText = true + } + if autoCode.Fields[i].FieldType == "pictures" { + autoCode.NeedJSON = true + autoCode.HasPic = true + } + if autoCode.Fields[i].FieldType == "file" { + autoCode.NeedJSON = true + autoCode.HasFile = true + } + } + // 增加判断: 重复创建struct + if autoCode.AutoMoveFile && AutoCodeHistoryServiceApp.Repeat(autoCode.BusinessDB, autoCode.StructName, autoCode.Package) { + return RepeatErr + } + dataList, fileList, needMkdir, err := autoCodeService.getNeedList(&autoCode) + if err != nil { + return err + } + meta, _ := json.Marshal(autoCode) + // 写入文件前,先创建文件夹 + if err = utils.CreateDir(needMkdir...); err != nil { + return err + } + + // 生成文件 + for _, value := range dataList { + f, err := os.OpenFile(value.autoCodePath, os.O_CREATE|os.O_WRONLY, 0o755) + if err != nil { + return err + } + if err = value.template.Execute(f, autoCode); err != nil { + return err + } + _ = f.Close() + } + + defer func() { // 移除中间文件 + if err := os.RemoveAll(autoPath); err != nil { + return + } + }() + bf := strings.Builder{} + idBf := strings.Builder{} + injectionCodeMeta := strings.Builder{} + for _, id := range ids { + idBf.WriteString(strconv.Itoa(int(id))) + idBf.WriteString(";") + } + if autoCode.AutoMoveFile { // 判断是否需要自动转移 + Init(autoCode.Package) + for index := range dataList { + autoCodeService.addAutoMoveFile(&dataList[index]) + } + // 判断目标文件是否都可以移动 + for _, value := range dataList { + if utils.FileExist(value.autoMoveFilePath) { + return errors.New(fmt.Sprintf("目标文件已存在:%s\n", value.autoMoveFilePath)) + } + } + for _, value := range dataList { // 移动文件 + if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil { + return err + } + } + + { + // 在gorm.go 注入 自动迁移 + path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "gorm.go") + varDB := utils.MaheHump(autoCode.BusinessDB) + ast2.AddRegisterTablesAst(path, "RegisterTables", autoCode.Package, varDB, autoCode.BusinessDB, autoCode.StructName) + } + + { + // router.go 注入 自动迁移 + path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "router.go") + ast2.AddRouterCode(path, "Routers", autoCode.Package, autoCode.StructName) + } + // 给各个enter进行注入 + err = injectionCode(autoCode.StructName, &injectionCodeMeta) + if err != nil { + return + } + // 保存生成信息 + for _, data := range dataList { + if len(data.autoMoveFilePath) != 0 { + bf.WriteString(data.autoMoveFilePath) + bf.WriteString(";") + } + } + } else { // 打包 + if err = utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil { + return err + } + } + if autoCode.AutoMoveFile || autoCode.AutoCreateApiToSql { + if autoCode.TableName != "" { + err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory( + string(meta), + autoCode.StructName, + autoCode.Description, + bf.String(), + injectionCodeMeta.String(), + autoCode.TableName, + idBf.String(), + autoCode.Package, + autoCode.BusinessDB, + ) + } else { + err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory( + string(meta), + autoCode.StructName, + autoCode.Description, + bf.String(), + injectionCodeMeta.String(), + autoCode.StructName, + idBf.String(), + autoCode.Package, + autoCode.BusinessDB, + ) + } + } + if err != nil { + return err + } + if autoCode.AutoMoveFile { + return system.ErrAutoMove + } + return nil +} + +// @author: [piexlmax](https://github.com/piexlmax) +// @function: GetAllTplFile +// @description: 获取 pathName 文件夹下所有 tpl 文件 +// @param: pathName string, fileList []string +// @return: []string, error + +func (autoCodeService *AutoCodeService) GetAllTplFile(pathName string, fileList []string) ([]string, error) { + files, err := os.ReadDir(pathName) + for _, fi := range files { + if fi.IsDir() { + fileList, err = autoCodeService.GetAllTplFile(pathName+"/"+fi.Name(), fileList) + if err != nil { + return nil, err + } + } else { + if strings.HasSuffix(fi.Name(), ".tpl") { + fileList = append(fileList, pathName+"/"+fi.Name()) + } + } + } + return fileList, err +} + +// @author: [piexlmax](https://github.com/piexlmax) +// @function: GetDB +// @description: 获取指定数据库和指定数据表的所有字段名,类型值等 +// @param: tableName string, dbName string +// @return: err error, Columns []request.ColumnReq + +func (autoCodeService *AutoCodeService) DropTable(BusinessDb, tableName string) error { + if BusinessDb != "" { + return global.MustGetGlobalDBByDBName(BusinessDb).Exec("DROP TABLE " + tableName).Error + } else { + return global.GVA_DB.Exec("DROP TABLE " + tableName).Error + } +} + +// @author: [SliverHorn](https://github.com/SliverHorn) +// @author: [songzhibin97](https://github.com/songzhibin97) +// @function: addAutoMoveFile +// @description: 生成对应的迁移文件路径 +// @param: *tplData +// @return: null + +func (autoCodeService *AutoCodeService) addAutoMoveFile(data *tplData) { + base := filepath.Base(data.autoCodePath) + fileSlice := strings.Split(data.autoCodePath, string(os.PathSeparator)) + n := len(fileSlice) + if n <= 2 { + return + } + if strings.Contains(fileSlice[1], "server.exe.exe") { + if strings.Contains(fileSlice[n-2], "router") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, + fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRouter, data.autoPackage), base) + } else if strings.Contains(fileSlice[n-2], "api") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SApi, data.autoPackage), base) + } else if strings.Contains(fileSlice[n-2], "service") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SService, data.autoPackage), base) + } else if strings.Contains(fileSlice[n-2], "model") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SModel, data.autoPackage), base) + } else if strings.Contains(fileSlice[n-2], "request") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SRequest, data.autoPackage), base) + } + } else if strings.Contains(fileSlice[1], "web") { + if strings.Contains(fileSlice[n-1], "js") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WApi, base) + } else if strings.Contains(fileSlice[n-2], "form") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WForm, filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), strings.TrimSuffix(base, filepath.Ext(base))+"Form.vue") + } else if strings.Contains(fileSlice[n-2], "table") { + data.autoMoveFilePath = filepath.Join(global.GVA_CONFIG.AutoCode.Root, + global.GVA_CONFIG.AutoCode.Web, global.GVA_CONFIG.AutoCode.WTable, filepath.Base(filepath.Dir(filepath.Dir(data.autoCodePath))), base) + } + } +} + +// @author: [piexlmax](https://github.com/piexlmax) +// @author: [SliverHorn](https://github.com/SliverHorn) +// @function: CreateApi +// @description: 自动创建api数据, +// @param: a *model.AutoCodeStruct +// @return: err error + +func (autoCodeService *AutoCodeService) AutoCreateApi(a *system.AutoCodeStruct) (ids []uint, err error) { + apiList := []system.SysApi{ + { + Path: "/" + a.Abbreviation + "/" + "create" + a.StructName, + Description: "新增" + a.Description, + ApiGroup: a.Description, + Method: "POST", + }, + { + Path: "/" + a.Abbreviation + "/" + "delete" + a.StructName, + Description: "删除" + a.Description, + ApiGroup: a.Description, + Method: "DELETE", + }, + { + Path: "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds", + Description: "批量删除" + a.Description, + ApiGroup: a.Description, + Method: "DELETE", + }, + { + Path: "/" + a.Abbreviation + "/" + "update" + a.StructName, + Description: "更新" + a.Description, + ApiGroup: a.Description, + Method: "PUT", + }, + { + Path: "/" + a.Abbreviation + "/" + "find" + a.StructName, + Description: "根据ID获取" + a.Description, + ApiGroup: a.Description, + Method: "GET", + }, + { + Path: "/" + a.Abbreviation + "/" + "get" + a.StructName + "List", + Description: "获取" + a.Description + "列表", + ApiGroup: a.Description, + Method: "GET", + }, + } + err = global.GVA_DB.Transaction(func(tx *gorm.DB) error { + for _, v := range apiList { + var api system.SysApi + if errors.Is(tx.Where("path = ? AND method = ?", v.Path, v.Method).First(&api).Error, gorm.ErrRecordNotFound) { + if err = tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务 + return err + } else { + ids = append(ids, v.ID) + } + } + } + return nil + }) + return ids, err +} + +func (autoCodeService *AutoCodeService) getNeedList(autoCode *system.AutoCodeStruct) (dataList []tplData, fileList []string, needMkdir []string, err error) { + // 去除所有空格 + utils.TrimSpace(autoCode) + for _, field := range autoCode.Fields { + utils.TrimSpace(field) + } + // 获取 basePath 文件夹下所有tpl文件 + tplFileList, err := autoCodeService.GetAllTplFile(autocodePath, nil) + if err != nil { + return nil, nil, nil, err + } + dataList = make([]tplData, 0, len(tplFileList)) + fileList = make([]string, 0, len(tplFileList)) + needMkdir = make([]string, 0, len(tplFileList)) // 当文件夹下存在多个tpl文件时,改为map更合理 + // 根据文件路径生成 tplData 结构体,待填充数据 + for _, value := range tplFileList { + dataList = append(dataList, tplData{locationPath: value, autoPackage: autoCode.Package}) + } + // 生成 *Template, 填充 template 字段 + for index, value := range dataList { + dataList[index].template, err = template.ParseFiles(value.locationPath) + if err != nil { + return nil, nil, nil, err + } + } + // 生成文件路径,填充 autoCodePath 字段,readme.txt.tpl不符合规则,需要特殊处理 + // resource/template/web/api.js.tpl -> autoCode/web/autoCode.PackageName/api/autoCode.PackageName.js + // resource/template/readme.txt.tpl -> autoCode/readme.txt + for index, value := range dataList { + trimBase := strings.TrimPrefix(value.locationPath, autocodePath+"/") + if trimBase == "readme.txt.tpl" { + dataList[index].autoCodePath = autoPath + "readme.txt" + continue + } + + if lastSeparator := strings.LastIndex(trimBase, "/"); lastSeparator != -1 { + origFileName := strings.TrimSuffix(trimBase[lastSeparator+1:], ".tpl") + firstDot := strings.Index(origFileName, ".") + if firstDot != -1 { + var fileName string + if origFileName[firstDot:] != ".go" { + fileName = autoCode.PackageName + origFileName[firstDot:] + } else { + fileName = autoCode.HumpPackageName + origFileName[firstDot:] + } + + dataList[index].autoCodePath = filepath.Join(autoPath, trimBase[:lastSeparator], autoCode.PackageName, + origFileName[:firstDot], fileName) + } + } + + if lastSeparator := strings.LastIndex(dataList[index].autoCodePath, string(os.PathSeparator)); lastSeparator != -1 { + needMkdir = append(needMkdir, dataList[index].autoCodePath[:lastSeparator]) + } + } + for _, value := range dataList { + fileList = append(fileList, value.autoCodePath) + } + return dataList, fileList, needMkdir, err +} + +// injectionCode 封装代码注入 +func injectionCode(structName string, bf *strings.Builder) error { + for _, meta := range injectionPaths { + code := fmt.Sprintf(meta.structNameF, structName) + ast2.ImportForAutoEnter(meta.path, meta.funcName, code) + bf.WriteString(fmt.Sprintf("%s@%s@%s;", meta.path, meta.funcName, code)) + } + return nil +} + +func (autoCodeService *AutoCodeService) CreateAutoCode(s *system.SysAutoCode) error { + if s.PackageName == "autocode" || s.PackageName == "system" || s.PackageName == "example" || s.PackageName == "" { + return errors.New("不能使用已保留的package name") + } + if !errors.Is(global.GVA_DB.Where("package_name = ?", s.PackageName).First(&system.SysAutoCode{}).Error, gorm.ErrRecordNotFound) { + return errors.New("存在相同PackageName") + } + if e := autoCodeService.CreatePackageTemp(s.PackageName); e != nil { + return e + } + return global.GVA_DB.Create(&s).Error +} + +func (autoCodeService *AutoCodeService) GetPackage() (pkgList []system.SysAutoCode, err error) { + err = global.GVA_DB.Find(&pkgList).Error + return pkgList, err +} + +func (autoCodeService *AutoCodeService) DelPackage(a system.SysAutoCode) error { + return global.GVA_DB.Delete(&a).Error +} + +func (autoCodeService *AutoCodeService) CreatePackageTemp(packageName string) error { + Init(packageName) + pendingTemp := []autoPackage{{ + path: packageService, + name: packageServiceName, + temp: string(subcontract.Server), + }, { + path: packageRouter, + name: packageRouterName, + temp: string(subcontract.Router), + }, { + path: packageAPI, + name: packageAPIName, + temp: string(subcontract.API), + }} + for i, s := range pendingTemp { + pendingTemp[i].path = filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, filepath.Clean(fmt.Sprintf(s.path, packageName))) + } + // 选择模板 + for _, s := range pendingTemp { + err := os.MkdirAll(filepath.Dir(s.path), 0755) + if err != nil { + return err + } + + f, err := os.Create(s.path) + if err != nil { + return err + } + + defer f.Close() + + temp, err := template.New("").Parse(s.temp) + if err != nil { + return err + } + err = temp.Execute(f, struct { + PackageName string `json:"package_name"` + }{packageName}) + if err != nil { + return err + } + } + // 创建完成后在对应的位置插入结构代码 + for _, v := range pendingTemp { + meta := packageInjectionMap[v.name] + if err := ast2.ImportReference(meta.path, fmt.Sprintf(meta.importCodeF, v.name, packageName), fmt.Sprintf(meta.structNameF, utils.FirstUpper(packageName)), fmt.Sprintf(meta.packageNameF, packageName), meta.groupName); err != nil { + return err + } + } + return nil +} + +// CreatePlug 自动创建插件模板 +func (autoCodeService *AutoCodeService) CreatePlug(plug system.AutoPlugReq) error { + // 检查列表参数是否有效 + plug.CheckList() + tplFileList, _ := autoCodeService.GetAllTplFile(plugPath, nil) + for _, tpl := range tplFileList { + temp, err := template.ParseFiles(tpl) + if err != nil { + zap.L().Error("parse err", zap.String("tpl", tpl), zap.Error(err)) + return err + } + pathArr := strings.SplitAfter(tpl, "/") + if strings.Index(pathArr[2], "tpl") < 0 { + dirPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SPlug, plug.Snake+"/"+pathArr[2])) + os.MkdirAll(dirPath, 0755) + } + file := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fmt.Sprintf(global.GVA_CONFIG.AutoCode.SPlug, plug.Snake+"/"+tpl[len(plugPath):len(tpl)-4])) + f, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0666) + if err != nil { + zap.L().Error("open file", zap.String("tpl", tpl), zap.Error(err), zap.Any("plug", plug)) + return err + } + defer f.Close() + + err = temp.Execute(f, plug) + if err != nil { + zap.L().Error("exec err", zap.String("tpl", tpl), zap.Error(err), zap.Any("plug", plug)) + return err + } + } + return nil +} + +func (autoCodeService *AutoCodeService) InstallPlugin(file *multipart.FileHeader) (web, server int, err error) { + const GVAPLUGPINATH = "./gva-plug-temp/" + defer os.RemoveAll(GVAPLUGPINATH) + _, err = os.Stat(GVAPLUGPINATH) + if os.IsNotExist(err) { + os.Mkdir(GVAPLUGPINATH, os.ModePerm) + } + + src, err := file.Open() + if err != nil { + return -1, -1, err + } + defer src.Close() + + out, err := os.Create(GVAPLUGPINATH + file.Filename) + if err != nil { + return -1, -1, err + } + defer out.Close() + + _, err = io.Copy(out, src) + + paths, err := utils.Unzip(GVAPLUGPINATH+file.Filename, GVAPLUGPINATH) + paths = filterFile(paths) + var webIndex = -1 + var serverIndex = -1 + for i := range paths { + paths[i] = filepath.ToSlash(paths[i]) + pathArr := strings.Split(paths[i], "/") + ln := len(pathArr) + if ln < 2 { + continue + } + if pathArr[ln-2] == "server.exe.exe" && pathArr[ln-1] == "plugin" { + serverIndex = i + } + if pathArr[ln-2] == "web" && pathArr[ln-1] == "plugin" { + webIndex = i + } + } + if webIndex == -1 && serverIndex == -1 { + zap.L().Error("非标准插件,请按照文档自动迁移使用") + return webIndex, serverIndex, errors.New("非标准插件,请按照文档自动迁移使用") + } + + if webIndex != -1 { + err = installation(paths[webIndex], global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.Web) + if err != nil { + return webIndex, serverIndex, err + } + } + + if serverIndex != -1 { + err = installation(paths[serverIndex], global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.Server) + } + return webIndex, serverIndex, err +} + +func installation(path string, formPath string, toPath string) error { + arr := strings.Split(filepath.ToSlash(path), "/") + ln := len(arr) + if ln < 3 { + return errors.New("arr") + } + name := arr[ln-3] + + var form = filepath.ToSlash(global.GVA_CONFIG.AutoCode.Root + formPath + "/" + path) + var to = filepath.ToSlash(global.GVA_CONFIG.AutoCode.Root + toPath + "/plugin/") + _, err := os.Stat(to + name) + if err == nil { + zap.L().Error("autoPath 已存在同名插件,请自行手动安装", zap.String("to", to)) + return errors.New(toPath + "已存在同名插件,请自行手动安装") + } + return cp.Copy(form, to, cp.Options{Skip: skipMacSpecialDocument}) +} + +func filterFile(paths []string) []string { + np := make([]string, 0, len(paths)) + for _, path := range paths { + if ok, _ := skipMacSpecialDocument(path); ok { + continue + } + np = append(np, path) + } + return np +} + +func skipMacSpecialDocument(src string) (bool, error) { + if strings.Contains(src, ".DS_Store") || strings.Contains(src, "__MACOSX") { + return true, nil + } + return false, nil +} + +func (autoCodeService *AutoCodeService) PubPlug(plugName string) (zipPath string, err error) { + if plugName == "" { + return "", errors.New("插件名称不能为空") + } + + // 防止路径穿越 + plugName = filepath.Clean(plugName) + + webPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Web, "plugin", plugName) + serverPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "plugin", plugName) + // 创建一个新的zip文件 + + // 判断目录是否存在 + webInfo, err := os.Stat(webPath) + if err != nil { + return "", errors.New("web路径不存在") + } + serverInfo, err := os.Stat(serverPath) + if err != nil { + return "", errors.New("server路径不存在") + } + + fileName := plugName + ".zip" + // 创建一个新的zip文件 + zipFile, err := os.Create(fileName) + if err != nil { + fmt.Println(err) + return + } + defer zipFile.Close() + + // 创建一个zip写入器 + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // 创建一个新的文件头 + webHeader, err := zip.FileInfoHeader(webInfo) + if err != nil { + return + } + + // 创建一个新的文件头 + serverHeader, err := zip.FileInfoHeader(serverInfo) + if err != nil { + return + } + + webHeader.Name = filepath.Join(plugName, "web", "plugin") + serverHeader.Name = filepath.Join(plugName, "server.exe.exe", "plugin") + + // 将文件添加到zip归档中 + _, err = zipWriter.CreateHeader(serverHeader) + _, err = zipWriter.CreateHeader(webHeader) + + // 遍历webPath目录并将所有非隐藏文件添加到zip归档中 + err = filepath.Walk(webPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // 跳过隐藏文件 + if strings.HasPrefix(info.Name(), ".") { + return nil + } + + // 创建一个新的文件头 + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // 将文件头的名称设置为文件的相对路径 + rel, _ := filepath.Rel(webPath, path) + header.Name = filepath.Join(plugName, "web", "plugin", plugName, rel) + + // 将文件添加到zip归档中 + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + // 打开文件并将其内容复制到zip归档中 + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(writer, file) + if err != nil { + return err + } + return nil + }) + if err != nil { + return + } + + // 遍历serverPath目录并将所有非隐藏文件添加到zip归档中 + err = filepath.Walk(serverPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // 跳过隐藏文件和目录 + if strings.HasPrefix(info.Name(), ".") { + return nil + } + + // 创建一个新的文件头 + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // 将文件头的名称设置为文件的相对路径 + rel, _ := filepath.Rel(serverPath, path) + header.Name = filepath.Join(plugName, "server.exe.exe", "plugin", plugName, rel) + // 将文件添加到zip归档中 + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + // 打开文件并将其内容复制到zip归档中 + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(writer, file) + if err != nil { + return err + } + + return nil + }) + if err != nil { + return + } + return filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fileName), nil +} diff --git a/service/system/sys_auto_code_interface.go b/service/system/sys_auto_code_interface.go new file mode 100644 index 0000000..633c798 --- /dev/null +++ b/service/system/sys_auto_code_interface.go @@ -0,0 +1,49 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/system/response" +) + +type Database interface { + GetDB(businessDB string) (data []response.Db, err error) + GetTables(businessDB string, dbName string) (data []response.Table, err error) + GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) +} + +func (autoCodeService *AutoCodeService) Database(businessDB string) Database { + + if businessDB == "" { + switch global.GVA_CONFIG.System.DbType { + case "mysql": + return AutoCodeMysql + case "pgsql": + return AutoCodePgsql + case "sqlite": + return AutoCodeSqlite + default: + return AutoCodeMysql + } + } else { + for _, info := range global.GVA_CONFIG.DBList { + if info.AliasName == businessDB { + switch info.Type { + case "mysql": + return AutoCodeMysql + case "mssql": + return AutoCodeMssql + case "pgsql": + return AutoCodePgsql + case "oracle": + return AutoCodeOracle + case "sqlite": + return AutoCodeSqlite + default: + return AutoCodeMysql + } + } + } + return AutoCodeMysql + } + +} diff --git a/service/system/sys_auto_code_mssql.go b/service/system/sys_auto_code_mssql.go new file mode 100644 index 0000000..60daa07 --- /dev/null +++ b/service/system/sys_auto_code_mssql.go @@ -0,0 +1,58 @@ +package system + +import ( + "fmt" + "miniapp/global" + "miniapp/model/system/response" +) + +var AutoCodeMssql = new(autoCodeMssql) + +type autoCodeMssql struct{} + +// GetDB 获取数据库的所有数据库名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMssql) GetDB(businessDB string) (data []response.Db, err error) { + var entities []response.Db + sql := "select name AS 'database' from sysdatabases;" + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + } + return entities, err +} + +// GetTables 获取数据库的所有表名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMssql) GetTables(businessDB string, dbName string) (data []response.Table, err error) { + var entities []response.Table + + sql := fmt.Sprintf(`select name as 'table_name' from %s.DBO.sysobjects where xtype='U'`, dbName) + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + } + + return entities, err +} + +// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMssql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) { + var entities []response.Column + sql := fmt.Sprintf(`select sc.name as column_name,st.name as data_type, sc.length as data_type_long + from %s.DBO.syscolumns sc,systypes st where sc.xtype=st.xtype and st.usertype=0 and sc.id in (select id from %s.DBO.sysobjects where xtype='U' and name='%s');`, dbName, dbName, tableName) + + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + } + + return entities, err +} diff --git a/service/system/sys_auto_code_mysql.go b/service/system/sys_auto_code_mysql.go new file mode 100644 index 0000000..20a7a2b --- /dev/null +++ b/service/system/sys_auto_code_mysql.go @@ -0,0 +1,69 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/system/response" +) + +var AutoCodeMysql = new(autoCodeMysql) + +type autoCodeMysql struct{} + +// GetDB 获取数据库的所有数据库名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMysql) GetDB(businessDB string) (data []response.Db, err error) { + var entities []response.Db + sql := "SELECT SCHEMA_NAME AS `database` FROM INFORMATION_SCHEMA.SCHEMATA;" + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + } + return entities, err +} + +// GetTables 获取数据库的所有表名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMysql) GetTables(businessDB string, dbName string) (data []response.Table, err error) { + var entities []response.Table + sql := `select table_name as table_name from information_schema.tables where table_schema = ?` + if businessDB == "" { + err = global.GVA_DB.Raw(sql, dbName).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql, dbName).Scan(&entities).Error + } + + return entities, err +} + +// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeMysql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) { + var entities []response.Column + sql := ` + SELECT COLUMN_NAME column_name, + DATA_TYPE data_type, + CASE DATA_TYPE + WHEN 'longtext' THEN c.CHARACTER_MAXIMUM_LENGTH + WHEN 'varchar' THEN c.CHARACTER_MAXIMUM_LENGTH + WHEN 'double' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE) + WHEN 'decimal' THEN CONCAT_WS(',', c.NUMERIC_PRECISION, c.NUMERIC_SCALE) + WHEN 'int' THEN c.NUMERIC_PRECISION + WHEN 'bigint' THEN c.NUMERIC_PRECISION + ELSE '' END AS data_type_long, + COLUMN_COMMENT column_comment + FROM INFORMATION_SCHEMA.COLUMNS c + WHERE table_name = ? + AND table_schema = ? + ` + if businessDB == "" { + err = global.GVA_DB.Raw(sql, tableName, dbName).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error + } + + return entities, err +} diff --git a/service/system/sys_auto_code_oracle.go b/service/system/sys_auto_code_oracle.go new file mode 100644 index 0000000..6c3a639 --- /dev/null +++ b/service/system/sys_auto_code_oracle.go @@ -0,0 +1,53 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/system/response" +) + +var AutoCodeOracle = new(autoCodeOracle) + +type autoCodeOracle struct{} + +// GetDB 获取数据库的所有数据库名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeOracle) GetDB(businessDB string) (data []response.Db, err error) { + var entities []response.Db + sql := `SELECT lower(username) AS "database" FROM all_users` + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + return entities, err +} + +// GetTables 获取数据库的所有表名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeOracle) GetTables(businessDB string, dbName string) (data []response.Table, err error) { + var entities []response.Table + sql := `select lower(table_name) as "table_name" from all_tables where lower(owner) = ?` + + err = global.GVA_DBList[businessDB].Raw(sql, dbName).Scan(&entities).Error + return entities, err +} + +// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (s *autoCodeOracle) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) { + var entities []response.Column + sql := ` + select lower(a.COLUMN_NAME) as "column_name", + (CASE WHEN a.DATA_TYPE = 'NUMBER' AND a.DATA_SCALE=0 THEN 'int' else lower(a.DATA_TYPE) end) as "data_type", + (CASE WHEN a.DATA_TYPE = 'NUMBER' THEN a.DATA_PRECISION else a.DATA_LENGTH end) as "data_type_long", + b.COMMENTS as "column_comment" + from all_tab_columns a , all_col_comments b + where a.OWNER = b.OWNER + and a.TABLE_NAME = b.TABLE_NAME + and a.COLUMN_NAME = b.COLUMN_NAME + and lower(a.table_name) = ? + and lower(a.OWNER) = ? +` + + err = global.GVA_DBList[businessDB].Raw(sql, tableName, dbName).Scan(&entities).Error + return entities, err +} diff --git a/service/system/sys_auto_code_pgsql.go b/service/system/sys_auto_code_pgsql.go new file mode 100644 index 0000000..b3ab042 --- /dev/null +++ b/service/system/sys_auto_code_pgsql.go @@ -0,0 +1,108 @@ +package system + +import ( + "github.com/pkg/errors" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "gorm.io/gorm/logger" + "miniapp/global" + "miniapp/model/system/response" +) + +var AutoCodePgsql = new(autoCodePgsql) + +type autoCodePgsql struct{} + +// GetDB 获取数据库的所有数据库名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodePgsql) GetDB(businessDB string) (data []response.Db, err error) { + var entities []response.Db + sql := `SELECT datname as database FROM pg_database WHERE datistemplate = false` + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&entities).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&entities).Error + } + + return entities, err +} + +// GetTables 获取数据库的所有表名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodePgsql) GetTables(businessDB string, dbName string) (data []response.Table, err error) { + var entities []response.Table + sql := `select table_name as table_name from information_schema.tables where table_catalog = ? and table_schema = ?` + db, _err := gorm.Open(postgres.Open(global.GVA_CONFIG.Pgsql.LinkDsn(dbName)), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)}) + if _err != nil { + return nil, errors.Wrapf(err, "[pgsql] 连接 数据库(%s)的表失败!", dbName) + } + + err = db.Raw(sql, dbName, "public").Scan(&entities).Error + return entities, err +} + +// GetColumn 获取指定数据库和指定数据表的所有字段名,类型值等 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodePgsql) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) { + // todo 数据获取不全, 待完善sql + sql := ` + SELECT psc.COLUMN_NAME AS COLUMN_NAME, + psc.udt_name AS data_type, +CASE + psc.udt_name + WHEN 'text' THEN + concat_ws ( '', '', psc.CHARACTER_MAXIMUM_LENGTH ) + WHEN 'varchar' THEN + concat_ws ( '', '', psc.CHARACTER_MAXIMUM_LENGTH ) + WHEN 'smallint' THEN + concat_ws ( ',', psc.NUMERIC_PRECISION, psc.NUMERIC_SCALE ) + WHEN 'decimal' THEN + concat_ws ( ',', psc.NUMERIC_PRECISION, psc.NUMERIC_SCALE ) + WHEN 'integer' THEN + concat_ws ( '', '', psc.NUMERIC_PRECISION ) + WHEN 'int4' THEN + concat_ws ( '', '', psc.NUMERIC_PRECISION ) + WHEN 'int8' THEN + concat_ws ( '', '', psc.NUMERIC_PRECISION ) + WHEN 'bigint' THEN + concat_ws ( '', '', psc.NUMERIC_PRECISION ) + WHEN 'timestamp' THEN + concat_ws ( '', '', psc.datetime_precision ) + ELSE '' + END AS data_type_long, + ( + SELECT + pd.description + FROM + pg_description pd + WHERE + (pd.objoid,pd.objsubid) in ( + SELECT pa.attrelid,pa.attnum + FROM + pg_attribute pa + WHERE pa.attrelid = ( SELECT oid FROM pg_class pc WHERE + pc.relname = psc.table_name + ) + and attname = psc.column_name + ) + ) AS column_comment +FROM + INFORMATION_SCHEMA.COLUMNS psc +WHERE + table_catalog = ? + AND table_schema = 'public' + AND TABLE_NAME = ?; + ` + var entities []response.Column + db, _err := gorm.Open(postgres.Open(global.GVA_CONFIG.Pgsql.LinkDsn(dbName)), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)}) + if _err != nil { + return nil, errors.Wrapf(err, "[pgsql] 连接 数据库(%s)的表(%s)失败!", dbName, tableName) + } + //sql = strings.ReplaceAll(sql, "@table_catalog", dbName) + //sql = strings.ReplaceAll(sql, "@table_name", tableName) + err = db.Raw(sql, dbName, tableName).Scan(&entities).Error + return entities, err +} diff --git a/service/system/sys_auto_code_sqlite.go b/service/system/sys_auto_code_sqlite.go new file mode 100644 index 0000000..4e455a9 --- /dev/null +++ b/service/system/sys_auto_code_sqlite.go @@ -0,0 +1,82 @@ +package system + +import ( + "fmt" + "miniapp/global" + "miniapp/model/system/response" + "path/filepath" + "strings" +) + +var AutoCodeSqlite = new(autoCodeSqlite) + +type autoCodeSqlite struct{} + +// GetDB 获取数据库的所有数据库名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodeSqlite) GetDB(businessDB string) (data []response.Db, err error) { + var entities []response.Db + sql := "PRAGMA database_list;" + var databaseList []struct { + File string `gorm:"column:file"` + } + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Find(&databaseList).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Find(&databaseList).Error + } + for _, database := range databaseList { + if database.File != "" { + fileName := filepath.Base(database.File) + fileExt := filepath.Ext(fileName) + fileNameWithoutExt := strings.TrimSuffix(fileName, fileExt) + + entities = append(entities, response.Db{fileNameWithoutExt}) + } + } + // entities = append(entities, response.Db{global.GVA_CONFIG.Sqlite.Dbname}) + return entities, err +} + +// GetTables 获取数据库的所有表名 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodeSqlite) GetTables(businessDB string, dbName string) (data []response.Table, err error) { + var entities []response.Table + sql := `SELECT name FROM sqlite_master WHERE type='table'` + tabelNames := []string{} + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Find(&tabelNames).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Find(&tabelNames).Error + } + for _, tabelName := range tabelNames { + entities = append(entities, response.Table{tabelName}) + } + return entities, err +} + +// GetColumn 获取指定数据表的所有字段名,类型值等 +// Author [piexlmax](https://github.com/piexlmax) +// Author [SliverHorn](https://github.com/SliverHorn) +func (a *autoCodeSqlite) GetColumn(businessDB string, tableName string, dbName string) (data []response.Column, err error) { + var entities []response.Column + sql := fmt.Sprintf("PRAGMA table_info(%s);", tableName) + var columnInfos []struct { + Name string `gorm:"column:name"` + Type string `gorm:"column:type"` + } + if businessDB == "" { + err = global.GVA_DB.Raw(sql).Scan(&columnInfos).Error + } else { + err = global.GVA_DBList[businessDB].Raw(sql).Scan(&columnInfos).Error + } + for _, columnInfo := range columnInfos { + entities = append(entities, response.Column{ + ColumnName: columnInfo.Name, + DataType: columnInfo.Type, + }) + } + return entities, err +} diff --git a/service/system/sys_autocode_history.go b/service/system/sys_autocode_history.go new file mode 100644 index 0000000..dbefe4e --- /dev/null +++ b/service/system/sys_autocode_history.go @@ -0,0 +1,153 @@ +package system + +import ( + "errors" + "fmt" + systemReq "miniapp/model/system/request" + "miniapp/utils/ast" + "path/filepath" + "strconv" + "strings" + "time" + + "miniapp/model/system/response" + + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" + "miniapp/utils" + + "go.uber.org/zap" +) + +var RepeatErr = errors.New("重复创建") + +type AutoCodeHistoryService struct{} + +var AutoCodeHistoryServiceApp = new(AutoCodeHistoryService) + +// CreateAutoCodeHistory 创建代码生成器历史记录 +// RouterPath : RouterPath@RouterString;RouterPath2@RouterString2 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) CreateAutoCodeHistory(meta, structName, structCNName, autoCodePath string, injectionMeta string, tableName string, apiIds string, Package string, BusinessDB string) error { + return global.GVA_DB.Create(&system.SysAutoCodeHistory{ + Package: Package, + RequestMeta: meta, + AutoCodePath: autoCodePath, + InjectionMeta: injectionMeta, + StructName: structName, + StructCNName: structCNName, + TableName: tableName, + ApiIDs: apiIds, + BusinessDB: BusinessDB, + }).Error +} + +// First 根据id获取代码生成器历史的数据 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) First(info *request.GetById) (string, error) { + var meta string + return meta, global.GVA_DB.Model(system.SysAutoCodeHistory{}).Select("request_meta").Where("id = ?", info.Uint()).First(&meta).Error +} + +// Repeat 检测重复 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) Repeat(businessDB, structName, Package string) bool { + var count int64 + global.GVA_DB.Model(&system.SysAutoCodeHistory{}).Where("business_db = ? and struct_name = ? and package = ? and flag = 0", businessDB, structName, Package).Count(&count) + return count > 0 +} + +// RollBack 回滚 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) RollBack(info *systemReq.RollBack) error { + md := system.SysAutoCodeHistory{} + if err := global.GVA_DB.Where("id = ?", info.ID).First(&md).Error; err != nil { + return err + } + // 清除API表 + + ids := request.IdsReq{} + idsStr := strings.Split(md.ApiIDs, ";") + for i := range idsStr[0 : len(idsStr)-1] { + id, err := strconv.Atoi(idsStr[i]) + if err != nil { + return err + } + ids.Ids = append(ids.Ids, id) + } + err := ApiServiceApp.DeleteApisByIds(ids) + if err != nil { + global.GVA_LOG.Error("ClearTag DeleteApiByIds:", zap.Error(err)) + } + // 删除表 + if info.DeleteTable { + if err = AutoCodeServiceApp.DropTable(md.BusinessDB, md.TableName); err != nil { + global.GVA_LOG.Error("ClearTag DropTable:", zap.Error(err)) + } + } + // 删除文件 + + for _, path := range strings.Split(md.AutoCodePath, ";") { + + // 增加安全判断补丁: + _path, err := filepath.Abs(path) + if err != nil || _path != path { + continue + } + + // 迁移 + nPath := filepath.Join(global.GVA_CONFIG.AutoCode.Root, + "rm_file", time.Now().Format("20060102"), filepath.Base(filepath.Dir(filepath.Dir(path))), filepath.Base(filepath.Dir(path)), filepath.Base(path)) + // 判断目标文件是否存在 + for utils.FileExist(nPath) { + fmt.Println("文件已存在:", nPath) + nPath += fmt.Sprintf("_%d", time.Now().Nanosecond()) + } + err = utils.FileMove(path, nPath) + if err != nil { + global.GVA_LOG.Error("file move err ", zap.Error(err)) + } + //_ = utils.DeLFile(path) + } + // 清除注入 + for _, v := range strings.Split(md.InjectionMeta, ";") { + // RouterPath@functionName@RouterString + meta := strings.Split(v, "@") + if len(meta) == 3 { + _ = utils.AutoClearCode(meta[0], meta[2]) + } + } + + ast.RollBackAst(md.Package, md.StructName) + + md.Flag = 1 + return global.GVA_DB.Save(&md).Error +} + +// Delete 删除历史数据 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) Delete(info *request.GetById) error { + return global.GVA_DB.Where("id = ?", info.Uint()).Delete(&system.SysAutoCodeHistory{}).Error +} + +// GetList 获取系统历史数据 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [songzhibin97](https://github.com/songzhibin97) +func (autoCodeHistoryService *AutoCodeHistoryService) GetList(info request.PageInfo) (list []response.AutoCodeHistory, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + db := global.GVA_DB.Model(&system.SysAutoCodeHistory{}) + var entities []response.AutoCodeHistory + err = db.Count(&total).Error + if err != nil { + return nil, total, err + } + err = db.Limit(limit).Offset(offset).Order("updated_at desc").Find(&entities).Error + return entities, total, err +} diff --git a/service/system/sys_base_menu.go b/service/system/sys_base_menu.go new file mode 100644 index 0000000..9946f03 --- /dev/null +++ b/service/system/sys_base_menu.go @@ -0,0 +1,125 @@ +package system + +import ( + "errors" + + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system" +) + +type BaseMenuService struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteBaseMenu +//@description: 删除基础路由 +//@param: id float64 +//@return: err error + +func (baseMenuService *BaseMenuService) DeleteBaseMenu(id int) (err error) { + err = global.GVA_DB.Preload("MenuBtn").Preload("Parameters").Where("parent_id = ?", id).First(&system.SysBaseMenu{}).Error + if err != nil { + var menu system.SysBaseMenu + db := global.GVA_DB.Preload("SysAuthoritys").Where("id = ?", id).First(&menu).Delete(&menu) + err = global.GVA_DB.Delete(&system.SysBaseMenuParameter{}, "sys_base_menu_id = ?", id).Error + err = global.GVA_DB.Delete(&system.SysBaseMenuBtn{}, "sys_base_menu_id = ?", id).Error + err = global.GVA_DB.Delete(&system.SysAuthorityBtn{}, "sys_menu_id = ?", id).Error + if err != nil { + return err + } + if len(menu.SysAuthoritys) > 0 { + err = global.GVA_DB.Model(&menu).Association("SysAuthoritys").Delete(&menu.SysAuthoritys) + } else { + err = db.Error + if err != nil { + return + } + } + } else { + return errors.New("此菜单存在子菜单不可删除") + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateBaseMenu +//@description: 更新路由 +//@param: menu model.SysBaseMenu +//@return: err error + +func (baseMenuService *BaseMenuService) UpdateBaseMenu(menu system.SysBaseMenu) (err error) { + var oldMenu system.SysBaseMenu + upDateMap := make(map[string]interface{}) + upDateMap["keep_alive"] = menu.KeepAlive + upDateMap["close_tab"] = menu.CloseTab + upDateMap["default_menu"] = menu.DefaultMenu + upDateMap["parent_id"] = menu.ParentId + upDateMap["path"] = menu.Path + upDateMap["name"] = menu.Name + upDateMap["hidden"] = menu.Hidden + upDateMap["component"] = menu.Component + upDateMap["title"] = menu.Title + upDateMap["active_name"] = menu.ActiveName + upDateMap["icon"] = menu.Icon + upDateMap["sort"] = menu.Sort + + err = global.GVA_DB.Transaction(func(tx *gorm.DB) error { + db := tx.Where("id = ?", menu.ID).Find(&oldMenu) + if oldMenu.Name != menu.Name { + if !errors.Is(tx.Where("id <> ? AND name = ?", menu.ID, menu.Name).First(&system.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) { + global.GVA_LOG.Debug("存在相同name修改失败") + return errors.New("存在相同name修改失败") + } + } + txErr := tx.Unscoped().Delete(&system.SysBaseMenuParameter{}, "sys_base_menu_id = ?", menu.ID).Error + if txErr != nil { + global.GVA_LOG.Debug(txErr.Error()) + return txErr + } + txErr = tx.Unscoped().Delete(&system.SysBaseMenuBtn{}, "sys_base_menu_id = ?", menu.ID).Error + if txErr != nil { + global.GVA_LOG.Debug(txErr.Error()) + return txErr + } + if len(menu.Parameters) > 0 { + for k := range menu.Parameters { + menu.Parameters[k].SysBaseMenuID = menu.ID + } + txErr = tx.Create(&menu.Parameters).Error + if txErr != nil { + global.GVA_LOG.Debug(txErr.Error()) + return txErr + } + } + + if len(menu.MenuBtn) > 0 { + for k := range menu.MenuBtn { + menu.MenuBtn[k].SysBaseMenuID = menu.ID + } + txErr = tx.Create(&menu.MenuBtn).Error + if txErr != nil { + global.GVA_LOG.Debug(txErr.Error()) + return txErr + } + } + + txErr = db.Updates(upDateMap).Error + if txErr != nil { + global.GVA_LOG.Debug(txErr.Error()) + return txErr + } + return nil + }) + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetBaseMenuById +//@description: 返回当前选中menu +//@param: id float64 +//@return: menu system.SysBaseMenu, err error + +func (baseMenuService *BaseMenuService) GetBaseMenuById(id int) (menu system.SysBaseMenu, err error) { + err = global.GVA_DB.Preload("MenuBtn").Preload("Parameters").Where("id = ?", id).First(&menu).Error + return +} diff --git a/service/system/sys_casbin.go b/service/system/sys_casbin.go new file mode 100644 index 0000000..ee17d01 --- /dev/null +++ b/service/system/sys_casbin.go @@ -0,0 +1,141 @@ +package system + +import ( + "errors" + "strconv" + "sync" + + "github.com/casbin/casbin/v2" + "github.com/casbin/casbin/v2/model" + gormadapter "github.com/casbin/gorm-adapter/v3" + _ "github.com/go-sql-driver/mysql" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/system/request" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateCasbin +//@description: 更新casbin权限 +//@param: authorityId string, casbinInfos []request.CasbinInfo +//@return: error + +type CasbinService struct{} + +var CasbinServiceApp = new(CasbinService) + +func (casbinService *CasbinService) UpdateCasbin(AuthorityID uint, casbinInfos []request.CasbinInfo) error { + authorityId := strconv.Itoa(int(AuthorityID)) + casbinService.ClearCasbin(0, authorityId) + rules := [][]string{} + //做权限去重处理 + deduplicateMap := make(map[string]bool) + for _, v := range casbinInfos { + key := authorityId + v.Path + v.Method + if _, ok := deduplicateMap[key]; !ok { + deduplicateMap[key] = true + rules = append(rules, []string{authorityId, v.Path, v.Method}) + } + } + e := casbinService.Casbin() + success, _ := e.AddPolicies(rules) + if !success { + return errors.New("存在相同api,添加失败,请联系管理员") + } + return nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateCasbinApi +//@description: API更新随动 +//@param: oldPath string, newPath string, oldMethod string, newMethod string +//@return: error + +func (casbinService *CasbinService) UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error { + err := global.GVA_DB.Model(&gormadapter.CasbinRule{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{ + "v1": newPath, + "v2": newMethod, + }).Error + e := casbinService.Casbin() + err = e.LoadPolicy() + if err != nil { + return err + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetPolicyPathByAuthorityId +//@description: 获取权限列表 +//@param: authorityId string +//@return: pathMaps []request.CasbinInfo + +func (casbinService *CasbinService) GetPolicyPathByAuthorityId(AuthorityID uint) (pathMaps []request.CasbinInfo) { + e := casbinService.Casbin() + authorityId := strconv.Itoa(int(AuthorityID)) + list := e.GetFilteredPolicy(0, authorityId) + for _, v := range list { + pathMaps = append(pathMaps, request.CasbinInfo{ + Path: v[1], + Method: v[2], + }) + } + return pathMaps +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: ClearCasbin +//@description: 清除匹配的权限 +//@param: v int, p ...string +//@return: bool + +func (casbinService *CasbinService) ClearCasbin(v int, p ...string) bool { + e := casbinService.Casbin() + success, _ := e.RemoveFilteredPolicy(v, p...) + return success +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Casbin +//@description: 持久化到数据库 引入自定义规则 +//@return: *casbin.Enforcer + +var ( + syncedCachedEnforcer *casbin.SyncedCachedEnforcer + once sync.Once +) + +func (casbinService *CasbinService) Casbin() *casbin.SyncedCachedEnforcer { + once.Do(func() { + a, err := gormadapter.NewAdapterByDB(global.GVA_DB) + if err != nil { + zap.L().Error("适配数据库失败请检查casbin表是否为InnoDB引擎!", zap.Error(err)) + return + } + text := ` + [request_definition] + r = sub, obj, act + + [policy_definition] + p = sub, obj, act + + [role_definition] + g = _, _ + + [policy_effect] + e = some(where (p.eft == allow)) + + [matchers] + m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act + ` + m, err := model.NewModelFromString(text) + if err != nil { + zap.L().Error("字符串加载模型失败!", zap.Error(err)) + return + } + syncedCachedEnforcer, _ = casbin.NewSyncedCachedEnforcer(m, a) + syncedCachedEnforcer.SetExpireTime(60 * 60) + _ = syncedCachedEnforcer.LoadPolicy() + }) + return syncedCachedEnforcer +} diff --git a/service/system/sys_chatgpt.go b/service/system/sys_chatgpt.go new file mode 100644 index 0000000..c2f28e5 --- /dev/null +++ b/service/system/sys_chatgpt.go @@ -0,0 +1,167 @@ +package system + +import ( + "context" + "errors" + "fmt" + "github.com/sashabaranov/go-openai" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system" + "miniapp/model/system/request" + "strings" +) + +type ChatGptService struct{} + +func (chat *ChatGptService) CreateSK(option system.SysChatGptOption) error { + _, err := chat.GetSK() + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return global.GVA_DB.Create(option).Error + } + return err + } + return errors.New("已经存在sk") +} + +func (chat *ChatGptService) GetSK() (option system.SysChatGptOption, err error) { + err = global.GVA_DB.First(&option).Error + return +} + +func (chat *ChatGptService) DeleteSK() error { + option, err := chat.GetSK() + if err != nil { + return err + } + return global.GVA_DB.Delete(option, "sk = ?", option.SK).Error +} + +func (chat *ChatGptService) GetTable(req request.ChatGptRequest) (sql string, results []map[string]interface{}, err error) { + if req.DBName == "" { + return "", nil, errors.New("未选择db") + } + var tablesInfo []system.ChatField + var tableName string + global.GVA_DB.Table("information_schema.columns").Where("TABLE_SCHEMA = ?", req.DBName).Scan(&tablesInfo) + + var tablesMap = make(map[string]bool) + for i := range tablesInfo { + tablesMap[tablesInfo[i].TABLE_NAME] = true + } + for i := range tablesMap { + tableName += i + "," + } + option, err := chat.GetSK() + if err != nil { + return "", nil, err + } + client := openai.NewClient(option.SK) + ctx := context.Background() + + tables, err := getTables(ctx, client, tableName, req.Chat) + if err != nil { + return "", nil, err + } + tableArr := strings.Split(tables, ",") + if len(tableArr) != 0 { + firstKeyArr := strings.Split(tableArr[0], ":") + tableArr[0] = strings.Trim(firstKeyArr[len(firstKeyArr)-1], "\n") + } + sql, err = getSql(ctx, client, tableArr, tablesInfo, req.Chat) + if err != nil { + return "", nil, err + } + err = global.GVA_DB.Raw(sql).Scan(&results).Error + return sql, results, err +} + +func getTables(ctx context.Context, client *openai.Client, tables string, chat string) (string, error) { + var tablePrompt = `You are a database administrator + +Filter out the table names you might need from the tables I provided formatted as: + +Table1,Table2,Table3 + +I will provide you with the following table configuration information: + +Table1,Table2,Table3 + +Do not return information other than the table + +Configured as: +%s + +The problem is: +%s +` + content := fmt.Sprintf(tablePrompt, tables, chat) + chatReq := openai.ChatCompletionRequest{ + Model: openai.GPT3Dot5Turbo, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleUser, + Content: content, + }, + }, + } + + resp, err := client.CreateChatCompletion(ctx, chatReq) + if err != nil { + fmt.Printf("Completion error: %v\n", err) + return "", err + } + return resp.Choices[0].Message.Content, nil +} + +func getSql(ctx context.Context, client *openai.Client, tables []string, ChatField []system.ChatField, chat string) (string, error) { + var sqlPrompt = `You are a database administrator + +Give me an SQL statement based on my question + +I will provide you with my current database table configuration information in the form below + +Table Name | Column Name | Column Description + +Do not return information other than SQL + +Configured as: + +%s + +The problem is: + +%s` + var configured string + for ii := range ChatField { + for i := range tables { + if strings.Index(tables[i], ChatField[ii].TABLE_NAME) > -1 { + configured += fmt.Sprintf("%s | %s | %s \n", ChatField[ii].TABLE_NAME, ChatField[ii].COLUMN_NAME, ChatField[ii].COLUMN_COMMENT) + } + } + } + + if configured == "" { + return "", errors.New("未找到表") + } + chatReq := openai.ChatCompletionRequest{ + Model: openai.GPT3Dot5Turbo, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleUser, + Content: fmt.Sprintf(sqlPrompt, configured, chat), + }, + }, + } + + resp, err := client.CreateChatCompletion(ctx, chatReq) + if err != nil { + fmt.Printf("Completion error: %v\n", err) + return "", err + } + sql := resp.Choices[0].Message.Content + sqlArr := strings.Split(sql, ":") + sql = sqlArr[len(sqlArr)-1] + return sql, nil +} diff --git a/service/system/sys_dictionary.go b/service/system/sys_dictionary.go new file mode 100644 index 0000000..0ac1dcc --- /dev/null +++ b/service/system/sys_dictionary.go @@ -0,0 +1,128 @@ +package system + +import ( + "errors" + + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system" + "miniapp/model/system/request" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteSysDictionary +//@description: 创建字典数据 +//@param: sysDictionary model.SysDictionary +//@return: err error + +type DictionaryService struct{} + +func (dictionaryService *DictionaryService) CreateSysDictionary(sysDictionary system.SysDictionary) (err error) { + if (!errors.Is(global.GVA_DB.First(&system.SysDictionary{}, "type = ?", sysDictionary.Type).Error, gorm.ErrRecordNotFound)) { + return errors.New("存在相同的type,不允许创建") + } + err = global.GVA_DB.Create(&sysDictionary).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteSysDictionary +//@description: 删除字典数据 +//@param: sysDictionary model.SysDictionary +//@return: err error + +func (dictionaryService *DictionaryService) DeleteSysDictionary(sysDictionary system.SysDictionary) (err error) { + err = global.GVA_DB.Where("id = ?", sysDictionary.ID).Preload("SysDictionaryDetails").First(&sysDictionary).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + return errors.New("请不要搞事") + } + if err != nil { + return err + } + err = global.GVA_DB.Delete(&sysDictionary).Error + if err != nil { + return err + } + + if sysDictionary.SysDictionaryDetails != nil { + return global.GVA_DB.Where("sys_dictionary_id=?", sysDictionary.ID).Delete(sysDictionary.SysDictionaryDetails).Error + } + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateSysDictionary +//@description: 更新字典数据 +//@param: sysDictionary *model.SysDictionary +//@return: err error + +func (dictionaryService *DictionaryService) UpdateSysDictionary(sysDictionary *system.SysDictionary) (err error) { + var dict system.SysDictionary + sysDictionaryMap := map[string]interface{}{ + "Name": sysDictionary.Name, + "Type": sysDictionary.Type, + "Status": sysDictionary.Status, + "Desc": sysDictionary.Desc, + } + db := global.GVA_DB.Where("id = ?", sysDictionary.ID).First(&dict) + if dict.Type != sysDictionary.Type { + if !errors.Is(global.GVA_DB.First(&system.SysDictionary{}, "type = ?", sysDictionary.Type).Error, gorm.ErrRecordNotFound) { + return errors.New("存在相同的type,不允许创建") + } + } + err = db.Updates(sysDictionaryMap).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetSysDictionary +//@description: 根据id或者type获取字典单条数据 +//@param: Type string, Id uint +//@return: err error, sysDictionary model.SysDictionary + +func (dictionaryService *DictionaryService) GetSysDictionary(Type string, Id uint, status *bool) (sysDictionary system.SysDictionary, err error) { + var flag = false + if status == nil { + flag = true + } else { + flag = *status + } + err = global.GVA_DB.Where("(type = ? OR id = ?) and status = ?", Type, Id, flag).Preload("SysDictionaryDetails", func(db *gorm.DB) *gorm.DB { + return db.Where("status = ?", true).Order("sort") + }).First(&sysDictionary).Error + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: GetSysDictionaryInfoList +//@description: 分页获取字典列表 +//@param: info request.SysDictionarySearch +//@return: err error, list interface{}, total int64 + +func (dictionaryService *DictionaryService) GetSysDictionaryInfoList(info request.SysDictionarySearch) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + // 创建db + db := global.GVA_DB.Model(&system.SysDictionary{}) + var sysDictionarys []system.SysDictionary + // 如果有条件搜索 下方会自动创建搜索语句 + if info.Name != "" { + db = db.Where("`name` LIKE ?", "%"+info.Name+"%") + } + if info.Type != "" { + db = db.Where("`type` LIKE ?", "%"+info.Type+"%") + } + if info.Status != nil { + db = db.Where("`status` = ?", info.Status) + } + if info.Desc != "" { + db = db.Where("`desc` LIKE ?", "%"+info.Desc+"%") + } + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Find(&sysDictionarys).Error + return sysDictionarys, total, err +} diff --git a/service/system/sys_dictionary_detail.go b/service/system/sys_dictionary_detail.go new file mode 100644 index 0000000..f9983df --- /dev/null +++ b/service/system/sys_dictionary_detail.go @@ -0,0 +1,86 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/system" + "miniapp/model/system/request" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateSysDictionaryDetail +//@description: 创建字典详情数据 +//@param: sysDictionaryDetail model.SysDictionaryDetail +//@return: err error + +type DictionaryDetailService struct{} + +func (dictionaryDetailService *DictionaryDetailService) CreateSysDictionaryDetail(sysDictionaryDetail system.SysDictionaryDetail) (err error) { + err = global.GVA_DB.Create(&sysDictionaryDetail).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteSysDictionaryDetail +//@description: 删除字典详情数据 +//@param: sysDictionaryDetail model.SysDictionaryDetail +//@return: err error + +func (dictionaryDetailService *DictionaryDetailService) DeleteSysDictionaryDetail(sysDictionaryDetail system.SysDictionaryDetail) (err error) { + err = global.GVA_DB.Delete(&sysDictionaryDetail).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: UpdateSysDictionaryDetail +//@description: 更新字典详情数据 +//@param: sysDictionaryDetail *model.SysDictionaryDetail +//@return: err error + +func (dictionaryDetailService *DictionaryDetailService) UpdateSysDictionaryDetail(sysDictionaryDetail *system.SysDictionaryDetail) (err error) { + err = global.GVA_DB.Save(sysDictionaryDetail).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetSysDictionaryDetail +//@description: 根据id获取字典详情单条数据 +//@param: id uint +//@return: sysDictionaryDetail system.SysDictionaryDetail, err error + +func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetail(id uint) (sysDictionaryDetail system.SysDictionaryDetail, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&sysDictionaryDetail).Error + return +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetSysDictionaryDetailInfoList +//@description: 分页获取字典详情列表 +//@param: info request.SysDictionaryDetailSearch +//@return: list interface{}, total int64, err error + +func (dictionaryDetailService *DictionaryDetailService) GetSysDictionaryDetailInfoList(info request.SysDictionaryDetailSearch) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + // 创建db + db := global.GVA_DB.Model(&system.SysDictionaryDetail{}) + var sysDictionaryDetails []system.SysDictionaryDetail + // 如果有条件搜索 下方会自动创建搜索语句 + if info.Label != "" { + db = db.Where("label LIKE ?", "%"+info.Label+"%") + } + if info.Value != 0 { + db = db.Where("value = ?", info.Value) + } + if info.Status != nil { + db = db.Where("status = ?", info.Status) + } + if info.SysDictionaryID != 0 { + db = db.Where("sys_dictionary_id = ?", info.SysDictionaryID) + } + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Order("sort").Find(&sysDictionaryDetails).Error + return sysDictionaryDetails, total, err +} diff --git a/service/system/sys_initdb.go b/service/system/sys_initdb.go new file mode 100644 index 0000000..72d0905 --- /dev/null +++ b/service/system/sys_initdb.go @@ -0,0 +1,184 @@ +package system + +import ( + "context" + "database/sql" + "errors" + "fmt" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system/request" + "sort" +) + +const ( + Mysql = "mysql" + Pgsql = "pgsql" + Sqlite = "sqlite" + InitSuccess = "\n[%v] --> 初始数据成功!\n" + InitDataExist = "\n[%v] --> %v 的初始数据已存在!\n" + InitDataFailed = "\n[%v] --> %v 初始数据失败! \nerr: %+v\n" + InitDataSuccess = "\n[%v] --> %v 初始数据成功!\n" +) + +const ( + InitOrderSystem = 10 + InitOrderInternal = 1000 + InitOrderExternal = 100000 +) + +var ( + ErrMissingDBContext = errors.New("missing db in context") + ErrMissingDependentContext = errors.New("missing dependent value in context") + ErrDBTypeMismatch = errors.New("db type mismatch") +) + +// SubInitializer 提供 source/*/init() 使用的接口,每个 initializer 完成一个初始化过程 +type SubInitializer interface { + InitializerName() string // 不一定代表单独一个表,所以改成了更宽泛的语义 + MigrateTable(ctx context.Context) (next context.Context, err error) + InitializeData(ctx context.Context) (next context.Context, err error) + TableCreated(ctx context.Context) bool + DataInserted(ctx context.Context) bool +} + +// TypedDBInitHandler 执行传入的 initializer +type TypedDBInitHandler interface { + EnsureDB(ctx context.Context, conf *request.InitDB) (context.Context, error) // 建库,失败属于 fatal error,因此让它 panic + WriteConfig(ctx context.Context) error // 回写配置 + InitTables(ctx context.Context, inits initSlice) error // 建表 handler + InitData(ctx context.Context, inits initSlice) error // 建数据 handler +} + +// orderedInitializer 组合一个顺序字段,以供排序 +type orderedInitializer struct { + order int + SubInitializer +} + +// initSlice 供 initializer 排序依赖时使用 +type initSlice []*orderedInitializer + +var ( + initializers initSlice + cache map[string]*orderedInitializer +) + +// RegisterInit 注册要执行的初始化过程,会在 InitDB() 时调用 +func RegisterInit(order int, i SubInitializer) { + if initializers == nil { + initializers = initSlice{} + } + if cache == nil { + cache = map[string]*orderedInitializer{} + } + name := i.InitializerName() + if _, existed := cache[name]; existed { + panic(fmt.Sprintf("Name conflict on %s", name)) + } + ni := orderedInitializer{order, i} + initializers = append(initializers, &ni) + cache[name] = &ni +} + +/* ---- * service * ---- */ + +type InitDBService struct{} + +// InitDB 创建数据库并初始化 总入口 +func (initDBService *InitDBService) InitDB(conf request.InitDB) (err error) { + ctx := context.TODO() + if len(initializers) == 0 { + return errors.New("无可用初始化过程,请检查初始化是否已执行完成") + } + sort.Sort(&initializers) // 保证有依赖的 initializer 排在后面执行 + // Note: 若 initializer 只有单一依赖,可以写为 B=A+1, C=A+1; 由于 BC 之间没有依赖关系,所以谁先谁后并不影响初始化 + // 若存在多个依赖,可以写为 C=A+B, D=A+B+C, E=A+1; + // C必然>A|B,因此在AB之后执行,D必然>A|B|C,因此在ABC后执行,而E只依赖A,顺序与CD无关,因此E与CD哪个先执行并不影响 + var initHandler TypedDBInitHandler + switch conf.DBType { + case "mysql": + initHandler = NewMysqlInitHandler() + ctx = context.WithValue(ctx, "dbtype", "mysql") + case "pgsql": + initHandler = NewPgsqlInitHandler() + ctx = context.WithValue(ctx, "dbtype", "pgsql") + case "sqlite": + initHandler = NewSqliteInitHandler() + ctx = context.WithValue(ctx, "dbtype", "sqlite") + default: + initHandler = NewMysqlInitHandler() + ctx = context.WithValue(ctx, "dbtype", "mysql") + } + ctx, err = initHandler.EnsureDB(ctx, &conf) + if err != nil { + return err + } + + db := ctx.Value("db").(*gorm.DB) + global.GVA_DB = db + + if err = initHandler.InitTables(ctx, initializers); err != nil { + return err + } + if err = initHandler.InitData(ctx, initializers); err != nil { + return err + } + + if err = initHandler.WriteConfig(ctx); err != nil { + return err + } + initializers = initSlice{} + cache = map[string]*orderedInitializer{} + return nil +} + +// createDatabase 创建数据库( EnsureDB() 中调用 ) +func createDatabase(dsn string, driver string, createSql string) error { + db, err := sql.Open(driver, dsn) + if err != nil { + return err + } + defer func(db *sql.DB) { + err = db.Close() + if err != nil { + fmt.Println(err) + } + }(db) + if err = db.Ping(); err != nil { + return err + } + _, err = db.Exec(createSql) + return err +} + +// createTables 创建表(默认 dbInitHandler.initTables 行为) +func createTables(ctx context.Context, inits initSlice) error { + next, cancel := context.WithCancel(ctx) + defer func(c func()) { c() }(cancel) + for _, init := range inits { + if init.TableCreated(next) { + continue + } + if n, err := init.MigrateTable(next); err != nil { + return err + } else { + next = n + } + } + return nil +} + +/* -- sortable interface -- */ + +func (a initSlice) Len() int { + return len(a) +} + +func (a initSlice) Less(i, j int) bool { + return a[i].order < a[j].order +} + +func (a initSlice) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} diff --git a/service/system/sys_initdb_mysql.go b/service/system/sys_initdb_mysql.go new file mode 100644 index 0000000..ee25125 --- /dev/null +++ b/service/system/sys_initdb_mysql.go @@ -0,0 +1,96 @@ +package system + +import ( + "context" + "errors" + "fmt" + "path/filepath" + + "github.com/gookit/color" + "miniapp/config" + + "miniapp/utils" + + "github.com/gofrs/uuid/v5" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system/request" +) + +type MysqlInitHandler struct{} + +func NewMysqlInitHandler() *MysqlInitHandler { + return &MysqlInitHandler{} +} + +// WriteConfig mysql回写配置 +func (h MysqlInitHandler) WriteConfig(ctx context.Context) error { + c, ok := ctx.Value("config").(config.Mysql) + if !ok { + return errors.New("mysql config invalid") + } + global.GVA_CONFIG.System.DbType = "mysql" + global.GVA_CONFIG.Mysql = c + global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String() + cs := utils.StructToMap(global.GVA_CONFIG) + for k, v := range cs { + global.GVA_VP.Set(k, v) + } + return global.GVA_VP.WriteConfig() +} + +// EnsureDB 创建数据库并初始化 mysql +func (h MysqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) { + if s, ok := ctx.Value("dbtype").(string); !ok || s != "mysql" { + return ctx, ErrDBTypeMismatch + } + + c := conf.ToMysqlConfig() + next = context.WithValue(ctx, "config", c) + if c.Dbname == "" { + return ctx, nil + } // 如果没有数据库名, 则跳出初始化数据 + + dsn := conf.MysqlEmptyDsn() + createSql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;", c.Dbname) + if err = createDatabase(dsn, "mysql", createSql); err != nil { + return nil, err + } // 创建数据库 + + var db *gorm.DB + if db, err = gorm.Open(mysql.New(mysql.Config{ + DSN: c.Dsn(), // DSN data source name + DefaultStringSize: 191, // string 类型字段的默认长度 + SkipInitializeWithVersion: true, // 根据版本自动配置 + }), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil { + return ctx, err + } + global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..") + next = context.WithValue(next, "db", db) + return next, err +} + +func (h MysqlInitHandler) InitTables(ctx context.Context, inits initSlice) error { + return createTables(ctx, inits) +} + +func (h MysqlInitHandler) InitData(ctx context.Context, inits initSlice) error { + next, cancel := context.WithCancel(ctx) + defer func(c func()) { c() }(cancel) + for _, init := range inits { + if init.DataInserted(next) { + color.Info.Printf(InitDataExist, Mysql, init.InitializerName()) + continue + } + if n, err := init.InitializeData(next); err != nil { + color.Info.Printf(InitDataFailed, Mysql, init.InitializerName(), err) + return err + } else { + next = n + color.Info.Printf(InitDataSuccess, Mysql, init.InitializerName()) + } + } + color.Info.Printf(InitSuccess, Mysql) + return nil +} diff --git a/service/system/sys_initdb_pgsql.go b/service/system/sys_initdb_pgsql.go new file mode 100644 index 0000000..05da66c --- /dev/null +++ b/service/system/sys_initdb_pgsql.go @@ -0,0 +1,95 @@ +package system + +import ( + "context" + "errors" + "fmt" + "path/filepath" + + "github.com/gookit/color" + "miniapp/config" + + "miniapp/utils" + + "github.com/gofrs/uuid/v5" + "gorm.io/driver/postgres" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/system/request" +) + +type PgsqlInitHandler struct{} + +func NewPgsqlInitHandler() *PgsqlInitHandler { + return &PgsqlInitHandler{} +} + +// WriteConfig pgsql 回写配置 +func (h PgsqlInitHandler) WriteConfig(ctx context.Context) error { + c, ok := ctx.Value("config").(config.Pgsql) + if !ok { + return errors.New("postgresql config invalid") + } + global.GVA_CONFIG.System.DbType = "pgsql" + global.GVA_CONFIG.Pgsql = c + global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String() + cs := utils.StructToMap(global.GVA_CONFIG) + for k, v := range cs { + global.GVA_VP.Set(k, v) + } + return global.GVA_VP.WriteConfig() +} + +// EnsureDB 创建数据库并初始化 pg +func (h PgsqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) { + if s, ok := ctx.Value("dbtype").(string); !ok || s != "pgsql" { + return ctx, ErrDBTypeMismatch + } + + c := conf.ToPgsqlConfig() + next = context.WithValue(ctx, "config", c) + if c.Dbname == "" { + return ctx, nil + } // 如果没有数据库名, 则跳出初始化数据 + + dsn := conf.PgsqlEmptyDsn() + createSql := fmt.Sprintf("CREATE DATABASE %s;", c.Dbname) + if err = createDatabase(dsn, "pgx", createSql); err != nil { + return nil, err + } // 创建数据库 + + var db *gorm.DB + if db, err = gorm.Open(postgres.New(postgres.Config{ + DSN: c.Dsn(), // DSN data source name + PreferSimpleProtocol: false, + }), &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}); err != nil { + return ctx, err + } + global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..") + next = context.WithValue(next, "db", db) + return next, err +} + +func (h PgsqlInitHandler) InitTables(ctx context.Context, inits initSlice) error { + return createTables(ctx, inits) +} + +func (h PgsqlInitHandler) InitData(ctx context.Context, inits initSlice) error { + next, cancel := context.WithCancel(ctx) + defer func(c func()) { c() }(cancel) + for i := 0; i < len(inits); i++ { + if inits[i].DataInserted(next) { + color.Info.Printf(InitDataExist, Pgsql, inits[i].InitializerName()) + continue + } + if n, err := inits[i].InitializeData(next); err != nil { + color.Info.Printf(InitDataFailed, Pgsql, inits[i].InitializerName(), err) + return err + } else { + next = n + color.Info.Printf(InitDataSuccess, Pgsql, inits[i].InitializerName()) + } + } + color.Info.Printf(InitSuccess, Pgsql) + return nil +} diff --git a/service/system/sys_initdb_sqlite.go b/service/system/sys_initdb_sqlite.go new file mode 100644 index 0000000..3d7f016 --- /dev/null +++ b/service/system/sys_initdb_sqlite.go @@ -0,0 +1,86 @@ +package system + +import ( + "context" + "errors" + "github.com/glebarez/sqlite" + "github.com/gofrs/uuid/v5" + "github.com/gookit/color" + "gorm.io/gorm" + "miniapp/config" + "miniapp/global" + "miniapp/model/system/request" + "miniapp/utils" + "path/filepath" +) + +type SqliteInitHandler struct{} + +func NewSqliteInitHandler() *SqliteInitHandler { + return &SqliteInitHandler{} +} + +// WriteConfig mysql回写配置 +func (h SqliteInitHandler) WriteConfig(ctx context.Context) error { + c, ok := ctx.Value("config").(config.Sqlite) + if !ok { + return errors.New("mysql config invalid") + } + global.GVA_CONFIG.System.DbType = "sqlite" + global.GVA_CONFIG.Sqlite = c + global.GVA_CONFIG.JWT.SigningKey = uuid.Must(uuid.NewV4()).String() + cs := utils.StructToMap(global.GVA_CONFIG) + for k, v := range cs { + global.GVA_VP.Set(k, v) + } + return global.GVA_VP.WriteConfig() +} + +// EnsureDB 创建数据库并初始化 sqlite +func (h SqliteInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) { + if s, ok := ctx.Value("dbtype").(string); !ok || s != "sqlite" { + return ctx, ErrDBTypeMismatch + } + + c := conf.ToSqliteConfig() + next = context.WithValue(ctx, "config", c) + if c.Dbname == "" { + return ctx, nil + } // 如果没有数据库名, 则跳出初始化数据 + + dsn := conf.SqliteEmptyDsn() + + var db *gorm.DB + if db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{ + DisableForeignKeyConstraintWhenMigrating: true, + }); err != nil { + return ctx, err + } + global.GVA_CONFIG.AutoCode.Root, _ = filepath.Abs("..") + next = context.WithValue(next, "db", db) + return next, err +} + +func (h SqliteInitHandler) InitTables(ctx context.Context, inits initSlice) error { + return createTables(ctx, inits) +} + +func (h SqliteInitHandler) InitData(ctx context.Context, inits initSlice) error { + next, cancel := context.WithCancel(ctx) + defer func(c func()) { c() }(cancel) + for _, init := range inits { + if init.DataInserted(next) { + color.Info.Printf(InitDataExist, Sqlite, init.InitializerName()) + continue + } + if n, err := init.InitializeData(next); err != nil { + color.Info.Printf(InitDataFailed, Sqlite, init.InitializerName(), err) + return err + } else { + next = n + color.Info.Printf(InitDataSuccess, Sqlite, init.InitializerName()) + } + } + color.Info.Printf(InitSuccess, Sqlite) + return nil +} diff --git a/service/system/sys_menu.go b/service/system/sys_menu.go new file mode 100644 index 0000000..2874af8 --- /dev/null +++ b/service/system/sys_menu.go @@ -0,0 +1,236 @@ +package system + +import ( + "errors" + "strconv" + + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: getMenuTreeMap +//@description: 获取路由总树map +//@param: authorityId string +//@return: treeMap map[string][]system.SysMenu, err error + +type MenuService struct{} + +var MenuServiceApp = new(MenuService) + +func (menuService *MenuService) getMenuTreeMap(authorityId uint) (treeMap map[string][]system.SysMenu, err error) { + var allMenus []system.SysMenu + var baseMenu []system.SysBaseMenu + var btns []system.SysAuthorityBtn + treeMap = make(map[string][]system.SysMenu) + + var SysAuthorityMenus []system.SysAuthorityMenu + err = global.GVA_DB.Where("sys_authority_authority_id = ?", authorityId).Find(&SysAuthorityMenus).Error + if err != nil { + return + } + + var MenuIds []string + + for i := range SysAuthorityMenus { + MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId) + } + + err = global.GVA_DB.Where("id in (?)", MenuIds).Order("sort").Preload("Parameters").Find(&baseMenu).Error + if err != nil { + return + } + + for i := range baseMenu { + allMenus = append(allMenus, system.SysMenu{ + SysBaseMenu: baseMenu[i], + AuthorityId: authorityId, + MenuId: strconv.Itoa(int(baseMenu[i].ID)), + Parameters: baseMenu[i].Parameters, + }) + } + + err = global.GVA_DB.Where("authority_id = ?", authorityId).Preload("SysBaseMenuBtn").Find(&btns).Error + if err != nil { + return + } + var btnMap = make(map[uint]map[string]uint) + for _, v := range btns { + if btnMap[v.SysMenuID] == nil { + btnMap[v.SysMenuID] = make(map[string]uint) + } + btnMap[v.SysMenuID][v.SysBaseMenuBtn.Name] = authorityId + } + for _, v := range allMenus { + v.Btns = btnMap[v.ID] + treeMap[v.ParentId] = append(treeMap[v.ParentId], v) + } + return treeMap, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetMenuTree +//@description: 获取动态菜单树 +//@param: authorityId string +//@return: menus []system.SysMenu, err error + +func (menuService *MenuService) GetMenuTree(authorityId uint) (menus []system.SysMenu, err error) { + menuTree, err := menuService.getMenuTreeMap(authorityId) + menus = menuTree["0"] + for i := 0; i < len(menus); i++ { + err = menuService.getChildrenList(&menus[i], menuTree) + } + return menus, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: getChildrenList +//@description: 获取子菜单 +//@param: menu *model.SysMenu, treeMap map[string][]model.SysMenu +//@return: err error + +func (menuService *MenuService) getChildrenList(menu *system.SysMenu, treeMap map[string][]system.SysMenu) (err error) { + menu.Children = treeMap[menu.MenuId] + for i := 0; i < len(menu.Children); i++ { + err = menuService.getChildrenList(&menu.Children[i], treeMap) + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetInfoList +//@description: 获取路由分页 +//@return: list interface{}, total int64,err error + +func (menuService *MenuService) GetInfoList() (list interface{}, total int64, err error) { + var menuList []system.SysBaseMenu + treeMap, err := menuService.getBaseMenuTreeMap() + menuList = treeMap["0"] + for i := 0; i < len(menuList); i++ { + err = menuService.getBaseChildrenList(&menuList[i], treeMap) + } + return menuList, total, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: getBaseChildrenList +//@description: 获取菜单的子菜单 +//@param: menu *model.SysBaseMenu, treeMap map[string][]model.SysBaseMenu +//@return: err error + +func (menuService *MenuService) getBaseChildrenList(menu *system.SysBaseMenu, treeMap map[string][]system.SysBaseMenu) (err error) { + menu.Children = treeMap[strconv.Itoa(int(menu.ID))] + for i := 0; i < len(menu.Children); i++ { + err = menuService.getBaseChildrenList(&menu.Children[i], treeMap) + } + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: AddBaseMenu +//@description: 添加基础路由 +//@param: menu model.SysBaseMenu +//@return: error + +func (menuService *MenuService) AddBaseMenu(menu system.SysBaseMenu) error { + if !errors.Is(global.GVA_DB.Where("name = ?", menu.Name).First(&system.SysBaseMenu{}).Error, gorm.ErrRecordNotFound) { + return errors.New("存在重复name,请修改name") + } + return global.GVA_DB.Create(&menu).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: getBaseMenuTreeMap +//@description: 获取路由总树map +//@return: treeMap map[string][]system.SysBaseMenu, err error + +func (menuService *MenuService) getBaseMenuTreeMap() (treeMap map[string][]system.SysBaseMenu, err error) { + var allMenus []system.SysBaseMenu + treeMap = make(map[string][]system.SysBaseMenu) + err = global.GVA_DB.Order("sort").Preload("MenuBtn").Preload("Parameters").Find(&allMenus).Error + for _, v := range allMenus { + treeMap[v.ParentId] = append(treeMap[v.ParentId], v) + } + return treeMap, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetBaseMenuTree +//@description: 获取基础路由树 +//@return: menus []system.SysBaseMenu, err error + +func (menuService *MenuService) GetBaseMenuTree() (menus []system.SysBaseMenu, err error) { + treeMap, err := menuService.getBaseMenuTreeMap() + menus = treeMap["0"] + for i := 0; i < len(menus); i++ { + err = menuService.getBaseChildrenList(&menus[i], treeMap) + } + return menus, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: AddMenuAuthority +//@description: 为角色增加menu树 +//@param: menus []model.SysBaseMenu, authorityId string +//@return: err error + +func (menuService *MenuService) AddMenuAuthority(menus []system.SysBaseMenu, authorityId uint) (err error) { + var auth system.SysAuthority + auth.AuthorityId = authorityId + auth.SysBaseMenus = menus + err = AuthorityServiceApp.SetMenuAuthority(&auth) + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetMenuAuthority +//@description: 查看当前角色树 +//@param: info *request.GetAuthorityId +//@return: menus []system.SysMenu, err error + +func (menuService *MenuService) GetMenuAuthority(info *request.GetAuthorityId) (menus []system.SysMenu, err error) { + var baseMenu []system.SysBaseMenu + var SysAuthorityMenus []system.SysAuthorityMenu + err = global.GVA_DB.Where("sys_authority_authority_id = ?", info.AuthorityId).Find(&SysAuthorityMenus).Error + if err != nil { + return + } + + var MenuIds []string + + for i := range SysAuthorityMenus { + MenuIds = append(MenuIds, SysAuthorityMenus[i].MenuId) + } + + err = global.GVA_DB.Where("id in (?) ", MenuIds).Order("sort").Find(&baseMenu).Error + + for i := range baseMenu { + menus = append(menus, system.SysMenu{ + SysBaseMenu: baseMenu[i], + AuthorityId: uint(info.AuthorityId), + MenuId: strconv.Itoa(int(baseMenu[i].ID)), + Parameters: baseMenu[i].Parameters, + }) + } + // sql := "SELECT authority_menu.keep_alive,authority_menu.default_menu,authority_menu.created_at,authority_menu.updated_at,authority_menu.deleted_at,authority_menu.menu_level,authority_menu.parent_id,authority_menu.path,authority_menu.`name`,authority_menu.hidden,authority_menu.component,authority_menu.title,authority_menu.icon,authority_menu.sort,authority_menu.menu_id,authority_menu.authority_id FROM authority_menu WHERE authority_menu.authority_id = ? ORDER BY authority_menu.sort ASC" + // err = global.GVA_DB.Raw(sql, authorityId).Scan(&menus).Error + return menus, err +} + +// UserAuthorityDefaultRouter 用户角色默认路由检查 +// +// Author [SliverHorn](https://github.com/SliverHorn) +func (menuService *MenuService) UserAuthorityDefaultRouter(user *system.SysUser) { + var menuIds []string + err := global.GVA_DB.Model(&system.SysAuthorityMenu{}).Where("sys_authority_authority_id = ?", user.AuthorityId).Pluck("sys_base_menu_id", &menuIds).Error + if err != nil { + return + } + var am system.SysBaseMenu + err = global.GVA_DB.First(&am, "name = ? and id in (?)", user.Authority.DefaultRouter, menuIds).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + user.Authority.DefaultRouter = "404" + } +} diff --git a/service/system/sys_operation_record.go b/service/system/sys_operation_record.go new file mode 100644 index 0000000..576b2bf --- /dev/null +++ b/service/system/sys_operation_record.go @@ -0,0 +1,86 @@ +package system + +import ( + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" + systemReq "miniapp/model/system/request" +) + +//@author: [granty1](https://github.com/granty1) +//@function: CreateSysOperationRecord +//@description: 创建记录 +//@param: sysOperationRecord model.SysOperationRecord +//@return: err error + +type OperationRecordService struct{} + +func (operationRecordService *OperationRecordService) CreateSysOperationRecord(sysOperationRecord system.SysOperationRecord) (err error) { + err = global.GVA_DB.Create(&sysOperationRecord).Error + return err +} + +//@author: [granty1](https://github.com/granty1) +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteSysOperationRecordByIds +//@description: 批量删除记录 +//@param: ids request.IdsReq +//@return: err error + +func (operationRecordService *OperationRecordService) DeleteSysOperationRecordByIds(ids request.IdsReq) (err error) { + err = global.GVA_DB.Delete(&[]system.SysOperationRecord{}, "id in (?)", ids.Ids).Error + return err +} + +//@author: [granty1](https://github.com/granty1) +//@function: DeleteSysOperationRecord +//@description: 删除操作记录 +//@param: sysOperationRecord model.SysOperationRecord +//@return: err error + +func (operationRecordService *OperationRecordService) DeleteSysOperationRecord(sysOperationRecord system.SysOperationRecord) (err error) { + err = global.GVA_DB.Delete(&sysOperationRecord).Error + return err +} + +//@author: [granty1](https://github.com/granty1) +//@function: DeleteSysOperationRecord +//@description: 根据id获取单条操作记录 +//@param: id uint +//@return: sysOperationRecord system.SysOperationRecord, err error + +func (operationRecordService *OperationRecordService) GetSysOperationRecord(id uint) (sysOperationRecord system.SysOperationRecord, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&sysOperationRecord).Error + return +} + +//@author: [granty1](https://github.com/granty1) +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetSysOperationRecordInfoList +//@description: 分页获取操作记录列表 +//@param: info systemReq.SysOperationRecordSearch +//@return: list interface{}, total int64, err error + +func (operationRecordService *OperationRecordService) GetSysOperationRecordInfoList(info systemReq.SysOperationRecordSearch) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + // 创建db + db := global.GVA_DB.Model(&system.SysOperationRecord{}) + var sysOperationRecords []system.SysOperationRecord + // 如果有条件搜索 下方会自动创建搜索语句 + if info.Method != "" { + db = db.Where("method = ?", info.Method) + } + if info.Path != "" { + db = db.Where("path LIKE ?", "%"+info.Path+"%") + } + if info.Status != 0 { + db = db.Where("status = ?", info.Status) + } + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Order("id desc").Limit(limit).Offset(offset).Preload("User").Find(&sysOperationRecords).Error + return sysOperationRecords, total, err +} diff --git a/service/system/sys_system.go b/service/system/sys_system.go new file mode 100644 index 0000000..37dd617 --- /dev/null +++ b/service/system/sys_system.go @@ -0,0 +1,60 @@ +package system + +import ( + "go.uber.org/zap" + "miniapp/config" + "miniapp/global" + "miniapp/model/system" + "miniapp/utils" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetSystemConfig +//@description: 读取配置文件 +//@return: conf config.Server, err error + +type SystemConfigService struct{} + +func (systemConfigService *SystemConfigService) GetSystemConfig() (conf config.Server, err error) { + return global.GVA_CONFIG, nil +} + +// @description set system config, +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetSystemConfig +//@description: 设置配置文件 +//@param: system model.System +//@return: err error + +func (systemConfigService *SystemConfigService) SetSystemConfig(system system.System) (err error) { + cs := utils.StructToMap(system.Config) + for k, v := range cs { + global.GVA_VP.Set(k, v) + } + err = global.GVA_VP.WriteConfig() + return err +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: GetServerInfo +//@description: 获取服务器信息 +//@return: server.exe.exe *utils.Server, err error + +func (systemConfigService *SystemConfigService) GetServerInfo() (server *utils.Server, err error) { + var s utils.Server + s.Os = utils.InitOS() + if s.Cpu, err = utils.InitCPU(); err != nil { + global.GVA_LOG.Error("func utils.InitCPU() Failed", zap.String("err", err.Error())) + return &s, err + } + if s.Ram, err = utils.InitRAM(); err != nil { + global.GVA_LOG.Error("func utils.InitRAM() Failed", zap.String("err", err.Error())) + return &s, err + } + if s.Disk, err = utils.InitDisk(); err != nil { + global.GVA_LOG.Error("func utils.InitDisk() Failed", zap.String("err", err.Error())) + return &s, err + } + + return &s, nil +} diff --git a/service/system/sys_user.go b/service/system/sys_user.go new file mode 100644 index 0000000..ee8f5b4 --- /dev/null +++ b/service/system/sys_user.go @@ -0,0 +1,245 @@ +package system + +import ( + "errors" + "fmt" + "time" + + "github.com/gofrs/uuid/v5" + "gorm.io/gorm" + "miniapp/global" + "miniapp/model/common/request" + "miniapp/model/system" + "miniapp/utils" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Register +//@description: 用户注册 +//@param: u model.SysUser +//@return: userInter system.SysUser, err error + +type UserService struct{} + +func (userService *UserService) Register(u system.SysUser) (userInter system.SysUser, err error) { + var user system.SysUser + if !errors.Is(global.GVA_DB.Where("username = ?", u.Username).First(&user).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册 + return userInter, errors.New("用户名已注册") + } + // 否则 附加uuid 密码hash加密 注册 + u.Password = utils.BcryptHash(u.Password) + u.UUID = uuid.Must(uuid.NewV4()) + err = global.GVA_DB.Create(&u).Error + return u, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: Login +//@description: 用户登录 +//@param: u *model.SysUser +//@return: err error, userInter *model.SysUser + +func (userService *UserService) Login(u *system.SysUser) (userInter *system.SysUser, err error) { + if nil == global.GVA_DB { + return nil, fmt.Errorf("db not init") + } + + var user system.SysUser + err = global.GVA_DB.Where("username = ?", u.Username).Preload("Authorities").Preload("Authority").First(&user).Error + if err == nil { + if ok := utils.BcryptCheck(u.Password, user.Password); !ok { + return nil, errors.New("密码错误") + } + MenuServiceApp.UserAuthorityDefaultRouter(&user) + } + return &user, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: ChangePassword +//@description: 修改用户密码 +//@param: u *model.SysUser, newPassword string +//@return: userInter *model.SysUser,err error + +func (userService *UserService) ChangePassword(u *system.SysUser, newPassword string) (userInter *system.SysUser, err error) { + var user system.SysUser + if err = global.GVA_DB.Where("id = ?", u.ID).First(&user).Error; err != nil { + return nil, err + } + if ok := utils.BcryptCheck(u.Password, user.Password); !ok { + return nil, errors.New("原密码错误") + } + user.Password = utils.BcryptHash(newPassword) + err = global.GVA_DB.Save(&user).Error + return &user, err + +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: GetUserInfoList +//@description: 分页获取数据 +//@param: info request.PageInfo +//@return: err error, list interface{}, total int64 + +func (userService *UserService) GetUserInfoList(info request.PageInfo) (list interface{}, total int64, err error) { + limit := info.PageSize + offset := info.PageSize * (info.Page - 1) + db := global.GVA_DB.Model(&system.SysUser{}) + var userList []system.SysUser + err = db.Count(&total).Error + if err != nil { + return + } + err = db.Limit(limit).Offset(offset).Preload("Authorities").Preload("Authority").Find(&userList).Error + return userList, total, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetUserAuthority +//@description: 设置一个用户的权限 +//@param: uuid uuid.UUID, authorityId string +//@return: err error + +func (userService *UserService) SetUserAuthority(id uint, authorityId uint) (err error) { + assignErr := global.GVA_DB.Where("sys_user_id = ? AND sys_authority_authority_id = ?", id, authorityId).First(&system.SysUserAuthority{}).Error + if errors.Is(assignErr, gorm.ErrRecordNotFound) { + return errors.New("该用户无此角色") + } + err = global.GVA_DB.Where("id = ?", id).First(&system.SysUser{}).Update("authority_id", authorityId).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetUserAuthorities +//@description: 设置一个用户的权限 +//@param: id uint, authorityIds []string +//@return: err error + +func (userService *UserService) SetUserAuthorities(id uint, authorityIds []uint) (err error) { + return global.GVA_DB.Transaction(func(tx *gorm.DB) error { + TxErr := tx.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error + if TxErr != nil { + return TxErr + } + var useAuthority []system.SysUserAuthority + for _, v := range authorityIds { + useAuthority = append(useAuthority, system.SysUserAuthority{ + SysUserId: id, SysAuthorityAuthorityId: v, + }) + } + TxErr = tx.Create(&useAuthority).Error + if TxErr != nil { + return TxErr + } + TxErr = tx.Where("id = ?", id).First(&system.SysUser{}).Update("authority_id", authorityIds[0]).Error + if TxErr != nil { + return TxErr + } + // 返回 nil 提交事务 + return nil + }) +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: DeleteUser +//@description: 删除用户 +//@param: id float64 +//@return: err error + +func (userService *UserService) DeleteUser(id int) (err error) { + var user system.SysUser + err = global.GVA_DB.Where("id = ?", id).Delete(&user).Error + if err != nil { + return err + } + err = global.GVA_DB.Delete(&[]system.SysUserAuthority{}, "sys_user_id = ?", id).Error + return err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetUserInfo +//@description: 设置用户信息 +//@param: reqUser model.SysUser +//@return: err error, user model.SysUser + +func (userService *UserService) SetUserInfo(req system.SysUser) error { + return global.GVA_DB.Model(&system.SysUser{}). + Select("updated_at", "nick_name", "header_img", "phone", "email", "sideMode", "enable"). + Where("id=?", req.ID). + Updates(map[string]interface{}{ + "updated_at": time.Now(), + "nick_name": req.NickName, + "header_img": req.HeaderImg, + "phone": req.Phone, + "email": req.Email, + "side_mode": req.SideMode, + "enable": req.Enable, + }).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: SetUserInfo +//@description: 设置用户信息 +//@param: reqUser model.SysUser +//@return: err error, user model.SysUser + +func (userService *UserService) SetSelfInfo(req system.SysUser) error { + return global.GVA_DB.Model(&system.SysUser{}). + Where("id=?", req.ID). + Updates(req).Error +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: GetUserInfo +//@description: 获取用户信息 +//@param: uuid uuid.UUID +//@return: err error, user system.SysUser + +func (userService *UserService) GetUserInfo(uuid uuid.UUID) (user system.SysUser, err error) { + var reqUser system.SysUser + err = global.GVA_DB.Preload("Authorities").Preload("Authority").First(&reqUser, "uuid = ?", uuid).Error + if err != nil { + return reqUser, err + } + MenuServiceApp.UserAuthorityDefaultRouter(&reqUser) + return reqUser, err +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: FindUserById +//@description: 通过id获取用户信息 +//@param: id int +//@return: err error, user *model.SysUser + +func (userService *UserService) FindUserById(id int) (user *system.SysUser, err error) { + var u system.SysUser + err = global.GVA_DB.Where("`id` = ?", id).First(&u).Error + return &u, err +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: FindUserByUuid +//@description: 通过uuid获取用户信息 +//@param: uuid string +//@return: err error, user *model.SysUser + +func (userService *UserService) FindUserByUuid(uuid string) (user *system.SysUser, err error) { + var u system.SysUser + if err = global.GVA_DB.Where("`uuid` = ?", uuid).First(&u).Error; err != nil { + return &u, errors.New("用户不存在") + } + return &u, nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: resetPassword +//@description: 修改用户密码 +//@param: ID uint +//@return: err error + +func (userService *UserService) ResetPassword(ID uint) (err error) { + err = global.GVA_DB.Model(&system.SysUser{}).Where("id = ?", ID).Update("password", utils.BcryptHash("123456")).Error + return err +} diff --git a/service/system/todos.go b/service/system/todos.go new file mode 100644 index 0000000..9b140a3 --- /dev/null +++ b/service/system/todos.go @@ -0,0 +1 @@ +package system diff --git a/source/example/file_upload_download.go b/source/example/file_upload_download.go new file mode 100644 index 0000000..3b2d983 --- /dev/null +++ b/source/example/file_upload_download.go @@ -0,0 +1,65 @@ +package example + +import ( + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + "miniapp/model/example" + "miniapp/service/system" +) + +const initOrderExaFile = system.InitOrderInternal + 1 + +type initExaFileMysql struct{} + +// auto run +func init() { + system.RegisterInit(initOrderExaFile, &initExaFileMysql{}) +} + +func (i *initExaFileMysql) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&example.ExaFileUploadAndDownload{}) +} + +func (i *initExaFileMysql) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&example.ExaFileUploadAndDownload{}) +} + +func (i initExaFileMysql) InitializerName() string { + return example.ExaFileUploadAndDownload{}.TableName() +} + +func (i *initExaFileMysql) InitializeData(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + entities := []example.ExaFileUploadAndDownload{ + {Name: "10.png", Url: "https://qmplusimg.henrongyi.top/gvalogo.png", Tag: "png", Key: "158787308910.png"}, + {Name: "logo.png", Url: "https://qmplusimg.henrongyi.top/1576554439myAvatar.png", Tag: "png", Key: "1587973709logo.png"}, + } + if err := db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, example.ExaFileUploadAndDownload{}.TableName()+"表数据初始化失败!") + } + return ctx, nil +} + +func (i *initExaFileMysql) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + lookup := example.ExaFileUploadAndDownload{Name: "logo.png", Key: "1587973709logo.png"} + if errors.Is(db.First(&lookup, &lookup).Error, gorm.ErrRecordNotFound) { + return false + } + return true +} diff --git a/source/system/api.go b/source/system/api.go new file mode 100644 index 0000000..bca98af --- /dev/null +++ b/source/system/api.go @@ -0,0 +1,176 @@ +package system + +import ( + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" +) + +type initApi struct{} + +const initOrderApi = system.InitOrderSystem + 1 + +// auto run +func init() { + system.RegisterInit(initOrderApi, &initApi{}) +} + +func (i initApi) InitializerName() string { + return sysModel.SysApi{}.TableName() +} + +func (i *initApi) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&sysModel.SysApi{}) +} + +func (i *initApi) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&sysModel.SysApi{}) +} + +func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + entities := []sysModel.SysApi{ + {ApiGroup: "jwt", Method: "POST", Path: "/jwt/jsonInBlacklist", Description: "jwt加入黑名单(退出,必选)"}, + + {ApiGroup: "系统用户", Method: "DELETE", Path: "/user/deleteUser", Description: "删除用户"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/admin_register", Description: "用户注册"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/getUserList", Description: "获取用户列表"}, + {ApiGroup: "系统用户", Method: "PUT", Path: "/user/setUserInfo", Description: "设置用户信息"}, + {ApiGroup: "系统用户", Method: "PUT", Path: "/user/setSelfInfo", Description: "设置自身信息(必选)"}, + {ApiGroup: "系统用户", Method: "GET", Path: "/user/getUserInfo", Description: "获取自身信息(必选)"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/setUserAuthorities", Description: "设置权限组"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/changePassword", Description: "修改密码(建议选择)"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/setUserAuthority", Description: "修改用户角色(必选)"}, + {ApiGroup: "系统用户", Method: "POST", Path: "/user/resetPassword", Description: "重置用户密码"}, + + {ApiGroup: "api", Method: "POST", Path: "/api/createApi", Description: "创建api"}, + {ApiGroup: "api", Method: "POST", Path: "/api/deleteApi", Description: "删除Api"}, + {ApiGroup: "api", Method: "POST", Path: "/api/updateApi", Description: "更新Api"}, + {ApiGroup: "api", Method: "POST", Path: "/api/getApiList", Description: "获取api列表"}, + {ApiGroup: "api", Method: "POST", Path: "/api/getAllApis", Description: "获取所有api"}, + {ApiGroup: "api", Method: "POST", Path: "/api/getApiById", Description: "获取api详细信息"}, + {ApiGroup: "api", Method: "DELETE", Path: "/api/deleteApisByIds", Description: "批量删除api"}, + + {ApiGroup: "角色", Method: "POST", Path: "/authority/copyAuthority", Description: "拷贝角色"}, + {ApiGroup: "角色", Method: "POST", Path: "/authority/createAuthority", Description: "创建角色"}, + {ApiGroup: "角色", Method: "POST", Path: "/authority/deleteAuthority", Description: "删除角色"}, + {ApiGroup: "角色", Method: "PUT", Path: "/authority/updateAuthority", Description: "更新角色信息"}, + {ApiGroup: "角色", Method: "POST", Path: "/authority/getAuthorityList", Description: "获取角色列表"}, + {ApiGroup: "角色", Method: "POST", Path: "/authority/setDataAuthority", Description: "设置角色资源权限"}, + + {ApiGroup: "casbin", Method: "POST", Path: "/casbin/updateCasbin", Description: "更改角色api权限"}, + {ApiGroup: "casbin", Method: "POST", Path: "/casbin/getPolicyPathByAuthorityId", Description: "获取权限列表"}, + + {ApiGroup: "菜单", Method: "POST", Path: "/menu/addBaseMenu", Description: "新增菜单"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/getMenu", Description: "获取菜单树(必选)"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/deleteBaseMenu", Description: "删除菜单"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/updateBaseMenu", Description: "更新菜单"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/getBaseMenuById", Description: "根据id获取菜单"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/getMenuList", Description: "分页获取基础menu列表"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/getBaseMenuTree", Description: "获取用户动态路由"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/getMenuAuthority", Description: "获取指定角色menu"}, + {ApiGroup: "菜单", Method: "POST", Path: "/menu/addMenuAuthority", Description: "增加menu和角色关联关系"}, + + {ApiGroup: "分片上传", Method: "GET", Path: "/fileUploadAndDownload/findFile", Description: "寻找目标文件(秒传)"}, + {ApiGroup: "分片上传", Method: "POST", Path: "/fileUploadAndDownload/breakpointContinue", Description: "断点续传"}, + {ApiGroup: "分片上传", Method: "POST", Path: "/fileUploadAndDownload/breakpointContinueFinish", Description: "断点续传完成"}, + {ApiGroup: "分片上传", Method: "POST", Path: "/fileUploadAndDownload/removeChunk", Description: "上传完成移除文件"}, + + {ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/upload", Description: "文件上传示例"}, + {ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/deleteFile", Description: "删除文件"}, + {ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/editFileName", Description: "文件名或者备注编辑"}, + {ApiGroup: "文件上传与下载", Method: "POST", Path: "/fileUploadAndDownload/getFileList", Description: "获取上传文件列表"}, + + {ApiGroup: "系统服务", Method: "POST", Path: "/system/getServerInfo", Description: "获取服务器信息"}, + {ApiGroup: "系统服务", Method: "POST", Path: "/system/getSystemConfig", Description: "获取配置文件内容"}, + {ApiGroup: "系统服务", Method: "POST", Path: "/system/setSystemConfig", Description: "设置配置文件内容"}, + + {ApiGroup: "客户", Method: "PUT", Path: "/customer/customer", Description: "更新客户"}, + {ApiGroup: "客户", Method: "POST", Path: "/customer/customer", Description: "创建客户"}, + {ApiGroup: "客户", Method: "DELETE", Path: "/customer/customer", Description: "删除客户"}, + {ApiGroup: "客户", Method: "GET", Path: "/customer/customer", Description: "获取单一客户"}, + {ApiGroup: "客户", Method: "GET", Path: "/customer/customerList", Description: "获取客户列表"}, + + {ApiGroup: "代码生成器", Method: "GET", Path: "/autoCode/getDB", Description: "获取所有数据库"}, + {ApiGroup: "代码生成器", Method: "GET", Path: "/autoCode/getTables", Description: "获取数据库表"}, + {ApiGroup: "代码生成器", Method: "POST", Path: "/autoCode/createTemp", Description: "自动化代码"}, + {ApiGroup: "代码生成器", Method: "POST", Path: "/autoCode/preview", Description: "预览自动化代码"}, + {ApiGroup: "代码生成器", Method: "GET", Path: "/autoCode/getColumn", Description: "获取所选table的所有字段"}, + {ApiGroup: "代码生成器", Method: "POST", Path: "/autoCode/createPlug", Description: "自动创建插件包"}, + {ApiGroup: "代码生成器", Method: "POST", Path: "/autoCode/installPlugin", Description: "安装插件"}, + {ApiGroup: "代码生成器", Method: "POST", Path: "/autoCode/pubPlug", Description: "打包插件"}, + + {ApiGroup: "包(pkg)生成器", Method: "POST", Path: "/autoCode/createPackage", Description: "生成包(package)"}, + {ApiGroup: "包(pkg)生成器", Method: "POST", Path: "/autoCode/getPackage", Description: "获取所有包(package)"}, + {ApiGroup: "包(pkg)生成器", Method: "POST", Path: "/autoCode/delPackage", Description: "删除包(package)"}, + + {ApiGroup: "代码生成器历史", Method: "POST", Path: "/autoCode/getMeta", Description: "获取meta信息"}, + {ApiGroup: "代码生成器历史", Method: "POST", Path: "/autoCode/rollback", Description: "回滚自动生成代码"}, + {ApiGroup: "代码生成器历史", Method: "POST", Path: "/autoCode/getSysHistory", Description: "查询回滚记录"}, + {ApiGroup: "代码生成器历史", Method: "POST", Path: "/autoCode/delSysHistory", Description: "删除回滚记录"}, + + {ApiGroup: "系统字典详情", Method: "PUT", Path: "/sysDictionaryDetail/updateSysDictionaryDetail", Description: "更新字典内容"}, + {ApiGroup: "系统字典详情", Method: "POST", Path: "/sysDictionaryDetail/createSysDictionaryDetail", Description: "新增字典内容"}, + {ApiGroup: "系统字典详情", Method: "DELETE", Path: "/sysDictionaryDetail/deleteSysDictionaryDetail", Description: "删除字典内容"}, + {ApiGroup: "系统字典详情", Method: "GET", Path: "/sysDictionaryDetail/findSysDictionaryDetail", Description: "根据ID获取字典内容"}, + {ApiGroup: "系统字典详情", Method: "GET", Path: "/sysDictionaryDetail/getSysDictionaryDetailList", Description: "获取字典内容列表"}, + + {ApiGroup: "系统字典", Method: "POST", Path: "/sysDictionary/createSysDictionary", Description: "新增字典"}, + {ApiGroup: "系统字典", Method: "DELETE", Path: "/sysDictionary/deleteSysDictionary", Description: "删除字典"}, + {ApiGroup: "系统字典", Method: "PUT", Path: "/sysDictionary/updateSysDictionary", Description: "更新字典"}, + {ApiGroup: "系统字典", Method: "GET", Path: "/sysDictionary/findSysDictionary", Description: "根据ID获取字典"}, + {ApiGroup: "系统字典", Method: "GET", Path: "/sysDictionary/getSysDictionaryList", Description: "获取字典列表"}, + + {ApiGroup: "操作记录", Method: "POST", Path: "/sysOperationRecord/createSysOperationRecord", Description: "新增操作记录"}, + {ApiGroup: "操作记录", Method: "GET", Path: "/sysOperationRecord/findSysOperationRecord", Description: "根据ID获取操作记录"}, + {ApiGroup: "操作记录", Method: "GET", Path: "/sysOperationRecord/getSysOperationRecordList", Description: "获取操作记录列表"}, + {ApiGroup: "操作记录", Method: "DELETE", Path: "/sysOperationRecord/deleteSysOperationRecord", Description: "删除操作记录"}, + {ApiGroup: "操作记录", Method: "DELETE", Path: "/sysOperationRecord/deleteSysOperationRecordByIds", Description: "批量删除操作历史"}, + + {ApiGroup: "断点续传(插件版)", Method: "POST", Path: "/simpleUploader/upload", Description: "插件版分片上传"}, + {ApiGroup: "断点续传(插件版)", Method: "GET", Path: "/simpleUploader/checkFileMd5", Description: "文件完整度验证"}, + {ApiGroup: "断点续传(插件版)", Method: "GET", Path: "/simpleUploader/mergeFileMd5", Description: "上传完成合并文件"}, + + {ApiGroup: "email", Method: "POST", Path: "/email/emailTest", Description: "发送测试邮件"}, + {ApiGroup: "email", Method: "POST", Path: "/email/emailSend", Description: "发送邮件示例"}, + + {ApiGroup: "按钮权限", Method: "POST", Path: "/authorityBtn/setAuthorityBtn", Description: "设置按钮权限"}, + {ApiGroup: "按钮权限", Method: "POST", Path: "/authorityBtn/getAuthorityBtn", Description: "获取已有按钮权限"}, + {ApiGroup: "按钮权限", Method: "POST", Path: "/authorityBtn/canRemoveAuthorityBtn", Description: "删除按钮"}, + + {ApiGroup: "万用表格", Method: "POST", Path: "/chatGpt/getTable", Description: "通过gpt获取内容"}, + {ApiGroup: "万用表格", Method: "POST", Path: "/chatGpt/createSK", Description: "录入sk"}, + {ApiGroup: "万用表格", Method: "GET", Path: "/chatGpt/getSK", Description: "获取sk"}, + {ApiGroup: "万用表格", Method: "DELETE", Path: "/chatGpt/deleteSK", Description: "删除sk"}, + } + if err := db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, sysModel.SysApi{}.TableName()+"表数据初始化失败!") + } + next := context.WithValue(ctx, i.InitializerName(), entities) + return next, nil +} + +func (i *initApi) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + if errors.Is(db.Where("path = ? AND method = ?", "/authorityBtn/canRemoveAuthorityBtn", "POST"). + First(&sysModel.SysApi{}).Error, gorm.ErrRecordNotFound) { + return false + } + return true +} diff --git a/source/system/authorities_menus.go b/source/system/authorities_menus.go new file mode 100644 index 0000000..a0858e1 --- /dev/null +++ b/source/system/authorities_menus.go @@ -0,0 +1,83 @@ +package system + +import ( + "context" + + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" +) + +const initOrderMenuAuthority = initOrderMenu + initOrderAuthority + +type initMenuAuthority struct{} + +// auto run +func init() { + system.RegisterInit(initOrderMenuAuthority, &initMenuAuthority{}) +} + +func (i *initMenuAuthority) MigrateTable(ctx context.Context) (context.Context, error) { + return ctx, nil // do nothing +} + +func (i *initMenuAuthority) TableCreated(ctx context.Context) bool { + return false // always replace +} + +func (i initMenuAuthority) InitializerName() string { + return "sys_menu_authorities" +} + +func (i *initMenuAuthority) InitializeData(ctx context.Context) (next context.Context, err error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + authorities, ok := ctx.Value(initAuthority{}.InitializerName()).([]sysModel.SysAuthority) + if !ok { + return ctx, errors.Wrap(system.ErrMissingDependentContext, "创建 [菜单-权限] 关联失败, 未找到权限表初始化数据") + } + menus, ok := ctx.Value(initMenu{}.InitializerName()).([]sysModel.SysBaseMenu) + if !ok { + return next, errors.Wrap(errors.New(""), "创建 [菜单-权限] 关联失败, 未找到菜单表初始化数据") + } + next = ctx + // 888 + if err = db.Model(&authorities[0]).Association("SysBaseMenus").Replace(menus); err != nil { + return next, err + } + + // 8881 + menu8881 := menus[:2] + menu8881 = append(menu8881, menus[7]) + if err = db.Model(&authorities[1]).Association("SysBaseMenus").Replace(menu8881); err != nil { + return next, err + } + + // 9528 + if err = db.Model(&authorities[2]).Association("SysBaseMenus").Replace(menus[:11]); err != nil { + return next, err + } + if err = db.Model(&authorities[2]).Association("SysBaseMenus").Append(menus[12:17]); err != nil { + return next, err + } + return next, nil +} + +func (i *initMenuAuthority) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + auth := &sysModel.SysAuthority{} + if ret := db.Model(auth). + Where("authority_id = ?", 9528).Preload("SysBaseMenus").Find(auth); ret != nil { + if ret.Error != nil { + return false + } + return len(auth.SysBaseMenus) > 0 + } + return false +} diff --git a/source/system/authority.go b/source/system/authority.go new file mode 100644 index 0000000..a8cab12 --- /dev/null +++ b/source/system/authority.go @@ -0,0 +1,88 @@ +package system + +import ( + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" + "miniapp/utils" +) + +const initOrderAuthority = initOrderCasbin + 1 + +type initAuthority struct{} + +// auto run +func init() { + system.RegisterInit(initOrderAuthority, &initAuthority{}) +} + +func (i *initAuthority) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&sysModel.SysAuthority{}) +} + +func (i *initAuthority) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&sysModel.SysAuthority{}) +} + +func (i initAuthority) InitializerName() string { + return sysModel.SysAuthority{}.TableName() +} + +func (i *initAuthority) InitializeData(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + entities := []sysModel.SysAuthority{ + {AuthorityId: 888, AuthorityName: "普通用户", ParentId: utils.Pointer[uint](0), DefaultRouter: "dashboard"}, + {AuthorityId: 9528, AuthorityName: "测试角色", ParentId: utils.Pointer[uint](0), DefaultRouter: "dashboard"}, + {AuthorityId: 8881, AuthorityName: "普通用户子角色", ParentId: utils.Pointer[uint](888), DefaultRouter: "dashboard"}, + } + + if err := db.Create(&entities).Error; err != nil { + return ctx, errors.Wrapf(err, "%s表数据初始化失败!", sysModel.SysAuthority{}.TableName()) + } + // data authority + if err := db.Model(&entities[0]).Association("DataAuthorityId").Replace( + []*sysModel.SysAuthority{ + {AuthorityId: 888}, + {AuthorityId: 9528}, + {AuthorityId: 8881}, + }); err != nil { + return ctx, errors.Wrapf(err, "%s表数据初始化失败!", + db.Model(&entities[0]).Association("DataAuthorityId").Relationship.JoinTable.Name) + } + if err := db.Model(&entities[1]).Association("DataAuthorityId").Replace( + []*sysModel.SysAuthority{ + {AuthorityId: 9528}, + {AuthorityId: 8881}, + }); err != nil { + return ctx, errors.Wrapf(err, "%s表数据初始化失败!", + db.Model(&entities[1]).Association("DataAuthorityId").Relationship.JoinTable.Name) + } + + next := context.WithValue(ctx, i.InitializerName(), entities) + return next, nil +} + +func (i *initAuthority) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + if errors.Is(db.Where("authority_id = ?", "8881"). + First(&sysModel.SysAuthority{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据 + return false + } + return true +} diff --git a/source/system/casbin.go b/source/system/casbin.go new file mode 100644 index 0000000..635ae97 --- /dev/null +++ b/source/system/casbin.go @@ -0,0 +1,258 @@ +package system + +import ( + "context" + + adapter "github.com/casbin/gorm-adapter/v3" + "github.com/pkg/errors" + "gorm.io/gorm" + "miniapp/service/system" +) + +const initOrderCasbin = initOrderApi + 1 + +type initCasbin struct{} + +// auto run +func init() { + system.RegisterInit(initOrderCasbin, &initCasbin{}) +} + +func (i *initCasbin) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&adapter.CasbinRule{}) +} + +func (i *initCasbin) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&adapter.CasbinRule{}) +} + +func (i initCasbin) InitializerName() string { + var entity adapter.CasbinRule + return entity.TableName() +} + +func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + entities := []adapter.CasbinRule{ + {Ptype: "p", V0: "888", V1: "/user/admin_register", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/api/createApi", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/getApiList", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/getApiById", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/deleteApi", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/updateApi", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/getAllApis", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/api/deleteApisByIds", V2: "DELETE"}, + + {Ptype: "p", V0: "888", V1: "/authority/copyAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authority/updateAuthority", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/authority/createAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authority/deleteAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authority/getAuthorityList", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authority/setDataAuthority", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/menu/getMenu", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/getMenuList", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/addBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/getBaseMenuTree", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/addMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/getMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/deleteBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/updateBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/menu/getBaseMenuById", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/user/getUserInfo", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/user/setUserInfo", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/user/setSelfInfo", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/user/getUserList", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/user/deleteUser", V2: "DELETE"}, + {Ptype: "p", V0: "888", V1: "/user/changePassword", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/user/setUserAuthority", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/user/setUserAuthorities", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/user/resetPassword", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/findFile", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/breakpointContinueFinish", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/breakpointContinue", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/removeChunk", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/upload", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/editFileName", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/fileUploadAndDownload/getFileList", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/casbin/updateCasbin", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/jwt/jsonInBlacklist", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/system/getSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/system/setSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/system/getServerInfo", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/customer/customer", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/customer/customer", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/customer/customer", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/customer/customer", V2: "DELETE"}, + {Ptype: "p", V0: "888", V1: "/customer/customerList", V2: "GET"}, + + {Ptype: "p", V0: "888", V1: "/autoCode/getDB", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/autoCode/getMeta", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/preview", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/getTables", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/autoCode/getColumn", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/autoCode/rollback", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/createTemp", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/delSysHistory", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/getSysHistory", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/createPackage", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/getPackage", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/delPackage", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/createPlug", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/installPlugin", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/autoCode/pubPlug", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/sysDictionaryDetail/findSysDictionaryDetail", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysDictionaryDetail/updateSysDictionaryDetail", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/sysDictionaryDetail/createSysDictionaryDetail", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/sysDictionaryDetail/getSysDictionaryDetailList", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysDictionaryDetail/deleteSysDictionaryDetail", V2: "DELETE"}, + + {Ptype: "p", V0: "888", V1: "/sysDictionary/findSysDictionary", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysDictionary/updateSysDictionary", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/sysDictionary/getSysDictionaryList", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysDictionary/createSysDictionary", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/sysDictionary/deleteSysDictionary", V2: "DELETE"}, + + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/findSysOperationRecord", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/updateSysOperationRecord", V2: "PUT"}, + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/createSysOperationRecord", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/getSysOperationRecordList", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/deleteSysOperationRecord", V2: "DELETE"}, + {Ptype: "p", V0: "888", V1: "/sysOperationRecord/deleteSysOperationRecordByIds", V2: "DELETE"}, + + {Ptype: "p", V0: "888", V1: "/email/emailTest", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/simpleUploader/upload", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/simpleUploader/checkFileMd5", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/simpleUploader/mergeFileMd5", V2: "GET"}, + + {Ptype: "p", V0: "888", V1: "/authorityBtn/setAuthorityBtn", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authorityBtn/getAuthorityBtn", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/authorityBtn/canRemoveAuthorityBtn", V2: "POST"}, + + {Ptype: "p", V0: "888", V1: "/chatGpt/getTable", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/chatGpt/createSK", V2: "POST"}, + {Ptype: "p", V0: "888", V1: "/chatGpt/getSK", V2: "GET"}, + {Ptype: "p", V0: "888", V1: "/chatGpt/deleteSK", V2: "DELETE"}, + + {Ptype: "p", V0: "8881", V1: "/user/admin_register", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/createApi", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/getApiList", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/getApiById", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/deleteApi", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/updateApi", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/api/getAllApis", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/authority/createAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/authority/deleteAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/authority/getAuthorityList", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/authority/setDataAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/getMenu", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/getMenuList", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/addBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/getBaseMenuTree", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/addMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/getMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/deleteBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/updateBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/menu/getBaseMenuById", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/user/changePassword", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/user/getUserList", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/user/setUserAuthority", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/upload", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/getFileList", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/fileUploadAndDownload/editFileName", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/casbin/updateCasbin", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/jwt/jsonInBlacklist", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/system/getSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/system/setSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/customer/customer", V2: "POST"}, + {Ptype: "p", V0: "8881", V1: "/customer/customer", V2: "PUT"}, + {Ptype: "p", V0: "8881", V1: "/customer/customer", V2: "DELETE"}, + {Ptype: "p", V0: "8881", V1: "/customer/customer", V2: "GET"}, + {Ptype: "p", V0: "8881", V1: "/customer/customerList", V2: "GET"}, + {Ptype: "p", V0: "8881", V1: "/user/getUserInfo", V2: "GET"}, + + {Ptype: "p", V0: "9528", V1: "/user/admin_register", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/createApi", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/getApiList", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/getApiById", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/deleteApi", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/updateApi", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/api/getAllApis", V2: "POST"}, + + {Ptype: "p", V0: "9528", V1: "/authority/createAuthority", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/authority/deleteAuthority", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/authority/getAuthorityList", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/authority/setDataAuthority", V2: "POST"}, + + {Ptype: "p", V0: "9528", V1: "/menu/getMenu", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/getMenuList", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/addBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/getBaseMenuTree", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/addMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/getMenuAuthority", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/deleteBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/updateBaseMenu", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/menu/getBaseMenuById", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/user/changePassword", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/user/getUserList", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/user/setUserAuthority", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/upload", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/getFileList", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/deleteFile", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/fileUploadAndDownload/editFileName", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/casbin/updateCasbin", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/casbin/getPolicyPathByAuthorityId", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/jwt/jsonInBlacklist", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/system/getSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/system/setSystemConfig", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/customer/customer", V2: "PUT"}, + {Ptype: "p", V0: "9528", V1: "/customer/customer", V2: "GET"}, + {Ptype: "p", V0: "9528", V1: "/customer/customer", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/customer/customer", V2: "DELETE"}, + {Ptype: "p", V0: "9528", V1: "/customer/customerList", V2: "GET"}, + {Ptype: "p", V0: "9528", V1: "/autoCode/createTemp", V2: "POST"}, + {Ptype: "p", V0: "9528", V1: "/user/getUserInfo", V2: "GET"}, + } + if err := db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, "Casbin 表 ("+i.InitializerName()+") 数据初始化失败!") + } + next := context.WithValue(ctx, i.InitializerName(), entities) + return next, nil +} + +func (i *initCasbin) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + if errors.Is(db.Where(adapter.CasbinRule{Ptype: "p", V0: "9528", V1: "/user/getUserInfo", V2: "GET"}). + First(&adapter.CasbinRule{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据 + return false + } + return true +} diff --git a/source/system/dictionary.go b/source/system/dictionary.go new file mode 100644 index 0000000..bbbb126 --- /dev/null +++ b/source/system/dictionary.go @@ -0,0 +1,71 @@ +package system + +import ( + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" +) + +const initOrderDict = initOrderCasbin + 1 + +type initDict struct{} + +// auto run +func init() { + system.RegisterInit(initOrderDict, &initDict{}) +} + +func (i *initDict) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&sysModel.SysDictionary{}) +} + +func (i *initDict) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&sysModel.SysDictionary{}) +} + +func (i initDict) InitializerName() string { + return sysModel.SysDictionary{}.TableName() +} + +func (i *initDict) InitializeData(ctx context.Context) (next context.Context, err error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + True := true + entities := []sysModel.SysDictionary{ + {Name: "性别", Type: "gender", Status: &True, Desc: "性别字典"}, + {Name: "数据库int类型", Type: "int", Status: &True, Desc: "int类型对应的数据库类型"}, + {Name: "数据库时间日期类型", Type: "time.Time", Status: &True, Desc: "数据库时间日期类型"}, + {Name: "数据库浮点型", Type: "float64", Status: &True, Desc: "数据库浮点型"}, + {Name: "数据库字符串", Type: "string", Status: &True, Desc: "数据库字符串"}, + {Name: "数据库bool类型", Type: "bool", Status: &True, Desc: "数据库bool类型"}, + } + + if err = db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, sysModel.SysDictionary{}.TableName()+"表数据初始化失败!") + } + next = context.WithValue(ctx, i.InitializerName(), entities) + return next, nil +} + +func (i *initDict) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + if errors.Is(db.Where("type = ?", "bool").First(&sysModel.SysDictionary{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据 + return false + } + return true +} diff --git a/source/system/dictionary_detail.go b/source/system/dictionary_detail.go new file mode 100644 index 0000000..762f3d7 --- /dev/null +++ b/source/system/dictionary_detail.go @@ -0,0 +1,113 @@ +package system + +import ( + "context" + "fmt" + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" +) + +const initOrderDictDetail = initOrderDict + 1 + +type initDictDetail struct{} + +// auto run +func init() { + system.RegisterInit(initOrderDictDetail, &initDictDetail{}) +} + +func (i *initDictDetail) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&sysModel.SysDictionaryDetail{}) +} + +func (i *initDictDetail) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&sysModel.SysDictionaryDetail{}) +} + +func (i initDictDetail) InitializerName() string { + return sysModel.SysDictionaryDetail{}.TableName() +} + +func (i *initDictDetail) InitializeData(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + dicts, ok := ctx.Value(initDict{}.InitializerName()).([]sysModel.SysDictionary) + if !ok { + return ctx, errors.Wrap(system.ErrMissingDependentContext, + fmt.Sprintf("未找到 %s 表初始化数据", sysModel.SysDictionary{}.TableName())) + } + True := true + dicts[0].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "男", Value: 1, Status: &True, Sort: 1}, + {Label: "女", Value: 2, Status: &True, Sort: 2}, + } + + dicts[1].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "smallint", Value: 1, Status: &True, Sort: 1}, + {Label: "mediumint", Value: 2, Status: &True, Sort: 2}, + {Label: "int", Value: 3, Status: &True, Sort: 3}, + {Label: "bigint", Value: 4, Status: &True, Sort: 4}, + } + + dicts[2].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "date", Status: &True}, + {Label: "time", Value: 1, Status: &True, Sort: 1}, + {Label: "year", Value: 2, Status: &True, Sort: 2}, + {Label: "datetime", Value: 3, Status: &True, Sort: 3}, + {Label: "timestamp", Value: 5, Status: &True, Sort: 5}, + } + dicts[3].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "float", Status: &True}, + {Label: "double", Value: 1, Status: &True, Sort: 1}, + {Label: "decimal", Value: 2, Status: &True, Sort: 2}, + } + + dicts[4].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "char", Status: &True}, + {Label: "varchar", Value: 1, Status: &True, Sort: 1}, + {Label: "tinyblob", Value: 2, Status: &True, Sort: 2}, + {Label: "tinytext", Value: 3, Status: &True, Sort: 3}, + {Label: "text", Value: 4, Status: &True, Sort: 4}, + {Label: "blob", Value: 5, Status: &True, Sort: 5}, + {Label: "mediumblob", Value: 6, Status: &True, Sort: 6}, + {Label: "mediumtext", Value: 7, Status: &True, Sort: 7}, + {Label: "longblob", Value: 8, Status: &True, Sort: 8}, + {Label: "longtext", Value: 9, Status: &True, Sort: 9}, + } + + dicts[5].SysDictionaryDetails = []sysModel.SysDictionaryDetail{ + {Label: "tinyint", Status: &True}, + } + for _, dict := range dicts { + if err := db.Model(&dict).Association("SysDictionaryDetails"). + Replace(dict.SysDictionaryDetails); err != nil { + return ctx, errors.Wrap(err, sysModel.SysDictionaryDetail{}.TableName()+"表数据初始化失败!") + } + } + return ctx, nil +} + +func (i *initDictDetail) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + var dict sysModel.SysDictionary + if err := db.Preload("SysDictionaryDetails"). + First(&dict, &sysModel.SysDictionary{Name: "数据库bool类型"}).Error; err != nil { + return false + } + return len(dict.SysDictionaryDetails) > 0 && dict.SysDictionaryDetails[0].Label == "tinyint" +} diff --git a/source/system/menu.go b/source/system/menu.go new file mode 100644 index 0000000..07654e8 --- /dev/null +++ b/source/system/menu.go @@ -0,0 +1,101 @@ +package system + +import ( + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + . "miniapp/model/system" + "miniapp/service/system" +) + +const initOrderMenu = initOrderAuthority + 1 + +type initMenu struct{} + +// auto run +func init() { + system.RegisterInit(initOrderMenu, &initMenu{}) +} + +func (i initMenu) InitializerName() string { + return SysBaseMenu{}.TableName() +} + +func (i *initMenu) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate( + &SysBaseMenu{}, + &SysBaseMenuParameter{}, + &SysBaseMenuBtn{}, + ) +} + +func (i *initMenu) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + m := db.Migrator() + return m.HasTable(&SysBaseMenu{}) && + m.HasTable(&SysBaseMenuParameter{}) && + m.HasTable(&SysBaseMenuBtn{}) +} + +func (i *initMenu) InitializeData(ctx context.Context) (next context.Context, err error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + entities := []SysBaseMenu{ + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "dashboard", Name: "dashboard", Component: "view/dashboard/index.vue", Sort: 1, Meta: Meta{Title: "仪表盘", Icon: "odometer"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "about", Name: "about", Component: "view/about/index.vue", Sort: 9, Meta: Meta{Title: "关于我们", Icon: "info-filled"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "admin", Name: "superAdmin", Component: "view/superAdmin/index.vue", Sort: 3, Meta: Meta{Title: "超级管理员", Icon: "user"}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "authority", Name: "authority", Component: "view/superAdmin/authority/authority.vue", Sort: 1, Meta: Meta{Title: "角色管理", Icon: "avatar"}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "menu", Name: "menu", Component: "view/superAdmin/menu/menu.vue", Sort: 2, Meta: Meta{Title: "菜单管理", Icon: "tickets", KeepAlive: true}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "api", Name: "api", Component: "view/superAdmin/api/api.vue", Sort: 3, Meta: Meta{Title: "api管理", Icon: "platform", KeepAlive: true}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "user", Name: "user", Component: "view/superAdmin/user/user.vue", Sort: 4, Meta: Meta{Title: "用户管理", Icon: "coordinate"}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "dictionary", Name: "dictionary", Component: "view/superAdmin/dictionary/sysDictionary.vue", Sort: 5, Meta: Meta{Title: "字典管理", Icon: "notebook"}}, + {MenuLevel: 0, Hidden: true, ParentId: "3", Path: "dictionaryDetail/:id", Name: "dictionaryDetail", Component: "view/superAdmin/dictionary/sysDictionaryDetail.vue", Sort: 1, Meta: Meta{Title: "字典详情-${id}", Icon: "list", ActiveName: "dictionary"}}, + {MenuLevel: 0, Hidden: false, ParentId: "3", Path: "operation", Name: "operation", Component: "view/superAdmin/operation/sysOperationRecord.vue", Sort: 6, Meta: Meta{Title: "操作历史", Icon: "pie-chart"}}, + {MenuLevel: 0, Hidden: true, ParentId: "0", Path: "person", Name: "person", Component: "view/person/person.vue", Sort: 4, Meta: Meta{Title: "个人信息", Icon: "message"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "example", Name: "example", Component: "view/example/index.vue", Sort: 7, Meta: Meta{Title: "示例文件", Icon: "management"}}, + {MenuLevel: 0, Hidden: false, ParentId: "12", Path: "upload", Name: "upload", Component: "view/example/upload/upload.vue", Sort: 5, Meta: Meta{Title: "媒体库(上传下载)", Icon: "upload"}}, + {MenuLevel: 0, Hidden: false, ParentId: "12", Path: "breakpoint", Name: "breakpoint", Component: "view/example/breakpoint/breakpoint.vue", Sort: 6, Meta: Meta{Title: "断点续传", Icon: "upload-filled"}}, + {MenuLevel: 0, Hidden: false, ParentId: "12", Path: "customer", Name: "customer", Component: "view/example/customer/customer.vue", Sort: 7, Meta: Meta{Title: "客户列表(资源示例)", Icon: "avatar"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "systemTools", Name: "systemTools", Component: "view/systemTools/index.vue", Sort: 5, Meta: Meta{Title: "系统工具", Icon: "tools"}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "autoCode", Name: "autoCode", Component: "view/systemTools/autoCode/index.vue", Sort: 1, Meta: Meta{Title: "代码生成器", Icon: "cpu", KeepAlive: true}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "formCreate", Name: "formCreate", Component: "view/systemTools/formCreate/index.vue", Sort: 2, Meta: Meta{Title: "表单生成器", Icon: "magic-stick", KeepAlive: true}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "system", Name: "system", Component: "view/systemTools/system/system.vue", Sort: 3, Meta: Meta{Title: "系统配置", Icon: "operation"}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "autoCodeAdmin", Name: "autoCodeAdmin", Component: "view/systemTools/autoCodeAdmin/index.vue", Sort: 1, Meta: Meta{Title: "自动化代码管理", Icon: "magic-stick"}}, + {MenuLevel: 0, Hidden: true, ParentId: "16", Path: "autoCodeEdit/:id", Name: "autoCodeEdit", Component: "view/systemTools/autoCode/index.vue", Sort: 0, Meta: Meta{Title: "自动化代码-${id}", Icon: "magic-stick"}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "autoPkg", Name: "autoPkg", Component: "view/systemTools/autoPkg/autoPkg.vue", Sort: 0, Meta: Meta{Title: "自动化package", Icon: "folder"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "https://www.gin-vue-admin.com", Name: "https://www.gin-vue-admin.com", Component: "/", Sort: 0, Meta: Meta{Title: "官方网站", Icon: "home-filled"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "state", Name: "state", Component: "view/system/state.vue", Sort: 8, Meta: Meta{Title: "服务器状态", Icon: "cloudy"}}, + {MenuLevel: 0, Hidden: false, ParentId: "0", Path: "plugin", Name: "plugin", Component: "view/routerHolder.vue", Sort: 6, Meta: Meta{Title: "插件系统", Icon: "cherry"}}, + {MenuLevel: 0, Hidden: false, ParentId: "25", Path: "https://plugin.gin-vue-admin.com/", Name: "https://plugin.gin-vue-admin.com/", Component: "https://plugin.gin-vue-admin.com/", Sort: 0, Meta: Meta{Title: "插件市场", Icon: "shop"}}, + {MenuLevel: 0, Hidden: false, ParentId: "25", Path: "installPlugin", Name: "installPlugin", Component: "view/systemTools/installPlugin/index.vue", Sort: 1, Meta: Meta{Title: "插件安装", Icon: "box"}}, + {MenuLevel: 0, Hidden: false, ParentId: "25", Path: "autoPlug", Name: "autoPlug", Component: "view/systemTools/autoPlug/autoPlug.vue", Sort: 2, Meta: Meta{Title: "插件模板", Icon: "folder"}}, + {MenuLevel: 0, Hidden: false, ParentId: "25", Path: "pubPlug", Name: "pubPlug", Component: "view/systemTools/pubPlug/pubPlug.vue", Sort: 3, Meta: Meta{Title: "打包插件", Icon: "files"}}, + {MenuLevel: 0, Hidden: false, ParentId: "25", Path: "plugin-email", Name: "plugin-email", Component: "plugin/email/view/index.vue", Sort: 4, Meta: Meta{Title: "邮件插件", Icon: "message"}}, + {MenuLevel: 0, Hidden: false, ParentId: "16", Path: "chatTable", Name: "chatTable", Component: "view/chatgpt/chatTable.vue", Sort: 6, Meta: Meta{Title: "万用表格", Icon: "chat-dot-square"}}, + } + if err = db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, SysBaseMenu{}.TableName()+"表数据初始化失败!") + } + next = context.WithValue(ctx, i.InitializerName(), entities) + return next, nil +} + +func (i *initMenu) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + if errors.Is(db.Where("path = ?", "autoPkg").First(&SysBaseMenu{}).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据 + return false + } + return true +} diff --git a/source/system/user.go b/source/system/user.go new file mode 100644 index 0000000..7c7d2f4 --- /dev/null +++ b/source/system/user.go @@ -0,0 +1,99 @@ +package system + +import ( + "context" + "github.com/gofrs/uuid/v5" + "github.com/pkg/errors" + "gorm.io/gorm" + sysModel "miniapp/model/system" + "miniapp/service/system" + "miniapp/utils" +) + +const initOrderUser = initOrderAuthority + 1 + +type initUser struct{} + +// auto run +func init() { + system.RegisterInit(initOrderUser, &initUser{}) +} + +func (i *initUser) MigrateTable(ctx context.Context) (context.Context, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + return ctx, db.AutoMigrate(&sysModel.SysUser{}, &sysModel.SysChatGptOption{}) +} + +func (i *initUser) TableCreated(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + return db.Migrator().HasTable(&sysModel.SysUser{}) +} + +func (i initUser) InitializerName() string { + return sysModel.SysUser{}.TableName() +} + +func (i *initUser) InitializeData(ctx context.Context) (next context.Context, err error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return ctx, system.ErrMissingDBContext + } + password := utils.BcryptHash("6447985") + adminPassword := utils.BcryptHash("123456") + + entities := []sysModel.SysUser{ + { + UUID: uuid.Must(uuid.NewV4()), + Username: "admin", + Password: adminPassword, + NickName: "Mr.奇淼", + HeaderImg: "https://qmplusimg.henrongyi.top/gva_header.jpg", + AuthorityId: 888, + Phone: "17611111111", + Email: "333333333@qq.com", + }, + { + UUID: uuid.Must(uuid.NewV4()), + Username: "a303176530", + Password: password, + NickName: "用户1", + HeaderImg: "https:///qmplusimg.henrongyi.top/1572075907logo.png", + AuthorityId: 9528, + Phone: "17611111111", + Email: "333333333@qq.com"}, + } + if err = db.Create(&entities).Error; err != nil { + return ctx, errors.Wrap(err, sysModel.SysUser{}.TableName()+"表数据初始化失败!") + } + next = context.WithValue(ctx, i.InitializerName(), entities) + authorityEntities, ok := ctx.Value(initAuthority{}.InitializerName()).([]sysModel.SysAuthority) + if !ok { + return next, errors.Wrap(system.ErrMissingDependentContext, "创建 [用户-权限] 关联失败, 未找到权限表初始化数据") + } + if err = db.Model(&entities[0]).Association("Authorities").Replace(authorityEntities); err != nil { + return next, err + } + if err = db.Model(&entities[1]).Association("Authorities").Replace(authorityEntities[:1]); err != nil { + return next, err + } + return next, err +} + +func (i *initUser) DataInserted(ctx context.Context) bool { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return false + } + var record sysModel.SysUser + if errors.Is(db.Where("username = ?", "a303176530"). + Preload("Authorities").First(&record).Error, gorm.ErrRecordNotFound) { // 判断是否存在数据 + return false + } + return len(record.Authorities) > 0 && record.Authorities[0].AuthorityId == 888 +} diff --git a/utils/ast/ast.go b/utils/ast/ast.go new file mode 100644 index 0000000..5420aec --- /dev/null +++ b/utils/ast/ast.go @@ -0,0 +1,47 @@ +package ast + +import ( + "fmt" + "go/ast" + "go/token" +) + +// 增加 import 方法 +func AddImport(astNode ast.Node, imp string) { + impStr := fmt.Sprintf("\"%s\"", imp) + ast.Inspect(astNode, func(node ast.Node) bool { + if genDecl, ok := node.(*ast.GenDecl); ok { + if genDecl.Tok == token.IMPORT { + for i := range genDecl.Specs { + if impNode, ok := genDecl.Specs[i].(*ast.ImportSpec); ok { + if impNode.Path.Value == impStr { + return false + } + } + } + genDecl.Specs = append(genDecl.Specs, &ast.ImportSpec{ + Path: &ast.BasicLit{ + Kind: token.STRING, + Value: impStr, + }, + }) + } + } + return true + }) +} + +// 查询特定function方法 +func FindFunction(astNode ast.Node, FunctionName string) *ast.FuncDecl { + var funcDeclP *ast.FuncDecl + ast.Inspect(astNode, func(node ast.Node) bool { + if funcDecl, ok := node.(*ast.FuncDecl); ok { + if funcDecl.Name.String() == FunctionName { + funcDeclP = funcDecl + return false + } + } + return true + }) + return funcDeclP +} diff --git a/utils/ast/ast_auto_enter.go b/utils/ast/ast_auto_enter.go new file mode 100644 index 0000000..382f554 --- /dev/null +++ b/utils/ast/ast_auto_enter.go @@ -0,0 +1,47 @@ +package ast + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "os" +) + +func ImportForAutoEnter(path string, funcName string, code string) { + src, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + } + fileSet := token.NewFileSet() + astFile, err := parser.ParseFile(fileSet, "", src, 0) + ast.Inspect(astFile, func(node ast.Node) bool { + if typeSpec, ok := node.(*ast.TypeSpec); ok { + if typeSpec.Name.Name == funcName { + if st, ok := typeSpec.Type.(*ast.StructType); ok { + for i := range st.Fields.List { + if t, ok := st.Fields.List[i].Type.(*ast.Ident); ok { + if t.Name == code { + return false + } + } + } + sn := &ast.Field{ + Type: &ast.Ident{Name: code}, + } + st.Fields.List = append(st.Fields.List, sn) + } + } + } + return true + }) + var out []byte + bf := bytes.NewBuffer(out) + err = printer.Fprint(bf, fileSet, astFile) + if err != nil { + return + } + _ = os.WriteFile(path, bf.Bytes(), 0666) +} diff --git a/utils/ast/ast_auto_enter_test.go b/utils/ast/ast_auto_enter_test.go new file mode 100644 index 0000000..509b775 --- /dev/null +++ b/utils/ast/ast_auto_enter_test.go @@ -0,0 +1,7 @@ +package ast + +import "testing" + +func TestImportForAutoEnter(t *testing.T) { + ImportForAutoEnter("D:\\gin-vue-admin\\server.exe.exe\\api\\v1\\test\\enter.go", "ApiGroup", "test") +} diff --git a/utils/ast/ast_enter.go b/utils/ast/ast_enter.go new file mode 100644 index 0000000..7a5c727 --- /dev/null +++ b/utils/ast/ast_enter.go @@ -0,0 +1,181 @@ +package ast + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "golang.org/x/text/cases" + "golang.org/x/text/language" + "log" + "os" + "strconv" + "strings" +) + +type Visitor struct { + ImportCode string + StructName string + PackageName string + GroupName string +} + +func (vi *Visitor) Visit(node ast.Node) ast.Visitor { + switch n := node.(type) { + case *ast.GenDecl: + // 查找有没有import context包 + // Notice:没有考虑没有import任何包的情况 + if n.Tok == token.IMPORT && vi.ImportCode != "" { + vi.addImport(n) + // 不需要再遍历子树 + return nil + } + if n.Tok == token.TYPE && vi.StructName != "" && vi.PackageName != "" && vi.GroupName != "" { + vi.addStruct(n) + return nil + } + case *ast.FuncDecl: + if n.Name.Name == "Routers" { + vi.addFuncBodyVar(n) + return nil + } + + } + return vi +} + +func (vi *Visitor) addStruct(genDecl *ast.GenDecl) ast.Visitor { + for i := range genDecl.Specs { + switch n := genDecl.Specs[i].(type) { + case *ast.TypeSpec: + if strings.Index(n.Name.Name, "Group") > -1 { + switch t := n.Type.(type) { + case *ast.StructType: + f := &ast.Field{ + Names: []*ast.Ident{ + { + Name: vi.StructName, + Obj: &ast.Object{ + Kind: ast.Var, + Name: vi.StructName, + }, + }, + }, + Type: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: vi.PackageName, + }, + Sel: &ast.Ident{ + Name: vi.GroupName, + }, + }, + } + t.Fields.List = append(t.Fields.List, f) + } + } + } + } + return vi +} + +func (vi *Visitor) addImport(genDecl *ast.GenDecl) ast.Visitor { + // 是否已经import + hasImported := false + for _, v := range genDecl.Specs { + importSpec := v.(*ast.ImportSpec) + // 如果已经包含 + if importSpec.Path.Value == strconv.Quote(vi.ImportCode) { + hasImported = true + } + } + if !hasImported { + genDecl.Specs = append(genDecl.Specs, &ast.ImportSpec{ + Path: &ast.BasicLit{ + Kind: token.STRING, + Value: strconv.Quote(vi.ImportCode), + }, + }) + } + return vi +} + +func (vi *Visitor) addFuncBodyVar(funDecl *ast.FuncDecl) ast.Visitor { + hasVar := false + for _, v := range funDecl.Body.List { + switch varSpec := v.(type) { + case *ast.AssignStmt: + for i := range varSpec.Lhs { + switch nn := varSpec.Lhs[i].(type) { + case *ast.Ident: + if nn.Name == vi.PackageName+"Router" { + hasVar = true + } + } + } + } + } + if !hasVar { + assignStmt := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: vi.PackageName + "Router", + Obj: &ast.Object{ + Kind: ast.Var, + Name: vi.PackageName + "Router", + }, + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.SelectorExpr{ + X: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "router", + }, + Sel: &ast.Ident{ + Name: "RouterGroupApp", + }, + }, + Sel: &ast.Ident{ + Name: cases.Title(language.English).String(vi.PackageName), + }, + }, + }, + } + funDecl.Body.List = append(funDecl.Body.List, funDecl.Body.List[1]) + index := 1 + copy(funDecl.Body.List[index+1:], funDecl.Body.List[index:]) + funDecl.Body.List[index] = assignStmt + } + return vi +} + +func ImportReference(filepath, importCode, structName, packageName, groupName string) error { + fSet := token.NewFileSet() + fParser, err := parser.ParseFile(fSet, filepath, nil, parser.ParseComments) + if err != nil { + return err + } + importCode = strings.TrimSpace(importCode) + v := &Visitor{ + ImportCode: importCode, + StructName: structName, + PackageName: packageName, + GroupName: groupName, + } + if importCode == "" { + ast.Print(fSet, fParser) + } + + ast.Walk(v, fParser) + + var output []byte + buffer := bytes.NewBuffer(output) + err = format.Node(buffer, fSet, fParser) + if err != nil { + log.Fatal(err) + } + // 写回数据 + return os.WriteFile(filepath, buffer.Bytes(), 0o600) +} diff --git a/utils/ast/ast_gorm.go b/utils/ast/ast_gorm.go new file mode 100644 index 0000000..f1cc55a --- /dev/null +++ b/utils/ast/ast_gorm.go @@ -0,0 +1,166 @@ +package ast + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "os" +) + +// 自动为 gorm.go 注册一个自动迁移 +func AddRegisterTablesAst(path, funcName, pk, varName, dbName, model string) { + modelPk := fmt.Sprintf("miniapp/model/%s", pk) + src, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + } + fileSet := token.NewFileSet() + astFile, err := parser.ParseFile(fileSet, "", src, 0) + if err != nil { + fmt.Println(err) + } + AddImport(astFile, modelPk) + FuncNode := FindFunction(astFile, funcName) + if FuncNode != nil { + ast.Print(fileSet, FuncNode) + } + addDBVar(FuncNode.Body, varName, dbName) + addAutoMigrate(FuncNode.Body, varName, pk, model) + var out []byte + bf := bytes.NewBuffer(out) + printer.Fprint(bf, fileSet, astFile) + + os.WriteFile(path, bf.Bytes(), 0666) +} + +// 增加一个 db库变量 +func addDBVar(astBody *ast.BlockStmt, varName, dbName string) { + if dbName == "" { + return + } + dbStr := fmt.Sprintf("\"%s\"", dbName) + + for i := range astBody.List { + if assignStmt, ok := astBody.List[i].(*ast.AssignStmt); ok { + if ident, ok := assignStmt.Lhs[0].(*ast.Ident); ok { + if ident.Name == varName { + return + } + } + } + } + assignNode := &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{ + Name: varName, + }, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: "global", + }, + Sel: &ast.Ident{ + Name: "GetGlobalDBByDBName", + }, + }, + Args: []ast.Expr{ + &ast.BasicLit{ + Kind: token.STRING, + Value: dbStr, + }, + }, + }, + }, + } + astBody.List = append([]ast.Stmt{assignNode}, astBody.List...) +} + +// 为db库变量增加 AutoMigrate 方法 +func addAutoMigrate(astBody *ast.BlockStmt, dbname string, pk string, model string) { + if dbname == "" { + dbname = "db" + } + flag := true + ast.Inspect(astBody, func(node ast.Node) bool { + // 首先判断需要加入的方法调用语句是否存在 不存在则直接走到下方逻辑 + switch n := node.(type) { + case *ast.CallExpr: + // 判断是否找到了AutoMigrate语句 + if s, ok := n.Fun.(*ast.SelectorExpr); ok { + if x, ok := s.X.(*ast.Ident); ok { + if s.Sel.Name == "AutoMigrate" && x.Name == dbname { + flag = false + if !NeedAppendModel(n, pk, model) { + return false + } + // 判断已经找到了AutoMigrate语句 + n.Args = append(n.Args, &ast.CompositeLit{ + Type: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: pk, + }, + Sel: &ast.Ident{ + Name: model, + }, + }, + }) + return false + } + } + } + } + return true + //然后判断 pk.model是否存在 如果存在直接跳出 如果不存在 则向已经找到的方法调用语句的node里面push一条 + }) + + if flag { + exprStmt := &ast.ExprStmt{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: dbname, + }, + Sel: &ast.Ident{ + Name: "AutoMigrate", + }, + }, + Args: []ast.Expr{ + &ast.CompositeLit{ + Type: &ast.SelectorExpr{ + X: &ast.Ident{ + Name: pk, + }, + Sel: &ast.Ident{ + Name: model, + }, + }, + }, + }, + }} + astBody.List = append(astBody.List, exprStmt) + } +} + +// 为automigrate增加实参 +func NeedAppendModel(callNode ast.Node, pk string, model string) bool { + flag := true + ast.Inspect(callNode, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.SelectorExpr: + if x, ok := n.X.(*ast.Ident); ok { + if n.Sel.Name == model && x.Name == pk { + flag = false + return false + } + } + } + return true + }) + return flag +} diff --git a/utils/ast/ast_gorm_test.go b/utils/ast/ast_gorm_test.go new file mode 100644 index 0000000..63c60f8 --- /dev/null +++ b/utils/ast/ast_gorm_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "miniapp/global" + "miniapp/model/example" + "testing" +) + +const A = 123 + +func TestAddRegisterTablesAst(t *testing.T) { + AddRegisterTablesAst("D:\\gin-vue-admin\\server.exe.exe\\utils\\ast_test.go", "Register", "test", "testDB", "testModel") +} + +func Register() { + test := global.GetGlobalDBByDBName("test") + test.AutoMigrate(example.ExaFile{}) +} diff --git a/utils/ast/ast_rollback.go b/utils/ast/ast_rollback.go new file mode 100644 index 0000000..d76a6a3 --- /dev/null +++ b/utils/ast/ast_rollback.go @@ -0,0 +1,157 @@ +package ast + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "miniapp/global" + "os" + "path/filepath" +) + +func RollBackAst(pk, model string) { + RollGormBack(pk, model) + RollRouterBack(pk, model) +} + +func RollGormBack(pk, model string) { + + // 首先分析存在多少个ttt作为调用方的node块 + // 如果多个 仅仅删除对应块即可 + // 如果单个 那么还需要剔除import + path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "initialize", "gorm.go") + src, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + } + fileSet := token.NewFileSet() + astFile, err := parser.ParseFile(fileSet, "", src, 0) + if err != nil { + fmt.Println(err) + } + var n *ast.CallExpr + var k int = -1 + var pkNum = 0 + ast.Inspect(astFile, func(node ast.Node) bool { + if node, ok := node.(*ast.CallExpr); ok { + for i := range node.Args { + pkOK := false + modelOK := false + ast.Inspect(node.Args[i], func(item ast.Node) bool { + if ii, ok := item.(*ast.Ident); ok { + if ii.Name == pk { + pkOK = true + pkNum++ + } + if ii.Name == model { + modelOK = true + } + } + if pkOK && modelOK { + n = node + k = i + } + return true + }) + } + } + return true + }) + if k > 0 { + n.Args = append(append([]ast.Expr{}, n.Args[:k]...), n.Args[k+1:]...) + } + if pkNum == 1 { + var imI int = -1 + var gp *ast.GenDecl + ast.Inspect(astFile, func(node ast.Node) bool { + if gen, ok := node.(*ast.GenDecl); ok { + for i := range gen.Specs { + if imspec, ok := gen.Specs[i].(*ast.ImportSpec); ok { + if imspec.Path.Value == "\"miniapp/model/"+pk+"\"" { + gp = gen + imI = i + return false + } + } + } + } + return true + }) + + if imI > -1 { + gp.Specs = append(append([]ast.Spec{}, gp.Specs[:imI]...), gp.Specs[imI+1:]...) + } + } + + var out []byte + bf := bytes.NewBuffer(out) + printer.Fprint(bf, fileSet, astFile) + os.Remove(path) + os.WriteFile(path, bf.Bytes(), 0666) + +} + +func RollRouterBack(pk, model string) { + + // 首先抓到所有的代码块结构 {} + // 分析结构中是否存在一个变量叫做 pk+Router + // 然后获取到代码块指针 对内部需要回滚的代码进行剔除 + path := filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, "initialize", "router.go") + src, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + } + fileSet := token.NewFileSet() + astFile, err := parser.ParseFile(fileSet, "", src, 0) + if err != nil { + fmt.Println(err) + } + + var block *ast.BlockStmt + ast.Inspect(astFile, func(node ast.Node) bool { + if n, ok := node.(*ast.BlockStmt); ok { + ast.Inspect(n, func(bNode ast.Node) bool { + if in, ok := bNode.(*ast.Ident); ok { + if in.Name == pk+"Router" { + block = n + return false + } + } + return true + }) + return true + } + return true + }) + var k int + for i := range block.List { + if stmtNode, ok := block.List[i].(*ast.ExprStmt); ok { + ast.Inspect(stmtNode, func(node ast.Node) bool { + if n, ok := node.(*ast.Ident); ok { + if n.Name == "Init"+model+"Router" { + k = i + return false + } + } + return true + }) + } + } + + block.List = append(append([]ast.Stmt{}, block.List[:k]...), block.List[k+1:]...) + + if len(block.List) == 1 { + // 说明这个块就没任何意义了 + block.List = nil + // TODO 删除空的{} + } + + var out []byte + bf := bytes.NewBuffer(out) + printer.Fprint(bf, fileSet, astFile) + os.Remove(path) + os.WriteFile(path, bf.Bytes(), 0666) +} diff --git a/utils/ast/ast_rollback_test.go b/utils/ast/ast_rollback_test.go new file mode 100644 index 0000000..8ce6f0c --- /dev/null +++ b/utils/ast/ast_rollback_test.go @@ -0,0 +1,11 @@ +package ast + +import "testing" + +func TestRollRouterBack(t *testing.T) { + RollRouterBack("ttt", "Testttt") +} + +func TestRollGormBack(t *testing.T) { + RollGormBack("ttt", "Testttt") +} diff --git a/utils/ast/ast_router.go b/utils/ast/ast_router.go new file mode 100644 index 0000000..64ffee0 --- /dev/null +++ b/utils/ast/ast_router.go @@ -0,0 +1,132 @@ +package ast + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "os" + "strings" +) + +func AppendNodeToList(stmts []ast.Stmt, stmt ast.Stmt, index int) []ast.Stmt { + return append(stmts[:index], append([]ast.Stmt{stmt}, stmts[index:]...)...) +} + +func AddRouterCode(path, funcName, pk, model string) { + src, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + } + fileSet := token.NewFileSet() + astFile, err := parser.ParseFile(fileSet, "", src, parser.ParseComments) + + if err != nil { + fmt.Println(err) + } + + FuncNode := FindFunction(astFile, funcName) + + pkName := strings.ToUpper(pk[:1]) + pk[1:] + routerName := fmt.Sprintf("%sRouter", pk) + modelName := fmt.Sprintf("Init%sRouter", model) + var bloctPre *ast.BlockStmt + for i := len(FuncNode.Body.List) - 1; i >= 0; i-- { + if block, ok := FuncNode.Body.List[i].(*ast.BlockStmt); ok { + bloctPre = block + } + } + ast.Print(fileSet, FuncNode) + if ok, b := needAppendRouter(FuncNode, pk); ok { + routerNode := + &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.AssignStmt{ + Lhs: []ast.Expr{ + &ast.Ident{Name: routerName}, + }, + Tok: token.DEFINE, + Rhs: []ast.Expr{ + &ast.SelectorExpr{ + X: &ast.SelectorExpr{ + X: &ast.Ident{Name: "router"}, + Sel: &ast.Ident{Name: "RouterGroupApp"}, + }, + Sel: &ast.Ident{Name: pkName}, + }, + }, + }, + }, + } + + FuncNode.Body.List = AppendNodeToList(FuncNode.Body.List, routerNode, len(FuncNode.Body.List)-2) + bloctPre = routerNode + } else { + bloctPre = b + } + + if needAppendInit(FuncNode, routerName, modelName) { + bloctPre.List = append(bloctPre.List, + &ast.ExprStmt{ + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.Ident{Name: routerName}, + Sel: &ast.Ident{Name: modelName}, + }, + Args: []ast.Expr{ + &ast.Ident{ + Name: "PrivateGroup", + }, + }, + }, + }) + } + var out []byte + bf := bytes.NewBuffer(out) + printer.Fprint(bf, fileSet, astFile) + os.WriteFile(path, bf.Bytes(), 0666) +} + +func needAppendRouter(funcNode ast.Node, pk string) (bool, *ast.BlockStmt) { + flag := true + var block *ast.BlockStmt + ast.Inspect(funcNode, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.BlockStmt: + for i := range n.List { + if assignNode, ok := n.List[i].(*ast.AssignStmt); ok { + if identNode, ok := assignNode.Lhs[0].(*ast.Ident); ok { + if identNode.Name == fmt.Sprintf("%sRouter", pk) { + flag = false + block = n + return false + } + } + } + } + + } + return true + }) + return flag, block +} + +func needAppendInit(funcNode ast.Node, routerName string, modelName string) bool { + flag := true + ast.Inspect(funcNode, func(node ast.Node) bool { + switch n := funcNode.(type) { + case *ast.CallExpr: + if selectNode, ok := n.Fun.(*ast.SelectorExpr); ok { + x, xok := selectNode.X.(*ast.Ident) + if xok && x.Name == routerName && selectNode.Sel.Name == modelName { + flag = false + return false + } + } + } + return true + }) + return flag +} diff --git a/utils/ast/ast_router_test.go b/utils/ast/ast_router_test.go new file mode 100644 index 0000000..5dc4e14 --- /dev/null +++ b/utils/ast/ast_router_test.go @@ -0,0 +1,9 @@ +package ast + +import ( + "testing" +) + +func TestAddRouterCode(t *testing.T) { + AddRouterCode("D:\\gin-vue-admin\\server.exe.exe\\utils\\ast\\ast_router_test.go", "Routers", "testRouter", "GVAStruct") +} diff --git a/utils/breakpoint_continue.go b/utils/breakpoint_continue.go new file mode 100644 index 0000000..c0baee5 --- /dev/null +++ b/utils/breakpoint_continue.go @@ -0,0 +1,112 @@ +package utils + +import ( + "errors" + "os" + "strconv" + "strings" +) + +// 前端传来文件片与当前片为什么文件的第几片 +// 后端拿到以后比较次分片是否上传 或者是否为不完全片 +// 前端发送每片多大 +// 前端告知是否为最后一片且是否完成 + +const ( + breakpointDir = "./breakpointDir/" + finishDir = "./fileDir/" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: BreakPointContinue +//@description: 断点续传 +//@param: content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string +//@return: error, string + +func BreakPointContinue(content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string) (string, error) { + path := breakpointDir + fileMd5 + "/" + err := os.MkdirAll(path, os.ModePerm) + if err != nil { + return path, err + } + pathC, err := makeFileContent(content, fileName, path, contentNumber) + return pathC, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CheckMd5 +//@description: 检查Md5 +//@param: content []byte, chunkMd5 string +//@return: CanUpload bool + +func CheckMd5(content []byte, chunkMd5 string) (CanUpload bool) { + fileMd5 := MD5V(content) + if fileMd5 == chunkMd5 { + return true // 可以继续上传 + } else { + return false // 切片不完整,废弃 + } +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: makeFileContent +//@description: 创建切片内容 +//@param: content []byte, fileName string, FileDir string, contentNumber int +//@return: string, error + +func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (string, error) { + if strings.Index(fileName, "..") > -1 || strings.Index(FileDir, "..") > -1 { + return "", errors.New("文件名或路径不合法") + } + path := FileDir + fileName + "_" + strconv.Itoa(contentNumber) + f, err := os.Create(path) + if err != nil { + return path, err + } else { + _, err = f.Write(content) + if err != nil { + return path, err + } + } + defer f.Close() + return path, nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: makeFileContent +//@description: 创建切片文件 +//@param: fileName string, FileMd5 string +//@return: error, string + +func MakeFile(fileName string, FileMd5 string) (string, error) { + rd, err := os.ReadDir(breakpointDir + FileMd5) + if err != nil { + return finishDir + fileName, err + } + _ = os.MkdirAll(finishDir, os.ModePerm) + fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o644) + if err != nil { + return finishDir + fileName, err + } + defer fd.Close() + for k := range rd { + content, _ := os.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k)) + _, err = fd.Write(content) + if err != nil { + _ = os.Remove(finishDir + fileName) + return finishDir + fileName, err + } + } + return finishDir + fileName, nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: RemoveChunk +//@description: 移除切片 +//@param: FileMd5 string +//@return: error + +func RemoveChunk(FileMd5 string) error { + err := os.RemoveAll(breakpointDir + FileMd5) + return err +} diff --git a/utils/captcha/redis.go b/utils/captcha/redis.go new file mode 100644 index 0000000..b5a9938 --- /dev/null +++ b/utils/captcha/redis.go @@ -0,0 +1,60 @@ +package captcha + +import ( + "context" + "time" + + "github.com/mojocn/base64Captcha" + "go.uber.org/zap" + "miniapp/global" +) + +func NewDefaultRedisStore() *RedisStore { + return &RedisStore{ + Expiration: time.Second * 180, + PreKey: "CAPTCHA_", + Context: context.TODO(), + } +} + +type RedisStore struct { + Expiration time.Duration + PreKey string + Context context.Context +} + +func (rs *RedisStore) UseWithCtx(ctx context.Context) base64Captcha.Store { + rs.Context = ctx + return rs +} + +func (rs *RedisStore) Set(id string, value string) error { + err := global.GVA_REDIS.Set(rs.Context, rs.PreKey+id, value, rs.Expiration).Err() + if err != nil { + global.GVA_LOG.Error("RedisStoreSetError!", zap.Error(err)) + return err + } + return nil +} + +func (rs *RedisStore) Get(key string, clear bool) string { + val, err := global.GVA_REDIS.Get(rs.Context, key).Result() + if err != nil { + global.GVA_LOG.Error("RedisStoreGetError!", zap.Error(err)) + return "" + } + if clear { + err := global.GVA_REDIS.Del(rs.Context, key).Err() + if err != nil { + global.GVA_LOG.Error("RedisStoreClearError!", zap.Error(err)) + return "" + } + } + return val +} + +func (rs *RedisStore) Verify(id, answer string, clear bool) bool { + key := rs.PreKey + id + v := rs.Get(key, clear) + return v == answer +} diff --git a/utils/clamis.go b/utils/clamis.go new file mode 100644 index 0000000..3527940 --- /dev/null +++ b/utils/clamis.go @@ -0,0 +1,88 @@ +package utils + +import ( + "github.com/gin-gonic/gin" + "github.com/gofrs/uuid/v5" + "miniapp/global" + systemReq "miniapp/model/system/request" +) + +func GetClaims(c *gin.Context) (*systemReq.CustomClaims, error) { + token := c.Request.Header.Get("x-token") + j := NewJWT() + claims, err := j.ParseToken(token) + if err != nil { + global.GVA_LOG.Error("从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构") + } + return claims, err +} + +// GetUserID 从Gin的Context中获取从jwt解析出来的用户ID +func GetUserID(c *gin.Context) uint { + if claims, exists := c.Get("claims"); !exists { + if cl, err := GetClaims(c); err != nil { + return 0 + } else { + return cl.BaseClaims.ID + } + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse.BaseClaims.ID + } +} + +// GetUserUuid 从Gin的Context中获取从jwt解析出来的用户UUID +func GetUserUuid(c *gin.Context) uuid.UUID { + if claims, exists := c.Get("claims"); !exists { + if cl, err := GetClaims(c); err != nil { + return uuid.UUID{} + } else { + return cl.UUID + } + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse.UUID + } +} + +// GetUserAuthorityId 从Gin的Context中获取从jwt解析出来的用户角色id +func GetUserAuthorityId(c *gin.Context) uint { + if claims, exists := c.Get("claims"); !exists { + if cl, err := GetClaims(c); err != nil { + return 0 + } else { + return cl.AuthorityId + } + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse.AuthorityId + } +} + +// GetUserInfo 从Gin的Context中获取从jwt解析出来的用户角色id +func GetUserInfo(c *gin.Context) *systemReq.CustomClaims { + if claims, exists := c.Get("claims"); !exists { + if cl, err := GetClaims(c); err != nil { + return nil + } else { + return cl + } + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse + } +} + +// GetUserName 从Gin的Context中获取从jwt解析出来的用户名 +func GetUserName(c *gin.Context) string { + if claims, exists := c.Get("claims"); !exists { + if cl, err := GetClaims(c); err != nil { + return "" + } else { + return cl.Username + } + } else { + waitUse := claims.(*systemReq.CustomClaims) + return waitUse.Username + } +} diff --git a/utils/db_automation.go b/utils/db_automation.go new file mode 100644 index 0000000..b0babc7 --- /dev/null +++ b/utils/db_automation.go @@ -0,0 +1,29 @@ +package utils + +import ( + "errors" + "fmt" + "time" + + "gorm.io/gorm" +) + +//@author: [songzhibin97](https://github.com/songzhibin97) +//@function: ClearTable +//@description: 清理数据库表数据 +//@param: db(数据库对象) *gorm.DB, tableName(表名) string, compareField(比较字段) string, interval(间隔) string +//@return: error + +func ClearTable(db *gorm.DB, tableName string, compareField string, interval string) error { + if db == nil { + return errors.New("db Cannot be empty") + } + duration, err := time.ParseDuration(interval) + if err != nil { + return err + } + if duration < 0 { + return errors.New("parse duration < 0") + } + return db.Debug().Exec(fmt.Sprintf("DELETE FROM %s WHERE %s < ?", tableName, compareField), time.Now().Add(-duration)).Error +} diff --git a/utils/desensitization.go b/utils/desensitization.go new file mode 100644 index 0000000..819fafb --- /dev/null +++ b/utils/desensitization.go @@ -0,0 +1,16 @@ +package utils + +type desensitization struct{} + +// Desensitization 暴露接口 - 脱敏相关 +func Desensitization() *desensitization { + return &desensitization{} +} + +// Phone 脱敏手机号 +func (desensitization) Phone(phone string) string { + if len(phone) == 11 { + return phone[:3] + "****" + phone[7:] + } + return phone +} diff --git a/utils/directory.go b/utils/directory.go new file mode 100644 index 0000000..507aefd --- /dev/null +++ b/utils/directory.go @@ -0,0 +1,124 @@ +package utils + +import ( + "errors" + "os" + "path/filepath" + "reflect" + "strings" + + "go.uber.org/zap" + "miniapp/global" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: PathExists +//@description: 文件目录是否存在 +//@param: path string +//@return: bool, error + +func PathExists(path string) (bool, error) { + fi, err := os.Stat(path) + if err == nil { + if fi.IsDir() { + return true, nil + } + return false, errors.New("存在同名文件") + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: CreateDir +//@description: 批量创建文件夹 +//@param: dirs ...string +//@return: err error + +func CreateDir(dirs ...string) (err error) { + for _, v := range dirs { + exist, err := PathExists(v) + if err != nil { + return err + } + if !exist { + global.GVA_LOG.Debug("create directory" + v) + if err := os.MkdirAll(v, os.ModePerm); err != nil { + global.GVA_LOG.Error("create directory"+v, zap.Any(" error:", err)) + return err + } + } + } + return err +} + +//@author: [songzhibin97](https://github.com/songzhibin97) +//@function: FileMove +//@description: 文件移动供外部调用 +//@param: src string, dst string(src: 源位置,绝对路径or相对路径, dst: 目标位置,绝对路径or相对路径,必须为文件夹) +//@return: err error + +func FileMove(src string, dst string) (err error) { + if dst == "" { + return nil + } + src, err = filepath.Abs(src) + if err != nil { + return err + } + dst, err = filepath.Abs(dst) + if err != nil { + return err + } + revoke := false + dir := filepath.Dir(dst) +Redirect: + _, err = os.Stat(dir) + if err != nil { + err = os.MkdirAll(dir, 0o755) + if err != nil { + return err + } + if !revoke { + revoke = true + goto Redirect + } + } + return os.Rename(src, dst) +} + +func DeLFile(filePath string) error { + return os.RemoveAll(filePath) +} + +//@author: [songzhibin97](https://github.com/songzhibin97) +//@function: TrimSpace +//@description: 去除结构体空格 +//@param: target interface (target: 目标结构体,传入必须是指针类型) +//@return: null + +func TrimSpace(target interface{}) { + t := reflect.TypeOf(target) + if t.Kind() != reflect.Ptr { + return + } + t = t.Elem() + v := reflect.ValueOf(target).Elem() + for i := 0; i < t.NumField(); i++ { + switch v.Field(i).Kind() { + case reflect.String: + v.Field(i).SetString(strings.TrimSpace(v.Field(i).String())) + } + } +} + +// FileExist 判断文件是否存在 +func FileExist(path string) bool { + fi, err := os.Lstat(path) + if err == nil { + return !fi.IsDir() + } + return !os.IsNotExist(err) +} diff --git a/utils/fmt_plus.go b/utils/fmt_plus.go new file mode 100644 index 0000000..e00f70d --- /dev/null +++ b/utils/fmt_plus.go @@ -0,0 +1,67 @@ +package utils + +import ( + "fmt" + "reflect" + "strings" +) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: StructToMap +//@description: 利用反射将结构体转化为map +//@param: obj interface{} +//@return: map[string]interface{} + +func StructToMap(obj interface{}) map[string]interface{} { + obj1 := reflect.TypeOf(obj) + obj2 := reflect.ValueOf(obj) + + data := make(map[string]interface{}) + for i := 0; i < obj1.NumField(); i++ { + if obj1.Field(i).Tag.Get("mapstructure") != "" { + data[obj1.Field(i).Tag.Get("mapstructure")] = obj2.Field(i).Interface() + } else { + data[obj1.Field(i).Name] = obj2.Field(i).Interface() + } + } + return data +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: ArrayToString +//@description: 将数组格式化为字符串 +//@param: array []interface{} +//@return: string + +func ArrayToString(array []interface{}) string { + return strings.Replace(strings.Trim(fmt.Sprint(array), "[]"), " ", ",", -1) +} + +func Pointer[T any](in T) (out *T) { + return &in +} + +func FirstUpper(s string) string { + if s == "" { + return "" + } + return strings.ToUpper(s[:1]) + s[1:] +} + +func FirstLower(s string) string { + if s == "" { + return "" + } + return strings.ToLower(s[:1]) + s[1:] +} + +// MaheHump 将字符串转换为驼峰命名 +func MaheHump(s string) string { + words := strings.Split(s, "-") + + for i := 1; i < len(words); i++ { + words[i] = strings.Title(words[i]) + } + + return strings.Join(words, "") +} diff --git a/utils/hash.go b/utils/hash.go new file mode 100644 index 0000000..9c3564b --- /dev/null +++ b/utils/hash.go @@ -0,0 +1,31 @@ +package utils + +import ( + "crypto/md5" + "encoding/hex" + "golang.org/x/crypto/bcrypt" +) + +// BcryptHash 使用 bcrypt 对密码进行加密 +func BcryptHash(password string) string { + bytes, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(bytes) +} + +// BcryptCheck 对比明文密码和数据库的哈希值 +func BcryptCheck(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: MD5V +//@description: md5加密 +//@param: str []byte +//@return: string + +func MD5V(str []byte, b ...byte) string { + h := md5.New() + h.Write(str) + return hex.EncodeToString(h.Sum(b)) +} diff --git a/utils/human_duration.go b/utils/human_duration.go new file mode 100644 index 0000000..0cdb055 --- /dev/null +++ b/utils/human_duration.go @@ -0,0 +1,29 @@ +package utils + +import ( + "strconv" + "strings" + "time" +) + +func ParseDuration(d string) (time.Duration, error) { + d = strings.TrimSpace(d) + dr, err := time.ParseDuration(d) + if err == nil { + return dr, nil + } + if strings.Contains(d, "d") { + index := strings.Index(d, "d") + + hour, _ := strconv.Atoi(d[:index]) + dr = time.Hour * 24 * time.Duration(hour) + ndr, err := time.ParseDuration(d[index+1:]) + if err != nil { + return dr, nil + } + return dr + ndr, nil + } + + dv, err := strconv.ParseInt(d, 10, 64) + return time.Duration(dv), err +} diff --git a/utils/human_duration_test.go b/utils/human_duration_test.go new file mode 100644 index 0000000..8a5294b --- /dev/null +++ b/utils/human_duration_test.go @@ -0,0 +1,49 @@ +package utils + +import ( + "testing" + "time" +) + +func TestParseDuration(t *testing.T) { + type args struct { + d string + } + tests := []struct { + name string + args args + want time.Duration + wantErr bool + }{ + { + name: "5h20m", + args: args{"5h20m"}, + want: time.Hour*5 + 20*time.Minute, + wantErr: false, + }, + { + name: "1d5h20m", + args: args{"1d5h20m"}, + want: 24*time.Hour + time.Hour*5 + 20*time.Minute, + wantErr: false, + }, + { + name: "1d", + args: args{"1d"}, + want: 24 * time.Hour, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseDuration(tt.args.d) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDuration() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ParseDuration() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/utils/injection_code.go b/utils/injection_code.go new file mode 100644 index 0000000..45d1eea --- /dev/null +++ b/utils/injection_code.go @@ -0,0 +1,180 @@ +package utils + +import ( + "errors" + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "strings" +) + +//@author: [LeonardWang](https://github.com/WangLeonard) +//@function: AutoInjectionCode +//@description: 向文件中固定注释位置写入代码 +//@param: filepath string, funcName string, codeData string +//@return: error + +const ( + startComment = "Code generated by miniapp Begin; DO NOT EDIT." + endComment = "Code generated by miniapp End; DO NOT EDIT." +) + +//@author: [LeonardWang](https://github.com/WangLeonard) +//@function: AutoInjectionCode +//@description: 向文件中固定注释位置写入代码 +//@param: filepath string, funcName string, codeData string +//@return: error + +func AutoInjectionCode(filepath string, funcName string, codeData string) error { + srcData, err := os.ReadFile(filepath) + if err != nil { + return err + } + srcDataLen := len(srcData) + fset := token.NewFileSet() + fparser, err := parser.ParseFile(fset, filepath, srcData, parser.ParseComments) + if err != nil { + return err + } + codeData = strings.TrimSpace(codeData) + codeStartPos := -1 + codeEndPos := srcDataLen + var expectedFunction *ast.FuncDecl + + startCommentPos := -1 + endCommentPos := srcDataLen + + // 如果指定了函数名,先寻找对应函数 + if funcName != "" { + for _, decl := range fparser.Decls { + if funDecl, ok := decl.(*ast.FuncDecl); ok && funDecl.Name.Name == funcName { + expectedFunction = funDecl + codeStartPos = int(funDecl.Body.Lbrace) + codeEndPos = int(funDecl.Body.Rbrace) + break + } + } + } + + // 遍历所有注释 + for _, comment := range fparser.Comments { + if int(comment.Pos()) > codeStartPos && int(comment.End()) <= codeEndPos { + if startComment != "" && strings.Contains(comment.Text(), startComment) { + startCommentPos = int(comment.Pos()) // Note: Pos is the second '/' + } + if endComment != "" && strings.Contains(comment.Text(), endComment) { + endCommentPos = int(comment.Pos()) // Note: Pos is the second '/' + } + } + } + + if endCommentPos == srcDataLen { + return fmt.Errorf("comment:%s not found", endComment) + } + + // 在指定函数名,且函数中startComment和endComment都存在时,进行区间查重 + if (codeStartPos != -1 && codeEndPos <= srcDataLen) && (startCommentPos != -1 && endCommentPos != srcDataLen) && expectedFunction != nil { + if exist := checkExist(&srcData, startCommentPos, endCommentPos, expectedFunction.Body, codeData); exist { + fmt.Printf("文件 %s 待插入数据 %s 已存在\n", filepath, codeData) + return nil // 这里不需要返回错误? + } + } + + // 两行注释中间没有换行时,会被认为是一条Comment + if startCommentPos == endCommentPos { + endCommentPos = startCommentPos + strings.Index(string(srcData[startCommentPos:]), endComment) + for srcData[endCommentPos] != '/' { + endCommentPos-- + } + } + + // 记录"//"之前的空字符,保持写入后的格式一致 + tmpSpace := make([]byte, 0, 10) + for tmp := endCommentPos - 2; tmp >= 0; tmp-- { + if srcData[tmp] != '\n' { + tmpSpace = append(tmpSpace, srcData[tmp]) + } else { + break + } + } + + reverseSpace := make([]byte, 0, len(tmpSpace)) + for index := len(tmpSpace) - 1; index >= 0; index-- { + reverseSpace = append(reverseSpace, tmpSpace[index]) + } + + // 插入数据 + indexPos := endCommentPos - 1 + insertData := []byte(append([]byte(codeData+"\n"), reverseSpace...)) + + remainData := append([]byte{}, srcData[indexPos:]...) + srcData = append(append(srcData[:indexPos], insertData...), remainData...) + + // 写回数据 + return os.WriteFile(filepath, srcData, 0o600) +} + +func checkExist(srcData *[]byte, startPos int, endPos int, blockStmt *ast.BlockStmt, target string) bool { + for _, list := range blockStmt.List { + switch stmt := list.(type) { + case *ast.ExprStmt: + if callExpr, ok := stmt.X.(*ast.CallExpr); ok && + int(callExpr.Pos()) > startPos && int(callExpr.End()) < endPos { + text := string((*srcData)[int(callExpr.Pos()-1):int(callExpr.End())]) + key := strings.TrimSpace(text) + if key == target { + return true + } + } + case *ast.BlockStmt: + if checkExist(srcData, startPos, endPos, stmt, target) { + return true + } + case *ast.AssignStmt: + // 为 model 中的代码进行检查 + if len(stmt.Rhs) > 0 { + if callExpr, ok := stmt.Rhs[0].(*ast.CallExpr); ok { + for _, arg := range callExpr.Args { + if int(arg.Pos()) > startPos && int(arg.End()) < endPos { + text := string((*srcData)[int(arg.Pos()-1):int(arg.End())]) + key := strings.TrimSpace(text) + if key == target { + return true + } + } + } + } + } + } + } + return false +} + +func AutoClearCode(filepath string, codeData string) error { + srcData, err := os.ReadFile(filepath) + if err != nil { + return err + } + srcData, err = cleanCode(codeData, string(srcData)) + if err != nil { + return err + } + return os.WriteFile(filepath, srcData, 0o600) +} + +func cleanCode(clearCode string, srcData string) ([]byte, error) { + bf := make([]rune, 0, 1024) + for i, v := range srcData { + if v == '\n' { + if strings.TrimSpace(string(bf)) == clearCode { + return append([]byte(srcData[:i-len(bf)]), []byte(srcData[i+1:])...), nil + } + bf = (bf)[:0] + continue + } + bf = append(bf, v) + } + return []byte(srcData), errors.New("未找到内容") +} diff --git a/utils/jwt.go b/utils/jwt.go new file mode 100644 index 0000000..d75180e --- /dev/null +++ b/utils/jwt.go @@ -0,0 +1,88 @@ +package utils + +import ( + "errors" + "time" + + jwt "github.com/golang-jwt/jwt/v4" + + "miniapp/global" + "miniapp/model/system/request" +) + +type JWT struct { + SigningKey []byte +} + +var ( + TokenExpired = errors.New("Token is expired") + TokenNotValidYet = errors.New("Token not active yet") + TokenMalformed = errors.New("That's not even a token") + TokenInvalid = errors.New("Couldn't handle this token:") +) + +func NewJWT() *JWT { + return &JWT{ + []byte(global.GVA_CONFIG.JWT.SigningKey), + } +} + +func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims { + bf, _ := ParseDuration(global.GVA_CONFIG.JWT.BufferTime) + ep, _ := ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime) + claims := request.CustomClaims{ + BaseClaims: baseClaims, + BufferTime: int64(bf / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失 + RegisteredClaims: jwt.RegisteredClaims{ + Audience: jwt.ClaimStrings{"GVA"}, // 受众 + NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)), // 签名生效时间 + ExpiresAt: jwt.NewNumericDate(time.Now().Add(ep)), // 过期时间 7天 配置文件 + Issuer: global.GVA_CONFIG.JWT.Issuer, // 签名的发行者 + }, + } + return claims +} + +// 创建一个token +func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(j.SigningKey) +} + +// CreateTokenByOldToken 旧token 换新token 使用归并回源避免并发问题 +func (j *JWT) CreateTokenByOldToken(oldToken string, claims request.CustomClaims) (string, error) { + v, err, _ := global.GVA_Concurrency_Control.Do("JWT:"+oldToken, func() (interface{}, error) { + return j.CreateToken(claims) + }) + return v.(string), err +} + +// 解析 token +func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) { + token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { + return j.SigningKey, nil + }) + if err != nil { + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + return nil, TokenMalformed + } else if ve.Errors&jwt.ValidationErrorExpired != 0 { + // Token is expired + return nil, TokenExpired + } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { + return nil, TokenNotValidYet + } else { + return nil, TokenInvalid + } + } + } + if token != nil { + if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid { + return claims, nil + } + return nil, TokenInvalid + + } else { + return nil, TokenInvalid + } +} diff --git a/utils/plugin/plugin.go b/utils/plugin/plugin.go new file mode 100644 index 0000000..a59d5b5 --- /dev/null +++ b/utils/plugin/plugin.go @@ -0,0 +1,18 @@ +package plugin + +import ( + "github.com/gin-gonic/gin" +) + +const ( + OnlyFuncName = "Plugin" +) + +// Plugin 插件模式接口化 +type Plugin interface { + // Register 注册路由 + Register(group *gin.RouterGroup) + + // RouterPath 用户返回注册路由 + RouterPath() string +} diff --git a/utils/reload.go b/utils/reload.go new file mode 100644 index 0000000..de5499b --- /dev/null +++ b/utils/reload.go @@ -0,0 +1,18 @@ +package utils + +import ( + "errors" + "os" + "os/exec" + "runtime" + "strconv" +) + +func Reload() error { + if runtime.GOOS == "windows" { + return errors.New("系统不支持") + } + pid := os.Getpid() + cmd := exec.Command("kill", "-1", strconv.Itoa(pid)) + return cmd.Run() +} diff --git a/utils/server.go b/utils/server.go new file mode 100644 index 0000000..a170b51 --- /dev/null +++ b/utils/server.go @@ -0,0 +1,118 @@ +package utils + +import ( + "runtime" + "time" + + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/mem" +) + +const ( + B = 1 + KB = 1024 * B + MB = 1024 * KB + GB = 1024 * MB +) + +type Server struct { + Os Os `json:"os"` + Cpu Cpu `json:"cpu"` + Ram Ram `json:"ram"` + Disk Disk `json:"disk"` +} + +type Os struct { + GOOS string `json:"goos"` + NumCPU int `json:"numCpu"` + Compiler string `json:"compiler"` + GoVersion string `json:"goVersion"` + NumGoroutine int `json:"numGoroutine"` +} + +type Cpu struct { + Cpus []float64 `json:"cpus"` + Cores int `json:"cores"` +} + +type Ram struct { + UsedMB int `json:"usedMb"` + TotalMB int `json:"totalMb"` + UsedPercent int `json:"usedPercent"` +} + +type Disk struct { + UsedMB int `json:"usedMb"` + UsedGB int `json:"usedGb"` + TotalMB int `json:"totalMb"` + TotalGB int `json:"totalGb"` + UsedPercent int `json:"usedPercent"` +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: InitCPU +//@description: OS信息 +//@return: o Os, err error + +func InitOS() (o Os) { + o.GOOS = runtime.GOOS + o.NumCPU = runtime.NumCPU() + o.Compiler = runtime.Compiler + o.GoVersion = runtime.Version() + o.NumGoroutine = runtime.NumGoroutine() + return o +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: InitCPU +//@description: CPU信息 +//@return: c Cpu, err error + +func InitCPU() (c Cpu, err error) { + if cores, err := cpu.Counts(false); err != nil { + return c, err + } else { + c.Cores = cores + } + if cpus, err := cpu.Percent(time.Duration(200)*time.Millisecond, true); err != nil { + return c, err + } else { + c.Cpus = cpus + } + return c, nil +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: InitRAM +//@description: RAM信息 +//@return: r Ram, err error + +func InitRAM() (r Ram, err error) { + if u, err := mem.VirtualMemory(); err != nil { + return r, err + } else { + r.UsedMB = int(u.Used) / MB + r.TotalMB = int(u.Total) / MB + r.UsedPercent = int(u.UsedPercent) + } + return r, nil +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@function: InitDisk +//@description: 硬盘信息 +//@return: d Disk, err error + +func InitDisk() (d Disk, err error) { + if u, err := disk.Usage("/"); err != nil { + return d, err + } else { + d.UsedMB = int(u.Used) / MB + d.UsedGB = int(u.Used) / GB + d.TotalMB = int(u.Total) / MB + d.TotalGB = int(u.Total) / GB + d.UsedPercent = int(u.UsedPercent) + } + return d, nil +} diff --git a/utils/timer/timed_task.go b/utils/timer/timed_task.go new file mode 100644 index 0000000..c5c1e4c --- /dev/null +++ b/utils/timer/timed_task.go @@ -0,0 +1,132 @@ +package timer + +import ( + "sync" + + "github.com/robfig/cron/v3" +) + +type Timer interface { + AddTaskByFunc(taskName string, spec string, task func(), option ...cron.Option) (cron.EntryID, error) + AddTaskByJob(taskName string, spec string, job interface{ Run() }, option ...cron.Option) (cron.EntryID, error) + FindCron(taskName string) (*cron.Cron, bool) + StartTask(taskName string) + StopTask(taskName string) + Remove(taskName string, id int) + Clear(taskName string) + Close() +} + +// timer 定时任务管理 +type timer struct { + taskList map[string]*cron.Cron + sync.Mutex +} + +// AddTaskByFunc 通过函数的方法添加任务 +func (t *timer) AddTaskByFunc(taskName string, spec string, task func(), option ...cron.Option) (cron.EntryID, error) { + t.Lock() + defer t.Unlock() + if _, ok := t.taskList[taskName]; !ok { + t.taskList[taskName] = cron.New(option...) + } + id, err := t.taskList[taskName].AddFunc(spec, task) + t.taskList[taskName].Start() + return id, err +} + +// AddTaskByFuncWithSeconds 通过函数的方法使用WithSeconds添加任务 +func (t *timer) AddTaskByFuncWhithSecond(taskName string, spec string, task func(), option ...cron.Option) (cron.EntryID, error) { + t.Lock() + defer t.Unlock() + option = append(option, cron.WithSeconds()) + if _, ok := t.taskList[taskName]; !ok { + t.taskList[taskName] = cron.New(option...) + } + id, err := t.taskList[taskName].AddFunc(spec, task) + t.taskList[taskName].Start() + return id, err +} + +// AddTaskByJob 通过接口的方法添加任务 +func (t *timer) AddTaskByJob(taskName string, spec string, job interface{ Run() }, option ...cron.Option) (cron.EntryID, error) { + t.Lock() + defer t.Unlock() + if _, ok := t.taskList[taskName]; !ok { + t.taskList[taskName] = cron.New(option...) + } + id, err := t.taskList[taskName].AddJob(spec, job) + t.taskList[taskName].Start() + return id, err +} + +// AddTaskByJobWithSeconds 通过接口的方法添加任务 +func (t *timer) AddTaskByJobWithSeconds(taskName string, spec string, job interface{ Run() }, option ...cron.Option) (cron.EntryID, error) { + t.Lock() + defer t.Unlock() + option = append(option, cron.WithSeconds()) + if _, ok := t.taskList[taskName]; !ok { + t.taskList[taskName] = cron.New(option...) + } + id, err := t.taskList[taskName].AddJob(spec, job) + t.taskList[taskName].Start() + return id, err +} + +// FindCron 获取对应taskName的cron 可能会为空 +func (t *timer) FindCron(taskName string) (*cron.Cron, bool) { + t.Lock() + defer t.Unlock() + v, ok := t.taskList[taskName] + return v, ok +} + +// StartTask 开始任务 +func (t *timer) StartTask(taskName string) { + t.Lock() + defer t.Unlock() + if v, ok := t.taskList[taskName]; ok { + v.Start() + } +} + +// StopTask 停止任务 +func (t *timer) StopTask(taskName string) { + t.Lock() + defer t.Unlock() + if v, ok := t.taskList[taskName]; ok { + v.Stop() + } +} + +// Remove 从taskName 删除指定任务 +func (t *timer) Remove(taskName string, id int) { + t.Lock() + defer t.Unlock() + if v, ok := t.taskList[taskName]; ok { + v.Remove(cron.EntryID(id)) + } +} + +// Clear 清除任务 +func (t *timer) Clear(taskName string) { + t.Lock() + defer t.Unlock() + if v, ok := t.taskList[taskName]; ok { + v.Stop() + delete(t.taskList, taskName) + } +} + +// Close 释放资源 +func (t *timer) Close() { + t.Lock() + defer t.Unlock() + for _, v := range t.taskList { + v.Stop() + } +} + +func NewTimerTask() Timer { + return &timer{taskList: make(map[string]*cron.Cron)} +} diff --git a/utils/timer/timed_task_test.go b/utils/timer/timed_task_test.go new file mode 100644 index 0000000..aa9ddec --- /dev/null +++ b/utils/timer/timed_task_test.go @@ -0,0 +1,67 @@ +package timer + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +var job = mockJob{} + +type mockJob struct{} + +func (job mockJob) Run() { + mockFunc() +} + +func mockFunc() { + time.Sleep(time.Second) + fmt.Println("1s...") +} + +func TestNewTimerTask(t *testing.T) { + tm := NewTimerTask() + _tm := tm.(*timer) + + { + _, err := tm.AddTaskByFunc("func", "@every 1s", mockFunc) + assert.Nil(t, err) + _, ok := _tm.taskList["func"] + if !ok { + t.Error("no find func") + } + } + + { + _, err := tm.AddTaskByJob("job", "@every 1s", job) + assert.Nil(t, err) + _, ok := _tm.taskList["job"] + if !ok { + t.Error("no find job") + } + } + + { + _, ok := tm.FindCron("func") + if !ok { + t.Error("no find func") + } + _, ok = tm.FindCron("job") + if !ok { + t.Error("no find job") + } + _, ok = tm.FindCron("none") + if ok { + t.Error("find none") + } + } + { + tm.Clear("func") + _, ok := tm.FindCron("func") + if ok { + t.Error("find func") + } + } +} diff --git a/utils/upload/aliyun_oss.go b/utils/upload/aliyun_oss.go new file mode 100644 index 0000000..b6d3f60 --- /dev/null +++ b/utils/upload/aliyun_oss.go @@ -0,0 +1,75 @@ +package upload + +import ( + "errors" + "mime/multipart" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + "go.uber.org/zap" + "miniapp/global" +) + +type AliyunOSS struct{} + +func (*AliyunOSS) UploadFile(file *multipart.FileHeader) (string, string, error) { + bucket, err := NewBucket() + if err != nil { + global.GVA_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error())) + return "", "", errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error()) + } + + // 读取本地文件。 + f, openError := file.Open() + if openError != nil { + global.GVA_LOG.Error("function file.Open() Failed", zap.Any("err", openError.Error())) + return "", "", errors.New("function file.Open() Failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + // 上传阿里云路径 文件名格式 自己可以改 建议保证唯一性 + // yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename + yunFileTmpPath := global.GVA_CONFIG.AliyunOSS.BasePath + "/" + "uploads" + "/" + time.Now().Format("2006-01-02") + "/" + file.Filename + + // 上传文件流。 + err = bucket.PutObject(yunFileTmpPath, f) + if err != nil { + global.GVA_LOG.Error("function formUploader.Put() Failed", zap.Any("err", err.Error())) + return "", "", errors.New("function formUploader.Put() Failed, err:" + err.Error()) + } + + return global.GVA_CONFIG.AliyunOSS.BucketUrl + "/" + yunFileTmpPath, yunFileTmpPath, nil +} + +func (*AliyunOSS) DeleteFile(key string) error { + bucket, err := NewBucket() + if err != nil { + global.GVA_LOG.Error("function AliyunOSS.NewBucket() Failed", zap.Any("err", err.Error())) + return errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error()) + } + + // 删除单个文件。objectName表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 + // 如需删除文件夹,请将objectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。 + err = bucket.DeleteObject(key) + if err != nil { + global.GVA_LOG.Error("function bucketManager.Delete() failed", zap.Any("err", err.Error())) + return errors.New("function bucketManager.Delete() failed, err:" + err.Error()) + } + + return nil +} + +func NewBucket() (*oss.Bucket, error) { + // 创建OSSClient实例。 + client, err := oss.New(global.GVA_CONFIG.AliyunOSS.Endpoint, global.GVA_CONFIG.AliyunOSS.AccessKeyId, global.GVA_CONFIG.AliyunOSS.AccessKeySecret) + if err != nil { + return nil, err + } + + // 获取存储空间。 + bucket, err := client.Bucket(global.GVA_CONFIG.AliyunOSS.BucketName) + if err != nil { + return nil, err + } + + return bucket, nil +} diff --git a/utils/upload/aws_s3.go b/utils/upload/aws_s3.go new file mode 100644 index 0000000..3e5c89f --- /dev/null +++ b/utils/upload/aws_s3.go @@ -0,0 +1,97 @@ +package upload + +import ( + "errors" + "fmt" + "mime/multipart" + "time" + + "miniapp/global" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/s3/s3manager" + "go.uber.org/zap" +) + +type AwsS3 struct{} + +//@author: [WqyJh](https://github.com/WqyJh) +//@object: *AwsS3 +//@function: UploadFile +//@description: Upload file to Aws S3 using aws-sdk-go. See https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/s3-example-basic-bucket-operations.html#s3-examples-bucket-ops-upload-file-to-bucket +//@param: file *multipart.FileHeader +//@return: string, string, error + +func (*AwsS3) UploadFile(file *multipart.FileHeader) (string, string, error) { + session := newSession() + uploader := s3manager.NewUploader(session) + + fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) + filename := global.GVA_CONFIG.AwsS3.PathPrefix + "/" + fileKey + f, openError := file.Open() + if openError != nil { + global.GVA_LOG.Error("function file.Open() failed", zap.Any("err", openError.Error())) + return "", "", errors.New("function file.Open() failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + + _, err := uploader.Upload(&s3manager.UploadInput{ + Bucket: aws.String(global.GVA_CONFIG.AwsS3.Bucket), + Key: aws.String(filename), + Body: f, + }) + if err != nil { + global.GVA_LOG.Error("function uploader.Upload() failed", zap.Any("err", err.Error())) + return "", "", err + } + + return global.GVA_CONFIG.AwsS3.BaseURL + "/" + filename, fileKey, nil +} + +//@author: [WqyJh](https://github.com/WqyJh) +//@object: *AwsS3 +//@function: DeleteFile +//@description: Delete file from Aws S3 using aws-sdk-go. See https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/s3-example-basic-bucket-operations.html#s3-examples-bucket-ops-delete-bucket-item +//@param: file *multipart.FileHeader +//@return: string, string, error + +func (*AwsS3) DeleteFile(key string) error { + session := newSession() + svc := s3.New(session) + filename := global.GVA_CONFIG.AwsS3.PathPrefix + "/" + key + bucket := global.GVA_CONFIG.AwsS3.Bucket + + _, err := svc.DeleteObject(&s3.DeleteObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(filename), + }) + if err != nil { + global.GVA_LOG.Error("function svc.DeleteObject() failed", zap.Any("err", err.Error())) + return errors.New("function svc.DeleteObject() failed, err:" + err.Error()) + } + + _ = svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(filename), + }) + return nil +} + +// newSession Create S3 session +func newSession() *session.Session { + sess, _ := session.NewSession(&aws.Config{ + Region: aws.String(global.GVA_CONFIG.AwsS3.Region), + Endpoint: aws.String(global.GVA_CONFIG.AwsS3.Endpoint), //minio在这里设置地址,可以兼容 + S3ForcePathStyle: aws.Bool(global.GVA_CONFIG.AwsS3.S3ForcePathStyle), + DisableSSL: aws.Bool(global.GVA_CONFIG.AwsS3.DisableSSL), + Credentials: credentials.NewStaticCredentials( + global.GVA_CONFIG.AwsS3.SecretID, + global.GVA_CONFIG.AwsS3.SecretKey, + "", + ), + }) + return sess +} diff --git a/utils/upload/local.go b/utils/upload/local.go new file mode 100644 index 0000000..270d63b --- /dev/null +++ b/utils/upload/local.go @@ -0,0 +1,86 @@ +package upload + +import ( + "errors" + "io" + "mime/multipart" + "os" + "path" + "strings" + "time" + + "go.uber.org/zap" + "miniapp/global" + "miniapp/utils" +) + +type Local struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [ccfish86](https://github.com/ccfish86) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@object: *Local +//@function: UploadFile +//@description: 上传文件 +//@param: file *multipart.FileHeader +//@return: string, string, error + +func (*Local) UploadFile(file *multipart.FileHeader) (string, string, error) { + // 读取文件后缀 + ext := path.Ext(file.Filename) + // 读取文件名并加密 + name := strings.TrimSuffix(file.Filename, ext) + name = utils.MD5V([]byte(name)) + // 拼接新文件名 + filename := name + "_" + time.Now().Format("20060102150405") + ext + // 尝试创建此路径 + mkdirErr := os.MkdirAll(global.GVA_CONFIG.Local.StorePath, os.ModePerm) + if mkdirErr != nil { + global.GVA_LOG.Error("function os.MkdirAll() failed", zap.Any("err", mkdirErr.Error())) + return "", "", errors.New("function os.MkdirAll() failed, err:" + mkdirErr.Error()) + } + // 拼接路径和文件名 + p := global.GVA_CONFIG.Local.StorePath + "/" + filename + filepath := global.GVA_CONFIG.Local.Path + "/" + filename + + f, openError := file.Open() // 读取文件 + if openError != nil { + global.GVA_LOG.Error("function file.Open() failed", zap.Any("err", openError.Error())) + return "", "", errors.New("function file.Open() failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + + out, createErr := os.Create(p) + if createErr != nil { + global.GVA_LOG.Error("function os.Create() failed", zap.Any("err", createErr.Error())) + + return "", "", errors.New("function os.Create() failed, err:" + createErr.Error()) + } + defer out.Close() // 创建文件 defer 关闭 + + _, copyErr := io.Copy(out, f) // 传输(拷贝)文件 + if copyErr != nil { + global.GVA_LOG.Error("function io.Copy() failed", zap.Any("err", copyErr.Error())) + return "", "", errors.New("function io.Copy() failed, err:" + copyErr.Error()) + } + return filepath, filename, nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [ccfish86](https://github.com/ccfish86) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@object: *Local +//@function: DeleteFile +//@description: 删除文件 +//@param: key string +//@return: error + +func (*Local) DeleteFile(key string) error { + p := global.GVA_CONFIG.Local.StorePath + "/" + key + if strings.Contains(p, global.GVA_CONFIG.Local.StorePath) { + if err := os.Remove(p); err != nil { + return errors.New("本地文件删除失败, err:" + err.Error()) + } + } + return nil +} diff --git a/utils/upload/obs.go b/utils/upload/obs.go new file mode 100644 index 0000000..5c0c0b2 --- /dev/null +++ b/utils/upload/obs.go @@ -0,0 +1,67 @@ +package upload + +import ( + "mime/multipart" + + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + "github.com/pkg/errors" + "miniapp/global" +) + +var HuaWeiObs = new(Obs) + +type Obs struct{} + +func NewHuaWeiObsClient() (client *obs.ObsClient, err error) { + return obs.New(global.GVA_CONFIG.HuaWeiObs.AccessKey, global.GVA_CONFIG.HuaWeiObs.SecretKey, global.GVA_CONFIG.HuaWeiObs.Endpoint) +} + +func (o *Obs) UploadFile(file *multipart.FileHeader) (string, string, error) { + // var open multipart.File + open, err := file.Open() + if err != nil { + return "", "", err + } + defer open.Close() + filename := file.Filename + input := &obs.PutObjectInput{ + PutObjectBasicInput: obs.PutObjectBasicInput{ + ObjectOperationInput: obs.ObjectOperationInput{ + Bucket: global.GVA_CONFIG.HuaWeiObs.Bucket, + Key: filename, + }, + ContentType: file.Header.Get("content-type"), + }, + Body: open, + } + + var client *obs.ObsClient + client, err = NewHuaWeiObsClient() + if err != nil { + return "", "", errors.Wrap(err, "获取华为对象存储对象失败!") + } + + _, err = client.PutObject(input) + if err != nil { + return "", "", errors.Wrap(err, "文件上传失败!") + } + filepath := global.GVA_CONFIG.HuaWeiObs.Path + "/" + filename + return filepath, filename, err +} + +func (o *Obs) DeleteFile(key string) error { + client, err := NewHuaWeiObsClient() + if err != nil { + return errors.Wrap(err, "获取华为对象存储对象失败!") + } + input := &obs.DeleteObjectInput{ + Bucket: global.GVA_CONFIG.HuaWeiObs.Bucket, + Key: key, + } + var output *obs.DeleteObjectOutput + output, err = client.DeleteObject(input) + if err != nil { + return errors.Wrapf(err, "删除对象(%s)失败!, output: %v", key, output) + } + return nil +} diff --git a/utils/upload/qiniu.go b/utils/upload/qiniu.go new file mode 100644 index 0000000..a5674eb --- /dev/null +++ b/utils/upload/qiniu.go @@ -0,0 +1,96 @@ +package upload + +import ( + "context" + "errors" + "fmt" + "mime/multipart" + "time" + + "github.com/qiniu/api.v7/v7/auth/qbox" + "github.com/qiniu/api.v7/v7/storage" + "go.uber.org/zap" + "miniapp/global" +) + +type Qiniu struct{} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [ccfish86](https://github.com/ccfish86) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@object: *Qiniu +//@function: UploadFile +//@description: 上传文件 +//@param: file *multipart.FileHeader +//@return: string, string, error + +func (*Qiniu) UploadFile(file *multipart.FileHeader) (string, string, error) { + putPolicy := storage.PutPolicy{Scope: global.GVA_CONFIG.Qiniu.Bucket} + mac := qbox.NewMac(global.GVA_CONFIG.Qiniu.AccessKey, global.GVA_CONFIG.Qiniu.SecretKey) + upToken := putPolicy.UploadToken(mac) + cfg := qiniuConfig() + formUploader := storage.NewFormUploader(cfg) + ret := storage.PutRet{} + putExtra := storage.PutExtra{Params: map[string]string{"x:name": "github logo"}} + + f, openError := file.Open() + if openError != nil { + global.GVA_LOG.Error("function file.Open() failed", zap.Any("err", openError.Error())) + + return "", "", errors.New("function file.Open() failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) // 文件名格式 自己可以改 建议保证唯一性 + putErr := formUploader.Put(context.Background(), &ret, upToken, fileKey, f, file.Size, &putExtra) + if putErr != nil { + global.GVA_LOG.Error("function formUploader.Put() failed", zap.Any("err", putErr.Error())) + return "", "", errors.New("function formUploader.Put() failed, err:" + putErr.Error()) + } + return global.GVA_CONFIG.Qiniu.ImgPath + "/" + ret.Key, ret.Key, nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@author: [ccfish86](https://github.com/ccfish86) +//@author: [SliverHorn](https://github.com/SliverHorn) +//@object: *Qiniu +//@function: DeleteFile +//@description: 删除文件 +//@param: key string +//@return: error + +func (*Qiniu) DeleteFile(key string) error { + mac := qbox.NewMac(global.GVA_CONFIG.Qiniu.AccessKey, global.GVA_CONFIG.Qiniu.SecretKey) + cfg := qiniuConfig() + bucketManager := storage.NewBucketManager(mac, cfg) + if err := bucketManager.Delete(global.GVA_CONFIG.Qiniu.Bucket, key); err != nil { + global.GVA_LOG.Error("function bucketManager.Delete() failed", zap.Any("err", err.Error())) + return errors.New("function bucketManager.Delete() failed, err:" + err.Error()) + } + return nil +} + +//@author: [SliverHorn](https://github.com/SliverHorn) +//@object: *Qiniu +//@function: qiniuConfig +//@description: 根据配置文件进行返回七牛云的配置 +//@return: *storage.Config + +func qiniuConfig() *storage.Config { + cfg := storage.Config{ + UseHTTPS: global.GVA_CONFIG.Qiniu.UseHTTPS, + UseCdnDomains: global.GVA_CONFIG.Qiniu.UseCdnDomains, + } + switch global.GVA_CONFIG.Qiniu.Zone { // 根据配置文件进行初始化空间对应的机房 + case "ZoneHuadong": + cfg.Zone = &storage.ZoneHuadong + case "ZoneHuabei": + cfg.Zone = &storage.ZoneHuabei + case "ZoneHuanan": + cfg.Zone = &storage.ZoneHuanan + case "ZoneBeimei": + cfg.Zone = &storage.ZoneBeimei + case "ZoneXinjiapo": + cfg.Zone = &storage.ZoneXinjiapo + } + return &cfg +} diff --git a/utils/upload/tencent_cos.go b/utils/upload/tencent_cos.go new file mode 100644 index 0000000..5ff1ccd --- /dev/null +++ b/utils/upload/tencent_cos.go @@ -0,0 +1,61 @@ +package upload + +import ( + "context" + "errors" + "fmt" + "mime/multipart" + "net/http" + "net/url" + "time" + + "miniapp/global" + + "github.com/tencentyun/cos-go-sdk-v5" + "go.uber.org/zap" +) + +type TencentCOS struct{} + +// UploadFile upload file to COS +func (*TencentCOS) UploadFile(file *multipart.FileHeader) (string, string, error) { + client := NewClient() + f, openError := file.Open() + if openError != nil { + global.GVA_LOG.Error("function file.Open() failed", zap.Any("err", openError.Error())) + return "", "", errors.New("function file.Open() failed, err:" + openError.Error()) + } + defer f.Close() // 创建文件 defer 关闭 + fileKey := fmt.Sprintf("%d%s", time.Now().Unix(), file.Filename) + + _, err := client.Object.Put(context.Background(), global.GVA_CONFIG.TencentCOS.PathPrefix+"/"+fileKey, f, nil) + if err != nil { + panic(err) + } + return global.GVA_CONFIG.TencentCOS.BaseURL + "/" + global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + fileKey, fileKey, nil +} + +// DeleteFile delete file form COS +func (*TencentCOS) DeleteFile(key string) error { + client := NewClient() + name := global.GVA_CONFIG.TencentCOS.PathPrefix + "/" + key + _, err := client.Object.Delete(context.Background(), name) + if err != nil { + global.GVA_LOG.Error("function bucketManager.Delete() failed", zap.Any("err", err.Error())) + return errors.New("function bucketManager.Delete() failed, err:" + err.Error()) + } + return nil +} + +// NewClient init COS client +func NewClient() *cos.Client { + urlStr, _ := url.Parse("https://" + global.GVA_CONFIG.TencentCOS.Bucket + ".cos." + global.GVA_CONFIG.TencentCOS.Region + ".myqcloud.com") + baseURL := &cos.BaseURL{BucketURL: urlStr} + client := cos.NewClient(baseURL, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: global.GVA_CONFIG.TencentCOS.SecretID, + SecretKey: global.GVA_CONFIG.TencentCOS.SecretKey, + }, + }) + return client +} diff --git a/utils/upload/upload.go b/utils/upload/upload.go new file mode 100644 index 0000000..e3176eb --- /dev/null +++ b/utils/upload/upload.go @@ -0,0 +1,37 @@ +package upload + +import ( + "mime/multipart" + + "miniapp/global" +) + +// OSS 对象存储接口 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [ccfish86](https://github.com/ccfish86) +type OSS interface { + UploadFile(file *multipart.FileHeader) (string, string, error) + DeleteFile(key string) error +} + +// NewOss OSS的实例化方法 +// Author [SliverHorn](https://github.com/SliverHorn) +// Author [ccfish86](https://github.com/ccfish86) +func NewOss() OSS { + switch global.GVA_CONFIG.System.OssType { + case "local": + return &Local{} + case "qiniu": + return &Qiniu{} + case "tencent-cos": + return &TencentCOS{} + case "aliyun-oss": + return &AliyunOSS{} + case "huawei-obs": + return HuaWeiObs + case "aws-s3": + return &AwsS3{} + default: + return &Local{} + } +} diff --git a/utils/validator.go b/utils/validator.go new file mode 100644 index 0000000..a56dac0 --- /dev/null +++ b/utils/validator.go @@ -0,0 +1,294 @@ +package utils + +import ( + "errors" + "reflect" + "regexp" + "strconv" + "strings" +) + +type Rules map[string][]string + +type RulesMap map[string]Rules + +var CustomizeMap = make(map[string]Rules) + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: RegisterRule +//@description: 注册自定义规则方案建议在路由初始化层即注册 +//@param: key string, rule Rules +//@return: err error + +func RegisterRule(key string, rule Rules) (err error) { + if CustomizeMap[key] != nil { + return errors.New(key + "已注册,无法重复注册") + } else { + CustomizeMap[key] = rule + return nil + } +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: NotEmpty +//@description: 非空 不能为其对应类型的0值 +//@return: string + +func NotEmpty() string { + return "notEmpty" +} + +// @author: [zooqkl](https://github.com/zooqkl) +// @function: RegexpMatch +// @description: 正则校验 校验输入项是否满足正则表达式 +// @param: rule string +// @return: string + +func RegexpMatch(rule string) string { + return "regexp=" + rule +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Lt +//@description: 小于入参(<) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Lt(mark string) string { + return "lt=" + mark +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Le +//@description: 小于等于入参(<=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Le(mark string) string { + return "le=" + mark +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Eq +//@description: 等于入参(==) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Eq(mark string) string { + return "eq=" + mark +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Ne +//@description: 不等于入参(!=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Ne(mark string) string { + return "ne=" + mark +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Ge +//@description: 大于等于入参(>=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Ge(mark string) string { + return "ge=" + mark +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Gt +//@description: 大于入参(>) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较 +//@param: mark string +//@return: string + +func Gt(mark string) string { + return "gt=" + mark +} + +// +//@author: [piexlmax](https://github.com/piexlmax) +//@function: Verify +//@description: 校验方法 +//@param: st interface{}, roleMap Rules(入参实例,规则map) +//@return: err error + +func Verify(st interface{}, roleMap Rules) (err error) { + compareMap := map[string]bool{ + "lt": true, + "le": true, + "eq": true, + "ne": true, + "ge": true, + "gt": true, + } + + typ := reflect.TypeOf(st) + val := reflect.ValueOf(st) // 获取reflect.Type类型 + + kd := val.Kind() // 获取到st对应的类别 + if kd != reflect.Struct { + return errors.New("expect struct") + } + num := val.NumField() + // 遍历结构体的所有字段 + for i := 0; i < num; i++ { + tagVal := typ.Field(i) + val := val.Field(i) + if tagVal.Type.Kind() == reflect.Struct { + if err = Verify(val.Interface(), roleMap); err != nil { + return err + } + } + if len(roleMap[tagVal.Name]) > 0 { + for _, v := range roleMap[tagVal.Name] { + switch { + case v == "notEmpty": + if isBlank(val) { + return errors.New(tagVal.Name + "值不能为空") + } + case strings.Split(v, "=")[0] == "regexp": + if !regexpMatch(strings.Split(v, "=")[1], val.String()) { + return errors.New(tagVal.Name + "格式校验不通过") + } + case compareMap[strings.Split(v, "=")[0]]: + if !compareVerify(val, v) { + return errors.New(tagVal.Name + "长度或值不在合法范围," + v) + } + } + } + } + } + return nil +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: compareVerify +//@description: 长度和数字的校验方法 根据类型自动校验 +//@param: value reflect.Value, VerifyStr string +//@return: bool + +func compareVerify(value reflect.Value, VerifyStr string) bool { + switch value.Kind() { + case reflect.String: + return compare(len([]rune(value.String())), VerifyStr) + case reflect.Slice, reflect.Array: + return compare(value.Len(), VerifyStr) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return compare(value.Uint(), VerifyStr) + case reflect.Float32, reflect.Float64: + return compare(value.Float(), VerifyStr) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return compare(value.Int(), VerifyStr) + default: + return false + } +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: isBlank +//@description: 非空校验 +//@param: value reflect.Value +//@return: bool + +func isBlank(value reflect.Value) bool { + switch value.Kind() { + case reflect.String, reflect.Slice: + return value.Len() == 0 + case reflect.Bool: + return !value.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return value.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return value.Uint() == 0 + case reflect.Float32, reflect.Float64: + return value.Float() == 0 + case reflect.Interface, reflect.Ptr: + return value.IsNil() + } + return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface()) +} + +//@author: [piexlmax](https://github.com/piexlmax) +//@function: compare +//@description: 比较函数 +//@param: value interface{}, VerifyStr string +//@return: bool + +func compare(value interface{}, VerifyStr string) bool { + VerifyStrArr := strings.Split(VerifyStr, "=") + val := reflect.ValueOf(value) + switch val.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + VInt, VErr := strconv.ParseInt(VerifyStrArr[1], 10, 64) + if VErr != nil { + return false + } + switch { + case VerifyStrArr[0] == "lt": + return val.Int() < VInt + case VerifyStrArr[0] == "le": + return val.Int() <= VInt + case VerifyStrArr[0] == "eq": + return val.Int() == VInt + case VerifyStrArr[0] == "ne": + return val.Int() != VInt + case VerifyStrArr[0] == "ge": + return val.Int() >= VInt + case VerifyStrArr[0] == "gt": + return val.Int() > VInt + default: + return false + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + VInt, VErr := strconv.Atoi(VerifyStrArr[1]) + if VErr != nil { + return false + } + switch { + case VerifyStrArr[0] == "lt": + return val.Uint() < uint64(VInt) + case VerifyStrArr[0] == "le": + return val.Uint() <= uint64(VInt) + case VerifyStrArr[0] == "eq": + return val.Uint() == uint64(VInt) + case VerifyStrArr[0] == "ne": + return val.Uint() != uint64(VInt) + case VerifyStrArr[0] == "ge": + return val.Uint() >= uint64(VInt) + case VerifyStrArr[0] == "gt": + return val.Uint() > uint64(VInt) + default: + return false + } + case reflect.Float32, reflect.Float64: + VFloat, VErr := strconv.ParseFloat(VerifyStrArr[1], 64) + if VErr != nil { + return false + } + switch { + case VerifyStrArr[0] == "lt": + return val.Float() < VFloat + case VerifyStrArr[0] == "le": + return val.Float() <= VFloat + case VerifyStrArr[0] == "eq": + return val.Float() == VFloat + case VerifyStrArr[0] == "ne": + return val.Float() != VFloat + case VerifyStrArr[0] == "ge": + return val.Float() >= VFloat + case VerifyStrArr[0] == "gt": + return val.Float() > VFloat + default: + return false + } + default: + return false + } +} + +func regexpMatch(rule, matchStr string) bool { + return regexp.MustCompile(rule).MatchString(matchStr) +} diff --git a/utils/validator_test.go b/utils/validator_test.go new file mode 100644 index 0000000..83a0bd3 --- /dev/null +++ b/utils/validator_test.go @@ -0,0 +1,37 @@ +package utils + +import ( + "miniapp/model/common/request" + "testing" +) + +type PageInfoTest struct { + PageInfo request.PageInfo + Name string +} + +func TestVerify(t *testing.T) { + PageInfoVerify := Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}, "Name": {NotEmpty()}} + var testInfo PageInfoTest + testInfo.Name = "test" + testInfo.PageInfo.Page = 0 + testInfo.PageInfo.PageSize = 0 + err := Verify(testInfo, PageInfoVerify) + if err == nil { + t.Error("校验失败,未能捕捉0值") + } + testInfo.Name = "" + testInfo.PageInfo.Page = 1 + testInfo.PageInfo.PageSize = 10 + err = Verify(testInfo, PageInfoVerify) + if err == nil { + t.Error("校验失败,未能正常检测name为空") + } + testInfo.Name = "test" + testInfo.PageInfo.Page = 1 + testInfo.PageInfo.PageSize = 10 + err = Verify(testInfo, PageInfoVerify) + if err != nil { + t.Error("校验失败,未能正常通过检测") + } +} diff --git a/utils/verify.go b/utils/verify.go new file mode 100644 index 0000000..3633360 --- /dev/null +++ b/utils/verify.go @@ -0,0 +1,19 @@ +package utils + +var ( + IdVerify = Rules{"ID": []string{NotEmpty()}} + ApiVerify = Rules{"Path": {NotEmpty()}, "Description": {NotEmpty()}, "ApiGroup": {NotEmpty()}, "Method": {NotEmpty()}} + MenuVerify = Rules{"Path": {NotEmpty()}, "ParentId": {NotEmpty()}, "Name": {NotEmpty()}, "Component": {NotEmpty()}, "Sort": {Ge("0")}} + MenuMetaVerify = Rules{"Title": {NotEmpty()}} + LoginVerify = Rules{"CaptchaId": {NotEmpty()}, "Username": {NotEmpty()}, "Password": {NotEmpty()}} + RegisterVerify = Rules{"Username": {NotEmpty()}, "NickName": {NotEmpty()}, "Password": {NotEmpty()}, "AuthorityId": {NotEmpty()}} + PageInfoVerify = Rules{"Page": {NotEmpty()}, "PageSize": {NotEmpty()}} + CustomerVerify = Rules{"CustomerName": {NotEmpty()}, "CustomerPhoneData": {NotEmpty()}} + AutoCodeVerify = Rules{"Abbreviation": {NotEmpty()}, "StructName": {NotEmpty()}, "PackageName": {NotEmpty()}, "Fields": {NotEmpty()}} + AutoPackageVerify = Rules{"PackageName": {NotEmpty()}} + AuthorityVerify = Rules{"AuthorityId": {NotEmpty()}, "AuthorityName": {NotEmpty()}} + AuthorityIdVerify = Rules{"AuthorityId": {NotEmpty()}} + OldAuthorityVerify = Rules{"OldAuthorityId": {NotEmpty()}} + ChangePasswordVerify = Rules{"Password": {NotEmpty()}, "NewPassword": {NotEmpty()}} + SetUserAuthorityVerify = Rules{"AuthorityId": {NotEmpty()}} +) diff --git a/utils/wechat.go b/utils/wechat.go new file mode 100644 index 0000000..0084218 --- /dev/null +++ b/utils/wechat.go @@ -0,0 +1,70 @@ +package utils + +import ( + "github.com/medivhzhan/weapp/v3" + "github.com/medivhzhan/weapp/v3/auth" + "github.com/medivhzhan/weapp/v3/phonenumber" + "go.uber.org/zap" + "miniapp/global" + "miniapp/model/app/request" +) + +type wechat struct{} + +func WeChatUtils() *wechat { + return &wechat{} +} + +// GetWechatUnionId 获取微信用户基础信息 +func (w wechat) GetWechatUnionId(code string) (unionId, openId, sessionKey string, err error) { + sdk := weapp.NewClient(global.GVA_CONFIG.MiniApp.AppId, global.GVA_CONFIG.MiniApp.AppSecret, weapp.WithLogger(nil)) + cli := sdk.NewAuth() + + p := auth.Code2SessionRequest{ + Appid: global.GVA_CONFIG.MiniApp.AppId, + Secret: global.GVA_CONFIG.MiniApp.AppSecret, + JsCode: code, + GrantType: "authorization_code", + } + + session, err := cli.Code2Session(&p) + if err != nil { + return + } + if session.GetResponseError() != nil { + global.GVA_LOG.Error("Code解析失败: %v", zap.Error(session.GetResponseError())) + err = session.GetResponseError() + return + } + // 设置UnionId值 + unionId = session.Unionid + openId = session.Openid + sessionKey = session.SessionKey + return +} + +// GetWechatPhone 根据Code获取小程序用户手机号 +// return 不带区号的手机号 +func (w wechat) GetWechatPhone(param request.DecryptMobile) (string, error) { + sdk := weapp.NewClient(global.GVA_CONFIG.MiniApp.AppId, global.GVA_CONFIG.MiniApp.AppSecret) + mobile, err := sdk.DecryptMobile(param.SessionKey, param.EncryptedData, param.Iv) + if err != nil { + global.GVA_LOG.Error("解密手机号失败: %v", zap.Error(err)) + return "", err + } + global.GVA_LOG.Debug("解密后的手机号: %+v", zap.String("mobile", mobile.PurePhoneNumber)) + return mobile.PurePhoneNumber, nil +} + +// GetPhoneNumber 获取手机号 +func (w wechat) GetPhoneNumber(code string) (phone string, err error) { + sdk := weapp.NewClient(global.GVA_CONFIG.MiniApp.AppId, global.GVA_CONFIG.MiniApp.AppSecret) + resp, err := sdk.NewPhonenumber().GetPhoneNumber(&phonenumber.GetPhoneNumberRequest{Code: code}) + if err != nil { + global.GVA_LOG.Error("获取手机号失败: %v", zap.Error(err)) + return + } + // 获取手机号 + phone = resp.Data.PurePhoneNumber + return +} diff --git a/utils/zip.go b/utils/zip.go new file mode 100644 index 0000000..e0075f4 --- /dev/null +++ b/utils/zip.go @@ -0,0 +1,110 @@ +package utils + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +// 解压 +func Unzip(zipFile string, destDir string) ([]string, error) { + zipReader, err := zip.OpenReader(zipFile) + var paths []string + if err != nil { + return []string{}, err + } + defer zipReader.Close() + + for _, f := range zipReader.File { + if strings.Index(f.Name, "..") > -1 { + return []string{}, fmt.Errorf("%s 文件名不合法", f.Name) + } + fpath := filepath.Join(destDir, f.Name) + paths = append(paths, fpath) + if f.FileInfo().IsDir() { + os.MkdirAll(fpath, os.ModePerm) + } else { + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return []string{}, err + } + + inFile, err := f.Open() + if err != nil { + return []string{}, err + } + defer inFile.Close() + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return []string{}, err + } + defer outFile.Close() + + _, err = io.Copy(outFile, inFile) + if err != nil { + return []string{}, err + } + } + } + return paths, nil +} + +func ZipFiles(filename string, files []string, oldForm, newForm string) error { + newZipFile, err := os.Create(filename) + if err != nil { + return err + } + defer func() { + _ = newZipFile.Close() + }() + + zipWriter := zip.NewWriter(newZipFile) + defer func() { + _ = zipWriter.Close() + }() + + // 把files添加到zip中 + for _, file := range files { + + err = func(file string) error { + zipFile, err := os.Open(file) + if err != nil { + return err + } + defer zipFile.Close() + // 获取file的基础信息 + info, err := zipFile.Stat() + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面 + header.Name = strings.Replace(file, oldForm, newForm, -1) + + // 优化压缩 + // 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants + header.Method = zip.Deflate + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + if _, err = io.Copy(writer, zipFile); err != nil { + return err + } + return nil + }(file) + if err != nil { + return err + } + } + return nil +}