From 95e10c72d694d72e61b14f4cc471cb1b7873af77 Mon Sep 17 00:00:00 2001 From: ZzIsGod1019 <1498852723@qq.com> Date: Thu, 12 Oct 2023 13:14:24 +0800 Subject: [PATCH] flow: front condition (#482) * flow: update dto * flow:update * flow: front condition finish --- .../flow/src/dto/flow_transition_dto.rs | 27 ++++++- middleware/flow/src/flow_initializer.rs | 54 +++++++++++++- middleware/flow/src/serv/flow_inst_serv.rs | 71 ++++++++++++++----- middleware/flow/src/serv/flow_model_serv.rs | 15 ++++ middleware/flow/tests/test_flow_scenes_fsm.rs | 44 ++++++------ 5 files changed, 169 insertions(+), 42 deletions(-) diff --git a/middleware/flow/src/dto/flow_transition_dto.rs b/middleware/flow/src/dto/flow_transition_dto.rs index dc53bdd97..6ecbf35bc 100644 --- a/middleware/flow/src/dto/flow_transition_dto.rs +++ b/middleware/flow/src/dto/flow_transition_dto.rs @@ -207,7 +207,7 @@ pub struct FlowTransitionActionChangeInfo { pub current: bool, pub var_name: String, pub changed_val: Option, - pub changed_current_time: Option, + pub changed_kind: Option, } impl From for FlowTransitionActionChangeAgg { @@ -232,7 +232,7 @@ impl From for FlowTransitionActionChangeAgg { obj_tag: value.obj_tag, var_name: value.var_name, changed_val: value.changed_val, - changed_current_time: value.changed_current_time, + changed_kind: value.changed_kind, }), state_change_info: None, }, @@ -263,7 +263,18 @@ pub struct FlowTransitionActionByVarChangeInfo { pub obj_tag: Option, pub var_name: String, pub changed_val: Option, - pub changed_current_time: Option, + pub changed_kind: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, poem_openapi::Enum, strum::EnumIter, sea_orm::DeriveActiveEnum)] +#[sea_orm(rs_type = "String", db_type = "String(Some(255))")] +pub enum FlowTransitionActionByVarChangeInfoChangedKind { + #[sea_orm(string_value = "clean")] + Clean, + #[sea_orm(string_value = "change_content")] + ChangeContent, + #[sea_orm(string_value = "auto_get_operate_time")] + AutoGetOperateTime, } #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, poem_openapi::Object, sea_orm::FromJsonQueryResult)] @@ -366,6 +377,9 @@ pub enum FlowTransitionFrontActionInfoRelevanceRelation { #[serde(rename = "not_in")] #[oai(rename = "not_in")] NotIn, + #[serde(rename = "between")] + #[oai(rename = "between")] + Between, } impl FlowTransitionFrontActionInfoRelevanceRelation { @@ -381,6 +395,13 @@ impl FlowTransitionFrontActionInfoRelevanceRelation { FlowTransitionFrontActionInfoRelevanceRelation::NotLike => !left_value.contains(&right_value), FlowTransitionFrontActionInfoRelevanceRelation::In => TardisFuns::json.str_to_obj::>(&right_value).unwrap_or_default().contains(&left_value), FlowTransitionFrontActionInfoRelevanceRelation::NotIn => !TardisFuns::json.str_to_obj::>(&right_value).unwrap_or_default().contains(&left_value), + FlowTransitionFrontActionInfoRelevanceRelation::Between => { + let time_interval = TardisFuns::json.str_to_obj::>(&right_value).unwrap_or_default(); + if time_interval.len() != 2 { + return false; + } + left_value >= time_interval[0] && left_value <= time_interval[1] + } } } } diff --git a/middleware/flow/src/flow_initializer.rs b/middleware/flow/src/flow_initializer.rs index ff27cdcf0..61735b4ab 100644 --- a/middleware/flow/src/flow_initializer.rs +++ b/middleware/flow/src/flow_initializer.rs @@ -6,9 +6,17 @@ use bios_basic::rbum::{ }; use bios_sdk_invoke::invoke_initializer; +use itertools::Itertools; +use serde_json::Value; use tardis::{ basic::{dto::TardisContext, field::TrimString, result::TardisResult}, - db::{reldb_client::TardisActiveModel, sea_orm::sea_query::Table}, + db::{ + reldb_client::TardisActiveModel, + sea_orm::{ + self, + sea_query::{Query, Table}, + }, + }, log::info, web::web_server::TardisWebServer, TardisFuns, TardisFunsInst, @@ -24,7 +32,7 @@ use crate::{ dto::{ flow_model_dto::FlowModelFilterReq, flow_state_dto::FlowSysStateKind, - flow_transition_dto::{FlowTransitionDoubleCheckInfo, FlowTransitionInitInfo}, + flow_transition_dto::{FlowTransitionActionChangeInfo, FlowTransitionDoubleCheckInfo, FlowTransitionInitInfo, FlowTransitionActionChangeKind, FlowTransitionActionByVarChangeInfoChangedKind}, }, flow_config::{BasicInfo, FlowBasicInfoManager, FlowConfig}, flow_constants, @@ -77,6 +85,7 @@ pub async fn init_db(mut funs: TardisFunsInst) -> TardisResult<()> { funs.db().init(flow_inst::ActiveModel::init(db_kind, None, compatible_type.clone())).await?; funs.db().init(flow_config::ActiveModel::init(db_kind, None, compatible_type.clone())).await?; init_rbum_data(&funs, &ctx).await?; + self::modify_post_actions(&funs, &ctx).await?; }; funs.commit().await?; Ok(()) @@ -115,6 +124,47 @@ async fn init_basic_info<'a>(funs: &TardisFunsInst) -> TardisResult<()> { Ok(()) } +pub async fn modify_post_actions(funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { + #[derive(sea_orm::FromQueryResult)] + pub struct FlowTransactionPostAction { + id: String, + action_by_post_changes: Value, + } + let transactions = funs.db() + .find_dtos::( + Query::select() + .columns([ + (flow_transition::Entity, flow_transition::Column::Id), + (flow_transition::Entity, flow_transition::Column::ActionByPostChanges), + ]) + .from(flow_transition::Entity), + ) + .await? + .into_iter() + .filter(|res| !TardisFuns::json.json_to_obj::>(res.action_by_post_changes.clone()).unwrap_or_default().is_empty()) + .collect_vec(); + for transaction in transactions { + let mut post_changes = TardisFuns::json.json_to_obj::>(transaction.action_by_post_changes.clone()).unwrap_or_default(); + for post_change in post_changes.iter_mut() { + if post_change.changed_kind.is_none() && post_change.kind == FlowTransitionActionChangeKind::Var { + if post_change.changed_val.is_some() { + post_change.changed_kind = Some(FlowTransitionActionByVarChangeInfoChangedKind::ChangeContent); + } else { + post_change.changed_kind = Some(FlowTransitionActionByVarChangeInfoChangedKind::Clean); + } + } + } + let flow_transition = flow_transition::ActiveModel { + id: sea_orm::ActiveValue::Set(transaction.id.clone()), + action_by_post_changes: sea_orm::ActiveValue::Set(TardisFuns::json.obj_to_json(&post_changes)?), + ..Default::default() + }; + funs.db().update_one(flow_transition, ctx).await?; + } + + Ok(()) +} + pub async fn init_rbum_data(funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult<()> { let kind_state_id = add_kind(flow_constants::RBUM_KIND_STATE_CODE, flow_constants::RBUM_EXT_TABLE_STATE, funs, ctx).await?; let kind_model_id = add_kind(flow_constants::RBUM_KIND_MODEL_CODE, flow_constants::RBUM_EXT_TABLE_MODEL, funs, ctx).await?; diff --git a/middleware/flow/src/serv/flow_inst_serv.rs b/middleware/flow/src/serv/flow_inst_serv.rs index c45adc9f0..0a34a526f 100644 --- a/middleware/flow/src/serv/flow_inst_serv.rs +++ b/middleware/flow/src/serv/flow_inst_serv.rs @@ -16,7 +16,7 @@ use itertools::Itertools; use serde_json::json; use tardis::{ basic::{dto::TardisContext, result::TardisResult}, - chrono::{DateTime, Utc}, + chrono::{DateTime, SecondsFormat, Utc}, db::sea_orm::{ self, sea_query::{Alias, Cond, Expr, Query}, @@ -41,8 +41,8 @@ use crate::{ flow_model_dto::{FlowModelDetailResp, FlowModelFilterReq}, flow_state_dto::{FlowStateFilterReq, FlowStateRelModelExt, FlowSysStateKind}, flow_transition_dto::{ - FlowTransitionActionByStateChangeInfo, FlowTransitionActionChangeAgg, FlowTransitionActionChangeInfo, FlowTransitionActionChangeKind, FlowTransitionDetailResp, - FlowTransitionFrontActionInfo, FlowTransitionFrontActionRightValue, StateChangeConditionOp, + FlowTransitionActionByStateChangeInfo, FlowTransitionActionByVarChangeInfoChangedKind, FlowTransitionActionChangeAgg, FlowTransitionActionChangeInfo, + FlowTransitionActionChangeKind, FlowTransitionDetailResp, FlowTransitionFrontActionInfo, FlowTransitionFrontActionRightValue, StateChangeConditionOp, }, }, serv::{flow_model_serv::FlowModelServ, flow_state_serv::FlowStateServ}, @@ -585,8 +585,26 @@ impl FlowInstServ { Ok(()) } - #[async_recursion] pub async fn transfer(flow_inst_id: &str, transfer_req: &FlowInstTransferReq, funs: &TardisFunsInst, ctx: &TardisContext) -> TardisResult { + // record updated instance id + let mut updated_instance_list: Vec = Vec::new(); + let result = Self::do_transfer(flow_inst_id, transfer_req, &mut updated_instance_list, funs, ctx).await; + + for updated_instance_id in updated_instance_list { + Self::do_front_change(&updated_instance_id, ctx, funs).await?; + } + + result + } + + #[async_recursion] + async fn do_transfer( + flow_inst_id: &str, + transfer_req: &FlowInstTransferReq, + updated_instance_list: &mut Vec, + funs: &TardisFunsInst, + ctx: &TardisContext, + ) -> TardisResult { let global_ctx = TardisContext { own_paths: "".to_string(), ..ctx.clone() @@ -725,6 +743,7 @@ impl FlowInstServ { } funs.db().update_one(flow_inst, ctx).await?; + updated_instance_list.push(flow_inst_id.to_string()); // get updated instance detail let flow_inst_detail = Self::get(flow_inst_id, funs, ctx).await?; @@ -753,7 +772,7 @@ impl FlowInstServ { let post_changes = model_transition.into_iter().find(|model_transition| model_transition.id == next_flow_transition.next_flow_transition_id).unwrap_or_default().action_by_post_changes(); if !post_changes.is_empty() { - Self::do_post_change(&flow_inst_detail, &flow_model, post_changes, ctx, funs).await?; + Self::do_post_change(&flow_inst_detail, &flow_model, post_changes, updated_instance_list, ctx, funs).await?; } let next_flow_transitions = Self::do_find_next_transitions(&flow_inst_detail, &flow_model, None, &None, funs, ctx).await?.next_flow_transitions; @@ -783,6 +802,7 @@ impl FlowInstServ { current_inst: &FlowInstDetailResp, current_model: &FlowModelDetailResp, post_changes: Vec, + updated_instance_list: &mut Vec, ctx: &TardisContext, funs: &TardisFunsInst, ) -> TardisResult<()> { @@ -791,8 +811,8 @@ impl FlowInstServ { match post_change.kind { FlowTransitionActionChangeKind::Var => { if let Some(mut change_info) = post_change.var_change_info { - if change_info.changed_current_time.is_some() && change_info.changed_current_time.unwrap() { - change_info.changed_val = Some(json!(Utc::now().to_string())); + if change_info.changed_kind.is_some() && change_info.changed_kind.unwrap() == FlowTransitionActionByVarChangeInfoChangedKind::AutoGetOperateTime { + change_info.changed_val = Some(json!(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true))); } let rel_tag = change_info.obj_tag.unwrap_or_default(); if !rel_tag.is_empty() { @@ -818,6 +838,7 @@ impl FlowInstServ { funs, ) .await?; + updated_instance_list.push(inst_id.clone()); } } } else { @@ -837,6 +858,7 @@ impl FlowInstServ { funs, ) .await?; + updated_instance_list.push(current_inst.id.clone()); } } } @@ -853,7 +875,7 @@ impl FlowInstServ { .await?; if !resp.rel_bus_objs.is_empty() { let inst_ids = Self::find_inst_ids_by_rel_obj_ids(resp.rel_bus_objs.pop().unwrap().rel_bus_obj_ids, &change_info, funs, ctx).await?; - Self::do_modify_state_by_post_action(inst_ids, &change_info, funs, ctx).await?; + Self::do_modify_state_by_post_action(inst_ids, &change_info, updated_instance_list, funs, ctx).await?; } } } @@ -960,6 +982,7 @@ impl FlowInstServ { async fn do_modify_state_by_post_action( rel_inst_ids: Vec, change_info: &FlowTransitionActionByStateChangeInfo, + updated_instance_list: &mut Vec, funs: &TardisFunsInst, ctx: &TardisContext, ) -> TardisResult<()> { @@ -988,13 +1011,14 @@ impl FlowInstServ { .collect_vec() .pop(); if let Some(transition) = transition_resp { - Self::transfer( + Self::do_transfer( &rel_inst.id, &FlowInstTransferReq { flow_transition_id: transition.next_flow_transition_id, message: None, vars: None, }, + updated_instance_list, funs, ctx, ) @@ -1182,11 +1206,14 @@ impl FlowInstServ { ..Default::default() }; funs.db().update_one(flow_inst, ctx).await?; + Self::do_front_change(flow_inst_id, ctx, funs).await?; Ok(()) } - async fn do_front_change(flow_inst_detail: &FlowInstDetailResp, ctx: &TardisContext, funs: &TardisFunsInst) -> TardisResult<()> { + #[async_recursion] + async fn do_front_change(flow_inst_id: &str, ctx: &TardisContext, funs: &TardisFunsInst) -> TardisResult<()> { + let flow_inst_detail = Self::get(flow_inst_id, funs, ctx).await?; let flow_model = FlowModelServ::get_item( &flow_inst_detail.rel_flow_model_id, &FlowModelFilterReq { @@ -1205,20 +1232,32 @@ impl FlowInstServ { .transitions() .into_iter() .filter(|trans| trans.from_flow_state_id == flow_inst_detail.current_state_id && !trans.action_by_front_changes().is_empty()) + .sorted_by_key(|trans| trans.sort) .collect_vec(); if flow_transitions.is_empty() { return Ok(()); } + for flow_transition in flow_transitions { + if Self::check_front_conditions(&flow_inst_detail, flow_transition.action_by_front_changes())? { + Self::transfer( + &flow_inst_detail.id, + &FlowInstTransferReq { + flow_transition_id: flow_transition.id.clone(), + message: None, + vars: None, + }, + funs, + ctx, + ) + .await?; + break; + } + } Ok(()) } - async fn check_front_conditions( - flow_inst_detail: &FlowInstDetailResp, - conditions: Vec, - ctx: &TardisContext, - funs: &TardisFunsInst, - ) -> TardisResult { + fn check_front_conditions(flow_inst_detail: &FlowInstDetailResp, conditions: Vec) -> TardisResult { if flow_inst_detail.current_vars.is_none() { return Ok(false); } diff --git a/middleware/flow/src/serv/flow_model_serv.rs b/middleware/flow/src/serv/flow_model_serv.rs index c49f0bbfc..c7df7a476 100644 --- a/middleware/flow/src/serv/flow_model_serv.rs +++ b/middleware/flow/src/serv/flow_model_serv.rs @@ -1196,6 +1196,7 @@ impl FlowModelServ { current_chain.push(transition_detail.id.clone()); let model_detail = Self::get_item(&transition_detail.rel_flow_model_id, &FlowModelFilterReq::default(), funs, ctx).await?; + // check post changes let post_changes = transition_detail .action_by_post_changes() .into_iter() @@ -1245,6 +1246,20 @@ impl FlowModelServ { } } } + // check front changes + let flow_transitions = model_detail + .transitions() + .into_iter() + .filter(|trans| trans.from_flow_state_id == transition_detail.to_flow_state_id && !trans.action_by_front_changes().is_empty()) + .sorted_by_key(|trans| trans.sort) + .collect_vec(); + for transition_detail in flow_transitions { + (is_ring, current_chain) = Self::check_post_action_ring(transition_detail, (is_ring, current_chain.clone()), funs, ctx).await?; + if is_ring { + return Ok((true, current_chain)); + } + } + Ok((is_ring, current_chain)) } diff --git a/middleware/flow/tests/test_flow_scenes_fsm.rs b/middleware/flow/tests/test_flow_scenes_fsm.rs index 3a7d8a7c0..4a70f47a5 100644 --- a/middleware/flow/tests/test_flow_scenes_fsm.rs +++ b/middleware/flow/tests/test_flow_scenes_fsm.rs @@ -6,7 +6,7 @@ use bios_basic::test::test_http_client::TestHttpClient; use bios_mw_flow::dto::flow_config_dto::FlowConfigModifyReq; use bios_mw_flow::dto::flow_inst_dto::{ FlowInstBatchBindReq, FlowInstBatchBindResp, FlowInstBindRelObjReq, FlowInstBindReq, FlowInstDetailResp, FlowInstFindNextTransitionResp, FlowInstFindNextTransitionsReq, - FlowInstFindStateAndTransitionsReq, FlowInstFindStateAndTransitionsResp, FlowInstStartReq, FlowInstTransferReq, FlowInstTransferResp, + FlowInstFindStateAndTransitionsReq, FlowInstFindStateAndTransitionsResp, FlowInstModifyCurrentVarsReq, FlowInstStartReq, FlowInstTransferReq, FlowInstTransferResp, }; use bios_mw_flow::dto::flow_model_dto::{ FlowModelAddCustomModelItemReq, FlowModelAddCustomModelReq, FlowModelAddCustomModelResp, FlowModelAggResp, FlowModelBindStateReq, FlowModelFindRelStateResp, @@ -14,8 +14,8 @@ use bios_mw_flow::dto::flow_model_dto::{ }; use bios_mw_flow::dto::flow_state_dto::{FlowStateAddReq, FlowStateSummaryResp, FlowSysStateKind}; use bios_mw_flow::dto::flow_transition_dto::{ - FlowTransitionActionChangeInfo, FlowTransitionActionChangeKind, FlowTransitionAddReq, FlowTransitionDoubleCheckInfo, FlowTransitionModifyReq, FlowTransitionSortStateInfoReq, - FlowTransitionSortStatesReq, StateChangeCondition, StateChangeConditionItem, StateChangeConditionOp, + FlowTransitionActionByVarChangeInfoChangedKind, FlowTransitionActionChangeInfo, FlowTransitionActionChangeKind, FlowTransitionAddReq, FlowTransitionDoubleCheckInfo, + FlowTransitionModifyReq, FlowTransitionSortStateInfoReq, FlowTransitionSortStatesReq, StateChangeCondition, StateChangeConditionItem, StateChangeConditionOp, }; use bios_mw_flow::dto::flow_var_dto::{FlowVarInfo, RbumDataTypeKind, RbumWidgetTypeKind}; @@ -185,7 +185,7 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli &json!({ "modify_transitions": [ { - "id": trans_start.id.clone(), + "id": trans_complate.id.clone(), "action_by_front_changes": [ { "relevance_relation": "=", @@ -260,7 +260,7 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli current: true, var_name: "".to_string(), changed_val: None, - changed_current_time: None, + changed_kind: None, }]), double_check: Some(FlowTransitionDoubleCheckInfo { is_open: true, @@ -296,8 +296,8 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli changed_state_id: "".to_string(), current: false, var_name: "id".to_string(), - changed_val: Some(json!("xxx".to_string())), - changed_current_time: None, + changed_val: None, + changed_kind: Some(FlowTransitionActionByVarChangeInfoChangedKind::AutoGetOperateTime), }]), double_check: None, sort: None, @@ -380,7 +380,7 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli current: true, var_name: "".to_string(), changed_val: None, - changed_current_time: None, + changed_kind: None, }]), double_check: None, sort: None, @@ -423,7 +423,7 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli current: true, var_name: "".to_string(), changed_val: None, - changed_current_time: None, + changed_kind: None, }]), double_check: None, sort: None, @@ -755,22 +755,24 @@ pub async fn test(flow_client: &mut TestHttpClient, _kv_client: &mut TestHttpCli ) .await; assert_eq!(state_and_next_transitions[0].next_flow_transitions.len(), 1); - let _transfer: FlowInstTransferResp = flow_client + // handle front change + let current_vars = HashMap::from([("status".to_string(), json!("xxx"))]); + let _: Void = flow_client + .patch( + &format!("/cc/inst/{}/modify_current_vars", req_inst_id2), + &FlowInstModifyCurrentVarsReq { vars: current_vars }, + ) + .await; + let state_and_next_transitions: Vec = flow_client .put( - &format!("/cc/inst/{}/transition/transfer", req_inst_id2), - &FlowInstTransferReq { - flow_transition_id: state_and_next_transitions[0] - .next_flow_transitions - .iter() - .find(|trans| trans.next_flow_state_name == "已完成") - .unwrap() - .next_flow_transition_id - .clone(), + "/cc/inst/batch/state_transitions", + &vec![FlowInstFindStateAndTransitionsReq { + flow_inst_id: req_inst_id2.clone(), vars: None, - message: None, - }, + }], ) .await; + assert_eq!(state_and_next_transitions[0].current_flow_state_name, "已完成"); Ok(()) }