diff --git a/backend/middlewares/flow/src/api/cc/flow_cc_model_api.rs b/backend/middlewares/flow/src/api/cc/flow_cc_model_api.rs index 15d3dfd3..69dd02e5 100644 --- a/backend/middlewares/flow/src/api/cc/flow_cc_model_api.rs +++ b/backend/middlewares/flow/src/api/cc/flow_cc_model_api.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use bios_basic::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumRelFilterReq}; use bios_basic::rbum::serv::rbum_item_serv::RbumItemCrudOperation; use bios_basic::rbum::serv::rbum_rel_serv::RbumRelServ; +use itertools::Itertools; use tardis::basic::dto::TardisContext; use tardis::web::context_extractor::TardisContextExtractor; use tardis::web::poem::Request; @@ -11,7 +12,13 @@ use tardis::web::poem_openapi::param::{Path, Query}; use tardis::web::poem_openapi::payload::Json; use tardis::web::web_resp::{TardisApiResult, TardisPage, TardisResp, Void}; -use crate::dto::flow_model_dto::{FlowModelAddReq, FlowModelAggResp, FlowModelFilterReq, FlowModelFindRelStateResp, FlowModelModifyReq, FlowModelSummaryResp}; +use crate::dto::flow_model_dto::{ + FlowModelAddReq, FlowModelAggResp, FlowModelBindStateReq, FlowModelFilterReq, FlowModelFindRelStateResp, FlowModelModifyReq, FlowModelSortStatesReq, FlowModelSummaryResp, + FlowModelUnbindStateReq, +}; +use crate::dto::flow_model_version_dto::{FlowModelVersionBindState, FlowModelVersionModifyReq, FlowModelVersionModifyState}; +use crate::dto::flow_state_dto::FlowStateRelModelModifyReq; +use crate::dto::flow_transition_dto::FlowTransitionSortStatesReq; use crate::flow_constants; use crate::serv::flow_model_serv::FlowModelServ; use crate::serv::flow_rel_serv::{FlowRelKind, FlowRelServ}; @@ -203,116 +210,116 @@ impl FlowCcModelApi { /// Bind State By Model Id [Deprecated] /// /// 绑定状态 [已废弃] - // #[oai(path = "/:flow_model_id/bind_state", method = "post")] - // async fn bind_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { - // let mut funs = flow_constants::get_tardis_inst(); - // funs.begin().await?; - // FlowModelServ::modify_model( - // &flow_model_id.0, - // &mut FlowModelModifyReq { - // bind_states: Some(vec![req.0]), - // ..Default::default() - // }, - // &funs, - // &ctx.0, - // ) - // .await?; - // funs.commit().await?; - // ctx.0.execute_task().await?; - // TardisResp::ok(Void {}) - // } + #[oai(path = "/:flow_model_id/bind_state", method = "post")] + async fn bind_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { + let mut funs = flow_constants::get_tardis_inst(); + funs.begin().await?; + FlowModelServ::modify_model( + &flow_model_id.0, + &mut FlowModelModifyReq { + modify_version: Some(FlowModelVersionModifyReq { + bind_states: Some(vec![FlowModelVersionBindState { + exist_state: Some(req.0), + ..Default::default() + }]), + ..Default::default() + }), + ..Default::default() + }, + &funs, + &ctx.0, + ) + .await?; + funs.commit().await?; + ctx.0.execute_task().await?; + TardisResp::ok(Void {}) + } /// Unbind State By Model Id [Deprecated] /// /// 解绑状态 [已废弃] - // #[oai(path = "/:flow_model_id/unbind_state", method = "post")] - // async fn unbind_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { - // let mut funs = flow_constants::get_tardis_inst(); - // funs.begin().await?; - // FlowModelServ::modify_model( - // &flow_model_id.0, - // &mut FlowModelModifyReq { - // unbind_states: Some(vec![req.state_id.clone()]), - // ..Default::default() - // }, - // &funs, - // &ctx.0, - // ) - // .await?; - // funs.commit().await?; - // ctx.0.execute_task().await?; - // TardisResp::ok(Void {}) - // } + #[oai(path = "/:flow_model_id/unbind_state", method = "post")] + async fn unbind_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { + let mut funs = flow_constants::get_tardis_inst(); + funs.begin().await?; + FlowModelServ::modify_model( + &flow_model_id.0, + &mut FlowModelModifyReq { + modify_version: Some(FlowModelVersionModifyReq { + unbind_states: Some(vec![req.state_id.clone()]), + ..Default::default() + }), + ..Default::default() + }, + &funs, + &ctx.0, + ) + .await?; + funs.commit().await?; + ctx.0.execute_task().await?; + TardisResp::ok(Void {}) + } /// Resort states [Deprecated] /// /// 状态重新排序 [已废弃] - // #[oai(path = "/:flow_model_id/resort_state", method = "post")] - // async fn resort_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { - // let mut funs = flow_constants::get_tardis_inst(); - // funs.begin().await?; - // FlowModelServ::modify_model( - // &flow_model_id.0, - // &mut FlowModelModifyReq { - // modify_states: Some( - // req.0 - // .sort_states - // .into_iter() - // .map(|state| FlowStateRelModelModifyReq { - // id: state.state_id, - // sort: Some(state.sort), - // show_btns: None, - // }) - // .collect_vec(), - // ), - // ..Default::default() - // }, - // &funs, - // &ctx.0, - // ) - // .await?; - // funs.commit().await?; - // ctx.0.execute_task().await?; - // TardisResp::ok(Void {}) - // } + #[oai(path = "/:flow_model_id/resort_state", method = "post")] + async fn resort_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { + let mut funs = flow_constants::get_tardis_inst(); + funs.begin().await?; + FlowModelServ::modify_model( + &flow_model_id.0, + &mut FlowModelModifyReq { + modify_version: Some(FlowModelVersionModifyReq { + modify_states: Some( + req.0 + .sort_states + .into_iter() + .map(|state| FlowModelVersionModifyState { + id: state.state_id.clone(), + modify_state: Some(FlowStateRelModelModifyReq { + id: state.state_id, + sort: Some(state.sort), + show_btns: None, + }), + add_transitions: None, + modify_transitions: None, + delete_transitions: None, + }) + .collect_vec(), + ), + ..Default::default() + }), + ..Default::default() + }, + &funs, + &ctx.0, + ) + .await?; + funs.commit().await?; + ctx.0.execute_task().await?; + TardisResp::ok(Void {}) + } /// Resort transitions [Deprecated] /// /// 动作重新排序 [已废弃] - // #[oai(path = "/:flow_model_id/resort_transition", method = "post")] - // async fn resort_transition( - // &self, - // flow_model_id: Path, - // req: Json, - // ctx: TardisContextExtractor, - // _request: &Request, - // ) -> TardisApiResult { - // let mut funs = flow_constants::get_tardis_inst(); - // funs.begin().await?; - // let modify_trans = req - // .0 - // .sort_states - // .into_iter() - // .map(|sort_req| FlowTransitionModifyReq { - // id: sort_req.id.clone().into(), - // sort: Some(sort_req.sort), - // ..Default::default() - // }) - // .collect_vec(); - // FlowModelServ::modify_model( - // &flow_model_id.0, - // &mut FlowModelModifyReq { - // modify_transitions: Some(modify_trans), - // ..Default::default() - // }, - // &funs, - // &ctx.0, - // ) - // .await?; - // funs.commit().await?; - // ctx.0.execute_task().await?; - // TardisResp::ok(Void {}) - // } + #[oai(path = "/:flow_model_id/resort_transition", method = "post")] + async fn resort_transition( + &self, + flow_model_id: Path, + req: Json, + ctx: TardisContextExtractor, + _request: &Request, + ) -> TardisApiResult { + let mut funs = flow_constants::get_tardis_inst(); + funs.begin().await?; + funs.begin().await?; + FlowModelServ::resort_transition(&flow_model_id.0, &req.0, &funs, &ctx.0).await?; + funs.commit().await?; + ctx.0.execute_task().await?; + TardisResp::ok(Void {}) + } /// find rel states by model_id /// @@ -334,24 +341,33 @@ impl FlowCcModelApi { /// modify related state [Deprecated] /// /// 编辑关联的状态 [已废弃] - // #[oai(path = "/:flow_model_id/modify_rel_state", method = "patch")] - // async fn modify_rel_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { - // let mut funs = flow_constants::get_tardis_inst(); - // funs.begin().await?; - // FlowModelServ::modify_model( - // &flow_model_id.0, - // &mut FlowModelModifyReq { - // modify_states: Some(vec![req.0]), - // ..Default::default() - // }, - // &funs, - // &ctx.0, - // ) - // .await?; - // funs.commit().await?; - // ctx.0.execute_task().await?; - // TardisResp::ok(Void {}) - // } + #[oai(path = "/:flow_model_id/modify_rel_state", method = "patch")] + async fn modify_rel_state(&self, flow_model_id: Path, req: Json, ctx: TardisContextExtractor, _request: &Request) -> TardisApiResult { + let mut funs = flow_constants::get_tardis_inst(); + funs.begin().await?; + FlowModelServ::modify_model( + &flow_model_id.0, + &mut FlowModelModifyReq { + modify_version: Some(FlowModelVersionModifyReq { + modify_states: Some(vec![FlowModelVersionModifyState { + id: req.0.id.clone(), + modify_state: Some(req.0), + add_transitions: None, + modify_transitions: None, + delete_transitions: None, + }]), + ..Default::default() + }), + ..Default::default() + }, + &funs, + &ctx.0, + ) + .await?; + funs.commit().await?; + ctx.0.execute_task().await?; + TardisResp::ok(Void {}) + } /// batch add rels with template and app /// diff --git a/backend/middlewares/flow/src/api/cc/flow_cc_model_version_api.rs b/backend/middlewares/flow/src/api/cc/flow_cc_model_version_api.rs new file mode 100644 index 00000000..e69de29b diff --git a/backend/middlewares/flow/src/api/ci/flow_ci_inst_api.rs b/backend/middlewares/flow/src/api/ci/flow_ci_inst_api.rs index ae51cf91..ff86bbd3 100644 --- a/backend/middlewares/flow/src/api/ci/flow_ci_inst_api.rs +++ b/backend/middlewares/flow/src/api/ci/flow_ci_inst_api.rs @@ -220,6 +220,7 @@ impl FlowCiInstApi { rel_business_obj_id: add_req.0.rel_business_obj_id.clone(), tag: add_req.0.tag.clone(), create_vars: add_req.0.create_vars.clone(), + transition_id: None, }, add_req.0.current_state_name.clone(), &funs, diff --git a/backend/middlewares/flow/src/domain/flow_model.rs b/backend/middlewares/flow/src/domain/flow_model.rs index cf560c24..ff5805c5 100644 --- a/backend/middlewares/flow/src/domain/flow_model.rs +++ b/backend/middlewares/flow/src/domain/flow_model.rs @@ -3,7 +3,7 @@ use tardis::db::sea_orm::prelude::Json; use tardis::db::sea_orm::*; use tardis::{TardisCreateEntity, TardisEmptyBehavior, TardisEmptyRelation}; -use crate::dto::flow_model_dto::FlowModelKind; +use crate::dto::flow_model_dto::{FlowModelKind, FlowModelStatus}; /// Model / 模型 /// @@ -28,6 +28,11 @@ pub struct Model { #[tardis_entity(custom_type = "String")] pub kind: FlowModelKind, + /// Status of workflow models / 工作流模型状态 + /// 启用/停用 + #[tardis_entity(custom_type = "String")] + pub status: FlowModelStatus, + /// Associated template / 关联模板 /// /// his function is used to associate this template with other templates, e.g. if the template refers to a template, then this association corresponds to the Id of the template diff --git a/backend/middlewares/flow/src/dto/flow_inst_dto.rs b/backend/middlewares/flow/src/dto/flow_inst_dto.rs index 631b27f7..f646e33b 100644 --- a/backend/middlewares/flow/src/dto/flow_inst_dto.rs +++ b/backend/middlewares/flow/src/dto/flow_inst_dto.rs @@ -22,6 +22,8 @@ pub struct FlowInstStartReq { pub tag: String, /// 创建时的参数列表 pub create_vars: Option>, + /// 触发的动作ID + pub transition_id: Option, } #[derive(Serialize, Deserialize, Debug, poem_openapi::Object)] @@ -39,6 +41,8 @@ pub struct FlowInstBatchBindReq { pub tag: String, /// 关联业务ID pub rel_business_objs: Vec, + /// 触发的动作ID + pub transition_id: Option, } #[derive(Serialize, Deserialize, Debug, poem_openapi::Object)] diff --git a/backend/middlewares/flow/src/dto/flow_model_dto.rs b/backend/middlewares/flow/src/dto/flow_model_dto.rs index 4e672d78..c0df240f 100644 --- a/backend/middlewares/flow/src/dto/flow_model_dto.rs +++ b/backend/middlewares/flow/src/dto/flow_model_dto.rs @@ -32,6 +32,8 @@ pub struct FlowModelAddReq { pub info: Option, /// 工作流模型类型 pub kind: FlowModelKind, + /// 工作流模型状态 + pub status: FlowModelStatus, /// 关联模板ID(目前可能是页面模板ID,或者是项目模板ID) pub rel_template_ids: Option>, /// 关联动作ID(触发当前工作流的动作,若为空则默认表示新建数据时触发) @@ -76,6 +78,7 @@ impl From for FlowModelAddReq { icon: Some(value.icon.clone()), info: Some(value.info.clone()), kind: value.kind, + status: value.status, rel_transition_ids: None, rel_template_ids: Some(value.rel_template_ids.clone()), add_version: Some(FlowModelVersionAddReq { @@ -108,6 +111,16 @@ pub enum FlowModelKind { AsTemplateAndAsModel, } +/// 工作流模型状态 +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, poem_openapi::Enum, EnumIter, sea_orm::DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "String(StringLen::N(255))")] +pub enum FlowModelStatus { + #[sea_orm(string_value = "enabled")] + Enabled, + #[sea_orm(string_value = "disabled")] + Disabled, +} + /// 修改请求 #[derive(Serialize, Deserialize, Debug, Default, poem_openapi::Object, Clone)] pub struct FlowModelModifyReq { @@ -119,6 +132,8 @@ pub struct FlowModelModifyReq { pub info: Option, /// 是否作为模板使用 pub template: Option, + /// 状态 + pub status: Option, /// 当前版本ID pub current_version_id: Option, /// 修改版本 @@ -151,6 +166,14 @@ pub struct FlowModelSummaryResp { pub tag: String, pub disabled: bool, + /// 关联动作 + pub rel_transition: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone, poem_openapi::Object, sea_orm::FromQueryResult)] +pub struct FlowModelRelTransition { + pub id: String, + pub name: String, } /// 工作流模型详细信息 @@ -161,6 +184,7 @@ pub struct FlowModelDetailResp { pub icon: String, pub info: String, pub kind: FlowModelKind, + pub status: FlowModelStatus, /// 是否作为模板使用 pub template: bool, @@ -184,6 +208,8 @@ pub struct FlowModelDetailResp { pub scope_level: RbumScopeLevelKind, pub disabled: bool, + /// 关联动作 + pub rel_transition: Option, } impl FlowModelDetailResp { @@ -200,6 +226,10 @@ impl FlowModelDetailResp { None => vec![], } } + + pub fn rel_transition(&self) -> Option { + self.rel_transition.clone().map(|rel_transition| TardisFuns::json.json_to_obj(rel_transition.clone()).unwrap()) + } } /// 工作流模型过滤器 @@ -212,6 +242,7 @@ pub struct FlowModelFilterReq { pub tags: Option>, pub kinds: Option>, + pub status: Option, /// 是否作为模板使用 pub template: Option, pub own_paths: Option>, diff --git a/backend/middlewares/flow/src/dto/flow_model_version_dto.rs b/backend/middlewares/flow/src/dto/flow_model_version_dto.rs index e8be141c..2a99793f 100644 --- a/backend/middlewares/flow/src/dto/flow_model_version_dto.rs +++ b/backend/middlewares/flow/src/dto/flow_model_version_dto.rs @@ -14,7 +14,7 @@ use tardis::{ use super::{ flow_model_dto::FlowModelBindStateReq, - flow_state_dto::{FlowStateAddReq, FlowStateAggResp}, + flow_state_dto::{FlowStateAddReq, FlowStateAggResp, FlowStateRelModelModifyReq}, flow_transition_dto::{FlowTransitionAddReq, FlowTransitionModifyReq}, }; @@ -67,13 +67,32 @@ pub struct FlowModelVersionBindState { pub is_init: bool, } -/// 添加请求 +/// 模型绑定状态节点 +#[derive(Clone, Serialize, Deserialize, Debug, Default, poem_openapi::Object)] +pub struct FlowModelVersionModifyState { + /// 若存在则表示,绑定已有状态节点 + pub id: String, + /// 若存在则表示,新建状态节点 + pub modify_state: Option, + /// 添加动作 + pub add_transitions: Option>, + /// 修改动作 + pub modify_transitions: Option>, + /// 删除动作 + pub delete_transitions: Option>, +} + +/// 修改请求 #[derive(Clone, Serialize, Deserialize, Debug, Default, poem_openapi::Object)] pub struct FlowModelVersionModifyReq { #[oai(validator(min_length = "2", max_length = "200"))] pub name: Option, - // 状态信息 + // 绑定状态 pub bind_states: Option>, + // 修改状态 + pub modify_states: Option>, + // 解绑状态 + pub unbind_states: Option>, /// 定义每个模块的初始状态 pub init_state_id: Option, /// 版本状态 diff --git a/backend/middlewares/flow/src/dto/flow_state_dto.rs b/backend/middlewares/flow/src/dto/flow_state_dto.rs index ff7bd6df..f418e725 100644 --- a/backend/middlewares/flow/src/dto/flow_state_dto.rs +++ b/backend/middlewares/flow/src/dto/flow_state_dto.rs @@ -1,6 +1,9 @@ -use bios_basic::rbum::{ - dto::rbum_filer_dto::{RbumBasicFilterReq, RbumItemFilterFetcher, RbumItemRelFilterReq}, - rbum_enumeration::RbumScopeLevelKind, +use bios_basic::{ + dto::BasicQueryCondInfo, + rbum::{ + dto::rbum_filer_dto::{RbumBasicFilterReq, RbumItemFilterFetcher, RbumItemRelFilterReq}, + rbum_enumeration::RbumScopeLevelKind, + }, }; use serde::{Deserialize, Serialize}; use tardis::{ @@ -9,6 +12,7 @@ use tardis::{ db::sea_orm::{self, prelude::*, EnumIter}, serde_json::Value, web::poem_openapi, + TardisFuns, }; use super::flow_transition_dto::FlowTransitionDetailResp; @@ -26,7 +30,7 @@ pub struct FlowStateAddReq { #[oai(validator(min_length = "2", max_length = "2000"))] pub info: Option, pub state_kind: Option, - pub kind_conf: Option, + pub kind_conf: Option, pub template: Option, #[oai(validator(min_length = "2", max_length = "255"))] @@ -39,6 +43,125 @@ pub struct FlowStateAddReq { pub disabled: Option, } +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FLowStateKindConf { + pub form: Option, + pub approval: Option, + pub branch: Option, +} + +/// 录入节点配置信息 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowStateForm { + pub nodify: Option, + /// 权限配置:为true时,创建人可以操作 + pub guard_by_creator: bool, + /// 权限配置:为true时,历史操作人可以操作 + pub guard_by_his_operators: bool, + /// 权限配置:为true时,负责人可以操作 + pub guard_by_assigned: bool, + /// 权限配置:自定义配置 + pub guard_custom_conf: Option, + /// 当操作人为空时的自动处理策略 + pub auto_transfer_when_empty_kind: Option, + /// 当操作人为空且策略选择为指定代理,则当前配置人员权限生效 + pub auto_transfer_when_empty_guard_custom_conf: Option, + /// 当操作人为空且策略选择为流转节点,则当前配置节点ID生效 + pub auto_transfer_when_empty_state_id: Option, + /// 是否允许转办 + pub referral: bool, + /// 转办自定义人员权限 + pub referral_guard_custom_conf: Option, + /// 字段配置 + pub vars_collect: FlowStateVarsCollect, +} + +/// 审批节点配置信息 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowStateApproval { + /// 通知 + pub nodify: Option, + /// 结果通知 + pub response_nodify: Option, + /// 权限配置:为true时,创建人可以操作 + pub guard_by_creator: bool, + /// 权限配置:为true时,历史操作人可以操作 + pub guard_by_his_operators: bool, + /// 权限配置:为true时,负责人可以操作 + pub guard_by_assigned: bool, + /// 当操作人为空时的自动处理策略 + pub auto_transfer_when_empty_kind: Option, + /// 当操作人为空且策略选择为指定代理,则当前配置人员权限生效 + pub auto_transfer_when_empty_guard_custom_conf: Option, + /// 当操作人为空且策略选择为流转节点,则当前配置节点ID生效 + pub auto_transfer_when_empty_state_id: Option, + /// 是否允许撤销 + pub revoke: bool, + /// 是否允许转办 + pub referral: bool, + /// 转办自定义人员权限 + pub referral_guard_custom_conf: Option, + /// 权限配置:自定义配置 + pub guard_custom_conf: Option, + /// 字段配置 + pub vars_collect: FlowStateVarsCollect, +} + +/// 分支节点配置信息 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowStateBranch { + /// 分支条件,三维数组表示。第一维表示不同分支,第二维表示分支中的或条件集合,第三维表示分支中的且条件集合 + pub conditions: Vec>>, +} + +/// 状态节点字段配置 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowStateVarsCollect { + pub show: Vec, + pub edit: Vec, + pub required: Vec, +} + +/// 状态自动处理的策略类型 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Enum, Default, EnumIter, sea_orm::DeriveActiveEnum, Clone)] +#[sea_orm(rs_type = "String", db_type = "String(StringLen::N(255))")] +pub enum FlowStatusAutoStrategyKind { + /// 自动跳过 + #[default] + #[sea_orm(string_value = "autoskip")] + Autoskip, + /// 指定代理 + #[sea_orm(string_value = "specify_agent")] + SpecifyAgent, + /// 流转节点 + #[sea_orm(string_value = "transfer_state")] + TransferState, +} + +/// 人员权限配置 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowGuardConf { + /// 权限配置:为true时,指定操作人可以操作 + pub guard_by_spec_account_ids: Vec, + /// 权限配置:为true时,指定角色可以操作 + pub guard_by_spec_role_ids: Vec, + /// 权限配置:为true时,指定组织可以操作 + pub guard_by_spec_org_ids: Vec, +} + +// 节点通知配置 +#[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default, Clone)] +pub struct FlowNodifyConf { + /// 权限配置:指定操作人可以操作 + pub guard_by_owner: bool, + /// 权限配置:自定义配置 + pub guard_custom_conf: Option, + /// 通知方式:短信通知 + pub send_sms: bool, + /// 通知方式:邮箱通知 + pub send_mail: bool, +} + #[derive(Serialize, Deserialize, Debug, poem_openapi::Object, Default)] pub struct FlowStateModifyReq { #[oai(validator(min_length = "2", max_length = "200"))] @@ -50,7 +173,7 @@ pub struct FlowStateModifyReq { #[oai(validator(min_length = "2", max_length = "2000"))] pub info: Option, pub state_kind: Option, - pub kind_conf: Option, + pub kind_conf: Option, pub template: Option, #[oai(validator(min_length = "2", max_length = "255"))] @@ -72,9 +195,6 @@ pub struct FlowStateSummaryResp { pub sys_state: FlowSysStateKind, pub info: String, - pub state_kind: FlowStateKind, - pub kind_conf: Value, - pub template: bool, pub rel_state_id: String, @@ -113,6 +233,12 @@ pub struct FlowStateDetailResp { pub disabled: bool, } +impl FlowStateDetailResp { + pub fn kind_conf(&self) -> FLowStateKindConf { + TardisFuns::json.json_to_obj(self.kind_conf.clone()).unwrap() + } +} + /// Type of state /// /// 状态类型 @@ -132,8 +258,10 @@ pub enum FlowSysStateKind { #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, poem_openapi::Enum, EnumIter, sea_orm::DeriveActiveEnum)] #[sea_orm(rs_type = "String", db_type = "String(StringLen::N(255))")] pub enum FlowStateKind { + /// 普通节点 #[sea_orm(string_value = "simple")] Simple, + /// 录入节点 #[sea_orm(string_value = "form")] Form, #[sea_orm(string_value = "mail")] @@ -144,6 +272,18 @@ pub enum FlowStateKind { Timer, #[sea_orm(string_value = "script")] Script, + /// 审批节点 + #[sea_orm(string_value = "approval")] + Approval, + /// 分支节点 + #[sea_orm(string_value = "branch")] + Branch, + /// 开始节点 + #[sea_orm(string_value = "begin")] + Begin, + /// 结束节点 + #[sea_orm(string_value = "Finish")] + Finish, } #[derive(poem_openapi::Object, Serialize, Deserialize, Debug, Clone, Default)] diff --git a/backend/middlewares/flow/src/dto/flow_transition_dto.rs b/backend/middlewares/flow/src/dto/flow_transition_dto.rs index 784713a9..9ba94da6 100644 --- a/backend/middlewares/flow/src/dto/flow_transition_dto.rs +++ b/backend/middlewares/flow/src/dto/flow_transition_dto.rs @@ -284,7 +284,7 @@ pub struct FlowTransitionSortStatesReq { pub sort_states: Vec, } -#[derive(Serialize, Deserialize, Debug, Default, poem_openapi::Object)] +#[derive(Serialize, Deserialize, Debug, Default, poem_openapi::Object, Clone)] pub struct FlowTransitionSortStateInfoReq { pub id: String, pub sort: i64, diff --git a/backend/middlewares/flow/src/serv/flow_inst_serv.rs b/backend/middlewares/flow/src/serv/flow_inst_serv.rs index 20e3ebe0..d834fcdc 100644 --- a/backend/middlewares/flow/src/serv/flow_inst_serv.rs +++ b/backend/middlewares/flow/src/serv/flow_inst_serv.rs @@ -52,6 +52,7 @@ use crate::{ use super::{ flow_event_serv::FlowEventServ, flow_external_serv::FlowExternalServ, + flow_model_version_serv::FlowModelVersionServ, flow_rel_serv::{FlowRelKind, FlowRelServ}, }; @@ -60,27 +61,17 @@ pub struct FlowInstServ; impl FlowInstServ { pub async fn start(start_req: &FlowInstStartReq, current_state_name: Option, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult { // get model by own_paths - let flow_model_id = FlowModelServ::get_model_id_by_own_paths_and_rel_template_id(&start_req.tag, None, funs, ctx).await?; - let flow_model = FlowModelServ::get_item( - &flow_model_id, - &FlowModelFilterReq { - basic: RbumBasicFilterReq { - with_sub_own_paths: true, - own_paths: Some("".to_string()), - ..Default::default() - }, - ..Default::default() - }, - funs, - ctx, - ) - .await?; + let flow_model = if let Some(transition_id) = &start_req.transition_id { + FlowModelServ::get_model_id_by_own_paths_and_transition_id(&start_req.tag, transition_id, funs, ctx).await? + } else { + FlowModelServ::get_model_id_by_own_paths_and_rel_template_id(&start_req.tag, None, funs, ctx).await? + }; let inst_id = TardisFuns::field.nanoid(); let current_state_id = if let Some(current_state_name) = ¤t_state_name { if current_state_name.is_empty() { flow_model.init_state_id.clone() } else { - FlowStateServ::match_state_id_by_name(&flow_model_id, current_state_name, funs, ctx).await? + FlowStateServ::match_state_id_by_name(&flow_model.id, current_state_name, funs, ctx).await? } } else { flow_model.init_state_id.clone() @@ -88,7 +79,7 @@ impl FlowInstServ { let flow_inst: flow_inst::ActiveModel = flow_inst::ActiveModel { id: Set(inst_id.clone()), tag: Set(Some(flow_model.tag.clone())), - rel_flow_version_id: Set(flow_model_id.to_string()), + rel_flow_version_id: Set(flow_model.current_version_id.to_string()), rel_business_obj_id: Set(start_req.rel_business_obj_id.to_string()), current_state_id: Set(current_state_id), @@ -97,6 +88,7 @@ impl FlowInstServ { create_ctx: Set(FlowOperationContext::from_ctx(ctx)), own_paths: Set(ctx.own_paths.to_string()), + main: Set(start_req.transition_id.is_none()), ..Default::default() }; funs.db().insert_one(flow_inst, ctx).await?; @@ -124,7 +116,11 @@ impl FlowInstServ { } current_ctx.own_paths = rel_business_obj.own_paths.clone().unwrap_or_default(); current_ctx.owner = rel_business_obj.owner.clone().unwrap_or_default(); - let flow_model_id = FlowModelServ::get_model_id_by_own_paths_and_rel_template_id(&batch_bind_req.tag, None, funs, ctx).await?; + let flow_model_id = if let Some(transition_id) = &batch_bind_req.transition_id { + FlowModelServ::get_model_id_by_own_paths_and_transition_id(&batch_bind_req.tag, transition_id, funs, ctx).await?.id + } else { + FlowModelServ::get_model_id_by_own_paths_and_rel_template_id(&batch_bind_req.tag, None, funs, ctx).await?.id + }; let current_state_id = FlowStateServ::match_state_id_by_name(&flow_model_id, &rel_business_obj.current_state_name.clone().unwrap_or_default(), funs, ctx).await?; let mut inst_id = Self::get_inst_ids_by_rel_business_obj_id(vec![rel_business_obj.rel_business_obj_id.clone().unwrap_or_default()], funs, ctx).await?.pop(); diff --git a/backend/middlewares/flow/src/serv/flow_model_serv.rs b/backend/middlewares/flow/src/serv/flow_model_serv.rs index e6a4ac81..c08367c9 100644 --- a/backend/middlewares/flow/src/serv/flow_model_serv.rs +++ b/backend/middlewares/flow/src/serv/flow_model_serv.rs @@ -28,11 +28,15 @@ use crate::{ dto::{ flow_model_dto::{ FlowModelAddReq, FlowModelAggResp, FlowModelAssociativeOperationKind, FlowModelBindStateReq, FlowModelDetailResp, FlowModelFilterReq, FlowModelFindRelStateResp, - FlowModelKind, FlowModelModifyReq, FlowModelSummaryResp, + FlowModelKind, FlowModelModifyReq, FlowModelRelTransition, FlowModelStatus, FlowModelSummaryResp, + }, + flow_model_version_dto::{ + FlowModelVersionAddReq, FlowModelVersionBindState, FlowModelVersionFilterReq, FlowModelVersionModifyReq, FlowModelVersionModifyState, FlowModelVesionState, }, - flow_model_version_dto::{FlowModelVersionAddReq, FlowModelVersionBindState, FlowModelVersionFilterReq, FlowModelVersionModifyReq, FlowModelVesionState}, flow_state_dto::{FlowStateAggResp, FlowStateDetailResp, FlowStateFilterReq, FlowStateRelModelExt}, - flow_transition_dto::{FlowTransitionAddReq, FlowTransitionDetailResp, FlowTransitionInitInfo, FlowTransitionPostActionInfo}, + flow_transition_dto::{ + FlowTransitionAddReq, FlowTransitionDetailResp, FlowTransitionInitInfo, FlowTransitionModifyReq, FlowTransitionPostActionInfo, FlowTransitionSortStatesReq, + }, }, flow_config::FlowBasicInfoManager, flow_constants, @@ -82,6 +86,7 @@ impl RbumItemCrudOperation TardisResult<()> { + async fn before_add_item(_add_req: &mut FlowModelAddReq, _funs: &TardisFunsInst, _ctx: &TardisContext) -> TardisResult<()> { Ok(()) } @@ -97,7 +102,7 @@ impl RbumItemCrudOperation TardisResult> { - if modify_req.icon.is_none() && modify_req.info.is_none() && modify_req.tag.is_none() && modify_req.rel_model_id.is_none() && modify_req.current_version_id.is_none() { + if modify_req.icon.is_none() + && modify_req.info.is_none() + && modify_req.tag.is_none() + && modify_req.rel_model_id.is_none() + && modify_req.current_version_id.is_none() + && modify_req.status.is_none() + { return Ok(None); } let mut flow_model = flow_model::ActiveModel { @@ -198,6 +209,9 @@ impl RbumItemCrudOperation TardisResult> { let mut flow_models = Self::do_find_detail_items(filter, desc_sort_by_create, desc_sort_by_update, funs, ctx).await?; for flow_model in &mut flow_models { - let flow_transitions = FlowTransitionServ::find_transitions(&flow_model.current_version_id, filter.specified_state_ids.as_deref(), funs, ctx).await?; - flow_model.transitions = Some(TardisFuns::json.obj_to_json(&flow_transitions)?); + if !flow_model.current_version_id.is_empty() { + let flow_transitions = FlowTransitionServ::find_transitions(&flow_model.current_version_id, filter.specified_state_ids.as_deref(), funs, ctx).await?; + flow_model.transitions = Some(TardisFuns::json.obj_to_json(&flow_transitions)?); + + let current_version = FlowModelVersionServ::get_item( + &flow_model.current_version_id, + &FlowModelVersionFilterReq { + basic: filter.basic.clone(), + ..Default::default() + }, + funs, + ctx, + ) + .await?; + flow_model.states = Some(current_version.states.unwrap_or_default()); + + let rel_template_ids = FlowRelServ::find_from_simple_rels(&FlowRelKind::FlowModelTemplate, &flow_model.id, None, None, funs, ctx) + .await? + .into_iter() + .map(|rel| rel.rel_id) + .collect_vec(); + flow_model.rel_template_ids = rel_template_ids; + + flow_model.init_state_id = current_version.init_state_id; + } + let rel_transition = FlowRelServ::find_from_simple_rels(&FlowRelKind::FlowModelTransition, &flow_model.id, None, None, funs, ctx) + .await? + .into_iter() + .map(|rel| FlowModelRelTransition { + id: rel.rel_id, + name: rel.rel_name, + }) + .collect_vec() + .pop(); + flow_model.rel_transition = rel_transition.map(|rel_transition| TardisFuns::json.obj_to_json(&rel_transition).unwrap_or_default()); } + Ok(flow_models) } } @@ -561,6 +624,7 @@ impl FlowModelServ { &mut FlowModelAddReq { name: model_name.into(), kind: FlowModelKind::AsTemplateAndAsModel, + status: FlowModelStatus::Enabled, add_version: Some(FlowModelVersionAddReq { name: model_name.into(), rel_model_id: None, @@ -756,7 +820,7 @@ impl FlowModelServ { .await?; let target_model_id = match op { FlowModelAssociativeOperationKind::Copy => { - if kind != FlowModelKind::AsModel { + if kind == FlowModelKind::AsModel { rel_model.rel_model_id = "".to_string(); rel_model.template = false; rel_model.scope_level = rbum_scope_helper::get_scope_level_by_context(ctx)?; @@ -980,7 +1044,7 @@ impl FlowModelServ { pub async fn find_rel_states(tags: Vec<&str>, rel_template_id: Option, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult> { let mut result = Vec::new(); for tag in tags { - let flow_model_id = Self::get_model_id_by_own_paths_and_rel_template_id(tag, rel_template_id.clone(), funs, ctx).await?; + let flow_model_id = Self::get_model_id_by_own_paths_and_rel_template_id(tag, rel_template_id.clone(), funs, ctx).await?.id; let mut states = Self::find_sorted_rel_states_by_model_id(&flow_model_id, funs, ctx) .await? .into_iter() @@ -1024,62 +1088,113 @@ impl FlowModelServ { .await) } - pub async fn get_model_id_by_own_paths_and_rel_template_id(tag: &str, rel_template_id: Option, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult { - let mut own_paths = ctx.own_paths.clone(); - let mut scope_level = rbum_scope_helper::get_scope_level_by_context(ctx)?.to_int(); + pub async fn get_model_id_by_own_paths_and_transition_id(tag: &str, transition_id: &str, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult { + let rel_model_id = FlowRelServ::find_to_simple_rels(&FlowRelKind::FlowModelTransition, transition_id, None, None, funs, ctx) + .await? + .pop() + .ok_or_else(|| { + funs.err().not_found( + &Self::get_obj_name(), + "get_model_id_by_own_paths_and_transition_id", + "rel model not found", + "404-flow-model-not-found", + ) + })? + .rel_id; + let model_detail = FlowModelServ::get_item(&rel_model_id, &FlowModelFilterReq::default(), funs, ctx).await?; + if model_detail.tag != *tag { + return Err(funs.err().not_found( + &Self::get_obj_name(), + "get_model_id_by_own_paths_and_transition_id", + "rel model not found", + "404-flow-model-not-found", + )); + } + Ok(model_detail) + } + /// 根据own_paths和rel_template_id获取模型ID + /// 规则1:如果rel_template_id不为空,优先通过rel_template_id查找rel表类型为FlowModelTemplate关联的模型ID,找不到则直接返回默认模板ID + /// 规则2:如果rel_template_id为空,则通过own_paths获取rel表类型为FlowAppTemplate关联的模型ID + /// 规则3:如果按照规则2未找到关联的模型,则通过own_paths直接获取model表中存在的模型ID + /// 规则4:如果按照规则3未找到关联的模型,则直接返回默认的模板ID + pub async fn get_model_id_by_own_paths_and_rel_template_id( + tag: &str, + rel_template_id: Option, + funs: &TardisFunsInst, + ctx: &TardisContext, + ) -> TardisResult { let mut result = None; - // Prioritize confirming the existence of mods related to own_paths - if let Some(rel_model) = Self::find_items( - &FlowModelFilterReq { - basic: RbumBasicFilterReq { - ids: Some(FlowRelServ::find_model_ids_by_app_id(Self::get_app_id_by_ctx(ctx).unwrap_or_default().as_str(), funs, ctx).await.unwrap_or_default()), - ignore_scope: true, - own_paths: Some("".to_string()), - with_sub_own_paths: true, + if let Some(rel_template_id) = rel_template_id { + // 规则1 + result = FlowModelServ::find_detail_items( + &FlowModelFilterReq { + basic: RbumBasicFilterReq { + own_paths: Some("".to_string()), + ignore_scope: true, + ..Default::default() + }, + template: Some(true), + rel: FlowRelServ::get_template_rel_filter(Some(rel_template_id.as_str())), + tags: Some(vec![tag.to_string()]), ..Default::default() }, - ..Default::default() - }, - None, - None, - funs, - ctx, - ) - .await? - .into_iter() - .find(|rel_model| rel_model.tag.as_str() == tag) - { - return Ok(rel_model.id); - } - // try get model in tenant path or app path - while !own_paths.is_empty() { - result = FlowModelServ::find_one_item( + None, + None, + funs, + ctx, + ) + .await? + .into_iter() + .find(|model| model.rel_transition.is_none()); // 筛选出没有触发动作的状态流 + } else { + // 规则2 + result = FlowModelServ::find_detail_items( &FlowModelFilterReq { basic: RbumBasicFilterReq { - own_paths: Some(own_paths.clone()), + ids: Some(FlowRelServ::find_model_ids_by_app_id(Self::get_app_id_by_ctx(ctx).unwrap_or_default().as_str(), funs, ctx).await.unwrap_or_default()), ignore_scope: true, + own_paths: Some("".to_string()), + with_sub_own_paths: true, ..Default::default() }, tags: Some(vec![tag.to_string()]), - template: Some(rel_template_id.is_some()), - rel: FlowRelServ::get_template_rel_filter(rel_template_id.as_deref()), ..Default::default() }, + None, + None, funs, ctx, ) - .await - .unwrap_or_default(); - if result.is_some() { - break; - } else { - own_paths = rbum_scope_helper::get_path_item(scope_level, &ctx.own_paths).unwrap_or_default(); - scope_level -= 1; + .await? + .into_iter() + .find(|model| model.rel_transition.is_none()); + if result.is_none() { + // 规则3 + result = FlowModelServ::find_detail_items( + &FlowModelFilterReq { + basic: RbumBasicFilterReq { + own_paths: Some(ctx.own_paths.clone()), + ignore_scope: true, + ..Default::default() + }, + tags: Some(vec![tag.to_string()]), + template: Some(false), + ..Default::default() + }, + None, + None, + funs, + ctx, + ) + .await? + .into_iter() + .find(|model| model.rel_transition.is_none()); } } + // 规则4 if result.is_none() { - result = FlowModelServ::find_one_item( + result = FlowModelServ::find_detail_items( &FlowModelFilterReq { basic: RbumBasicFilterReq { own_paths: Some("".to_string()), @@ -1089,17 +1204,98 @@ impl FlowModelServ { tags: Some(vec![tag.to_string()]), ..Default::default() }, + None, + None, funs, ctx, ) - .await?; + .await? + .into_iter() + .find(|model| model.rel_transition.is_none()); } match result { - Some(model) => Ok(model.id), - None => Err(funs.err().not_found("flow_inst_serv", "get_model_id_by_own_paths", "model not found", "404-flow-model-not-found")), + Some(model) => Ok(model), + None => Err(funs.err().not_found("flow_model_serv", "get_model_id_by_own_paths", "model not found", "404-flow-model-not-found")), } } + /// 根据own_paths和rel_template_id获取 + // pub async fn get_model_id_by_own_paths_and_rel_template_id(tag: &str, rel_template_id: Option, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult { + // let mut own_paths = ctx.own_paths.clone(); + // let mut scope_level = rbum_scope_helper::get_scope_level_by_context(ctx)?.to_int(); + + // let mut result = None; + // // Prioritize confirming the existence of mods related to own_paths + // if let Some(rel_model) = Self::find_items( + // &FlowModelFilterReq { + // basic: RbumBasicFilterReq { + // ids: Some(FlowRelServ::find_model_ids_by_app_id(Self::get_app_id_by_ctx(ctx).unwrap_or_default().as_str(), funs, ctx).await.unwrap_or_default()), + // ignore_scope: true, + // own_paths: Some("".to_string()), + // with_sub_own_paths: true, + // ..Default::default() + // }, + // ..Default::default() + // }, + // None, + // None, + // funs, + // ctx, + // ) + // .await? + // .into_iter() + // .find(|rel_model| rel_model.tag.as_str() == tag) + // { + // return Ok(rel_model.id); + // } + // // try get model in tenant path or app path + // while !own_paths.is_empty() { + // result = FlowModelServ::find_one_item( + // &FlowModelFilterReq { + // basic: RbumBasicFilterReq { + // own_paths: Some(own_paths.clone()), + // ignore_scope: true, + // ..Default::default() + // }, + // tags: Some(vec![tag.to_string()]), + // template: Some(rel_template_id.is_some()), + // rel: FlowRelServ::get_template_rel_filter(rel_template_id.as_deref()), + // ..Default::default() + // }, + // funs, + // ctx, + // ) + // .await + // .unwrap_or_default(); + // if result.is_some() { + // break; + // } else { + // own_paths = rbum_scope_helper::get_path_item(scope_level, &ctx.own_paths).unwrap_or_default(); + // scope_level -= 1; + // } + // } + // if result.is_none() { + // result = FlowModelServ::find_one_item( + // &FlowModelFilterReq { + // basic: RbumBasicFilterReq { + // own_paths: Some("".to_string()), + // ignore_scope: true, + // ..Default::default() + // }, + // tags: Some(vec![tag.to_string()]), + // ..Default::default() + // }, + // funs, + // ctx, + // ) + // .await?; + // } + // match result { + // Some(model) => Ok(model.id), + // None => Err(funs.err().not_found("flow_model_serv", "get_model_id_by_own_paths", "model not found", "404-flow-model-not-found")), + // } + // } + pub async fn find_models_by_rel_template_id( tag: String, template: Option, @@ -1320,4 +1516,50 @@ impl FlowModelServ { .await?; Ok(()) } + + pub async fn resort_transition(flow_model_id: &str, resort_req: &FlowTransitionSortStatesReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + let model_detail = Self::get_item(flow_model_id, &FlowModelFilterReq::default(), funs, ctx).await?; + let modify_trans = resort_req + .sort_states + .clone() + .into_iter() + .map(|sort_req| FlowTransitionModifyReq { + id: sort_req.id.clone().into(), + sort: Some(sort_req.sort), + ..Default::default() + }) + .collect_vec(); + let mut modify_states = HashMap::new(); + let transitions = FlowTransitionServ::find_transitions(&model_detail.current_version_id, None, funs, ctx).await?; + for modify_tran in modify_trans { + let tansition = transitions.iter().find(|tran| tran.id == modify_tran.id.to_string()).unwrap(); + let modify_transitons = modify_states.entry(&tansition.from_flow_state_id).or_insert(vec![]); + modify_transitons.push(modify_tran); + } + FlowModelServ::modify_model( + flow_model_id, + &mut FlowModelModifyReq { + modify_version: Some(FlowModelVersionModifyReq { + modify_states: Some( + modify_states + .into_iter() + .map(|(id, modify_transitions)| FlowModelVersionModifyState { + id: id.clone(), + modify_state: None, + add_transitions: None, + modify_transitions: Some(modify_transitions), + delete_transitions: None, + }) + .collect_vec(), + ), + ..Default::default() + }), + ..Default::default() + }, + funs, + ctx, + ) + .await?; + Ok(()) + } } diff --git a/backend/middlewares/flow/src/serv/flow_model_version_serv.rs b/backend/middlewares/flow/src/serv/flow_model_version_serv.rs index 59283e85..78e3f992 100644 --- a/backend/middlewares/flow/src/serv/flow_model_version_serv.rs +++ b/backend/middlewares/flow/src/serv/flow_model_version_serv.rs @@ -123,7 +123,7 @@ impl } async fn package_ext_modify(id: &str, modify_req: &FlowModelVersionModifyReq, _: &TardisFunsInst, _: &TardisContext) -> TardisResult> { - if modify_req.init_state_id.is_none() && modify_req.init_state_id.is_none() && modify_req.status.is_none() { + if modify_req.init_state_id.is_none() && modify_req.status.is_none() { return Ok(None); } let mut flow_mode_version = flow_model_version::ActiveModel { @@ -143,6 +143,27 @@ impl if let Some(bind_states) = &modify_req.bind_states { Self::bind_states_and_transitions(id, bind_states, funs, ctx).await?; } + if let Some(modify_states) = &modify_req.modify_states { + for modify_state in modify_states { + if let Some(modify_state) = &modify_state.modify_state { + FlowStateServ::modify_rel_state_ext(&modify_state.id, modify_state, funs, ctx).await?; + } + if let Some(add_transitions) = &modify_state.add_transitions { + FlowTransitionServ::add_transitions(id, &modify_state.id, add_transitions, funs, ctx).await?; + } + if let Some(modify_transitions) = &modify_state.modify_transitions { + FlowTransitionServ::modify_transitions(id, modify_transitions, funs, ctx).await?; + } + if let Some(delete_transitions) = &modify_state.delete_transitions { + FlowTransitionServ::delete_transitions(id, delete_transitions, funs, ctx).await?; + } + } + } + if let Some(unbind_states) = &modify_req.unbind_states { + for delete_state in unbind_states { + Self::unbind_state(id, delete_state, funs, ctx).await?; + } + } Ok(()) } diff --git a/backend/middlewares/flow/src/serv/flow_rel_serv.rs b/backend/middlewares/flow/src/serv/flow_rel_serv.rs index 12153d29..f78efab5 100644 --- a/backend/middlewares/flow/src/serv/flow_rel_serv.rs +++ b/backend/middlewares/flow/src/serv/flow_rel_serv.rs @@ -29,7 +29,7 @@ pub enum FlowRelKind { FlowModelTemplate, FlowModelPath, FlowAppTemplate, - FlowNodelTransition, + FlowModelTransition, } impl FlowRelServ { diff --git a/backend/middlewares/flow/src/serv/flow_state_serv.rs b/backend/middlewares/flow/src/serv/flow_state_serv.rs index 6aec9f4f..9c7bdaa8 100644 --- a/backend/middlewares/flow/src/serv/flow_state_serv.rs +++ b/backend/middlewares/flow/src/serv/flow_state_serv.rs @@ -78,7 +78,7 @@ impl RbumItemCrudOperation = flow_client + .post( + "/ci/model/copy_or_reference_model", + &FlowModelCopyOrReferenceCiReq { + rel_template_id: Some(req_template_id1.to_string()), + op: FlowModelAssociativeOperationKind::Copy, + }, + ) + .await; + info!("result: {:?}", result); + let models: HashMap = flow_client.put("/cc/model/find_rel_models?tag_ids=REQ,PROJ,ITER,TICKET&is_shared=false", &json!("")).await; + info!("models: {:?}", models); + sleep(Duration::from_millis(1000)).await; + let req_inst_id1: String = flow_client + .post( + "/cc/inst", + &FlowInstStartReq { + tag: "REQ".to_string(), + create_vars: None, + rel_business_obj_id: TardisFuns::field.nanoid(), + transition_id: None, + }, + ) + .await; + info!("req_inst_id1: {:?}", req_inst_id1); + let req_inst1: FlowInstDetailResp = flow_client.get(&format!("/cc/inst/{}", req_inst_id1)).await; + info!("req_inst1: {:?}", req_inst1); + let state_and_next_transitions: Vec = flow_client + .put( + "/cc/inst/batch/state_transitions", + &vec![FlowInstFindStateAndTransitionsReq { + flow_inst_id: req_inst_id1.clone(), + vars: None, + }], + ) + .await; + assert_eq!(state_and_next_transitions.len(), 1); + assert_eq!(state_and_next_transitions[0].current_flow_state_name, "待开始"); Ok(()) }