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

介绍

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

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低代码应用平台体验

Like (0)
nation's avatarnation数式员工
Previous 2024年5月15日 pm7:27
Next 2024年5月16日 am10:30

相关推荐

  • 前端低无一体使用教程

    介绍 客户在使用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日
    3.9K00
  • 如何在多标签页切换时自动刷新视图

    在日常项目中,常常会遇到多视图(Multi-View)标签的场景,用户在切换不同视图时,可能需要刷新当前活动标签内的视图数据或状态。本文将详细解析下面这段代码,并说明如何利用它在视图切换时刷新对应的视图。 下列代码写在ss-boot里面的main.ts import { VueOioProvider } from '@kunlun/dependencies'; import { delay } from 'lodash-es'; VueOioProvider( { … 自己的配置 }, [ () => { setTimeout(() => { subscribeRoute( (route) => { const page = route.segmentParams.page || {}; // 如果不是表格类型,则不刷新(根据自己的需求判断) if (page.viewType !== ViewType.Table) { return; } const { model, action } = page; const multiTabsManager = MultiTabsManager.INSTANCE; delay(() => { const tab = multiTabsManager.getActiveTab(); if (tab?.key && tab.stack.some((s) => s.parameters?.model === model && s.parameters?.action === action)) { multiTabsManager.refresh(tab.key); } }, 200); }, { distinct: true } ); }, 1000); } ] ); 1. VueOioProvider 及其作用 首先,代码通过 VueOioProvider 初始化应用程序或组件,并传入两部分参数: 配置对象:可以根据实际业务需求进行自定义配置; 回调函数数组:这里传入了一个匿名函数,用于在应用初始化后执行额外的逻辑 2. 延时执行与路由监听 在回调函数中,使用了 setTimeout 延时 1000 毫秒执行,目的通常是为了确保其他组件或全局状态已经初始化完毕,再开始进行路由监听。 随后,代码调用 subscribeRoute 来监听路由的变化。subscribeRoute 接收两个参数: 回调函数:每次路由变化时都会触发该函数,并将最新的 route 对象传递给它; 配置对象:此处使用 { distinct: true } 来避免重复的触发,提高性能。 3. 判断视图类型 在路由回调函数内部,首先通过 route.segmentParams.page 获取当前页面的配置信息。通过判断 page.viewType 是否等于 ViewType.Table,代码可以确定当前视图是否为“表格类型”: 如果不是表格类型:则直接返回,不做刷新操作; 如果是表格类型:则继续执行后续刷新逻辑。 这种判断机制保证了只有特定类型的视图(例如表格)在切换时才会触发刷新,避免了不必要的操作 4. 多视图标签的刷新逻辑 当确认当前视图为表格类型后,从 MultiTabsManager 中获取当前活动标签: MultiTabsManager.INSTANCE.getActiveTab() 返回当前活动的标签对象; 如果 key 存在,并且激活的标签内部存储的action跟url一致, 就调用 multiTabsManager.refresh(key) 方法来刷新当前标签内的视图。

    2025年3月13日
    1.6K00
  • 左树右表页面,点击表格的新建按钮,获取选中的树节点

    左树右表页面,点击表格的新建按钮,获取选中的树节点 通过自定义action的方式来实现 新建一个action文件TreeActionWidget.ts import { ActionType, ActionWidget, SPI, ViewActionTarget, RouterViewActionWidget } from '@kunlun/dependencies'; import { OioNotification } from '@kunlun/vue-ui-antd'; @SPI.ClassFactory( ActionWidget.Token({ actionType: [ActionType.View], target: [ViewActionTarget.Router], name: 'uiView0000000000079503' // action对应的name }) ) export class TreeActionWidget extends RouterViewActionWidget { protected async clickAction() { const context = this.rootRuntimeContext.view.context || {}; const activeTreeContext = context.activeTreeContext || null; if (!activeTreeContext) { // 没有选中左侧树 OioNotification.error('', '请选择左侧节点!'); } else { // 选中的时候 (this.action as any).context = activeTreeContext; // 执行原先的action逻辑 super.clickAction(); } } }

    2023年11月1日
    1.9K00
  • 前端自定义左树右表中的树

    在 oinone 平台中,提供了默认的左树右表的视图,用户可以通过界面设计器配置,默认的树视图不一定满足所有需求,尤其当需要自定义功能或复杂的交互时,我们可以通过自定义视图来实现更灵活的展现。 本文将带你一步步了解如何自定义左树右表视图中的树组件。 自定义树视图 1. 使用界面设计器配置视图 首先,我们需要通过界面设计器生成基础的左树右表视图。界面设计器允许用户根据不同需求进行拖拽配置,快速创建可视化界面。 配置完视图之后,我们可以重写左侧的树组件。Oinone 的默认树组件是 TableSearchTreeWidget,通过自定义的方式,我们可以实现更高级的功能。 2. 重写 TableSearchTreeWidget import { BaseElementWidget, SPI, TableSearchTreeWidget, ViewType } from '@kunlun/dependencies'; import CustomTableSearchTree from './CustomTableSearchTree.vue'; @SPI.ClassFactory( BaseElementWidget.Token({ viewType: [ViewType.Table, ViewType.Form], widget: 'tree', model: 'resource.k2.Model0000000100' // 改成自己的模型 }) ) export class CustomTableSearchTreeWidget extends TableSearchTreeWidget { public initialize(props) { super.initialize(props); this.setComponent(CustomTableSearchTree); return this; } } 3. 定义 Vue 树组件 接下来,我们来实现 CustomTableSearchTree.vue 组件。这个组件将处理树的数据加载、节点选中等逻辑。你可以根据项目的需要修改其中的交互逻辑或 UI 设计。 <template> <a-tree :load-data="onLoadData" :tree-data="treeData" @select="onSelected" /> </template> <script lang="ts"> import { OioTreeNode, TreeUtils } from '@kunlun/dependencies'; import { computed, defineComponent } from 'vue'; export default defineComponent({ props: { rootNode: { type: Object }, loadData: { type: Function, required: true }, onSelected: { type: Function, required: true } }, setup(props) { // // 计算树的数据源,使用 TreeUtils 处理 const treeData = computed(() => { return TreeUtils.fillLoadMoreAction([…(props.rootNode?.children || [])]); }); // 异步加载子节点 const onLoadData = async (node) => { return await props.loadData(node.dataRef); }; // 处理节点选中事件 const onSelected = ( selectedKeys: string[], e: { nativeEvent: PointerEvent; node: { dataRef: OioTreeNode }; selected: boolean } ) => { props.onSelected?.(e.node.dataRef, e.selected); }; return { treeData, onLoadData, onSelected }; } }); </script> 4. 自定义…

    2024年10月21日
    3.5K00
  • 前端表格复制

    我们可能会遇到表格复制的需求,也就是表格填写的时候,不是增加一行数据,而是增加一个表格。以下是代码实现和原理分析。 代码实现 在 boot 工程的 main.ts 中加入以下代码 import { registerDesignerFieldWidgetCreator, selectorDesignerFieldWidgetCreator } from '@oinone/kunlun-ui-designer-dependencies'; // 注册无代码组件,将表头分组的无代码组件,注册成字段表格组件 registerDesignerFieldWidgetCreator( { widget: 'DynamicCreateTable' }, selectorDesignerFieldWidgetCreator({ widget: TABLE_WIDGET })! ); DynamicCreateTableWidget 动态添加表格 ts 组件 import { FormO2MTableFieldWidget, Widget, DslDefinition, RuntimeView, SubmitValue, BaseFieldWidget, ModelFieldType, SPI, ViewType, ActiveRecord, uniqueKeyGenerator } from '@oinone/kunlun-dependencies'; import { MyMetadataViewWidget } from './MyMetadataViewWidget'; import DynamicCreateTable from './DynamicCreateTable.vue'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.OneToMany, widget: 'DynamicCreateTable' }) ) export class DynamicCreateTableWidget extends FormO2MTableFieldWidget { public myMetadataViewWidget: MyMetadataViewWidget[] = []; @Widget.Reactive() public myMetadataViewWidgetLength = 0; @Widget.Reactive() public myMetadataViewWidgetKeys: string[] = []; protected props: Record<string, unknown> = {}; public initialize(props) { super.initialize(props); this.props = props; this.setComponent(DynamicCreateTable); return this; } // region 创建动态表格 @Widget.Method() public async createTableWidget(record: ActiveRecord) { const index = this.myMetadataViewWidget.length; const handle = uniqueKeyGenerator(); const slotKey = `MyMetadataViewWidget_${handle}`; const widget = this.createWidget( new MyMetadataViewWidget(handle), slotKey, // 插槽名称 { subIndex: index, metadataHandle: this.metadataHandle, rootHandle: this.rootHandle, automatic: true, internal: true, inline: true } ); this.initDynamicSubview(this.props, widget); widget.setData(record); this.myMetadataViewWidgetLength++; this.myMetadataViewWidgetKeys.push(slotKey); this.myMetadataViewWidget.push(widget); } protected initDynamicSubview(props: Record<string, unknown>, widget: MyMetadataViewWidget) { const { currentViewDsl } = this; let viewDsl = currentViewDsl; if (!viewDsl) { viewDsl = this.getViewDsl(props)…

    2025年7月21日
    94500

Leave a Reply

Please Login to Comment