Browse Source

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

1319612909 4 years ago
parent
commit
5411dde193

+ 6 - 6
server/api/v1/sys_authority.go

@@ -28,7 +28,7 @@ func CreateAuthority(c *gin.Context) {
 	}
 	if err, authBack := service.CreateAuthority(authority); err != nil {
 		global.GVA_LOG.Error("创建失败!", zap.Any("err", err))
-		response.FailWithMessage("创建失败", c)
+		response.FailWithMessage("创建失败"+err.Error(), c)
 	} else {
 		response.OkWithDetailed(response.SysAuthorityResponse{Authority: authBack}, "创建成功", c)
 	}
@@ -55,7 +55,7 @@ func CopyAuthority(c *gin.Context) {
 	}
 	if err, authBack := service.CopyAuthority(copyInfo); err != nil {
 		global.GVA_LOG.Error("拷贝失败!", zap.Any("err", err))
-		response.FailWithMessage("拷贝失败", c)
+		response.FailWithMessage("拷贝失败"+err.Error(), c)
 	} else {
 		response.OkWithDetailed(response.SysAuthorityResponse{Authority: authBack}, "拷贝成功", c)
 	}
@@ -78,7 +78,7 @@ func DeleteAuthority(c *gin.Context) {
 	}
 	if err := service.DeleteAuthority(&authority); err != nil { // 删除角色之前需要判断是否有用户正在使用此角色
 		global.GVA_LOG.Error("删除失败!", zap.Any("err", err))
-		response.FailWithMessage("删除失败", c)
+		response.FailWithMessage("删除失败"+err.Error(), c)
 	} else {
 		response.OkWithMessage("删除成功", c)
 	}
@@ -101,7 +101,7 @@ func UpdateAuthority(c *gin.Context) {
 	}
 	if err, authority := service.UpdateAuthority(auth); err != nil {
 		global.GVA_LOG.Error("更新失败!", zap.Any("err", err))
-		response.FailWithMessage("更新失败", c)
+		response.FailWithMessage("更新失败"+err.Error(), c)
 	} else {
 		response.OkWithDetailed(response.SysAuthorityResponse{Authority: authority}, "更新成功", c)
 	}
@@ -124,7 +124,7 @@ func GetAuthorityList(c *gin.Context) {
 	}
 	if err, list, total := service.GetAuthorityInfoList(pageInfo); err != nil {
 		global.GVA_LOG.Error("获取失败!", zap.Any("err", err))
-		response.FailWithMessage("获取失败", c)
+		response.FailWithMessage("获取失败"+err.Error(), c)
 	} else {
 		response.OkWithDetailed(response.PageResult{
 			List:     list,
@@ -152,7 +152,7 @@ func SetDataAuthority(c *gin.Context) {
 	}
 	if err := service.SetDataAuthority(auth); err != nil {
 		global.GVA_LOG.Error("设置失败!", zap.Any("err", err))
-		response.FailWithMessage("设置失败", c)
+		response.FailWithMessage("设置失败"+err.Error(), c)
 	} else {
 		response.OkWithMessage("设置成功", c)
 	}

+ 5 - 45
server/api/v1/sys_auto_code.go

@@ -30,51 +30,11 @@ func CreateTemp(c *gin.Context) {
 		return
 	}
 	if a.AutoCreateApiToSql {
-		apiList := [6]model.SysApi{
-			{
-				Path:        "/" + a.Abbreviation + "/" + "create" + a.StructName,
-				Description: "新增" + a.Description,
-				ApiGroup:    a.Abbreviation,
-				Method:      "POST",
-			},
-			{
-				Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName,
-				Description: "删除" + a.Description,
-				ApiGroup:    a.Abbreviation,
-				Method:      "DELETE",
-			},
-			{
-				Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds",
-				Description: "批量删除" + a.Description,
-				ApiGroup:    a.Abbreviation,
-				Method:      "DELETE",
-			},
-			{
-				Path:        "/" + a.Abbreviation + "/" + "update" + a.StructName,
-				Description: "更新" + a.Description,
-				ApiGroup:    a.Abbreviation,
-				Method:      "PUT",
-			},
-			{
-				Path:        "/" + a.Abbreviation + "/" + "find" + a.StructName,
-				Description: "根据ID获取" + a.Description,
-				ApiGroup:    a.Abbreviation,
-				Method:      "GET",
-			},
-			{
-				Path:        "/" + a.Abbreviation + "/" + "get" + a.StructName + "List",
-				Description: "获取" + a.Description + "列表",
-				ApiGroup:    a.Abbreviation,
-				Method:      "GET",
-			},
-		}
-		for _, v := range apiList {
-			if err := service.AutoCreateApi(v); err != nil {
-				global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Any("err", err))
-				c.Writer.Header().Add("success", "false")
-				c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!"))
-				return
-			}
+		if err := service.AutoCreateApi(&a); err != nil {
+			global.GVA_LOG.Error("自动化创建失败!请自行清空垃圾数据!", zap.Any("err", err))
+			c.Writer.Header().Add("success", "false")
+			c.Writer.Header().Add("msg", url.QueryEscape("自动化创建失败!请自行清空垃圾数据!"))
+			return
 		}
 	}
 	err := service.CreateTemp(a)

+ 1 - 1
server/api/v1/sys_system.go

@@ -72,7 +72,7 @@ func GetServerInfo(c *gin.Context) {
 		global.GVA_LOG.Error("获取失败!", zap.Any("err", err))
 		response.FailWithMessage("获取失败", c)
 		return
-	}else {
+	} else {
 		response.OkWithDetailed(gin.H{"server": server}, "获取成功", c)
 	}
 

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

@@ -32,7 +32,7 @@ func Login(c *gin.Context) {
 		U := &model.SysUser{Username: L.Username, Password: L.Password}
 		if err, user := service.Login(U); err != nil {
 			global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误", zap.Any("err", err))
-			response.FailWithMessage("登陆失败!", c)
+			response.FailWithMessage("用户名不存在或者密码错误", c)
 		} else {
 			tokenNext(c, *user)
 		}

+ 53 - 0
server/cmd/gva/run.go

@@ -0,0 +1,53 @@
+/*
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package gva
+
+import (
+	"gin-vue-admin/utils"
+	"github.com/spf13/cobra"
+	"os"
+)
+
+// runCmd represents the run command
+var runCmd = &cobra.Command{
+	Use:   "run",
+	Short: "running go codes with hot-compiled-like feature",
+	Long: `
+	The "run" command is used for running go codes with hot-compiled-like feature,     
+	which compiles and runs the go codes asynchronously when codes change.
+`,
+	Run: func(cmd *cobra.Command, args []string) {
+		w := utils.NewWatch()
+		t := utils.NewT()
+		path, _ := os.Getwd()
+		go w.Watch(path, t)
+		t.RunTask()
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(runCmd)
+
+	// Here you will define your flags and configuration settings.
+
+	// Cobra supports Persistent Flags which will work for this command
+	// and all subcommands, e.g.:
+	// runCmd.PersistentFlags().String("foo", "", "A help for foo")
+
+	// Cobra supports local flags which will only run when this command
+	// is called directly, e.g.:
+	// runCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}

+ 1 - 1
server/go.mod

@@ -1,6 +1,6 @@
 module gin-vue-admin
 
-go 1.12
+go 1.14
 
 require (
 	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect

+ 3 - 3
server/model/sys_base_menu.go

@@ -29,7 +29,7 @@ type Meta struct {
 type SysBaseMenuParameter struct {
 	global.GVA_MODEL
 	SysBaseMenuID uint
-	Type          string `json:"type" gorm:"commit:'地址栏携带参数为params还是query'"`
-	Key           string `json:"key" gorm:"commit:'地址栏携带参数的key'"`
-	Value         string `json:"value" gorm:"commit:'地址栏携带参数的值'"`
+	Type          string `json:"type" gorm:"comment:地址栏携带参数为params还是query"`
+	Key           string `json:"key" gorm:"comment:地址栏携带参数的key"`
+	Value         string `json:"value" gorm:"comment:地址栏携带参数的值"`
 }

+ 0 - 22
server/service/sys_api.go

@@ -33,28 +33,6 @@ func DeleteApi(api model.SysApi) (err error) {
 	return err
 }
 
-//@author: [piexlmax](https://github.com/piexlmax)
-//@function: CreateApi
-//@description: 自动创建api数据,
-//@param: api model.SysApi
-//@return: err error
-
-func AutoCreateApi(api model.SysApi) (err error) {
-	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
-		var fApi model.SysApi
-		var txErr error
-		fxErr := tx.Where("path = ? AND method = ?", api.Path, api.Method).First(&fApi).Error
-		if errors.Is(fxErr, gorm.ErrRecordNotFound) {
-			txErr = tx.Create(&api).Error
-			if txErr != nil{
-				return txErr
-			}
-		}
-		return nil
-	})
-	return err
-}
-
 //@author: [piexlmax](https://github.com/piexlmax)
 //@function: GetAPIInfoList
 //@description: 分页获取数据,

+ 63 - 0
server/service/sys_auto_code.go

@@ -7,6 +7,7 @@ import (
 	"gin-vue-admin/model"
 	"gin-vue-admin/model/request"
 	"gin-vue-admin/utils"
+	"gorm.io/gorm"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -207,3 +208,65 @@ func addAutoMoveFile(data *tplData) {
 		}
 	}
 }
+
+
+//@author: [piexlmax](https://github.com/piexlmax)
+//@author: [SliverHorn](https://github.com/SliverHorn)
+//@function: CreateApi
+//@description: 自动创建api数据,
+//@param: a *model.AutoCodeStruct
+//@return: error
+
+func AutoCreateApi(a *model.AutoCodeStruct) (err error) {
+	var apiList = []model.SysApi{
+		{
+			Path:        "/" + a.Abbreviation + "/" + "create" + a.StructName,
+			Description: "新增" + a.Description,
+			ApiGroup:    a.Abbreviation,
+			Method:      "POST",
+		},
+		{
+			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName,
+			Description: "删除" + a.Description,
+			ApiGroup:    a.Abbreviation,
+			Method:      "DELETE",
+		},
+		{
+			Path:        "/" + a.Abbreviation + "/" + "delete" + a.StructName + "ByIds",
+			Description: "批量删除" + a.Description,
+			ApiGroup:    a.Abbreviation,
+			Method:      "DELETE",
+		},
+		{
+			Path:        "/" + a.Abbreviation + "/" + "update" + a.StructName,
+			Description: "更新" + a.Description,
+			ApiGroup:    a.Abbreviation,
+			Method:      "PUT",
+		},
+		{
+			Path:        "/" + a.Abbreviation + "/" + "find" + a.StructName,
+			Description: "根据ID获取" + a.Description,
+			ApiGroup:    a.Abbreviation,
+			Method:      "GET",
+		},
+		{
+			Path:        "/" + a.Abbreviation + "/" + "get" + a.StructName + "List",
+			Description: "获取" + a.Description + "列表",
+			ApiGroup:    a.Abbreviation,
+			Method:      "GET",
+		},
+	}
+	err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
+		for _, v := range apiList {
+			var api model.SysApi
+			if err := tx.Where("path = ? AND method = ?", v.Path, v.Method).First(&api).Error; err != nil {
+				return err
+			}
+			if err := tx.Create(&v).Error; err != nil { // 遇到错误时回滚事务
+				return err
+			}
+		}
+		return nil
+	})
+	return err
+}

+ 12 - 12
server/service/sys_base_menu.go

@@ -58,26 +58,26 @@ func UpdateBaseMenu(menu model.SysBaseMenu) (err error) {
 				return errors.New("存在相同name修改失败")
 			}
 		}
-		err = tx.Delete(&model.SysBaseMenuParameter{}, "sys_base_menu_id = ?", menu.ID).Error
-		if err != nil {
-			global.GVA_LOG.Debug(err.Error())
-			return err
+		txErr := tx.Unscoped().Delete(&model.SysBaseMenuParameter{}, "sys_base_menu_id = ?", menu.ID).Error
+		if txErr != nil {
+			global.GVA_LOG.Debug(txErr.Error())
+			return txErr
 		}
 		if len(menu.Parameters) > 0 {
 			for k, _ := range menu.Parameters {
 				menu.Parameters[k].SysBaseMenuID = menu.ID
 			}
-			err = tx.Create(&menu.Parameters).Error
-			if err != nil {
-				global.GVA_LOG.Debug(err.Error())
-				return err
+			txErr = tx.Create(&menu.Parameters).Error
+			if txErr != nil {
+				global.GVA_LOG.Debug(txErr.Error())
+				return txErr
 			}
 		}
 
-		err = db.Updates(upDateMap).Error
-		if err != nil {
-			global.GVA_LOG.Debug(err.Error())
-			return err
+		txErr = db.Updates(upDateMap).Error
+		if txErr != nil {
+			global.GVA_LOG.Debug(txErr.Error())
+			return txErr
 		}
 		return nil
 	})

+ 140 - 0
server/utils/cmd_Task.go

@@ -0,0 +1,140 @@
+package utils
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"sync"
+)
+
+type RunTask interface {
+	AddTask()
+	RunTask()
+}
+
+// T: Task任务
+type T struct {
+	sync.Mutex
+
+	// ch: 获取事件channel
+	ch chan struct{}
+
+	closeChan chan struct{}
+
+	// 记录process对象
+	p *os.Process
+
+	// f: 执行任务
+	f func(chan struct{}) error
+}
+
+// NewT: 实例化方法
+func NewT() *T {
+	return newT(nil)
+}
+func newT(f func(chan struct{}) error) *T {
+	t := &T{
+		Mutex:     sync.Mutex{},
+		ch:        make(chan struct{}, 1),
+		closeChan: make(chan struct{}),
+		f:         f,
+	}
+	if f == nil {
+		t.f = t.DefaultF
+	}
+	return t
+}
+
+func (t *T) AddTask() {
+	t.Lock()
+	defer t.Unlock()
+	if len(t.ch) == 1 {
+		// 代表已经有任务了
+		// 直接丢弃这次任务
+		return
+	}
+	t.ch <- struct{}{}
+}
+
+func (t *T) RunTask() {
+	fmt.Println("进入")
+	// 这里做的make 是用于关闭上一个执行的任务
+	ch := make(chan struct{})
+	// 先run服务
+	go t.f(ch)
+	for {
+		_, ok := <-t.ch
+		ch <- struct{}{}
+		if !ok {
+			return
+		}
+		// 等待上一个关闭
+		<-t.closeChan
+		go t.f(ch)
+	}
+
+}
+
+// DefaultF: 默认的StartFunction
+func (t *T) DefaultF(ch chan struct{}) error {
+
+	var buildCmd *exec.Cmd
+	var cmd *exec.Cmd
+
+	// 判断是否有makefile
+	_, err := os.Stat(filepath.Join("Makefile"))
+	if runtime.GOOS != "windows" && err != nil {
+		_, err := exec.LookPath("make")
+		if err == nil {
+			cmd = exec.Command("makefile")
+			goto makefile
+		}
+	}
+	// 检测系统是否有编译环境
+	_, err = exec.LookPath("go")
+	if err != nil {
+		return err
+	}
+	// build
+
+	switch runtime.GOOS {
+	case "windows":
+		buildCmd = exec.Command("go", "build", "-o", "gva.exe", "main.go")
+	default:
+		buildCmd = exec.Command("go", "build", "-o", "gva", "main.go")
+	}
+
+	err = buildCmd.Run()
+	fmt.Println("build 执行完成")
+	if err != nil {
+		return err
+	}
+	// 执行
+
+	switch runtime.GOOS {
+	case "windows":
+		cmd = exec.Command("gva.exe")
+	default:
+		cmd = exec.Command("./gva")
+	}
+makefile:
+	// 开始执行任务
+	err = cmd.Start()
+	if err != nil {
+		return err
+	}
+	t.p = cmd.Process
+	fmt.Println("pid", t.p.Pid)
+	go func() {
+		err = cmd.Wait()
+	}()
+	<-ch
+	// 回收资源
+	err = cmd.Process.Kill()
+	fmt.Println("kill err", err)
+	// 发送关闭完成信号
+	t.closeChan <- struct{}{}
+	return err
+}

+ 127 - 0
server/utils/cmd_monitor.go

@@ -0,0 +1,127 @@
+package utils
+
+import (
+	"errors"
+	"fmt"
+	"github.com/fsnotify/fsnotify"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+)
+
+// Watch: 监控对象
+type Watch struct {
+	*fsnotify.Watcher
+}
+
+func NewWatch() *Watch {
+	obj, _ := fsnotify.NewWatcher()
+	return &Watch{obj}
+}
+
+// Watch: 监控对象
+func (w *Watch) Watch(path string, t *T) error {
+	// 先转化为绝对路径
+	path, err := filepath.Abs(path)
+	if err != nil {
+		return err
+	}
+	// 判断是单个文件还是目录文件
+	fileInfo, err := os.Stat(path)
+	if err != nil {
+		return err
+	}
+	// 判断是否是目录 添加监控
+	if fileInfo.IsDir() {
+		// dir
+		err = w.watchDir(path)
+
+	} else {
+		err = w.watchFile(path)
+
+	}
+	if err != nil {
+		return err
+	}
+	c := make(chan error)
+	// 启动监控
+	go func() {
+		for {
+			select {
+			case even, ok := <-w.Events:
+				if !ok {
+					// close
+					fmt.Println("Errors close")
+					c <- errors.New("errors close")
+					return
+				}
+				// 判断时间
+				fmt.Println("even", even)
+				switch {
+				// todo 待处理
+				case even.Op&fsnotify.Create == fsnotify.Create:
+					//这里获取新创建文件的信息,如果是目录,则加入监控中
+					fmt.Println("创建文件 : ", even.Name)
+					//t.AddTask()
+					_ = w.Add(even.Name)
+				case even.Op&fsnotify.Write == fsnotify.Write:
+					fmt.Println("修改 : ", even.Name)
+					fmt.Println(filepath.Ext(even.Name))
+					if filepath.Ext(even.Name) == ".go" {
+						fmt.Println("send addtask:", even.Name)
+						t.AddTask()
+					}
+				case even.Op&fsnotify.Remove == fsnotify.Remove:
+					fmt.Println("删除 : ", even.Name)
+					//t.AddTask()
+					_ = w.Remove(even.Name)
+				case even.Op&fsnotify.Rename == fsnotify.Rename:
+					fmt.Println("重命名 : ", even.Name)
+					//t.AddTask()
+					_ = w.Remove(even.Name)
+				}
+			case err = <-w.Errors:
+				fmt.Println("79", err)
+				c <- err
+				return
+			}
+		}
+	}()
+	return <-c
+
+}
+
+// watchDir: 处理监控目录
+func (w *Watch) watchDir(path string) error {
+	// 先将自己添加到监控
+	err := w.Add(path)
+
+	if err != nil {
+		return err
+	}
+	fileSlice, err := ioutil.ReadDir(path)
+	if err != nil {
+		return err
+	}
+	for _, f := range fileSlice {
+		fPath := filepath.Join(path, f.Name())
+		if !f.IsDir() {
+			// todo 这里加一些条件筛选添加监控的内容
+			err = w.watchFile(fPath)
+			if err != nil {
+				return err
+			}
+		} else {
+			err := w.watchDir(fPath)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return err
+}
+
+// watchDir: 处理监控单文件
+func (w *Watch) watchFile(path string) error {
+	return w.Add(path)
+}