未验证 提交 3e95cca8 编写于 作者: Mr.奇淼('s avatar Mr.奇淼( 提交者: GitHub

v2.5.1 beta2 (#1048)

* 修复日志中间件报文过大的报错问题

* 修复 Token 失效后导致的白屏问题

* 增加自动创建插件模板功能

* 密码加密方式改为 hash

* 增加刷新防抖
Co-authored-by: Nsongzhibin97 <718428482@qq.com>
Co-authored-by: Nicedays <icedays@163.com>
Co-authored-by: LaravelCode's avatarhedeqiang <laravel_code@163.com>
上级 14c1b959
......@@ -211,3 +211,26 @@ func (autoApi *AutoCodeApi) DelPackage(c *gin.Context) {
response.OkWithMessage("删除成功", c)
}
}
// DelPackage
// @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
_ = c.ShouldBindJSON(&a)
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)
} else {
response.Ok(c)
}
}
......@@ -111,6 +111,7 @@ autocode:
# 请不要手动配置,他会在项目加载的时候识别出根路径
root: ""
server: /server
server-plug: /plugin/%s
server-api: /api/v1/%s
server-initialize: /initialize
server-model: /model/%s
......
......@@ -5,6 +5,7 @@ type Autocode struct {
Root string `mapstructure:"root" json:"root" yaml:"root"`
Server string `mapstructure:"server" json:"server" yaml:"server"`
SApi string `mapstructure:"server-api" json:"server-api" yaml:"server-api"`
SPlug string `mapstructure:"server-plug" json:"server-plug" yaml:"server-plug"`
SInitialize string `mapstructure:"server-initialize" json:"server-initialize" yaml:"server-initialize"`
SModel string `mapstructure:"server-model" json:"server-model" yaml:"server-model"`
SRequest string `mapstructure:"server-request" json:"server-request" yaml:"server-request"`
......
......@@ -8,6 +8,7 @@ import (
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
......@@ -21,6 +22,14 @@ import (
var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService
var respPool sync.Pool
func init() {
respPool.New = func() interface{} {
return make([]byte, 1024)
}
}
func OperationRecord() gin.HandlerFunc {
return func(c *gin.Context) {
var body []byte
......@@ -64,12 +73,18 @@ func OperationRecord() gin.HandlerFunc {
Body: string(body),
UserID: userId,
}
// 上传文件时候 中间件日志进行裁断操作
if strings.Index(c.GetHeader("Content-Type"), "multipart/form-data") > -1 {
if len(record.Body) > 512 {
record.Body = "File or Length out of limit"
if len(record.Body) > 1024 {
// 截断
newBody := respPool.Get().([]byte)
copy(newBody, record.Body)
record.Body = string(newBody)
defer respPool.Put(newBody[:0])
}
}
writer := responseBodyWriter{
ResponseWriter: c.Writer,
body: &bytes.Buffer{},
......@@ -85,6 +100,24 @@ func OperationRecord() gin.HandlerFunc {
record.Latency = latency
record.Resp = writer.body.String()
if strings.Index(c.Writer.Header().Get("Pragma"), "public") > -1 ||
strings.Index(c.Writer.Header().Get("Expires"), "0") > -1 ||
strings.Index(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Type"), "application/force-download") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Type"), "application/octet-stream") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Type"), "application/download") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Disposition"), "attachment") > -1 ||
strings.Index(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") > -1 {
if len(record.Resp) > 1024 {
// 截断
newBody := respPool.Get().([]byte)
copy(newBody, record.Resp)
record.Body = string(newBody)
defer respPool.Put(newBody[:0])
}
}
if err := operationRecordService.CreateSysOperationRecord(record); err != nil {
global.GVA_LOG.Error("create operation record error:", zap.Error(err))
}
......
......@@ -17,8 +17,8 @@ type AutoCodeStruct struct {
AutoMoveFile bool `json:"autoMoveFile"` // 是否自动移动文件
Fields []*Field `json:"fields"`
DictTypes []string `json:"-"`
Package string `json:"package"`
PackageT string `json:"-"`
Package string `json:"package"`
PackageT string `json:"-"`
}
type Field struct {
......@@ -38,6 +38,31 @@ var AutoMoveErr error = errors.New("创建代码成功并移动文件成功")
type SysAutoCode struct {
global.GVA_MODEL
PackageName string `json:"packageName" gorm:"comment:包名"`
Label string `json:"label" 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 []struct {
Key string `json:"key"`
Type string `json:"type"`
Desc string `json:"desc"`
} `json:"global"`
Request []struct {
Key string `json:"key"`
Type string `json:"type"`
Desc string `json:"desc"`
} `json:"request"`
Response []struct {
Key string `json:"key"`
Type string `json:"type"`
Desc string `json:"desc"`
} `json:"response"`
}
## GVA 阿里云短信发送功能插件
#### 开发者:GIN-VUE-ADMIN 官方
### 使用步骤
#### 1. 前往GVA主程序下的initialize/router.go 在Routers 方法最末尾按照你需要的及安全模式添加本插件
例:
本插件可以采用gva的配置文件 也可以直接写死内容作为配置 建议为gva添加配置文件结构 然后将配置传入
PluginInit(PublicGroup, sms.CreateAliSmsPlug("短信的AccessKey ID", "短信的AccessKey Secret", "短信的 SignName"))
### 2. 配置说明
#### 2-1 全局配置结构体说明
type AliSms struct {
AccessKeyId string `mapstructure:"accessKeyId" json:"accessKeyId" yaml:"accessKeyId"` // 短信的AccessKey ID
AccessSecret string `mapstructure:"accessSecret" json:"accessSecret" yaml:"accessSecret"` // 短信的AccessKey Secret
SignName string `mapstructure:"signName" json:"signName" yaml:"signName"` // 短信的 SignName
}
#### 2-2 入参结构说明
type AliModel struct {
Phones []string `json:"phones"` // 需要发送的手机(可传入多个)
TemplateCode string `json:"templateCode"` // 短信模板的code
TemplateParam string `json:"templateParam"` // 短信模板的填充
}
templateParam: 模板使用json字符串 {"code":"xxx"} 对应你模板里面的变量key和value
### 3. 方法API
// 无
### 4. 可直接调用的接口
发送邮件接口接口: /aliSms/sendSms [post] 已配置swagger
入参:
type AliModel struct {
Phones []string `json:"phones"` // 需要发送的手机(可传入多个)
TemplateCode string `json:"templateCode"` // 短信模板的code
TemplateParam string `json:"templateParam"` // 短信模板的填充
}
package api
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
{{ if .NeedModel }} "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/model" {{ end }}
"github.com/flipped-aurora/gin-vue-admin/server/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 err{{- if .HasResponse }},res {{ end -}}:= 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 -}}
}
}
package api
type ApiGroup struct {
{{ .PlugName}}Api
}
var ApiGroupApp = new(ApiGroup)
package config
{{- if .HasGlobal }}
type {{ .PlugName }} struct {
{{- range .Global }}
{{ .Key }} {{ .Type }} {{- if ne .Desc "" }} // {{ .Desc }} {{ end -}}
{{- end }}
}
{{ end -}}
\ No newline at end of file
package global
{{- if .HasGlobal }}
import "github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/config"
var GlobalConfig = new(config.{{ .PlugName}})
{{ end -}}
\ No newline at end of file
package {{ .Snake}}
import (
{{- if .HasGlobal }}
"github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/global"
{{- end }}
"github.com/flipped-aurora/gin-vue-admin/server/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}}"
}
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 -}}
package router
type RouterGroup struct {
{{ .PlugName}}Router
}
var RouterGroupApp = new(RouterGroup)
package router
import (
"github.com/flipped-aurora/gin-vue-admin/server/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)
}
}
package service
type ServiceGroup struct {
{{ .PlugName}}Service
}
var ServiceGroupApp = new(ServiceGroup)
package service
{{- if .NeedModel }}
import (
"github.com/flipped-aurora/gin-vue-admin/server/plugin/{{ .Snake}}/model"
)
{{ end }}
type {{ .PlugName}}Service struct{}
func (e *{{ .PlugName}}Service) PlugService({{- if .HasRequest }}req model.Request {{ end -}}) (err error{{- if .HasResponse }},res model.Response{{ end -}}) {
// 写你的业务逻辑
return nil{{- if .HasResponse }},res {{ end }}
}
......@@ -11,13 +11,14 @@ 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.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) // 自动插件包模板
}
}
......@@ -17,7 +17,7 @@ import (
"strings"
"text/template"
"github.com/flipped-aurora/gin-vue-admin/server/resource/template/subcontract"
"github.com/flipped-aurora/gin-vue-admin/server/resource/autocode_template/subcontract"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
......@@ -28,7 +28,8 @@ import (
const (
autoPath = "autocode_template/"
basePath = "resource/template"
autocodePath = "resource/autocode_template"
plugPath = "resource/plug_template"
packageService = "service/%s/enter.go"
packageServiceName = "service"
packageRouter = "router/%s/enter.go"
......@@ -483,7 +484,7 @@ func (autoCodeService *AutoCodeService) getNeedList(autoCode *system.AutoCodeStr
utils.TrimSpace(field)
}
// 获取 basePath 文件夹下所有tpl文件
tplFileList, err := autoCodeService.GetAllTplFile(basePath, nil)
tplFileList, err := autoCodeService.GetAllTplFile(autocodePath, nil)
if err != nil {
return nil, nil, nil, err
}
......@@ -505,7 +506,7 @@ func (autoCodeService *AutoCodeService) getNeedList(autoCode *system.AutoCodeStr
// 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, basePath+"/")
trimBase := strings.TrimPrefix(value.locationPath, autocodePath+"/")
if trimBase == "readme.txt.tpl" {
dataList[index].autoCodePath = autoPath + "readme.txt"
continue
......@@ -789,3 +790,26 @@ func ImportReference(filepath, importCode, structName, packageName, groupName st
// 写回数据
return ioutil.WriteFile(filepath, buffer.Bytes(), 0o600)
}
// 自动创建插件模板
func (autoCodeService *AutoCodeService) CreatePlug(plug system.AutoPlugReq) error {
tplFileList, _ := autoCodeService.GetAllTplFile(plugPath, nil)
for _, tpl := range tplFileList {
temp, err := template.ParseFiles(tpl)
fmt.Println(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, _ := os.OpenFile(file, os.O_WRONLY|os.O_CREATE, 0666)
e := temp.Execute(f, plug)
if e != nil {
fmt.Println(e)
return e
}
defer f.Close()
}
return nil
}
......@@ -3,7 +3,6 @@ package system
import (
"errors"
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
......@@ -25,8 +24,8 @@ func (userService *UserService) Register(u system.SysUser) (err error, userInter
if !errors.Is(global.GVA_DB.Where("username = ?", u.Username).First(&user).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册
return errors.New("用户名已注册"), userInter
}
// 否则 附加uuid 密码md5简单加密 注册
u.Password = utils.MD5V([]byte(u.Password))
// 否则 附加uuid 密码hash加密 注册
u.Password = utils.BcryptHash(u.Password)
u.UUID = uuid.NewV4()
err = global.GVA_DB.Create(&u).Error
return err, u
......@@ -44,15 +43,18 @@ func (userService *UserService) Login(u *system.SysUser) (err error, userInter *
}
var user system.SysUser
u.Password = utils.MD5V([]byte(u.Password))
err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).Preload("Authorities").Preload("Authority").First(&user).Error
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 errors.New("密码错误"), nil
}
var am system.SysMenu
ferr := global.GVA_DB.First(&am, "name = ? AND authority_id = ?", user.Authority.DefaultRouter, user.AuthorityId).Error
if errors.Is(ferr, gorm.ErrRecordNotFound) {
user.Authority.DefaultRouter = "404"
}
}
return err, &user
}
......@@ -64,9 +66,17 @@ func (userService *UserService) Login(u *system.SysUser) (err error, userInter *
func (userService *UserService) ChangePassword(u *system.SysUser, newPassword string) (err error, userInter *system.SysUser) {
var user system.SysUser
u.Password = utils.MD5V([]byte(u.Password))
err = global.GVA_DB.Where("username = ? AND password = ?", u.Username, u.Password).First(&user).Update("password", utils.MD5V([]byte(newPassword))).Error
return err, u
err = global.GVA_DB.Where("username = ?", u.Username).First(&user).Error
if err != nil {
return err, nil
}
if ok := utils.BcryptCheck(u.Password, user.Password); !ok {
return errors.New("原密码错误"), nil
}
user.Password = utils.BcryptHash(newPassword)
err = global.GVA_DB.Save(&user).Error
return err, &user
}
//@author: [piexlmax](https://github.com/piexlmax)
......@@ -213,6 +223,6 @@ func (userService *UserService) FindUserByUuid(uuid string) (err error, user *sy
//@return: err error
func (userService *UserService) ResetPassword(ID uint) (err error) {
err = global.GVA_DB.Model(&system.SysUser{}).Where("id = ?", ID).Update("password", utils.MD5V([]byte("123456"))).Error
err = global.GVA_DB.Model(&system.SysUser{}).Where("id = ?", ID).Update("password", utils.BcryptHash("123456")).Error
return err
}
......@@ -111,6 +111,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{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: "包(pkg)生成器", Method: "POST", Path: "/autoCode/createPackage", Description: "生成包(package)"},
{ApiGroup: "包(pkg)生成器", Method: "POST", Path: "/autoCode/getPackage", Description: "获取所有包(package)"},
......
......@@ -119,6 +119,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{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: "/sysDictionaryDetail/findSysDictionaryDetail", V2: "GET"},
{PType: "p", V0: "888", V1: "/sysDictionaryDetail/updateSysDictionaryDetail", V2: "PUT"},
......
......@@ -78,6 +78,7 @@ func (i *initMenu) InitializeData(ctx context.Context) (next context.Context, er
{MenuLevel: 0, Hidden: false, ParentId: "14", Path: "autoCodeAdmin", Name: "autoCodeAdmin", Component: "view/systemTools/autoCodeAdmin/index.vue", Sort: 1, Meta: Meta{Title: "自动化代码管理", Icon: "magic-stick"}},
{MenuLevel: 0, Hidden: true, ParentId: "14", Path: "autoCodeEdit/:id", Name: "autoCodeEdit", Component: "view/systemTools/autoCode/index.vue", Sort: 0, Meta: Meta{Title: "自动化代码(复用)", Icon: "magic-stick"}},
{MenuLevel: 0, Hidden: false, ParentId: "14", Path: "autoPkg", Name: "autoPkg", Component: "view/systemTools/autoPkg/autoPkg.vue", Sort: 0, Meta: Meta{Title: "自动化package", Icon: "folder"}},
{MenuLevel: 0, Hidden: false, ParentId: "14", Path: "autoPlug", Name: "autoPlug", Component: "view/systemTools/autoPlug/autoPlug.vue", Sort: 4, Meta: Meta{Title: "自动化插件模板", Icon: "folder"}},
}
if err = db.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, SysBaseMenu{}.TableName()+"表数据初始化失败!")
......
......@@ -5,6 +5,7 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
sysModel "github.com/flipped-aurora/gin-vue-admin/server/model/system"
"github.com/flipped-aurora/gin-vue-admin/server/service/system"
"github.com/flipped-aurora/gin-vue-admin/server/utils"
"github.com/pkg/errors"
uuid "github.com/satori/go.uuid"
"gorm.io/gorm"
......@@ -44,9 +45,29 @@ func (i *initUser) InitializeData(ctx context.Context) (next context.Context, er
if !ok {
return ctx, system.ErrMissingDBContext
}
password := utils.BcryptHash("6447985")
adminPassword := utils.BcryptHash("123456")
entities := []sysModel.SysUser{
{UUID: uuid.NewV4(), Username: "admin", Password: "e10adc3949ba59abbe56e057f20f883e", NickName: "超级管理员", HeaderImg: "https://qmplusimg.henrongyi.top/gva_header.jpg", AuthorityId: "888", Phone: "17611111111", Email: "333333333@qq.com"},
{UUID: uuid.NewV4(), Username: "a303176530", Password: "3ec063004a6f31642261936a379fde3d", NickName: "QMPlusUser", HeaderImg: "https:///qmplusimg.henrongyi.top/1572075907logo.png", AuthorityId: "9528", Phone: "17611111111", Email: "333333333@qq.com"},
{
UUID: uuid.NewV4(),
Username: "admin",
Password: adminPassword,
NickName: "超级管理员",
HeaderImg: "https://qmplusimg.henrongyi.top/gva_header.jpg",
AuthorityId: "888",
Phone: "17611111111",
Email: "333333333@qq.com",
},
{
UUID: uuid.NewV4(),
Username: "a303176530",
Password: password,
NickName: "QMPlusUser",
HeaderImg: "https:///qmplusimg.henrongyi.top/1572075907logo.png",
AuthorityId: "9528",
Phone: "17611111111",
Email: "333333333@qq.com"},
}
if err = global.GVA_DB.Create(&entities).Error; err != nil {
return ctx, errors.Wrap(err, sysModel.SysUser{}.TableName()+"表数据初始化失败!")
......
package utils
import (
"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
}
......@@ -115,3 +115,12 @@ export const deletePackageApi = (data) => {
data
})
}
export const createPlugApi = (data) => {
return service({
url: '/autoCode/createPlug',
method: 'post',
data
})
}
......@@ -58,7 +58,14 @@ router.beforeEach(async(to, from, next) => {
if (!asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
asyncRouterFlag++
await getRouter(userStore)
next({ ...to, replace: true })
if (userStore.token) {
next({ ...to, replace: true })
} else {
next({
name: 'Login',
query: { redirect: to.href }
})
}
} else {
if (to.matched.length) {
next()
......
......@@ -85,17 +85,17 @@ service.interceptors.response.use(
error => {
closeLoading()
if(!error.response){
if (!error.response) {
ElMessageBox.confirm(`
<p>检测到请求错误</p>
<p>${error}</p>
`, '请求报错', {
dangerouslyUseHTMLString: true,
distinguishCancelAndClose: true,
confirmButtonText: '稍后重试',
cancelButtonText: '取消'
})
return
dangerouslyUseHTMLString: true,
distinguishCancelAndClose: true,
confirmButtonText: '稍后重试',
cancelButtonText: '取消'
})
return
}
switch (error.response.status) {
......
......@@ -200,15 +200,21 @@ const changeUserAuth = async(id) => {
}
const reloadFlag = ref(true)
let reloadTimer = null
const reload = async() => {
if (route.meta.keepAlive) {
reloadFlag.value = false
await nextTick()
reloadFlag.value = true
} else {
const title = route.meta.title
router.push({ name: 'Reload', params: { title }})
if (reloadTimer) {
window.clearTimeout(reloadTimer)
}
reloadTimer = window.setTimeout(async() => {
if (route.meta.keepAlive) {
reloadFlag.value = false
await nextTick()
reloadFlag.value = true
} else {
const title = route.meta.title
router.push({ name: 'Reload', params: { title }})
}
}, 400)
}
const isShadowBg = ref(false)
......
<template>
<div>
<div class="gva-table-box">
<el-form label-width="140px" class="plug-form">
<el-form-item label="插件名">
<el-input v-model="form.plugName" placeholder="必填(英文大写字母开头)" @blur="titleCase" />
</el-form-item>
<el-form-item label="路由组">
<el-input v-model="form.routerGroup" placeholder="将会作为插件路由组使用" />
</el-form-item>
<el-form-item label="使用全局属性">
<el-checkbox v-model="form.hasGlobal" />
</el-form-item>
<el-form-item v-if="form.hasGlobal" label="全局属性">
<div v-for="(i,k) in form.global" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.global)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.global,k)" />
</span>
</div>
</el-form-item>
<el-form-item label="使用Request">
<el-checkbox v-model="form.hasRequest" />
</el-form-item>
<el-form-item v-if="form.hasRequest" label="Request">
<div v-for="(i,k) in form.request" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.request)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.request,k)" />
</span>
</div>
</el-form-item>
<el-form-item label="使用Response">
<el-checkbox v-model="form.hasResponse" />
</el-form-item>
<el-form-item v-if="form.hasResponse" label="Response">
<div v-for="(i,k) in form.response" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.response)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.response,k)" />
</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="createPlug">创建</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import { toUpperCase } from '@/utils/stringFun'
import {
Plus,
Minus
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { createPlugApi } from '@/api/autoCode.js'
import { reactive } from 'vue'
const form = reactive({
plugName: '',
routerGroup: '',
hasGlobal: true,
hasRequest: true,
hasResponse: true,
global: [{
key: '',
type: '',
desc: '',
}],
request: [{
key: '',
type: '',
desc: '',
}],
response: [{
key: '',
type: '',
desc: '',
}]
})
const titleCase = () => {
form.plugName = toUpperCase(form.plugName)
}
const createPlug = async() => {
if (!form.plugName || !form.routerGroup) {
ElMessage.error('插件名称和插件路由组为必填项')
return
}
if (form.hasGlobal) {
const intercept = form.global.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('全局属性的key和type为必填项')
return
}
}
if (form.hasRequest) {
const intercept = form.request.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('请求属性的key和type为必填项')
return
}
}
if (form.hasResponse) {
const intercept = form.response.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('响应属性的key和type为必填项')
return
}
}
const res = await createPlugApi(form)
if (res.code === 0) {
ElMessageBox('创建成功,插件已自动写入后端plugin目录下,请按照自己的逻辑进行创造')
}
}
const addkv = (arr) => {
arr.push({
key: '',
value: '',
})
}
const minkv = (arr, key) => {
if (arr.length === 1) {
ElMessage.warning('至少有一个全局属性')
return
}
arr.splice(key, 1)
}
</script>
<style lang="scss" scoped>
.plug-form{
width: 680px;
}
.plug-row{
display: flex;
align-items: center;
width: 100%;
&+&{
margin-top: 12px;
}
&>span{
margin-left: 8px;
}
}
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册