package shkd.repc.repmd.formplugin; import com.alibaba.dubbo.common.utils.CollectionUtils; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import kd.bos.dataentity.OperateOption; import kd.bos.dataentity.entity.DynamicObject; import kd.bos.dataentity.entity.DynamicObjectCollection; import kd.bos.dataentity.utils.StringUtils; import kd.bos.entity.datamodel.IDataModel; import kd.bos.entity.datamodel.RowDataEntity; import kd.bos.entity.datamodel.events.AfterAddRowEventArgs; import kd.bos.entity.datamodel.events.BeforeImportEntryEventArgs; import kd.bos.entity.datamodel.events.ImportDataEventArgs; import kd.bos.entity.datamodel.events.PropertyChangedArgs; import kd.bos.entity.operate.result.OperationResult; import kd.bos.entity.plugin.ImportLogger; import kd.bos.form.container.Tab; import kd.bos.form.control.Control; import kd.bos.form.control.EntryGrid; import kd.bos.form.control.Label; import kd.bos.form.control.Toolbar; import kd.bos.form.control.events.BeforeItemClickEvent; import kd.bos.form.control.events.ItemClickEvent; import kd.bos.form.control.events.RowClickEvent; import kd.bos.form.control.events.RowClickEventListener; import kd.bos.form.events.ClientCallBackEvent; import kd.bos.form.plugin.AbstractFormPlugin; import kd.bos.form.plugin.importentry.resolving.ImportEntryData; import kd.bos.orm.query.QCP; import kd.bos.orm.query.QFilter; import kd.bos.servicehelper.BusinessDataServiceHelper; import kd.bos.servicehelper.operation.OperationServiceHelper; import kd.bos.servicehelper.operation.SaveServiceHelper; import kd.sdk.plugin.Plugin; import kd.tsc.tsrbs.business.domain.oprecord.service.helper.OprecordHelper; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; /** * 位置:【项目主数据】-【项目建立】-表单插件 * 功能:面积数据合计赋值 * 时间:2024/12/16 */ public class TotalAssignmentPlugin extends AbstractFormPlugin implements RowClickEventListener, Plugin { private static final String BILL_NAME="billname"; private static final String RENTAL_AREA="qeug_decimalfield5"; private static final String RENTAL_AREA_ENTRY="qeug_productentry_saleare"; private static final String ENTRY_VALUE = "qeug_jrgsbsz"; private static final String PRODUCT_ENTRY = "productentry"; private static final String PRODUCT_TYPE = "productentry_producttype"; private static final String PRODUCT_TYPE_NUMBER = "productentry_producttype.longnumber"; private static final String SUB_ENTRY = "qeug_subentryentity"; // 控件缓存 private Label publicAmountLabel; private Label watertightAmountLabel; private Label hardcoverAmountLabel; @Override public void registerListener(EventObject e) { super.registerListener(e); this.addItemClickListeners("tbmain"); this.addItemClickListeners("advcontoolbarap"); this.addItemClickListeners("qeug_advcontoolbarap"); EntryGrid entryGrid = this.getControl(PRODUCT_ENTRY); entryGrid.addRowClickListener(this); // 缓存控件,减少重复调用 publicAmountLabel = (Label) this.getControl("qeug_publicamount"); watertightAmountLabel = (Label) this.getControl("qeug_watertightamount"); hardcoverAmountLabel = (Label) this.getControl("qeug_hardcoveramount"); } @Override public void clientCallBack(ClientCallBackEvent e) { super.clientCallBack(e); String name = e.getName(); if ("auto_save".equals(name)) { this.getView().invokeOperation("save"); } } @Override public void entryRowClick(RowClickEvent evt) { EntryGrid entryGrid = (EntryGrid) evt.getSource(); if (PRODUCT_ENTRY.equals(entryGrid.getKey())) { //选中行 int[] selectRows = entryGrid.getSelectRows(); if (selectRows != null && selectRows.length > 0) { //产品构成 DynamicObjectCollection productEntity = this.getModel().getEntryEntity(PRODUCT_ENTRY); if (null !=productEntity && productEntity.size()!=0){ DynamicObjectCollection areaEntry = new DynamicObjectCollection(); for (int selectRow : selectRows) { DynamicObject productObj = productEntity.get(selectRow); if (null!=productObj){ DynamicObjectCollection collection = productObj.getDynamicObjectCollection(SUB_ENTRY); if (null!=collection&&collection.size()!=0){ areaEntry.addAll(collection); } } } if (areaEntry.size()!=0) { onlyCalculateArea(areaEntry); } this.getView().updateView(SUB_ENTRY); } } } } @Override public void propertyChanged(PropertyChangedArgs e) { super.propertyChanged(e); publicAmountLabel = (Label) this.getControl("qeug_publicamount"); watertightAmountLabel = (Label) this.getControl("qeug_watertightamount"); hardcoverAmountLabel = (Label) this.getControl("qeug_hardcoveramount"); String fieldKey = e.getProperty().getName(); switch (fieldKey){ case ENTRY_VALUE: int index = this.getModel().getEntryCurrentRowIndex(PRODUCT_ENTRY); DynamicObjectCollection collections = (DynamicObjectCollection) this.getModel().getValue(SUB_ENTRY); if (null!=collections&&collections.size()!=0){ DynamicObject parent = (DynamicObject) collections.get(0).getParent(); Long id = parent.getLong("id"); if (id != 0L) { //更新指标信息数据 Object pkValue = this.getModel().getValue("id"); Long typeId = parent.getLong("productentry_producttype.id"); this.updateMetricInfo(collections, typeId, pkValue); //更新产品构成数据(不切换标签也能生效) DynamicObjectCollection productEntry = this.getModel().getEntryEntity(PRODUCT_ENTRY); this.setProductEntryValue(productEntry,collections,id); } //依旧选择该行数据 EntryGrid entryGrid = this.getControl("productentry"); entryGrid.selectRows(index); } break; case BILL_NAME: String value = (String) this.getModel().getValue("billno"); if (value != null) { this.getView().addClientCallBack("auto_save", 0); } break; case RENTAL_AREA_ENTRY: BigDecimal canSaleArea=BigDecimal.ZERO; DynamicObjectCollection productEntry = this.getModel().getEntryEntity(PRODUCT_ENTRY); if (null!=productEntry){ for (DynamicObject dynamicObject : productEntry) { BigDecimal area = dynamicObject.getBigDecimal(RENTAL_AREA_ENTRY); if (area.compareTo(BigDecimal.ZERO)!=0){ canSaleArea=canSaleArea.add(area); } } this.getModel().setValue(RENTAL_AREA,canSaleArea); } break; } } @Override public void afterBindData(EventObject e) { super.afterBindData(e); DynamicObjectCollection productEntry = this.getModel().getEntryEntity(PRODUCT_ENTRY); if (null != productEntry && productEntry.size() != 0) { //进入页面 boolean isImport = productEntry.stream() .allMatch(d -> d.getLong("id") != 0L); //防止页面打开触发该方法 if (!isImport){ //选中第一条数据 EntryGrid entryGrid = this.getControl("productentry"); entryGrid.selectRows(0); //已保存数据的产品id Set savedProductTypeIds = productEntry.stream() .filter(d -> d.getLong("id")!=0L) .map(d -> d.getLong("productentry_producttype.id")) .collect(Collectors.toSet()); //相同产品数据 boolean exitSameProduct = false; // 2. 倒序循环检查未保存数据(id == 0L) for (int i = productEntry.size() - 1; i >= 0; i--) { DynamicObject dynamicObject = productEntry.get(i); long id = dynamicObject.getLong("id"); if (id == 0L) { // 未保存数据 long productTypeId = dynamicObject.getLong("productentry_producttype.id"); if (savedProductTypeIds.contains(productTypeId)) { // 获取未保存数据的 transferredEntry DynamicObjectCollection transferredEntry = dynamicObject.getDynamicObjectCollection(SUB_ENTRY); if (transferredEntry != null && !transferredEntry.isEmpty()) { // 3. 查找对应的已保存数据 for (DynamicObject savedObject : productEntry) { if (savedObject.getLong("id") != 0L && savedObject.getLong("productentry_producttype.id")==productTypeId) { // 4. 替换已保存数据的 SUB_ENTRY savedObject.set(SUB_ENTRY, transferredEntry); // 5. 移除未保存的数据 productEntry.remove(i); exitSameProduct=true; break; // 找到匹配项后就可以退出循环 } } } } } } if (exitSameProduct){ for (int i = 0; i < productEntry.size(); i++) { //获取产品构成分录相关联的面积数据分录 DynamicObjectCollection collections = productEntry.get(i).getDynamicObjectCollection(SUB_ENTRY); //先清空计入估算表数值再赋值,触发保存 for (int j = 0; j < collections.size(); j++) { if (collections.get(j).getString("qeug_fl").equals("非标")){ this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ONE, j, i); this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ZERO, j, i); }else { this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ZERO, j, i); BigDecimal hjs = collections.get(j).getBigDecimal("qeug_hjs"); BigDecimal tzz = collections.get(j).getBigDecimal("qeug_tzz"); this.getModel().setValue("qeug_jrgsbsz", hjs.add(tzz), j, i); } } } }else { DynamicObjectCollection subEntryEntity = (DynamicObjectCollection) this.getModel().getValue(SUB_ENTRY); if (null != subEntryEntity && subEntryEntity.size() != 0) { //获取产品构成分录父数据实体类型 DynamicObject parent = (DynamicObject) ((DynamicObject) subEntryEntity.getParent()).getParent(); DynamicObjectCollection productParent = parent.getDynamicObjectCollection(PRODUCT_ENTRY); for (int i = 0; i < productParent.size(); i++) { //获取产品构成分录相关联的面积数据分录 DynamicObjectCollection collections = productParent.get(i).getDynamicObjectCollection(SUB_ENTRY); //先清空计入估算表数值再赋值,触发保存 for (int j = 0; j < collections.size(); j++) { if (collections.get(j).getString("qeug_fl").equals("非标")){ this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ONE, j, i); this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ZERO, j, i); }else { this.getModel().setValue("qeug_jrgsbsz", BigDecimal.ZERO, j, i); BigDecimal hjs = collections.get(j).getBigDecimal("qeug_hjs"); BigDecimal tzz = collections.get(j).getBigDecimal("qeug_tzz"); this.getModel().setValue("qeug_jrgsbsz", hjs.add(tzz), j, i); } } } } } this.getView().addClientCallBack("auto_save", 0); } } } @Override public void afterCreateNewData(EventObject e) { super.afterCreateNewData(e); DynamicObjectCollection keynodeentry = (DynamicObjectCollection)this.getModel().getValue("keynodeentry"); if (keynodeentry!=null) { for (int i = 0; i < keynodeentry.size(); i++) { DynamicObject dynamicObject = keynodeentry.get(i); switch (i+1){ case 1:dynamicObject.set("knentry_node","现场踏勘");break; case 2:dynamicObject.set("knentry_node","项目立项");break; case 3:dynamicObject.set("knentry_node","项目启动");break; case 4:dynamicObject.set("knentry_node","房屋移交");break; case 5:dynamicObject.set("knentry_node","编制项目规划表、供应商需求计划");break; case 6:dynamicObject.set("knentry_node","施工图审查");break; case 7:dynamicObject.set("knentry_node","施工许可证办理");break; case 8:dynamicObject.set("knentry_node","招商中心工程完成");break; case 9:dynamicObject.set("knentry_node","公区改造完成");break; case 10:dynamicObject.set("knentry_node","样板间改造完成");break; case 11:dynamicObject.set("knentry_node","外墙改造完成");break; case 12:dynamicObject.set("knentry_node","室外改造工程完成");break; case 13:dynamicObject.set("knentry_node","工程估算范围内其他工程完成");break; case 14:dynamicObject.set("knentry_node","投资类改造工程完成");break; case 15:dynamicObject.set("knentry_node","改造工程内部竣工验收完成");break; case 16:dynamicObject.set("knentry_node","政府竣备验收完成");break; case 17:dynamicObject.set("knentry_node","项目移交");break; } } } } @Override public void itemClick(ItemClickEvent evt) { super.itemClick(evt); if (StringUtils.equals("qeug_advconbaritemap7", evt.getItemKey())) { //表单id Object pkValue = this.getModel().getValue("id"); DynamicObjectCollection productEntry = this.getModel().getEntryEntity(PRODUCT_ENTRY); if (null != productEntry && productEntry.size() != 0) { for (int i = 0; i < productEntry.size(); i++) { DynamicObjectCollection collections = productEntry.get(i).getDynamicObjectCollection(SUB_ENTRY); if (null!=collections){ this.setProductEntryValue(productEntry,collections,productEntry.get(i).getLong("id")); //指标信息赋值 Long typeId = productEntry.get(i).getLong("productentry_producttype.id"); this.updateMetricInfo(collections, typeId, pkValue); } } Tab tab = this.getView().getControl("tabap"); tab.activeTab("indexpage_tab"); } } else if (StringUtils.equals("deleteproductentry", evt.getItemKey())) { //保存表单 this.getView().addClientCallBack("auto_save", 0); //清空标签控件 updateLabel(publicAmountLabel, BigDecimal.ZERO); updateLabel(watertightAmountLabel, BigDecimal.ZERO); updateLabel(hardcoverAmountLabel, BigDecimal.ZERO); } } @Override public void beforeImportEntry(BeforeImportEntryEventArgs e) { super.beforeImportEntry(e); Set existCodes = new HashSet<>(); DynamicObjectCollection orderFormEntry = (DynamicObjectCollection) this.getModel().getValue(PRODUCT_ENTRY); if (null != orderFormEntry && orderFormEntry.size() != 0) { for (DynamicObject dynamicObject : orderFormEntry) { String number = dynamicObject.getString(PRODUCT_TYPE_NUMBER); existCodes.add(number); } } Set>> entries = ((HashMap) e.getSource()).entrySet(); for (Map.Entry> entry : entries) { String entryName = entry.getKey(); List entryEntityImportDataList = entry.getValue(); if (CollectionUtils.isEmpty(entryEntityImportDataList)) { return; } Map indexVsMsgMap = validateEntry(entryEntityImportDataList, existCodes); Set indexSet = indexVsMsgMap.keySet(); Map> logMap = e.getEntryDataMap(); ImportLogger importLogger = (ImportLogger) logMap.get(entryName).get(0); for (Map.Entry indexVsMsgEntry : indexVsMsgMap.entrySet()) { Integer index = indexVsMsgEntry.getKey(); importLogger.log(index, indexVsMsgEntry.getValue()); importLogger.fail(); importLogger.setTotal(importLogger.getTotal() + 1); } Iterator iterator = entryEntityImportDataList.iterator(); while (iterator.hasNext()) { ImportEntryData entryData = iterator.next(); Integer rowNum = (Integer) entryData.getData().get("rowNum"); if (indexSet.contains(rowNum)) { iterator.remove(); } } // **合并相同编码的 qeug_subentryentity** Map> groupedByNumber = new HashMap<>(); // 将 entryEntityImportDataList 按照 number 分组 for (ImportEntryData entryData : entryEntityImportDataList) { String number = entryData.getData().getJSONObject("productentry_producttype").getString("number"); groupedByNumber.putIfAbsent(number, new ArrayList<>()); groupedByNumber.get(number).add(entryData); } // 遍历按 number 分组的条目并合并 qeug_subentryentity List mergedEntries = new ArrayList<>(); for (List groupedEntries : groupedByNumber.values()) { ImportEntryData firstEntry = groupedEntries.get(0); JSONArray mergedSubEntryEntities = firstEntry.getData().getJSONArray("qeug_subentryentity"); // 合并相同 number 的所有 qeug_subentryentity for (int i = 1; i < groupedEntries.size(); i++) { ImportEntryData currentEntry = groupedEntries.get(i); JSONArray currentSubEntryEntities = currentEntry.getData().getJSONArray("qeug_subentryentity"); // 将当前的 qeug_subentryentity 加入到 mergedSubEntryEntities mergedSubEntryEntities.addAll(currentSubEntryEntities); } // 更新第一个条目的 qeug_subentryentity 为合并后的结果 firstEntry.getData().put("qeug_subentryentity", mergedSubEntryEntities); // 将合并后的条目添加到结果列表中 mergedEntries.add(firstEntry); } // 更新 entryEntityImportDataList 为合并后的条目 entryEntityImportDataList.clear(); entryEntityImportDataList.addAll(mergedEntries); } } private Map validateEntry(List entryEntityImportDataList, Set existCodes) { Map indexVsMsgMap = new HashMap<>(); for (int i = 0; i < entryEntityImportDataList.size(); i++) { ImportEntryData entryData = entryEntityImportDataList.get(i); // 获取当前行的 JSONObject 数据 JSONObject data = entryData.getData(); Map map = data.toJavaObject(Map.class); JSONObject productType = (JSONObject) map.get(PRODUCT_TYPE); // 获取编码 String number = productType.getString("number"); // 获取当前行号 Integer rowNum = (Integer) entryData.getData().get("rowNum"); // 校验物料编码和物料单位 if (number == null || number.trim().isEmpty()) { indexVsMsgMap.put(rowNum, "第" + (i + 1) + "行:产品类型编码不能为空或空字符串"); } // 校验物料编码是否已经存在于当前页面的表格中 // if (existCodes.contains(number)) { // indexVsMsgMap.put(rowNum, "第" + (i + 1) + "行:产品类型编码已存在表单分录,不能重复导入"); // } } return indexVsMsgMap; } private void onlyCalculateArea(DynamicObjectCollection subEntryEntity) { if (subEntryEntity == null || subEntryEntity.isEmpty()) { return; // 防止空集合 } // 合计值 BigDecimal publicArea = BigDecimal.ZERO; BigDecimal publicAndInside = BigDecimal.ZERO; BigDecimal watertight = BigDecimal.ZERO; BigDecimal hardcover = BigDecimal.ZERO; // 分类处理 for (DynamicObject entry : subEntryEntity) { String type = entry.getString("qeug_fl"); BigDecimal value = entry.getBigDecimal(ENTRY_VALUE); if (StringUtils.isNotEmpty(type)) { switch (type) { case "公区": publicArea = publicArea.add(value); publicAndInside = publicAndInside.add(value); break; case "套内": publicAndInside = publicAndInside.add(value); hardcover = hardcover.add(value); break; case "防水": watertight = watertight.add(value); break; case "非标": case "总面积": case "可出租面积": break; default: this.getView().showMessage("无效的分类: " + type + ", 请重新选择!"); break; } } } // 更新控件显示 updateLabel(publicAmountLabel, publicArea); updateLabel(watertightAmountLabel, watertight); updateLabel(hardcoverAmountLabel, hardcover); } private void updateLabel(Label label, BigDecimal value) { // 设置值并确保格式化保留两位小数 if (label != null && value != null) { label.setText(value.setScale(2, RoundingMode.HALF_UP).toString()); } } /** * 更新指标信息 * * @param collections 面积数据分录数据 * @param productTypeId 产品构成产品类型 * @param pkValue 表单id */ private void updateMetricInfo(DynamicObjectCollection collections, Long productTypeId, Object pkValue) { //获取【总面积】分类的总面积 BigDecimal allArea=areaSummary(collections,"总面积"); // 获取【总面积】分类的地下面积汇总值 BigDecimal groundFloorSummary = collections.stream() .filter(collection -> "总面积".equals(collection.getString("qeug_fl"))) .map(collection -> { // 获取两个 BigDecimal 值,如果为 null,则使用 BigDecimal.ZERO BigDecimal b1f = collection.getBigDecimal("qeug_b1f") != null ? collection.getBigDecimal("qeug_b1f") : BigDecimal.ZERO; BigDecimal b2f = collection.getBigDecimal("qeug_b2f") != null ? collection.getBigDecimal("qeug_b2f") : BigDecimal.ZERO; return b1f.add(b2f); // 返回 b1f 和 b2f 的和 }) .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加所有的和 // 获取地上面积 - 地下面积 - 防水面积 BigDecimal groundSummary = allArea.subtract(groundFloorSummary); // 获取精装面积汇总值 BigDecimal hardcoverSummary = areaSummary(collections,"套内"); QFilter qFilter = new QFilter("mainprojectid", QCP.equals, pkValue); DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle("repmd_index_products", qFilter.toArray()); if (null != dynamicObject) { DynamicObjectCollection buildingEntry = dynamicObject.getDynamicObjectCollection("buildingindexentry"); if (buildingEntry != null && buildingEntry.size() != 0) { for (DynamicObject entry : buildingEntry) { Long typeId = entry.getLong("buildentry_producttype.id"); if (typeId.compareTo(productTypeId) == 0) { entry.set("buildentry_allbuildarea", groundSummary.add(groundFloorSummary)); entry.set("buildentry_onbuildarea", groundSummary); entry.set("buildentry_downbuildarea", groundFloorSummary); entry.set("buildentry_finedecortarea", hardcoverSummary); SaveServiceHelper.update(dynamicObject); } } } } } /** * 产品构成分录赋值 * * @param productEntry 产品构成分录 * @param collections 面积数据分录 * @param id 产品构成分录id */ private void setProductEntryValue(DynamicObjectCollection productEntry, DynamicObjectCollection collections, Long id) { //公区面积汇总 BigDecimal publicArea=BigDecimal.ZERO; BigDecimal hardcoverArea=BigDecimal.ZERO; BigDecimal waterproofArea=BigDecimal.ZERO; BigDecimal hireArea=BigDecimal.ZERO; BigDecimal allArea=BigDecimal.ZERO; if (collections.size()!=0){ //公区面积汇总 publicArea = areaSummary(collections,"公区"); //套内面积汇总 hardcoverArea = areaSummary(collections,"套内"); //防水面积汇总 waterproofArea = areaSummary(collections,"防水"); //可出租面积 hireArea = areaSummary(collections,"可出租面积"); //总面积 allArea = areaSummary(collections,"总面积"); } for (int i = 0; i < productEntry.size(); i++) { DynamicObject dynamicObject = productEntry.get(i); Long id1 = dynamicObject.getLong("id"); if (id1.compareTo(id) == 0) { //改建后建筑面积 dynamicObject.set("productentry_buildingarea",allArea); //实际装修面积=公区+套内 dynamicObject.set("qeug_actualarea", publicArea.add(hardcoverArea)); //防水面积 dynamicObject.set("qeug_waterproofarea",waterproofArea); //改建后可出租面积 dynamicObject.set("qeug_productentry_saleare",hireArea); SaveServiceHelper.update(dynamicObject); } } this.getView().updateView("productentry"); // 更新控件显示 updateLabel(publicAmountLabel, publicArea); updateLabel(watertightAmountLabel, waterproofArea); updateLabel(hardcoverAmountLabel, hardcoverArea); } /** * 面积分类汇总 * @param collections * @param type * @return */ private BigDecimal areaSummary(DynamicObjectCollection collections,String type){ return collections.stream() .filter(collection -> type.equals(collection.getString("qeug_fl"))) .map(collection -> { BigDecimal hjs = collection.getBigDecimal("qeug_hjs"); BigDecimal tzz = collection.getBigDecimal("qeug_tzz"); return hjs.add(tzz); }) .reduce(BigDecimal.ZERO, BigDecimal::add); } }