备份代码
This commit is contained in:
parent
903cf7f516
commit
1dfc2f9245
|
@ -8,4 +8,7 @@ const (
|
||||||
CreatorKey = "CreatorKey"
|
CreatorKey = "CreatorKey"
|
||||||
ApproverKey = "ApproverKey"
|
ApproverKey = "ApproverKey"
|
||||||
ApplicantKey = "ApplicantKey"
|
ApplicantKey = "ApplicantKey"
|
||||||
|
|
||||||
|
TenantKey = "TenantKey"
|
||||||
|
AssociateKey = "AssociateKey"
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,9 +17,13 @@ func RegisterRoutes(r *gin.Engine) error {
|
||||||
{
|
{
|
||||||
instancesGroup.POST("/create", api.InstancesCreate)
|
instancesGroup.POST("/create", api.InstancesCreate)
|
||||||
instancesGroup.POST("/start", api.InstancesStart)
|
instancesGroup.POST("/start", api.InstancesStart)
|
||||||
|
instancesGroup.POST("/start/rule", api.InstancesStartRule)
|
||||||
stepsGroup := instancesGroup.Group("/steps")
|
stepsGroup := instancesGroup.Group("/steps")
|
||||||
{
|
{
|
||||||
stepsGroup.POST("/add", api.InstancesStepsAdd)
|
stepsGroup.POST("/add", api.InstancesStepsAdd)
|
||||||
|
stepsGroup.POST("/approve", api.InstancesStepsApprove)
|
||||||
|
stepsGroup.POST("/reject", api.InstancesStepsReject)
|
||||||
|
stepsGroup.POST("/cancel", api.InstancesStepsCancel)
|
||||||
stepsGroup.POST("/update", api.InstancesStepsUpdate)
|
stepsGroup.POST("/update", api.InstancesStepsUpdate)
|
||||||
stepsGroup.POST("/revert", api.InstancesStepsRevert)
|
stepsGroup.POST("/revert", api.InstancesStepsRevert)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +34,5 @@ func RegisterRoutes(r *gin.Engine) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ type InstancesCreateParam struct {
|
||||||
FlowID int64 `json:"flow_id"`
|
FlowID int64 `json:"flow_id"`
|
||||||
ApplicantKey string `json:"applicant_key"` //申请人ID
|
ApplicantKey string `json:"applicant_key"` //申请人ID
|
||||||
CreatorKey string `json:"creator_key"`
|
CreatorKey string `json:"creator_key"`
|
||||||
|
AssociateKey string `json:"associate_key"`
|
||||||
|
TenantKey string `json:"tenant_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstancesCreate handler
|
// InstancesCreate handler
|
||||||
|
@ -33,6 +35,13 @@ func (api *FlowInstanceApi) InstancesCreate(c *gin.Context) {
|
||||||
data := make(map[string]interface{})
|
data := make(map[string]interface{})
|
||||||
data[base.ApplicantKey] = param.ApplicantKey
|
data[base.ApplicantKey] = param.ApplicantKey
|
||||||
data[base.CreatorKey] = param.CreatorKey
|
data[base.CreatorKey] = param.CreatorKey
|
||||||
|
|
||||||
|
if param.AssociateKey != "" {
|
||||||
|
data[base.AssociateKey] = param.AssociateKey
|
||||||
|
}
|
||||||
|
if param.TenantKey != "" {
|
||||||
|
data[base.TenantKey] = param.TenantKey
|
||||||
|
}
|
||||||
flow, err := definitionService.GetFlow(c, param.FlowID)
|
flow, err := definitionService.GetFlow(c, param.FlowID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.FailWithErr(c, err)
|
res.FailWithErr(c, err)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package flow_instance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/http/base/res"
|
||||||
|
"approveflow/app/provider/flow_instance"
|
||||||
|
"approveflow/app/utils"
|
||||||
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstancesStartRuleParam struct {
|
||||||
|
InstanceID int64 `json:"instance_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstancesStartRule handler
|
||||||
|
// @Summary 启动审批流自动规则
|
||||||
|
// @Description 启动审批流自动规则
|
||||||
|
// @ID instances-start-rule
|
||||||
|
// @Tags flow-instances
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param InstancesStartRuleParam body InstancesStartRuleParam true "启动实例ID"
|
||||||
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
|
// @Router /instances/start/rule [post]
|
||||||
|
func (api *FlowInstanceApi) InstancesStartRule(context *gin.Context) {
|
||||||
|
param := utils.QuickBind[InstancesStartParam](context)
|
||||||
|
instanceService := context.MustMake(flow_instance.FlowInstanceKey).(flow_instance.Service)
|
||||||
|
_, err := instanceService.StartInstanceRule(context, param.InstanceID)
|
||||||
|
if err != nil {
|
||||||
|
res.FailWithErr(context, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(context)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package flow_instance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/http/base/res"
|
||||||
|
"approveflow/app/provider/flow_instance"
|
||||||
|
"approveflow/app/utils"
|
||||||
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstancesStepsApproveParam struct {
|
||||||
|
InstanceID int64 `json:"instance_id"`
|
||||||
|
StepID int64 `json:"step_id"`
|
||||||
|
Comments string `json:"comments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstancesStepsApprove handler
|
||||||
|
// @Summary 审批通过
|
||||||
|
// @Description 根据实例号和节点号通过审批
|
||||||
|
// @ID instances-steps-approve
|
||||||
|
// @Tags flow-instances
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param InstancesStepsApproveParam body InstancesStepsApproveParam true "输入参数描述"
|
||||||
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
|
// @Router /instances/steps/approve [post]
|
||||||
|
func (api *FlowInstanceApi) InstancesStepsApprove(context *gin.Context) {
|
||||||
|
param := utils.QuickBind[InstancesStepsApproveParam](context)
|
||||||
|
instanceService := context.MustMake(flow_instance.FlowInstanceKey).(flow_instance.Service)
|
||||||
|
err := instanceService.ApproveStep(context, param.InstanceID, param.StepID, param.Comments)
|
||||||
|
if err != nil {
|
||||||
|
res.FailWithErr(context, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(context)
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package flow_instance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/http/base/res"
|
||||||
|
"approveflow/app/provider/flow_instance"
|
||||||
|
"approveflow/app/utils"
|
||||||
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstancesStepsCancelParam struct {
|
||||||
|
InstanceID int64 `json:"instance_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstancesStepsCancel handler
|
||||||
|
// @Summary 审批取消
|
||||||
|
// @Description 根据实例号取消审批
|
||||||
|
// @ID instances-steps-cancel
|
||||||
|
// @Tags flow-instances
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param InstancesStepsCancelParam body InstancesStepsCancelParam true "审批取消参数"
|
||||||
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
|
// @Router /instances/steps/cancel [post]
|
||||||
|
func (api *FlowInstanceApi) InstancesStepsCancel(context *gin.Context) {
|
||||||
|
param := utils.QuickBind[InstancesStepsCancelParam](context)
|
||||||
|
instanceService := context.MustMake(flow_instance.FlowInstanceKey).(flow_instance.Service)
|
||||||
|
err := instanceService.CancelInstance(context, param.InstanceID)
|
||||||
|
if err != nil {
|
||||||
|
res.FailWithErr(context, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(context)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package flow_instance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/http/base/res"
|
||||||
|
"approveflow/app/provider/flow_instance"
|
||||||
|
"approveflow/app/utils"
|
||||||
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InstancesStepsRejectParam struct {
|
||||||
|
InstanceID int64 `json:"instance_id"`
|
||||||
|
StepID int64 `json:"step_id"`
|
||||||
|
Comments string `json:"comments"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstancesStepsReject handler
|
||||||
|
// @Summary 审批驳回
|
||||||
|
// @Description 根据实例号和节点号驳回审批
|
||||||
|
// @ID instances-steps-reject
|
||||||
|
// @Tags flow-instances
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param InstancesStepsRejectParam body InstancesStepsRejectParam true "驳回参数"
|
||||||
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
|
// @Router /instances/steps/reject [post]
|
||||||
|
func (api *FlowInstanceApi) InstancesStepsReject(context *gin.Context) {
|
||||||
|
param := utils.QuickBind[InstancesStepsRejectParam](context)
|
||||||
|
instanceService := context.MustMake(flow_instance.FlowInstanceKey).(flow_instance.Service)
|
||||||
|
err := instanceService.RejectStep(context, param.InstanceID, param.StepID, param.Comments)
|
||||||
|
if err != nil {
|
||||||
|
res.FailWithErr(context, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Success(context)
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ type ApprovalInstanceDTO struct {
|
||||||
CurrentStepIDs []*CurrentStepDTO `json:"current_step_ids"` // 当前步骤ID
|
CurrentStepIDs []*CurrentStepDTO `json:"current_step_ids"` // 当前步骤ID
|
||||||
Steps []*InstanceStepDTO `json:"steps"` // 实例步骤
|
Steps []*InstanceStepDTO `json:"steps"` // 实例步骤
|
||||||
DynamicPathConfigs []*DynamicPathConfigDTO `json:"dynamic_path_configs"` // 动态路径配置,自定义,不直接存储
|
DynamicPathConfigs []*DynamicPathConfigDTO `json:"dynamic_path_configs"` // 动态路径配置,自定义,不直接存储
|
||||||
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CurrentStepDTO struct {
|
type CurrentStepDTO struct {
|
||||||
|
@ -25,6 +26,7 @@ type InstanceStepDTO struct {
|
||||||
ApproverComments string `json:"approver_comments"` // 审批意见
|
ApproverComments string `json:"approver_comments"` // 审批意见
|
||||||
IsDynamic bool `json:"is_dynamic"` // 是否为动态步骤
|
IsDynamic bool `json:"is_dynamic"` // 是否为动态步骤
|
||||||
Records []*ApprovalRecordDTO `json:"records"` // 审批记录
|
Records []*ApprovalRecordDTO `json:"records"` // 审批记录
|
||||||
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApprovalRecordDTO struct {
|
type ApprovalRecordDTO struct {
|
||||||
|
@ -34,6 +36,7 @@ type ApprovalRecordDTO struct {
|
||||||
Status string `json:"status"` // 审批状态
|
Status string `json:"status"` // 审批状态
|
||||||
Comments string `json:"comments"` // 审批意见
|
Comments string `json:"comments"` // 审批意见
|
||||||
IsTimeout bool `json:"is_timeout"` // 是否超时
|
IsTimeout bool `json:"is_timeout"` // 是否超时
|
||||||
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DynamicPathConfigDTO struct {
|
type DynamicPathConfigDTO struct {
|
||||||
|
@ -43,4 +46,5 @@ type DynamicPathConfigDTO struct {
|
||||||
ToStepID int64 `json:"to_step_id"` // 目标步骤ID
|
ToStepID int64 `json:"to_step_id"` // 目标步骤ID
|
||||||
IsParallel bool `json:"is_parallel"` // 是否并行
|
IsParallel bool `json:"is_parallel"` // 是否并行
|
||||||
Priority int `json:"priority"` // 路径优先级
|
Priority int `json:"priority"` // 路径优先级
|
||||||
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ import (
|
||||||
func MapApprovalInstanceToDTOBatch(approvalInstances []*instanceModel.ApprovalInstance) ([]*ApprovalInstanceDTO, error) {
|
func MapApprovalInstanceToDTOBatch(approvalInstances []*instanceModel.ApprovalInstance) ([]*ApprovalInstanceDTO, error) {
|
||||||
res := make([]*ApprovalInstanceDTO, 0, len(approvalInstances))
|
res := make([]*ApprovalInstanceDTO, 0, len(approvalInstances))
|
||||||
for _, instance := range approvalInstances {
|
for _, instance := range approvalInstances {
|
||||||
|
for _, step := range instance.Steps {
|
||||||
|
step.Status = step.GetStatus()
|
||||||
|
}
|
||||||
dto, err := MapApprovalInstanceToDTO(instance)
|
dto, err := MapApprovalInstanceToDTO(instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -21,6 +24,10 @@ func MapApprovalInstanceToDTO(approvalInstance *instanceModel.ApprovalInstance)
|
||||||
// 创建目标 ApprovalInstanceDTO 对象
|
// 创建目标 ApprovalInstanceDTO 对象
|
||||||
approvalInstanceDTO := &ApprovalInstanceDTO{}
|
approvalInstanceDTO := &ApprovalInstanceDTO{}
|
||||||
|
|
||||||
|
for _, step := range approvalInstance.Steps {
|
||||||
|
step.Status = step.GetStatus()
|
||||||
|
}
|
||||||
|
|
||||||
// 使用 Convert 方法将 实体对象 转换为 DTO
|
// 使用 Convert 方法将 实体对象 转换为 DTO
|
||||||
if err := utils.Convert(approvalInstance, approvalInstanceDTO); err != nil {
|
if err := utils.Convert(approvalInstance, approvalInstanceDTO); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -408,6 +408,47 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/instances/start/rule": {
|
||||||
|
"post": {
|
||||||
|
"description": "启动审批流自动规则",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "启动审批流自动规则",
|
||||||
|
"operationId": "instances-start-rule",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "启动实例ID",
|
||||||
|
"name": "InstancesStartRuleParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStartRuleParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/instances/steps/add": {
|
"/instances/steps/add": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "输入你的接口总结详情",
|
"description": "输入你的接口总结详情",
|
||||||
|
@ -449,6 +490,129 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/instances/steps/approve": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号和节点号通过审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批通过",
|
||||||
|
"operationId": "instances-steps-approve",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsApproveParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsApproveParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/cancel": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号取消审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批取消",
|
||||||
|
"operationId": "instances-steps-cancel",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "审批取消参数",
|
||||||
|
"name": "InstancesStepsCancelParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsCancelParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/reject": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号和节点号驳回审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批驳回",
|
||||||
|
"operationId": "instances-steps-reject",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "驳回参数",
|
||||||
|
"name": "InstancesStepsRejectParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsRejectParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/instances/steps/revert": {
|
"/instances/steps/revert": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "输入你的接口总结详情",
|
"description": "输入你的接口总结详情",
|
||||||
|
@ -673,6 +837,9 @@ const docTemplate = `{
|
||||||
"description": "主键ID",
|
"description": "主键ID",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "审批状态",
|
"description": "审批状态",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -709,6 +876,9 @@ const docTemplate = `{
|
||||||
"description": "是否超时",
|
"description": "是否超时",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "审批状态",
|
"description": "审批状态",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -745,6 +915,9 @@ const docTemplate = `{
|
||||||
"description": "是否并行",
|
"description": "是否并行",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"description": "路径优先级",
|
"description": "路径优先级",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -778,6 +951,9 @@ const docTemplate = `{
|
||||||
"description": "是否为动态步骤",
|
"description": "是否为动态步骤",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"records": {
|
"records": {
|
||||||
"description": "审批记录",
|
"description": "审批记录",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -839,9 +1015,53 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flow_instance.InstancesStartRuleParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"flow_instance.InstancesStepsAddParam": {
|
"flow_instance.InstancesStepsAddParam": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"flow_instance.InstancesStepsApproveParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"comments": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsCancelParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsRejectParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"comments": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"flow_instance.InstancesStepsRevertParam": {
|
"flow_instance.InstancesStepsRevertParam": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
|
|
@ -401,6 +401,47 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/instances/start/rule": {
|
||||||
|
"post": {
|
||||||
|
"description": "启动审批流自动规则",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "启动审批流自动规则",
|
||||||
|
"operationId": "instances-start-rule",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "启动实例ID",
|
||||||
|
"name": "InstancesStartRuleParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStartRuleParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/instances/steps/add": {
|
"/instances/steps/add": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "输入你的接口总结详情",
|
"description": "输入你的接口总结详情",
|
||||||
|
@ -442,6 +483,129 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/instances/steps/approve": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号和节点号通过审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批通过",
|
||||||
|
"operationId": "instances-steps-approve",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsApproveParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsApproveParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/cancel": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号取消审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批取消",
|
||||||
|
"operationId": "instances-steps-cancel",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "审批取消参数",
|
||||||
|
"name": "InstancesStepsCancelParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsCancelParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/reject": {
|
||||||
|
"post": {
|
||||||
|
"description": "根据实例号和节点号驳回审批",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "审批驳回",
|
||||||
|
"operationId": "instances-steps-reject",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "驳回参数",
|
||||||
|
"name": "InstancesStepsRejectParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsRejectParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/instances/steps/revert": {
|
"/instances/steps/revert": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "输入你的接口总结详情",
|
"description": "输入你的接口总结详情",
|
||||||
|
@ -666,6 +830,9 @@
|
||||||
"description": "主键ID",
|
"description": "主键ID",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "审批状态",
|
"description": "审批状态",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -702,6 +869,9 @@
|
||||||
"description": "是否超时",
|
"description": "是否超时",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"description": "审批状态",
|
"description": "审批状态",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -738,6 +908,9 @@
|
||||||
"description": "是否并行",
|
"description": "是否并行",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"priority": {
|
"priority": {
|
||||||
"description": "路径优先级",
|
"description": "路径优先级",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -771,6 +944,9 @@
|
||||||
"description": "是否为动态步骤",
|
"description": "是否为动态步骤",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"records": {
|
"records": {
|
||||||
"description": "审批记录",
|
"description": "审批记录",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -832,9 +1008,53 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flow_instance.InstancesStartRuleParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"flow_instance.InstancesStepsAddParam": {
|
"flow_instance.InstancesStepsAddParam": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"flow_instance.InstancesStepsApproveParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"comments": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsCancelParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsRejectParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"comments": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"flow_instance.InstancesStepsRevertParam": {
|
"flow_instance.InstancesStepsRevertParam": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
|
|
@ -97,6 +97,8 @@ definitions:
|
||||||
id:
|
id:
|
||||||
description: 主键ID
|
description: 主键ID
|
||||||
type: integer
|
type: integer
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: 审批状态
|
description: 审批状态
|
||||||
type: string
|
type: string
|
||||||
|
@ -123,6 +125,8 @@ definitions:
|
||||||
is_timeout:
|
is_timeout:
|
||||||
description: 是否超时
|
description: 是否超时
|
||||||
type: boolean
|
type: boolean
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
description: 审批状态
|
description: 审批状态
|
||||||
type: string
|
type: string
|
||||||
|
@ -148,6 +152,8 @@ definitions:
|
||||||
is_parallel:
|
is_parallel:
|
||||||
description: 是否并行
|
description: 是否并行
|
||||||
type: boolean
|
type: boolean
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
priority:
|
priority:
|
||||||
description: 路径优先级
|
description: 路径优先级
|
||||||
type: integer
|
type: integer
|
||||||
|
@ -172,6 +178,8 @@ definitions:
|
||||||
is_dynamic:
|
is_dynamic:
|
||||||
description: 是否为动态步骤
|
description: 是否为动态步骤
|
||||||
type: boolean
|
type: boolean
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
records:
|
records:
|
||||||
description: 审批记录
|
description: 审批记录
|
||||||
items:
|
items:
|
||||||
|
@ -213,8 +221,36 @@ definitions:
|
||||||
instance_id:
|
instance_id:
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
|
flow_instance.InstancesStartRuleParam:
|
||||||
|
properties:
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
flow_instance.InstancesStepsAddParam:
|
flow_instance.InstancesStepsAddParam:
|
||||||
type: object
|
type: object
|
||||||
|
flow_instance.InstancesStepsApproveParam:
|
||||||
|
properties:
|
||||||
|
comments:
|
||||||
|
type: string
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
step_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStepsCancelParam:
|
||||||
|
properties:
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStepsRejectParam:
|
||||||
|
properties:
|
||||||
|
comments:
|
||||||
|
type: string
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
step_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
flow_instance.InstancesStepsRevertParam:
|
flow_instance.InstancesStepsRevertParam:
|
||||||
type: object
|
type: object
|
||||||
flow_instance.InstancesStepsUpdateParam:
|
flow_instance.InstancesStepsUpdateParam:
|
||||||
|
@ -473,6 +509,33 @@ paths:
|
||||||
summary: 启动审批流
|
summary: 启动审批流
|
||||||
tags:
|
tags:
|
||||||
- flow-instances
|
- flow-instances
|
||||||
|
/instances/start/rule:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 启动审批流自动规则
|
||||||
|
operationId: instances-start-rule
|
||||||
|
parameters:
|
||||||
|
- description: 启动实例ID
|
||||||
|
in: body
|
||||||
|
name: InstancesStartRuleParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStartRuleParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 启动审批流自动规则
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
/instances/steps/add:
|
/instances/steps/add:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
@ -500,6 +563,87 @@ paths:
|
||||||
summary: 输入你的接口总结
|
summary: 输入你的接口总结
|
||||||
tags:
|
tags:
|
||||||
- flow-instances
|
- flow-instances
|
||||||
|
/instances/steps/approve:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 根据实例号和节点号通过审批
|
||||||
|
operationId: instances-steps-approve
|
||||||
|
parameters:
|
||||||
|
- description: 输入参数描述
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsApproveParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsApproveParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 审批通过
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/steps/cancel:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 根据实例号取消审批
|
||||||
|
operationId: instances-steps-cancel
|
||||||
|
parameters:
|
||||||
|
- description: 审批取消参数
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsCancelParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsCancelParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 审批取消
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/steps/reject:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 根据实例号和节点号驳回审批
|
||||||
|
operationId: instances-steps-reject
|
||||||
|
parameters:
|
||||||
|
- description: 驳回参数
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsRejectParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsRejectParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 审批驳回
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
/instances/steps/revert:
|
/instances/steps/revert:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
@ -38,18 +38,23 @@ func NewOrmInstanceRepositoryImplAndRegister(container framework.Container) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InstanceRepositoryImpl) SaveToDB(entity *InstanceModel.ApprovalInstance) error {
|
func (u *InstanceRepositoryImpl) SaveToDB(entity *InstanceModel.ApprovalInstance) error {
|
||||||
|
// 先保存 ApprovalFlow 本身
|
||||||
|
if entity.ID != 0 {
|
||||||
|
// 使用FullSaveAssociations 方法来确保模型的整体状态,包括其所有关联都反映在了数据库中,从在应用中保持数据的完整性和一致性
|
||||||
|
return u.db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(entity).Error
|
||||||
|
}
|
||||||
return u.db.Save(entity).Error
|
return u.db.Save(entity).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InstanceRepositoryImpl) FindByIDFromDB(id int64) (*InstanceModel.ApprovalInstance, error) {
|
func (u *InstanceRepositoryImpl) FindByIDFromDB(id int64) (*InstanceModel.ApprovalInstance, error) {
|
||||||
entity := &InstanceModel.ApprovalInstance{}
|
entity := &InstanceModel.ApprovalInstance{}
|
||||||
err := u.db.First(entity, id).Error
|
err := u.db.Preload("CurrentStepIDs").Preload("StatusEvents").Preload("Steps").Preload("Steps.StatusEvents").Preload("Steps.Records").Preload("Steps.InstancePathConfigs").First(entity, id).Error
|
||||||
return entity, err
|
return entity, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *InstanceRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*InstanceModel.ApprovalInstance, error) {
|
func (u *InstanceRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*InstanceModel.ApprovalInstance, error) {
|
||||||
var entities []*InstanceModel.ApprovalInstance
|
var entities []*InstanceModel.ApprovalInstance
|
||||||
err := u.db.Where("id IN ?", ids).Find(&entities).Error
|
err := u.db.Where("id IN ?", ids).Preload("StatusEvents").Preload("CurrentStepIDs").Preload("Steps").Preload("Steps.StatusEvents").Preload("Steps.Records").Preload("Steps.InstancePathConfigs").Find(&entities).Error
|
||||||
return entities, err
|
return entities, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ func (u *FlowRepositoryImpl) FindByIDFromDB(id int64) (*FlowDefinitionModule.App
|
||||||
|
|
||||||
func (u *FlowRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*FlowDefinitionModule.ApprovalFlow, error) {
|
func (u *FlowRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*FlowDefinitionModule.ApprovalFlow, error) {
|
||||||
var entities []*FlowDefinitionModule.ApprovalFlow
|
var entities []*FlowDefinitionModule.ApprovalFlow
|
||||||
err := u.db.Where("id IN ?", ids).Find(&entities).Error
|
err := u.db.Where("id IN ?", ids).Preload("Steps").Preload("Steps.Rules").Preload("Steps.DynamicConfig").Preload("Steps.PathConfigs").Find(&entities).Error
|
||||||
return entities, err
|
return entities, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ type NodeManager interface {
|
||||||
SetNodes([]AbstractNode)
|
SetNodes([]AbstractNode)
|
||||||
GetNodeMap() map[string]AbstractNode
|
GetNodeMap() map[string]AbstractNode
|
||||||
NewNodePathConfig(fromNodeKey, toNodeKey string) AbstractNodePathConfig
|
NewNodePathConfig(fromNodeKey, toNodeKey string) AbstractNodePathConfig
|
||||||
|
Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeManagerS struct {
|
type NodeManagerS struct {
|
||||||
|
@ -26,6 +27,7 @@ type AbstractNode interface {
|
||||||
GetPathConfigs() []AbstractNodePathConfig
|
GetPathConfigs() []AbstractNodePathConfig
|
||||||
SetPathConfigs([]AbstractNodePathConfig)
|
SetPathConfigs([]AbstractNodePathConfig)
|
||||||
GetKey() string
|
GetKey() string
|
||||||
|
Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
type AbstractNodePathConfig interface {
|
type AbstractNodePathConfig interface {
|
||||||
|
@ -33,6 +35,7 @@ type AbstractNodePathConfig interface {
|
||||||
GetNodeID() int64
|
GetNodeID() int64
|
||||||
GetFromNodeKey() string
|
GetFromNodeKey() string
|
||||||
GetToNodeKey() string
|
GetToNodeKey() string
|
||||||
|
Delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
@ -270,9 +273,11 @@ func addPath(nct NodeManager, fromNode, toNode AbstractNode) {
|
||||||
func removePath(nct NodeManager, fromNode, toNode AbstractNode) {
|
func removePath(nct NodeManager, fromNode, toNode AbstractNode) {
|
||||||
var newPathConfigs []AbstractNodePathConfig
|
var newPathConfigs []AbstractNodePathConfig
|
||||||
for _, pc := range fromNode.GetPathConfigs() {
|
for _, pc := range fromNode.GetPathConfigs() {
|
||||||
if !(pc.GetFromNodeKey() == fromNode.GetKey() && pc.GetToNodeKey() == toNode.GetKey()) {
|
if pc.GetFromNodeKey() == fromNode.GetKey() && pc.GetToNodeKey() == toNode.GetKey() {
|
||||||
newPathConfigs = append(newPathConfigs, pc)
|
// 使用软删除的方式
|
||||||
|
pc.Delete()
|
||||||
}
|
}
|
||||||
|
newPathConfigs = append(newPathConfigs, pc)
|
||||||
}
|
}
|
||||||
fromNode.SetPathConfigs(newPathConfigs)
|
fromNode.SetPathConfigs(newPathConfigs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ type ApprovalCondition interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApprovalConditionCommon struct {
|
type ApprovalConditionCommon struct {
|
||||||
ApprovalCondition
|
ApprovalCondition `gorm:"-"`
|
||||||
ConditionExpression string `gorm:"type:text" json:"condition_expression"` // 条件表达式
|
ConditionExpression string `gorm:"type:text" json:"condition_expression"` // 条件表达式
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package flow_definition
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
userProvider "approveflow/app/provider/user"
|
userProvider "approveflow/app/provider/user"
|
||||||
|
"encoding/json"
|
||||||
"github.com/Superdanda/hade/framework/gin"
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,6 +23,14 @@ type DynamicApprovalStepConfig struct {
|
||||||
base.Model // 通用字段,包括创建时间、更新时间等
|
base.Model // 通用字段,包括创建时间、更新时间等
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (config *DynamicApprovalStepConfig) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *DynamicApprovalStepConfig) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, config)
|
||||||
|
}
|
||||||
|
|
||||||
// NewDirectSupervisorRule 创建审批人为直属领导审批规则
|
// NewDirectSupervisorRule 创建审批人为直属领导审批规则
|
||||||
func NewDirectSupervisorRule() *DynamicApprovalStepConfig {
|
func NewDirectSupervisorRule() *DynamicApprovalStepConfig {
|
||||||
directSupervisorApproval := &DynamicApprovalStepConfig{
|
directSupervisorApproval := &DynamicApprovalStepConfig{
|
||||||
|
|
|
@ -15,6 +15,7 @@ type ApprovalFlow struct {
|
||||||
Description string `gorm:"type:text" json:"description"` // 流程描述
|
Description string `gorm:"type:text" json:"description"` // 流程描述
|
||||||
Steps []*ApprovalStep `gorm:"foreignKey:FlowID;constraint:OnDelete:CASCADE" json:"steps"` // 流程步骤
|
Steps []*ApprovalStep `gorm:"foreignKey:FlowID;constraint:OnDelete:CASCADE" json:"steps"` // 流程步骤
|
||||||
NodeMap map[string]connect.AbstractNode `gorm:"-" json:"node_map"` // 流程步骤
|
NodeMap map[string]connect.AbstractNode `gorm:"-" json:"node_map"` // 流程步骤
|
||||||
|
TenantKey string `gorm:"type:varchar(50);not null" json:"tenant_key"`
|
||||||
base.Model // 通用字段,包括创建时间、更新时间等
|
base.Model // 通用字段,包括创建时间、更新时间等
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ func (step *ApprovalStep) SetPathConfigs(configs []connect.AbstractNodePathConfi
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("Error in SetPathConfigs: %v", err))
|
panic(fmt.Sprintf("Error in SetPathConfigs: %v", err))
|
||||||
}
|
}
|
||||||
|
for _, path := range step.PathConfigs {
|
||||||
|
path.Delete()
|
||||||
|
}
|
||||||
step.PathConfigs = convertedConfigs
|
step.PathConfigs = convertedConfigs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package flow_definition
|
package flow_definition
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"approveflow/app/provider/abstract/connect"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Superdanda/hade/framework"
|
"github.com/Superdanda/hade/framework"
|
||||||
|
@ -40,18 +41,11 @@ func (f *FlowDefinitionService) DeleteFlow(ctx context.Context, flowID int64) er
|
||||||
func (f *FlowDefinitionService) AddStepWithPosition(ctx context.Context, flowID int64, step *ApprovalStep, fromStepId string, toStepKey string) error {
|
func (f *FlowDefinitionService) AddStepWithPosition(ctx context.Context, flowID int64, step *ApprovalStep, fromStepId string, toStepKey string) error {
|
||||||
return f.handlerFlow(ctx, flowID, func(ctx context.Context, flow *ApprovalFlow) error {
|
return f.handlerFlow(ctx, flowID, func(ctx context.Context, flow *ApprovalFlow) error {
|
||||||
fromStep, err := flow.GetStepByKey(fromStepId)
|
fromStep, err := flow.GetStepByKey(fromStepId)
|
||||||
_, err = flow.GetStepByKey(toStepKey)
|
toStep, err := flow.GetStepByKey(toStepKey)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
path, ok := fromStep.GetPathByToKey(toStepKey)
|
err = connect.InsertNodeBetween(flow, fromStep, toStep, step)
|
||||||
if !ok {
|
|
||||||
return errors.New("这两个节点不相邻")
|
|
||||||
}
|
|
||||||
_, toPath := path.NewPathWithStep(step)
|
|
||||||
err = step.AddPathConfig(toPath)
|
|
||||||
err = flow.AddStep(step)
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ type Service interface {
|
||||||
CreateInstance(ctx *gin.Context, approvalFlow *flow_definition.ApprovalFlow, data map[string]interface{}) (*model.ApprovalInstance, error)
|
CreateInstance(ctx *gin.Context, approvalFlow *flow_definition.ApprovalFlow, data map[string]interface{}) (*model.ApprovalInstance, error)
|
||||||
// StartInstance 功能:启动新的审批流程实例。
|
// StartInstance 功能:启动新的审批流程实例。
|
||||||
StartInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
StartInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||||
|
// StartInstanceRule 功能:启动新的审批流程实例规则。
|
||||||
|
StartInstanceRule(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||||
// GetInstance 功能:获取指定流程实例的详细信息。
|
// GetInstance 功能:获取指定流程实例的详细信息。
|
||||||
GetInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
GetInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||||
// GetInstancePage 功能:分页查询流程实例的详细信息。
|
// GetInstancePage 功能:分页查询流程实例的详细信息。
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusCreated = "Created" // 审批实例已创建
|
StatusCreated = "Created" // 审批实例已创建
|
||||||
|
StatusReject = "Reject" // 审批实例已创建
|
||||||
StatusInProgress = "InProgress" // 审批进行中
|
StatusInProgress = "InProgress" // 审批进行中
|
||||||
StatusCompleted = "Completed" // 审批完成
|
StatusCompleted = "Completed" // 审批完成
|
||||||
StatusCancelled = "Cancelled" // 审批取消
|
StatusCancelled = "Cancelled" // 审批取消
|
||||||
|
@ -26,14 +27,47 @@ type ApprovalInstance struct {
|
||||||
FlowID int64 `gorm:"type:bigint;index;not null" json:"flow_id"` // 流程ID
|
FlowID int64 `gorm:"type:bigint;index;not null" json:"flow_id"` // 流程ID
|
||||||
ApplicantKey string `gorm:"type:bigint;index;not null" json:"approver_id"` //申请人ID
|
ApplicantKey string `gorm:"type:bigint;index;not null" json:"approver_id"` //申请人ID
|
||||||
CreatorKey string `gorm:"type:bigint;not null" json:"creator_id"` // 创建者ID
|
CreatorKey string `gorm:"type:bigint;not null" json:"creator_id"` // 创建者ID
|
||||||
Status string `gorm:"type:varchar(50);not null" json:"status"` // 审批状态
|
Status string `gorm:"-" json:"status"` // 审批状态
|
||||||
CurrentStepIDs []*CurrentStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"current_step_ids"` // 当前步骤ID
|
CurrentStepIDs []*CurrentStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"current_step_ids"` // 当前步骤ID
|
||||||
Steps []*InstanceStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"steps"` // 实例步骤
|
Steps []*InstanceStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"steps"` // 实例步骤
|
||||||
Data string `gorm:"type:json" json:"data"` // 保存审批数据的 JSON
|
StatusEvents []*InstanceStatusEvent `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"status_events"` // 实例步骤
|
||||||
|
Data string `gorm:"type:json" json:"data"`
|
||||||
|
NodeMap map[string]connect.AbstractNode `gorm:"-" json:"node_map"` // 保存审批数据的 JSON
|
||||||
|
TenantKey string `gorm:"type:varchar(50);not null" json:"tenant_key"`
|
||||||
|
AssociateKey string `gorm:"type:varchar(50);not null" json:"associate_key"`
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstanceStatusEvent 审批实例状态表
|
||||||
|
type InstanceStatusEvent struct {
|
||||||
|
InstanceID int64 `gorm:"type:bigint;not null" json:"instance_id"`
|
||||||
|
Status string `gorm:"type:varchar(50);not null" json:"status"`
|
||||||
|
Extension string `gorm:"type:varchar(50);not null" json:"extension"`
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) CheckIfComplete() bool {
|
||||||
|
currentSteps := instance.GetCurrentSteps()
|
||||||
|
if instance.GetStatus() == StatusCompleted {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(currentSteps) == 1 && currentSteps[0].StepCode == flow_definition.StepEnd {
|
||||||
|
currentSteps[0].AddCompletedEvent()
|
||||||
|
instance.AddCompletedEvent()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, instance)
|
||||||
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) GetNodes() []connect.AbstractNode {
|
func (instance *ApprovalInstance) GetNodes() []connect.AbstractNode {
|
||||||
return utils.ConvertToAbstractNodes(instance.Steps, func(step *InstanceStep) connect.AbstractNode {
|
return utils.ConvertToAbstractNodes(instance.Steps, func(step *InstanceStep) connect.AbstractNode {
|
||||||
return step
|
return step
|
||||||
|
@ -41,24 +75,41 @@ func (instance *ApprovalInstance) GetNodes() []connect.AbstractNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) SetNodes(nodes []connect.AbstractNode) {
|
func (instance *ApprovalInstance) SetNodes(nodes []connect.AbstractNode) {
|
||||||
//TODO implement me
|
specificType, _ := utils.ConvertToSpecificType[*InstanceStep, connect.AbstractNode](nodes, func(node connect.AbstractNode) (*InstanceStep, bool) {
|
||||||
panic("implement me")
|
return node.(*InstanceStep), true
|
||||||
|
})
|
||||||
|
instance.Steps = specificType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) GetNodeMap() map[string]connect.AbstractNode {
|
func (instance *ApprovalInstance) GetNodeMap() map[string]connect.AbstractNode {
|
||||||
//TODO implement me
|
if instance.NodeMap == nil {
|
||||||
panic("implement me")
|
instance.NodeMap = map[string]connect.AbstractNode{}
|
||||||
|
connect.InitializeNodeMap(instance)
|
||||||
|
}
|
||||||
|
return instance.NodeMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) NewNodePathConfig(fromNodeKey, toNodeKey string) connect.AbstractNodePathConfig {
|
func (instance *ApprovalInstance) NewNodePathConfig(fromNodeKey, toNodeKey string) connect.AbstractNodePathConfig {
|
||||||
//TODO implement me
|
fromStep, err := instance.GetStepByKey(fromNodeKey)
|
||||||
panic("implement me")
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return NewDynamicPathConfig(instance.ID, fromStep.ID, fromNodeKey, toNodeKey, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentStep 目前审批中的节点
|
// CurrentStep 目前审批中的节点
|
||||||
type CurrentStep struct {
|
type CurrentStep struct {
|
||||||
CurrentStepId int64 `gorm:"type:bigint;index;not null" json:"current_step_id"`
|
CurrentStepId int64 `gorm:"type:bigint;index;not null" json:"current_step_id"`
|
||||||
InstanceID int64 `gorm:"type:bigint;index;not null" json:"instance_id"`
|
InstanceID int64 `gorm:"type:bigint;index;not null" json:"instance_id"`
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (current *CurrentStep) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(current)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (current *CurrentStep) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, current)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApprovalInstance 初始化创建一个审批流实例
|
// NewApprovalInstance 初始化创建一个审批流实例
|
||||||
|
@ -78,6 +129,15 @@ func NewApprovalInstance(
|
||||||
Steps: []*InstanceStep{},
|
Steps: []*InstanceStep{},
|
||||||
Data: string(bytes),
|
Data: string(bytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存租户键和关联键
|
||||||
|
if value, ok := data[base.TenantKey]; ok {
|
||||||
|
instance.TenantKey = value.(string)
|
||||||
|
}
|
||||||
|
if value, ok := data[base.AssociateKey]; ok {
|
||||||
|
instance.TenantKey = value.(string)
|
||||||
|
}
|
||||||
|
|
||||||
// Get the first step of the approval flow
|
// Get the first step of the approval flow
|
||||||
firstStep, err := approvalFlow.FirstStep()
|
firstStep, err := approvalFlow.FirstStep()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,15 +145,19 @@ func NewApprovalInstance(
|
||||||
}
|
}
|
||||||
// Build the steps recursively
|
// Build the steps recursively
|
||||||
processedSteps := make(map[string]*InstanceStep)
|
processedSteps := make(map[string]*InstanceStep)
|
||||||
err = buildInstanceSteps(ctx, instance, firstStep, nil, data, processedSteps)
|
err = buildInstanceSteps(ctx, approvalFlow, instance, firstStep, nil, data, processedSteps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 赋予创建状态
|
||||||
|
instance.AddCreatedEvent()
|
||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildInstanceSteps recursively builds instance steps from approval steps
|
// buildInstanceSteps recursively builds instance steps from approval steps
|
||||||
func buildInstanceSteps(ctx *gin.Context, instance *ApprovalInstance, currentApprovalStep *flow_definition.ApprovalStep,
|
func buildInstanceSteps(ctx *gin.Context, approvalFlow *flow_definition.ApprovalFlow,
|
||||||
|
instance *ApprovalInstance, currentApprovalStep *flow_definition.ApprovalStep,
|
||||||
previousInstanceStep *InstanceStep, data map[string]interface{}, processedSteps map[string]*InstanceStep) error {
|
previousInstanceStep *InstanceStep, data map[string]interface{}, processedSteps map[string]*InstanceStep) error {
|
||||||
// Check if this step has already been processed to avoid cycles
|
// Check if this step has already been processed to avoid cycles
|
||||||
if existingInstanceStep, ok := processedSteps[currentApprovalStep.Key]; ok {
|
if existingInstanceStep, ok := processedSteps[currentApprovalStep.Key]; ok {
|
||||||
|
@ -102,15 +166,21 @@ func buildInstanceSteps(ctx *gin.Context, instance *ApprovalInstance, currentApp
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Create a new instance step
|
|
||||||
var approverKey string
|
var approverKey string
|
||||||
|
if currentApprovalStep.DynamicConfig != nil {
|
||||||
approver, err := currentApprovalStep.DynamicConfig.GetApprover(ctx, data)
|
approver, err := currentApprovalStep.DynamicConfig.GetApprover(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
approverKey = ""
|
approverKey = ""
|
||||||
} else {
|
} else {
|
||||||
approverKey = approver.Key
|
approverKey = approver.Key
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
approverKey = ""
|
||||||
|
}
|
||||||
|
|
||||||
currentInstanceStep := NewInstanceStep(currentApprovalStep, approverKey, false)
|
currentInstanceStep := NewInstanceStep(currentApprovalStep, approverKey, false)
|
||||||
|
|
||||||
// Insert the instance step into the instance
|
// Insert the instance step into the instance
|
||||||
if previousInstanceStep == nil {
|
if previousInstanceStep == nil {
|
||||||
connect.InsertNodeFirst(instance, currentInstanceStep)
|
connect.InsertNodeFirst(instance, currentInstanceStep)
|
||||||
|
@ -119,14 +189,16 @@ func buildInstanceSteps(ctx *gin.Context, instance *ApprovalInstance, currentApp
|
||||||
}
|
}
|
||||||
// Mark this step as processed
|
// Mark this step as processed
|
||||||
processedSteps[currentApprovalStep.Key] = currentInstanceStep
|
processedSteps[currentApprovalStep.Key] = currentInstanceStep
|
||||||
|
|
||||||
// Get the next steps and recursively build them
|
// Get the next steps and recursively build them
|
||||||
nextSteps, err := connect.GetNextNodes(instance, currentApprovalStep)
|
flowStep, err := approvalFlow.GetStep(currentInstanceStep.StepID)
|
||||||
|
nextFlowSteps, err := connect.GetNextNodes(approvalFlow, flowStep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, nextStep := range nextSteps {
|
for _, nextStep := range nextFlowSteps {
|
||||||
nextApprovalStep := nextStep.(*flow_definition.ApprovalStep)
|
nextApprovalStep := nextStep.(*flow_definition.ApprovalStep)
|
||||||
err := buildInstanceSteps(ctx, instance, nextApprovalStep, currentInstanceStep, data, processedSteps)
|
err := buildInstanceSteps(ctx, approvalFlow, instance, nextApprovalStep, currentInstanceStep, data, processedSteps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -162,7 +234,7 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
||||||
instance.RLock()
|
instance.RLock()
|
||||||
defer instance.RUnlock()
|
defer instance.RUnlock()
|
||||||
|
|
||||||
if instance.Status != StatusCreated {
|
if instance.GetStatus() != StatusCreated && instance.GetStatus() != StatusReject {
|
||||||
return fmt.Errorf("审批流程已启动或已完成,无法再次启动")
|
return fmt.Errorf("审批流程已启动或已完成,无法再次启动")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +246,7 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
||||||
|
|
||||||
// 设置当前步骤为第一个步骤,并更改状态
|
// 设置当前步骤为第一个步骤,并更改状态
|
||||||
instance.AddCurrentStepID(firstStep)
|
instance.AddCurrentStepID(firstStep)
|
||||||
instance.Status = StatusInProgress
|
instance.AddInProgressEvent()
|
||||||
|
|
||||||
err = instance.SendApprovalNotification(firstStep, ctx)
|
err = instance.SendApprovalNotification(firstStep, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -210,19 +282,19 @@ func (instance *ApprovalInstance) MoveToNextStep() error {
|
||||||
}
|
}
|
||||||
currentStep := currentStepSlice[0]
|
currentStep := currentStepSlice[0]
|
||||||
// 完成当前步骤
|
// 完成当前步骤
|
||||||
currentStep.Status = StepStatusCompleted
|
currentStep.AddCompletedEvent()
|
||||||
|
|
||||||
// 获取下一个步骤
|
// 获取下一个步骤
|
||||||
var nextStep *InstanceStep
|
var nextStep *InstanceStep
|
||||||
nextStepArr, err := instance.getNextStep(currentStep, dataMap)
|
nextStepArr, err := instance.getNextStep(currentStep, dataMap)
|
||||||
if nextStepArr != nil && len(nextStepArr) == 0 {
|
if nextStepArr != nil && len(nextStepArr) == 1 {
|
||||||
nextStep = nextStepArr[0]
|
nextStep = nextStepArr[0]
|
||||||
} else {
|
} else {
|
||||||
return errors.New("暂时不支持并行审批")
|
return errors.New("暂时不支持并行审批")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
instance.Status = StatusCompleted // 流程结束
|
instance.AddCompletedEvent() // 流程结束
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +302,8 @@ func (instance *ApprovalInstance) MoveToNextStep() error {
|
||||||
instance.RemoveCurrentStepID(currentStep.ID)
|
instance.RemoveCurrentStepID(currentStep.ID)
|
||||||
instance.AddCurrentStepID(nextStep)
|
instance.AddCurrentStepID(nextStep)
|
||||||
|
|
||||||
nextStep.Status = StepStatusPending
|
nextStep.AddPendingEvent()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +376,7 @@ func (instance *ApprovalInstance) GetStepByKey(key string) (*InstanceStep, error
|
||||||
return step, nil
|
return step, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("step with key %d not found in approval flow", key)
|
return nil, fmt.Errorf("step with key %s not found in approval flow", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCurrentStepID adds a new CurrentStep to the CurrentStepIDs slice if it does not already exist
|
// AddCurrentStepID adds a new CurrentStep to the CurrentStepIDs slice if it does not already exist
|
||||||
|
@ -324,6 +397,7 @@ func (instance *ApprovalInstance) RemoveCurrentStepID(stepID int64) {
|
||||||
for i, s := range instance.CurrentStepIDs {
|
for i, s := range instance.CurrentStepIDs {
|
||||||
if s.CurrentStepId == stepID {
|
if s.CurrentStepId == stepID {
|
||||||
// Remove the step by slicing
|
// Remove the step by slicing
|
||||||
|
s.Delete()
|
||||||
instance.CurrentStepIDs = append(instance.CurrentStepIDs[:i], instance.CurrentStepIDs[i+1:]...)
|
instance.CurrentStepIDs = append(instance.CurrentStepIDs[:i], instance.CurrentStepIDs[i+1:]...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -343,7 +417,7 @@ func (instance *ApprovalInstance) HasCurrentStepID(stepID int64) bool {
|
||||||
// GetCurrentSteps returns a copy of the CurrentSteps slice
|
// GetCurrentSteps returns a copy of the CurrentSteps slice
|
||||||
func (instance *ApprovalInstance) GetCurrentSteps() []*InstanceStep {
|
func (instance *ApprovalInstance) GetCurrentSteps() []*InstanceStep {
|
||||||
// Return a copy of the slice to avoid modifications
|
// Return a copy of the slice to avoid modifications
|
||||||
currentSteps := make([]*InstanceStep, len(instance.CurrentStepIDs))
|
var currentSteps []*InstanceStep
|
||||||
for _, step := range instance.Steps {
|
for _, step := range instance.Steps {
|
||||||
if instance.HasCurrentStepID(step.ID) {
|
if instance.HasCurrentStepID(step.ID) {
|
||||||
currentSteps = append(currentSteps, step)
|
currentSteps = append(currentSteps, step)
|
||||||
|
@ -362,9 +436,60 @@ func (instance *ApprovalInstance) GetCurrentStepsById(id int64) *InstanceStep {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeApprovalStep 执行审批步骤
|
func (instance *ApprovalInstance) ExecuteApprovalReversal(reversal *ApprovalReversal) error {
|
||||||
func (instance *ApprovalInstance) executeApprovalStep(approvalFlow flow_definition.ApprovalFlow) error {
|
step, err := instance.GetStepByKey(reversal.StepKey)
|
||||||
for _, instanceStep := range instance.GetCurrentSteps() {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
currentStep := instance.GetCurrentStepsById(step.ID)
|
||||||
|
if currentStep == nil {
|
||||||
|
return errors.New("当前反转节点不是正在审批的节点")
|
||||||
|
}
|
||||||
|
switch reversal.FixAction {
|
||||||
|
case FixActionReApproveAndUpdateData:
|
||||||
|
err := currentStep.Reject(reversal.Reason)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 移除当前所有节点,替换为开始节点
|
||||||
|
for _, step := range instance.GetCurrentSteps() {
|
||||||
|
instance.RemoveCurrentStepID(step.ID)
|
||||||
|
}
|
||||||
|
reversalStep, err := instance.GetStepByKey(reversal.ReversedStepKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, step := range instance.Steps {
|
||||||
|
// 所有节点重新加入待审批事件
|
||||||
|
if step.GetStatus() == StepStatusApproved {
|
||||||
|
// 如果是通过的话要再审批
|
||||||
|
step.AddPendingEvent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.AddCurrentStepID(reversalStep)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) Reversal(step *InstanceStep, reversedStep *InstanceStep, reason string, fixAction string) error {
|
||||||
|
reversal := NewReversal(step, reversedStep, reason, fixAction)
|
||||||
|
step.addApprovalReversal(reversal)
|
||||||
|
instance.AddRejectEvent()
|
||||||
|
return instance.ExecuteApprovalReversal(reversal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteApprovalStep 执行审批步骤规则
|
||||||
|
func (instance *ApprovalInstance) ExecuteApprovalStep(approvalFlow *flow_definition.ApprovalFlow) error {
|
||||||
|
currentSteps := instance.GetCurrentSteps()
|
||||||
|
for _, instanceStep := range currentSteps {
|
||||||
|
|
||||||
|
// 只对待审批的节点进行处理
|
||||||
|
if instanceStep.GetStatus() != StepStatusPending {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
flowStep, err := approvalFlow.GetStep(instanceStep.StepID)
|
flowStep, err := approvalFlow.GetStep(instanceStep.StepID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
@ -415,11 +540,88 @@ func (instance *ApprovalInstance) executeApprovalStep(approvalFlow flow_definiti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return instance.CheckIfMoveToNextStep(currentSteps)
|
||||||
|
}
|
||||||
|
|
||||||
return nil // 如果没有规则满足,正常返回
|
func (instance *ApprovalInstance) CheckIfMoveToNextStep(currentSteps []*InstanceStep) error {
|
||||||
|
if instance.CheckIfComplete() {
|
||||||
|
return errors.New("当前审批流已结束")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前节点所有的处理完毕,那么当前节点将向后移动
|
||||||
|
currentIsCompleted := true
|
||||||
|
for _, step := range currentSteps {
|
||||||
|
if step.GetStatus() != StepStatusCompleted && step.GetStatus() != StepStatusApproved {
|
||||||
|
currentIsCompleted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if currentIsCompleted {
|
||||||
|
err := instance.MoveToNextStep()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
instance.CheckIfComplete()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) GetPathByFromStepKey(fromStepKey string) (*InstancePathConfig, error) {
|
func (instance *ApprovalInstance) GetPathByFromStepKey(fromStepKey string) (*InstancePathConfig, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) GetStartStep() *InstanceStep {
|
||||||
|
for _, step := range instance.Steps {
|
||||||
|
if step.StepCode == flow_definition.StepStart {
|
||||||
|
return step
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) GetEndStep() *InstanceStep {
|
||||||
|
for _, step := range instance.Steps {
|
||||||
|
if step.StepCode == flow_definition.StepEnd {
|
||||||
|
return step
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) GetStatus() string {
|
||||||
|
return instance.StatusEvents[len(instance.StatusEvents)-1].Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddStatusEvent(status string) {
|
||||||
|
if instance.StatusEvents == nil {
|
||||||
|
instance.StatusEvents = make([]*InstanceStatusEvent, 0)
|
||||||
|
}
|
||||||
|
if len(instance.StatusEvents) > 0 && instance.GetStatus() == status {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
instance.StatusEvents = append(instance.StatusEvents, &InstanceStatusEvent{
|
||||||
|
InstanceID: instance.ID, Status: status, Extension: "",
|
||||||
|
})
|
||||||
|
instance.Status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddCreatedEvent() {
|
||||||
|
instance.AddStatusEvent(StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddRejectEvent() {
|
||||||
|
instance.AddStatusEvent(StatusReject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddInProgressEvent() {
|
||||||
|
instance.AddStatusEvent(StatusInProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddCompletedEvent() {
|
||||||
|
instance.AddStatusEvent(StatusCompleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (instance *ApprovalInstance) AddCancelledEvent() {
|
||||||
|
instance.AddStatusEvent(StatusCancelled)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -21,6 +22,14 @@ type ApprovalRecord struct {
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (record *ApprovalRecord) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (record *ApprovalRecord) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, record)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateRecord 创建新的审批记录
|
// CreateRecord 创建新的审批记录
|
||||||
func (record *ApprovalRecord) CreateRecord(stepID int64, approverKey, status, comments string) {
|
func (record *ApprovalRecord) CreateRecord(stepID int64, approverKey, status, comments string) {
|
||||||
record.InstanceStepID = stepID
|
record.InstanceStepID = stepID
|
||||||
|
|
|
@ -1,28 +1,48 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "approveflow/app/base"
|
import (
|
||||||
|
"approveflow/app/base"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
// ApprovalReversal 审批反转表
|
// ApprovalReversal 审批反转表
|
||||||
type ApprovalReversal struct {
|
type ApprovalReversal struct {
|
||||||
InstanceID int64 `gorm:"index;not null" json:"instance_id"` // 关联的审批实例ID
|
InstanceID int64 `gorm:"type:bigint;index;not null" json:"instance_id"` // 关联的审批实例ID
|
||||||
StepID int64 `gorm:"index;not null" json:"step_id"` // 关联的步骤ID
|
StepID int64 `gorm:"type:bigint;index;not null" json:"step_id"` // 关联的步骤ID
|
||||||
ReversedStepID int64 `gorm:"index;not null" json:"reversed_step_id"` // 反转的步骤ID
|
StepKey string `gorm:"type:varchar(50);index;not null" json:"step_key"` // 关联的步骤ID
|
||||||
|
ReversedStepKey string `gorm:"type:varchar(50);index;not null" json:"reversed_step_id"` // 反转的步骤ID
|
||||||
FixAction string `gorm:"type:varchar(100);not null" json:"fix_action"` // 修正动作
|
FixAction string `gorm:"type:varchar(100);not null" json:"fix_action"` // 修正动作
|
||||||
Reason string `gorm:"type:text" json:"reason"` // 反转原因
|
Reason string `gorm:"type:text" json:"reason"` // 反转原因
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReverseStep 执行步骤的反转操作
|
// FixAction 定义常量表示审批反转的修正动作
|
||||||
func (reversal *ApprovalReversal) ReverseStep(step *InstanceStep, reason string) error {
|
const (
|
||||||
reversal.InstanceID = step.InstanceID
|
FixActionReApproveAndUpdateData = "ReApproveAndUpdateData"
|
||||||
reversal.StepID = step.StepID
|
FixActionReApprove = "ReApprove" // 重新审批
|
||||||
reversal.ReversedStepID = step.ID
|
FixActionReassignApprover = "ReassignApprover" // 重新指定审批人
|
||||||
reversal.Reason = reason
|
FixActionRollback = "Rollback" // 回滚到某个步骤
|
||||||
reversal.FixAction = "Reversal"
|
FixActionUpdateData = "UpdateData" // 更新审批数据
|
||||||
|
FixActionReopen = "Reopen" // 重新打开审批流程
|
||||||
|
)
|
||||||
|
|
||||||
// 更新步骤状态为反转
|
func (reversal *ApprovalReversal) MarshalBinary() ([]byte, error) {
|
||||||
step.Status = "Reversed"
|
return json.Marshal(reversal)
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func (reversal *ApprovalReversal) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, reversal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReversal(step *InstanceStep, reversedStep *InstanceStep, reason string, fixAction string) *ApprovalReversal {
|
||||||
|
reversal := &ApprovalReversal{
|
||||||
|
StepID: step.ID,
|
||||||
|
StepKey: step.Key,
|
||||||
|
ReversedStepKey: reversedStep.Key,
|
||||||
|
FixAction: fixAction,
|
||||||
|
Reason: reason,
|
||||||
|
}
|
||||||
|
return reversal
|
||||||
}
|
}
|
||||||
|
|
||||||
// FixIssue 执行修正操作
|
// FixIssue 执行修正操作
|
||||||
|
|
|
@ -2,6 +2,7 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,3 +16,17 @@ type BatchApprovalTask struct {
|
||||||
ActionTime time.Time `json:"action_time"` // 审批时间
|
ActionTime time.Time `json:"action_time"` // 审批时间
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BatchApprovalTaskContent struct {
|
||||||
|
InstanceID int64
|
||||||
|
InstanceStepID int64
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (task *BatchApprovalTask) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (task *BatchApprovalTask) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, task)
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package model
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
"approveflow/app/provider/flow_definition"
|
"approveflow/app/provider/flow_definition"
|
||||||
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InstancePathConfig 动态路径配置表结构
|
// InstancePathConfig 动态路径配置表结构
|
||||||
|
@ -18,19 +19,27 @@ type InstancePathConfig struct {
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d InstancePathConfig) GetKey() string {
|
func (d *InstancePathConfig) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstancePathConfig) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstancePathConfig) GetKey() string {
|
||||||
return d.Key
|
return d.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d InstancePathConfig) GetNodeID() int64 {
|
func (d *InstancePathConfig) GetNodeID() int64 {
|
||||||
return d.NodeID
|
return d.NodeID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d InstancePathConfig) GetFromNodeKey() string {
|
func (d *InstancePathConfig) GetFromNodeKey() string {
|
||||||
return d.FromNodeKey
|
return d.FromNodeKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d InstancePathConfig) GetToNodeKey() string {
|
func (d *InstancePathConfig) GetToNodeKey() string {
|
||||||
return d.ToNodeKey
|
return d.ToNodeKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,11 +56,11 @@ func NewDynamicPathConfig(instanceID, nodeId int64, FromStepKey, ToStepKey strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsConditionMet 判断路径条件是否满足
|
// IsConditionMet 判断路径条件是否满足
|
||||||
func (a *InstancePathConfig) IsConditionMet(data map[string]interface{}) (bool, error) {
|
func (d *InstancePathConfig) IsConditionMet(data map[string]interface{}) (bool, error) {
|
||||||
if a.ConditionExpression == "" {
|
if d.ConditionExpression == "" {
|
||||||
return true, nil // 无条件,默认满足
|
return true, nil // 无条件,默认满足
|
||||||
}
|
}
|
||||||
result, err := a.EvaluateCondition(data)
|
result, err := d.EvaluateCondition(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"approveflow/app/provider/abstract/connect"
|
"approveflow/app/provider/abstract/connect"
|
||||||
"approveflow/app/provider/flow_definition"
|
"approveflow/app/provider/flow_definition"
|
||||||
"approveflow/app/utils"
|
"approveflow/app/utils"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
@ -25,14 +26,75 @@ type InstanceStep struct {
|
||||||
StepName string `gorm:"type:varchar(50);not null" json:"step_name"`
|
StepName string `gorm:"type:varchar(50);not null" json:"step_name"`
|
||||||
StepCode string `gorm:"type:varchar(100)" json:"step_code"` // 步骤编号用于标识特殊的审批节点
|
StepCode string `gorm:"type:varchar(100)" json:"step_code"` // 步骤编号用于标识特殊的审批节点
|
||||||
ApproverKey string `gorm:"type:varchar(50);not null" json:"approver_id"` // 审批人ID
|
ApproverKey string `gorm:"type:varchar(50);not null" json:"approver_id"` // 审批人ID
|
||||||
Status string `gorm:"type:varchar(50);not null" json:"status"` // 审批状态
|
Status string `gorm:"-" json:"status"` // 审批状态
|
||||||
ApproverComments string `gorm:"type:text" json:"approver_comments"` // 审批意见
|
ApproverComments string `gorm:"type:text" json:"approver_comments"` // 审批意见
|
||||||
IsDynamic bool `gorm:"not null;default:false" json:"is_dynamic"` // 是否为动态步骤
|
IsDynamic bool `gorm:"not null;default:false" json:"is_dynamic"` // 是否为动态步骤
|
||||||
|
StatusEvents []*InstanceStepStatusEvent `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"status_events"` // 状态事件表
|
||||||
InstancePathConfigs []*InstancePathConfig `gorm:"foreignKey:NodeID;constraint:OnDelete:CASCADE" json:"instance_path_configs"` // 动态路径配置,自定义,不直接存储
|
InstancePathConfigs []*InstancePathConfig `gorm:"foreignKey:NodeID;constraint:OnDelete:CASCADE" json:"instance_path_configs"` // 动态路径配置,自定义,不直接存储
|
||||||
Records []*ApprovalRecord `gorm:"foreignKey:InstanceStepID;constraint:OnDelete:CASCADE" json:"records"` // 审批记录
|
Records []*ApprovalRecord `gorm:"foreignKey:InstanceStepID;constraint:OnDelete:CASCADE" json:"records"` // 审批记录
|
||||||
|
Reversals []*ApprovalReversal `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"reversals"` // 反转记录
|
||||||
base.Model
|
base.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstanceStepStatusEvent 审批步骤状态表
|
||||||
|
type InstanceStepStatusEvent struct {
|
||||||
|
StepID int64 `gorm:"type:bigint;not null" json:"step_id"`
|
||||||
|
Status string `gorm:"type:varchar(50);not null" json:"status"`
|
||||||
|
Extension string `gorm:"type:varchar(50);not null" json:"extension"`
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
type ByCreatedAt []*InstanceStepStatusEvent
|
||||||
|
|
||||||
|
func (a ByCreatedAt) Len() int { return len(a) }
|
||||||
|
func (a ByCreatedAt) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a ByCreatedAt) Less(i, j int) bool { return a[i].CreatedAt.After(a[j].CreatedAt) }
|
||||||
|
|
||||||
|
func (step *InstanceStep) GetStatus() string {
|
||||||
|
return step.StatusEvents[len(step.StatusEvents)-1].Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddStatusEvent(status string) {
|
||||||
|
if step.StatusEvents == nil {
|
||||||
|
step.StatusEvents = make([]*InstanceStepStatusEvent, 0)
|
||||||
|
}
|
||||||
|
if len(step.StatusEvents) > 0 && step.GetStatus() == status {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
step.StatusEvents = append(step.StatusEvents, &InstanceStepStatusEvent{
|
||||||
|
StepID: step.ID, Status: status, Extension: "",
|
||||||
|
})
|
||||||
|
step.Status = status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddPendingEvent() {
|
||||||
|
step.AddStatusEvent(StepStatusPending)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddApprovedEvent() {
|
||||||
|
step.AddStatusEvent(StepStatusApproved)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddRejectedEvent() {
|
||||||
|
step.AddStatusEvent(StepStatusRejected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddReversedEvent() {
|
||||||
|
step.AddStatusEvent(StepStatusReversed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) AddCompletedEvent() {
|
||||||
|
step.AddStatusEvent(StepStatusCompleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(step)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, step)
|
||||||
|
}
|
||||||
|
|
||||||
func (step *InstanceStep) GetPathConfigs() []connect.AbstractNodePathConfig {
|
func (step *InstanceStep) GetPathConfigs() []connect.AbstractNodePathConfig {
|
||||||
return utils.ConvertToAbstractNodes(step.InstancePathConfigs, func(t *InstancePathConfig) connect.AbstractNodePathConfig {
|
return utils.ConvertToAbstractNodes(step.InstancePathConfigs, func(t *InstancePathConfig) connect.AbstractNodePathConfig {
|
||||||
return t
|
return t
|
||||||
|
@ -60,19 +122,19 @@ func NewInstanceStep(flowStep *flow_definition.ApprovalStep, approverKey string,
|
||||||
StepName: flowStep.Name,
|
StepName: flowStep.Name,
|
||||||
StepCode: flowStep.StepCode,
|
StepCode: flowStep.StepCode,
|
||||||
ApproverKey: approverKey,
|
ApproverKey: approverKey,
|
||||||
Status: StepStatusPending,
|
|
||||||
IsDynamic: isDynamic,
|
IsDynamic: isDynamic,
|
||||||
}
|
}
|
||||||
|
instanceStep.AddPendingEvent()
|
||||||
instanceStep.Key = uuid.New().String()
|
instanceStep.Key = uuid.New().String()
|
||||||
return instanceStep
|
return instanceStep
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approve 审批通过
|
// Approve 审批通过
|
||||||
func (step *InstanceStep) Approve(comments string) error {
|
func (step *InstanceStep) Approve(comments string) error {
|
||||||
if step.Status != StepStatusPending {
|
if step.GetStatus() != StepStatusPending {
|
||||||
return fmt.Errorf("当前步骤不是待审批状态")
|
return fmt.Errorf("当前步骤不是待审批状态")
|
||||||
}
|
}
|
||||||
step.Status = StepStatusApproved
|
step.AddApprovedEvent()
|
||||||
step.ApproverComments = comments
|
step.ApproverComments = comments
|
||||||
step.addApprovalRecord(StepStatusApproved, comments)
|
step.addApprovalRecord(StepStatusApproved, comments)
|
||||||
return nil
|
return nil
|
||||||
|
@ -80,10 +142,10 @@ func (step *InstanceStep) Approve(comments string) error {
|
||||||
|
|
||||||
// Reject 审批驳回
|
// Reject 审批驳回
|
||||||
func (step *InstanceStep) Reject(comments string) error {
|
func (step *InstanceStep) Reject(comments string) error {
|
||||||
if step.Status != StepStatusPending {
|
//if step.GetStatus() != StepStatusPending {
|
||||||
return fmt.Errorf("当前步骤不是待审批状态")
|
// return fmt.Errorf("当前步骤不是待审批状态")
|
||||||
}
|
//}
|
||||||
step.Status = StepStatusRejected
|
step.AddRejectedEvent()
|
||||||
step.ApproverComments = comments
|
step.ApproverComments = comments
|
||||||
step.addApprovalRecord(StepStatusRejected, comments)
|
step.addApprovalRecord(StepStatusRejected, comments)
|
||||||
return nil
|
return nil
|
||||||
|
@ -99,3 +161,9 @@ func (step *InstanceStep) addApprovalRecord(status string, comments string) {
|
||||||
}
|
}
|
||||||
step.Records = append(step.Records, record)
|
step.Records = append(step.Records, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) addApprovalReversal(reversal *ApprovalReversal) {
|
||||||
|
var reversals []*ApprovalReversal
|
||||||
|
reversals = append(reversals, reversal)
|
||||||
|
step.Reversals = reversals
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/provider/database_connect"
|
||||||
|
tests "approveflow/test"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModel(t *testing.T) {
|
||||||
|
|
||||||
|
container := tests.InitBaseContainer()
|
||||||
|
databaseConnectService := container.MustMake(database_connect.DatabaseConnectKey).(database_connect.Service)
|
||||||
|
|
||||||
|
db := databaseConnectService.DefaultDatabaseConnect()
|
||||||
|
db.AutoMigrate(ApprovalInstance{},
|
||||||
|
InstanceStatusEvent{},
|
||||||
|
ApprovalRecord{},
|
||||||
|
ApprovalReversal{},
|
||||||
|
BatchApprovalTask{},
|
||||||
|
CurrentStep{},
|
||||||
|
InstancePathConfig{},
|
||||||
|
InstanceStep{},
|
||||||
|
InstanceStepStatusEvent{})
|
||||||
|
}
|
|
@ -29,6 +29,19 @@ func (f *FlowInstanceService) CreateInstance(ctx *gin.Context, approvalFlow *flo
|
||||||
func (f *FlowInstanceService) StartInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error) {
|
func (f *FlowInstanceService) StartInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error) {
|
||||||
return f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
return f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
||||||
err := instance.Start(ctx)
|
err := instance.Start(ctx)
|
||||||
|
flowService := f.container.MustMake(flow_definition.FlowDefinitionKey).(flow_definition.Service)
|
||||||
|
flow, err := flowService.GetFlow(ctx, instance.FlowID)
|
||||||
|
err = instance.ExecuteApprovalStep(flow)
|
||||||
|
err = instance.CheckIfMoveToNextStep(instance.GetCurrentSteps())
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FlowInstanceService) StartInstanceRule(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error) {
|
||||||
|
return f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
||||||
|
flowService := f.container.MustMake(flow_definition.FlowDefinitionKey).(flow_definition.Service)
|
||||||
|
flow, err := flowService.GetFlow(ctx, instance.FlowID)
|
||||||
|
err = instance.ExecuteApprovalStep(flow)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -42,13 +55,21 @@ func (f *FlowInstanceService) GetInstancePage(ctx context.Context, pageNum, page
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowInstanceService) CancelInstance(ctx context.Context, instanceID int64) error {
|
func (f *FlowInstanceService) CancelInstance(ctx context.Context, instanceID int64) error {
|
||||||
//TODO implement me
|
_, err := f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
||||||
panic("implement me")
|
if instance.GetStatus() == model.StatusInProgress || instance.GetStatus() == model.StatusCreated {
|
||||||
|
instance.AddCancelledEvent()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("instance is cancelled or Completed")
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FlowInstanceService) ApproveStep(ctx context.Context, instanceID int64, stepID int64, comments string) error {
|
func (f *FlowInstanceService) ApproveStep(ctx context.Context, instanceID int64, stepID int64, comments string) error {
|
||||||
return f.handlerStep(ctx, instanceID, stepID, func(ctx context.Context, instance *model.ApprovalInstance, step *model.InstanceStep) error {
|
return f.handlerStep(ctx, instanceID, stepID, func(ctx context.Context, instance *model.ApprovalInstance, step *model.InstanceStep) error {
|
||||||
err := step.Approve(comments)
|
err := instance.CheckIfMoveToNextStep(instance.GetCurrentSteps())
|
||||||
|
err = step.Approve(comments)
|
||||||
|
err = instance.CheckIfMoveToNextStep(instance.GetCurrentSteps())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -58,7 +79,8 @@ func (f *FlowInstanceService) ApproveStep(ctx context.Context, instanceID int64,
|
||||||
|
|
||||||
func (f *FlowInstanceService) RejectStep(ctx context.Context, instanceID int64, stepID int64, comments string) error {
|
func (f *FlowInstanceService) RejectStep(ctx context.Context, instanceID int64, stepID int64, comments string) error {
|
||||||
return f.handlerStep(ctx, instanceID, stepID, func(ctx context.Context, instance *model.ApprovalInstance, step *model.InstanceStep) error {
|
return f.handlerStep(ctx, instanceID, stepID, func(ctx context.Context, instance *model.ApprovalInstance, step *model.InstanceStep) error {
|
||||||
err := step.Reject(comments)
|
err := instance.CheckIfMoveToNextStep(instance.GetCurrentSteps())
|
||||||
|
err = instance.Reversal(step, instance.GetStartStep(), comments, model.FixActionReApproveAndUpdateData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -150,6 +172,11 @@ func (f *FlowInstanceService) handlerInstance(ctx context.Context, instanceID in
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = f.GetFlowInstanceRepository().SaveInstance(ctx, instance)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,26 @@ type UserService struct {
|
||||||
container framework.Container
|
container framework.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *UserService) GetDirectSupervisorByUserId(userId int64) (*User, error) {
|
||||||
|
return &User{
|
||||||
|
ID: 1,
|
||||||
|
UserName: "dandan",
|
||||||
|
Name: "卢麟哲",
|
||||||
|
EmployeeNo: "230615020",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserService) GetDirectSupervisorByUserKey(userKey string) (*User, error) {
|
||||||
|
user := &User{
|
||||||
|
ID: 1,
|
||||||
|
UserName: "dandan",
|
||||||
|
Name: "卢麟哲",
|
||||||
|
EmployeeNo: "230615020",
|
||||||
|
}
|
||||||
|
user.Key = "230615020"
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewUserService(params ...interface{}) (interface{}, error) {
|
func NewUserService(params ...interface{}) (interface{}, error) {
|
||||||
container := params[0].(framework.Container)
|
container := params[0].(framework.Container)
|
||||||
return &UserService{container: container}, nil
|
return &UserService{container: container}, nil
|
||||||
|
|
Loading…
Reference in New Issue