本文介绍了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
图1
2. Spread数据存储
创建一个基础资料来存SpreadJson数据
图2
3. Spread控件怎么与后台交互
开发平台添加Spread通用控件
图3
预览添加后的效果
图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); } } }
四、效果图
图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.zip(12.93KB)
推荐阅读