本文介绍了在前端界面上实现树形单据体控件的新增分录并填充数据的详细过程。首先明确了树形单据体控件的编程模型和特点,然后通过两种方案(批量填充数据包和通过接口新增/插入行)展示了如何在页面加载和工具栏按钮点击时填充树形单据体数据。方案一适用于批量数据赋值,性能更优,并强调了id和pid字段的重要性。同时指出了苍穹缓存不同步和控件视图不更新的问题及解决方案。方案二适用于数据量小的场景,要求确保行号的正确性。最后,提醒了将单据体控件的“缺省行数”设为0以及参考资料的获取途径。
关键词:树形单据体
一、需求
树形单据体控件在前端界面上新增分录并填充数据。
二、思路与方案
在 控件使用指南——树形单据体 中,明确指出单据体是单据体的一种特例,会将单据体以父子层级的样式去展示。其控件编程模型类为kd.bos.form.control.TreeEntryGrid,派生自表格控件基类kd.bos.form.control.AbstractGrid,并提供了诸多方法和事件。
三、实现过程
为简化案例,本文将固定设置树形单据体只包含一个文本字段(层级/kdec_hierarchy),并只展示 3 层节点数据,且每层节点只有 3 条业务数据。
1. 新建单据页面(案例单据(树形单据体)/kdec_treeentrybill),其设计器界面如下图所示。
注意:
单据体控件的业务属性“缺省行数”设置为0。
2. 编写单据插件,响应事件 afterCreateNewData(EventObject) 以实现页面加载时自动为树形单据体填充数据,响应事件 itemClick(ItemClickEvent) 以实现点击工具栏按钮时为树形单据体填充数据。
@Override public void afterCreateNewData(EventObject e) { this.treeEntryEntitySetVal1(); // this.treeEntryEntitySetVal2(); super.afterCreateNewData(e); } @Override public void itemClick(ItemClickEvent evt) { String itemKey = evt.getItemKey(); if (StringUtils.equalsIgnoreCase("kdec_bartest", itemKey)) { // this.treeEntryEntitySetVal1(); // 点击事件之后需更新树形单据体控件视图 // this.getView().updateView(KEY_TREEENTRYENTITY); } super.itemClick(evt); }
3.1 方案一
通过设置表单数据包来实现批量填充树形单据体数据。
private void treeEntryEntitySetVal1() { DynamicObjectType treeEntryType = this.getModel().getEntryEntity(KEY_TREEENTRYENTITY).getDynamicObjectType(); DynamicObjectCollection treeEntryColl = this.getModel().getEntryEntity(KEY_TREEENTRYENTITY); for (int i = 0; i < 3; i++) { // 根节点数据 DynamicObject parentEntryObj = new DynamicObject(treeEntryType); long currRootDataId = ORM.create().genLongId(treeEntryType); String rootHierarchy = String.valueOf(i + 1); parentEntryObj.set("id", currRootDataId); parentEntryObj.set(KEY_TREEENTRY_HIERARCHY, String.format("当前层级:【%s】", rootHierarchy)); treeEntryColl.add(parentEntryObj); // 第一层节点数据 for (int j = 0; j < 3; j++) { DynamicObject currLevel1EntryObj = new DynamicObject(treeEntryType); long currLevel1ObjId = ORM.create().genLongId(treeEntryType); String currLevel1Hierarchy = String.format("%1$s-%2$s", rootHierarchy, (j + 1)); // 通过设置数据包的形式填充树形单据体数据, 必须设置树形单据体中【id】&【pid】两个字段的值 currLevel1EntryObj.set("id", currLevel1ObjId); currLevel1EntryObj.set("pid", currRootDataId); currLevel1EntryObj.set(KEY_TREEENTRY_HIERARCHY, String.format("当前层级:【%s】", currLevel1Hierarchy)); treeEntryColl.add(currLevel1EntryObj); // 第二层节点数据 for (int k = 0; k < 3; k++) { DynamicObject currLevel2EntryObj = new DynamicObject(treeEntryType); long currLevel2ObjId = ORM.create().genLongId(treeEntryType); String currLevel2Hierarchy = String.format("%1$s-%2$s", currLevel1Hierarchy, (k + 1)); // 通过设置数据包的形式填充树形单据体数据, 必须设置树形单据体中【id】&【pid】两个字段的值 currLevel2EntryObj.set("id", currLevel2ObjId); currLevel2EntryObj.set("pid", currLevel1ObjId); currLevel2EntryObj.set(KEY_TREEENTRY_HIERARCHY, String.format("当前层级:【%s】", currLevel2Hierarchy)); treeEntryColl.add(currLevel2EntryObj); } } } // 点击事件, 存在苍穹缓存不同步的问题, 需代码处理 this.getModel().updateEntryCache(treeEntryColl); }
3.2 方案二
通过平台提供的接口先新增/插入行之后,再为每个列字段赋值。
private void treeEntryEntitySetVal2() { int currRowIndex = 0; // 根节点数据 for (int i = 0; i < 3; i++) { this.getModel().createNewEntryRow(KEY_TREEENTRYENTITY); int currRootDataIndex = currRowIndex; String rootHierarchy = String.valueOf(i + 1); this.getModel().setValue(KEY_TREEENTRY_HIERARCHY, String.format("当前层级: %s", String.valueOf(i + 1)), currRootDataIndex); // 第一层节点数据 for (int j = 0; j < 3; j++) { this.getModel().insertEntryRow("kdec_treeentryentity", currRootDataIndex); int currLevel1DataIndex = (currRowIndex += 1); String currLevel1Hierarchy = String.format("%1$s-%2$s", rootHierarchy, (j + 1)); this.getModel().setValue(KEY_TREEENTRY_HIERARCHY, String.format("当前层级: %s", currLevel1Hierarchy), currLevel1DataIndex); // 第二层节点数据 int [] level2DataIndex = this.getModel().batchInsertEntryRow("kdec_treeentryentity", currLevel1DataIndex, 3); for (int k = 0; k < level2DataIndex.length; k++) { String currLevel2Hierarchy = String.format("%1$s-%2$s", currLevel1Hierarchy, (k + 1)); this.getModel().setValue(KEY_TREEENTRY_HIERARCHY, String.format("当前层级: %s", currLevel2Hierarchy), level2DataIndex[k]); currRowIndex++; } } currRowIndex ++; } }
四、效果图
4.1 方案一
4.2 方案二
五、开发环境版本
不限
六、注意事项
1. 方案一适用于批量数据赋值,性能较优,重点推荐该方案,方案二适用于数据量小的业务场景。
2. 方案一为树形单据体批量填充数据时,必须设置每行数据中 id & pid 字段的值。其中,id 为当前行数据的主键ID,pid 为父行数据的主键ID。
3. 当点击工具栏按钮时,采用方案一为树形单据体填充数据,会存在以下两个问题:
苍穹缓存不同步,需通过代码处理:this.getModel().updateEntryCache(DynamicObjectCollection)。该接口在V5.0之前版本可能会存在问题,使用之后无效果,如有遇到,可改用 this.getModel().updateCache(); 全量刷新单据缓存。
页面上树形单据体控件视图不更新,需通过代码处理:this.getView().updateView(String)。
其它响应事件可参照该方案处理。
4. 本案例中,注意将单据体控件的业务属性“缺省行数”设置为0。否则,默认会按该配置多出空行。
5. 采用方案二为树形单据体填充数据时,需严格保证行号的正确性!
七、参考资料
如何在界面上为树形单据体创建分录行并填充数据.zip(9.79KB)
推荐阅读