Compare commits

...
26 Commits
Author SHA1 Message Date
SliverHornandSliverHorn 23952c5f5f Update: (#1758)
1.config gorm相关移除DBBASE实现改为GeneralDB实现LogLevel函数
2.移除initializel/internal/logger实现,改为gorm_logger_writer实现gorm的logger通过zap输出到文件或者控制台
3.优化initializel/internal/gorm代码

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-05-27 10:24:19 +08:00
02fc5036d7 v2.6.5版本更新 (#1757)
* feature:增加资源加载loading

* feature:修正sql无法落盘的问题

* fixed: 修复切换角色出现404的问题。

* 删除selectImage.vue中chooseImg下多余的console.log(url)

---------

Co-authored-by: krank <emosick@qq.com>
Co-authored-by: Qing Liang <106448173+xue-ding-e@users.noreply.github.com>
2024-05-26 21:49:34 +08:00
a6a65ed9f4 fixed:修复自动化生成表格缺少的prop (#1755)
* fixed:修复自动化生成表格缺少的prop

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
Co-authored-by: wall-js <wall_js@foxmail.com>
2024-05-26 21:24:33 +08:00
Wallandwall-js 369f657aa6 fixed:修复自动化代码无法识别json类型,去掉插件路由冗余代码 (#1751)
* fix(bug): [api.go.tpl]自动化代码swag路径冲突

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
2024-05-22 16:56:55 +08:00
pixelmaxQM 1801e5b30f fixed:selectImage组件图片偏移的bug 2024-05-21 21:26:16 +08:00
pixelmaxQM b10d5103f3 fixed:selectImage组件重构 2024-05-20 22:07:45 +08:00
pixelmaxQM 9964bfef8b fixed:修复特殊符号下无法预览图片的bug 2024-05-20 21:08:32 +08:00
Juneyx 9945a19f2c state.vue: 修复展示多硬盘信息时无法上下滚动的bug (#1749) 2024-05-20 10:27:32 +08:00
pixelmaxQM a5d43e6f14 fixed:修复右上角focus-visible状态下会出现outline的bug 2024-05-18 23:11:28 +08:00
pixelmaxQM b61b9a06dd feature:增加首页插件推荐 2024-05-18 21:58:50 +08:00
pixelmaxQM f28570fa98 feature:新版树组件适配暗夜模式 2024-05-18 21:48:42 +08:00
Juneyx fb53d639be 添加展示多硬盘用量信息的功能 (#1747)
* featurel: 添加多磁盘用量信息展示
2024-05-18 11:52:44 +08:00
nonstop 42de9257c3 fixed: 修复文件分片上传在已选择文件的情况下,再次选择并取消出现控制台飘红且原文件清空的bug (#1746) 2024-05-18 11:48:28 +08:00
Wallandwall-js 0fba597a61 fixed:调整自动化代码swagger文档返回值类型 (#1742)
* fix(bug): [api.go.tpl]自动化代码swag路径冲突

* fixed:调整自动化代码swagger文档返回值类型

* fixed:修复RouterPrefix修改后不影响插件路由问题

---------

Co-authored-by: wall-js <liujun@grectronics.cn>
2024-05-17 16:22:16 +08:00
pixelMax(奇淼 d0393c4e9f fixed:调整前端打包的base路径,适配history模式路由。 2024-05-17 13:25:31 +08:00
pixelMax(奇淼 a21d2a591e feature:优化数据源字段和数组字段展示 2024-05-17 11:26:51 +08:00
pixelMax(奇淼 de54688c56 fixed:自动导入功能将根据表内字段自动创建created_at和updated_at的时间 2024-05-17 10:26:47 +08:00
pixelmaxQM 3c486d9117 feature:暗夜模式兼容调整,初始化需要手动写入初始密码。 2024-05-16 21:55:32 +08:00
pixelmaxQM e8128250f4 feature:暗夜模式兼容调整,初始化需要手动写入初始密码。 2024-05-16 21:49:56 +08:00
pixelmaxQM 58a1b72910 fixed:登录页面暗夜模式适配 2024-05-16 21:02:16 +08:00
SliverHornandSliverHorn ee00d29afd Update: (#1743)
1. 移除zap配置文件MaxAge字段
2. 重构自定义Cutter切分日志
3. 自定义ZapCore, 可实现根据fields自定义功能文件输出

Co-authored-by: SliverHorn <caiwei.lai@jutze.com.cn>
2024-05-16 18:21:30 +08:00
pixelMax(奇淼 5cfcc538a8 fixed:左侧菜单栏超长支持滚动 2024-05-16 15:22:21 +08:00
pixelmaxQM e7c8a9d420 feature:增加自动化代码页面暂时存储功能 2024-05-15 21:40:36 +08:00
pixelmaxQM 6b07ffe8f7 feature:增加数据源一对多关系。 2024-05-15 21:26:32 +08:00
pixelmaxQM 0d17340445 feature:增加数据源一对多关系。 2024-05-15 21:15:41 +08:00
pixelMax(奇淼 2a0b92713b fixed:兼容旧自动化数据 2024-05-15 10:50:22 +08:00
75 changed files with 997 additions and 981 deletions
+5 -16
View File
@@ -1,10 +1,8 @@
package system
import (
"errors"
"fmt"
"net/url"
"os"
"strings"
"github.com/flipped-aurora/gin-vue-admin/server/global"
@@ -86,21 +84,12 @@ func (autoApi *AutoCodeApi) CreateTemp(c *gin.Context) {
a.PackageT = utils.FirstUpper(a.Package)
err := autoCodeService.CreateTemp(a, menuId, apiIds...)
if err != nil {
if errors.Is(err, system.ErrAutoMove) {
c.Writer.Header().Add("success", "true")
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
} else {
c.Writer.Header().Add("success", "false")
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
_ = os.Remove("./ginvueadmin.zip")
}
} else {
c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", "ginvueadmin.zip")) // fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名
c.Writer.Header().Add("Content-Type", "application/json")
c.Writer.Header().Add("success", "true")
c.File("./ginvueadmin.zip")
_ = os.Remove("./ginvueadmin.zip")
c.Writer.Header().Add("success", "false")
c.Writer.Header().Add("msg", url.QueryEscape(err.Error()))
return
}
c.Writer.Header().Add("Content-Type", "application/json")
c.Writer.Header().Add("success", "true")
}
// GetDB
+4
View File
@@ -233,6 +233,10 @@ hua-wei-obs:
excel:
dir: ./resource/excel/
# disk usage configuration
disk-list:
- mount-point: "/"
# 跨域配置
# 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用
cors:
+2
View File
@@ -27,6 +27,8 @@ type Server struct {
Excel Excel `mapstructure:"excel" json:"excel" yaml:"excel"`
DiskList []DiskList `mapstructure:"disk-list" json:"disk-list" yaml:"disk-list"`
// 跨域配置
Cors CORS `mapstructure:"cors" json:"cors" yaml:"cors"`
}
+22 -2
View File
@@ -1,5 +1,10 @@
package config
import (
"gorm.io/gorm/logger"
"strings"
)
type DsnProvider interface {
Dsn() string
}
@@ -16,14 +21,29 @@ type GeneralDB struct {
Username string `mapstructure:"username" json:"username" yaml:"username"` // 数据库密码
Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码
Path string `mapstructure:"path" json:"path" yaml:"path"`
Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` //数据库引擎,默认InnoDB
Engine string `mapstructure:"engine" json:"engine" yaml:"engine" default:"InnoDB"` // 数据库引擎,默认InnoDB
LogMode string `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"` // 是否开启Gorm全局日志
MaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"` // 空闲中的最大连接数
MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` //是否开启全局禁用复数,true表示开启
Singular bool `mapstructure:"singular" json:"singular" yaml:"singular"` // 是否开启全局禁用复数,true表示开启
LogZap bool `mapstructure:"log-zap" json:"log-zap" yaml:"log-zap"` // 是否通过zap写入日志文件
}
func (c GeneralDB) LogLevel() logger.LogLevel {
switch strings.ToLower(c.LogMode) {
case "silent", "Silent":
return logger.Silent
case "error", "Error":
return logger.Error
case "warn", "Warn":
return logger.Warn
case "info", "Info":
return logger.Info
default:
return logger.Info
}
}
type SpecializedDB struct {
Type string `mapstructure:"type" json:"type" yaml:"type"`
AliasName string `mapstructure:"alias-name" json:"alias-name" yaml:"alias-name"`
+9
View File
@@ -0,0 +1,9 @@
package config
type Disk struct {
MountPoint string `mapstructure:"mount-point" json:"mount-point" yaml:"mount-point"`
}
type DiskList struct {
Disk `yaml:",inline" mapstructure:",squash"`
}
+2 -5
View File
@@ -3,11 +3,8 @@ package config
type Mssql struct {
GeneralDB `yaml:",inline" mapstructure:",squash"`
}
//dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
// Dsn "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
func (m *Mssql) Dsn() string {
return "sqlserver://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "?database=" + m.Dbname + "&encrypt=disable"
}
func (m *Mssql) GetLogMode() string {
return m.LogMode
}
-4
View File
@@ -7,7 +7,3 @@ type Mysql struct {
func (m *Mysql) Dsn() string {
return m.Username + ":" + m.Password + "@tcp(" + m.Path + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
}
func (m *Mysql) GetLogMode() string {
return m.LogMode
}
-4
View File
@@ -8,7 +8,3 @@ func (m *Oracle) Dsn() string {
return "oracle://" + m.Username + ":" + m.Password + "@" + m.Path + ":" + m.Port + "/" + m.Dbname + "?" + m.Config
}
func (m *Oracle) GetLogMode() string {
return m.LogMode
}
-4
View File
@@ -15,7 +15,3 @@ func (p *Pgsql) Dsn() string {
func (p *Pgsql) LinkDsn(dbname string) string {
return "host=" + p.Path + " user=" + p.Username + " password=" + p.Password + " dbname=" + dbname + " port=" + p.Port + " " + p.Config
}
func (m *Pgsql) GetLogMode() string {
return m.LogMode
}
-4
View File
@@ -11,7 +11,3 @@ type Sqlite struct {
func (s *Sqlite) Dsn() string {
return filepath.Join(s.Path, s.Dbname+".db")
}
func (s *Sqlite) GetLogMode() string {
return s.LogMode
}
+45 -35
View File
@@ -2,7 +2,7 @@ package config
import (
"go.uber.org/zap/zapcore"
"strings"
"time"
)
type Zap struct {
@@ -12,49 +12,59 @@ type Zap struct {
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` // 编码级
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` // 栈名
MaxAge int `mapstructure:"max-age" json:"max-age" yaml:"max-age"` // 日志留存时间
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
}
// ZapEncodeLevel 根据 EncodeLevel 返回 zapcore.LevelEncoder
// Levels 根据字符串转化为 zapcore.Levels
func (c *Zap) Levels() []zapcore.Level {
levels := make([]zapcore.Level, 0, 7)
level, err := zapcore.ParseLevel(c.Level)
if err != nil {
level = zapcore.DebugLevel
}
for ; level <= zapcore.FatalLevel; level++ {
levels = append(levels, level)
}
return levels
}
func (c *Zap) Encoder() zapcore.Encoder {
config := zapcore.EncoderConfig{
TimeKey: "time",
NameKey: "name",
LevelKey: "level",
CallerKey: "caller",
MessageKey: "message",
StacktraceKey: c.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(c.Prefix + t.Format("2006-01-02 15:04:05.000"))
},
EncodeLevel: c.LevelEncoder(),
EncodeCaller: zapcore.FullCallerEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
}
if c.Format == "json" {
return zapcore.NewJSONEncoder(config)
}
return zapcore.NewConsoleEncoder(config)
}
// LevelEncoder 根据 EncodeLevel 返回 zapcore.LevelEncoder
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *Zap) ZapEncodeLevel() zapcore.LevelEncoder {
func (c *Zap) LevelEncoder() zapcore.LevelEncoder {
switch {
case z.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
case c.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
return zapcore.LowercaseLevelEncoder
case z.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
case c.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
return zapcore.LowercaseColorLevelEncoder
case z.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
case c.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
return zapcore.CapitalLevelEncoder
case z.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
case c.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
return zapcore.CapitalColorLevelEncoder
default:
return zapcore.LowercaseLevelEncoder
}
}
// TransportLevel 根据字符串转化为 zapcore.Level
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *Zap) TransportLevel() zapcore.Level {
z.Level = strings.ToLower(z.Level)
switch z.Level {
case "debug":
return zapcore.DebugLevel
case "info":
return zapcore.InfoLevel
case "warn":
return zapcore.WarnLevel
case "error":
return zapcore.ErrorLevel
case "dpanic":
return zapcore.DPanicLevel
case "panic":
return zapcore.PanicLevel
case "fatal":
return zapcore.FatalLevel
default:
return zapcore.DebugLevel
}
}
+39 -41
View File
@@ -3,33 +3,43 @@ package internal
import (
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"time"
)
// Cutter 实现 io.Writer 接口
// 用于日志切割, strings.Join([]string{director,layout, formats..., level+".log"}, os.PathSeparator)
type Cutter struct {
level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
format string // 时间格式(2006-01-02)
Director string // 日志文件夹
layout string // 时间格式 2006-01-02 15:04:05
formats []string // 自定义参数([]string{Director,"2006-01-02", "business"(此参数可不写), level+".log"}
director string // 日志文件夹
file *os.File // 文件句柄
mutex *sync.RWMutex // 读写锁
}
type CutterOption func(*Cutter)
// WithCutterFormat 设置时间格式
func WithCutterFormat(format string) CutterOption {
// CutterWithLayout 时间格式
func CutterWithLayout(layout string) CutterOption {
return func(c *Cutter) {
c.format = format
c.layout = layout
}
}
// CutterWithFormats 格式化参数
func CutterWithFormats(format ...string) CutterOption {
return func(c *Cutter) {
if len(format) > 0 {
c.formats = format
}
}
}
func NewCutter(director string, level string, options ...CutterOption) *Cutter {
rotate := &Cutter{
level: level,
Director: director,
director: director,
mutex: new(sync.RWMutex),
}
for i := 0; i < len(options); i++ {
@@ -51,41 +61,19 @@ func (c *Cutter) Write(bytes []byte) (n int, err error) {
}
c.mutex.Unlock()
}()
var business string
if strings.Contains(string(bytes), "business") {
var compile *regexp.Regexp
compile, err = regexp.Compile(`{"business": "([^,]+)"}`)
if err != nil {
return 0, err
}
if compile.Match(bytes) {
finds := compile.FindSubmatch(bytes)
business = string(finds[len(finds)-1])
bytes = compile.ReplaceAll(bytes, []byte(""))
}
compile, err = regexp.Compile(`"business": "([^,]+)"`)
if err != nil {
return 0, err
}
if compile.Match(bytes) {
finds := compile.FindSubmatch(bytes)
business = string(finds[len(finds)-1])
bytes = compile.ReplaceAll(bytes, []byte(""))
}
length := len(c.formats)
values := make([]string, 0, 3+length)
values = append(values, c.director)
if c.layout != "" {
values = append(values, time.Now().Format(c.layout))
}
format := time.Now().Format(c.format)
formats := make([]string, 0, 4)
formats = append(formats, c.Director)
if format != "" {
formats = append(formats, format)
for i := 0; i < length; i++ {
values = append(values, c.formats[i])
}
if business != "" {
formats = append(formats, business)
}
formats = append(formats, c.level+".log")
filename := filepath.Join(formats...)
dirname := filepath.Dir(filename)
err = os.MkdirAll(dirname, 0755)
values = append(values, c.level+".log")
filename := filepath.Join(values...)
director := filepath.Dir(filename)
err = os.MkdirAll(director, os.ModePerm)
if err != nil {
return 0, err
}
@@ -95,3 +83,13 @@ func (c *Cutter) Write(bytes []byte) (n int, err error) {
}
return c.file.Write(bytes)
}
func (c *Cutter) Sync() error {
c.mutex.Lock()
defer c.mutex.Unlock()
if c.file != nil {
return c.file.Sync()
}
return nil
}
-21
View File
@@ -1,21 +0,0 @@
package internal
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"go.uber.org/zap/zapcore"
"os"
)
var FileRotatelogs = new(fileRotatelogs)
type fileRotatelogs struct{}
// GetWriteSyncer 获取 zapcore.WriteSyncer
// Author [SliverHorn](https://github.com/SliverHorn)
func (r *fileRotatelogs) GetWriteSyncer(level string) zapcore.WriteSyncer {
fileWriter := NewCutter(global.GVA_CONFIG.Zap.Director, level, WithCutterFormat("2006-01-02"))
if global.GVA_CONFIG.Zap.LogInConsole {
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(fileWriter))
}
return zapcore.AddSync(fileWriter)
}
-101
View File
@@ -1,101 +0,0 @@
package internal
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"time"
)
var Zap = new(_zap)
type _zap struct{}
// GetEncoder 获取 zapcore.Encoder
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) GetEncoder() zapcore.Encoder {
if global.GVA_CONFIG.Zap.Format == "json" {
return zapcore.NewJSONEncoder(z.GetEncoderConfig())
}
return zapcore.NewConsoleEncoder(z.GetEncoderConfig())
}
// GetEncoderConfig 获取zapcore.EncoderConfig
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) GetEncoderConfig() zapcore.EncoderConfig {
return zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
StacktraceKey: global.GVA_CONFIG.Zap.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: global.GVA_CONFIG.Zap.ZapEncodeLevel(),
EncodeTime: z.CustomTimeEncoder,
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.FullCallerEncoder,
}
}
// GetEncoderCore 获取Encoder的 zapcore.Core
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) GetEncoderCore(l zapcore.Level, level zap.LevelEnablerFunc) zapcore.Core {
writer := FileRotatelogs.GetWriteSyncer(l.String()) // 日志分割
return zapcore.NewCore(z.GetEncoder(), writer, level)
}
// CustomTimeEncoder 自定义日志输出时间格式
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) CustomTimeEncoder(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(global.GVA_CONFIG.Zap.Prefix + t.Format("2006/01/02 - 15:04:05.000"))
}
// GetZapCores 根据配置文件的Level获取 []zapcore.Core
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) GetZapCores() []zapcore.Core {
cores := make([]zapcore.Core, 0, 7)
for level := global.GVA_CONFIG.Zap.TransportLevel(); level <= zapcore.FatalLevel; level++ {
cores = append(cores, z.GetEncoderCore(level, z.GetLevelPriority(level)))
}
return cores
}
// GetLevelPriority 根据 zapcore.Level 获取 zap.LevelEnablerFunc
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *_zap) GetLevelPriority(level zapcore.Level) zap.LevelEnablerFunc {
switch level {
case zapcore.DebugLevel:
return func(level zapcore.Level) bool { // 调试级别
return level == zap.DebugLevel
}
case zapcore.InfoLevel:
return func(level zapcore.Level) bool { // 日志级别
return level == zap.InfoLevel
}
case zapcore.WarnLevel:
return func(level zapcore.Level) bool { // 警告级别
return level == zap.WarnLevel
}
case zapcore.ErrorLevel:
return func(level zapcore.Level) bool { // 错误级别
return level == zap.ErrorLevel
}
case zapcore.DPanicLevel:
return func(level zapcore.Level) bool { // dpanic级别
return level == zap.DPanicLevel
}
case zapcore.PanicLevel:
return func(level zapcore.Level) bool { // panic级别
return level == zap.PanicLevel
}
case zapcore.FatalLevel:
return func(level zapcore.Level) bool { // 终止级别
return level == zap.FatalLevel
}
default:
return func(level zapcore.Level) bool { // 调试级别
return level == zap.DebugLevel
}
}
}
+67
View File
@@ -0,0 +1,67 @@
package internal
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
"time"
)
type ZapCore struct {
level zapcore.Level
zapcore.Core
}
func NewZapCore(level zapcore.Level) *ZapCore {
entity := &ZapCore{level: level}
syncer := entity.WriteSyncer()
levelEnabler := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
return l == level
})
entity.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, levelEnabler)
return entity
}
func (z *ZapCore) WriteSyncer(formats ...string) zapcore.WriteSyncer {
cutter := NewCutter(
global.GVA_CONFIG.Zap.Director,
z.level.String(),
CutterWithLayout(time.DateOnly),
CutterWithFormats(formats...),
)
if global.GVA_CONFIG.Zap.LogInConsole {
multiSyncer := zapcore.NewMultiWriteSyncer(os.Stdout, cutter)
return zapcore.AddSync(multiSyncer)
}
return zapcore.AddSync(cutter)
}
func (z *ZapCore) Enabled(level zapcore.Level) bool {
return z.level == level
}
func (z *ZapCore) With(fields []zapcore.Field) zapcore.Core {
return z.Core.With(fields)
}
func (z *ZapCore) Check(entry zapcore.Entry, check *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if z.Enabled(entry.Level) {
return check.AddCore(entry, z)
}
return check
}
func (z *ZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
for i := 0; i < len(fields); i++ {
if fields[i].Key == "business" || fields[i].Key == "folder" || fields[i].Key == "directory" {
syncer := z.WriteSyncer(fields[i].String)
z.Core = zapcore.NewCore(global.GVA_CONFIG.Zap.Encoder(), syncer, z.level)
}
}
return z.Core.Write(entry, fields)
}
func (z *ZapCore) Sync() error {
return z.Core.Sync()
}
+1 -1
View File
@@ -38,7 +38,7 @@ func RunWindowsServer() {
fmt.Printf(`
欢迎使用 gin-vue-admin
当前版本:v2.6.4
当前版本:v2.6.5
加群方式:微信号:shouzi_1994 QQ群:470239250
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
+7 -3
View File
@@ -17,10 +17,14 @@ func Zap() (logger *zap.Logger) {
fmt.Printf("create %v directory\n", global.GVA_CONFIG.Zap.Director)
_ = os.Mkdir(global.GVA_CONFIG.Zap.Director, os.ModePerm)
}
cores := internal.Zap.GetZapCores()
levels := global.GVA_CONFIG.Zap.Levels()
length := len(levels)
cores := make([]zapcore.Core, 0, length)
for i := 0; i < length; i++ {
core := internal.NewZapCore(levels[i])
cores = append(cores, core)
}
logger = zap.New(zapcore.NewTee(cores...))
if global.GVA_CONFIG.Zap.ShowLine {
logger = logger.WithOptions(zap.AddCaller())
}
+1 -1
View File
@@ -6997,7 +6997,7 @@ const docTemplate = `{
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "v2.6.4",
Version: "v2.6.5",
Host: "",
BasePath: "",
Schemes: []string{},
+1 -1
View File
@@ -4,7 +4,7 @@
"description": "使用gin+vue进行极速开发的全栈开发基础平台",
"title": "Gin-Vue-Admin Swagger API接口文档",
"contact": {},
"version": "v2.6.4"
"version": "v2.6.5"
},
"paths": {
"/api/createApi": {
+1 -1
View File
@@ -1582,7 +1582,7 @@ info:
contact: {}
description: 使用gin+vue进行极速开发的全栈开发基础平台
title: Gin-Vue-Admin Swagger API接口文档
version: v2.6.4
version: v2.6.5
paths:
/api/createApi:
post:
+19 -3
View File
@@ -44,19 +44,25 @@ require (
gorm.io/driver/mysql v1.5.6
gorm.io/driver/postgres v1.5.7
gorm.io/driver/sqlserver v1.5.1
gorm.io/gorm v1.25.9
gorm.io/gorm v1.25.10
nhooyr.io/websocket v1.8.7
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/bodgit/plumbing v1.2.0 // indirect
github.com/bodgit/sevenzip v1.3.0 // indirect
github.com/bodgit/windows v1.0.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/casbin/govaluate v1.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/clbanning/mxj v1.8.4 // indirect
github.com/connesc/cipherio v0.2.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dsnet/compress v0.0.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
@@ -73,9 +79,11 @@ require (
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
@@ -86,13 +94,15 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mholt/archiver/v4 v4.0.0-alpha.8 // indirect
github.com/microsoft/go-mssqldb v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -100,7 +110,9 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.7.0 // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
@@ -112,10 +124,12 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
@@ -126,6 +140,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
@@ -135,6 +150,7 @@ require (
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/datatypes v1.2.0 // indirect
gorm.io/plugin/dbresolver v1.4.1 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
+48 -2
View File
@@ -47,10 +47,18 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible h1:KpbJFXwhVeuxNtBJ74MCGbIoaBok2uZvkD7QXp2+Wis=
github.com/aliyun/aliyun-oss-go-sdk v2.2.7+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/aws/aws-sdk-go v1.44.307 h1:2R0/EPgpZcFSUwZhYImq/srjaOrOfLv5MNRzrFyAM38=
github.com/aws/aws-sdk-go v1.44.307/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM=
github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8=
github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY=
github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM=
github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA=
github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
@@ -80,6 +88,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw=
github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -87,6 +97,9 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -195,6 +208,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -241,6 +256,11 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -284,12 +304,18 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -313,6 +339,10 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM=
github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A=
github.com/microsoft/go-mssqldb v1.1.0 h1:jsV+tpvcPTbNNKW0o3kiCD69kOHICsfjZ2VcVu2lKYc=
github.com/microsoft/go-mssqldb v1.1.0/go.mod h1:LzkFdl4z2Ck+Hi+ycGOTbL56VEfgoyA2DvYejrNGbRk=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@@ -334,6 +364,8 @@ github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk=
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
@@ -343,6 +375,8 @@ github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -374,6 +408,7 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08=
github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
@@ -421,6 +456,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
github.com/tencentyun/cos-go-sdk-v5 v0.7.42 h1:Up1704BJjI5orycXKjpVpvuOInt9GC5pqY4knyE9Uds=
github.com/tencentyun/cos-go-sdk-v5 v0.7.42/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
@@ -432,6 +469,9 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk=
github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@@ -483,6 +523,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
@@ -853,19 +895,23 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco=
gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04=
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/driver/sqlserver v1.5.1 h1:wpyW/pR26U94uaujltiFGXY7fd2Jw5hC9PB1ZF/Y5s4=
gorm.io/driver/sqlserver v1.5.1/go.mod h1:AYHzzte2msKTmYBYsSIq8ZUsznLJwBdkB2wpI+kt0nM=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8=
gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/plugin/dbresolver v1.4.1 h1:Ug4LcoPhrvqq71UhxtF346f+skTYoCa/nEsdjvHwEzk=
gorm.io/plugin/dbresolver v1.4.1/go.mod h1:CTbCtMWhsjXSiJqiW2R8POvJ2cq18RVOl4WGyT5nhNc=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+25 -39
View File
@@ -1,20 +1,16 @@
package internal
import (
"github.com/flipped-aurora/gin-vue-admin/server/config"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"log"
"os"
"time"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type DBBASE interface {
GetLogMode() string
}
var Gorm = new(_gorm)
type _gorm struct{}
@@ -22,41 +18,31 @@ type _gorm struct{}
// Config gorm 自定义配置
// Author [SliverHorn](https://github.com/SliverHorn)
func (g *_gorm) Config(prefix string, singular bool) *gorm.Config {
config := &gorm.Config{
var general config.GeneralDB
switch global.GVA_CONFIG.System.DbType {
case "mysql":
general = global.GVA_CONFIG.Mysql.GeneralDB
case "pgsql":
general = global.GVA_CONFIG.Pgsql.GeneralDB
case "oracle":
general = global.GVA_CONFIG.Oracle.GeneralDB
case "sqlite":
general = global.GVA_CONFIG.Sqlite.GeneralDB
case "mssql":
general = global.GVA_CONFIG.Mssql.GeneralDB
default:
general = global.GVA_CONFIG.Mysql.GeneralDB
}
return &gorm.Config{
Logger: logger.New(NewWriter(general, log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: general.LogLevel(),
Colorful: true,
}),
NamingStrategy: schema.NamingStrategy{
TablePrefix: prefix,
SingularTable: singular,
},
DisableForeignKeyConstraintWhenMigrating: true,
}
_default := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
Colorful: true,
})
var logMode DBBASE
switch global.GVA_CONFIG.System.DbType {
case "mysql":
logMode = &global.GVA_CONFIG.Mysql
case "pgsql":
logMode = &global.GVA_CONFIG.Pgsql
case "oracle":
logMode = &global.GVA_CONFIG.Oracle
default:
logMode = &global.GVA_CONFIG.Mysql
}
switch logMode.GetLogMode() {
case "silent", "Silent":
config.Logger = _default.LogMode(logger.Silent)
case "error", "Error":
config.Logger = _default.LogMode(logger.Error)
case "warn", "Warn":
config.Logger = _default.LogMode(logger.Warn)
case "info", "Info":
config.Logger = _default.LogMode(logger.Info)
default:
config.Logger = _default.LogMode(logger.Info)
}
return config
}
@@ -0,0 +1,37 @@
package internal
import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/config"
"go.uber.org/zap"
"gorm.io/gorm/logger"
)
type Writer struct {
config config.GeneralDB
writer logger.Writer
}
func NewWriter(config config.GeneralDB, writer logger.Writer) *Writer {
return &Writer{config: config, writer: writer}
}
// Printf 格式化打印日志
func (c *Writer) Printf(message string, data ...any) {
if c.config.LogZap {
switch c.config.LogLevel() {
case logger.Silent:
zap.L().Debug(fmt.Sprintf(message, data...))
case logger.Error:
zap.L().Error(fmt.Sprintf(message, data...))
case logger.Warn:
zap.L().Warn(fmt.Sprintf(message, data...))
case logger.Info:
zap.L().Info(fmt.Sprintf(message, data...))
default:
zap.L().Info(fmt.Sprintf(message, data...))
}
return
}
c.writer.Printf(message, data...)
}
-35
View File
@@ -1,35 +0,0 @@
package internal
import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"gorm.io/gorm/logger"
)
type writer struct {
logger.Writer
}
// NewWriter writer 构造函数
// Author [SliverHorn](https://github.com/SliverHorn)
func NewWriter(w logger.Writer) *writer {
return &writer{Writer: w}
}
// Printf 格式化打印日志
// Author [SliverHorn](https://github.com/SliverHorn)
func (w *writer) Printf(message string, data ...interface{}) {
var logZap bool
switch global.GVA_CONFIG.System.DbType {
case "mysql":
logZap = global.GVA_CONFIG.Mysql.LogZap
case "pgsql":
logZap = global.GVA_CONFIG.Pgsql.LogZap
}
if logZap {
global.GVA_LOG.Info(fmt.Sprintf(message+"\n", data...))
} else {
w.Writer.Printf(message, data...)
}
}
+3 -6
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
"github.com/flipped-aurora/gin-vue-admin/server/plugin/email"
"github.com/flipped-aurora/gin-vue-admin/server/utils/plugin"
"github.com/gin-gonic/gin"
@@ -17,12 +16,10 @@ func PluginInit(group *gin.RouterGroup, Plugin ...plugin.Plugin) {
}
}
func InstallPlugin(Router *gin.Engine) {
PublicGroup := Router.Group("")
fmt.Println("无鉴权插件安装==》", PublicGroup)
PrivateGroup := Router.Group("")
func InstallPlugin(PrivateGroup *gin.RouterGroup, PublicRouter *gin.RouterGroup) {
fmt.Println("无鉴权插件安装==》", PublicRouter)
fmt.Println("鉴权插件安装==》", PrivateGroup)
PrivateGroup.Use(middleware.JWTAuth()).Use(middleware.CasbinHandler())
// 添加跟角色挂钩权限的插件 示例 本地示例模式于在线仓库模式注意上方的import 可以自行切换 效果相同
PluginInit(PrivateGroup, email.CreateEmailPlug(
global.GVA_CONFIG.Email.To,
+6 -3
View File
@@ -1,6 +1,9 @@
package initialize
import (
"net/http"
"os"
"github.com/flipped-aurora/gin-vue-admin/server/docs"
"github.com/flipped-aurora/gin-vue-admin/server/global"
"github.com/flipped-aurora/gin-vue-admin/server/middleware"
@@ -8,8 +11,6 @@ import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
"os"
)
type justFilesFilesystem struct {
@@ -39,7 +40,6 @@ func Routers() *gin.Engine {
Router.Use(gin.Logger())
}
InstallPlugin(Router) // 安装插件
systemRouter := router.RouterGroupApp.System
exampleRouter := router.RouterGroupApp.Example
// 如果想要不使用nginx代理前端网页,可以修改 web/.env.production 下的
@@ -93,6 +93,9 @@ func Routers() *gin.Engine {
}
//插件路由安装
InstallPlugin(PrivateGroup, PublicGroup)
global.GVA_LOG.Info("router register success")
return Router
}
+1 -1
View File
@@ -15,7 +15,7 @@ import (
//go:generate go mod download
// @title Gin-Vue-Admin Swagger API接口文档
// @version v2.6.4
// @version v2.6.5
// @description 使用gin+vue进行极速开发的全栈开发基础平台
// @securityDefinitions.apikey ApiKeyAuth
// @in header
+8 -7
View File
@@ -7,13 +7,14 @@ import (
)
type InitDB struct {
DBType string `json:"dbType"` // 数据库类型
Host string `json:"host"` // 服务器地址
Port string `json:"port"` // 数据库连接端口
UserName string `json:"userName"` // 数据库用户名
Password string `json:"password"` // 数据库密码
DBName string `json:"dbName" binding:"required"` // 数据库名
DBPath string `json:"dbPath"` // sqlite数据库文件路径
AdminPassword string `json:"adminPassword" binding:"required"`
DBType string `json:"dbType"` // 数据库类型
Host string `json:"host"` // 服务器地址
Port string `json:"port"` // 数据库连接端口
UserName string `json:"userName"` // 数据库用户名
Password string `json:"password"` // 数据库密码
DBName string `json:"dbName" binding:"required"` // 数据库名
DBPath string `json:"dbPath"` // sqlite数据库文件路径
}
// MysqlEmptyDsn msyql 空数据库 建库链接
+4 -7
View File
@@ -1,7 +1,6 @@
package system
import (
"errors"
"go/token"
"strings"
@@ -19,7 +18,6 @@ type AutoCodeStruct struct {
AutoCreateApiToSql bool `json:"autoCreateApiToSql"` // 是否自动创建api
AutoCreateMenuToSql bool `json:"autoCreateMenuToSql"` // 是否自动创建menu
AutoCreateResource bool `json:"autoCreateResource"` // 是否自动创建资源标识
AutoMoveFile bool `json:"autoMoveFile"` // 是否自动移动文件
BusinessDB string `json:"businessDB"` // 业务数据库
GvaModel bool `json:"gvaModel"` // 是否使用gva默认Model
Fields []*Field `json:"fields"`
@@ -40,9 +38,10 @@ type AutoCodeStruct struct {
}
type DataSource struct {
Table string `json:"table"`
Label string `json:"label"`
Value string `json:"value"`
Association int `json:"association"` // 关联关系 1 一对一 2 一对多
Table string `json:"table"`
Label string `json:"label"`
Value string `json:"value"`
}
func (a *AutoCodeStruct) Pretreatment() {
@@ -87,8 +86,6 @@ type Field struct {
CheckDataSource bool `json:"checkDataSource"` // 是否检查数据源
}
var ErrAutoMove error = errors.New("创建代码成功并移动文件成功")
type SysAutoCode struct {
global.GVA_MODEL
PackageName string `json:"packageName" gorm:"comment:包名"`
@@ -26,7 +26,7 @@ var {{.Abbreviation}}Service = service.ServiceGroupApp.{{.PackageT}}ServiceGroup
// @accept application/json
// @Produce application/json
// @Param data body {{.Package}}.{{.StructName}} true "创建{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Success 200 {object} response.Response{msg=string} "创建成功"
// @Router /{{.Abbreviation}}/create{{.StructName}} [post]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Context) {
var {{.Abbreviation}} {{.Package}}.{{.StructName}}
@@ -54,7 +54,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Create{{.StructName}}(c *gin.Con
// @accept application/json
// @Produce application/json
// @Param data body {{.Package}}.{{.StructName}} true "删除{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Success 200 {object} response.Response{msg=string} "删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}} [delete]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}(c *gin.Context) {
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
@@ -75,7 +75,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}(c *gin.Con
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"批量删除成功"}"
// @Success 200 {object} response.Response{msg=string} "批量删除成功"
// @Router /{{.Abbreviation}}/delete{{.StructName}}ByIds [delete]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gin.Context) {
{{.PrimaryField.FieldJson}}s := c.QueryArray("{{.PrimaryField.FieldJson}}s[]")
@@ -97,7 +97,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Delete{{.StructName}}ByIds(c *gi
// @accept application/json
// @Produce application/json
// @Param data body {{.Package}}.{{.StructName}} true "更新{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Success 200 {object} response.Response{msg=string} "更新成功"
// @Router /{{.Abbreviation}}/update{{.StructName}} [put]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Context) {
var {{.Abbreviation}} {{.Package}}.{{.StructName}}
@@ -125,7 +125,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Update{{.StructName}}(c *gin.Con
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}.{{.StructName}} true "用id查询{{.Description}}"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Success 200 {object} response.Response{data=object{re{{.Abbreviation}}={{.Package}}.{{.StructName}}},msg=string} "查询成功"
// @Router /{{.Abbreviation}}/find{{.StructName}} [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Context) {
{{.PrimaryField.FieldJson}} := c.Query("{{.PrimaryField.FieldJson}}")
@@ -144,7 +144,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Find{{.StructName}}(c *gin.Conte
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Success 200 {object} response.Response{data=response.PageResult,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}List [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Context) {
var pageInfo {{.Package}}Req.{{.StructName}}Search
@@ -172,7 +172,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}List(c *gin.Co
// @Summary 获取{{.StructName}}的数据源
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Success 200 {object} response.Response{data=object,msg=string} "查询成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}DataSource [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *gin.Context) {
// 此接口为获取数据源定义的数据
@@ -191,7 +191,7 @@ func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}DataSource(c *
// @accept application/json
// @Produce application/json
// @Param data query {{.Package}}Req.{{.StructName}}Search true "分页获取{{.Description}}列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Success 200 {object} response.Response{data=object,msg=string} "获取成功"
// @Router /{{.Abbreviation}}/get{{.StructName}}Public [get]
func ({{.Abbreviation}}Api *{{.StructName}}Api) Get{{.StructName}}Public(c *gin.Context) {
// 此接口不需要鉴权
@@ -18,13 +18,15 @@ type {{.StructName}} struct {
{{- else if eq .FieldType "video" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "file" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}}`
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}} swaggertype:"array,object"`
{{- else if eq .FieldType "pictures" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}}`
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}} swaggertype:"array,object"`
{{- else if eq .FieldType "richtext" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}type:text;" {{- if .Require }} binding:"required"{{- end -}}`
{{- else if eq .FieldType "json" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}type:text;" {{- if .Require }} binding:"required"{{- end -}}`
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}type:text;" {{- if .Require }} binding:"required"{{- end -}} swaggertype:"object"`
{{- else if eq .FieldType "array" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}type:text;" {{- if .Require }} binding:"required"{{- end -}} swaggertype:"array,object"`
{{- else if ne .FieldType "string" }}
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" gorm:"{{- if .PrimaryKey -}}primarykey;{{- end -}}{{- if .DefaultValue -}}default:{{ .DefaultValue }};{{- end -}}column:{{.ColumnName}};comment:{{.Comment}};{{- if .DataTypeLong -}}size:{{.DataTypeLong}};{{- end -}}" {{- if .Require }} binding:"required"{{- end -}}`
{{- else }}
@@ -24,11 +24,15 @@ type {{.StructName}}Search struct{
{{- else if eq .FieldType "video" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- else if eq .FieldType "file" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" swaggertype:"array,object"`
{{- else if eq .FieldType "pictures" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" swaggertype:"array,object"`
{{- else if eq .FieldType "richtext" }}
{{.FieldName}} string `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- else if eq .FieldType "json" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" swaggertype:"object"`
{{- else if eq .FieldType "array" }}
{{.FieldName}} datatypes.JSON `json:"{{.FieldJson}}" form:"{{.FieldJson}}" swaggertype:"array,object"`
{{- else if ne .FieldType "string" }}
{{.FieldName}} *{{.FieldType}} `json:"{{.FieldJson}}" form:"{{.FieldJson}}" `
{{- else }}
@@ -5,7 +5,7 @@
{{- range .Fields}}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}">
{{- if .CheckDataSource}}
<el-select v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in dataSource.{{.FieldJson}}" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@@ -139,6 +139,9 @@ const formData = ref({
{{- if eq .FieldType "json" }}
{{.FieldJson}}: {},
{{- end }}
{{- if eq .FieldType "array" }}
{{.FieldJson}}: [],
{{- end }}
{{- end }}
})
// 验证规则
@@ -99,7 +99,7 @@
>
<el-table-column type="selection" width="55" />
{{ if .GvaModel }}
<el-table-column align="left" label="日期" width="180">
<el-table-column align="left" label="日期" prop="createdAt" width="180">
<template #default="scope">{{ "{{ formatDate(scope.row.CreatedAt) }}" }}</template>
</el-table-column>
{{ end }}
@@ -107,7 +107,13 @@
{{- if .CheckDataSource }}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="120">
<template #default="scope">
{{"{{"}} filterDataSource(dataSource.{{.FieldJson}},scope.row.{{.FieldJson}}) {{"}}"}}
{{if eq .DataSource.Association 2}}
<el-tag v-for="(item,key) in filterDataSource(dataSource.{{.FieldJson}},scope.row.{{.FieldJson}})" :key="key">
{{ "{{ item }}" }}
</el-tag>
{{ else }}
<span>{{"{{"}} filterDataSource(dataSource.{{.FieldJson}},scope.row.{{.FieldJson}}) {{"}}"}}</span>
{{ end }}
</template>
</el-table-column>
{{- else if .DictType}}
@@ -121,17 +127,17 @@
<template #default="scope">{{"{{"}} formatBoolean(scope.row.{{.FieldJson}}) {{"}}"}}</template>
</el-table-column>
{{- else if eq .FieldType "time.Time" }}
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" width="180">
<el-table-column {{- if .Sort}} sortable{{- end}} align="left" label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="180">
<template #default="scope">{{"{{"}} formatDate(scope.row.{{.FieldJson}}) {{"}}"}}</template>
</el-table-column>
{{- else if eq .FieldType "picture" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<el-image style="width: 100px; height: 100px" :src="getUrl(scope.row.{{.FieldJson}})" fit="cover"/>
</template>
</el-table-column>
{{- else if eq .FieldType "pictures" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="multiple-img-box">
<el-image v-for="(item,index) in scope.row.{{.FieldJson}}" :key="index" style="width: 80px; height: 80px" :src="getUrl(item)" fit="cover"/>
@@ -139,7 +145,7 @@
</template>
</el-table-column>
{{- else if eq .FieldType "video" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<video
style="width: 100px; height: 100px"
@@ -151,13 +157,13 @@
</template>
</el-table-column>
{{- else if eq .FieldType "richtext" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
[富文本内容]
</template>
</el-table-column>
{{- else if eq .FieldType "file" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
<div class="file-list">
<el-tag v-for="file in scope.row.{{.FieldJson}}" :key="file.uid">{{"{{"}}file.name{{"}}"}}</el-tag>
@@ -165,7 +171,7 @@
</template>
</el-table-column>
{{- else if eq .FieldType "json" }}
<el-table-column label="{{.FieldDesc}}" width="200">
<el-table-column label="{{.FieldDesc}}" prop="{{.FieldJson}}" width="200">
<template #default="scope">
[JSON]
</template>
@@ -208,7 +214,7 @@
{{- range .FrontFields}}
<el-form-item label="{{.FieldDesc}}:" prop="{{.FieldJson}}" >
{{- if .CheckDataSource}}
<el-select v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-select {{if eq .DataSource.Association 2}} multiple {{ end }} v-model="formData.{{.FieldJson}}" placeholder="请选择{{.FieldDesc}}" style="width:100%" :clearable="{{.Clearable}}" >
<el-option v-for="(item,key) in dataSource.{{.FieldJson}}" :key="key" :label="item.label" :value="item.value" />
</el-select>
{{- else }}
@@ -231,6 +237,11 @@
// 此字段为json结构,可以前端自行控制展示和数据绑定模式 需绑定json的key为 formData.{{.FieldJson}} 后端会按照json的类型进行存取
{{"{{"}} formData.{{.FieldJson}} {{"}}"}}
{{- end }}
{{- if eq .FieldType "array" }}
<el-tag v-for="(item,key) in formData.{{.FieldJson}}" :key="key">
{{ "{{ item }}" }}
</el-tag>
{{- end }}
{{- if eq .FieldType "int" }}
<el-input v-model.number="formData.{{ .FieldJson }}" :clearable="{{.Clearable}}" placeholder="请输入{{.FieldDesc}}" />
{{- end }}
@@ -308,7 +319,7 @@ import SelectFile from '@/components/selectFile/selectFile.vue'
{{- end }}
// 全量引入格式化工具 请按需保留
import { getDictFunc, formatDate, formatBoolean, filterDict,filterDataSource, ReturnArrImg, onDownloadFile } from '@/utils/format'
import { getDictFunc, formatDate, formatBoolean, filterDict ,filterDataSource, ReturnArrImg, onDownloadFile } from '@/utils/format'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ref, reactive } from 'vue'
@@ -355,6 +366,9 @@ const formData = ref({
{{- if eq .FieldType "json" }}
{{.FieldJson}}: {},
{{- end }}
{{- if eq .FieldType "array" }}
{{.FieldJson}}: [],
{{- end }}
{{- end }}
})
+70 -132
View File
@@ -1,10 +1,11 @@
package system
import (
"archive/zip"
"context"
"encoding/json"
"errors"
"fmt"
"github.com/mholt/archiver/v4"
"io"
"mime/multipart"
"os"
@@ -214,10 +215,10 @@ func makeDictTypes(autoCode *system.AutoCodeStruct) {
func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruct, menuID uint, ids ...uint) (err error) {
fmtField(&autoCode)
// 增加判断: 重复创建struct
if autoCode.AutoMoveFile && AutoCodeHistoryServiceApp.Repeat(autoCode.BusinessDB, autoCode.StructName, autoCode.Package) {
if AutoCodeHistoryServiceApp.Repeat(autoCode.BusinessDB, autoCode.StructName, autoCode.Package) {
return RepeatErr
}
dataList, fileList, needMkdir, err := autoCodeService.getNeedList(&autoCode)
dataList, _, needMkdir, err := autoCodeService.getNeedList(&autoCode)
if err != nil {
return err
}
@@ -257,55 +258,49 @@ func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruc
idBf.WriteString(strconv.Itoa(int(id)))
idBf.WriteString(";")
}
if autoCode.AutoMoveFile { // 判断是否需要自动转移
Init(autoCode.Package)
for index := range dataList {
autoCodeService.addAutoMoveFile(&dataList[index])
Init(autoCode.Package)
for index := range dataList {
autoCodeService.addAutoMoveFile(&dataList[index])
}
// 判断目标文件是否都可以移动
for _, value := range dataList {
if utils.FileExist(value.autoMoveFilePath) {
return errors.New(fmt.Sprintf("目标文件已存在:%s\n", value.autoMoveFilePath))
}
// 判断目标文件是否都可以移动
for _, value := range dataList {
if utils.FileExist(value.autoMoveFilePath) {
return errors.New(fmt.Sprintf("目标文件已存在:%s\n", value.autoMoveFilePath))
}
}
for _, value := range dataList { // 移动文件
if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil {
return err
}
}
{
// 在gorm.go 注入 自动迁移
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "gorm.go")
varDB := utils.MaheHump(autoCode.BusinessDB)
ast2.AddRegisterTablesAst(path, "RegisterTables", autoCode.Package, varDB, autoCode.BusinessDB, autoCode.StructName)
}
{
// router.go 注入 自动迁移
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "router.go")
ast2.AddRouterCode(path, "Routers", autoCode.Package, autoCode.StructName)
}
// 给各个enter进行注入
err = injectionCode(autoCode.StructName, &injectionCodeMeta)
if err != nil {
return
}
// 保存生成信息
for _, data := range dataList {
if len(data.autoMoveFilePath) != 0 {
bf.WriteString(data.autoMoveFilePath)
bf.WriteString(";")
}
}
} else { // 打包
if err = utils.ZipFiles("./ginvueadmin.zip", fileList, ".", "."); err != nil {
}
for _, value := range dataList { // 移动文件
if err := utils.FileMove(value.autoCodePath, value.autoMoveFilePath); err != nil {
return err
}
}
if autoCode.AutoMoveFile || autoCode.AutoCreateApiToSql || autoCode.AutoCreateMenuToSql {
{
// 在gorm.go 注入 自动迁移
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "gorm.go")
varDB := utils.MaheHump(autoCode.BusinessDB)
ast2.AddRegisterTablesAst(path, "RegisterTables", autoCode.Package, varDB, autoCode.BusinessDB, autoCode.StructName)
}
{
// router.go 注入 自动迁移
path := filepath.Join(global.GVA_CONFIG.AutoCode.Root,
global.GVA_CONFIG.AutoCode.Server, global.GVA_CONFIG.AutoCode.SInitialize, "router.go")
ast2.AddRouterCode(path, "Routers", autoCode.Package, autoCode.StructName)
}
// 给各个enter进行注入
err = injectionCode(autoCode.StructName, &injectionCodeMeta)
if err != nil {
return
}
// 保存生成信息
for _, data := range dataList {
if len(data.autoMoveFilePath) != 0 {
bf.WriteString(data.autoMoveFilePath)
bf.WriteString(";")
}
}
if autoCode.AutoCreateApiToSql || autoCode.AutoCreateMenuToSql {
if autoCode.TableName != "" {
err = AutoCodeHistoryServiceApp.CreateAutoCodeHistory(
string(meta),
@@ -337,9 +332,6 @@ func (autoCodeService *AutoCodeService) CreateTemp(autoCode system.AutoCodeStruc
if err != nil {
return err
}
if autoCode.AutoMoveFile {
return system.ErrAutoMove
}
return nil
}
@@ -862,88 +854,31 @@ func (autoCodeService *AutoCodeService) PubPlug(plugName string) (zipPath string
fileName := plugName + ".zip"
// 创建一个新的zip文件
zipFile, err := os.Create(fileName)
if err != nil {
fmt.Println(err)
return
}
defer zipFile.Close()
// 创建一个zip写入器
zipWriter := zip.NewWriter(zipFile)
defer zipWriter.Close()
webHeaderName := filepath.Join(plugName, "web", "plugin", plugName)
err = autoCodeService.doZip(zipWriter, webPath, webHeaderName)
if err != nil {
return
}
serverHeaderName := filepath.Join(plugName, "server", "plugin", plugName)
err = autoCodeService.doZip(zipWriter, serverPath, serverHeaderName)
if err != nil {
return
}
return filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fileName), nil
}
/*
*
zipWriter zip写入器
serverPath 存储的路径
headerName 写有zip的路径
*
*/
func (autoCodeService *AutoCodeService) doZip(zipWriter *zip.Writer, serverPath, headerName string) (err error) {
// 遍历serverPath目录并将所有非隐藏文件添加到zip归档中
err = filepath.Walk(serverPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 跳过隐藏文件和目录
if strings.HasPrefix(info.Name(), ".") {
return nil
}
// 创建一个新的文件头
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// 将文件头的名称设置为文件的相对路径
rel, _ := filepath.Rel(serverPath, path)
header.Name = filepath.Join(headerName, rel)
// 目录需要拼上一个 "/" ,否则会出现一个和目录一样的文件在压缩包中
if info.IsDir() {
header.Name += "/"
}
// 将文件添加到zip归档中
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
if info.IsDir() {
return nil
}
// 打开文件并将其内容复制到zip归档中
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(writer, file)
if err != nil {
return err
}
return nil
files, err := archiver.FilesFromDisk(nil, map[string]string{
webPath: plugName + "/web/plugin/" + plugName,
serverPath: plugName + "/server/plugin/" + plugName,
})
return err
// create the output file we'll write to
out, err := os.Create(fileName)
if err != nil {
return
}
defer out.Close()
// we can use the CompressedArchive type to gzip a tarball
// (compression is not required; you could use Tar directly)
format := archiver.CompressedArchive{
Archival: archiver.Zip{},
}
// create the archive
err = format.Archive(context.Background(), out, files)
if err != nil {
return
}
return filepath.Join(global.GVA_CONFIG.AutoCode.Root, global.GVA_CONFIG.AutoCode.Server, fileName), nil
}
func fmtField(autoCode *system.AutoCodeStruct) {
@@ -980,6 +915,9 @@ func fmtField(autoCode *system.AutoCodeStruct) {
if autoCode.Fields[i].FieldType == "json" {
autoCode.NeedJSON = true
}
if autoCode.Fields[i].FieldType == "array" {
autoCode.NeedJSON = true
}
if autoCode.Fields[i].FieldType == "file" {
autoCode.HasFile = true
autoCode.NeedJSON = true
@@ -101,14 +101,14 @@ func (dictionaryDetailService *DictionaryDetailService) GetDictionaryListByType(
}
// 按照字典id+字典内容value获取单条字典内容
func (dictionaryDetailService *DictionaryDetailService) GetDictionaryInfoByValue(dictionaryID uint, value uint) (detail system.SysDictionaryDetail, err error) {
func (dictionaryDetailService *DictionaryDetailService) GetDictionaryInfoByValue(dictionaryID uint, value string) (detail system.SysDictionaryDetail, err error) {
var sysDictionaryDetail system.SysDictionaryDetail
err = global.GVA_DB.First(&sysDictionaryDetail, "sys_dictionary_id = ? and value = ?", dictionaryID, value).Error
return sysDictionaryDetail, err
}
// 按照字典type+字典内容value获取单条字典内容
func (dictionaryDetailService *DictionaryDetailService) GetDictionaryInfoByTypeValue(t string, value uint) (detail system.SysDictionaryDetail, err error) {
func (dictionaryDetailService *DictionaryDetailService) GetDictionaryInfoByTypeValue(t string, value string) (detail system.SysDictionaryDetail, err error) {
var sysDictionaryDetails system.SysDictionaryDetail
db := global.GVA_DB.Model(&system.SysDictionaryDetail{}).Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id")
err = db.First(&sysDictionaryDetails, "sys_dictionaries.type = ? and sys_dictionary_details.value = ?", t, value).Error
+10 -10
View File
@@ -15,6 +15,7 @@ import (
"net/url"
"strconv"
"strings"
"time"
)
type SysExportTemplateService struct {
@@ -348,16 +349,15 @@ func (sysExportTemplateService *SysExportTemplateService) ImportExcel(templateID
item[key] = value
}
// 此处需要等待gorm修复HasColumn中的painc问题
//needCreated := tx.Migrator().HasColumn(template.TableName, "created_at")
//needUpdated := tx.Migrator().HasColumn(template.TableName, "updated_at")
//
//if item["created_at"] == nil && needCreated {
// item["created_at"] = time.Now()
//}
//if item["updated_at"] == nil && needUpdated {
// item["updated_at"] = time.Now()
//}
needCreated := tx.Migrator().HasColumn(template.TableName, "created_at")
needUpdated := tx.Migrator().HasColumn(template.TableName, "updated_at")
if item["created_at"] == nil && needCreated {
item["created_at"] = time.Now()
}
if item["updated_at"] == nil && needUpdated {
item["updated_at"] = time.Now()
}
items = append(items, item)
}
+1
View File
@@ -89,6 +89,7 @@ type InitDBService struct{}
// InitDB 创建数据库并初始化 总入口
func (initDBService *InitDBService) InitDB(conf request.InitDB) (err error) {
ctx := context.TODO()
ctx = context.WithValue(ctx, "adminPassword", conf.AdminPassword)
if len(initializers) == 0 {
return errors.New("无可用初始化过程,请检查初始化是否已执行完成")
}
+9 -2
View File
@@ -44,8 +44,15 @@ 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")
ap := ctx.Value("adminPassword")
apStr, ok := ap.(string)
if !ok {
apStr = "123456"
}
password := utils.BcryptHash(apStr)
adminPassword := utils.BcryptHash(apStr)
entities := []sysModel.SysUser{
{
+18 -10
View File
@@ -1,6 +1,7 @@
package utils
import (
"github.com/flipped-aurora/gin-vue-admin/server/global"
"runtime"
"time"
@@ -20,7 +21,7 @@ type Server struct {
Os Os `json:"os"`
Cpu Cpu `json:"cpu"`
Ram Ram `json:"ram"`
Disk Disk `json:"disk"`
Disk []Disk `json:"disk"`
}
type Os struct {
@@ -43,6 +44,7 @@ type Ram struct {
}
type Disk struct {
MountPoint string `json:"mountPoint"`
UsedMB int `json:"usedMb"`
UsedGB int `json:"usedGb"`
TotalMB int `json:"totalMb"`
@@ -104,15 +106,21 @@ func InitRAM() (r Ram, err error) {
//@description: 硬盘信息
//@return: d Disk, err error
func InitDisk() (d Disk, err error) {
if u, err := disk.Usage("/"); err != nil {
return d, err
} else {
d.UsedMB = int(u.Used) / MB
d.UsedGB = int(u.Used) / GB
d.TotalMB = int(u.Total) / MB
d.TotalGB = int(u.Total) / GB
d.UsedPercent = int(u.UsedPercent)
func InitDisk() (d []Disk, err error) {
for i := range global.GVA_CONFIG.DiskList {
mp := global.GVA_CONFIG.DiskList[i].MountPoint
if u, err := disk.Usage(mp); err != nil {
return d, err
} else {
d = append(d, Disk{
MountPoint: mp,
UsedMB: int(u.Used) / MB,
UsedGB: int(u.Used) / GB,
TotalMB: int(u.Total) / MB,
TotalGB: int(u.Total) / GB,
UsedPercent: int(u.UsedPercent),
})
}
}
return d, nil
}
-57
View File
@@ -51,60 +51,3 @@ func Unzip(zipFile string, destDir string) ([]string, error) {
}
return paths, nil
}
func ZipFiles(filename string, files []string, oldForm, newForm string) error {
newZipFile, err := os.Create(filename)
if err != nil {
return err
}
defer func() {
_ = newZipFile.Close()
}()
zipWriter := zip.NewWriter(newZipFile)
defer func() {
_ = zipWriter.Close()
}()
// 把files添加到zip中
for _, file := range files {
err = func(file string) error {
zipFile, err := os.Open(file)
if err != nil {
return err
}
defer zipFile.Close()
// 获取file的基础信息
info, err := zipFile.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
// 使用上面的FileInforHeader() 就可以把文件保存的路径替换成我们自己想要的了,如下面
header.Name = strings.Replace(file, oldForm, newForm, -1)
// 优化压缩
// 更多参考see http://golang.org/pkg/archive/zip/#pkg-constants
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
if _, err = io.Copy(writer, zipFile); err != nil {
return err
}
return nil
}(file)
if err != nil {
return err
}
}
return nil
}
+79 -2
View File
@@ -8,16 +8,93 @@
<meta content="Gin,Vue,Admin.Gin-Vue-Admin,GVA,gin-vue-admin,后台管理框架,vue后台管理框架,gin-vue-admin文档,gin-vue-admin首页,gin-vue-admin" name="keywords" />
<link rel="icon" href="favicon.ico">
<title></title>
<style>
<style>
.transition-colors{
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
</style>
body{
margin: 0;
--64f90c3645474bd5: #409eff;
}
#gva-loading-box{
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
#loading-text {
position: absolute;
bottom: calc(50% - 100px);
left: 0;
width: 100%;
text-align: center;
color: #666;
font-size: 14px;
}
#loading {
position: absolute;
top: calc(50% - 20px);
left: calc(50% - 20px);
}
@keyframes loader {
0% { left: -100px }
100% { left: 110%; }
}
#box {
width: 50px;
height: 50px;
background: var(--64f90c3645474bd5);
animation: animate .5s linear infinite;
position: absolute;
top: 0;
left: 0;
border-radius: 3px;
}
@keyframes animate {
17% { border-bottom-right-radius: 3px; }
25% { transform: translateY(9px) rotate(22.5deg); }
50% {
transform: translateY(18px) scale(1,.9) rotate(45deg) ;
border-bottom-right-radius: 40px;
}
75% { transform: translateY(9px) rotate(67.5deg); }
100% { transform: translateY(0) rotate(90deg); }
}
#shadow {
width: 50px;
height: 5px;
background: #000;
opacity: 0.1;
position: absolute;
top: 59px;
left: 0;
border-radius: 50%;
animation: shadow .5s linear infinite;
}
.dark #shadow{
background: #fff;
}
@keyframes shadow {
50% {
transform: scale(1.2,1);
}
}
</style>
</head>
<body>
<div id="gva-loading-box">
<div id="loading">
<div id="shadow"></div>
<div id="box"></div>
</div>
<div id="loading-text">系统正在加载中,请稍候...</div>
</div>
<div id="app"></div>
<script type="module" src="./src/main.js"></script>
</body>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gin-vue-admin",
"version": "2.6.4",
"version": "2.6.5",
"private": true,
"scripts": {
"serve": "node openDocument.js && vite --host --mode development",
@@ -8,9 +8,11 @@
<el-button
type="primary"
icon="upload"
>导入</el-button>
class="ml-3"
>
导入
</el-button>
</el-upload>
</template>
<script setup>
@@ -0,0 +1,65 @@
<template>
<div
class="w-40 h-40 relative rounded border border-dashed border-gray-300 overflow-hidden cursor-pointer group"
>
<el-icon
v-if="isVideoExt(model || '')"
:size="32"
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
>
<VideoPlay />
</el-icon>
<video
v-if="isVideoExt(model || '')"
class="w-full h-full object-cover"
muted
preload="metadata"
>
<source :src="getUrl(model) + '#t=1'">
</video>
<img v-if="model&&!isVideoExt(model)" class="w-full h-full" :src="getUrl(model)" alt="图片">
<div
v-if="model"
class="left-0 top-0 hidden text-gray-600 group-hover:bg-gray-600 group-hover:bg-opacity-30 w-full h-full group-hover:flex justify-center items-center absolute z-10"
@click="deleteItem"
>
<el-icon>
<delete />
</el-icon>
删除
</div>
<div
v-else
class="text-gray-600 group-hover:bg-gray-400 w-full h-full flex justify-center items-center"
@click="chooseItem"
>
<el-icon>
<plus />
</el-icon>
上传
</div>
</div>
</template>
<script setup>
import { getUrl, isVideoExt } from '@/utils/image'
import { Delete, Plus } from '@element-plus/icons-vue'
defineProps({
model: {
default: '',
type: String
}
})
const emits = defineEmits(['chooseItem', 'deleteItem'])
const chooseItem = () => {
emits('chooseItem')
}
const deleteItem = () => {
emits('deleteItem')
}
</script>
+33 -239
View File
@@ -1,104 +1,29 @@
<template>
<div>
<div
<selectComponent
v-if="!multiple"
class="update-image"
:style="{
'background-image': `url(${getUrl(model)})`,
'position': 'relative',
}"
>
<el-icon
v-if="isVideoExt(model || '')"
:size="32"
class="video video-icon"
style=""
>
<VideoPlay />
</el-icon>
<video
v-if="isVideoExt(model || '')"
class="avatar video-avatar video"
muted
preload="metadata"
style=""
@click="openChooseImg"
>
<source :src="getUrl(model) + '#t=1'">
</video>
<span
v-if="model"
class="update"
style="position: absolute;"
@click="openChooseImg"
>
<el-icon>
<delete />
</el-icon>
删除</span>
<span
v-else
class="update text-gray-600"
@click="openChooseImg"
>
<el-icon>
<plus />
</el-icon>
上传</span>
</div>
:model="model"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
/>
<div
v-else
class="multiple-img"
class="w-full gap-4 flex"
>
<div
<selectComponent
v-for="(item, index) in multipleValue"
:key="index"
class="update-image"
:style="{
'background-image': `url(${getUrl(item)})`,
'position': 'relative',
}"
>
<el-icon
v-if="isVideoExt(item || '')"
:size="32"
class="video video-icon"
>
<VideoPlay />
</el-icon>
<video
v-if="isVideoExt(item || '')"
class="avatar video-avatar video"
muted
preload="metadata"
@click="deleteImg(index)"
>
<source :src="getUrl(item) + '#t=1'">
</video>
<span
class="update"
style="position: absolute;"
@click="deleteImg(index)"
>
<el-icon>
<delete />
</el-icon>
删除</span>
</div>
<div
v-if="!maxUpdateCount || maxUpdateCount>multipleValue.length"
class="add-image"
>
<span
class="update text-gray-600"
@click="openChooseImg"
>
<el-icon>
<Plus />
</el-icon>
上传</span>
</div>
:model="item"
@chooseItem="openChooseImg"
@deleteItem="deleteImg(index)"
/>
<selectComponent
v-if="multipleValue.length < props.maxUpdateCount || props.maxUpdateCount === 0"
@chooseItem="openChooseImg"
@deleteItem="openChooseImg"
/>
</div>
<el-drawer
v-model="drawer"
title="媒体库"
@@ -107,7 +32,7 @@
<warning-bar
title="点击“文件名/备注”可以编辑文件名或者备注内容。"
/>
<div class="gva-btn-list">
<div class="gva-btn-list gap-2">
<upload-common
:image-common="imageCommon"
@on-success="getImageList"
@@ -127,34 +52,35 @@
type="primary"
icon="search"
@click="getImageList"
>查询
>
查询
</el-button>
</div>
<div class="media">
<div class="flex flex-wrap gap-4">
<div
v-for="(item,key) in picList"
:key="key"
class="media-box"
class="w-40"
>
<div class="header-img-box-list">
<div class="w-40 h-40 border rounded overflow-hidden border-dashed border-gray-300 cursor-pointer">
<el-image
:key="key"
:src="getUrl(item.url)"
fit="cover"
style="width: 100%;height: 100%;"
class="w-full h-full relative"
@click="chooseImg(item.url)"
>
<template #error>
<el-icon
v-if="isVideoExt(item.url || '')"
:size="32"
class="video video-icon"
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
>
<VideoPlay />
</el-icon>
<video
v-if="isVideoExt(item.url || '')"
class="avatar video-avatar video"
class="w-full h-full object-cover"
muted
preload="metadata"
@click="chooseImg(item.url)"
@@ -164,9 +90,9 @@
</video>
<div
v-else
class="header-img-box-list"
class="w-full h-full object-cover flex items-center justify-center"
>
<el-icon class="lost-image">
<el-icon :size="32">
<icon-picture />
</el-icon>
</div>
@@ -174,9 +100,10 @@
</el-image>
</div>
<div
class="img-title"
class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full"
@click="editFileNameFunc(item)"
>{{ item.name }}
>
{{ item.name }}
</div>
</div>
</div>
@@ -202,7 +129,8 @@ import UploadImage from '@/components/upload/image.vue'
import UploadCommon from '@/components/upload/common.vue'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Delete, Plus, Picture as IconPicture } from '@element-plus/icons-vue'
import { Picture as IconPicture } from '@element-plus/icons-vue'
import selectComponent from '@/components/selectImage/selectComponent.vue'
const imageUrl = ref('')
const imageCommon = ref('')
@@ -259,7 +187,6 @@ const editFileNameFunc = async(row) => {
inputValue: row.name
}).then(async({ value }) => {
row.name = value
// console.log(row)
const res = await editFileName(row)
if (res.code === 0) {
ElMessage({
@@ -288,7 +215,6 @@ const listObj = {
}
const chooseImg = (url) => {
console.log(url)
if (props.fileType) {
const typeSuccess = listObj[props.fileType].some(item => {
if (url.includes(item)) {
@@ -332,135 +258,3 @@ const getImageList = async() => {
</script>
<style scoped lang="scss">
.multiple-img {
display: flex;
gap: 8px;
width: 100%;
flex-wrap: wrap;
}
.add-image {
width: 120px;
height: 120px;
line-height: 120px;
display: flex;
justify-content: center;
border-radius: 20px;
border: 1px dashed #ccc;
background-size: cover;
cursor: pointer;
}
.update-image {
cursor: pointer;
width: 120px;
height: 120px;
line-height: 120px;
display: flex;
justify-content: center;
border-radius: 20px;
border: 1px dashed #ccc;
background-repeat: no-repeat;
background-size: cover;
position: relative;
&:hover {
color: #fff;
background: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.15) 0%,
rgba(0, 0, 0, 0.15) 100%
),
radial-gradient(
at top center,
rgba(255, 255, 255, 0.4) 0%,
rgba(0, 0, 0, 0.4) 120%
) #989898;
background-blend-mode: multiply, multiply;
background-size: cover;
.update {
color: #fff;
}
.video {
opacity: 0.2;
}
}
.video-icon {
position: absolute;
left: calc(50% - 16px);
top: calc(50% - 16px);
}
video {
object-fit: cover;
max-width: 100%;
border-radius: 20px;
}
.update {
height: 120px;
width: 120px;
text-align: center;
color: transparent;
position: absolute;
}
}
.media {
display: flex;
flex-wrap: wrap;
gap: 12px;
.media-box {
width: 120px;
.img-title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 36px;
text-align: center;
cursor: pointer;
}
.header-img-box-list {
width: 120px;
height: 120px;
border: 1px dashed #ccc;
border-radius: 8px;
text-align: center;
line-height: 120px;
cursor: pointer;
overflow: hidden;
.el-image__inner {
max-width: 120px;
max-height: 120px;
vertical-align: middle;
width: unset;
height: unset;
}
.el-image {
position: relative;
}
.video-icon {
position: absolute;
left: calc(50% - 16px);
top: calc(50% - 16px);
}
video {
object-fit: cover;
max-width: 100%;
min-height: 100%;
border-radius: 8px;
}
}
}
}
</style>
+1 -1
View File
@@ -20,7 +20,7 @@ export const viteLogo = (env) => {
)
console.log(
chalk.green(
`> 当前版本:v2.6.4`
`> 当前版本:v2.6.5`
)
)
console.log(
+1 -1
View File
@@ -10,7 +10,7 @@ export default {
register(app)
console.log(`
欢迎使用 Gin-Vue-Admin
当前版本:v2.6.4
当前版本:v2.6.5
加群方式:微信:shouzi_1994 QQ群:622360840
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
+5 -18
View File
@@ -18,27 +18,14 @@ import App from './App.vue'
import { initDom } from './utils/positionToCode'
initDom()
/**
* @description 导入加载进度条,防止首屏加载时间过长,用户等待
*
* */
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
Nprogress.configure({ showSpinner: false, ease: 'ease', speed: 500 })
Nprogress.start()
/**
* 无需在这块结束,会在路由中间件中结束此块内容
* */
const app = createApp(App)
app.config.productionTip = false
app
.use(run)
.use(store)
.use(auth)
.use(router)
.mount('#app')
.use(run)
.use(store)
.use(auth)
.use(router)
.mount('#app')
export default app
+17
View File
@@ -3,6 +3,8 @@ import { useRouterStore } from '@/pinia/modules/router'
import getPageTitle from '@/utils/page'
import router from '@/router'
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
Nprogress.configure({ showSpinner: false, ease: 'ease', speed: 500 })
const whiteList = ['Login', 'Init']
@@ -75,6 +77,11 @@ router.beforeEach(async(to, from) => {
} else {
// 不在白名单中并且已经登录的时候
if (token) {
console.log(sessionStorage.getItem("needCloseAll"))
if(sessionStorage.getItem("needToHome") === 'true') {
sessionStorage.removeItem("needToHome")
return { path: '/'}
}
// 添加flag防止多次获取动态路由和栈溢出
if (!routerStore.asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
await getRouter(userStore)
@@ -110,13 +117,23 @@ router.beforeEach(async(to, from) => {
}
})
const removeLoading = () => {
const element = document.getElementById('gva-loading-box');
if (element) {
element.remove();
}
}
router.afterEach(() => {
// 路由加载完成后关闭进度条
document.getElementsByClassName('main-cont main-right')[0]?.scrollTo(0, 0)
removeLoading()
Nprogress.done()
})
router.onError(() => {
// 路由发生错误后销毁进度条
removeLoading()
Nprogress.remove()
})
+2 -2
View File
@@ -23,7 +23,7 @@ export const useAppStore = defineStore('app', () => {
Object.keys(originSetting).forEach(key => {
config[key] = originSetting[key]
if(key === 'primaryColor'){
setBodyPrimaryColor(originSetting[key])
setBodyPrimaryColor(originSetting[key],config.darkMode)
}
})
@@ -72,7 +72,7 @@ export const useAppStore = defineStore('app', () => {
const togglePrimaryColor = (e) => {
config.primaryColor = e;
setBodyPrimaryColor(e)
setBodyPrimaryColor(e,config.darkMode)
}
const toggleTabs = (e) => {
+3 -1
View File
@@ -119,5 +119,7 @@
html.dark {
/* 自定义深色背景颜色 */
--el-bg-color: rgb(30 ,41 ,59);
--el-bg-color-overlay: rgba(30 ,41 ,59, 0.8);
--el-bg-color-overlay: rgb(40 ,51 ,69);
--el-fill-color-light: rgb(15 ,23 ,42);
--el-fill-color : rgb(15 ,23 ,42);
}
+12 -1
View File
@@ -17,7 +17,7 @@
}
.gva-btn-list {
@apply mb-3 flex gap-3 items-center;
@apply mb-3 flex items-center;
}
@@ -40,3 +40,14 @@
.gva-form-box {
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded m-2;
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content{
background: var(--el-color-primary-bg) !important;
}
.el-dropdown{
outline: none;
div{
outline: none;
}
}
+1 -1
View File
@@ -505,4 +505,4 @@ ul,
ol,
li {
list-style-type: none;
}
}
+26 -5
View File
@@ -23,6 +23,12 @@ export const filterDict = (value, options) => {
}
export const filterDataSource = (dataSource, value) => {
if (Array.isArray(value)) {
return value.map(item => {
const rowLabel = dataSource && dataSource.find(i => i.value === item)
return rowLabel?.label
})
}
const rowLabel = dataSource && dataSource.find(item => item.value === value)
return rowLabel?.label
}
@@ -71,11 +77,19 @@ const hexToColor = (u,e,t)=>{
}
const generateAllColors = (u,e)=> {
let t = colorToHex(u);
const target = [10, 10, 30];
for (let a = 0; a < 3; a++)
t[a] = Math.floor((255 - t[a]) * e + t[a]);
t[a] = Math.floor(t[a] * (1 - e) + target[a] * e);
return hexToColor(t[0], t[1], t[2])
}
const generateAllLightColors = (u, e) => {
let t = colorToHex(u);
const target = [240, 248, 255]; // RGB for blue white color
for (let a = 0; a < 3; a++)
t[a] = Math.floor(t[a] * (1 - e) + target[a] * e);
return hexToColor(t[0], t[1], t[2]);
}
function addOpacityToColor(u, opacity) {
@@ -84,13 +98,20 @@ function addOpacityToColor(u, opacity) {
}
export const setBodyPrimaryColor = ( primaryColor ) =>{
export const setBodyPrimaryColor = ( primaryColor, darkMode ) =>{
let fmtColorFunc = generateAllColors
if (darkMode === 'light') {
fmtColorFunc = generateAllLightColors
}
document.documentElement.style.setProperty('--el-color-primary', primaryColor)
document.documentElement.style.setProperty('--el-color-primary-bg', addOpacityToColor(primaryColor, 0.4))
for (let times = 1; times <= 2; times++) {
document.documentElement.style.setProperty(`--el-color-primary-dark-${times}`, generateAllColors(primaryColor, times / 10))
document.documentElement.style.setProperty(`--el-color-primary-dark-${times}`, fmtColorFunc(primaryColor, times / 10))
}
for (let times = 1; times <= 10; times++) {
document.documentElement.style.setProperty(`--el-color-primary-light-${times}`, generateAllColors(primaryColor, times / 10))
document.documentElement.style.setProperty(`--el-color-primary-light-${times}`, fmtColorFunc(primaryColor, times / 10))
}
document.documentElement.style.setProperty(`--el-menu-hover-bg-color`, addOpacityToColor(primaryColor, 0.1))
document.documentElement.style.setProperty(`--el-menu-hover-bg-color`, addOpacityToColor(primaryColor, 0.2))
}
@@ -27,6 +27,10 @@ const banners = [
{
img: banner2,
link: "https://plugin.gin-vue-admin.com"
},
{
img: "https://qmplusimg.henrongyi.top/gvaDemo/k8s.jpg",
link: "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=42"
}
]
</script>
@@ -5,8 +5,8 @@
<template>
<div>
<el-table :data="tableData" stripe style="width: 100%" @row-click="toPath">
<el-table-column prop="ranking" label="排名" width="80" align="center"/>
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column prop="ranking" label="排名" width="80" align="center" />
<el-table-column prop="title" label="插件标题" show-overflow-tooltip>
<template #default="{ row }">
<a class="text-active" :href="row.link" target="_blank">{{ row.title }}</a>
@@ -83,6 +83,11 @@ const percentageFlage = ref(true)
// 选中文件的函数
const choseFile = async(e) => {
// 点击选择文件后取消 直接return
if (!e.target.files.length) {
return
}
const fileR = new FileReader() // 创建一个reader用来读取文件流
const fileInput = e.target.files[0] // 获取当前文件
const maxSize = 5 * 1024 * 1024
+1 -1
View File
@@ -4,7 +4,7 @@
<warning-bar
title="点击“文件名/备注”可以编辑文件名或者备注内容。"
/>
<div class="gva-btn-list">
<div class="gva-btn-list gap-3">
<upload-common
:image-common="imageCommon"
@on-success="getTableData"
+32 -9
View File
@@ -1,16 +1,16 @@
<template>
<div class="rounded-lg flex items-center justify-evenly w-full h-full relative bg-white md:w-screen md:h-screen md:bg-[#194bfb] overflow-hidden">
<div class="rounded-lg flex items-center justify-evenly w-full h-full relative md:w-screen md:h-screen md:bg-[#194bfb] overflow-hidden">
<div class="rounded-md w-full h-full flex items-center justify-center overflow-hidden">
<div class="oblique h-[130%] w-3/5 bg-white transform -rotate-12 absolute -ml-80" />
<div class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-80" />
<div
v-if="!page.showForm"
:class="[page.showReadme ?'slide-out-right' :'slide-in-fwd-top' ]"
>
<div class=" text-lg">
<div class="font-sans text-4xl font-bold text-center mb-4">GIN-VUE-ADMIN</div>
<p class="text-gray-600 mb-2">初始化须知</p>
<p class="text-gray-600 mb-2">1.您需有用一定的VUE和GOLANG基础</p>
<p class="text-gray-600 mb-2">2.请您确认是否已经阅读过<a
<div class="font-sans text-4xl font-bold text-center mb-4 dark:text-white">GIN-VUE-ADMIN</div>
<p class="text-gray-600 dark:text-gray-300 mb-2">初始化须知</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">1.您需有用一定的VUE和GOLANG基础</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">2.请您确认是否已经阅读过<a
class="text-blue-600 font-bold"
href="https://www.gin-vue-admin.com"
target="_blank"
@@ -19,9 +19,9 @@
href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=2"
target="_blank"
>初始化视频</a></p>
<p class="text-gray-600 mb-2">3.请您确认是否了解后续的配置流程</p>
<p class="text-gray-600 mb-2">4.如果您使用mysql数据库,请确认数据库引擎为<span class="text-red-600 font-bold text-3xl ml-2 ">innoDB</span></p>
<p class="text-gray-600 mb-2">注:开发组不为文档中书写过的内容提供无偿服务</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">3.请您确认是否了解后续的配置流程</p>
<p class="text-gray-600 dark:text-gray-300 mb-2">4.如果您使用mysql数据库,请确认数据库引擎为<span class="text-red-600 font-bold text-3xl ml-2 ">innoDB</span></p>
<p class="text-gray-600 dark:text-gray-300 mb-2">注:开发组不为文档中书写过的内容提供无偿服务</p>
<p class="flex items-center justify-between mt-8">
<el-button
type="primary"
@@ -51,6 +51,9 @@
label-width="100px"
size="large"
>
<el-form-item label="管理员密码">
<el-input v-model="form.adminPassword" placeholder="admin账号的默认密码"></el-input>
</el-form-item>
<el-form-item label="数据库类型">
<el-select
v-model="form.dbType"
@@ -201,6 +204,8 @@ const changeDB = (val) => {
switch (val) {
case 'mysql':
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'mysql',
host: '127.0.0.1',
port: '3306',
@@ -212,6 +217,8 @@ const changeDB = (val) => {
break
case 'pgsql':
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'pgsql',
host: '127.0.0.1',
port: '5432',
@@ -223,6 +230,8 @@ const changeDB = (val) => {
break
case 'oracle':
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'oracle',
host: '127.0.0.1',
port: '1521',
@@ -234,6 +243,8 @@ const changeDB = (val) => {
break
case 'mssql':
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'mssql',
host: '127.0.0.1',
port: '1433',
@@ -245,6 +256,8 @@ const changeDB = (val) => {
break
case 'sqlite':
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'sqlite',
host: '',
port: '',
@@ -256,6 +269,8 @@ const changeDB = (val) => {
break
default:
Object.assign(form, {
adminPassword:'',
reAdminPassword:'',
dbType: 'mysql',
host: '127.0.0.1',
port: '3306',
@@ -267,6 +282,14 @@ const changeDB = (val) => {
}
}
const onSubmit = async() => {
if (form.adminPassword.length < 6) {
ElMessage({
type: 'error',
message: '密码长度不能小于6位',
})
return
}
const loading = ElLoading.service({
lock: true,
text: '正在初始化数据库,请稍候',
+23 -21
View File
@@ -6,28 +6,30 @@
width : layoutSideWidth + 'px',
}"
>
<transition
:duration="{ enter: 800, leave: 100 }"
mode="out-in"
name="el-fade-in-linear"
>
<el-menu
:collapse="isCollapse"
:collapse-transition="false"
:default-active="active"
class="border-r-0 w-full"
unique-opened
@select="selectMenuItem"
<el-scrollbar>
<transition
:duration="{ enter: 800, leave: 100 }"
mode="out-in"
name="el-fade-in-linear"
>
<template v-for="item in routerStore.asyncRouters[0].children">
<aside-component
v-if="!item.hidden"
:key="item.name"
:router-info="item"
/>
</template>
</el-menu>
</transition>
<el-menu
:collapse="isCollapse"
:collapse-transition="false"
:default-active="active"
class="border-r-0 w-full"
unique-opened
@select="selectMenuItem"
>
<template v-for="item in routerStore.asyncRouters[0].children">
<aside-component
v-if="!item.hidden"
:key="item.name"
:router-info="item"
/>
</template>
</el-menu>
</transition>
</el-scrollbar>
<div
class="absolute bottom-8 right-2 w-8 h-8 bg-gray-50 dark:bg-slate-800 flex items-center justify-center rounded cursor-pointer "
:class="isCollapse ? 'right-0 left-0 mx-auto' : 'right-2'"
+1
View File
@@ -123,6 +123,7 @@ const changeUserAuth = async (id) => {
});
if (res.code === 0) {
window.sessionStorage.setItem("needCloseAll", "true");
window.sessionStorage.setItem("needToHome", "true");
window.location.reload();
}
};
+3 -3
View File
@@ -4,10 +4,10 @@
class="w-full h-full relative"
>
<div
class="rounded-lg flex items-center justify-evenly w-full h-full bg-white md:w-screen md:h-screen md:bg-[#194bfb]"
class="rounded-lg flex items-center justify-evenly w-full h-full md:w-screen md:h-screen md:bg-[#194bfb]"
>
<div class="md:w-3/5 w-10/12 h-full flex items-center justify-evenly">
<div class="oblique h-[130%] w-3/5 bg-white transform -rotate-12 absolute -ml-52" />
<div class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-52" />
<!-- 分割斜块 -->
<div class="z-[999] pt-12 pb-10 md:w-96 w-full rounded-lg flex flex-col justify-between box-border">
<div>
@@ -202,7 +202,7 @@ const loginForm = ref(null)
const picPath = ref('')
const loginFormData = reactive({
username: 'admin',
password: '123456',
password: '',
captcha: '',
captchaId: '',
openCaptcha: false,
+5 -5
View File
@@ -1,9 +1,9 @@
<template>
<div>
<div class="gva-form-box">
<div class="grid grid-cols-12 w-full gap-2">
<div class="col-span-3 h-full">
<div class="w-full h-full bg-white px-4 py-8 rounded-lg shadow-lg box-border">
<div class="user-card px-6 text-center bg-white shrink-0">
<div class="w-full h-full bg-white dark:bg-slate-900 px-4 py-8 rounded-lg shadow-lg box-border">
<div class="user-card px-6 text-center bg-white dark:bg-slate-900 shrink-0">
<div class="flex justify-center">
<SelectImage
v-model="userStore.userInfo.headerImg"
@@ -92,7 +92,7 @@
</div>
</div>
<div class="col-span-9 ">
<div class="bg-white h-full px-4 py-8 rounded-lg shadow-lg box-border">
<div class="bg-white dark:bg-slate-900 h-full px-4 py-8 rounded-lg shadow-lg box-border">
<el-tabs
v-model="activeName"
@tab-click="handleClick"
@@ -494,7 +494,7 @@ const changeEmail = async() => {
<style lang="scss">
.borderd {
@apply border-b-2 border-solid border-gray-100 border-t-0 border-r-0 border-l-0;
@apply border-b-2 border-solid border-gray-100 dark:border-gray-500 border-t-0 border-r-0 border-l-0;
&:last-child{
@apply border-b-0;
}
@@ -1,6 +1,6 @@
<template>
<div>
<div class="sticky top-0.5 z-10 bg-white">
<div class="sticky top-0.5 z-10">
<el-input
v-model="filterText"
class="w-3/5"
@@ -4,7 +4,7 @@
title="此功能仅用于创建角色和角色的many2many关系表,具体使用还须自己结合表实现业务,详情参考示例代码(客户示例)。此功能不建议使用,建议使用插件市场【组织管理功能(点击前往)】来管理资源权限。"
href="https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=36"
/>
<div class="sticky top-0.5 z-10 bg-white my-4">
<div class="sticky top-0.5 z-10 my-4">
<el-button
class="float-left"
type="primary"
@@ -1,6 +1,6 @@
<template>
<div>
<div class="sticky top-0.5 z-10 bg-white">
<div class="sticky top-0.5 z-10">
<el-input
v-model="filterText"
class="w-3/5"
+26 -12
View File
@@ -55,47 +55,61 @@
<el-card
v-if="state.disk"
class="card_item"
:body-style="{ height: '180px', 'overflow-y': 'scroll' }"
>
<template #header>
<div>Disk</div>
</template>
<div>
<el-row :gutter="10">
<el-row
v-for="(item, index) in state.disk"
:key="index"
:gutter="10"
style="margin-bottom: 2rem"
>
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="12">MountPoint</el-col>
<el-col
:span="12"
v-text="item.mountPoint"
/>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (MB)</el-col>
<el-col
:span="12"
v-text="state.disk.totalMb"
:span="12"
v-text="item.totalMb"
/>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (MB)</el-col>
<el-col
:span="12"
v-text="state.disk.usedMb"
:span="12"
v-text="item.usedMb"
/>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (GB)</el-col>
<el-col
:span="12"
v-text="state.disk.totalGb"
:span="12"
v-text="item.totalGb"
/>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (GB)</el-col>
<el-col
:span="12"
v-text="state.disk.usedGb"
:span="12"
v-text="item.usedGb"
/>
</el-row>
</el-col>
<el-col :span="12">
<el-progress
type="dashboard"
:percentage="state.disk.usedPercent"
:color="colors"
type="dashboard"
:percentage="item.usedPercent"
:color="colors"
/>
</el-col>
</el-row>
@@ -156,32 +156,52 @@
</el-form>
<el-collapse v-model="activeNames">
<el-collapse-item
title="数据源配置(此配置为高级配置,如编程基础不牢,可能导致自动化代码不可用)"
name="1"
title="数据源配置(此配置为高级配置,如编程基础不牢,可能导致自动化代码不可用)"
name="1"
>
<el-row :gutter="8">
<el-col
:span="8"
:span="3"
>
<el-select
v-model="middleDate.dataSource.association"
placeholder="关联模式"
@change="associationChange"
>
<el-option
label="一对一"
:value="1"
/>
<el-option
label="一对多"
:value="2"
/>
</el-select>
</el-col>
<el-col
:span="7"
>
<el-input
v-model="middleDate.dataSource.table"
placeholder="数据源表"
v-model="middleDate.dataSource.table"
placeholder="数据源表"
/>
</el-col>
<el-col
:span="8"
:span="7"
>
<el-input
v-model="middleDate.dataSource.label"
placeholder="展示用字段"
v-model="middleDate.dataSource.label"
placeholder="展示用字段"
/>
</el-col>
<el-col
:span="8"
:span="7"
>
<el-input
v-model="middleDate.dataSource.value"
placeholder="存储用字端"
v-model="middleDate.dataSource.value"
placeholder="存储用字端"
/>
</el-col>
</el-row>
@@ -195,6 +215,7 @@ import { toLowerCase, toSQLLine } from '@/utils/stringFun'
import { getSysDictionaryList } from '@/api/sysDictionary'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
defineOptions({
name: 'FieldDialog'
@@ -277,6 +298,24 @@ const clearOther = () => {
middleDate.value.dictType = ''
}
const associationChange = (val) => {
if (val === 2) {
ElMessageBox.confirm(
'一对多关联模式下,数据类型会改变为数组,后端表现为json,具体表现为数组模式,是否继续?',
'提示',
{
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
middleDate.value.fieldType = 'array'
}).catch(() => {
middleDate.value.dataSource.association = 1
})
}
}
const fieldDialogFrom = ref(null)
defineExpose({ fieldDialogFrom })
</script>
+60 -41
View File
@@ -2,7 +2,7 @@
<div>
<warning-bar
href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=3"
title="此功能为开发环境使用,不建议发布到生产,具体使用效果请看视频https://www.bilibili.com/video/BV1kv4y1g7nT?p=3"
title="此功能为开发环境使用,不建议发布到生产,具体使用效果请点我观看。页面数据内容会自动暂存,如需清除,请点击【清除缓存】"
/>
<!-- 从数据库直接获取字段 -->
<div class="gva-search-box">
@@ -105,6 +105,16 @@
</el-form>
</el-collapse-item>
</el-collapse>
<div class="flex justify-end">
<el-button
type="primary"
@click="clearCatch()"
>清除暂存</el-button>
<el-button
type="primary"
@click="catchData()"
>暂存</el-button>
</div>
</div>
<div class="gva-search-box">
<!-- 初始版本自动化代码工具 -->
@@ -283,18 +293,7 @@
</template>
<el-checkbox v-model="form.autoCreateMenuToSql" />
</el-form-item>
<el-form-item>
<template #label>
<el-tooltip
content="注:自动迁移生成的文件到yaml配置的对应位置"
placement="bottom"
effect="light"
>
<div> 自动移动文件 <el-icon><QuestionFilled /></el-icon></div>
</el-tooltip>
</template>
<el-checkbox v-model="form.autoMoveFile" />
</el-form-item>
</div>
</el-form>
</div>
@@ -663,6 +662,10 @@ const typeOptions = ref([
{
label: 'JSON',
value: 'json',
},
{
label: '数组',
value: 'array',
}
])
@@ -716,6 +719,7 @@ const fieldTemplate = {
fieldSearchType: '',
dictType: '',
dataSource: {
association:1,
table: '',
label: '',
value: ''
@@ -743,7 +747,6 @@ const form = ref({
businessDB: '',
autoCreateApiToSql: true,
autoCreateMenuToSql: true,
autoMoveFile: true,
gvaModel: true,
autoCreateResource: false,
fields: []
@@ -808,6 +811,14 @@ const editAndAddField = (item) => {
dialogFlag.value = true
if (item) {
addFlag.value = 'edit'
if(!item.dataSource){
item.dataSource = {
association:1,
table: '',
label: '',
value: ''
}
}
bk.value = JSON.parse(JSON.stringify(item))
dialogMiddle.value = item
} else {
@@ -912,37 +923,12 @@ const enterForm = async(isPreview) => {
if (data.headers?.success === 'false') {
return
}
if (form.value.autoMoveFile) {
ElMessage({
type: 'success',
message: '自动化代码创建成功,自动移动成功'
})
return
}
ElMessage({
type: 'success',
message: '自动化代码创建成功,正在下载'
})
const blob = new Blob([data])
const fileName = 'ginvueadmin.zip'
if ('download' in document.createElement('a')) {
// 不是IE浏览器
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
} else {
// IE 10+
window.navigator.msSaveBlob(blob, fileName)
}
clearCatch()
}
} else {
return false
}
})
}
@@ -983,7 +969,6 @@ const getColumnFunc = async() => {
form.value.abbreviation = tbHump
form.value.description = tbHump + '表'
form.value.autoCreateApiToSql = true
form.value.autoMoveFile = true
form.value.fields = []
res.data.columns &&
res.data.columns.forEach(item => {
@@ -1006,6 +991,7 @@ const getColumnFunc = async() => {
dictType: '',
front: true,
dataSource: {
association:1,
table: '',
label: '',
value: ''
@@ -1072,4 +1058,37 @@ watch(() => route.params.id, () => {
}
})
const catchData = () => {
window.sessionStorage.setItem('autoCode', JSON.stringify(form.value))
}
const getCatch = () => {
const data = window.sessionStorage.getItem('autoCode')
if(data){
form.value = JSON.parse(data)
}
}
const clearCatch = async () => {
form.value = {
structName: '',
tableName: '',
packageName: '',
package: '',
abbreviation: '',
description: '',
businessDB: '',
autoCreateApiToSql: true,
autoCreateMenuToSql: true,
gvaModel: true,
autoCreateResource: false,
fields: []
}
await nextTick()
window.sessionStorage.removeItem('autoCode')
}
getCatch()
</script>
@@ -1,5 +1,5 @@
<template>
<div>
<div class="gva-form-box">
<el-upload
drag
:action="`${path}/autoCode/installPlugin`"
+14 -11
View File
@@ -1,17 +1,20 @@
<template>
<div class="p-5 bg-white">
<WarningBar title="目前只支持标准插件(通过插件模板生成的标准目录插件),非标准插件请自行打包" />
<div class="flex items-center gap-3">
<el-input
v-model="plugName"
placeholder="插件模板处填写的【插件名】"
/>
<el-button
type="primary"
@click="pubPlugin"
>打包插件</el-button>
<div class="gva-form-box">
<div class="p-4 bg-white dark:bg-slate-900">
<WarningBar title="目前只支持标准插件(通过插件模板生成的标准目录插件),非标准插件请自行打包" />
<div class="flex items-center gap-3">
<el-input
v-model="plugName"
placeholder="插件模板处填写的【插件名】"
/>
<el-button
type="primary"
@click="pubPlugin"
>打包插件</el-button>
</div>
</div>
</div>
</template>
<script setup>
+1 -1
View File
@@ -549,7 +549,7 @@ const email = async() => {
<style lang="scss">
.system {
@apply bg-white p-9 rounded;
@apply bg-white p-9 rounded dark:bg-slate-900;
h2 {
@apply p-2.5 my-2.5 text-lg shadow;
}
+1 -1
View File
@@ -50,7 +50,7 @@ export default ({
}
const config = {
base: './', // index.html文件所在位置
base: '/', // index.html文件所在位置
root: './', // js导入的资源路径,src
resolve: {
alias,