如何在表格的字段内添加动作

介绍

在日常的业务中,我们经常需要在表格内直接点击动作完成一些操作,而不是只能在操作栏中,例如:订单的表格内点击商品名称或者里面的按钮跳转到商品详情页面,这里我们将带来大家来通过自定义表格字段来实现这个功能。

1.编写表格字段组件

组件ts文件TableBtnFieldWidget.ts

import {
  ActionWidget,
  ActiveRecordExtendKeys,
  BaseFieldWidget,
  BaseListView,
  ModelFieldType,
  queryDslWidget,
  queryRowActionBar,
  RowContext,
  SPI,
  TableStringFieldWidget,
  BaseElementListViewWidget,
  ViewType,
  Widget
} from '@kunlun/dependencies';
import { createVNode, VNode } from 'vue';
import { toString } from 'lodash-es';
import TableBtnField from './TableBtnField.vue';

@SPI.ClassFactory(
  BaseFieldWidget.Token({
    viewType: ViewType.Table,
    ttype: [ModelFieldType.String, ModelFieldType.Text],
    // widget: 'StringLink',
    // 以下3行配置代码测试用,生产建议在界面设计器自定义组件,widget填自定义组件的api名称
    model: 'resource.k2.Model0000000109',
    name: 'name'
  })
)
export class TableBtnFieldWidget extends TableStringFieldWidget {
  @Widget.Reactive()
  private get triggerActionLabel() {
    // 界面设计器组件内设计该属性
    return this.getDsl().triggerActionLabel || '更新';
  }

  private getTriggerAction() {
    return this.model.modelActions.find((a) => a.label === this.triggerActionLabel);
  }

  private getTriggerActionWidget(widgetHandle: string, draftId: string, triggerActionLabel: string): ActionWidget | undefined {
    const listView = Widget.select(widgetHandle) as unknown as BaseListView;
    const listWidget = queryDslWidget(listView?.getChildrenInstance(), BaseElementListViewWidget);
    if (!listWidget) {
      return undefined;
    }
    const rowActionBar = queryRowActionBar(listWidget.getChildrenInstance(), draftId);
    const actionWidget = rowActionBar?.getChildrenInstance().find((a) => (a as ActionWidget).action.label === triggerActionLabel);
    return actionWidget as ActionWidget;
  }

  protected clickAction(context: RowContext) {
    const draftId = context.data[ActiveRecordExtendKeys.DRAFT_ID] as unknown as string;
    const actionWidget = this.getTriggerActionWidget(this.getRootHandle()!, draftId, this.triggerActionLabel);
    if (!actionWidget) {
      console.error('未找到action', this.triggerActionLabel);
      return;
    }
    actionWidget.click();
  }

  @Widget.Method()
  public renderDefaultSlot(context: RowContext): VNode[] | string {
    const value = toString(this.compute(context));
    if (value) {
      return [
        createVNode(TableBtnField, {
            value,
            triggerAction: this.getTriggerAction(),
            clickAction: () => this.clickAction(context)
          }
        )
      ];
    }
    return [];
  }
}

组件的vue文件TableBtnField.vue

这里的vue组件是将动作直接以按钮的形式展现,可以根据实际需要给字段内容包裹一个div后直接添加点击事件触发clickAction方法

<template>
  <span>
    {{ value }}
  </span>
  <oio-button type="primary" size="small" @click="clickAction" v-if="triggerAction">{{ triggerAction.label || triggerAction.displayName }}</oio-button>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { RuntimeAction } from '@kunlun/dependencies';
import { OioButton } from '@kunlun/vue-ui-antd';

export default defineComponent({
  components: { OioButton },
  props: { value: String, triggerAction: Object as PropType<RuntimeAction>, clickAction: Function },
  setup(props) {
    return {
    };
  }
});
</script>

2.在界面设计器的设计页面将需要在字段单元格展示的动作拖入到操作栏中,这样我们就可以在字段组件中拿到需要触发的动作的元数据。由于这个动作并不需要在操作栏真的展示,所以再将这个字段设置隐藏。

如果需要跳转到其他模型的页面,可以在动作的属性面板的上下文中配置参数,查看参考文档 页面跳转的时候如何增加跳转参数

如何在表格的字段内添加动作

3.预览页面效果

如何在表格的字段内添加动作

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

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

(0)
nation的头像nation数式员工
上一篇 2024年5月15日 pm7:27
下一篇 2024年5月16日 am10:30

相关推荐

  • oio-select 选择器

    API Select props 参数 说明 类型 默认值 版本 allowClear 支持清除 boolean false autofocus 默认获取焦点 boolean false clearIcon 自定义的多选框清空图标 VNode | slot – disabled 是否禁用 boolean false dropdownClassName 下拉菜单的 className 属性 string – dropdownRender 自定义下拉框内容 ({menuNode: VNode, props}) => VNode | v-slot – filterOption 是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false。 boolean | function(inputValue, option) true getTriggerContainer 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 function(triggerNode) () => document.body menuItemSelectedIcon 自定义当前选中的条目图标 VNode | slot – options options 数据,如果设置则不需要手动构造 selectOption 节点 array<{value, label, [disabled, key, title]}> [] placeholder 选择框默认文字 string|slot – removeIcon 自定义的多选框清除图标 VNode | slot – suffixIcon 自定义的选择框后缀图标 VNode | slot – value(v-model:value) 指定当前选中的条目 string|string[]|number|number[] – 注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select,请尝试使用 getPopupContainer={triggerNode => triggerNode.parentNode} 将下拉弹层渲染节点固定在触发器的父元素中。 事件 事件名称 说明 回调参数 blur 失去焦点的时回调 function change 选中 option,或 input 的 value 变化(combobox 模式下)时,调用此函数 function(value, option:Option/Array<Option>) deselect 取消选中时调用,参数为选中项的 value (或 key) 值,仅在 multiple 或 tags 模式下生效 function(value,option:Option) dropdownVisibleChange 展开下拉菜单的回调 function(open) focus 获得焦点时回调 function inputKeyDown 键盘按下时回调 function mouseenter 鼠标移入时回调 function mouseleave 鼠标移出时回调 function popupScroll 下拉列表滚动时的回调 function search 文本框值变化时回调 function(value: string) select 被选中时调用,参数为选中项的 value (或 key) 值 function(value, option:Option)

    2023年12月18日
    95000
  • oio-drawer抽屉

    屏幕边缘滑出的浮层面板。 何时使用 抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到原任务。 当需要一个附加的面板来控制父窗体内容,这个面板在需要时呼出。比如,控制界面展示样式,往界面中添加内容。 当需要在当前任务流中插入临时任务,创建或预览附加内容。比如展示协议条款,创建子对象。 API 参数 说明 类型 默认值 版本 class 对话框外层容器的类名 string – closable 是否显示左上角的关闭按钮 boolean true closeIcon 自定义关闭图标 VNode | slot destroyOnClose 关闭时销毁 Drawer 里的子元素 boolean false footer 抽屉的页脚 VNode | slot – getTriggerContainer 指定 Drawer 挂载的 HTML 节点 HTMLElement | () => HTMLElement | Selectors ‘body’ height 高度, 在 placement 为 top 或 bottom 时使用 string | number keyboard 是否支持键盘 esc 关闭 boolean true mask 是否展示遮罩 Boolean true maskClosable 点击蒙层是否允许关闭 boolean true placement 抽屉的方向 ‘top’ | ‘right’ | ‘bottom’ | ‘left’ ‘right’ style 可用于设置 Drawer 最外层容器的样式,和 drawerStyle 的区别是作用节点包括 mask CSSProperties – title 标题 string | slot – visible(v-model:visible) Drawer 是否可见 boolean – width 宽度 string | number 378 zIndex 设置 Drawer 的 z-index Number 1000 cancelCallback 点击遮罩层或右上角叉或取消按钮的回调, return true则关闭弹窗 function(e) enterCallback 点击确定回调 function(e)

    2023年12月18日
    1.3K00
  • 组件数据交互基础(v4)

    阅读之前 你应该: 了解DSL相关内容。母版-布局-DSL 渲染基础(v4) 了解SPI机制相关内容。组件SPI机制(v4) 了解组件相关内容。 Class Component(ts)(v4) 组件生命周期(v4) 组件数据交互概述 数据结构设计 数据结构分为三大类,列表(List)、对象(Object)以及弹出层(Popup)。 列表(List):用于多条数据的展示,主要包括搜索(用户端)、自定义条件(产品端)、排序、分页、数据选中、数据提交、数据校验功能。 对象(Object):用于单条数据的展示,主要包括数据提交、数据校验功能。 弹出层(Popup):用于在一块独立的空间展示对应类型的数据。 数据结构与对于的内置视图类型: 列表(List):表格视图(TABLE)、画廊视图(GALLERY) 对象(Object):表单视图(FORM)、详情视图(DETAIL) 数据交互设计原则 组件与组件之间的结构关系是独立的,组件与组件之间的数据是关联的。因此,数据交互整体采用“作用域隔离(View),行为互通(CallChaining),数据互通(ActiveRecords)”这样的基本原则进行设计。实现时,围绕不同视图类型定义了一类数据结构所需的基本属性。 在弹出层进行设计时,使用Submetadata的方式,将包括弹出层在内的所有组件包含在内,以形成新的作用域。 通用属性及方法 属性 rootData:根数据源 dataSource:当前数据源 activeRecords:当前激活数据源 为了在实现时包含所有数据结构,我们统一采用ActiveRecord[]类型为所有数据源的类型,这些数据源在不同类型的视图中表示不同的含义: 列表(List):dataSource为列表当前数据源,activeRecords为列表中被选中的数据。特别的,showDataSource为当前展示的数据源,它是dataSource经过搜索、排序、分页等处理后的数据源,也是我们在组件中真正使用的数据源。 对象(Object):daraSource和activeRecords总是完全一致的,且长度永远为1。因此我们有时也在组件中定义formData属性,并提供默认实现:this.activeRecords?.[0] || {}。 方法 reloadDataSource:重载当前数据源 reloadActiveRecords:重载当前激活数据源 由于底层实现并不能正确判断当前使用的数据类型,因此我们无法采用统一标准的数据源修改方法,这时候需要开发者们自行判断。 重载列表数据源 cosnt dataSource: ActiveRecord[] = 新的数据源 // 重载数据源 this.reloadDataSource(dataSource); // 重置选中行 this.reloadActiveRecords([]); 重载表单数据源 cosnt dataSource: ActiveRecord[] = 新的数据源(数组中有且仅有一项) // 重载数据源 this.reloadDataSource(dataSource); // 此处必须保持相同引用 this.reloadActiveRecords(dataSource); 内置CallChaining(链式调用) 在自动化渲染过程中,我们通常无法明确知道当前组件与子组件交互的具体情况,甚至我们在定义当前组件时,并不需要关心(某些情况下可能无法关心)子组件的具体情况。这也决定了我们无法在任何一个组件中完整定义所需的一切功能。 为了保证组件行为的一致性,我们需要某些行为在各个组件的实现需要做到组件自治。以表格视图为例:当view标签在挂载时,我们无法确定应该怎样正确的加载数据,因此,我们需要交给一个具体的element标签来完成这一功能。当element标签对应的组件发生变化时,只需按照既定的重载方式将数据源提交给view标签即可。 除了保证组件行为的一致性外,我们不能完全的信任第三方框架对组件生命周期的处理顺序。因此,我们还需要对组件行为进行进一步的有序处理。以表格视图为例:我们希望搜索视图(SEARCH)的处理总是在加载数据前就处理完成的,这样将可以保证我们加载数据可以正确处理搜索条件,而这一特性并不随着模板结构的变化而发生变化。 平台内置的CallChaining mountedCallChaining:挂载时钩子; refreshCallChaining:刷新时钩子; submitCallChaining:提交时钩子; validatorCallChaining:验证时钩子; 优先级常量 VIEW_WIDGET_PRIORITY(0):视图组件优先级 FETCH_DATA_WIDGET_PRIORITY(100):数据提供者组件优先级 SUBVIEW_WIDGET_PRIORITY(200):子视图组件优先级 未设置优先级的hook将最后执行,在通常情况下,你无需关心优先级的问题。 注意事项 CallChaining通常不需要手动初始化,仅需通过inject方式获取即可。 CallChaining的hook/unhook方法需要在组件生命周期的mounted/unmounted分别执行,如无特殊情况,一般通过this.path作为挂载钩子的唯一键。 在字段组件中使用mountedCallChaing @Widget.Reactive() @Widget.Inject() protected mountedCallChaining: CallChaining | undefined; protected mountedProcess() { // 挂载时处理 } protected mounted() { super.mounted(); this.mountedCallChaining?.hook(this.path, () => { this.mountedProcess(); }); } protected unmounted() { super.unmounted(); this.mountedCallChaining?.unhook(this.path); } 字段组件的mountedCallChaing并不是必须的,因此我们未进行内置处理。 一般的,当视图数据被加载完成时,字段组件的formData和value等属性,将通过响应式自动获取对应的值,因此在大多数情况下是不需要使用这一特性的。 当我们需要对字段获取的值做进一步初始化处理时,我们将需要使用这一特性。例如TreeSelect组件,必须在初始化时填充树下拉所需的结构化数据,这样才能正确展示对应的值。 当字段组件的mounted方法被执行时,我们还未执行视图数据加载,因此,在我们无法在mounted方法中操作formData和value等属性,只有在mountedCallChaining被view标签执行时,按照执行顺序,此时字段的mountedChaining将在视图数据被加载完成后执行。 数据源持有者和数据源提供者 在设计上,我们通常将view标签设计为数据源持有者,将element标签设计为数据源提供者。 原则上,在一个视图中有且仅有一个数据源提供者。 即:当一个element标签的实现组件通过reloadDataSource方法向view标签设置数据源,我们就称该实现组件为当前view标签的数据源提供者,view标签为数据源持有者。 provider/inject 阅读该章节需要理解vue的依赖注入原理 在实现上,我们通过provider/inject机制将上述通用属性/方法进行交替处理,就可以实现根据模板定义的结构进行隔离和共享功能。 例如dataSource属性的实现: /** * 上级数据源 * @protected */ @Widget.Reactive() @Widget.Inject('dataSource') protected parentDataSource: ActiveRecord[] | undefined; /** * 当前数据源 * @protected */ @Widget.Reactive() private currentDataSource: ActiveRecord[] | null | undefined; /** * 提供给下级的数据源 * @protected */ @Widget.Reactive() @Widget.Provide() public get dataSource(): ActiveRecord[] | undefined { return this.currentDataSource || this.parentDataSource; } 不足的是,由于provider/inject机制特性决定,通过provider提供的属性和方法,在某些情况下可能会进行穿透,导致组件通过inject获取的属性和方法并非是我们所期望的那样,因此,我们仍然需要进行一些特殊的处理,才能正确的处理子视图的数据交互,这一点在对象(Object)类型的视图中会详细介绍。 运行时上下文(metadataHandle/rootHandle) 在之前的文章中,我们知道前端的字段/动作组件渲染和后端元数据之间是密不可分的。 在数据交互方面,后端元数据对于字段类型的定义,将决定从API接口中获取的字段、数据类型和格式,以及通过API接口提交数据到后端时的字段、数据类型和格式。 数据类型和格式可以通过field标签的data属性,获取到经过后端编译的相关字段元数据。 那么,我们该如何决定,当数据提供者向后端发起请求时,应该获取哪些字段呢? 因此,我们设计了RuntimeContext机制,并通过metadataHandle/rootHandle机制,在任何一个组件都可以通过view标签正确获取已经实现隔离的运行时上下文机制。 以表单视图为例,我们来看这样一个经过合并后的完整视图模板: (以下模板所展示的并非实际的运行时的结果,而是为了方便描述所提供的完整视图模板) <view type="FORM"> <element widget="actions"> <action…

    2023年11月1日
    1.7K00
  • oio-switch 开关

    API 参数 说明 类型 默认值 版本 autofocus 组件自动获取焦点 boolean false checked(v-model: checked ) 指定当前是否选中 checkedValue | unCheckedValue false checkedChildren 选中时的内容 slot checkedValue 选中时的值 boolean | string | number true disabled 是否禁用 boolean false loading 加载中的开关 boolean false unCheckedChildren 非选中时的内容 slot unCheckedValue 非选中时的值 boolean | string | number false 事件 事件名称 说明 回调参数 change 变化时回调函数 Function(checked: boolean | string | number, event: Event)

    2023年12月18日
    1.2K00
  • 运行时上下文API文档(v4)

    运行时上下文 RuntimeContext export interface RuntimeContext<Framework = unknown> extends ContextNode<RuntimeContext<Framework>> { /** * 框架实例 */ frameworkInstance: Framework; /** * 路由路径 */ routers: RouterPath[]; /** * 运行时跳转动作(通过跳转动作创建的运行时上下文具备该属性) */ viewAction?: RuntimeViewAction; /** * 运行时字段(通过字段创建的运行时上下文具备该属性) */ field?: RuntimeModelField; /** * 运行时模块 */ module: RuntimeModule; /** * 运行时模型 */ model: RuntimeModel; /** * 运行时视图 */ view: RuntimeView; /** * 视图布局dsl,从运行时视图解析获得 */ viewLayout: DslDefinition | undefined; /** * 视图模板dsl,从运行时视图解析获得 */ viewDsl: DslDefinition | undefined; /** * 视图最终执行dsl,从运行时视图解析获得或根据布局dsl和模板dsl合并生成 */ viewTemplate: DslDefinition; /** * 扩展数据 */ extendData: Record<string, unknown>; /** * 获取模型 * @param model 模型编码 * @return 返回获取的模型和所在的运行时上下文 */ getModel(model: string): GetModelResult | undefined; /** * 获取模型字段 * @param name 字段名称 * @return 返回获取的模型字段和所在的运行时上下文 */ getModelField(name: string): GetModelFieldResult | undefined; /** * 创建字段上下文 * @param field 运行时模型字段 */ createFieldRuntimeContext(field: RuntimeModelField): RuntimeContext; /** * 深度解析模板,创建必要的子运行时上下文 */ deepResolve(): void; /** * 传输上下文参数到指定运行时上下文 * @param runtimeContext 运行时上下文 * @param clone 是否克隆; 默认: true */ transfer(runtimeContext: RuntimeContext, clone?: boolean); /** * 获取请求字段 */ getRequestModelFields(options?: GetRequestModelFieldsOptions): RequestModelField[]; /** * 获取默认值 */ getDefaultValue(): Promise<Record<string, unknown>>; /** * 获取初始值 */ getInitialValue(): Promise<Record<string, unknown>>; } 相关类型声明 export type GetModelResult = { model: RuntimeModel; runtimeContext: RuntimeContext;…

    2023年11月1日
    1.3K00

Leave a Reply

登录后才能评论