备份代码
This commit is contained in:
parent
0a3da4a609
commit
903cf7f516
|
@ -18,13 +18,13 @@ type InstancesCreateParam struct {
|
||||||
// InstancesCreate handler
|
// InstancesCreate handler
|
||||||
// @Summary 创建流程实例
|
// @Summary 创建流程实例
|
||||||
// @Description 通过流程模板创建流程实例
|
// @Description 通过流程模板创建流程实例
|
||||||
// @ID Instances-Create
|
// @ID instances-create
|
||||||
// @Tags Instances-Create
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesCreateParam body InstancesCreateParam true "创建参数"
|
// @Param InstancesCreateParam body InstancesCreateParam true "创建参数"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/create [post]
|
// @Router /instances/create [post]
|
||||||
func (api *FlowInstanceApi) InstancesCreate(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesCreate(c *gin.Context) {
|
||||||
param := utils.QuickBind[InstancesCreateParam](c)
|
param := utils.QuickBind[InstancesCreateParam](c)
|
||||||
|
|
|
@ -15,12 +15,12 @@ type InstancesQueryParam struct {
|
||||||
// @Summary 实例查询
|
// @Summary 实例查询
|
||||||
// @Description 通过实例的ID查询流程实例详情
|
// @Description 通过实例的ID查询流程实例详情
|
||||||
// @ID instances-query
|
// @ID instances-query
|
||||||
// @Tags instances-query
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesQueryParam body InstancesQueryParam true "查询参数"
|
// @Param InstancesQueryParam body InstancesQueryParam true "查询参数"
|
||||||
// @Success 200 {object} result.Result{data = ApprovalInstanceDTO} "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result{data=ApprovalInstanceDTO} "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/query [post]
|
// @Router /instances/query [post]
|
||||||
func (api *FlowInstanceApi) InstancesQuery(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesQuery(c *gin.Context) {
|
||||||
param := utils.QuickBind[InstancesQueryParam](c)
|
param := utils.QuickBind[InstancesQueryParam](c)
|
||||||
|
|
|
@ -15,13 +15,13 @@ type InstancesQueryListParam struct {
|
||||||
// InstancesQueryList handler
|
// InstancesQueryList handler
|
||||||
// @Summary 输入你的接口总结
|
// @Summary 输入你的接口总结
|
||||||
// @Description 输入你的接口总结详情
|
// @Description 输入你的接口总结详情
|
||||||
// @ID 接口Id
|
// @ID instances-query-list
|
||||||
// @Tags 接口tag
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesQueryListParam body InstancesQueryListParam true "输入参数描述"
|
// @Param InstancesQueryListParam body InstancesQueryListParam true "输入参数描述"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/query/list [post]
|
// @Router /instances/query/list [post]
|
||||||
func (api *FlowInstanceApi) InstancesQueryList(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesQueryList(c *gin.Context) {
|
||||||
param := utils.QuickBind[InstancesQueryListParam](c)
|
param := utils.QuickBind[InstancesQueryListParam](c)
|
||||||
|
|
|
@ -14,13 +14,13 @@ type InstancesStartParam struct {
|
||||||
// InstancesStart handler
|
// InstancesStart handler
|
||||||
// @Summary 启动审批流
|
// @Summary 启动审批流
|
||||||
// @Description 启动审批流
|
// @Description 启动审批流
|
||||||
// @ID Instances-Start
|
// @ID instances-start
|
||||||
// @Tags Instances-Start
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesStartParam body InstancesStartParam true "启动实例ID"
|
// @Param InstancesStartParam body InstancesStartParam true "启动实例ID"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/start [post]
|
// @Router /instances/start [post]
|
||||||
func (api *FlowInstanceApi) InstancesStart(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesStart(c *gin.Context) {
|
||||||
param := utils.QuickBind[InstancesStartParam](c)
|
param := utils.QuickBind[InstancesStartParam](c)
|
||||||
|
|
|
@ -10,13 +10,13 @@ type InstancesStepsAddParam struct {
|
||||||
// InstancesStepsAdd handler
|
// InstancesStepsAdd handler
|
||||||
// @Summary 输入你的接口总结
|
// @Summary 输入你的接口总结
|
||||||
// @Description 输入你的接口总结详情
|
// @Description 输入你的接口总结详情
|
||||||
// @ID 接口Id
|
// @ID instances-steps-add
|
||||||
// @Tags 接口tag
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesStepsAddParam body InstancesStepsAddParam true "输入参数描述"
|
// @Param InstancesStepsAddParam body InstancesStepsAddParam true "输入参数描述"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/steps/add [post]
|
// @Router /instances/steps/add [post]
|
||||||
func (api *FlowInstanceApi) InstancesStepsAdd(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesStepsAdd(c *gin.Context) {
|
||||||
// TODO: Implement InstancesStepsAdd
|
// TODO: Implement InstancesStepsAdd
|
||||||
|
|
|
@ -9,13 +9,13 @@ type InstancesStepsRevertParam struct{}
|
||||||
// InstancesStepsRevert handler
|
// InstancesStepsRevert handler
|
||||||
// @Summary 输入你的接口总结
|
// @Summary 输入你的接口总结
|
||||||
// @Description 输入你的接口总结详情
|
// @Description 输入你的接口总结详情
|
||||||
// @ID 接口Id
|
// @ID instances-steps-revert
|
||||||
// @Tags 接口tag
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesStepsRevertParam body InstancesStepsRevertParam true "输入参数描述"
|
// @Param InstancesStepsRevertParam body InstancesStepsRevertParam true "输入参数描述"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/steps/revert [post]
|
// @Router /instances/steps/revert [post]
|
||||||
func (api *FlowInstanceApi) InstancesStepsRevert(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesStepsRevert(c *gin.Context) {
|
||||||
// TODO: Implement InstancesStepsRevert
|
// TODO: Implement InstancesStepsRevert
|
||||||
|
|
|
@ -9,13 +9,13 @@ type InstancesStepsUpdateParam struct{}
|
||||||
// InstancesStepsUpdate handler
|
// InstancesStepsUpdate handler
|
||||||
// @Summary 输入你的接口总结
|
// @Summary 输入你的接口总结
|
||||||
// @Description 输入你的接口总结详情
|
// @Description 输入你的接口总结详情
|
||||||
// @ID 接口Id
|
// @ID instances-steps-update
|
||||||
// @Tags 接口tag
|
// @Tags flow-instances
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param InstancesStepsUpdateParam body InstancesStepsUpdateParam true "输入参数描述"
|
// @Param InstancesStepsUpdateParam body InstancesStepsUpdateParam true "输入参数描述"
|
||||||
// @Success 200 {object} result.Result "返回成功的流程定义数据"
|
// @Success 200 {object} base.Result "返回成功的流程定义数据"
|
||||||
// @Failure 500 {object} result.Result "返回失败的流程定义数据"
|
// @Failure 500 {object} base.Result "返回失败的流程定义数据"
|
||||||
// @Router /instances/steps/update [post]
|
// @Router /instances/steps/update [post]
|
||||||
func (api *FlowInstanceApi) InstancesStepsUpdate(c *gin.Context) {
|
func (api *FlowInstanceApi) InstancesStepsUpdate(c *gin.Context) {
|
||||||
// TODO: Implement InstancesStepsUpdate
|
// TODO: Implement InstancesStepsUpdate
|
||||||
|
|
|
@ -231,6 +231,305 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/instances/create": {
|
||||||
|
"post": {
|
||||||
|
"description": "通过流程模板创建流程实例",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "创建流程实例",
|
||||||
|
"operationId": "instances-create",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "创建参数",
|
||||||
|
"name": "InstancesCreateParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesCreateParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/query": {
|
||||||
|
"post": {
|
||||||
|
"description": "通过实例的ID查询流程实例详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "实例查询",
|
||||||
|
"operationId": "instances-query",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "查询参数",
|
||||||
|
"name": "InstancesQueryParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesQueryParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/flow_instance.ApprovalInstanceDTO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/query/list": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-query-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesQueryListParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesQueryListParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/start": {
|
||||||
|
"post": {
|
||||||
|
"description": "启动审批流",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "启动审批流",
|
||||||
|
"operationId": "instances-start",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "启动实例ID",
|
||||||
|
"name": "InstancesStartParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStartParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/add": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-add",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsAddParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsAddParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/revert": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-revert",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsRevertParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsRevertParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/update": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-update",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsUpdateParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsUpdateParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
@ -340,6 +639,214 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.ApprovalInstanceDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_id": {
|
||||||
|
"description": "申请人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator_id": {
|
||||||
|
"description": "创建者ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"current_step_ids": {
|
||||||
|
"description": "当前步骤ID",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.CurrentStepDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dynamic_path_configs": {
|
||||||
|
"description": "动态路径配置,自定义,不直接存储",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.DynamicPathConfigDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_id": {
|
||||||
|
"description": "流程ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"steps": {
|
||||||
|
"description": "实例步骤",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstanceStepDTO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.ApprovalRecordDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_id": {
|
||||||
|
"description": "审批人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"comments": {
|
||||||
|
"description": "审批意见",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_step_id": {
|
||||||
|
"description": "关联的步骤实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_timeout": {
|
||||||
|
"description": "是否超时",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.CurrentStepDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"current_step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.DynamicPathConfigDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"from_step_id": {
|
||||||
|
"description": "来源步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"description": "关联的审批实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_parallel": {
|
||||||
|
"description": "是否并行",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"description": "路径优先级",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"to_step_id": {
|
||||||
|
"description": "目标步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstanceStepDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_comments": {
|
||||||
|
"description": "审批意见",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"approver_id": {
|
||||||
|
"description": "审批人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"description": "所属审批实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_dynamic": {
|
||||||
|
"description": "是否为动态步骤",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"records": {
|
||||||
|
"description": "审批记录",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.ApprovalRecordDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"description": "关联的流程步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesCreateParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"applicant_key": {
|
||||||
|
"description": "申请人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"flow_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesQueryListParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"page_number": {
|
||||||
|
"description": "当前页码,默认是第一页",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"page_size": {
|
||||||
|
"description": "每页记录数,默认是10条",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesQueryParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStartParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsAddParam": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsRevertParam": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsUpdateParam": {
|
||||||
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
|
|
@ -224,6 +224,305 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/instances/create": {
|
||||||
|
"post": {
|
||||||
|
"description": "通过流程模板创建流程实例",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "创建流程实例",
|
||||||
|
"operationId": "instances-create",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "创建参数",
|
||||||
|
"name": "InstancesCreateParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesCreateParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/query": {
|
||||||
|
"post": {
|
||||||
|
"description": "通过实例的ID查询流程实例详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "实例查询",
|
||||||
|
"operationId": "instances-query",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "查询参数",
|
||||||
|
"name": "InstancesQueryParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesQueryParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"$ref": "#/definitions/flow_instance.ApprovalInstanceDTO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/query/list": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-query-list",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesQueryListParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesQueryListParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/start": {
|
||||||
|
"post": {
|
||||||
|
"description": "启动审批流",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "启动审批流",
|
||||||
|
"operationId": "instances-start",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "启动实例ID",
|
||||||
|
"name": "InstancesStartParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStartParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/add": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-add",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsAddParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsAddParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/revert": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-revert",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsRevertParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsRevertParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/instances/steps/update": {
|
||||||
|
"post": {
|
||||||
|
"description": "输入你的接口总结详情",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"flow-instances"
|
||||||
|
],
|
||||||
|
"summary": "输入你的接口总结",
|
||||||
|
"operationId": "instances-steps-update",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "输入参数描述",
|
||||||
|
"name": "InstancesStepsUpdateParam",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstancesStepsUpdateParam"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "返回成功的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "返回失败的流程定义数据",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/base.Result"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
@ -333,6 +632,214 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.ApprovalInstanceDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_id": {
|
||||||
|
"description": "申请人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator_id": {
|
||||||
|
"description": "创建者ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"current_step_ids": {
|
||||||
|
"description": "当前步骤ID",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.CurrentStepDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dynamic_path_configs": {
|
||||||
|
"description": "动态路径配置,自定义,不直接存储",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.DynamicPathConfigDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_id": {
|
||||||
|
"description": "流程ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"steps": {
|
||||||
|
"description": "实例步骤",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.InstanceStepDTO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.ApprovalRecordDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_id": {
|
||||||
|
"description": "审批人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"comments": {
|
||||||
|
"description": "审批意见",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_step_id": {
|
||||||
|
"description": "关联的步骤实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_timeout": {
|
||||||
|
"description": "是否超时",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.CurrentStepDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"current_step_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.DynamicPathConfigDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"from_step_id": {
|
||||||
|
"description": "来源步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"description": "关联的审批实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_parallel": {
|
||||||
|
"description": "是否并行",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"description": "路径优先级",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"to_step_id": {
|
||||||
|
"description": "目标步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstanceStepDTO": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approver_comments": {
|
||||||
|
"description": "审批意见",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"approver_id": {
|
||||||
|
"description": "审批人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "主键ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"instance_id": {
|
||||||
|
"description": "所属审批实例ID",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"is_dynamic": {
|
||||||
|
"description": "是否为动态步骤",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"records": {
|
||||||
|
"description": "审批记录",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/flow_instance.ApprovalRecordDTO"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "审批状态",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"step_id": {
|
||||||
|
"description": "关联的流程步骤ID",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesCreateParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"applicant_key": {
|
||||||
|
"description": "申请人ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator_key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"flow_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesQueryListParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"page_number": {
|
||||||
|
"description": "当前页码,默认是第一页",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"page_size": {
|
||||||
|
"description": "每页记录数,默认是10条",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesQueryParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStartParam": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instance_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsAddParam": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsRevertParam": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"flow_instance.InstancesStepsUpdateParam": {
|
||||||
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
|
|
@ -73,6 +73,152 @@ definitions:
|
||||||
description: 流程名称
|
description: 流程名称
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
flow_instance.ApprovalInstanceDTO:
|
||||||
|
properties:
|
||||||
|
approver_id:
|
||||||
|
description: 申请人ID
|
||||||
|
type: string
|
||||||
|
creator_id:
|
||||||
|
description: 创建者ID
|
||||||
|
type: string
|
||||||
|
current_step_ids:
|
||||||
|
description: 当前步骤ID
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/flow_instance.CurrentStepDTO'
|
||||||
|
type: array
|
||||||
|
dynamic_path_configs:
|
||||||
|
description: 动态路径配置,自定义,不直接存储
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/flow_instance.DynamicPathConfigDTO'
|
||||||
|
type: array
|
||||||
|
flow_id:
|
||||||
|
description: 流程ID
|
||||||
|
type: integer
|
||||||
|
id:
|
||||||
|
description: 主键ID
|
||||||
|
type: integer
|
||||||
|
status:
|
||||||
|
description: 审批状态
|
||||||
|
type: string
|
||||||
|
steps:
|
||||||
|
description: 实例步骤
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/flow_instance.InstanceStepDTO'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
flow_instance.ApprovalRecordDTO:
|
||||||
|
properties:
|
||||||
|
approver_id:
|
||||||
|
description: 审批人ID
|
||||||
|
type: string
|
||||||
|
comments:
|
||||||
|
description: 审批意见
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
description: 主键ID
|
||||||
|
type: integer
|
||||||
|
instance_step_id:
|
||||||
|
description: 关联的步骤实例ID
|
||||||
|
type: integer
|
||||||
|
is_timeout:
|
||||||
|
description: 是否超时
|
||||||
|
type: boolean
|
||||||
|
status:
|
||||||
|
description: 审批状态
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
flow_instance.CurrentStepDTO:
|
||||||
|
properties:
|
||||||
|
current_step_id:
|
||||||
|
type: integer
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.DynamicPathConfigDTO:
|
||||||
|
properties:
|
||||||
|
from_step_id:
|
||||||
|
description: 来源步骤ID
|
||||||
|
type: integer
|
||||||
|
id:
|
||||||
|
description: 主键ID
|
||||||
|
type: integer
|
||||||
|
instance_id:
|
||||||
|
description: 关联的审批实例ID
|
||||||
|
type: integer
|
||||||
|
is_parallel:
|
||||||
|
description: 是否并行
|
||||||
|
type: boolean
|
||||||
|
priority:
|
||||||
|
description: 路径优先级
|
||||||
|
type: integer
|
||||||
|
to_step_id:
|
||||||
|
description: 目标步骤ID
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstanceStepDTO:
|
||||||
|
properties:
|
||||||
|
approver_comments:
|
||||||
|
description: 审批意见
|
||||||
|
type: string
|
||||||
|
approver_id:
|
||||||
|
description: 审批人ID
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
description: 主键ID
|
||||||
|
type: integer
|
||||||
|
instance_id:
|
||||||
|
description: 所属审批实例ID
|
||||||
|
type: integer
|
||||||
|
is_dynamic:
|
||||||
|
description: 是否为动态步骤
|
||||||
|
type: boolean
|
||||||
|
records:
|
||||||
|
description: 审批记录
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/flow_instance.ApprovalRecordDTO'
|
||||||
|
type: array
|
||||||
|
status:
|
||||||
|
description: 审批状态
|
||||||
|
type: string
|
||||||
|
step_id:
|
||||||
|
description: 关联的流程步骤ID
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesCreateParam:
|
||||||
|
properties:
|
||||||
|
applicant_key:
|
||||||
|
description: 申请人ID
|
||||||
|
type: string
|
||||||
|
creator_key:
|
||||||
|
type: string
|
||||||
|
flow_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesQueryListParam:
|
||||||
|
properties:
|
||||||
|
page_number:
|
||||||
|
description: 当前页码,默认是第一页
|
||||||
|
type: integer
|
||||||
|
page_size:
|
||||||
|
description: 每页记录数,默认是10条
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesQueryParam:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStartParam:
|
||||||
|
properties:
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStepsAddParam:
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStepsRevertParam:
|
||||||
|
type: object
|
||||||
|
flow_instance.InstancesStepsUpdateParam:
|
||||||
|
type: object
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
email: yejianfeng
|
email: yejianfeng
|
||||||
|
@ -214,6 +360,200 @@ paths:
|
||||||
summary: 添加步骤到流程
|
summary: 添加步骤到流程
|
||||||
tags:
|
tags:
|
||||||
- flow-definition
|
- flow-definition
|
||||||
|
/instances/create:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 通过流程模板创建流程实例
|
||||||
|
operationId: instances-create
|
||||||
|
parameters:
|
||||||
|
- description: 创建参数
|
||||||
|
in: body
|
||||||
|
name: InstancesCreateParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesCreateParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 创建流程实例
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/query:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 通过实例的ID查询流程实例详情
|
||||||
|
operationId: instances-query
|
||||||
|
parameters:
|
||||||
|
- description: 查询参数
|
||||||
|
in: body
|
||||||
|
name: InstancesQueryParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesQueryParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/base.Result'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
$ref: '#/definitions/flow_instance.ApprovalInstanceDTO'
|
||||||
|
type: object
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 实例查询
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/query/list:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 输入你的接口总结详情
|
||||||
|
operationId: instances-query-list
|
||||||
|
parameters:
|
||||||
|
- description: 输入参数描述
|
||||||
|
in: body
|
||||||
|
name: InstancesQueryListParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesQueryListParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 输入你的接口总结
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/start:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 启动审批流
|
||||||
|
operationId: instances-start
|
||||||
|
parameters:
|
||||||
|
- description: 启动实例ID
|
||||||
|
in: body
|
||||||
|
name: InstancesStartParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStartParam'
|
||||||
|
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:
|
||||||
|
- application/json
|
||||||
|
description: 输入你的接口总结详情
|
||||||
|
operationId: instances-steps-add
|
||||||
|
parameters:
|
||||||
|
- description: 输入参数描述
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsAddParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsAddParam'
|
||||||
|
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:
|
||||||
|
- application/json
|
||||||
|
description: 输入你的接口总结详情
|
||||||
|
operationId: instances-steps-revert
|
||||||
|
parameters:
|
||||||
|
- description: 输入参数描述
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsRevertParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsRevertParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 输入你的接口总结
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
|
/instances/steps/update:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 输入你的接口总结详情
|
||||||
|
operationId: instances-steps-update
|
||||||
|
parameters:
|
||||||
|
- description: 输入参数描述
|
||||||
|
in: body
|
||||||
|
name: InstancesStepsUpdateParam
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/flow_instance.InstancesStepsUpdateParam'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: 返回成功的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
"500":
|
||||||
|
description: 返回失败的流程定义数据
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/base.Result'
|
||||||
|
summary: 输入你的接口总结
|
||||||
|
tags:
|
||||||
|
- flow-instances
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
ApiKeyAuth:
|
ApiKeyAuth:
|
||||||
in: header
|
in: header
|
||||||
|
|
|
@ -0,0 +1,302 @@
|
||||||
|
package connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/base"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NodeConnectTest struct {
|
||||||
|
Nodes []*Node
|
||||||
|
NodeMap map[string]*Node // 用于快速查找节点
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeManager interface {
|
||||||
|
GetNodes() []AbstractNode
|
||||||
|
SetNodes([]AbstractNode)
|
||||||
|
GetNodeMap() map[string]AbstractNode
|
||||||
|
NewNodePathConfig(fromNodeKey, toNodeKey string) AbstractNodePathConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodeManagerS struct {
|
||||||
|
NodeManager
|
||||||
|
}
|
||||||
|
|
||||||
|
type AbstractNode interface {
|
||||||
|
GetPathConfigs() []AbstractNodePathConfig
|
||||||
|
SetPathConfigs([]AbstractNodePathConfig)
|
||||||
|
GetKey() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AbstractNodePathConfig interface {
|
||||||
|
GetKey() string
|
||||||
|
GetNodeID() int64
|
||||||
|
GetFromNodeKey() string
|
||||||
|
GetToNodeKey() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
PathConfigs []AbstractNodePathConfig `gorm:"-" json:"path_configs"`
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) GetPathConfigs() []AbstractNodePathConfig {
|
||||||
|
return n.PathConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) SetPathConfigs(configs []AbstractNodePathConfig) {
|
||||||
|
n.PathConfigs = configs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) GetKey() string {
|
||||||
|
return n.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
type NodePathConfig struct {
|
||||||
|
NodeID int64 `gorm:"type:bigint;index;not null" json:"node_id"`
|
||||||
|
FromNodeKey string `gorm:"type:varchar(50);index;not null" json:"from_node_key"`
|
||||||
|
ToNodeKey string ` gorm:"type:varchar(50);index;not null" json:"to_node_key"`
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodePathConfig) MarshalBinary() ([]byte, error) {
|
||||||
|
return json.Marshal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodePathConfig) UnmarshalBinary(data []byte) error {
|
||||||
|
return json.Unmarshal(data, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NodePathConfig) GetKey() string {
|
||||||
|
return n.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NodePathConfig) GetNodeID() int64 {
|
||||||
|
return n.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NodePathConfig) GetFromNodeKey() string {
|
||||||
|
return n.FromNodeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n NodePathConfig) GetToNodeKey() string {
|
||||||
|
return n.ToNodeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) InitializeNodeMap() {
|
||||||
|
InitializeNodeMap(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeNodeMap(nct NodeManager) {
|
||||||
|
for _, node := range nct.GetNodes() {
|
||||||
|
nct.GetNodeMap()[node.GetKey()] = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNextNodes(nct NodeManager, node AbstractNode) ([]AbstractNode, error) {
|
||||||
|
// 获取所有节点和路径配置
|
||||||
|
nodeMap := nct.GetNodeMap()
|
||||||
|
pathConfigs := node.GetPathConfigs()
|
||||||
|
// 存储下一个节点
|
||||||
|
var nextNodes []AbstractNode
|
||||||
|
// 遍历当前节点的路径配置
|
||||||
|
for _, pathConfig := range pathConfigs {
|
||||||
|
if pathConfig.GetFromNodeKey() == node.GetKey() {
|
||||||
|
// 根据路径配置的 ToNodeKey 找到目标节点
|
||||||
|
nextNodeKey := pathConfig.GetToNodeKey()
|
||||||
|
if nextNode, exists := nodeMap[nextNodeKey]; exists {
|
||||||
|
nextNodes = append(nextNodes, nextNode)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("next node with key %s not found", nextNodeKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) InsertNodeFirst(newNode AbstractNode) *NodeManagerS {
|
||||||
|
if s.GetNodes() == nil {
|
||||||
|
s.SetNodes([]AbstractNode{newNode})
|
||||||
|
}
|
||||||
|
s.SetNodes(append(s.GetNodes(), newNode))
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertNodeFirst(nct NodeManager, newNode AbstractNode) {
|
||||||
|
if nct.GetNodes() == nil {
|
||||||
|
nct.SetNodes([]AbstractNode{newNode})
|
||||||
|
}
|
||||||
|
nct.SetNodes(append(nct.GetNodes(), newNode))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) InsertNodeBetween(fromNode, toNode, newNode AbstractNode) error {
|
||||||
|
return InsertNodeBetween(s, fromNode, toNode, newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertNodeBetween 在两个节点之间插入新节点
|
||||||
|
func InsertNodeBetween(nct NodeManager, fromNode, toNode, newNode AbstractNode) error {
|
||||||
|
if fromNode == nil || toNode == nil || newNode == nil {
|
||||||
|
return fmt.Errorf("节点不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除从 fromNode 到 toNode 的路径
|
||||||
|
removePath(nct, fromNode, toNode)
|
||||||
|
|
||||||
|
// 添加从 fromNode 到 newNode 的路径
|
||||||
|
addPath(nct, fromNode, newNode)
|
||||||
|
|
||||||
|
// 添加从 newNode 到 toNode 的路径
|
||||||
|
addPath(nct, newNode, toNode)
|
||||||
|
|
||||||
|
// 如果新节点不在节点列表中,添加进去
|
||||||
|
if _, exists := nct.GetNodeMap()[newNode.GetKey()]; !exists {
|
||||||
|
nct.SetNodes(append(nct.GetNodes(), newNode))
|
||||||
|
nct.GetNodeMap()[newNode.GetKey()] = newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) InsertNodeAfter(node, newNode AbstractNode) error {
|
||||||
|
return InsertNodeAfter(s, node, newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertNodeAfter 在指定节点之后插入节点
|
||||||
|
func InsertNodeAfter(nct NodeManager, node, newNode AbstractNode) error {
|
||||||
|
if node == nil || newNode == nil {
|
||||||
|
return fmt.Errorf("节点不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取从当前节点出去的所有节点
|
||||||
|
outgoingNodes := getOutgoingNodes(nct, node)
|
||||||
|
|
||||||
|
// 移除这些路径并重新连接
|
||||||
|
for _, toNode := range outgoingNodes {
|
||||||
|
removePath(nct, node, toNode)
|
||||||
|
addPath(nct, newNode, toNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加从当前节点到新节点的路径
|
||||||
|
addPath(nct, node, newNode)
|
||||||
|
|
||||||
|
// 如果新节点不在节点列表中,添加进去
|
||||||
|
if _, exists := nct.GetNodeMap()[newNode.GetKey()]; !exists {
|
||||||
|
nct.SetNodes(append(nct.GetNodes(), newNode))
|
||||||
|
nct.GetNodeMap()[newNode.GetKey()] = newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) InsertNodeBefore(node, newNode AbstractNode) error {
|
||||||
|
return InsertNodeBefore(s, node, newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertNodeBefore 在指定节点之前插入节点
|
||||||
|
func InsertNodeBefore(nct NodeManager, node, newNode AbstractNode) error {
|
||||||
|
if node == nil || newNode == nil {
|
||||||
|
return fmt.Errorf("节点不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指向当前节点的所有节点
|
||||||
|
incomingNodes := getIncomingNodes(nct, node)
|
||||||
|
|
||||||
|
// 移除这些路径并重新连接
|
||||||
|
for _, fromNode := range incomingNodes {
|
||||||
|
removePath(nct, fromNode, node)
|
||||||
|
addPath(nct, fromNode, newNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加从新节点到当前节点的路径
|
||||||
|
addPath(nct, newNode, node)
|
||||||
|
|
||||||
|
// 如果新节点不在节点列表中,添加进去
|
||||||
|
if _, exists := nct.GetNodeMap()[newNode.GetKey()]; !exists {
|
||||||
|
nct.SetNodes(append(nct.GetNodes(), newNode))
|
||||||
|
nct.GetNodeMap()[newNode.GetKey()] = newNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) VerifyConnections() error {
|
||||||
|
return VerifyConnections(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyConnections 验证节点连接
|
||||||
|
func VerifyConnections(nct NodeManager) error {
|
||||||
|
for _, node := range nct.GetNodes() {
|
||||||
|
for _, pc := range node.GetPathConfigs() {
|
||||||
|
if _, exists := nct.GetNodeMap()[pc.GetFromNodeKey()]; !exists {
|
||||||
|
return fmt.Errorf("FromNodeKey %s 不存在", pc.GetFromNodeKey())
|
||||||
|
}
|
||||||
|
if _, exists := nct.GetNodeMap()[pc.GetToNodeKey()]; !exists {
|
||||||
|
return fmt.Errorf("ToNodeKey %s 不存在", pc.GetToNodeKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NodeManagerS) PrintConnections() {
|
||||||
|
PrintConnections(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintConnections 打印连接情况
|
||||||
|
func PrintConnections(nct NodeManager) {
|
||||||
|
fmt.Println("节点连接情况:")
|
||||||
|
for _, node := range nct.GetNodes() {
|
||||||
|
for _, pc := range node.GetPathConfigs() {
|
||||||
|
fmt.Printf("节点 %s -> 节点 %s\n", pc.GetFromNodeKey(), pc.GetToNodeKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addPath 添加路径
|
||||||
|
func addPath(nct NodeManager, fromNode, toNode AbstractNode) {
|
||||||
|
pathConfig := nct.NewNodePathConfig(fromNode.GetKey(), toNode.GetKey())
|
||||||
|
fromNode.SetPathConfigs(append(fromNode.GetPathConfigs(), pathConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
// removePath 移除路径
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fromNode.SetPathConfigs(newPathConfigs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getOutgoingNodes 获取后继节点
|
||||||
|
func getOutgoingNodes(nct NodeManager, node AbstractNode) []AbstractNode {
|
||||||
|
var result []AbstractNode
|
||||||
|
for _, pc := range node.GetPathConfigs() {
|
||||||
|
if toNode, exists := nct.GetNodeMap()[pc.GetToNodeKey()]; exists {
|
||||||
|
result = append(result, toNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// getIncomingNodes 获取前驱节点
|
||||||
|
func getIncomingNodes(nct NodeManager, node AbstractNode) []AbstractNode {
|
||||||
|
var result []AbstractNode
|
||||||
|
for _, n := range nct.GetNodes() {
|
||||||
|
for _, pc := range n.GetPathConfigs() {
|
||||||
|
if pc.GetToNodeKey() == node.GetKey() {
|
||||||
|
result = append(result, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
|
@ -1,182 +0,0 @@
|
||||||
package abstract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"approveflow/app/base"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NodeConnectTest struct {
|
|
||||||
Nodes []*Node
|
|
||||||
NodeMap map[string]*Node // 用于快速查找节点
|
|
||||||
}
|
|
||||||
|
|
||||||
type NodeManager interface {
|
|
||||||
GetNodes() []*Node
|
|
||||||
SetNodes([]*Node)
|
|
||||||
GetNodeMap() map[string]*Node
|
|
||||||
}
|
|
||||||
|
|
||||||
type Node struct {
|
|
||||||
PathConfigs []*NodePathConfig `gorm:"foreignKey:NodeID;constraint:OnDelete:CASCADE" json:"path_configs"`
|
|
||||||
base.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
type NodePathConfig struct {
|
|
||||||
NodeID int64 `gorm:"type:bigint;index;not null" json:"node_id"`
|
|
||||||
FromNodeKey string `gorm:"type:varchar(50);index;not null" json:"from_node_key"`
|
|
||||||
ToNodeKey string ` gorm:"type:varchar(50);index;not null" json:"to_node_key"`
|
|
||||||
base.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitializeNodeMap(nct NodeManager) {
|
|
||||||
for _, node := range nct.GetNodes() {
|
|
||||||
nct.GetNodeMap()[node.Key] = node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertNodeBetween 在两个节点之间插入新节点
|
|
||||||
func InsertNodeBetween(nct NodeManager, fromNode, toNode, newNode *Node) error {
|
|
||||||
if fromNode == nil || toNode == nil || newNode == nil {
|
|
||||||
return fmt.Errorf("节点不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除从 fromNode 到 toNode 的路径
|
|
||||||
removePath(nct, fromNode, toNode)
|
|
||||||
|
|
||||||
// 添加从 fromNode 到 newNode 的路径
|
|
||||||
addPath(nct, fromNode, newNode)
|
|
||||||
|
|
||||||
// 添加从 newNode 到 toNode 的路径
|
|
||||||
addPath(nct, newNode, toNode)
|
|
||||||
|
|
||||||
// 如果新节点不在节点列表中,添加进去
|
|
||||||
if _, exists := nct.GetNodeMap()[newNode.Key]; !exists {
|
|
||||||
nct.SetNodes(append(nct.GetNodes(), newNode))
|
|
||||||
nct.GetNodeMap()[newNode.Key] = newNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertNodeAfter 在指定节点之后插入节点
|
|
||||||
func InsertNodeAfter(nct NodeManager, node, newNode *Node) error {
|
|
||||||
if node == nil || newNode == nil {
|
|
||||||
return fmt.Errorf("节点不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取从当前节点出去的所有节点
|
|
||||||
outgoingNodes := getOutgoingNodes(nct, node)
|
|
||||||
|
|
||||||
// 移除这些路径并重新连接
|
|
||||||
for _, toNode := range outgoingNodes {
|
|
||||||
removePath(nct, node, toNode)
|
|
||||||
addPath(nct, newNode, toNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加从当前节点到新节点的路径
|
|
||||||
addPath(nct, node, newNode)
|
|
||||||
|
|
||||||
// 如果新节点不在节点列表中,添加进去
|
|
||||||
if _, exists := nct.GetNodeMap()[newNode.Key]; !exists {
|
|
||||||
nct.SetNodes(append(nct.GetNodes(), newNode))
|
|
||||||
nct.GetNodeMap()[newNode.Key] = newNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertNodeBefore 在指定节点之前插入节点
|
|
||||||
func InsertNodeBefore(nct NodeManager, node, newNode *Node) error {
|
|
||||||
if node == nil || newNode == nil {
|
|
||||||
return fmt.Errorf("节点不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取指向当前节点的所有节点
|
|
||||||
incomingNodes := getIncomingNodes(nct, node)
|
|
||||||
|
|
||||||
// 移除这些路径并重新连接
|
|
||||||
for _, fromNode := range incomingNodes {
|
|
||||||
removePath(nct, fromNode, node)
|
|
||||||
addPath(nct, fromNode, newNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加从新节点到当前节点的路径
|
|
||||||
addPath(nct, newNode, node)
|
|
||||||
|
|
||||||
// 如果新节点不在节点列表中,添加进去
|
|
||||||
if _, exists := nct.GetNodeMap()[newNode.Key]; !exists {
|
|
||||||
nct.SetNodes(append(nct.GetNodes(), newNode))
|
|
||||||
nct.GetNodeMap()[newNode.Key] = newNode
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyConnections 验证节点连接
|
|
||||||
func VerifyConnections(nct NodeManager) error {
|
|
||||||
for _, node := range nct.GetNodes() {
|
|
||||||
for _, pc := range node.PathConfigs {
|
|
||||||
if _, exists := nct.GetNodeMap()[pc.FromNodeKey]; !exists {
|
|
||||||
return fmt.Errorf("FromNodeKey %s 不存在", pc.FromNodeKey)
|
|
||||||
}
|
|
||||||
if _, exists := nct.GetNodeMap()[pc.ToNodeKey]; !exists {
|
|
||||||
return fmt.Errorf("ToNodeKey %s 不存在", pc.ToNodeKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrintConnections 打印连接情况
|
|
||||||
func PrintConnections(nct NodeManager) {
|
|
||||||
fmt.Println("节点连接情况:")
|
|
||||||
for _, node := range nct.GetNodes() {
|
|
||||||
for _, pc := range node.PathConfigs {
|
|
||||||
fmt.Printf("节点 %s -> 节点 %s\n", pc.FromNodeKey, pc.ToNodeKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addPath 添加路径
|
|
||||||
func addPath(nct NodeManager, fromNode, toNode *Node) {
|
|
||||||
pathConfig := &NodePathConfig{
|
|
||||||
FromNodeKey: fromNode.Key,
|
|
||||||
ToNodeKey: toNode.Key,
|
|
||||||
}
|
|
||||||
fromNode.PathConfigs = append(fromNode.PathConfigs, pathConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// removePath 移除路径
|
|
||||||
func removePath(nct NodeManager, fromNode, toNode *Node) {
|
|
||||||
var newPathConfigs []*NodePathConfig
|
|
||||||
for _, pc := range fromNode.PathConfigs {
|
|
||||||
if !(pc.FromNodeKey == fromNode.Key && pc.ToNodeKey == toNode.Key) {
|
|
||||||
newPathConfigs = append(newPathConfigs, pc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fromNode.PathConfigs = newPathConfigs
|
|
||||||
}
|
|
||||||
|
|
||||||
// getOutgoingNodes 获取后继节点
|
|
||||||
func getOutgoingNodes(nct NodeManager, node *Node) []*Node {
|
|
||||||
var result []*Node
|
|
||||||
for _, pc := range node.PathConfigs {
|
|
||||||
if toNode, exists := nct.GetNodeMap()[pc.ToNodeKey]; exists {
|
|
||||||
result = append(result, toNode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// getIncomingNodes 获取前驱节点
|
|
||||||
func getIncomingNodes(nct NodeManager, node *Node) []*Node {
|
|
||||||
var result []*Node
|
|
||||||
for _, n := range nct.GetNodes() {
|
|
||||||
for _, pc := range n.PathConfigs {
|
|
||||||
if pc.ToNodeKey == node.Key {
|
|
||||||
result = append(result, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
|
@ -2,17 +2,52 @@ package flow_definition
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
|
"approveflow/app/provider/abstract/connect"
|
||||||
|
"approveflow/app/utils"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ApprovalFlow 审批流程表
|
// ApprovalFlow 审批流程表
|
||||||
type ApprovalFlow struct {
|
type ApprovalFlow struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
Name string `gorm:"type:varchar(100);not null" json:"name"` // 流程名称
|
Name string `gorm:"type:varchar(100);not null" json:"name"` // 流程名称
|
||||||
Description string `gorm:"type:text" json:"description"` // 流程描述
|
Description string `gorm:"type:text" json:"description"` // 流程描述
|
||||||
Steps []*ApprovalStep `gorm:"foreignKey:FlowID;constraint:OnDelete:CASCADE" json:"steps"` // 流程步骤
|
Steps []*ApprovalStep `gorm:"foreignKey:FlowID;constraint:OnDelete:CASCADE" json:"steps"` // 流程步骤
|
||||||
base.Model // 通用字段,包括创建时间、更新时间等
|
NodeMap map[string]connect.AbstractNode `gorm:"-" json:"node_map"` // 流程步骤
|
||||||
|
base.Model // 通用字段,包括创建时间、更新时间等
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *ApprovalFlow) GetNodes() []connect.AbstractNode {
|
||||||
|
return utils.ConvertToAbstractNodes(flow.Steps, func(step *ApprovalStep) connect.AbstractNode {
|
||||||
|
return step
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *ApprovalFlow) SetNodes(nodes []connect.AbstractNode) {
|
||||||
|
steps := make([]*ApprovalStep, len(nodes))
|
||||||
|
for i, node := range nodes {
|
||||||
|
// 类型断言,将 abstract.AbstractNode 转换为 *ApprovalStep
|
||||||
|
if step, ok := node.(*ApprovalStep); ok {
|
||||||
|
steps[i] = step
|
||||||
|
} else {
|
||||||
|
// 如果转换失败,可以选择处理错误,抛出异常或记录日志
|
||||||
|
panic("node is not of type *ApprovalStep")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flow.Steps = steps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *ApprovalFlow) GetNodeMap() map[string]connect.AbstractNode {
|
||||||
|
if flow.NodeMap == nil {
|
||||||
|
flow.NodeMap = map[string]connect.AbstractNode{}
|
||||||
|
connect.InitializeNodeMap(flow)
|
||||||
|
}
|
||||||
|
return flow.NodeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flow *ApprovalFlow) NewNodePathConfig(fromNodeKey, toNodeKey string) connect.AbstractNodePathConfig {
|
||||||
|
return NewPathConfig(fromNodeKey, toNodeKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (flow *ApprovalFlow) MarshalBinary() ([]byte, error) {
|
func (flow *ApprovalFlow) MarshalBinary() ([]byte, error) {
|
||||||
|
@ -31,10 +66,13 @@ func NewApprovalFlow(name string, description string) *ApprovalFlow {
|
||||||
}
|
}
|
||||||
startStep := NewStartStep()
|
startStep := NewStartStep()
|
||||||
endStep := NewEndStep()
|
endStep := NewEndStep()
|
||||||
path := NewPathBetween(startStep, endStep)
|
|
||||||
err := startStep.AddPathConfig(path)
|
connect.InsertNodeFirst(approvalFlow, startStep)
|
||||||
err = approvalFlow.AddStep(startStep)
|
err := connect.InsertNodeAfter(approvalFlow, startStep, endStep)
|
||||||
err = approvalFlow.AddStep(endStep)
|
//path := NewPathBetween(startStep, endStep)
|
||||||
|
//err := startStep.AddPathConfig(path)
|
||||||
|
//err = approvalFlow.AddStep(startStep)
|
||||||
|
//err = approvalFlow.AddStep(endStep)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -115,31 +153,9 @@ func (flow *ApprovalFlow) Validate() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirstStep 获取审批流程中的第一个审批节点
|
// FirstStep 获取审批流程中的第一个审批节点
|
||||||
func (flow *ApprovalFlow) FirstStep(data map[string]interface{}) (*ApprovalStep, error) {
|
func (flow *ApprovalFlow) FirstStep() (*ApprovalStep, error) {
|
||||||
// 首先检查是否有步骤
|
|
||||||
if len(flow.Steps) == 0 {
|
|
||||||
return nil, fmt.Errorf("no steps found in the approval flow")
|
|
||||||
}
|
|
||||||
// 创建一个 map 用于存储所有指向目标节点的 StepKey
|
|
||||||
toStepKeys := make(map[string]bool)
|
|
||||||
for _, step := range flow.Steps {
|
for _, step := range flow.Steps {
|
||||||
for _, pathConfig := range step.PathConfigs {
|
if step.StepCode == StepStart {
|
||||||
condition, err := pathConfig.EvaluateCondition(data)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !condition {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// 使用 pathConfig.ToStepKey 替换 ToStepID,并且存储为 string 类型
|
|
||||||
toStepKeys[pathConfig.ToStepKey] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 遍历步骤,找到第一个没有被指向的步骤
|
|
||||||
for _, step := range flow.Steps {
|
|
||||||
// 假设 step.Key 是 string 类型,检查是否存在于 toStepKeys 中
|
|
||||||
if _, exists := toStepKeys[step.Key]; !exists {
|
|
||||||
// 如果当前步骤的 Key 不在 toStepKeys 中,则它是第一个审批节点
|
|
||||||
return step, nil
|
return step, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,30 @@ import (
|
||||||
|
|
||||||
// ApprovalPathConfig 审批路径配置表
|
// ApprovalPathConfig 审批路径配置表
|
||||||
type ApprovalPathConfig struct {
|
type ApprovalPathConfig struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
FromStepID int64 `gorm:"index;not null" json:"from_step_id"` // 来源步骤ID
|
NodeID int64 `gorm:"type:bigint;index;not null" json:"node_id"`
|
||||||
FromStepKey string `gorm:"type:varchar(50);index;not null" json:"from_step_key"` // 来源步骤ID
|
FromNodeKey string `gorm:"type:varchar(50);index;not null" json:"from_node_key"`
|
||||||
|
ToNodeKey string ` gorm:"type:varchar(50);index;not null" json:"to_node_key"`
|
||||||
ToStepKey string `gorm:"type:varchar(50);index;not null" json:"to_step_key"` // 目标步骤ID
|
IsParallel bool `gorm:"type:bool;default:false" json:"is_parallel"` // 是否并行
|
||||||
IsParallel bool `gorm:"type:bool;default:false" json:"is_parallel"` // 是否并行
|
ConditionExpression string `gorm:"type:text" json:"condition_expression"` // 条件表达式
|
||||||
ConditionExpression string `gorm:"type:text" json:"condition_expression"` // 条件表达式
|
base.Model
|
||||||
ApprovalConditionCommon `gorm:"-"`
|
ApprovalConditionCommon `gorm:"-"`
|
||||||
base.Model // 通用字段,包括创建时间、更新时间等
|
}
|
||||||
|
|
||||||
|
func (a *ApprovalPathConfig) GetKey() string {
|
||||||
|
return a.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApprovalPathConfig) GetNodeID() int64 {
|
||||||
|
return a.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApprovalPathConfig) GetFromNodeKey() string {
|
||||||
|
return a.FromNodeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApprovalPathConfig) GetToNodeKey() string {
|
||||||
|
return a.ToNodeKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ApprovalPathConfig) MarshalBinary() ([]byte, error) {
|
func (a *ApprovalPathConfig) MarshalBinary() ([]byte, error) {
|
||||||
|
@ -31,23 +46,31 @@ func (a *ApprovalPathConfig) UnmarshalBinary(data []byte) error {
|
||||||
|
|
||||||
func (a *ApprovalPathConfig) NewPathWithStep(step *ApprovalStep) (*ApprovalPathConfig, *ApprovalPathConfig) {
|
func (a *ApprovalPathConfig) NewPathWithStep(step *ApprovalStep) (*ApprovalPathConfig, *ApprovalPathConfig) {
|
||||||
toPath := &ApprovalPathConfig{
|
toPath := &ApprovalPathConfig{
|
||||||
FromStepID: step.ID,
|
IsParallel: false,
|
||||||
FromStepKey: step.Key,
|
|
||||||
ToStepKey: a.ToStepKey,
|
|
||||||
IsParallel: false,
|
|
||||||
}
|
}
|
||||||
a.ToStepKey = step.Key
|
a.FromNodeKey = step.Key
|
||||||
|
a.NodeID = step.ID
|
||||||
|
a.ToNodeKey = step.Key
|
||||||
return a, toPath
|
return a, toPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPathBetween(fromStep, toStep *ApprovalStep) *ApprovalPathConfig {
|
func NewPathBetween(fromStep, toStep *ApprovalStep) *ApprovalPathConfig {
|
||||||
return &ApprovalPathConfig{
|
path := &ApprovalPathConfig{
|
||||||
FromStepID: fromStep.ID,
|
|
||||||
FromStepKey: fromStep.Key,
|
|
||||||
//ToStepID: toStep.ID,
|
|
||||||
ToStepKey: toStep.Key,
|
|
||||||
IsParallel: false,
|
IsParallel: false,
|
||||||
}
|
}
|
||||||
|
path.FromNodeKey = fromStep.Key
|
||||||
|
path.NodeID = fromStep.ID
|
||||||
|
path.ToNodeKey = toStep.Key
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPathConfig(fromStepKey, toStepKey string) *ApprovalPathConfig {
|
||||||
|
path := &ApprovalPathConfig{
|
||||||
|
IsParallel: false,
|
||||||
|
}
|
||||||
|
path.FromNodeKey = fromStepKey
|
||||||
|
path.ToNodeKey = toStepKey
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPathWithTarget(target *ApprovalStep) *ApprovalPathConfig {
|
func NewPathWithTarget(target *ApprovalStep) *ApprovalPathConfig {
|
||||||
|
|
|
@ -2,6 +2,8 @@ package flow_definition
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
|
"approveflow/app/provider/abstract/connect"
|
||||||
|
"approveflow/app/utils"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -10,14 +12,37 @@ import (
|
||||||
|
|
||||||
// ApprovalStep 审批步骤表
|
// ApprovalStep 审批步骤表
|
||||||
type ApprovalStep struct {
|
type ApprovalStep struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
FlowID int64 `gorm:"index;not null" json:"flow_id"` // 所属流程ID
|
FlowID int64 `gorm:"index;not null" json:"flow_id"` // 所属流程ID
|
||||||
Name string `gorm:"type:varchar(100);not null" json:"name"` // 步骤名称
|
Name string `gorm:"type:varchar(100);not null" json:"name"` // 步骤名称
|
||||||
StepCode string `gorm:"type:varchar(100)" json:"step_code"` // 步骤编号用于标识特殊的审批节点
|
StepCode string `gorm:"type:varchar(100)" json:"step_code"` // 步骤编号用于标识特殊的审批节点
|
||||||
Rules []*ApprovalRule `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"rules"` // Foreign key for Rules
|
Rules []*ApprovalRule `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"rules"` // Foreign key for Rules
|
||||||
DynamicConfig *DynamicApprovalStepConfig `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"dynamic_config"` // One-to-one with DynamicConfig
|
DynamicConfig *DynamicApprovalStepConfig `gorm:"foreignKey:StepID;constraint:OnDelete:CASCADE" json:"dynamic_config"` // One-to-one with DynamicConfig
|
||||||
PathConfigs []*ApprovalPathConfig `gorm:"foreignKey:FromStepID;constraint:OnDelete:CASCADE" json:"from_path_configs"` // 路径配置集合
|
PathConfigs []*ApprovalPathConfig `gorm:"foreignKey:NodeID;constraint:OnDelete:CASCADE" json:"path_configs"` // 路径配置集合
|
||||||
base.Model // 通用字段,包括创建时间、更新时间等
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *ApprovalStep) GetPathConfigs() []connect.AbstractNodePathConfig {
|
||||||
|
abstractConfigs := make([]connect.AbstractNodePathConfig, len(step.PathConfigs))
|
||||||
|
for i, config := range step.PathConfigs {
|
||||||
|
abstractConfigs[i] = config // 直接赋值,因为 ApprovalPathConfig 实现了 AbstractNodePathConfig
|
||||||
|
}
|
||||||
|
return abstractConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *ApprovalStep) SetPathConfigs(configs []connect.AbstractNodePathConfig) {
|
||||||
|
convertedConfigs, err := utils.ConvertToSpecificType(configs, func(item connect.AbstractNodePathConfig) (*ApprovalPathConfig, bool) {
|
||||||
|
specificConfig, ok := item.(*ApprovalPathConfig)
|
||||||
|
return specificConfig, ok
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Error in SetPathConfigs: %v", err))
|
||||||
|
}
|
||||||
|
step.PathConfigs = convertedConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *ApprovalStep) GetKey() string {
|
||||||
|
return step.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
func (step *ApprovalStep) MarshalBinary() ([]byte, error) {
|
func (step *ApprovalStep) MarshalBinary() ([]byte, error) {
|
||||||
|
@ -105,7 +130,7 @@ func (step *ApprovalStep) AddPathConfig(pathConfig *ApprovalPathConfig) error {
|
||||||
return fmt.Errorf("path config with ID %d already exists in step", pathConfig.ID)
|
return fmt.Errorf("path config with ID %d already exists in step", pathConfig.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pathConfig.FromStepID = step.ID
|
pathConfig.NodeID = step.ID
|
||||||
step.PathConfigs = append(step.PathConfigs, pathConfig)
|
step.PathConfigs = append(step.PathConfigs, pathConfig)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -130,7 +155,7 @@ func (step *ApprovalStep) GetNextStepIDs(data map[string]interface{}) ([]string,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if met {
|
if met {
|
||||||
nextStepKeys = append(nextStepKeys, pathConfig.ToStepKey)
|
nextStepKeys = append(nextStepKeys, pathConfig.ToNodeKey)
|
||||||
if !pathConfig.IsParallel {
|
if !pathConfig.IsParallel {
|
||||||
break // 非并行时,只取第一个满足条件的路径
|
break // 非并行时,只取第一个满足条件的路径
|
||||||
}
|
}
|
||||||
|
@ -141,7 +166,7 @@ func (step *ApprovalStep) GetNextStepIDs(data map[string]interface{}) ([]string,
|
||||||
|
|
||||||
func (step *ApprovalStep) GetPathByToKey(toStepKey string) (*ApprovalPathConfig, bool) {
|
func (step *ApprovalStep) GetPathByToKey(toStepKey string) (*ApprovalPathConfig, bool) {
|
||||||
for _, pathConfig := range step.PathConfigs {
|
for _, pathConfig := range step.PathConfigs {
|
||||||
if pathConfig.ToStepKey == toStepKey {
|
if pathConfig.ToNodeKey == toStepKey {
|
||||||
return pathConfig, true
|
return pathConfig, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,4 +19,6 @@ func TestModel(t *testing.T) {
|
||||||
base.BaseExtensionField{},
|
base.BaseExtensionField{},
|
||||||
ApprovalStep{},
|
ApprovalStep{},
|
||||||
ApprovalRule{})
|
ApprovalRule{})
|
||||||
|
|
||||||
|
db.AutoMigrate(ApprovalStep{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ func (f *FlowDefinitionService) AddStepWithPosition(ctx context.Context, flowID
|
||||||
return f.handlerFlow(ctx, flowID, func(ctx context.Context, flow *ApprovalFlow) error {
|
return f.handlerFlow(ctx, flowID, func(ctx context.Context, flow *ApprovalFlow) error {
|
||||||
fromStep, err := flow.GetStepByKey(fromStepId)
|
fromStep, err := flow.GetStepByKey(fromStepId)
|
||||||
_, err = flow.GetStepByKey(toStepKey)
|
_, err = flow.GetStepByKey(toStepKey)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -202,7 +203,7 @@ func (f *FlowDefinitionService) UpdatePathConfig(ctx context.Context, flowID int
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pathById.ToStepKey = config.ToStepKey
|
pathById.ToNodeKey = config.ToNodeKey
|
||||||
pathById.IsParallel = config.IsParallel
|
pathById.IsParallel = config.IsParallel
|
||||||
pathById.ConditionExpression = config.ConditionExpression
|
pathById.ConditionExpression = config.ConditionExpression
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -2,7 +2,9 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"approveflow/app/base"
|
"approveflow/app/base"
|
||||||
|
"approveflow/app/provider/abstract/connect"
|
||||||
"approveflow/app/provider/flow_definition"
|
"approveflow/app/provider/flow_definition"
|
||||||
|
"approveflow/app/utils"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -20,20 +22,39 @@ const (
|
||||||
|
|
||||||
// ApprovalInstance 审批实例表
|
// ApprovalInstance 审批实例表
|
||||||
type ApprovalInstance struct {
|
type ApprovalInstance struct {
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
FlowID int64 `gorm:"type:bigint;index;not null" json:"flow_id"` // 流程ID
|
FlowID int64 `gorm:"type:bigint;index;not null" json:"flow_id"` // 流程ID
|
||||||
ApplicantKey string `gorm:"type:bigint;index;not null" json:"approver_id"` //申请人ID
|
ApplicantKey string `gorm:"type:bigint;index;not null" json:"approver_id"` //申请人ID
|
||||||
CreatorKey string `gorm:"type:bigint;not null" json:"creator_id"` // 创建者ID
|
CreatorKey string `gorm:"type:bigint;not null" json:"creator_id"` // 创建者ID
|
||||||
Status string `gorm:"type:varchar(50);not null" json:"status"` // 审批状态
|
Status string `gorm:"type:varchar(50);not null" json:"status"` // 审批状态
|
||||||
CurrentStepIDs []*CurrentStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"current_step_ids"` // 当前步骤ID
|
CurrentStepIDs []*CurrentStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"current_step_ids"` // 当前步骤ID
|
||||||
Steps []*InstanceStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"steps"` // 实例步骤
|
Steps []*InstanceStep `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"steps"` // 实例步骤
|
||||||
DynamicPathConfigs []*DynamicPathConfig `gorm:"foreignKey:InstanceID;constraint:OnDelete:CASCADE" json:"dynamic_path_configs"` // 动态路径配置,自定义,不直接存储
|
Data string `gorm:"type:json" json:"data"` // 保存审批数据的 JSON
|
||||||
Data string `gorm:"type:json" json:"data"` // 保存审批数据的 JSON
|
|
||||||
ApprovalFlow *flow_definition.ApprovalFlow `gorm:"-" json:"approval_flow"`
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
base.Model
|
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 目前审批中的节点
|
// CurrentStep 目前审批中的节点
|
||||||
type CurrentStep struct {
|
type CurrentStep struct {
|
||||||
CurrentStepId int64 `gorm:"type:bigint;index;not null" json:"current_step_id"`
|
CurrentStepId int64 `gorm:"type:bigint;index;not null" json:"current_step_id"`
|
||||||
|
@ -51,27 +72,68 @@ func NewApprovalInstance(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
instance := &ApprovalInstance{
|
instance := &ApprovalInstance{
|
||||||
FlowID: approvalFlow.ID,
|
FlowID: approvalFlow.ID,
|
||||||
ApplicantKey: data[base.ApplicantKey].(string),
|
ApplicantKey: data[base.ApplicantKey].(string),
|
||||||
CreatorKey: data[base.CreatorKey].(string),
|
CreatorKey: data[base.CreatorKey].(string),
|
||||||
Steps: []*InstanceStep{},
|
Steps: []*InstanceStep{},
|
||||||
DynamicPathConfigs: []*DynamicPathConfig{},
|
Data: string(bytes),
|
||||||
Data: string(bytes),
|
|
||||||
}
|
}
|
||||||
|
// Get the first step of the approval flow
|
||||||
// 从审批模板创建 审批节点
|
firstStep, err := approvalFlow.FirstStep()
|
||||||
for _, step := range approvalFlow.Steps {
|
if err != nil {
|
||||||
approver, err := step.DynamicConfig.GetApprover(ctx, data)
|
return nil, err
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
// Build the steps recursively
|
||||||
}
|
processedSteps := make(map[string]*InstanceStep)
|
||||||
instanceStep := NewInstanceStep(step.ID, step.Name, approver.Key, false)
|
err = buildInstanceSteps(ctx, instance, firstStep, nil, data, processedSteps)
|
||||||
instance.Steps = append(instance.Steps, instanceStep)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance, nil
|
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 发送审批通知给第一个审批人的方法
|
// SendApprovalNotification 发送审批通知给第一个审批人的方法
|
||||||
func (instance *ApprovalInstance) SendApprovalNotification(step *InstanceStep, ctx context.Context) error {
|
func (instance *ApprovalInstance) SendApprovalNotification(step *InstanceStep, ctx context.Context) error {
|
||||||
|
|
||||||
|
@ -105,12 +167,7 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取第一个审批步骤
|
// 获取第一个审批步骤
|
||||||
dataMap, err := instance.DataToMap()
|
firstStep, err := instance.getFirstStep()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
firstStep, err := instance.getFirstStep(dataMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -127,39 +184,13 @@ func (instance *ApprovalInstance) Start(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFirstStep 获取第一个审批步骤
|
// getFirstStep 获取第一个审批步骤
|
||||||
func (instance *ApprovalInstance) getFirstStep(data map[string]interface{}) (*InstanceStep, error) {
|
func (instance *ApprovalInstance) getFirstStep() (*InstanceStep, error) {
|
||||||
// 从模板路径中获取第一个节点
|
|
||||||
firstTemplateStep, err := instance.ApprovalFlow.FirstStep(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error getting first step from template: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找到实例步骤中对应的第一个模板步骤
|
|
||||||
var firstInstanceStep *InstanceStep
|
|
||||||
for _, step := range instance.Steps {
|
for _, step := range instance.Steps {
|
||||||
if step.StepID == firstTemplateStep.ID {
|
if step.StepCode == flow_definition.StepStart {
|
||||||
firstInstanceStep = step
|
return step, nil
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("未找到起点")
|
||||||
if firstInstanceStep == nil {
|
|
||||||
return nil, fmt.Errorf("未找到第一个审批步骤")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查动态路径配置,找到优先级更高的路径
|
|
||||||
for _, dynamicConfig := range instance.DynamicPathConfigs {
|
|
||||||
if dynamicConfig.ToStepID == firstTemplateStep.ID {
|
|
||||||
// 在实例的步骤中找到对应的动态路径起点
|
|
||||||
for _, step := range instance.Steps {
|
|
||||||
if step.StepID == dynamicConfig.FromStepID {
|
|
||||||
firstInstanceStep = step
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return firstInstanceStep, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveToNextStep 移动到下一个步骤
|
// MoveToNextStep 移动到下一个步骤
|
||||||
|
@ -205,41 +236,20 @@ func (instance *ApprovalInstance) MoveToNextStep() error {
|
||||||
|
|
||||||
// getNextStep 获取下一个步骤
|
// getNextStep 获取下一个步骤
|
||||||
func (instance *ApprovalInstance) getNextStep(currentStep *InstanceStep, data map[string]interface{}) ([]*InstanceStep, error) {
|
func (instance *ApprovalInstance) getNextStep(currentStep *InstanceStep, data map[string]interface{}) ([]*InstanceStep, error) {
|
||||||
// 先从动态路径查找下一个步骤
|
pathConfigs := currentStep.InstancePathConfigs
|
||||||
for _, path := range instance.DynamicPathConfigs {
|
var nextSteps []*InstanceStep
|
||||||
if path.FromStepID == currentStep.StepID {
|
for _, pathConfig := range pathConfigs {
|
||||||
stepByID, err := instance.findStepByID(path.ToStepID)
|
met, err := pathConfig.IsConditionMet(data)
|
||||||
if err != nil {
|
if err != nil || !met {
|
||||||
return nil, err
|
continue
|
||||||
}
|
|
||||||
return []*InstanceStep{stepByID}, nil
|
|
||||||
}
|
}
|
||||||
}
|
nextStep, err := instance.GetStepByKey(pathConfig.GetToNodeKey())
|
||||||
|
|
||||||
// 如果动态路径找不到,使用模板路径 , 如果是模板节点,那么必定存在对于的模板路径,如果没有模板路径说明说明审批结束了
|
|
||||||
flowStep, err := instance.ApprovalFlow.GetStep(currentStep.StepID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
nextStepIDs, err := flowStep.GetNextStepIDs(data)
|
|
||||||
if len(nextStepIDs) == 0 {
|
|
||||||
return nil, fmt.Errorf("未找到符合条件的下一个步骤")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(nextStepIDs) == 1 {
|
|
||||||
// 如果是只有一个模板节点,那么说明是单审批节点
|
|
||||||
stepId := nextStepIDs[0]
|
|
||||||
stepByID, err := instance.findStepByKey(stepId)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []*InstanceStep{stepByID}, nil
|
nextSteps = append(nextSteps, nextStep)
|
||||||
}
|
}
|
||||||
|
return nextSteps, nil
|
||||||
if len(nextStepIDs) > 1 {
|
|
||||||
// 说明是并行节点 ,暂不支持
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("未找到符合条件的下一个步骤")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) findStepByID(id int64) (*InstanceStep, error) {
|
func (instance *ApprovalInstance) findStepByID(id int64) (*InstanceStep, error) {
|
||||||
|
@ -353,9 +363,9 @@ func (instance *ApprovalInstance) GetCurrentStepsById(id int64) *InstanceStep {
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeApprovalStep 执行审批步骤
|
// executeApprovalStep 执行审批步骤
|
||||||
func (instance *ApprovalInstance) executeApprovalStep() error {
|
func (instance *ApprovalInstance) executeApprovalStep(approvalFlow flow_definition.ApprovalFlow) error {
|
||||||
for _, instanceStep := range instance.GetCurrentSteps() {
|
for _, instanceStep := range instance.GetCurrentSteps() {
|
||||||
flowStep, err := instance.ApprovalFlow.GetStep(instanceStep.StepID)
|
flowStep, err := approvalFlow.GetStep(instanceStep.StepID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -409,24 +419,7 @@ func (instance *ApprovalInstance) executeApprovalStep() error {
|
||||||
return nil // 如果没有规则满足,正常返回
|
return nil // 如果没有规则满足,正常返回
|
||||||
}
|
}
|
||||||
|
|
||||||
func (instance *ApprovalInstance) AddStepBetween(step, fromStep, toStep *InstanceStep) *DynamicPathConfig {
|
func (instance *ApprovalInstance) GetPathByFromStepKey(fromStepKey string) (*InstancePathConfig, error) {
|
||||||
// 获取 pathConfig
|
|
||||||
if fromStep.IsDynamic {
|
|
||||||
for _, pathConfig := range instance.DynamicPathConfigs {
|
|
||||||
if pathConfig.FromStepKey == fromStep.Key {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
steps := instance.ApprovalFlow.Steps
|
|
||||||
for _, flowStep := range steps {
|
|
||||||
if flowStep.ID == fromStep.StepID {
|
|
||||||
flowStep.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (instance *ApprovalInstance) GetPathByFromStepKey(fromStepKey string) (*DynamicPathConfig, error) {
|
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
import "approveflow/app/base"
|
|
||||||
|
|
||||||
// DynamicPathConfig 动态路径配置表结构
|
|
||||||
type DynamicPathConfig struct {
|
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
|
||||||
InstanceID int64 `gorm:"type:bigint;index;not null" json:"instance_id"` // 关联的审批实例ID
|
|
||||||
FromStepID int64 `gorm:"type:bigint;not null" json:"from_step_id"` // 来源步骤ID
|
|
||||||
FromStepKey string `gorm:"type:varchar(50);not null" json:"from_step_key"` // 来源步骤ID
|
|
||||||
ToStepKey string `gorm:"type:varchar(50);not null" json:"to_step_key"` // 目标步骤ID
|
|
||||||
IsParallel bool `gorm:"not null;default:false" json:"is_parallel"` // 是否并行
|
|
||||||
Priority int `gorm:"not null;default:0" json:"priority"` // 路径优先级
|
|
||||||
base.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDynamicPathConfig 创建动态路径
|
|
||||||
func NewDynamicPathConfig(instanceID, fromStepID int64, FromStepKey, ToStepKey string, isParallel bool) *DynamicPathConfig {
|
|
||||||
pathConfig := &DynamicPathConfig{
|
|
||||||
InstanceID: instanceID,
|
|
||||||
FromStepID: fromStepID,
|
|
||||||
FromStepKey: FromStepKey,
|
|
||||||
ToStepKey: ToStepKey,
|
|
||||||
IsParallel: isParallel,
|
|
||||||
Priority: 0,
|
|
||||||
}
|
|
||||||
return pathConfig
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"approveflow/app/base"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
StepStatusPending = "Pending" // 待审批
|
|
||||||
StepStatusApproved = "Approved" // 已批准
|
|
||||||
StepStatusRejected = "Rejected" // 已驳回
|
|
||||||
StepStatusReversed = "Reversed" // 已反转
|
|
||||||
StepStatusCompleted = "Completed" // 步骤已完成
|
|
||||||
)
|
|
||||||
|
|
||||||
// InstanceStep 审批步骤实例表
|
|
||||||
type InstanceStep struct {
|
|
||||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
|
||||||
InstanceID int64 `gorm:"index;not null" json:"instance_id"` // 所属审批实例ID
|
|
||||||
StepID int64 `gorm:"type:bigint;not null" json:"step_id"` // 关联的流程步骤ID
|
|
||||||
StepName string `gorm:"type:varchar(50);not null" json:"step_name"`
|
|
||||||
ApproverKey string `gorm:"type:varchar(50);not null" json:"approver_id"` // 审批人ID
|
|
||||||
Status string `gorm:"type:varchar(50);not null" json:"status"` // 审批状态
|
|
||||||
ApproverComments string `gorm:"type:text" json:"approver_comments"` // 审批意见
|
|
||||||
IsDynamic bool `gorm:"not null;default:false" json:"is_dynamic"` // 是否为动态步骤
|
|
||||||
Records []*ApprovalRecord `gorm:"foreignKey:InstanceStepID;constraint:OnDelete:CASCADE" json:"records"` // 审批记录
|
|
||||||
base.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInstanceStep(stepID int64, stepName, approverKey string, isDynamic bool) *InstanceStep {
|
|
||||||
instanceStep := &InstanceStep{
|
|
||||||
StepID: stepID,
|
|
||||||
StepName: stepName,
|
|
||||||
ApproverKey: approverKey,
|
|
||||||
Status: StepStatusPending,
|
|
||||||
IsDynamic: isDynamic,
|
|
||||||
}
|
|
||||||
return instanceStep
|
|
||||||
}
|
|
||||||
|
|
||||||
// Approve 审批通过
|
|
||||||
func (step *InstanceStep) Approve(comments string) error {
|
|
||||||
if step.Status != StepStatusPending {
|
|
||||||
return fmt.Errorf("当前步骤不是待审批状态")
|
|
||||||
}
|
|
||||||
step.Status = StepStatusApproved
|
|
||||||
step.ApproverComments = comments
|
|
||||||
step.addApprovalRecord(StepStatusApproved, comments)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reject 审批驳回
|
|
||||||
func (step *InstanceStep) Reject(comments string) error {
|
|
||||||
if step.Status != StepStatusPending {
|
|
||||||
return fmt.Errorf("当前步骤不是待审批状态")
|
|
||||||
}
|
|
||||||
step.Status = StepStatusRejected
|
|
||||||
step.ApproverComments = comments
|
|
||||||
step.addApprovalRecord(StepStatusRejected, comments)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// addApprovalRecord 添加审批记录
|
|
||||||
func (step *InstanceStep) addApprovalRecord(status string, comments string) {
|
|
||||||
record := &ApprovalRecord{
|
|
||||||
InstanceStepID: step.ID,
|
|
||||||
ApproverKey: step.ApproverKey,
|
|
||||||
Status: status,
|
|
||||||
Comments: comments,
|
|
||||||
}
|
|
||||||
step.Records = append(step.Records, record)
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/base"
|
||||||
|
"approveflow/app/provider/flow_definition"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InstancePathConfig 动态路径配置表结构
|
||||||
|
type InstancePathConfig struct {
|
||||||
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
|
NodeID int64 `gorm:"type:bigint;index;not null" json:"node_id"`
|
||||||
|
FromNodeKey string `gorm:"type:varchar(50);index;not null" json:"from_node_key"`
|
||||||
|
ToNodeKey string ` gorm:"type:varchar(50);index;not null" json:"to_node_key"`
|
||||||
|
IsParallel bool `gorm:"not null;default:false" json:"is_parallel"` // 是否并行
|
||||||
|
IsDynamic bool `gorm:"not null;default:false" json:"is_dynamic"` // 是否为动态步骤
|
||||||
|
Priority int `gorm:"not null;default:0" json:"priority"` // 路径优先级
|
||||||
|
flow_definition.ApprovalConditionCommon
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d InstancePathConfig) GetKey() string {
|
||||||
|
return d.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d InstancePathConfig) GetNodeID() int64 {
|
||||||
|
return d.NodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d InstancePathConfig) GetFromNodeKey() string {
|
||||||
|
return d.FromNodeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d InstancePathConfig) GetToNodeKey() string {
|
||||||
|
return d.ToNodeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDynamicPathConfig 创建动态路径
|
||||||
|
func NewDynamicPathConfig(instanceID, nodeId int64, FromStepKey, ToStepKey string, isParallel bool) *InstancePathConfig {
|
||||||
|
pathConfig := &InstancePathConfig{
|
||||||
|
NodeID: nodeId,
|
||||||
|
FromNodeKey: FromStepKey,
|
||||||
|
ToNodeKey: ToStepKey,
|
||||||
|
IsParallel: isParallel,
|
||||||
|
Priority: 0,
|
||||||
|
}
|
||||||
|
return pathConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsConditionMet 判断路径条件是否满足
|
||||||
|
func (a *InstancePathConfig) IsConditionMet(data map[string]interface{}) (bool, error) {
|
||||||
|
if a.ConditionExpression == "" {
|
||||||
|
return true, nil // 无条件,默认满足
|
||||||
|
}
|
||||||
|
result, err := a.EvaluateCondition(data)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"approveflow/app/base"
|
||||||
|
"approveflow/app/provider/abstract/connect"
|
||||||
|
"approveflow/app/provider/flow_definition"
|
||||||
|
"approveflow/app/utils"
|
||||||
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StepStatusPending = "Pending" // 待审批
|
||||||
|
StepStatusApproved = "Approved" // 已批准
|
||||||
|
StepStatusRejected = "Rejected" // 已驳回
|
||||||
|
StepStatusReversed = "Reversed" // 已反转
|
||||||
|
StepStatusCompleted = "Completed" // 步骤已完成
|
||||||
|
)
|
||||||
|
|
||||||
|
// InstanceStep 审批步骤实例表
|
||||||
|
type InstanceStep struct {
|
||||||
|
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` // 主键ID
|
||||||
|
InstanceID int64 `gorm:"index;not null" json:"instance_id"` // 所属审批实例ID
|
||||||
|
StepID int64 `gorm:"type:bigint;not null" json:"step_id"` // 关联的流程步骤ID
|
||||||
|
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"` // 审批状态
|
||||||
|
ApproverComments string `gorm:"type:text" json:"approver_comments"` // 审批意见
|
||||||
|
IsDynamic bool `gorm:"not null;default:false" json:"is_dynamic"` // 是否为动态步骤
|
||||||
|
InstancePathConfigs []*InstancePathConfig `gorm:"foreignKey:NodeID;constraint:OnDelete:CASCADE" json:"instance_path_configs"` // 动态路径配置,自定义,不直接存储
|
||||||
|
Records []*ApprovalRecord `gorm:"foreignKey:InstanceStepID;constraint:OnDelete:CASCADE" json:"records"` // 审批记录
|
||||||
|
base.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) GetPathConfigs() []connect.AbstractNodePathConfig {
|
||||||
|
return utils.ConvertToAbstractNodes(step.InstancePathConfigs, func(t *InstancePathConfig) connect.AbstractNodePathConfig {
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) SetPathConfigs(configs []connect.AbstractNodePathConfig) {
|
||||||
|
convertedConfigs, err := utils.ConvertToSpecificType(configs, func(item connect.AbstractNodePathConfig) (*InstancePathConfig, bool) {
|
||||||
|
specificConfig, ok := item.(*InstancePathConfig)
|
||||||
|
return specificConfig, ok
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Error in SetPathConfigs: %v", err))
|
||||||
|
}
|
||||||
|
step.InstancePathConfigs = convertedConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (step *InstanceStep) GetKey() string {
|
||||||
|
return step.Key
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInstanceStep(flowStep *flow_definition.ApprovalStep, approverKey string, isDynamic bool) *InstanceStep {
|
||||||
|
instanceStep := &InstanceStep{
|
||||||
|
StepID: flowStep.ID,
|
||||||
|
StepName: flowStep.Name,
|
||||||
|
StepCode: flowStep.StepCode,
|
||||||
|
ApproverKey: approverKey,
|
||||||
|
Status: StepStatusPending,
|
||||||
|
IsDynamic: isDynamic,
|
||||||
|
}
|
||||||
|
instanceStep.Key = uuid.New().String()
|
||||||
|
return instanceStep
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approve 审批通过
|
||||||
|
func (step *InstanceStep) Approve(comments string) error {
|
||||||
|
if step.Status != StepStatusPending {
|
||||||
|
return fmt.Errorf("当前步骤不是待审批状态")
|
||||||
|
}
|
||||||
|
step.Status = StepStatusApproved
|
||||||
|
step.ApproverComments = comments
|
||||||
|
step.addApprovalRecord(StepStatusApproved, comments)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject 审批驳回
|
||||||
|
func (step *InstanceStep) Reject(comments string) error {
|
||||||
|
if step.Status != StepStatusPending {
|
||||||
|
return fmt.Errorf("当前步骤不是待审批状态")
|
||||||
|
}
|
||||||
|
step.Status = StepStatusRejected
|
||||||
|
step.ApproverComments = comments
|
||||||
|
step.addApprovalRecord(StepStatusRejected, comments)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addApprovalRecord 添加审批记录
|
||||||
|
func (step *InstanceStep) addApprovalRecord(status string, comments string) {
|
||||||
|
record := &ApprovalRecord{
|
||||||
|
InstanceStepID: step.ID,
|
||||||
|
ApproverKey: step.ApproverKey,
|
||||||
|
Status: status,
|
||||||
|
Comments: comments,
|
||||||
|
}
|
||||||
|
step.Records = append(step.Records, record)
|
||||||
|
}
|
|
@ -82,9 +82,10 @@ func (f *FlowInstanceService) AddCustomStep(ctx context.Context, instanceID int6
|
||||||
}
|
}
|
||||||
// 如果是 自定义阶段 那么它的路径配置能够实例对象中找到
|
// 如果是 自定义阶段 那么它的路径配置能够实例对象中找到
|
||||||
if fromStep.IsDynamic {
|
if fromStep.IsDynamic {
|
||||||
instance.DynamicPathConfigs
|
//instance.InstancePathConfigs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,31 @@ package utils
|
||||||
import (
|
import (
|
||||||
"approveflow/app/http/base"
|
"approveflow/app/http/base"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/Superdanda/hade/framework/gin"
|
"github.com/Superdanda/hade/framework/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ConvertToSpecificType[T any, I interface{}](items []I, convertFunc func(I) (T, bool)) ([]T, error) {
|
||||||
|
specificItems := make([]T, 0, len(items))
|
||||||
|
for i, item := range items {
|
||||||
|
if specificItem, ok := convertFunc(item); ok {
|
||||||
|
specificItems = append(specificItems, specificItem)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("invalid type at index %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return specificItems, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertToAbstractNodes[T any, I interface{}](items []T, toInterface func(T) I) []I {
|
||||||
|
nodes := make([]I, len(items))
|
||||||
|
for i, item := range items {
|
||||||
|
nodes[i] = toInterface(item)
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
||||||
|
|
||||||
func QuickBind[T any](c *gin.Context) *T {
|
func QuickBind[T any](c *gin.Context) *T {
|
||||||
var params T
|
var params T
|
||||||
if err := c.ShouldBindJSON(¶ms); err != nil {
|
if err := c.ShouldBindJSON(¶ms); err != nil {
|
||||||
|
|
Loading…
Reference in New Issue