表格新增空行或者按照数据如何复制行

场景

描述

新增按钮点击后表格出现空行,不带业务数据,需要有行内编辑

如何实现

第一步

在layout目录下新增copyTable组件,组件代码如下

import { BaseElementWidget, SPI, TableWidget, Widget } from '@kunlun/dependencies';
import { OioNotification } from '@kunlun/vue-ui-antd';

@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'copy-table-row' }))
export class CopyTableWidget extends TableWidget {
    @Widget.BehaviorSubContext(Symbol("$$TABLE_COPY_CB"), {})
    private tableCopySub;

    @Widget.BehaviorSubContext(Symbol("$$TABLE_DELETE_CB"))
    private tableDeleteSub;

    @Widget.Reactive()
    @Widget.Provide()
    protected get editorMode(): any {
        return 'manual'
    }

    public async copyRowData(row,currentRow) {
        // 获取vxetable 实例
        const tableRef = this.getTableInstance()!.getOrigin();
        if (tableRef) {
            // 有复制未保存数据,如何处理?
            const insertData = tableRef.getInsertRecords();
            if(insertData.length > 0){
                OioNotification.warning("警告","请检查未保存数据!")
                return;
            }

            const { row: newRow } = await tableRef.insertAt(row,currentRow)
            // 插入一条数据并触发校验, 其中字段名称可以替换
            await tableRef.setEditCell(newRow, 'city')
        }
    }

    public async deleteRowData(row) {
        // 获取vxetable 实例
        const tableRef = this.getTableInstance()!.getOrigin();
        if (tableRef) {
            // 有复制未保存数据,如何处理?
            console.log(row, 'remove row')
            tableRef.remove(row)
            // 插入一条数据并触发校验
        }
    }

    async mounted() {
        super.mounted();
        this.tableCopySub.subject.next({copyCb: (row,currentRow) => this.copyRowData(row,currentRow)})
        this.tableDeleteSub.subject.next({deleteCb: (row) => this.deleteRowData(row)})
    }
}

第二步

在action目录下覆盖新增按钮或者复制行按钮;代码如下

import {ActionWidget, ClickResult, ReturnPromise, SPI, Widget} from "@kunlun/dependencies";

@SPI.ClassFactory(
  ActionWidget.Token({
    model: 'resource.k2.Model0000001211', // 替换对应模型
    name: 'uiView57c25f66fac9439089d590a4ac47f027' // 替换对应action的name
  })
)
export class CopyRow extends ActionWidget{
  @Widget.BehaviorSubContext(Symbol("$$TABLE_COPY_CB"))
  private tableCopySub;

  private tableCopyCb;

  @Widget.Method()
  public clickAction(): ReturnPromise<ClickResult> {
    // 按照某一条数据复制行, 按钮在行内
    // let data = JSON.parse(JSON.stringify(this.activeRecords?.[0]));
    // 复制行删除id
    // if(data) {
    //   delete data.id
    //   delete  data['_X_ROW_KEY']
    // }
    // console.log(data, 'datatatatat')
    // this.tableCopyCb(data,this.activeRecords?.[0])

    // 全局新增,不带默认数据
    this.tableCopyCb({},null)
  }

  mounted() {
    super.mounted()
    this.tableCopySub.subscribe((value) => {
      if(value) {
        // debugger
        this.tableCopyCb = value.copyCb
      }
    })
  }
}

第三步

替换对应的表格layout

// 替换第二个入参的模型和动作
const registerGlobalTableLayout = () => {
    return registerLayout(`<view type="TABLE">
    <pack widget="group">
        <view type="SEARCH">
            <element widget="search" slot="search" slotSupport="field" />
        </view>
    </pack>
    <element widget="actionBar" slot="actionBar" slotSupport="action">
        <xslot name="actions" slotSupport="action" />
    </element>
    <pack widget="group" slot="tableGroup">
        <element widget="copy-table-row" slot="table" slotSupport="field">
            <element widget="expandColumn" slot="expandRow" />
            <xslot name="fields" slotSupport="field" />
            <element widget="rowActions" slot="rowActions" slotSupport="action" />
        </element>
    </pack>
</view>`, { viewType: ViewType.Table, model: 'resource.k2.Model0000001211' }) 
}

registerGlobalTableLayout()

补充

  1. 新增空行后的动作可以根据行内数据配置显隐,比如有无id配置是编辑还是保存
  2. 新增后怎么开启行内编辑?可以进入界面设计器选中表格字段,开启行内编辑,新增行后会默认有行内编辑

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

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

(0)
王海明的头像王海明数式管理员
上一篇 2024年7月12日 pm3:34
下一篇 2024年7月15日 pm3:59

相关推荐

  • 前端日期组件国际化支持方案

    在 oinone 平台中,系统默认支持基础的国际化翻译功能。但由于日期时间组件的国际化依赖对应语言包,而全量引入语言包会显著增加打包体积,因此前端默认仅集成了中、英文的日期时间支持。若需为日期时间组件扩展其他语言(如日语)的国际化支持,需手动导入对应语言包并完成配置,具体步骤如下: 假设我们现在国际化翻译切换成了日语,那么我们在日期时间也要支持日语,那么需要如下操作: 1: 重写 RootWidget 继承平台默认的 RootWidget,SPI 注册条件保持跟平台一致即可覆盖平台默认的RootWidget // CustomRootWidget.ts import { RootComponentSPI, RootWidget, SPIFactory } from '@oinone/kunlun-dependencies'; import Root from './Root.vue'; // 通过SPI注册覆盖平台默认的root组件 @SPIFactory.Register(RootComponentSPI.Token({ widget: 'root' })) export class CustomRootWidget extends RootWidget { public initialize() { super.initialize(); this.setComponent(Root); return this; } } 2: 覆盖 Root 组件的 Vue 文件 自定义的 Vue 文件需负责导入目标语言(如日语)的语言包,并根据当前语言环境动态切换配置。这里需要同时处理 ant-design-vue、element-plus 组件库及 dayjs 工具的语言包,确保日期组件的展示和交互统一适配目标语言。 <!– Root.vue –> <template> <a-config-provider :locale="antLocale"> <el-config-provider :locale="eleLocale"> <match :rootToken="root"> <template v-for="page in pages" :key="page.widget"> <route v-if="page.widget" :path="page.path" :slotName="page.slotName" :widget="page.widget"> <slot :name="page.slotName" /> </route> </template> <route :path="pagePath" slotName="page" :widgets="{ page: widgets.page }"> <slot name="page" /> </route> <route path="/" slotName="homePage"> <slot name="homePage" /> </route> </match> </el-config-provider> </a-config-provider> </template> <script lang="ts"> import { CurrentLanguage, EN_US_CODE, UrlHelper, ZH_CN_CODE } from '@oinone/kunlun-dependencies'; import { ConfigProvider as AConfigProvider } from 'ant-design-vue'; import { ElConfigProvider } from 'element-plus'; import dayjs from 'dayjs'; // 导入ant-design-vue语言包 import enUS from 'ant-design-vue/es/locale/en_US'; import zhCN from 'ant-design-vue/lib/locale/zh_CN'; import jaJP from 'ant-design-vue/lib/locale/ja_JP'; // 新增:日语语言包 // 导入 dayjs的语言包 import 'dayjs/locale/zh-cn'; import 'dayjs/locale/ja'; // 新增:日语语言包 // 导入element-plus语言包 import elEn from 'element-plus/dist/locale/en.mjs'; import elZhCn from 'element-plus/dist/locale/zh-cn.mjs'; import elJaJP from 'element-plus/dist/locale/ja.mjs'; // 新增:日语语言包 import { computed, defineComponent, onMounted,…

    2025年8月13日
    69800
  • 如何自定义指定页面的样式

    可以通过在layout上给页面元素加css的class来解决此问题 import { registerLayout, ViewType } from '@kunlun/dependencies'; export const install = () => { registerLayout( ` <!– 给视图加class –> <view type="FORM" class="my-form-view"> <!– 给动作条组件加class –> <element widget="actionBar" slot="actionBar" class="my-action-bar" slotSupport="action" > <xslot name="actions" slotSupport="action" /> </element> <!– 给表单组件加class –> <element widget="form" slot="form" class="my-form-widget"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> `, { viewType: ViewType.Form, // 页面的模型编码,可在浏览器地址栏的model=xxxx获取 model: 'resource.k2.Model0000000109', // 页面的动作名称,可在浏览器地址栏的action=xxxx获取 actionName: 'uiViewb2de116be1754ff781e1ffa8065477fa' } ); }; install(); 这样我们就可以在浏览器的html标签中查看到给组件加的class,通过加上这个作用域,可以给当前页面写特定样式

    2024年8月16日
    1.3K00
  • 自定义的「视图、字段」调用界面设计器配置的按钮(包含权限控制)

    我们在业务开发中,经常会遇到自定义的视图或字段。有时候期望点击某一块区域的时候,打开一个弹窗或者是跳转新页面亦或者是执行服务端动作(调接口),但是希望这个动作是界面设计器拖拽进来的。 这篇文章详细的讲解了自定义的视图、字段怎么执行界面设计器拖出来的按钮。 自定义视图 1: 先设计一个页面,把对应的动作拖拽进来,可以不需要配置字段2: 将该页面绑定菜单 3: 自定义对应的页面 当我们自定义视图的时候,首先会注册一个视图,下面是我自定义的一个表单视图 registerLayout( `<view type="FORM"> <element widget="actionBar" slot="actionBar"> <xslot name="actions" /> </element> <element widget="MyWidget" slot="form"> <xslot name="fields" /> </element> </view>`, { moduleName: 'ys0328', model: 'ys0328.k2.Model0000000453', actionName: 'MenuuiMenu78ec23b054314ff5a12b4fe95fe4d7b5', viewType: ViewType.Form } ); 我自定义了一个叫做MyWidget的 element,下面是对应的ts代码 @SPI.ClassFactory(BaseElementWidget.Token({ widget: 'MyWidget' })) export class MyWidgetManageWidget extends FormWidget { public initialize(props): this { super.initialize(props); this.setComponent(MyVue); return this; } } 这是对应的 vue 文件: MyVue.vue <template> <div @click="onClick">点击执行动作</div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ props: ['onClick'] }); </script> 这个时候,我希望点击的时候,执行 onClick,会执行对应的动作,这时只需要在对应的 ts 文件中写对应的代码逻辑即可: @SPI.ClassFactory(BaseElementWidget.Token({ widget: 'MyWidget' })) export class MyWidgetManageWidget extends BaseElementWidget { // 获取当前页面所有的按钮 @Widget.Reactive() public get modelActions() { return this.metadataRuntimeContext.model.modelActions || [] } // 用来解析上下文表达式的,如果不需要,可以删除 public executeCustomExpression<T>( parameters: Partial<ExpressionRunParam>, expression: string, errorValue?: T ): T | string | undefined { const scene = this.scene; return Expression.run( { activeRecords: parameters.activeRecords, rootRecord: parameters.rootRecord, openerRecord: parameters.openerRecord, scene: parameters.scene || scene, activeRecord: parameters.activeRecord } as ExpressionRunParam, expression, errorValue ); } // 点击事件 @Widget.Method() public onClick() { // 找到对应的按钮 const action = this.modelActions.find((a) => a.label === '动作的显示名称'); /** * 如果是服务端动作,就执行 executeServerAction */ // executeServerAction(action, 参数对象) // 第二个参数是调用对应的接口传递的参数 /** *…

    2023年11月8日
    1.4K02
  • 左树右表默认选择第一行

    import { BaseElementWidget, Widget, SPI, ViewType, TableSearchTreeWidget } from '@kunlun/dependencies'; @SPI.ClassFactory( BaseElementWidget.Token({ viewType: ViewType.Table, widget: 'tree', model: '改成当前视图的模型' }) ) export class CustomTableSearchTreeWidget extends TableSearchTreeWidget { protected hasExe = false; @Widget.Watch('rootNode.children.length') protected watchRootNode(len) { if (len && !this.hasExe) { this.hasExe = true; const firstChild = this.rootNode?.children?.[0]; if (firstChild) { this.onNodeSelected(firstChild); this.selectedKeys = [firstChild.key]; } } } }

    2024年11月26日
    1.2K00
  • 前端自定义字段与视图最佳方案

    自定义视图获取数据 在某些情况下,oinone 提供的默认视图无法满足需求,这时我们就需要自定义视图。通常,虽然视图的 UI 不足以满足要求,但数据结构是不变的。此时,重点是修改页面 UI,数据的请求与回填可以利用平台默认的能力。 如何实现? 界面设计器的使用 你可以通过界面设计器先配置页面,平台在运行时会根据设计器生成对应的 GraphQL 请求,并自动回填数据。 视图的数据结构 视图的数据类型分为可以分为 Object 跟 List Object 代表当前视图的数据结构是对象 List 代表当前视图的数据结构是数组。 如果我们将 Object 跟 List 分的更细一点就变成了这样: 1: Object: 对象,代表当前视图的数据结构是单个对象,例如:表单视图、详情视图1: List: 对象数组,代表当前视图的数据结构数组,例如:表格视图、卡片视图、画廊视图 视图类型 平台组件 数据属性 表格视图 TableWidget dataSource 画廊视图 GalleryWidget dataSource 表单视图 FormWidget formData 详情视图 DetailWidget formData 自定义视图时,需要先确认当前视图的类型,再通过界面设计器进行页面配置。前端部分只需继承相应的组件,平台底层会自动处理接口数据的获取与回填。 表单视图示例: import Form from './Form.vue'; // 自定义表单视图 @SPI.ClassFactory( BaseElementWidget.Token({ widget: 'custom-form' }) ) export class CustomForm extends FormWidget { public initialize(props: Props) { super.initialize(props); this.setComponent(Form); return this; } } Vue 组件: <template></template> <script lang="ts"> export default defineComponent({ props: { formData: { // 当前表单的数据 type: Object, default: () => ({}) } } }); </script> 自定义layout // 原始的layout模版 <view type="FORM"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> //自定义的layout模版 <view type="FORM"> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> <element widget="custom-form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> </view> 其实就是把 widget="form" 改成 widget="custom-form" 表格视图示例: import Table from './Table.vue'; // 自定义表格视图 @SPI.ClassFactory( BaseElementWidget.Token({ widget: 'custom-table' }) ) export class CustomTable extends TableWidget { public initialize(props: Props) { super.initialize(props); this.setComponent(Table); return this; } } Vue 组件: <template></template> <script…

    2024年10月17日
    1.8K00

Leave a Reply

登录后才能评论