mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	feat: 目录及代码优化调整
This commit is contained in:
		
							
								
								
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							@@ -9,7 +9,7 @@
 | 
				
			|||||||
            "type": "go",
 | 
					            "type": "go",
 | 
				
			||||||
            "request": "launch",
 | 
					            "request": "launch",
 | 
				
			||||||
            "mode": "auto",
 | 
					            "mode": "auto",
 | 
				
			||||||
            "program": "${fileDirname}/../main.go",
 | 
					            "program": "${fileDirname}/main.go",
 | 
				
			||||||
            "env": {},
 | 
					            "env": {},
 | 
				
			||||||
            "args": []
 | 
					            "args": []
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
package model
 | 
					package biz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,6 +24,12 @@ func IsTrue(exp bool, msg string, params ...interface{}) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsTrueBy(exp bool, err BizError) {
 | 
				
			||||||
 | 
						if !exp {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NotEmpty(str string, msg string, params ...interface{}) {
 | 
					func NotEmpty(str string, msg string, params ...interface{}) {
 | 
				
			||||||
	if str == "" {
 | 
						if str == "" {
 | 
				
			||||||
		panic(NewBizErr(fmt.Sprintf(msg, params...)))
 | 
							panic(NewBizErr(fmt.Sprintf(msg, params...)))
 | 
				
			||||||
							
								
								
									
										41
									
								
								base/biz/bizerror.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								base/biz/bizerror.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					package biz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 业务错误
 | 
				
			||||||
 | 
					type BizError struct {
 | 
				
			||||||
 | 
						code int16
 | 
				
			||||||
 | 
						err  string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						SuccessCode = 200
 | 
				
			||||||
 | 
						SuccessMsg  = "success"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BizErrorCode = 400
 | 
				
			||||||
 | 
						BizErrorMsg  = "error"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ServerErrorCode = 500
 | 
				
			||||||
 | 
						ServerErrorMsg  = "server error"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TokenErrorCode = 501
 | 
				
			||||||
 | 
						TokenErrorMsg  = "token error"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 错误消息
 | 
				
			||||||
 | 
					func (e *BizError) Error() string {
 | 
				
			||||||
 | 
						return e.err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 错误码
 | 
				
			||||||
 | 
					func (e *BizError) Code() int16 {
 | 
				
			||||||
 | 
						return e.code
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建业务逻辑错误结构体,默认为业务逻辑错误
 | 
				
			||||||
 | 
					func NewBizErr(msg string) *BizError {
 | 
				
			||||||
 | 
						return &BizError{code: BizErrorCode, err: msg}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建业务逻辑错误结构体,可设置指定错误code
 | 
				
			||||||
 | 
					func NewBizErrCode(code int16, msg string) *BizError {
 | 
				
			||||||
 | 
						return &BizError{code: code, err: msg}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,12 +2,11 @@ package base
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
 | 
						"mayfly-go/base/mlog"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/base/token"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/beego/beego/v2/core/logs"
 | 
					 | 
				
			||||||
	"github.com/beego/beego/v2/core/validation"
 | 
						"github.com/beego/beego/v2/core/validation"
 | 
				
			||||||
	"github.com/beego/beego/v2/server/web"
 | 
						"github.com/beego/beego/v2/server/web"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -25,7 +24,7 @@ type operationFunc func(loginAccount *ctx.LoginAccount)
 | 
				
			|||||||
// 将请求体的json赋值给指定的结构体
 | 
					// 将请求体的json赋值给指定的结构体
 | 
				
			||||||
func (c *Controller) UnmarshalBody(data interface{}) {
 | 
					func (c *Controller) UnmarshalBody(data interface{}) {
 | 
				
			||||||
	err := json.Unmarshal(c.Ctx.Input.RequestBody, data)
 | 
						err := json.Unmarshal(c.Ctx.Input.RequestBody, data)
 | 
				
			||||||
	model.BizErrIsNil(err, "request body解析错误")
 | 
						biz.BizErrIsNil(err, "request body解析错误")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 校验表单数据
 | 
					// 校验表单数据
 | 
				
			||||||
@@ -37,7 +36,7 @@ func (c *Controller) validForm(form interface{}) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if !b {
 | 
						if !b {
 | 
				
			||||||
		e := valid.Errors[0]
 | 
							e := valid.Errors[0]
 | 
				
			||||||
		panic(model.NewBizErr(e.Field + " " + e.Message))
 | 
							panic(biz.NewBizErr(e.Field + " " + e.Message))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,72 +47,61 @@ func (c *Controller) UnmarshalBodyAndValid(data interface{}) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 返回数据
 | 
					// 返回数据
 | 
				
			||||||
// @param checkToken  是否校验token
 | 
					// @param reqCtx  请求上下文
 | 
				
			||||||
// @param getData  获取数据的回调函数
 | 
					// @param getData  获取数据的回调函数
 | 
				
			||||||
func (c *Controller) ReturnData(checkToken bool, getData getDataFunc) {
 | 
					func (c *Controller) ReturnData(reqCtx *ctx.ReqCtx, getData getDataFunc) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if err := recover(); err != nil {
 | 
							if err := recover(); err != nil {
 | 
				
			||||||
 | 
								ctx.ApplyAfterHandler(reqCtx, err.(error))
 | 
				
			||||||
			c.parseErr(err)
 | 
								c.parseErr(err)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// 应用所有请求后置处理器
 | 
				
			||||||
 | 
								ctx.ApplyAfterHandler(reqCtx, nil)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	var loginAccount *ctx.LoginAccount
 | 
						reqCtx.Req = c.Ctx.Request
 | 
				
			||||||
	if checkToken {
 | 
						// 调用请求前所有处理器
 | 
				
			||||||
		loginAccount = c.CheckToken()
 | 
						err := ctx.ApplyBeforeHandler(reqCtx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.Success(getData(loginAccount))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 返回数据
 | 
						resp := getData(reqCtx.LoginAccount)
 | 
				
			||||||
// @param checkToken  是否校验token
 | 
						c.Success(resp)
 | 
				
			||||||
// @param getData  获取数据的回调函数
 | 
						reqCtx.RespObj = resp
 | 
				
			||||||
func (c *Controller) ReturnDataWithPermisison(permission ctx.Permission, getData getDataFunc) {
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if err := recover(); err != nil {
 | 
					 | 
				
			||||||
			c.parseErr(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	var logMsg string
 | 
					 | 
				
			||||||
	var loginAccount *ctx.LoginAccount
 | 
					 | 
				
			||||||
	if permission.CheckToken {
 | 
					 | 
				
			||||||
		loginAccount = c.CheckToken()
 | 
					 | 
				
			||||||
		logMsg = fmt.Sprintf("[uid=%d, uname=%s]\n", loginAccount.Id, loginAccount.Username)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	c.Success(getData(loginAccount))
 | 
					 | 
				
			||||||
	logs.Info(logMsg)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 无返回数据的操作,如新增修改等无需返回数据的操作
 | 
					// 无返回数据的操作,如新增修改等无需返回数据的操作
 | 
				
			||||||
// @param checkToken  是否校验token
 | 
					// @param reqCtx  请求上下文
 | 
				
			||||||
func (c *Controller) Operation(checkToken bool, operation operationFunc) {
 | 
					func (c *Controller) Operation(reqCtx *ctx.ReqCtx, operation operationFunc) {
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
		if err := recover(); err != nil {
 | 
							if err := recover(); err != nil {
 | 
				
			||||||
 | 
								ctx.ApplyAfterHandler(reqCtx, err.(error))
 | 
				
			||||||
			c.parseErr(err)
 | 
								c.parseErr(err)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ctx.ApplyAfterHandler(reqCtx, nil)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	var loginAccount *ctx.LoginAccount
 | 
						reqCtx.Req = c.Ctx.Request
 | 
				
			||||||
	if checkToken {
 | 
						// 调用请求前所有处理器
 | 
				
			||||||
		loginAccount = c.CheckToken()
 | 
						err := ctx.ApplyBeforeHandler(reqCtx)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operation(loginAccount)
 | 
					 | 
				
			||||||
	c.SuccessNoData()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 校验token,并返回登录者账号信息
 | 
						operation(reqCtx.LoginAccount)
 | 
				
			||||||
func (c *Controller) CheckToken() *ctx.LoginAccount {
 | 
						c.SuccessNoData()
 | 
				
			||||||
	tokenStr := c.Ctx.Input.Header("Authorization")
 | 
					
 | 
				
			||||||
	loginAccount, err := token.ParseToken(tokenStr)
 | 
						// 不记录返回结果
 | 
				
			||||||
	if err != nil || loginAccount == nil {
 | 
						reqCtx.RespObj = 0
 | 
				
			||||||
		panic(model.NewBizErrCode(model.TokenErrorCode, model.TokenErrorMsg))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return loginAccount
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取分页参数
 | 
					// 获取分页参数
 | 
				
			||||||
func (c *Controller) GetPageParam() *model.PageParam {
 | 
					func (c *Controller) GetPageParam() *model.PageParam {
 | 
				
			||||||
	pn, err := c.GetInt("pageNum", 1)
 | 
						pn, err := c.GetInt("pageNum", 1)
 | 
				
			||||||
	model.BizErrIsNil(err, "pageNum参数错误")
 | 
						biz.BizErrIsNil(err, "pageNum参数错误")
 | 
				
			||||||
	ps, serr := c.GetInt("pageSize", 10)
 | 
						ps, serr := c.GetInt("pageSize", 10)
 | 
				
			||||||
	model.BizErrIsNil(serr, "pageSize参数错误")
 | 
						biz.BizErrIsNil(serr, "pageSize参数错误")
 | 
				
			||||||
	return &model.PageParam{PageNum: pn, PageSize: ps}
 | 
						return &model.PageParam{PageNum: pn, PageSize: ps}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -134,7 +122,7 @@ func (c *Controller) SuccessNoData() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 返回业务错误
 | 
					// 返回业务错误
 | 
				
			||||||
func (c *Controller) BizError(bizError model.BizError) {
 | 
					func (c *Controller) BizError(bizError *biz.BizError) {
 | 
				
			||||||
	c.Result(model.Error(bizError.Code(), bizError.Error()))
 | 
						c.Result(model.Error(bizError.Code(), bizError.Error()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,20 +134,20 @@ func (c *Controller) ServerError() {
 | 
				
			|||||||
// 解析error,并对不同error返回不同result
 | 
					// 解析error,并对不同error返回不同result
 | 
				
			||||||
func (c *Controller) parseErr(err interface{}) {
 | 
					func (c *Controller) parseErr(err interface{}) {
 | 
				
			||||||
	switch t := err.(type) {
 | 
						switch t := err.(type) {
 | 
				
			||||||
	case model.BizError:
 | 
						case *biz.BizError:
 | 
				
			||||||
		c.BizError(t)
 | 
							c.BizError(t)
 | 
				
			||||||
		break
 | 
							break
 | 
				
			||||||
	case error:
 | 
						case error:
 | 
				
			||||||
		c.ServerError()
 | 
							c.ServerError()
 | 
				
			||||||
		logs.Error(t)
 | 
							mlog.Log.Error(t)
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
		//break
 | 
							//break
 | 
				
			||||||
	case string:
 | 
						case string:
 | 
				
			||||||
		c.ServerError()
 | 
							c.ServerError()
 | 
				
			||||||
		logs.Error(t)
 | 
							mlog.Log.Error(t)
 | 
				
			||||||
		panic(err)
 | 
							panic(err)
 | 
				
			||||||
		//break
 | 
							//break
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		logs.Error(t)
 | 
							mlog.Log.Error(t)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
package ctx
 | 
					package ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AppContext struct {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LoginAccount struct {
 | 
					type LoginAccount struct {
 | 
				
			||||||
	Id       uint64
 | 
						Id       uint64
 | 
				
			||||||
	Username string
 | 
						Username string
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										62
									
								
								base/ctx/req_ctx.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								base/ctx/req_ctx.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					package ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ReqCtx struct {
 | 
				
			||||||
 | 
						Req          *http.Request
 | 
				
			||||||
 | 
						NeedToken    bool          // 是否需要token
 | 
				
			||||||
 | 
						LoginAccount *LoginAccount // 登录账号信息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 日志相关信息
 | 
				
			||||||
 | 
						NeedLog     bool        // 是否需要记录日志
 | 
				
			||||||
 | 
						LogResp     bool        // 是否记录返回结果
 | 
				
			||||||
 | 
						Description string      // 请求描述
 | 
				
			||||||
 | 
						ReqParam    interface{} // 请求参数
 | 
				
			||||||
 | 
						RespObj     interface{} // 响应结果
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 请求前置处理器
 | 
				
			||||||
 | 
					type BeforeHandler interface {
 | 
				
			||||||
 | 
						Handler(rc *ReqCtx) error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 请求后置处理器
 | 
				
			||||||
 | 
					type AfterHandler interface {
 | 
				
			||||||
 | 
						Handler(rc *ReqCtx, err error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						BeforeHandlers []BeforeHandler
 | 
				
			||||||
 | 
						AfterHandlers  []AfterHandler
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 应用所有请求前置处理器
 | 
				
			||||||
 | 
					func ApplyBeforeHandler(rc *ReqCtx) error {
 | 
				
			||||||
 | 
						for _, e := range BeforeHandlers {
 | 
				
			||||||
 | 
							err := e.Handler(rc)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 应用所有后置处理器
 | 
				
			||||||
 | 
					func ApplyAfterHandler(rc *ReqCtx, err error) {
 | 
				
			||||||
 | 
						for _, e := range AfterHandlers {
 | 
				
			||||||
 | 
							e.Handler(rc, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 新建请求上下文,默认为需要记录日志
 | 
				
			||||||
 | 
					// @param needToken 是否需要token才可访问
 | 
				
			||||||
 | 
					// @param description 请求描述
 | 
				
			||||||
 | 
					func NewReqCtx(needToken bool, description string) *ReqCtx {
 | 
				
			||||||
 | 
						return &ReqCtx{NeedToken: needToken, Description: description, NeedLog: true}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewNoLogReqCtx(needToken bool) *ReqCtx {
 | 
				
			||||||
 | 
						return &ReqCtx{NeedToken: needToken, NeedLog: false}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										86
									
								
								base/ctx/req_log_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								base/ctx/req_log_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					package ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/mlog"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						// customFormatter := new(log.TextFormatter)
 | 
				
			||||||
 | 
						// customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
 | 
				
			||||||
 | 
						// customFormatter.FullTimestamp = true
 | 
				
			||||||
 | 
						log.SetFormatter(new(mlog.LogFormatter))
 | 
				
			||||||
 | 
						log.SetReportCaller(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						AfterHandlers = append(AfterHandlers, new(LogHandler))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LogHandler struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *LogHandler) Handler(rc *ReqCtx, err error) {
 | 
				
			||||||
 | 
						if !rc.NeedLog {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lfs := log.Fields{}
 | 
				
			||||||
 | 
						if la := rc.LoginAccount; la != nil {
 | 
				
			||||||
 | 
							lfs["uid"] = la.Id
 | 
				
			||||||
 | 
							lfs["uname"] = la.Username
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// lfs["errMsg"] = err.Error()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// switch t := err.(type) {
 | 
				
			||||||
 | 
							// case *biz.BizError:
 | 
				
			||||||
 | 
							// 	lfs["errCode"] = t.Code()
 | 
				
			||||||
 | 
							// 	break
 | 
				
			||||||
 | 
							// default:
 | 
				
			||||||
 | 
							// }
 | 
				
			||||||
 | 
							log.WithFields(lfs).Error(getErrMsg(rc, err))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// rb, _ := json.Marshal(rc.ReqParam)
 | 
				
			||||||
 | 
						// lfs["req"] = string(rb)
 | 
				
			||||||
 | 
						// // 返回结果不为空,则记录返回结果
 | 
				
			||||||
 | 
						// if rc.LogResp && !utils.IsBlank(reflect.ValueOf(rc.RespObj)) {
 | 
				
			||||||
 | 
						// 	respB, _ := json.Marshal(rc.RespObj)
 | 
				
			||||||
 | 
						// 	lfs["resp"] = string(respB)
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						log.WithFields(lfs).Info(getLogMsg(rc))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getLogMsg(rc *ReqCtx) string {
 | 
				
			||||||
 | 
						msg := rc.Description
 | 
				
			||||||
 | 
						rb, _ := json.Marshal(rc.ReqParam)
 | 
				
			||||||
 | 
						msg = msg + fmt.Sprintf("\n--> %s", string(rb))
 | 
				
			||||||
 | 
						// 返回结果不为空,则记录返回结果
 | 
				
			||||||
 | 
						if rc.LogResp && !utils.IsBlank(reflect.ValueOf(rc.RespObj)) {
 | 
				
			||||||
 | 
							respB, _ := json.Marshal(rc.RespObj)
 | 
				
			||||||
 | 
							msg = msg + fmt.Sprintf("\n<-- %s", string(respB))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return msg
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getErrMsg(rc *ReqCtx, err error) string {
 | 
				
			||||||
 | 
						msg := rc.Description
 | 
				
			||||||
 | 
						rb, _ := json.Marshal(rc.ReqParam)
 | 
				
			||||||
 | 
						msg = msg + fmt.Sprintf("\n--> %s", string(rb))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var errMsg string
 | 
				
			||||||
 | 
						switch t := err.(type) {
 | 
				
			||||||
 | 
						case *biz.BizError:
 | 
				
			||||||
 | 
							errMsg = fmt.Sprintf("\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							errMsg = fmt.Sprintf("\n<-e errMsg: %s", t.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return (msg + errMsg)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								base/ctx/req_permission_handler.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								base/ctx/req_permission_handler.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					package ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						BeforeHandlers = append(BeforeHandlers, new(PermissionHandler))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var permissionError = biz.NewBizErrCode(501, "token error")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type PermissionHandler struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *PermissionHandler) Handler(rc *ReqCtx) error {
 | 
				
			||||||
 | 
						if !rc.NeedToken {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tokenStr := rc.Req.Header.Get("Authorization")
 | 
				
			||||||
 | 
						if tokenStr == "" {
 | 
				
			||||||
 | 
							return permissionError
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						loginAccount, err := ParseToken(tokenStr)
 | 
				
			||||||
 | 
						if err != nil || loginAccount == nil {
 | 
				
			||||||
 | 
							return permissionError
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rc.LoginAccount = loginAccount
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package token
 | 
					package ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
					
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/dgrijalva/jwt-go"
 | 
						"github.com/dgrijalva/jwt-go"
 | 
				
			||||||
@@ -26,12 +26,12 @@ func CreateToken(userId uint64, username string) string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 使用自定义字符串加密 and get the complete encoded token as a string
 | 
						// 使用自定义字符串加密 and get the complete encoded token as a string
 | 
				
			||||||
	tokenString, err := token.SignedString([]byte(JwtKey))
 | 
						tokenString, err := token.SignedString([]byte(JwtKey))
 | 
				
			||||||
	model.BizErrIsNil(err, "token创建失败")
 | 
						biz.BizErrIsNil(err, "token创建失败")
 | 
				
			||||||
	return tokenString
 | 
						return tokenString
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 解析token,并返回登录者账号信息
 | 
					// 解析token,并返回登录者账号信息
 | 
				
			||||||
func ParseToken(tokenStr string) (*ctx.LoginAccount, error) {
 | 
					func ParseToken(tokenStr string) (*LoginAccount, error) {
 | 
				
			||||||
	if tokenStr == "" {
 | 
						if tokenStr == "" {
 | 
				
			||||||
		return nil, errors.New("token error")
 | 
							return nil, errors.New("token error")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -43,5 +43,5 @@ func ParseToken(tokenStr string) (*ctx.LoginAccount, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	i := token.Claims.(jwt.MapClaims)
 | 
						i := token.Claims.(jwt.MapClaims)
 | 
				
			||||||
	return &ctx.LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
 | 
						return &LoginAccount{Id: uint64(i["id"].(float64)), Username: i["username"].(string)}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										37
									
								
								base/mlog/mlog.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								base/mlog/mlog.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					package mlog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var Log = logrus.New()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						// customFormatter := new(logrus.TextFormatter)
 | 
				
			||||||
 | 
						// customFormatter.TimestampFormat = "2006-01-02 15:04:05.000"
 | 
				
			||||||
 | 
						// customFormatter.FullTimestamp = true
 | 
				
			||||||
 | 
						Log.SetFormatter(new(LogFormatter))
 | 
				
			||||||
 | 
						Log.SetReportCaller(true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LogFormatter struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (l *LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
 | 
				
			||||||
 | 
						timestamp := time.Now().Local().Format("2006-01-02 15:04:05.000")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						level := entry.Level
 | 
				
			||||||
 | 
						logMsg := fmt.Sprintf("%s [%s]", timestamp, strings.ToUpper(level.String()))
 | 
				
			||||||
 | 
						// 如果存在调用信息,且为error级别以上记录文件及行号
 | 
				
			||||||
 | 
						if caller := entry.Caller; caller != nil && level <= logrus.ErrorLevel {
 | 
				
			||||||
 | 
							logMsg = logMsg + fmt.Sprintf(" [%s:%d]", caller.File, caller.Line)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for k, v := range entry.Data {
 | 
				
			||||||
 | 
							logMsg = logMsg + fmt.Sprintf(" [%s=%v]", k, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						logMsg = logMsg + fmt.Sprintf(" : %s\n", entry.Message)
 | 
				
			||||||
 | 
						return []byte(logMsg), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,27 +0,0 @@
 | 
				
			|||||||
package model
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 业务错误
 | 
					 | 
				
			||||||
type BizError struct {
 | 
					 | 
				
			||||||
	code int16
 | 
					 | 
				
			||||||
	err  string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 错误消息
 | 
					 | 
				
			||||||
func (e *BizError) Error() string {
 | 
					 | 
				
			||||||
	return e.err
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 错误码
 | 
					 | 
				
			||||||
func (e *BizError) Code() int16 {
 | 
					 | 
				
			||||||
	return e.code
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 创建业务逻辑错误结构体,默认为业务逻辑错误
 | 
					 | 
				
			||||||
func NewBizErr(msg string) BizError {
 | 
					 | 
				
			||||||
	return BizError{code: BizErrorCode, err: msg}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 创建业务逻辑错误结构体,可设置指定错误code
 | 
					 | 
				
			||||||
func NewBizErrCode(code int16, msg string) BizError {
 | 
					 | 
				
			||||||
	return BizError{code: code, err: msg}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -2,6 +2,7 @@ package model
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
@@ -125,9 +126,9 @@ func GetPage(seter orm.QuerySeter, pageParam *PageParam, models interface{}, toM
 | 
				
			|||||||
		return PageResult{Total: 0, List: nil}
 | 
							return PageResult{Total: 0, List: nil}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, qerr := seter.Limit(pageParam.PageSize, pageParam.PageNum-1).All(models, getFieldNames(toModels)...)
 | 
						_, qerr := seter.Limit(pageParam.PageSize, pageParam.PageNum-1).All(models, getFieldNames(toModels)...)
 | 
				
			||||||
	BizErrIsNil(qerr, "查询错误")
 | 
						biz.BizErrIsNil(qerr, "查询错误")
 | 
				
			||||||
	err := utils.Copy(toModels, models)
 | 
						err := utils.Copy(toModels, models)
 | 
				
			||||||
	BizErrIsNil(err, "实体转换错误")
 | 
						biz.BizErrIsNil(err, "实体转换错误")
 | 
				
			||||||
	return PageResult{Total: count, List: toModels}
 | 
						return PageResult{Total: count, List: toModels}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -176,7 +177,7 @@ func GetListBySql(sql string, params ...interface{}) *[]orm.Params {
 | 
				
			|||||||
func GetList(seter orm.QuerySeter, model interface{}, toModel interface{}) {
 | 
					func GetList(seter orm.QuerySeter, model interface{}, toModel interface{}) {
 | 
				
			||||||
	_, _ = seter.All(model, getFieldNames(toModel)...)
 | 
						_, _ = seter.All(model, getFieldNames(toModel)...)
 | 
				
			||||||
	err := utils.Copy(toModel, model)
 | 
						err := utils.Copy(toModel, model)
 | 
				
			||||||
	BizErrIsNil(err, "实体转换错误")
 | 
						biz.BizErrIsNil(err, "实体转换错误")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 根据toModel结构体字段查询单条记录,并将值赋值给toModel
 | 
					// 根据toModel结构体字段查询单条记录,并将值赋值给toModel
 | 
				
			||||||
@@ -186,7 +187,7 @@ func GetOne(seter orm.QuerySeter, model interface{}, toModel interface{}) error
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cerr := utils.Copy(toModel, model)
 | 
						cerr := utils.Copy(toModel, model)
 | 
				
			||||||
	BizErrIsNil(cerr, "实体转换错误")
 | 
						biz.BizErrIsNil(cerr, "实体转换错误")
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,72 +0,0 @@
 | 
				
			|||||||
package model
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
					 | 
				
			||||||
	"mayfly-go/controllers/vo"
 | 
					 | 
				
			||||||
	"mayfly-go/models"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/beego/beego/v2/client/orm"
 | 
					 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type AccountDetailVO struct {
 | 
					 | 
				
			||||||
	Id       int64
 | 
					 | 
				
			||||||
	Username string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func init() {
 | 
					 | 
				
			||||||
	orm.RegisterDriver("mysql", orm.DRMySQL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	orm.RegisterDataBase("default", "mysql", "root:111049@tcp(localhost:3306)/mayfly-go?charset=utf8")
 | 
					 | 
				
			||||||
	orm.Debug = true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestGetList(t *testing.T) {
 | 
					 | 
				
			||||||
	query := QuerySetter(new(models.Account)).OrderBy("-Id")
 | 
					 | 
				
			||||||
	list := new([]AccountDetailVO)
 | 
					 | 
				
			||||||
	GetList(query, new([]models.Account), list)
 | 
					 | 
				
			||||||
	fmt.Println(list)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestGetOne(t *testing.T) {
 | 
					 | 
				
			||||||
	model := new(models.Account)
 | 
					 | 
				
			||||||
	query := QuerySetter(model).Filter("Id", 2)
 | 
					 | 
				
			||||||
	adv := new(AccountDetailVO)
 | 
					 | 
				
			||||||
	GetOne(query, model, adv)
 | 
					 | 
				
			||||||
	fmt.Println(adv)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestMap(t *testing.T) {
 | 
					 | 
				
			||||||
	//o := getOrm()
 | 
					 | 
				
			||||||
	//
 | 
					 | 
				
			||||||
	////v := new([]Account)
 | 
					 | 
				
			||||||
	//var maps []orm.Params
 | 
					 | 
				
			||||||
	//_, err := o.Raw("SELECT a.Id, a.Username, r.Id AS 'Role.Id', r.Name AS 'Role.Name' FROM " +
 | 
					 | 
				
			||||||
	//	"t_account a JOIN t_role r ON a.id = r.account_id").Values(&maps)
 | 
					 | 
				
			||||||
	//fmt.Println(err)
 | 
					 | 
				
			||||||
	//////res := new([]Account)
 | 
					 | 
				
			||||||
	////model := &Account{}
 | 
					 | 
				
			||||||
	////o.QueryTable("t_account").Filter("id", 1).RelatedSel().One(model)
 | 
					 | 
				
			||||||
	////o.LoadRelated(model, "Role")
 | 
					 | 
				
			||||||
	res := new([]vo.AccountVO)
 | 
					 | 
				
			||||||
	sql := "SELECT a.Id, a.Username, r.Id AS 'Role.Id', r.Name AS 'Role.Name' FROM t_account a JOIN t_role r ON a.id = r.account_id"
 | 
					 | 
				
			||||||
	//limitSql := sql + " LIMIT 1, 3"
 | 
					 | 
				
			||||||
	//selectIndex := strings.Index(sql, "SELECT ") + 7
 | 
					 | 
				
			||||||
	//fromIndex := strings.Index(sql, " FROM")
 | 
					 | 
				
			||||||
	//selectCol := sql[selectIndex:fromIndex]
 | 
					 | 
				
			||||||
	//countSql := strings.Replace(sql, selectCol, "COUNT(*)", 1)
 | 
					 | 
				
			||||||
	//fmt.Println(limitSql)
 | 
					 | 
				
			||||||
	//fmt.Println(selectCol)
 | 
					 | 
				
			||||||
	//fmt.Println(countSql)
 | 
					 | 
				
			||||||
	page := GetPageBySql(sql, res, &PageParam{PageNum: 1, PageSize: 1})
 | 
					 | 
				
			||||||
	fmt.Println(page)
 | 
					 | 
				
			||||||
	//return res
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCase2Camel(t *testing.T) {
 | 
					 | 
				
			||||||
	fmt.Println(utils.Case2Camel("create_time"))
 | 
					 | 
				
			||||||
	fmt.Println(strings.Title("username"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										64
									
								
								base/rediscli/rediscli.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								base/rediscli/rediscli.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					package rediscli
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/go-redis/redis"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var cli *redis.Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func SetCli(client *redis.Client) {
 | 
				
			||||||
 | 
						cli = client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetCli() *redis.Client {
 | 
				
			||||||
 | 
						return cli
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// get key value
 | 
				
			||||||
 | 
					func Get(key string) string {
 | 
				
			||||||
 | 
						val, err := cli.Get(key).Result()
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case err == redis.Nil:
 | 
				
			||||||
 | 
							fmt.Println("key does not exist")
 | 
				
			||||||
 | 
						case err != nil:
 | 
				
			||||||
 | 
							fmt.Println("Get failed", err)
 | 
				
			||||||
 | 
						case val == "":
 | 
				
			||||||
 | 
							fmt.Println("value is empty")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return val
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// set key value
 | 
				
			||||||
 | 
					func Set(key string, val string, expiration time.Duration) {
 | 
				
			||||||
 | 
						cli.Set(key, val, expiration)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func HSet(key string, field string, val interface{}) {
 | 
				
			||||||
 | 
						cli.HSet(key, field, val)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hget
 | 
				
			||||||
 | 
					func HGet(key string, field string) string {
 | 
				
			||||||
 | 
						val, _ := cli.HGet(key, field).Result()
 | 
				
			||||||
 | 
						return val
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hget
 | 
				
			||||||
 | 
					func HExist(key string, field string) bool {
 | 
				
			||||||
 | 
						val, _ := cli.HExists(key, field).Result()
 | 
				
			||||||
 | 
						return val
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hgetall
 | 
				
			||||||
 | 
					func HGetAll(key string) map[string]string {
 | 
				
			||||||
 | 
						vals, _ := cli.HGetAll(key).Result()
 | 
				
			||||||
 | 
						return vals
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hdel
 | 
				
			||||||
 | 
					func HDel(key string, fields ...string) int {
 | 
				
			||||||
 | 
						return int(cli.HDel(key, fields...).Val())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								base/utils/yml/yml.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								base/utils/yml/yml.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					package yml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"gopkg.in/yaml.v3"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 从指定路径加载yaml文件
 | 
				
			||||||
 | 
					func LoadYml(path string, out interface{}) error {
 | 
				
			||||||
 | 
						yamlFileBytes, readErr := ioutil.ReadFile(path)
 | 
				
			||||||
 | 
						if readErr != nil {
 | 
				
			||||||
 | 
							return readErr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// yaml解析
 | 
				
			||||||
 | 
						err := yaml.Unmarshal(yamlFileBytes, out)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return errors.New("无法解析 [" + path + "]")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -3,7 +3,7 @@ httpport = 8888
 | 
				
			|||||||
copyrequestbody = true
 | 
					copyrequestbody = true
 | 
				
			||||||
autorender = false
 | 
					autorender = false
 | 
				
			||||||
EnableErrorsRender = false
 | 
					EnableErrorsRender = false
 | 
				
			||||||
runmode = "dev"
 | 
					runmode = "prod"
 | 
				
			||||||
; mysqluser = "root"
 | 
					; mysqluser = "root"
 | 
				
			||||||
; mysqlpass = "111049"
 | 
					; mysqlpass = "111049"
 | 
				
			||||||
; mysqlurls = "127.0.0.1"
 | 
					; mysqlurls = "127.0.0.1"
 | 
				
			||||||
@@ -16,6 +16,6 @@ AdminHttpPort = 8088
 | 
				
			|||||||
[dev]
 | 
					[dev]
 | 
				
			||||||
httpport = 8888
 | 
					httpport = 8888
 | 
				
			||||||
[prod]
 | 
					[prod]
 | 
				
			||||||
httpport = 8080
 | 
					httpport = 8888
 | 
				
			||||||
[test]
 | 
					[test]
 | 
				
			||||||
httpport = 8888
 | 
					httpport = 8888
 | 
				
			||||||
@@ -2,11 +2,11 @@ package controllers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base"
 | 
						"mayfly-go/base"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/base/token"
 | 
						"mayfly-go/devops/controllers/form"
 | 
				
			||||||
	"mayfly-go/controllers/form"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"mayfly-go/models"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AccountController struct {
 | 
					type AccountController struct {
 | 
				
			||||||
@@ -20,14 +20,14 @@ type AccountController struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /accounts/login [post]
 | 
					// @router /accounts/login [post]
 | 
				
			||||||
func (c *AccountController) Login() {
 | 
					func (c *AccountController) Login() {
 | 
				
			||||||
	c.ReturnData(false, func(la *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewReqCtx(false, "用户登录"), func(la *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		loginForm := &form.LoginForm{}
 | 
							loginForm := &form.LoginForm{}
 | 
				
			||||||
		c.UnmarshalBodyAndValid(loginForm)
 | 
							c.UnmarshalBodyAndValid(loginForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		a := &models.Account{Username: loginForm.Username, Password: loginForm.Password}
 | 
							a := &models.Account{Username: loginForm.Username, Password: loginForm.Password}
 | 
				
			||||||
		model.BizErrIsNil(model.GetBy(a, "Username", "Password"), "用户名或密码错误")
 | 
							biz.BizErrIsNil(model.GetBy(a, "Username", "Password"), "用户名或密码错误")
 | 
				
			||||||
		return map[string]interface{}{
 | 
							return map[string]interface{}{
 | 
				
			||||||
			"token":    token.CreateToken(a.Id, a.Username),
 | 
								"token":    ctx.CreateToken(a.Id, a.Username),
 | 
				
			||||||
			"username": a.Username,
 | 
								"username": a.Username,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -35,7 +35,7 @@ func (c *AccountController) Login() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /accounts [get]
 | 
					// @router /accounts [get]
 | 
				
			||||||
func (c *AccountController) Accounts() {
 | 
					func (c *AccountController) Accounts() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewReqCtx(true, "获取账号列表"), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		//s := c.GetString("username")
 | 
							//s := c.GetString("username")
 | 
				
			||||||
		//query := models.QuerySetter(new(models.Account)).OrderBy("-Id").RelatedSel()
 | 
							//query := models.QuerySetter(new(models.Account)).OrderBy("-Id").RelatedSel()
 | 
				
			||||||
		//return models.GetPage(query, c.GetPageParam(), new([]models.Account), new([]vo.AccountVO))
 | 
							//return models.GetPage(query, c.GetPageParam(), new([]models.Account), new([]vo.AccountVO))
 | 
				
			||||||
@@ -3,12 +3,13 @@ package controllers
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base"
 | 
						"mayfly-go/base"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/controllers/form"
 | 
						"mayfly-go/devops/controllers/form"
 | 
				
			||||||
	"mayfly-go/controllers/vo"
 | 
						"mayfly-go/devops/controllers/vo"
 | 
				
			||||||
	"mayfly-go/db"
 | 
						"mayfly-go/devops/db"
 | 
				
			||||||
	"mayfly-go/models"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +19,7 @@ type DbController struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/dbs [get]
 | 
					// @router /api/dbs [get]
 | 
				
			||||||
func (c *DbController) Dbs() {
 | 
					func (c *DbController) Dbs() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		m := new([]models.Db)
 | 
							m := new([]models.Db)
 | 
				
			||||||
		querySetter := model.QuerySetter(new(models.Db))
 | 
							querySetter := model.QuerySetter(new(models.Db))
 | 
				
			||||||
		return model.GetPage(querySetter, c.GetPageParam(), m, new([]vo.SelectDataDbVO))
 | 
							return model.GetPage(querySetter, c.GetPageParam(), m, new([]vo.SelectDataDbVO))
 | 
				
			||||||
@@ -27,12 +28,14 @@ func (c *DbController) Dbs() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/select [get]
 | 
					// @router /api/db/:dbId/select [get]
 | 
				
			||||||
func (c *DbController) SelectData() {
 | 
					func (c *DbController) SelectData() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						rc := ctx.NewReqCtx(true, "执行数据库查询语句")
 | 
				
			||||||
 | 
						c.ReturnData(rc, func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		selectSql := c.GetString("selectSql")
 | 
							selectSql := c.GetString("selectSql")
 | 
				
			||||||
		model.NotEmpty(selectSql, "selectSql不能为空")
 | 
							rc.ReqParam = selectSql
 | 
				
			||||||
 | 
							biz.NotEmpty(selectSql, "selectSql不能为空")
 | 
				
			||||||
		res, err := db.GetDbInstance(c.GetDbId()).SelectData(selectSql)
 | 
							res, err := db.GetDbInstance(c.GetDbId()).SelectData(selectSql)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(model.NewBizErr(fmt.Sprintf("查询失败: %s", err.Error())))
 | 
								panic(biz.NewBizErr(fmt.Sprintf("查询失败: %s", err.Error())))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return res
 | 
							return res
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -40,12 +43,12 @@ func (c *DbController) SelectData() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/exec-sql [post]
 | 
					// @router /api/db/:dbId/exec-sql [post]
 | 
				
			||||||
func (c *DbController) ExecSql() {
 | 
					func (c *DbController) ExecSql() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewReqCtx(true, "sql执行"), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		selectSql := c.GetString("sql")
 | 
							selectSql := c.GetString("sql")
 | 
				
			||||||
		model.NotEmpty(selectSql, "sql不能为空")
 | 
							biz.NotEmpty(selectSql, "sql不能为空")
 | 
				
			||||||
		num, err := db.GetDbInstance(c.GetDbId()).Exec(selectSql)
 | 
							num, err := db.GetDbInstance(c.GetDbId()).Exec(selectSql)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			panic(model.NewBizErr(fmt.Sprintf("执行失败: %s", err.Error())))
 | 
								panic(biz.NewBizErr(fmt.Sprintf("执行失败: %s", err.Error())))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return num
 | 
							return num
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -53,16 +56,16 @@ func (c *DbController) ExecSql() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/t-metadata [get]
 | 
					// @router /api/db/:dbId/t-metadata [get]
 | 
				
			||||||
func (c *DbController) TableMA() {
 | 
					func (c *DbController) TableMA() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		return db.GetDbInstance(c.GetDbId()).GetTableMetedatas()
 | 
							return db.GetDbInstance(c.GetDbId()).GetTableMetedatas()
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/c-metadata [get]
 | 
					// @router /api/db/:dbId/c-metadata [get]
 | 
				
			||||||
func (c *DbController) ColumnMA() {
 | 
					func (c *DbController) ColumnMA() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		tn := c.GetString("tableName")
 | 
							tn := c.GetString("tableName")
 | 
				
			||||||
		model.NotEmpty(tn, "tableName不能为空")
 | 
							biz.NotEmpty(tn, "tableName不能为空")
 | 
				
			||||||
		return db.GetDbInstance(c.GetDbId()).GetColumnMetadatas(tn)
 | 
							return db.GetDbInstance(c.GetDbId()).GetColumnMetadatas(tn)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -70,7 +73,7 @@ func (c *DbController) ColumnMA() {
 | 
				
			|||||||
// @router /api/db/:dbId/hint-tables [get]
 | 
					// @router /api/db/:dbId/hint-tables [get]
 | 
				
			||||||
// 数据表及字段前端提示接口
 | 
					// 数据表及字段前端提示接口
 | 
				
			||||||
func (c *DbController) HintTables() {
 | 
					func (c *DbController) HintTables() {
 | 
				
			||||||
	c.ReturnData(false, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		dbi := db.GetDbInstance(c.GetDbId())
 | 
							dbi := db.GetDbInstance(c.GetDbId())
 | 
				
			||||||
		tables := dbi.GetTableMetedatas()
 | 
							tables := dbi.GetTableMetedatas()
 | 
				
			||||||
		res := make(map[string][]string)
 | 
							res := make(map[string][]string)
 | 
				
			||||||
@@ -94,14 +97,16 @@ func (c *DbController) HintTables() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/sql [post]
 | 
					// @router /api/db/:dbId/sql [post]
 | 
				
			||||||
func (c *DbController) SaveSql() {
 | 
					func (c *DbController) SaveSql() {
 | 
				
			||||||
	c.Operation(true, func(account *ctx.LoginAccount) {
 | 
						rc := ctx.NewReqCtx(true, "保存sql内容")
 | 
				
			||||||
 | 
						c.Operation(rc, func(account *ctx.LoginAccount) {
 | 
				
			||||||
		dbSqlForm := &form.DbSqlSaveForm{}
 | 
							dbSqlForm := &form.DbSqlSaveForm{}
 | 
				
			||||||
		c.UnmarshalBodyAndValid(dbSqlForm)
 | 
							c.UnmarshalBodyAndValid(dbSqlForm)
 | 
				
			||||||
 | 
							rc.ReqParam = dbSqlForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dbId := c.GetDbId()
 | 
							dbId := c.GetDbId()
 | 
				
			||||||
		// 判断dbId是否存在
 | 
							// 判断dbId是否存在
 | 
				
			||||||
		err := model.GetById(new(models.Db), dbId)
 | 
							err := model.GetById(new(models.Db), dbId)
 | 
				
			||||||
		model.BizErrIsNil(err, "该数据库信息不存在")
 | 
							biz.BizErrIsNil(err, "该数据库信息不存在")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
							// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
				
			||||||
		dbSql := &models.DbSql{Type: dbSqlForm.Type, DbId: dbId}
 | 
							dbSql := &models.DbSql{Type: dbSqlForm.Type, DbId: dbId}
 | 
				
			||||||
@@ -121,7 +126,7 @@ func (c *DbController) SaveSql() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/sql [get]
 | 
					// @router /api/db/:dbId/sql [get]
 | 
				
			||||||
func (c *DbController) GetSql() {
 | 
					func (c *DbController) GetSql() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
							// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
				
			||||||
		dbSql := &models.DbSql{Type: 1, DbId: c.GetDbId()}
 | 
							dbSql := &models.DbSql{Type: 1, DbId: c.GetDbId()}
 | 
				
			||||||
		dbSql.CreatorId = account.Id
 | 
							dbSql.CreatorId = account.Id
 | 
				
			||||||
@@ -135,6 +140,6 @@ func (c *DbController) GetSql() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (c *DbController) GetDbId() uint64 {
 | 
					func (c *DbController) GetDbId() uint64 {
 | 
				
			||||||
	dbId, _ := strconv.Atoi(c.Ctx.Input.Param(":dbId"))
 | 
						dbId, _ := strconv.Atoi(c.Ctx.Input.Param(":dbId"))
 | 
				
			||||||
	model.IsTrue(dbId > 0, "dbId错误")
 | 
						biz.IsTrue(dbId > 0, "dbId错误")
 | 
				
			||||||
	return uint64(dbId)
 | 
						return uint64(dbId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,10 +2,10 @@ package controllers
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base"
 | 
						"mayfly-go/base"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/ctx"
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/devops/machine"
 | 
				
			||||||
	"mayfly-go/machine"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"mayfly-go/models"
 | 
					 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,44 +25,47 @@ var upgrader = websocket.Upgrader{
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *MachineController) Machines() {
 | 
					func (c *MachineController) Machines() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		return models.GetMachineList(c.GetPageParam())
 | 
							return models.GetMachineList(c.GetPageParam())
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *MachineController) Run() {
 | 
					func (c *MachineController) Run() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						rc := ctx.NewReqCtx(true, "执行机器命令")
 | 
				
			||||||
 | 
						c.ReturnData(rc, func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		cmd := c.GetString("cmd")
 | 
							cmd := c.GetString("cmd")
 | 
				
			||||||
		model.NotEmpty(cmd, "cmd不能为空")
 | 
							biz.NotEmpty(cmd, "cmd不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc.ReqParam = cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		res, err := c.getCli().Run(cmd)
 | 
							res, err := c.getCli().Run(cmd)
 | 
				
			||||||
		model.BizErrIsNil(err, "执行命令失败")
 | 
							biz.BizErrIsNil(err, "执行命令失败")
 | 
				
			||||||
		return res
 | 
							return res
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 系统基本信息
 | 
					// 系统基本信息
 | 
				
			||||||
func (c *MachineController) SysInfo() {
 | 
					func (c *MachineController) SysInfo() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		res, err := c.getCli().GetSystemInfo()
 | 
							res, err := c.getCli().GetSystemInfo()
 | 
				
			||||||
		model.BizErrIsNil(err, "获取系统基本信息失败")
 | 
							biz.BizErrIsNil(err, "获取系统基本信息失败")
 | 
				
			||||||
		return res
 | 
							return res
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// top命令信息
 | 
					// top命令信息
 | 
				
			||||||
func (c *MachineController) Top() {
 | 
					func (c *MachineController) Top() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		return c.getCli().GetTop()
 | 
							return c.getCli().GetTop()
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *MachineController) GetProcessByName() {
 | 
					func (c *MachineController) GetProcessByName() {
 | 
				
			||||||
	c.ReturnData(true, func(account *ctx.LoginAccount) interface{} {
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
		name := c.GetString("name")
 | 
							name := c.GetString("name")
 | 
				
			||||||
		model.NotEmpty(name, "name不能为空")
 | 
							biz.NotEmpty(name, "name不能为空")
 | 
				
			||||||
		res, err := c.getCli().GetProcessByName(name)
 | 
							res, err := c.getCli().GetProcessByName(name)
 | 
				
			||||||
		model.BizErrIsNil(err, "获取失败")
 | 
							biz.BizErrIsNil(err, "获取失败")
 | 
				
			||||||
		return res
 | 
							return res
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -70,7 +73,7 @@ func (c *MachineController) GetProcessByName() {
 | 
				
			|||||||
func (c *MachineController) WsSSH() {
 | 
					func (c *MachineController) WsSSH() {
 | 
				
			||||||
	wsConn, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
 | 
						wsConn, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		panic(model.NewBizErr("获取requst responsewirte错误"))
 | 
							panic(biz.NewBizErr("获取requst responsewirte错误"))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cols, _ := c.GetInt("cols", 80)
 | 
						cols, _ := c.GetInt("cols", 80)
 | 
				
			||||||
@@ -78,7 +81,7 @@ func (c *MachineController) WsSSH() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	sws, err := machine.NewLogicSshWsSession(cols, rows, c.getCli(), wsConn)
 | 
						sws, err := machine.NewLogicSshWsSession(cols, rows, c.getCli(), wsConn)
 | 
				
			||||||
	if sws == nil {
 | 
						if sws == nil {
 | 
				
			||||||
		panic(model.NewBizErr("连接失败"))
 | 
							panic(biz.NewBizErr("连接失败"))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	//if wshandleError(wsConn, err) {
 | 
						//if wshandleError(wsConn, err) {
 | 
				
			||||||
	//	return
 | 
						//	return
 | 
				
			||||||
@@ -94,12 +97,12 @@ func (c *MachineController) WsSSH() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (c *MachineController) GetMachineId() uint64 {
 | 
					func (c *MachineController) GetMachineId() uint64 {
 | 
				
			||||||
	machineId, _ := strconv.Atoi(c.Ctx.Input.Param(":machineId"))
 | 
						machineId, _ := strconv.Atoi(c.Ctx.Input.Param(":machineId"))
 | 
				
			||||||
	model.IsTrue(machineId > 0, "machineId错误")
 | 
						biz.IsTrue(machineId > 0, "machineId错误")
 | 
				
			||||||
	return uint64(machineId)
 | 
						return uint64(machineId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *MachineController) getCli() *machine.Cli {
 | 
					func (c *MachineController) getCli() *machine.Cli {
 | 
				
			||||||
	cli, err := machine.GetCli(c.GetMachineId())
 | 
						cli, err := machine.GetCli(c.GetMachineId())
 | 
				
			||||||
	model.BizErrIsNil(err, "获取客户端错误")
 | 
						biz.BizErrIsNil(err, "获取客户端错误")
 | 
				
			||||||
	return cli
 | 
						return cli
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -4,8 +4,8 @@ import (
 | 
				
			|||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/models"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -104,12 +104,12 @@ func GetDbInstance(id uint64) *DbInstance {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	d := models.GetDbById(uint64(id))
 | 
						d := models.GetDbById(uint64(id))
 | 
				
			||||||
	model.NotNil(d, "数据库信息不存在")
 | 
						biz.NotNil(d, "数据库信息不存在")
 | 
				
			||||||
	DB, err := sql.Open(d.Type, getDsn(d))
 | 
						DB, err := sql.Open(d.Type, getDsn(d))
 | 
				
			||||||
	model.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
						biz.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
				
			||||||
	perr := DB.Ping()
 | 
						perr := DB.Ping()
 | 
				
			||||||
	if perr != nil {
 | 
						if perr != nil {
 | 
				
			||||||
		panic(model.NewBizErr(fmt.Sprintf("数据库连接失败: %s", perr.Error())))
 | 
							panic(biz.NewBizErr(fmt.Sprintf("数据库连接失败: %s", perr.Error())))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 最大连接周期,超过时间的连接就close
 | 
						// 最大连接周期,超过时间的连接就close
 | 
				
			||||||
							
								
								
									
										1
									
								
								devops/lastupdate.tmp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								devops/lastupdate.tmp
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"/Users/hml/Desktop/project/go/mayfly-go/devops/controllers":1616491109228810023}
 | 
				
			||||||
@@ -4,8 +4,8 @@ import (
 | 
				
			|||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/models"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@@ -115,12 +115,12 @@ func (c *Cli) Close() {
 | 
				
			|||||||
func (c *Cli) GetSftpCli() *sftp.Client {
 | 
					func (c *Cli) GetSftpCli() *sftp.Client {
 | 
				
			||||||
	if c.client == nil {
 | 
						if c.client == nil {
 | 
				
			||||||
		if err := c.connect(); err != nil {
 | 
							if err := c.connect(); err != nil {
 | 
				
			||||||
			panic(model.NewBizErr("连接ssh失败:" + err.Error()))
 | 
								panic(biz.NewBizErr("连接ssh失败:" + err.Error()))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client, serr := sftp.NewClient(c.client, sftp.MaxPacket(1<<15))
 | 
						client, serr := sftp.NewClient(c.client, sftp.MaxPacket(1<<15))
 | 
				
			||||||
	if serr != nil {
 | 
						if serr != nil {
 | 
				
			||||||
		panic(model.NewBizErr("获取sftp client失败:" + serr.Error()))
 | 
							panic(biz.NewBizErr("获取sftp client失败:" + serr.Error()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return client
 | 
						return client
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,9 +2,9 @@ package machine
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
	"mayfly-go/models"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/siddontang/go/log"
 | 
						"github.com/siddontang/go/log"
 | 
				
			||||||
@@ -51,7 +51,7 @@ func getShellContent(name string) string {
 | 
				
			|||||||
		return cacheShell
 | 
							return cacheShell
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bytes, err := ioutil.ReadFile(BasePath + name + ".sh")
 | 
						bytes, err := ioutil.ReadFile(BasePath + name + ".sh")
 | 
				
			||||||
	model.ErrIsNil(err, "获取shell文件失败")
 | 
						biz.ErrIsNil(err, "获取shell文件失败")
 | 
				
			||||||
	shellStr := string(bytes)
 | 
						shellStr := string(bytes)
 | 
				
			||||||
	shellCache[name] = shellStr
 | 
						shellCache[name] = shellStr
 | 
				
			||||||
	return shellStr
 | 
						return shellStr
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package machine
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
@@ -93,7 +93,7 @@ func (c *Cli) GetTop() *Top {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	top := &Top{Time: time, Up: up, NowUsers: users, OneMinLoadavg: float32(oneMinLa), FiveMinLoadavg: float32(fiveMinLa), FifteenMinLoadavg: float32(fifMinLa)}
 | 
						top := &Top{Time: time, Up: up, NowUsers: users, OneMinLoadavg: float32(oneMinLa), FiveMinLoadavg: float32(fiveMinLa), FifteenMinLoadavg: float32(fifMinLa)}
 | 
				
			||||||
	err := utils.Map2Struct(resMap, top)
 | 
						err := utils.Map2Struct(resMap, top)
 | 
				
			||||||
	model.BizErrIsNil(err, "解析top出错")
 | 
						biz.BizErrIsNil(err, "解析top出错")
 | 
				
			||||||
	return top
 | 
						return top
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										212
									
								
								devops/machine/ws_shell_session.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								devops/machine/ws_shell_session.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,212 @@
 | 
				
			|||||||
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"mayfly-go/base/mlog"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type safeBuffer struct {
 | 
				
			||||||
 | 
						buffer bytes.Buffer
 | 
				
			||||||
 | 
						mu     sync.Mutex
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (w *safeBuffer) Write(p []byte) (int, error) {
 | 
				
			||||||
 | 
						w.mu.Lock()
 | 
				
			||||||
 | 
						defer w.mu.Unlock()
 | 
				
			||||||
 | 
						return w.buffer.Write(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (w *safeBuffer) Bytes() []byte {
 | 
				
			||||||
 | 
						w.mu.Lock()
 | 
				
			||||||
 | 
						defer w.mu.Unlock()
 | 
				
			||||||
 | 
						return w.buffer.Bytes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (w *safeBuffer) Reset() {
 | 
				
			||||||
 | 
						w.mu.Lock()
 | 
				
			||||||
 | 
						defer w.mu.Unlock()
 | 
				
			||||||
 | 
						w.buffer.Reset()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						wsMsgCmd    = "cmd"
 | 
				
			||||||
 | 
						wsMsgResize = "resize"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WsMsg struct {
 | 
				
			||||||
 | 
						Type string `json:"type"`
 | 
				
			||||||
 | 
						Msg  string `json:"msg"`
 | 
				
			||||||
 | 
						Cols int    `json:"cols"`
 | 
				
			||||||
 | 
						Rows int    `json:"rows"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type LogicSshWsSession struct {
 | 
				
			||||||
 | 
						stdinPipe       io.WriteCloser
 | 
				
			||||||
 | 
						comboOutput     *safeBuffer //ssh 终端混合输出
 | 
				
			||||||
 | 
						logBuff         *safeBuffer //保存session的日志
 | 
				
			||||||
 | 
						inputFilterBuff *safeBuffer //用来过滤输入的命令和ssh_filter配置对比的
 | 
				
			||||||
 | 
						session         *ssh.Session
 | 
				
			||||||
 | 
						wsConn          *websocket.Conn
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewLogicSshWsSession(cols, rows int, cli *Cli, wsConn *websocket.Conn) (*LogicSshWsSession, error) {
 | 
				
			||||||
 | 
						sshSession, err := cli.GetSession()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stdinP, err := sshSession.StdinPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						comboWriter := new(safeBuffer)
 | 
				
			||||||
 | 
						logBuf := new(safeBuffer)
 | 
				
			||||||
 | 
						inputBuf := new(safeBuffer)
 | 
				
			||||||
 | 
						//ssh.stdout and stderr will write output into comboWriter
 | 
				
			||||||
 | 
						sshSession.Stdout = comboWriter
 | 
				
			||||||
 | 
						sshSession.Stderr = comboWriter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						modes := ssh.TerminalModes{
 | 
				
			||||||
 | 
							ssh.ECHO:          1,     // disable echo
 | 
				
			||||||
 | 
							ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
 | 
				
			||||||
 | 
							ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Request pseudo terminal
 | 
				
			||||||
 | 
						if err := sshSession.RequestPty("xterm", rows, cols, modes); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Start remote shell
 | 
				
			||||||
 | 
						if err := sshSession.Shell(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//sshSession.Run("top")
 | 
				
			||||||
 | 
						return &LogicSshWsSession{
 | 
				
			||||||
 | 
							stdinPipe:       stdinP,
 | 
				
			||||||
 | 
							comboOutput:     comboWriter,
 | 
				
			||||||
 | 
							logBuff:         logBuf,
 | 
				
			||||||
 | 
							inputFilterBuff: inputBuf,
 | 
				
			||||||
 | 
							session:         sshSession,
 | 
				
			||||||
 | 
							wsConn:          wsConn,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Close 关闭
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) Close() {
 | 
				
			||||||
 | 
						if sws.session != nil {
 | 
				
			||||||
 | 
							sws.session.Close()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if sws.logBuff != nil {
 | 
				
			||||||
 | 
							sws.logBuff = nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if sws.comboOutput != nil {
 | 
				
			||||||
 | 
							sws.comboOutput = nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) Start(quitChan chan bool) {
 | 
				
			||||||
 | 
						go sws.receiveWsMsg(quitChan)
 | 
				
			||||||
 | 
						go sws.sendComboOutput(quitChan)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//receiveWsMsg  receive websocket msg do some handling then write into ssh.session.stdin
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) {
 | 
				
			||||||
 | 
						wsConn := sws.wsConn
 | 
				
			||||||
 | 
						//tells other go routine quit
 | 
				
			||||||
 | 
						defer setQuit(exitCh)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-exitCh:
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								//read websocket msg
 | 
				
			||||||
 | 
								_, wsData, err := wsConn.ReadMessage()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									mlog.Log.Error("reading webSocket message failed: ", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								//unmashal bytes into struct
 | 
				
			||||||
 | 
								msgObj := WsMsg{}
 | 
				
			||||||
 | 
								if err := json.Unmarshal(wsData, &msgObj); err != nil {
 | 
				
			||||||
 | 
									mlog.Log.Error("unmarshal websocket message failed:", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								switch msgObj.Type {
 | 
				
			||||||
 | 
								case wsMsgResize:
 | 
				
			||||||
 | 
									//handle xterm.js size change
 | 
				
			||||||
 | 
									if msgObj.Cols > 0 && msgObj.Rows > 0 {
 | 
				
			||||||
 | 
										if err := sws.session.WindowChange(msgObj.Rows, msgObj.Cols); err != nil {
 | 
				
			||||||
 | 
											mlog.Log.Error("ssh pty change windows size failed")
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case wsMsgCmd:
 | 
				
			||||||
 | 
									//handle xterm.js stdin
 | 
				
			||||||
 | 
									//decodeBytes, err := base64.StdEncoding.DecodeString(msgObj.Cmd)
 | 
				
			||||||
 | 
									//if err != nil {
 | 
				
			||||||
 | 
									//	logs.Error("websock cmd string base64 decoding failed")
 | 
				
			||||||
 | 
									//	//panic(base.NewBizErr("websock cmd string base64 decoding failed"))
 | 
				
			||||||
 | 
									//}
 | 
				
			||||||
 | 
									sws.sendWebsocketInputCommandToSshSessionStdinPipe([]byte(msgObj.Msg))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//sendWebsocketInputCommandToSshSessionStdinPipe
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) sendWebsocketInputCommandToSshSessionStdinPipe(cmdBytes []byte) {
 | 
				
			||||||
 | 
						if _, err := sws.stdinPipe.Write(cmdBytes); err != nil {
 | 
				
			||||||
 | 
							mlog.Log.Error("ws cmd bytes write to ssh.stdin pipe failed")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) sendComboOutput(exitCh chan bool) {
 | 
				
			||||||
 | 
						wsConn := sws.wsConn
 | 
				
			||||||
 | 
						//todo 优化成一个方法
 | 
				
			||||||
 | 
						//tells other go routine quit
 | 
				
			||||||
 | 
						defer setQuit(exitCh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//every 120ms write combine output bytes into websocket response
 | 
				
			||||||
 | 
						tick := time.NewTicker(time.Millisecond * time.Duration(60))
 | 
				
			||||||
 | 
						//for range time.Tick(120 * time.Millisecond){}
 | 
				
			||||||
 | 
						defer tick.Stop()
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							select {
 | 
				
			||||||
 | 
							case <-tick.C:
 | 
				
			||||||
 | 
								if sws.comboOutput == nil {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								bs := sws.comboOutput.Bytes()
 | 
				
			||||||
 | 
								if len(bs) > 0 {
 | 
				
			||||||
 | 
									err := wsConn.WriteMessage(websocket.TextMessage, bs)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										mlog.Log.Error("ssh sending combo output to webSocket failed")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									_, err = sws.logBuff.Write(bs)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										mlog.Log.Error("combo output to log buffer failed")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									sws.comboOutput.buffer.Reset()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case <-exitCh:
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) Wait(quitChan chan bool) {
 | 
				
			||||||
 | 
						if err := sws.session.Wait(); err != nil {
 | 
				
			||||||
 | 
							setQuit(quitChan)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (sws *LogicSshWsSession) LogString() string {
 | 
				
			||||||
 | 
						return sws.logBuff.buffer.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setQuit(ch chan bool) {
 | 
				
			||||||
 | 
						ch <- true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	_ "mayfly-go/routers"
 | 
						_ "mayfly-go/devops/routers"
 | 
				
			||||||
	scheduler "mayfly-go/scheudler"
 | 
						scheduler "mayfly-go/devops/scheudler"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,7 +20,7 @@ func init() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	orm.Debug = true
 | 
						// orm.Debug = true
 | 
				
			||||||
	// 跨域配置
 | 
						// 跨域配置
 | 
				
			||||||
	web.InsertFilter("/**", web.BeforeRouter, cors.Allow(&cors.Options{
 | 
						web.InsertFilter("/**", web.BeforeRouter, cors.Allow(&cors.Options{
 | 
				
			||||||
		AllowAllOrigins:  true,
 | 
							AllowAllOrigins:  true,
 | 
				
			||||||
@@ -39,5 +39,5 @@ func TransparentStatic(ctx *context.Context) {
 | 
				
			|||||||
	if strings.Index(ctx.Request.URL.Path, "api/") >= 0 {
 | 
						if strings.Index(ctx.Request.URL.Path, "api/") >= 0 {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	http.ServeFile(ctx.ResponseWriter, ctx.Request, "static/"+ctx.Request.URL.Path)
 | 
						http.ServeFile(ctx.ResponseWriter, ctx.Request, "mock-server/static/"+ctx.Request.URL.Path)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2,7 +2,7 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/controllers/vo"
 | 
						"mayfly-go/devops/controllers/vo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/beego/beego/v2/client/orm"
 | 
						"github.com/beego/beego/v2/client/orm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -2,7 +2,7 @@ package models
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/controllers/vo"
 | 
						"mayfly-go/devops/controllers/vo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/beego/beego/v2/client/orm"
 | 
						"github.com/beego/beego/v2/client/orm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:AccountController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:AccountController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:AccountController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:AccountController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "Accounts",
 | 
					            Method: "Accounts",
 | 
				
			||||||
            Router: "/accounts",
 | 
					            Router: "/accounts",
 | 
				
			||||||
@@ -16,7 +16,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:AccountController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:AccountController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:AccountController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:AccountController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "Login",
 | 
					            Method: "Login",
 | 
				
			||||||
            Router: "/accounts/login",
 | 
					            Router: "/accounts/login",
 | 
				
			||||||
@@ -25,7 +25,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "ColumnMA",
 | 
					            Method: "ColumnMA",
 | 
				
			||||||
            Router: "/api/db/:dbId/c-metadata",
 | 
					            Router: "/api/db/:dbId/c-metadata",
 | 
				
			||||||
@@ -34,7 +34,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "ExecSql",
 | 
					            Method: "ExecSql",
 | 
				
			||||||
            Router: "/api/db/:dbId/exec-sql",
 | 
					            Router: "/api/db/:dbId/exec-sql",
 | 
				
			||||||
@@ -43,7 +43,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "HintTables",
 | 
					            Method: "HintTables",
 | 
				
			||||||
            Router: "/api/db/:dbId/hint-tables",
 | 
					            Router: "/api/db/:dbId/hint-tables",
 | 
				
			||||||
@@ -52,7 +52,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "SelectData",
 | 
					            Method: "SelectData",
 | 
				
			||||||
            Router: "/api/db/:dbId/select",
 | 
					            Router: "/api/db/:dbId/select",
 | 
				
			||||||
@@ -61,7 +61,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "SaveSql",
 | 
					            Method: "SaveSql",
 | 
				
			||||||
            Router: "/api/db/:dbId/sql",
 | 
					            Router: "/api/db/:dbId/sql",
 | 
				
			||||||
@@ -70,7 +70,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "GetSql",
 | 
					            Method: "GetSql",
 | 
				
			||||||
            Router: "/api/db/:dbId/sql",
 | 
					            Router: "/api/db/:dbId/sql",
 | 
				
			||||||
@@ -79,7 +79,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "TableMA",
 | 
					            Method: "TableMA",
 | 
				
			||||||
            Router: "/api/db/:dbId/t-metadata",
 | 
					            Router: "/api/db/:dbId/t-metadata",
 | 
				
			||||||
@@ -88,7 +88,7 @@ func init() {
 | 
				
			|||||||
            Filters: nil,
 | 
					            Filters: nil,
 | 
				
			||||||
            Params: nil})
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    beego.GlobalControllerRouter["mayfly-go/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/controllers:DbController"],
 | 
					    beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"] = append(beego.GlobalControllerRouter["mayfly-go/devops/controllers:DbController"],
 | 
				
			||||||
        beego.ControllerComments{
 | 
					        beego.ControllerComments{
 | 
				
			||||||
            Method: "Dbs",
 | 
					            Method: "Dbs",
 | 
				
			||||||
            Router: "/api/dbs",
 | 
					            Router: "/api/dbs",
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package routers
 | 
					package routers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/controllers"
 | 
						"mayfly-go/devops/controllers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/beego/beego/v2/server/web"
 | 
						"github.com/beego/beego/v2/server/web"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
package scheduler
 | 
					package scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/base/mlog"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
	"mayfly-go/base/utils"
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
	"mayfly-go/machine"
 | 
						"mayfly-go/devops/machine"
 | 
				
			||||||
	"mayfly-go/models"
 | 
						"mayfly-go/devops/models"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/siddontang/go/log"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@@ -20,14 +19,14 @@ func SaveMachineMonitor() {
 | 
				
			|||||||
			go func() {
 | 
								go func() {
 | 
				
			||||||
				cli, err := machine.GetCli(uint64(utils.GetInt4Map(m, "id")))
 | 
									cli, err := machine.GetCli(uint64(utils.GetInt4Map(m, "id")))
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					log.Error("获取客户端失败:", err.Error())
 | 
										mlog.Log.Error("获取客户端失败:", err.Error())
 | 
				
			||||||
					return
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				mm := cli.GetMonitorInfo()
 | 
									mm := cli.GetMonitorInfo()
 | 
				
			||||||
				if mm != nil {
 | 
									if mm != nil {
 | 
				
			||||||
					_, err := model.Insert(mm)
 | 
										_, err := model.Insert(mm)
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						log.Error("保存机器监控信息失败: ", err.Error())
 | 
											mlog.Log.Error("保存机器监控信息失败: ", err.Error())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}()
 | 
								}()
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package scheduler
 | 
					package scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/robfig/cron/v3"
 | 
						"github.com/robfig/cron/v3"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -23,7 +23,7 @@ func GetCron() *cron.Cron {
 | 
				
			|||||||
func AddFun(spec string, cmd func()) cron.EntryID {
 | 
					func AddFun(spec string, cmd func()) cron.EntryID {
 | 
				
			||||||
	id, err := c.AddFunc(spec, cmd)
 | 
						id, err := c.AddFunc(spec, cmd)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		panic(model.NewBizErr("添加任务失败:" + err.Error()))
 | 
							panic(biz.NewBizErr("添加任务失败:" + err.Error()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return id
 | 
						return id
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB  | 
							
								
								
									
										5
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,13 +6,16 @@ require (
 | 
				
			|||||||
	github.com/beego/beego/v2 v2.0.1
 | 
						github.com/beego/beego/v2 v2.0.1
 | 
				
			||||||
	// jwt
 | 
						// jwt
 | 
				
			||||||
	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 | 
						github.com/dgrijalva/jwt-go v3.2.0+incompatible
 | 
				
			||||||
 | 
						github.com/go-redis/redis v6.14.2+incompatible
 | 
				
			||||||
	github.com/go-sql-driver/mysql v1.5.0
 | 
						github.com/go-sql-driver/mysql v1.5.0
 | 
				
			||||||
	github.com/gorilla/websocket v1.4.2
 | 
						github.com/gorilla/websocket v1.4.2
 | 
				
			||||||
	github.com/pkg/sftp v1.12.0
 | 
						github.com/pkg/sftp v1.12.0
 | 
				
			||||||
	// 定时任务
 | 
						// 定时任务
 | 
				
			||||||
	github.com/robfig/cron/v3 v3.0.1
 | 
						github.com/robfig/cron/v3 v3.0.1
 | 
				
			||||||
	github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0
 | 
						github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0
 | 
				
			||||||
	github.com/smartystreets/goconvey v1.6.4
 | 
					 | 
				
			||||||
	// ssh
 | 
						// ssh
 | 
				
			||||||
	golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
 | 
						golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
 | 
				
			||||||
 | 
						gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
 | 
				
			||||||
 | 
						github.com/sirupsen/logrus v1.6.0
 | 
				
			||||||
 | 
					// github.com/go-redis/redis/v8 v8.6.0
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								go.sum
									
									
									
									
									
								
							@@ -7,8 +7,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 | 
				
			|||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 | 
					github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 | 
				
			||||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
 | 
					github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
 | 
				
			||||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
 | 
					github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
 | 
				
			||||||
github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
 | 
					 | 
				
			||||||
github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
 | 
					 | 
				
			||||||
github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE=
 | 
					github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE=
 | 
				
			||||||
github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI=
 | 
					github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI=
 | 
				
			||||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
 | 
					github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
 | 
				
			||||||
@@ -43,19 +41,19 @@ github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3C
 | 
				
			|||||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 | 
					github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 | 
				
			||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 | 
					github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 | 
				
			||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 | 
					github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 | 
				
			||||||
 | 
					github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 | 
				
			||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
					github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
				
			||||||
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
 | 
					github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
 | 
				
			||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
					github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
				
			||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
					github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 | 
				
			||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
					github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 | 
				
			||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 | 
					github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 | 
				
			||||||
 | 
					github.com/go-redis/redis v6.14.2+incompatible h1:UE9pLhzmWf+xHNmZsoccjXosPicuiNaInPgym8nzfg0=
 | 
				
			||||||
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 | 
					github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 | 
				
			||||||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 | 
					github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
 | 
				
			||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 | 
					github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 | 
				
			||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 | 
					github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 | 
				
			||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 | 
					github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 | 
				
			||||||
github.com/godror/godror v0.9.0 h1:IQ+HRUl00B1V03jR4AduWKkKlP9RsTq9E4iEG3gcCZY=
 | 
					 | 
				
			||||||
github.com/godror/godror v0.9.0/go.mod h1:06LLZykQEXjuUYiVKBa7Ls+AvbUZ8sbtolIALCeL/jw=
 | 
					 | 
				
			||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 | 
					github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 | 
				
			||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 | 
					github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 | 
				
			||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 | 
					github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 | 
				
			||||||
@@ -82,22 +80,20 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 | 
				
			|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
					github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 | 
				
			||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
					github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
				
			||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
					github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
				
			||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
 | 
					 | 
				
			||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 | 
					 | 
				
			||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 | 
					github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 | 
				
			||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
					github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
				
			||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 | 
					github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 | 
				
			||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 | 
					github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 | 
				
			||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 | 
					github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 | 
				
			||||||
 | 
					github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 | 
				
			||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
					github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
				
			||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
					github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 | 
				
			||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
					github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 | 
				
			||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 | 
					 | 
				
			||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 | 
					 | 
				
			||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 | 
					github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 | 
				
			||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 | 
					github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
 | 
				
			||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 | 
					github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 | 
				
			||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
					github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
				
			||||||
 | 
					github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
				
			||||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 | 
					github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 | 
				
			||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
					github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 | 
				
			||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 | 
					github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 | 
				
			||||||
@@ -114,8 +110,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
 | 
				
			|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
					github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
 | 
					github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
					github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
				
			||||||
github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
 | 
					 | 
				
			||||||
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
					 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
				
			||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
					github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 | 
				
			||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 | 
					github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 | 
				
			||||||
@@ -125,12 +119,13 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
 | 
				
			|||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
					github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 | 
				
			||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
					github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
				
			||||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
					github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
				
			||||||
 | 
					github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
 | 
				
			||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 | 
					github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
 | 
				
			||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 | 
					github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 | 
				
			||||||
 | 
					github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
 | 
				
			||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 | 
					github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 | 
				
			||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 | 
					github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 | 
				
			||||||
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 | 
					github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 | 
				
			||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 | 
					 | 
				
			||||||
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
 | 
					github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
 | 
				
			||||||
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
 | 
					github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
 | 
				
			||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
					github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
				
			||||||
@@ -163,20 +158,15 @@ 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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 | 
				
			||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
 | 
					github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
 | 
				
			||||||
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 | 
					github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 | 
				
			||||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 | 
					 | 
				
			||||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 | 
					 | 
				
			||||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0 h1:QIF48X1cihydXibm+4wfAc0r/qyPyuFiPFRNphdMpEE=
 | 
					github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0 h1:QIF48X1cihydXibm+4wfAc0r/qyPyuFiPFRNphdMpEE=
 | 
				
			||||||
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 | 
					github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 | 
				
			||||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=
 | 
					 | 
				
			||||||
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 | 
					 | 
				
			||||||
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
 | 
					github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
 | 
				
			||||||
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
 | 
					github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
 | 
				
			||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
					github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 | 
				
			||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 | 
					github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 | 
				
			||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 | 
					github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
 | 
				
			||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 | 
					github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 | 
				
			||||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 | 
					github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 | 
				
			||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 | 
					 | 
				
			||||||
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 | 
					github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 | 
				
			||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
				
			||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
					github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
				
			||||||
@@ -204,8 +194,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 | 
				
			|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
 | 
					golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
					golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
 | 
					 | 
				
			||||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 | 
					 | 
				
			||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
					golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
				
			||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
					golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
				
			||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 | 
					golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 | 
				
			||||||
@@ -252,8 +240,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM
 | 
				
			|||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
 | 
					golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
 | 
				
			||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
					golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
 | 
					 | 
				
			||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
					 | 
				
			||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
					golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 | 
				
			||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
					golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
				
			||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
					golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 | 
				
			||||||
@@ -265,7 +251,6 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm
 | 
				
			|||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 | 
					golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 | 
					golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 | 
					 | 
				
			||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 | 
					golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
					golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
					golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
				
			||||||
@@ -302,8 +287,10 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 | 
				
			|||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 | 
					gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 | 
				
			||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
					gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
				
			||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 | 
					gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 | 
				
			||||||
 | 
					gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 | 
				
			||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 | 
					gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 | 
				
			||||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
 | 
					gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
 | 
				
			||||||
 | 
					gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 | 
				
			||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
					gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
				
			||||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
 | 
					gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
 | 
				
			||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
					gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,4 +2,4 @@
 | 
				
			|||||||
ENV = 'production'
 | 
					ENV = 'production'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# base api
 | 
					# base api
 | 
				
			||||||
VUE_APP_BASE_API = 'http://localhost:8888/api'
 | 
					VUE_APP_BASE_API = 'http://128.64.98.54:8888/api'
 | 
				
			||||||
@@ -13,6 +13,7 @@
 | 
				
			|||||||
    "core-js": "^3.6.5",
 | 
					    "core-js": "^3.6.5",
 | 
				
			||||||
    "echarts": "^4.8.0",
 | 
					    "echarts": "^4.8.0",
 | 
				
			||||||
    "element-ui": "^2.13.2",
 | 
					    "element-ui": "^2.13.2",
 | 
				
			||||||
 | 
					    "jsonlint": "^1.6.3",
 | 
				
			||||||
    "sql-formatter": "^2.3.3",
 | 
					    "sql-formatter": "^2.3.3",
 | 
				
			||||||
    "vue": "^2.6.11",
 | 
					    "vue": "^2.6.11",
 | 
				
			||||||
    "vue-class-component": "^7.2.3",
 | 
					    "vue-class-component": "^7.2.3",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										72
									
								
								mayfly-go-front/src/common/Utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								mayfly-go-front/src/common/Utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 工具类
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class Utils {
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 属性拷贝,将一个对象的属性拷贝给另一个对象
 | 
				
			||||||
 | 
					   * @param {Object} source  源对象
 | 
				
			||||||
 | 
					   * @param {Object} target 目标对象
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static copyProperties(source: any, target: any) {
 | 
				
			||||||
 | 
					    for (const k in target) {
 | 
				
			||||||
 | 
					      const value = source[k];
 | 
				
			||||||
 | 
					      if (value) {
 | 
				
			||||||
 | 
					        target[k] = value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 重置对象属性为null
 | 
				
			||||||
 | 
					   * @param {Object} target  对象
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  static resetProperties(target: any) {
 | 
				
			||||||
 | 
					    for (const k in target) {
 | 
				
			||||||
 | 
					      const value = target[k];
 | 
				
			||||||
 | 
					      if (value != null) {
 | 
				
			||||||
 | 
					        target[k] = null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 绑定事件 on(element, event, handler)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const on = (function () {
 | 
				
			||||||
 | 
					  if (document.addEventListener != null) {
 | 
				
			||||||
 | 
					    return function (element: any, event: any, handler: any) {
 | 
				
			||||||
 | 
					      if (element && event && handler) {
 | 
				
			||||||
 | 
					        element.addEventListener(event, handler, false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return function (element: any, event: any, handler: any) {
 | 
				
			||||||
 | 
					      if (element && event && handler) {
 | 
				
			||||||
 | 
					        element.attachEvent('on' + event, handler);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 解绑事件 off(element, event, handler)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const off = (function () {
 | 
				
			||||||
 | 
					  if (document.removeEventListener != null) {
 | 
				
			||||||
 | 
					    return function (element: any, event: any, handler: any) {
 | 
				
			||||||
 | 
					      if (element && event) {
 | 
				
			||||||
 | 
					        element.removeEventListener(event, handler, false);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return function (element: any, event: any, handler: any) {
 | 
				
			||||||
 | 
					      if (element && event) {
 | 
				
			||||||
 | 
					        element.detachEvent('on' + event, handler);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
@@ -4,7 +4,7 @@ import { ResultEnum } from './enums'
 | 
				
			|||||||
import Api from './Api';
 | 
					import Api from './Api';
 | 
				
			||||||
import { AuthUtils } from './AuthUtils'
 | 
					import { AuthUtils } from './AuthUtils'
 | 
				
			||||||
import config from './config';
 | 
					import config from './config';
 | 
				
			||||||
import ElementUI from 'element-ui';
 | 
					import { Message } from 'element-ui';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Result {
 | 
					export interface Result {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@@ -29,7 +29,7 @@ const baseUrl = config.baseApiUrl
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
function notifyErrorMsg(msg: string) {
 | 
					function notifyErrorMsg(msg: string) {
 | 
				
			||||||
  // 危险通知
 | 
					  // 危险通知
 | 
				
			||||||
  ElementUI.Message.error(msg);
 | 
					  Message.error(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// create an axios instance
 | 
					// create an axios instance
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,6 +67,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
 | 
					import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
 | 
				
			||||||
 | 
					import { Message } from 'element-ui'
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  name: 'DynamicForm'
 | 
					  name: 'DynamicForm'
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
@@ -99,7 +100,7 @@ export default class DynamicForm extends Vue {
 | 
				
			|||||||
          this.submitDisabled = true
 | 
					          this.submitDisabled = true
 | 
				
			||||||
          operation.request(this.form).then(
 | 
					          operation.request(this.form).then(
 | 
				
			||||||
            (res: any) => {
 | 
					            (res: any) => {
 | 
				
			||||||
              this.$message.success('保存成功')
 | 
					              Message.success('保存成功')
 | 
				
			||||||
              this.$emit('submitSuccess', subform)
 | 
					              this.$emit('submitSuccess', subform)
 | 
				
			||||||
              this.submitDisabled = false
 | 
					              this.submitDisabled = false
 | 
				
			||||||
              // this.cancel()
 | 
					              // this.cancel()
 | 
				
			||||||
@@ -109,7 +110,7 @@ export default class DynamicForm extends Vue {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
          )
 | 
					          )
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          this.$message.error('表单未设置对应的提交权限')
 | 
					          Message.error('表单未设置对应的提交权限')
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        return false
 | 
					        return false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
  <div class="main">
 | 
					  <div class="main">
 | 
				
			||||||
    <div class="header">
 | 
					    <div class="header">
 | 
				
			||||||
      <div class="logo">
 | 
					      <div class="logo">
 | 
				
			||||||
        <span class="big">Mayfly-Go</span>
 | 
					        <span class="big">Mock-Server.go</span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="right">
 | 
					      <div class="right">
 | 
				
			||||||
        <span class="header-btn">
 | 
					        <span class="header-btn">
 | 
				
			||||||
@@ -176,6 +176,22 @@ export default class App extends Vue {
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 3,
 | 
				
			||||||
 | 
					        type: 1,
 | 
				
			||||||
 | 
					        name: 'Mock数据',
 | 
				
			||||||
 | 
					        icon: 'el-icon-menu',
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            id: 31,
 | 
				
			||||||
 | 
					            type: 1,
 | 
				
			||||||
 | 
					            name: '数据列表',
 | 
				
			||||||
 | 
					            url: '/mock-data',
 | 
				
			||||||
 | 
					            icon: 'el-icon-menu',
 | 
				
			||||||
 | 
					            code: 'mock-data',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        id: 2,
 | 
					        id: 2,
 | 
				
			||||||
        type: 1,
 | 
					        type: 1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,16 @@ const routes: Array<RouteConfig> = [
 | 
				
			|||||||
      //   },
 | 
					      //   },
 | 
				
			||||||
      //   component: () => import('@/views/db/SelectData.vue')
 | 
					      //   component: () => import('@/views/db/SelectData.vue')
 | 
				
			||||||
      // }]
 | 
					      // }]
 | 
				
			||||||
    }]
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: 'mock-data',
 | 
				
			||||||
 | 
					      name: 'mock-data',
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        title: '数据列表',
 | 
				
			||||||
 | 
					        keepAlive: false
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      component: () => import('@/views/mock-server')
 | 
				
			||||||
 | 
					    },]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,11 +74,13 @@ router.beforeEach((to: any, from: any, next: any) => {
 | 
				
			|||||||
    next()
 | 
					    next()
 | 
				
			||||||
    return
 | 
					    return
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (!AuthUtils.getToken() && toPath != '/login') {
 | 
					  // if (!AuthUtils.getToken() && toPath != '/login') {
 | 
				
			||||||
    next({ path: '/login' });
 | 
					  //   next({ path: '/login' });
 | 
				
			||||||
  } else {
 | 
					  // } else {
 | 
				
			||||||
 | 
					  //   next();
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  next();
 | 
					  next();
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default router
 | 
					export default router
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,6 +149,7 @@ import 'codemirror/addon/hint/sql-hint.js'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import sqlFormatter from 'sql-formatter'
 | 
					import sqlFormatter from 'sql-formatter'
 | 
				
			||||||
import { notEmpty } from '@/common/assert'
 | 
					import { notEmpty } from '@/common/assert'
 | 
				
			||||||
 | 
					import { Message } from 'element-ui'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
@@ -239,7 +240,7 @@ export default class SelectData extends Vue {
 | 
				
			|||||||
    notEmpty(this.sql, 'sql内容不能为空')
 | 
					    notEmpty(this.sql, 'sql内容不能为空')
 | 
				
			||||||
    notEmpty(this.dbId, '请先选择数据库')
 | 
					    notEmpty(this.dbId, '请先选择数据库')
 | 
				
			||||||
    await dbApi.saveSql.request({ id: this.dbId, sql: this.sql, type: 1 })
 | 
					    await dbApi.saveSql.request({ id: this.dbId, sql: this.sql, type: 1 })
 | 
				
			||||||
    this.$message.success('保存成功')
 | 
					    Message.success('保存成功')
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 更改数据库事件
 | 
					  // 更改数据库事件
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -146,16 +146,17 @@
 | 
				
			|||||||
      :visible.sync="terminalDialog.visible"
 | 
					      :visible.sync="terminalDialog.visible"
 | 
				
			||||||
      width="70%"
 | 
					      width="70%"
 | 
				
			||||||
      :close-on-click-modal="false"
 | 
					      :close-on-click-modal="false"
 | 
				
			||||||
 | 
					      :modal="false"
 | 
				
			||||||
      @close="closeTermnial"
 | 
					      @close="closeTermnial"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <ssh-terminal ref="terminal" :socketURI="terminalDialog.socketUri" />
 | 
					      <ssh-terminal ref="terminal" :socketURI="terminalDialog.socketUri" />
 | 
				
			||||||
    </el-dialog>
 | 
					    </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- <FileManage
 | 
					    <service-manage
 | 
				
			||||||
      :title="dialog.title"
 | 
					      :title="serviceDialog.title"
 | 
				
			||||||
      :visible.sync="dialog.visible"
 | 
					      :visible.sync="serviceDialog.visible"
 | 
				
			||||||
      :machineId.sync="dialog.machineId"
 | 
					      :machineId.sync="serviceDialog.machineId"
 | 
				
			||||||
    />-->
 | 
					    />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <dynamic-form-dialog
 | 
					    <dynamic-form-dialog
 | 
				
			||||||
      :visible.sync="formDialog.visible"
 | 
					      :visible.sync="formDialog.visible"
 | 
				
			||||||
@@ -173,6 +174,7 @@ import { DynamicFormDialog } from '@/components/dynamic-form'
 | 
				
			|||||||
import Monitor from './Monitor.vue'
 | 
					import Monitor from './Monitor.vue'
 | 
				
			||||||
import { machineApi } from './api'
 | 
					import { machineApi } from './api'
 | 
				
			||||||
import SshTerminal from './SshTerminal.vue'
 | 
					import SshTerminal from './SshTerminal.vue'
 | 
				
			||||||
 | 
					import ServiceManage from './ServiceManage.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  name: 'MachineList',
 | 
					  name: 'MachineList',
 | 
				
			||||||
@@ -180,6 +182,7 @@ import SshTerminal from './SshTerminal.vue'
 | 
				
			|||||||
    DynamicFormDialog,
 | 
					    DynamicFormDialog,
 | 
				
			||||||
    Monitor,
 | 
					    Monitor,
 | 
				
			||||||
    SshTerminal,
 | 
					    SshTerminal,
 | 
				
			||||||
 | 
					    ServiceManage
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export default class MachineList extends Vue {
 | 
					export default class MachineList extends Vue {
 | 
				
			||||||
@@ -191,6 +194,11 @@ export default class MachineList extends Vue {
 | 
				
			|||||||
    visible: false,
 | 
					    visible: false,
 | 
				
			||||||
    info: '',
 | 
					    info: '',
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  serviceDialog = {
 | 
				
			||||||
 | 
					    visible: false,
 | 
				
			||||||
 | 
					    machineId: 0,
 | 
				
			||||||
 | 
					    title: ''
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  monitorDialog = {
 | 
					  monitorDialog = {
 | 
				
			||||||
    visible: false,
 | 
					    visible: false,
 | 
				
			||||||
    machineId: 0,
 | 
					    machineId: 0,
 | 
				
			||||||
@@ -369,10 +377,10 @@ export default class MachineList extends Vue {
 | 
				
			|||||||
    this.search()
 | 
					    this.search()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fileManage(row: any) {
 | 
					  serviceManager(row: any) {
 | 
				
			||||||
    this.dialog.machineId = row.id
 | 
					    this.serviceDialog.machineId = row.id
 | 
				
			||||||
    this.dialog.visible = true
 | 
					    this.serviceDialog.visible = true
 | 
				
			||||||
    this.dialog.title = `${row.name} => ${row.ip}`
 | 
					    this.serviceDialog.title = `${row.name} => ${row.ip}`
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  submitSuccess() {
 | 
					  submitSuccess() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,8 +108,7 @@ export default class Monitor extends Vue {
 | 
				
			|||||||
      icon: 'md-chatbubbles',
 | 
					      icon: 'md-chatbubbles',
 | 
				
			||||||
      count: 12,
 | 
					      count: 12,
 | 
				
			||||||
      color: '#91AFC8',
 | 
					      color: '#91AFC8',
 | 
				
			||||||
    },
 | 
					    }
 | 
				
			||||||
    { title: '新增页面', icon: 'md-map', count: 14, color: '#91AFC8' },
 | 
					 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
  taskData = [
 | 
					  taskData = [
 | 
				
			||||||
    { value: 0, name: '运行中', color: '#3AA1FFB' },
 | 
					    { value: 0, name: '运行中', color: '#3AA1FFB' },
 | 
				
			||||||
@@ -280,7 +279,7 @@ export default class Monitor extends Vue {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  startInterval() {
 | 
					  startInterval() {
 | 
				
			||||||
    if (!this.timer) {
 | 
					    if (!this.timer) {
 | 
				
			||||||
      this.timer = setInterval(this.getTop, 3000)
 | 
					      // this.timer = setInterval(this.getTop, 3000)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										345
									
								
								mayfly-go-front/src/views/machine/ServiceManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								mayfly-go-front/src/views/machine/ServiceManage.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,345 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="file-manage">
 | 
				
			||||||
 | 
					    <el-dialog
 | 
				
			||||||
 | 
					      :title="title"
 | 
				
			||||||
 | 
					      :visible.sync="visible"
 | 
				
			||||||
 | 
					      :show-close="true"
 | 
				
			||||||
 | 
					      :before-close="handleClose"
 | 
				
			||||||
 | 
					      width="800px"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div style="float: right;">
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          @click="add"
 | 
				
			||||||
 | 
					          icon="el-icon-plus"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          plain
 | 
				
			||||||
 | 
					        >添加</el-button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <el-table :data="fileTable" stripe style="width: 100%">
 | 
				
			||||||
 | 
					        <el-table-column prop="name" label="名称" width>
 | 
				
			||||||
 | 
					          <template slot-scope="scope">
 | 
				
			||||||
 | 
					            <el-input
 | 
				
			||||||
 | 
					              v-model="scope.row.name"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              :disabled="scope.row.id != null"
 | 
				
			||||||
 | 
					              clearable
 | 
				
			||||||
 | 
					            ></el-input>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column prop="name" label="类型" width>
 | 
				
			||||||
 | 
					          <template slot-scope="scope">
 | 
				
			||||||
 | 
					            <el-select
 | 
				
			||||||
 | 
					              :disabled="scope.row.id != null"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              v-model="scope.row.type"
 | 
				
			||||||
 | 
					              style="width: 100px"
 | 
				
			||||||
 | 
					              placeholder="请选择"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <el-option
 | 
				
			||||||
 | 
					                v-for="item in enums.FileTypeEnum"
 | 
				
			||||||
 | 
					                :key="item.value"
 | 
				
			||||||
 | 
					                :label="item.label"
 | 
				
			||||||
 | 
					                :value="item.value"
 | 
				
			||||||
 | 
					              ></el-option>
 | 
				
			||||||
 | 
					            </el-select>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column prop="path" label="路径" width>
 | 
				
			||||||
 | 
					          <template slot-scope="scope">
 | 
				
			||||||
 | 
					            <el-input
 | 
				
			||||||
 | 
					              v-model="scope.row.path"
 | 
				
			||||||
 | 
					              :disabled="scope.row.id != null"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              clearable
 | 
				
			||||||
 | 
					            ></el-input>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					        <el-table-column label="操作" width>
 | 
				
			||||||
 | 
					          <template slot-scope="scope">
 | 
				
			||||||
 | 
					            <el-button
 | 
				
			||||||
 | 
					              v-if="scope.row.id == null"
 | 
				
			||||||
 | 
					              @click="addFiles(scope.row)"
 | 
				
			||||||
 | 
					              type="success"
 | 
				
			||||||
 | 
					              :ref="scope.row"
 | 
				
			||||||
 | 
					              icon="el-icon-success"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              plain
 | 
				
			||||||
 | 
					            >确定</el-button>
 | 
				
			||||||
 | 
					            <el-button
 | 
				
			||||||
 | 
					              v-if="scope.row.id != null"
 | 
				
			||||||
 | 
					              @click="getConf(scope.row)"
 | 
				
			||||||
 | 
					              type="primary"
 | 
				
			||||||
 | 
					              :ref="scope.row"
 | 
				
			||||||
 | 
					              icon="el-icon-tickets"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              plain
 | 
				
			||||||
 | 
					            >查看</el-button>
 | 
				
			||||||
 | 
					            <el-button
 | 
				
			||||||
 | 
					              type="danger"
 | 
				
			||||||
 | 
					              :ref="scope.row"
 | 
				
			||||||
 | 
					              @click="deleteRow(scope.$index, scope.row)"
 | 
				
			||||||
 | 
					              icon="el-icon-delete"
 | 
				
			||||||
 | 
					              size="mini"
 | 
				
			||||||
 | 
					              plain
 | 
				
			||||||
 | 
					            >删除</el-button>
 | 
				
			||||||
 | 
					          </template>
 | 
				
			||||||
 | 
					        </el-table-column>
 | 
				
			||||||
 | 
					      </el-table>
 | 
				
			||||||
 | 
					    </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-dialog
 | 
				
			||||||
 | 
					      :title="fileContent.dialogTitle"
 | 
				
			||||||
 | 
					      :visible.sync="fileContent.contentVisible"
 | 
				
			||||||
 | 
					      width="850px"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-form :model="form">
 | 
				
			||||||
 | 
					        <el-form-item>
 | 
				
			||||||
 | 
					          <el-input
 | 
				
			||||||
 | 
					            v-model="fileContent.content"
 | 
				
			||||||
 | 
					            type="textarea"
 | 
				
			||||||
 | 
					            :autosize="{ minRows: 18, maxRows:25}"
 | 
				
			||||||
 | 
					            autocomplete="off"
 | 
				
			||||||
 | 
					          ></el-input>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-form>
 | 
				
			||||||
 | 
					      <div slot="footer" class="dialog-footer">
 | 
				
			||||||
 | 
					        <el-button @click="fileContent.contentVisible = false" size="mini">取 消</el-button>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          v-permission="permission.updateFileContent.code"
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          @click="updateContent"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					        >确 定</el-button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </el-dialog>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
 | 
				
			||||||
 | 
					import { machineApi } from './api'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  name: 'ServiceManage',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export default class ServiceManage extends Vue {
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  visible: boolean
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  machineId: [number]
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  title: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addFile = machineApi.addConf
 | 
				
			||||||
 | 
					  delFile = machineApi.delConf
 | 
				
			||||||
 | 
					  updateFileContent = machineApi.updateFileContent
 | 
				
			||||||
 | 
					  uploadFile = machineApi.uploadFile
 | 
				
			||||||
 | 
					  files = machineApi.files
 | 
				
			||||||
 | 
					  activeName = 'conf-file'
 | 
				
			||||||
 | 
					  token = sessionStorage.getItem('token')
 | 
				
			||||||
 | 
					  form = {
 | 
				
			||||||
 | 
					    id: null,
 | 
				
			||||||
 | 
					    type: null,
 | 
				
			||||||
 | 
					    name: '',
 | 
				
			||||||
 | 
					    remark: '',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  fileTable: any[] = []
 | 
				
			||||||
 | 
					  btnLoading = false
 | 
				
			||||||
 | 
					  fileContent = {
 | 
				
			||||||
 | 
					    fileId: 0,
 | 
				
			||||||
 | 
					    content: '',
 | 
				
			||||||
 | 
					    contentVisible: false,
 | 
				
			||||||
 | 
					    dialogTitle: '',
 | 
				
			||||||
 | 
					    path: '',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  tree = {
 | 
				
			||||||
 | 
					    title: '',
 | 
				
			||||||
 | 
					    visible: false,
 | 
				
			||||||
 | 
					    folder: { id: 0 },
 | 
				
			||||||
 | 
					    node: {
 | 
				
			||||||
 | 
					      childNodes: [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    resolve: {},
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  props = {
 | 
				
			||||||
 | 
					    label: 'name',
 | 
				
			||||||
 | 
					    children: 'zones',
 | 
				
			||||||
 | 
					    isLeaf: 'leaf',
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Watch('machineId', { deep: true })
 | 
				
			||||||
 | 
					  onDataChange() {
 | 
				
			||||||
 | 
					    if (this.machineId) {
 | 
				
			||||||
 | 
					      this.getFiles()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async getFiles() {
 | 
				
			||||||
 | 
					    const res = await this.files.request({ id: this.machineId })
 | 
				
			||||||
 | 
					    this.fileTable = res
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * tab切换触发事件
 | 
				
			||||||
 | 
					   * @param {Object} tab
 | 
				
			||||||
 | 
					   * @param {Object} event
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  // handleClick(tab, event) {
 | 
				
			||||||
 | 
					  //   // if (tab.name == 'file-manage') {
 | 
				
			||||||
 | 
					  //   //   this.fileManage.node.childNodes = [];
 | 
				
			||||||
 | 
					  //   //   this.loadNode(this.fileManage.node, this.fileManage.resolve);
 | 
				
			||||||
 | 
					  //   // }
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  add() {
 | 
				
			||||||
 | 
					    // 往数组头部添加元素
 | 
				
			||||||
 | 
					    this.fileTable = [{}].concat(this.fileTable)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addFiles(row: any) {
 | 
				
			||||||
 | 
					    row.machineId = this.machineId
 | 
				
			||||||
 | 
					    await this.addFile.request(row)
 | 
				
			||||||
 | 
					    this.$message.success('添加成功')
 | 
				
			||||||
 | 
					    this.getFiles()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteRow(idx: any, row: any) {
 | 
				
			||||||
 | 
					    if (row.id) {
 | 
				
			||||||
 | 
					      this.$confirm(`此操作将删除 [${row.name}], 是否继续?`, '提示', {
 | 
				
			||||||
 | 
					        confirmButtonText: '确定',
 | 
				
			||||||
 | 
					        cancelButtonText: '取消',
 | 
				
			||||||
 | 
					        type: 'warning',
 | 
				
			||||||
 | 
					      }).then(() => {
 | 
				
			||||||
 | 
					        // 删除配置文件
 | 
				
			||||||
 | 
					        this.delFile
 | 
				
			||||||
 | 
					          .request({
 | 
				
			||||||
 | 
					            machineId: this.machineId,
 | 
				
			||||||
 | 
					            id: row.id,
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .then((res) => {
 | 
				
			||||||
 | 
					            this.fileTable.splice(idx, 1)
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.fileTable.splice(idx, 1)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getConf(row: any) {
 | 
				
			||||||
 | 
					    if (row.type == 1) {
 | 
				
			||||||
 | 
					      this.tree.folder = row
 | 
				
			||||||
 | 
					      this.tree.title = row.name
 | 
				
			||||||
 | 
					      const treeNode = (this.tree.node.childNodes = [])
 | 
				
			||||||
 | 
					      this.loadNode(this.tree.node, this.tree.resolve)
 | 
				
			||||||
 | 
					      this.tree.visible = true
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.getFileContent(row.id, row.path)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async getFileContent(fileId: number, path: string) {
 | 
				
			||||||
 | 
					    const res = await machineApi.fileContent.request({
 | 
				
			||||||
 | 
					      fileId,
 | 
				
			||||||
 | 
					      path,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    this.fileContent.content = res
 | 
				
			||||||
 | 
					    this.fileContent.fileId = fileId
 | 
				
			||||||
 | 
					    this.fileContent.dialogTitle = path
 | 
				
			||||||
 | 
					    this.fileContent.path = path
 | 
				
			||||||
 | 
					    this.fileContent.contentVisible = true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async updateContent() {
 | 
				
			||||||
 | 
					    await this.updateFileContent.request({
 | 
				
			||||||
 | 
					      content: this.fileContent.content,
 | 
				
			||||||
 | 
					      id: this.fileContent.fileId,
 | 
				
			||||||
 | 
					      path: this.fileContent.path,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    this.$message.success('修改成功')
 | 
				
			||||||
 | 
					    this.fileContent.contentVisible = false
 | 
				
			||||||
 | 
					    this.fileContent.content = ''
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 关闭取消按钮触发的事件
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  handleClose() {
 | 
				
			||||||
 | 
					    this.$emit('update:visible', false)
 | 
				
			||||||
 | 
					    this.$emit('update:machineId', null)
 | 
				
			||||||
 | 
					    this.$emit('cancel')
 | 
				
			||||||
 | 
					    this.activeName = 'conf-file'
 | 
				
			||||||
 | 
					    this.fileTable = []
 | 
				
			||||||
 | 
					    this.tree.folder = { id: 0 }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 加载文件树节点
 | 
				
			||||||
 | 
					   * @param {Object} node
 | 
				
			||||||
 | 
					   * @param {Object} resolve
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  async loadNode(node: any, resolve: any) {
 | 
				
			||||||
 | 
					    if (typeof resolve !== 'function') {
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const folder: any = this.tree.folder
 | 
				
			||||||
 | 
					    if (node.level === 0) {
 | 
				
			||||||
 | 
					      this.tree.node = node
 | 
				
			||||||
 | 
					      this.tree.resolve = resolve
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // let folder: any = this.tree.folder
 | 
				
			||||||
 | 
					      const path = folder ? folder.path : '/'
 | 
				
			||||||
 | 
					      return resolve([
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          name: path,
 | 
				
			||||||
 | 
					          type: 'd',
 | 
				
			||||||
 | 
					          path: path,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let path
 | 
				
			||||||
 | 
					    const data = node.data
 | 
				
			||||||
 | 
					    // 只有在第一级节点时,name==path,即上述level==0时设置的
 | 
				
			||||||
 | 
					    if (!data || data.name == data.path) {
 | 
				
			||||||
 | 
					      path = folder.path
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      path = data.path
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const res = await machineApi.lsFile.request({
 | 
				
			||||||
 | 
					      fileId: folder.id,
 | 
				
			||||||
 | 
					      path,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    for (const file of res) {
 | 
				
			||||||
 | 
					      const type = file.type
 | 
				
			||||||
 | 
					      if (type != 'd') {
 | 
				
			||||||
 | 
					        file.leaf = true
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return resolve(res)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteFile(node: any, data: any) {
 | 
				
			||||||
 | 
					    const file = data.path
 | 
				
			||||||
 | 
					    this.$confirm(`此操作将删除 [${file}], 是否继续?`, '提示', {
 | 
				
			||||||
 | 
					      confirmButtonText: '确定',
 | 
				
			||||||
 | 
					      cancelButtonText: '取消',
 | 
				
			||||||
 | 
					      type: 'warning',
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        machineApi.rmFile
 | 
				
			||||||
 | 
					          .request({ fileId: this.tree.folder.id, path: file })
 | 
				
			||||||
 | 
					          .then((res) => {
 | 
				
			||||||
 | 
					            this.$message.success('删除成功')
 | 
				
			||||||
 | 
					            const fileTree: any = this.$refs.fileTree
 | 
				
			||||||
 | 
					            fileTree.remove(node)
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(() => {})
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					<style lang="less">
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@@ -14,6 +14,7 @@ export default {
 | 
				
			|||||||
      type: String,
 | 
					      type: String,
 | 
				
			||||||
      default: '',
 | 
					      default: '',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    cmd: String
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  watch: {
 | 
					  watch: {
 | 
				
			||||||
    socketURI(val) {
 | 
					    socketURI(val) {
 | 
				
			||||||
@@ -38,11 +39,11 @@ export default {
 | 
				
			|||||||
        // cursorStyle: 'underline', //光标样式
 | 
					        // cursorStyle: 'underline', //光标样式
 | 
				
			||||||
        disableStdin: false,
 | 
					        disableStdin: false,
 | 
				
			||||||
        theme: {
 | 
					        theme: {
 | 
				
			||||||
        foreground: "#7e9192", //字体
 | 
					          foreground: '#7e9192', //字体
 | 
				
			||||||
        background: "#002833", //背景色
 | 
					          background: '#002833', //背景色
 | 
				
			||||||
        cursor: "help", //设置光标
 | 
					          cursor: 'help', //设置光标
 | 
				
			||||||
        lineHeight: 16
 | 
					          lineHeight: 16,
 | 
				
			||||||
      }
 | 
					        },
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      const fitAddon = new FitAddon()
 | 
					      const fitAddon = new FitAddon()
 | 
				
			||||||
      term.loadAddon(fitAddon)
 | 
					      term.loadAddon(fitAddon)
 | 
				
			||||||
@@ -66,11 +67,7 @@ export default {
 | 
				
			|||||||
      //  * /
 | 
					      //  * /
 | 
				
			||||||
      // 支持输入与粘贴方法
 | 
					      // 支持输入与粘贴方法
 | 
				
			||||||
      term.onData((key) => {
 | 
					      term.onData((key) => {
 | 
				
			||||||
        const cmd = {
 | 
					        this.sendCmd(key)
 | 
				
			||||||
          type: 'cmd',
 | 
					 | 
				
			||||||
          msg: key,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.send(cmd)
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      // 为解决窗体resize方法才会向后端发送列数和行数,所以页面加载时也要触发此方法
 | 
					      // 为解决窗体resize方法才会向后端发送列数和行数,所以页面加载时也要触发此方法
 | 
				
			||||||
      this.send({
 | 
					      this.send({
 | 
				
			||||||
@@ -78,6 +75,10 @@ export default {
 | 
				
			|||||||
        Cols: parseInt(term.cols),
 | 
					        Cols: parseInt(term.cols),
 | 
				
			||||||
        Rows: parseInt(term.rows),
 | 
					        Rows: parseInt(term.rows),
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      // 如果有初始要执行的命令,则发送执行命令
 | 
				
			||||||
 | 
					      if (this.cmd) {
 | 
				
			||||||
 | 
					        this.sendCmd(this.cmd + " \r")
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    initSocket() {
 | 
					    initSocket() {
 | 
				
			||||||
      this.socket = new WebSocket(this.socketURI)
 | 
					      this.socket = new WebSocket(this.socketURI)
 | 
				
			||||||
@@ -128,6 +129,13 @@ export default {
 | 
				
			|||||||
      // console.log(msg)
 | 
					      // console.log(msg)
 | 
				
			||||||
      this.socket.send(JSON.stringify(msg))
 | 
					      this.socket.send(JSON.stringify(msg))
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sendCmd(key) {
 | 
				
			||||||
 | 
					      this.send({
 | 
				
			||||||
 | 
					        type: 'cmd',
 | 
				
			||||||
 | 
					        msg: key,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    closeAll() {
 | 
					    closeAll() {
 | 
				
			||||||
      this.close()
 | 
					      this.close()
 | 
				
			||||||
      this.term.dispose()
 | 
					      this.term.dispose()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										236
									
								
								mayfly-go-front/src/views/mock-server/MockDataEdit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								mayfly-go-front/src/views/mock-server/MockDataEdit.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,236 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="mock-data-dialog">
 | 
				
			||||||
 | 
					    <el-dialog
 | 
				
			||||||
 | 
					      :title="title"
 | 
				
			||||||
 | 
					      :visible="visible"
 | 
				
			||||||
 | 
					      :show-close="false"
 | 
				
			||||||
 | 
					      width="800px"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-form :model="form" ref="mockDataForm" label-width="70px" size="small">
 | 
				
			||||||
 | 
					        <el-form-item prop="method" label="方法名">
 | 
				
			||||||
 | 
					          <el-input
 | 
				
			||||||
 | 
					            :disabled="type == 1"
 | 
				
			||||||
 | 
					            v-model.trim="form.method"
 | 
				
			||||||
 | 
					            placeholder="请输入方法名"
 | 
				
			||||||
 | 
					          ></el-input>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-form-item prop="description" label="描述">
 | 
				
			||||||
 | 
					          <el-input
 | 
				
			||||||
 | 
					            v-model.trim="form.description"
 | 
				
			||||||
 | 
					            placeholder="请输入方法描述"
 | 
				
			||||||
 | 
					          ></el-input>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-form-item prop="description" label="生效用户">
 | 
				
			||||||
 | 
					          <el-select
 | 
				
			||||||
 | 
					            v-model="form.effectiveUser"
 | 
				
			||||||
 | 
					            multiple
 | 
				
			||||||
 | 
					            filterable
 | 
				
			||||||
 | 
					            allow-create
 | 
				
			||||||
 | 
					            default-first-option
 | 
				
			||||||
 | 
					            style="width:100%"
 | 
				
			||||||
 | 
					            placeholder="请选择或创建生效用户,空为所有用户都生效"
 | 
				
			||||||
 | 
					          > 
 | 
				
			||||||
 | 
					          </el-select>
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-form-item prop="data" label="数据" id="jsonedit">
 | 
				
			||||||
 | 
					          <codemirror
 | 
				
			||||||
 | 
					            style="height: 400px"
 | 
				
			||||||
 | 
					            ref="cmEditor"
 | 
				
			||||||
 | 
					            v-model="form.data"
 | 
				
			||||||
 | 
					            :options="cmOptions"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </el-form-item>
 | 
				
			||||||
 | 
					      </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div style="text-align: center" class="dialog-footer">
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          :loading="btnLoading"
 | 
				
			||||||
 | 
					          @click="btnOk"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          :disabled="submitDisabled"
 | 
				
			||||||
 | 
					          >确 定</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-button @click="cancel()" :disabled="submitDisabled" size="mini"
 | 
				
			||||||
 | 
					          >取 消</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </el-dialog>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
 | 
				
			||||||
 | 
					import { mockApi } from './api'
 | 
				
			||||||
 | 
					import { notEmpty } from '@/common/assert'
 | 
				
			||||||
 | 
					import Utils from '../../common/Utils'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { codemirror } from 'vue-codemirror'
 | 
				
			||||||
 | 
					import 'codemirror/lib/codemirror.css'
 | 
				
			||||||
 | 
					import 'codemirror/theme/panda-syntax.css'
 | 
				
			||||||
 | 
					// import base style
 | 
				
			||||||
 | 
					require('codemirror/addon/selection/active-line')
 | 
				
			||||||
 | 
					import 'codemirror/mode/javascript/javascript.js'
 | 
				
			||||||
 | 
					import 'codemirror/addon/selection/active-line.js'
 | 
				
			||||||
 | 
					// 匹配括号
 | 
				
			||||||
 | 
					import 'codemirror/addon/edit/matchbrackets.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// json校验
 | 
				
			||||||
 | 
					require('script-loader!jsonlint')
 | 
				
			||||||
 | 
					import 'codemirror/addon/lint/lint'
 | 
				
			||||||
 | 
					import 'codemirror/addon/lint/lint.css'
 | 
				
			||||||
 | 
					import 'codemirror/addon/lint/json-lint'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  name: 'MockDataEdit',
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    codemirror,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export default class MockDataEdit extends Vue {
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  visible: boolean
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  data: [object, boolean]
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  title: string
 | 
				
			||||||
 | 
					  @Prop()
 | 
				
			||||||
 | 
					  type: number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cmOptions = {
 | 
				
			||||||
 | 
					    tabSize: 2,
 | 
				
			||||||
 | 
					    mode: 'application/json',
 | 
				
			||||||
 | 
					    theme: 'panda-syntax',
 | 
				
			||||||
 | 
					    // mode: {
 | 
				
			||||||
 | 
					    //   // 模式, 可查看 codemirror/mode 中的所有模式
 | 
				
			||||||
 | 
					    //   name: 'javascript',
 | 
				
			||||||
 | 
					    //   json: true,
 | 
				
			||||||
 | 
					    // },
 | 
				
			||||||
 | 
					    line: true,
 | 
				
			||||||
 | 
					    // 开启校验
 | 
				
			||||||
 | 
					    lint: true,
 | 
				
			||||||
 | 
					    gutters: ['CodeMirror-lint-markers'],
 | 
				
			||||||
 | 
					    indentWithTabs: true,
 | 
				
			||||||
 | 
					    smartIndent: true,
 | 
				
			||||||
 | 
					    matchBrackets: true,
 | 
				
			||||||
 | 
					    autofocus: true,
 | 
				
			||||||
 | 
					    styleSelectedText: true,
 | 
				
			||||||
 | 
					    styleActiveLine: true, // 高亮选中行
 | 
				
			||||||
 | 
					    foldGutter: true, // 块槽
 | 
				
			||||||
 | 
					    hintOptions: {
 | 
				
			||||||
 | 
					      // 当匹配只有一项的时候是否自动补全
 | 
				
			||||||
 | 
					      completeSingle: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  submitDisabled = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  form = {
 | 
				
			||||||
 | 
					    method: '',
 | 
				
			||||||
 | 
					    description: '',
 | 
				
			||||||
 | 
					    data: '',
 | 
				
			||||||
 | 
					    effectiveUser: null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  btnLoading = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // rules = {
 | 
				
			||||||
 | 
					  //   method: [
 | 
				
			||||||
 | 
					  //     {
 | 
				
			||||||
 | 
					  //       required: true,
 | 
				
			||||||
 | 
					  //       message: '请输入方法名',
 | 
				
			||||||
 | 
					  //       trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					  //     },
 | 
				
			||||||
 | 
					  //   ],
 | 
				
			||||||
 | 
					  //   description: [
 | 
				
			||||||
 | 
					  //     {
 | 
				
			||||||
 | 
					  //       required: true,
 | 
				
			||||||
 | 
					  //       message: '请输入方法描述',
 | 
				
			||||||
 | 
					  //       trigger: ['change', 'blur'],
 | 
				
			||||||
 | 
					  //     },
 | 
				
			||||||
 | 
					  //   ],
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Watch('data', { deep: true })
 | 
				
			||||||
 | 
					  onDataChange() {
 | 
				
			||||||
 | 
					    if (this.data) {
 | 
				
			||||||
 | 
					      Utils.copyProperties(this.data, this.form)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      Utils.resetProperties(this.form)
 | 
				
			||||||
 | 
					      this.form.data = ''
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // mounted() {
 | 
				
			||||||
 | 
					  //   Utils.copyProperties(this.data, this.form)
 | 
				
			||||||
 | 
					  //   this.codemirror.setValue(
 | 
				
			||||||
 | 
					  //     JSON.stringify(JSON.parse(this.data['data']), null, 2)
 | 
				
			||||||
 | 
					  //   )
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get codemirror() {
 | 
				
			||||||
 | 
					    return this.$refs.cmEditor['codemirror']
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  btnOk() {
 | 
				
			||||||
 | 
					    const mockDataForm: any = this.$refs['mockDataForm']
 | 
				
			||||||
 | 
					    mockDataForm.validate((valid: any) => {
 | 
				
			||||||
 | 
					      if (valid) {
 | 
				
			||||||
 | 
					        notEmpty(this.form.method, '方法名不能为空')
 | 
				
			||||||
 | 
					        notEmpty(this.form.description, '描述不能为空')
 | 
				
			||||||
 | 
					        notEmpty(this.form.data, '数据不能为空')
 | 
				
			||||||
 | 
					        let res
 | 
				
			||||||
 | 
					        if (this.type == 1) {
 | 
				
			||||||
 | 
					          res = mockApi.update.request(this.form)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          res = mockApi.create.request(this.form)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        res.then(
 | 
				
			||||||
 | 
					          (res: any) => {
 | 
				
			||||||
 | 
					            this.$message.success('保存成功')
 | 
				
			||||||
 | 
					            this.$emit('submitSuccess')
 | 
				
			||||||
 | 
					            this.submitDisabled = false
 | 
				
			||||||
 | 
					            this.cancel()
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          (e: any) => {
 | 
				
			||||||
 | 
					            this.submitDisabled = false
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return false
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  cancel() {
 | 
				
			||||||
 | 
					    this.$emit('update:visible', false)
 | 
				
			||||||
 | 
					    this.$emit('cancel')
 | 
				
			||||||
 | 
					    // this.codemirror.setValue('')
 | 
				
			||||||
 | 
					    // setTimeout(() => {
 | 
				
			||||||
 | 
					    //   this.resetForm()
 | 
				
			||||||
 | 
					    // }, 200)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  resetForm() {
 | 
				
			||||||
 | 
					    const mockDataForm: any = this.$refs['mockDataForm']
 | 
				
			||||||
 | 
					    if (mockDataForm) {                                       
 | 
				
			||||||
 | 
					      mockDataForm.clearValidate()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					<style lang="less">
 | 
				
			||||||
 | 
					// 	.m-dialog {
 | 
				
			||||||
 | 
					// 		.el-cascader {
 | 
				
			||||||
 | 
					// 			width: 100%;
 | 
				
			||||||
 | 
					// 		}
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					#jsonedit {
 | 
				
			||||||
 | 
					  .CodeMirror {
 | 
				
			||||||
 | 
					    overflow-y: scroll !important;
 | 
				
			||||||
 | 
					    height: 400px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										244
									
								
								mayfly-go-front/src/views/mock-server/MockDataList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								mayfly-go-front/src/views/mock-server/MockDataList.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,244 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <div class="toolbar">
 | 
				
			||||||
 | 
					      <div class="fl">
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          @click="search"
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          icon="el-icon-refresh"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          plain
 | 
				
			||||||
 | 
					          >刷新</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          @click="editData(null)"
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          icon="el-icon-plus"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          plain
 | 
				
			||||||
 | 
					          >添加</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          type="primary"
 | 
				
			||||||
 | 
					          icon="el-icon-edit"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          :disabled="currentData == null"
 | 
				
			||||||
 | 
					          @click="editData(currentData)"
 | 
				
			||||||
 | 
					          plain
 | 
				
			||||||
 | 
					          >查看&编辑</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          :disabled="currentData == null"
 | 
				
			||||||
 | 
					          type="danger"
 | 
				
			||||||
 | 
					          icon="el-icon-delete"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          @click="deleteData()"
 | 
				
			||||||
 | 
					          >删除</el-button
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div style="float: right">
 | 
				
			||||||
 | 
					        <el-input
 | 
				
			||||||
 | 
					          placeholder="方法名过滤"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					          style="width: 140px"
 | 
				
			||||||
 | 
					          @clear="search"
 | 
				
			||||||
 | 
					          plain
 | 
				
			||||||
 | 
					          v-model="queryParam"
 | 
				
			||||||
 | 
					          clearable
 | 
				
			||||||
 | 
					        ></el-input>
 | 
				
			||||||
 | 
					        <el-button
 | 
				
			||||||
 | 
					          @click="filterData"
 | 
				
			||||||
 | 
					          type="success"
 | 
				
			||||||
 | 
					          icon="el-icon-search"
 | 
				
			||||||
 | 
					          size="mini"
 | 
				
			||||||
 | 
					        ></el-button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-table
 | 
				
			||||||
 | 
					      :data="data"
 | 
				
			||||||
 | 
					      @current-change="choose"
 | 
				
			||||||
 | 
					      border
 | 
				
			||||||
 | 
					      stripe
 | 
				
			||||||
 | 
					      style="width: 100%"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <el-table-column label="选择" width="55px">
 | 
				
			||||||
 | 
					        <template slot-scope="scope">
 | 
				
			||||||
 | 
					          <el-radio v-model="currentMethod" :label="scope.row.method">
 | 
				
			||||||
 | 
					            <i></i>
 | 
				
			||||||
 | 
					          </el-radio>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </el-table-column>
 | 
				
			||||||
 | 
					      <el-table-column
 | 
				
			||||||
 | 
					        prop="method"
 | 
				
			||||||
 | 
					        label="方法名"
 | 
				
			||||||
 | 
					        :min-width="50"
 | 
				
			||||||
 | 
					      ></el-table-column>
 | 
				
			||||||
 | 
					      <el-table-column
 | 
				
			||||||
 | 
					        prop="description"
 | 
				
			||||||
 | 
					        label="描述"
 | 
				
			||||||
 | 
					        :min-width="50"
 | 
				
			||||||
 | 
					      ></el-table-column>
 | 
				
			||||||
 | 
					      <el-table-column prop="description" label="状态" :width="75">
 | 
				
			||||||
 | 
					        <template slot-scope="scope">
 | 
				
			||||||
 | 
					          <el-tooltip
 | 
				
			||||||
 | 
					            :content="scope.row.enable == 1 ? '启用' : '禁用'"
 | 
				
			||||||
 | 
					            placement="top"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <el-switch
 | 
				
			||||||
 | 
					              v-model="scope.row.enable"
 | 
				
			||||||
 | 
					              :active-value="1"
 | 
				
			||||||
 | 
					              active-color="#13ce66"
 | 
				
			||||||
 | 
					              inactive-color="#ff4949"
 | 
				
			||||||
 | 
					              @change="changeStatus(scope.row)"
 | 
				
			||||||
 | 
					            ></el-switch>
 | 
				
			||||||
 | 
					          </el-tooltip>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </el-table-column>
 | 
				
			||||||
 | 
					      <el-table-column
 | 
				
			||||||
 | 
					        prop="effectiveUser"
 | 
				
			||||||
 | 
					        label="生效用户"
 | 
				
			||||||
 | 
					        :min-width="70"
 | 
				
			||||||
 | 
					        show-overflow-tooltip
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <template slot-scope="scope">
 | 
				
			||||||
 | 
					          {{ showEffectiveUser(scope.row.effectiveUser) }}
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					      </el-table-column>
 | 
				
			||||||
 | 
					      <el-table-column
 | 
				
			||||||
 | 
					        prop="data"
 | 
				
			||||||
 | 
					        label="数据"
 | 
				
			||||||
 | 
					        min-width="100"
 | 
				
			||||||
 | 
					        show-overflow-tooltip
 | 
				
			||||||
 | 
					      ></el-table-column>
 | 
				
			||||||
 | 
					    </el-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <mock-data-edit
 | 
				
			||||||
 | 
					      :visible.sync="editDialog.visible"
 | 
				
			||||||
 | 
					      :data.sync="editDialog.data"
 | 
				
			||||||
 | 
					      :title="editDialog.title"
 | 
				
			||||||
 | 
					      :type="editDialog.type"
 | 
				
			||||||
 | 
					      @cancel="closeEditDialog"
 | 
				
			||||||
 | 
					      @submitSuccess="submitSuccess"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { Component, Vue } from 'vue-property-decorator'
 | 
				
			||||||
 | 
					import { mockApi } from './api'
 | 
				
			||||||
 | 
					import MockDataEdit from './MockDataEdit.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  name: 'MockDataList',
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    MockDataEdit,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export default class MockDataList extends Vue {
 | 
				
			||||||
 | 
					  data: Array<any> = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  currentData: any = null
 | 
				
			||||||
 | 
					  currentMethod = null
 | 
				
			||||||
 | 
					  queryParam = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  editDialog = {
 | 
				
			||||||
 | 
					    data: {},
 | 
				
			||||||
 | 
					    visible: false,
 | 
				
			||||||
 | 
					    title: '',
 | 
				
			||||||
 | 
					    type: 0,
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  choose(item: any) {
 | 
				
			||||||
 | 
					    if (!item) {
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.currentData = item
 | 
				
			||||||
 | 
					    this.currentMethod = item.method
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  editData(data: any) {
 | 
				
			||||||
 | 
					    this.editDialog.data = data
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      this.editDialog.title = '修改mock数据'
 | 
				
			||||||
 | 
					      this.editDialog.type = 1
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.editDialog.title = '新增mock数据'
 | 
				
			||||||
 | 
					      this.editDialog.type = 0
 | 
				
			||||||
 | 
					      // this.delChoose()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.editDialog.visible = true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  closeEditDialog() {
 | 
				
			||||||
 | 
					    // this.currentData.opentime = Date.now()
 | 
				
			||||||
 | 
					    // this.editDialog.data = this.currentData
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  delChoose() {
 | 
				
			||||||
 | 
					    this.currentMethod = null
 | 
				
			||||||
 | 
					    this.currentData = null
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  changeStatus(row: any) {
 | 
				
			||||||
 | 
					    const enable = row.enable
 | 
				
			||||||
 | 
					    row.enable = enable ? 1 : 0
 | 
				
			||||||
 | 
					    mockApi.update
 | 
				
			||||||
 | 
					      .request(row)
 | 
				
			||||||
 | 
					      .then((res) => {
 | 
				
			||||||
 | 
					        this.$message.success('操作成功')
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch((e) => {
 | 
				
			||||||
 | 
					        row.enable = enable
 | 
				
			||||||
 | 
					        this.$message.success('操作失败')
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  showEffectiveUser(users: string[]) {
 | 
				
			||||||
 | 
					    if (!users || users.length == 0) {
 | 
				
			||||||
 | 
					      return '全部用户'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return users.join(', ')
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deleteData() {
 | 
				
			||||||
 | 
					    mockApi.delete.request({ method: this.currentMethod }).then((res) => {
 | 
				
			||||||
 | 
					      this.$message.success('删除成功')
 | 
				
			||||||
 | 
					      this.search()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  submitSuccess() {
 | 
				
			||||||
 | 
					    this.delChoose()
 | 
				
			||||||
 | 
					    this.search()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mounted() {
 | 
				
			||||||
 | 
					    this.search()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  filterData() {
 | 
				
			||||||
 | 
					    this.data = this.data.filter(
 | 
				
			||||||
 | 
					      (item) => item.method.indexOf(this.queryParam) != -1
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async search() {
 | 
				
			||||||
 | 
					    if (this.data.length != 0) {
 | 
				
			||||||
 | 
					      this.data = []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const res = await mockApi.list.request(null)
 | 
				
			||||||
 | 
					    const values: string[] = Object.values(res)
 | 
				
			||||||
 | 
					    for (const value of values) {
 | 
				
			||||||
 | 
					      this.data.push(JSON.parse(value))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					.el-dialog__body {
 | 
				
			||||||
 | 
					  padding: 2px 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										9
									
								
								mayfly-go-front/src/views/mock-server/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								mayfly-go-front/src/views/mock-server/api.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import Api from '@/common/Api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mockApi = {
 | 
				
			||||||
 | 
					    // 获取权限列表
 | 
				
			||||||
 | 
					    list: Api.create("/mock-datas", 'get'),
 | 
				
			||||||
 | 
					    create: Api.create("/mock-datas", 'post'),
 | 
				
			||||||
 | 
					    update: Api.create("/mock-datas", 'put'),
 | 
				
			||||||
 | 
					    delete: Api.create("/mock-datas/{method}", 'delete'),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								mayfly-go-front/src/views/mock-server/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mayfly-go-front/src/views/mock-server/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export { default } from './MockDataList.vue';
 | 
				
			||||||
							
								
								
									
										21
									
								
								mock-server/conf/app.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								mock-server/conf/app.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					appname = mayfly-mock
 | 
				
			||||||
 | 
					httpport = 8888
 | 
				
			||||||
 | 
					copyrequestbody = true
 | 
				
			||||||
 | 
					autorender = false
 | 
				
			||||||
 | 
					EnableErrorsRender = false
 | 
				
			||||||
 | 
					runmode = "prod"
 | 
				
			||||||
 | 
					; mysqluser = "root"
 | 
				
			||||||
 | 
					; mysqlpass = "111049"
 | 
				
			||||||
 | 
					; mysqlurls = "127.0.0.1"
 | 
				
			||||||
 | 
					; mysqldb   = "mayfly-job"
 | 
				
			||||||
 | 
					# EnableAdmin = false
 | 
				
			||||||
 | 
					# AdminHttpAddr = 0.0.0.0 #默认监听地址是localhost
 | 
				
			||||||
 | 
					# AdminHttpPort = 8088
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dev]
 | 
				
			||||||
 | 
					httpport = 8888
 | 
				
			||||||
 | 
					[prod]
 | 
				
			||||||
 | 
					httpport = 8888
 | 
				
			||||||
 | 
					[test]
 | 
				
			||||||
 | 
					httpport = 8888
 | 
				
			||||||
							
								
								
									
										3
									
								
								mock-server/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								mock-server/config.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					redis:
 | 
				
			||||||
 | 
					  host: 127.0.0.1
 | 
				
			||||||
 | 
					  port: 6379
 | 
				
			||||||
							
								
								
									
										23
									
								
								mock-server/controllers/form/form.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mock-server/controllers/form/form.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MockData struct {
 | 
				
			||||||
 | 
						Method        string   `valid:"Required" json:"method"`
 | 
				
			||||||
 | 
						Enable        uint     `json:"enable"`
 | 
				
			||||||
 | 
						Description   string   `valid:"Required" json:"description"`
 | 
				
			||||||
 | 
						Data          string   `valid:"Required" json:"data"`
 | 
				
			||||||
 | 
						EffectiveUser []string `json:"effectiveUser"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Machine struct {
 | 
				
			||||||
 | 
						Name     string `json:"name"`
 | 
				
			||||||
 | 
						Ip       string `json:"ip"`       // IP地址
 | 
				
			||||||
 | 
						Username string `json:"username"` // 用户名
 | 
				
			||||||
 | 
						Password string `json:"-"`
 | 
				
			||||||
 | 
						Port     int    `json:"port"` // 端口号
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MachineService struct {
 | 
				
			||||||
 | 
						Name    string `json:"name"`
 | 
				
			||||||
 | 
						Ip      string `json:"ip"`      // IP地址
 | 
				
			||||||
 | 
						Service string `json:"service"` // 服务命令
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										127
									
								
								mock-server/controllers/machine.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								mock-server/controllers/machine.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
				
			|||||||
 | 
					package controllers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/base"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
 | 
						"mayfly-go/base/rediscli"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"mayfly-go/mock-server/machine"
 | 
				
			||||||
 | 
						"mayfly-go/mock-server/models"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MachineController struct {
 | 
				
			||||||
 | 
						base.Controller
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const machineKey = "ccbscf:machines"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var upgrader = websocket.Upgrader{
 | 
				
			||||||
 | 
						ReadBufferSize:  1024,
 | 
				
			||||||
 | 
						WriteBufferSize: 1024 * 1024 * 10,
 | 
				
			||||||
 | 
						CheckOrigin: func(r *http.Request) bool {
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) Machines() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							return rediscli.HGetAll(machineKey)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 创建机器信息
 | 
				
			||||||
 | 
					func (c *MachineController) CreateMachine() {
 | 
				
			||||||
 | 
						c.Operation(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) {
 | 
				
			||||||
 | 
							machine := &models.Machine{}
 | 
				
			||||||
 | 
							c.UnmarshalBodyAndValid(machine)
 | 
				
			||||||
 | 
							machine.CreateMachine()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas/:method [delete]
 | 
				
			||||||
 | 
					func (c *MockController) DeleteMachine() {
 | 
				
			||||||
 | 
						c.Operation(ctx.NewReqCtx(false, "删除mock数据"), func(account *ctx.LoginAccount) {
 | 
				
			||||||
 | 
							models.DeleteMachine(c.Ctx.Input.Param(":ip"))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) Run() {
 | 
				
			||||||
 | 
						rc := ctx.NewReqCtx(true, "执行机器命令")
 | 
				
			||||||
 | 
						c.ReturnData(rc, func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							cmd := c.GetString("cmd")
 | 
				
			||||||
 | 
							biz.NotEmpty(cmd, "cmd不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rc.ReqParam = cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							res, err := c.getCli().Run(cmd)
 | 
				
			||||||
 | 
							biz.BizErrIsNil(err, "执行命令失败")
 | 
				
			||||||
 | 
							return res
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 系统基本信息
 | 
				
			||||||
 | 
					func (c *MachineController) SysInfo() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							res, err := c.getCli().GetSystemInfo()
 | 
				
			||||||
 | 
							biz.BizErrIsNil(err, "获取系统基本信息失败")
 | 
				
			||||||
 | 
							return res
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// top命令信息
 | 
				
			||||||
 | 
					func (c *MachineController) Top() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							return c.getCli().GetTop()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) GetProcessByName() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(true), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							name := c.GetString("name")
 | 
				
			||||||
 | 
							biz.NotEmpty(name, "name不能为空")
 | 
				
			||||||
 | 
							res, err := c.getCli().GetProcessByName(name)
 | 
				
			||||||
 | 
							biz.BizErrIsNil(err, "获取失败")
 | 
				
			||||||
 | 
							return res
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) WsSSH() {
 | 
				
			||||||
 | 
						wsConn, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(biz.NewBizErr("获取requst responsewirte错误"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cols, _ := c.GetInt("cols", 80)
 | 
				
			||||||
 | 
						rows, _ := c.GetInt("rows", 40)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sws, err := machine.NewLogicSshWsSession(cols, rows, c.getCli(), wsConn)
 | 
				
			||||||
 | 
						if sws == nil {
 | 
				
			||||||
 | 
							panic(biz.NewBizErr("连接失败"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//if wshandleError(wsConn, err) {
 | 
				
			||||||
 | 
						//	return
 | 
				
			||||||
 | 
						//}
 | 
				
			||||||
 | 
						defer sws.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						quitChan := make(chan bool, 3)
 | 
				
			||||||
 | 
						sws.Start(quitChan)
 | 
				
			||||||
 | 
						go sws.Wait(quitChan)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<-quitChan
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) GetMachineIp() string {
 | 
				
			||||||
 | 
						machineIp := c.Ctx.Input.Param(":ip")
 | 
				
			||||||
 | 
						biz.IsTrue(utils.StrLen(machineIp) > 0, "ip错误")
 | 
				
			||||||
 | 
						return machineIp
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *MachineController) getCli() *machine.Cli {
 | 
				
			||||||
 | 
						cli, err := machine.GetCli(c.GetMachineIp())
 | 
				
			||||||
 | 
						biz.BizErrIsNil(err, "获取客户端错误")
 | 
				
			||||||
 | 
						return cli
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										78
									
								
								mock-server/controllers/mock.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								mock-server/controllers/mock.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					package controllers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"mayfly-go/base"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/ctx"
 | 
				
			||||||
 | 
						"mayfly-go/base/rediscli"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"mayfly-go/mock-server/controllers/form"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const key = "ccbscf:mock:data"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MockController struct {
 | 
				
			||||||
 | 
						base.Controller
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas/:method [get]
 | 
				
			||||||
 | 
					func (c *MockController) GetMockData() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(false), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							val := rediscli.HGet(key, c.Ctx.Input.Param(":method"))
 | 
				
			||||||
 | 
							mockData := &form.MockData{}
 | 
				
			||||||
 | 
							json.Unmarshal([]byte(val), mockData)
 | 
				
			||||||
 | 
							biz.IsTrue(mockData.Enable == 1, "无该mock数据")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							eu := mockData.EffectiveUser
 | 
				
			||||||
 | 
							// 如果设置的生效用户为空,则表示所有用户都生效
 | 
				
			||||||
 | 
							if len(eu) == 0 {
 | 
				
			||||||
 | 
								return mockData.Data
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 该mock数据需要指定的生效用户才可访问
 | 
				
			||||||
 | 
							username := c.GetString("username")
 | 
				
			||||||
 | 
							biz.IsTrue(utils.StrLen(username) != 0, "该用户无法访问该mock数据")
 | 
				
			||||||
 | 
							for _, e := range eu {
 | 
				
			||||||
 | 
								if username == e {
 | 
				
			||||||
 | 
									return mockData.Data
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							panic(biz.NewBizErr("该用户无法访问该mock数据"))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas [put]
 | 
				
			||||||
 | 
					func (c *MockController) UpdateMockData() {
 | 
				
			||||||
 | 
						c.Operation(ctx.NewReqCtx(true, "修改mock数据"), func(account *ctx.LoginAccount) {
 | 
				
			||||||
 | 
							mockData := &form.MockData{}
 | 
				
			||||||
 | 
							c.UnmarshalBodyAndValid(mockData)
 | 
				
			||||||
 | 
							val, _ := json.Marshal(mockData)
 | 
				
			||||||
 | 
							rediscli.HSet(key, mockData.Method, val)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas [post]
 | 
				
			||||||
 | 
					func (c *MockController) CreateMockData() {
 | 
				
			||||||
 | 
						c.Operation(ctx.NewReqCtx(true, "保存mock数据"), func(account *ctx.LoginAccount) {
 | 
				
			||||||
 | 
							mockData := &form.MockData{}
 | 
				
			||||||
 | 
							c.UnmarshalBodyAndValid(mockData)
 | 
				
			||||||
 | 
							biz.IsTrue(!rediscli.HExist(key, mockData.Method), "该方法已存在")
 | 
				
			||||||
 | 
							val, _ := json.Marshal(mockData)
 | 
				
			||||||
 | 
							rediscli.HSet(key, mockData.Method, val)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas [get]
 | 
				
			||||||
 | 
					func (c *MockController) GetAllData() {
 | 
				
			||||||
 | 
						c.ReturnData(ctx.NewNoLogReqCtx(false), func(account *ctx.LoginAccount) interface{} {
 | 
				
			||||||
 | 
							return rediscli.HGetAll(key)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @router /api/mock-datas/:method [delete]
 | 
				
			||||||
 | 
					func (c *MockController) DeleteMockData() {
 | 
				
			||||||
 | 
						c.Operation(ctx.NewReqCtx(false, "删除mock数据"), func(account *ctx.LoginAccount) {
 | 
				
			||||||
 | 
							rediscli.HDel(key, c.Ctx.Input.Param(":method"))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								mock-server/lastupdate.tmp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								mock-server/lastupdate.tmp
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					{"/Users/hml/Desktop/project/go/mayfly-go/mock-server/controllers":1615026881770981752}
 | 
				
			||||||
							
								
								
									
										192
									
								
								mock-server/machine/machine.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								mock-server/machine/machine.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"mayfly-go/mock-server/models"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/pkg/sftp"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/ssh/terminal"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 客户端信息
 | 
				
			||||||
 | 
					type Cli struct {
 | 
				
			||||||
 | 
						machine *models.Machine
 | 
				
			||||||
 | 
						// ssh客户端
 | 
				
			||||||
 | 
						client *ssh.Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 客户端缓存
 | 
				
			||||||
 | 
					var clientCache sync.Map
 | 
				
			||||||
 | 
					var mutex sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 从缓存中获取客户端信息,不存在则查库,并新建
 | 
				
			||||||
 | 
					func GetCli(machineIp string) (*Cli, error) {
 | 
				
			||||||
 | 
						mutex.Lock()
 | 
				
			||||||
 | 
						defer mutex.Unlock()
 | 
				
			||||||
 | 
						load, ok := clientCache.Load(machineIp)
 | 
				
			||||||
 | 
						if ok {
 | 
				
			||||||
 | 
							return load.(*Cli), nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cli, err := newClient(models.GetMachineByIp(machineIp))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						clientCache.LoadOrStore(machineIp, cli)
 | 
				
			||||||
 | 
						return cli, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//根据机器信息创建客户端对象
 | 
				
			||||||
 | 
					func newClient(machine *models.Machine) (*Cli, error) {
 | 
				
			||||||
 | 
						if machine == nil {
 | 
				
			||||||
 | 
							return nil, errors.New("机器不存在")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cli := new(Cli)
 | 
				
			||||||
 | 
						cli.machine = machine
 | 
				
			||||||
 | 
						err := cli.connect()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cli, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//连接
 | 
				
			||||||
 | 
					func (c *Cli) connect() error {
 | 
				
			||||||
 | 
						// 如果已经有client则直接返回
 | 
				
			||||||
 | 
						if c.client != nil {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						m := c.machine
 | 
				
			||||||
 | 
						config := ssh.ClientConfig{
 | 
				
			||||||
 | 
							User: m.Username,
 | 
				
			||||||
 | 
							Auth: []ssh.AuthMethod{ssh.Password(m.Password)},
 | 
				
			||||||
 | 
							HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Timeout: 5 * time.Second,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						addr := fmt.Sprintf("%s:%d", m.Ip, m.Port)
 | 
				
			||||||
 | 
						sshClient, err := ssh.Dial("tcp", addr, &config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.client = sshClient
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 测试连接
 | 
				
			||||||
 | 
					func TestConn(m *models.Machine) (*ssh.Client, error) {
 | 
				
			||||||
 | 
						config := ssh.ClientConfig{
 | 
				
			||||||
 | 
							User: m.Username,
 | 
				
			||||||
 | 
							Auth: []ssh.AuthMethod{ssh.Password(m.Password)},
 | 
				
			||||||
 | 
							HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Timeout: 5 * time.Second,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						addr := fmt.Sprintf("%s:%d", m.Ip, m.Port)
 | 
				
			||||||
 | 
						sshClient, err := ssh.Dial("tcp", addr, &config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return sshClient, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 关闭client和并从缓存中移除
 | 
				
			||||||
 | 
					func (c *Cli) Close() {
 | 
				
			||||||
 | 
						if c.client != nil {
 | 
				
			||||||
 | 
							c.client.Close()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if utils.StrLen(c.machine.Ip) > 0 {
 | 
				
			||||||
 | 
							clientCache.Delete(c.machine.Ip)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取sftp client
 | 
				
			||||||
 | 
					func (c *Cli) GetSftpCli() *sftp.Client {
 | 
				
			||||||
 | 
						if c.client == nil {
 | 
				
			||||||
 | 
							if err := c.connect(); err != nil {
 | 
				
			||||||
 | 
								panic(biz.NewBizErr("连接ssh失败:" + err.Error()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						client, serr := sftp.NewClient(c.client, sftp.MaxPacket(1<<15))
 | 
				
			||||||
 | 
						if serr != nil {
 | 
				
			||||||
 | 
							panic(biz.NewBizErr("获取sftp client失败:" + serr.Error()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取session
 | 
				
			||||||
 | 
					func (c *Cli) GetSession() (*ssh.Session, error) {
 | 
				
			||||||
 | 
						if c.client == nil {
 | 
				
			||||||
 | 
							if err := c.connect(); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c.client.NewSession()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//执行shell
 | 
				
			||||||
 | 
					//@param shell shell脚本命令
 | 
				
			||||||
 | 
					func (c *Cli) Run(shell string) (*string, error) {
 | 
				
			||||||
 | 
						session, err := c.GetSession()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							c.Close()
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer session.Close()
 | 
				
			||||||
 | 
						buf, rerr := session.CombinedOutput(shell)
 | 
				
			||||||
 | 
						if rerr != nil {
 | 
				
			||||||
 | 
							return nil, rerr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						res := string(buf)
 | 
				
			||||||
 | 
						return &res, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//执行带交互的命令
 | 
				
			||||||
 | 
					func (c *Cli) RunTerminal(shell string, stdout, stderr io.Writer) error {
 | 
				
			||||||
 | 
						session, err := c.GetSession()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						//defer session.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd := int(os.Stdin.Fd())
 | 
				
			||||||
 | 
						oldState, err := terminal.MakeRaw(fd)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer terminal.Restore(fd, oldState)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						session.Stdout = stdout
 | 
				
			||||||
 | 
						session.Stderr = stderr
 | 
				
			||||||
 | 
						session.Stdin = os.Stdin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						termWidth, termHeight, err := terminal.GetSize(fd)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Set up terminal modes
 | 
				
			||||||
 | 
						modes := ssh.TerminalModes{
 | 
				
			||||||
 | 
							ssh.ECHO:          1,     // enable echoing
 | 
				
			||||||
 | 
							ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
 | 
				
			||||||
 | 
							ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Request pseudo terminal
 | 
				
			||||||
 | 
						if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return session.Run(shell)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										142
									
								
								mock-server/machine/machine_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								mock-server/machine/machine_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSSH(t *testing.T) {
 | 
				
			||||||
 | 
						//ssh.ListenAndServe("148.70.36.197")
 | 
				
			||||||
 | 
						//cli := New("148.70.36.197", "root", "gea&630_..91mn#", 22)
 | 
				
			||||||
 | 
						////output, err := cli.Run("free -h")
 | 
				
			||||||
 | 
						////fmt.Printf("%v\n%v", output, err)
 | 
				
			||||||
 | 
						//err := cli.RunTerminal("tail -f /usr/local/java/logs/eatlife-info.log", os.Stdout, os.Stdin)
 | 
				
			||||||
 | 
						//fmt.Println(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						res := "top - 17:14:07 up 5 days,  6:30,  2 users,  load average: 0.03, 0.04, 0.05\nTasks: 101 total,   1 running, 100 sleeping,   0 stopped,   0 zombie\n%Cpu(s):  6.2 us,  0.0 sy,  0.0 ni, 93.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st\nKiB Mem :  1882012 total,    73892 free,   770360 used,  1037760 buff/cache\nKiB Swap:        0 total,        0 free,        0 used.   933492 avail Mem"
 | 
				
			||||||
 | 
						split := strings.Split(res, "\n")
 | 
				
			||||||
 | 
						//var firstLine string
 | 
				
			||||||
 | 
						//for i := 0; i < len(split); i++ {
 | 
				
			||||||
 | 
						//	if i == 0 {
 | 
				
			||||||
 | 
						//		val := strings.Split(split[i], "top -")[1]
 | 
				
			||||||
 | 
						//		vals := strings.Split(val, ",")
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						//	}
 | 
				
			||||||
 | 
						//}
 | 
				
			||||||
 | 
						firstLine := strings.Split(strings.Split(split[0], "top -")[1], ",")
 | 
				
			||||||
 | 
						//  17:14:07 up 5 days
 | 
				
			||||||
 | 
						up := strings.Trim(strings.Split(firstLine[0], "up")[1], " ") + firstLine[1]
 | 
				
			||||||
 | 
						//   2 users
 | 
				
			||||||
 | 
						users := strings.Split(strings.Trim(firstLine[2], " "), " ")[0]
 | 
				
			||||||
 | 
						//   load average: 0.03
 | 
				
			||||||
 | 
						oneMinLa := strings.Trim(strings.Split(strings.Trim(firstLine[3], " "), ":")[1], " ")
 | 
				
			||||||
 | 
						fiveMinLa := strings.Trim(firstLine[4], " ")
 | 
				
			||||||
 | 
						fietMinLa := strings.Trim(firstLine[5], " ")
 | 
				
			||||||
 | 
						fmt.Println(firstLine, up, users, oneMinLa, fiveMinLa, fietMinLa)
 | 
				
			||||||
 | 
						tasks := Parse(strings.Split(split[1], "Tasks:")[1])
 | 
				
			||||||
 | 
						cpu := Parse(strings.Split(split[2], "%Cpu(s):")[1])
 | 
				
			||||||
 | 
						mem := Parse(strings.Split(split[3], "KiB Mem :")[1])
 | 
				
			||||||
 | 
						fmt.Println(tasks, cpu, mem)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Parse(val string) map[string]string {
 | 
				
			||||||
 | 
						res := make(map[string]string)
 | 
				
			||||||
 | 
						vals := strings.Split(val, ",")
 | 
				
			||||||
 | 
						for i := 0; i < len(vals); i++ {
 | 
				
			||||||
 | 
							trimData := strings.Trim(vals[i], " ")
 | 
				
			||||||
 | 
							keyValue := strings.Split(trimData, " ")
 | 
				
			||||||
 | 
							res[keyValue[1]] = keyValue[0]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestTemplateRev(t *testing.T) {
 | 
				
			||||||
 | 
						temp := "hello my name is {name} hahahaha lihaiba {age} years old {public}"
 | 
				
			||||||
 | 
						str := "hello my name is   hmlhmlhm  慌慌信息    hahahaha lihaiba   15   years old private  protected"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//temp1 := " top - {up},  {users} users,  load average: {loadavg}"
 | 
				
			||||||
 | 
						//str1 := " top - 17:14:07 up 5 days,  6:30,  2 users,  load average: 0.03, 0.04, 0.05"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//taskTemp := "Tasks: {total} total,   {running} running, {sleeping} sleeping,   {stopped} stopped,   {zombie} zombie"
 | 
				
			||||||
 | 
						//taskVal := "Tasks:   101  total,   1 running, 100   sleeping,    0   stopped,   0  zombie"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//nameRunne := []rune(str)
 | 
				
			||||||
 | 
						//index := strings.Index(temp, "{")
 | 
				
			||||||
 | 
						//ei := strings.Index(temp, "}") + 1
 | 
				
			||||||
 | 
						//next := temp[ei:]
 | 
				
			||||||
 | 
						//key := temp[index+1 : ei-1]
 | 
				
			||||||
 | 
						//value := SubString(str, index, UnicodeIndex(str, next))
 | 
				
			||||||
 | 
						res := make(map[string]interface{})
 | 
				
			||||||
 | 
						utils.ReverStrTemplate(temp, str, res)
 | 
				
			||||||
 | 
						fmt.Println(res)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//func ReverStrTemplate(temp, str string, res map[string]string) {
 | 
				
			||||||
 | 
					//	index := UnicodeIndex(temp, "{")
 | 
				
			||||||
 | 
					//	ei := UnicodeIndex(temp, "}") + 1
 | 
				
			||||||
 | 
					//	next := temp[ei:]
 | 
				
			||||||
 | 
					//	nextContain := UnicodeIndex(next, "{")
 | 
				
			||||||
 | 
					//	nextIndexValue := next
 | 
				
			||||||
 | 
					//	if nextContain != -1 {
 | 
				
			||||||
 | 
					//		nextIndexValue = SubString(next, 0, nextContain)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//	key := temp[index+1 : ei-1]
 | 
				
			||||||
 | 
					//	// 如果后面没有内容了,则取字符串的长度即可
 | 
				
			||||||
 | 
					//	var valueLastIndex int
 | 
				
			||||||
 | 
					//	if nextIndexValue == "" {
 | 
				
			||||||
 | 
					//		valueLastIndex = StrLen(str)
 | 
				
			||||||
 | 
					//	} else {
 | 
				
			||||||
 | 
					//		valueLastIndex = UnicodeIndex(str, nextIndexValue)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//	value := SubString(str, index, valueLastIndex)
 | 
				
			||||||
 | 
					//	res[key] = value
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	if nextContain != -1 {
 | 
				
			||||||
 | 
					//		ReverStrTemplate(next, SubString(str, UnicodeIndex(str, value)+StrLen(value), StrLen(str)), res)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//func StrLen(str string) int {
 | 
				
			||||||
 | 
					//	return len([]rune(str))
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//func SubString(str string, begin, end int) (substr string) {
 | 
				
			||||||
 | 
					//	// 将字符串的转换成[]rune
 | 
				
			||||||
 | 
					//	rs := []rune(str)
 | 
				
			||||||
 | 
					//	lth := len(rs)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// 简单的越界判断
 | 
				
			||||||
 | 
					//	if begin < 0 {
 | 
				
			||||||
 | 
					//		begin = 0
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//	if begin >= lth {
 | 
				
			||||||
 | 
					//		begin = lth
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//	if end > lth {
 | 
				
			||||||
 | 
					//		end = lth
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// 返回子串
 | 
				
			||||||
 | 
					//	return string(rs[begin:end])
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//func UnicodeIndex(str, substr string) int {
 | 
				
			||||||
 | 
					//	// 子串在字符串的字节位置
 | 
				
			||||||
 | 
					//	result := strings.Index(str, substr)
 | 
				
			||||||
 | 
					//	if result >= 0 {
 | 
				
			||||||
 | 
					//		// 获得子串之前的字符串并转换成[]byte
 | 
				
			||||||
 | 
					//		prefix := []byte(str)[0:result]
 | 
				
			||||||
 | 
					//		// 将子串之前的字符串转换成[]rune
 | 
				
			||||||
 | 
					//		rs := []rune(string(prefix))
 | 
				
			||||||
 | 
					//		// 获得子串之前的字符串的长度,便是子串在字符串的字符位置
 | 
				
			||||||
 | 
					//		result = len(rs)
 | 
				
			||||||
 | 
					//	}
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	return result
 | 
				
			||||||
 | 
					//}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestRunShellFile(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								mock-server/machine/shell.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								mock-server/machine/shell.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BasePath = "./machine/shell/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MonitorTemp = "cpuRate:{cpuRate}%,memRate:{memRate}%,sysLoad:{sysLoad}\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// shell文件内容缓存,避免每次读取文件
 | 
				
			||||||
 | 
					var shellCache = make(map[string]string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Cli) GetProcessByName(name string) (*string, error) {
 | 
				
			||||||
 | 
						return c.Run(getShellContent("sys_info"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Cli) GetSystemInfo() (*string, error) {
 | 
				
			||||||
 | 
						return c.Run(getShellContent("system_info"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取shell内容
 | 
				
			||||||
 | 
					func getShellContent(name string) string {
 | 
				
			||||||
 | 
						cacheShell := shellCache[name]
 | 
				
			||||||
 | 
						if cacheShell != "" {
 | 
				
			||||||
 | 
							return cacheShell
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bytes, err := ioutil.ReadFile(BasePath + name + ".sh")
 | 
				
			||||||
 | 
						biz.ErrIsNil(err, "获取shell文件失败")
 | 
				
			||||||
 | 
						shellStr := string(bytes)
 | 
				
			||||||
 | 
						shellCache[name] = shellStr
 | 
				
			||||||
 | 
						return shellStr
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								mock-server/machine/shell/get_process_by_name.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mock-server/machine/shell/get_process_by_name.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					#! /bin/bash
 | 
				
			||||||
 | 
					# Function: 根据输入的程序的名字过滤出所对应的PID,并显示出详细信息,如果有几个PID,则全部显示
 | 
				
			||||||
 | 
					NAME=%s
 | 
				
			||||||
 | 
					N=`ps -aux | grep $NAME | grep -v grep | wc -l`    ##统计进程总数
 | 
				
			||||||
 | 
					if [ $N -le 0 ];then
 | 
				
			||||||
 | 
					  echo "该进程名没有运行!"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					i=1
 | 
				
			||||||
 | 
					while [ $N -gt 0 ]
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
					  echo "进程PID: `ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $2}'`"
 | 
				
			||||||
 | 
					  echo "进程命令:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $11}'`"
 | 
				
			||||||
 | 
					  echo "进程所属用户: `ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $1}'`"
 | 
				
			||||||
 | 
					  echo "CPU占用率:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $3}'`%"
 | 
				
			||||||
 | 
					  echo "内存占用率:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $4}'`%"
 | 
				
			||||||
 | 
					  echo "进程开始运行的时刻:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $9}'`"
 | 
				
			||||||
 | 
					  echo "进程运行的时间:`  ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $11}'`"
 | 
				
			||||||
 | 
					  echo "进程状态:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $8}'`"
 | 
				
			||||||
 | 
					  echo "进程虚拟内存:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $5}'`"
 | 
				
			||||||
 | 
					  echo "进程共享内存:`ps -aux | grep $NAME | grep -v grep | awk 'NR=='$i'{print $0}'| awk '{print $6}'`"
 | 
				
			||||||
 | 
					  echo "***************************************************************"
 | 
				
			||||||
 | 
					  let N-- i++
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
							
								
								
									
										13
									
								
								mock-server/machine/shell/monitor.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								mock-server/machine/shell/monitor.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取监控信息
 | 
				
			||||||
 | 
					function get_monitor_info() {
 | 
				
			||||||
 | 
					  cpu_rate=$(cat /proc/stat | awk '/cpu/{printf("%.2f%\n"), ($2+$4)*100/($2+$4+$5)}' | awk '{print $0}' | head -1)
 | 
				
			||||||
 | 
					  mem_rate=$(free -m | sed -n '2p' | awk '{print""($3/$2)*100"%"}')
 | 
				
			||||||
 | 
					  sys_load=$(uptime | cut -d: -f5)
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					cpuRate:${cpu_rate},memRate:${mem_rate},sysLoad:${sys_load}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					get_monitor_info
 | 
				
			||||||
							
								
								
									
										192
									
								
								mock-server/machine/shell/sys_info.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								mock-server/machine/shell/sys_info.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
				
			|||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					# func:sys info check
 | 
				
			||||||
 | 
					[ $(id -u) -ne 0 ] && echo "请用root用户执行此脚本!" && exit 1
 | 
				
			||||||
 | 
					sysversion=$(rpm -q centos-release | cut -d- -f3)
 | 
				
			||||||
 | 
					line="-------------------------------------------------"
 | 
				
			||||||
 | 
					# 获取系统cpu信息
 | 
				
			||||||
 | 
					function get_cpu_info() {
 | 
				
			||||||
 | 
					  Physical_CPUs=$(grep "physical id" /proc/cpuinfo | sort | uniq | wc -l)
 | 
				
			||||||
 | 
					  Virt_CPUs=$(grep "processor" /proc/cpuinfo | wc -l)
 | 
				
			||||||
 | 
					  CPU_Kernels=$(grep "cores" /proc/cpuinfo | uniq | awk -F ': ' '{print $2}')
 | 
				
			||||||
 | 
					  CPU_Type=$(grep "model name" /proc/cpuinfo | awk -F ': ' '{print $2}' | sort | uniq)
 | 
				
			||||||
 | 
					  CPU_Arch=$(uname -m)
 | 
				
			||||||
 | 
					  cpu_usage=$(cat /proc/stat | awk '/cpu/{printf("%.2f%\n"), ($2+$4)*100/($2+$4+$5)}' | awk '{print $0}' | head -1)
 | 
				
			||||||
 | 
					  #echo -e '\033[32m CPU信息:\033[0m'
 | 
				
			||||||
 | 
					  echo -e ' CPU信息:'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					物理CPU个数: $Physical_CPUs
 | 
				
			||||||
 | 
					逻辑CPU个数: $Virt_CPUs
 | 
				
			||||||
 | 
					每CPU核心数: $CPU_Kernels
 | 
				
			||||||
 | 
					CPU型号: $CPU_Type
 | 
				
			||||||
 | 
					CPU架构: $CPU_Arch
 | 
				
			||||||
 | 
					CPU使用率: $cpu_usage
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取系统内存信息
 | 
				
			||||||
 | 
					function get_mem_info() {
 | 
				
			||||||
 | 
					  Total=$(free -m | sed -n '2p' | awk '{print $2"M"}')
 | 
				
			||||||
 | 
					  Used=$(free -m | sed -n '2p' | awk '{print $3"M"}')
 | 
				
			||||||
 | 
					  Rate=$(free -m | sed -n '2p' | awk '{print""($3/$2)*100"%"}')
 | 
				
			||||||
 | 
					  echo -e ' 内存信息:'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					内存总容量:$Total
 | 
				
			||||||
 | 
					内存已使用:$Used
 | 
				
			||||||
 | 
					内存使用率:$Rate
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取系统网络信息
 | 
				
			||||||
 | 
					function get_net_info() {
 | 
				
			||||||
 | 
					  pri_ipadd=$(ifconfig | awk 'NR==2{print $2}')
 | 
				
			||||||
 | 
					  #pub_ipadd=$(curl ip.sb 2>&1)
 | 
				
			||||||
 | 
					  pub_ipadd=$(curl -s http://ddns.oray.com/checkip | awk -F ":" '{print $2}' | awk -F "<" '{print $1}' | awk '{print $1}')
 | 
				
			||||||
 | 
					  gateway=$(ip route | grep default | awk '{print $3}')
 | 
				
			||||||
 | 
					  mac_info=$(ip link | egrep -v "lo" | grep link | awk '{print $2}')
 | 
				
			||||||
 | 
					  dns_config=$(egrep 'nameserver' /etc/resolv.conf)
 | 
				
			||||||
 | 
					  route_info=$(route -n)
 | 
				
			||||||
 | 
					  echo -e ' IP信息:'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					系统公网地址: ${pub_ipadd}
 | 
				
			||||||
 | 
					系统私网地址: ${pri_ipadd}
 | 
				
			||||||
 | 
					网关地址: ${gateway}
 | 
				
			||||||
 | 
					MAC地址: ${mac_info}
 | 
				
			||||||
 | 
					路由信息:
 | 
				
			||||||
 | 
					${route_info}
 | 
				
			||||||
 | 
					DNS 信息:
 | 
				
			||||||
 | 
					${dns_config}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取系统磁盘信息
 | 
				
			||||||
 | 
					function get_disk_info() {
 | 
				
			||||||
 | 
					  disk_info=$(fdisk -l | grep "Disk /dev" | cut -d, -f1)
 | 
				
			||||||
 | 
					  disk_use=$(df -hTP | awk '$2!="tmpfs"{print}')
 | 
				
			||||||
 | 
					  disk_inode=$(df -hiP | awk '$1!="tmpfs"{print}')
 | 
				
			||||||
 | 
					  echo -e ' 磁盘信息:'
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					${disk_info}
 | 
				
			||||||
 | 
					磁盘使用:
 | 
				
			||||||
 | 
					${disk_use}
 | 
				
			||||||
 | 
					inode信息:
 | 
				
			||||||
 | 
					${disk_inode}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取系统信息
 | 
				
			||||||
 | 
					function get_systatus_info() {
 | 
				
			||||||
 | 
					  sys_os=$(uname -o)
 | 
				
			||||||
 | 
					  sys_release=$(cat /etc/redhat-release)
 | 
				
			||||||
 | 
					  sys_kernel=$(uname -r)
 | 
				
			||||||
 | 
					  sys_hostname=$(hostname)
 | 
				
			||||||
 | 
					  sys_selinux=$(getenforce)
 | 
				
			||||||
 | 
					  sys_lang=$(echo $LANG)
 | 
				
			||||||
 | 
					  sys_lastreboot=$(who -b | awk '{print $3,$4}')
 | 
				
			||||||
 | 
					  sys_runtime=$(uptime | awk '{print  $3,$4}' | cut -d, -f1)
 | 
				
			||||||
 | 
					  sys_time=$(date)
 | 
				
			||||||
 | 
					  sys_load=$(uptime | cut -d: -f5)
 | 
				
			||||||
 | 
					  echo -e ' 系统信息:'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					系统: ${sys_os}
 | 
				
			||||||
 | 
					发行版本:   ${sys_release}
 | 
				
			||||||
 | 
					系统内核:   ${sys_kernel}
 | 
				
			||||||
 | 
					主机名:    ${sys_hostname}
 | 
				
			||||||
 | 
					selinux状态:  ${sys_selinux}
 | 
				
			||||||
 | 
					系统语言:   ${sys_lang}
 | 
				
			||||||
 | 
					系统当前时间: ${sys_time}
 | 
				
			||||||
 | 
					系统最后重启时间:   ${sys_lastreboot}
 | 
				
			||||||
 | 
					系统运行时间: ${sys_runtime}
 | 
				
			||||||
 | 
					系统负载:   ${sys_load}
 | 
				
			||||||
 | 
					---------------------------------------
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取服务信息
 | 
				
			||||||
 | 
					function get_service_info() {
 | 
				
			||||||
 | 
					  port_listen=$(netstat -lntup | grep -v "Active Internet")
 | 
				
			||||||
 | 
					  kernel_config=$(sysctl -p 2>/dev/null)
 | 
				
			||||||
 | 
					  if [ ${sysversion} -gt 6 ]; then
 | 
				
			||||||
 | 
					    service_config=$(systemctl list-unit-files --type=service --state=enabled | grep "enabled")
 | 
				
			||||||
 | 
					    run_service=$(systemctl list-units --type=service --state=running | grep ".service")
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    service_config=$(/sbin/chkconfig | grep -E ":on|:启用" | column -t)
 | 
				
			||||||
 | 
					    run_service=$(/sbin/service --status-all | grep -E "running")
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  echo -e ' 服务启动配置:'
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					${service_config}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					运行的服务:
 | 
				
			||||||
 | 
					${run_service}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					监听端口:
 | 
				
			||||||
 | 
					${port_listen}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					内核参考配置:
 | 
				
			||||||
 | 
					${kernel_config}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function get_sys_user() {
 | 
				
			||||||
 | 
					  login_user=$(awk -F: '{if ($NF=="/bin/bash") print $0}' /etc/passwd)
 | 
				
			||||||
 | 
					  ssh_config=$(egrep -v "^#|^$" /etc/ssh/sshd_config)
 | 
				
			||||||
 | 
					  sudo_config=$(egrep -v "^#|^$" /etc/sudoers | grep -v "^Defaults")
 | 
				
			||||||
 | 
					  host_config=$(egrep -v "^#|^$" /etc/hosts)
 | 
				
			||||||
 | 
					  crond_config=$(for cronuser in /var/spool/cron/*; do
 | 
				
			||||||
 | 
					    ls ${cronuser} 2>/dev/null | cut -d/ -f5
 | 
				
			||||||
 | 
					    egrep -v "^$|^#" ${cronuser} 2>/dev/null
 | 
				
			||||||
 | 
					    echo ""
 | 
				
			||||||
 | 
					  done)
 | 
				
			||||||
 | 
					  echo -e ' 系统登录用户:'
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					${login_user}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					ssh 配置信息:
 | 
				
			||||||
 | 
					${ssh_config}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					sudo 配置用户:
 | 
				
			||||||
 | 
					${sudo_config}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					定时任务配置:
 | 
				
			||||||
 | 
					${crond_config}
 | 
				
			||||||
 | 
					${line}
 | 
				
			||||||
 | 
					hosts 信息:
 | 
				
			||||||
 | 
					${host_config}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function process_top_info() {
 | 
				
			||||||
 | 
					  top_title=$(top -b n1 | head -7 | tail -1)
 | 
				
			||||||
 | 
					  cpu_top10=$(top b -n1 | head -17 | tail -10)
 | 
				
			||||||
 | 
					  mem_top10=$(top -b n1 | head -17 | tail -10 | sort -k10 -r)
 | 
				
			||||||
 | 
					  echo -e ' CPU占用top10:'
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					${top_title}
 | 
				
			||||||
 | 
					${cpu_top10}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					  echo -e ' 内存占用top10:'
 | 
				
			||||||
 | 
					  cat <<EOF
 | 
				
			||||||
 | 
					${top_title}
 | 
				
			||||||
 | 
					${mem_top10}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function sys_check() {
 | 
				
			||||||
 | 
					  get_systatus_info
 | 
				
			||||||
 | 
					  echo ${line}
 | 
				
			||||||
 | 
					  get_cpu_info
 | 
				
			||||||
 | 
					  echo ${line}
 | 
				
			||||||
 | 
					  get_mem_info
 | 
				
			||||||
 | 
					  echo ${line}
 | 
				
			||||||
 | 
					  #    get_net_info
 | 
				
			||||||
 | 
					  #    echo ${line}
 | 
				
			||||||
 | 
					  get_disk_info
 | 
				
			||||||
 | 
					  echo ${line}
 | 
				
			||||||
 | 
					      get_service_info
 | 
				
			||||||
 | 
					      echo ${line}
 | 
				
			||||||
 | 
					#  get_sys_user
 | 
				
			||||||
 | 
					#  echo ${line}
 | 
				
			||||||
 | 
					  process_top_info
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sys_check
 | 
				
			||||||
							
								
								
									
										41
									
								
								mock-server/machine/shell/system_info.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								mock-server/machine/shell/system_info.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					# 获取系统cpu信息
 | 
				
			||||||
 | 
					function get_cpu_info() {
 | 
				
			||||||
 | 
					  Physical_CPUs=$(grep "physical id" /proc/cpuinfo | sort | uniq | wc -l)
 | 
				
			||||||
 | 
					  Virt_CPUs=$(grep "processor" /proc/cpuinfo | wc -l)
 | 
				
			||||||
 | 
					  CPU_Kernels=$(grep "cores" /proc/cpuinfo | uniq | awk -F ': ' '{print $2}')
 | 
				
			||||||
 | 
					  CPU_Type=$(grep "model name" /proc/cpuinfo | awk -F ': ' '{print $2}' | sort | uniq)
 | 
				
			||||||
 | 
					  CPU_Arch=$(uname -m)
 | 
				
			||||||
 | 
					  echo -e '\n-------------------------- CPU信息 --------------------------'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					物理CPU个数: $Physical_CPUs
 | 
				
			||||||
 | 
					逻辑CPU个数: $Virt_CPUs
 | 
				
			||||||
 | 
					每CPU核心数: $CPU_Kernels
 | 
				
			||||||
 | 
					CPU型号: $CPU_Type
 | 
				
			||||||
 | 
					CPU架构: $CPU_Arch
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 获取系统信息
 | 
				
			||||||
 | 
					function get_systatus_info() {
 | 
				
			||||||
 | 
					  sys_os=$(uname -o)
 | 
				
			||||||
 | 
					  sys_release=$(cat /etc/redhat-release)
 | 
				
			||||||
 | 
					  sys_kernel=$(uname -r)
 | 
				
			||||||
 | 
					  sys_hostname=$(hostname)
 | 
				
			||||||
 | 
					  sys_selinux=$(getenforce)
 | 
				
			||||||
 | 
					  sys_lang=$(echo $LANG)
 | 
				
			||||||
 | 
					  sys_lastreboot=$(who -b | awk '{print $3,$4}')
 | 
				
			||||||
 | 
					  echo -e '-------------------------- 系统信息 --------------------------'
 | 
				
			||||||
 | 
					  cat <<EOF | column -t
 | 
				
			||||||
 | 
					系统: ${sys_os}
 | 
				
			||||||
 | 
					发行版本:   ${sys_release}
 | 
				
			||||||
 | 
					系统内核:   ${sys_kernel}
 | 
				
			||||||
 | 
					主机名:    ${sys_hostname}
 | 
				
			||||||
 | 
					selinux状态:  ${sys_selinux}
 | 
				
			||||||
 | 
					系统语言:   ${sys_lang}
 | 
				
			||||||
 | 
					系统最后重启时间:   ${sys_lastreboot}
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					get_systatus_info
 | 
				
			||||||
 | 
					#echo -e "\n"
 | 
				
			||||||
 | 
					get_cpu_info
 | 
				
			||||||
							
								
								
									
										105
									
								
								mock-server/machine/status.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								mock-server/machine/status.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					package machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SystemVersion struct {
 | 
				
			||||||
 | 
						Version string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Cli) GetSystemVersion() *SystemVersion {
 | 
				
			||||||
 | 
						res, _ := c.Run("cat /etc/redhat-release")
 | 
				
			||||||
 | 
						return &SystemVersion{
 | 
				
			||||||
 | 
							Version: *res,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//top - 17:14:07 up 5 days,  6:30,  2 users,  load average: 0.03, 0.04, 0.05
 | 
				
			||||||
 | 
					//Tasks: 101 total,   1 running, 100 sleeping,   0 stopped,   0 zombie
 | 
				
			||||||
 | 
					//%Cpu(s):  6.2 us,  0.0 sy,  0.0 ni, 93.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
 | 
				
			||||||
 | 
					//KiB Mem :  1882012 total,    73892 free,   770360 used,  1037760 buff/cache
 | 
				
			||||||
 | 
					//KiB Swap:        0 total,        0 free,        0 used.   933492 avail Mem
 | 
				
			||||||
 | 
					type Top struct {
 | 
				
			||||||
 | 
						Time string `json:"time"`
 | 
				
			||||||
 | 
						// 从本次开机到现在经过的时间
 | 
				
			||||||
 | 
						Up string `json:"up"`
 | 
				
			||||||
 | 
						// 当前有几个用户登录到该机器
 | 
				
			||||||
 | 
						NowUsers int `json:"nowUsers"`
 | 
				
			||||||
 | 
						// load average: 0.03, 0.04, 0.05 (系统1分钟、5分钟、15分钟内的平均负载值)
 | 
				
			||||||
 | 
						OneMinLoadavg     float32 `json:"oneMinLoadavg"`
 | 
				
			||||||
 | 
						FiveMinLoadavg    float32 `json:"fiveMinLoadavg"`
 | 
				
			||||||
 | 
						FifteenMinLoadavg float32 `json:"fifteenMinLoadavg"`
 | 
				
			||||||
 | 
						// 进程总数
 | 
				
			||||||
 | 
						TotalTask int `json:"totalTask"`
 | 
				
			||||||
 | 
						// 正在运行的进程数,对应状态TASK_RUNNING
 | 
				
			||||||
 | 
						RunningTask  int `json:"runningTask"`
 | 
				
			||||||
 | 
						SleepingTask int `json:"sleepingTask"`
 | 
				
			||||||
 | 
						StoppedTask  int `json:"stoppedTask"`
 | 
				
			||||||
 | 
						ZombieTask   int `json:"zombieTask"`
 | 
				
			||||||
 | 
						// 进程在用户空间(user)消耗的CPU时间占比,不包含调整过优先级的进程
 | 
				
			||||||
 | 
						CpuUs float32 `json:"cpuUs"`
 | 
				
			||||||
 | 
						// 进程在内核空间(system)消耗的CPU时间占比
 | 
				
			||||||
 | 
						CpuSy float32 `json:"cpuSy"`
 | 
				
			||||||
 | 
						// 调整过用户态优先级的(niced)进程的CPU时间占比
 | 
				
			||||||
 | 
						CpuNi float32 `json:"cpuNi"`
 | 
				
			||||||
 | 
						// 空闲的(idle)CPU时间占比
 | 
				
			||||||
 | 
						CpuId float32 `json:"cpuId"`
 | 
				
			||||||
 | 
						// 等待(wait)I/O完成的CPU时间占比
 | 
				
			||||||
 | 
						CpuWa float32 `json:"cpuWa"`
 | 
				
			||||||
 | 
						// 处理硬中断(hardware interrupt)的CPU时间占比
 | 
				
			||||||
 | 
						CpuHi float32 `json:"cpuHi"`
 | 
				
			||||||
 | 
						// 处理硬中断(hardware interrupt)的CPU时间占比
 | 
				
			||||||
 | 
						CpuSi float32 `json:"cpuSi"`
 | 
				
			||||||
 | 
						// 当Linux系统是在虚拟机中运行时,等待CPU资源的时间(steal time)占比
 | 
				
			||||||
 | 
						CpuSt float32 `json:"cpuSt"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TotalMem int `json:"totalMem"`
 | 
				
			||||||
 | 
						FreeMem  int `json:"freeMem"`
 | 
				
			||||||
 | 
						UsedMem  int `json:"usedMem"`
 | 
				
			||||||
 | 
						CacheMem int `json:"cacheMem"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TotalSwap int `json:"totalSwap"`
 | 
				
			||||||
 | 
						FreeSwap  int `json:"freeSwap"`
 | 
				
			||||||
 | 
						UsedSwap  int `json:"usedSwap"`
 | 
				
			||||||
 | 
						AvailMem  int `json:"availMem"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Cli) GetTop() *Top {
 | 
				
			||||||
 | 
						res, _ := c.Run("top -b -n 1 | head -5")
 | 
				
			||||||
 | 
						topTemp := "top - {upAndUsers},  load average: {loadavg}\n" +
 | 
				
			||||||
 | 
							"Tasks:{totalTask} total,{runningTask} running,{sleepingTask} sleeping,{stoppedTask} stopped,{zombieTask} zombie\n" +
 | 
				
			||||||
 | 
							"%Cpu(s):{cpuUs} us,{cpuSy} sy,{cpuNi} ni,{cpuId} id,{cpuWa} wa,{cpuHi} hi,{cpuSi} si,{cpuSt} st\n" +
 | 
				
			||||||
 | 
							"KiB Mem :{totalMem} total,{freeMem} free,{usedMem} used,{cacheMem} buff/cache\n" +
 | 
				
			||||||
 | 
							"KiB Swap:{totalSwap} total,{freeSwap} free,{usedSwap} used. {availMem} avail Mem \n"
 | 
				
			||||||
 | 
						resMap := make(map[string]interface{})
 | 
				
			||||||
 | 
						utils.ReverStrTemplate(topTemp, *res, resMap)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//17:14:07 up 5 days,  6:30,  2
 | 
				
			||||||
 | 
						timeUpAndUserStr := resMap["upAndUsers"].(string)
 | 
				
			||||||
 | 
						timeUpAndUser := strings.Split(timeUpAndUserStr, "up")
 | 
				
			||||||
 | 
						time := utils.StrTrim(timeUpAndUser[0])
 | 
				
			||||||
 | 
						upAndUsers := strings.Split(timeUpAndUser[1], ",")
 | 
				
			||||||
 | 
						up := utils.StrTrim(upAndUsers[0]) + upAndUsers[1]
 | 
				
			||||||
 | 
						users, _ := strconv.Atoi(utils.StrTrim(strings.Split(utils.StrTrim(upAndUsers[2]), " ")[0]))
 | 
				
			||||||
 | 
						// 0.03, 0.04, 0.05
 | 
				
			||||||
 | 
						loadavgs := strings.Split(resMap["loadavg"].(string), ",")
 | 
				
			||||||
 | 
						oneMinLa, _ := strconv.ParseFloat(loadavgs[0], 32)
 | 
				
			||||||
 | 
						fiveMinLa, _ := strconv.ParseFloat(utils.StrTrim(loadavgs[1]), 32)
 | 
				
			||||||
 | 
						fifMinLa, _ := strconv.ParseFloat(utils.StrTrim(loadavgs[2]), 32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						top := &Top{Time: time, Up: up, NowUsers: users, OneMinLoadavg: float32(oneMinLa), FiveMinLoadavg: float32(fiveMinLa), FifteenMinLoadavg: float32(fifMinLa)}
 | 
				
			||||||
 | 
						err := utils.Map2Struct(resMap, top)
 | 
				
			||||||
 | 
						biz.BizErrIsNil(err, "解析top出错")
 | 
				
			||||||
 | 
						return top
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Status struct {
 | 
				
			||||||
 | 
						// 系统版本
 | 
				
			||||||
 | 
						SysVersion SystemVersion
 | 
				
			||||||
 | 
						// top信息
 | 
				
			||||||
 | 
						Top Top
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -199,7 +199,6 @@ func (sws *LogicSshWsSession) sendComboOutput(exitCh chan bool) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (sws *LogicSshWsSession) Wait(quitChan chan bool) {
 | 
					func (sws *LogicSshWsSession) Wait(quitChan chan bool) {
 | 
				
			||||||
	if err := sws.session.Wait(); err != nil {
 | 
						if err := sws.session.Wait(); err != nil {
 | 
				
			||||||
		logs.Error("ssh session wait failed: ", err)
 | 
					 | 
				
			||||||
		setQuit(quitChan)
 | 
							setQuit(quitChan)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										95
									
								
								mock-server/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								mock-server/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"flag"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"mayfly-go/base/rediscli"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils/yml"
 | 
				
			||||||
 | 
						_ "mayfly-go/mock-server/routers"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/beego/beego/v2/server/web"
 | 
				
			||||||
 | 
						"github.com/beego/beego/v2/server/web/context"
 | 
				
			||||||
 | 
						"github.com/beego/beego/v2/server/web/filter/cors"
 | 
				
			||||||
 | 
						"github.com/go-redis/redis"
 | 
				
			||||||
 | 
						// _ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 启动配置参数
 | 
				
			||||||
 | 
					type StartConfigParam struct {
 | 
				
			||||||
 | 
						ConfigFilePath string // 配置文件路径
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// yaml配置文件映射对象
 | 
				
			||||||
 | 
					type Config struct {
 | 
				
			||||||
 | 
						Server struct {
 | 
				
			||||||
 | 
							Port int `yaml:"port"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Redis struct {
 | 
				
			||||||
 | 
							Host     string `yaml:"host"`
 | 
				
			||||||
 | 
							Port     int    `yaml:"port"`
 | 
				
			||||||
 | 
							Password string `yaml:"password"`
 | 
				
			||||||
 | 
							Db       int    `yaml:"db"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 启动可执行文件时的参数
 | 
				
			||||||
 | 
					var startConfigParam *StartConfigParam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 配置文件映射对象
 | 
				
			||||||
 | 
					var ymlConfig Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 获取执行可执行文件时,指定的启动参数
 | 
				
			||||||
 | 
					func getStartConfig() *StartConfigParam {
 | 
				
			||||||
 | 
						configFilePath := flag.String("e", "./config.yml", "配置文件路径,默认为可执行文件目录")
 | 
				
			||||||
 | 
						flag.Parse()
 | 
				
			||||||
 | 
						// 获取配置文件绝对路径
 | 
				
			||||||
 | 
						path, _ := filepath.Abs(*configFilePath)
 | 
				
			||||||
 | 
						sc := &StartConfigParam{ConfigFilePath: path}
 | 
				
			||||||
 | 
						return sc
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						configFilePath := flag.String("e", "./config.yml", "配置文件路径,默认为可执行文件目录")
 | 
				
			||||||
 | 
						flag.Parse()
 | 
				
			||||||
 | 
						// 获取启动参数中,配置文件的绝对路径
 | 
				
			||||||
 | 
						path, _ := filepath.Abs(*configFilePath)
 | 
				
			||||||
 | 
						startConfigParam = &StartConfigParam{ConfigFilePath: path}
 | 
				
			||||||
 | 
						// 读取配置文件信息
 | 
				
			||||||
 | 
						yc := &Config{}
 | 
				
			||||||
 | 
						if err := yml.LoadYml(startConfigParam.ConfigFilePath, yc); err != nil {
 | 
				
			||||||
 | 
							panic(fmt.Sprintf("读取配置文件[%s]失败: %s", startConfigParam.ConfigFilePath, err.Error()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ymlConfig = *yc
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						// 设置redis客户端
 | 
				
			||||||
 | 
						rdb := redis.NewClient(&redis.Options{
 | 
				
			||||||
 | 
							Addr:     fmt.Sprintf("%s:%d", ymlConfig.Redis.Host, ymlConfig.Redis.Port),
 | 
				
			||||||
 | 
							Password: ymlConfig.Redis.Password, // no password set
 | 
				
			||||||
 | 
							DB:       ymlConfig.Redis.Db,       // use default DB
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						rediscli.SetCli(rdb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						web.InsertFilter("/*", web.BeforeRouter, TransparentStatic)
 | 
				
			||||||
 | 
						// 跨域配置
 | 
				
			||||||
 | 
						web.InsertFilter("/**", web.BeforeRouter, cors.Allow(&cors.Options{
 | 
				
			||||||
 | 
							AllowAllOrigins:  true,
 | 
				
			||||||
 | 
							AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
 | 
				
			||||||
 | 
							AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
 | 
				
			||||||
 | 
							ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
 | 
				
			||||||
 | 
							AllowCredentials: true,
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						web.Run()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 解决beego无法访问根目录静态文件
 | 
				
			||||||
 | 
					func TransparentStatic(ctx *context.Context) {
 | 
				
			||||||
 | 
						if strings.Index(ctx.Request.URL.Path, "api/") >= 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						http.ServeFile(ctx.ResponseWriter, ctx.Request, "static/"+ctx.Request.URL.Path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								mock-server/mock-server
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mock-server/mock-server
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										37
									
								
								mock-server/models/machine.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								mock-server/models/machine.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"mayfly-go/base/biz"
 | 
				
			||||||
 | 
						"mayfly-go/base/rediscli"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const machineKey = "ccbscf:machines"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Machine struct {
 | 
				
			||||||
 | 
						Name     string `json:"name"`
 | 
				
			||||||
 | 
						Ip       string `json:"ip"`       // IP地址
 | 
				
			||||||
 | 
						Username string `json:"username"` // 用户名
 | 
				
			||||||
 | 
						Password string `json:"-"`
 | 
				
			||||||
 | 
						Port     int    `json:"port"` // 端口号
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Machine) CreateMachine() {
 | 
				
			||||||
 | 
						biz.IsTrue(!rediscli.HExist(machineKey, c.Ip), "该机器已存在")
 | 
				
			||||||
 | 
						val, _ := json.Marshal(c)
 | 
				
			||||||
 | 
						rediscli.HSet(machineKey, c.Ip, val)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DeleteMachine(ip string) {
 | 
				
			||||||
 | 
						rediscli.HDel(machineKey, ip)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetMachineByIp(ip string) *Machine {
 | 
				
			||||||
 | 
						machine := &Machine{}
 | 
				
			||||||
 | 
						json.Unmarshal([]byte(rediscli.HGet(machineKey, ip)), machine)
 | 
				
			||||||
 | 
						return machine
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetMachineList() map[string]string {
 | 
				
			||||||
 | 
						return rediscli.HGetAll(machineKey)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								mock-server/routers/commentsRouter_controllers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								mock-server/routers/commentsRouter_controllers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					package routers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						beego "github.com/beego/beego/v2/server/web"
 | 
				
			||||||
 | 
						"github.com/beego/beego/v2/server/web/context/param"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"] = append(beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"],
 | 
				
			||||||
 | 
					        beego.ControllerComments{
 | 
				
			||||||
 | 
					            Method: "UpdateMockData",
 | 
				
			||||||
 | 
					            Router: "/api/mock-datas",
 | 
				
			||||||
 | 
					            AllowHTTPMethods: []string{"put"},
 | 
				
			||||||
 | 
					            MethodParams: param.Make(),
 | 
				
			||||||
 | 
					            Filters: nil,
 | 
				
			||||||
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"] = append(beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"],
 | 
				
			||||||
 | 
					        beego.ControllerComments{
 | 
				
			||||||
 | 
					            Method: "CreateMockData",
 | 
				
			||||||
 | 
					            Router: "/api/mock-datas",
 | 
				
			||||||
 | 
					            AllowHTTPMethods: []string{"post"},
 | 
				
			||||||
 | 
					            MethodParams: param.Make(),
 | 
				
			||||||
 | 
					            Filters: nil,
 | 
				
			||||||
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"] = append(beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"],
 | 
				
			||||||
 | 
					        beego.ControllerComments{
 | 
				
			||||||
 | 
					            Method: "GetAllData",
 | 
				
			||||||
 | 
					            Router: "/api/mock-datas",
 | 
				
			||||||
 | 
					            AllowHTTPMethods: []string{"get"},
 | 
				
			||||||
 | 
					            MethodParams: param.Make(),
 | 
				
			||||||
 | 
					            Filters: nil,
 | 
				
			||||||
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"] = append(beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"],
 | 
				
			||||||
 | 
					        beego.ControllerComments{
 | 
				
			||||||
 | 
					            Method: "GetMockData",
 | 
				
			||||||
 | 
					            Router: "/api/mock-datas/:method",
 | 
				
			||||||
 | 
					            AllowHTTPMethods: []string{"get"},
 | 
				
			||||||
 | 
					            MethodParams: param.Make(),
 | 
				
			||||||
 | 
					            Filters: nil,
 | 
				
			||||||
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"] = append(beego.GlobalControllerRouter["mayfly-go/mock-server/controllers:MockController"],
 | 
				
			||||||
 | 
					        beego.ControllerComments{
 | 
				
			||||||
 | 
					            Method: "DeleteMockData",
 | 
				
			||||||
 | 
					            Router: "/api/mock-datas/:method",
 | 
				
			||||||
 | 
					            AllowHTTPMethods: []string{"delete"},
 | 
				
			||||||
 | 
					            MethodParams: param.Make(),
 | 
				
			||||||
 | 
					            Filters: nil,
 | 
				
			||||||
 | 
					            Params: nil})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								mock-server/routers/router.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								mock-server/routers/router.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package routers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/mock-server/controllers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/beego/beego/v2/server/web"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						web.Include(&controllers.MockController{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mock := &controllers.MockController{}
 | 
				
			||||||
 | 
						web.Router("/api/mock-datas", mock, "post:CreateMockData")
 | 
				
			||||||
 | 
						web.Router("/api/mock-datas/?:method", mock, "get:GetMockData")
 | 
				
			||||||
 | 
						web.Router("/api/mock-datas", mock, "put:UpdateMockData")
 | 
				
			||||||
 | 
						web.Router("/api/mock-datas/?:method", mock, "delete:DeleteMockData")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								mock-server/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mock-server/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										1
									
								
								mock-server/static/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mock-server/static/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>mayfly-go-front</title><link href="/static/css/chunk-09c3f704.f03c28a3.css" rel="prefetch"><link href="/static/css/chunk-589cf4a2.676f6792.css" rel="prefetch"><link href="/static/css/chunk-76193938.2d81c5bb.css" rel="prefetch"><link href="/static/css/chunk-7f8e443f.53f73f21.css" rel="prefetch"><link href="/static/css/chunk-e3082940.1463bb24.css" rel="prefetch"><link href="/static/js/chunk-09c3f704.a1d504c3.js" rel="prefetch"><link href="/static/js/chunk-589cf4a2.b6d10755.js" rel="prefetch"><link href="/static/js/chunk-6e9f0a70.cf14b007.js" rel="prefetch"><link href="/static/js/chunk-76193938.f9c11d74.js" rel="prefetch"><link href="/static/js/chunk-7f8e443f.2c011f90.js" rel="prefetch"><link href="/static/js/chunk-e3082940.ee363d97.js" rel="prefetch"><link href="/static/css/app.b4088619.css" rel="preload" as="style"><link href="/static/css/chunk-vendors.16da611a.css" rel="preload" as="style"><link href="/static/js/app.3ffb27d0.js" rel="preload" as="script"><link href="/static/js/chunk-vendors.bf6005f5.js" rel="preload" as="script"><link href="/static/css/chunk-vendors.16da611a.css" rel="stylesheet"><link href="/static/css/app.b4088619.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but mayfly-go-front doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/chunk-vendors.bf6005f5.js"></script><script src="/static/js/app.3ffb27d0.js"></script></body></html>
 | 
				
			||||||
							
								
								
									
										1
									
								
								mock-server/static/static/css/app.b4088619.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mock-server/static/static/css/app.b4088619.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					#app{background-color:#222d32}.main{display:flex}.main .el-menu:not(.el-menu--collapse){width:230px}.main .app{width:100%;background-color:#ecf0f5}.main .aside{position:fixed;margin-top:50px;z-index:10;background-color:#222d32;transition:all .3s ease-in-out}.main .aside .menu{overflow-y:auto;height:100vh}.main .app-body{margin-left:230px;transition:margin-left .3s ease-in-out}.main .main-container{margin-top:88px;padding:2px;min-height:calc(100vh - 88px)}.header{width:100%;position:fixed;display:flex;z-index:10}.header,.header .logo{height:50px;background-color:#303643}.header .logo{width:230px;text-align:center;line-height:50px;color:#fff;transition:all .3s ease-in-out}.header .logo .min{display:none}.header .right{position:absolute;right:0}.header .header-btn{overflow:hidden;height:50px;display:inline-block;text-align:center;line-height:50px;cursor:pointer;padding:0 14px;color:#fff}.header .header-btn .el-badge__content{top:14px;right:7px;text-align:center;font-size:9px;padding:0 3px;background-color:#00a65a;color:#fff;border:none;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.header .header-btn:hover{background-color:#222d32}.menu{border-right:none;-moz-user-select:-moz-none;-moz-user-select:none;-o-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.el-menu--vertical{min-width:190px}.setting-category{padding:10px 0;border-bottom:1px solid #eee}#mainContainer iframe{border:none;outline:none;width:100%;height:100%;position:absolute;background-color:#ecf0f5}.el-menu-item,.el-submenu__title{font-weight:500}#nav-bar{margin-top:50px;height:38px;width:100%;z-index:8;background:#fff;box-shadow:0 1px 3px 0 rgba(0,0,0,.12),0 0 3px 0 rgba(0,0,0,.04);position:fixed;top:0}*{padding:0;margin:0;outline:none;box-sizing:border-box}body{font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,微软雅黑,Arial,sans-serif}a{color:#3c8dbc;text-decoration:none}::-webkit-scrollbar{width:4px;height:8px;background-color:#f5f5f5}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,.3);background-color:#f5f5f5}.el-menu .fa{vertical-align:middle;margin-right:5px;width:24px;text-align:center}.el-menu .fa:not(.is-children){font-size:14px}.gray-mode{filter:grayscale(100%)}.fade-enter-active,.fade-leave-active{transition:opacity .2s ease-in-out}.fade-enter,.fade-leave-to{opacity:0}.none-select{moz-user-select:-moz-none;-moz-user-select:none;-o-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.toolbar{width:100%;padding:8px;background-color:#fff;overflow:hidden;line-height:32px;border:1px solid #e6ebf5}.fl{float:left}
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					.cm-s-panda-syntax{background:#292a2b;color:#e6e6e6;line-height:1.5;font-family:Operator Mono,Source Code Pro,Menlo,Monaco,Consolas,Courier New,monospace}.cm-s-panda-syntax .CodeMirror-cursor{border-color:#ff2c6d}.cm-s-panda-syntax .CodeMirror-activeline-background{background:rgba(99,123,156,.1)}.cm-s-panda-syntax .CodeMirror-selected{background:#fff}.cm-s-panda-syntax .cm-comment{font-style:italic;color:#676b79}.cm-s-panda-syntax .cm-operator{color:#f3f3f3}.cm-s-panda-syntax .cm-string{color:#19f9d8}.cm-s-panda-syntax .cm-string-2{color:#ffb86c}.cm-s-panda-syntax .cm-tag{color:#ff2c6d}.cm-s-panda-syntax .cm-meta{color:#b084eb}.cm-s-panda-syntax .cm-number{color:#ffb86c}.cm-s-panda-syntax .cm-atom{color:#ff2c6d}.cm-s-panda-syntax .cm-keyword{color:#ff75b5}.cm-s-panda-syntax .cm-variable{color:#ffb86c}.cm-s-panda-syntax .cm-type,.cm-s-panda-syntax .cm-variable-2,.cm-s-panda-syntax .cm-variable-3{color:#ff9ac1}.cm-s-panda-syntax .cm-def{color:#e6e6e6}.cm-s-panda-syntax .cm-property{color:#f3f3f3}.cm-s-panda-syntax .cm-attribute,.cm-s-panda-syntax .cm-unit{color:#ffb86c}.cm-s-panda-syntax .CodeMirror-matchingbracket{border-bottom:1px dotted #19f9d8;padding-bottom:2px;color:#e6e6e6}.cm-s-panda-syntax .CodeMirror-gutters{background:#292a2b;border-right-color:hsla(0,0%,100%,.1)}.cm-s-panda-syntax .CodeMirror-linenumber{color:#e6e6e6;opacity:.6}.CodeMirror-lint-markers{width:16px}.CodeMirror-lint-tooltip{background-color:#ffd;border:1px solid #000;border-radius:4px 4px 4px 4px;color:#000;font-family:monospace;font-size:10pt;overflow:hidden;padding:2px 5px;position:fixed;white-space:pre;white-space:pre-wrap;z-index:100;max-width:600px;opacity:0;transition:opacity .4s;-moz-transition:opacity .4s;-webkit-transition:opacity .4s;-o-transition:opacity .4s;-ms-transition:opacity .4s}.CodeMirror-lint-mark{background-position:0 100%;background-repeat:repeat-x}.CodeMirror-lint-mark-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=")}.CodeMirror-lint-mark-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==")}.CodeMirror-lint-marker{background-position:50%;background-repeat:no-repeat;cursor:pointer;display:inline-block;height:16px;width:16px;vertical-align:middle;position:relative}.CodeMirror-lint-message{padding-left:18px;background-position:0 0;background-repeat:no-repeat}.CodeMirror-lint-marker-warning,.CodeMirror-lint-message-warning{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII=")}.CodeMirror-lint-marker-error,.CodeMirror-lint-message-error{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII=")}.CodeMirror-lint-marker-multiple{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC");background-repeat:no-repeat;background-position:100% 100%;width:100%;height:100%}#jsonedit .CodeMirror{overflow-y:scroll!important;height:400px!important}.el-dialog__body{padding:2px 2px}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user