init: 条件流引擎初始提交
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.fsdpf.net/go/condflow"
|
||||
"git.fsdpf.net/go/condflow/tests/fixtures"
|
||||
"git.fsdpf.net/go/condition"
|
||||
"git.fsdpf.net/go/contracts/base"
|
||||
"git.fsdpf.net/go/reflux"
|
||||
"git.fsdpf.net/go/reflux/fieldx"
|
||||
"git.fsdpf.net/go/req"
|
||||
"git.fsdpf.net/go/req/resx"
|
||||
"github.com/samber/do/v2"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// CondFlowTestSuite 条件流测试套件
|
||||
type CondFlowTestSuite struct {
|
||||
suite.Suite
|
||||
app do.Injector
|
||||
flow *condflow.CondFlow
|
||||
executor condflow.ActionInvoker
|
||||
}
|
||||
|
||||
// SetupTest 在每个测试前运行
|
||||
func (s *CondFlowTestSuite) SetupTest() {
|
||||
// 初始化 DI 容器
|
||||
s.app = do.New()
|
||||
|
||||
// 创建 executor
|
||||
approveRes := resx.New(s.app, "Approval", "approvals",
|
||||
resx.WithUuid("550e8400-e29b-41d4-a716-446655440001"),
|
||||
resx.WithName("审批"),
|
||||
resx.WithFields(
|
||||
resx.NewResField("id", "", resx.FieldWithName("ID"), resx.FieldWithDataType(req.ResInteger)),
|
||||
resx.NewResField("created_user", "", resx.FieldWithName("创建者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("owned_user", "", resx.FieldWithName("拥有者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("created_at", "", resx.FieldWithName("创建时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
||||
resx.NewResField("updated_at", "", resx.FieldWithName("更新时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
||||
resx.NewResField("uuid", "", resx.FieldWithName("UUID"), resx.FieldWithDefault("sql:uuid()"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("status", "", resx.FieldWithName("状态"), resx.FieldWithDefault("pending"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("amount", "", resx.FieldWithName("审批金额"), resx.FieldWithDefault("0"), resx.FieldWithDataType(req.ResDecimal)),
|
||||
resx.NewResField("approver_role", "", resx.FieldWithName("审批人角色"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("approval_method", "", resx.FieldWithName("审批方式"), resx.FieldWithDataType(req.ResString)),
|
||||
),
|
||||
)
|
||||
|
||||
s.executor = condflow.NewActionInvoker(fixtures.NewApproveExecutor(approveRes), nil)
|
||||
|
||||
do.ProvideNamedValue(s.app, fmt.Sprintf("%s/ApproveExecutor", s.executor.Res().GetCode()), s.executor)
|
||||
|
||||
// 通过字符串验证预期的 action 是否注册成功
|
||||
expectedActions := []string{
|
||||
"AutoApprove",
|
||||
"Manager",
|
||||
"Director",
|
||||
"Reject",
|
||||
}
|
||||
|
||||
for _, actionName := range expectedActions {
|
||||
_, err := s.executor.GetAction(actionName)
|
||||
s.Require().NoError(err, "获取 action '%s' 失败", actionName)
|
||||
}
|
||||
|
||||
// 创建条件流
|
||||
s.flow = condflow.New("test-flow")
|
||||
}
|
||||
|
||||
// TearDownTest 在每个测试后运行
|
||||
func (s *CondFlowTestSuite) TearDownTest() {
|
||||
if s.app != nil {
|
||||
s.app.Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
// TestSmallAmountAutoApproval 测试小额自动审批
|
||||
func (s *CondFlowTestSuite) TestSmallAmountAutoApproval() {
|
||||
// 创建条件: 金额 <= 1000
|
||||
cond := condition.New(condition.Describe("小额自动审批"))
|
||||
cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING)))
|
||||
|
||||
config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"message": map[string]any{
|
||||
"type": "string",
|
||||
"value": "申请已自动通过",
|
||||
},
|
||||
})
|
||||
|
||||
// 创建条件分支,使用 action 名称字符串
|
||||
condCase := condflow.NewCondCase("auto-approve-small", cond, "Approval/ApproveExecutor@AutoApprove").
|
||||
WithPriority(100).
|
||||
WithActionConfig(config)
|
||||
|
||||
// 添加到流程
|
||||
s.flow.AddCase(condCase)
|
||||
|
||||
// 准备输入数据
|
||||
input := reflux.New(map[string]any{
|
||||
"amount": 500.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 80,
|
||||
},
|
||||
})
|
||||
|
||||
// 执行流程
|
||||
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
// TestManagerApproval 测试经理审批
|
||||
func (s *CondFlowTestSuite) TestManagerApproval() {
|
||||
// 创建条件: 1000 < 金额 <= 10000
|
||||
cond := condition.New(condition.Describe("经理审批"))
|
||||
cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING)))
|
||||
|
||||
config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"approver_role": map[string]any{
|
||||
"type": "string",
|
||||
"value": "manager",
|
||||
},
|
||||
"timeout_hours": map[string]any{
|
||||
"type": "string",
|
||||
"value": "24",
|
||||
},
|
||||
})
|
||||
|
||||
// 创建条件分支,使用 action 名称字符串
|
||||
condCase := condflow.NewCondCase("manager-approval", cond, "Approval/ApproveExecutor@Manager").
|
||||
WithPriority(90).
|
||||
WithActionConfig(config)
|
||||
|
||||
// 添加到流程
|
||||
s.flow.AddCase(condCase)
|
||||
|
||||
// 准备输入数据
|
||||
input := reflux.New(map[string]any{
|
||||
"amount": 5000.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 80,
|
||||
},
|
||||
})
|
||||
|
||||
// 执行流程
|
||||
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
// TestLowCreditReject 测试低信用评分拒绝
|
||||
func (s *CondFlowTestSuite) TestLowCreditReject() {
|
||||
// 创建条件: 用户信用评分 < 60
|
||||
cond := condition.New(condition.Describe("信用不足拒绝"))
|
||||
cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING)))
|
||||
|
||||
config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"reason": map[string]any{
|
||||
"type": "string",
|
||||
"value": "信用评分不足",
|
||||
},
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"suggest_retry": map[string]any{
|
||||
"type": "string",
|
||||
"value": "false",
|
||||
},
|
||||
})
|
||||
|
||||
// 创建条件分支,使用 action 名称字符串
|
||||
condCase := condflow.NewCondCase("reject-low-credit", cond, "Approval/ApproveExecutor@Reject").
|
||||
WithPriority(200).
|
||||
WithActionConfig(config)
|
||||
|
||||
// 添加到流程
|
||||
s.flow.AddCase(condCase)
|
||||
|
||||
// 准备输入数据
|
||||
input := reflux.New(map[string]any{
|
||||
"amount": 500.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 50,
|
||||
},
|
||||
})
|
||||
|
||||
// 执行流程
|
||||
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
||||
s.NoError(err)
|
||||
}
|
||||
|
||||
// TestMultipleCases 测试多个条件分支
|
||||
func (s *CondFlowTestSuite) TestMultipleCases() {
|
||||
// Case 1: 小额自动审批
|
||||
case1Cond := condition.New(condition.Describe("小额自动审批"))
|
||||
case1Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING)))
|
||||
|
||||
case1 := condflow.NewCondCase("auto-approve-small", case1Cond, "Approval/ApproveExecutor@AutoApprove").
|
||||
WithPriority(100)
|
||||
|
||||
// Case 2: 经理审批
|
||||
case2Cond := condition.New(condition.Describe("经理审批"))
|
||||
case2Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING)))
|
||||
|
||||
case2 := condflow.NewCondCase("manager-approval", case2Cond, "Approval/ApproveExecutor@Manager").
|
||||
WithPriority(90)
|
||||
|
||||
// Case 3: 总监审批
|
||||
case3Cond := condition.New(condition.Describe("总监审批"))
|
||||
case3Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("10000", condition.STRING)))
|
||||
|
||||
case3 := condflow.NewCondCase("director-approval", case3Cond, "Approval/ApproveExecutor@Director").
|
||||
WithPriority(80)
|
||||
|
||||
// Case 4: 低信用拒绝(最高优先级)
|
||||
case4Cond := condition.New(condition.Describe("信用不足拒绝"))
|
||||
case4Cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING)))
|
||||
|
||||
case4Config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"reason": map[string]any{
|
||||
"type": "string",
|
||||
"value": "信用评分不足",
|
||||
},
|
||||
})
|
||||
|
||||
case4 := condflow.NewCondCase("reject-low-credit", case4Cond, "Approval/ApproveExecutor@Reject").
|
||||
WithPriority(200).
|
||||
WithActionConfig(case4Config)
|
||||
|
||||
// 添加所有条件分支
|
||||
s.flow.AddCase(case4).
|
||||
AddCase(case1).
|
||||
AddCase(case2).
|
||||
AddCase(case3)
|
||||
|
||||
// 测试不同的输入数据
|
||||
testCases := []struct {
|
||||
name string
|
||||
input map[string]any
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
name: "小额正常用户",
|
||||
input: map[string]any{
|
||||
"amount": 500.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 80,
|
||||
},
|
||||
},
|
||||
expect: "auto-approve",
|
||||
},
|
||||
{
|
||||
name: "中额正常用户",
|
||||
input: map[string]any{
|
||||
"amount": 5000.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 80,
|
||||
},
|
||||
},
|
||||
expect: "manager-approve",
|
||||
},
|
||||
{
|
||||
name: "大额正常用户",
|
||||
input: map[string]any{
|
||||
"amount": 15000.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 80,
|
||||
},
|
||||
},
|
||||
expect: "director-approve",
|
||||
},
|
||||
{
|
||||
name: "低信用用户",
|
||||
input: map[string]any{
|
||||
"amount": 500.0,
|
||||
"user": map[string]any{
|
||||
"id": 1,
|
||||
"credit_score": 50,
|
||||
},
|
||||
},
|
||||
expect: "reject",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
input := reflux.New(tc.input)
|
||||
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
||||
s.NoError(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSuite 运行测试套件
|
||||
func TestCondFlow(t *testing.T) {
|
||||
suite.Run(t, new(CondFlowTestSuite))
|
||||
}
|
||||
@@ -0,0 +1,591 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.fsdpf.net/go/condflow"
|
||||
"git.fsdpf.net/go/condflow/tests/fixtures"
|
||||
"git.fsdpf.net/go/condition"
|
||||
"git.fsdpf.net/go/contracts/base"
|
||||
"git.fsdpf.net/go/reflux"
|
||||
"git.fsdpf.net/go/reflux/fieldx"
|
||||
"git.fsdpf.net/go/req"
|
||||
"git.fsdpf.net/go/req/resx"
|
||||
"github.com/samber/do/v2"
|
||||
)
|
||||
|
||||
// setupExampleExecutor 创建并注册示例 executor
|
||||
func setupExampleExecutor(app do.Injector) {
|
||||
// 创建 resource
|
||||
exampleRes := resx.New(app, "Example", "examples",
|
||||
resx.WithUuid("660e8400-e29b-41d4-a716-446655440002"),
|
||||
resx.WithName("示例"),
|
||||
resx.WithFields(
|
||||
resx.NewResField("id", "", resx.FieldWithName("ID"), resx.FieldWithDataType(req.ResInteger)),
|
||||
resx.NewResField("created_user", "", resx.FieldWithName("创建者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("owned_user", "", resx.FieldWithName("拥有者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("created_at", "", resx.FieldWithName("创建时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
||||
resx.NewResField("updated_at", "", resx.FieldWithName("更新时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
||||
resx.NewResField("uuid", "", resx.FieldWithName("UUID"), resx.FieldWithDefault("sql:uuid()"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("status", "", resx.FieldWithName("状态"), resx.FieldWithDefault("pending"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("type", "", resx.FieldWithName("类型"), resx.FieldWithDataType(req.ResString)),
|
||||
resx.NewResField("data", "", resx.FieldWithName("数据"), resx.FieldWithDefault("{}"), resx.FieldWithDataType(req.ResJson)),
|
||||
),
|
||||
)
|
||||
|
||||
executor := condflow.NewActionInvoker(fixtures.NewExampleExecutor(exampleRes), nil)
|
||||
|
||||
do.ProvideNamedValue(app, fmt.Sprintf("%s/ExampleExecutor", executor.Res().GetCode()), executor)
|
||||
}
|
||||
|
||||
// Example_userApprovalFlow 用户审批流示例
|
||||
func Example_userApprovalFlow() {
|
||||
// 初始化 DI 容器并注册 executor
|
||||
app := do.New()
|
||||
setupExampleExecutor(app)
|
||||
|
||||
// 创建条件流
|
||||
flow := condflow.New("user-approval-flow")
|
||||
|
||||
// Case 1: 金额 <= 1000,自动通过
|
||||
case1Cond := condition.New(condition.Describe("小额自动审批"))
|
||||
case1Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING)))
|
||||
|
||||
case1Config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"message": map[string]any{
|
||||
"type": "string",
|
||||
"value": "申请已自动通过",
|
||||
},
|
||||
})
|
||||
|
||||
case1 := condflow.NewCondCase(
|
||||
"auto-approve-small",
|
||||
case1Cond,
|
||||
"Example/ExampleExecutor@AutoApprove",
|
||||
).
|
||||
WithPriority(100).
|
||||
WithActionConfig(case1Config)
|
||||
|
||||
// Case 2: 1000 < 金额 <= 10000,需要经理审批
|
||||
case2Cond := condition.New(condition.Describe("经理审批"))
|
||||
case2Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING)))
|
||||
|
||||
case2Config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"approver_role": map[string]any{
|
||||
"type": "string",
|
||||
"value": "manager",
|
||||
},
|
||||
"timeout_hours": map[string]any{
|
||||
"type": "string",
|
||||
"value": "24",
|
||||
},
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
case2 := condflow.NewCondCase(
|
||||
"manager-approval",
|
||||
case2Cond,
|
||||
"Example/ExampleExecutor@ManagerApproval",
|
||||
).
|
||||
WithPriority(90).
|
||||
WithActionConfig(case2Config)
|
||||
|
||||
// Case 3: 金额 > 10000,需要总监审批
|
||||
case3Cond := condition.New(condition.Describe("总监审批"))
|
||||
case3Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("10000", condition.STRING)))
|
||||
|
||||
case3Config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"approver_role": map[string]any{
|
||||
"type": "string",
|
||||
"value": "director",
|
||||
},
|
||||
"timeout_hours": map[string]any{
|
||||
"type": "string",
|
||||
"value": "48",
|
||||
},
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"cc_roles": map[string]any{
|
||||
"type": "string",
|
||||
"value": "manager,ceo",
|
||||
},
|
||||
})
|
||||
|
||||
case3 := condflow.NewCondCase(
|
||||
"director-approval",
|
||||
case3Cond,
|
||||
"Example/ExampleExecutor@DirectorApproval",
|
||||
).
|
||||
WithPriority(80).
|
||||
WithActionConfig(case3Config)
|
||||
|
||||
// Case 4: 用户信用评分 < 60,直接拒绝
|
||||
case4Cond := condition.New(condition.Describe("信用不足拒绝"))
|
||||
case4Cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING)))
|
||||
|
||||
case4Config, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"reason": map[string]any{
|
||||
"type": "string",
|
||||
"value": "信用评分不足",
|
||||
},
|
||||
"notify": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"suggest_retry": map[string]any{
|
||||
"type": "string",
|
||||
"value": "false",
|
||||
},
|
||||
})
|
||||
|
||||
case4 := condflow.NewCondCase(
|
||||
"reject-low-credit",
|
||||
case4Cond,
|
||||
"Example/ExampleExecutor@Reject",
|
||||
).
|
||||
WithPriority(200). // 最高优先级,优先检查
|
||||
WithActionConfig(case4Config)
|
||||
|
||||
// 添加所有条件分支到流程
|
||||
flow.AddCase(case4). // 优先级最高
|
||||
AddCase(case1).
|
||||
AddCase(case2).
|
||||
AddCase(case3)
|
||||
|
||||
// 生成包含多种数据类型的测试 map
|
||||
input := reflux.New(map[string]any{
|
||||
// 基础类型
|
||||
"amount": 5000.50, // float64
|
||||
"count": 100, // int
|
||||
"active": true, // bool
|
||||
"user_name": "张三", // string
|
||||
"age": int32(25), // int32
|
||||
"total": int64(1000000), // int64
|
||||
"score": float32(98.5), // float32
|
||||
"is_vip": false, // bool
|
||||
|
||||
// 数组/切片类型
|
||||
"tags": []string{"vip", "premium", "active"}, // slice
|
||||
"scores": []int{85, 90, 95}, // slice of int
|
||||
"prices": []float64{19.99, 29.99, 39.99}, // slice of float
|
||||
|
||||
// Map 类型
|
||||
"preferences": map[string]any{
|
||||
"newsletter": true,
|
||||
"theme": "dark",
|
||||
"language": "zh-CN",
|
||||
},
|
||||
|
||||
// 嵌套结构
|
||||
"user": map[string]any{
|
||||
"id": 12345,
|
||||
"email": "user@example.com",
|
||||
"level": 5,
|
||||
"credit_score": 85,
|
||||
"created_at": "2024-01-01",
|
||||
},
|
||||
|
||||
// 空值测试
|
||||
"nullable_field": nil,
|
||||
"empty_string": "",
|
||||
})
|
||||
|
||||
flow.Run(app, input, base.GetSystemUser())
|
||||
|
||||
fmt.Printf("条件流名称: %s\n", flow.Name())
|
||||
fmt.Printf("条件分支数量: %d\n", flow.CaseCount())
|
||||
|
||||
// Output:
|
||||
// 条件流名称: user-approval-flow
|
||||
// 条件分支数量: 4
|
||||
}
|
||||
|
||||
// Example_emailCampaignFlow 邮件营销活动流示例
|
||||
func Example_emailCampaignFlow() {
|
||||
// 初始化 DI 容器并注册 executor
|
||||
app := do.New()
|
||||
setupExampleExecutor(app)
|
||||
|
||||
// 创建邮件营销条件流
|
||||
flow := condflow.New("email-campaign-flow")
|
||||
|
||||
// Case 1: VIP 用户 - 发送专属优惠
|
||||
vipCond := condition.New(condition.Describe("VIP用户筛选"))
|
||||
vipCond.SetExpr(condition.NewExpr("User", "level", condition.Operator(condition.GE), condition.Token("5", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("User", "email", condition.Operator(condition.IS_NOT_NULL))).
|
||||
SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("true", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("User", "tags", condition.FieldSqlFn("json_contains", ""), condition.Token("vip", condition.STRING)))
|
||||
|
||||
vipConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"template": map[string]any{
|
||||
"type": "string",
|
||||
"value": "vip-exclusive-offer",
|
||||
},
|
||||
"subject": map[string]any{
|
||||
"type": "string",
|
||||
"value": "尊贵的VIP会员,专属优惠来啦!",
|
||||
},
|
||||
"discount": map[string]any{
|
||||
"type": "string",
|
||||
"value": "30",
|
||||
},
|
||||
"valid_days": map[string]any{
|
||||
"type": "string",
|
||||
"value": "30",
|
||||
},
|
||||
"priority": map[string]any{
|
||||
"type": "string",
|
||||
"value": "high",
|
||||
},
|
||||
"attachments": map[string]any{
|
||||
"type": "string",
|
||||
"value": "vip-catalog.pdf",
|
||||
},
|
||||
})
|
||||
|
||||
vipCase := condflow.NewCondCase("vip-campaign", vipCond, "Example/ExampleExecutor@VIPEmail").
|
||||
WithPriority(100).
|
||||
WithActionConfig(vipConfig)
|
||||
|
||||
// Case 2: 新用户 - 发送欢迎邮件
|
||||
newUserCond := condition.New(condition.Describe("新用户识别"))
|
||||
newUserCond.SetExpr(condition.NewExpr("User", "created_at", condition.Operator(condition.GE), condition.Token("DATE_SUB(NOW(), INTERVAL 7 DAY)", condition.SQL))).
|
||||
SetExpr(condition.NewExpr("User", "email_verified", condition.Token("true", condition.STRING)))
|
||||
|
||||
newUserConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"template": map[string]any{
|
||||
"type": "string",
|
||||
"value": "welcome-new-user",
|
||||
},
|
||||
"subject": map[string]any{
|
||||
"type": "string",
|
||||
"value": "欢迎加入我们!",
|
||||
},
|
||||
"coupon_code": map[string]any{
|
||||
"type": "string",
|
||||
"value": "WELCOME2024",
|
||||
},
|
||||
"discount": map[string]any{
|
||||
"type": "string",
|
||||
"value": "10",
|
||||
},
|
||||
"trigger_delay": map[string]any{
|
||||
"type": "string",
|
||||
"value": "1h",
|
||||
},
|
||||
})
|
||||
|
||||
newUserCase := condflow.NewCondCase("new-user-welcome", newUserCond, "Example/ExampleExecutor@WelcomeEmail").
|
||||
WithPriority(90).
|
||||
WithActionConfig(newUserConfig)
|
||||
|
||||
// Case 3: 普通活跃用户 - 发送常规营销邮件
|
||||
regularCond := condition.New(condition.Describe("活跃普通用户"))
|
||||
regularCond.SetExpr(condition.NewExpr("User", "last_login_at", condition.Operator(condition.GE), condition.Token("DATE_SUB(NOW(), INTERVAL 30 DAY)", condition.SQL))).
|
||||
SetExpr(condition.NewExpr("User", "email", condition.Operator(condition.IS_NOT_NULL))).
|
||||
SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("true", condition.STRING)))
|
||||
|
||||
regularConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"template": map[string]any{
|
||||
"type": "string",
|
||||
"value": "regular-promotion",
|
||||
},
|
||||
"subject": map[string]any{
|
||||
"type": "string",
|
||||
"value": "本月精选优惠",
|
||||
},
|
||||
"discount": map[string]any{
|
||||
"type": "string",
|
||||
"value": "15",
|
||||
},
|
||||
"valid_days": map[string]any{
|
||||
"type": "string",
|
||||
"value": "14",
|
||||
},
|
||||
})
|
||||
|
||||
regularCase := condflow.NewCondCase("regular-campaign", regularCond, "Example/ExampleExecutor@RegularEmail").
|
||||
WithPriority(50).
|
||||
WithActionConfig(regularConfig)
|
||||
|
||||
// Case 4: 未订阅用户 - 跳过
|
||||
skipCond := condition.New(condition.Describe("未订阅用户"))
|
||||
skipCond.SetExpr(condition.NewExpr("User", "preferences->'newsletter'", condition.Token("false", condition.STRING)))
|
||||
|
||||
skipConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"reason": map[string]any{
|
||||
"type": "string",
|
||||
"value": "用户未订阅营销邮件",
|
||||
},
|
||||
"log": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
skipCase := condflow.NewCondCase("skip-unsubscribed", skipCond, "Example/ExampleExecutor@Skip").
|
||||
WithPriority(200). // 最高优先级
|
||||
WithActionConfig(skipConfig)
|
||||
|
||||
// 添加所有条件分支
|
||||
flow.AddCase(skipCase).
|
||||
AddCase(vipCase).
|
||||
AddCase(newUserCase).
|
||||
AddCase(regularCase)
|
||||
|
||||
fmt.Printf("条件流名称: %s\n", flow.Name())
|
||||
fmt.Printf("条件分支数量: %d\n", flow.CaseCount())
|
||||
|
||||
// Output:
|
||||
// 条件流名称: email-campaign-flow
|
||||
// 条件分支数量: 4
|
||||
}
|
||||
|
||||
// Example_orderProcessingFlow 订单处理流示例
|
||||
func Example_orderProcessingFlow() {
|
||||
// 初始化 DI 容器并注册 executor
|
||||
app := do.New()
|
||||
setupExampleExecutor(app)
|
||||
|
||||
// 创建订单处理条件流
|
||||
flow := condflow.New("order-processing-flow")
|
||||
|
||||
// Case 1: 高价值订单 + VIP客户 -> 优先处理 + 包邮
|
||||
premiumCond := condition.New(condition.Describe("高价值VIP订单"))
|
||||
premiumCond.SetExpr(condition.NewExpr("Order", "total_amount", condition.Operator(condition.GE), condition.Token("5000", condition.STRING))).
|
||||
SetExpr(condition.NewExpr("User", "level", condition.Operator(condition.GE), condition.Token("5", condition.STRING)))
|
||||
|
||||
premiumConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"shipping_method": map[string]any{
|
||||
"type": "string",
|
||||
"value": "express",
|
||||
},
|
||||
"shipping_fee": map[string]any{
|
||||
"type": "string",
|
||||
"value": "0",
|
||||
},
|
||||
"priority": map[string]any{
|
||||
"type": "string",
|
||||
"value": "high",
|
||||
},
|
||||
"gift_wrapping": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"insurance": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
premiumCase := condflow.NewCondCase("premium-order", premiumCond, "Example/ExampleExecutor@ExpressShipping").
|
||||
WithPriority(100).
|
||||
WithActionConfig(premiumConfig).
|
||||
WithNextCaseOnSuccess(true) // 继续执行下一个case(通知客户)
|
||||
|
||||
// Case 2: 紧急订单 -> 加急配送
|
||||
urgentCond := condition.New(condition.Describe("紧急订单"))
|
||||
urgentCond.SetExpr(condition.NewExpr("Order", "tags", condition.FieldSqlFn("json_contains", ""), condition.Token("urgent", condition.STRING)))
|
||||
|
||||
urgentConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"shipping_method": map[string]any{
|
||||
"type": "string",
|
||||
"value": "express",
|
||||
},
|
||||
"max_hours": map[string]any{
|
||||
"type": "string",
|
||||
"value": "24",
|
||||
},
|
||||
"priority": map[string]any{
|
||||
"type": "string",
|
||||
"value": "urgent",
|
||||
},
|
||||
})
|
||||
|
||||
urgentCase := condflow.NewCondCase("urgent-order", urgentCond, "Example/ExampleExecutor@ExpressShipping").
|
||||
WithPriority(95).
|
||||
WithActionConfig(urgentConfig)
|
||||
|
||||
// Case 3: 跨区域订单 -> 仓库调配
|
||||
crossRegionCond := condition.New(condition.Describe("跨区域订单"))
|
||||
crossRegionCond.SetExpr(condition.NewExpr("Order", "shipping_province", condition.Operator(condition.NE), condition.Token("warehouse_province", condition.PARAM)))
|
||||
|
||||
crossRegionConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"check_inventory": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"transfer_if_needed": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
"estimated_days": map[string]any{
|
||||
"type": "string",
|
||||
"value": "5",
|
||||
},
|
||||
})
|
||||
|
||||
crossRegionCase := condflow.NewCondCase("cross-region-order", crossRegionCond, "Example/ExampleExecutor@WarehouseTransfer").
|
||||
WithPriority(80).
|
||||
WithActionConfig(crossRegionConfig)
|
||||
|
||||
// Case 4: 普通订单 -> 标准配送
|
||||
standardCond := condition.New(condition.Describe("普通订单"))
|
||||
standardCond.SetExpr(condition.NewExpr("Order", "total_amount", condition.Operator(condition.GT), condition.Token("0", condition.STRING)))
|
||||
|
||||
standardConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"shipping_method": map[string]any{
|
||||
"type": "string",
|
||||
"value": "standard",
|
||||
},
|
||||
"estimated_days": map[string]any{
|
||||
"type": "string",
|
||||
"value": "3",
|
||||
},
|
||||
})
|
||||
|
||||
standardCase := condflow.NewCondCase("standard-order", standardCond, "Example/ExampleExecutor@StandardShipping").
|
||||
WithPriority(50).
|
||||
WithActionConfig(standardConfig)
|
||||
|
||||
// Case 5: 通知客户(配合 premium case 的 nextCaseOnSuccess)
|
||||
notifyCond := condition.New(condition.Describe("需要通知的订单"))
|
||||
notifyCond.SetExpr(condition.NewExpr("Order", "notify_customer", condition.Token("true", condition.STRING)))
|
||||
|
||||
notifyConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"channels": map[string]any{
|
||||
"type": "string",
|
||||
"value": "email,sms",
|
||||
},
|
||||
"template": map[string]any{
|
||||
"type": "string",
|
||||
"value": "order-confirmed",
|
||||
},
|
||||
"immediate": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
notifyCase := condflow.NewCondCase("notify-customer", notifyCond, "Example/ExampleExecutor@NotifyCustomer").
|
||||
WithPriority(40).
|
||||
WithActionConfig(notifyConfig)
|
||||
|
||||
// 添加所有条件分支
|
||||
flow.AddCase(premiumCase).
|
||||
AddCase(urgentCase).
|
||||
AddCase(crossRegionCase).
|
||||
AddCase(standardCase).
|
||||
AddCase(notifyCase)
|
||||
|
||||
fmt.Printf("条件流名称: %s\n", flow.Name())
|
||||
fmt.Printf("条件分支数量: %d\n", flow.CaseCount())
|
||||
|
||||
// Output:
|
||||
// 条件流名称: order-processing-flow
|
||||
// 条件分支数量: 5
|
||||
}
|
||||
|
||||
// Example_nestedFlow 嵌套流程示例 - 展示如何使用 NextFlowOnSuccess
|
||||
func Example_nestedFlow() {
|
||||
// 初始化 DI 容器并注册 executor
|
||||
app := do.New()
|
||||
setupExampleExecutor(app)
|
||||
|
||||
// 创建主流程:用户注册流程
|
||||
mainFlow := condflow.New("user-registration-flow")
|
||||
|
||||
// 创建子流程:邮件验证流程
|
||||
emailVerificationFlow := condflow.New("email-verification-flow")
|
||||
|
||||
verifyCond := condition.New(condition.Describe("发送验证邮件"))
|
||||
verifyConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"template": map[string]any{
|
||||
"type": "string",
|
||||
"value": "email-verification",
|
||||
},
|
||||
"expire_in": map[string]any{
|
||||
"type": "string",
|
||||
"value": "24h",
|
||||
},
|
||||
})
|
||||
verifyCase := condflow.NewCondCase("send-verify-email", verifyCond, "Example/ExampleExecutor@SendVerification").
|
||||
WithActionConfig(verifyConfig)
|
||||
|
||||
emailVerificationFlow.AddCase(verifyCase)
|
||||
|
||||
// 创建子流程:欢迎礼包流程
|
||||
welcomePackFlow := condflow.New("welcome-pack-flow")
|
||||
|
||||
couponCond := condition.New(condition.Describe("创建新用户优惠券"))
|
||||
couponConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"coupon_type": map[string]any{
|
||||
"type": "string",
|
||||
"value": "new_user",
|
||||
},
|
||||
"discount": map[string]any{
|
||||
"type": "string",
|
||||
"value": "20",
|
||||
},
|
||||
"valid_days": map[string]any{
|
||||
"type": "string",
|
||||
"value": "30",
|
||||
},
|
||||
})
|
||||
couponCase := condflow.NewCondCase("new-user-coupon", couponCond, "Example/ExampleExecutor@CreateCoupon").
|
||||
WithActionConfig(couponConfig)
|
||||
|
||||
welcomePackFlow.AddCase(couponCase)
|
||||
|
||||
// 主流程 Case: 邮箱注册用户
|
||||
emailRegCond := condition.New(condition.Describe("邮箱注册"))
|
||||
emailRegCond.SetExpr(condition.NewExpr("User", "register_type", condition.Token("email", condition.STRING)))
|
||||
|
||||
emailRegConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"send_welcome": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
emailRegCase := condflow.NewCondCase("email-registration", emailRegCond, "Example/ExampleExecutor@CreateUser").
|
||||
WithPriority(100).
|
||||
WithNextFlowOnSuccess(emailVerificationFlow, nil). // 成功后执行邮件验证流程
|
||||
WithActionConfig(emailRegConfig)
|
||||
|
||||
// 主流程 Case: 手机号注册用户
|
||||
phoneRegCond := condition.New(condition.Describe("手机号注册"))
|
||||
phoneRegCond.SetExpr(condition.NewExpr("User", "register_type", condition.Token("phone", condition.STRING)))
|
||||
|
||||
phoneRegConfig, _ := fieldx.SchemaFromMap(map[string]any{
|
||||
"send_sms": map[string]any{
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
},
|
||||
})
|
||||
|
||||
phoneRegCase := condflow.NewCondCase("phone-registration", phoneRegCond, "Example/ExampleExecutor@CreateUser").
|
||||
WithPriority(90).
|
||||
WithNextFlowOnSuccess(welcomePackFlow, nil). // 成功后执行欢迎礼包流程
|
||||
WithActionConfig(phoneRegConfig)
|
||||
|
||||
mainFlow.AddCase(emailRegCase).
|
||||
AddCase(phoneRegCase)
|
||||
|
||||
fmt.Printf("主流程名称: %s\n", mainFlow.Name())
|
||||
fmt.Printf("主流程分支数量: %d\n", mainFlow.CaseCount())
|
||||
|
||||
// Output:
|
||||
// 主流程名称: user-registration-flow
|
||||
// 主流程分支数量: 2
|
||||
}
|
||||
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
"git.fsdpf.net/go/condflow"
|
||||
"git.fsdpf.net/go/reflux"
|
||||
"git.fsdpf.net/go/reflux/valuex"
|
||||
"git.fsdpf.net/go/req"
|
||||
)
|
||||
|
||||
// ApproveExecutor 审批执行器
|
||||
type ApproveExecutor struct {
|
||||
res req.Resource
|
||||
}
|
||||
|
||||
// NewApproveExecutor 创建审批执行器
|
||||
func NewApproveExecutor(res req.Resource) *ApproveExecutor {
|
||||
return &ApproveExecutor{res: res}
|
||||
}
|
||||
|
||||
func (ae *ApproveExecutor) Res() req.Resource {
|
||||
return ae.res
|
||||
}
|
||||
|
||||
// AutoApprove 自动审批
|
||||
func (ae *ApproveExecutor) AutoApprove(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{
|
||||
"status": "approved",
|
||||
"method": "auto",
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Manager 经理审批
|
||||
func (ae *ApproveExecutor) Manager(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{
|
||||
"status": "pending",
|
||||
"approver": "manager",
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Director 总监审批
|
||||
func (ae *ApproveExecutor) Director(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{
|
||||
"status": "pending",
|
||||
"approver": "director",
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Reject 拒绝
|
||||
func (ae *ApproveExecutor) Reject(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
reason, _ := cfg.Lookup("reason")
|
||||
return reflux.New(map[string]any{
|
||||
"status": "rejected",
|
||||
"reason": reason.String(),
|
||||
}), nil
|
||||
}
|
||||
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
"git.fsdpf.net/go/condflow"
|
||||
"git.fsdpf.net/go/reflux"
|
||||
"git.fsdpf.net/go/reflux/valuex"
|
||||
"git.fsdpf.net/go/req"
|
||||
)
|
||||
|
||||
// ExampleExecutor 示例执行器
|
||||
type ExampleExecutor struct {
|
||||
res req.Resource
|
||||
}
|
||||
|
||||
// NewExampleExecutor 创建示例执行器
|
||||
func NewExampleExecutor(res req.Resource) *ExampleExecutor {
|
||||
return &ExampleExecutor{res: res}
|
||||
}
|
||||
|
||||
func (ee *ExampleExecutor) Res() req.Resource {
|
||||
return ee.res
|
||||
}
|
||||
|
||||
// AutoApprove 自动审批
|
||||
func (ee *ExampleExecutor) AutoApprove(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"status": "approved", "method": "auto"}), nil
|
||||
}
|
||||
|
||||
// ManagerApproval 经理审批
|
||||
func (ee *ExampleExecutor) ManagerApproval(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"status": "pending", "approver": "manager"}), nil
|
||||
}
|
||||
|
||||
// DirectorApproval 总监审批
|
||||
func (ee *ExampleExecutor) DirectorApproval(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"status": "pending", "approver": "director"}), nil
|
||||
}
|
||||
|
||||
// Reject 拒绝
|
||||
func (ee *ExampleExecutor) Reject(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
reason, _ := cfg.Lookup("reason")
|
||||
return reflux.New(map[string]any{"status": "rejected", "reason": reason.String()}), nil
|
||||
}
|
||||
|
||||
// VIPEmail 处理VIP邮件
|
||||
func (ee *ExampleExecutor) VIPEmail(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
template, _ := cfg.Lookup("template")
|
||||
return reflux.New(map[string]any{"sent": true, "template": template.String()}), nil
|
||||
}
|
||||
|
||||
// RegularEmail 处理普通邮件
|
||||
func (ee *ExampleExecutor) RegularEmail(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
template, _ := cfg.Lookup("template")
|
||||
return reflux.New(map[string]any{"sent": true, "template": template.String()}), nil
|
||||
}
|
||||
|
||||
// WelcomeEmail 处理欢迎邮件
|
||||
func (ee *ExampleExecutor) WelcomeEmail(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
template, _ := cfg.Lookup("template")
|
||||
return reflux.New(map[string]any{"sent": true, "template": template.String()}), nil
|
||||
}
|
||||
|
||||
// Skip 跳过处理
|
||||
func (ee *ExampleExecutor) Skip(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
reason, _ := cfg.Lookup("reason")
|
||||
return reflux.New(map[string]any{"skipped": true, "reason": reason.String()}), nil
|
||||
}
|
||||
|
||||
// ExpressShipping 处理快递配送
|
||||
func (ee *ExampleExecutor) ExpressShipping(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
fee, _ := cfg.Lookup("shipping_fee")
|
||||
return reflux.New(map[string]any{"shipping": "express", "fee": fee.Int()}), nil
|
||||
}
|
||||
|
||||
// StandardShipping 处理标准配送
|
||||
func (ee *ExampleExecutor) StandardShipping(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"shipping": "standard"}), nil
|
||||
}
|
||||
|
||||
// WarehouseTransfer 处理仓库调配
|
||||
func (ee *ExampleExecutor) WarehouseTransfer(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"transfer": true}), nil
|
||||
}
|
||||
|
||||
// NotifyCustomer 通知客户
|
||||
func (ee *ExampleExecutor) NotifyCustomer(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"notified": true}), nil
|
||||
}
|
||||
|
||||
// SendVerification 发送验证
|
||||
func (ee *ExampleExecutor) SendVerification(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"verification_sent": true}), nil
|
||||
}
|
||||
|
||||
// WaitVerification 等待验证
|
||||
func (ee *ExampleExecutor) WaitVerification(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"waiting": true}), nil
|
||||
}
|
||||
|
||||
// CreateCoupon 创建优惠券
|
||||
func (ee *ExampleExecutor) CreateCoupon(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
discount, _ := cfg.Lookup("discount")
|
||||
return reflux.New(map[string]any{"coupon_created": true, "discount": discount.Int()}), nil
|
||||
}
|
||||
|
||||
// GrantPoints 授予积分
|
||||
func (ee *ExampleExecutor) GrantPoints(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"points_granted": true}), nil
|
||||
}
|
||||
|
||||
// CreateUser 创建用户
|
||||
func (ee *ExampleExecutor) CreateUser(ctx condflow.Context, cfg valuex.Accessor) (reflux.R, error) {
|
||||
return reflux.New(map[string]any{"user_created": true}), nil
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
|
||||
// "git.fsdpf.net/go/contracts"
|
||||
"git.fsdpf.net/go/contracts/base"
|
||||
// "git.fsdpf.net/go/db"
|
||||
"github.com/samber/do"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caches = append(caches, _ResCache{injector: func(app *do.Injector) {
|
||||
do.Provide(app, GetCondflowServiceProvider)
|
||||
|
||||
// 缓存 Condflow
|
||||
do.Provide(app, func(i *do.Injector) ([]base.Condflow, error) {
|
||||
defer useRefreshCache(i, "Condflow", func() error {
|
||||
do.Override(i, GetCondflowServiceProvider)
|
||||
do.Override(i, func(i *do.Injector) ([]base.Condflow, error) {
|
||||
return getCondflowCaches(i)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return getCondflowCaches(i)
|
||||
})
|
||||
}, priority: 0})
|
||||
}
|
||||
|
||||
func GetCondflowServiceProvider(container *do.Injector) (base.GetCondflow, error) {
|
||||
caches := do.MustInvoke[[]base.Condflow](container)
|
||||
|
||||
return func(code string) (base.Condflow, bool) {
|
||||
item, flag := lo.Find(caches, func(i base.Condflow) bool {
|
||||
return i.Code == code || i.Uuid == code
|
||||
})
|
||||
return item, flag
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getCondflowCaches(app *do.Injector) (items []base.Condflow, err error) {
|
||||
// TODO: 临时测试数据,等待资源表创建后从数据库读取
|
||||
// if res, ok := do.MustInvoke[contracts.GetResource](app)("Condflow"); !ok {
|
||||
// return items, fmt.Errorf("获取 Condflow 资源失败")
|
||||
// } else {
|
||||
// items = []base.Condflow{}
|
||||
// if e := res.GetDBTable(base.GetSystemUser()).
|
||||
// Select(
|
||||
// db.T("Condflow").All(),
|
||||
// ).
|
||||
// Order(db.I("Condflow.id").Asc()).
|
||||
// ScanStructs(&items); e != nil {
|
||||
// err = fmt.Errorf("获取 Condflow 资源失败, %w", e)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
items = []base.Condflow{
|
||||
{
|
||||
Uuid: "550e8400-e29b-41d4-a716-446655440001",
|
||||
Name: "用户审批流程",
|
||||
Code: "user-approval-flow",
|
||||
Comment: "处理用户申请的审批流程,根据金额和信用评分自动分配审批策略",
|
||||
Params: []base.CondflowParam{
|
||||
{Name: "申请金额", Code: "amount", DataType: "decimal", IsRequired: true, Comment: "申请的金额"},
|
||||
{Name: "用户信息", Code: "user", DataType: "json", IsRequired: true, Comment: "用户详细信息"},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "550e8400-e29b-41d4-a716-446655440002",
|
||||
Name: "邮件营销活动流程",
|
||||
Code: "email-campaign-flow",
|
||||
Comment: "根据用户等级和活跃度自动发送不同类型的营销邮件",
|
||||
Params: []base.CondflowParam{
|
||||
{Name: "用户信息", Code: "user", DataType: "json", IsRequired: true, Comment: "用户详细信息"},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "550e8400-e29b-41d4-a716-446655440003",
|
||||
Name: "订单处理流程",
|
||||
Code: "order-processing-flow",
|
||||
Comment: "订单自动化处理流程,包括配送方式选择和客户通知",
|
||||
Params: []base.CondflowParam{
|
||||
{Name: "订单信息", Code: "order", DataType: "json", IsRequired: true, Comment: "订单详细信息"},
|
||||
{Name: "用户信息", Code: "user", DataType: "json", IsRequired: true, Comment: "下单用户信息"},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
|
||||
// "git.fsdpf.net/go/contracts"
|
||||
"git.fsdpf.net/go/contracts/base"
|
||||
// "git.fsdpf.net/go/db"
|
||||
"github.com/samber/do"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caches = append(caches, _ResCache{injector: func(app *do.Injector) {
|
||||
do.Provide(app, GetCondflowCasesServiceProvider)
|
||||
|
||||
// 缓存 CondflowCase
|
||||
do.Provide(app, func(i *do.Injector) ([]base.CondflowCase, error) {
|
||||
defer useRefreshCache(i, "CondflowCase", func() error {
|
||||
do.Override(i, GetCondflowCasesServiceProvider)
|
||||
do.Override(i, func(i *do.Injector) ([]base.CondflowCase, error) {
|
||||
return getCondflowCaseCaches(i)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return getCondflowCaseCaches(i)
|
||||
})
|
||||
}, priority: 0})
|
||||
}
|
||||
|
||||
func GetCondflowCasesServiceProvider(container *do.Injector) (base.GetCondflowCases, error) {
|
||||
caches := do.MustInvoke[[]base.CondflowCase](container)
|
||||
|
||||
return func(uuid string) []base.CondflowCase {
|
||||
items := lo.Filter(caches, func(item base.CondflowCase, _ int) bool {
|
||||
return item.CondflowUuid == uuid
|
||||
})
|
||||
|
||||
return items
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getCondflowCaseCaches(app *do.Injector) (items []base.CondflowCase, err error) {
|
||||
// TODO: 临时测试数据,等待资源表创建后从数据库读取
|
||||
// if res, ok := do.MustInvoke[contracts.GetResource](app)("CondflowCase"); !ok {
|
||||
// return items, fmt.Errorf("获取 CondflowCase 资源失败")
|
||||
// } else {
|
||||
// items = []base.CondflowCase{}
|
||||
// if e := res.GetDBTable(base.GetSystemUser()).
|
||||
// Select(
|
||||
// db.T("CondflowCase").All(),
|
||||
// ).
|
||||
// Order(db.I("CondflowCase.priority").Desc(), db.I("CondflowCase.id").Asc()).
|
||||
// ScanStructs(&items); e != nil {
|
||||
// err = fmt.Errorf("获取 CondflowCase 资源失败, %w", e)
|
||||
// }
|
||||
// }
|
||||
items = []base.CondflowCase{
|
||||
// 用户审批流程的 cases
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440001",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440001",
|
||||
Name: "低信用拒绝",
|
||||
Code: "reject-low-credit",
|
||||
Priority: 200,
|
||||
Action: "Approval/ApproveExecutor@Reject",
|
||||
Config: map[string]any{"reason": "信用评分不足", "notify": true, "suggest_retry": false},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "信用评分低于60,直接拒绝",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440002",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440001",
|
||||
Name: "小额自动审批",
|
||||
Code: "auto-approve-small",
|
||||
Priority: 100,
|
||||
Action: "Approval/ApproveExecutor@AutoApprove",
|
||||
Config: map[string]any{"notify": true, "message": "申请已自动通过"},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "金额 <= 1000,自动通过",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440003",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440001",
|
||||
Name: "经理审批",
|
||||
Code: "manager-approval",
|
||||
Priority: 90,
|
||||
Action: "Approval/ApproveExecutor@Manager",
|
||||
Config: map[string]any{"approver_role": "manager", "timeout_hours": 24, "notify": true},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "1000 < 金额 <= 10000,需要经理审批",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440004",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440001",
|
||||
Name: "总监审批",
|
||||
Code: "director-approval",
|
||||
Priority: 80,
|
||||
Action: "Approval/ApproveExecutor@Director",
|
||||
Config: map[string]any{"approver_role": "director", "timeout_hours": 48, "notify": true, "cc_roles": []string{"manager", "ceo"}},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "金额 > 10000,需要总监审批",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
|
||||
// 邮件营销活动流程的 cases
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440005",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440002",
|
||||
Name: "跳过未订阅用户",
|
||||
Code: "skip-unsubscribed",
|
||||
Priority: 200,
|
||||
Action: "Marketing/EmailExecutor@Skip",
|
||||
Config: map[string]any{"reason": "用户未订阅营销邮件", "log": true},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "未订阅营销邮件的用户跳过",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440006",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440002",
|
||||
Name: "VIP 用户营销",
|
||||
Code: "vip-campaign",
|
||||
Priority: 100,
|
||||
Action: "Marketing/EmailExecutor@VIP",
|
||||
Config: map[string]any{"template": "vip-exclusive-offer", "discount": 30, "valid_days": 30, "priority": "high"},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "VIP 用户发送专属优惠",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440007",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440002",
|
||||
Name: "新用户欢迎",
|
||||
Code: "new-user-welcome",
|
||||
Priority: 90,
|
||||
Action: "Marketing/EmailExecutor@Welcome",
|
||||
Config: map[string]any{"template": "welcome-new-user", "coupon_code": "WELCOME2024", "discount": 10},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "新注册用户发送欢迎邮件",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
|
||||
// 订单处理流程的 cases
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440008",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440003",
|
||||
Name: "VIP 订单优先处理",
|
||||
Code: "premium-order",
|
||||
Priority: 100,
|
||||
Action: "Order/ShippingExecutor@Express",
|
||||
Config: map[string]any{"shipping_method": "express", "shipping_fee": 0, "priority": "high", "gift_wrapping": true},
|
||||
NextCaseOnSuccess: true, // 继续执行通知客户
|
||||
NextFlowUuid: "",
|
||||
Comment: "高价值 VIP 订单加急处理",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440009",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440003",
|
||||
Name: "标准配送",
|
||||
Code: "standard-order",
|
||||
Priority: 50,
|
||||
Action: "Order/ShippingExecutor@Standard",
|
||||
Config: map[string]any{"shipping_method": "standard", "estimated_days": 3},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "普通订单标准配送",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "case-550e8400-e29b-41d4-a716-446655440010",
|
||||
CondflowUuid: "550e8400-e29b-41d4-a716-446655440003",
|
||||
Name: "通知客户",
|
||||
Code: "notify-customer",
|
||||
Priority: 40,
|
||||
Action: "Order/NotificationExecutor@Notify",
|
||||
Config: map[string]any{"channels": []string{"email", "sms"}, "template": "order-confirmed", "immediate": true},
|
||||
NextCaseOnSuccess: false,
|
||||
NextFlowUuid: "",
|
||||
Comment: "订单确认后通知客户",
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
// "fmt"
|
||||
|
||||
// "git.fsdpf.net/go/contracts"
|
||||
|
||||
"git.fsdpf.net/go/contracts/base"
|
||||
// "git.fsdpf.net/go/db"
|
||||
"github.com/samber/do"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caches = append(caches, _ResCache{injector: func(app *do.Injector) {
|
||||
do.Provide(app, GetCondflowDecisionServiceProvider)
|
||||
|
||||
// 缓存 CondflowDecision
|
||||
do.Provide(app, func(i *do.Injector) ([]base.CondflowDecision, error) {
|
||||
defer useRefreshCache(i, "CondflowDecision", func() error {
|
||||
do.Override(i, GetCondflowDecisionServiceProvider)
|
||||
do.Override(i, func(i *do.Injector) ([]base.CondflowDecision, error) {
|
||||
return getCondflowDecisionCaches(i)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return getCondflowDecisionCaches(i)
|
||||
})
|
||||
}, priority: 0})
|
||||
}
|
||||
|
||||
func GetCondflowDecisionServiceProvider(container *do.Injector) (base.GetCondflowDecision, error) {
|
||||
caches := do.MustInvoke[[]base.CondflowDecision](container)
|
||||
|
||||
return func(code string) (base.CondflowDecision, bool) {
|
||||
item, flag := lo.Find(caches, func(i base.CondflowDecision) bool {
|
||||
return i.Code == code || i.Uuid == code
|
||||
})
|
||||
return item, flag
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getCondflowDecisionCaches(app *do.Injector) (items []base.CondflowDecision, err error) {
|
||||
// TODO: 临时测试数据,等待资源表创建后从数据库读取
|
||||
// if res, ok := do.MustInvoke[contracts.GetResource](app)("CondflowDecision"); !ok {
|
||||
// return items, fmt.Errorf("获取 CondflowDecision 资源失败")
|
||||
// } else {
|
||||
// items = []base.CondflowDecision{}
|
||||
// if e := res.GetDBTable(base.GetSystemUser()).
|
||||
// Select(
|
||||
// db.T("CondflowDecision").All(),
|
||||
// ).
|
||||
// Order(db.I("CondflowDecision.id").Asc()).
|
||||
// ScanStructs(&items); e != nil {
|
||||
// err = fmt.Errorf("获取 CondflowDecision 资源失败, %w", e)
|
||||
// }
|
||||
// }
|
||||
items = []base.CondflowDecision{
|
||||
{
|
||||
Uuid: "exec-550e8400-e29b-41d4-a716-446655440001",
|
||||
ResourceUuid: "550e8400-e29b-41d4-a716-446655440100", // Approval 资源 UUID
|
||||
Name: "审批执行器",
|
||||
Code: "ApproveDecision",
|
||||
Comment: "处理各类审批操作的执行器",
|
||||
Actions: []base.CondflowDecisionAction{
|
||||
{
|
||||
Name: "自动审批",
|
||||
Code: "AutoApprove",
|
||||
ConfigSchema: map[string]any{
|
||||
"notify": map[string]any{"type": "boolean", "default": true, "description": "是否发送通知"},
|
||||
"message": map[string]any{"type": "string", "description": "通知消息内容"},
|
||||
},
|
||||
Comment: "小额申请自动审批通过",
|
||||
},
|
||||
{
|
||||
Name: "经理审批",
|
||||
Code: "Manager",
|
||||
ConfigSchema: map[string]any{
|
||||
"approver_role": map[string]any{"type": "string", "default": "manager", "description": "审批人角色"},
|
||||
"timeout_hours": map[string]any{"type": "integer", "default": 24, "description": "审批超时时间(小时)"},
|
||||
"notify": map[string]any{"type": "boolean", "default": true, "description": "是否发送通知"},
|
||||
},
|
||||
Comment: "中额申请需要经理审批",
|
||||
},
|
||||
{
|
||||
Name: "总监审批",
|
||||
Code: "Director",
|
||||
ConfigSchema: map[string]any{
|
||||
"approver_role": map[string]any{"type": "string", "default": "director", "description": "审批人角色"},
|
||||
"timeout_hours": map[string]any{"type": "integer", "default": 48, "description": "审批超时时间(小时)"},
|
||||
"notify": map[string]any{"type": "boolean", "default": true, "description": "是否发送通知"},
|
||||
"cc_roles": map[string]any{"type": "array", "description": "抄送角色列表"},
|
||||
},
|
||||
Comment: "大额申请需要总监审批",
|
||||
},
|
||||
{
|
||||
Name: "拒绝",
|
||||
Code: "Reject",
|
||||
ConfigSchema: map[string]any{
|
||||
"reason": map[string]any{"type": "string", "required": true, "description": "拒绝原因"},
|
||||
"notify": map[string]any{"type": "boolean", "default": true, "description": "是否发送通知"},
|
||||
"suggest_retry": map[string]any{"type": "boolean", "default": false, "description": "是否建议重试"},
|
||||
},
|
||||
Comment: "拒绝申请",
|
||||
},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "exec-550e8400-e29b-41d4-a716-446655440002",
|
||||
ResourceUuid: "550e8400-e29b-41d4-a716-446655440200", // Marketing 资源 UUID
|
||||
Name: "邮件营销执行器",
|
||||
Code: "EmailDecision",
|
||||
Comment: "处理邮件营销活动的执行器",
|
||||
Actions: []base.CondflowDecisionAction{
|
||||
{
|
||||
Name: "VIP 邮件",
|
||||
Code: "VIP",
|
||||
ConfigSchema: map[string]any{
|
||||
"template": map[string]any{"type": "string", "required": true, "description": "邮件模板"},
|
||||
"subject": map[string]any{"type": "string", "description": "邮件主题"},
|
||||
"discount": map[string]any{"type": "integer", "description": "折扣百分比"},
|
||||
"valid_days": map[string]any{"type": "integer", "description": "有效天数"},
|
||||
"priority": map[string]any{"type": "string", "enum": []string{"low", "normal", "high"}, "description": "优先级"},
|
||||
"attachments": map[string]any{"type": "array", "description": "附件列表"},
|
||||
},
|
||||
Comment: "发送 VIP 专属营销邮件",
|
||||
},
|
||||
{
|
||||
Name: "欢迎邮件",
|
||||
Code: "Welcome",
|
||||
ConfigSchema: map[string]any{
|
||||
"template": map[string]any{"type": "string", "required": true, "description": "邮件模板"},
|
||||
"subject": map[string]any{"type": "string", "description": "邮件主题"},
|
||||
"coupon_code": map[string]any{"type": "string", "description": "优惠券代码"},
|
||||
"discount": map[string]any{"type": "integer", "description": "折扣百分比"},
|
||||
"trigger_delay": map[string]any{"type": "string", "description": "延迟发送时间"},
|
||||
},
|
||||
Comment: "发送新用户欢迎邮件",
|
||||
},
|
||||
{
|
||||
Name: "跳过",
|
||||
Code: "Skip",
|
||||
ConfigSchema: map[string]any{
|
||||
"reason": map[string]any{"type": "string", "description": "跳过原因"},
|
||||
"log": map[string]any{"type": "boolean", "default": true, "description": "是否记录日志"},
|
||||
},
|
||||
Comment: "跳过邮件发送",
|
||||
},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "exec-550e8400-e29b-41d4-a716-446655440003",
|
||||
ResourceUuid: "550e8400-e29b-41d4-a716-446655440300", // Order 资源 UUID
|
||||
Name: "配送执行器",
|
||||
Code: "ShippingDecision",
|
||||
Comment: "处理订单配送的执行器",
|
||||
Actions: []base.CondflowDecisionAction{
|
||||
{
|
||||
Name: "加急配送",
|
||||
Code: "Express",
|
||||
ConfigSchema: map[string]any{
|
||||
"shipping_method": map[string]any{"type": "string", "default": "express", "description": "配送方式"},
|
||||
"shipping_fee": map[string]any{"type": "number", "description": "配送费用"},
|
||||
"priority": map[string]any{"type": "string", "enum": []string{"normal", "high", "urgent"}, "description": "优先级"},
|
||||
"gift_wrapping": map[string]any{"type": "boolean", "default": false, "description": "是否礼品包装"},
|
||||
"insurance": map[string]any{"type": "boolean", "default": false, "description": "是否购买保险"},
|
||||
},
|
||||
Comment: "加急配送服务",
|
||||
},
|
||||
{
|
||||
Name: "标准配送",
|
||||
Code: "Standard",
|
||||
ConfigSchema: map[string]any{
|
||||
"shipping_method": map[string]any{"type": "string", "default": "standard", "description": "配送方式"},
|
||||
"estimated_days": map[string]any{"type": "integer", "default": 3, "description": "预计送达天数"},
|
||||
},
|
||||
Comment: "标准配送服务",
|
||||
},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
{
|
||||
Uuid: "exec-550e8400-e29b-41d4-a716-446655440004",
|
||||
ResourceUuid: "550e8400-e29b-41d4-a716-446655440300", // Order 资源 UUID
|
||||
Name: "通知执行器",
|
||||
Code: "NotificationDecision",
|
||||
Comment: "处理客户通知的执行器",
|
||||
Actions: []base.CondflowDecisionAction{
|
||||
{
|
||||
Name: "发送通知",
|
||||
Code: "Notify",
|
||||
ConfigSchema: map[string]any{
|
||||
"channels": map[string]any{"type": "array", "required": true, "description": "通知渠道列表"},
|
||||
"template": map[string]any{"type": "string", "required": true, "description": "通知模板"},
|
||||
"immediate": map[string]any{"type": "boolean", "default": true, "description": "是否立即发送"},
|
||||
},
|
||||
Comment: "向客户发送通知",
|
||||
},
|
||||
},
|
||||
CreatedAt: "2024-01-01 00:00:00",
|
||||
UpdatedAt: "2024-01-01 00:00:00",
|
||||
},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user