mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	refactor: 机器计划任务与流程定义关联至标签
This commit is contained in:
		@@ -95,9 +95,9 @@ func (d *Db) ExecSql(rc *req.Ctx) {
 | 
			
		||||
	dbId := getDbId(rc)
 | 
			
		||||
	dbConn, err := d.DbApp.GetDbConn(dbId, form.Db)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.CodePath...), "%s")
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, dbConn.Info.TagPath[0])
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, dbConn.Info.CodePath[0])
 | 
			
		||||
 | 
			
		||||
	sqlBytes, err := base64.StdEncoding.DecodeString(form.Sql)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "sql解码失败: %s")
 | 
			
		||||
@@ -172,10 +172,8 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
 | 
			
		||||
	clientId := rc.Query("clientId")
 | 
			
		||||
 | 
			
		||||
	dbConn, err := d.DbApp.GetDbConn(dbId, dbName)
 | 
			
		||||
	// 开启流程审批时,执行文件暂时还未处理
 | 
			
		||||
	biz.IsTrue(dbConn.Info.FlowProcdefKey == "", "该库已开启流程审批,暂不支持该操作")
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(d.TagApp.CanAccess(rc.GetLoginAccount().Id, dbConn.Info.CodePath...), "%s")
 | 
			
		||||
	rc.ReqParam = fmt.Sprintf("filename: %s -> %s", filename, dbConn.Info.GetLogDesc())
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
@@ -243,7 +241,7 @@ func (d *Db) ExecSqlFile(rc *req.Ctx) {
 | 
			
		||||
			}
 | 
			
		||||
			dbConn, err = d.DbApp.GetDbConn(dbId, stmtUse.DBName.String())
 | 
			
		||||
			biz.ErrIsNil(err)
 | 
			
		||||
			biz.ErrIsNilAppendErr(d.TagApp.CanAccess(laId, dbConn.Info.TagPath...), "%s")
 | 
			
		||||
			biz.ErrIsNilAppendErr(d.TagApp.CanAccess(laId, dbConn.Info.CodePath...), "%s")
 | 
			
		||||
			execReq.DbConn = dbConn
 | 
			
		||||
		}
 | 
			
		||||
		// 需要记录执行记录
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ type DbBackup struct {
 | 
			
		||||
func (d *DbBackup) GetPageList(rc *req.Ctx) {
 | 
			
		||||
	dbId := uint64(rc.PathParamInt("dbId"))
 | 
			
		||||
	biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId, "db_instance_id", "database")
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
 | 
			
		||||
 | 
			
		||||
	queryCond, page := req.BindQueryAndPage[*entity.DbBackupQuery](rc, new(entity.DbBackupQuery))
 | 
			
		||||
@@ -49,7 +49,7 @@ func (d *DbBackup) Create(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	dbId := uint64(rc.PathParamInt("dbId"))
 | 
			
		||||
	biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId, "instanceId")
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
 | 
			
		||||
	jobs := make([]*entity.DbBackup, 0, len(dbNames))
 | 
			
		||||
	for _, dbName := range dbNames {
 | 
			
		||||
@@ -147,7 +147,7 @@ func (d *DbBackup) GetDbNamesWithoutBackup(rc *req.Ctx) {
 | 
			
		||||
func (d *DbBackup) GetHistoryPageList(rc *req.Ctx) {
 | 
			
		||||
	dbId := uint64(rc.PathParamInt("dbId"))
 | 
			
		||||
	biz.IsTrue(dbId > 0, "无效的 dbId: %v", dbId)
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId, "db_instance_id", "database")
 | 
			
		||||
	db, err := d.dbApp.GetById(dbId, "instance_id", "database")
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取数据库信息失败: %v")
 | 
			
		||||
 | 
			
		||||
	backupHistoryCond, page := req.BindQueryAndPage[*entity.DbBackupHistoryQuery](rc, new(entity.DbBackupHistoryQuery))
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,6 @@ type DbListVO struct {
 | 
			
		||||
	Host         string  `json:"host"`
 | 
			
		||||
	Port         int     `json:"port"`
 | 
			
		||||
 | 
			
		||||
	FlowProcdefKey string `json:"flowProcdefKey"`
 | 
			
		||||
 | 
			
		||||
	CreateTime *time.Time `json:"createTime"`
 | 
			
		||||
	Creator    *string    `json:"creator"`
 | 
			
		||||
	CreatorId  *int64     `json:"creatorId"`
 | 
			
		||||
 
 | 
			
		||||
@@ -186,13 +186,9 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		di.TagPath = d.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeDbName), db.Code)
 | 
			
		||||
		di.CodePath = d.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeDbName), db.Code)
 | 
			
		||||
		di.Id = db.Id
 | 
			
		||||
 | 
			
		||||
		if db.FlowProcdefKey != nil {
 | 
			
		||||
			di.FlowProcdefKey = *db.FlowProcdefKey
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		checkDb := di.GetDatabase()
 | 
			
		||||
		if !strings.Contains(" "+db.Database+" ", " "+checkDb+" ") {
 | 
			
		||||
			return nil, errorx.NewBiz("未配置数据库【%s】的操作权限", dbName)
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,7 @@ type dbSqlExecAppImpl struct {
 | 
			
		||||
	dbSqlExecRepo repository.DbSqlExec `inject:"DbSqlExecRepo"`
 | 
			
		||||
 | 
			
		||||
	flowProcinstApp flowapp.Procinst `inject:"ProcinstApp"`
 | 
			
		||||
	flowProcdefApp  flowapp.Procdef  `inject:"ProcdefApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createSqlExecRecord(ctx context.Context, execSqlReq *DbSqlExecReq) *entity.DbSqlExec {
 | 
			
		||||
@@ -348,11 +349,11 @@ func (d *dbSqlExecAppImpl) doInsert(ctx context.Context, insert *sqlparser.Inser
 | 
			
		||||
 | 
			
		||||
func (d *dbSqlExecAppImpl) doExec(ctx context.Context, execSqlReq *DbSqlExecReq, dbSqlExecRecord *entity.DbSqlExec) (*DbSqlExecRes, error) {
 | 
			
		||||
	dbConn := execSqlReq.DbConn
 | 
			
		||||
	flowProcdefKey := dbConn.Info.FlowProcdefKey
 | 
			
		||||
	if flowProcdefKey != "" {
 | 
			
		||||
 | 
			
		||||
	if flowProcdefId := d.flowProcdefApp.GetProcdefIdByCodePath(ctx, dbConn.Info.CodePath...); flowProcdefId != 0 {
 | 
			
		||||
		bizKey := stringx.Rand(24)
 | 
			
		||||
		// 如果该库关联了审批流程,则启动流程实例即可
 | 
			
		||||
		_, err := d.flowProcinstApp.StartProc(ctx, flowProcdefKey, &flowapp.StarProcParam{
 | 
			
		||||
		_, err := d.flowProcinstApp.StartProc(ctx, flowProcdefId, &flowapp.StarProcParam{
 | 
			
		||||
			BizType: DbSqlExecFlowBizType,
 | 
			
		||||
			BizKey:  bizKey,
 | 
			
		||||
			Remark:  dbSqlExecRecord.Remark,
 | 
			
		||||
 
 | 
			
		||||
@@ -47,8 +47,7 @@ type DbInfo struct {
 | 
			
		||||
	Params   string
 | 
			
		||||
	Database string // 若有schema的库则为'database/scheam'格式
 | 
			
		||||
 | 
			
		||||
	FlowProcdefKey     string // 流程定义key
 | 
			
		||||
	TagPath            []string
 | 
			
		||||
	CodePath           []string
 | 
			
		||||
	SshTunnelMachineId int
 | 
			
		||||
 | 
			
		||||
	Meta Meta
 | 
			
		||||
@@ -56,7 +55,7 @@ type DbInfo struct {
 | 
			
		||||
 | 
			
		||||
// 获取记录日志的描述
 | 
			
		||||
func (d *DbInfo) GetLogDesc() string {
 | 
			
		||||
	return fmt.Sprintf("DB[id=%d, tag=%s, name=%s, ip=%s:%d, database=%s]", d.Id, d.TagPath, d.Name, d.Host, d.Port, d.Database)
 | 
			
		||||
	return fmt.Sprintf("DB[id=%d, tag=%s, name=%s, ip=%s:%d, database=%s]", d.Id, d.CodePath, d.Name, d.Host, d.Port, d.Database)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 连接数据库
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,10 @@ import (
 | 
			
		||||
type Db struct {
 | 
			
		||||
	model.Model
 | 
			
		||||
 | 
			
		||||
	Code           string `orm:"column(code)" json:"code"`
 | 
			
		||||
	Name           string `orm:"column(name)" json:"name"`
 | 
			
		||||
	Database       string `orm:"column(database)" json:"database"`
 | 
			
		||||
	Remark         string `json:"remark"`
 | 
			
		||||
	InstanceId     uint64
 | 
			
		||||
	AuthCertName   string  `json:"authCertName"`
 | 
			
		||||
	FlowProcdefKey *string `json:"flowProcdefKey"` // 审批流-流程定义key(有值则说明关键操作需要进行审批执行),使用指针为了方便更新空字符串(取消流程审批)
 | 
			
		||||
	Code         string `orm:"column(code)" json:"code"`
 | 
			
		||||
	Name         string `orm:"column(name)" json:"name"`
 | 
			
		||||
	Database     string `orm:"column(database)" json:"database"`
 | 
			
		||||
	Remark       string `json:"remark"`
 | 
			
		||||
	InstanceId   uint64
 | 
			
		||||
	AuthCertName string `json:"authCertName"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,6 @@ type Procdef struct {
 | 
			
		||||
	Tasks  string               `json:"tasks" binding:"required"` // 审批节点任务信息
 | 
			
		||||
	Status entity.ProcdefStatus `json:"status" binding:"required"`
 | 
			
		||||
	Remark string               `json:"remark"`
 | 
			
		||||
 | 
			
		||||
	CodePaths []string `json:"codePaths"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,39 +2,50 @@ package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/internal/flow/api/form"
 | 
			
		||||
	"mayfly-go/internal/flow/api/vo"
 | 
			
		||||
	"mayfly-go/internal/flow/application"
 | 
			
		||||
	"mayfly-go/internal/flow/domain/entity"
 | 
			
		||||
	tagapp "mayfly-go/internal/tag/application"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Procdef struct {
 | 
			
		||||
	ProcdefApp application.Procdef `inject:""`
 | 
			
		||||
	ProcdefApp       application.Procdef  `inject:""`
 | 
			
		||||
	TagTreeRelateApp tagapp.TagTreeRelate `inject:"TagTreeRelateApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procdef) GetProcdefPage(rc *req.Ctx) {
 | 
			
		||||
	cond, page := req.BindQueryAndPage(rc, new(entity.Procdef))
 | 
			
		||||
	res, err := p.ProcdefApp.GetPageList(cond, page, new([]entity.Procdef))
 | 
			
		||||
	var procdefs []*vo.Procdef
 | 
			
		||||
	res, err := p.ProcdefApp.GetPageList(cond, page, &procdefs)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 | 
			
		||||
	p.TagTreeRelateApp.FillTagInfo(tagentity.TagRelateTypeFlowDef, collx.ArrayMap(procdefs, func(mvo *vo.Procdef) tagentity.IRelateTag {
 | 
			
		||||
		return mvo
 | 
			
		||||
	})...)
 | 
			
		||||
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procdef) GetProcdef(rc *req.Ctx) {
 | 
			
		||||
	defkey := rc.PathParam("key")
 | 
			
		||||
	biz.NotEmpty(defkey, "流程定义key不能为空")
 | 
			
		||||
 | 
			
		||||
	procdef := &entity.Procdef{DefKey: defkey}
 | 
			
		||||
	biz.ErrIsNil(p.ProcdefApp.GetByCond(procdef), "该流程定义不存在")
 | 
			
		||||
	rc.ResData = procdef
 | 
			
		||||
	resourceType := rc.PathParamInt("resourceType")
 | 
			
		||||
	resourceCode := rc.PathParam("resourceCode")
 | 
			
		||||
	rc.ResData = p.ProcdefApp.GetProcdefByResource(rc.MetaCtx, int8(resourceType), resourceCode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Procdef) Save(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Procdef{}
 | 
			
		||||
	procdef := req.BindJsonAndCopyTo(rc, form, new(entity.Procdef))
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	biz.ErrIsNil(a.ProcdefApp.Save(rc.MetaCtx, procdef))
 | 
			
		||||
	biz.ErrIsNil(a.ProcdefApp.SaveProcdef(rc.MetaCtx, &application.SaveProcdefParam{
 | 
			
		||||
		Procdef:   procdef,
 | 
			
		||||
		CodePaths: form.CodePaths,
 | 
			
		||||
	}))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procdef) Delete(rc *req.Ctx) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								server/internal/flow/api/vo/procdef.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								server/internal/flow/api/vo/procdef.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
package vo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/internal/flow/domain/entity"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Procdef struct {
 | 
			
		||||
	tagentity.RelateTags // 标签信息
 | 
			
		||||
	entity.Procdef
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procdef) GetRelateId() uint64 {
 | 
			
		||||
	return p.Id
 | 
			
		||||
}
 | 
			
		||||
@@ -4,29 +4,47 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"mayfly-go/internal/flow/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/flow/domain/repository"
 | 
			
		||||
	tagapp "mayfly-go/internal/tag/application"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SaveProcdefParam struct {
 | 
			
		||||
	Procdef   *entity.Procdef
 | 
			
		||||
	CodePaths []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Procdef interface {
 | 
			
		||||
	base.App[*entity.Procdef]
 | 
			
		||||
 | 
			
		||||
	GetPageList(condition *entity.Procdef, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
 | 
			
		||||
	// 保存流程实例信息
 | 
			
		||||
	Save(ctx context.Context, def *entity.Procdef) error
 | 
			
		||||
	SaveProcdef(ctx context.Context, def *SaveProcdefParam) error
 | 
			
		||||
 | 
			
		||||
	// 删除流程实例信息
 | 
			
		||||
	DeleteProcdef(ctx context.Context, defId uint64) error
 | 
			
		||||
 | 
			
		||||
	// GetProcdefIdByCodePath 根据资源编号路径获取对应的流程定义id
 | 
			
		||||
	GetProcdefIdByCodePath(ctx context.Context, codePaths ...string) uint64
 | 
			
		||||
 | 
			
		||||
	// GetProcdefByResource 根据资源获取对应的流程定义
 | 
			
		||||
	GetProcdefByResource(ctx context.Context, resourceType int8, resourceCode string) *entity.Procdef
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type procdefAppImpl struct {
 | 
			
		||||
	base.AppImpl[*entity.Procdef, repository.Procdef]
 | 
			
		||||
 | 
			
		||||
	procinstApp Procinst `inject:"ProcinstApp"`
 | 
			
		||||
 | 
			
		||||
	tagTreeApp       tagapp.TagTree       `inject:"TagTreeApp"`
 | 
			
		||||
	tagTreeRelateApp tagapp.TagTreeRelate `inject:"TagTreeRelateApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (Procdef) = (*procdefAppImpl)(nil)
 | 
			
		||||
 | 
			
		||||
// 注入repo
 | 
			
		||||
func (p *procdefAppImpl) InjectProcdefRepo(procdefRepo repository.Procdef) {
 | 
			
		||||
	p.Repo = procdefRepo
 | 
			
		||||
@@ -36,24 +54,29 @@ func (p *procdefAppImpl) GetPageList(condition *entity.Procdef, pageParam *model
 | 
			
		||||
	return p.Repo.GetPageList(condition, pageParam, toEntity, orderBy...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *procdefAppImpl) Save(ctx context.Context, def *entity.Procdef) error {
 | 
			
		||||
func (p *procdefAppImpl) SaveProcdef(ctx context.Context, defParam *SaveProcdefParam) error {
 | 
			
		||||
	def := defParam.Procdef
 | 
			
		||||
	if err := entity.ProcdefStatusEnum.Valid(def.Status); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if def.Id == 0 {
 | 
			
		||||
		if p.GetByCond(&entity.Procdef{DefKey: def.DefKey}) == nil {
 | 
			
		||||
			return errorx.NewBiz("该流程实例key已存在")
 | 
			
		||||
		}
 | 
			
		||||
		return p.Insert(ctx, def)
 | 
			
		||||
	} else {
 | 
			
		||||
		// 防止误修改key
 | 
			
		||||
		def.DefKey = ""
 | 
			
		||||
		if err := p.canModify(def.Id); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 防止误修改key
 | 
			
		||||
	def.DefKey = ""
 | 
			
		||||
	if err := p.canModify(def.Id); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p.UpdateById(ctx, def)
 | 
			
		||||
	return p.Tx(ctx, func(ctx context.Context) error {
 | 
			
		||||
		return p.Save(ctx, def)
 | 
			
		||||
	}, func(ctx context.Context) error {
 | 
			
		||||
		return p.tagTreeRelateApp.RelateTag(ctx, tagentity.TagRelateTypeFlowDef, def.Id, defParam.CodePaths...)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *procdefAppImpl) DeleteProcdef(ctx context.Context, defId uint64) error {
 | 
			
		||||
@@ -63,6 +86,31 @@ func (p *procdefAppImpl) DeleteProcdef(ctx context.Context, defId uint64) error
 | 
			
		||||
	return p.DeleteById(ctx, defId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *procdefAppImpl) GetProcdefIdByCodePath(ctx context.Context, codePaths ...string) uint64 {
 | 
			
		||||
	relateIds, err := p.tagTreeRelateApp.GetRelateIds(ctx, tagentity.TagRelateTypeFlowDef, codePaths...)
 | 
			
		||||
	if err != nil || len(relateIds) == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return relateIds[len(relateIds)-1]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *procdefAppImpl) GetProcdefByResource(ctx context.Context, resourceType int8, resourceCode string) *entity.Procdef {
 | 
			
		||||
	resourceCodePaths := p.tagTreeApp.ListTagPathByTypeAndCode(resourceType, resourceCode)
 | 
			
		||||
	procdefId := p.GetProcdefIdByCodePath(ctx, resourceCodePaths...)
 | 
			
		||||
	if procdefId == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	procdef, err := p.GetById(procdefId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if procdef.Status == entity.ProcdefStatusDisable {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return procdef
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 判断该流程实例是否可以执行修改操作
 | 
			
		||||
func (p *procdefAppImpl) canModify(prodefId uint64) error {
 | 
			
		||||
	if activeInstCount := p.procinstApp.CountByCond(&entity.Procinst{ProcdefId: prodefId, Status: entity.ProcinstStatusActive}); activeInstCount > 0 {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,8 @@ type Procinst interface {
 | 
			
		||||
	// 获取流程实例审批节点任务
 | 
			
		||||
	GetProcinstTasks(condition *entity.ProcinstTaskQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
 | 
			
		||||
	// 根据流程定义key启动一个流程实例
 | 
			
		||||
	StartProc(ctx context.Context, procdefKey string, reqParam *StarProcParam) (*entity.Procinst, error)
 | 
			
		||||
	// StartProc 根据流程定义启动一个流程实例
 | 
			
		||||
	StartProc(ctx context.Context, procdefId uint64, reqParam *StarProcParam) (*entity.Procinst, error)
 | 
			
		||||
 | 
			
		||||
	// 取消流程
 | 
			
		||||
	CancelProc(ctx context.Context, procinstId uint64) error
 | 
			
		||||
@@ -42,6 +42,8 @@ type procinstAppImpl struct {
 | 
			
		||||
	procdefApp       Procdef                 `inject:"ProcdefApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (Procinst) = (*procinstAppImpl)(nil)
 | 
			
		||||
 | 
			
		||||
// 注入repo
 | 
			
		||||
func (p *procinstAppImpl) InjectProcinstRepo(procinstRepo repository.Procinst) {
 | 
			
		||||
	p.Repo = procinstRepo
 | 
			
		||||
@@ -55,10 +57,10 @@ func (p *procinstAppImpl) GetProcinstTasks(condition *entity.ProcinstTaskQuery,
 | 
			
		||||
	return p.procinstTaskRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *procinstAppImpl) StartProc(ctx context.Context, procdefKey string, reqParam *StarProcParam) (*entity.Procinst, error) {
 | 
			
		||||
	procdef := &entity.Procdef{DefKey: procdefKey}
 | 
			
		||||
	if err := p.procdefApp.GetByCond(procdef); err != nil {
 | 
			
		||||
		return nil, errorx.NewBiz("流程实例[%s]不存在", procdefKey)
 | 
			
		||||
func (p *procinstAppImpl) StartProc(ctx context.Context, procdefId uint64, reqParam *StarProcParam) (*entity.Procinst, error) {
 | 
			
		||||
	procdef, err := p.procdefApp.GetById(procdefId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errorx.NewBiz("流程实例[%d]不存在", procdefId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if procdef.Status != entity.ProcdefStatusEnable {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ func InitProcdefouter(router *gin.RouterGroup) {
 | 
			
		||||
		reqs := [...]*req.Conf{
 | 
			
		||||
			req.NewGet("", p.GetProcdefPage),
 | 
			
		||||
 | 
			
		||||
			req.NewGet("/:key", p.GetProcdef),
 | 
			
		||||
			req.NewGet("/:resourceType/:resourceCode", p.GetProcdef),
 | 
			
		||||
 | 
			
		||||
			req.NewPost("", p.Save).Log(req.NewLogSave("流程定义-保存")).RequiredPermissionCode("flow:procdef:save"),
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,8 +41,8 @@ type MachineCronJobForm struct {
 | 
			
		||||
	Script          string   `json:"script" binding:"required"`
 | 
			
		||||
	Status          int      `json:"status" binding:"required"`
 | 
			
		||||
	SaveExecResType int      `json:"saveExecResType" binding:"required"`
 | 
			
		||||
	MachineIds      []uint64 `json:"machineIds"`
 | 
			
		||||
	Remark          string   `json:"remark"`
 | 
			
		||||
	CodePaths       []string `json:"codePaths"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineCmdConfForm struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -152,7 +152,7 @@ func (m *Machine) GetProcess(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	cli, err := m.MachineApp.GetCli(GetMachineId(rc))
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.CodePath...), "%s")
 | 
			
		||||
 | 
			
		||||
	res, err := cli.Run(cmd)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
 | 
			
		||||
@@ -166,7 +166,7 @@ func (m *Machine) KillProcess(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
	cli, err := m.MachineApp.GetCli(GetMachineId(rc))
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.CodePath...), "%s")
 | 
			
		||||
 | 
			
		||||
	res, err := cli.Run("sudo kill -9 " + pid)
 | 
			
		||||
	biz.ErrIsNil(err, "终止进程失败: %s", res)
 | 
			
		||||
@@ -194,9 +194,9 @@ func (m *Machine) WsSSH(g *gin.Context) {
 | 
			
		||||
	cli, err := m.MachineApp.NewCli(GetMachineAc(rc))
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, mcm.GetErrorContentRn("获取客户端连接失败: %s"))
 | 
			
		||||
	defer cli.Close()
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath...), mcm.GetErrorContentRn("%s"))
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.CodePath...), mcm.GetErrorContentRn("%s"))
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, cli.Info.TagPath[0])
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, cli.Info.CodePath[0])
 | 
			
		||||
 | 
			
		||||
	cols := rc.QueryIntDefault("cols", 80)
 | 
			
		||||
	rows := rc.QueryIntDefault("rows", 32)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,28 +5,37 @@ import (
 | 
			
		||||
	"mayfly-go/internal/machine/api/vo"
 | 
			
		||||
	"mayfly-go/internal/machine/application"
 | 
			
		||||
	"mayfly-go/internal/machine/domain/entity"
 | 
			
		||||
	tagapp "mayfly-go/internal/tag/application"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/req"
 | 
			
		||||
	"mayfly-go/pkg/scheduler"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MachineCronJob struct {
 | 
			
		||||
	MachineCronJobApp application.MachineCronJob `inject:""`
 | 
			
		||||
	TagTreeRelateApp  tagapp.TagTreeRelate       `inject:"TagTreeRelateApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) MachineCronJobs(rc *req.Ctx) {
 | 
			
		||||
	cond, pageParam := req.BindQueryAndPage(rc, new(entity.MachineCronJob))
 | 
			
		||||
 | 
			
		||||
	vos := new([]*vo.MachineCronJobVO)
 | 
			
		||||
	pageRes, err := m.MachineCronJobApp.GetPageList(cond, pageParam, vos)
 | 
			
		||||
	var vos []*vo.MachineCronJobVO
 | 
			
		||||
	pageRes, err := m.MachineCronJobApp.GetPageList(cond, pageParam, &vos)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	for _, mcj := range *vos {
 | 
			
		||||
 | 
			
		||||
	for _, mcj := range vos {
 | 
			
		||||
		mcj.Running = scheduler.ExistKey(mcj.Key)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.TagTreeRelateApp.FillTagInfo(tagentity.TagRelateTypeMachineCronJob, collx.ArrayMap(vos, func(mvo *vo.MachineCronJobVO) tagentity.IRelateTag {
 | 
			
		||||
		return mvo
 | 
			
		||||
	})...)
 | 
			
		||||
 | 
			
		||||
	rc.ResData = pageRes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -35,11 +44,11 @@ func (m *MachineCronJob) Save(rc *req.Ctx) {
 | 
			
		||||
	mcj := req.BindJsonAndCopyTo[*entity.MachineCronJob](rc, jobForm, new(entity.MachineCronJob))
 | 
			
		||||
	rc.ReqParam = jobForm
 | 
			
		||||
 | 
			
		||||
	cronJobId, err := m.MachineCronJobApp.SaveMachineCronJob(rc.MetaCtx, mcj)
 | 
			
		||||
	err := m.MachineCronJobApp.SaveMachineCronJob(rc.MetaCtx, &application.SaveMachineCronJobParam{
 | 
			
		||||
		CronJob:   mcj,
 | 
			
		||||
		CodePaths: jobForm.CodePaths,
 | 
			
		||||
	})
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 | 
			
		||||
	// 关联机器
 | 
			
		||||
	m.MachineCronJobApp.CronJobRelateMachines(rc.MetaCtx, cronJobId, jobForm.MachineIds)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) Delete(rc *req.Ctx) {
 | 
			
		||||
@@ -54,14 +63,6 @@ func (m *MachineCronJob) Delete(rc *req.Ctx) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) GetRelateMachineIds(rc *req.Ctx) {
 | 
			
		||||
	rc.ResData = m.MachineCronJobApp.GetRelateMachineIds(uint64(rc.QueryIntDefault("cronJobId", -1)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) GetRelateCronJobIds(rc *req.Ctx) {
 | 
			
		||||
	rc.ResData = m.MachineCronJobApp.GetRelateMachineIds(uint64(rc.QueryIntDefault("machineId", -1)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) RunCronJob(rc *req.Ctx) {
 | 
			
		||||
	cronJobKey := rc.PathParam("key")
 | 
			
		||||
	biz.NotEmpty(cronJobKey, "cronJob key不能为空")
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ func (m *MachineScript) RunMachineScript(rc *req.Ctx) {
 | 
			
		||||
	}
 | 
			
		||||
	cli, err := m.MachineApp.GetCliByAc(ac)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.TagApp.CanAccess(rc.GetLoginAccount().Id, cli.Info.CodePath...), "%s")
 | 
			
		||||
 | 
			
		||||
	res, err := cli.Run(script)
 | 
			
		||||
	// 记录请求参数
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,8 @@ type MachineScriptVO struct {
 | 
			
		||||
 | 
			
		||||
// 机器记录任务
 | 
			
		||||
type MachineCronJobVO struct {
 | 
			
		||||
	tagentity.RelateTags // 标签信息
 | 
			
		||||
 | 
			
		||||
	Id              uint64 `json:"id"`
 | 
			
		||||
	Key             string `json:"key"`
 | 
			
		||||
	Name            string `json:"name"`
 | 
			
		||||
@@ -57,6 +59,10 @@ type MachineCronJobVO struct {
 | 
			
		||||
	Running         bool   `json:"running" gorm:"-"` // 是否运行中
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mcj *MachineCronJobVO) GetRelateId() uint64 {
 | 
			
		||||
	return mcj.Id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineFileVO struct {
 | 
			
		||||
	Id        *int64  `json:"id"`
 | 
			
		||||
	Name      *string `json:"name"`
 | 
			
		||||
 
 | 
			
		||||
@@ -341,7 +341,7 @@ func (m *machineAppImpl) toMi(me *entity.Machine, authCert *tagentity.ResourceAu
 | 
			
		||||
	mi.Name = me.Name
 | 
			
		||||
	mi.Ip = me.Ip
 | 
			
		||||
	mi.Port = me.Port
 | 
			
		||||
	mi.TagPath = m.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeMachineAuthCert), authCert.Name)
 | 
			
		||||
	mi.CodePath = m.tagApp.ListTagPathByTypeAndCode(int8(tagentity.TagTypeMachineAuthCert), authCert.Name)
 | 
			
		||||
	mi.EnableRecorder = me.EnableRecorder
 | 
			
		||||
	mi.Protocol = me.Protocol
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ type MachineCmdConf interface {
 | 
			
		||||
 | 
			
		||||
	DeleteCmdConf(ctx context.Context, id uint64) error
 | 
			
		||||
 | 
			
		||||
	GetCmdConfsByMachineTags(tagPaths ...string) []*MachineCmd
 | 
			
		||||
	GetCmdConfsByMachineTags(ctx context.Context, tagPaths ...string) []*MachineCmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type machineCmdConfAppImpl struct {
 | 
			
		||||
@@ -71,9 +71,9 @@ func (m *machineCmdConfAppImpl) DeleteCmdConf(ctx context.Context, id uint64) er
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCmdConfAppImpl) GetCmdConfsByMachineTags(tagPaths ...string) []*MachineCmd {
 | 
			
		||||
func (m *machineCmdConfAppImpl) GetCmdConfsByMachineTags(ctx context.Context, tagPaths ...string) []*MachineCmd {
 | 
			
		||||
	var cmds []*MachineCmd
 | 
			
		||||
	cmdConfIds, err := m.tagTreeRelateApp.GetRelateIds(tagentity.TagRelateTypeMachineCmd, tagPaths...)
 | 
			
		||||
	cmdConfIds, err := m.tagTreeRelateApp.GetRelateIds(ctx, tagentity.TagRelateTypeMachineCmd, tagPaths...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.Errorf("获取命令配置信息失败: %s", err.Error())
 | 
			
		||||
		return cmds
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"mayfly-go/internal/machine/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/machine/domain/repository"
 | 
			
		||||
	tagapp "mayfly-go/internal/tag/application"
 | 
			
		||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
@@ -17,6 +19,11 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type SaveMachineCronJobParam struct {
 | 
			
		||||
	CronJob   *entity.MachineCronJob
 | 
			
		||||
	CodePaths []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineCronJob interface {
 | 
			
		||||
	base.App[*entity.MachineCronJob]
 | 
			
		||||
 | 
			
		||||
@@ -26,22 +33,10 @@ type MachineCronJob interface {
 | 
			
		||||
	// 获取分页执行结果列表
 | 
			
		||||
	GetExecPageList(condition *entity.MachineCronJobExec, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
 | 
			
		||||
	SaveMachineCronJob(ctx context.Context, entity *entity.MachineCronJob) (uint64, error)
 | 
			
		||||
	SaveMachineCronJob(ctx context.Context, param *SaveMachineCronJobParam) error
 | 
			
		||||
 | 
			
		||||
	Delete(ctx context.Context, id uint64)
 | 
			
		||||
 | 
			
		||||
	// 获取计划任务关联的机器列表id
 | 
			
		||||
	GetRelateMachineIds(cronJobId uint64) []uint64
 | 
			
		||||
 | 
			
		||||
	// 获取机器关联的计划任务列表
 | 
			
		||||
	GetRelateCronJobIds(machineId uint64) []uint64
 | 
			
		||||
 | 
			
		||||
	// 计划任务关联机器
 | 
			
		||||
	CronJobRelateMachines(ctx context.Context, cronJobId uint64, machineIds []uint64)
 | 
			
		||||
 | 
			
		||||
	// 机器关联计划任务
 | 
			
		||||
	MachineRelateCronJobs(ctx context.Context, machineId uint64, cronJobs []uint64)
 | 
			
		||||
 | 
			
		||||
	// 初始化计划任务
 | 
			
		||||
	InitCronJob()
 | 
			
		||||
 | 
			
		||||
@@ -53,11 +48,15 @@ type MachineCronJob interface {
 | 
			
		||||
type machineCronJobAppImpl struct {
 | 
			
		||||
	base.AppImpl[*entity.MachineCronJob, repository.MachineCronJob]
 | 
			
		||||
 | 
			
		||||
	machineCronJobRelateRepo repository.MachineCronJobRelate `inject:"MachineCronJobRelateRepo"`
 | 
			
		||||
	machineCronJobExecRepo   repository.MachineCronJobExec   `inject:"MachineCronJobExecRepo"`
 | 
			
		||||
	machineApp               Machine                         `inject:"MachineApp"`
 | 
			
		||||
	machineCronJobExecRepo repository.MachineCronJobExec `inject:"MachineCronJobExecRepo"`
 | 
			
		||||
	machineApp             Machine                       `inject:"MachineApp"`
 | 
			
		||||
 | 
			
		||||
	tagTreeApp       tagapp.TagTree       `inject:"TagTreeApp"`
 | 
			
		||||
	tagTreeRelateApp tagapp.TagTreeRelate `inject:"TagTreeRelateApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (MachineCronJob) = (*machineCronJobAppImpl)(nil)
 | 
			
		||||
 | 
			
		||||
// 注入MachineCronJobRepo
 | 
			
		||||
func (m *machineCronJobAppImpl) InjectMachineCronJobRepo(repo repository.MachineCronJob) {
 | 
			
		||||
	m.Repo = repo
 | 
			
		||||
@@ -74,79 +73,36 @@ func (m *machineCronJobAppImpl) GetExecPageList(condition *entity.MachineCronJob
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 保存机器任务信息
 | 
			
		||||
func (m *machineCronJobAppImpl) SaveMachineCronJob(ctx context.Context, mcj *entity.MachineCronJob) (uint64, error) {
 | 
			
		||||
	// 更新操作
 | 
			
		||||
	if mcj.Id != 0 {
 | 
			
		||||
		m.UpdateById(ctx, mcj)
 | 
			
		||||
		cj, err := m.GetById(mcj.Id)
 | 
			
		||||
func (m *machineCronJobAppImpl) SaveMachineCronJob(ctx context.Context, param *SaveMachineCronJobParam) error {
 | 
			
		||||
	mcj := param.CronJob
 | 
			
		||||
 | 
			
		||||
	// 赋值cron job key
 | 
			
		||||
	if mcj.Id == 0 {
 | 
			
		||||
		mcj.Key = stringx.Rand(16)
 | 
			
		||||
	} else {
 | 
			
		||||
		oldMcj, err := m.GetById(mcj.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, errorx.NewBiz("该任务不存在")
 | 
			
		||||
			return errorx.NewBiz("该计划任务不存在")
 | 
			
		||||
		}
 | 
			
		||||
		// 处理最新的计划任务
 | 
			
		||||
		m.addCronJob(cj)
 | 
			
		||||
		return mcj.Id, nil
 | 
			
		||||
		mcj.Key = oldMcj.Key
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := m.Tx(ctx, func(ctx context.Context) error {
 | 
			
		||||
		return m.Save(ctx, mcj)
 | 
			
		||||
	}, func(ctx context.Context) error {
 | 
			
		||||
		return m.tagTreeRelateApp.RelateTag(ctx, tagentity.TagRelateTypeMachineCronJob, mcj.Id, param.CodePaths...)
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.addCronJob(mcj)
 | 
			
		||||
	if err := m.Insert(ctx, mcj); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return mcj.Id, nil
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) Delete(ctx context.Context, id uint64) {
 | 
			
		||||
	m.DeleteById(ctx, id)
 | 
			
		||||
	m.machineCronJobExecRepo.DeleteByCond(ctx, &entity.MachineCronJobExec{CronJobId: id})
 | 
			
		||||
	m.machineCronJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: id})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) GetRelateMachineIds(cronJobId uint64) []uint64 {
 | 
			
		||||
	return m.machineCronJobRelateRepo.GetMachineIds(cronJobId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) GetRelateCronJobIds(machineId uint64) []uint64 {
 | 
			
		||||
	return m.machineCronJobRelateRepo.GetCronJobIds(machineId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) CronJobRelateMachines(ctx context.Context, cronJobId uint64, machineIds []uint64) {
 | 
			
		||||
	oldMachineIds := m.machineCronJobRelateRepo.GetMachineIds(cronJobId)
 | 
			
		||||
	addIds, delIds, _ := collx.ArrayCompare[uint64](machineIds, oldMachineIds)
 | 
			
		||||
	addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
			
		||||
 | 
			
		||||
	for _, addId := range addIds {
 | 
			
		||||
		addVals = append(addVals, &entity.MachineCronJobRelate{
 | 
			
		||||
			MachineId: addId,
 | 
			
		||||
			CronJobId: cronJobId,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	m.machineCronJobRelateRepo.BatchInsert(ctx, addVals)
 | 
			
		||||
 | 
			
		||||
	for _, delId := range delIds {
 | 
			
		||||
		m.machineCronJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: cronJobId, MachineId: delId})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) MachineRelateCronJobs(ctx context.Context, machineId uint64, cronJobs []uint64) {
 | 
			
		||||
	if len(cronJobs) == 0 {
 | 
			
		||||
		m.machineCronJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{MachineId: machineId})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oldCronIds := m.machineCronJobRelateRepo.GetCronJobIds(machineId)
 | 
			
		||||
	addIds, delIds, _ := collx.ArrayCompare[uint64](cronJobs, oldCronIds)
 | 
			
		||||
	addVals := make([]*entity.MachineCronJobRelate, 0)
 | 
			
		||||
 | 
			
		||||
	for _, addId := range addIds {
 | 
			
		||||
		addVals = append(addVals, &entity.MachineCronJobRelate{
 | 
			
		||||
			MachineId: machineId,
 | 
			
		||||
			CronJobId: addId,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	m.machineCronJobRelateRepo.BatchInsert(ctx, addVals)
 | 
			
		||||
 | 
			
		||||
	for _, delId := range delIds {
 | 
			
		||||
		m.machineCronJobRelateRepo.DeleteByCond(ctx, &entity.MachineCronJobRelate{CronJobId: delId, MachineId: machineId})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) InitCronJob() {
 | 
			
		||||
@@ -160,17 +116,16 @@ func (m *machineCronJobAppImpl) InitCronJob() {
 | 
			
		||||
		PageSize: 100,
 | 
			
		||||
		PageNum:  1,
 | 
			
		||||
	}
 | 
			
		||||
	cond := new(entity.MachineCronJob)
 | 
			
		||||
	cond.Status = entity.MachineCronJobStatusEnable
 | 
			
		||||
	mcjs := new([]entity.MachineCronJob)
 | 
			
		||||
 | 
			
		||||
	pr, _ := m.GetPageList(cond, pageParam, mcjs)
 | 
			
		||||
	var mcjs []*entity.MachineCronJob
 | 
			
		||||
	cond := &entity.MachineCronJob{Status: entity.MachineCronJobStatusEnable}
 | 
			
		||||
	pr, _ := m.GetPageList(cond, pageParam, &mcjs)
 | 
			
		||||
	total := pr.Total
 | 
			
		||||
	add := 0
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		for _, mcj := range *mcjs {
 | 
			
		||||
			m.addCronJob(&mcj)
 | 
			
		||||
		for _, mcj := range mcjs {
 | 
			
		||||
			m.addCronJob(mcj)
 | 
			
		||||
			add++
 | 
			
		||||
		}
 | 
			
		||||
		if add >= int(total) {
 | 
			
		||||
@@ -197,26 +152,24 @@ func (m *machineCronJobAppImpl) RunCronJob(key string) {
 | 
			
		||||
	// 不存在或禁用,则移除该任务
 | 
			
		||||
	if err != nil || cronJob.Status == entity.MachineCronJobStatusDisable {
 | 
			
		||||
		scheduler.RemoveByKey(key)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	machienIds := m.machineCronJobRelateRepo.GetMachineIds(cronJob.Id)
 | 
			
		||||
	for _, machineId := range machienIds {
 | 
			
		||||
		go m.runCronJob0(machineId, cronJob)
 | 
			
		||||
	relateCodePaths := m.tagTreeRelateApp.GetTagPathsByRelate(tagentity.TagRelateTypeMachineCronJob, cronJob.Id)
 | 
			
		||||
	var machineTags []tagentity.TagTree
 | 
			
		||||
	m.tagTreeApp.ListByQuery(&tagentity.TagTreeQuery{CodePathLikes: relateCodePaths, Type: tagentity.TagTypeMachine}, &machineTags)
 | 
			
		||||
	machines, _ := m.machineApp.ListByCond(model.NewCond().In("code", collx.ArrayMap(machineTags, func(tag tagentity.TagTree) string {
 | 
			
		||||
		return tag.Code
 | 
			
		||||
	})), "id")
 | 
			
		||||
 | 
			
		||||
	for _, machine := range machines {
 | 
			
		||||
		go m.runCronJob0(machine.Id, cronJob)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) addCronJob(mcj *entity.MachineCronJob) {
 | 
			
		||||
	var key string
 | 
			
		||||
	key := mcj.Key
 | 
			
		||||
	isDisable := mcj.Status == entity.MachineCronJobStatusDisable
 | 
			
		||||
	if mcj.Id == 0 {
 | 
			
		||||
		key = stringx.Rand(16)
 | 
			
		||||
		mcj.Key = key
 | 
			
		||||
		if isDisable {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		key = mcj.Key
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isDisable {
 | 
			
		||||
		scheduler.RemoveByKey(key)
 | 
			
		||||
@@ -227,6 +180,7 @@ func (m *machineCronJobAppImpl) addCronJob(mcj *entity.MachineCronJob) {
 | 
			
		||||
		m.RunCronJob(key)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineCronJob) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := recover(); err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,6 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MachineFileOpParam struct {
 | 
			
		||||
	Ua           *model.LoginAccount
 | 
			
		||||
	MachineId    uint64 `json:"machineId" binding:"required" form:"machineId"`
 | 
			
		||||
	Protocol     int    `json:"protocol" binding:"required" form:"protocol"`
 | 
			
		||||
	AuthCertName string `json:"authCertName"  binding:"required" form:"authCertName"` // 授权凭证
 | 
			
		||||
@@ -221,7 +220,7 @@ func (m *machineFileAppImpl) MkDir(ctx context.Context, opParam *MachineFileOpPa
 | 
			
		||||
	if opParam.Protocol == entity.MachineProtocolRdp {
 | 
			
		||||
		path = m.GetRdpFilePath(contextx.GetLoginAccount(ctx), path)
 | 
			
		||||
		os.MkdirAll(path, os.ModePerm)
 | 
			
		||||
		return nil, nil
 | 
			
		||||
		return &mcm.MachineInfo{Name: opParam.AuthCertName, Ip: opParam.AuthCertName}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi, sftpCli, err := m.GetMachineSftpCli(opParam)
 | 
			
		||||
@@ -238,8 +237,11 @@ func (m *machineFileAppImpl) CreateFile(ctx context.Context, opParam *MachineFil
 | 
			
		||||
	if opParam.Protocol == entity.MachineProtocolRdp {
 | 
			
		||||
		path = m.GetRdpFilePath(contextx.GetLoginAccount(ctx), path)
 | 
			
		||||
		file, err := os.Create(path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return &mcm.MachineInfo{Name: opParam.AuthCertName, Ip: opParam.AuthCertName}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi, sftpCli, err := m.GetMachineSftpCli(opParam)
 | 
			
		||||
@@ -271,12 +273,12 @@ func (m *machineFileAppImpl) WriteFileContent(ctx context.Context, opParam *Mach
 | 
			
		||||
	if opParam.Protocol == entity.MachineProtocolRdp {
 | 
			
		||||
		path = m.GetRdpFilePath(contextx.GetLoginAccount(ctx), path)
 | 
			
		||||
		file, err := os.Create(path)
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		file.Write(content)
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return &mcm.MachineInfo{Name: opParam.AuthCertName, Ip: opParam.AuthCertName}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi, sftpCli, err := m.GetMachineSftpCli(opParam)
 | 
			
		||||
@@ -303,12 +305,12 @@ func (m *machineFileAppImpl) UploadFile(ctx context.Context, opParam *MachineFil
 | 
			
		||||
	if opParam.Protocol == entity.MachineProtocolRdp {
 | 
			
		||||
		path = m.GetRdpFilePath(contextx.GetLoginAccount(ctx), path)
 | 
			
		||||
		file, err := os.Create(path + filename)
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		defer file.Close()
 | 
			
		||||
		io.Copy(file, reader)
 | 
			
		||||
		return nil, nil
 | 
			
		||||
		return &mcm.MachineInfo{Name: opParam.AuthCertName, Ip: opParam.AuthCertName}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi, sftpCli, err := m.GetMachineSftpCli(opParam)
 | 
			
		||||
@@ -364,7 +366,7 @@ func (m *machineFileAppImpl) UploadFiles(ctx context.Context, opParam *MachineFi
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, nil
 | 
			
		||||
	return &mcm.MachineInfo{Name: opParam.AuthCertName, Ip: opParam.AuthCertName}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 删除文件
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
 | 
			
		||||
		LogCmd:    cli.Info.EnableRecorder == 1,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmdConfs := m.machineCmdConfApp.GetCmdConfsByMachineTags(cli.Info.TagPath...)
 | 
			
		||||
	cmdConfs := m.machineCmdConfApp.GetCmdConfsByMachineTags(ctx, cli.Info.CodePath...)
 | 
			
		||||
	if len(cmdConfs) > 0 {
 | 
			
		||||
		createTsParam.CmdFilterFuncs = []mcm.CmdFilterFunc{func(cmd string) error {
 | 
			
		||||
			for _, cmdConf := range cmdConfs {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,14 +19,6 @@ type MachineCronJob struct {
 | 
			
		||||
	SaveExecResType int        `json:"saveExecResType"` // 记录执行结果类型
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 计划任务与机器关联信息
 | 
			
		||||
type MachineCronJobRelate struct {
 | 
			
		||||
	model.CreateModel
 | 
			
		||||
 | 
			
		||||
	CronJobId uint64
 | 
			
		||||
	MachineId uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 机器任务执行记录
 | 
			
		||||
type MachineCronJobExec struct {
 | 
			
		||||
	model.DeletedModel
 | 
			
		||||
 
 | 
			
		||||
@@ -12,14 +12,6 @@ type MachineCronJob interface {
 | 
			
		||||
	GetPageList(condition *entity.MachineCronJob, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineCronJobRelate interface {
 | 
			
		||||
	base.Repo[*entity.MachineCronJobRelate]
 | 
			
		||||
 | 
			
		||||
	GetMachineIds(cronJobId uint64) []uint64
 | 
			
		||||
 | 
			
		||||
	GetCronJobIds(machineId uint64) []uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MachineCronJobExec interface {
 | 
			
		||||
	base.Repo[*entity.MachineCronJobExec]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
package persistence
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/internal/machine/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/machine/domain/repository"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type machineCronJobRelateRepoImpl struct {
 | 
			
		||||
	base.RepoImpl[*entity.MachineCronJobRelate]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMachineCronJobRelateRepo() repository.MachineCronJobRelate {
 | 
			
		||||
	return &machineCronJobRelateRepoImpl{base.RepoImpl[*entity.MachineCronJobRelate]{M: new(entity.MachineCronJobRelate)}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobRelateRepoImpl) GetMachineIds(cronJobId uint64) []uint64 {
 | 
			
		||||
	var machineIds []uint64
 | 
			
		||||
	m.SelectByCondToAny(model.NewModelCond(&entity.MachineCronJobRelate{CronJobId: cronJobId}).Columns("machine_id"), &machineIds)
 | 
			
		||||
	return machineIds
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *machineCronJobRelateRepoImpl) GetCronJobIds(machineId uint64) []uint64 {
 | 
			
		||||
	var cronJobIds []uint64
 | 
			
		||||
	m.SelectByCondToAny(model.NewModelCond(&entity.MachineCronJobRelate{MachineId: machineId}).Columns("cron_job_id"), &cronJobIds)
 | 
			
		||||
	return cronJobIds
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,6 @@ func InitIoc() {
 | 
			
		||||
	ioc.Register(newMachineScriptRepo(), ioc.WithComponentName("MachineScriptRepo"))
 | 
			
		||||
	ioc.Register(newMachineCronJobRepo(), ioc.WithComponentName("MachineCronJobRepo"))
 | 
			
		||||
	ioc.Register(newMachineCronJobExecRepo(), ioc.WithComponentName("MachineCronJobExecRepo"))
 | 
			
		||||
	ioc.Register(newMachineCronJobRelateRepo(), ioc.WithComponentName("MachineCronJobRelateRepo"))
 | 
			
		||||
	ioc.Register(newMachineTermOpRepoImpl(), ioc.WithComponentName("MachineTermOpRepo"))
 | 
			
		||||
	ioc.Register(newMachineCmdConfRepo(), ioc.WithComponentName("MachineCmdConfRepo"))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,11 +37,4 @@ func Init() {
 | 
			
		||||
		me := event.Val.(*entity.Machine)
 | 
			
		||||
		return application.GetMachineScriptApp().DeleteByCond(ctx, &entity.MachineScript{MachineId: me.Id})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Subscribe(event.EventTopicDeleteMachine, "machineCronJob", func(ctx context.Context, event *eventbus.Event) error {
 | 
			
		||||
		me := event.Val.(*entity.Machine)
 | 
			
		||||
		var jobIds []uint64
 | 
			
		||||
		application.GetMachineCronJobApp().MachineRelateCronJobs(ctx, me.Id, jobIds)
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ type MachineInfo struct {
 | 
			
		||||
	SshTunnelMachine *MachineInfo `json:"-"` // ssh隧道机器
 | 
			
		||||
	TempSshMachineId uint64       `json:"-"` // ssh隧道机器id,用于记录隧道机器id,连接出错后关闭隧道
 | 
			
		||||
	EnableRecorder   int8         `json:"-"` // 是否启用终端回放记录
 | 
			
		||||
	TagPath          []string     `json:"tagPath"`
 | 
			
		||||
	CodePath         []string     `json:"codePath"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineInfo) UseSshTunnel() bool {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,6 @@ func InitMachineCronJobRouter(router *gin.RouterGroup) {
 | 
			
		||||
		// 获取机器任务列表
 | 
			
		||||
		req.NewGet("", cj.MachineCronJobs),
 | 
			
		||||
 | 
			
		||||
		req.NewGet("/machine-ids", cj.GetRelateMachineIds),
 | 
			
		||||
 | 
			
		||||
		req.NewGet("/cronjob-ids", cj.GetRelateCronJobIds),
 | 
			
		||||
 | 
			
		||||
		req.NewPost("", cj.Save).Log(req.NewLogSave("保存机器计划任务")),
 | 
			
		||||
 | 
			
		||||
		req.NewDelete(":ids", cj.Delete).Log(req.NewLogSave("删除机器计划任务")),
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ func (m *Mongo) Collections(rc *req.Ctx) {
 | 
			
		||||
	conn, err := m.MongoApp.GetMongoConn(m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, conn.Info.TagPath[0])
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, conn.Info.CodePath[0])
 | 
			
		||||
 | 
			
		||||
	db := rc.Query("database")
 | 
			
		||||
	biz.NotEmpty(db, "database不能为空")
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,6 @@ type Mongo struct {
 | 
			
		||||
func (me *Mongo) ToMongoInfo(tagPath ...string) *mgm.MongoInfo {
 | 
			
		||||
	mongoInfo := new(mgm.MongoInfo)
 | 
			
		||||
	structx.Copy(mongoInfo, me)
 | 
			
		||||
	mongoInfo.TagPath = tagPath
 | 
			
		||||
	mongoInfo.CodePath = tagPath
 | 
			
		||||
	return mongoInfo
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ type MongoInfo struct {
 | 
			
		||||
 | 
			
		||||
	Uri string `json:"-"`
 | 
			
		||||
 | 
			
		||||
	TagPath            []string `json:"tagPath"`
 | 
			
		||||
	CodePath           []string `json:"codePath"`
 | 
			
		||||
	SshTunnelMachineId int      `json:"-"` // ssh隧道机器id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,10 @@ func (r *Redis) RunCmd(rc *req.Ctx) {
 | 
			
		||||
	biz.IsTrue(len(cmdReq.Cmd) > 0, "redis命令不能为空")
 | 
			
		||||
 | 
			
		||||
	redisConn := r.getRedisConn(rc)
 | 
			
		||||
	biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.GetLoginAccount().Id, redisConn.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.GetLoginAccount().Id, redisConn.Info.CodePath...), "%s")
 | 
			
		||||
	rc.ReqParam = collx.Kvs("redis", redisConn.Info, "cmd", cmdReq.Cmd)
 | 
			
		||||
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, redisConn.Info.TagPath[0])
 | 
			
		||||
	global.EventBus.Publish(rc.MetaCtx, event.EventTopicResourceOp, redisConn.Info.CodePath[0])
 | 
			
		||||
 | 
			
		||||
	res, err := r.RedisApp.RunCmd(rc.MetaCtx, redisConn, runCmdParam)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -232,7 +232,7 @@ func (r *Redis) checkKeyAndGetRedisConn(rc *req.Ctx) (*rdm.RedisConn, string) {
 | 
			
		||||
func (r *Redis) getRedisConn(rc *req.Ctx) *rdm.RedisConn {
 | 
			
		||||
	ri, err := r.RedisApp.GetRedisConn(getIdAndDbNum(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.GetLoginAccount().Id, ri.Info.TagPath...), "%s")
 | 
			
		||||
	biz.ErrIsNilAppendErr(r.TagApp.CanAccess(rc.GetLoginAccount().Id, ri.Info.CodePath...), "%s")
 | 
			
		||||
	return ri
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,6 @@ type Redis struct {
 | 
			
		||||
	Mode               *string    `json:"mode"`
 | 
			
		||||
	SshTunnelMachineId int        `json:"sshTunnelMachineId"` // ssh隧道机器id
 | 
			
		||||
	Remark             *string    `json:"remark"`
 | 
			
		||||
	FlowProcdefKey     string     `json:"flowProcdefKey"`
 | 
			
		||||
	CreateTime         *time.Time `json:"createTime"`
 | 
			
		||||
	Creator            *string    `json:"creator"`
 | 
			
		||||
	CreatorId          *int64     `json:"creatorId"`
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	RedisRunWriteCmdFlowBizType = "redis_run_write_cmd_flow" // db sql exec flow biz type
 | 
			
		||||
	RedisRunWriteCmdFlowBizType = "redis_run_write_cmd_flow"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func InitRedisFlowHandler() {
 | 
			
		||||
 
 | 
			
		||||
@@ -64,6 +64,7 @@ type redisAppImpl struct {
 | 
			
		||||
	base.AppImpl[*entity.Redis, repository.Redis]
 | 
			
		||||
 | 
			
		||||
	tagApp              tagapp.TagTree          `inject:"TagTreeApp"`
 | 
			
		||||
	procdefApp          flowapp.Procdef         `inject:"ProcdefApp"`
 | 
			
		||||
	procinstApp         flowapp.Procinst        `inject:"ProcinstApp"`
 | 
			
		||||
	resourceAuthCertApp tagapp.ResourceAuthCert `inject:"ResourceAuthCertApp"`
 | 
			
		||||
}
 | 
			
		||||
@@ -150,7 +151,7 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, param *SaveRedisParam) err
 | 
			
		||||
		return errorx.NewBiz("该实例已存在")
 | 
			
		||||
	}
 | 
			
		||||
	// 如果修改了redis实例的库信息,则关闭旧库的连接
 | 
			
		||||
	if oldRedis.Db != re.Db || oldRedis.SshTunnelMachineId != re.SshTunnelMachineId || oldRedis.FlowProcdefKey != re.FlowProcdefKey {
 | 
			
		||||
	if oldRedis.Db != re.Db || oldRedis.SshTunnelMachineId != re.SshTunnelMachineId {
 | 
			
		||||
		for _, dbStr := range strings.Split(oldRedis.Db, ",") {
 | 
			
		||||
			db, _ := strconv.Atoi(dbStr)
 | 
			
		||||
			rdm.CloseConn(re.Id, db)
 | 
			
		||||
@@ -238,8 +239,8 @@ func (r *redisAppImpl) RunCmd(ctx context.Context, redisConn *rdm.RedisConn, cmd
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 开启工单流程,并且为写入命令,则开启对应审批流程
 | 
			
		||||
	if procdefKey := redisConn.Info.FlowProcdefKey; procdefKey != "" && rdm.IsWriteCmd(cmdParam.Cmd[0]) {
 | 
			
		||||
		_, err := r.procinstApp.StartProc(ctx, procdefKey, &flowapp.StarProcParam{
 | 
			
		||||
	if procdefId := r.procdefApp.GetProcdefIdByCodePath(ctx, redisConn.Info.CodePath...); procdefId != 0 && rdm.IsWriteCmd(cmdParam.Cmd[0]) {
 | 
			
		||||
		_, err := r.procinstApp.StartProc(ctx, procdefId, &flowapp.StarProcParam{
 | 
			
		||||
			BizType: RedisRunWriteCmdFlowBizType,
 | 
			
		||||
			BizKey:  stringx.Rand(24),
 | 
			
		||||
			BizForm: jsonx.ToStr(cmdParam),
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ type Redis struct {
 | 
			
		||||
	Db                 string `orm:"column(database)" json:"db"`
 | 
			
		||||
	SshTunnelMachineId int    `orm:"column(ssh_tunnel_machine_id)" json:"sshTunnelMachineId"` // ssh隧道机器id
 | 
			
		||||
	Remark             string
 | 
			
		||||
	FlowProcdefKey     *string `json:"flowProcdefKey"` // 审批流-流程定义key(有值则说明关键操作需要进行审批执行),使用指针为了方便更新空字符串(取消流程审批)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToRedisInfo 转换为redisInfo进行连接
 | 
			
		||||
@@ -27,6 +26,6 @@ func (r *Redis) ToRedisInfo(db int, authCert *tagentity.ResourceAuthCert, tagPat
 | 
			
		||||
	redisInfo.Username = authCert.Username
 | 
			
		||||
	redisInfo.Password = authCert.Ciphertext
 | 
			
		||||
	redisInfo.Db = db
 | 
			
		||||
	redisInfo.TagPath = tagPath
 | 
			
		||||
	redisInfo.CodePath = tagPath
 | 
			
		||||
	return redisInfo
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,10 +32,8 @@ type RedisInfo struct {
 | 
			
		||||
	Password string    `json:"-"`
 | 
			
		||||
 | 
			
		||||
	Name               string   `json:"-"`
 | 
			
		||||
	TagPath            []string `json:"tagPath"`
 | 
			
		||||
	CodePath           []string `json:"codePath"`
 | 
			
		||||
	SshTunnelMachineId int      `json:"-"`
 | 
			
		||||
 | 
			
		||||
	FlowProcdefKey string `json:"flowProcdefKey"` // 工单流程定义key
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *RedisInfo) Conn() (*RedisConn, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ import (
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/may-fly/cast"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TagTree struct {
 | 
			
		||||
@@ -20,8 +22,15 @@ type TagTree struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *TagTree) GetTagTree(rc *req.Ctx) {
 | 
			
		||||
	tagType := entity.TagType(rc.QueryInt("type"))
 | 
			
		||||
	accountTags := p.TagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &entity.TagTreeQuery{Type: tagType})
 | 
			
		||||
	tagTypesStr := rc.Query("type")
 | 
			
		||||
	var tagTypes []entity.TagType
 | 
			
		||||
	if tagTypesStr != "" {
 | 
			
		||||
		tagTypes = collx.ArrayMap[string, entity.TagType](strings.Split(tagTypesStr, ","), func(val string) entity.TagType {
 | 
			
		||||
			return entity.TagType(cast.ToInt8(val))
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	accountTags := p.TagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &entity.TagTreeQuery{Types: tagTypes})
 | 
			
		||||
	if len(accountTags) == 0 {
 | 
			
		||||
		rc.ResData = []any{}
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import (
 | 
			
		||||
	"mayfly-go/internal/common/consts"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/repository"
 | 
			
		||||
	"mayfly-go/internal/tag/infrastructure/cache"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/contextx"
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
@@ -103,6 +104,8 @@ type tagTreeAppImpl struct {
 | 
			
		||||
	tagTreeRelateApp TagTreeRelate `inject:"TagTreeRelateApp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ (TagTree) = (*tagTreeAppImpl)(nil)
 | 
			
		||||
 | 
			
		||||
// 注入TagTreeRepo
 | 
			
		||||
func (p *tagTreeAppImpl) InjectTagTreeRepo(tagTreeRepo repository.TagTree) {
 | 
			
		||||
	p.Repo = tagTreeRepo
 | 
			
		||||
@@ -253,6 +256,7 @@ func (p *tagTreeAppImpl) RelateTagsByCodeAndType(ctx context.Context, param *Rel
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -361,7 +365,8 @@ func (p *tagTreeAppImpl) ListByQuery(condition *entity.TagTreeQuery, toEntity an
 | 
			
		||||
 | 
			
		||||
func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQuery) []*entity.TagTree {
 | 
			
		||||
	tagResourceQuery := &entity.TagTreeQuery{
 | 
			
		||||
		Type: query.Type,
 | 
			
		||||
		Type:  query.Type,
 | 
			
		||||
		Types: query.Types,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tagResources []*entity.TagTree
 | 
			
		||||
@@ -383,27 +388,7 @@ func (p *tagTreeAppImpl) GetAccountTags(accountId uint64, query *entity.TagTreeQ
 | 
			
		||||
		if len(accountTagPaths) == 0 {
 | 
			
		||||
			accountTagPaths = tagPaths
 | 
			
		||||
		} else {
 | 
			
		||||
			queryPaths := collx.ArrayFilter[string](tagPaths, func(tagPath string) bool {
 | 
			
		||||
				for _, acPath := range accountTagPaths {
 | 
			
		||||
					// 查询条件: a/b/  有权的:a/  查询结果应该是  a/b/
 | 
			
		||||
					if strings.HasPrefix(tagPath, acPath) {
 | 
			
		||||
						return true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return false
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			acPaths := collx.ArrayFilter[string](accountTagPaths, func(acPath string) bool {
 | 
			
		||||
				for _, tagPath := range tagPaths {
 | 
			
		||||
					// 查询条件: a/  有权的:a/b/  查询结果应该是  a/b/
 | 
			
		||||
					if strings.HasPrefix(acPath, tagPath) {
 | 
			
		||||
						return true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return false
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			accountTagPaths = append(queryPaths, acPaths...)
 | 
			
		||||
			accountTagPaths = filterCodePaths(accountTagPaths, tagPaths)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -441,7 +426,12 @@ func (p *tagTreeAppImpl) ListTagPathByTypeAndCode(resourceType int8, resourceCod
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *tagTreeAppImpl) ListTagByAccountId(accountId uint64) []string {
 | 
			
		||||
	return p.tagTreeRelateApp.GetTagPathsByAccountId(accountId)
 | 
			
		||||
	tagPaths, err := cache.GetAccountTagPaths(accountId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		tagPaths = p.tagTreeRelateApp.GetTagPathsByAccountId(accountId)
 | 
			
		||||
		cache.SaveAccountTagPaths(accountId, tagPaths)
 | 
			
		||||
	}
 | 
			
		||||
	return tagPaths
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *tagTreeAppImpl) CanAccess(accountId uint64, tagPath ...string) error {
 | 
			
		||||
@@ -547,3 +537,50 @@ func (p *tagTreeAppImpl) deleteByIds(ctx context.Context, tagIds []uint64) error
 | 
			
		||||
	// 删除与标签有关联信息的记录(如团队关联的标签等)
 | 
			
		||||
	return p.tagTreeRelateApp.DeleteByCond(ctx, model.NewCond().In("tag_id", tagIds))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterCodePaths 根据账号拥有的标签路径以及指定的标签路径,过滤出符合查询条件的标签路径
 | 
			
		||||
func filterCodePaths(accountTagPaths []string, tagPaths []string) []string {
 | 
			
		||||
	var res []string
 | 
			
		||||
	queryPaths := collx.ArrayFilter[string](tagPaths, func(tagPath string) bool {
 | 
			
		||||
		for _, acPath := range accountTagPaths {
 | 
			
		||||
			// 查询条件: a/b/  有权的:a/  查询结果应该是: a/b/
 | 
			
		||||
			if strings.HasPrefix(tagPath, acPath) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	acPaths := collx.ArrayFilter[string](accountTagPaths, func(acPath string) bool {
 | 
			
		||||
		for _, tagPath := range tagPaths {
 | 
			
		||||
			// 查询条件: a/  有权的:a/b/  查询结果应该是: a/b/,如果以a/去查可能会查出无权的 a/c/相关联的数据
 | 
			
		||||
			if strings.HasPrefix(acPath, tagPath) {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	res = append(queryPaths, acPaths...)
 | 
			
		||||
	return collx.ArrayDeduplicate(res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// hasConflictPath 判断标签路径中是否存在冲突路径,如不能同时存在tag1/tag2/tag3  tag1/  tag1/tag2等,因为拥有父级标签则拥有所有子标签资源等信息
 | 
			
		||||
func hasConflictPath(codePaths []string) bool {
 | 
			
		||||
	if len(codePaths) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	seen := make(map[string]bool)
 | 
			
		||||
	for _, str := range codePaths {
 | 
			
		||||
		parts := strings.Split(str, entity.CodePathSeparator)
 | 
			
		||||
		var prefix string
 | 
			
		||||
		for _, part := range parts {
 | 
			
		||||
			prefix += part + entity.CodePathSeparator
 | 
			
		||||
			if seen[prefix] {
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		seen[str] = true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,11 @@ package application
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"mayfly-go/internal/common/consts"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/repository"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/contextx"
 | 
			
		||||
	"mayfly-go/pkg/errorx"
 | 
			
		||||
	"mayfly-go/pkg/model"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
@@ -17,7 +19,7 @@ type TagTreeRelate interface {
 | 
			
		||||
	RelateTag(ctx context.Context, relateType entity.TagRelateType, relateId uint64, tagCodePaths ...string) error
 | 
			
		||||
 | 
			
		||||
	// GetRelateIds 根据标签路径获取对应关联的id
 | 
			
		||||
	GetRelateIds(relateType entity.TagRelateType, tagPaths ...string) ([]uint64, error)
 | 
			
		||||
	GetRelateIds(ctx context.Context, relateType entity.TagRelateType, tagPaths ...string) ([]uint64, error)
 | 
			
		||||
 | 
			
		||||
	// GetTagPathsByAccountId 根据账号id获取该账号可操作的标签code路径
 | 
			
		||||
	GetTagPathsByAccountId(accountId uint64) []string
 | 
			
		||||
@@ -45,10 +47,16 @@ func (p *tagTreeRelateAppImpl) InjectTagTreeRelateRepo(tagTreeRelateRepo reposit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tr *tagTreeRelateAppImpl) RelateTag(ctx context.Context, relateType entity.TagRelateType, relateId uint64, tagCodePaths ...string) error {
 | 
			
		||||
	if hasConflictPath(tagCodePaths) {
 | 
			
		||||
		return errorx.NewBiz("存在冲突的编号路径")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var tags []*entity.TagTree
 | 
			
		||||
	tr.tagTreeApp.ListByQuery(&entity.TagTreeQuery{CodePaths: tagCodePaths}, &tags)
 | 
			
		||||
	if len(tags) != len(tagCodePaths) {
 | 
			
		||||
		return errorx.NewBiz("存在错误标签路径")
 | 
			
		||||
	if len(tagCodePaths) > 0 {
 | 
			
		||||
		tr.tagTreeApp.ListByQuery(&entity.TagTreeQuery{CodePaths: tagCodePaths}, &tags)
 | 
			
		||||
		if len(tags) != len(tagCodePaths) {
 | 
			
		||||
			return errorx.NewBiz("存在错误标签路径")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oldRelates, _ := tr.ListByCond(&entity.TagTreeRelate{RelateType: relateType, RelateId: relateId})
 | 
			
		||||
@@ -83,9 +91,15 @@ func (tr *tagTreeRelateAppImpl) RelateTag(ctx context.Context, relateType entity
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tr *tagTreeRelateAppImpl) GetRelateIds(relateType entity.TagRelateType, tagPaths ...string) ([]uint64, error) {
 | 
			
		||||
func (tr *tagTreeRelateAppImpl) GetRelateIds(ctx context.Context, relateType entity.TagRelateType, tagPaths ...string) ([]uint64, error) {
 | 
			
		||||
	la := contextx.GetLoginAccount(ctx)
 | 
			
		||||
	canAccessTagPaths := tagPaths
 | 
			
		||||
	if la != nil && la.Id != consts.AdminId {
 | 
			
		||||
		canAccessTagPaths = filterCodePaths(tr.tagTreeApp.ListTagByAccountId(la.Id), tagPaths)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	poisibleTagPaths := make([]string, 0)
 | 
			
		||||
	for _, tagPath := range tagPaths {
 | 
			
		||||
	for _, tagPath := range canAccessTagPaths {
 | 
			
		||||
		// 追加可能关联的标签路径,如tagPath = tag1/tag2/1|xxx/,需要获取所有关联的自身及父标签(tag1/  tag1/tag2/ tag1/tag2/1|xxx)
 | 
			
		||||
		poisibleTagPaths = append(poisibleTagPaths, entity.GetAllCodePath(tagPath)...)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/entity"
 | 
			
		||||
	"mayfly-go/internal/tag/domain/repository"
 | 
			
		||||
	"mayfly-go/internal/tag/infrastructure/cache"
 | 
			
		||||
	"mayfly-go/pkg/base"
 | 
			
		||||
	"mayfly-go/pkg/biz"
 | 
			
		||||
	"mayfly-go/pkg/contextx"
 | 
			
		||||
@@ -90,6 +91,12 @@ func (p *teamAppImpl) SaveTeam(ctx context.Context, saveParam *SaveTeamParam) er
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 删除该团队关联账号的标签缓存
 | 
			
		||||
	teamMembers, _ := p.teamMemberRepo.SelectByCond(&entity.TeamMember{TeamId: team.Id})
 | 
			
		||||
	for _, tm := range teamMembers {
 | 
			
		||||
		cache.DelAccountTagPaths(tm.AccountId)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 保存团队关联的标签信息
 | 
			
		||||
	return p.tagTreeRelateApp.RelateTag(ctx, entity.TagRelateTypeTeam, team.Id, saveParam.CodePaths...)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,10 @@ type TagTreeRelate struct {
 | 
			
		||||
type TagRelateType int8
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TagRelateTypeTeam       TagRelateType = 1 // 关联团队
 | 
			
		||||
	TagRelateTypeMachineCmd TagRelateType = 2 // 关联机器命令配置
 | 
			
		||||
	TagRelateTypeTeam           TagRelateType = 1 // 关联团队
 | 
			
		||||
	TagRelateTypeMachineCmd     TagRelateType = 2 // 关联机器命令配置
 | 
			
		||||
	TagRelateTypeMachineCronJob TagRelateType = 3 // 关联机器定时任务配置
 | 
			
		||||
	TagRelateTypeFlowDef        TagRelateType = 4 // 关联流程定义
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 关联标签信息,如果要实现填充关联标签信息,则结构体需要实现该接口
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								server/internal/tag/infrastructure/cache/tag_tree.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								server/internal/tag/infrastructure/cache/tag_tree.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	global_cache "mayfly-go/pkg/cache"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const AccountTagsKey = "mayfly:tag:account:%d"
 | 
			
		||||
 | 
			
		||||
func SaveAccountTagPaths(accountId uint64, tags []string) error {
 | 
			
		||||
	return global_cache.Set(fmt.Sprintf(AccountTagsKey, accountId), tags, 30*time.Minute)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetAccountTagPaths(accountId uint64) ([]string, error) {
 | 
			
		||||
	var res []string
 | 
			
		||||
	if !global_cache.Get(fmt.Sprintf(AccountTagsKey, accountId), &res) {
 | 
			
		||||
		return nil, errors.New("不存在该值")
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DelAccountTagPaths(accountId uint64) {
 | 
			
		||||
	global_cache.Del(fmt.Sprintf(AccountTagsKey, accountId))
 | 
			
		||||
}
 | 
			
		||||
@@ -39,7 +39,7 @@ func (p *tagTreeRepoImpl) SelectByCondition(condition *entity.TagTreeQuery, toEn
 | 
			
		||||
		params = append(params, condition.Type)
 | 
			
		||||
	}
 | 
			
		||||
	if len(condition.Types) > 0 {
 | 
			
		||||
		sql = sql + " AND p.type = IN (?)"
 | 
			
		||||
		sql = sql + " AND p.type IN (?)"
 | 
			
		||||
		params = append(params, condition.Types)
 | 
			
		||||
	}
 | 
			
		||||
	if len(condition.CodePathLikes) > 0 {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user