3.3.2 模型的类型

本文会介绍不同类型模型以及其简单的应用场景,方便大家理解不同类型模型的用途

模型分为元模型和业务模型。元数据是指描述应用程序运行所必需的数据、规则和逻辑的数据集;元模型是指用于描述内核元数据的一套模式集合;业务模型是指用于描述业务应用元数据的一套模式集合。

元模型分为模块域、模型域和函数域三个域。域的划分规则是根据元模型定义数据关联关系的离散性来判断,离散程度越小越聚集到一个域。在4.1.4【模块元数据详解】一文中介绍的ModuleDefinition就是元模型。而我们在开发中涉及的就是业务模型

一、模型类型

  • 抽象模型:往往是提供公共能力和字段的模型,它本身不会直接用于构建协议和基础设施(如表结构等)。

  • 传输模型:用于表现层和应用层之间的数据交互,本身不会存储,没有默认的数据管理器,只有数据构造器。

  • 存储模型:存储模型用于定义数据表结构和数据的增删改查(数据管理器)功能,是直接与连接器进行交互的数据容器。

  • 代理模型:用于代理存储模型的数据管理器能力的同时,扩展出非存储数据信息的交互功能的模型。

二、模型定义种类

模型定义就是模型描述,不同定义类型,代表计算描述模型的元数据的规则不同

  • 静态模型定义:模型元数据不持久化、不进行模型定义的计算(默认值、主键、继承、关联关系)

  • 静态计算模型定义:模型元数据不持久化但初始化时进行模型定义计算获得最终的模型定义

  • 动态模型定义:模型元数据持久化且初始化时进行模型定义计算获得最终的模型定义

静态模型定义需要使用@Model.Static进行注解;静态计算模型定义使用@Model.Static(compute=true)进行注解;动态模型定义不注解@Model.Static注解。

三、安装与更新

使用@Model.model来配置模型的不可变更编码。模型一旦安装,无法在对该模型编码值进行修改,之后的模型配置更新会依据该编码进行查找并更新;如果仍然修改该注解的配置值,则系统会将该模型识别为新模型,存储模型会创建新的数据库表,而原表将会rename为废弃表。

如果模型配置了@Base注解,表明在【oinone的设计器】中该模型配置不可变更;如果字段配置了@Base注解,表明在【oinone的设计器】中该字段配置不可变更。

四、基础配置

模型基类

所有的模型都需要继承以下模型中的一种,来表明模型的类型,同时继承以下模型的默认数据管理器(详见3.3.3模型的数据管理器一节)。

  • 继承BaseModel,构建存储模型,默认无id属性。

  • 继承BaseRelation,构建多对多关系模型,默认无id属性。

  • 继承TransientModel,构建临时模型(传输模型),临时模型没有数据管理器,也没有id属性。

  • 继承EnhanceModel,构建数据源为ElasticSearch的增强模型。

快捷继承

  • 继承IdModel,构建主键为id的模型。继承IdModel的模型会数据管理器会增加queryById方法(根据id查询单条记录)

  • 继承CodeModel,构建带有唯一编码code的主键为id的模型。可以使用@Model.Code注解配置编码生成规则。也可以直接覆盖CodeModel的generateCode方法或者自定义新增的前置扩展点自定义编码生成逻辑。继承CodeModel的模型会数据管理器会增加queryByCode方法(根据唯一编码查询单条记录)

  • 继承VersionModel,构建带有乐观锁,唯一编码code且主键为id的模型。

  • 继承IdRelation,构建主键为id的多对多关系模型。

模型继承关系图

3.3.2 模型的类型

图3-3-2-1 模型继承关系图

  • AbstractModel抽象基类是包含createDate创建时间、writeDate更新时间、createUid创建用户ID、writeUid更新用户ID、aggs聚合结果和activePks批量主键列表等基础字段的抽象模型。

  • TransientModel传输模型抽象基类是所有传输模型的基类,传输模型不存储,没有数据管理器。

  • TransientRelation传输关系模型是所有传输关系模型的基类,传输关系模型不存储,用于承载多对多关系,没有数据管理器。

  • BaseModel存储模型基类提供数据管理器功能,数据模型主键可以不是ID。

  • IdModel带id模型抽象基类,在BaseModel数据管理器基础之上提供根据ID查询、更新、删除数据的功能。

  • BaseRelation关系模型抽象基类用于承载多对多关系,是多对多关系的中间模型,数据模型主键可以不是ID。

  • IdRelation带id关系模型抽象基类,在BaseRelation数据管理器基础之上提供根据ID查询、更新、删除数据的功能。

  • CodeModel带code模型抽象基类,提供按配置生成业务唯一编码功能,根据code查询、更新、删除数据的功能。

  • EnhanceModel增强模型,提供全文检索能力。此模型会在4.1.25【框架之搜索引擎】一文中展开介绍。

五、抽象模型(举例)

抽象模型本身不会直接用于构建协议和基础设施(如表结构等),而是通过继承的机制供子模型复用其字段和函数。子模型可以是所有类型的模型。

比如demo模块要管理的一些公共模型字段,我们可以建一个AbstractDemoIdModel和AbstractDemoCodeModel,demo模块中的实体模型就可以继承它们。我们来为demo模块的模型统一增加一个数据状态这么一个字段,用做数据的生效与失效管理。

Step1 引入DataStatusEnum类

pamirs-demo-api的pom.xml包增加依赖,便于引入DataStatusEnum类,当然也可以自己建,这里只是oinone提供了统一的数据记录状态的枚举,以及相应的通用方法,这边就直接引入

<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-core-common</artifactId>
</dependency>

图3-3-2-2 引入通用类库

Step2 修改DemoModule

DataStatusEnum枚举类本身也会做为数据字典,以元数据的方式被管理起来,当一个模块依赖另一个模块的元数据相关对象,则需要改模块的模块依赖定义。为DemoModule增加CommonModule的依赖注解

package pro.shushi.pamirs.demo.api;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.boot.base.ux.annotation.action.UxRoute;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxHomepage;
import pro.shushi.pamirs.core.common.CommonModule;
import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.meta.annotation.Module;
import pro.shushi.pamirs.meta.base.PamirsModule;
import pro.shushi.pamirs.meta.common.constants.ModuleConstants;

@Component
@Module(
        name = DemoModule.MODULE_NAME,
        displayName = "oinoneDemo工程",
        version = "1.0.0",
        dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE}
)
@Module.module(DemoModule.MODULE_MODULE)
@Module.Advanced(selfBuilt = true, application = true)
@UxHomepage(@UxRoute(PetShop.MODEL_MODEL))
public class DemoModule implements PamirsModule {
    public static final String MODULE_MODULE = "demo_core";
    public static final String MODULE_NAME = "DemoCore";

    @Override
    public String[] packagePrefix() {
        return new String[]{ "pro.shushi.pamirs.demo"};
    }
}

图3-3-2-3 定义模块依赖

Step3 新建AbstractDemoCodeModel和AbstractDemoIdModel

并新增AbstractDemoIdModel和AbstractDemoCodeModel分别继承IdModel和CodeModel,实现IDataStatus接口不是必须的,刚好DataStatus有配套的通用逻辑,暂时也先加进去,具体使用会在本文的【代理模型】这段介绍

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.core.common.behavior.IDataStatus;
import pro.shushi.pamirs.core.common.enmu.DataStatusEnum;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.annotation.sys.Base;
import pro.shushi.pamirs.meta.base.common.CodeModel;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;

@Base
@Model.model(AbstractDemoCodeModel.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.ABSTRACT)
@Model(displayName = "AbstractDemoCodeModel")
public abstract class AbstractDemoCodeModel extends CodeModel implements IDataStatus {

    public static final String MODEL_MODEL="demo.AbstractDemoCodeModel";

    @Base
    @Field.Enum
    @Field(displayName = "数据状态",defaultValue = "DISABLED",required = true,summary = "作为基类给每一个继承模型增加一个数据状态字段")
    private DataStatusEnum dataStatus;
}

图3-3-2-4 新建AbstractDemoCodeModel

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.core.common.behavior.IDataStatus;
import pro.shushi.pamirs.core.common.enmu.DataStatusEnum;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.annotation.sys.Base;
import pro.shushi.pamirs.meta.base.IdModel;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;

@Base
@Model.model(AbstractDemoIdModel.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.ABSTRACT)
@Model(displayName = "AbstractDemoIdModel")
public abstract class AbstractDemoIdModel extends IdModel implements IDataStatus {

    public static final String MODEL_MODEL="demo.AbstractDemoIdModel";

    @Base
    @Field.Enum
    @Field(displayName = "数据状态",defaultValue = "DISABLED",required = true,summary = "作为基类给每一个继承模型增加一个数据状态字段")
    private DataStatusEnum dataStatus;
}

图3-3-2-5 新建AbstractDemoIdModel

Step4 修改PetShop的父类

修改PetShop父类从IdMode变更为AbstractDemoIdModel

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import java.sql.Time;

@Model.model(PetShop.MODEL_MODEL)
@Model(displayName = "宠物店铺",summary="宠物店铺")
public class PetShop extends AbstractDemoIdModel {
    public static final String MODEL_MODEL="demo.PetShop";

    @Field(displayName = "店铺名称",required = true)
    private String shopName;

    @Field(displayName = "开店时间",required = true)
    private Time openTime;

    @Field(displayName = "闭店时间",required = true)
    private Time closeTime;
}

图3-3-2-6 修改PetShop的父类

重启看效果

宠物商店的列表页面和修改页面都增加数据状态字段,如下图3-3-2-7及3-3-2-8所示:

3.3.2 模型的类型

图3-3-2-7 宠物商店列表页增加数据状态字段

3.3.2 模型的类型

图3-3-2-8 宠物商店修改页增加数据状态字段

六、存储模型

存储模型用于定义数据表结构和数据的增删改查(数据管理器)功能,是直接与连接器进行交互的数据容器。

PetShop就是一个存储模型,这里就不过多举例子介绍了

七、代理模型(举例)

代理模型是用于代理存储模型的数据管理器能力,同时又可以扩展出非存储数据信息的交互功能的模型。

如果我们PetShop模型要展示创建人昵称?那么就可以建一个PetShopProxy类来完成,代理模型增加的字段都是非存储字段,只用于交互包括展示或提交

Step1 引入PamirsUser类

pamirs-demo-api的pom.xml包增加依赖,便于引入PamirsUser类。

<dependency>
    <groupId>pro.shushi.pamirs.core</groupId>
    <artifactId>pamirs-user-api</artifactId>
</dependency>

图3-3-2-9 引入基础类库user

Step2 新建PetShopProxy模型

新建一个PetShopProxy类继承PetShop,并声明类型为PROXY。同时增加一个creater字段

package pro.shushi.pamirs.demo.api.proxy;

import pro.shushi.pamirs.demo.api.model.PetShop;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ModelTypeEnum;
import pro.shushi.pamirs.user.api.model.PamirsUser;

@Model.model(PetShopProxy.MODEL_MODEL)
@Model.Advanced(type = ModelTypeEnum.PROXY)
@Model(displayName = "宠物店铺代理模型",summary="宠物店铺代理模型")
public class PetShopProxy extends PetShop {

    public static final String MODEL_MODEL="demo.PetShopProxy";

    @Field.many2one
    @Field(displayName = "创建者",required = true)
    @Field.Relation(relationFields = {"createUid"},referenceFields = {"id"})
    private PamirsUser creater;
}

图3-3-2-10 新建PetShopProxy模型

Step3 修改DemoModule

PamirsUser模型隶属于UserModule。为DemoModule增加UserModule的依赖注解,同时修改DemoModule的homepage注解,默认进入PetShopProxy的管理页面

package pro.shushi.pamirs.demo.api;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.boot.base.ux.annotation.action.UxRoute;
import pro.shushi.pamirs.boot.base.ux.annotation.navigator.UxHomepage;
import pro.shushi.pamirs.core.common.CommonModule;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxy;
import pro.shushi.pamirs.meta.annotation.Module;
import pro.shushi.pamirs.meta.base.PamirsModule;
import pro.shushi.pamirs.meta.common.constants.ModuleConstants;
import pro.shushi.pamirs.user.api.UserModule;

@Component
@Module(
        name = DemoModule.MODULE_NAME,
        displayName = "oinoneDemo工程",
        version = "1.0.0",
        dependencies = {ModuleConstants.MODULE_BASE, CommonModule.MODULE_MODULE, UserModule.MODULE_MODULE})
@Module.module(DemoModule.MODULE_MODULE)
@Module.Advanced(selfBuilt = true, application = true)
@UxHomepage(@UxRoute(PetShopProxy.MODEL_MODEL))
public class DemoModule implements PamirsModule {

    public static final String MODULE_MODULE = "demo_core";
    public static final String MODULE_NAME = "DemoCore";

    @Override
    public String[] packagePrefix() {
        return new String[]{ "pro.shushi.pamirs.demo"};
    }
} 

图3-3-2-11 定义模块依赖及修改首页入口

Step4 新增PetShopProxyAction类

为了展示效果覆盖PetShopProxy默认从PetShop继承的数据管理器方法,但对于Action和Function这些这里不展开介绍,具体会3.4【oinone以函数为内在】和3.5【oinone以交互为外在】两章中介绍。

  1. 新建一个PetShopProxyAction类,Model.model设置为PetShopProxy,也就是把所有aciton和function都挂在PetShopProxy这个模型载体上

  2. PetShopProxyAction继承DataStatusBehavior类配套dataStatus使用,定义一个【启用】serverAction,而启用逻辑则复用父类DataStatusBehavior的dataStatusEnable方法。

  3. 覆盖【queryPage】Function,该方法名为前后约定协议中列表查询的默认方法

package pro.shushi.pamirs.demo.core.action;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.core.common.behavior.impl.DataStatusBehavior;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxy;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;

@Model.model(PetShopProxy.MODEL_MODEL)
@Component
public class PetShopProxyAction extends DataStatusBehavior<PetShopProxy> {

    @Override
    protected PetShopProxy fetchData(PetShopProxy data) {
        return data.queryById();
    }
    @Action(displayName = "启用")
    public PetShopProxy dataStatusEnable(PetShopProxy data){
        data = super.dataStatusEnable(data);
        data.updateById();
        return data;
    }

    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<PetShopProxy> queryPage(Pagination<PetShopProxy> page, IWrapper<PetShopProxy> queryWrapper){
        Pagination<PetShopProxy> result = new PetShopProxy().queryPage(page,queryWrapper);
        new PetShopProxy().listFieldQuery(result.getContent(),PetShopProxy::getCreater);
        return result;
    }

}

图3-3-2-12 新增PetShopProxyAction类

Step5 重启看效果

宠物商店的列表页面和修改页面都增加数据状态字段,如下图3-3-24所示:

3.3.2 模型的类型

图3-3-2-13 宠物商店页面效果

多次点击启用会报对应的错误。当然如果场景不需要,则没有必要复用DataStatusBehavior逻辑,也就不需要实现IDataStatus接口了,启动按钮只在禁用状态展示在后续的教程中会学到

3.3.2 模型的类型

图3-3-2-14 启用操作效果

八、传输模型(举例)

由于传输模型没有默认的数据管理器,只有数据构造器,所以在不自定义动作的情况下,传输模型可以打开详情页、新增表单和修改表单和列表页,但是所有的动作全部为窗口动作。传输模型本身不会存储,如果是关联关系字段关联传输模型,可以将传输模型序列化存储在模型的关联关系字段上。因为没有数据管理器,所以传输模型的列表页没有分页能力。

场景举例:如果我们想批量修改PetShop的数据状态,那么我们需要在列表页选中数据记录点击【批量修改】跳转到一个批量修改页面,选择要修改的数据状态,并点确认提交。那么传输模型就可以承载批量修改页面、数据以及操作的载体模型。

Step1 新建PetShopBatchUpdate模型

新建一个PetShopBatchUpdate类继承TransientModel,同时增加petShopList和dataStatus字段用于接收页面传值

package pro.shushi.pamirs.demo.api.tmodel;

import pro.shushi.pamirs.core.common.enmu.DataStatusEnum;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxy;
import pro.shushi.pamirs.meta.annotation.Field;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.base.TransientModel;

import java.util.List;

@Model.model(PetShopBatchUpdate.MODEL_MODEL)
@Model(displayName = "批量修改宠物商店数据状态",summary = "批量修改宠物商店数据状态")
public class PetShopBatchUpdate extends TransientModel {
    public static final String MODEL_MODEL="demo.PetShopBatchUpdate";

    @Field(displayName = "数据状态",required = true)
    private DataStatusEnum dataStatus;

    @Field(displayName = "宠物商店列表",required = true)
    @Field.many2many
    private List<PetShopProxy> petShopList;
}

图3-3-2-15 新建PetShopBatchUpdate模型

Step2 新增PetShopBatchUpdateAction类

传输模型没有默认的数据管理器,只有数据构造器(construct)。

  1. 新建一个PetShopBatchUpdateAction类,Model.model设置为PetShopBatchUpdate,也就是把所有Aciton和Function都挂在PetShopBatchUpdateAction这个模型载体上

  2. 覆盖数据构造器(construct),接收从宠物商店列表多选带过来的数据参数,非PetShopBatchUpdate本模型参数不能放第一个,用List petShopList来接收,进行数据组装逻辑处理,对应数据也是由PetShopBatchUpdate来承载返回给PetShopBatchUpdate的Form编辑页。

  3. 定义一个【确定】serverAction,绑定PetShopBatchUpdate的Form编辑页。点击确定则批量修改Form页面中的宠物商店列表为指定的数据状态

package pro.shushi.pamirs.demo.core.action;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.proxy.PetShopProxy;
import pro.shushi.pamirs.demo.api.tmodel.PetShopBatchUpdate;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.meta.enmu.ViewTypeEnum;

import java.util.List;

@Model.model(PetShopBatchUpdate.MODEL_MODEL)
@Component
public class PetShopBatchUpdateAction {

    @Function(openLevel = FunctionOpenEnum.API)
    @Function.Advanced(type= FunctionTypeEnum.QUERY)
    public PetShopBatchUpdate construct(PetShopBatchUpdate petShopBatchUpdate, List<PetShopProxy> petShopList){
        PetShopBatchUpdate result = new PetShopBatchUpdate();
        //前端传递只有id,补全下数据
        petShopList = FetchUtil.fetchList(petShopList);
        //补全创建者字段
        new PetShopProxy().listFieldQuery(petShopList,PetShopProxy::getCreater);
        result.setPetShopList(petShopList);
        return result;
    }

    @Action(displayName = "确定",bindingType = ViewTypeEnum.FORM,contextType = ActionContextTypeEnum.SINGLE)
    public PetShopBatchUpdate conform(PetShopBatchUpdate data){
        List<PetShopProxy> proxyList = data.getPetShopList();
        for(PetShopProxy petShopProxy:proxyList){
            petShopProxy.setDataStatus(data.getDataStatus());
        }
        new PetShopProxy().updateBatch(proxyList);
        return data;
    }
}

图3-3-2-16 新建PetShopBatchUpdateAction类

Step3 注解式初始化ViewAction窗口动作

在PetShopProxyAction增加类注解,并注释掉DemoModuleMetaDataEditor的viewActionInit方法体代码。用UxRouteButton注解来申明一个ViewAction。更多Ux系列注解详见3.5.4【Ux注解详解】一文

  1. @Model.model(PetShopProxy.MODEL_MODEL),代表UxRouteButton申明viewAction所在模型

  2. @UxRoute.model代表viewAction的resModel,路由的目标模型

@Model.model(PetShopProxy.MODEL_MODEL)
@UxRouteButton(action = @UxAction(name = "demo_petShop_batch_update", label = "批量更新数据状态",contextType = ActionContextTypeEnum.SINGLE_AND_BATCH), value = @UxRoute(model = PetShopBatchUpdate.MODEL_MODEL, viewType = ViewTypeEnum.FORM,openType = ActionTargetEnum.DIALOG,viewName= ViewConstants.Name.formView))
@Component
public class PetShopProxyAction extends DataStatusBehavior<PetShopProxy> {}

图3-3-2-17 在PetShopProxyAction增加类注解

Step4 重启看效果

3.3.2 模型的类型

图3-3-2-18 批量操作效果示意

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9233.html

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

Like (2)
史, 昂's avatar史, 昂数式管理员
Previous 2024年5月23日 am9:49
Next 2024年5月23日 am9:51

相关推荐

  • 4.2.4 框架之网络请求-HttpClient

    oinone提供统一的网络请求底座,基于graphql二次封装 一、初始化 import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); http.setMiddleware() // 必须设置,请求回调。具体查看文章https://shushi.yuque.com/yqitvf/oinone/vwo80g http.setBaseURL() // 必须设置,后端请求的路径 图4-2-4-1 初始化代码示例 二、HttpClient详细介绍 获取实例 import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); 图4-2-4-2 获取实例 接口地址 import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); http.setBaseURL('接口地址'); http.getBaseURL(); // 获取接口地址 图4-2-4-3 接口地址 请求头 import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); http.setHeader({key: value}); 图4-2-4-4 请求头 variables import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); http.setExtendVariables((moduleName: string) => { return customFuntion(); }); 图4-2-4-5 variables 回调 import { HttpClient } from '@kunlun/dependencies'; const http = HttpClient.getInstance(); http.setMiddleware([middleware]); 图4-2-4-6 回调 业务使用-query private http = HttpClient.getInstance(); private getTestQuery = async () => { const query = `gql str`; const result = await this.http.query('module name', query); console.log(result) return result.data[`xx`]['xx']; // 返回的接口,打印出result对象层次返回 }; 图4-2-4-7 业务使用-query 业务使用-mutate private http = HttpClient.getInstance(); private getTestMutate = async () => { const mutation = `gql str`; const result = await this.http.mutate('module name', mutation); console.log(result) return result.data[`xx`]['xx']; // 返回的接口,打印出result对象层次返回 }; 图4-2-4-8 业务使用-mutate 三、如何使用HttpClient 初始化 在项目目录src/main.ts下初始化httpClient 初始化必须要做的事: 设置服务接口链接 设置接口请求回调 业务实战 前文说到自定义新增宠物表单,让我们在这个基础上加入我们的httpClient; 第一步新增service.ts 图4-2-4-8 新增service.ts service.ts import { HttpClient }…

    2024年5月23日
    2.5K00
  • 登录日志

    1. 登录日志 登录日志:记录企业成员/用户登录平台的历史明细,包括登录时间、位置、IP、登录设备、登录平台等信息,登录平台包括:PC Web、小程序、H5、APP。登录日志不需要通过审计规则订阅,平台会记录每位用户的登录日志。 操作支持导出、查看详情。

    2024年6月20日
    1.7K00
  • 1.5 Oinone与行业对比

    随着企业数字化转型的推进,软件公司获得了许多机会。尽管竞争日趋激烈,但由于需求旺盛,各种模式仍在不断涌现。因此,当前市场上存在各种各样的数字化转型解决方案,围绕企业的各个方面展开。每种解决方案都有其优点和缺点。本文将从定位、技术和产品等方面简单比较,帮助您从不同的视角了解Oinone的差异。 1.4.1 整体视角对比 一、与对标公司Odoo的对比 Odoo Oinone 定位 一站式全业务链管理平台:赋能企业信息化升级 一站式低代码商业支撑平台:赋能企业数字化升级 需求变化 关注单一企业的管理、流程、效率的提升 关注企业价值链的网络竞争,围绕外部协同、运营、数据、商业展开 技术更替 关注稳定、安全、功能丰富度 除了稳定、安全、功能丰富度以外,更强调需求响应速度、用户体验、系统承载极限与弹性扩展、智能化 表1-1 Oinone与对标公司Odoo的对比 二、与国内低代码或无代码公司对比 低代码或无代码公司 Oinone 定位 低代码开发工具:提供各类系统模版,基于模版快速搭建和个性化配置。但系统模版无法再升级 平台型SaaS:提供各类系统产品,产品安装后客户可以根据需求进行个性化调整,同时产品永远在线可升级 场景差异 只能支持企业内部人员使用,以完成部门级边缘系统为主,一般多为没有专业软件厂商支撑和强临时性特性 从内外部协同的商业场景出发,关注企业核心业务场景,适应【企业业务在线化后,所有的业务变化与创新都需要通过系统来触达上下游】的时代背景,以敏捷响应业务的变化与创新为目标 技术代差 单表支撑100万数据已是业内天花板 支撑单模型数据过亿,无单点瓶颈。封装互联网架构并且做到单体与分布式的灵活部署,为不同大小公司提供不同技术支撑 表1-2 Oinone与国内低代码/无代码公司对比 1.4.2 从技术角度对比 我们不会与其他无代码平台进行比较,因为它们不能解决业务复杂性的问题。相反,我们将重点介绍三种不同的低代码平台模式(如下图1-8所示)。 第一种模式是最基础的低代码平台,也被称为代码生成器。它通过预定义应用程序模板和必要的配置生成代码,简化了工程搭建并提供了一些基础逻辑。虽然在信息化时代内部流程标准化方面较为适合,但在数字化时代外部协同业务在线的情况下就不那么合适了。因为这种模式不能减少研发难度和提高效率,也无法体现敏捷迭代快速创新的优势。 第二种模式是经典的低代码平台,以元数据为基础,以模型为驱动。当无法满足需要时,通过特定方式将代码以插件的形式注入平台,作为低代码平台的内置逻辑,供设计器使用。它的优点在于降低了研发门槛,当无法满足需求时才需要编写代码。它可以实现企业内部的复杂流程和复杂逻辑,但其性能和工程管理存在局限性。性能问题使其不适合处理互联网化的在线业务,而工程管理问题则使其不适合处理快速变化的业务。这也是许多研发人员反对低代码的核心原因之一,因为研发人员变成了辅助角色,而软件工程是一门需要技术能力的学科,让没有技术能力的人主导是违反常理的。对于软件产品公司来说,产品需要迭代规划,需要多人协作,需要工程化管理。 第三种模式是oinone提出的基于互联网架构的低代码平台,它采用低无一体的设计。首先,oinone屏蔽了互联网架构带来的复杂性。其次,同样以元数据为基础,以模型为驱动,但是元数据的生成方式有两种:一种是使用无代码设计器(与经典低代码相同),另一种是通过代码来描述元数据。通过使用代码来描述元数据,可以无缝地与代码衔接,并在不改变研发习惯的情况下降低门槛、提高效率,并进行工程化管理。 最后总结来说:低无一体不仅仅是指两种模式的结合,还包括两种模式的融合应用方式。具体来说,这种融合应用方式可以分为两种情况: 当开发核心产品时,主要采用低代码开发,无代码设计器作为辅助。这种方式可以提高开发效率和代码质量,同时保证产品的快速迭代和升级。 当需要满足个性化或非产品支持的需求时,主要采用无代码设计器,低代码作为辅助。这种方式可以快速地满足客户需求,并且避免对产品的核心代码产生影响。 简单来说,低代码模式适用于产品的迭代升级,而无代码设计器则适用于满足个性化和非产品支撑的额外需求。低代码和无代码模式在整个软件生命周期中都有各自的价值,在不同场景下可以相互融合,发挥最大的优势。 图1-8 代码生成器、低代码平台与Oinone的优缺点对比 1.4.3 从产品角度对比 产品上的对比,从客户、场景满足度、再次销售三个方面来做简易的对比 一、Oinone vs 数字化软件服务商 客户 满足度 销售 Oinone 一站式商业智能软件,更高性价比、用户体验客户范围:5000万~5亿、5亿~100亿、标杆:100亿~1000亿、1000亿以上 满足企业核心业务需求,并联合伙伴一起满足企业所有需求,无需集成提供统一工作台、数据接口、底层协议,无论基于Oinone的开源框架还是增加其他应用都有很好的扩展性 支持OP+SaaS两种模式,收费方式不同:OP按买断方式进行,SaaS按效果付费跟账号数无关新的模块进行二次销售 数字化软件服务商 针对成熟的大型企业需投入巨大资源和成本客户范围:100亿~1000亿、1000亿以上 满足企业部分需求,无法输出技术标准,无法解决多供应商一起开发的问题,只能通过集成实现对接 OP模式进行销售,通过设置权限来进行来实现二次销售或无法进行二次销售 表1-3 Oinone vs 数字化软件服务商 二、Oinone vs 低代码或无代码行业 客户 满足度 销售 Oinone 一站式商业智能软件客户范围:5000万~5亿、5亿~100亿、标杆:100亿~1000亿、1000亿以上 从外部商业场景出发,强业务场景驱动,符合企业从信息化管理到业务创新的数字化转变的趋势。提供统一工作台、数据接口、底层协议,无论基于oinone的开源框架还是增加其他应用都有很好的扩展性 支持OP+SaaS两种模式,收费方式不同:OP按买断方式进行,SaaS按效果付费跟账号数无关新的模块进行二次销售 低代码或无代码公司 针对小微企业内部信息化管理诉求,以表单流程为主客户范围:5亿以下 满足企业部门级信息化的适应性需求,无法满足企业核心业务管理与业务创新诉求 按应用模块进行收费,新的模块进行二次销售 表1-4 Oinone vs 低代码或无代码行业 三、Oinone vs 国外对标公司Odoo 客户 满足度 销售 Oinone 一站式商业智能软件客户范围:5000万~5亿、5亿~100亿、标杆:100亿~1000亿、1000亿以上 从外部商业场景出发,强业务场景驱动,符合企业从信息化管理到业务创新的数字化转变的趋势。基线产品覆盖:采购、营销、服务、销售、交易等企业商业领域。主要涉及行业:零售品牌。其他领域或行业靠合作伙伴共建方式进行 支持OP+SaaS两种模式,收费方式不同:OP按买断方式进行,SaaS按效果付费跟账号数无关新的模块进行二次销售 Odoo 一站式企业管理软件客户范围:5000万~5亿、5亿~100亿、标杆:100亿~1000亿、1000亿以上 从企业内部管理需求出发,逐渐拥有互联网相关应用组件,但还是属于强内部管理、弱外部场景。基线产品覆盖:业务财务一体化、人财务、进销存。主要涉及行业:建造业。其他领域或行业靠合作伙伴共建方式进行 支持OP+SaaS两种模式,收费方式相同:按用户数+应用模块进行收费新的模块进行二次销售 表1-5 Oinone vs 国外对标公司Odoo

    2024年5月23日
    3.0K20
  • 2.4.3 Oinone独特性之低无一体

    当今企业软件开发行业,低代码和无代码已经成为热门话题。它们的优势很明显:加速软件开发周期、减少代码开发时间、降低开发成本、易于维护等等。而 Oinone 作为一个低无一体的开发平台,更是在这些优势上做出了巨大的创新。 技术亮点 低代码-在不改变研发习惯的前提下,提升效率降低难度(如下图2-15所示) 一、提高专业开发人员效率 低代码开发模式大大降低了繁琐、重复的工作,模型定义完后,数据 API、数据管理器、基础管理的界面都不需要再进行开发。同时,低代码模式让分布式微服务架构的系统开发变得简单,研发人员不需要考虑分布式部署能力和大数据能力,也不需要去关心一些业务无关的通用能力,如权限、导入导出、国际化翻译、消息、审计等。这样,开发人员可以专注于业务研发,从而大幅提高开发效率。 二、提升系统扩展性 在研发标品的时候,低代码模式让开发人员不再需要关心系统的扩展性。与传统模式不同,低代码模式更加注重元数据的管理,这样就可以更好地保障系统扩展性。 三、保留研发人员习惯 Oinone 平台非常开放,满足开发人员的各种习惯,比如原有的 IDE 环境、熟悉的 Spring Boot 工程结构等。而且在 Oinone 的低代码模式下,研发人员还可以通过无代码方式,在线可视化地修改应用。这样,即使在使用低代码模式的情况下,开发人员也可以保留原有的习惯,提升开发效率。 四、提供更加开放的解决方案 Oinone 提供了非常开放的解决方案,让开发人员可以自由定制和组合各种功能。当行业出现特殊的功能需求时,开发人员可以整合成平台组件,并集成到应用中。Oinone的低代码模式具有高度的开放性和灵活性,这使得它在与其他低代码平台的比较中具有明显的优势。相比其他低代码平台,Oinone不会在无法满足特定需求的情况下限制开发人员的创造力(如下图2-16所示)。 图2-15 Oinone低代码特性介绍 图2-16 Oinone低代码的被集成特性示意图 无代码-五大设计器覆盖研发方方面面,让业务、实施也能参与 它是LCDP的产品化呈现,是冰山露在外面大家看得到的,核心还是在LCDP本身。这部分实时在演进迭代,如您有想体验最新版本,可以在Oinone官网:https://www.oinone.top注册。 设计器 说明 产品展示 模型设计器 1.以模型为驱动,当有模型、数据字典、数据编码等设计功能,我们就可以完整地定义产品数据模型,模型设计器默认整体呈现区别于普通ER图,以当前模型为核心视角展开,可以点击关联模型切换主视角。2.多种模式可切换:专家与经典切换,图与表模式的切换 界面设计器 1.界面设计器旨在帮助用户快速搭建页面;2.所见即所得和根据不同视图类型设计契合的搭建交互就变得尤为重要;3.多端页面设计能力。 流程设计器 1.为业务流程和审批流程提供可自动执行的流程模型,通过定义流转过程中的各个动作、规则,以此实现流程自动化;2.流程可以跨应用设计,不同应用的模型之间可以通过同一流程执行。 逻辑设计器 1.组件化、可视化逻辑编排,逻辑动态变更、动态管理,实施验证。 数据可视化 1.从内部系统模型获取数据内容后,根据业务需求自定义图表,目的是为企业提供更高效的数据分析工具;2.可以智取业务系统模型,系统自动解析选择的模型、接口、表格中的字段后进行数据分析;3.降低对数据分析人员的研发能力要求,提升数据分析的效率 表2-3 Oinone无代码-五大设计器简述 真正的低无一体,体现在一体化的融合能力上 在开发核心产品时,我们主要采用低代码开发,辅以无代码的开发方式。你可以参考我们的低代码开发基础入门教程中3.5.5【设计器的结合】的文章。 而在实施或者处理临时需求时,我们主要采用无代码的开发方式,低代码作为辅助。这种模式比较特殊,只在SaaS模式下提供。如果你发现某个客户个性化部分无法通过无代码设计器完成,我们提供了一个“低无一体”模块,可以反向生成API代码,生成对应的扩展工程和API依赖包,再由专业研发人员基于扩展工程,利用API包进行开发并上传至平台,可以参考关于7.4【Oinone的低无一体】的文章。 场景 融合形式 具体操作 标准产品以低代码开发为主,以无代码为辅助 标品开发时结合无代码设计器来完成页面开发,可以把设计后的页面元数据装载为标准产品的一部分。详细教程见:3.5.5【设计器的结合】一文 项目交付以无代码为主,以低代码为辅助 当有特殊需求设计器无法支持时,则可以通过低无一体应用的代码模式来完成。支持了两种使用模式:上传jar包模式、源码托管模式。详细教程见:7.4【Oinone的低无一体】一文 表2-4 不同场景适配方式说明 实现原理 本章节我们将从以下三个方面来解读Oinone的低无一体。 一:低无一体的设计原则及好处:真正的低无一体平台应该确保标准产品迭代与个性化保持独立,让软件企业具备为客户提供在线化的快速响应、个性化定制、持续更新等服务的能力,让企业客户能够真正自主做到敏捷响应和快速创新。所以Oinone的元数据融合方案跟其他平台有所区别(如下图2-17所示)。 图2-17 Oinone与其他平台的元数据融合对比图 二:低无一体中低与无的关系:无代码是低代码平台的图形化呈现,是低代码的一个子集,它将无限接近低代码的能力,同时也将成为低代码平台的必备特征,是通过低代码开发的标准产品的二开配套工具。 三:低无一体中低与无的定位:通过表2-3可以看出,低代码和无代码在Oinone的体系中相互融合,共同构成了一个完整的低无一体模式,提供更加开放、灵活和可扩展的解决方案,让用户能够更加轻松地完成开发和实施。 低代码模式 无代码模式 用户群体 专业研发 产品经理、需求分析师、直接业务人员 支撑场景 企业全场景软件以及二开 企业全场景软件以及二开,专业化场景比较高的则需低代码支持 核心能力 不改变研发习惯,提升研发效率 可视化编程无需专业编程语言知识 核心定位 开发标准模块 标准模块的二开无标品支撑场景的新模块开发 表2-3 Oinone低代码开发平台的两种开发模式对比

    2024年5月23日
    2.5K00
  • 用户中心

    1. 创建用户 进入用户中心应用,在用户列表中点击创建。 填写表单中的必填信息。 若未设置昵称,则右上角头像右侧展示名称。若设置了昵称,则右上角头像右侧展示昵称。 是否激活账号选择是,选择否时用户登录会显示“未找到首页”。 角色分组中,选择创建的用户的角色,默认选择了超级管理员(包含所有权限)。 点击确定,用户创建完成。 用户登录时可用登录账号/邮箱/手机号登录。 2. 用户相关操作 表格页中包含常规的搜索、批量删除功能。 冻结:当将“是否有效”状态为“是”时展示,将用户“是否有效”修改为“否”。 解冻:当将“是否有效”状态为“否”时展示,将用户“是否有效”修改为“是”。 修改:进入用户信息修改页面,“编码、登录账号、注册时间”只读。 重置密码:点击后在弹窗“账号确认”中输入账号,点击重置密码后,展示新密码。

    2024年6月20日
    3.3K00

Leave a Reply

Please Login to Comment