插件开发
苍穹开发知识总结
- 获取简单字段的值
- 数据模型IDataModel中存储了当前页面的数据包,对于文本类型、整数、时间字段等简单类型字段,可以直接通过IDataModel的get方法直接获取字段值,值的返回类型有String、Date、BigDecimal等。
- IDataModel model = this.getModel();
- String remark = (String)model .getValue("文本字段标识");
- BigDecimal qty=this.getModel().getValue("数量字段标识",0)
- 获取基础资料的属性值
- 方式1:在表单设计器中引用人员的“生日”属性,然后再通过以下代码可以取到基础资料某个属性。
- DynamicObject creatorDObj = (DynamicObject) this.getModel().getValue("creator");
- String birthday = creatorDObj.getString("birthday");
- 方式2:先拿到基础资料的id,再通过orm接口去查基础资料的某个属性值。
- //获取当前页面创建人字段的数据对象
- DynamicObject creatorDObj = (DynamicObject) this.getModel().getValue("creator");
- Object pkValue = creatorDObj.getPkValue();//拿主键即id
- QFilter idQFilter = new QFilter("id", QCP.equals, pkValue);//构造过滤条件
- DynamicObject queryRuselt =
- QueryServiceHelper.queryOne("bos_user", "birthday",new QFilter[] {idQFilter} );//查 询数据库
- String birthday = queryRuselt.getString("birthday");//拿属性的值
- 方式1:在表单设计器中引用人员的“生日”属性,然后再通过以下代码可以取到基础资料某个属性。
- 获取单据体某个字段或行对象
- 获取单据体某行某个字段的值 this.getModel().getValue("kded_textfield", 0);//0代表第一行
- 获取单据体中各行的数据
- 方式1:
- //获取当前页面的数据包
- DynamicObject dataEntity = this.getModel().getDataEntity(true);
- //获取单据体数据的集合
- DynamicObjectCollection goodsEntities=dataEntity.getDynamicObjectCollection(" 单据体标识");
- for (DynamicObject entryObj : goodsEntities) {
- //获取某行数据的id
- Object pk=entryObj.getPkValue();
- //获取某行的某个字段的值
- Object object = entryObj.get("字段标识");
- }
- 方式2:
- DynamicObjectCollection entryRows = this.getModel().getEntryEntity("单据体标识");
- 方式1:
- 获取子单据体某个字段或行
- 取子单据体某行某个字段 this.getModel().getValue("kded_textfield", 0,0);
//第一个整数代表子单据体行号,第二个整数代表父单据体行号
- 获取子单据体中各行的数据
//获取当前页面的数据包
DynamicObject dataEntity = this.getModel().getDataEntity(true);
//先获取单据体数据的集合
DynamicObjectCollection goodsEntities=dataEntity.getDynamicObjectCollection(" 单据体标识");
for (DynamicObject entryObj : goodsEntities) {
//再获取子单据体行某行数据的id
DynamicObjectCollection cols=entryObj .getDynamicObjectCollection("子单据体 标识");
for (DynamicObject col: cols) {
col.get("字段标识");//获取子单据体字段的值
}
}
- 获取富文本控件的值
富文本是通用控件,通用控件不能存储数据,所以不能通过model来取值,富文本的控件模型提供了相应的接口。
RichTextEditor edit = this.getView().getControl("富文本控件标识");
String text = edit.getText();
- 获取多选基础资料的值
多选基础资料字段配置的时候是要写表名的,通过model拿到的就是该表某些数据的集合,遍历集合才能拿到实际选择的基础资料数据对象。
DynamicObjectCollection multiCols = (DynamicObjectCollection) this.getModel().getValue("kded_mulbasedatafield");
for(DynamicObject col:multiCols){
//获取选择的基础资料数据对象
DynamicObject baseData = (DynamicObject) col.get("fbasedataid");
}
- 给简单字段赋值
简单字段的赋值,直接通过当前页面的数据模型IDataModel 赋值给字段赋值。
@Override
public void afterCreateNewData(EventObject e) {
IDataModel model = this.getModel();
model.setValue("kded_remark", "我的备注数据");
}
- 给基础资料字段赋值
给基础资料赋值必须用基础资料的id或者基础资料的DynamicObject。
@Override
public void afterCreateNewData(EventObject e) {
long currentUserId = UserServiceHelper.getCurrentUserId();
//方式1:通过id赋值-推荐
this.getModel().setValue("kded_registrant", currentUserId );
//方式2:通过对象赋值
DynamicObject user = BusinessDataServiceHelper.loadSingle(currentUserId, "bos_user");
this.getModel().setValue("kded_registrant", user);
}
注意:不能使用QueryServiceHelper.queryOne查到的平铺对象赋值给基础资料字段。
- 给单据体的字段赋值
方式1:如果是知道行号index,且只需要给这行的字段赋值,则参考:
this.getModel().setValue("字段标识","字段值",index);
方式2:需要给每行赋值,则需遍历单据体进行赋值:
DynamicObjectCollection entryRows = this.getModel().getEntryEntity("单据体标识");
for (DynamicObject entryObj : entryRows) {
//修改某行的某个字段的值
entryObj.set("kded_textfield", "测试");}
this.getView().updateView("entryentity");
}
注意点:方式2如果在afterCreateNewData事件则不需要updateView,否则需要代码刷新前台才会显示。
- 给单据体新建行
- 方式1:单据体虽然是集合,但是数据模型IModel提供了直接增加行的接口,需要知道要增加的行数row。
- int[] newEntryRow = this.getModel().batchCreateNewEntryRow("单据体标识", row);
- for (int index : newEntryRow) {
- this.getModel().setValue("单据体某个字段标识", 值, index);
- }
- 方式2:给单据体创建行对象,再调用IModel增加行的接口。
- DynamicObject entry = ORM.create().newDynamicObject(this.getModel().getEntryEntity("单据体标 识 ").getDynamicObjectType());
- entry.set("kded_textfield1","44");
- entry.set("kded_amountfield","10");
- int rowindex = this.getModel().createNewEntryRow("单据体标识", entry);
- 注意:如果单据体字段有设置默认值,此方式默认值会覆盖代码设置的值。
- 方式3:通过数据包给单据体直接新增行对象。
- DynamicObjectCollection entryentityCols = this.getModel().getDataEntity(true).getDynamicObjectCollection("entryentity");
- DynamicObject entryCol = entryentityCols.addNew();
- entryCol.set("kded_textfield", "方式4");
- this.getView().updateView("entryentity");
- 获取单据体数据包,在数据包新增行对象,是需要代码调用updateView才会将新内容显示到界面上。
- 方式1:单据体虽然是集合,但是数据模型IModel提供了直接增加行的接口,需要知道要增加的行数row。
- 给子单据体新建一行
//先设置父单据体选中行
this.getModel().setEntryCurrentRowIndex("entryentity",0);
//创建子单据体行-方式1
int[] ints = this.getModel().batchCreateNewEntryRow("kded_subentryentity", 1);
for (int index : ints) {
this.getModel().setValue("kded_textfield2", "文本值", index);
}
//创建子单据体行-方式2
DynamicObject subEntry = ORM.create().newDynamicObject(this.getModel().getEntryEntity("kded_subentryentit y").getDynamicObjectType());
subEntry.set("kded_textfield2","行对象");
int rowindex = this.getModel().createNewEntryRow("kded_subentryentity", subEntry);
- 给富文本控件赋值
富文本是通用控件,不能像实体字段一样直接用数据模型this.getmodel赋值,需要通过富文本控件模型RichTextEditor 提供的方法setText设置值。
RichTextEditor edit = this.getView().getControl("richtexteditorap");
edit.setText("要设置的内容");
- 给多选基础资料赋值
https://vip.kingdee.com/article/198799132897594368?productLineId=29
- 列表页面赋值
https://vip.kingdee.com/article/306390194805169920?productLineId=29
- 如何复制单据数据
public class SrSubmitOpPlugin extends AbstractOperationServicePlugIn {
@Override
public void onPreparePropertys(PreparePropertysEventArgs e) {
super.onPreparePropertys(e);
e.getFieldKeys().add("kded_srstatus");
}
@Override
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
super.beginOperationTransaction(e);
DynamicObject[] dataEntities = e.getDataEntities();
for(DynamicObject data : dataEntities) {
//单据标识
String entityNumber = data.getDataEntityType().getName();
//data是保存前且校验通过的数据包,此处备份数据
Object pkValue = obj.getPkValue()
boolean exists = QueryServiceHelper.exists(entityNumber , pkValue);
if(exists){
//如下复制数据方案1或者方案2
)else{
}
}
}
}
数据复制有两种方案:
方案1:创建空数据包,并逐一赋值-不推荐,后续表单增加字段,需要不断迭代代码。
//创建空的数据包
DynamicObject newDynamicObject = BusinessDataServiceHelper.newDynamicObject(entityNumber);
newDynamicObject.set("单据头字段标识a", data.get("单据头字段标识a"));
newDynamicObject.set("备注字段标识", "备份数据");
//单据体数据行
DynamicObjectCollection newCol = newDynamicObject.getDynamicObjectCollection("单据体标识");
DynamicObjectCollection oldCol = data.getDynamicObjectCollection("单据体标 识 ");
//复制当前分录数据到新增数据包的新增分录行上
for (DynamicObject oldEntry : oldCol) {
//创建一个空的分录行
DynamicObject newEntry = new DynamicObject(newCol.getDynamicObjectType());
newEntry.set("单据体字段标识x", oldEntry.get("单据体字段标识x"));
//新增数据行添加到单据体上
newCol.add(newEntry);
}
//保存数据
SaveServiceHelper.saveOperate(entityNumber, new DynamicObject[] {newDynamicObject})
方案2:直接克隆整个数据包-增加字段无需迭代代码,推荐。
DynamicObject newData = (DynamicObject) new CloneUtils(false,true).clone(data );
newData.set("备注字段标识", "备份数据");
//保存数据
SaveServiceHelper.saveOperate(entityNumber, new DynamicObject[] {newData })
- 如何判断界面是否新增界面
①首先确认要重写的事件,要在“新增”和“编辑”状态下都会执行。而弹出提示是view的行为,所以一般建议在afterBindData事件中处理。
②每个界面视图中,都保存了相关界面的参数,包括但不局限于:页面pageid,表单标识、表单运行插件、父页面传过来的自定义参数等,例如当前页面是新增状态还是编辑状态,可以根据单据页面的界面参数FormShowParameter中的getStatus方法获取到。
BillShowParameter bsp=(BillShowParameter)this.getView().getFormShowParameter();
if(bsp.getStatus()==OperationStatus.ADDNEW ){
this.getView().showTipNotification("您正在新增办公用品登记单");
}
if(bsp.getStatus()==OperationStatus.EDIT){
this.getView().showTipNotification("您正在编辑一个办公用品登记单");
}
- 取消打开页面
@Override
public void preOpenForm(PreOpenFormEventArgs e) {
e.setCancel(true);
e.setCancelMessage("对不起,周日不能制单!");
}
- 锁定单据头字段
方式1:表单设计器上设置”新增锁定、修改锁定、提交锁定、审核锁定"。
方式2:通过如下代码设置锁定性。
@Override
public void afterBindData(EventObject e) {
super.afterBindData(e);
this.getView().setEnable(false, "字段标识");
}
说明:其他场景下,影响锁定性的因素还有单据类型、界面规则、布局等。
- 锁定单据体或单据体字段
问题1:如何锁定单据体某几行?
参考答案:
//锁定单据体某几行,所有字段都锁定
EntryGrid entryGrid = this.getView().getControl("entryentity");
entryGrid.setRowLock(true,new int[]{0,1});
问题2:如何锁定单据体某一行某一列?
参考答案:
//锁定单据体某行某列
this.getView().setEnable(false,2,"kded_dealdesc");
问题3:如何锁定某一列?
参考答案:没有锁定整列的接口,需遍历单据体行锁定
int rowCount = this.getModel().getEntryRowCount("entryentity");
for(int i = 0,i<rowCount ,i++){
this.getView().setEnable(false,i,"kded_dealdesc");
}
问题4:如何锁定整个单据体?
参考答案:
this.getView().setEnable(false,"entryentity");
在afterBindData事件中先判断单据状态是审核状态时,再设置审核人字段可见:this.getView().setVisible(true, "字段标识");
问题1:如何通过代码设置单据头字段必录?
参考答案:
TextEdit textField = (TextEdit)this.getView().getControl("kded_textfield1");
textField.setMustInput(true);
问题2:如何通过代码设置单据体字段必录?
参考答案:
//设置单据体字段必录,kded_dealdesc是单据体一个文本字段的标识
TextEdit textField1 = (TextEdit)this.getView().getControl("kded_dealdesc");
textField1.setMustInput(true);
TextProp it2 =(TextProp) textField1.getProperty();
it2.setMustInput(true);
- 设置单据体选中行
//数据模型中获取单据体的数据行数
int entryRowCount = this.getModel().getEntryRowCount("sunp_entryentity");
if (entryRowCount!=0) {
//获取单据体控件模型
EntryGrid eg = this.getView().getControl("sunp_entryentity");
//通过单据体控件模型的方法实现选中行功能
eg.selectRows(0);
}
//tbmain是工具栏标识,bar_save是工具栏项标识,save是工具栏绑定的操作
Toolbar toolbar = this.getView().getControl("tbmain");
toolbar.itemClick("bar_save", "save");
//触发按钮,kded_btsave是按钮标识
Button button = this.getView().getControl("kded_btsave");
button.click();
问题:如何通过代码触发某个操作?
参考答案:界面模型提供了相关接口。
this.getView().invokeOperation("save");//save是操作标识
- 刷新数据
问题1:通过插件给单据头的字段赋值,发现值没显示出来时,应该如何刷新字段的值?
参考答案:
this.getView().updateView("字段标识");
//或者
this.getView().updateView();
问题2:通过插件给单据体的字段赋值,发现值没显示出来时,应该如何刷新单据体字段的值?
参考答案:
this.getView().updateView("单据体字段", 所在行号);
//如果刷新很多单据体字段,可以选择刷新整个单据体
this.getView().updateView("单据体标识");
//或者
this.getView().updateView();
问题3:在用户打开查看单据的某条数据时,并在插件中通过BusinessDataServiceHelper.loadSingle查数据库中对应的数据进行修改,并通过SaveServiceHelper.update更新数据到数据库,那么用户此时该如何刷新修改的数据到当前页面
参考答案:
//或者调用表单的“刷新”操作
this.getView().invokeOperation("refresh");
推荐:由于刷新是有性能消耗的,updateView建议指定刷新字段或刷新单据体的标识,尽量不要进行全局刷新-this.getView().updateView()。
在页面关闭时的校验,那么可以在页面关闭前事件beforeClosed中,通过修改事件参数取消校验。
@Override
public void beforeClosed(BeforeClosedEvent e) {
super.beforeClosed(e);
e.setCheckDataChange(false);
}
问题2:如何通过代码关闭页面。
参考答案:
this.getView().close();
//或者
this.getView().invokeOperation("close");
this.getView.showMessage("提示信息");
https://vip.kingdee.com/school/238714716992919296?topicId=239383452913417728&stageId=239383671570873856&pathId=239410657773565696&productLineId=29
问题1:如何通过代码修改字段控件的名称?
参考答案:TextEdit的父类FieldEdit提供setCaption接口修改控件名称。如:
TextEdit textField = (TextEdit)this.getView().getControl("kded_textfield1");
textField.setCaption(new LocaleString("sss"));
注意:当通过该方式修改字段标题后,修改该字段退出界面会提示已有XXX字段修改,是否继续退出,这里还是显示修改前的字段名称,需要通过以下代码修改主数据模型对应属性的标题:
//对应修改元数据对应属性的标题
Map<String, IDataEntityProperty> allFields
=this.getModel().getDataEntityType().getAllFields();
IDataEntityProperty kded_textfield1 = allFields.get("kded_textfield1");
kded_textfield1.getDisplayName().setLocaleValue("sss");
问题2:如何通过代码修改非字段类型的控件名称,比如按钮、高级面板等?
参考答案:使用动态更新元数据属性的接口updateControlMetadata。
Map<String, Object> text = new HashMap<>();
Map<String, Object> text1 = new HashMap<>();
text.put("zh_CN", "test");
text1.put("text", text);
this.getView().updateControlMetadata("控件标识", text1);
问题:如何使用页面缓存?
参考答案:
this.getView().getPageCache().put("isLeaf","true");
String isLeaf = this.getView().getPageCache().get("isLeaf");
问题:如何获取运行期表单及表单所有控件信息?
参考答案:
元数据相关的servicehelper:MetadataServiceHelper、AppMetaServiceHelper、ConvertMetaServiceHelper、LocaleMetadataServiceHelper等,优先使用这些。(注意不要用到非平台的)
//根据表单编码获取表单id
String id = MetadataDao.getIdByNumber("kdec_cehsi", MetaCategory.Form);
//获取表单元数据
FormMetadata formMeta = (FormMetadata) MetadataDao.readRuntimeMeta(id, Meta Category.Form);
//遍历获取所有控件集合
for (ControlAp<?> item : formMeta.getItems()) {
//可见性
String visible = item.getVisible();
//控件名称
String name = item.getName().getLocaleValue();
//控件编码
String key = item.getKey();
}
问题:办公用品登记单选择物品后,如何自动给物品分类赋值?
参考答案:
方式1:使用基础资料属性字段,然后绑定物品字段,显示属性选择物品分类名称。
方式2:通过业务规则配置【计算定义公式的值并填写到指定列 】服务实现。
方式3:在值更新事件propertyChanged中获取变更的物品值,并给“物品分类”字段赋值。
@Override
public void propertyChanged(PropertyChangedArgs e) {
if (e.getProperty().getName().equals("物品字段标识")) {
ChangeData changeData = e.getChangeSet()[0];
//变更后的数据
DynamicObject newValue = (DynamicObject) changeData.getNewValue();
DynamicObject
goodObj=BusinessDataServiceHelper.loadSingle(newValue.getPkValue(), "物 品的标识", "物品里分类字段标识");
DynamicObject groupObj = goodObj.getDynamicObject("物品里分类字段标 识");
this.getModel().setValue("物品分类字段标识", groupObj);
}
}
方式1:在afterCreatedNewData事件赋值,是不会触发值更新事件的。
方式2:在其他事件赋值时,使用以下方式赋值。
this.getModel().beginInit();
this.getModel().setValue("字段标识","字段值");
this.getModel().endInit();
- 用户点击
苍穹平台表单页面的点击及触发原理也是基于Java委托事件处理机制,关键对象包括如下:
Event Source(事件源):事件发生的场所,通常就是各个组件,例如按钮、窗口、菜单、工具栏(在苍穹上对应Toolbar控件)等。
Event(事件):事件封装了GUI组件上发生的特定事情(用户动作、行为)。
Event Listener(事件监听器):注册于某个事件源上,用于响应特定的事件。
在苍穹平台中,所有标准控件的事件源(Button.class,Toolbal.class,EntryGrid.class等)已经定义好了,用户点击苍穹表单页面某个地方时,是否会触发特定的响应方法(click、itemClick、billListHyperLinkClick等),需要满足以下两个条件。
①事件的产生:以用户点击工具栏新增按钮为例,表单微服务根据前端发送的指令最终调用事件源(Toolbar控件模型)创建了两个事件(BeforeItemClickEvent、ItemClickEvent)。


②在表单插件的registerListener方法中注册ToolBar事件源的事件监听器(ClickListener、ItemClickListener)并重写监听器对应的响应事件方法click、itemClick。

由于只产生了BeforeItemClickEvent、ItemClickEvent这两个事件,没有ClickEvent事件,所以只会响应itemClick方法。

第一步:办公用品登记单插件的itemClick方法中弹出物品新增申请单。
@Override
public void itemClick(ItemClickEvent evt) {
FormShowParameter fsp = new FormShowParameter();
fsp.setFormId("物品新增申请单");
fsp.getOpenStyle().setShowType(ShowType.Modal);
fsp.setCloseCallBack(new CloseCallBack(this, "show-kded_supaddnew"));//
this.getView().showForm(fsp);
super.itemClick(evt);
}
修改父页面的数据
方案1:直接在子页面的表单插件中拿到父页面的数据模型model进行赋值。
@Override
public void click(EventObject evt) {
if (evt.getSource() instanceof Button) {
Button bt=(Button) evt.getSource();
String key = bt.getKey();
if (key.equals("btnok")) {
Object goodName = this.getModel().getValue("物品名称字段标识");
IFormView parentView = this.getView().getParentView();//父页面
IDataModel parentModel = parentView.getModel();
parentModel.setValue("sunp_textfield",goodName ) );//修改父页面数据
parentView .updateView();//刷新
//调用了其他表单的控制方法时,需调用以下方法将目标表单的控制 指 //令发给前端
this.getView().sendFormAction(this.getView().getParentView()); this.getView().close();
}
}
super.click(evt);
}
方案2:将子页面的字段值传给父页面,然后在父页面的表单插件的closedCallBack方法中修改备注字段值。
新增物品申请单表单插件:
@Override
public void click(EventObject evt) {
if (evt.getSource() instanceof Button) {
Button bt=(Button) evt.getSource();
String key = bt.getKey();
if (key.equals("btnok")) {//确定按钮或者是邮件通知按钮
Object goodName = this.getModel().getValue("物品名称字段标识");/
this.getView().returnDataToParent(goodName);//返回数据给父页面
this.getView().close();
}
}
}
办公用品登记单插件:
@Override
public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
if (closedCallBackEvent.getActionId().equals("show-kded_supaddnew")) {
Object returnData = closedCallBackEvent.getReturnData();
this.getModel().setValue("sunp_textfield",returnData);
}
super.closedCallBack(closedCallBackEvent);
}
方案3:将子页面的值放到父页面缓存,由父页面插件进行赋值处理。
新增物品申请单表单插件:
@Override
public void click(EventObject evt) {
if (evt.getSource() instanceof Button) {
Button bt=(Button) evt.getSource();
String key = bt.getKey();
if (key.equals("btnok")) {//确定按钮或者是邮件通知按钮
Object goodName = this.getModel().getValue("物品名称字段标识");/
//通过界面缓存传递值
this.getView().getParentView().getPageCache().put("name", goodName );
this.getView().close();
}
}
}
}
办公用品登记单插件:
@Override
public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
if (closedCallBackEvent.getActionId().equals("show-kded_supaddnew")) {
this.getModel().setValue("sunp_textfield",this.getView().getPageCache(). get("name"));
}
super.closedCallBack(closedCallBackEvent);
}
- 基础资料选择界面(F7)
F7选择界面显示哪些字段
基本上F7选择界面都是统一的界面,普通基础资料用的是bos_listf7,分组基础资料和树形基础资料用的是bos_templatetreelistf7界面,部分基础资料,比如人员、组织、客户、供应商等基础资料有自己的f7界面。
F7选择界面的字段由基础资料列表的字段决定,给列表增加字段,并且【可见性】选上F7界面可见。

F7选择界面显示未审核的数据
@Override
public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
if("kded_basedatafield".equals(beforeF7SelectEvent.getProperty().getName())){
ListShowParameter listShowParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
listShowParameter.setShowApproved(false);
}
}
F7选择界面展示已选择的数据,开启多选等
public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
if("kded_basedatafield".equals(beforeF7SelectEvent.getProperty().getName())){
ListShowParameter listShowParameter = (ListShowParameter)
beforeF7SelectEvent.getFormShowParameter();
listShowParameter.setShowApproved(false);
DynamicObject baseData = (DynamicObject) this.getModel().getValue("kded_basedatafield");
if(baseData != null) {
//设置单个已选
listShowParameter.setSelectedRow(baseData.getPkValue()); listShowParameter.setSelectedRows(new Object[]{baseData.getPkValue()});//设置多个已选
listShowParameter.setMultiSelect(true);//开启多选
}
}
- 新建数据对象并赋值
新建空数据对象
可以使用DynamicObject的构造函数,也可以使用BusinessDataServiceHelper或ORM提供的接口。
方式1:
DynamicObject data
=BusinessDataServiceHelper.newDynamicObject("kded_simplebill");
方式2:
DynamicObject kded_simplebill =
ORM.create().newDynamicObject("kded_simplebill");
方式3
MainEntityType type =
EntityMetadataCache.getDataEntityType("kded_simplebill");
DynamicObject data1 = new DynamicObject((DynamicObjectType) type);
给对象赋简单字段的值
data.set("billno","测试0002");
data.set("billstatus","A");
给对象新增单据体并赋值
DynamicObjectCollection entryentity =
data.getDynamicObjectCollection("entryentity");
//新增单据体方式一:
DynamicObject dynamicObject = entryentity.addNew();
dynamicObject.set("kded_textfield","代码新增单据体方式1");
//新增单据体方式二:
DynamicObject dynamicObject1 =
new DynamicObject(entryentity.getDynamicObjectType());
dynamicObject1.set("kded_textfield","代码新增单据体方式2");
entryentity.add(dynamicObject1);
给对象新增子单据体并赋值
DynamicObjectCollection entryentity = data.getDynamicObjectCollection("entryentity");
DynamicObject entry = new DynamicObject(entryentity.getDynamicObjectType()); entry.set("kdec_textfield","hello1");
entry.set("kdec_integerfield", 95271);
entryentity.add(entry);
//单据体数据
DynamicObjectCollection subentryentity = entry.getDynamicObjectCollection("subentryentity");
//单据体的子单据体
DynamicObject subentry = new DynamicObject(subentryentity.getDynamicObjectType());
subentry.set("kdec_textfield1","world");
subentry.set("kdec_integerfield1", 12138); subentryentity.add(subentry);
- 保存数据对象
SaveServiceHelper
//方式1-走保存操作的校验
OperationResult operationResult1 =
SaveServiceHelper.saveOperate("kded_simplebill", new DynamicObject[]{data},
OperateOption.create());
//方式2-直接存库
SaveServiceHelper.save(new DynamicObject[]{data});
OperationServiceHelper
该接口可以执行单据的操作,如执行提交操作:
OperationResult operationResult =
OperationServiceHelper.executeOperate("submit","kded_simplebill",new DynamicObject[]{data},OperateOption.create());
if(!operationResult.getSuccessPkIds().isEmpty()){
//执行成功
}
- 查询数据对象
查询简单字段&使用简单字段做过滤条件
//方式1-根据单据id查询-可以查询所有字段
Object billId = "1515996182680175616";
DynamicObject simpleBill = BusinessDataServiceHelper.loadSingle(billId,
"kded_simplebill");
//方式2-根据单据id查询-查询指定字段,查询结果是平铺的
QFilter filter = new QFilter("id", QCP.equals, billId);
DynamicObject simpleBillObject =
QueryServiceHelper.queryOne("kded_simplebill", "id,billno,createtime", new QFilter[]{filter});
查询复杂字段&使用复杂字段做过滤条件
//方式1-根据创建人的名称构造过滤条件-BusinessDataServiceHelper
QFilter filter2 = new QFilter("creator.name", QCP.equals, "XXX");
DynamicObject simpleBill2 =
BusinessDataServiceHelper.loadSingle("kded_simplebill","id,billno,creator,creato r.id,createtime",new QFilter[]{filter2});
DynamicObject creator = simpleBill2.getDynamicObject("creator");
long creatorId = simpleBill2.getLong("creator.id");
//方式2-根据创建人的名称构造过滤条件-QueryServiceHelper
DynamicObject simpleBillObject3 =
QueryServiceHelper.queryOne("kded_simplebill",
"id,billno,creator,creator.id,createtime", new QFilter[]{filter2});
DynamicObject creator1 = simpleBill2.getDynamicObject("creator");
查询单据体字段&使用单据体字段做过滤条件
①使用BusinessDataServiceHelper
//根据单据体的字段构造过滤条件
QFilter filter3 = new QFilter("entryentity.kded_dealuser.name", QCP.equals, "金小
蝶");
DynamicObject simpleBill3 =
BusinessDataServiceHelper.loadSingle("kded_simplebill","id,billno,kded_dealuse r,kded_dealdesc",new QFilter[]{filter3});
DynamicObjectCollection cols =
simpleBill3.getDynamicObjectCollection("entryentity");
for(DynamicObject col:cols){
DynamicObject user = col.getDynamicObject("kded_dealuser");
String name = user.getString("name");
String dec = col.getString("kded_dealdesc");
}
注意点:
1.过滤条件使用单据体字段做过滤条件需要加上单据体标识,如entryentity.kded_dealuser.name;
2.查询字段selectfields查询单据体字段可不用加单据体标识,如
DynamicObject user = col.getDynamicObject("kded_dealuser");
3.user默认有id,number、name字段,如需其他字段,需要单据给该基础资料字段配置引用属性。
②使用BusinessDataServiceHelper
QFilter filter5 = new QFilter("entryentity.kded_dealuser.name", QCP.equals, "金小
蝶");
DynamicObjectCollection simpleBills =
QueryServiceHelper.query("kded_simplebill","id,billno,entryentity.kded_dealuser. name,entryentity.kded_dealdesc",new QFilter[]{filter5});
for (DynamicObject dynamicObject : simpleBills) {
dynamicObject.get("entryentity.kded_dealuser.name");
}
注意点:过滤条件和查询字段使用单据体字段都需要用单据体标识entryentity, 指定什么字段则查出什么字段。
查询子单据体字段&使用单据体字段做过滤条件
//根据单据体的字段构造过滤条件查询子单据体字段
QFilter filter4 = new QFilter("entryentity.kded_dealuser.name", QCP.equals, "金小蝶 ");
DynamicObject simpleBill4 =
BusinessDataServiceHelper.loadSingle("kded_simplebill","id,billno,kded_dealuser, kded_dealdesc,kded_subdealuser,kded_subdec",new QFilter[]{filter4});
DynamicObjectCollection cols1 =
simpleBill4.getDynamicObjectCollection("entryentity");
for(DynamicObject col:cols1){
//获取单据体字段
DynamicObject user = col.getDynamicObject("kded_dealuser");
String name = user.getString("name");
String dec = col.getString("kded_dealdesc");
DynamicObjectCollection subCols =
col.getDynamicObjectCollection("kded_subentryentity");
for (DynamicObject subCol:subCols) {
//获取子单据体字段
DynamicObject subDealUser =
subCol.getDynamicObject("kded_subdealuser");
String subDec = subCol.getString("kded_subdec");
}
}
- 删除数据对象
(1)直接从数据库删除数据,不触发数据校验
DynamicObject dObj = null;
//IDataEntityType 为实体类型基类
IDataEntityType dataEntityType = dObj.getDataEntityType();
//pks为数据主键值
DeleteServiceHelper.delete(IDataEntityType type, Object[] pks)
(2)删除数据时,触发数据校验
DeleteServiceHelper deleteServiceHelper = new DeleteServiceHelper();
deleteServiceHelper.deleteOperate("删除的操作代码", "单据标识", pks,
OperateOption.create());
//或者直接调用通用操作接口
OperationServiceHelper.executeOperate("删除的操作代码", "单据标识", pks,
OperateOption.create())
- 界面插件触发操作
界面模型View提供了触发操作的接口。
this.getView().invokeOperation("submit");
非界面插件没有界面模型View,需要通过操作服务工具类触发(也可以界面插件使用)。
OperationResult operationResult =
OperationServiceHelper.executeOperate("submit","kded_simplebill",new DynamicObject[]{data},OperateOption.create());
if(!operationResult.getSuccessPkIds().isEmpty()){
//todo;
}
通过OperateOption传递对应参数,可以绕过权限校验。
OperateOption option = OperateOption.create();
option.setVariableValue(OperateOptionConst.ISHASRIGHT, "true");OperationResult
配置实现
单据状态、日期这两种类型的字段可以在操作配置刷新字段实现。

代码实现
@Override
public void afterDoOperation(AfterDoOperationEventArgs
afterDoOperationEventArgs) {
super.afterDoOperation(afterDoOperationEventArgs);
FormOperate formoperate = (FormOperate)
afterDoOperationEventArgs.getSource();
if("操作代码".equals(formoperate.getOperateKey())) {
if(!afterDoOperationEventArgs.getOperationResult().getSuccessPkIds().
isEmpty()) {
this.getView().updateView("字段标识");
}
}
配置提示
固定的提示语可以直接在操作进行配置,如图:

代码修改操作后的提示
首先得在操作配置操作成功后提示,通过代码修改提示内容才会弹出显示。
方式1:在操作插件实现。
@Override
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
if("save".equals(e.getOperationKey())&&!this.getOperationResult().getSuccessPkI ds().isEmpty()) {
this.getOperationResult().setMessage("保存成功啦-操作插件");
}
}
方式2:在界面插件实现。
@Override
public void afterDoOperation(AfterDoOperationEventArgs
afterDoOperationEventArgs) {
super.afterDoOperation(afterDoOperationEventArgs);
FormOperate formoperate = (FormOperate)
afterDoOperationEventArgs.getSource();
if("save".equals(formoperate.getOperateKey())&&!afterDoOperationEventA rgs.getOperationResult().getSuccessPkIds().isEmpty()) {
afterDoOperationEventArgs.getOperationResult().setMessage("保存成
功!-界面插件");
}
}
从界面传递参数给操作插件
首先在界面插件给操作塞参数
@Override
public void beforeDoOperation(BeforeDoOperationEventArgs args) {
super.beforeDoOperation(args);
FormOperate formoperate = (FormOperate) args.getSource();
if("save".equals(formoperate.getOperateKey())) {
formoperate.getOption().setVariableValue("customItem",this.getView().
getPageCache().get("customItem"));
}
}
然后在操作插件取参数:
@Override
public void beginOperationTransaction(BeginOperationTransactionArgs e) {
super.beginOperationTransaction(e);
if ("save".equals(e.getOperationKey())) {
//取出界面传过来的参数
String customItem = this.getOption().getVariableValue("customItem");
}
}
从操作插件传递参数给界面
首先在操作插件给操作Option塞参数
@Override
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
if("save".equals(e.getOperationKey())&&!this.getOperationResult().getSuccessPkI ds(). isEmpty()) {
this.getOption().setVariableValue("allBillNo","");
}
}
然后在界面插件取参数
@Override
public void afterDoOperation(AfterDoOperationEventArgs
afterDoOperationEventArgs) {
super.afterDoOperation(afterDoOperationEventArgs);
FormOperate formoperate = (FormOperate)
afterDoOperationEventArgs.getSource();
if("save".equals(formoperate.getOperateKey())&&!afterDoOperationEventArgs.g etOperationResult().getSuccessPkIds().isEmpty()) {
String allBillNo = formoperate.getOption().getVariableValue("allBillNo");
}
}

浙公网安备 33010602011771号