自定义审批方式、自定义审批节点名称

@Model.model(审批模型.MODEL_MODEL)
@Component
public class 审批模型Action {

    @Function
    @Function.Advanced(category = FunctionCategoryEnum.CUSTOM_DESIGNER, displayName = "测试自定义审批类型")
    public WorkflowSignTypeEnum signType(String json) { // json为业务数据,可用JsonUtils转换
        return WorkflowSignTypeEnum.COUNTERSIGN_ONEAGREE_ONEREJUST;
    }

    @Function
    @Function.Advanced(category = FunctionCategoryEnum.CUSTOM_DESIGNER, displayName = "测试自定义审批名称")
    public String customApprovalName() {
        return UUID.randomUUID().toString();
    }
}

本文来自投稿,不代表Oinone社区立场,如若转载,请注明出处:https://doc.oinone.top/backend/4847.html

(0)
yakir的头像yakir数式员工
上一篇 2023年12月4日 pm10:09
下一篇 2023年12月7日 pm1:44

相关推荐

  • 自定义用户中心菜单

    使用扩展点实现用户中心菜单替换 1. 工程中引起pamirs-user-api <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-user-api</artifactId> </dependency> 2. 实现TopBarUserBlockAction的后置扩展 实现HookAfter后置扩展接口 @Hook(model = {TopBarUserBlock.MODEL_MODEL}, fun = {"construct"})添加Hook注解注明是TopBarUserBlock模型的construct函数的后置扩展。 增加用户中心菜单 @Component @Order(1) @SPI.Service public class MyTopBarActionExt implements TopBarActionExtendApi { public void edit(List<TopBarAction> list) { list.add(new TopBarAction("top_demo", "top.Teacher", "uiView9a0caf1d574a42c9847a057a0c4a4ad1", ActionTypeEnum.VIEW, 1) .setDisplayName("商品管理") .setIcon("oinone-gongzuotai") ); } } 实现效果 替换原有的用户中心菜单 替换原有的菜单跳转 @Component public class DemoTopBarUserBlockDataHookAfter implements HookAfter { @Override @Hook(model = {TopBarUserBlock.MODEL_MODEL}, fun = {"construct"}) public Object run(Function function, Object ret) { if (ret == null) { return null; } TopBarUserBlock result = null; if (ret instanceof Object[]) { Object[] rets = (Object[]) ((Object[]) ret); if (rets.length == 1) { result = (TopBarUserBlock) rets[0]; //例:替换用户中心:修改密码菜单 //使用name和model查询出模型的ViewAction替换修改密码ViewAction ViewAction demoViewAction = PamirsSession.getContext().getExtendCache(ActionCacheApi.class).get(Dog.MODEL_MODEL, "changePassword"); //设置菜单的icon Map<String, Object> attributes = Optional.ofNullable(demoViewAction.getAttributes()).orElse(new HashMap<>()); attributes.put("icon", "oinone-xiugaimima"); demoViewAction.setAttributes(attributes); //UserViewAction第0个是修改密码ViewAction,使用自定义的ViewAction就可以实现替换 result.getUserViewAction().set(0, demoViewAction); } } else { result = (TopBarUserBlock) ret; } return result; } } 使用@UxRouteButton方式新增ViewAction,更多新增Action方式详见:Action的类型 @Model.model(Dog.MODEL_MODEL) @Component @UxRouteButton( action = @UxAction(name = "changePassword", displayName = "修改密码"), value = @UxRoute(model = Dog.MODEL_MODEL, openType = ActionTargetEnum.DIALOG)) public class DogAction { } 替换原有的个人设置头像跳转 修改点击头像绑定的跳转逻辑 @Order(10) @Component @SPI.Service public class DemoTopBarUserBlockDataApi implements TopBarUserBlockDataApi { @Override public TopBarUserBlock extendData(TopBarUserBlock data) { //例如增加一个菜单, PamirsDemo.MODEL_MODEL: 模型。 MenuuiMenu31f22466735a4abe8e0544b428ed88ac:viewAction的name。 Action demoViewAction =…

    2024年7月4日
    1.5K00
  • 函数之异步执行

    总体介绍 异步任务是非常常见的一种开发模式,它在分布式的开发模式中有很多应用场景如: 高并发场景中,我们一般采用把长流程切短,用异步方式去掉可以异步的非关键功能,缩小主流程响应时间,提升用户体验 异构系统的集成调用,通过异步任务完成解耦与自动重试 分布式系统最终一致性的可选方案 本文将介绍oinone是如何结合Spring+TbSchedule来完成异步任务 构建第一个异步任务 新建PetShopService和PetShopServiceImpl 1、 新建PetShopService定义updatePetShops方法 package pro.shushi.pamirs.demo.api.service; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) public interface PetShopService { String FUN_NAMESPACE = "demo.PetShop.PetShopService"; @Function void updatePetShops(List<PetShop> petShops); } 2、PetShopServiceImpl实现PetShopService接口并在updatePetShops增加@XAsync注解 package pro.shushi.pamirs.demo.core.service; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.PetShop; import pro.shushi.pamirs.demo.api.service.PetShopService; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.trigger.annotation.XAsync; import java.util.List; @Fun(PetShopService.FUN_NAMESPACE) @Component public class PetShopServiceImpl implements PetShopService { @Override @Function @XAsync(displayName = "异步批量更新宠物商店",limitRetryNumber = 3,nextRetryTimeValue = 60) public void updatePetShops(List<PetShop> petShops) { new PetShop().updateBatch(petShops); } } a. displayName = "异步批量更新宠物商店",定义异步任务展示名称b. limitRetryNumber = 3,定义任务失败重试次数,,默认:-1不断重试c. nextRetryTimeValue = 60,定义任务失败重试的时间数,默认:3d. nextRetryTimeUnit,定义任务失败重试的时间单位,默认:TimeUnitEnum.SECONDe. delayTime,定义任务延迟执行的时间数,默认:0f. delayTimeUnit,定义任务延迟执行的时间单位,默认:TimeUnitEnum.SECOND 修改PetShopBatchUpdateAction调用异步任务 引入PetShopService 修改conform方法,调用petShopService.updatePetShops方法 package pro.shushi.pamirs.demo.core.action; @Model.model(PetShopBatchUpdate.MODEL_MODEL) @Component public class PetShopBatchUpdateAction { @Autowired private PetShopService petShopService; @Action(displayName = "确定",bindingType = ViewTypeEnum.FORM,contextType = ActionContextTypeEnum.SINGLE) public PetShopBatchUpdate conform(PetShopBatchUpdate data){ List<PetShop> shops = ArgUtils.convert(PetShopProxy.MODEL_MODEL, PetShop.MODEL_MODEL,proxyList); // 调用异步任务 petShopService.updatePetShops(shops); }); return data; } } 不同应用如何隔离执行单元 在schedule跟模块部署一起的时候,多模块独立boot的情况下,需要做必要的配置。如果schedule独立部署则没有必要,因为全部走远程,不存在类找不到的问题 通过配置pamirs.zookeeper.rootPath,确保两组机器都能覆盖所有任务分片,这样不会漏数据 通过pamirs.event.schedule.ownSign来隔离。确保两组机器只取各自产生的数据,这样不会重复执行数据 pamirs: zookeeper: zkConnectString: 127.0.0.1:2181 zkSessionTimeout: 60000 rootPath: /demo event: enabled: true schedule: enabled: true ownSign: demo rocket-mq: namesrv-addr: 127.0.0.1:9876

    2024年5月25日
    1.2K00
  • 工作流审核撤回/回退/拒绝/同意/反悔钩子使用

    目录 1. 流程撤回、拒绝和回退调用自定义函数1.1 工作流【撤销】回调钩子1.2 撤销【回退】回调钩子1.3 工作流【拒绝】回调钩子1.4 工作流【同意】回调钩子1.4 工作流【反悔】回调钩子1.4 回调钩子在业务系统中的调用示例2. 自定义审批方式、自定义审批节点名称 1.流程撤回、拒绝和回退调用自定义函数 1.1工作流【撤销】回调钩子 使用方式:把该方法放置到XXX模型的Action下面,或@Fun(XXX.MODEL_MODEL)触发方式:当流程实例被撤销时调用入口:pro.shushi.pamirs.workflow.app.core.service.impl.WorkflowInstanceServiceImpl#undoInstance /** * XXX为当前流程触发方式为模型触发时对应的触发模型、 * 对应返回不影响流程上下文 * @param data 入参为触发时的业务数据,数据的JsonString * @return */ @Function public XXX recall(String data) { // TODO: 根据实际的业务逻辑把data转换为对象 WorkRecord workRecord = JsonUtils.parseObject(data, new TypeReference<WorkRecord>(){}); // TODO: 增加自定义业务逻辑 return new XXX(); } 1.2撤销【回退】回调钩子 使用方式:把该方法放置到XXX模型的Action下面,或@Fun(XXX.MODEL_MODEL)触发方式:流程待办进行回退操作时调用入口:pro.shushi.pamirs.workflow.app.core.service.operator.ApprovalFallbackOperatorService /** * XXX为当前流程触发方式为模型触发时对应的触发模型 * 对应返回不影响流程上下文 * @param data 入参为触发时的业务数据,数据的JsonString * @return */ @Function public XXX fallBack(String data) { // TODO: 根据实际的业务逻辑把data转换为对象 WorkRecord workRecord = JsonUtils.parseObject(data, new TypeReference<WorkRecord>(){}); // TODO: 增加自定义业务逻辑 return new XXX(); } 1.3工作流【拒绝】回调钩子 使用方式:把该方法放置到XXX模型的Action下面,或@Fun(XXX.MODEL_MODEL)触发方式:流程待办进行拒绝操作时调用入口:pro.shushi.pamirs.workflow.app.core.service.operator.ApprovalFallbackOperatorService /** * XXX为当前流程触发方式为模型触发时对应的触发模型 * 对应返回不影响流程上下文 * @param data 入参为触发时的业务数据,数据的JsonString * @return */ @Function public XXX reject(String data) { // TODO: 根据实际的业务逻辑把data转换为对象 WorkRecord workRecord = JsonUtils.parseObject(data, new TypeReference<WorkRecord>(){}); // TODO: 增加自定义业务逻辑 return new XXX(); } 1.4 工作流【同意】回调钩子 使用方式:把该方法放置到XXX模型的Action下面,或@Fun(XXX.MODEL_MODEL)触发方式:流程待办进行同意操作时调用入口:pro.shushi.pamirs.workflow.app.core.util.ArtificialTaskUtils @Function(summary = "发起的审批同意时会自动调用此方法") @Function.Advanced(displayName = "审批同意") public Teacher agree(String data) { // TODO: 根据实际的业务逻辑把data转换为对象 // WorkRecord workRecord = JsonUtils.parseObject(data, new TypeReference<WorkRecord>(){}); // TODO: 增加自定义业务逻辑 return new Teacher(); } 1.4 工作流【反悔】回调钩子 使用方式:把该方法放置到XXX模型的Action下面,或@Fun(XXX.MODEL_MODEL)触发方式:流程待办进行反悔操作时使用场景:流程待办进行反悔操作时,需要额外更改其他的业务数据逻辑时可用该回调钩子。 注意:该函数的namespace需要设置为流程触发模型。 调用入口:pro.shushi.pamirs.workflow.app.core.service.operator.ArtificialRetractOperatorService @Function @Function.fun(WorkflowBizCallConstants.retract) public void retract(WorkflowUserTask workflowUserTask) { // 获取流程实例 workflowUserTask.fieldQuery(WorkflowUserTask::getInstance); WorkflowInstance instance = workflowUserTask.getInstance(); // 获取用户任务实例 WorkflowUserInstance userInstance = new WorkflowUserInstance() .setId(workflowUserTask.getWorkflowUserInstanceId()) .queryById(); // 反悔的用户id…

    2023年11月15日
    1.2K00
  • 如何把平台功能菜单加到项目中?

    概述 在使用Oinone低代码平台进行项目开发的过程中,会存在把平台默认提供的菜单加到自己的项目中。这篇文章介绍实现方式,以角色管理为例。 1. 低代码情况 即项目是通过后端代码初始化菜单的方式。 通常在 XXXMenu.java类通过@UxMenu注解的方式,代码片段如下: 此种情况与添加项目本地的菜单无区别,具体代码: @UxMenu(value = "账号管理", icon = "icon-yonghuguanli") class AccountManage { @UxMenu("用户管理") @UxRoute(value = CustomerCompanyUserProxy.MODEL_MODEL, title = "用户管理") class CompanyUserManage { } @UxMenu("角色管理") @UxRoute(value = AuthRole.MODEL_MODEL, module = AdminModule.MODULE_MODULE, title = "角色管理") class RoleManage { } @UxMenu("操作日志") @UxRoute(value = OperationLog.MODEL_MODEL, module = AdminModule.MODULE_MODULE/***菜单所挂载的模块**/) class OperateLog { } } 2. 无代码情况 在界面设计器中,新建菜单–>选择绑定已有页面,进行发布即可。

    2024年4月19日
    1.6K00
  • 如何在代码中使用自增ID和获取序列

    在使用继承IDModel或CodeModel时,id和code是系统默认自动生成, 默认值规则:ID–>分布式ID; CODE–>根据定义的SequenceConfig规则自动生成。 在特定情况下需要落库前先生成ID或者Code,这些场景下可参照如下代码示例 一、使用自增ID 单个字段设置方式 // 主键字段,可以使用mysql的自增能力 @Field.Integer @Field.PrimaryKey(keyGenerator = KeyGeneratorEnum.AUTO_INCREMENT) @Field.Advanced(batchStrategy = FieldStrategyEnum.NEVER) @Field(displayName = "id", summary = "Id字段,⾃增") private Long id; @Field.Integer @Field(displayName = "自增版本") @Field.Sequence(sequence = "SEQ", initial = 1) private Long version; 全局设置方式 该方式会作用到每一个存储模型的id字段,在application.yml配置文件中修改id的生成规则,查找配置项关键字key-generator,默认为DISTRIBUTION(分布式id),可修改为 AUTO_INCREMENT(自增id) 二、手动方式获取序列 获取方式示例1 /** * 在特定场景下需要手动生成Id或者code时,可参照这个示例 */ public void manualSetIdCode(){ DemoItem demoItem = new DemoItem(); //手动生成ID和code Object idObj = Spider.getDefaultExtension(IdGenerator.class).generate(PamirsTableInfo.fetchKeyGenerator(DemoItem.MODEL_MODEL)); demoItem.setId(TypeUtils.createLong(idObj)); Object codeObj = CommonApiFactory.getSequenceGenerator().generate("SEQ",DemoItem.MODEL_MODEL); String code = TypeUtils.stringValueOf(codeObj); demoItem.setCode(code); //…… } 获取方式示例2 1、在系统启动的时候初始化SequenceConfig package pro.shushi.pamirs.demo.core.init; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.demo.core.constant.SeqConstants; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.enmu.SequenceEnum; import java.util.Map; /** * DemoMetadataEditor */ @Slf4j @Component public class DemoMetadataEditor implements MetaDataEditor { @Override public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) { InitializationUtil util = InitializationUtil.get(metaMap, DemoModule.MODULE_MODULE, DemoModule.MODULE_NAME); if (util == null) { log.error("获取初始化序列失败"); return; } bizSequence(util); } private void bizSequence(InitializationUtil util) { util.createSequenceConfig("申请单编码生成", SeqConstants.NABEL_SAMPLE_APPLY_SEQ, SequenceEnum.ORDERLY_SEQ, 8) .setStep(1) .setInitial(80000000L) .setIsRandomStep(false); util.createSequenceConfig("订单编码生成", SeqConstants.NABEL_SAMPLE_ORDER_SEQ_YP, SequenceEnum.ORDERLY_SEQ, 8) .setPrefix("YP") .setStep(1) .setInitial(80000000L) .setIsRandomStep(false); } } 2、在代码中使用序列 public static String getSaleOrderCode() { Object sequence = CommonApiFactory.getSequenceGenerator().generate(SequenceEnum.ORDERLY_SEQ.value(), SeqConstants.NABEL_SAMPLE_STRUCTURE_SEQ); return TypeUtils.stringValueOf(sequence); } public static String getApplyOrderCode(String prefix) { Object sequence = CommonApiFactory.getSequenceGenerator().generate(SequenceEnum.ORDERLY_SEQ.value(), SeqConstants.NABEL_SAMPLE_APPLY_SEQ); return…

    2024年5月25日
    1.8K00

Leave a Reply

登录后才能评论