如何实现页面间的跳转

介绍

在日常的业务中,我们经常需要在多个模型的页面之间跳转,例如从商品的行可以直接点击链接跳转到类目详情,还有查看该订单发起的售后单列表,这里将给大家展示如何在oinone中如何实现这些功能。

方法一、通过界面设计器的无代码能力配置

表格行跳转到表单页/详情页

  1. 拖入一个跳转动作到表格行,保存动作后,在左侧的动作属性面板底部有个请求配置,里面的上下文属性就是配置跳转参数的地方,点击添加按钮可以增加一行参数
    如何实现页面间的跳转

  2. 点击添加按钮后,可以看到新增了一行,行内有2个输入框,左侧输入框为目标视图模型的字段,右侧输入框为当前视图模型的表达式
    如何实现页面间的跳转

注意 表达式中activeRecord关键字代表当前行的数据对象

“上下文”相关知识点

  • 当前页面的模型和跳转后的页面模型相同的情况下,会字段带上当前行数据的id作为路由参数
  • 上下文是从当前页面跳转到下个页面带的自定义参数
  • 上下文会作为跳转后的页面数据加载函数的入参,后端的该函数需要根据该条件查询到数据返回给前端,典型的例子就是编辑页,根据id查询对象的其他字段信息返回
  • 跳转后页面的数据加载函数可以在动作场景的时候选择加载函数,也可以在页面的加载函数处设置

方法二、通过低代码方式在自定义代码中调用

oinone提供了内置函数executeViewAction实现该功能

import {
  DefaultComparisonOperator,
  executeViewAction,
  QueryExpression,
  RuntimeViewAction,
  ViewActionTarget,
  ViewType
} from '@kunlun/dependencies';

export class JumpActionWidget {

  protected goToObjectView() {
    executeViewAction(
      {
        viewType: ViewType.Form,
        moduleName: 'resource',
        model: 'resource.ResourceCountry',
        name: 'redirectUpdatePage',
        target: ViewActionTarget.Router
      } as RuntimeViewAction,
      undefined,
      undefined,
      {
        // 此处为id参数,目前只有表单和详情页需要
        id: '12223',
        // 此处为上下文参数,context内对象的key是目标页面需要传递的默认值
        context: JSON.stringify({code: 'xxx'}),
        // 此处为跳转后左侧菜单展开选中的配置
        menu: JSON.stringify({"selectedKeys":["国家"],"openKeys":["地址库","地区"]})
      }
    );
  }

  protected goToListView() {
    const searchConditions: QueryExpression[] = [];
    searchConditions.push({
      leftValue: ['countryCode'], // 查询条件的字段
      operator: DefaultComparisonOperator.EQUAL,
      right: 'CN' // 字段的值
    });
    executeViewAction(
      {
        viewType: ViewType.Table,
        moduleName: 'resource',
        model: 'resource.ResourceCity',
        name: 'resource#市',
        target: ViewActionTarget.OpenWindow
      } as RuntimeViewAction,
      undefined,
      undefined,
      {
        // searchConditions相当于domain,不会随页面搜索项重置动作一起被清空
        searchConditions: encodeURIComponent(JSON.stringify(searchConditions)),
        // searchBody的字段会填充搜索区域的字段组件,会随页面搜索项重置动作一起被清空
        searchBody: JSON.stringify({code: 'CN'}),
        menu: JSON.stringify({"selectedKeys":["国家"],"openKeys":["地址库","地区"]})
      }
    );
  }
}

扩展知识点

为什么executeViewAction跳转到的新页面不是入参的moduleName属性对应的模块?
答:跳转后所在的模块优先级为:
  1. 第一个入参的resModuleName属性对应的模块
  2. 执行executeViewAction时所在的模块
  3. 第一个入参的moduleName属性对应的模块
如何快速获取选中菜单的值?
答:先通过页面菜单手动打开页面,然后在浏览器自带调试工具的控制台执行decodeURIComponent(location.href),其中的menu参数就是我们需要的值

如何实现页面间的跳转

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

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

(2)
nation的头像nation数式员工
上一篇 2024年5月13日 pm7:06
下一篇 2024年5月14日 pm2:35

相关推荐

  • 树型表格全量加载数据如何处理

    阅读该文档的前置条件 【界面设计器】树形表格 1.前端自定义表格组件 import { ActiveRecord, BaseElementWidget, Condition, Entity, SPI, TableWidget, ViewType } from '@kunlun/dependencies'; @SPI.ClassFactory( BaseElementWidget.Token({ type: ViewType.Table, widget: ['demo-tree-table'] }) ) export class TreeTableWidget extends TableWidget { // 默认展开所有层级 protected getTreeExpandAll() { return true; } // 关闭懒加载 protected getTreeLazy(): boolean { return false; } public async $$loadTreeNodes(condition?: Condition, currentRow?: ActiveRecord): Promise<Entity[]> { // 树表加载数据的方法,默认首次只查第一层的数据,这里去掉这个查询条件的参数condition,这样就会查所有层级数据 return super.$$loadTreeNodes(undefined, currentRow); } } 2. 注册layout import { registerLayout, ViewType } from '@kunlun/dependencies'; const install = () => { registerLayout( ` <view type="TABLE"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="demo-tree-table" slot="table"> <element widget="expandColumn" slot="expandRow" /> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" slotSupport="action" /> </element> </view> `, { viewType: ViewType.Table, model: "resource.resourceCity", // 变量,需要替换 actionName: "MenuuiMenu6f6005bdddba468bb2fb814a62fa83c6", // 变量,需要替换 } ); }; install();

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

    阅读之前 此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 业务背景 用户在输入【金额】字段时,实时展示千分位格式。 业务分析 从需求来看,我们需要实现一个【千分位】组件,并且该组件允许在【表单】视图中使用。 扩展实现:该组件虽然仅要求在【表单】中使用,但也可以在【搜索】中使用完全相同的实现,因此这里我们在注册时会增加【搜索】视图,将【千分位】组件应用在【搜索】中。对于【表格】、【详情】和【画廊】来说,该组件是没有【输入】行为的展示组件,在这里我们不进行演示。 准备工作 此处你应该已经在某个业务模型下,可以完整执行当前模型的全部【增删改查】操作。 业务模型定义 (以下仅展示本文章用到的模型字段,忽略其他无关字段。) 名称 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日
    1.1K00
  • 表格主题配置(v4)

    TableThemeConfig /** * 表格主题配置 */ export interface TableThemeConfig { border: boolean | string; stripe: boolean; isCurrent: boolean; isHover: boolean; /** * 表格列主题配置 */ column: Partial<TableColumnThemeConfig>; } /** * 表格列主题配置 */ export interface TableColumnThemeConfig { /** * <h3>最小宽度</h3> * <ul> * <li>boolean: enabled column width auto compute</li> * <li>number: using css width (default: px)</li> * <li>string: using css width</li> * <li> * object: auto compute width for label by default function * <ul> * <li>min: min min width (default: 120)</li> * <li>max: max min width (default: 432)</li> * <li>chineseWidth: chinese width (default: 14 -> fontSize: 14px)</li> * <li>otherWidth: non chinese width (default: 9 -> fontSize: 14px)</li> * <li>sortableFixWidth: sortable handle width (default: 40)</li> * <li>nonSortableFixWidth: non sortable fix width (default: 22)</li> * </ul> * </li> * <li>function: auto compute width for label by function</li> * </ul> */ minWidth: boolean | number | string | Partial<TableColumnMinWidthComputeConfig> | TableColumnMinWidthComputeFunction; /** * 操作列 */ operation: { /** * 宽度 (default: 165) */ width?: number | string; /** * 最小宽度 (default: 120) */ minWidth?: number | string; }; } export interface TableColumnMinWidthComputeConfig { min: number;…

    2023年11月6日
    1.1K00
  • 弹窗生命周期实践

    在oinone平台中,弹窗、抽屉是用户界面设计中最为常见的,而对于开发者而言,能够监听弹窗的生命周期事件通常是十分重要的,因为它提供了一个机会去执行一些逻辑。在这篇文章中,我们将深入探讨如何监听弹窗、抽屉生命周期事件,并讨论一些可能的应用场景。 首先,我们来实现一个监听弹窗销毁的事件。 让我们看一下提供的代码片段: // 1: 自定义打开弹窗的动作 @SPI.ClassFactory( BaseActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Dialog], model: 'model', name: 'name' }) ) export class MyDialogViewActionWidget extends DialogViewActionWidget { protected subscribePopupDispose = (manager: IPopupManager, instance: IPopupInstance, action) => { // 自定义销毁弹窗后的逻辑 }; protected mounted() { PopupManager.INSTANCE.onDispose(this.subscribePopupDispose.bind(this)); } protected unmounted() { PopupManager.INSTANCE.clearOnDispose(this.subscribePopupDispose.bind(this)); } } 在上面的代码中,我们自定义了打开弹窗的动作,并且监听了弹窗销毁事件。 让我们逐步解析这段代码: 1: subscribePopupDispose 是一个函数,作为弹窗销毁事件的处理程序。它接收三个参数:manager、instance 和 action。 manager: 弹窗事件管理器 instance: 弹窗实例 action: 操作弹窗的动作,如果是点击弹窗右上角的关闭按钮,那action为null 2: 组件挂载的时候,进行监听. 4: 最后组件销毁的时候需要清除对应的监听 那么,如果监听到弹窗销毁,我们可以执行什么样的逻辑呢? 1: 更新相关组件状态: 弹窗销毁后,可能需要更新其他组件的状态。通过 popupWidget 可以获取到弹窗相关的信息,进而执行一些状态更新操作。 2: 处理弹窗销毁时的数据或动作: 在 subscribePopupDispose 函数中,action 参数含一些关于弹窗销毁时的动作信息,如果是点击弹窗右上角的销毁按钮,那action为null。我们可以根据这些信息执行相应的逻辑,例如更新界面状态、保存用户输入等 3: 触发其他操作: 弹窗销毁后,可能需要触发一些后续操作,比如显示另一个弹窗、发起网络请求等。 完整的生命周期 方法名 功能描述 onPush(fn) 监听 弹出窗口被推入时的事件处理器 clearOnPush(fn) 清除onPush事件的监听 onCreated(fn) 监听 弹出窗口创建时的事件处理器 clearOnCreated(fn) 清除onCreated事件的监听 onOpen(fn) 监听 弹出窗口打开时的事件处理器 clearOnOpen(fn) 清除onOpen事件的监听 onClose(fn) 监听 弹出窗口关闭时的事件处理器 clearOnClose(fn) 清除onClose事件的监听 onDispose(fn) 监听 弹出窗口被销毁时的事件处理器 clearOnDispose(fn) 清除onDispose事件的监听 onDisposeAll(fn) 监听 所有弹出窗口被销毁时的事件处理器 clearOnDisposeAll(fn) 清除onDisposeAll事件的监听 结语 开发者可以更灵活地响应用户操作,提升用户体验。在实际项目中,根据应用需求和设计,可以根据以上优化逻辑定制具体的处理流程。希望这篇文章为你提供了更深入的理解。

    2023年11月17日
    99500
  • 自定义字段组件如何处理vue组件内的表单校验

    介绍 本示例以字符串字段为业务场景,将输入框用element-plus的组件实现了一遍,vue组件内在onMounted生命周期内将ElForm表单实例通过ts组件内提供到props的setFormInstance方法设置到了ts组件的属性formInstance上,这样就可以在ts组件校验方法validator()触发的时候直接调用表单组件实例formInstance的校验方法validate() 适用场景 当前字段存储了动态表单的配置json,vue组件内自行实现了一套表单渲染逻辑,需要在vue组件和ts组件内同时触发校验 参考文档 element-plus表单组件文档 如何编写自定义字段组件的校验逻辑 示例代码 ts组件 import { BaseFieldWidget, FormStringFieldSingleWidget, isValidatorSuccess, ModelFieldType, SPI, ValidatorInfo, ViewType, Widget } from '@kunlun/dependencies'; import { FormInstance } from 'element-plus'; import MyFormStringField from './MyFormStringField.vue'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: [ViewType.Form, ViewType.Search], ttype: ModelFieldType.String, widget: 'Input', model: 'resource.k2.Model0000000109', name: 'code', }) ) export class MyFormStringFieldWidget extends FormStringFieldSingleWidget { public initialize(props) { super.initialize(props); this.setComponent(MyFormStringField); return this; } /** * ElementPlus的表单vue组件实例 * @private */ private formInstance?: FormInstance; @Widget.Method() private setFormInstance(formInstance: FormInstance | undefined) { this.formInstance = formInstance; } /** * 字段校验方法 */ public async validator(): Promise<ValidatorInfo> { const validRes = await this.formInstance?.validate((valid, fields) => {}); console.log('validRes', validRes) if (!validRes) { return this.validatorError('校验失败'); } const res = await super.validator(); if (!isValidatorSuccess(res)) { return res; } if (this.value == null) { return this.validatorSuccess(); } return this.validateLength(this.value); } } vue组件 <template> <ElForm ref="formInstance" :model="model" :rules="rules"> <ElFormItem label="编码" prop="code"> <ElInput v-model="model.code" @input="onValueChange"></ElInput> </ElFormItem> </ElForm> </template> <script lang="ts"> import { defineComponent, reactive, ref, onMounted, watch } from 'vue'; import { ElForm, ElFormItem, ElInput, FormInstance } from 'element-plus'; export default defineComponent({ name: 'MyFormStringField', components: { ElForm, ElFormItem, ElInput }, props: ['value', 'setFormInstance', 'onChange'],…

    2024年9月6日
    1.5K00

Leave a Reply

登录后才能评论