如何存储Spread数据及Spread控件如何与后台交互原创
金蝶云社区-cosmicstudio
cosmicstudio
16人赞赏了该文章 4,944次浏览 未经作者许可,禁止转载编辑于2022年04月15日 13:55:19
summary-icon摘要由AI智能服务提供

本文介绍了Spread控件的基本用法及其与后台交互的实现。Spread控件是一个纯前端表格控件,功能类似于Excel,支持在线导入导出Excel、在线编辑等。文章详细说明了使用Spread控件需要考虑的问题,包括其用途、数据存储以及与后台的交互方式。接着,介绍了Spread控件的具体实现过程,包括控件的初始化、数据存储的实现,以及通过编写插件实现Spread控件与后台的数据保存、加载及指令交互。具体展示了如何创建基础资料来存储SpreadJson数据,并通过插件实现Spread控件的保存功能。

关键词:Spread控件

 

一、需求

Spread控件介绍Spread控件具体怎么用

二、思路与方案

使用Spread控件要考虑几个问题:

1. Spread控件是来做什么的

2. Spread数据怎么存储

3. Spread控件怎么与后台交互

三、实现过程

1. Spread控件介绍

1) 纯前端表格控件,功能布局与 Excel 高度类似

2) 在线导入、导出Excel(xlsx)

3) 在线表格编辑器

4) Spread控件官网: https://www.grapecity.com.cn/developer/spreadjs

 image.png

1

 

2. Spread数据存储

创建一个基础资料来存SpreadJson数据

 image.png

2

3. Spread控件怎么与后台交互

开发平台添加Spread通用控件

 image.png

3

预览添加后的效果

 image.png

4

编写插件实现Spread控件数据保存加载与控件按钮前后端指令交互

package kd.bos.debug.mservice.spread;

import kd.bos.context.RequestContext;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.form.IClientViewProxy;
import kd.bos.form.control.events.ItemClickEvent;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.form.spread.event.ISpreadAction;
import kd.bos.id.ID;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.TimeServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import org.apache.commons.lang3.StringUtils;

import java.util.EventObject;
import java.util.HashMap;
import java.util.Map;

public class SpreadBasePlugin extends AbstractFormPlugin {

    /**
     * 获取Spread控件标识
     * @return
     */
    public String getSpreadKey() {
        return "template_spread";
    }

    /**
     * 侦听各个控件的插件事件
     * @param e
     */
    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        // 侦听工具栏点击事件
        this.addItemClickListeners(new String[]{"toolbarap"});
    }

    @Override
    public void initialize() {
        super.initialize();
        // 初始化后端响应前端事件类
        this.getView().addService(ISpreadAction.class, this.getSpreadDataModelService());
    }

    protected ISpreadAction getSpreadDataModelService() {
        // 参数当前传表单插件 可用于回调表单插件方法 获取视图模型等
        return new SpreadDataModelImpl(this);
    }

    @Override
    public void afterCreateNewData(EventObject e) {
        super.afterCreateNewData(e);

        String json = StringUtils.EMPTY;
        DynamicObject dynamicObject;
        Long id = this.getView().getFormShowParameter().getCustomParam("id");
        if (id != null && id != 0) {
            this.getModel().setValue("kdec_model_id", id);
            // 查询spread基础资料数据用于回显
            dynamicObject = BusinessDataServiceHelper.loadSingleFromCache(id, "kdec_spread_data", "id,name,number,enable,status,spreadjson,creator,createtime,modifytime,modifier");
            if (dynamicObject != null) {
                json = dynamicObject.getString("spreadjson");
            }
        }

        if (StringUtils.isNotBlank(json)) {
            // 发送指令初始化spread表格内容
            IClientViewProxy view = this.getView().getService(IClientViewProxy.class);
            view.invokeControlMethod(this.getSpreadKey(), "setSpreadJson", new Object[]{json});
        }
    }

    @Override
    public void itemClick(ItemClickEvent evt) {
        super.itemClick(evt);
        String itemKey = evt.getItemKey();
        switch (itemKey) {
            case "btn_save":
                this.invokeSaveEvent();
                break;
        }
    }

    /**
     * 后台给前端发指令 获取前端spreadjson串 并回调保存spread数据
     */
    private void invokeSaveEvent() {
        Map<String, String> params = new HashMap();
        params.put("callback", "invokeAction");
        params.put("invokemethod", "actionSave");

        // 后台给前端发指令 获取前端spreadjson串
        IClientViewProxy view = this.getView().getService(IClientViewProxy.class);
        view.invokeControlMethod(this.getSpreadKey(), "getSpreadJson", new Object[]{params});

    }

    /**
     * 回调方法保存spread数据
     *
     * @param spreadJson
     */
    public void actionSave(String spreadJson) {
        DynamicObject dynamicObject = null;
        Long modelID = (Long) this.getModel().getValue("kdec_model_id");
        if (modelID != null) {
            dynamicObject = BusinessDataServiceHelper.loadSingleFromCache(modelID, "kdec_spread_data", "id,name,number,enable,status,spreadjson,creator,createtime,modifytime,modifier");
        }

        if (dynamicObject != null) {
            dynamicObject.set("modifier", RequestContext.get().getCurrUserId());
            dynamicObject.set("modifytime", TimeServiceHelper.now());
            dynamicObject.set("spreadJson", spreadJson);
        } else {
            dynamicObject = BusinessDataServiceHelper.newDynamicObject("kdec_spread_data");
            dynamicObject.set("enable", 1);
            dynamicObject.set("status", "B");
            dynamicObject.set("number", ID.genStringId());
            dynamicObject.set("name", ID.genStringId());
            dynamicObject.set("spreadJson", spreadJson);
            dynamicObject.set("creator", RequestContext.get().getCurrUserId());
            dynamicObject.set("createtime", TimeServiceHelper.now());
        }

        // 调用保存操作保存spread数据
        OperationResult result = SaveServiceHelper.saveOperate("kdec_spread_data", new DynamicObject[]{dynamicObject}, OperateOption.create());
        if (result.isSuccess()) {
            this.getView().showSuccessNotification("保存成功!");
            this.getModel().setValue("kdec_model_id", dynamicObject.getPkValue());
        } else {
            // 返回错误信息
            this.getView().showOperationResult(result);
        }
    }

}

后台响应前端按钮事件:

继承kd.bos.form.spread.SpreadActionAdapter,实现前端过来的相关指令

初始化插件 initialize() 方法中实现这个服务

package kd.bos.debug.mservice.spread;

import kd.bos.exception.KDBizException;
import kd.bos.form.IClientViewProxy;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.form.spread.Spread;
import kd.bos.form.spread.SpreadActionAdapter;
import kd.bos.form.spread.SpreadPostDataInfo;
import kd.bos.form.spread.event.SpreadEvent;
import org.apache.commons.beanutils.MethodUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class SpreadDataModelImpl extends SpreadActionAdapter {

    public SpreadDataModelImpl(AbstractFormPlugin plugin) {
        super(plugin);
    }

    /**
     * 删除行
     * @param event
     */
    @Override
    public void deleteRows(SpreadEvent event) {

    }

    /**
     * 删除列
     * @param event
     */
    @Override
    public void deleteColumns(SpreadEvent event) {

    }

    /**
     * 新增行
     * @param event
     */
    @Override
    public void addRows(SpreadEvent event) {

    }

    /**
     * 新增列
     * @param event
     */
    @Override
    public void addColumns(SpreadEvent event) {
    }

    /**
     * 获取客户端视图代理
     * @return
     */
    public IClientViewProxy getClientViewProxy() {
        return this.plugin.getView().getService(IClientViewProxy.class);
    }

    /**
     * 删除 插入 行列 询问是否执行事件
     * @param event
     */
    @Override
    public void askExecute(SpreadEvent event) {
        super.askExecute(event);
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
        LinkedHashMap<String, Object> invokeParams =  data.getInvokeParams();
        if (invokeParams != null && invokeParams.size() > 0) {
            LinkedHashMap<String, Object> e = data.getInvokeParams();
            List<Integer> val = (List)e.get("data");
            String method = (String)e.get("method");
            updateRowAndCol2View(getClientViewProxy(),spread.getKey(),val,method);
        }
    }

    private void updateRowAndCol2View(IClientViewProxy view, String spreadKey,  List<Integer> val,String method) {
        LinkedHashMap<String, Object> map = new LinkedHashMap();
        map.put("status", true);
        if (val.size() > 0) {
            map.put("data", val);
            view.invokeControlMethod(spreadKey, method, new Object[]{map});
        }
    }

    /**
     * 表格选择范围
     * @param event
     */
    @Override
    public void selectedSpread(SpreadEvent event) {
        SpreadPostDataInfo data = event.getPostData();
        if (data.getSelRows() != null && data.getSelRows().size() > 0 && data.getSelCols() != null && data.getSelCols().size() > 0) {

        }

    }

    /**
     * 更新单元格值
     * @param event
     */
    @Override
    public void updateCellValue(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     * 公式修改
     * @param event
     */
    @Override
    public void updateFormula(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     *  显示单元格维度信息
     * @param event
     */
    @Override
    public void showCellDimInfo(SpreadEvent event) {

    }

    /**
     * 插入选择范围内行记录, 选择行往下移
     * @param event
     */
    @Override
    public void insertRangeRow(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     * 插入选择范围内列记录, 选择列往右移
     * @param event
     */
    @Override
    public void insertRangeCols(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     * 删除选择范围内行记录,选择行往上移
     * @param event
     */
    @Override
    public void delRangeRow(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     * 删除选择范围内列记录,选择列往左移
     * @param event
     */
    @Override
    public void delRangeCols(SpreadEvent event) {
        Spread spread = (Spread)event.getSource();
        SpreadPostDataInfo data = spread.getPostDataInfo();
    }

    /**
     * F7手工录入模糊匹配查询处理
     * @param event
     */
    @Override
    public void getLookupData(SpreadEvent event) {
        if (event.getPostData().getInvokeParams() != null) {
            int r = (Integer)event.getPostData().getInvokeParams().get("r");
            int c = (Integer)event.getPostData().getInvokeParams().get("c");
            Map<String, Object> lookupDataInfo = (Map)event.getPostData().getInvokeParams().get("lookupInfo");

        }

    }

    /**
     * 回调插件方法
     * @param event
     */
    @Override
    public void invokePluginMethod(SpreadEvent event) {
        String methodName = (String)event.getPostData().getInvokeParams().get("invokemethod");
        Object data = event.getPostData().getInvokeParams().get("data");

        try {
            MethodUtils.invokeMethod(this.plugin, methodName, data);
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException var5) {
            this.handleException(var5);
        }

    }

    private void handleException(Exception e) {
        if (e != null && e.getCause() instanceof KDBizException) {
            throw (KDBizException)e.getCause();
        } else {
            throw new RuntimeException(e);
        }
    }
}

四、效果图

image.png 

图5

后台给前端发指令:

  • Spreadkey为界面上报表控件标识

  • Methodname为前端方法名

  • Map为前端参数

((IClientViewProxy)this.getView().getService(IClientViewProxy.class)).invokeControlMethod(spreadkey,methodname, map);

例如:

private void updateRowAndCol2View(IClientViewProxy view, String spreadKey,  List<Integer> val,String method) {
    LinkedHashMap<String, Object> map = new LinkedHashMap();
    map.put("status", true);
    if (val.size() > 0) {
        map.put("data", val);
        view.invokeControlMethod(spreadKey, method, new Object[]{map});
    }
}

 

 

五、开发环境版本

V4.0.015.0

 

六、参考资料

【开发平台】指导手册

学习成长中心

Spread开发

Spread控件支持查找替换功能

Spread控件快速实现报表打印

Spread指令方法

 

 

七、附件


spread.zip(12.93KB)

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

您的鼓励与嘉奖将成为创作者们前进的动力,如果觉得本文还不错,可以给予作者创作打赏哦!

请选择打赏金币数 *

10金币20金币30金币40金币50金币60金币
可用金币: 0