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 [31merror[0m C:/Users/Administrator/Desktop/server/api/v1/system/sys_user.go:56 登陆失败! 用户名不存在或者密码错误! {"error": "db not init"}
+[miniapp]2023/10/11 - 12:49:14.470 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 12:49:32.985 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 14:32:21.261 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 14:32:27.921 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 15:44:36.062 [31merror[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 21:30:35.762 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 21:30:35.765 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 21:49:14.248 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 21:49:14.250 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 21:51:29.985 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 21:54:28.659 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 21:54:28.661 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 21:57:19.306 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 21:57:19.308 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:03:49.141 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:03:49.777 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:03:49.780 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:04:26.818 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:04:26.820 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:08:45.745 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:08:45.745 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:08:45.745 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:08:45.748 [31merror[0m 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 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:08:46.371 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:11:23.110 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/utils/clamis.go:15 从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构
+[miniapp]2023/10/11 - 22:13:36.216 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 清理失败,跳过清理
+[miniapp]2023/10/11 - 22:36:29.261 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 22:47:14.886 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 23:00:59.633 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 23:00:59.633 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/10/11 - 23:01:00.334 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:44 register swagger handler
+[miniapp]2023/10/11 - 12:17:24.316 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:81 router register success
+[miniapp]2023/10/11 - 12:17:24.318 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 12:17:59.631 [34minfo[0m C:/Users/Administrator/Desktop/server/api/v1/system/sys_initdb.go:57 前往初始化数据库
+[miniapp]2023/10/11 - 12:22:36.247 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:41:36.502 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:41:36.504 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 12:41:36.505 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 12:41:36.505 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success
+[miniapp]2023/10/11 - 12:41:36.518 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 12:47:37.733 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:47:37.735 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 12:47:37.736 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 12:47:37.736 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success
+[miniapp]2023/10/11 - 12:47:37.745 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 12:48:02.622 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:48:02.624 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 12:48:02.625 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 12:48:02.626 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success
+[miniapp]2023/10/11 - 12:48:02.633 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 12:48:47.654 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:48:47.659 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 12:48:47.660 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 12:48:47.660 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success
+[miniapp]2023/10/11 - 12:48:47.676 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 12:51:25.617 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 12:51:25.619 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 12:51:25.620 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 12:51:25.621 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:85 router register success
+[miniapp]2023/10/11 - 12:51:25.631 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 14:46:18.358 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 14:46:18.361 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 14:46:18.362 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 14:47:00.201 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:63 register table success
+[miniapp]2023/10/11 - 14:47:00.204 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 14:47:00.205 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 14:47:00.205 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 14:47:00.219 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 14:53:02.134 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 14:53:02.137 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 14:53:02.137 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 14:53:02.138 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 14:53:02.150 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 15:00:11.005 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 15:00:11.008 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 15:00:11.008 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 15:00:11.009 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 15:00:11.023 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 15:41:43.799 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 15:41:43.802 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 15:41:43.802 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 15:41:43.803 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 15:41:43.814 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 22:16:48.448 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 22:16:48.451 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 22:16:48.451 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 22:16:48.452 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 22:16:48.456 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 23:23:50.878 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 23:23:50.880 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 23:23:50.881 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 23:23:50.881 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 23:23:50.890 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/11 - 23:24:18.312 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/11 - 23:24:18.315 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/11 - 23:24:18.315 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/11 - 23:24:18.316 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/11 - 23:24:18.321 [34minfo[0m 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 [31mpanic[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.798 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.842 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.849 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.856 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.863 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/12 - 20:49:24.893 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 清理失败,跳过清理
+[miniapp]2023/10/12 - 20:49:24.894 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/12 - 14:46:11.067 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 14:46:11.068 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 14:46:11.068 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/12 - 14:46:11.071 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 14:47:42.187 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/12 - 14:47:42.203 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 14:47:42.204 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 14:47:42.204 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:86 router register success
+[miniapp]2023/10/12 - 14:47:42.217 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 17:28:23.736 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/12 - 17:28:23.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 17:28:23.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 17:28:23.740 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 17:28:23.756 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 17:29:04.795 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:73 register table success
+[miniapp]2023/10/12 - 17:29:04.798 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 17:29:04.798 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 17:29:04.799 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 17:29:04.804 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 17:32:13.919 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:74 register table success
+[miniapp]2023/10/12 - 17:32:13.922 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 17:32:13.922 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 17:32:13.923 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 17:32:13.937 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 21:07:08.230 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success
+[miniapp]2023/10/12 - 21:07:08.233 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 21:07:08.233 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 21:07:08.234 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 21:07:08.235 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 21:13:51.791 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success
+[miniapp]2023/10/12 - 21:13:51.803 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 21:13:51.804 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 21:13:51.804 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 21:13:51.812 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/12 - 21:43:51.654 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success
+[miniapp]2023/10/12 - 21:43:51.657 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/12 - 21:43:51.658 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/12 - 21:43:51.658 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/12 - 21:43:51.667 [34minfo[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/17 - 09:24:07.298 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:75 register table success
+[miniapp]2023/10/17 - 08:18:29.957 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 08:18:29.957 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 08:18:29.958 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 08:18:29.965 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 08:28:22.029 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:76 register table success
+[miniapp]2023/10/17 - 08:28:22.032 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 08:28:22.032 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 08:28:22.033 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 08:28:22.049 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 08:43:13.963 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:76 register table success
+[miniapp]2023/10/17 - 08:43:13.966 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 08:43:13.966 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 08:43:13.967 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 08:43:13.975 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 08:48:32.173 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 08:48:32.176 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 08:48:32.177 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 08:48:32.177 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 08:48:32.189 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:00:52.809 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:00:52.811 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:00:52.811 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:00:52.812 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:00:52.818 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:13:20.930 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:13:20.932 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:13:20.932 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:13:20.933 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:13:20.937 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:15:05.736 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:15:05.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:15:05.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:15:05.740 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:15:05.752 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:16:26.672 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:16:26.674 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:16:26.675 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:16:26.675 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:16:26.688 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:23:41.666 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:23:41.669 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:23:41.669 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:23:41.670 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:23:41.674 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 09:26:05.699 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 09:26:05.702 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 09:26:05.702 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 09:26:05.703 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 09:26:05.706 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 19:02:13.365 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 19:02:13.368 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 19:02:13.369 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 19:02:13.373 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 19:02:13.383 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server run success on {"address": ":8888"}
+[miniapp]2023/10/17 - 21:48:19.564 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/17 - 21:48:19.567 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/17 - 21:48:19.568 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/17 - 21:48:19.568 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/17 - 21:48:19.577 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/20 - 07:54:00.942 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/20 - 07:54:00.943 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/20 - 07:54:00.944 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/20 - 07:54:00.952 [34minfo[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/23 - 12:45:53.047 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/23 - 12:03:11.277 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/23 - 12:03:11.278 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/23 - 12:03:11.279 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/23 - 12:03:11.292 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"}
+[miniapp]2023/10/23 - 12:43:49.800 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/23 - 12:43:49.803 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/23 - 12:43:49.804 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/23 - 12:43:49.804 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/23 - 12:43:49.813 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"}
+[miniapp]2023/10/23 - 12:50:34.031 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/23 - 12:50:34.033 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/23 - 12:50:34.034 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/23 - 12:50:34.035 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/23 - 12:50:34.049 [34minfo[0m C:/Users/Administrator/Desktop/server/core/server.go:36 server.exe run success on {"address": ":8888"}
+[miniapp]2023/10/23 - 12:52:29.098 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/23 - 12:52:29.100 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/23 - 12:52:29.101 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/23 - 12:52:29.102 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/23 - 12:52:29.115 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/24 - 19:58:03.153 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/24 - 19:58:03.153 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/24 - 19:58:03.154 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/24 - 19:58:03.157 [34minfo[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户信息或创建用户失败,错误信息:登录失败
+[miniapp]2023/10/25 - 18:36:37.534 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 登录失败,请联系管理员
+[miniapp]2023/10/25 - 18:36:59.107 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户信息或创建用户失败,错误信息:登录失败
+[miniapp]2023/10/25 - 18:36:59.111 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 登录失败,请联系管理员
+[miniapp]2023/10/25 - 22:33:30.865 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/25 - 22:39:31.822 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/25 - 22:48:41.964 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/25 - 22:49:04.522 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/25 - 23:51:51.256 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/25 - 18:29:32.390 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/25 - 18:29:32.390 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/25 - 18:29:32.391 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/25 - 18:29:32.405 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/27 - 11:45:32.630 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/27 - 11:45:32.631 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/27 - 11:45:32.632 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/27 - 11:45:32.637 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/27 - 12:10:35.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/27 - 12:10:35.739 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/27 - 12:10:35.740 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/27 - 12:10:35.749 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/27 - 12:47:41.064 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/27 - 12:47:41.066 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/27 - 12:47:41.067 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/27 - 12:47:41.081 [34minfo[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/31 - 20:55:09.937 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/31 - 20:55:09.978 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/31 - 20:55:17.840 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/31 - 20:56:13.511 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 获取手机号失败
+[miniapp]2023/10/31 - 20:57:16.209 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/api/v1/system/article.go:100 获取失败record not found
+[miniapp]2023/10/31 - 21:10:01.493 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:28:37.154 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:28:39.406 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:28:39.533 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:28:39.617 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:28:42.450 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:29:42.352 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:29:46.792 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:137 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:33:00.380 [31merror[0m 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 [31merror[0m C:/Users/Administrator/Desktop/server/service/app/user.go:138 创建用户Todo列表失败 {"error": "empty slice found"}
+[miniapp]2023/10/31 - 22:47:43.126 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 20:24:53.732 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 20:24:53.733 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 20:24:53.733 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 20:24:53.742 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 20:54:05.441 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 20:54:05.441 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 20:54:05.442 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 20:54:05.444 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 21:07:42.774 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 21:07:42.775 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 21:07:42.775 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 21:07:42.789 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 21:08:25.718 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 21:08:25.718 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 21:08:25.719 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 21:08:25.728 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 21:09:59.779 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 21:09:59.779 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 21:09:59.780 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 21:09:59.792 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 21:10:45.448 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 21:10:45.449 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 21:10:45.450 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 21:10:45.455 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 22:39:24.368 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 22:39:24.369 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 22:39:24.369 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 22:39:24.385 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 23:12:22.876 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 23:12:22.877 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 23:12:22.878 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:87 router register success
+[miniapp]2023/10/31 - 23:12:22.893 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 23:13:39.018 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 23:13:39.018 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 23:13:39.019 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/10/31 - 23:13:39.022 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 23:35:11.078 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 23:35:11.079 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 23:35:11.079 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/10/31 - 23:35:11.091 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 23:42:07.187 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 23:42:07.188 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 23:42:07.188 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/10/31 - 23:42:07.201 [34minfo[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/10/31 - 23:43:16.973 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/10/31 - 23:43:16.973 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/10/31 - 23:43:16.974 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/10/31 - 23:43:16.975 [34minfo[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/11/01 - 00:15:40.724 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/11/01 - 00:17:03.179 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/11/01 - 00:17:12.790 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/11/01 - 00:17:42.207 [31merror[0m D:/GOPATH/pkg/mod/git.echol.cn/loser/logger@v1.0.15/log/say.go:65 获取用户基础账号信息失败: 未知的用户身份类型
+[miniapp]2023/11/01 - 00:20:44.193 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/11/01 - 00:16:23.521 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/11/01 - 00:16:23.522 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/11/01 - 00:16:23.522 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/11/01 - 00:16:23.528 [34minfo[0m 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 [31merror[0m 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 [31merror[0m 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 [31merror[0m 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 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/gorm.go:77 register table success
+[miniapp]2023/11/02 - 04:09:23.251 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/redis.go:23 redis connect ping response: {"pong": "PONG"}
+[miniapp]2023/11/02 - 04:09:23.252 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:39 register swagger handler
+[miniapp]2023/11/02 - 04:09:23.252 [34minfo[0m C:/Users/Administrator/Desktop/server/initialize/router.go:88 router register success
+[miniapp]2023/11/02 - 04:09:23.267 [34minfo[0m 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 @@
+
+
+
+
+ {{- range .Fields}}
+
+ {{- if eq .FieldType "bool" }}
+
+ {{- end }}
+ {{- if eq .FieldType "string" }}
+
+ {{- end }}
+ {{- if eq .FieldType "richtext" }}
+
+ {{- end }}
+ {{- if eq .FieldType "int" }}
+ {{- if .DictType }}
+
+
+
+ {{- else }}
+
+ {{- end }}
+ {{- end }}
+ {{- if eq .FieldType "time.Time" }}
+
+ {{- end }}
+ {{- if eq .FieldType "float64" }}
+
+ {{- end }}
+ {{- if eq .FieldType "enum" }}
+
+
+
+ {{- end }}
+ {{- if eq .FieldType "picture" }}
+
+ {{- end }}
+ {{- if eq .FieldType "video" }}
+
+ {{- end }}
+ {{- if eq .FieldType "pictures" }}
+
+ {{- end }}
+ {{- if eq .FieldType "file" }}
+
+ {{- end }}
+
+ {{- end }}
+
+ 保存
+ 返回
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+ 创建日期
+
+
+
+
+
+
+ —
+
+
+ {{- range .Fields}} {{- if .FieldSearchType}} {{- if eq .FieldType "bool" }}
+
+
+
+
+
+
+
+
+ {{- else if .DictType}}
+
+ {searchInfo.{{.FieldJson}}=undefined}">
+
+
+
+ {{- else}}
+
+
+
+ {{- if eq .FieldType "float64" "int"}}
+ {{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
+
+ —
+
+ {{- else}}
+ {{- if .DictType}}
+
+
+
+ {{- else}}
+
+ {{- end }}
+ {{- end}}
+ {{- else if eq .FieldType "time.Time"}}
+ {{if eq .FieldSearchType "BETWEEN" "NOT BETWEEN"}}
+
+
+ {{.FieldDesc}}
+
+
+
+
+
+
+ —
+
+ {{- else}}
+
+ {{- end}}
+ {{- else}}
+
+ {{- end}}
+
+ {{ end }}{{ end }}{{ end }}
+
+ 查询
+ 重置
+
+
+
+
+
+
新增
+
+ 确定要删除吗?
+
+ 取消
+ 确定
+
+
+ 删除
+
+
+
+
+
+
+ {{ "{{ formatDate(scope.row.CreatedAt) }}" }}
+
+ {{- range .Fields}}
+ {{- if .DictType}}
+
+
+ {{"{{"}} filterDict(scope.row.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
+
+
+ {{- else if eq .FieldType "bool" }}
+
+ {{"{{"}} formatBoolean(scope.row.{{.FieldJson}}) {{"}}"}}
+
+ {{- else if eq .FieldType "time.Time" }}
+
+ {{"{{"}} formatDate(scope.row.{{.FieldJson}}) {{"}}"}}
+
+ {{- else if eq .FieldType "picture" }}
+
+
+
+
+
+ {{- else if eq .FieldType "pictures" }}
+
+
+
+
+
+
+
+ {{- else if eq .FieldType "video" }}
+
+
+
+
+
+ {{- else if eq .FieldType "richtext" }}
+
+
+ [富文本内容]
+
+
+ {{- else if eq .FieldType "file" }}
+
+
+
+ {{"{{"}}file.name{{"}}"}}
+
+
+
+ {{- else }}
+
+ {{- end }}
+ {{- end }}
+
+
+
+
+ 查看详情
+
+ 变更
+ 删除
+
+
+
+
+
+
+
+
+ {{- range .Fields}}
+
+ {{- if eq .FieldType "bool" }}
+
+ {{- end }}
+ {{- if eq .FieldType "string" }}
+
+ {{- end }}
+ {{- if eq .FieldType "richtext" }}
+
+ {{- end }}
+ {{- if eq .FieldType "int" }}
+ {{- if .DictType}}
+
+
+
+ {{- else }}
+
+ {{- end }}
+ {{- end }}
+ {{- if eq .FieldType "time.Time" }}
+
+ {{- end }}
+ {{- if eq .FieldType "float64" }}
+
+ {{- end }}
+ {{- if eq .FieldType "enum" }}
+
+
+
+ {{- end }}
+ {{- if eq .FieldType "picture" }}
+
+ {{- end }}
+ {{- if eq .FieldType "pictures" }}
+
+ {{- end }}
+ {{- if eq .FieldType "video" }}
+
+ {{- end }}
+ {{- if eq .FieldType "file" }}
+
+ {{- end }}
+
+ {{- end }}
+
+
+
+
+
+
+
+
+
+
+ {{- range .Fields}}
+
+ {{- if .DictType}}
+ {{"{{"}} filterDict(formData.{{.FieldJson}},{{.DictType}}Options) {{"}}"}}
+ {{- else if eq .FieldType "picture" }}
+
+ {{- else if eq .FieldType "video" }}
+
+ {{- else if eq .FieldType "pictures" }}
+
+ {{- else if eq .FieldType "file" }}
+
+
+
+ {{"{{"}} item.name {{"}}"}}
+
+
+ {{- else if eq .FieldType "bool" }}
+ {{"{{"}} formatBoolean(formData.{{.FieldJson}}) {{"}}"}}
+ {{- else if eq .FieldType "time.Time" }}
+ {{"{{"}} formatDate(formData.{{.FieldJson}}) {{"}}"}}
+ {{- else if eq .FieldType "richtext" }}
+ [富文本内容]
+ {{- else}}
+ {{"{{"}} formData.{{.FieldJson}} {{"}}"}}
+ {{- end }}
+
+ {{- end }}
+
+
+
+
+
+
+
+
+
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
+}