mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
feat: dbms新增支持工单流程审批
This commit is contained in:
@@ -30,7 +30,7 @@ require (
|
||||
github.com/sijms/go-ora/v2 v2.8.9
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.mongodb.org/mongo-driver v1.14.0 // mongo
|
||||
golang.org/x/crypto v0.19.0 // ssh
|
||||
golang.org/x/crypto v0.20.0 // ssh
|
||||
golang.org/x/oauth2 v0.17.0
|
||||
golang.org/x/sync v0.6.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
@@ -49,8 +50,15 @@ func (d *Db) Dbs(rc *req.Ctx) {
|
||||
}
|
||||
queryCond.Codes = codes
|
||||
|
||||
res, err := d.DbApp.GetPageList(queryCond, page, new([]vo.DbListVO))
|
||||
var dbvos []*vo.DbListVO
|
||||
res, err := d.DbApp.GetPageList(queryCond, page, &dbvos)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
// 填充标签信息
|
||||
d.TagApp.FillTagInfo(collx.ArrayMap(dbvos, func(dbvo *vo.DbListVO) tagentity.ITagResource {
|
||||
return dbvo
|
||||
})...)
|
||||
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
@@ -117,7 +125,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
s = stringx.TrimSpaceAndBr(s)
|
||||
// 多条执行,暂不支持查询语句
|
||||
if isMulti {
|
||||
biz.IsTrue(!strings.HasPrefix(strings.ToLower(s), "select"), "多条语句执行暂不不支持select语句")
|
||||
biz.IsTrue(!strings.HasPrefix(strings.ToLower(s[:10]), "select"), "多条语句执行暂不不支持select语句")
|
||||
}
|
||||
|
||||
execReq.Sql = s
|
||||
@@ -132,8 +140,10 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
colAndRes := make(map[string]any)
|
||||
colAndRes["columns"] = execResAll.Columns
|
||||
colAndRes["res"] = execResAll.Res
|
||||
if execResAll != nil {
|
||||
colAndRes["columns"] = execResAll.Columns
|
||||
colAndRes["res"] = execResAll.Res
|
||||
}
|
||||
rc.ResData = colAndRes
|
||||
}
|
||||
|
||||
@@ -161,6 +171,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")
|
||||
rc.ReqParam = fmt.Sprintf("filename: %s -> %s", filename, dbConn.Info.GetLogDesc())
|
||||
|
||||
@@ -5,6 +5,9 @@ import (
|
||||
"mayfly-go/internal/db/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/conv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DbSqlExec struct {
|
||||
@@ -13,6 +16,12 @@ type DbSqlExec struct {
|
||||
|
||||
func (d *DbSqlExec) DbSqlExecs(rc *req.Ctx) {
|
||||
queryCond, page := req.BindQueryAndPage(rc, new(entity.DbSqlExecQuery))
|
||||
|
||||
if statusStr := rc.Query("status"); statusStr != "" {
|
||||
queryCond.Status = collx.ArrayMap[string, int8](strings.Split(statusStr, ","), func(val string) int8 {
|
||||
return int8(conv.Str2Int(val, 0))
|
||||
})
|
||||
}
|
||||
res, err := d.DbSqlExecApp.GetPageList(queryCond, page, new([]entity.DbSqlExec))
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package form
|
||||
|
||||
type DbForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Database string `json:"database"`
|
||||
Remark string `json:"remark"`
|
||||
TagId []uint64 `binding:"required" json:"tagId"`
|
||||
InstanceId uint64 `binding:"required" json:"instanceId"`
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Database string `json:"database"`
|
||||
Remark string `json:"remark"`
|
||||
TagId []uint64 `binding:"required" json:"tagId"`
|
||||
InstanceId uint64 `binding:"required" json:"instanceId"`
|
||||
FlowProcdefKey string `json:"flowProcdefKey"`
|
||||
}
|
||||
|
||||
type DbSqlSaveForm struct {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package vo
|
||||
|
||||
import "time"
|
||||
import (
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DbListVO struct {
|
||||
tagentity.ResourceTags
|
||||
|
||||
Id *int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
@@ -16,6 +21,8 @@ type DbListVO struct {
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
|
||||
FlowProcdefKey string `json:"flowProcdefKey"`
|
||||
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
Creator *string `json:"creator"`
|
||||
CreatorId *int64 `json:"creatorId"`
|
||||
@@ -23,3 +30,7 @@ type DbListVO struct {
|
||||
Modifier *string `json:"modifier"`
|
||||
ModifierId *int64 `json:"modifierId"`
|
||||
}
|
||||
|
||||
func (d DbListVO) GetCode() string {
|
||||
return d.Code
|
||||
}
|
||||
|
||||
@@ -34,9 +34,14 @@ func Init() {
|
||||
panic(fmt.Sprintf("初始化 DbBinlogApp 失败: %v", err))
|
||||
}
|
||||
GetDataSyncTaskApp().InitCronJob()
|
||||
InitDbFlowHandler()
|
||||
})()
|
||||
}
|
||||
|
||||
func GetDbSqlExecApp() DbSqlExec {
|
||||
return ioc.Get[DbSqlExec]("DbSqlExecApp")
|
||||
}
|
||||
|
||||
func GetDbBackupApp() *DbBackupApp {
|
||||
return ioc.Get[*DbBackupApp]("DbBackupApp")
|
||||
}
|
||||
|
||||
@@ -168,7 +168,12 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
|
||||
if err := instance.PwdDecrypt(); err != nil {
|
||||
return nil, errorx.NewBiz(err.Error())
|
||||
}
|
||||
return toDbInfo(instance, dbId, dbName, d.tagApp.ListTagPathByResource(consts.TagResourceTypeDb, db.Code)...), nil
|
||||
di := toDbInfo(instance, dbId, dbName, d.tagApp.ListTagPathByResource(consts.TagResourceTypeDb, db.Code)...)
|
||||
if db.FlowProcdefKey != nil {
|
||||
di.FlowProcdefKey = *db.FlowProcdefKey
|
||||
}
|
||||
|
||||
return di, nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
11
server/internal/db/application/db_flow.go
Normal file
11
server/internal/db/application/db_flow.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package application
|
||||
|
||||
import flowapp "mayfly-go/internal/flow/application"
|
||||
|
||||
const (
|
||||
DbSqlExecFlowBizType = "db_sql_exec_flow" // db sql exec flow biz type
|
||||
)
|
||||
|
||||
func InitDbFlowHandler() {
|
||||
flowapp.RegisterBizHandler(DbSqlExecFlowBizType, GetDbSqlExecApp())
|
||||
}
|
||||
@@ -7,11 +7,14 @@ import (
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/internal/db/domain/entity"
|
||||
"mayfly-go/internal/db/domain/repository"
|
||||
flowapp "mayfly-go/internal/flow/application"
|
||||
flowentity "mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/pkg/contextx"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -47,6 +50,8 @@ func (d *DbSqlExecRes) Merge(execRes *DbSqlExecRes) {
|
||||
}
|
||||
|
||||
type DbSqlExec interface {
|
||||
flowapp.FlowBizHandler
|
||||
|
||||
// 执行sql
|
||||
Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error)
|
||||
|
||||
@@ -58,7 +63,10 @@ type DbSqlExec interface {
|
||||
}
|
||||
|
||||
type dbSqlExecAppImpl struct {
|
||||
dbApp Db `inject:"DbApp"`
|
||||
dbSqlExecRepo repository.DbSqlExec `inject:"DbSqlExecRepo"`
|
||||
|
||||
flowProcinstApp flowapp.Procinst `inject:"ProcinstApp"`
|
||||
}
|
||||
|
||||
func createSqlExecRecord(ctx context.Context, execSqlReq *DbSqlExecReq) *entity.DbSqlExec {
|
||||
@@ -67,6 +75,7 @@ func createSqlExecRecord(ctx context.Context, execSqlReq *DbSqlExecReq) *entity.
|
||||
dbSqlExecRecord.Db = execSqlReq.Db
|
||||
dbSqlExecRecord.Sql = execSqlReq.Sql
|
||||
dbSqlExecRecord.Remark = execSqlReq.Remark
|
||||
dbSqlExecRecord.Status = entity.DbSqlExecStatusSuccess
|
||||
dbSqlExecRecord.FillBaseInfo(model.IdGenTypeNone, contextx.GetLoginAccount(ctx))
|
||||
return dbSqlExecRecord
|
||||
}
|
||||
@@ -105,9 +114,9 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (
|
||||
}
|
||||
var execErr error
|
||||
if isSelect || strings.HasPrefix(lowerSql, "show") {
|
||||
execRes, execErr = doRead(ctx, execSqlReq)
|
||||
execRes, execErr = d.doRead(ctx, execSqlReq)
|
||||
} else {
|
||||
execRes, execErr = doExec(ctx, execSqlReq.Sql, execSqlReq.DbConn)
|
||||
execRes, execErr = d.doExec(ctx, execSqlReq, dbSqlExecRecord)
|
||||
}
|
||||
if execErr != nil {
|
||||
return nil, execErr
|
||||
@@ -119,29 +128,76 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (
|
||||
switch stmt := stmt.(type) {
|
||||
case *sqlparser.Select:
|
||||
isSelect = true
|
||||
execRes, err = doSelect(ctx, stmt, execSqlReq)
|
||||
execRes, err = d.doSelect(ctx, stmt, execSqlReq)
|
||||
case *sqlparser.Show:
|
||||
isSelect = true
|
||||
execRes, err = doRead(ctx, execSqlReq)
|
||||
execRes, err = d.doRead(ctx, execSqlReq)
|
||||
case *sqlparser.OtherRead:
|
||||
isSelect = true
|
||||
execRes, err = doRead(ctx, execSqlReq)
|
||||
execRes, err = d.doRead(ctx, execSqlReq)
|
||||
case *sqlparser.Update:
|
||||
execRes, err = doUpdate(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
execRes, err = d.doUpdate(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
case *sqlparser.Delete:
|
||||
execRes, err = doDelete(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
execRes, err = d.doDelete(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
case *sqlparser.Insert:
|
||||
execRes, err = doInsert(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
execRes, err = d.doInsert(ctx, stmt, execSqlReq, dbSqlExecRecord)
|
||||
default:
|
||||
execRes, err = doExec(ctx, execSqlReq.Sql, execSqlReq.DbConn)
|
||||
execRes, err = d.doExec(ctx, execSqlReq, dbSqlExecRecord)
|
||||
}
|
||||
|
||||
d.saveSqlExecLog(isSelect, dbSqlExecRecord)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.saveSqlExecLog(isSelect, dbSqlExecRecord)
|
||||
return execRes, nil
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) FlowBizHandle(ctx context.Context, procinstStatus flowentity.ProcinstStatus, bizKey string) error {
|
||||
logx.Debugf("DbSqlExec FlowBizHandle -> bizKey: %s, procinstStatus: %s", bizKey, flowentity.ProcinstStatusEnum.GetDesc(procinstStatus))
|
||||
// 流程挂起不处理
|
||||
if procinstStatus == flowentity.ProcinstSuspended {
|
||||
return nil
|
||||
}
|
||||
dbSqlExec := &entity.DbSqlExec{FlowBizKey: bizKey}
|
||||
if err := d.dbSqlExecRepo.GetBy(dbSqlExec); err != nil {
|
||||
logx.Errorf("flow-[%s]关联的sql执行信息不存在", bizKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
if procinstStatus != flowentity.ProcinstCompleted {
|
||||
dbSqlExec.Status = entity.DbSqlExecStatusNo
|
||||
dbSqlExec.Res = fmt.Sprintf("流程%s", flowentity.ProcinstStatusEnum.GetDesc(procinstStatus))
|
||||
return d.dbSqlExecRepo.UpdateById(ctx, dbSqlExec)
|
||||
}
|
||||
|
||||
dbSqlExec.Status = entity.DbSqlExecStatusFail
|
||||
dbConn, err := d.dbApp.GetDbConn(dbSqlExec.DbId, dbSqlExec.Db)
|
||||
if err != nil {
|
||||
dbSqlExec.Res = err.Error()
|
||||
d.dbSqlExecRepo.UpdateById(ctx, dbSqlExec)
|
||||
return err
|
||||
}
|
||||
|
||||
rowsAffected, err := dbConn.ExecContext(ctx, dbSqlExec.Sql)
|
||||
if err != nil {
|
||||
dbSqlExec.Res = err.Error()
|
||||
d.dbSqlExecRepo.UpdateById(ctx, dbSqlExec)
|
||||
return err
|
||||
}
|
||||
|
||||
dbSqlExec.Status = entity.DbSqlExecStatusSuccess
|
||||
dbSqlExec.Res = fmt.Sprintf("执行成功,影响条数: %d", rowsAffected)
|
||||
return d.dbSqlExecRepo.UpdateById(ctx, dbSqlExec)
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) DeleteBy(ctx context.Context, condition *entity.DbSqlExec) {
|
||||
d.dbSqlExecRepo.DeleteByCond(ctx, condition)
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) GetPageList(condition *entity.DbSqlExecQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
return d.dbSqlExecRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
|
||||
}
|
||||
|
||||
// 保存sql执行记录,如果是查询类则根据系统配置判断是否保存
|
||||
func (d *dbSqlExecAppImpl) saveSqlExecLog(isQuery bool, dbSqlExecRecord *entity.DbSqlExec) {
|
||||
if !isQuery {
|
||||
@@ -156,15 +212,7 @@ func (d *dbSqlExecAppImpl) saveSqlExecLog(isQuery bool, dbSqlExecRecord *entity.
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) DeleteBy(ctx context.Context, condition *entity.DbSqlExec) {
|
||||
d.dbSqlExecRepo.DeleteByCond(ctx, condition)
|
||||
}
|
||||
|
||||
func (d *dbSqlExecAppImpl) GetPageList(condition *entity.DbSqlExecQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
return d.dbSqlExecRepo.GetPageList(condition, pageParam, toEntity, orderBy...)
|
||||
}
|
||||
|
||||
func doSelect(ctx context.Context, selectStmt *sqlparser.Select, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doSelect(ctx context.Context, selectStmt *sqlparser.Select, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error) {
|
||||
selectExprsStr := sqlparser.String(selectStmt.SelectExprs)
|
||||
if selectExprsStr == "*" || strings.Contains(selectExprsStr, ".*") ||
|
||||
len(strings.Split(selectExprsStr, ",")) > 1 {
|
||||
@@ -189,10 +237,10 @@ func doSelect(ctx context.Context, selectStmt *sqlparser.Select, execSqlReq *DbS
|
||||
}
|
||||
}
|
||||
|
||||
return doRead(ctx, execSqlReq)
|
||||
return d.doRead(ctx, execSqlReq)
|
||||
}
|
||||
|
||||
func doRead(ctx context.Context, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doRead(ctx context.Context, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error) {
|
||||
dbConn := execSqlReq.DbConn
|
||||
sql := execSqlReq.Sql
|
||||
cols, res, err := dbConn.QueryContext(ctx, sql)
|
||||
@@ -205,7 +253,7 @@ func doRead(ctx context.Context, execSqlReq *DbSqlExecReq) (*DbSqlExecRes, error
|
||||
}, nil
|
||||
}
|
||||
|
||||
func doUpdate(ctx context.Context, update *sqlparser.Update, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doUpdate(ctx context.Context, update *sqlparser.Update, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
dbConn := execSqlReq.DbConn
|
||||
|
||||
tableStr := sqlparser.String(update.TableExprs)
|
||||
@@ -256,10 +304,10 @@ func doUpdate(ctx context.Context, update *sqlparser.Update, execSqlReq *DbSqlEx
|
||||
dbSqlExec.Table = tableName
|
||||
dbSqlExec.Type = entity.DbSqlExecTypeUpdate
|
||||
|
||||
return doExec(ctx, execSqlReq.Sql, dbConn)
|
||||
return d.doExec(ctx, execSqlReq, dbSqlExec)
|
||||
}
|
||||
|
||||
func doDelete(ctx context.Context, delete *sqlparser.Delete, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doDelete(ctx context.Context, delete *sqlparser.Delete, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
dbConn := execSqlReq.DbConn
|
||||
|
||||
tableStr := sqlparser.String(delete.TableExprs)
|
||||
@@ -278,24 +326,47 @@ func doDelete(ctx context.Context, delete *sqlparser.Delete, execSqlReq *DbSqlEx
|
||||
dbSqlExec.Table = table
|
||||
dbSqlExec.Type = entity.DbSqlExecTypeDelete
|
||||
|
||||
return doExec(ctx, execSqlReq.Sql, dbConn)
|
||||
return d.doExec(ctx, execSqlReq, dbSqlExec)
|
||||
}
|
||||
|
||||
func doInsert(ctx context.Context, insert *sqlparser.Insert, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doInsert(ctx context.Context, insert *sqlparser.Insert, execSqlReq *DbSqlExecReq, dbSqlExec *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
tableStr := sqlparser.String(insert.Table)
|
||||
// 可能使用别名,故空格切割
|
||||
table := strings.Split(tableStr, " ")[0]
|
||||
dbSqlExec.Table = table
|
||||
dbSqlExec.Type = entity.DbSqlExecTypeInsert
|
||||
|
||||
return doExec(ctx, execSqlReq.Sql, execSqlReq.DbConn)
|
||||
return d.doExec(ctx, execSqlReq, dbSqlExec)
|
||||
}
|
||||
|
||||
func doExec(ctx context.Context, sql string, dbConn *dbi.DbConn) (*DbSqlExecRes, error) {
|
||||
func (d *dbSqlExecAppImpl) doExec(ctx context.Context, execSqlReq *DbSqlExecReq, dbSqlExecRecord *entity.DbSqlExec) (*DbSqlExecRes, error) {
|
||||
dbConn := execSqlReq.DbConn
|
||||
flowProcdefKey := dbConn.Info.FlowProcdefKey
|
||||
if flowProcdefKey != "" {
|
||||
bizKey := stringx.Rand(24)
|
||||
// 如果该库关联了审批流程,则启动流程实例即可
|
||||
_, err := d.flowProcinstApp.StartProc(ctx, flowProcdefKey, &flowapp.StarProcParam{
|
||||
BizType: DbSqlExecFlowBizType,
|
||||
BizKey: bizKey,
|
||||
Remark: dbSqlExecRecord.Remark,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dbSqlExecRecord.FlowBizKey = bizKey
|
||||
dbSqlExecRecord.Status = entity.DbSqlExecStatusWait
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sql := execSqlReq.Sql
|
||||
rowsAffected, err := dbConn.ExecContext(ctx, sql)
|
||||
execRes := "success"
|
||||
if err != nil {
|
||||
execRes = err.Error()
|
||||
dbSqlExecRecord.Status = entity.DbSqlExecStatusFail
|
||||
dbSqlExecRecord.Res = err.Error()
|
||||
} else {
|
||||
dbSqlExecRecord.Res = fmt.Sprintf("执行成功,影响条数: %d", rowsAffected)
|
||||
}
|
||||
res := make([]map[string]any, 0)
|
||||
resData := make(map[string]any)
|
||||
|
||||
@@ -23,6 +23,7 @@ type DbInfo struct {
|
||||
Params string
|
||||
Database string
|
||||
|
||||
FlowProcdefKey string // 流程定义key
|
||||
TagPath []string
|
||||
SshTunnelMachineId int
|
||||
|
||||
|
||||
@@ -7,9 +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
|
||||
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
|
||||
FlowProcdefKey *string `json:"flowProcdefKey"` // 审批流-流程定义key(有值则说明关键操作需要进行审批执行),使用指针为了方便更新空字符串(取消流程审批)
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ import (
|
||||
type DbInstance struct {
|
||||
model.Model
|
||||
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // 类型,mysql oracle等
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Network string `json:"network"`
|
||||
Sid string `json:"sid"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"`
|
||||
Params string `json:"params"`
|
||||
Remark string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // 类型,mysql oracle等
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Network string `json:"network"`
|
||||
Sid string `json:"sid"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"-"`
|
||||
Params *string `json:"params"`
|
||||
Remark string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
}
|
||||
|
||||
func (d *DbInstance) TableName() string {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package entity
|
||||
|
||||
import "mayfly-go/pkg/model"
|
||||
import (
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
// 数据库sql执行记录
|
||||
type DbSqlExec struct {
|
||||
@@ -13,6 +15,10 @@ type DbSqlExec struct {
|
||||
Sql string `json:"sql"` // 执行的sql
|
||||
OldValue string `json:"oldValue"`
|
||||
Remark string `json:"remark"`
|
||||
Status int8 `json:"status"` // 执行状态
|
||||
Res string `json:"res"` // 执行结果
|
||||
|
||||
FlowBizKey string `json:"flowBizKey"` // 流程业务key
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -21,4 +27,9 @@ const (
|
||||
DbSqlExecTypeDelete int8 = 2 // 删除类型
|
||||
DbSqlExecTypeInsert int8 = 3 // 插入类型
|
||||
DbSqlExecTypeQuery int8 = 4 // 查询类型,如select、show等
|
||||
|
||||
DbSqlExecStatusWait = 1
|
||||
DbSqlExecStatusSuccess = 2
|
||||
DbSqlExecStatusNo = -1 // 不执行
|
||||
DbSqlExecStatusFail = -2
|
||||
)
|
||||
|
||||
@@ -31,12 +31,14 @@ type DbQuery struct {
|
||||
}
|
||||
|
||||
type DbSqlExecQuery struct {
|
||||
Id uint64 `json:"id" form:"id"`
|
||||
DbId uint64 `json:"dbId" form:"dbId"`
|
||||
Db string `json:"db" form:"db"`
|
||||
Table string `json:"table" form:"table"`
|
||||
Type int8 `json:"type" form:"type"` // 类型
|
||||
Id uint64 `json:"id" form:"id"`
|
||||
DbId uint64 `json:"dbId" form:"dbId"`
|
||||
Db string `json:"db" form:"db"`
|
||||
Table string `json:"table" form:"table"`
|
||||
Type int8 `json:"type" form:"type"` // 类型
|
||||
FlowBizKey string `json:"flowBizKey" form:"flowBizKey"`
|
||||
|
||||
Status []int8
|
||||
CreatorId uint64
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ func (d *dbSqlExecRepoImpl) GetPageList(condition *entity.DbSqlExecQuery, pagePa
|
||||
Eq("`table`", condition.Table).
|
||||
Eq("type", condition.Type).
|
||||
Eq("creator_id", condition.CreatorId).
|
||||
Eq("flow_biz_key", condition.FlowBizKey).
|
||||
In("status", condition.Status).
|
||||
RLike("db", condition.Db).WithOrderBy(orderBy...)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func InitDbSqlExecRouter(router *gin.RouterGroup) {
|
||||
db := router.Group("/dbs/:dbId/sql-execs")
|
||||
db := router.Group("/dbs/sql-execs")
|
||||
|
||||
d := new(api.DbSqlExec)
|
||||
biz.ErrIsNil(ioc.Inject(d))
|
||||
|
||||
12
server/internal/flow/api/form/procdef.go
Normal file
12
server/internal/flow/api/form/procdef.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package form
|
||||
|
||||
import "mayfly-go/internal/flow/domain/entity"
|
||||
|
||||
type Procdef struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name" binding:"required"` // 名称
|
||||
DefKey string `json:"defKey" binding:"required"`
|
||||
Tasks string `json:"tasks" binding:"required"` // 审批节点任务信息
|
||||
Status entity.ProcdefStatus `json:"status" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
6
server/internal/flow/api/form/procinst.go
Normal file
6
server/internal/flow/api/form/procinst.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package form
|
||||
|
||||
type ProcinstTaskAudit struct {
|
||||
Id uint64 `json:"id" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
50
server/internal/flow/api/procdef.go
Normal file
50
server/internal/flow/api/procdef.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/api/form"
|
||||
"mayfly-go/internal/flow/application"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/req"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Procdef struct {
|
||||
ProcdefApp application.Procdef `inject:""`
|
||||
}
|
||||
|
||||
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))
|
||||
biz.ErrIsNil(err)
|
||||
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.GetBy(procdef), "该流程定义不存在")
|
||||
rc.ResData = procdef
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
func (p *Procdef) Delete(rc *req.Ctx) {
|
||||
idsStr := rc.PathParam("id")
|
||||
rc.ReqParam = idsStr
|
||||
ids := strings.Split(idsStr, ",")
|
||||
|
||||
for _, v := range ids {
|
||||
value, err := strconv.Atoi(v)
|
||||
biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
|
||||
biz.ErrIsNilAppendErr(p.ProcdefApp.DeleteProcdef(rc.MetaCtx, uint64(value)), "删除失败:%s")
|
||||
}
|
||||
}
|
||||
99
server/internal/flow/api/procinst.go
Normal file
99
server/internal/flow/api/procinst.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/common/consts"
|
||||
"mayfly-go/internal/flow/api/form"
|
||||
"mayfly-go/internal/flow/api/vo"
|
||||
"mayfly-go/internal/flow/application"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/domain/repository"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/structx"
|
||||
)
|
||||
|
||||
type Procinst struct {
|
||||
ProcinstApp application.Procinst `inject:""`
|
||||
ProcdefApp application.Procdef `inject:""`
|
||||
|
||||
ProcinstTaskRepo repository.ProcinstTask `inject:""`
|
||||
}
|
||||
|
||||
func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
|
||||
cond, page := req.BindQueryAndPage(rc, new(entity.ProcinstQuery))
|
||||
// 非管理员只能获取自己申请的流程
|
||||
if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
|
||||
cond.CreatorId = laId
|
||||
}
|
||||
|
||||
res, err := p.ProcinstApp.GetPageList(cond, page, new([]entity.Procinst))
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (p *Procinst) ProcinstCancel(rc *req.Ctx) {
|
||||
instId := uint64(rc.PathParamInt("id"))
|
||||
rc.ReqParam = instId
|
||||
biz.ErrIsNil(p.ProcinstApp.CancelProc(rc.MetaCtx, instId))
|
||||
}
|
||||
|
||||
func (p *Procinst) GetProcinstDetail(rc *req.Ctx) {
|
||||
pi, err := p.ProcinstApp.GetById(new(entity.Procinst), uint64(rc.PathParamInt("id")))
|
||||
biz.ErrIsNil(err, "流程实例不存在")
|
||||
pivo := new(vo.ProcinstVO)
|
||||
structx.Copy(pivo, pi)
|
||||
|
||||
// 流程定义信息
|
||||
procdef, _ := p.ProcdefApp.GetById(new(entity.Procdef), pi.ProcdefId)
|
||||
pivo.Procdef = procdef
|
||||
|
||||
// 流程实例任务信息
|
||||
instTasks := new([]*entity.ProcinstTask)
|
||||
biz.ErrIsNil(p.ProcinstTaskRepo.ListByCond(&entity.ProcinstTask{ProcinstId: pi.Id}, instTasks))
|
||||
pivo.ProcinstTasks = *instTasks
|
||||
|
||||
rc.ResData = pivo
|
||||
}
|
||||
|
||||
func (p *Procinst) GetTasks(rc *req.Ctx) {
|
||||
instTaskQuery, page := req.BindQueryAndPage(rc, new(entity.ProcinstTaskQuery))
|
||||
if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
|
||||
// 赋值操作人为当前登录账号
|
||||
instTaskQuery.Assignee = fmt.Sprintf("%d", rc.GetLoginAccount().Id)
|
||||
}
|
||||
|
||||
taskVos := new([]*vo.ProcinstTask)
|
||||
res, err := p.ProcinstApp.GetProcinstTasks(instTaskQuery, page, taskVos)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
instIds := collx.ArrayMap[*vo.ProcinstTask, uint64](*taskVos, func(val *vo.ProcinstTask) uint64 { return val.ProcinstId })
|
||||
insts := new([]*entity.Procinst)
|
||||
p.ProcinstApp.GetByIdIn(insts, instIds)
|
||||
instId2Inst := collx.ArrayToMap[*entity.Procinst, uint64](*insts, func(val *entity.Procinst) uint64 { return val.Id })
|
||||
|
||||
// 赋值任务对应的流程实例
|
||||
for _, task := range *taskVos {
|
||||
task.Procinst = instId2Inst[task.ProcinstId]
|
||||
}
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (p *Procinst) CompleteTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
rc.ReqParam = auditForm
|
||||
biz.ErrIsNil(p.ProcinstApp.CompleteTask(rc.MetaCtx, auditForm.Id, auditForm.Remark))
|
||||
}
|
||||
|
||||
func (p *Procinst) RejectTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
rc.ReqParam = auditForm
|
||||
biz.ErrIsNil(p.ProcinstApp.RejectTask(rc.MetaCtx, auditForm.Id, auditForm.Remark))
|
||||
}
|
||||
|
||||
func (p *Procinst) BackTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
|
||||
rc.ReqParam = auditForm
|
||||
biz.ErrIsNil(p.ProcinstApp.BackTask(rc.MetaCtx, auditForm.Id, auditForm.Remark))
|
||||
}
|
||||
45
server/internal/flow/api/vo/procinst.go
Normal file
45
server/internal/flow/api/vo/procinst.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProcinstVO struct {
|
||||
Id uint64 `json:"id"`
|
||||
ProcdefId uint64 `json:"procdefId"` // 流程定义id
|
||||
ProcdefName string `json:"procdefName"` // 流程定义名称
|
||||
|
||||
BizType string `json:"bizType"` // 业务类型
|
||||
BizKey string `json:"bizKey"` // 业务key
|
||||
BizStatus int8 `json:"bizStatus"` // 业务状态
|
||||
BizHandleRes string `json:"bizHandleRes"` // 业务处理结果
|
||||
TaskKey string `json:"taskKey"` // 当前任务key
|
||||
Remark string `json:"remark"`
|
||||
Status int8 `json:"status"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
Duration int64 `json:"duration"` // 持续时间(开始到结束)
|
||||
|
||||
Creator string `json:"creator"`
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
UpdateTime *time.Time `json:"updateTime"`
|
||||
|
||||
Procdef *entity.Procdef `json:"procdef"`
|
||||
ProcinstTasks []*entity.ProcinstTask `json:"procinstTasks"`
|
||||
}
|
||||
|
||||
type ProcinstTask struct {
|
||||
Id uint64 `json:"id"`
|
||||
ProcinstId uint64 `json:"procinstId"` // 流程实例id
|
||||
TaskKey string `json:"taskKey"` // 当前任务key
|
||||
TaskName string `json:"taskName"` // 当前任务名称
|
||||
Assignee string `json:"assignee"` // 分配到该任务的用户
|
||||
|
||||
Status entity.ProcinstTaskStatus `json:"status"` // 状态
|
||||
Remark string `json:"remark"`
|
||||
Duration int64 `json:"duration"` // 持续时间(开始到结束)
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
|
||||
Procinst *entity.Procinst `json:"procinst"`
|
||||
}
|
||||
13
server/internal/flow/application/application.go
Normal file
13
server/internal/flow/application/application.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/infrastructure/persistence"
|
||||
"mayfly-go/pkg/ioc"
|
||||
)
|
||||
|
||||
func InitIoc() {
|
||||
persistence.Init()
|
||||
|
||||
ioc.Register(new(procdefAppImpl), ioc.WithComponentName("ProcdefApp"))
|
||||
ioc.Register(new(procinstAppImpl), ioc.WithComponentName("ProcinstApp"))
|
||||
}
|
||||
42
server/internal/flow/application/biz_handler.go
Normal file
42
server/internal/flow/application/biz_handler.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
)
|
||||
|
||||
// 流程业务处理函数(流程结束后会根据流程业务类型获取该函数进行处理)
|
||||
// @param procinstStatus 流程实例状态
|
||||
// @param bizKey 业务key,可为业务数据对应的主键
|
||||
// type FlowBizHandlerFunc func(ctx context.Context, procinstStatus entity.ProcinstStatus, bizKey string) error
|
||||
|
||||
// 业务流程处理器(流程状态变更后会根据流程业务类型获取对应的处理器进行回调处理)
|
||||
type FlowBizHandler interface {
|
||||
|
||||
// 业务流程处理函数
|
||||
// @param procinstStatus 流程实例状态
|
||||
// @param bizKey 业务key,可为业务数据对应的主键
|
||||
FlowBizHandle(ctx context.Context, procinstStatus entity.ProcinstStatus, bizKey string) error
|
||||
}
|
||||
|
||||
var (
|
||||
handlers map[string]FlowBizHandler = make(map[string]FlowBizHandler, 0)
|
||||
)
|
||||
|
||||
// 注册流程业务处理函数
|
||||
func RegisterBizHandler(flowBizType string, handler FlowBizHandler) {
|
||||
logx.Infof("flow register biz handelr: bizType=%s", flowBizType)
|
||||
handlers[flowBizType] = handler
|
||||
}
|
||||
|
||||
// 流程业务处理
|
||||
func FlowBizHandle(ctx context.Context, flowBizType string, bizKey string, procinstStatus entity.ProcinstStatus) error {
|
||||
if handler, ok := handlers[flowBizType]; !ok {
|
||||
logx.Warnf("flow biz handler not found: bizType=%s", flowBizType)
|
||||
return errorx.NewBiz("业务流程处理器不存在")
|
||||
} else {
|
||||
return handler.FlowBizHandle(ctx, procinstStatus, bizKey)
|
||||
}
|
||||
}
|
||||
13
server/internal/flow/application/param.go
Normal file
13
server/internal/flow/application/param.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package application
|
||||
|
||||
// 启动流程实例请求入参
|
||||
type StarProcParam struct {
|
||||
BizType string // 业务类型
|
||||
BizKey string // 业务key
|
||||
Remark string // 备注
|
||||
}
|
||||
|
||||
type CompleteProcinstTaskParam struct {
|
||||
TaskId uint64
|
||||
Remark string // 备注
|
||||
}
|
||||
75
server/internal/flow/application/procdef.go
Normal file
75
server/internal/flow/application/procdef.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
// 删除流程实例信息
|
||||
DeleteProcdef(ctx context.Context, defId uint64) error
|
||||
}
|
||||
|
||||
type procdefAppImpl struct {
|
||||
base.AppImpl[*entity.Procdef, repository.Procdef]
|
||||
|
||||
procinstApp Procinst `inject:"ProcinstApp"`
|
||||
}
|
||||
|
||||
// 注入repo
|
||||
func (p *procdefAppImpl) InjectProcdefRepo(procdefRepo repository.Procdef) {
|
||||
p.Repo = procdefRepo
|
||||
}
|
||||
|
||||
func (p *procdefAppImpl) GetPageList(condition *entity.Procdef, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
return p.Repo.GetPageList(condition, pageParam, toEntity, orderBy...)
|
||||
}
|
||||
|
||||
func (p *procdefAppImpl) Save(ctx context.Context, def *entity.Procdef) error {
|
||||
if err := entity.ProcdefStatusEnum.Valid(def.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
if def.Id == 0 {
|
||||
if p.GetBy(&entity.Procdef{DefKey: def.DefKey}) == nil {
|
||||
return errorx.NewBiz("该流程实例key已存在")
|
||||
}
|
||||
return p.Insert(ctx, def)
|
||||
}
|
||||
|
||||
// 防止误修改key
|
||||
def.DefKey = ""
|
||||
if err := p.canModify(def.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.UpdateById(ctx, def)
|
||||
}
|
||||
|
||||
func (p *procdefAppImpl) DeleteProcdef(ctx context.Context, defId uint64) error {
|
||||
if err := p.canModify(defId); err != nil {
|
||||
return err
|
||||
}
|
||||
return p.DeleteById(ctx, defId)
|
||||
}
|
||||
|
||||
// 判断该流程实例是否可以执行修改操作
|
||||
func (p *procdefAppImpl) canModify(prodefId uint64) error {
|
||||
if activeInstCount := p.procinstApp.CountByCond(&entity.Procinst{ProcdefId: prodefId, Status: entity.ProcinstActive}); activeInstCount > 0 {
|
||||
return errorx.NewBiz("存在运行中的流程实例,无法操作")
|
||||
}
|
||||
if suspInstCount := p.procinstApp.CountByCond(&entity.Procinst{ProcdefId: prodefId, Status: entity.ProcinstSuspended}); suspInstCount > 0 {
|
||||
return errorx.NewBiz("存在挂起中的流程实例,无法操作")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
295
server/internal/flow/application/procinst.go
Normal file
295
server/internal/flow/application/procinst.go
Normal file
@@ -0,0 +1,295 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/contextx"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type Procinst interface {
|
||||
base.App[*entity.Procinst]
|
||||
|
||||
GetPageList(condition *entity.ProcinstQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
|
||||
// 获取流程实例审批节点任务
|
||||
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)
|
||||
|
||||
// 取消流程
|
||||
CancelProc(ctx context.Context, procinstId uint64) error
|
||||
|
||||
// 完成任务
|
||||
CompleteTask(ctx context.Context, taskId uint64, remark string) error
|
||||
|
||||
// 拒绝任务
|
||||
RejectTask(ctx context.Context, taskId uint64, remark string) error
|
||||
|
||||
// 驳回任务(允许重新提交)
|
||||
BackTask(ctx context.Context, taskId uint64, remark string) error
|
||||
}
|
||||
|
||||
type procinstAppImpl struct {
|
||||
base.AppImpl[*entity.Procinst, repository.Procinst]
|
||||
|
||||
procinstTaskRepo repository.ProcinstTask `inject:"ProcinstTaskRepo"`
|
||||
procdefApp Procdef `inject:"ProcdefApp"`
|
||||
}
|
||||
|
||||
// 注入repo
|
||||
func (p *procinstAppImpl) InjectProcinstRepo(procinstRepo repository.Procinst) {
|
||||
p.Repo = procinstRepo
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) GetPageList(condition *entity.ProcinstQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
return p.Repo.GetPageList(condition, pageParam, toEntity, orderBy...)
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) GetProcinstTasks(condition *entity.ProcinstTaskQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
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.GetBy(procdef); err != nil {
|
||||
return nil, errorx.NewBiz("流程实例[%s]不存在", procdefKey)
|
||||
}
|
||||
|
||||
if procdef.Status != entity.ProcdefStatusEnable {
|
||||
return nil, errorx.NewBiz("该流程定义非启用状态")
|
||||
}
|
||||
|
||||
procinst := &entity.Procinst{
|
||||
BizType: reqParam.BizType,
|
||||
BizKey: reqParam.BizKey,
|
||||
BizStatus: entity.ProcinstBizStatusWait,
|
||||
ProcdefId: procdef.Id,
|
||||
ProcdefName: procdef.Name,
|
||||
Remark: reqParam.Remark,
|
||||
Status: entity.ProcinstActive,
|
||||
}
|
||||
|
||||
task := p.getNextTask(procdef, "")
|
||||
procinst.TaskKey = task.TaskKey
|
||||
|
||||
if err := p.Save(ctx, procinst); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return procinst, p.createProcinstTask(ctx, procinst, task)
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) CancelProc(ctx context.Context, procinstId uint64) error {
|
||||
procinst, err := p.GetById(new(entity.Procinst), procinstId)
|
||||
if err != nil {
|
||||
return errorx.NewBiz("流程不存在")
|
||||
}
|
||||
|
||||
la := contextx.GetLoginAccount(ctx)
|
||||
if la == nil {
|
||||
return errorx.NewBiz("未登录")
|
||||
}
|
||||
if procinst.CreatorId != la.Id {
|
||||
return errorx.NewBiz("只能取消自己创建的流程")
|
||||
}
|
||||
procinst.Status = entity.ProcinstCancelled
|
||||
procinst.BizStatus = entity.ProcinstBizStatusNo
|
||||
procinst.SetEnd()
|
||||
|
||||
return p.Tx(ctx, func(ctx context.Context) error {
|
||||
return p.cancelInstTasks(ctx, procinstId, "流程已取消")
|
||||
}, func(ctx context.Context) error {
|
||||
return p.Save(ctx, procinst)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.triggerProcinstStatusChangeEvent(ctx, procinst)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) CompleteTask(ctx context.Context, instTaskId uint64, remark string) error {
|
||||
instTask, err := p.getAndValidInstTask(ctx, instTaskId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 赋值状态和备注
|
||||
instTask.Status = entity.ProcinstTaskStatusPass
|
||||
instTask.Remark = remark
|
||||
instTask.SetEnd()
|
||||
|
||||
procinst := new(entity.Procinst)
|
||||
p.GetById(procinst, instTask.ProcinstId)
|
||||
|
||||
procdef := new(entity.Procdef)
|
||||
p.procdefApp.GetById(procdef, procinst.ProcdefId)
|
||||
|
||||
// 获取下一实例审批任务
|
||||
task := p.getNextTask(procdef, instTask.TaskKey)
|
||||
if task == nil {
|
||||
procinst.Status = entity.ProcinstCompleted
|
||||
procinst.SetEnd()
|
||||
} else {
|
||||
procinst.TaskKey = task.TaskKey
|
||||
}
|
||||
|
||||
return p.Tx(ctx, func(ctx context.Context) error {
|
||||
return p.UpdateById(ctx, procinst)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.procinstTaskRepo.UpdateById(ctx, instTask)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.createProcinstTask(ctx, procinst, task)
|
||||
}, func(ctx context.Context) error {
|
||||
// 下一审批节点任务不存在,说明该流程已结束
|
||||
if task == nil {
|
||||
return p.triggerProcinstStatusChangeEvent(ctx, procinst)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) RejectTask(ctx context.Context, instTaskId uint64, remark string) error {
|
||||
instTask, err := p.getAndValidInstTask(ctx, instTaskId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 赋值状态和备注
|
||||
instTask.Status = entity.ProcinstTaskStatusReject
|
||||
instTask.Remark = remark
|
||||
instTask.SetEnd()
|
||||
|
||||
procinst := new(entity.Procinst)
|
||||
p.GetById(procinst, instTask.ProcinstId)
|
||||
// 更新流程实例为终止状态,无法重新提交
|
||||
procinst.Status = entity.ProcinstTerminated
|
||||
procinst.BizStatus = entity.ProcinstBizStatusNo
|
||||
procinst.SetEnd()
|
||||
|
||||
return p.Tx(ctx, func(ctx context.Context) error {
|
||||
return p.UpdateById(ctx, procinst)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.procinstTaskRepo.UpdateById(ctx, instTask)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.triggerProcinstStatusChangeEvent(ctx, procinst)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *procinstAppImpl) BackTask(ctx context.Context, instTaskId uint64, remark string) error {
|
||||
instTask, err := p.getAndValidInstTask(ctx, instTaskId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 赋值状态和备注
|
||||
instTask.Status = entity.ProcinstTaskStatusBack
|
||||
instTask.Remark = remark
|
||||
|
||||
procinst := new(entity.Procinst)
|
||||
p.GetById(procinst, instTask.ProcinstId)
|
||||
|
||||
// 更新流程实例为挂起状态,等待重新提交
|
||||
procinst.Status = entity.ProcinstSuspended
|
||||
|
||||
return p.Tx(ctx, func(ctx context.Context) error {
|
||||
return p.UpdateById(ctx, procinst)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.procinstTaskRepo.UpdateById(ctx, instTask)
|
||||
}, func(ctx context.Context) error {
|
||||
return p.triggerProcinstStatusChangeEvent(ctx, procinst)
|
||||
})
|
||||
}
|
||||
|
||||
// 取消处理中的流程实例任务
|
||||
func (p *procinstAppImpl) cancelInstTasks(ctx context.Context, procinstId uint64, cancelReason string) error {
|
||||
// 流程实例任务信息
|
||||
instTasks := new([]*entity.ProcinstTask)
|
||||
p.procinstTaskRepo.ListByCond(&entity.ProcinstTask{ProcinstId: procinstId, Status: entity.ProcinstTaskStatusProcess}, instTasks)
|
||||
for _, instTask := range *instTasks {
|
||||
instTask.Status = entity.ProcinstTaskStatusCanceled
|
||||
instTask.Remark = cancelReason
|
||||
instTask.SetEnd()
|
||||
p.procinstTaskRepo.UpdateById(ctx, instTask)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 触发流程实例状态改变事件
|
||||
func (p *procinstAppImpl) triggerProcinstStatusChangeEvent(ctx context.Context, procinst *entity.Procinst) error {
|
||||
err := FlowBizHandle(ctx, procinst.BizType, procinst.BizKey, procinst.Status)
|
||||
if err != nil {
|
||||
// 业务处理错误,非完成状态则终止流程
|
||||
if procinst.Status != entity.ProcinstCompleted {
|
||||
procinst.Status = entity.ProcinstTerminated
|
||||
procinst.SetEnd()
|
||||
p.cancelInstTasks(ctx, procinst.Id, "业务处理失败")
|
||||
}
|
||||
procinst.BizStatus = entity.ProcinstBizStatusFail
|
||||
procinst.BizHandleRes = err.Error()
|
||||
return p.UpdateById(ctx, procinst)
|
||||
}
|
||||
|
||||
// 处理成功,并且状态为完成,则更新业务状态为成功
|
||||
if procinst.Status == entity.ProcinstCompleted {
|
||||
procinst.BizStatus = entity.ProcinstBizStatusSuccess
|
||||
procinst.BizHandleRes = "success"
|
||||
return p.UpdateById(ctx, procinst)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取并校验实例任务
|
||||
func (p *procinstAppImpl) getAndValidInstTask(ctx context.Context, instTaskId uint64) (*entity.ProcinstTask, error) {
|
||||
instTask := new(entity.ProcinstTask)
|
||||
if err := p.procinstTaskRepo.GetById(instTask, instTaskId); err != nil {
|
||||
return nil, errorx.NewBiz("流程实例任务不存在")
|
||||
}
|
||||
|
||||
la := contextx.GetLoginAccount(ctx)
|
||||
if instTask.Assignee != fmt.Sprintf("%d", la.Id) {
|
||||
return nil, errorx.NewBiz("当前用户不是任务处理人,无法完成任务")
|
||||
}
|
||||
|
||||
return instTask, nil
|
||||
}
|
||||
|
||||
// 创建流程实例节点任务
|
||||
func (p *procinstAppImpl) createProcinstTask(ctx context.Context, procinst *entity.Procinst, task *entity.ProcdefTask) error {
|
||||
if task == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
procinstTask := &entity.ProcinstTask{
|
||||
ProcinstId: procinst.Id,
|
||||
Status: entity.ProcinstTaskStatusProcess,
|
||||
|
||||
TaskKey: task.TaskKey,
|
||||
TaskName: task.Name,
|
||||
Assignee: task.UserId,
|
||||
}
|
||||
return p.procinstTaskRepo.Insert(ctx, procinstTask)
|
||||
}
|
||||
|
||||
// 获取下一审批节点任务
|
||||
func (p *procinstAppImpl) getNextTask(procdef *entity.Procdef, nowTaskKey string) *entity.ProcdefTask {
|
||||
tasks := procdef.GetTasks()
|
||||
if len(tasks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if nowTaskKey == "" {
|
||||
// nowTaskKey为空,则说明为刚启动该流程实例
|
||||
return tasks[0]
|
||||
}
|
||||
|
||||
for index, t := range tasks {
|
||||
if (t.TaskKey == nowTaskKey) && (index < len(tasks)-1) {
|
||||
return tasks[index+1]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
52
server/internal/flow/domain/entity/procdef.go
Normal file
52
server/internal/flow/domain/entity/procdef.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"mayfly-go/pkg/enumx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
// 流程定义信息
|
||||
type Procdef struct {
|
||||
model.Model
|
||||
|
||||
Name string `json:"name" form:"name"` // 名称
|
||||
DefKey string `json:"defKey" form:"defKey"` //
|
||||
Tasks string `json:"tasks"` // 审批节点任务信息
|
||||
Status ProcdefStatus `json:"status"` // 状态
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
func (p *Procdef) TableName() string {
|
||||
return "t_flow_procdef"
|
||||
}
|
||||
|
||||
// 获取审批节点任务列表
|
||||
func (p *Procdef) GetTasks() []*ProcdefTask {
|
||||
var tasks []*ProcdefTask
|
||||
err := json.Unmarshal([]byte(p.Tasks), &tasks)
|
||||
if err != nil {
|
||||
logx.ErrorTrace("解析procdef tasks失败", err)
|
||||
return tasks
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
type ProcdefTask struct {
|
||||
Name string `json:"name" form:"name"` // 审批节点任务名称
|
||||
TaskKey string `json:"taskKey" form:"taskKey"` // 任务key
|
||||
UserId string `json:"userId"` // 审批人
|
||||
}
|
||||
|
||||
type ProcdefStatus int8
|
||||
|
||||
const (
|
||||
ProcdefStatusEnable ProcdefStatus = 1
|
||||
ProcdefStatusDisable ProcdefStatus = -1
|
||||
)
|
||||
|
||||
var ProcdefStatusEnum = enumx.NewEnum[ProcdefStatus]("流程定义状态").
|
||||
Add(ProcdefStatusEnable, "启用").
|
||||
Add(ProcdefStatusDisable, "禁用")
|
||||
100
server/internal/flow/domain/entity/procinst.go
Normal file
100
server/internal/flow/domain/entity/procinst.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/enumx"
|
||||
"mayfly-go/pkg/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 流程实例信息 -> 根据流程定义信息启动一个流程实例
|
||||
type Procinst struct {
|
||||
model.Model
|
||||
|
||||
ProcdefId uint64 `json:"procdefId"` // 流程定义id
|
||||
ProcdefName string `json:"procdefName"` // 流程定义名称
|
||||
|
||||
BizType string `json:"bizType"` // 业务类型
|
||||
BizKey string `json:"bizKey"` // 业务key
|
||||
BizStatus ProcinstBizStatus `json:"bizStatus"` // 业务状态
|
||||
BizHandleRes string `json:"bizHandleRes"` // 业务处理结果
|
||||
TaskKey string `json:"taskKey"` // 当前任务key
|
||||
Status ProcinstStatus `json:"status"` // 状态
|
||||
Remark string `json:"remark"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
Duration int64 `json:"duration"` // 持续时间(开始到结束)
|
||||
}
|
||||
|
||||
func (a *Procinst) TableName() string {
|
||||
return "t_flow_procinst"
|
||||
}
|
||||
|
||||
// 设置流程终止结束的一些信息
|
||||
func (a *Procinst) SetEnd() {
|
||||
nowTime := time.Now()
|
||||
a.EndTime = &nowTime
|
||||
a.Duration = int64(time.Since(*a.CreateTime).Seconds())
|
||||
}
|
||||
|
||||
type ProcinstStatus int8
|
||||
|
||||
const (
|
||||
ProcinstActive ProcinstStatus = 1 // 流程实例正在执行中,当前有活动任务等待执行或者正在运行的流程节点
|
||||
ProcinstCompleted ProcinstStatus = 2 // 流程实例已经成功执行完成,没有剩余任务或者等待事件
|
||||
ProcinstSuspended ProcinstStatus = -1 // 流程实例被挂起,暂停执行,可能被驳回等待修改重新提交
|
||||
ProcinstTerminated ProcinstStatus = -2 // 流程实例被终止,可能是由于某种原因如被拒绝等导致流程无法正常执行
|
||||
ProcinstCancelled ProcinstStatus = -3 // 流程实例被取消,通常是用户手动操作取消了流程的执行
|
||||
)
|
||||
|
||||
var ProcinstStatusEnum = enumx.NewEnum[ProcinstStatus]("流程状态").
|
||||
Add(ProcinstActive, "执行中").
|
||||
Add(ProcinstCompleted, "完成").
|
||||
Add(ProcinstSuspended, "挂起").
|
||||
Add(ProcinstTerminated, "终止").
|
||||
Add(ProcinstCancelled, "取消")
|
||||
|
||||
type ProcinstBizStatus int8
|
||||
|
||||
const (
|
||||
ProcinstBizStatusWait ProcinstBizStatus = 1 // 待处理
|
||||
ProcinstBizStatusSuccess ProcinstBizStatus = 2 // 成功
|
||||
ProcinstBizStatusNo ProcinstBizStatus = -1 // 不处理
|
||||
ProcinstBizStatusFail ProcinstBizStatus = -2 // 失败
|
||||
)
|
||||
|
||||
//----------流程实例关联任务-----------
|
||||
|
||||
// 流程实例关联的审批节点任务
|
||||
type ProcinstTask struct {
|
||||
model.Model
|
||||
|
||||
ProcinstId uint64 `json:"procinstId"` // 流程实例id
|
||||
TaskKey string `json:"taskKey"` // 当前任务key
|
||||
TaskName string `json:"taskName"` // 当前任务名称
|
||||
Assignee string `json:"assignee"` // 分配到该任务的用户
|
||||
|
||||
Status ProcinstTaskStatus `json:"status"` // 状态
|
||||
Remark string `json:"remark"`
|
||||
EndTime *time.Time `json:"endTime"`
|
||||
Duration int64 `json:"duration"` // 持续时间(开始到结束)
|
||||
}
|
||||
|
||||
func (a *ProcinstTask) TableName() string {
|
||||
return "t_flow_procinst_task"
|
||||
}
|
||||
|
||||
// 设置流程任务终止结束的一些信息
|
||||
func (p *ProcinstTask) SetEnd() {
|
||||
nowTime := time.Now()
|
||||
p.EndTime = &nowTime
|
||||
p.Duration = int64(time.Since(*p.CreateTime).Seconds())
|
||||
}
|
||||
|
||||
type ProcinstTaskStatus int8
|
||||
|
||||
const (
|
||||
ProcinstTaskStatusProcess ProcinstTaskStatus = 1 // 处理中
|
||||
ProcinstTaskStatusPass ProcinstTaskStatus = 2 // 通过
|
||||
ProcinstTaskStatusReject ProcinstTaskStatus = -1 // 拒绝
|
||||
ProcinstTaskStatusBack ProcinstTaskStatus = -2 // 驳回
|
||||
ProcinstTaskStatusCanceled ProcinstTaskStatus = -3 // 取消
|
||||
)
|
||||
20
server/internal/flow/domain/entity/query.go
Normal file
20
server/internal/flow/domain/entity/query.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package entity
|
||||
|
||||
type ProcinstQuery struct {
|
||||
ProcdefId uint64 `json:"procdefId" form:"procdefId"` // 流程定义id
|
||||
ProcdefName string `json:"procdefName"` // 流程定义名称
|
||||
|
||||
BizType string `json:"bizType" form:"bizType"` // 业务类型
|
||||
BizKey string `json:"bizKey"` // 业务key
|
||||
Status ProcinstStatus `json:"status" form:"status"` // 状态
|
||||
|
||||
CreatorId uint64
|
||||
}
|
||||
|
||||
type ProcinstTaskQuery struct {
|
||||
ProcinstId uint64 `json:"procinstId"` // 流程实例id
|
||||
ProcinstName string `json:"procinstName"` // 流程实例名称
|
||||
BizType string `json:"bizType" form:"bizType"`
|
||||
Assignee string `json:"assignee"` // 分配到该任务的用户
|
||||
Status ProcinstTaskStatus `json:"status" form:"status"` // 状态
|
||||
}
|
||||
13
server/internal/flow/domain/repository/procdef.go
Normal file
13
server/internal/flow/domain/repository/procdef.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type Procdef interface {
|
||||
base.Repo[*entity.Procdef]
|
||||
|
||||
GetPageList(condition *entity.Procdef, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
}
|
||||
19
server/internal/flow/domain/repository/procinst.go
Normal file
19
server/internal/flow/domain/repository/procinst.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type Procinst interface {
|
||||
base.Repo[*entity.Procinst]
|
||||
|
||||
GetPageList(condition *entity.ProcinstQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
}
|
||||
|
||||
type ProcinstTask interface {
|
||||
base.Repo[*entity.ProcinstTask]
|
||||
|
||||
GetPageList(condition *entity.ProcinstTaskQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/ioc"
|
||||
)
|
||||
|
||||
func Init() {
|
||||
ioc.Register(newProcdefRepo(), ioc.WithComponentName("ProcdefRepo"))
|
||||
ioc.Register(newProcinstRepo(), ioc.WithComponentName("ProcinstRepo"))
|
||||
ioc.Register(newProcinstTaskRepo(), ioc.WithComponentName("ProcinstTaskRepo"))
|
||||
}
|
||||
24
server/internal/flow/infrastructure/persistence/procdef.go
Normal file
24
server/internal/flow/infrastructure/persistence/procdef.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/gormx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type procdefImpl struct {
|
||||
base.RepoImpl[*entity.Procdef]
|
||||
}
|
||||
|
||||
func newProcdefRepo() repository.Procdef {
|
||||
return &procdefImpl{base.RepoImpl[*entity.Procdef]{M: new(entity.Procdef)}}
|
||||
}
|
||||
|
||||
func (p *procdefImpl) GetPageList(condition *entity.Procdef, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
qd := gormx.NewQuery(new(entity.Procdef)).
|
||||
Like("name", condition.Name).
|
||||
Like("def_key", condition.DefKey)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
37
server/internal/flow/infrastructure/persistence/procinst.go
Normal file
37
server/internal/flow/infrastructure/persistence/procinst.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/gormx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type procinstImpl struct {
|
||||
base.RepoImpl[*entity.Procinst]
|
||||
}
|
||||
|
||||
func newProcinstRepo() repository.Procinst {
|
||||
return &procinstImpl{base.RepoImpl[*entity.Procinst]{M: new(entity.Procinst)}}
|
||||
}
|
||||
|
||||
func (p *procinstImpl) GetPageList(condition *entity.ProcinstQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
qd := gormx.NewQuery(new(entity.Procinst)).WithCondModel(condition)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
|
||||
//-----------procinst task--------------
|
||||
|
||||
type procinstTaskImpl struct {
|
||||
base.RepoImpl[*entity.ProcinstTask]
|
||||
}
|
||||
|
||||
func newProcinstTaskRepo() repository.ProcinstTask {
|
||||
return &procinstTaskImpl{base.RepoImpl[*entity.ProcinstTask]{M: new(entity.ProcinstTask)}}
|
||||
}
|
||||
|
||||
func (p *procinstTaskImpl) GetPageList(condition *entity.ProcinstTaskQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
qd := gormx.NewQuery(new(entity.ProcinstTask)).WithCondModel(condition)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
12
server/internal/flow/init/init.go
Normal file
12
server/internal/flow/init/init.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/flow/application"
|
||||
"mayfly-go/internal/flow/router"
|
||||
)
|
||||
|
||||
func init() {
|
||||
initialize.AddInitIocFunc(application.InitIoc)
|
||||
initialize.AddInitRouterFunc(router.Init)
|
||||
}
|
||||
30
server/internal/flow/router/procdef.go
Normal file
30
server/internal/flow/router/procdef.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/api"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ioc"
|
||||
"mayfly-go/pkg/req"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func InitProcdefouter(router *gin.RouterGroup) {
|
||||
p := new(api.Procdef)
|
||||
biz.ErrIsNil(ioc.Inject(p))
|
||||
|
||||
reqGroup := router.Group("/flow/procdefs")
|
||||
{
|
||||
reqs := [...]*req.Conf{
|
||||
req.NewGet("", p.GetProcdefPage),
|
||||
|
||||
req.NewGet("/:key", p.GetProcdef),
|
||||
|
||||
req.NewPost("", p.Save).Log(req.NewLogSave("流程定义-保存")).RequiredPermissionCode("flow:procdef:save"),
|
||||
|
||||
req.NewDelete(":id", p.Delete).Log(req.NewLogSave("流程定义-删除")).RequiredPermissionCode("flow:procdef:del"),
|
||||
}
|
||||
|
||||
req.BatchSetGroup(reqGroup, reqs[:])
|
||||
}
|
||||
}
|
||||
36
server/internal/flow/router/procinst.go
Normal file
36
server/internal/flow/router/procinst.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/flow/api"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/ioc"
|
||||
"mayfly-go/pkg/req"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func InitProcinstRouter(router *gin.RouterGroup) {
|
||||
p := new(api.Procinst)
|
||||
biz.ErrIsNil(ioc.Inject(p))
|
||||
|
||||
reqGroup := router.Group("/flow/procinsts")
|
||||
{
|
||||
reqs := [...]*req.Conf{
|
||||
req.NewGet("", p.GetProcinstPage),
|
||||
|
||||
req.NewGet("/:id", p.GetProcinstDetail),
|
||||
|
||||
req.NewPost("/:id/cancel", p.ProcinstCancel).Log(req.NewLogSave("流程-取消")),
|
||||
|
||||
req.NewGet("/tasks", p.GetTasks),
|
||||
|
||||
req.NewPost("/tasks/complete", p.CompleteTask).Log(req.NewLogSave("流程-任务完成")),
|
||||
|
||||
req.NewPost("/tasks/reject", p.RejectTask).Log(req.NewLogSave("流程-任务拒绝")),
|
||||
|
||||
req.NewPost("/tasks/back", p.BackTask).Log(req.NewLogSave("流程-任务驳回")),
|
||||
}
|
||||
|
||||
req.BatchSetGroup(reqGroup, reqs[:])
|
||||
}
|
||||
}
|
||||
8
server/internal/flow/router/router.go
Normal file
8
server/internal/flow/router/router.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package router
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func Init(router *gin.RouterGroup) {
|
||||
InitProcdefouter(router)
|
||||
InitProcinstRouter(router)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"mayfly-go/internal/machine/config"
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/model"
|
||||
@@ -43,14 +44,20 @@ func (m *Machine) Machines(rc *req.Ctx) {
|
||||
}
|
||||
condition.Codes = codes
|
||||
|
||||
res, err := m.MachineApp.GetMachineList(condition, pageParam, new([]*vo.MachineVO))
|
||||
var machinevos []*vo.MachineVO
|
||||
res, err := m.MachineApp.GetMachineList(condition, pageParam, &machinevos)
|
||||
biz.ErrIsNil(err)
|
||||
if res.Total == 0 {
|
||||
rc.ResData = res
|
||||
return
|
||||
}
|
||||
|
||||
for _, mv := range *res.List {
|
||||
// 填充标签信息
|
||||
m.TagApp.FillTagInfo(collx.ArrayMap(machinevos, func(mvo *vo.MachineVO) tagentity.ITagResource {
|
||||
return mvo
|
||||
})...)
|
||||
|
||||
for _, mv := range machinevos {
|
||||
if machineStats, err := m.MachineApp.GetMachineStats(mv.Id); err == nil {
|
||||
mv.Stat = collx.M{
|
||||
"cpuIdle": machineStats.CPU.Idle,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -12,6 +13,8 @@ type AuthCertBaseVO struct {
|
||||
}
|
||||
|
||||
type MachineVO struct {
|
||||
tagentity.ResourceTags
|
||||
|
||||
Id uint64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
@@ -35,6 +38,10 @@ type MachineVO struct {
|
||||
Stat map[string]any `json:"stat" gorm:"-"`
|
||||
}
|
||||
|
||||
func (m *MachineVO) GetCode() string {
|
||||
return m.Code
|
||||
}
|
||||
|
||||
type MachineScriptVO struct {
|
||||
Id *int64 `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
|
||||
@@ -67,6 +67,9 @@ func checkClientAvailability(interval time.Duration) {
|
||||
continue
|
||||
}
|
||||
cli := v.Value.(*Cli)
|
||||
if cli.Info == nil {
|
||||
continue
|
||||
}
|
||||
if _, _, err := cli.sshClient.Conn.SendRequest("ping", true, nil); err != nil {
|
||||
logx.Errorf("machine[%s] cache client is not available: %s", cli.Info.Name, err.Error())
|
||||
DeleteCli(cli.Info.Id)
|
||||
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"context"
|
||||
"mayfly-go/internal/common/consts"
|
||||
"mayfly-go/internal/mongo/api/form"
|
||||
"mayfly-go/internal/mongo/api/vo"
|
||||
"mayfly-go/internal/mongo/application"
|
||||
"mayfly-go/internal/mongo/domain/entity"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
@@ -36,8 +38,15 @@ func (m *Mongo) Mongos(rc *req.Ctx) {
|
||||
}
|
||||
queryCond.Codes = codes
|
||||
|
||||
res, err := m.MongoApp.GetPageList(queryCond, page, new([]entity.Mongo))
|
||||
var mongovos []*vo.Mongo
|
||||
res, err := m.MongoApp.GetPageList(queryCond, page, &mongovos)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
// 填充标签信息
|
||||
m.TagApp.FillTagInfo(collx.ArrayMap(mongovos, func(mvo *vo.Mongo) tagentity.ITagResource {
|
||||
return mvo
|
||||
})...)
|
||||
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
|
||||
20
server/internal/mongo/api/vo/mongo.go
Normal file
20
server/internal/mongo/api/vo/mongo.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type Mongo struct {
|
||||
model.Model
|
||||
tagentity.ResourceTags
|
||||
|
||||
Code string `orm:"column(code)" json:"code"`
|
||||
Name string `orm:"column(name)" json:"name"`
|
||||
Uri string `orm:"column(uri)" json:"uri"`
|
||||
SshTunnelMachineId int `orm:"column(ssh_tunnel_machine_id)" json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
}
|
||||
|
||||
func (m *Mongo) GetCode() string {
|
||||
return m.Code
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"mayfly-go/internal/redis/domain/entity"
|
||||
"mayfly-go/internal/redis/rdm"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
@@ -37,8 +38,15 @@ func (r *Redis) RedisList(rc *req.Ctx) {
|
||||
}
|
||||
queryCond.Codes = codes
|
||||
|
||||
res, err := r.RedisApp.GetPageList(queryCond, page, new([]vo.Redis))
|
||||
var redisvos []*vo.Redis
|
||||
res, err := r.RedisApp.GetPageList(queryCond, page, &redisvos)
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
// 填充标签信息
|
||||
r.TagApp.FillTagInfo(collx.ArrayMap(redisvos, func(rvo *vo.Redis) tagentity.ITagResource {
|
||||
return rvo
|
||||
})...)
|
||||
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package vo
|
||||
|
||||
import "time"
|
||||
import (
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Redis struct {
|
||||
tagentity.ResourceTags
|
||||
Id *int64 `json:"id"`
|
||||
Code *string `json:"code"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Db string `json:"db"`
|
||||
@@ -19,6 +23,10 @@ type Redis struct {
|
||||
ModifierId *int64 `json:"modifierId"`
|
||||
}
|
||||
|
||||
func (r *Redis) GetCode() string {
|
||||
return r.Code
|
||||
}
|
||||
|
||||
type Keys struct {
|
||||
Cursor map[string]uint64 `json:"cursor"`
|
||||
Keys []string `json:"keys"`
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/conv"
|
||||
"mayfly-go/pkg/utils/cryptox"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -119,13 +120,29 @@ func (a *Account) UpdateAccount(rc *req.Ctx) {
|
||||
|
||||
// @router /accounts [get]
|
||||
func (a *Account) Accounts(rc *req.Ctx) {
|
||||
condition := &entity.Account{}
|
||||
condition := &entity.AccountQuery{}
|
||||
condition.Username = rc.Query("username")
|
||||
condition.Name = rc.Query("name")
|
||||
res, err := a.AccountApp.GetPageList(condition, rc.GetPageParam(), new([]vo.AccountManageVO))
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (a *Account) SimpleAccounts(rc *req.Ctx) {
|
||||
condition := &entity.AccountQuery{}
|
||||
condition.Username = rc.Query("username")
|
||||
condition.Name = rc.Query("name")
|
||||
idsStr := rc.Query("ids")
|
||||
if idsStr != "" {
|
||||
condition.Ids = collx.ArrayMap[string, uint64](strings.Split(idsStr, ","), func(val string) uint64 {
|
||||
return uint64(conv.Str2Int(val, 0))
|
||||
})
|
||||
}
|
||||
res, err := a.AccountApp.GetPageList(condition, rc.GetPageParam(), new([]vo.SimpleAccountVO))
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// @router /accounts
|
||||
func (a *Account) SaveAccount(rc *req.Ctx) {
|
||||
form := &form.AccountCreateForm{}
|
||||
|
||||
@@ -15,6 +15,12 @@ type AccountManageVO struct {
|
||||
OtpSecret string `json:"otpSecret"`
|
||||
}
|
||||
|
||||
type SimpleAccountVO struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// 账号角色信息
|
||||
type AccountRoleVO struct {
|
||||
RoleId uint64 `json:"roleId"`
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
type Account interface {
|
||||
base.App[*entity.Account]
|
||||
|
||||
GetPageList(condition *entity.Account, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
GetPageList(condition *entity.AccountQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
|
||||
Create(ctx context.Context, account *entity.Account) error
|
||||
|
||||
@@ -34,7 +34,7 @@ func (a *accountAppImpl) InjectAccountRepo(repo repository.Account) {
|
||||
a.Repo = repo
|
||||
}
|
||||
|
||||
func (a *accountAppImpl) GetPageList(condition *entity.Account, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
func (a *accountAppImpl) GetPageList(condition *entity.AccountQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
return a.GetRepo().GetPageList(condition, pageParam, toEntity)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package entity
|
||||
|
||||
type AccountQuery struct {
|
||||
Ids []uint64 `json:"ids"`
|
||||
Name string `json:"name" form:"name"`
|
||||
Username string `json:"code" form:"code"`
|
||||
}
|
||||
|
||||
type SysLogQuery struct {
|
||||
CreatorId uint64 `json:"creatorId" form:"creatorId"`
|
||||
Type int8 `json:"type" form:"type"`
|
||||
|
||||
@@ -9,5 +9,5 @@ import (
|
||||
type Account interface {
|
||||
base.Repo[*entity.Account]
|
||||
|
||||
GetPageList(condition *entity.Account, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
GetPageList(condition *entity.AccountQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
|
||||
}
|
||||
|
||||
@@ -16,9 +16,10 @@ func newAccountRepo() repository.Account {
|
||||
return &AccountRepoImpl{base.RepoImpl[*entity.Account]{M: new(entity.Account)}}
|
||||
}
|
||||
|
||||
func (m *AccountRepoImpl) GetPageList(condition *entity.Account, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
func (m *AccountRepoImpl) GetPageList(condition *entity.AccountQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
qd := gormx.NewQuery(new(entity.Account)).
|
||||
Like("name", condition.Name).
|
||||
Like("username", condition.Username)
|
||||
Like("username", condition.Username).
|
||||
In("id", condition.Ids)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ func InitAccountRouter(router *gin.RouterGroup) {
|
||||
// 获取所有用户列表
|
||||
req.NewGet("", a.Accounts),
|
||||
|
||||
// 获取用户列表信息(只包含最基础信息)
|
||||
req.NewGet("/simple", a.SimpleAccounts),
|
||||
|
||||
req.NewPost("", a.SaveAccount).Log(req.NewLogSave("保存账号信息")).RequiredPermission(addAccountPermission),
|
||||
|
||||
req.NewPut("change-status/:id/:status", a.ChangeStatus).Log(req.NewLogSave("修改账号状态")).RequiredPermission(addAccountPermission),
|
||||
|
||||
@@ -47,6 +47,9 @@ type TagTree interface {
|
||||
|
||||
// 账号是否有权限访问该标签关联的资源信息
|
||||
CanAccess(accountId uint64, tagPath ...string) error
|
||||
|
||||
// 填充资源的标签信息
|
||||
FillTagInfo(resources ...entity.ITagResource)
|
||||
}
|
||||
|
||||
type tagTreeAppImpl struct {
|
||||
@@ -231,6 +234,26 @@ func (p *tagTreeAppImpl) CanAccess(accountId uint64, tagPath ...string) error {
|
||||
return errorx.NewBiz("您无权操作该资源")
|
||||
}
|
||||
|
||||
func (p *tagTreeAppImpl) FillTagInfo(resources ...entity.ITagResource) {
|
||||
if len(resources) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// 资源编号 -> 资源
|
||||
resourceCode2Resouce := collx.ArrayToMap(resources, func(rt entity.ITagResource) string {
|
||||
return rt.GetCode()
|
||||
})
|
||||
|
||||
// 获取所有资源code关联的标签列表信息
|
||||
var tagResources []*entity.TagResource
|
||||
p.tagResourceApp.ListByQuery(&entity.TagResourceQuery{ResourceCodes: collx.MapKeys(resourceCode2Resouce)}, &tagResources)
|
||||
|
||||
for _, tr := range tagResources {
|
||||
// 赋值标签信息
|
||||
resourceCode2Resouce[tr.ResourceCode].SetTagInfo(entity.ResourceTag{TagId: tr.TagId, TagPath: tr.TagPath})
|
||||
}
|
||||
}
|
||||
|
||||
func (p *tagTreeAppImpl) Delete(ctx context.Context, id uint64) error {
|
||||
accountId := contextx.GetLoginAccount(ctx).Id
|
||||
tag, err := p.GetById(new(entity.TagTree), id)
|
||||
|
||||
@@ -13,3 +13,35 @@ type TagResource struct {
|
||||
ResourceCode string `json:"resourceCode"` // 资源标识
|
||||
ResourceType int8 `json:"resourceType"` // 资源类型
|
||||
}
|
||||
|
||||
// 标签接口资源,如果要实现资源结构体填充标签信息,则资源结构体需要实现该接口
|
||||
type ITagResource interface {
|
||||
// 获取资源code
|
||||
GetCode() string
|
||||
|
||||
// 赋值标签基本信息
|
||||
SetTagInfo(rt ResourceTag)
|
||||
}
|
||||
|
||||
// 资源关联的标签信息
|
||||
type ResourceTag struct {
|
||||
TagId uint64 `json:"tagId" gorm:"-"`
|
||||
TagPath string `json:"tagPath" gorm:"-"` // 标签路径
|
||||
}
|
||||
|
||||
func (r *ResourceTag) SetTagInfo(rt ResourceTag) {
|
||||
r.TagId = rt.TagId
|
||||
r.TagPath = rt.TagPath
|
||||
}
|
||||
|
||||
// 资源标签列表
|
||||
type ResourceTags struct {
|
||||
Tags []ResourceTag `json:"tags" gorm:"-"`
|
||||
}
|
||||
|
||||
func (r *ResourceTags) SetTagInfo(rt ResourceTag) {
|
||||
if r.Tags == nil {
|
||||
r.Tags = make([]ResourceTag, 0)
|
||||
}
|
||||
r.Tags = append(r.Tags, rt)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
_ "mayfly-go/internal/auth/init"
|
||||
_ "mayfly-go/internal/common/init"
|
||||
_ "mayfly-go/internal/db/init"
|
||||
_ "mayfly-go/internal/flow/init"
|
||||
_ "mayfly-go/internal/machine/init"
|
||||
_ "mayfly-go/internal/mongo/init"
|
||||
_ "mayfly-go/internal/msg/init"
|
||||
|
||||
@@ -4,7 +4,7 @@ import "fmt"
|
||||
|
||||
const (
|
||||
AppName = "mayfly-go"
|
||||
Version = "v1.7.3"
|
||||
Version = "v1.7.4"
|
||||
)
|
||||
|
||||
func GetAppInfo() string {
|
||||
|
||||
@@ -128,3 +128,18 @@ func ArrayRemoveFunc[T any](arr []T, isDeleteFunc func(T) bool) []T {
|
||||
}
|
||||
return newArr
|
||||
}
|
||||
|
||||
// 数组元素去重
|
||||
func ArrayDeduplicate[T comparable](arr []T) []T {
|
||||
encountered := map[T]bool{}
|
||||
result := []T{}
|
||||
|
||||
for v := range arr {
|
||||
if !encountered[arr[v]] {
|
||||
encountered[arr[v]] = true
|
||||
result = append(result, arr[v])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// 逻辑空字符串(由于gorm更新结构体只更新非零值,所以使用该值最为逻辑空字符串,方便更新结构体)
|
||||
const LogicEmptyStr = "-"
|
||||
|
||||
// 是否为逻辑上空字符串
|
||||
func IsLogicEmpty(str string) bool {
|
||||
return str == "" || str == LogicEmptyStr
|
||||
}
|
||||
|
||||
// 可判断中文
|
||||
func Len(str string) int {
|
||||
return len([]rune(str))
|
||||
|
||||
@@ -635,3 +635,26 @@ func Case2Camel(name string) string {
|
||||
name = strings.Title(name)
|
||||
return strings.Replace(name, " ", "", -1)
|
||||
}
|
||||
|
||||
// 结构体转为map
|
||||
func ToMap(input any) map[string]any {
|
||||
result := make(map[string]any)
|
||||
v := Indirect(reflect.ValueOf(input))
|
||||
if v.Kind() != reflect.Struct {
|
||||
return result
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
zeroValue := reflect.Zero(field.Type()).Interface()
|
||||
fieldValue := field.Interface()
|
||||
|
||||
if !reflect.DeepEqual(fieldValue, zeroValue) {
|
||||
result[v.Type().Field(i).Name] = fieldValue
|
||||
} else {
|
||||
result[v.Type().Field(i).Name] = zeroValue
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type Src struct {
|
||||
Id *int64 `json:"id"`
|
||||
Id int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
CreateTime time.Time `json:"time"`
|
||||
UpdateTime time.Time
|
||||
UpdateTime *time.Time
|
||||
Inner *SrcInner
|
||||
}
|
||||
|
||||
@@ -194,3 +194,12 @@ func TestTemplateResolve(t *testing.T) {
|
||||
fmt.Println(resolve)
|
||||
|
||||
}
|
||||
|
||||
func TestToMap(t *testing.T) {
|
||||
mapRes := ToMap(&Src{
|
||||
Id: 0,
|
||||
Username: "哈哈哈",
|
||||
CreateTime: time.Now(),
|
||||
})
|
||||
fmt.Println(mapRes)
|
||||
}
|
||||
|
||||
@@ -836,6 +836,13 @@ INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight,
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES (155, 150, 'Jra0n7De/PigmSGVg/', 2, 1, '日志', 'db:sync:log', 1704266866, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2024-01-03 15:27:47', '2024-01-03 15:27:47', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES (160, 49, 'dbms23ax/xleaiec2/3NUXQFIO/', 2, 1, '数据库备份', 'db:backup', 1705973876, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:37:56', '2024-01-23 09:37:56', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES (161, 49, 'dbms23ax/xleaiec2/ghErkTdb/', 2, 1, '数据库恢复', 'db:restore', 1705973909, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:38:29', '2024-01-23 09:38:29', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208354, 1708911264, '6egfEVYr/fw0Hhvye/b4cNf3iq/', 2, 1, '删除流程', 'flow:procdef:del', 1709208354, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:54', '2024-02-29 20:05:54', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208339, 1708911264, '6egfEVYr/fw0Hhvye/r9ZMTHqC/', 2, 1, '保存流程', 'flow:procdef:save', 1709208339, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:40', '2024-02-29 20:05:40', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709103180, 1708910975, '6egfEVYr/oNCIbynR/', 1, 1, '我的流程', 'procinsts', 1708911263, '{"component":"flow/ProcinstList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstList"}', 1, 'admin', 1, 'admin', '2024-02-28 14:53:00', '2024-02-29 20:36:07', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709045735, 1708910975, '6egfEVYr/3r3hHEub/', 1, 1, '我的任务', 'procinst-tasks', 1708911263, '{"component":"flow/ProcinstTaskList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstTaskList"}', 1, 'admin', 1, 'admin', '2024-02-27 22:55:35', '2024-02-27 22:56:35', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708911264, 1708910975, '6egfEVYr/fw0Hhvye/', 1, 1, '流程定义', 'procdefs', 1708911264, '{"component":"flow/ProcdefList","icon":"List","isKeepAlive":true,"routeName":"ProcdefList"}', 1, 'admin', 1, 'admin', '2024-02-26 09:34:24', '2024-02-27 22:54:32', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, type, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708910975, 0, '6egfEVYr/', 1, 1, '工单流程', '/flow', 60000000, '{"icon":"List","isKeepAlive":true,"routeName":"flow"}', 1, 'admin', 1, 'admin', '2024-02-26 09:29:36', '2024-02-26 15:37:52', 0, NULL);
|
||||
|
||||
|
||||
-- Table: t_sys_role
|
||||
CREATE TABLE IF NOT EXISTS "t_sys_role" (
|
||||
|
||||
@@ -34,21 +34,23 @@ CREATE TABLE `t_db_instance` (
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `t_db`;
|
||||
CREATE TABLE `t_db` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'code',
|
||||
`name` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库实例名称',
|
||||
`database` varchar(3000) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库,空格分割多个数据库',
|
||||
`remark` varchar(125) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注,描述等',
|
||||
`instance_id` bigint(20) NOT NULL COMMENT '数据库实例 ID',
|
||||
`create_time` datetime DEFAULT NULL,
|
||||
`creator_id` bigint(20) DEFAULT NULL,
|
||||
`creator` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`update_time` datetime DEFAULT NULL,
|
||||
`modifier_id` bigint(20) DEFAULT NULL,
|
||||
`modifier` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`is_deleted` tinyint(8) NOT NULL DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`database` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`remark` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`instance_id` bigint unsigned NOT NULL,
|
||||
`flow_procdef_key` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '审批流-流程定义key(有值则说明关键操作需要进行审批执行)',
|
||||
`create_time` datetime DEFAULT NULL,
|
||||
`creator_id` bigint DEFAULT NULL,
|
||||
`creator` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`update_time` datetime DEFAULT NULL,
|
||||
`modifier_id` bigint DEFAULT NULL,
|
||||
`modifier` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_code` (`code`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据库资源信息表';
|
||||
|
||||
-- ----------------------------
|
||||
@@ -86,6 +88,9 @@ CREATE TABLE `t_db_sql_exec` (
|
||||
`sql` varchar(5000) NOT NULL COMMENT '执行sql',
|
||||
`old_value` varchar(5000) DEFAULT NULL COMMENT '操作前旧值',
|
||||
`remark` varchar(128) DEFAULT NULL COMMENT '备注',
|
||||
`status` tinyint DEFAULT NULL COMMENT '执行状态',
|
||||
`flow_biz_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '流程关联的业务key',
|
||||
`res` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '执行结果',
|
||||
`create_time` datetime NOT NULL,
|
||||
`creator` varchar(36) NOT NULL,
|
||||
`creator_id` bigint(20) NOT NULL,
|
||||
@@ -94,7 +99,8 @@ CREATE TABLE `t_db_sql_exec` (
|
||||
`modifier_id` bigint(20) NOT NULL,
|
||||
`is_deleted` tinyint(8) NOT NULL DEFAULT 0,
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_flow_biz_key` (`flow_biz_key`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据库sql执行记录表';
|
||||
|
||||
-- ----------------------------
|
||||
@@ -797,6 +803,13 @@ INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(150, 36, 'Jra0n7De/', 1, 1, '数据同步', 'sync', 1693040707, '{"component":"ops/db/SyncTaskList","icon":"Coin","isKeepAlive":true,"routeName":"SyncTaskList"}', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-22 09:51:34', '2023-12-27 10:16:57', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(160, 49, 'dbms23ax/xleaiec2/3NUXQFIO/', 2, 1, '数据库备份', 'db:backup', 1705973876, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:37:56', '2024-01-23 09:37:56', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(161, 49, 'dbms23ax/xleaiec2/ghErkTdb/', 2, 1, '数据库恢复', 'db:restore', 1705973909, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:38:29', '2024-01-23 09:38:29', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208354, 1708911264, '6egfEVYr/fw0Hhvye/b4cNf3iq/', 2, 1, '删除流程', 'flow:procdef:del', 1709208354, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:54', '2024-02-29 20:05:54', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208339, 1708911264, '6egfEVYr/fw0Hhvye/r9ZMTHqC/', 2, 1, '保存流程', 'flow:procdef:save', 1709208339, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:40', '2024-02-29 20:05:40', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709103180, 1708910975, '6egfEVYr/oNCIbynR/', 1, 1, '我的流程', 'procinsts', 1708911263, '{"component":"flow/ProcinstList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstList"}', 1, 'admin', 1, 'admin', '2024-02-28 14:53:00', '2024-02-29 20:36:07', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709045735, 1708910975, '6egfEVYr/3r3hHEub/', 1, 1, '我的任务', 'procinst-tasks', 1708911263, '{"component":"flow/ProcinstTaskList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstTaskList"}', 1, 'admin', 1, 'admin', '2024-02-27 22:55:35', '2024-02-27 22:56:35', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708911264, 1708910975, '6egfEVYr/fw0Hhvye/', 1, 1, '流程定义', 'procdefs', 1708911264, '{"component":"flow/ProcdefList","icon":"List","isKeepAlive":true,"routeName":"ProcdefList"}', 1, 'admin', 1, 'admin', '2024-02-26 09:34:24', '2024-02-27 22:54:32', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708910975, 0, '6egfEVYr/', 1, 1, '工单流程', '/flow', 60000000, '{"icon":"List","isKeepAlive":true,"routeName":"flow"}', 1, 'admin', 1, 'admin', '2024-02-26 09:29:36', '2024-02-26 15:37:52', 0, NULL);
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
@@ -1002,4 +1015,73 @@ BEGIN;
|
||||
INSERT INTO `t_team_member` VALUES (7, 3, 1, 'admin', '2022-10-26 20:04:36', 1, 'admin', '2022-10-26 20:04:36', 1, 'admin', 0, NULL);
|
||||
COMMIT;
|
||||
|
||||
DROP TABLE IF EXISTS `t_flow_procdef`;
|
||||
-- 工单流程相关表
|
||||
CREATE TABLE `t_flow_procdef` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`def_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义key',
|
||||
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '流程名称',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`tasks` varchar(3000) COLLATE utf8mb4_bin NOT NULL COMMENT '审批节点任务信息',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`create_time` datetime NOT NULL,
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程定义';
|
||||
|
||||
DROP TABLE IF EXISTS `t_flow_procinst`;
|
||||
CREATE TABLE `t_flow_procinst` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`procdef_id` bigint NOT NULL COMMENT '流程定义id',
|
||||
`procdef_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义名称',
|
||||
`task_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '当前任务key',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`biz_type` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '关联业务类型',
|
||||
`biz_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '关联业务key',
|
||||
`biz_status` tinyint DEFAULT NULL COMMENT '业务状态',
|
||||
`biz_handle_res` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '关联的业务处理结果',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration` bigint DEFAULT NULL COMMENT '流程持续时间(开始到结束)',
|
||||
`create_time` datetime NOT NULL COMMENT '流程发起时间',
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '流程发起人',
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_procdef_id` (`procdef_id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程实例(根据流程定义开启一个流程)';
|
||||
|
||||
DROP TABLE IF EXISTS `t_flow_procinst_task`;
|
||||
CREATE TABLE `t_flow_procinst_task` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`procinst_id` bigint NOT NULL COMMENT '流程实例id',
|
||||
`task_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '任务key',
|
||||
`task_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务名称',
|
||||
`assignee` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '分配到该任务的用户',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration` bigint DEFAULT NULL COMMENT '任务持续时间(开始到结束)',
|
||||
`create_time` datetime NOT NULL COMMENT '任务开始时间',
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_procinst_id` (`procinst_id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程实例任务';
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
87
server/resources/script/sql/v1.7/v1.7.4.sql
Normal file
87
server/resources/script/sql/v1.7/v1.7.4.sql
Normal file
@@ -0,0 +1,87 @@
|
||||
begin;
|
||||
|
||||
-- 新增工单流程相关菜单
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208354, 1708911264, '6egfEVYr/fw0Hhvye/b4cNf3iq/', 2, 1, '删除流程', 'flow:procdef:del', 1709208354, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:54', '2024-02-29 20:05:54', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208339, 1708911264, '6egfEVYr/fw0Hhvye/r9ZMTHqC/', 2, 1, '保存流程', 'flow:procdef:save', 1709208339, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:40', '2024-02-29 20:05:40', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709103180, 1708910975, '6egfEVYr/oNCIbynR/', 1, 1, '我的流程', 'procinsts', 1708911263, '{"component":"flow/ProcinstList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstList"}', 1, 'admin', 1, 'admin', '2024-02-28 14:53:00', '2024-02-29 20:36:07', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709045735, 1708910975, '6egfEVYr/3r3hHEub/', 1, 1, '我的任务', 'procinst-tasks', 1708911263, '{"component":"flow/ProcinstTaskList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstTaskList"}', 1, 'admin', 1, 'admin', '2024-02-27 22:55:35', '2024-02-27 22:56:35', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708911264, 1708910975, '6egfEVYr/fw0Hhvye/', 1, 1, '流程定义', 'procdefs', 1708911264, '{"component":"flow/ProcdefList","icon":"List","isKeepAlive":true,"routeName":"ProcdefList"}', 1, 'admin', 1, 'admin', '2024-02-26 09:34:24', '2024-02-27 22:54:32', 0, NULL);
|
||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1708910975, 0, '6egfEVYr/', 1, 1, '工单流程', '/flow', 60000000, '{"icon":"List","isKeepAlive":true,"routeName":"flow"}', 1, 'admin', 1, 'admin', '2024-02-26 09:29:36', '2024-02-26 15:37:52', 0, NULL);
|
||||
|
||||
-- 工单流程相关表
|
||||
CREATE TABLE `t_flow_procdef` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`def_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义key',
|
||||
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '流程名称',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`tasks` varchar(3000) COLLATE utf8mb4_bin NOT NULL COMMENT '审批节点任务信息',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`create_time` datetime NOT NULL,
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程定义';
|
||||
|
||||
CREATE TABLE `t_flow_procinst` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`procdef_id` bigint NOT NULL COMMENT '流程定义id',
|
||||
`procdef_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义名称',
|
||||
`task_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '当前任务key',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`biz_type` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '关联业务类型',
|
||||
`biz_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '关联业务key',
|
||||
`biz_status` tinyint DEFAULT NULL COMMENT '业务状态',
|
||||
`biz_handle_res` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '关联的业务处理结果',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration` bigint DEFAULT NULL COMMENT '流程持续时间(开始到结束)',
|
||||
`create_time` datetime NOT NULL COMMENT '流程发起时间',
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '流程发起人',
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_procdef_id` (`procdef_id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程实例(根据流程定义开启一个流程)';
|
||||
|
||||
CREATE TABLE `t_flow_procinst_task` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`procinst_id` bigint NOT NULL COMMENT '流程实例id',
|
||||
`task_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '任务key',
|
||||
`task_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '任务名称',
|
||||
`assignee` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '分配到该任务的用户',
|
||||
`status` tinyint DEFAULT NULL COMMENT '状态',
|
||||
`remark` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||
`duration` bigint DEFAULT NULL COMMENT '任务持续时间(开始到结束)',
|
||||
`create_time` datetime NOT NULL COMMENT '任务开始时间',
|
||||
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`creator_id` bigint NOT NULL,
|
||||
`update_time` datetime NOT NULL,
|
||||
`modifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`modifier_id` bigint NOT NULL,
|
||||
`is_deleted` tinyint DEFAULT '0',
|
||||
`delete_time` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_procinst_id` (`procinst_id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='流程-流程实例任务';
|
||||
|
||||
-- 新增工单流程相关字段
|
||||
ALTER TABLE t_db_sql_exec ADD status tinyint NULL COMMENT '执行状态';
|
||||
ALTER TABLE t_db_sql_exec ADD flow_biz_key varchar(64) NULL COMMENT '工单流程定义key';
|
||||
ALTER TABLE t_db_sql_exec ADD res varchar(1000) NULL COMMENT '执行结果';
|
||||
|
||||
ALTER TABLE t_db ADD flow_procdef_key varchar(64) NULL COMMENT '审批流-流程定义key(有值则说明关键操作需要进行审批执行)';
|
||||
|
||||
-- 历史执行记录调整为成功状态
|
||||
UPDATE t_db_sql_exec SET status = 2
|
||||
|
||||
commit;
|
||||
Reference in New Issue
Block a user