Quellcode durchsuchen

Merge branch 'gva_gormv2_dev' of https://github.com/flipped-aurora/gin-vue-admin into gva_gormv2_dev

SliverHorn vor 4 Jahren
Ursprung
Commit
2414eb2cba
38 geänderte Dateien mit 618 neuen und 499 gelöschten Zeilen
  1. 8 3
      README.md
  2. 3 1
      server/Makefile
  3. 4 4
      server/api/v1/sys_user.go
  4. 2 0
      server/config.yaml
  5. 3 1
      server/config/jwt.go
  6. 2 2
      server/go.mod
  7. 16 29
      server/initialize/gorm.go
  8. 76 61
      server/initialize/internal/logger.go
  9. 1 1
      server/middleware/jwt.go
  10. 1 1
      server/model/request/common.go
  11. 1 1
      server/model/sys_workflow.go
  12. 1 1
      server/resource/template/server/service.go.tpl
  13. 6 0
      server/resource/template/web/table.vue.tpl
  14. 1 1
      server/service/exa_customer.go
  15. 2 2
      server/service/exa_file_upload_download.go
  16. 1 1
      server/service/jwt_black_list.go
  17. 1 1
      server/service/sys_api.go
  18. 1 1
      server/service/sys_dictionary.go
  19. 1 1
      server/service/sys_dictionary_detail.go
  20. 1 1
      server/service/sys_operation_record.go
  21. 5 5
      server/service/sys_workflow.go
  22. 18 0
      web/build.config.js
  23. 0 1
      web/debug.log
  24. 88 61
      web/package-lock.json
  25. 4 4
      web/public/index.html
  26. 1 0
      web/src/store/module/user.js
  27. 5 2
      web/src/view/example/customer/customer.vue
  28. 22 34
      web/src/view/example/upload/upload.vue
  29. 13 19
      web/src/view/login/login.vue
  30. 105 97
      web/src/view/superAdmin/api/api.vue
  31. 8 5
      web/src/view/superAdmin/authority/authority.vue
  32. 112 99
      web/src/view/superAdmin/dictionary/sysDictionary.vue
  33. 11 9
      web/src/view/superAdmin/dictionary/sysDictionaryDetail.vue
  34. 5 2
      web/src/view/superAdmin/menu/menu.vue
  35. 44 38
      web/src/view/superAdmin/operation/sysOperationRecord.vue
  36. 0 1
      web/src/view/superAdmin/user/user.vue
  37. 20 4
      web/src/view/workflow/workflowProcess/workflowProcess.vue
  38. 25 5
      web/vue.config.js

+ 8 - 3
README.md

@@ -12,8 +12,11 @@
 
 [English](./README-en.md) | 简体中文
 
-[gitee地址](https://gitee.com/pixelmax/gin-vue-admin)|
-[github地址](https://github.com/flipped-aurora/gin-vue-admin)
+[gitee地址:https://gitee.com/pixelmax/gin-vue-admin](https://gitee.com/pixelmax/gin-vue-admin)
+
+[github地址:https://github.com/flipped-aurora/gin-vue-admin](https://github.com/flipped-aurora/gin-vue-admin)
+
+[vue3版本分支地址:https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop](https://github.com/flipped-aurora/gin-vue-admin/tree/vue3Develop)
 
 # 项目文档
 [在线文档](https://www.gin-vue-admin.com/) : https://www.gin-vue-admin.com/
@@ -72,7 +75,7 @@ Gin-vue-admin 的成长离不开大家的支持,如果你愿意为 gin-vue-adm
 - node版本 > v8.6.0
 - golang版本 >= v1.14
 - IDE推荐:Goland
-- gormv2版本初始化数据库可以利用批量创建功能,这里已经写好初始化代码,需要在main.go内打开 initialize.Data() 的注释即可
+- 初始化项目: 不同版本数据库初始化不通 参见https://www.gin-vue-admin.com/docs/server#1-%E5%88%9D%E5%A7%8B%E5%8C%96server%E9%A1%B9%E7%9B%AE
 - 替换掉项目中的七牛云公钥,私钥,仓名和默认url地址,以免发生测试文件数据错乱
 ```
 
@@ -160,6 +163,8 @@ npm run serve
 
 ### 2.2 server端
 
+使用 goland等编辑工具,打开server目录,不可以打开 gin-vue-admin跟目录
+
 ```bash
 # 使用 go.mod
 

+ 3 - 1
server/Makefile

@@ -1,11 +1,13 @@
 .PHONY: all build run gotool clean help
 
-BINARY="server"
+BINARY="gin-vue-admin"
 GVA = "gva"
 
 all: check gva initdb run
 
 gva:
+	go env -w GO111MODULE=on
+    go env -w GOPROXY=https://goproxy.io,direct
 	go build -o ${GVA} cmd/main.go
 
 initdb:

+ 4 - 4
server/api/v1/sys_user.go

@@ -50,11 +50,11 @@ func tokenNext(c *gin.Context, user model.SysUser) {
 		NickName:    user.NickName,
 		Username:    user.Username,
 		AuthorityId: user.AuthorityId,
-		BufferTime:  60 * 60 * 24, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
+		BufferTime:  global.GVA_CONFIG.JWT.BufferTime, // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
 		StandardClaims: jwt.StandardClaims{
-			NotBefore: time.Now().Unix() - 1000,       // 签名生效时间
-			ExpiresAt: time.Now().Unix() + 60*60*24*7, // 过期时间 7天
-			Issuer:    "qmPlus",                       // 签名的发行者
+			NotBefore: time.Now().Unix() - 1000,                              // 签名生效时间
+			ExpiresAt: time.Now().Unix() + global.GVA_CONFIG.JWT.ExpiresTime, // 过期时间 7天  配置文件
+			Issuer:    "qmPlus",                                              // 签名的发行者
 		},
 	}
 	token, err := j.CreateToken(claims)

+ 2 - 0
server/config.yaml

@@ -3,6 +3,8 @@
 # jwt configuration
 jwt:
   signing-key: 'qmPlus'
+  expires-time: 604800
+  buffer-time: 86400
 
 # zap logger configuration
 zap:

+ 3 - 1
server/config/jwt.go

@@ -1,5 +1,7 @@
 package config
 
 type JWT struct {
-	SigningKey string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
+	SigningKey  string `mapstructure:"signing-key" json:"signingKey" yaml:"signing-key"`
+	ExpiresTime int64  `mapstructure:"expires-time" json:"expiresTime" yaml:"expires-time"`
+	BufferTime  int64  `mapstructure:"buffer-time" json:"bufferTime" yaml:"buffer-time"`
 }

+ 2 - 2
server/go.mod

@@ -54,7 +54,7 @@ require (
 	gopkg.in/ini.v1 v1.55.0 // indirect
 	gopkg.in/yaml.v2 v2.3.0 // indirect
 	gorm.io/driver/mysql v0.3.0
-	gorm.io/gorm v1.20.5
+	gorm.io/gorm v1.20.9
 )
 
-replace github.com/casbin/gorm-adapter/v3 => github.com/casbin/gorm-adapter/v3 v3.0.2
+replace github.com/casbin/gorm-adapter/v3 => github.com/casbin/gorm-adapter/v3 v3.0.2

+ 16 - 29
server/initialize/gorm.go

@@ -2,6 +2,7 @@ package initialize
 
 import (
 	"gin-vue-admin/global"
+	"gin-vue-admin/initialize/internal"
 	"gin-vue-admin/model"
 	"go.uber.org/zap"
 	"gorm.io/driver/mysql"
@@ -97,38 +98,24 @@ func GormMysql() *gorm.DB {
 //@return: *gorm.Config
 
 func gormConfig(mod bool) *gorm.Config {
+	var config = &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}
 	switch global.GVA_CONFIG.Mysql.LogZap {
-	case "Silent":
-		return &gorm.Config{
-			Logger:                                   Default.LogMode(logger.Silent),
-			DisableForeignKeyConstraintWhenMigrating: true,
-		}
-	case "Error":
-		return &gorm.Config{
-			Logger:                                   Default.LogMode(logger.Error),
-			DisableForeignKeyConstraintWhenMigrating: true,
-		}
-	case "Warn":
-		return &gorm.Config{
-			Logger:                                   Default.LogMode(logger.Warn),
-			DisableForeignKeyConstraintWhenMigrating: true,
-		}
-	case "Info":
-		return &gorm.Config{
-			Logger:                                   Default.LogMode(logger.Info),
-			DisableForeignKeyConstraintWhenMigrating: true,
-		}
+	case "silent", "Silent":
+		config.Logger = internal.Default.LogMode(logger.Silent)
+	case "error", "Error":
+		config.Logger = internal.Default.LogMode(logger.Error)
+	case "warn", "Warn":
+		config.Logger = internal.Default.LogMode(logger.Warn)
+	case "info", "Info":
+		config.Logger = internal.Default.LogMode(logger.Info)
+	case "zap", "Zap":
+		config.Logger = internal.Default.LogMode(logger.Info)
 	default:
 		if mod {
-			return &gorm.Config{
-				Logger:                                   logger.Default.LogMode(logger.Info),
-				DisableForeignKeyConstraintWhenMigrating: true,
-			}
-		} else {
-			return &gorm.Config{
-				Logger:                                   logger.Default.LogMode(logger.Silent),
-				DisableForeignKeyConstraintWhenMigrating: true,
-			}
+			config.Logger = internal.Default.LogMode(logger.Info)
+			break
 		}
+		config.Logger = internal.Default.LogMode(logger.Silent)
 	}
+	return config
 }

+ 76 - 61
server/initialize/logger.go → server/initialize/internal/logger.go

@@ -1,4 +1,4 @@
-package initialize
+package internal
 
 import (
 	"context"
@@ -13,9 +13,20 @@ import (
 	"time"
 )
 
+// writer log writer interface
+type writer interface {
+	Printf(string, ...interface{})
+}
+
+type config struct {
+	SlowThreshold time.Duration
+	Colorful      bool
+	LogLevel      logger.LogLevel
+}
+
 var (
-	Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), log.New(ioutil.Discard, "", log.LstdFlags), GormConfig{})
-	Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), log.New(os.Stdout, "\r\n", log.LstdFlags), GormConfig{
+	Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), config{})
+	Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), config{
 		SlowThreshold: 200 * time.Millisecond,
 		LogLevel:      logger.Warn,
 		Colorful:      true,
@@ -23,15 +34,7 @@ var (
 	Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
 )
 
-type traceRecorder struct {
-	logger.Interface
-	BeginAt      time.Time
-	SQL          string
-	RowsAffected int64
-	Err          error
-}
-
-func New(writer Writer, gormWriter logger.Writer, config GormConfig) logger.Interface {
+func New(writer writer, config config) logger.Interface {
 	var (
 		infoStr      = "%s\n[info] "
 		warnStr      = "%s\n[warn] "
@@ -50,10 +53,9 @@ func New(writer Writer, gormWriter logger.Writer, config GormConfig) logger.Inte
 		traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
 	}
 
-	return &GormLogger{
-		Writer:       writer,
-		gormWriter:   gormWriter,
-		GormConfig:   config,
+	return &customLogger{
+		writer:       writer,
+		config:       config,
 		infoStr:      infoStr,
 		warnStr:      warnStr,
 		errStr:       errStr,
@@ -63,81 +65,74 @@ func New(writer Writer, gormWriter logger.Writer, config GormConfig) logger.Inte
 	}
 }
 
-// Writer log writer interface
-type Writer interface {
-	Printf(string, ...interface{})
-}
-
-type GormConfig struct {
-	SlowThreshold time.Duration
-	Colorful      bool
-	LogLevel      logger.LogLevel
-}
-
-type GormLogger struct {
-	Writer
-	gormWriter logger.Writer
-	GormConfig
+type customLogger struct {
+	writer
+	config
 	infoStr, warnStr, errStr            string
 	traceStr, traceErrStr, traceWarnStr string
 }
 
-func (g *GormLogger) LogMode(level logger.LogLevel) logger.Interface {
-	newLogger := *g
+// LogMode log mode
+func (c *customLogger) LogMode(level logger.LogLevel) logger.Interface {
+	newLogger := *c
 	newLogger.LogLevel = level
 	return &newLogger
 }
 
-func (g *GormLogger) Info(ctx context.Context, message string, data ...interface{}) {
-	if g.LogLevel >= logger.Info {
-		g.Printf(g.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
+// Info print info
+func (c *customLogger) Info(ctx context.Context, message string, data ...interface{}) {
+	if c.LogLevel >= logger.Info {
+		c.Printf(c.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
 	}
 }
 
-func (g *GormLogger) Warn(ctx context.Context, message string, data ...interface{}) {
-	if g.LogLevel >= logger.Warn {
-		g.Printf(g.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
+// Warn print warn messages
+func (c *customLogger) Warn(ctx context.Context, message string, data ...interface{}) {
+	if c.LogLevel >= logger.Warn {
+		c.Printf(c.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
 	}
 }
 
-func (g *GormLogger) Error(ctx context.Context, message string, data ...interface{}) {
-	if g.LogLevel >= logger.Error {
-		g.Printf(g.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
+// Error print error messages
+func (c *customLogger) Error(ctx context.Context, message string, data ...interface{}) {
+	if c.LogLevel >= logger.Error {
+		c.Printf(c.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
 	}
 }
 
-func (g *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
-	if g.LogLevel > 0 {
+// Trace print sql message
+func (c *customLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
+	if c.LogLevel > 0 {
 		elapsed := time.Since(begin)
 		switch {
-		case err != nil && g.LogLevel >= logger.Error:
+		case err != nil && c.LogLevel >= logger.Error:
 			sql, rows := fc()
 			if rows == -1 {
-				g.Printf(g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
+				c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
 			} else {
-				g.Printf(g.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
+				c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
 			}
-		case elapsed > g.SlowThreshold && g.SlowThreshold != 0 && g.LogLevel >= logger.Warn:
+		case elapsed > c.SlowThreshold && c.SlowThreshold != 0 && c.LogLevel >= logger.Warn:
 			sql, rows := fc()
-			slowLog := fmt.Sprintf("SLOW SQL >= %v", g.SlowThreshold)
+			slowLog := fmt.Sprintf("SLOW SQL >= %v", c.SlowThreshold)
 			if rows == -1 {
-				g.Printf(g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
+				c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
 			} else {
-				g.Printf(g.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
+				c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
 			}
-		case g.LogLevel >= logger.Info:
+		case c.LogLevel >= logger.Info:
 			sql, rows := fc()
 			if rows == -1 {
-				g.Printf(g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
+				c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
 			} else {
-				g.Printf(g.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
+				c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
 			}
 		}
 	}
 }
 
-func (g *GormLogger) Printf(message string, data ...interface{}) {
-	if global.GVA_CONFIG.Mysql.LogZap == "Info" && !global.GVA_CONFIG.Mysql.LogMode {
+func (c *customLogger) Printf(message string, data ...interface{}) {
+	if global.GVA_CONFIG.Mysql.LogZap != "" {
 		switch len(data) {
 		case 0:
 			global.GVA_LOG.Info(message)
@@ -154,14 +149,34 @@ func (g *GormLogger) Printf(message string, data ...interface{}) {
 	}
 	switch len(data) {
 	case 0:
-		g.gormWriter.Printf(message, "")
+		c.writer.Printf(message, "")
 	case 1:
-		g.gormWriter.Printf(message, data[0].(string))
+		c.writer.Printf(message, data[0])
 	case 2:
-		g.gormWriter.Printf(message, data[0].(string), data[1].(float64))
+		c.writer.Printf(message, data[0], data[1])
 	case 3:
-		g.gormWriter.Printf(message, data[0].(string), data[1].(float64), data[2].(string))
+		c.writer.Printf(message, data[0], data[1], data[2])
 	case 4:
-		g.gormWriter.Printf(message, data[0].(string), data[1].(float64), data[2].(string), data[3].(string))
+		c.writer.Printf(message, data[0], data[1], data[2], data[3])
+	case 5:
+		c.writer.Printf(message, data[0], data[1], data[2], data[3], data[4])
 	}
 }
+
+type traceRecorder struct {
+	logger.Interface
+	BeginAt      time.Time
+	SQL          string
+	RowsAffected int64
+	Err          error
+}
+
+func (t traceRecorder) New() *traceRecorder {
+	return &traceRecorder{Interface: t.Interface, BeginAt: time.Now()}
+}
+
+func (t *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
+	t.BeginAt = begin
+	t.SQL, t.RowsAffected = fc()
+	t.Err = err
+}

+ 1 - 1
server/middleware/jwt.go

@@ -47,7 +47,7 @@ func JWTAuth() gin.HandlerFunc {
 			c.Abort()
 		}
 		if claims.ExpiresAt-time.Now().Unix() < claims.BufferTime {
-			claims.ExpiresAt = time.Now().Unix() + 60*60*24*7
+			claims.ExpiresAt = time.Now().Unix() + global.GVA_CONFIG.JWT.ExpiresTime
 			newToken, _ := j.CreateToken(*claims)
 			newClaims, _ := j.ParseToken(newToken)
 			c.Header("new-token", newToken)

+ 1 - 1
server/model/request/common.go

@@ -20,4 +20,4 @@ type GetAuthorityId struct {
 	AuthorityId string
 }
 
-type Empty struct {}
+type Empty struct{}

+ 1 - 1
server/model/sys_workflow.go

@@ -110,7 +110,7 @@ type WorkflowNode struct {
 	Cycle             string         `json:"cycle" gorm:"comment:循环时间"`
 	Duration          string         `json:"duration" gorm:"comment:持续时间"`
 	HideIcon          bool           `json:"hideIcon" gorm:"comment:是否隐藏图标"`
-	DueDate           time.Time      `json:"dueDate" gorm:"comment:到期时间"`
+	DueDate           *time.Time     `json:"dueDate" gorm:"comment:到期时间"`
 	AssignType        string         `json:"assignType" gorm:"comment:审批类型"`
 	AssignValue       string         `json:"assignValue" gorm:"comment:审批类型值"`
 	Success           bool           `json:"success" gorm:"comment:是否成功"`

+ 1 - 1
server/resource/template/server/service.go.tpl

@@ -24,7 +24,7 @@ func Create{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error)
 //@return: err error
 
 func Delete{{.StructName}}({{.Abbreviation}} model.{{.StructName}}) (err error) {
-	err = global.GVA_DB.Delete({{.Abbreviation}}).Error
+	err = global.GVA_DB.Delete(&{{.Abbreviation}}).Error
 	return err
 }
 

+ 6 - 0
server/resource/template/web/table.vue.tpl

@@ -227,6 +227,9 @@ export default {
             type: 'success',
             message: '删除成功'
           })
+          if (this.tableData.length == ids.length) {
+              this.page--;
+          }
           this.deleteVisible = false
           this.getTableData()
         }
@@ -269,6 +272,9 @@ export default {
           type: "success",
           message: "删除成功"
         });
+        if (this.tableData.length == 1) {
+            this.page--;
+        }
         this.getTableData();
       }
     },

+ 1 - 1
server/service/exa_customer.go

@@ -24,7 +24,7 @@ func CreateExaCustomer(e model.ExaCustomer) (err error) {
 //@return: err error
 
 func DeleteExaCustomer(e model.ExaCustomer) (err error) {
-	err = global.GVA_DB.Delete(e).Error
+	err = global.GVA_DB.Delete(&e).Error
 	return err
 }
 

+ 2 - 2
server/service/exa_file_upload_download.go

@@ -42,10 +42,10 @@ func DeleteFile(file model.ExaFileUploadAndDownload) (err error) {
 	var fileFromDb model.ExaFileUploadAndDownload
 	err, fileFromDb = FindFile(file.ID)
 	oss := upload.NewOss()
-	if err = oss.DeleteFile(fileFromDb.Key); err != nil{
+	if err = oss.DeleteFile(fileFromDb.Key); err != nil {
 		return errors.New("文件删除失败")
 	}
-	err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(file).Error
+	err = global.GVA_DB.Where("id = ?", file.ID).Unscoped().Delete(&file).Error
 	return err
 }
 

+ 1 - 1
server/service/jwt_black_list.go

@@ -49,7 +49,7 @@ func GetRedisJWT(userName string) (err error, redisJWT string) {
 
 func SetRedisJWT(jwt string, userName string) (err error) {
 	// 此处过期时间等于jwt过期时间
-	timer := 60 * 60 * 24 * 7 * time.Second
+	timer := time.Duration(global.GVA_CONFIG.JWT.ExpiresTime) * time.Second
 	err = global.GVA_REDIS.Set(userName, jwt, timer).Err()
 	return err
 }

+ 1 - 1
server/service/sys_api.go

@@ -28,7 +28,7 @@ func CreateApi(api model.SysApi) (err error) {
 //@return: err error
 
 func DeleteApi(api model.SysApi) (err error) {
-	err = global.GVA_DB.Delete(api).Error
+	err = global.GVA_DB.Delete(&api).Error
 	ClearCasbin(1, api.Path, api.Method)
 	return err
 }

+ 1 - 1
server/service/sys_dictionary.go

@@ -29,7 +29,7 @@ func CreateSysDictionary(sysDictionary model.SysDictionary) (err error) {
 //@return: err error
 
 func DeleteSysDictionary(sysDictionary model.SysDictionary) (err error) {
-	err = global.GVA_DB.Delete(sysDictionary).Delete(&sysDictionary.SysDictionaryDetails).Error
+	err = global.GVA_DB.Delete(&sysDictionary).Delete(&sysDictionary.SysDictionaryDetails).Error
 	return err
 }
 

+ 1 - 1
server/service/sys_dictionary_detail.go

@@ -24,7 +24,7 @@ func CreateSysDictionaryDetail(sysDictionaryDetail model.SysDictionaryDetail) (e
 //@return: err error
 
 func DeleteSysDictionaryDetail(sysDictionaryDetail model.SysDictionaryDetail) (err error) {
-	err = global.GVA_DB.Delete(sysDictionaryDetail).Error
+	err = global.GVA_DB.Delete(&sysDictionaryDetail).Error
 	return err
 }
 

+ 1 - 1
server/service/sys_operation_record.go

@@ -36,7 +36,7 @@ func DeleteSysOperationRecordByIds(ids request.IdsReq) (err error) {
 //@return: err error
 
 func DeleteSysOperationRecord(sysOperationRecord model.SysOperationRecord) (err error) {
-	err = global.GVA_DB.Delete(sysOperationRecord).Error
+	err = global.GVA_DB.Delete(&sysOperationRecord).Error
 	return err
 }
 

+ 5 - 5
server/service/sys_workflow.go

@@ -36,12 +36,12 @@ func CreateWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
 func DeleteWorkflowProcess(workflowProcess model.WorkflowProcess) (err error) {
 	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 		var txErr error
-		txErr = tx.Delete(workflowProcess).Error
+		txErr = tx.Delete(&workflowProcess).Error
 		if txErr != nil {
 			return txErr
 		}
 		var edges []model.WorkflowEdge
-		txErr = tx.Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
+		txErr = tx.Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
 		if txErr != nil {
 			return txErr
 		}
@@ -86,7 +86,7 @@ func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
 		if txErr != nil {
 			return txErr
 		}
-		txErr = tx.Unscoped().Delete(model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
+		txErr = tx.Unscoped().Delete(&model.WorkflowNode{}, "workflow_process_id = ?", workflowProcess.ID).Error
 		if txErr != nil {
 			return txErr
 		}
@@ -101,11 +101,11 @@ func UpdateWorkflowProcess(workflowProcess *model.WorkflowProcess) (err error) {
 		for _, v := range edges {
 			edgesIds = append(edgesIds, v.ID)
 		}
-		txErr = tx.Unscoped().Delete(model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
+		txErr = tx.Unscoped().Delete(&model.WorkflowStartPoint{}, "workflow_edge_id in ?", edgesIds).Error
 		if txErr != nil {
 			return txErr
 		}
-		txErr = tx.Unscoped().Delete(model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
+		txErr = tx.Unscoped().Delete(&model.WorkflowEndPoint{}, "workflow_edge_id in ?", edgesIds).Error
 		if txErr != nil {
 			return txErr
 		}

+ 18 - 0
web/build.config.js

@@ -0,0 +1,18 @@
+'use strict'
+
+module.exports = {
+    title: 'GIN-VUE-ADMIN1',
+    baseCdnUrl: '//cdn.staticfile.org',
+    cdns: [
+        /**
+         * 如果设置path属性, { name: 'vue', scope: 'Vue', path: '/vue/2.6.9/vue.min.js' } 即编译出来以[baseCdnUrl][path]
+         * 否则自动拼写 [baseCdnUrl]/[name]/[version]/[name].min.js
+         * */ 
+        { name: 'vue', scope: 'Vue' },
+        { name: 'vue-router', scope: 'VueRouter' },
+        { name: 'vuex', scope: 'Vuex' },
+        { name: 'axios', scope: 'axios' },
+        { name: 'echarts', scope: 'echarts' },
+        { name: 'element-ui', scope: 'ELEMENT',  path: '/element-ui/2.12.0/index.js'},
+    ]
+};

+ 0 - 1
web/debug.log

@@ -1 +0,0 @@
-[1110/113210.377:ERROR:directory_reader_win.cc(43)] FindFirstFile: 系统找不到指定的路径。 (0x3)

+ 88 - 61
web/package-lock.json

@@ -3449,13 +3449,6 @@
                     "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=",
                     "dev": true
                 },
-                "emojis-list": {
-                    "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-                    "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
-                    "dev": true,
-                    "optional": true
-                },
                 "fast-deep-equal": {
                     "version": "3.1.3",
                     "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz?cache=0&sync_timestamp=1591599659970&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-deep-equal%2Fdownload%2Ffast-deep-equal-3.1.3.tgz",
@@ -3483,31 +3476,12 @@
                         "path-exists": "^4.0.0"
                     }
                 },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true,
-                    "optional": true
-                },
                 "is-fullwidth-code-point": {
                     "version": "3.0.0",
                     "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz",
                     "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=",
                     "dev": true
                 },
-                "loader-utils": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-                    "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
-                    "dev": true,
-                    "optional": true,
-                    "requires": {
-                        "big.js": "^5.2.2",
-                        "emojis-list": "^3.0.0",
-                        "json5": "^2.1.2"
-                    }
-                },
                 "locate-path": {
                     "version": "5.0.0",
                     "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-5.0.0.tgz",
@@ -3673,16 +3647,6 @@
                         "ansi-regex": "^5.0.0"
                     }
                 },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "optional": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                },
                 "terser": {
                     "version": "4.8.0",
                     "resolved": "https://registry.npm.taobao.org/terser/download/terser-4.8.0.tgz?cache=0&sync_timestamp=1599751633316&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fterser%2Fdownload%2Fterser-4.8.0.tgz",
@@ -3721,31 +3685,6 @@
                         "punycode": "^2.1.1"
                     }
                 },
-                "vue-loader-v16": {
-                    "version": "npm:[email protected]",
-                    "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.1.1.tgz",
-                    "integrity": "sha512-wz/+HFg/3SBayHWAlZXARcnDTl3VOChrfW9YnxvAweiuyKX/7IGx1ad/4yJHmwhgWlOVYMAbTiI7GV8G33PfGQ==",
-                    "dev": true,
-                    "optional": true,
-                    "requires": {
-                        "chalk": "^4.1.0",
-                        "hash-sum": "^2.0.0",
-                        "loader-utils": "^2.0.0"
-                    },
-                    "dependencies": {
-                        "chalk": {
-                            "version": "4.1.0",
-                            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-                            "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
-                            "dev": true,
-                            "optional": true,
-                            "requires": {
-                                "ansi-styles": "^4.1.0",
-                                "supports-color": "^7.1.0"
-                            }
-                        }
-                    }
-                },
                 "wrap-ansi": {
                     "version": "6.2.0",
                     "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz",
@@ -14998,6 +14937,94 @@
                 }
             }
         },
+        "vue-loader-v16": {
+            "version": "npm:[email protected]",
+            "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.1.1.tgz",
+            "integrity": "sha512-wz/+HFg/3SBayHWAlZXARcnDTl3VOChrfW9YnxvAweiuyKX/7IGx1ad/4yJHmwhgWlOVYMAbTiI7GV8G33PfGQ==",
+            "dev": true,
+            "optional": true,
+            "requires": {
+                "chalk": "^4.1.0",
+                "hash-sum": "^2.0.0",
+                "loader-utils": "^2.0.0"
+            },
+            "dependencies": {
+                "ansi-styles": {
+                    "version": "4.3.0",
+                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "color-convert": "^2.0.1"
+                    }
+                },
+                "chalk": {
+                    "version": "4.1.0",
+                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+                    "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "ansi-styles": "^4.1.0",
+                        "supports-color": "^7.1.0"
+                    }
+                },
+                "color-convert": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "color-name": "~1.1.4"
+                    }
+                },
+                "color-name": {
+                    "version": "1.1.4",
+                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+                    "dev": true,
+                    "optional": true
+                },
+                "emojis-list": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+                    "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+                    "dev": true,
+                    "optional": true
+                },
+                "has-flag": {
+                    "version": "4.0.0",
+                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+                    "dev": true,
+                    "optional": true
+                },
+                "loader-utils": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
+                    "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "big.js": "^5.2.2",
+                        "emojis-list": "^3.0.0",
+                        "json5": "^2.1.2"
+                    }
+                },
+                "supports-color": {
+                    "version": "7.2.0",
+                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+                    "dev": true,
+                    "optional": true,
+                    "requires": {
+                        "has-flag": "^4.0.0"
+                    }
+                }
+            }
+        },
         "vue-particle-line": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/vue-particle-line/-/vue-particle-line-0.1.4.tgz",

+ 4 - 4
web/public/index.html

@@ -7,11 +7,11 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title>GIN-VUE-ADMIN</title>
+    <title><%=htmlWebpackPlugin.options.title%></title>
     <% if(process.env.NODE_ENV!=='development'){ %>
-    <script src="//cdn.staticfile.org/vue/2.6.10/vue.min.js"></script>
-    <script src="//cdn.staticfile.org/axios/0.19.0/axios.min.js"></script>
-    <script src="//cdn.staticfile.org/echarts/4.7.0/echarts.min.js"></script>    
+      <% htmlWebpackPlugin.options.cdns.forEach(function(item){ if(item.js){ %>
+        <script type="text/javascript" src="<%= item.js %>"></script>
+      <% } }) %>
     <% } %>  
 </head>
 

+ 1 - 0
web/src/store/module/user.js

@@ -46,6 +46,7 @@ export const user = {
                 } else {
                     router.push({ path: '/layout/dashboard' })
                 }
+                return true
             }
         },
         async LoginOut({ commit }) {

+ 5 - 2
web/src/view/example/customer/customer.vue

@@ -62,7 +62,7 @@
         <el-button @click="enterDialog" type="primary">确 定</el-button>
       </div>
     </el-dialog>
-    <div class="tips"> 在资源权限中将此角色的资源权限清空 或者不包含创建者的角色 即可屏蔽此客户资源的显示</div>
+    <div class="tips">在资源权限中将此角色的资源权限清空 或者不包含创建者的角色 即可屏蔽此客户资源的显示</div>
   </div>
 </template>
 
@@ -124,8 +124,11 @@ export default {
       if (res.code == 0) {
         this.$message({
           type: "success",
-          message: "删除成功"
+          message: ""
         });
+        if (this.tableData.length == 1) {
+          this.page--;
+        }
         this.getTableData();
       }
     },

+ 22 - 34
web/src/view/example/upload/upload.vue

@@ -12,9 +12,7 @@
             :show-file-list="false"
           >
             <el-button size="small" type="primary">点击上传</el-button>
-            <div class="el-upload__tip" slot="tip">
-              只能上传jpg/png文件,且不超过500kb
-            </div>
+            <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
           </el-upload>
         </el-col>
         <el-col :span="12">
@@ -35,33 +33,20 @@
             <div>{{ scope.row.UpdatedAt | formatDate }}</div>
           </template>
         </el-table-column>
-        <el-table-column
-          label="文件名"
-          prop="name"
-          width="180"
-        ></el-table-column>
-        <el-table-column
-          label="链接"
-          prop="url"
-          min-width="300"
-        ></el-table-column>
+        <el-table-column label="文件名" prop="name" width="180"></el-table-column>
+        <el-table-column label="链接" prop="url" min-width="300"></el-table-column>
         <el-table-column label="标签" prop="tag" width="100">
           <template slot-scope="scope">
             <el-tag
               :type="scope.row.tag === 'jpg' ? 'primary' : 'success'"
               disable-transitions
-              >{{ scope.row.tag }}</el-tag
-            >
+            >{{ scope.row.tag }}</el-tag>
           </template>
         </el-table-column>
         <el-table-column label="操作" width="160">
           <template slot-scope="scope">
-            <el-button @click="downloadFile(scope.row)" size="small" type="text"
-              >下载</el-button
-            >
-            <el-button @click="deleteFile(scope.row)" size="small" type="text"
-              >删除</el-button
-            >
+            <el-button @click="downloadFile(scope.row)" size="small" type="text">下载</el-button>
+            <el-button @click="deleteFile(scope.row)" size="small" type="text">删除</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -93,7 +78,7 @@ export default {
   mixins: [infoList],
   components: {
     CustomPic,
-    UploadImage,
+    UploadImage
   },
   data() {
     return {
@@ -101,43 +86,46 @@ export default {
       listApi: getFileList,
       path: path,
       tableData: [],
-      imageUrl: "",
+      imageUrl: ""
     };
   },
   computed: {
-    ...mapGetters("user", ["userInfo", "token"]),
+    ...mapGetters("user", ["userInfo", "token"])
   },
   filters: {
-    formatDate: function (time) {
+    formatDate: function(time) {
       if (time != null && time != "") {
         var date = new Date(time);
         return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
       } else {
         return "";
       }
-    },
+    }
   },
   methods: {
     async deleteFile(row) {
       this.$confirm("此操作将永久文件, 是否继续?", "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
-        type: "warning",
+        type: "warning"
       })
         .then(async () => {
           const res = await deleteFile(row);
           if (res.code == 0) {
             this.$message({
               type: "success",
-              message: "删除成功!",
+              message: "删除成功!"
             });
+            if (this.tableData.length == 1) {
+              this.page--;
+            }
             this.getTableData();
           }
         })
         .catch(() => {
           this.$message({
             type: "info",
-            message: "已取消删除",
+            message: "已取消删除"
           });
         });
     },
@@ -161,7 +149,7 @@ export default {
       if (res.code == 0) {
         this.$message({
           type: "success",
-          message: "上传成功",
+          message: "上传成功"
         });
         if (res.code == 0) {
           this.getTableData();
@@ -169,23 +157,23 @@ export default {
       } else {
         this.$message({
           type: "warning",
-          message: res.msg,
+          message: res.msg
         });
       }
     },
     uploadError() {
       this.$message({
         type: "error",
-        message: "上传失败",
+        message: "上传失败"
       });
       this.fullscreenLoading = false;
     },
     downloadFile(row) {
       downloadImage(row.url, row.name);
-    },
+    }
   },
   created() {
     this.getTableData();
-  },
+  }
 };
 </script>

+ 13 - 19
web/src/view/login/login.vue

@@ -20,14 +20,9 @@
           @keyup.enter.native="submitForm"
         >
           <el-form-item prop="username">
-            <el-input
-              placeholder="请输入用户名"
-              v-model="loginForm.username"
-            >
-            <i
-                class="el-input__icon el-icon-user"
-                slot="suffix"
-              ></i></el-input>
+            <el-input placeholder="请输入用户名" v-model="loginForm.username">
+              <i class="el-input__icon el-icon-user" slot="suffix"></i
+            ></el-input>
           </el-form-item>
           <el-form-item prop="password">
             <el-input
@@ -42,12 +37,12 @@
               ></i>
             </el-input>
           </el-form-item>
-          <el-form-item style="position:relative">
+          <el-form-item style="position: relative">
             <el-input
               v-model="loginForm.captcha"
               name="logVerify"
               placeholder="请输入验证码"
-              style="width:60%"
+              style="width: 60%"
             />
             <div class="vPic">
               <img
@@ -61,7 +56,7 @@
             </div>
           </el-form-item>
           <el-form-item>
-            <el-button type="primary" @click="submitForm" style="width:100%"
+            <el-button type="primary" @click="submitForm" style="width: 100%"
               >登 录</el-button
             >
           </el-form-item>
@@ -83,9 +78,7 @@
             ><img src="@/assets/video.png" class="link-icon"
           /></a>
         </div>
-        <div class="copyright">
-          Copyright &copy; {{ curYear }} 💖flipped-aurora
-        </div>
+        <div class="copyright">Copyright &copy; {{ curYear }} 💖flipped-aurora</div>
       </div>
     </div>
   </div>
@@ -135,13 +128,15 @@ export default {
   methods: {
     ...mapActions("user", ["LoginIn"]),
     async login() {
-      await this.LoginIn(this.loginForm);
+      return await this.LoginIn(this.loginForm);
     },
     async submitForm() {
       this.$refs.loginForm.validate(async (v) => {
         if (v) {
-          this.login();
-          this.loginVefify();
+          const flag = await this.login();
+          if (!flag) {
+            this.loginVefify();
+          }
         } else {
           this.$message({
             type: "error",
@@ -167,6 +162,5 @@ export default {
 </script>
 
 <style scoped lang="scss">
-@import '@/style/login.scss';
-
+@import "@/style/login.scss";
 </style>

+ 105 - 97
web/src/view/superAdmin/api/api.vue

@@ -52,7 +52,12 @@
       <el-table-column fixed="right" label="操作" width="200">
         <template slot-scope="scope">
           <el-button @click="editApi(scope.row)" size="small" type="primary" icon="el-icon-edit">编辑</el-button>
-          <el-button @click="deleteApi(scope.row)" size="small" type="danger" icon="el-icon-delete">删除</el-button>
+          <el-button
+            @click="deleteApi(scope.row)"
+            size="small"
+            type="danger"
+            icon="el-icon-delete"
+          >删除</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -108,194 +113,197 @@ import {
   createApi,
   updateApi,
   deleteApi
-} from '@/api/api'
-import infoList from '@/mixins/infoList'
-import { toSQLLine } from '@/utils/stringFun'
+} from "@/api/api";
+import infoList from "@/mixins/infoList";
+import { toSQLLine } from "@/utils/stringFun";
 const methodOptions = [
   {
-    value: 'POST',
-    label: '创建',
-    type: 'success'
+    value: "POST",
+    label: "创建",
+    type: "success"
   },
   {
-    value: 'GET',
-    label: '查看',
-    type: ''
+    value: "GET",
+    label: "查看",
+    type: ""
   },
   {
-    value: 'PUT',
-    label: '更新',
-    type: 'warning'
+    value: "PUT",
+    label: "更新",
+    type: "warning"
   },
   {
-    value: 'DELETE',
-    label: '删除',
-    type: 'danger'
+    value: "DELETE",
+    label: "删除",
+    type: "danger"
   }
-]
+];
 
 export default {
-  name: 'Api',
+  name: "Api",
   mixins: [infoList],
   data() {
     return {
       listApi: getApiList,
       dialogFormVisible: false,
-      dialogTitle: '新增Api',
+      dialogTitle: "新增Api",
       form: {
-        path: '',
-        apiGroup: '',
-        method: '',
-        description: ''
+        path: "",
+        apiGroup: "",
+        method: "",
+        description: ""
       },
       methodOptions: methodOptions,
-      type: '',
+      type: "",
       rules: {
-        path: [{ required: true, message: '请输入api路径', trigger: 'blur' }],
+        path: [{ required: true, message: "请输入api路径", trigger: "blur" }],
         apiGroup: [
-          { required: true, message: '请输入组名称', trigger: 'blur' }
+          { required: true, message: "请输入组名称", trigger: "blur" }
         ],
         method: [
-          { required: true, message: '请选择请求方式', trigger: 'blur' }
+          { required: true, message: "请选择请求方式", trigger: "blur" }
         ],
         description: [
-          { required: true, message: '请输入api介绍', trigger: 'blur' }
+          { required: true, message: "请输入api介绍", trigger: "blur" }
         ]
       }
-    }
+    };
   },
   methods: {
     // 排序
     sortChange({ prop, order }) {
       if (prop) {
-        this.searchInfo.orderKey = toSQLLine(prop)
-        this.searchInfo.desc = order == 'descending'
+        this.searchInfo.orderKey = toSQLLine(prop);
+        this.searchInfo.desc = order == "descending";
       }
-      this.getTableData()
+      this.getTableData();
     },
     //条件搜索前端看此方法
     onSubmit() {
-      this.page = 1
-      this.pageSize = 10
-      this.getTableData()
+      this.page = 1;
+      this.pageSize = 10;
+      this.getTableData();
     },
     initForm() {
-      this.$refs.apiForm.resetFields()
-      this.form= {
-        path: '',
-        apiGroup: '',
-        method: '',
-        description: ''
-      }
+      this.$refs.apiForm.resetFields();
+      this.form = {
+        path: "",
+        apiGroup: "",
+        method: "",
+        description: ""
+      };
     },
     closeDialog() {
-      this.initForm()
-      this.dialogFormVisible = false
+      this.initForm();
+      this.dialogFormVisible = false;
     },
     openDialog(type) {
       switch (type) {
-        case 'addApi':
-          this.dialogTitlethis = '新增Api'
-          break
-        case 'edit':
-          this.dialogTitlethis = '编辑Api'
-          break
+        case "addApi":
+          this.dialogTitlethis = "新增Api";
+          break;
+        case "edit":
+          this.dialogTitlethis = "编辑Api";
+          break;
         default:
-          break
+          break;
       }
-      this.type = type
-      this.dialogFormVisible = true
+      this.type = type;
+      this.dialogFormVisible = true;
     },
     async editApi(row) {
-      const res = await getApiById({ id: row.ID })
-      this.form = res.data.api
-      this.openDialog('edit')
+      const res = await getApiById({ id: row.ID });
+      this.form = res.data.api;
+      this.openDialog("edit");
     },
     async deleteApi(row) {
-      this.$confirm('此操作将永久删除所有角色下该菜单, 是否继续?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
+      this.$confirm("此操作将永久删除所有角色下该api, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
       })
         .then(async () => {
-          const res = await deleteApi(row)
+          const res = await deleteApi(row);
           if (res.code == 0) {
             this.$message({
-              type: 'success',
-              message: '删除成功!'
-            })
-            this.getTableData()
+              type: "success",
+              message: "删除成功!"
+            });
+            if (this.tableData.length == 1) {
+              this.page--;
+            }
+            this.getTableData();
           }
         })
         .catch(() => {
           this.$message({
-            type: 'info',
-            message: '已取消删除'
-          })
-        })
+            type: "info",
+            message: "已取消删除"
+          });
+        });
     },
     async enterDialog() {
       this.$refs.apiForm.validate(async valid => {
         if (valid) {
           switch (this.type) {
-            case 'addApi':
+            case "addApi":
               {
-                const res = await createApi(this.form)
+                const res = await createApi(this.form);
                 if (res.code == 0) {
                   this.$message({
-                    type: 'success',
-                    message: '添加成功',
+                    type: "success",
+                    message: "添加成功",
                     showClose: true
-                  })
+                  });
                 }
-                this.getTableData()
-                this.closeDialog()
+                this.getTableData();
+                this.closeDialog();
               }
 
-              break
-            case 'edit':
+              break;
+            case "edit":
               {
-                const res = await updateApi(this.form)
+                const res = await updateApi(this.form);
                 if (res.code == 0) {
                   this.$message({
-                    type: 'success',
-                    message: '编辑成功',
+                    type: "success",
+                    message: "编辑成功",
                     showClose: true
-                  })
+                  });
                 }
-                this.getTableData()
-                this.closeDialog()
+                this.getTableData();
+                this.closeDialog();
               }
-              break
+              break;
             default:
               {
                 this.$message({
-                  type: 'error',
-                  message: '未知操作',
+                  type: "error",
+                  message: "未知操作",
                   showClose: true
-                })
+                });
               }
-              break
+              break;
           }
         }
-      })
+      });
     }
   },
   filters: {
     methodFiletr(value) {
-      const target = methodOptions.filter(item => item.value === value)[0]
+      const target = methodOptions.filter(item => item.value === value)[0];
       // return target && `${target.label}(${target.value})`
-      return target && `${target.label}`
+      return target && `${target.label}`;
     },
     tagTypeFiletr(value) {
-      const target = methodOptions.filter(item => item.value === value)[0]
-      return target && `${target.type}`
+      const target = methodOptions.filter(item => item.value === value)[0];
+      return target && `${target.type}`;
     }
   },
-  created(){
-    this.getTableData()
+  created() {
+    this.getTableData();
   }
-}
+};
 </script>
 <style scoped lang="scss">
 .button-box {

+ 8 - 5
web/src/view/superAdmin/authority/authority.vue

@@ -106,10 +106,10 @@ export default {
   mixins: [infoList],
   data() {
     var mustUint = (rule, value, callback) => {
-      if (!(/^[0-9]*[1-9][0-9]*$/).test(value)){
-       return  callback(new Error("请输入正整数"));
-      } 
-      return  callback()
+      if (!/^[0-9]*[1-9][0-9]*$/.test(value)) {
+        return callback(new Error("请输入正整数"));
+      }
+      return callback();
     };
 
     return {
@@ -136,7 +136,7 @@ export default {
       rules: {
         authorityId: [
           { required: true, message: "请输入角色ID", trigger: "blur" },
-          {validator: mustUint, trigger: 'blur'  }
+          { validator: mustUint, trigger: "blur" }
         ],
         authorityName: [
           { required: true, message: "请输入角色名", trigger: "blur" }
@@ -191,6 +191,9 @@ export default {
               type: "success",
               message: "删除成功!"
             });
+            if (this.tableData.length == 1) {
+              this.page--;
+            }
             this.getTableData();
           }
         })

+ 112 - 99
web/src/view/superAdmin/dictionary/sysDictionary.vue

@@ -4,27 +4,19 @@
       <el-form :inline="true" :model="searchInfo" class="demo-form-inline">
         <el-form-item label="字典名(中)">
           <el-input placeholder="搜索条件" v-model="searchInfo.name"></el-input>
-        </el-form-item>    
+        </el-form-item>
         <el-form-item label="字典名(英)">
           <el-input placeholder="搜索条件" v-model="searchInfo.type"></el-input>
-        </el-form-item>    
-            <el-form-item label="状态" prop="status">
-            <el-select v-model="searchInfo.status" clear placeholder="请选择">
-                <el-option
-                    key="true"
-                    label="是"
-                    value="true">
-                </el-option>
-                <el-option
-                    key="false"
-                    label="否"
-                    value="false">
-                </el-option>
-            </el-select>
-            </el-form-item>   
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="searchInfo.status" clear placeholder="请选择">
+            <el-option key="true" label="是" value="true"></el-option>
+            <el-option key="false" label="否" value="false"></el-option>
+          </el-select>
+        </el-form-item>
         <el-form-item label="描述">
           <el-input placeholder="搜索条件" v-model="searchInfo.desc"></el-input>
-        </el-form-item>    
+        </el-form-item>
         <el-form-item>
           <el-button @click="onSubmit" type="primary">查询</el-button>
         </el-form-item>
@@ -41,21 +33,21 @@
       style="width: 100%"
       tooltip-effect="dark"
     >
-    <el-table-column type="selection" width="55"></el-table-column>
-    <el-table-column label="日期" width="180">
-         <template slot-scope="scope">{{scope.row.CreatedAt|formatDate}}</template>
-    </el-table-column>
-    
-    <el-table-column label="字典名(中)" prop="name" width="120"></el-table-column> 
-    
-    <el-table-column label="字典名(英)" prop="type" width="120"></el-table-column> 
-    
-    <el-table-column label="状态" prop="status" width="120">
-         <template slot-scope="scope">{{scope.row.status|formatBoolean}}</template>
-    </el-table-column>
-    
-    <el-table-column label="描述" prop="desc" width="280"></el-table-column> 
-    
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column label="日期" width="180">
+        <template slot-scope="scope">{{scope.row.CreatedAt|formatDate}}</template>
+      </el-table-column>
+
+      <el-table-column label="字典名(中)" prop="name" width="120"></el-table-column>
+
+      <el-table-column label="字典名(英)" prop="type" width="120"></el-table-column>
+
+      <el-table-column label="状态" prop="status" width="120">
+        <template slot-scope="scope">{{scope.row.status|formatBoolean}}</template>
+      </el-table-column>
+
+      <el-table-column label="描述" prop="desc" width="280"></el-table-column>
+
       <el-table-column label="按钮组">
         <template slot-scope="scope">
           <el-button @click="toDetile(scope.row)" size="small" type="success">详情</el-button>
@@ -85,20 +77,30 @@
 
     <el-dialog :before-close="closeDialog" :visible.sync="dialogFormVisible" title="弹窗操作">
       <el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="110px">
-      <el-form-item label="字典名(中)" prop="name">
-        <el-input v-model="formData.name" placeholder="请输入字典名(中)" clearable :style="{width: '100%'}"></el-input>
-      </el-form-item>
-      <el-form-item label="字典名(英)" prop="type">
-        <el-input v-model="formData.type" placeholder="请输入字典名(英)" clearable :style="{width: '100%'}"></el-input>
-      </el-form-item>
-      <el-form-item label="状态" prop="status" required>
-        <el-switch v-model="formData.status" active-text="开启" inactive-text="停用"></el-switch>
-      </el-form-item>
-      <el-form-item label="描述" prop="desc">
-        <el-input v-model="formData.desc" placeholder="请输入描述" clearable :style="{width: '100%'}"></el-input>
-      </el-form-item>
-    </el-form>
-      
+        <el-form-item label="字典名(中)" prop="name">
+          <el-input
+            v-model="formData.name"
+            placeholder="请输入字典名(中)"
+            clearable
+            :style="{width: '100%'}"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="字典名(英)" prop="type">
+          <el-input
+            v-model="formData.type"
+            placeholder="请输入字典名(英)"
+            clearable
+            :style="{width: '100%'}"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="状态" prop="status" required>
+          <el-switch v-model="formData.status" active-text="开启" inactive-text="停用"></el-switch>
+        </el-form-item>
+        <el-form-item label="描述" prop="desc">
+          <el-input v-model="formData.desc" placeholder="请输入描述" clearable :style="{width: '100%'}"></el-input>
+        </el-form-item>
+      </el-form>
+
       <div class="dialog-footer" slot="footer">
         <el-button @click="closeDialog">取 消</el-button>
         <el-button @click="enterDialog" type="primary">确 定</el-button>
@@ -111,12 +113,12 @@
 
 <script>
 import {
-    createSysDictionary,
-    deleteSysDictionary,
-    updateSysDictionary,
-    findSysDictionary,
-    getSysDictionaryList
-} from "@/api/sysDictionary";  //  此处请自行替换地址
+  createSysDictionary,
+  deleteSysDictionary,
+  updateSysDictionary,
+  findSysDictionary,
+  getSysDictionaryList
+} from "@/api/sysDictionary"; //  此处请自行替换地址
 import { formatTimeToStr } from "@/utils/date";
 import infoList from "@/mixins/infoList";
 export default {
@@ -129,25 +131,34 @@ export default {
       visible: false,
       type: "",
       formData: {
-        name:null,type:null,status:true,desc:null
+        name: null,
+        type: null,
+        status: true,
+        desc: null
       },
       rules: {
-        name: [{
-          required: true,
-          message: '请输入字典名(中)',
-          trigger: 'blur'
-        }],
-        type: [{
-          required: true,
-          message: '请输入字典名(英)',
-          trigger: 'blur'
-        }],
-        desc: [{
-          required: true,
-          message: '请输入描述',
-          trigger: 'blur'
-        }],
-      },
+        name: [
+          {
+            required: true,
+            message: "请输入字典名(中)",
+            trigger: "blur"
+          }
+        ],
+        type: [
+          {
+            required: true,
+            message: "请输入字典名(英)",
+            trigger: "blur"
+          }
+        ],
+        desc: [
+          {
+            required: true,
+            message: "请输入描述",
+            trigger: "blur"
+          }
+        ]
+      }
     };
   },
   filters: {
@@ -161,30 +172,30 @@ export default {
     },
     formatBoolean: function(bool) {
       if (bool != null) {
-        return bool ? "是" :"否";
+        return bool ? "是" : "否";
       } else {
         return "";
       }
     }
   },
   methods: {
-      toDetile(row){
-        this.$router.push({
-          name:"dictionaryDetail",
-          params:{
-            id:row.ID
-          }
-        })
-      },
-      //条件搜索前端看此方法
-      onSubmit() {
-        this.page = 1
-        this.pageSize = 10        
-        if (this.searchInfo.status==""){
-          this.searchInfo.status=null
-        }       
-        this.getTableData()
-      },
+    toDetile(row) {
+      this.$router.push({
+        name: "dictionaryDetail",
+        params: {
+          id: row.ID
+        }
+      });
+    },
+    //条件搜索前端看此方法
+    onSubmit() {
+      this.page = 1;
+      this.pageSize = 10;
+      if (this.searchInfo.status == "") {
+        this.searchInfo.status = null;
+      }
+      this.getTableData();
+    },
     async updateSysDictionary(row) {
       const res = await findSysDictionary({ ID: row.ID });
       this.type = "update";
@@ -196,10 +207,10 @@ export default {
     closeDialog() {
       this.dialogFormVisible = false;
       this.formData = {
-          name:null,
-          type:null,
-          status:true,
-          desc:null,
+        name: null,
+        type: null,
+        status: true,
+        desc: null
       };
     },
     async deleteSysDictionary(row) {
@@ -210,12 +221,15 @@ export default {
           type: "success",
           message: "删除成功"
         });
+        if (this.tableData.length == 1) {
+          this.page--;
+        }
         this.getTableData();
       }
     },
     async enterDialog() {
-      this.$refs['elForm'].validate(async valid => {
-        if (!valid) return
+      this.$refs["elForm"].validate(async valid => {
+        if (!valid) return;
         let res;
         switch (this.type) {
           case "create":
@@ -228,12 +242,11 @@ export default {
             res = await createSysDictionary(this.formData);
             break;
         }
-         if (res.code == 0) {
-        this.closeDialog();
-        this.getTableData();
-      }
-      })
-     
+        if (res.code == 0) {
+          this.closeDialog();
+          this.getTableData();
+        }
+      });
     },
     openDialog() {
       this.type = "create";

+ 11 - 9
web/src/view/superAdmin/dictionary/sysDictionaryDetail.vue

@@ -210,13 +210,16 @@ export default {
           type: "success",
           message: "删除成功"
         });
+        if (this.tableData.length == 1) {
+          this.page--;
+        }
         this.getTableData();
       }
     },
     async enterDialog() {
-    this.formData.sysDictionaryID = Number(this.$route.params.id)
-      this.$refs['elForm'].validate(async valid => {
-        if (!valid) return
+      this.formData.sysDictionaryID = Number(this.$route.params.id);
+      this.$refs["elForm"].validate(async valid => {
+        if (!valid) return;
         let res;
         switch (this.type) {
           case "create":
@@ -231,14 +234,13 @@ export default {
         }
         if (res.code == 0) {
           this.$message({
-            type:"success",
-            message:"创建/更改成功"
-          })
+            type: "success",
+            message: "创建/更改成功"
+          });
           this.closeDialog();
           this.getTableData();
         }
-      })
-      
+      });
     },
     openDialog() {
       this.type = "create";
@@ -246,7 +248,7 @@ export default {
     }
   },
   created() {
-    this.searchInfo.sysDictionaryID = this.$route.params.id
+    this.searchInfo.sysDictionaryID = this.$route.params.id;
     this.getTableData();
   }
 };

+ 5 - 2
web/src/view/superAdmin/menu/menu.vue

@@ -231,8 +231,8 @@ export default {
   },
   methods: {
     addParameter(form) {
-      if (!form.parameters){
-        this.$set(form,"parameters",[])
+      if (!form.parameters) {
+        this.$set(form, "parameters", []);
       }
       form.parameters.push({
         type: "query",
@@ -316,6 +316,9 @@ export default {
               type: "success",
               message: "删除成功!"
             });
+            if (this.tableData.length == 1) {
+              this.page--;
+            }
             this.getTableData();
           }
         })

+ 44 - 38
web/src/view/superAdmin/operation/sysOperationRecord.vue

@@ -112,19 +112,19 @@ import {
   deleteSysOperationRecord,
   getSysOperationRecordList,
   deleteSysOperationRecordByIds
-} from '@/api/sysOperationRecord' //  此处请自行替换地址
-import { formatTimeToStr } from '@/utils/date'
-import infoList from '@/mixins/infoList'
+} from "@/api/sysOperationRecord"; //  此处请自行替换地址
+import { formatTimeToStr } from "@/utils/date";
+import infoList from "@/mixins/infoList";
 
 export default {
-  name: 'SysOperationRecord',
+  name: "SysOperationRecord",
   mixins: [infoList],
   data() {
     return {
       listApi: getSysOperationRecordList,
       dialogFormVisible: false,
       visible: false,
-      type: '',
+      type: "",
       deleteVisible: false,
       multipleSelection: [],
       formData: {
@@ -137,74 +137,80 @@ export default {
         error_message: null,
         user_id: null
       }
-    }
+    };
   },
   filters: {
     formatDate: function(time) {
-      if (time != null && time != '') {
-        var date = new Date(time)
-        return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss')
+      if (time != null && time != "") {
+        var date = new Date(time);
+        return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
       } else {
-        return ''
+        return "";
       }
     },
     formatBoolean: function(bool) {
       if (bool != null) {
-        return bool ? '是' : '否'
+        return bool ? "是" : "否";
       } else {
-        return ''
+        return "";
       }
     }
   },
   methods: {
     //条件搜索前端看此方法
     onSubmit() {
-      this.page = 1
-      this.pageSize = 10
-      this.getTableData()
+      this.page = 1;
+      this.pageSize = 10;
+      this.getTableData();
     },
     handleSelectionChange(val) {
-      this.multipleSelection = val
+      this.multipleSelection = val;
     },
     async onDelete() {
-      const ids = []
+      const ids = [];
       this.multipleSelection &&
         this.multipleSelection.map(item => {
-          ids.push(item.ID)
-        })
-      const res = await deleteSysOperationRecordByIds({ ids })
+          ids.push(item.ID);
+        });
+      const res = await deleteSysOperationRecordByIds({ ids });
       if (res.code == 0) {
         this.$message({
-          type: 'success',
-          message: '删除成功'
-        })
-        this.deleteVisible = false
-        this.getTableData()
+          type: "success",
+          message: "删除成功"
+        });
+        if (this.tableData.length == ids.length) {
+          this.page--;
+        }
+        this.deleteVisible = false;
+        this.getTableData();
       }
     },
     async deleteSysOperationRecord(row) {
-      this.visible = false
-      const res = await deleteSysOperationRecord({ ID: row.ID })
+      this.visible = false;
+      const res = await deleteSysOperationRecord({ ID: row.ID });
       if (res.code == 0) {
         this.$message({
-          type: 'success',
-          message: '删除成功'
-        })
-        this.getTableData()
+          type: "success",
+          message: "删除成功"
+        });
+        if (this.tableData.length == 1) {
+          this.page--;
+        }
+        this.getTableData();
       }
     },
-    fmtBody(value){
-      try{
-        return JSON.parse(value)
-      }catch (err){
-        return  value
+    fmtBody(value) {
+      try {
+        return JSON.parse(value);
+      } catch (err) {
+        return value;
       }
     }
   },
   created() {
-    this.getTableData()
+    this.getTableData();
   }
-}
+};
 </script>
 
 <style lang="scss">

+ 0 - 1
web/src/view/superAdmin/user/user.vue

@@ -69,7 +69,6 @@
         </el-form-item>
         <el-form-item label="用户角色" label-width="80px" prop="authorityId">
           <el-cascader
-            @change="changeAuthority(scope.row)"
             v-model="userInfo.authorityId"
             :options="authOptions"
             :show-all-levels="false"

+ 20 - 4
web/src/view/workflow/workflowProcess/workflowProcess.vue

@@ -56,9 +56,19 @@
 
       <el-table-column label="按钮组">
         <template slot-scope="scope">
-          <el-button class="table-button" @click="useWorkflowProcess(scope.row)" size="success" >启动</el-button>
-          <el-button class="table-button" @click="updateWorkflowProcess(scope.row)" size="small" type="primary">变更</el-button>
-          <el-button class="table-button" @click="viewWorkflowProcess(scope.row)" size="small" type="warning">查看</el-button>
+          <el-button class="table-button" @click="useWorkflowProcess(scope.row)" size="success">启动</el-button>
+          <el-button
+            class="table-button"
+            @click="updateWorkflowProcess(scope.row)"
+            size="small"
+            type="primary"
+          >变更</el-button>
+          <el-button
+            class="table-button"
+            @click="viewWorkflowProcess(scope.row)"
+            size="small"
+            type="warning"
+          >查看</el-button>
           <el-popover placement="top" width="160" v-model="scope.row.visible">
             <p>确定要删除吗?</p>
             <div style="text-align: right; margin: 0">
@@ -147,6 +157,9 @@ export default {
           type: "success",
           message: "删除成功"
         });
+        if (this.tableData.length == ids.length) {
+          this.page--;
+        }
         this.deleteVisible = false;
         this.getTableData();
       }
@@ -160,7 +173,7 @@ export default {
         }
       });
     },
-    async useWorkflowProcess(row){
+    async useWorkflowProcess(row) {
       this.$router.push({
         name: "workflowUse",
         query: {
@@ -185,6 +198,9 @@ export default {
           type: "success",
           message: "删除成功"
         });
+        if (this.tableData.length == 1) {
+          this.page--;
+        }
         this.getTableData();
       }
     },

+ 25 - 5
web/vue.config.js

@@ -1,6 +1,8 @@
 'use strict'
 
 const path = require('path')
+const buildConf = require('./build.config')
+const packageConf = require('./package.json')
 
 function resolve(dir) {
     return path.join(__dirname, dir)
@@ -63,13 +65,31 @@ module.exports = {
                     // 不打包 begin
                     // 1.目前已经测试通过[vue,axios,echarts]可以cdn引用,其它组件测试通过后可继续添加
                     // 2.此处添加不打包后,需在public/index.html head中添加相应cdn资源链接
-                    config.set('externals', {
-                        vue: 'Vue',
-                        axios: 'axios',
-                        echarts: 'echarts'
-                    })
+                    config.set('externals', buildConf.cdns.reduce((p, a) => {
+                        p[a.name] = a.scope 
+                        return p
+                    },{}))
                     // 不打包 end
 
+                    config.plugin('html')
+                        .tap(args => {
+                            if(buildConf.title) {
+                                args[0].title = buildConf.title
+                            }
+                            if(buildConf.cdns.length > 0) {
+                                args[0].cdns = buildConf.cdns.map(conf => {
+                                    if (conf.path) {
+                                        conf.js = `${buildConf.baseCdnUrl}${conf.path}`
+                                    } else {
+                                        conf.js = `${buildConf.baseCdnUrl}/${conf.name}/${packageConf.dependencies[conf.name].replace('^', '')}/${conf.name}.min.js`
+                                    }
+
+                                    return conf
+                                })
+                            }
+                            return args
+                        })
+
                     config
                         .plugin('ScriptExtHtmlWebpackPlugin')
                         .after('html')