|
|
|
@ -19,11 +19,11 @@ import apelet.common.generator.model.OnlFormHead; |
|
|
|
import apelet.common.generator.service.IOnlFormFieldService; |
|
|
|
import apelet.common.generator.service.IOnlFormFieldService; |
|
|
|
import apelet.common.generator.service.IOnlFormHeadService; |
|
|
|
import apelet.common.generator.service.IOnlFormHeadService; |
|
|
|
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
|
|
|
import apelet.common.generator.utils.OrmGenDataSourceUtil; |
|
|
|
|
|
|
|
import apelet.common.online.config.OnlineProperties; |
|
|
|
import apelet.common.online.abstractplugin.ListDataEasService; |
|
|
|
import apelet.common.online.abstractplugin.ListDataEasService; |
|
|
|
import apelet.common.online.abstractplugin.ListDataOrmService; |
|
|
|
import apelet.common.online.abstractplugin.ListDataOrmService; |
|
|
|
import apelet.common.online.abstractplugin.ListDataService; |
|
|
|
import apelet.common.online.abstractplugin.ListDataService; |
|
|
|
import apelet.common.online.abstractplugin.model.GridData; |
|
|
|
import apelet.common.online.abstractplugin.model.GridData; |
|
|
|
import apelet.common.online.config.OnlineProperties; |
|
|
|
|
|
|
|
import apelet.common.online.dao.ConvertRelationFOnLineMapper; |
|
|
|
import apelet.common.online.dao.ConvertRelationFOnLineMapper; |
|
|
|
import apelet.common.online.dao.OnlineOperationMapper; |
|
|
|
import apelet.common.online.dao.OnlineOperationMapper; |
|
|
|
import apelet.common.online.dto.OnlineEventPluginExecuteDto; |
|
|
|
import apelet.common.online.dto.OnlineEventPluginExecuteDto; |
|
|
|
@ -32,8 +32,11 @@ import apelet.common.online.dto.OnlinePluginExecuteDto; |
|
|
|
import apelet.common.online.dto.OnlinePluginExecuteSortDto; |
|
|
|
import apelet.common.online.dto.OnlinePluginExecuteSortDto; |
|
|
|
import apelet.common.online.exception.OnlineRuntimeException; |
|
|
|
import apelet.common.online.exception.OnlineRuntimeException; |
|
|
|
import apelet.common.online.model.*; |
|
|
|
import apelet.common.online.model.*; |
|
|
|
import apelet.common.online.model.constant.*; |
|
|
|
import apelet.common.online.model.constant.EventEnum; |
|
|
|
import apelet.common.online.model.constant.FieldFilterType; |
|
|
|
import apelet.common.online.model.constant.FieldFilterType; |
|
|
|
|
|
|
|
import apelet.common.online.model.constant.FieldKind; |
|
|
|
|
|
|
|
import apelet.common.online.model.constant.RelationType; |
|
|
|
|
|
|
|
import apelet.common.online.model.constant.VirtualType; |
|
|
|
import apelet.common.online.object.ColumnData; |
|
|
|
import apelet.common.online.object.ColumnData; |
|
|
|
import apelet.common.online.object.ConstDictInfo; |
|
|
|
import apelet.common.online.object.ConstDictInfo; |
|
|
|
import apelet.common.online.object.JoinTableInfo; |
|
|
|
import apelet.common.online.object.JoinTableInfo; |
|
|
|
@ -50,6 +53,7 @@ import apelet.common.orm.impl.*; |
|
|
|
import apelet.common.redis.util.CommonRedisUtil; |
|
|
|
import apelet.common.redis.util.CommonRedisUtil; |
|
|
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
|
|
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollectionUtil; |
|
|
|
import cn.hutool.core.io.FileUtil; |
|
|
|
import cn.hutool.core.io.FileUtil; |
|
|
|
import cn.hutool.core.lang.Assert; |
|
|
|
import cn.hutool.core.lang.Assert; |
|
|
|
import cn.hutool.core.map.MapUtil; |
|
|
|
import cn.hutool.core.map.MapUtil; |
|
|
|
@ -1128,319 +1132,6 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 批量新增:一次提交多张新单据(库里不存在的数据)。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* <p>入参与单条 executePlugin 同名同义,只是 masterData 变成数组、每个元素一张单据; |
|
|
|
|
|
|
|
* 每张单据补齐主键后逐条走同一条单条保存链路(附件、反写等逻辑全部复用), |
|
|
|
|
|
|
|
* 整批一个事务,任一条失败整批回滚。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param onlinePluginExecuteDto 操作按钮等参数。 |
|
|
|
|
|
|
|
* @param masterDataArray 表头数据数组,每个元素一张单据。 |
|
|
|
|
|
|
|
* @param slaveData 分录数据对象(整批共享),或与表头数组同长度的数组,或 null。 |
|
|
|
|
|
|
|
* @return 操作结果。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public OperationResult executePluginBatch(OnlinePluginExecuteDto onlinePluginExecuteDto, |
|
|
|
|
|
|
|
JSONArray masterDataArray, Object slaveData) { |
|
|
|
|
|
|
|
if (masterDataArray == null || masterDataArray.isEmpty()) { |
|
|
|
|
|
|
|
return this.makeFailedResult("没有可保存的数据!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineForm onlineForm = onlineFormService.getOnlineFormFromCache(onlinePluginExecuteDto.getFormId()); |
|
|
|
|
|
|
|
if (onlineForm == null) { |
|
|
|
|
|
|
|
return this.makeFailedResult("数据验证失败,表单不存在或已失效,请刷新后重试!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(onlineForm.getMasterTableId()); |
|
|
|
|
|
|
|
if (onlineTable == null || onlineTable.getPrimaryKeyColumn() == null) { |
|
|
|
|
|
|
|
return this.makeFailedResult("数据验证失败,表单主表或主键配置缺失,无法批量新增!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<OnlinePluginExecuteSortDto> sortDtoList = this.getSortDtoList(onlineForm, onlinePluginExecuteDto.getButtonName()); |
|
|
|
|
|
|
|
if (!this.containsPlugin(sortDtoList, SaveOperationServicePlugIn.class)) { |
|
|
|
|
|
|
|
return this.makeFailedResult("批量新增仅支持绑定保存插件的按钮!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.executeBatchSave(onlinePluginExecuteDto, masterDataArray, slaveData, |
|
|
|
|
|
|
|
onlineForm, onlineTable, sortDtoList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 批量新增:把多张新单据拆成 N 份单条入参,补齐主键后逐条走单条保存链路。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* <p>补齐主键的原因:保存插件里表头主键为空会被当作「没有可保存的数据」跳过, |
|
|
|
|
|
|
|
* 而且分录的 parent_id 也要挂到表头主键上,所以先由 IdGeneratorWrapper 统一发号。 |
|
|
|
|
|
|
|
* 分录没有主键时同样补号,保证与新主键一起按每张单据各自保存、不会互相串。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param onlinePluginExecuteDto 操作按钮等参数。 |
|
|
|
|
|
|
|
* @param masterArray 表头数据数组。 |
|
|
|
|
|
|
|
* @param slaveData 分录数据对象,或与表头数组同长度的数组,或 null。 |
|
|
|
|
|
|
|
* @param onlineForm 当前表单。 |
|
|
|
|
|
|
|
* @param onlineTable 表头对应的在线数据表。 |
|
|
|
|
|
|
|
* @param sortDtoList 已解析并按执行顺序排好的插件列表(整批只需解析一次)。 |
|
|
|
|
|
|
|
* @return 操作结果。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private OperationResult executeBatchSave(OnlinePluginExecuteDto onlinePluginExecuteDto, JSONArray masterArray, |
|
|
|
|
|
|
|
Object slaveData, OnlineForm onlineForm, OnlineTable onlineTable, |
|
|
|
|
|
|
|
List<OnlinePluginExecuteSortDto> sortDtoList) { |
|
|
|
|
|
|
|
if (masterArray.isEmpty()) { |
|
|
|
|
|
|
|
return this.makeFailedResult("没有可保存的数据!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONArray slaveArray = null; |
|
|
|
|
|
|
|
if (slaveData instanceof JSONArray) { |
|
|
|
|
|
|
|
slaveArray = (JSONArray) slaveData; |
|
|
|
|
|
|
|
if (slaveArray.size() != masterArray.size()) { |
|
|
|
|
|
|
|
return this.makeFailedResult("数据验证失败,分录数据条数与待保存单据条数不一致!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (slaveData != null && !(slaveData instanceof JSONObject)) { |
|
|
|
|
|
|
|
return this.makeFailedResult("数据验证失败,分录数据格式不正确!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<JSONObject> masterList = new LinkedList<>(); |
|
|
|
|
|
|
|
List<JSONObject> slaveList = new LinkedList<>(); |
|
|
|
|
|
|
|
// 同一批次里发号生成的主键集合,用于防御生成器回绕或配置问题导致的重复主键。
|
|
|
|
|
|
|
|
Set<Long> newIdSet = new HashSet<>(); |
|
|
|
|
|
|
|
String primaryKeyName = onlineTable.getPrimaryKeyColumn().getColumnName(); |
|
|
|
|
|
|
|
for (int i = 0; i < masterArray.size(); i++) { |
|
|
|
|
|
|
|
Object element = masterArray.get(i); |
|
|
|
|
|
|
|
if (!(element instanceof JSONObject)) { |
|
|
|
|
|
|
|
return this.makeFailedResult("数据验证失败,第 " + (i + 1) + " 张单据的数据格式不正确!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONObject master = (JSONObject) element; |
|
|
|
|
|
|
|
master.put(primaryKeyName, this.generatePrimaryKey(onlineTable.getPrimaryKeyColumn(), newIdSet)); |
|
|
|
|
|
|
|
Object slaveElement = slaveArray == null ? slaveData : slaveArray.get(i); |
|
|
|
|
|
|
|
JSONObject slave = slaveElement instanceof JSONObject ? (JSONObject) slaveElement : null; |
|
|
|
|
|
|
|
if (slave != null) { |
|
|
|
|
|
|
|
this.makeupEntryPrimaryKey(slave, newIdSet); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
masterList.add(master); |
|
|
|
|
|
|
|
slaveList.add(slave); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return onlineOperationService.executeBatchSaveInTransaction(masterList, slaveList, |
|
|
|
|
|
|
|
onlinePluginExecuteDto, onlineForm, sortDtoList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 批量新增的事务边界:整批逐条保存,任一条抛异常则整批回滚。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* <p>必须经 Spring 代理调用(见 {@code executeBatchSave} 里的 |
|
|
|
|
|
|
|
* {@code onlineOperationService.executeBatchSaveInTransaction}), |
|
|
|
|
|
|
|
* {@link #executePluginsForBill} 内部调用的 {@code executePluginTransaction} 是自调用,其事务注解不生效。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param masterList 表头数据列表。 |
|
|
|
|
|
|
|
* @param slaveList 分录数据列表,下标与表头对齐。 |
|
|
|
|
|
|
|
* @param onlinePluginExecuteDto 操作按钮等参数。 |
|
|
|
|
|
|
|
* @param onlineForm 当前表单。 |
|
|
|
|
|
|
|
* @return 操作结果。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public OperationResult executeBatchSaveInTransaction(List<JSONObject> masterList, List<JSONObject> slaveList, |
|
|
|
|
|
|
|
OnlinePluginExecuteDto onlinePluginExecuteDto, |
|
|
|
|
|
|
|
OnlineForm onlineForm, |
|
|
|
|
|
|
|
List<OnlinePluginExecuteSortDto> sortDtoList) { |
|
|
|
|
|
|
|
List<String> savedIdList = new LinkedList<>(); |
|
|
|
|
|
|
|
for (int i = 0; i < masterList.size(); i++) { |
|
|
|
|
|
|
|
JSONObject master = masterList.get(i); |
|
|
|
|
|
|
|
// 逐条复用单条链路:附件摘取/回写、插件链顺序、反写触发等都与编辑页保存完全一致。
|
|
|
|
|
|
|
|
OperationResult singleResult = |
|
|
|
|
|
|
|
this.executePluginsForBill(onlinePluginExecuteDto, master, slaveList.get(i), sortDtoList); |
|
|
|
|
|
|
|
if (singleResult != null && !singleResult.isSuccess()) { |
|
|
|
|
|
|
|
throw new OnlineRuntimeException(singleResult.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
savedIdList.add(String.valueOf(master.get(this.resolvePrimaryKeyName(master)))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OperationResult operationResult = new OperationResult(); |
|
|
|
|
|
|
|
operationResult.setInfo(String.join(",", savedIdList)); |
|
|
|
|
|
|
|
operationResult.setShowMessage(true); |
|
|
|
|
|
|
|
operationResult.setMessage("保存成功,共保存 " + savedIdList.size() + " 条数据!"); |
|
|
|
|
|
|
|
return operationResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 取单据主键在 JSON 中的实际 key。 |
|
|
|
|
|
|
|
* <p>ORM 约定主键列为 id,这里兼容大小写差异,避免前端或配置写成 Id 时取不到结果。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param master 单据数据。 |
|
|
|
|
|
|
|
* @return 主键 key。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private String resolvePrimaryKeyName(JSONObject master) { |
|
|
|
|
|
|
|
if (master.containsKey("id")) { |
|
|
|
|
|
|
|
return "id"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (String key : master.keySet()) { |
|
|
|
|
|
|
|
if ("id".equalsIgnoreCase(key)) { |
|
|
|
|
|
|
|
return key; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return "id"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 生成主键:与 makeupColumnValue 的发号规则保持一致,Long 列走 nextLongId, |
|
|
|
|
|
|
|
* 其它类型(Integer / String / BigDecimal 等)走 nextStringId 再按列类型转换, |
|
|
|
|
|
|
|
* 避免把 Long 直接塞进字符串主键列而引发类型转换失败。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param primaryKeyColumn 主键字段,为空表示表未配置主键。 |
|
|
|
|
|
|
|
* @param newIdSet 本批次已生成的主键集合,用于防重复。 |
|
|
|
|
|
|
|
* @return 新主键。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Object generatePrimaryKey(OnlineColumn primaryKeyColumn, Set<Long> newIdSet) { |
|
|
|
|
|
|
|
if (primaryKeyColumn == null) { |
|
|
|
|
|
|
|
throw new OnlineRuntimeException("数据验证失败,表未配置主键字段,无法批量新增!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String objectFieldType = primaryKeyColumn.getObjectFieldType(); |
|
|
|
|
|
|
|
if (ObjectFieldType.LONG.equals(objectFieldType)) { |
|
|
|
|
|
|
|
long id; |
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
id = idGenerator.nextLongId(); |
|
|
|
|
|
|
|
} while (!newIdSet.add(id)); |
|
|
|
|
|
|
|
return id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 非 Long 主键(Integer / String 等):发号后按列类型转换,避免把 Long 塞进字符串主键列。
|
|
|
|
|
|
|
|
String textId = idGenerator.nextStringId(); |
|
|
|
|
|
|
|
if (ObjectFieldType.INTEGER.equals(objectFieldType)) { |
|
|
|
|
|
|
|
return Integer.valueOf(textId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return textId; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 给缺少主键的分录行补发主键,使每张单据的分录落到各自的表头下。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param slaveData 一张单据的分录数据,key 为分录表 tableId。 |
|
|
|
|
|
|
|
* @param newIdSet 本批次已生成的主键集合,用于防重复。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void makeupEntryPrimaryKey(JSONObject slaveData, Set<Long> newIdSet) { |
|
|
|
|
|
|
|
for (String tableIdStr : slaveData.keySet()) { |
|
|
|
|
|
|
|
OnlineTable entryTable = onlineTableService.getOnlineTableFromCache(this.convertToLongId(tableIdStr)); |
|
|
|
|
|
|
|
if (entryTable == null || entryTable.getPrimaryKeyColumn() == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String primaryKeyName = entryTable.getPrimaryKeyColumn().getColumnName(); |
|
|
|
|
|
|
|
Object entryValue = slaveData.get(tableIdStr); |
|
|
|
|
|
|
|
// 分录数据既可能是「行数组」,也可能是「单行对象」(一对一关系),两种都补齐主键。
|
|
|
|
|
|
|
|
List<JSONObject> entryRowList = new LinkedList<>(); |
|
|
|
|
|
|
|
if (entryValue instanceof JSONArray) { |
|
|
|
|
|
|
|
for (Object row : (JSONArray) entryValue) { |
|
|
|
|
|
|
|
if (row instanceof JSONObject) { |
|
|
|
|
|
|
|
entryRowList.add((JSONObject) row); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (entryValue instanceof JSONObject) { |
|
|
|
|
|
|
|
entryRowList.add((JSONObject) entryValue); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (JSONObject entryRow : entryRowList) { |
|
|
|
|
|
|
|
if (entryRow.get(primaryKeyName) == null) { |
|
|
|
|
|
|
|
entryRow.put(primaryKeyName, this.generatePrimaryKey(entryTable.getPrimaryKeyColumn(), newIdSet)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 构造失败结果:前端统一按红色提示展示 message。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private OperationResult makeFailedResult(String message) { |
|
|
|
|
|
|
|
OperationResult operationResult = new OperationResult(); |
|
|
|
|
|
|
|
operationResult.setSuccess(false); |
|
|
|
|
|
|
|
operationResult.setShowMessage(true); |
|
|
|
|
|
|
|
operationResult.setMessage(message); |
|
|
|
|
|
|
|
return operationResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 从表单 widgetJson 中解析出指定按钮按执行顺序排好的插件列表。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param onlineForm 当前表单。 |
|
|
|
|
|
|
|
* @param buttonName 按钮名称。 |
|
|
|
|
|
|
|
* @return 排序后的插件列表。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private List<OnlinePluginExecuteSortDto> getSortDtoList(OnlineForm onlineForm, String buttonName) { |
|
|
|
|
|
|
|
JSONObject jsonObject = JSONObject.parseObject(onlineForm.getWidgetJson()); |
|
|
|
|
|
|
|
JSONArray jsonArray = jsonObject.getJSONObject(AppDeviceType.getDeviceType()).getJSONArray("operationList"); |
|
|
|
|
|
|
|
List<OnlinePluginExecuteSortDto> sortDtoList = new ArrayList<>(); |
|
|
|
|
|
|
|
for (int i = 0; i < jsonArray.size(); i++) { |
|
|
|
|
|
|
|
JSONObject object = jsonArray.getJSONObject(i); |
|
|
|
|
|
|
|
if (object.getString("name").equals(buttonName) && object.containsKey("pluginList") && !object.getJSONArray("pluginList").isEmpty()) { |
|
|
|
|
|
|
|
if (object.getBoolean("enabled")) { |
|
|
|
|
|
|
|
JSONArray pluginList = object.getJSONArray("pluginList"); |
|
|
|
|
|
|
|
for (int j = 0; j < pluginList.size(); j++) { |
|
|
|
|
|
|
|
JSONObject pluginListJSONObject = pluginList.getJSONObject(j); |
|
|
|
|
|
|
|
//是否启用
|
|
|
|
|
|
|
|
boolean isEnable = pluginListJSONObject.getBoolean("isEnable"); |
|
|
|
|
|
|
|
if (isEnable) { |
|
|
|
|
|
|
|
String aClass = pluginListJSONObject.getString("class"); |
|
|
|
|
|
|
|
String order = pluginListJSONObject.getString("order"); |
|
|
|
|
|
|
|
OnlinePluginExecuteSortDto executeSortDto = new OnlinePluginExecuteSortDto(); |
|
|
|
|
|
|
|
executeSortDto.setClassPath(aClass); |
|
|
|
|
|
|
|
executeSortDto.setOrder(order); |
|
|
|
|
|
|
|
sortDtoList.add(executeSortDto); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return sortDtoList.stream().sorted(Comparator.comparing(OnlinePluginExecuteSortDto::getOrder)).collect(Collectors.toList()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 针对一张单据执行完整的插件链(表头/分录构建、附件摘取与回写、反写触发)。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* <p>批量新增复用此方法:保证每张单据走的插件链与 executePlugin 完全一致, |
|
|
|
|
|
|
|
* 只是插件列表由调用方传入,整批只需解析一次 widgetJson。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param onlinePluginExecuteDto 操作按钮等参数。 |
|
|
|
|
|
|
|
* @param masterData 表头数据。 |
|
|
|
|
|
|
|
* @param slaveData 分录数据。 |
|
|
|
|
|
|
|
* @param list 按执行顺序排好的插件列表。 |
|
|
|
|
|
|
|
* @return 操作结果。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private OperationResult executePluginsForBill(OnlinePluginExecuteDto onlinePluginExecuteDto, JSONObject masterData, |
|
|
|
|
|
|
|
JSONObject slaveData, List<OnlinePluginExecuteSortDto> list) { |
|
|
|
|
|
|
|
OnlineForm onlineForm = onlineFormService.getOnlineFormFromCache(onlinePluginExecuteDto.getFormId()); |
|
|
|
|
|
|
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(onlineForm.getMasterTableId()); |
|
|
|
|
|
|
|
OnlFormHead onlFormHead = onlFormHeadService.getHeadTableNameCache(onlineTable.getTableName()); |
|
|
|
|
|
|
|
if (BooleanUtil.isTrue(onlinePluginExecuteDto.getIsSelectAll())) { |
|
|
|
|
|
|
|
List<String> allBillIds = this.queryAllBillIds(onlineTable, onlinePluginExecuteDto.getQueryParams()); |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(allBillIds)) { |
|
|
|
|
|
|
|
OperationResult empty = new OperationResult(); |
|
|
|
|
|
|
|
empty.setMessage("没有符合条件的数据!"); |
|
|
|
|
|
|
|
return empty; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
onlinePluginExecuteDto.setBillId(CollUtil.join(allBillIds, ",")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// executePlugin 是所有按钮的统一入口,附件的写入/清理必须按插件类型分别设闸,
|
|
|
|
|
|
|
|
// 否则「审核」这类只提交部分字段的按钮会把附件全量覆盖掉,「删除」则不会清理附件。
|
|
|
|
|
|
|
|
boolean saveOperation = this.containsPlugin(list, SaveOperationServicePlugIn.class); |
|
|
|
|
|
|
|
boolean deleteOperation = this.containsPlugin(list, DeleteOperationServicePlugIn.class); |
|
|
|
|
|
|
|
ObjectValue finalObjectValue = null; |
|
|
|
|
|
|
|
List<PendingFileColumn> pendingFileList = new LinkedList<>(); |
|
|
|
|
|
|
|
if (onlFormHead.getIsomerismMark() != null) { |
|
|
|
|
|
|
|
finalObjectValue = this.cntEasValue(onlinePluginExecuteDto, |
|
|
|
|
|
|
|
masterData, |
|
|
|
|
|
|
|
slaveData, |
|
|
|
|
|
|
|
onlFormHead, |
|
|
|
|
|
|
|
onlineTable); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if(masterData != null){ |
|
|
|
|
|
|
|
finalObjectValue = onlineFormService.getObjectValue(masterData, slaveData, onlineTable.getTableName()); |
|
|
|
|
|
|
|
if (saveOperation) { |
|
|
|
|
|
|
|
// 附件上传/图片上传字段:先摘出入参值并把业务列置NULL,等ORM保存回写主键后再落 zz_online_file。
|
|
|
|
|
|
|
|
pendingFileList = this.extractFileColumn(finalObjectValue, onlineTable, slaveData); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 删除会被ORM级联删掉分录行,附件归属的分录主键必须在删除前查出来,删完就查不到了。
|
|
|
|
|
|
|
|
Map<Long, List<Long>> removeFileBusinessIdMap = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
if (deleteOperation && onlFormHead.getIsomerismMark() == null) { |
|
|
|
|
|
|
|
removeFileBusinessIdMap = this.collectFileBusinessIdForRemove(onlineTable, onlinePluginExecuteDto.getBillId()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OperationResult operationResult = exePlugin(list, onlinePluginExecuteDto.getBillId(), onlineTable.getTableName(), finalObjectValue, onlineForm); |
|
|
|
|
|
|
|
// ORM保存会把生成的主键回写到入参的ObjectValue实例上,此时才能确定附件归属的业务主键。
|
|
|
|
|
|
|
|
this.flushPendingFileColumn(pendingFileList); |
|
|
|
|
|
|
|
this.removeFileByBusinessIdMap(removeFileBusinessIdMap); |
|
|
|
|
|
|
|
return operationResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 按列表筛选条件查询主表全部主键,用于"选择全部按钮"。 |
|
|
|
* 按列表筛选条件查询主表全部主键,用于"选择全部按钮"。 |
|
|
|
* queryParams 为 {列名: 值} 的等值条件;为空表示无筛选(即整表)。 |
|
|
|
* queryParams 为 {列名: 值} 的等值条件;为空表示无筛选(即整表)。 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -1833,7 +1524,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
boolean isHasValue = false; |
|
|
|
boolean isHasValue = false; |
|
|
|
for(int j = 0; j < objectCollection.size() ; j++){ |
|
|
|
for(int j = 0; j < objectCollection.size() ; j++){ |
|
|
|
|
|
|
|
|
|
|
|
if(billId.equals(objectCollection.getObject(j).getPkValue()+"")){ |
|
|
|
if(billId.equals(objectCollection.getObject(0).getPkValue()+"")){ |
|
|
|
isHasValue = true; |
|
|
|
isHasValue = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|