Oinone平台之Router扩展

问题描述

在Oinone平台内置路由中,默认了三种路由

/login //默认登录页
/page //默认主逻辑页
/ //根页面,会自动发起查询优先级最高的应用,并跳转

在实际的业务迭代中,我们通常有以下三种需求:

  1. 我要覆盖默认的登录页,页面我不喜欢,登录逻辑满足不了;
  2. 我要在平台上加个帮助中心;
  3. 这个路径不符合我司规范,我要自定义加前缀

接下来,我将在Oinone平台中满足以上场景

覆盖默认路径

以登录页为例

  1. 在项目目录src/main.ts下,添加自定义router
import 'ant-design-vue/dist/antd.css';
import 'element-plus/dist/index.css';

import '@kunlun/vue-ui-antd/dist/kunlun-vue-ui-antd.css';
import '@kunlun/vue-ui-el/dist/kunlun-vue-ui-el.css';

import 'reflect-metadata';
import { VueOioProvider } from '@kunlun/dependencies';
import interceptor from './middleware/network-interceptor';

import './field';
import './view';
import './actions';

VueOioProvider(
  {
    http: {
      url: location.origin,
      callback: interceptor
    },
    browser: {
      title: 'Oinone - 构你想象!',
      favicon: 'https://pamirs.oss-cn-hangzhou.aliyuncs.com/pamirs/image/default_favicon.ico'
    },
    router: [{ path: '/login', widget: 'CustomLogin'}] // 用CustomLogin覆盖默认登录页
  },
  []
);
  1. 定义CustomLogin, 定义方式同书籍中的自定义表单和自定义表格类似,精简版的代码为:
import { RouterWidget, SPI } from "@kunlun/dependencies";

@SPI.ClassFactory(RouterWidget.Token({ widget: 'CustomLogin' })) // SPI注册,router得widget和此处的widgetshi对应的
export class CustomLogin extends RouterWidget {
  public initialize(props) {
    super.initialize(props);
    this.setComponent('定义的vue文件');
    return this;
  }
}

增加新的访问路径

同覆盖登录页

  1. 在router中增加路由
    router: [{ path: '/login', widget: 'CustomLogin'}, { path: '/help', widget: 'Help'}]
  2. 定义Help,同覆盖登录页

定义个性化路径

需要再所有访问路径前统一加标识,比如添加Oinone;
在项目目录下新建.env文件(若存在,可以复用),在env文件中添加:

BASE_PATH=/Oinone

修改后重启工程即可,访问/Oinone/login即可

结语

以上就是Oinone平台路由的扩展能力,在Oinone平台中,通过自定义Router达到扩展路由的能力,并通过采用env等通用配置的能力,解决批量修改路由的目的。

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

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

Like (0)
oinone's avataroinone
Previous 2023年6月20日 pm4:07
Next 2023年11月2日 pm1:58

相关推荐

  • 前端低无一体使用教程

    介绍 客户在使用oinone平台的时候,有一些个性化的前端展示或交互需求,oinone作为开发平台,不可能提前预置好一个跟客户需求一模一样的组件,这个时候我们提供了一个“低无一体”模块,可以反向生成API代码,生成对应的扩展工程和API依赖包,再由专业前端研发人员基于扩展工程(kunlun-sdk),利用API包进行开发并上传至平台,这样就可以在界面设计器的组件里切换为我们通过低无一体自定义的新组件。 低无一体的具体体现 “低”— 指低代码,在sdk扩展工程内编写的组件代码 “无”— 指无代码,在页面设计器的组件功能处新建的组件定义 低无一体的组件跟直接在自有工程内写组件的区别? 低无一体的组件复用性更高,可以在本工程其他页面和其他业务工程中再次使用。 组件、元件介绍 元件 — 指定视图类型(viewType) + 指定业务类型(ttype)字段的个性化交互展示。组件 — 同一类个性化交互展示的元件的集合。组件是一个大一点的概念,比如常用的 Input 组件,他的元件在表单视图有字符串输入元件、密码输入元件,在详情和表格展示的时候就是只读的,页面最终使用的其实是元件。通过组件+ttype+视图类型+是否多值+组件名可以找到符合条件的元件,组件下有多个元件会根据最优匹配规则找到最合适的具体元件。 如何使用低无一体 界面设计器组件管理页面添加组件 进入组件的元件管理页面 点击“添加元件” 设计元件的属性 这里以是否“显示清除按钮”作为自定义属性从左侧拖入到中间设计区域,然后发布 点击“返回组件” 鼠标悬浮到卡片的更多按钮的图标,弹出下拉弹出“低无一体”的按钮 在弹窗内点击“生成SDK”的按钮 生成完成后,点击“下载模板工程” 解压模板工程kunlun-sdk.zip 解压后先查看README.MD,了解一下工程运行要点,可以先运行 npm i 安装依赖 再看kunlun-plugin目录下已经有生成好的组件对应的ts和vue文件 下面在vue文件内增加自定义代码,可以运行 npm run dev 在开发模式下调试看效果 <template> <div class="my-form-string-input"> <oio-input :value="realValue" @update:value="change" > <template #prepend>MyPrepend</template> </oio-input> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; import { OioInput } from '@kunlun/vue-ui-antd'; export default defineComponent({ name: 'customField1', components: { OioInput }, props: { value: { type: String }, change: { type: Function }, }, setup(props) { const realValue = ref<string | null | undefined>(props.value); return { realValue }; } }); </script> <style lang="scss"> .my-form-string-input { border: 1px solid red; } </style> 确定改好代码后运行 npm run build,生成上传所需的js和css文件 可以看到 kunlun-plugin目录下多出了dist目录,我们需要的是 kunlun-plugin.umd.js 和 kunlun-plugin.css 这2个文件 再次回到组件的“低无一体”管理弹窗页面,上传上面生成的js和css文件,并点击“确定”保存,到这里我们的组件就新增完成了。 下面我们再到页面设计器的页面中使用上面设计的组件(这里的表单页面是提前准备好的,这里就不介绍如何新建表单页面了) 将左侧组件库拉直最底部,可以看到刚刚新建的组件,将其拖至中间设计区域,我们可以看到自定义组件的展示结果跟刚刚的代码是对应上的(ps: 如果样式未生效,请刷新页面查看,因为刚刚上传的js和css文件在页面初始加载的时候才会导入进来,刚刚上传的动作未导入新上传的代码文件),再次点击设计区域中的自定义组件,可以看到右侧属性设置面板也出现了元件设计时拖入的属性。 最后再去运行时的页面查看效果,与代码逻辑一致! 注意事项 为什么我上传了组件后页面未生效? 检查前端启动工程的低无一体是否配置正确

    2023年11月6日
    4.1K00
  • 表单页如何在服务端动作点击后让整个表单都处于loading状态

    介绍 在业务场景中,有时候由于提交的数据很多,导致服务端动作耗时较长,为了保证这个过程中表单内的字段不再能被编辑,我们可以通过自定义能力将整个表单区域处于loading状态 自定义动作组件代码 import { ActionType, ActionWidget, BaseElementViewWidget, BaseView, ClickResult, ServerActionWidget, SPI, Widget } from '@kunlun/dependencies'; @SPI.ClassFactory(ActionWidget.Token({ actionType: ActionType.Server })) class LoadingServerActionWidget extends ServerActionWidget { protected async clickAction(): Promise<ClickResult> { const baseView = Widget.select(this.rootHandle) as unknown as BaseView; if (!baseView) { return super.clickAction(); } const baseViewWidget = baseView.getChildrenInstance().find((a) => a instanceof BaseElementViewWidget) as unknown as BaseElementViewWidget; if (!baseViewWidget) { return super.clickAction(); } return new Promise((resolve, reject) => { try { baseViewWidget.load(async () => { const res = await super.clickAction(); resolve(res); }); } catch (e) { reject(false); } }); } } 本案例知识点 BaseElementWidget提供了load方法将继承了该class的元素渲染的区域做整体loading交互,等入参的函数处理完成后恢复正常状态,其实所有继承了ActionWidget的组件也提供了这个能力让按钮在执行函数中的时候处于loading状态, 每个组件都有一个全局唯一的handle值,所在根视图的rootHandle,组件可以用this.rootHandle通过Widget.Select方法查找到所在的根视图组件,从视图的实例化子元素里可以查找到具体的业务类型视图组件,如详情页的DetailWidget、表单页的FormWidget、表格页的TableWidget,拿到这些实例后就可以操作里面的属性和方法了

    2024年5月29日
    2.4K00
  • 前端元数据介绍

    模型 属性名 类型 描述 id string 模型id model string 模型编码 name string 技术名称 modelFields RuntimeModelField[] 模型字段 modelActions RuntimeAction[] 模型动作 type ModelType 模型类型 module string 模块编码 moduleName string 模块名称 moduleDefinition RuntimeModule 模块定义 pks string[] 主键 uniques string[][] 唯一键 indexes string[][] 索引 sorting string 排序 label string 显示标题 labelFields string[] 标题字段 模型字段 属性名 类型 描述 model string 模型编码 modelName string 模型名称 data string 属性名称 name string API名称 ttype ModelFieldType 字段业务类型 multi boolean (可选) 是否多值 store boolean 是否存储 displayName string (可选) 字段显示名称 label string (可选) 字段页面显示名称(优先于displayName) required boolean | string (可选) 必填规则 readonly boolean | string (可选) 只读规则 invisible boolean | string (可选) 隐藏规则 disabled boolean | string (可选) 禁用规则 字段业务类型 字段类型 值 描述 String ‘STRING’ 文本 Text ‘TEXT’ 多行文本 HTML ‘HTML’ 富文本 Phone ‘PHONE’ 手机 Email ‘EMAIL’ 邮箱 Integer ‘INTEGER’ 整数 Long ‘LONG’ 长整型 Float ‘FLOAT’ 浮点数 Currency ‘MONEY’ 金额 DateTime ‘DATETIME’ 时间日期 Date ‘DATE’ 日期 Time ‘TIME’ 时间 Year ‘YEAR’ 年份 Boolean ‘BOOLEAN’ 布尔型 Enum ‘ENUM’ 数据字典 Map ‘MAP’ 键值对 Related ‘RELATED’ 引用类型 OneToOne ‘O2O’ 一对一 OneToMany ‘O2M’ 一对多 ManyToOne ‘M2O’ 多对一 ManyToMany ‘M2M’ 多对多 模型动作 属性名 类型 描述 name string…

    2024年9月21日
    2.4K00
  • 表格页自定义按钮如何获取搜索区域的查询条件

    介绍 在使用 Oinone 平台开发过程中,开发者可能会遇到自定义动作需要获取搜索条件并传递给后端的情况。本文将介绍如何利用 Oinone平台 实现此功能。 技术基础知识 当我们在自定义一个动作的时候要先明确自定义的动作类型是什么样的,在Oinone平台中,分为了如下几个动作: 1: 视图动作2: 服务端动作3: 客户端动作3: URL动作 功能步骤或代码示例 案例1、服务端动作,动作点击时候要拿到搜索内容,然后传递给后端。 import { ActionType, ActionWidget, SPI, ServerActionWidget } from '@kunlun/dependencies'; @SPI.ClassFactory( ActionWidget.Token({ name: 'name', model: 'model', actionType: ActionType.Server }) ) export class MyServerActionWidget extends ServerActionWidget { protected async clickAction() { const rst = this.getSearchRsqlAndQueryParams(); } } 案例2、视图动作点击的时候把搜索内容带到另外一个视图或者弹窗 import { ActionType, ActionWidget, SPI, ServerActionWidget } from '@kunlun/dependencies'; @SPI.ClassFactory( ActionWidget.Token({ name: 'name', model: 'model' }) ) export class MyDialogViewActionWidget extends DialogViewActionWidget { // 继承当前动作原本的class protected async clickAction() { const { queryData } = this.getSearchRsqlAndQueryParams(); this.action.context = queryData super.clickAction() return true } } 在上述代码中,我们自定义了一个服务器动作,并在点击触发函数中调用了getSearchRsqlAndQueryParams方法,该方法会返回一个对象: { rsql: String, // 搜索内容对应的rsql queryData: Object, // 搜索的数据 condition: Condition, // 搜索内容对应的数据结构 queryDataToString: Function // 将搜索内容转成JSON字符串 } 这样我们就可以根据业务场景使用对应的值。 注意事项 1: 确保正确导入所需的依赖包。2: 理解并适当修改代码以满足特定业务需求。 总结 本文介绍了在 Oinone 平台中如何自定义一个服务端动作,并获取搜索条件传递给后端的方法。通过合理利用这些功能,开发者可以更灵活地定制应用程序,满足不同的业务需求。 实践案例 如何自定义点击导出动作绑定指定模板

    2024年3月6日
    1.8K00
  • 从一个方法开始:浅析页面渲染流程

    渲染前的准备 渲染前的准备,在 Vue 渲染框架下,会先安装所有所支持的默认组件,比如 Mask,Header 等,这些组件支持 XML 默认模版的 Vue 框架下的渲染,详情可见 main.ts 中,maskInstall 与 install,这两个函数将平台内部支持的组件进行了注册,随后将整个 Vue 挂载为运行时 App,随后进行初始化。 渲染的起步 OioProvider 方法是整个应用的入口,我们忽略掉一些配置方法,将注意力集中到 initializeServices 从名称中我们可以看出来内部保存的都是初始化服务,其中提供了渲染服务等,我们当前使用的是 Vue 框架,所以当前其渲染的 Root 节点为 Vue, 以此,我们视野可以暂时转移到 admin-base中的 Root.vue以及 RootWidget上, 其实现了整个 Vue 框架下的 Root 节点如何渲染,其中定义了多个 widget,比如登陆页,首页,忘记密码已经重置密码等页面, 在本文中我们着重关注渲染首页的能力,RootWidget将 DefaultMetadataMainViewWidget作为渲染 Props中的 page即首页提供给下层组件使用, 渐入佳境 DefaultMetadataMainViewWidget从名称中可以看到,其为元数据主视图,主要做两件事,1:提供 Mask 的渲染2:提供元数据上下文初始化 该组件主要通过观察路由变化触发上面两个动作,当路由发生变化,该组件 reloadPage将被调用,reloadPage方法通过组装路由参数构成一个唯一 key 向后段查询当前路由所对应的渲染信息, 随后将获取到的信息进行处理,初始化,即 元数据上下文初始化,在初始化后,会将获取到的数据注入到 MetadataViewWidget中, Mask 的渲染 关于 Mask 的渲染,在获取到数据后,将生成 maskTemplate,并将其赋值, DefaultMetadataMainView.vue文件将渲染该模板,并渲染到页面中 数据的变更 当上面两件任务完成后,将开始主视图的渲染,上文提到,DefaultMetadataMainViewWidget只负责 mask 的渲染和上下文的初始化,所以 DefaultMetadataMainViewWidget通过触发事件的方式来实现主视图的渲染, DefaultMetadataMainViewWidget将必要信息作为事件参数触发,MultiTabsContainerWidget接收到 reloadMainViewCallChaining事件后,开启主视图渲染, MultiTabsContainerWidget会刷新运行时上下文,即 refreshRuntimeContext,该方法将尝试查询并通过 createOrUpdateEnterTab方法创建 Tab 页,createOrUpdateEnterTab最终生成一个 MultiTabItem格式的对象,该对象描述了 Tab 的相关信息,随后调用 createTabContainerWidget创建 tab 的容器即新建了一个 MultiTabContainerWidget组件即单个 tab 的容器,随后调用 setActiveTabItem, 并获取其绑定的 Vue 组件,并将其组件放置在 KeepAlive内部,触发更新, 主视图的渲染 MultiTabContainerWidget继承自MetadataViewWidget,当 MetadataViewWidget数据发生变更, 其绑定的 Vue 组件将解析 viewTemplate, 获取到与该模板 dslNodeType想匹配的 Vue 组件,当前例子中为 View.vue,随后 View.vue开始渲染,View.vue文件只是一个纯粹的容器,当 View.vue被挂载时,其内部的 template属性包含了整个页面的描述信息,View.vue需要做的就是将这个 template翻译并渲染成 DOM 展现在浏览器上, 渲染整个页面 当 View.vue被挂载时,其内部的 template属性包含了整个页面的描述信息,View.vue主要做了两个事情,一:将 template 中的 widget转换为组件,二:根据当前的 template信息生成 slot信息, const currentSlots = computed<Slots | undefined>( () => DslRender.fetchVNodeSlots(props.dslDefinition) || (Object.keys(context.slots).length ? context.slots : undefined) ); const renderWidget = createCustomWidget(InternalWidget.View, { …context.attrs, type: props.type || viewType.value, template: props.dslDefinition, metadataHandle: props.metadataHandle || metadataHandle.value, rootHandle: props.rootHandle || rootHandle.value, parentHandle: props.parentHandle || parentHandle.value, slotName: props.slotName, inline: inlineProp } as ViewWidgetProps); 生成这两部分信息后,View.vue会将这两部分挂载到页面上,这两部分从代码中可以看出,主要靠 fetchVNodeSlots,createCustomWidget两个函数, export function createCustomWidget( widget: string, props: CustomWidgetProps ): RenderWidget | undefined public static fetchVNodeSlots(dsl: DslDefinition | undefined, supportedSlotNames?: string[]):…

    2025年3月19日
    1.0K00

Leave a Reply

Please Login to Comment