插件实现附件面板和附件字段的携带转换原创
金蝶云社区-时空蔷薇
时空蔷薇
29人赞赏了该文章 9,683次浏览 未经作者许可,禁止转载编辑于2022年03月10日 14:55:31
summary-icon摘要由AI智能服务提供

本文档主要讨论了在不同业务单据转换场景中,如何在苍穹系统中实现附件在不同类型(附件面板与附件字段)之间的上传与转换。详细描述了附件面板与附件字段的特点,以及通过AttachmentServiceHelper和AttachmentFieldModel等工具类进行附件数据获取、处理和上传的方法。具体方案包括附件面板到附件面板、附件面板到附件字段、附件字段到附件字段、以及附件字段到附件面板的转换过程,每个过程都包含数据获取、数据加工处理、数据上传以及赋值等关键步骤,并给出了相应的代码示例。此外,还提供了在转换过程中可能遇到的问题及解决方案,如共用附件对象数据的注意事项等。

关键词:

页面开发,附件面板,附件字段

一、需求

    在BOTP等有业务单据转换的场景,需要把某张单据的附件上传到另外一张单据中,怎么实现?

二、思路与方案

2.1 分析思路

    苍穹系统附件类型有附件面板和附件字段。

    附件面板是面板控件,其附件对象数据存储于bos_attachment,只有控件编程模型,没有数据模型,但我们可以通过AttachmentServiceHelper.getAttachments(String, Object, String)获取附件面板数据、

 

AttachmentServiceHelper.upload(String, Object, String, List<Map<String, Object>>)或者AttachmentServiceHelper.saveTempAttachments(String, Object, String, Map<String, Object>)上传附件面板数据。

    附件字段继承自多选基础资料,具有数据模型,其关联的基础资料类型是bd_attachment,附件字段赋值类似多选基础资料,也可通过fbasedataid实现。

    那么借助这些方法即可随心所欲实现附件面板、附件字段之间的携带转换。

2.2 实现方案

1. 附件面板To附件面板

    先获取源附件面板数据,页面前台用AttachmentPanel.getAttachmentData()或者插件后台用AttachmentServiceHelper.getAttachments(String, Object, String),然后对lastModifiedurl等进行数据加工处理,调用AttachmentServiceHelper.upload(String, Object, String, List<Map<String, Object>>)上传到目标附件面板。

2. 附件面板To附件字段

    先获取源附件面板数据,页面前台用AttachmentPanel.getAttachmentData()或者插件后台用AttachmentServiceHelper.getAttachments(String, Object, String),然后对uid、关联单据实体编码、关联单据实体id等进行数据加工处理,调用AttachmentFieldModel.saveAttachments(IDataModel, String, String, List<Map<String, Object>>)将附件数据上传到文件服务器,生成bd_attachment附件对象,再赋值给目标附件字段。

3. 附件字段To附件字段

    参考多选基础资料字段,先加载源附件字段的数据值集合,取出fbasedataid赋值给目标附件字段。

4. 附件字段To附件面板

    先加载源附件字段的数据值集合,通过bd_attachment附件对象里的url将附件上传到文件服务器,并自己构造附件面板数据,再调用AttachmentServiceHelper.saveTempAttachments(String, Object, String, Map<String, Object>)将数据绑定到目标附件面板。

 

三、实现过程

1. 附件面板To附件面板

(1) 获取源附件面板数据并进行数据加工

关键代码:

//通过AttachmentServiceHelper.getAttachments(formId, pkId, attachKey)获取源单据附件面板附件数据
List<Map<String, Object>> attachmentData = AttachmentServiceHelper.getAttachments("kded_sourcebill", sourcebill.getLong("id"), "attachmentpanel");
attachmentData.forEach(attach -> {
    try {
        //源附件数据的lastModified是timestamp,会出现强转long错误在此置null
        attach.put("lastModified", null);
        //源附件数据的url已经过URL编码,需要在此先解码获取原始下载路径,AttachmentServiceHelper.upload()会进行URL编码
        attach.put("url", getPathfromDownloadUrl(URLDecoder.decode(String.valueOf(attach.get("url")), "UTF-8")));
    } catch (IOException e) {
        //do something with log.
        e.printStackTrace();
    }
})
 
/**
 * 获取文件服务器相对路径
 * @param url
 * @return
 * @throws IOException
 */
private String getPathfromDownloadUrl(String url) throws IOException {
    String path = StringUtils.substringAfter(url, "path=");
    path = URLDecoder.decode(path, "UTF-8");
    return FilePathUtil.dealPath(path, "attach");
}

(2) 将附件数据上传到目标附件面板

关键代码:

//调用AttachmentServiceHelper.upload(formId, pkId, attachKey,  attachments)将附件数据上传到目标附件面板
AttachmentServiceHelper.upload(getView().getEntityId(), getModel().getValue("id"), "attachmentpanel", attachmentData);

 

2. 附件面板To附件字段

(1) 获取源附件面板数据并进行数据加工

关键代码:

//通过AttachmentServiceHelper.getAttachments(formId, pkId, attachKey)获取源单据附件面板附件数据
List<Map<String, Object>> attachmentData1 = AttachmentServiceHelper.getAttachments("kded_sourcebill", sourcebill1.getLong("id"), "attachmentpanel");
attachmentData1.forEach(attach -> {
    //修改附件数据的uid、关联单据实体编码、关联单据实体id
    attach.put("uid", getUid().toString());
    attach.put("entityNum", getView().getEntityId());
    attach.put("billPkId", String.valueOf(getModel().getValue("id")));
});
/**
 * 获取附件uid
 * @return
 */
private StringBuffer getUid() {
    StringBuffer uid = new StringBuffer("rc-upload-");
    uid.append((new Date()).getTime());
    uid.append("-");
    int index = (int)(1.0D + Math.random() * 10.0D);
    uid.append(index);
    return uid;
}

 

(2) 调用AttachmentFieldModel.saveAttachments(IDataModel, String, String, List<Map<String, Object>>)将附件数据上传到文件服务器

关键代码:

AttachmentEdit attEdit = this.getView().getControl("kded_attachment");
List<DynamicObject> saveAttachments = attEdit.getAttachmentModel().saveAttachments(attEdit.getModel(), this.getView().getPageId(), this.getModel().getDataEntityType().getName(), attachmentData1);

 

(3) 给目标附件字段赋值

关键代码:

List<Long> idSet = new ArrayList<>();
//获取保存后的bd_attachment附件对象id
saveAttachments.forEach(save -> idSet.add(save.getLong("id")));
//给目标附件字段赋值
getModel().setValue("kded_attachment", idSet.toArray());

 

3. 附件字段To附件字段

(1) 获取源附件字段附件对象bd_attachment)的id集合

关键代码:

//获取源附件字段的值
DynamicObject sourceBill2 = BusinessDataServiceHelper.loadSingle("kded_sourcebill", "id,kded_attachment", qFilter2.toArray());
DynamicObjectCollection sourceAttachcol = (DynamicObjectCollection) sourceBill2.get("kded_attachment");
//获取源附件字段附件对象id集合 
List<Long> attchIdSet = new ArrayList<>();
sourceAttachcol.forEach(attach -> {
    attchIdSet.add(attach.getDynamicObject("fbasedataId").getLong("id"));
});

 

(2) 给目标附件字段赋值

方案一:因为在目标单据页面操作,获取源附件字段附件对象bd_attachmentid通过setValue赋值给目标附件字段即可

关键代码:

getModel().setValue("kded_attachment", attchIdSet.toArray());

 

方案二:后台处理可先获取目标单据附件字段的集合,根据源附件字段附件对象idbd_attachment)加载附件数据再通过fbasedataid赋值给目标附件字段

关键代码:

DynamicObjectCollection targetAttachCol = this.getModel().getDataEntity(true).getDynamicObjectCollection("kded_attachment");
DynamicObject[] sourceAttachments = BusinessDataServiceHelper.load(attchIdSet.toArray(), EntityMetadataCache.getDataEntityType("bd_attachment"));
//将bd_attachment查出来的附件对象绑定到目标附件字段上,即跟源单共用附件基础资料
Arrays.asList(sourceAttachments).forEach(attachObj -> 
    targetAttachCol.addNew().set("fbasedataid", attachObj)
);
//刷新当前页面验证效果
getView().updateView("kded_attachment");

 

注意:案例中此时源字段与目标字段共用同个附件对象数据,有一方删除附件则另一方也同时删除。可通过附件url获取文件流再自行上传至文件服务器创建另一个附件对象。

 

4. 附件字段To附件面板

(1) 获取源附件字段附件对象bd_attachment)数据

关键代码:

//获取源附件字段的值
DynamicObject sourceBill3 = BusinessDataServiceHelper.loadSingle("kded_sourcebill", "id,kded_attachment", qFilter3.toArray());
DynamicObjectCollection sourceAttachCol3 = (DynamicObjectCollection) sourceBill3.get("kded_attachment");

 

(2) 根据附件字段数据构造附件面板数据,通过FileServiceFactory获取AttachmentFileService,并通过附件字段附件对象数据获取源附件文件流上传到文件服务器,拿到返回的url构造附件面板数据集。

关键代码:

//根据附件字段数据构造附件面板数据
Map<String, Object> attachemnts = new HashMap<>();
List<Map<String, Object>> attachmentData3 = buildAttachmentDataFromEdit(sourceAttachCol3);
//key:目标附件面板标识,value:目标附件面板附件数据
attachemnts.put("attachmentpanel", attachmentData3);
 
/**
 * 根据附件字段数据构造附件面板数据
 * @param sourceAttachCol
 * @return
 */
private List<Map<String, Object>> buildAttachmentDataFromEdit(DynamicObjectCollection sourceAttachCol) {
    List<Map<String, Object>> attachDataList = new ArrayList<>();
    sourceAttachCol.forEach(attach -> {
        DynamicObject attachObj = attach.getDynamicObject("fbasedataid");
        Map<String, Object> attachMap = new HashMap<>();
        //description
        attachMap.put("description", attachObj.getString("description"));
        attachMap.put("type", attachObj.getString("type"));
        //获取附件inputstream上传到缓存服务
        InputStream inputStream = FileServiceFactory.getAttachmentFileService().getInputStream(attachObj.getString("url"));
        String saveUrl = CacheFactory.getCommonCacheFactory().getTempFileCache().saveAsFullUrl(attachObj.getString("name"), new BufferedInputStream(inputStream), 2*3600);
        //url
        attachMap.put("url", saveUrl);
        //uid
        attachMap.put("uid", getUid());
        //name
        attachMap.put("name", attachObj.getString("name"));
        //size
        attachMap.put("size", attachObj.get("size"));
        attachMap.put("fattachmentpanel", "attachmentpanel");
        //entityNum
        attachMap.put("entityNum", getView().getEntityId());
        attachMap.put("billPkId", String.valueOf(getModel().getValue("id")));
        //lastModified
        attachMap.put("lastModified", new Date().getTime());
        attachMap.put("status", "success");
        //client
        attachMap.put("client", null);
        attachDataList.add(attachMap);
    });
    return attachDataList;
}

 

(3) 调用AttachmentServiceHelper.saveTempAttachments(String, Object, String, Map<String, Object>)将数据绑定到目标附件面板

关键代码:

AttachmentServiceHelper.saveTempAttachments(getView().getEntityId(), getModel().getValue("id"), "kded_clztest", attachemnts);
//刷新页面
getView().updateView("attachmentpanel");

四、效果图

1. 附件面板To附件面板,如图1-3

 

 

图片1.png

源单据附件面板上传图片

图片2.png

 

通过插件将源附件面板图片上传到目标附件面板

图片3.png

 

3 目标附件面板图片可正常浏览

 

2. 附件面板To附件字段,借用图1附件面板的数据0.0,如图4,也可正常浏览的噢

图片4.png

4 通过插件将源附件面板图片上传到目标附件字段

3. 附件字段To附件字段,如图5-6,还是可以正常浏览哒

图片5.png

  

5 源单据附件字段上传图片

 

图片6.png

6 通过插件将源附件字段图片上传到目标附件字段

 

4. 附件字段To附件面板,借用图5附件面板的数据0-0,如图7

图片7.png

 

7 通过插件将源附件字段图片上传到目标附件面板


图标赞 29
29人点赞
还没有人点赞,快来当第一个点赞的人吧!
图标打赏
0人打赏
还没有人打赏,快来当第一个打赏的人吧!