备份代码
This commit is contained in:
parent
903cf7f516
commit
1dfc2f9245
|
@ -8,4 +8,7 @@ const (
|
|||
CreatorKey = "CreatorKey"
|
||||
ApproverKey = "ApproverKey"
|
||||
ApplicantKey = "ApplicantKey"
|
||||
|
||||
TenantKey = "TenantKey"
|
||||
AssociateKey = "AssociateKey"
|
||||
)
|
||||
|
|
|
@ -17,9 +17,13 @@ func RegisterRoutes(r *gin.Engine) error {
|
|||
{
|
||||
instancesGroup.POST("/create", api.InstancesCreate)
|
||||
instancesGroup.POST("/start", api.InstancesStart)
|
||||
instancesGroup.POST("/start/rule", api.InstancesStartRule)
|
||||
stepsGroup := instancesGroup.Group("/steps")
|
||||
{
|
||||
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("/revert", api.InstancesStepsRevert)
|
||||
}
|
||||
|
@ -30,6 +34,5 @@ func RegisterRoutes(r *gin.Engine) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ type InstancesCreateParam struct {
|
|||
FlowID int64 `json:"flow_id"`
|
||||
ApplicantKey string `json:"applicant_key"` //申请人ID
|
||||
CreatorKey string `json:"creator_key"`
|
||||
AssociateKey string `json:"associate_key"`
|
||||
TenantKey string `json:"tenant_key"`
|
||||
}
|
||||
|
||||
// InstancesCreate handler
|
||||
|
@ -33,6 +35,13 @@ func (api *FlowInstanceApi) InstancesCreate(c *gin.Context) {
|
|||
data := make(map[string]interface{})
|
||||
data[base.ApplicantKey] = param.ApplicantKey
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
Steps []*InstanceStepDTO `json:"steps"` // 实例步骤
|
||||
DynamicPathConfigs []*DynamicPathConfigDTO `json:"dynamic_path_configs"` // 动态路径配置,自定义,不直接存储
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type CurrentStepDTO struct {
|
||||
|
@ -25,6 +26,7 @@ type InstanceStepDTO struct {
|
|||
ApproverComments string `json:"approver_comments"` // 审批意见
|
||||
IsDynamic bool `json:"is_dynamic"` // 是否为动态步骤
|
||||
Records []*ApprovalRecordDTO `json:"records"` // 审批记录
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type ApprovalRecordDTO struct {
|
||||
|
@ -34,6 +36,7 @@ type ApprovalRecordDTO struct {
|
|||
Status string `json:"status"` // 审批状态
|
||||
Comments string `json:"comments"` // 审批意见
|
||||
IsTimeout bool `json:"is_timeout"` // 是否超时
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type DynamicPathConfigDTO struct {
|
||||
|
@ -43,4 +46,5 @@ type DynamicPathConfigDTO struct {
|
|||
ToStepID int64 `json:"to_step_id"` // 目标步骤ID
|
||||
IsParallel bool `json:"is_parallel"` // 是否并行
|
||||
Priority int `json:"priority"` // 路径优先级
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ import (
|
|||
func MapApprovalInstanceToDTOBatch(approvalInstances []*instanceModel.ApprovalInstance) ([]*ApprovalInstanceDTO, error) {
|
||||
res := make([]*ApprovalInstanceDTO, 0, len(approvalInstances))
|
||||
for _, instance := range approvalInstances {
|
||||
for _, step := range instance.Steps {
|
||||
step.Status = step.GetStatus()
|
||||
}
|
||||
dto, err := MapApprovalInstanceToDTO(instance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -21,6 +24,10 @@ func MapApprovalInstanceToDTO(approvalInstance *instanceModel.ApprovalInstance)
|
|||
// 创建目标 ApprovalInstanceDTO 对象
|
||||
approvalInstanceDTO := &ApprovalInstanceDTO{}
|
||||
|
||||
for _, step := range approvalInstance.Steps {
|
||||
step.Status = step.GetStatus()
|
||||
}
|
||||
|
||||
// 使用 Convert 方法将 实体对象 转换为 DTO
|
||||
if err := utils.Convert(approvalInstance, approvalInstanceDTO); err != nil {
|
||||
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": {
|
||||
"post": {
|
||||
"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": {
|
||||
"post": {
|
||||
"description": "输入你的接口总结详情",
|
||||
|
@ -673,6 +837,9 @@ const docTemplate = `{
|
|||
"description": "主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "审批状态",
|
||||
"type": "string"
|
||||
|
@ -709,6 +876,9 @@ const docTemplate = `{
|
|||
"description": "是否超时",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "审批状态",
|
||||
"type": "string"
|
||||
|
@ -745,6 +915,9 @@ const docTemplate = `{
|
|||
"description": "是否并行",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "路径优先级",
|
||||
"type": "integer"
|
||||
|
@ -778,6 +951,9 @@ const docTemplate = `{
|
|||
"description": "是否为动态步骤",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"records": {
|
||||
"description": "审批记录",
|
||||
"type": "array",
|
||||
|
@ -839,9 +1015,53 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"flow_instance.InstancesStartRuleParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"instance_id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flow_instance.InstancesStepsAddParam": {
|
||||
"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": {
|
||||
"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": {
|
||||
"post": {
|
||||
"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": {
|
||||
"post": {
|
||||
"description": "输入你的接口总结详情",
|
||||
|
@ -666,6 +830,9 @@
|
|||
"description": "主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "审批状态",
|
||||
"type": "string"
|
||||
|
@ -702,6 +869,9 @@
|
|||
"description": "是否超时",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"description": "审批状态",
|
||||
"type": "string"
|
||||
|
@ -738,6 +908,9 @@
|
|||
"description": "是否并行",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "路径优先级",
|
||||
"type": "integer"
|
||||
|
@ -771,6 +944,9 @@
|
|||
"description": "是否为动态步骤",
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"records": {
|
||||
"description": "审批记录",
|
||||
"type": "array",
|
||||
|
@ -832,9 +1008,53 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"flow_instance.InstancesStartRuleParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"instance_id": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"flow_instance.InstancesStepsAddParam": {
|
||||
"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": {
|
||||
"type": "object"
|
||||
},
|
||||
|
|
|
@ -97,6 +97,8 @@ definitions:
|
|||
id:
|
||||
description: 主键ID
|
||||
type: integer
|
||||
key:
|
||||
type: string
|
||||
status:
|
||||
description: 审批状态
|
||||
type: string
|
||||
|
@ -123,6 +125,8 @@ definitions:
|
|||
is_timeout:
|
||||
description: 是否超时
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
status:
|
||||
description: 审批状态
|
||||
type: string
|
||||
|
@ -148,6 +152,8 @@ definitions:
|
|||
is_parallel:
|
||||
description: 是否并行
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
priority:
|
||||
description: 路径优先级
|
||||
type: integer
|
||||
|
@ -172,6 +178,8 @@ definitions:
|
|||
is_dynamic:
|
||||
description: 是否为动态步骤
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
records:
|
||||
description: 审批记录
|
||||
items:
|
||||
|
@ -213,8 +221,36 @@ definitions:
|
|||
instance_id:
|
||||
type: integer
|
||||
type: object
|
||||
flow_instance.InstancesStartRuleParam:
|
||||
properties:
|
||||
instance_id:
|
||||
type: integer
|
||||
type: object
|
||||
flow_instance.InstancesStepsAddParam:
|
||||
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:
|
||||
type: object
|
||||
flow_instance.InstancesStepsUpdateParam:
|
||||
|
@ -473,6 +509,33 @@ paths:
|
|||
summary: 启动审批流
|
||||
tags:
|
||||
- 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:
|
||||
post:
|
||||
consumes:
|
||||
|
@ -500,6 +563,87 @@ paths:
|
|||
summary: 输入你的接口总结
|
||||
tags:
|
||||
- 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:
|
||||
post:
|
||||
consumes:
|
||||
|
|
|
@ -38,18 +38,23 @@ func NewOrmInstanceRepositoryImplAndRegister(container framework.Container) {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (u *InstanceRepositoryImpl) FindByIDFromDB(id int64) (*InstanceModel.ApprovalInstance, error) {
|
||||
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
|
||||
}
|
||||
|
||||
func (u *InstanceRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*InstanceModel.ApprovalInstance, error) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ func (u *FlowRepositoryImpl) FindByIDFromDB(id int64) (*FlowDefinitionModule.App
|
|||
|
||||
func (u *FlowRepositoryImpl) FindByIDsFromDB(ids []int64) ([]*FlowDefinitionModule.ApprovalFlow, error) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ type NodeManager interface {
|
|||
SetNodes([]AbstractNode)
|
||||
GetNodeMap() map[string]AbstractNode
|
||||
NewNodePathConfig(fromNodeKey, toNodeKey string) AbstractNodePathConfig
|
||||
Delete()
|
||||
}
|
||||
|
||||
type NodeManagerS struct {
|
||||
|
@ -26,6 +27,7 @@ type AbstractNode interface {
|
|||
GetPathConfigs() []AbstractNodePathConfig
|
||||
SetPathConfigs([]AbstractNodePathConfig)
|
||||
GetKey() string
|
||||
Delete()
|
||||
}
|
||||
|
||||
type AbstractNodePathConfig interface {
|
||||
|
@ -33,6 +35,7 @@ type AbstractNodePathConfig interface {
|
|||
GetNodeID() int64
|
||||
GetFromNodeKey() string
|
||||
GetToNodeKey() string
|
||||
Delete()
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
|
@ -270,9 +273,11 @@ func addPath(nct NodeManager, fromNode, toNode AbstractNode) {
|
|||
func removePath(nct NodeManager, fromNode, toNode AbstractNode) {
|
||||
var newPathConfigs []AbstractNodePathConfig
|
||||
for _, pc := range fromNode.GetPathConfigs() {
|
||||
if !(pc.GetFromNodeKey() == fromNode.GetKey() && pc.GetToNodeKey() == toNode.GetKey()) {
|
||||
newPathConfigs = append(newPathConfigs, pc)
|
||||
if pc.GetFromNodeKey() == fromNode.GetKey() && pc.GetToNodeKey() == toNode.GetKey() {
|
||||
// 使用软删除的方式
|
||||
pc.Delete()
|
||||
}
|
||||
newPathConfigs = append(newPathConfigs, pc)
|
||||
}
|
||||
fromNode.SetPathConfigs(newPathConfigs)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ type ApprovalCondition interface {
|
|||
}
|
||||
|
||||
type ApprovalConditionCommon struct {
|
||||
ApprovalCondition
|
||||
ApprovalCondition `gorm:"-"`
|
||||
ConditionExpression string `gorm:"type:text" json:"condition_expression"` // 条件表达式
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package flow_definition
|
|||
import (
|
||||
"approveflow/app/base"
|
||||
userProvider "approveflow/app/provider/user"
|
||||
"encoding/json"
|
||||
"github.com/Superdanda/hade/framework/gin"
|
||||
)
|
||||
|
||||
|
@ -22,6 +23,14 @@ type DynamicApprovalStepConfig struct {
|
|||
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 创建审批人为直属领导审批规则
|
||||
func NewDirectSupervisorRule() *DynamicApprovalStepConfig {
|
||||
directSupervisorApproval := &DynamicApprovalStepConfig{
|
||||
|
|
|
@ -15,6 +15,7 @@ type ApprovalFlow struct {
|
|||
Description string `gorm:"type:text" json:"description"` // 流程描述
|
||||
Steps []*ApprovalStep `gorm:"foreignKey:FlowID;constraint:OnDelete:CASCADE" json:"steps"` // 流程步骤
|
||||
NodeMap map[string]connect.AbstractNode `gorm:"-" json:"node_map"` // 流程步骤
|
||||
TenantKey string `gorm:"type:varchar(50);not null" json:"tenant_key"`
|
||||
base.Model // 通用字段,包括创建时间、更新时间等
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ func (step *ApprovalStep) SetPathConfigs(configs []connect.AbstractNodePathConfi
|
|||
if err != nil {
|
||||
panic(fmt.Sprintf("Error in SetPathConfigs: %v", err))
|
||||
}
|
||||
for _, path := range step.PathConfigs {
|
||||
path.Delete()
|
||||
}
|
||||
step.PathConfigs = convertedConfigs
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package flow_definition
|
||||
|
||||
import (
|
||||
"approveflow/app/provider/abstract/connect"
|
||||
"context"
|
||||
"fmt"
|
||||
"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 {
|
||||
return f.handlerFlow(ctx, flowID, func(ctx context.Context, flow *ApprovalFlow) error {
|
||||
fromStep, err := flow.GetStepByKey(fromStepId)
|
||||
_, err = flow.GetStepByKey(toStepKey)
|
||||
|
||||
toStep, err := flow.GetStepByKey(toStepKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path, ok := fromStep.GetPathByToKey(toStepKey)
|
||||
if !ok {
|
||||
return errors.New("这两个节点不相邻")
|
||||
}
|
||||
_, toPath := path.NewPathWithStep(step)
|
||||
err = step.AddPathConfig(toPath)
|
||||
err = flow.AddStep(step)
|
||||
err = connect.InsertNodeBetween(flow, fromStep, toStep, step)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ type Service interface {
|
|||
CreateInstance(ctx *gin.Context, approvalFlow *flow_definition.ApprovalFlow, data map[string]interface{}) (*model.ApprovalInstance, error)
|
||||
// StartInstance 功能:启动新的审批流程实例。
|
||||
StartInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||
// StartInstanceRule 功能:启动新的审批流程实例规则。
|
||||
StartInstanceRule(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||
// GetInstance 功能:获取指定流程实例的详细信息。
|
||||
GetInstance(ctx context.Context, instanceID int64) (*model.ApprovalInstance, error)
|
||||
// GetInstancePage 功能:分页查询流程实例的详细信息。
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
const (
|
||||
StatusCreated = "Created" // 审批实例已创建
|
||||
StatusReject = "Reject" // 审批实例已创建
|
||||
StatusInProgress = "InProgress" // 审批进行中
|
||||
StatusCompleted = "Completed" // 审批完成
|
||||
StatusCancelled = "Cancelled" // 审批取消
|
||||
|
@ -26,14 +27,47 @@ type ApprovalInstance struct {
|
|||
FlowID int64 `gorm:"type:bigint;index;not null" json:"flow_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
|
||||
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
|
||||
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
|
||||
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 {
|
||||
return utils.ConvertToAbstractNodes(instance.Steps, func(step *InstanceStep) connect.AbstractNode {
|
||||
return step
|
||||
|
@ -41,24 +75,41 @@ func (instance *ApprovalInstance) GetNodes() []connect.AbstractNode {
|
|||
}
|
||||
|
||||
func (instance *ApprovalInstance) SetNodes(nodes []connect.AbstractNode) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
specificType, _ := utils.ConvertToSpecificType[*InstanceStep, connect.AbstractNode](nodes, func(node connect.AbstractNode) (*InstanceStep, bool) {
|
||||
return node.(*InstanceStep), true
|
||||
})
|
||||
instance.Steps = specificType
|
||||
}
|
||||
|
||||
func (instance *ApprovalInstance) GetNodeMap() map[string]connect.AbstractNode {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
if instance.NodeMap == nil {
|
||||
instance.NodeMap = map[string]connect.AbstractNode{}
|
||||
connect.InitializeNodeMap(instance)
|
||||
}
|
||||
return instance.NodeMap
|
||||
}
|
||||
|
||||
func (instance *ApprovalInstance) NewNodePathConfig(fromNodeKey, toNodeKey string) connect.AbstractNodePathConfig {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
fromStep, err := instance.GetStepByKey(fromNodeKey)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return NewDynamicPathConfig(instance.ID, fromStep.ID, fromNodeKey, toNodeKey, false)
|
||||
}
|
||||
|
||||
// CurrentStep 目前审批中的节点
|
||||
type CurrentStep struct {
|
||||
CurrentStepId int64 `gorm:"type:bigint;index;not null" json:"current_step_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 初始化创建一个审批流实例
|
||||
|
@ -78,6 +129,15 @@ func NewApprovalInstance(
|
|||
Steps: []*InstanceStep{},
|
||||
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
|
||||
firstStep, err := approvalFlow.FirstStep()
|
||||
if err != nil {
|
||||
|
@ -85,15 +145,19 @@ func NewApprovalInstance(
|
|||
}
|
||||
// Build the steps recursively
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 赋予创建状态
|
||||
instance.AddCreatedEvent()
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// Check if this step has already been processed to avoid cycles
|
||||
if existingInstanceStep, ok := processedSteps[currentApprovalStep.Key]; ok {
|
||||
|
@ -102,15 +166,21 @@ func buildInstanceSteps(ctx *gin.Context, instance *ApprovalInstance, currentApp
|
|||
}
|
||||
return nil
|
||||
}
|
||||
// Create a new instance step
|
||||
|
||||
var approverKey string
|
||||
if currentApprovalStep.DynamicConfig != nil {
|
||||
approver, err := currentApprovalStep.DynamicConfig.GetApprover(ctx, data)
|
||||
if err != nil {
|
||||
approverKey = ""
|
||||
} else {
|
||||
approverKey = approver.Key
|
||||
}
|
||||
} else {
|
||||
approverKey = ""
|
||||
}
|
||||
|
||||
currentInstanceStep := NewInstanceStep(currentApprovalStep, approverKey, false)
|
||||
|
||||
// Insert the instance step into the instance
|
||||
if previousInstanceStep == nil {
|
||||
connect.InsertNodeFirst(instance, currentInstanceStep)
|
||||
|
@ -119,14 +189,16 @@ func buildInstanceSteps(ctx *gin.Context, instance *ApprovalInstance, currentApp
|
|||
}
|
||||
// Mark this step as processed
|
||||
processedSteps[currentApprovalStep.Key] = currentInstanceStep
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
for _, nextStep := range nextSteps {
|
||||
for _, nextStep := range nextFlowSteps {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -162,7 +234,7 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
|||
instance.RLock()
|
||||
defer instance.RUnlock()
|
||||
|
||||
if instance.Status != StatusCreated {
|
||||
if instance.GetStatus() != StatusCreated && instance.GetStatus() != StatusReject {
|
||||
return fmt.Errorf("审批流程已启动或已完成,无法再次启动")
|
||||
}
|
||||
|
||||
|
@ -174,7 +246,7 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
|||
|
||||
// 设置当前步骤为第一个步骤,并更改状态
|
||||
instance.AddCurrentStepID(firstStep)
|
||||
instance.Status = StatusInProgress
|
||||
instance.AddInProgressEvent()
|
||||
|
||||
err = instance.SendApprovalNotification(firstStep, ctx)
|
||||
if err != nil {
|
||||
|
@ -210,19 +282,19 @@ func (instance *ApprovalInstance) MoveToNextStep() error {
|
|||
}
|
||||
currentStep := currentStepSlice[0]
|
||||
// 完成当前步骤
|
||||
currentStep.Status = StepStatusCompleted
|
||||
currentStep.AddCompletedEvent()
|
||||
|
||||
// 获取下一个步骤
|
||||
var nextStep *InstanceStep
|
||||
nextStepArr, err := instance.getNextStep(currentStep, dataMap)
|
||||
if nextStepArr != nil && len(nextStepArr) == 0 {
|
||||
if nextStepArr != nil && len(nextStepArr) == 1 {
|
||||
nextStep = nextStepArr[0]
|
||||
} else {
|
||||
return errors.New("暂时不支持并行审批")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
instance.Status = StatusCompleted // 流程结束
|
||||
instance.AddCompletedEvent() // 流程结束
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -230,7 +302,8 @@ func (instance *ApprovalInstance) MoveToNextStep() error {
|
|||
instance.RemoveCurrentStepID(currentStep.ID)
|
||||
instance.AddCurrentStepID(nextStep)
|
||||
|
||||
nextStep.Status = StepStatusPending
|
||||
nextStep.AddPendingEvent()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -303,7 +376,7 @@ func (instance *ApprovalInstance) GetStepByKey(key string) (*InstanceStep, error
|
|||
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
|
||||
|
@ -324,6 +397,7 @@ func (instance *ApprovalInstance) RemoveCurrentStepID(stepID int64) {
|
|||
for i, s := range instance.CurrentStepIDs {
|
||||
if s.CurrentStepId == stepID {
|
||||
// Remove the step by slicing
|
||||
s.Delete()
|
||||
instance.CurrentStepIDs = append(instance.CurrentStepIDs[:i], instance.CurrentStepIDs[i+1:]...)
|
||||
return
|
||||
}
|
||||
|
@ -343,7 +417,7 @@ func (instance *ApprovalInstance) HasCurrentStepID(stepID int64) bool {
|
|||
// GetCurrentSteps returns a copy of the CurrentSteps slice
|
||||
func (instance *ApprovalInstance) GetCurrentSteps() []*InstanceStep {
|
||||
// Return a copy of the slice to avoid modifications
|
||||
currentSteps := make([]*InstanceStep, len(instance.CurrentStepIDs))
|
||||
var currentSteps []*InstanceStep
|
||||
for _, step := range instance.Steps {
|
||||
if instance.HasCurrentStepID(step.ID) {
|
||||
currentSteps = append(currentSteps, step)
|
||||
|
@ -362,9 +436,60 @@ func (instance *ApprovalInstance) GetCurrentStepsById(id int64) *InstanceStep {
|
|||
return nil
|
||||
}
|
||||
|
||||
// executeApprovalStep 执行审批步骤
|
||||
func (instance *ApprovalInstance) executeApprovalStep(approvalFlow flow_definition.ApprovalFlow) error {
|
||||
for _, instanceStep := range instance.GetCurrentSteps() {
|
||||
func (instance *ApprovalInstance) ExecuteApprovalReversal(reversal *ApprovalReversal) error {
|
||||
step, err := instance.GetStepByKey(reversal.StepKey)
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
|
||||
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 (
|
||||
"approveflow/app/base"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -21,6 +22,14 @@ type ApprovalRecord struct {
|
|||
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 创建新的审批记录
|
||||
func (record *ApprovalRecord) CreateRecord(stepID int64, approverKey, status, comments string) {
|
||||
record.InstanceStepID = stepID
|
||||
|
|
|
@ -1,28 +1,48 @@
|
|||
package model
|
||||
|
||||
import "approveflow/app/base"
|
||||
import (
|
||||
"approveflow/app/base"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// ApprovalReversal 审批反转表
|
||||
type ApprovalReversal struct {
|
||||
InstanceID int64 `gorm:"index;not null" json:"instance_id"` // 关联的审批实例ID
|
||||
StepID int64 `gorm:"index;not null" json:"step_id"` // 关联的步骤ID
|
||||
ReversedStepID int64 `gorm:"index;not null" json:"reversed_step_id"` // 反转的步骤ID
|
||||
InstanceID int64 `gorm:"type:bigint;index;not null" json:"instance_id"` // 关联的审批实例ID
|
||||
StepID int64 `gorm:"type:bigint;index;not null" json:"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"` // 修正动作
|
||||
Reason string `gorm:"type:text" json:"reason"` // 反转原因
|
||||
base.Model
|
||||
}
|
||||
|
||||
// ReverseStep 执行步骤的反转操作
|
||||
func (reversal *ApprovalReversal) ReverseStep(step *InstanceStep, reason string) error {
|
||||
reversal.InstanceID = step.InstanceID
|
||||
reversal.StepID = step.StepID
|
||||
reversal.ReversedStepID = step.ID
|
||||
reversal.Reason = reason
|
||||
reversal.FixAction = "Reversal"
|
||||
// FixAction 定义常量表示审批反转的修正动作
|
||||
const (
|
||||
FixActionReApproveAndUpdateData = "ReApproveAndUpdateData"
|
||||
FixActionReApprove = "ReApprove" // 重新审批
|
||||
FixActionReassignApprover = "ReassignApprover" // 重新指定审批人
|
||||
FixActionRollback = "Rollback" // 回滚到某个步骤
|
||||
FixActionUpdateData = "UpdateData" // 更新审批数据
|
||||
FixActionReopen = "Reopen" // 重新打开审批流程
|
||||
)
|
||||
|
||||
// 更新步骤状态为反转
|
||||
step.Status = "Reversed"
|
||||
return nil
|
||||
func (reversal *ApprovalReversal) MarshalBinary() ([]byte, error) {
|
||||
return json.Marshal(reversal)
|
||||
}
|
||||
|
||||
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 执行修正操作
|
||||
|
|
|
@ -2,6 +2,7 @@ package model
|
|||
|
||||
import (
|
||||
"approveflow/app/base"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -15,3 +16,17 @@ type BatchApprovalTask struct {
|
|||
ActionTime time.Time `json:"action_time"` // 审批时间
|
||||
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 (
|
||||
"approveflow/app/base"
|
||||
"approveflow/app/provider/flow_definition"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// InstancePathConfig 动态路径配置表结构
|
||||
|
@ -18,19 +19,27 @@ type InstancePathConfig struct {
|
|||
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
|
||||
}
|
||||
|
||||
func (d InstancePathConfig) GetNodeID() int64 {
|
||||
func (d *InstancePathConfig) GetNodeID() int64 {
|
||||
return d.NodeID
|
||||
}
|
||||
|
||||
func (d InstancePathConfig) GetFromNodeKey() string {
|
||||
func (d *InstancePathConfig) GetFromNodeKey() string {
|
||||
return d.FromNodeKey
|
||||
}
|
||||
|
||||
func (d InstancePathConfig) GetToNodeKey() string {
|
||||
func (d *InstancePathConfig) GetToNodeKey() string {
|
||||
return d.ToNodeKey
|
||||
}
|
||||
|
||||
|
@ -47,11 +56,11 @@ func NewDynamicPathConfig(instanceID, nodeId int64, FromStepKey, ToStepKey strin
|
|||
}
|
||||
|
||||
// IsConditionMet 判断路径条件是否满足
|
||||
func (a *InstancePathConfig) IsConditionMet(data map[string]interface{}) (bool, error) {
|
||||
if a.ConditionExpression == "" {
|
||||
func (d *InstancePathConfig) IsConditionMet(data map[string]interface{}) (bool, error) {
|
||||
if d.ConditionExpression == "" {
|
||||
return true, nil // 无条件,默认满足
|
||||
}
|
||||
result, err := a.EvaluateCondition(data)
|
||||
result, err := d.EvaluateCondition(data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"approveflow/app/provider/abstract/connect"
|
||||
"approveflow/app/provider/flow_definition"
|
||||
"approveflow/app/utils"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -25,14 +26,75 @@ type InstanceStep struct {
|
|||
StepName string `gorm:"type:varchar(50);not null" json:"step_name"`
|
||||
StepCode string `gorm:"type:varchar(100)" json:"step_code"` // 步骤编号用于标识特殊的审批节点
|
||||
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"` // 审批意见
|
||||
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"` // 动态路径配置,自定义,不直接存储
|
||||
Records []*ApprovalRecord `gorm:"foreignKey:InstanceStepID;constraint:OnDelete:CASCADE" json:"records"` // 审批记录
|
||||
Reversals []*ApprovalReversal `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"reversals"` // 反转记录
|
||||
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 {
|
||||
return utils.ConvertToAbstractNodes(step.InstancePathConfigs, func(t *InstancePathConfig) connect.AbstractNodePathConfig {
|
||||
return t
|
||||
|
@ -60,19 +122,19 @@ func NewInstanceStep(flowStep *flow_definition.ApprovalStep, approverKey string,
|
|||
StepName: flowStep.Name,
|
||||
StepCode: flowStep.StepCode,
|
||||
ApproverKey: approverKey,
|
||||
Status: StepStatusPending,
|
||||
IsDynamic: isDynamic,
|
||||
}
|
||||
instanceStep.AddPendingEvent()
|
||||
instanceStep.Key = uuid.New().String()
|
||||
return instanceStep
|
||||
}
|
||||
|
||||
// Approve 审批通过
|
||||
func (step *InstanceStep) Approve(comments string) error {
|
||||
if step.Status != StepStatusPending {
|
||||
if step.GetStatus() != StepStatusPending {
|
||||
return fmt.Errorf("当前步骤不是待审批状态")
|
||||
}
|
||||
step.Status = StepStatusApproved
|
||||
step.AddApprovedEvent()
|
||||
step.ApproverComments = comments
|
||||
step.addApprovalRecord(StepStatusApproved, comments)
|
||||
return nil
|
||||
|
@ -80,10 +142,10 @@ func (step *InstanceStep) Approve(comments string) error {
|
|||
|
||||
// Reject 审批驳回
|
||||
func (step *InstanceStep) Reject(comments string) error {
|
||||
if step.Status != StepStatusPending {
|
||||
return fmt.Errorf("当前步骤不是待审批状态")
|
||||
}
|
||||
step.Status = StepStatusRejected
|
||||
//if step.GetStatus() != StepStatusPending {
|
||||
// return fmt.Errorf("当前步骤不是待审批状态")
|
||||
//}
|
||||
step.AddRejectedEvent()
|
||||
step.ApproverComments = comments
|
||||
step.addApprovalRecord(StepStatusRejected, comments)
|
||||
return nil
|
||||
|
@ -99,3 +161,9 @@ func (step *InstanceStep) addApprovalRecord(status string, comments string) {
|
|||
}
|
||||
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) {
|
||||
return f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
||||
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
|
||||
})
|
||||
}
|
||||
|
@ -42,13 +55,21 @@ func (f *FlowInstanceService) GetInstancePage(ctx context.Context, pageNum, page
|
|||
}
|
||||
|
||||
func (f *FlowInstanceService) CancelInstance(ctx context.Context, instanceID int64) error {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
_, err := f.handlerInstance(ctx, instanceID, func(ctx context.Context, instance *model.ApprovalInstance) error {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -150,6 +172,11 @@ func (f *FlowInstanceService) handlerInstance(ctx context.Context, instanceID in
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = f.GetFlowInstanceRepository().SaveInstance(ctx, instance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,26 @@ type UserService struct {
|
|||
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) {
|
||||
container := params[0].(framework.Container)
|
||||
return &UserService{container: container}, nil
|
||||
|
|
Loading…
Reference in New Issue