【前端】项目开发前端知识要点地图

概述

下面整理了目前现有的所有文章,并提供了基本的学习路径。所有使用*标记的文章属于推荐必读文章。

目录

基础篇

入门篇

进阶篇

最佳实践篇

界面设计器实战篇

其他

API文档

Oinone社区 作者:数式-海波原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/51.html

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

Like (0)
数式-海波's avatar数式-海波数式管理员
Previous 2024年5月24日 pm9:11
Next 2024年5月25日 pm4:19

相关推荐

  • 前端 SPI 注册 + 渲染

    在阅读本篇文章之前,您需要学习以下知识点: 1: TS 结合 Vue 实现动态注册和响应式管理 前端开发者在使用 oinone 平台的时候会发现,不管是自定义字段还是视图,对应的 typescript 都会用到@SPI.ClassFactory(参数),然后在对用的class中重写initialize方法`: @SPI.ClassFactory(参数) export class CustomClass extends xxx { public initialize(props) { super.initialize(props); this.setComponent(FormString); return this; } } 本文将带您熟悉 oinone 前端的 SPI 注册机制以及 TS + Vue 的渲染过程。 不管是自定义字段还是视图@SPI.ClassFactory(参数)都是固定写法,区别在于参数不同,这篇文章里面详细描述了参数的定义。 SPI 注册机制 有自定义过字段、视图经验的开发者可能会发现,字段(表单字段)SPI 注册用的是FormFieldWidget.Token生成对应的参数,视图 SPI 注册用的是BaseElementWidget.Token,那么为什么要这样定义呢? 大家可以想象成现在有一个大的房子,房子里面有很多房间,每个房间都有自己的名字,比如FormFieldWidget就是房间的名字,BaseElementWidget也是房间的名字,这样一来我们就可以根据不同的房间存放不同的东西。 下面给大家展示下伪代码实现: class SPI { static container = new Map<string, WeakMap<object, object>>() static ClassFactory(token) { return (target) => { if(!SPI.container.get(token.type)) { SPI.container.set(token.type, new WeakMap()) } const services = SPI.container.get(token.type) services?.set(token, target) } } } class FormFieldWidget { static Token(options) { return { …options, type: 'Field' } } static Selector(options) { const fieldWidgets = SPI.container.get('Field') if(fieldWidgets) { return fieldWidgets.get(options)! } return null } } @SPI.ClassFactory(FormFieldWidget.Token({ viewType: 'Form', ttype: 'String', widget: 'Input' })) class StringWidget { } // 字段元数据 const fieldMeta = { name: "name", field: "name", mode: 'demo.model', widget: 'Input', ttype: 'String', viewType: 'Form' } // 找到对应的widget const widget = FormFieldWidget.Selector({ viewType: fieldMeta.viewType, ttype: fieldMeta.ttype, widget: fieldMeta.widget, }) 在上述代码中,我们主要是做了这么写事情: 1.SPI class class SPI { static container = new Map<string, WeakMap<object, object>>() } SPI 类是一个静态类,用于管理服务的注册和获取。 container 是一个静态属性,类型是 Map,它的键是字符串,值是 WeakMap。这个结构允许我们为每个服务类型(例如,Field)管理多个服务实例。 2.ClassFactory 方法 static ClassFactory(token) { return (target) => { if…

    2024年9月26日
    2.1K00
  • 集成设计器数据流程、流程设计器可以暴露接口触发

    集成设计器数据流程暴露接口触发 需求:在集成设计器配置的连接器、数据流程链接到外部接口,需要可以有一个管理页面,统一管理这些集成配置。比如对接多个医院的挂号系统,希望可以配置好数据流程之后,能够在已经实现的开放接口上,动态的调用集成平台配置的数据流程。 连接器暴露接口触发 设计连接器资源配置模型。使用业务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; } 开放接口定义,文档参考: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;…

    2025年4月21日
    99200
  • 模型定义在数据库中的映射

    模型定义在数据库中的映射 Oinone中通过定义模型来建立数据表,使用注解的方式来使多张表之间的关联。 数据库字段与模型定义字段映射 package pro.shushi.pamirs.top.api.model; 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.base.IdModel; import pro.shushi.pamirs.meta.enmu.DateFormatEnum; import pro.shushi.pamirs.meta.enmu.DateTypeEnum; import pro.shushi.pamirs.meta.enmu.MimeTypeEnum; import java.math.BigDecimal; import java.util.Date; @Model.model(PamirsDemo.MODEL_MODEL) @Model(displayName = “PamirsDemo”) public class PamirsDemo extends IdModel { public static final String MODEL_MODEL = “top.PamirsDemo”; @Field.Binary(mime = MimeTypeEnum.html) @Field(displayName = “二进制类型”) private Byte[] byteType; @Field.Integer @Field(displayName = “整数”) private Long longType; @Field.Float @Field(displayName = “浮点数”) private BigDecimal floatType; @Field.Boolean @Field(displayName = “布尔类型”) private Boolean booleanType; @Field.Enum @Field(displayName = “枚举”) private DataStatusEnum enumType; @Field.String @Field(displayName = “字符串”) private String stringType; @Field.Text @Field(displayName = “多行文本”) private String textType; @Field.Html @Field(displayName = “富文本”) private String richText; @Field.Date(type = DateTypeEnum.DATE, format = DateFormatEnum.DATE) @Field(displayName = “日期类型”) private Date dataType; @Field.Date(type = DateTypeEnum.DATETIME, format = DateFormatEnum.DATETIME) @Field(displayName = “日期时间类型”) private Date dataTimeType; @Field.Money @Field(displayName = “金额”) private BigDecimal amount; } 更多字段基础请参考文档字段基础与复合 多对一的关系映射 例:设计一张教师表,一张科目表,教师表对科目表属于多对一的关系,在教师表中使用科目id管理关联关系。 教师表teacher 科目表professional 那么在Oinone的模型定义中,这两张表定义是这样的; 教师模型 package pro.shushi.pamirs.top.api.model; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; @Model.model(Teacher.MODEL_MODEL) @Model(displayName = “教师”, summary = “教师”) public class Teacher extends IdModel { public static final String MODEL_MODEL = “top.Teacher”; @Field.String @Field(displayName = “教师名字”) private String teacherName; @Field.Integer @Field(displayName = “科目id”) private Long professionalId; @Field(displayName…

    2024年8月16日
    1.6K00
  • 列表页内上下文无关的动作如何添加自定义上下文

    场景 在界面设计器,可以配置当前列表页从上个页面带的上下文参数,现在需要传递这个上下文到下个页面,设计器没有配置入口,我们可以通过自定义改动作来解决 示例代码 import { ActionType, ActionWidget, RouterViewActionWidget, SPI, ViewActionTarget } from '@kunlun/dependencies'; @SPI.ClassFactory( ActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Router], // 模型编码 model: 'module.model', // 动作名称 name: 'actionName' }) ) export class DemoRouterViewActionWidget extends RouterViewActionWidget { protected async clickAction(): Promise<void> { // initialContext内是上个页面传来的上下文,手动将值传递到下个页面的上下文 // 这里假设需要传递的字段名为type this.action.context = { type: this.initialContext.type }; return super.clickAction(); } }

    2024年8月20日
    2.4K00
  • 【界面设计器】自定义字段组件实战——千分位输入框

    阅读之前 此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 业务背景 用户在输入【金额】字段时,实时展示千分位格式。 业务分析 从需求来看,我们需要实现一个【千分位】组件,并且该组件允许在【表单】视图中使用。 扩展实现:该组件虽然仅要求在【表单】中使用,但也可以在【搜索】中使用完全相同的实现,因此这里我们在注册时会增加【搜索】视图,将【千分位】组件应用在【搜索】中。对于【表格】、【详情】和【画廊】来说,该组件是没有【输入】行为的展示组件,在这里我们不进行演示。 准备工作 此处你应该已经在某个业务模型下,可以完整执行当前模型的全部【增删改查】操作。 业务模型定义 (以下仅展示本文章用到的模型字段,忽略其他无关字段。) 名称 API名称 业务类型 是否多值 长度(单值长度) 编码 code 文本 否 128 名称 name 文本 否 128 金额 money 金额 否 – 创建组件、元件 准备工作完成后,我们需要根据【业务背景】确定【组件】以及【元件】相关信息,并在【界面设计器】中进行创建。 以下操作过程将省略详细步骤,仅展示可能需要确认的关键页面。 创建千分位组件 创建千分位元件 启动SDK工程进行组件基本功能开发 (npm相关操作请自行查看SDK工程中内置的README.MD) 关键点详解 数据交互类型的字段组件(以下简称展示组件)与仅展示类型的字段组件(以下简称交互组件)有一些差别。 通常情况下,在展示组件中仅需使用value属性即可展示相关内容。在交互组件中除了value用于展示外,还需使用change、focus以及blur处理用户输入时的基本交互逻辑。 数据交互方法主要功能说明: change方法:当值发生变更时调用,根据字段相关配置将值回填至表单中。 focus方法:当组件获取焦点时调用,记录当前值,并在调用blur方法时进行处理。 blur方法:当前组件失去焦点时调用,根据focus方法记录的值,进行失焦触发逻辑的执行。 这里的三个数据交互方法仅仅是对用户行为的抽象,而并非限定其使用场景。 通常来说,这三个方法的调用顺序为:focus –> change –> blur。 如在日期时间组件中,面板打开时调用了focus方法,面板值发生变更时,调用了change方法,面板关闭时调用了blur方法。 如在地图组件中,选中地图上的某个点时仅会调用change方法,用户交互上并不能体现出focus和blur的行为。因此对于这个组件而言,只会有change方法被执行。 代码实现参考 PS:oio-input-number样式必须升级到4.6.x以上的最新版本才支持 Thousandth.vue <template> <a-input-number class="oio-input-number" :value="inputValue" :formatter="formatter" :parser="parser" @update:value="change" @focus="focus" @blur="blur" /> </template> <script lang="ts"> import { InputNumber as AInputNumber } from 'ant-design-vue'; import { computed, defineComponent } from 'vue'; export default defineComponent({ name: 'Thousandth', components: { AInputNumber }, props: { value: { type: [String, Number] }, change: { type: Function }, focus: { type: Function }, blur: { type: Function } }, setup(props) { const inputValue = computed(() => { return props.value; }); const formatter = (value) => { return `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; const parser = (value) => { return value.replace(/\$\s?|(,*)/g, ''); }; return { inputValue, formatter, parser }; } }); </script> FormMoneyThousandthFieldWidget.ts import { FormFieldWidget, ModelFieldType, SPI, ViewType } from '@kunlun/dependencies'; import Thousandth from './Thousandth.vue'; @SPI.ClassFactory( FormFieldWidget.Token({ viewType: [ViewType.Form, ViewType.Search], ttype: ModelFieldType.Currency, widget:…

    2024年4月19日
    2.0K00

Leave a Reply

Please Login to Comment