diff --git a/workflow/workflow.go b/workflow/workflow.go index 3b910a7c..b81e6a41 100644 --- a/workflow/workflow.go +++ b/workflow/workflow.go @@ -16,6 +16,23 @@ import ( "github.com/yaoapp/xiang/xlog" ) +// Process +// 读取工作流 xiang.workflow.Open(uid, data_id) +// 读取工作流 xiang.workflow.Find(workflow_id) +// 保存工作流 xiang.workflow.Save(uid, node_name, data_id, input, ...output) +// 进入下一个节点 xiang.workflow.Next(uid, workflow_id, output) +// 跳转到指定节点 xiang.workflow.Goto(uid, workflow_id, node_name, output) +// 更新流程状态 xiang.workflow.Status(uid, workflow_id, status_name, output) +// 结束流程 xiang.workflow.Done(uid, workflow_id, output) +// 关闭流程 xiang.workflow.Close(uid, workflow_id, output) +// 重置流程 xiang.workflow.Reset(uid, workflow_id, output) + +// API: +// 读取工作流 GET /api/xiang/workflow/<工作流名称>/open +// 读取工作流 GET /api/xiang/workflow/<工作流名称>/find/:id +// 读取工作流配置 GET /api/xiang/workflow/<工作流名称>/setting +// 调用自定义API POST /api/xiang/workflow/<工作流名称>/<自定义API路由> + // WorkFlows 工作流列表 var WorkFlows = map[string]*WorkFlow{} @@ -78,19 +95,6 @@ func (workflow *WorkFlow) Reload() *WorkFlow { return new } -// Process -// 读取工作流 xiang.workflow.Open(uid, name, data_id) -// 读取工作流 xiang.workflow.Find(id) -// 保存工作流 xiang.workflow.Save(uid, name, node, input) -// 进入下一个节点 xiang.workflow.Next(uid, id, input) -// 跳转到指定节点 xiang.workflow.Goto(uid, id, node, input) - -// API: -// 读取工作流 GET /api/xiang/workflow/<工作流名称>/open -// 读取工作流 GET /api/xiang/workflow/<工作流名称>/find/:id -// 读取工作流配置 GET /api/xiang/workflow/<工作流名称>/setting -// 调用自定义API POST /api/xiang/workflow/<工作流名称>/<自定义API路由> - // Setting 返回配置信息 func (workflow *WorkFlow) Setting(id int) {} @@ -203,9 +207,36 @@ func (workflow *WorkFlow) Save(uid int, name string, id interface{}, input Input return wflow.MustFind(id, gou.QueryParam{}) } -// Status 标记工作流状态 +// Done 标记完成 // uid 当前处理人ID, id 工作流ID -func (workflow *WorkFlow) Status(uid int, id int, output map[string]interface{}) { +func (workflow *WorkFlow) Done(uid int, id int, output map[string]interface{}) map[string]interface{} { + return workflow.Status(uid, id, "已完成", output) +} + +// Close 标记关闭 +// uid 当前处理人ID, id 工作流ID +func (workflow *WorkFlow) Close(uid int, id int, output map[string]interface{}) map[string]interface{} { + return workflow.Status(uid, id, "已关闭", output) +} + +// Status 设定状态 +// uid 当前处理人ID, id 工作流ID +func (workflow *WorkFlow) Status(uid int, id int, status string, output map[string]interface{}) map[string]interface{} { + wflow := workflow.Find(id) + mod := gou.Select("xiang.workflow") + output = workflow.MergeData(wflow["output"], output) + mod.Save(map[string]interface{}{ + "id": wflow["id"], + "output": output, + "status": status, + }) + return workflow.Find(id) +} + +// Reset 重新开始 +// uid 当前处理人ID, id 工作流ID +func (workflow *WorkFlow) Reset(uid int, id int, output map[string]interface{}) map[string]interface{} { + return workflow.Goto(uid, id, workflow.Nodes[0].Name, output) } // Goto 工作流跳转 diff --git a/workflow/workflow_test.go b/workflow/workflow_test.go index 9ed985de..63c045a3 100644 --- a/workflow/workflow_test.go +++ b/workflow/workflow_test.go @@ -202,6 +202,73 @@ func TestGoto(t *testing.T) { capsule.Query().From("xiang_workflow").Truncate() } +func TestReset(t *testing.T) { + assignFlow := Select("assign") + wflow := assignFlow.Save(1, "选择商务负责人", 1, Input{ + Data: map[string]interface{}{"id": 1, "name": "云主机"}, + Form: map[string]interface{}{"biz_id": 1, "name": "张良明"}, + }) + id := any.Of(wflow["id"]).CInt() + assignFlow.Next(1, id, map[string]interface{}{ + "项目名称": "测试项目", + "商务负责人名称": "林明波", + }) + + wflow = assignFlow.Reset(2, id, map[string]interface{}{"审批结果": "驳回"}) + data := maps.Of(wflow).Dot() + assert.Equal(t, true, data.Has("id")) + assert.Equal(t, "assign", data.Get("name")) + assert.Equal(t, "选择商务负责人", data.Get("node_name")) + assert.Equal(t, "进行中", data.Get("node_status")) + assert.Equal(t, "进行中", data.Get("status")) + assert.Equal(t, int64(1), data.Get("user_id")) + assert.Equal(t, float64(1), data.Get("users.选择商务负责人")) + assert.Equal(t, float64(2), data.Get("users.项目负责人审批")) + + // 清理数据 + capsule.Query().From("xiang_workflow").Truncate() +} + +func TestDone(t *testing.T) { + assignFlow := Select("assign") + wflow := assignFlow.Save(1, "选择商务负责人", 1, Input{ + Data: map[string]interface{}{"id": 1, "name": "云主机"}, + Form: map[string]interface{}{"biz_id": 1, "name": "张良明"}, + }) + id := any.Of(wflow["id"]).CInt() + assignFlow.Next(1, id, map[string]interface{}{ + "项目名称": "测试项目", + "商务负责人名称": "林明波", + }) + + wflow = assignFlow.Done(2, id, map[string]interface{}{"关闭原因": "测试完成"}) + data := maps.Of(wflow).Dot() + assert.Equal(t, "已完成", data.Get("status")) + assert.Equal(t, "测试完成", data.Get("output.关闭原因")) + // 清理数据 + capsule.Query().From("xiang_workflow").Truncate() +} + +func TestClose(t *testing.T) { + assignFlow := Select("assign") + wflow := assignFlow.Save(1, "选择商务负责人", 1, Input{ + Data: map[string]interface{}{"id": 1, "name": "云主机"}, + Form: map[string]interface{}{"biz_id": 1, "name": "张良明"}, + }) + id := any.Of(wflow["id"]).CInt() + assignFlow.Next(1, id, map[string]interface{}{ + "项目名称": "测试项目", + "商务负责人名称": "林明波", + }) + + wflow = assignFlow.Close(2, id, map[string]interface{}{"关闭原因": "测试关闭"}) + data := maps.Of(wflow).Dot() + assert.Equal(t, "已关闭", data.Get("status")) + assert.Equal(t, "测试关闭", data.Get("output.关闭原因")) + // 清理数据 + capsule.Query().From("xiang_workflow").Truncate() +} + func check(t *testing.T) { keys := []string{} for key, workflow := range WorkFlows {