集成设计器数据流程、流程设计器可以暴露接口触发

集成设计器数据流程暴露接口触发

需求:在集成设计器配置的连接器、数据流程链接到外部接口,需要可以有一个管理页面,统一管理这些集成配置。比如对接多个医院的挂号系统,希望可以配置好数据流程之后,能够在已经实现的开放接口上,动态的调用集成平台配置的数据流程。

连接器暴露接口触发

  1. 设计连接器资源配置模型。使用业务ID+接口唯一标识+连接器实现连接器资源和业务唯一。

    @Model.model(EipConnectorResourceSetting.MODEL_MODEL)
    @Model(displayName = "连接器资源配置", summary = "连接器资源配置")
    @Model.Advanced(unique = {"hospitalId, interfaceUnique"})
    public class EipConnectorResourceSetting extends IdModel {
    
    public static final String MODEL_MODEL = "hr.simple.EipConnectorResourceSetting";
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field(displayName = "医院", required = true)
    @Field.Relation(relationFields = {"hospitalId"}, referenceFields = {"id"})
    private Hospital hospital;
    
    @Field.Integer
    @Field(displayName = "医院ID", invisible = true)
    private Long hospitalId;
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field.String
    @Field(displayName = "接口唯一标识", required = true)
    private String interfaceUnique;
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field.many2one
    @Field(displayName = "连接器", required = true)
    @Field.Relation(relationFields = {"connectorId"}, referenceFields = {"id"})
    private EipConnector connector;
    
    @Field.Integer
    @Field(displayName = "连接器ID", invisible = true)
    private Long connectorId;
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field.many2one
    @Field(displayName = "连接器接口", required = true)
    @Field.Relation(relationFields = {"integrationInterfaceId"}, referenceFields = {"id"}, domain = "connectorId==${activeRecord.connector.id}")
    private EipConnectorResource connectorResource;
    
    @Field.Integer
    @Field(displayName = "连接器接口ID", invisible = true)
    private Long connectorResourceId;
    }
  2. 开放接口定义,文档参考:https://doc.oinone.top/oio4/9326.html
    外部平台调用开放接口,实现动态调用连接器资源

    @Model.model(HospitalSection.MODEL_MODEL)
    @Model(displayName = "医院科室", summary = "医院科室")
    public class HospitalSection extends IdModel {
    
    public static final String MODEL_MODEL = "net.example.HospitalSection";
    
    @Field(displayName = "科室Code", required = true)
    private String deptCode;
    
    @Field(displayName = "科室名称", required = true)
    private String deptName;
    
    @Field(displayName = "科室描述")
    private String deptDesc;
    }
    @Slf4j
    @Fun
    @Component
    public class TestOpenService {
    
    @Resource
    private TestCommonService testCommonService;
    
    @Function
    @Open(name = "获取科室", path = "test/gainSections")
    @Open.Advanced(httpMethod = "POST")
    public OpenEipResult<List<HospitalSection>> gainSections(IEipContext<SuperMap> context, ExtendedExchange exchange) {
        return new OpenEipResult<>(testCommonService.gainSections(context));
    }
    }
    @Slf4j
    @Component
    public class TestCommonService {
    
    @Resource
    private CustomWorkflowService customWorkflowService;
    
    /**
     * 获取科室
     *
     * @param context 请求上下文
     * @return 科室集合
     */
    public List<HospitalSection> gainSections(IEipContext<SuperMap> context) {
        EipResult<SuperMap> gainSections = executeEipConnector(context, "gainSections");
        if (gainSections.getSuccess()) {
            if (gainSections.getContext().getInterfaceContext().get("DepartmentList")!=null) {
                return JSON.parseArray(JSON.toJSONString(gainSections.getContext().getInterfaceContext().get("DepartmentList")),
                        HospitalSection.class);
    
            }
        }
        String errorCode = gainSections.getErrorCode();
        String errorMessage = gainSections.getErrorMessage();
        // Object result = gainSections.getResult();
        return new ArrayList<>();
    }
        /**
     * 根据请求参数中医院id和参数key-value、接口标识获取连接器
     *
     * @param context         请求上下文
     * @param interfaceUnique 接口标识
     * @return 连接器
     */
    private EipResult<SuperMap> executeEipConnector(IEipContext<SuperMap> context, String interfaceUnique) {
        String hospitalId = Optional.ofNullable(String.valueOf(context.getInterfaceContext().getIteration("hospitalId"))).orElse("");
        String parameterValue = Optional.ofNullable(String.valueOf(context.getInterfaceContext().getIteration("parameterValue"))).orElse("");
        //step1. 获取连接器模型
        EipConnectorResourceSetting interfaceSetting = new EipConnectorResourceSetting()
                .setHospitalId(Long.valueOf(hospitalId)).setInterfaceUnique(interfaceUnique).queryOne();
        if (interfaceSetting == null) {
            throw PamirsException.construct(ExpEnumerate.SYSTEM_ERROR).appendMsg("连接器模型未找到").errThrow();
        }
        //step2. 获取连接器接口
        interfaceSetting.fieldQuery(EipConnectorResourceSetting::getConnectorResource);
        EipConnectorResource connectorResource = interfaceSetting.getConnectorResource();
        if (connectorResource == null) {
            throw PamirsException.construct(ExpEnumerate.SYSTEM_ERROR).appendMsg("连接器接口未找到").errThrow();
        }
        //3. 执行连接器获取结果
        Map<String, Object> params = new HashMap<>();
        params.put("wxValue1", parameterValue);
        return EipExecutor.newInstance().call(connectorResource.getInterfaceName(), params);
    }

数据流程暴露接口触发

  1. 设计数据流程配置模型。使用业务ID+接口唯一标识+连接器实现数据流程配置和业务唯一。

    @Model.model(EipOpenDataflowSetting.MODEL_MODEL)
    @Model(displayName = "数据流程配置", summary = "数据流程配置")
    @Model.Advanced(unique = {"hospitalId,interfaceUnique"})
    public class EipOpenDataflowSetting extends IdModel {
    
    public static final String MODEL_MODEL = "hr.simple.EipOpenDataflowSetting";
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field(displayName = "医院", required = true)
    @Field.Relation(relationFields = {"hospitalId"}, referenceFields = {"id"})
    private Hospital hospital;
    
    @Field.Integer
    @Field(displayName = "医院ID", invisible = true)
    private Long hospitalId;
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field.String
    @Field(displayName = "接口唯一标识", required = true)
    private String interfaceUnique;
    
    @UxTableSearch.FieldWidget(@UxWidget())
    @Field.many2one
    @Field(displayName = "数据流程", required = true)
    @Field.Relation(relationFields = {"dataflowId"}, referenceFields = {"id"})
    private DataflowDesigner dataflow;
    
    @Field.Integer
    @Field(displayName = "数据流程编码", invisible = true)
    private Long dataflowId;
    
    @Field.String
    @Field.Related(related = {"dataflow", "code"})
    @UxForm.FieldWidget(@UxWidget(readonly = "true"))
    @Field(displayName = "数据流程编码", store = NullableBoolEnum.TRUE)
    private String dataflowCode;
    }
  2. 开放接口定义。

    @Fun(RegisterOpenService.FUN_NAMESPACE)
    public interface RegisterOpenService {
    
    String FUN_NAMESPACE = "net.example.RegisterService";
    
    @Function
    RegisterOrder queryById(Long hospitalId, Long memberId);
    }
    @Slf4j
    @Fun(RegisterOpenService.FUN_NAMESPACE)
    @Component
    public class RegisterOpenServiceImpl implements RegisterOpenService {
    
    @Autowired
    private CustomWorkflowService customWorkflowService;
    
    /**
     * 开放接口:把自己的开放出去供外部调用(如:小程序调用)
     *
     * 文档参考:https://doc.oinone.top/oio4/9326.html
     *
     * 1、接口访问URL地址:http://127.0.0.1:8195/openapi/pamirs/register/queryById 端口根据yml配置进行修改
     * 2、参数默认是map格式,构造为IEipContext对象
     */
    @Function
    @Open(name = "根据ID查询挂号流水", path = "register/queryById")
    @Open.Advanced(
            httpMethod = "GET"
    )
    public OpenEipResult<RegisterOrder> queryById4Open(IEipContext<SuperMap> context, ExtendedExchange exchange) {
        String memberId = Optional.ofNullable(String.valueOf(context.getInterfaceContext().getIteration("id"))).orElse("0");
        String hospitalId = Optional.ofNullable(String.valueOf(context.getInterfaceContext().getIteration("hospitalId"))).orElse("0");
        // 开发接口的内部具体实现
        RegisterOrder register = queryById(Long.valueOf(hospitalId), Long.valueOf(memberId));
        if (register!=null) {
            return new OpenEipResult<>(register);
        } else {
            throw PamirsException.construct(EipExpEnumerate.SYSTEM_ERROR).appendMsg("根据ID "+ memberId +"查询挂号流水").errThrow();
        }
    }
    
    @Override
    @Function
    public RegisterOrder queryById(Long hospitalId, Long memberId) {
        // step1、业务前置逻辑、参数校验等
        // step2、构造请求数据、或者通过BD获取数据(这里先进行Mock)
        RegisterOrder register = new RegisterOrder();
        register.setHospitalId("719331903102009889");
        register.setSectionId("1");
        register.setDoctorId("1");
        register.setSourceId("1");
        register.setPatienterName("zhangsan");
        register.setPatienterIdCard("123444");
        // 配置表,医院 + 接口功能 == >> 流程编码。   ****** 实际项目这些基础数据需要缓存,如果Caffeine/Redis*********
        EipOpenDataflowSetting dataflowSetting = new EipOpenDataflowSetting().setHospitalId(hospitalId).setInterfaceUnique("theWeather").queryOne();
        if (dataflowSetting !=  null) {
            // step3、调用数据流程
            WorkflowDefinition workflowDefinition = customWorkflowService.queryWorkflowDefinition(dataflowSetting.getDataflowCode());
            if (workflowDefinition != null) {
                // 分支1:调用数据流程
                Map<String, Object> result = customWorkflowService.startWorkflow(workflowDefinition, register);
                log.info("调用数据流程返回:" + result);
    
                // 根据返回处理业务逻辑
            }
        } else {
            // 分支2:异常处理,或者没有数据流程实现执行默认逻辑
        }
    
        // Step4 业务后置逻辑,数据操作、其他service的调用之类
        return register;
    }
    }
    @Slf4j
    @Component
    public class CustomWorkflowService {
    
    public WorkflowDefinition queryWorkflowDefinition(String workflowCode) {
        return new WorkflowDefinition().queryOneByWrapper(
                Pops.<WorkflowDefinition>lambdaQuery()
                        .from(WorkflowDefinition.MODEL_MODEL)
                        .eq(WorkflowDefinition::getWorkflowCode, workflowCode)
                        .eq(WorkflowDefinition::getActive, 1)
        );
    }
    
    /**
     * 触发⼯作流实例
     */
    public Map<String, Object> startWorkflow(WorkflowDefinition workflowDefinition, IdModel modelData) {
        Map<String, Object> result = new HashMap<>();
        if (null == workflowDefinition) {
            // 流程没有运⾏实例
            return result;
        }
        String model = Models.api().getModel(modelData);
        //⼯作流上下⽂
        WorkflowDataContext wdc = new WorkflowDataContext();
        wdc.setDataType(WorkflowVariationTypeEnum.ADD);
        wdc.setModel(model);
        wdc.setWorkflowDefinitionDefinition(workflowDefinition.parseContent());
        wdc.setWorkflowDefinition(workflowDefinition);
        wdc.setWorkflowDefinitionId(workflowDefinition.getId());
        IdModel copyData = KryoUtils.get().copy(modelData);
        // ⼿动触发创建的动作流,将操作⼈设置为当前用户,作为流程的发起⼈
        copyData.setCreateUid(PamirsSession.getUserId());
        copyData.setWriteUid(PamirsSession.getUserId());
        String jsonData = JsonUtils.toJSONString(copyData.get_d());
        //触发工作流 新增时触发-onCreateManual 更新时触发-onUpdateManual
        Fun.run(WorkflowModelTriggerFunction.FUN_NAMESPACE, "onCreateManualSync", wdc, "1", jsonData);
    
        // 处理返回结果
        Long workflowInstanceId = (Long) wdc.getDataMap().get(WorkflowConstant.WORKFLOW_INSTANCE_ID);
        if (workflowInstanceId !=null) {
            WorkflowInstance workflowInstance = new WorkflowInstance().setId(workflowInstanceId).queryById();
            WorkflowContext workflowContext = workflowInstance.fetchWorkflowContext();
            result = (HashMap)workflowContext.get(ParamNode.PARAM_PREFIX);
        }
    
        return result;
    }
    
    public Map<String,Object> startCreatOrderWorkflow(WorkflowDefinition workflowDefinition, IdModel modelData){
        Map<String, Object> result = new HashMap<>();
        if (null == workflowDefinition) {
            // 流程没有运⾏实例
            return result;
        }
        String model = Models.api().getModel(modelData);
        //⼯作流上下⽂
        WorkflowDataContext wdc = new WorkflowDataContext();
        wdc.setDataType(WorkflowVariationTypeEnum.ADD);
        wdc.setModel(model);
        wdc.setWorkflowDefinitionDefinition(workflowDefinition.parseContent());
        wdc.setWorkflowDefinition(workflowDefinition);
        wdc.setWorkflowDefinitionId(workflowDefinition.getId());
        IdModel copyData = KryoUtils.get().copy(modelData);
        // ⼿动触发创建的动作流,将操作⼈设置为当前用户,作为流程的发起⼈
        copyData.setCreateUid(PamirsSession.getUserId());
        copyData.setWriteUid(PamirsSession.getUserId());
        String jsonData = JsonUtils.toJSONString(copyData.get_d());
        //触发⼯作流 新增时触发-onCreateManual 更新时触发-onUpdateManual
        Fun.run(WorkflowModelTriggerFunction.FUN_NAMESPACE, "onCreateManualSync", wdc, "1", jsonData);
    
        // 处理返回结果
        Long workflowInstanceId = (Long) wdc.getDataMap().get(WorkflowConstant.WORKFLOW_INSTANCE_ID);
        if (workflowInstanceId !=null) {
            WorkflowInstance workflowInstance = new WorkflowInstance().setId(workflowInstanceId).queryById();
            WorkflowContext workflowContext = workflowInstance.fetchWorkflowContext();
            result = (HashMap)workflowContext.get(ParamNode.PARAM_PREFIX);
        }
    
        return result;
    }
    }

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/20972.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
yexiu的头像yexiu数式员工
上一篇 2025年4月17日 pm8:52
下一篇 2025年4月21日 pm3:53

相关推荐

  • Oinone登录扩展:对接SSO(适应于4.7.8及之后的版本)

    适配版本 4.7.8及其之后的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletResponse; /** * * @author shushi * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker = BeanDefinitionUtils.getBean(IUserLoginChecker.class); } return checker.check4login(user); } /** * 重写登录拦截功能 * 该函数主要作用,通过三方权限校验. * @return */ // 版本升级需要修改 @Override public PamirsUserDTO fetchUserIdByReq() { String sessionId =…

    2024年4月2日
    2.1K00
  • 如何使用位运算的数据字典

    场景举例 日常有很多项目,数据库中都有表示“多选状态标识”的字段。在这里用我们项目中的一个例子进行说明一下: 示例一: 表示某个商家是否支持多种会员卡打折(如有金卡、银卡、其他卡等),项目中的以往的做法是:在每条商家记录中为每种会员卡建立一个标志位字段。如图: 用多字段来表示“多选标识”存在一定的缺点:首先这种设置方式很明显不符合数据库设计第一范式,增加了数据冗余和存储空间。再者,当业务发生变化时,不利于灵活调整。比如,增加了一种新的会员卡类型时,需要在数据表中增加一个新的字段,以适应需求的变化。  – 改进设计:标签位flag设计二进制的“位”本来就有表示状态的作用。可以用各个位来分别表示不同种类的会员卡打折支持:这样,“MEMBERCARD”字段仍采用整型。当某个商家支持金卡打折时,则保存“1(0001)”,支持银卡时,则保存“2(0010)”,两种都支持,则保存“3(0011)”。其他类似。表结构如图: 我们在编写SQL语句时,只需要通过“位”的与运算,就能简单的查询出想要数据。通过这样的处理方式既节省存储空间,查询时又简单方便。 //查询支持金卡打折的商家信息:   select * from factory where MEMBERCARD & b'0001'; // 或者:   select * from factory where MEMBERCARD & 1;    // 查询支持银卡打折的商家信息:   select * from factory where MEMBERCARD & b'0010'; // 或者:   select * from factory where MEMBERCARD & 2; 二进制( 位运算)枚举 可以通过@Dict注解设置数据字典的bit属性或者实现BitEnum接口来标识该枚举值为2的次幂。二进制枚举最大的区别在于值的序列化和反序列化方式是不一样的。 位运算的枚举定义示例 import pro.shushi.pamirs.meta.annotation.Dict; import pro.shushi.pamirs.meta.common.enmu.BitEnum; @Dict(dictionary = ClientTypeEnum.DICTIONARY, displayName = "客户端类型枚举", summary = "客户端类型枚举") public enum ClientTypeEnum implements BitEnum { PC(1L, "PC端", "PC端"), MOBILE(1L << 1, "移动端", "移动端"), ; public static final String DICTIONARY = "base.ClientTypeEnum"; private final Long value; private final String displayName; private final String help; ClientTypeEnum(Long value, String displayName, String help) { this.value = value; this.displayName = displayName; this.help = help; } @Override public Long value() { return value; } @Override public String displayName() { return displayName; } @Override public String help() { return help; } } 使用方法示例 API: addTo 和 removeFrom List<ClientTypeEnum> clientTypes = module.getClientTypes(); // addTo ClientTypeEnum.PC.addTo(clientTypes); // removeFrom ClientTypeEnum.PC.removeFrom(clientTypes); 在查询条件中的使用 List<Menu> moduleMenus = new Menu().queryListByWrapper(menuPage, LoaderUtils.authQuery(wrapper).eq(Menu::getClientTypes, ClientTypeEnum.PC));

    2023年11月24日
    1.9K00
  • 如何跳过固定path路径下面所有的按钮权限

    场景: 业务上需要跳过弹窗打开里面的所有按钮权限。 实践: 实现AuthFilterService权限接口。 package pro.shushi.pamirs.top.api.spi; import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.auth.api.spi.AuthFilterService; import pro.shushi.pamirs.boot.web.session.AccessResourceInfoSession; import pro.shushi.pamirs.meta.common.spi.SPI; /** * @author Yexiu at 09:04 on 2024/9/27 */ @Order(88) @Component @SPI.Service public class CustomAuthFilterService implements AuthFilterService { public static final String skipPath = "/top_demo/uiMenuc6238c29bca44250a041691565056a63/ACTION#top.Teacher#uiView2b60cc6daa334c7280cb78207d41addc"; @Override public Boolean isAccessAction(String model, String name) { String path = AccessResourceInfoSession.getInfo().getOriginPath(); if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } @Override public Boolean isAccessAction(String path) { if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } } 可以看到弹窗下面的按钮都不需要权限控制了。

    2025年3月11日
    92100
  • 读写分离

    总体介绍 Oinone的读写分离方案是基于Sharding-JDBC的整合方案,要先具备一些Sharding-JDBC的知识。 [Sharding-JDBC] 读写分离依赖于主从复制来同步数据,从库复制数据后,才能通过读写分离策略将读请求分发到从库,实现读写操作的分流,请根据业务需求自行实现主从配置。 配置读写策略 配置 top_demo 模块走读写分离的逻辑数据源 pamirsSharding。 配置数据源。 为 pamirsSharding 配置数据源以及 sharding 规则。 指定需要被sharding-jdbc接管的模块 指定top_demo模块给 Sharding-JDBC 接管,接管逻辑数据源名为 pamirsSharding pamirs: framework: data: ds-map: base: base top_demo: pamirsSharding 配置数据源 pamirs: datasource: pamirsMaster: driverClassName: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://127.0.0.1:3306/61_pamirs_mydemo_master?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: root password: ma123456 initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true pamirsSlaver: # 从库数据源配置 driverClassName: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://127.0.0.1:3306/61_pamirs_mydemo_slaver?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: root password: ma123456 initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 配置读写数据源及规则 pamirs: sharding: define: data-sources: pamirsSharding: pamirsMaster # 为逻辑数据源pamirsSharding指向主数据源pamirsMaster。 models: "[trigger.PamirsSchedule]": tables: 0..13 rule: pamirsSharding: actual-ds: # 指定逻辑数据源pamirsSharding代理的数据源为pamirsMaster、pamirsSlaver – pamirsMaster – pamirsSlaver # 以下配置跟sharding-jdbc配置一致 replicaQueryRules: – data-sources: pamirsSharding: primaryDataSourceName: pamirsMaster # 写库数据源 replicaDataSourceNames: – pamirsSlaver # 读库数据源 loadBalancerName: round_robin load-balancers: round_robin: type: ROUND_ROBIN # 读写规则

    2025年5月22日
    59700
  • 同一行操作跳转到不同的视图(动态表单)

    背景 实际项目中,存在这样的场景:同一列表中的数据是泛化的数据集合,即数据来源于不同的模型;行操作需要根据来源去向不同的目标页。 如下图,「提报」操作需根据「报表类型」去向不同的表单。 并支持目标弹窗标题和弹框大小的配置。 解决思路 每行记录需要跳转到不同的模型不同视图,增加一个配置页面用于维护源模型和目标模型的调整动作关系; 返回数据的时候,同时返回自定义的动作。 前端自定义实现如上面图例中的「填报」,从返回数据中获取ViewAction并做对应的跳转。 具体步骤 [后端] 建立模型和视图的关系设置的模型 1、创建 模型和视图的关系设置的模型,用于配置列表模型和各记录即目标模型的视图关系 import pro.shushi.oinone.examples.simple.api.proxy.system.SimpleModel; import pro.shushi.oinone.examples.simple.api.proxy.system.SimpleModule; import pro.shushi.pamirs.boot.base.enmu.ActionTargetEnum; import pro.shushi.pamirs.boot.base.model.View; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; /** * 模型和视图的关系设置 * ModelRelViewSetting */ @Model.model(ModelRelViewSetting.MODEL_MODEL) @Model(displayName = "模型和视图的关系设置", summary = "模型和视图的关系设置") @Model.Advanced(unique = {"oModel,model,target,viewType,viewName"}) public class ModelRelViewSetting extends IdModel { public static final String MODEL_MODEL = "examples.custom.ModelRelViewSetting"; @Field.many2one @Field(displayName = "模块") @Field.Relation(relationFields = {"module"}, referenceFields = {"module"}) private SimpleModule moduleDef; @Field.String @Field(displayName = "模块编码", invisible = true) private String module; @Field.many2one @Field(displayName = "源模型") @Field.Relation(relationFields = {"oModel"}, referenceFields = {"model"}) private SimpleModel originModel; @Field.String @Field(displayName = "源模型编码", invisible = true) private String oModel; @Field.many2one @Field(displayName = "目标模型") @Field.Relation(relationFields = {"model"}, referenceFields = {"model"}) private SimpleModel targetModel; @Field.String @Field(displayName = "目标模型编码", invisible = true) private String model; @Field.Enum @Field(displayName = "视图类型") private ViewTypeEnum viewType; @Field.Enum @Field(displayName = "打开方式", required = true) private ActionTargetEnum target; @Field.String @Field(displayName = "动作名称", invisible = true) private String name; @Field.many2one @Field.Relation(relationFields = {"model", "viewName"}, referenceFields = {"model", "name"}, domain = "systemSource=='UI'") @Field(displayName = "绑定页面", summary = "绑定页面") private View view; @Field.String @Field(displayName = "视图/页面", invisible…

    2025年2月19日
    1.0K00

Leave a Reply

登录后才能评论