426 lines
13 KiB
Go
426 lines
13 KiB
Go
package model
|
|
|
|
import (
|
|
"approveflow/app/base"
|
|
"approveflow/app/provider/abstract/connect"
|
|
"approveflow/app/provider/flow_definition"
|
|
"approveflow/app/utils"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/Superdanda/hade/framework/gin"
|
|
"github.com/pkg/errors"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
StatusCreated = "Created" // 审批实例已创建
|
|
StatusInProgress = "InProgress" // 审批进行中
|
|
StatusCompleted = "Completed" // 审批完成
|
|
StatusCancelled = "Cancelled" // 审批取消
|
|
)
|
|
|
|
// ApprovalInstance 审批实例表
|
|
type ApprovalInstance struct {
|
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"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
|
|
CreatorKey string `gorm:"type:bigint;not null" json:"creator_id"` // 创建者ID
|
|
Status string `gorm:"type:varchar(50);not null" 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
|
|
sync.RWMutex
|
|
base.Model
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetNodes() []connect.AbstractNode {
|
|
return utils.ConvertToAbstractNodes(instance.Steps, func(step *InstanceStep) connect.AbstractNode {
|
|
return step
|
|
})
|
|
}
|
|
|
|
func (instance *ApprovalInstance) SetNodes(nodes []connect.AbstractNode) {
|
|
//TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetNodeMap() map[string]connect.AbstractNode {
|
|
//TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
func (instance *ApprovalInstance) NewNodePathConfig(fromNodeKey, toNodeKey string) connect.AbstractNodePathConfig {
|
|
//TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
// 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"`
|
|
}
|
|
|
|
// NewApprovalInstance 初始化创建一个审批流实例
|
|
func NewApprovalInstance(
|
|
ctx *gin.Context,
|
|
approvalFlow *flow_definition.ApprovalFlow,
|
|
data map[string]interface{}) (*ApprovalInstance, error) {
|
|
|
|
bytes, err := json.Marshal(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
instance := &ApprovalInstance{
|
|
FlowID: approvalFlow.ID,
|
|
ApplicantKey: data[base.ApplicantKey].(string),
|
|
CreatorKey: data[base.CreatorKey].(string),
|
|
Steps: []*InstanceStep{},
|
|
Data: string(bytes),
|
|
}
|
|
// Get the first step of the approval flow
|
|
firstStep, err := approvalFlow.FirstStep()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Build the steps recursively
|
|
processedSteps := make(map[string]*InstanceStep)
|
|
err = buildInstanceSteps(ctx, instance, firstStep, nil, data, processedSteps)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return instance, nil
|
|
}
|
|
|
|
// buildInstanceSteps recursively builds instance steps from approval steps
|
|
func buildInstanceSteps(ctx *gin.Context, 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 {
|
|
if previousInstanceStep != nil {
|
|
connect.InsertNodeAfter(instance, previousInstanceStep, existingInstanceStep)
|
|
}
|
|
return nil
|
|
}
|
|
// Create a new instance step
|
|
var approverKey string
|
|
approver, err := currentApprovalStep.DynamicConfig.GetApprover(ctx, data)
|
|
if err != nil {
|
|
approverKey = ""
|
|
} else {
|
|
approverKey = approver.Key
|
|
}
|
|
currentInstanceStep := NewInstanceStep(currentApprovalStep, approverKey, false)
|
|
// Insert the instance step into the instance
|
|
if previousInstanceStep == nil {
|
|
connect.InsertNodeFirst(instance, currentInstanceStep)
|
|
} else {
|
|
connect.InsertNodeAfter(instance, previousInstanceStep, currentInstanceStep)
|
|
}
|
|
// Mark this step as processed
|
|
processedSteps[currentApprovalStep.Key] = currentInstanceStep
|
|
// Get the next steps and recursively build them
|
|
nextSteps, err := connect.GetNextNodes(instance, currentApprovalStep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, nextStep := range nextSteps {
|
|
nextApprovalStep := nextStep.(*flow_definition.ApprovalStep)
|
|
err := buildInstanceSteps(ctx, instance, nextApprovalStep, currentInstanceStep, data, processedSteps)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SendApprovalNotification 发送审批通知给第一个审批人的方法
|
|
func (instance *ApprovalInstance) SendApprovalNotification(step *InstanceStep, ctx context.Context) error {
|
|
|
|
// 向消息队列发送审批开始事件
|
|
|
|
//userService := container.MustMake(userProvider.Key).(userProvider.Service)
|
|
//approver, err := userService.GetUserByID(step.ApproverID)
|
|
//if err != nil {
|
|
// return fmt.Errorf("获取审批人失败: %v", err)
|
|
//}
|
|
//
|
|
//// 构建通知内容
|
|
//notification := fmt.Sprintf("审批流程已启动,请您审批步骤: %s", step.Name)
|
|
//
|
|
//// 发送通知
|
|
//err = sendNotificationToUser(approver, notification)
|
|
//if err != nil {
|
|
// return fmt.Errorf("发送通知失败: %v", err)
|
|
//}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Start 开始审批流程,设置第一个步骤为当前步骤
|
|
func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
|
instance.RLock()
|
|
defer instance.RUnlock()
|
|
|
|
if instance.Status != StatusCreated {
|
|
return fmt.Errorf("审批流程已启动或已完成,无法再次启动")
|
|
}
|
|
|
|
// 获取第一个审批步骤
|
|
firstStep, err := instance.getFirstStep()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 设置当前步骤为第一个步骤,并更改状态
|
|
instance.AddCurrentStepID(firstStep)
|
|
instance.Status = StatusInProgress
|
|
|
|
err = instance.SendApprovalNotification(firstStep, ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// getFirstStep 获取第一个审批步骤
|
|
func (instance *ApprovalInstance) getFirstStep() (*InstanceStep, error) {
|
|
for _, step := range instance.Steps {
|
|
if step.StepCode == flow_definition.StepStart {
|
|
return step, nil
|
|
}
|
|
}
|
|
return nil, errors.New("未找到起点")
|
|
}
|
|
|
|
// MoveToNextStep 移动到下一个步骤
|
|
func (instance *ApprovalInstance) MoveToNextStep() error {
|
|
instance.Lock()
|
|
defer instance.Unlock()
|
|
|
|
currentStepSlice := instance.GetCurrentSteps()
|
|
|
|
if currentStepSlice == nil || len(currentStepSlice) == 0 {
|
|
return fmt.Errorf("当前步骤不存在")
|
|
}
|
|
|
|
dataMap, err := instance.DataToMap()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
currentStep := currentStepSlice[0]
|
|
// 完成当前步骤
|
|
currentStep.Status = StepStatusCompleted
|
|
|
|
// 获取下一个步骤
|
|
var nextStep *InstanceStep
|
|
nextStepArr, err := instance.getNextStep(currentStep, dataMap)
|
|
if nextStepArr != nil && len(nextStepArr) == 0 {
|
|
nextStep = nextStepArr[0]
|
|
} else {
|
|
return errors.New("暂时不支持并行审批")
|
|
}
|
|
|
|
if err != nil {
|
|
instance.Status = StatusCompleted // 流程结束
|
|
return nil
|
|
}
|
|
|
|
// 设置新的当前步骤
|
|
instance.RemoveCurrentStepID(currentStep.ID)
|
|
instance.AddCurrentStepID(nextStep)
|
|
|
|
nextStep.Status = StepStatusPending
|
|
return nil
|
|
}
|
|
|
|
// getNextStep 获取下一个步骤
|
|
func (instance *ApprovalInstance) getNextStep(currentStep *InstanceStep, data map[string]interface{}) ([]*InstanceStep, error) {
|
|
pathConfigs := currentStep.InstancePathConfigs
|
|
var nextSteps []*InstanceStep
|
|
for _, pathConfig := range pathConfigs {
|
|
met, err := pathConfig.IsConditionMet(data)
|
|
if err != nil || !met {
|
|
continue
|
|
}
|
|
nextStep, err := instance.GetStepByKey(pathConfig.GetToNodeKey())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nextSteps = append(nextSteps, nextStep)
|
|
}
|
|
return nextSteps, nil
|
|
}
|
|
|
|
func (instance *ApprovalInstance) findStepByID(id int64) (*InstanceStep, error) {
|
|
for _, step := range instance.Steps {
|
|
if step.ID == id {
|
|
return step, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (instance *ApprovalInstance) findStepByKey(key string) (*InstanceStep, error) {
|
|
for _, step := range instance.Steps {
|
|
if step.Key == key {
|
|
return step, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (instance *ApprovalInstance) getStepByFlowStepID(flowStepId int64) *InstanceStep {
|
|
for _, step := range instance.Steps {
|
|
if step.StepID == flowStepId {
|
|
return step
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DataToMap 将 Data 字段转为 map[string]interface{}
|
|
func (instance *ApprovalInstance) DataToMap() (map[string]interface{}, error) {
|
|
var dataMap map[string]interface{}
|
|
if err := json.Unmarshal([]byte(instance.Data), &dataMap); err != nil {
|
|
return nil, fmt.Errorf("解析 Data 字段失败: %v", err)
|
|
}
|
|
return dataMap, nil
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetStep(id int64) (*InstanceStep, error) {
|
|
for _, step := range instance.Steps {
|
|
if step.ID == id {
|
|
return step, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("step with ID %d not found in approval flow", id)
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetStepByKey(key string) (*InstanceStep, error) {
|
|
for _, step := range instance.Steps {
|
|
if step.Key == key {
|
|
return step, nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("step with key %d not found in approval flow", key)
|
|
}
|
|
|
|
// AddCurrentStepID adds a new CurrentStep to the CurrentStepIDs slice if it does not already exist
|
|
func (instance *ApprovalInstance) AddCurrentStepID(step *InstanceStep) {
|
|
// Check if the step already exists
|
|
for _, s := range instance.CurrentStepIDs {
|
|
if s.CurrentStepId == step.ID {
|
|
return // Step already exists, do nothing
|
|
}
|
|
}
|
|
// Add the new step
|
|
instance.CurrentStepIDs = append(instance.CurrentStepIDs, &CurrentStep{CurrentStepId: step.ID, InstanceID: instance.ID})
|
|
}
|
|
|
|
// RemoveCurrentStepID removes a CurrentStep from the CurrentStepIDs slice based on its ID
|
|
func (instance *ApprovalInstance) RemoveCurrentStepID(stepID int64) {
|
|
// Find the index of the step to remove
|
|
for i, s := range instance.CurrentStepIDs {
|
|
if s.CurrentStepId == stepID {
|
|
// Remove the step by slicing
|
|
instance.CurrentStepIDs = append(instance.CurrentStepIDs[:i], instance.CurrentStepIDs[i+1:]...)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// HasCurrentStepID checks if a CurrentStep with a given ID exists in the CurrentStepIDs slice
|
|
func (instance *ApprovalInstance) HasCurrentStepID(stepID int64) bool {
|
|
for _, s := range instance.CurrentStepIDs {
|
|
if s.CurrentStepId == stepID {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 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))
|
|
for _, step := range instance.Steps {
|
|
if instance.HasCurrentStepID(step.ID) {
|
|
currentSteps = append(currentSteps, step)
|
|
}
|
|
}
|
|
return currentSteps
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetCurrentStepsById(id int64) *InstanceStep {
|
|
currentSteps := instance.GetCurrentSteps()
|
|
for _, step := range currentSteps {
|
|
if step.ID == id {
|
|
return step
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// executeApprovalStep 执行审批步骤
|
|
func (instance *ApprovalInstance) executeApprovalStep(approvalFlow flow_definition.ApprovalFlow) error {
|
|
for _, instanceStep := range instance.GetCurrentSteps() {
|
|
flowStep, err := approvalFlow.GetStep(instanceStep.StepID)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, rule := range flowStep.Rules {
|
|
// 评估条件表达式是否满足
|
|
dataToMap, err := instance.DataToMap()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
conditionMet, err := rule.EvaluateCondition(dataToMap)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if conditionMet {
|
|
switch rule.Action {
|
|
case flow_definition.ActionAutoApprove:
|
|
// 自动通过
|
|
err := instanceStep.Approve("自动通过")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
//case ActionAutoReject:
|
|
// // 自动驳回
|
|
// err := instanceService.RejectStep(ctx, instance, step, "自动驳回")
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// return nil
|
|
//case ActionReassignApprover:
|
|
// // 重新指定审批人
|
|
// newApprover, err := getNewApprover(container, data)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// step.ApproverID = newApprover.ID
|
|
// // 更新步骤信息
|
|
// err = updateApprovalStep(step)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// return nil
|
|
// 可以添加更多的 Action 处理逻辑
|
|
default:
|
|
return fmt.Errorf("unsupported action: %s", rule.Action)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil // 如果没有规则满足,正常返回
|
|
}
|
|
|
|
func (instance *ApprovalInstance) GetPathByFromStepKey(fromStepKey string) (*InstancePathConfig, error) {
|
|
|
|
return nil, nil
|
|
}
|