|
|
|
@ -1,63 +1,65 @@ |
|
|
|
package apelet.common.online.service.impl; |
|
|
|
package apelet.common.online.service.impl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import apelet.common.core.annotation.MultiDatabaseWriteMethod; |
|
|
|
|
|
|
|
import apelet.common.core.annotation.MyDataSourceResolver; |
|
|
|
|
|
|
|
import apelet.common.core.cache.CacheConfig; |
|
|
|
|
|
|
|
import apelet.common.core.constant.*; |
|
|
|
|
|
|
|
import apelet.common.core.exception.MyRuntimeException; |
|
|
|
|
|
|
|
import apelet.common.core.exception.NoDataPermException; |
|
|
|
|
|
|
|
import apelet.common.core.object.*; |
|
|
|
import apelet.common.core.util.*; |
|
|
|
import apelet.common.core.util.*; |
|
|
|
|
|
|
|
import apelet.common.datafilter.config.DataFilterProperties; |
|
|
|
|
|
|
|
import apelet.common.dbutil.constant.DblinkType; |
|
|
|
|
|
|
|
import apelet.common.dbutil.provider.DataSourceProvider; |
|
|
|
|
|
|
|
import apelet.common.dict.model.TenantGlobalDict; |
|
|
|
|
|
|
|
import apelet.common.dict.service.GlobalDictService; |
|
|
|
|
|
|
|
import apelet.common.dict.service.TenantGlobalDictService; |
|
|
|
import apelet.common.generator.model.OnlFormField; |
|
|
|
import apelet.common.generator.model.OnlFormField; |
|
|
|
import apelet.common.generator.model.OnlFormHead; |
|
|
|
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.dao.ConvertRelationFOnLineMapper; |
|
|
|
import apelet.common.online.dao.ConvertRelationFOnLineMapper; |
|
|
|
|
|
|
|
import apelet.common.online.dao.OnlineOperationMapper; |
|
|
|
|
|
|
|
import apelet.common.online.dto.OnlineFilterDto; |
|
|
|
import apelet.common.online.dto.OnlinePluginExecuteDto; |
|
|
|
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.model.*; |
|
|
|
|
|
|
|
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.ConstDictInfo; |
|
|
|
|
|
|
|
import apelet.common.online.object.JoinTableInfo; |
|
|
|
|
|
|
|
import apelet.common.online.object.TransactionalBusinessData; |
|
|
|
import apelet.common.online.plugin.OperationResult; |
|
|
|
import apelet.common.online.plugin.OperationResult; |
|
|
|
import apelet.common.online.plugin.OperationServicePlugIn; |
|
|
|
import apelet.common.online.plugin.OperationServicePlugIn; |
|
|
|
import apelet.common.online.plugin.PlugInArgs; |
|
|
|
import apelet.common.online.plugin.PlugInArgs; |
|
|
|
|
|
|
|
import apelet.common.online.plugin.pre.DeleteOperationServicePlugIn; |
|
|
|
|
|
|
|
import apelet.common.online.plugin.pre.SaveOperationServicePlugIn; |
|
|
|
|
|
|
|
import apelet.common.online.service.*; |
|
|
|
|
|
|
|
import apelet.common.online.util.*; |
|
|
|
import apelet.common.orm.impl.*; |
|
|
|
import apelet.common.orm.impl.*; |
|
|
|
|
|
|
|
import apelet.common.redis.util.CommonRedisUtil; |
|
|
|
|
|
|
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
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.text.StrFormatter; |
|
|
|
import cn.hutool.core.text.StrFormatter; |
|
|
|
import cn.hutool.core.util.BooleanUtil; |
|
|
|
import cn.hutool.core.util.BooleanUtil; |
|
|
|
import cn.hutool.core.util.EnumUtil; |
|
|
|
import cn.hutool.core.util.EnumUtil; |
|
|
|
import cn.hutool.core.util.ObjectUtil; |
|
|
|
import cn.hutool.core.util.ObjectUtil; |
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
import cn.hutool.core.util.StrUtil; |
|
|
|
import cn.hutool.core.map.MapUtil; |
|
|
|
|
|
|
|
import cn.hutool.http.HttpUtil; |
|
|
|
import cn.hutool.http.HttpUtil; |
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import com.alibaba.fastjson.JSON; |
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
import com.alibaba.fastjson.TypeReference; |
|
|
|
import com.alibaba.fastjson.TypeReference; |
|
|
|
import apelet.common.core.annotation.MultiDatabaseWriteMethod; |
|
|
|
|
|
|
|
import apelet.common.core.annotation.MyDataSourceResolver; |
|
|
|
|
|
|
|
import apelet.common.core.cache.CacheConfig; |
|
|
|
|
|
|
|
import apelet.common.core.constant.*; |
|
|
|
|
|
|
|
import apelet.common.core.exception.MyRuntimeException; |
|
|
|
|
|
|
|
import apelet.common.core.exception.NoDataPermException; |
|
|
|
|
|
|
|
import apelet.common.core.object.*; |
|
|
|
|
|
|
|
import apelet.common.datafilter.config.DataFilterProperties; |
|
|
|
|
|
|
|
import apelet.common.dbutil.constant.DblinkType; |
|
|
|
|
|
|
|
import apelet.common.dbutil.provider.DataSourceProvider; |
|
|
|
|
|
|
|
import apelet.common.dict.model.TenantGlobalDict; |
|
|
|
|
|
|
|
import apelet.common.dict.service.GlobalDictService; |
|
|
|
|
|
|
|
import apelet.common.dict.service.TenantGlobalDictService; |
|
|
|
|
|
|
|
import apelet.common.online.config.OnlineProperties; |
|
|
|
|
|
|
|
import apelet.common.online.dao.OnlineOperationMapper; |
|
|
|
|
|
|
|
import apelet.common.online.dto.OnlineFilterDto; |
|
|
|
|
|
|
|
import apelet.common.online.exception.OnlineRuntimeException; |
|
|
|
|
|
|
|
import apelet.common.online.model.*; |
|
|
|
|
|
|
|
import apelet.common.online.model.constant.FieldFilterType; |
|
|
|
|
|
|
|
import apelet.common.online.model.constant.*; |
|
|
|
|
|
|
|
import apelet.common.online.object.ConstDictInfo; |
|
|
|
|
|
|
|
import apelet.common.online.object.*; |
|
|
|
|
|
|
|
import apelet.common.online.service.*; |
|
|
|
|
|
|
|
import apelet.common.online.util.*; |
|
|
|
|
|
|
|
import apelet.common.orm.impl.EntityColumn; |
|
|
|
|
|
|
|
import apelet.common.orm.impl.EntityTable; |
|
|
|
|
|
|
|
import apelet.common.orm.impl.LinkEntityColumn; |
|
|
|
|
|
|
|
import apelet.common.redis.util.CommonRedisUtil; |
|
|
|
|
|
|
|
import apelet.common.sequence.wrapper.IdGeneratorWrapper; |
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
|
|
|
|
|
|
|
import com.google.common.collect.LinkedHashMultimap; |
|
|
|
import com.google.common.collect.LinkedHashMultimap; |
|
|
|
import com.google.common.collect.Multimap; |
|
|
|
import com.google.common.collect.Multimap; |
|
|
|
import lombok.Data; |
|
|
|
import lombok.Data; |
|
|
|
@ -73,12 +75,9 @@ import org.springframework.transaction.annotation.Transactional; |
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
import javax.annotation.Resource; |
|
|
|
import java.io.File; |
|
|
|
import java.io.File; |
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
import java.io.Serializable; |
|
|
|
import java.io.Serializable; |
|
|
|
import java.nio.file.Files; |
|
|
|
|
|
|
|
import java.sql.Connection; |
|
|
|
import java.sql.Connection; |
|
|
|
import java.time.LocalDateTime; |
|
|
|
import java.time.LocalDateTime; |
|
|
|
import java.time.temporal.ValueRange; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.util.*; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
|
|
|
@ -135,6 +134,8 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
private OnlineOperationService onlineOperationService; |
|
|
|
private OnlineOperationService onlineOperationService; |
|
|
|
@Autowired |
|
|
|
@Autowired |
|
|
|
private IOnlFormFieldService onlFormFieldService; |
|
|
|
private IOnlFormFieldService onlFormFieldService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
|
|
private OnlineFileService onlineFileService; |
|
|
|
|
|
|
|
|
|
|
|
private static final String DICT_MAP_SUFFIX = "DictMap"; |
|
|
|
private static final String DICT_MAP_SUFFIX = "DictMap"; |
|
|
|
private static final String DICT_MAP_LIST_SUFFIX = "DictMapList"; |
|
|
|
private static final String DICT_MAP_LIST_SUFFIX = "DictMapList"; |
|
|
|
@ -197,6 +198,8 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.saveFileColumn(table, id, data); |
|
|
|
|
|
|
|
this.nullifyFileColumnValues(columnDataList, columnValueList); |
|
|
|
this.doInsert(table, columnNames, columnValueList); |
|
|
|
this.doInsert(table, columnNames, columnValueList); |
|
|
|
// List<String> list = Arrays.asList(columnNames.split(","));
|
|
|
|
// List<String> list = Arrays.asList(columnNames.split(","));
|
|
|
|
// ObjectValue objectValue = new ObjectValue(table.getTableName());
|
|
|
|
// ObjectValue objectValue = new ObjectValue(table.getTableName());
|
|
|
|
@ -245,6 +248,8 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// this.doInsert(table, columnNames, columnValueList);
|
|
|
|
// this.doInsert(table, columnNames, columnValueList);
|
|
|
|
|
|
|
|
this.saveFileColumn(table, id, data); |
|
|
|
|
|
|
|
this.nullifyFileColumnValues(columnDataList, columnValueList); |
|
|
|
List<String> column = Arrays.asList(columnNames.split(",")); |
|
|
|
List<String> column = Arrays.asList(columnNames.split(",")); |
|
|
|
for (int i = 0; i < columnValueList.size(); i++) { |
|
|
|
for (int i = 0; i < columnValueList.size(); i++) { |
|
|
|
if (columnValueList.get(i) != null) { |
|
|
|
if (columnValueList.get(i) != null) { |
|
|
|
@ -371,6 +376,10 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (FieldKind.isFileKind(columnData.getColumn().getFieldKind())) { |
|
|
|
|
|
|
|
// 文件字段值已写入 zz_online_file,业务列统一置NULL。
|
|
|
|
|
|
|
|
columnData.setColumnValue(null); |
|
|
|
|
|
|
|
} |
|
|
|
if (!MyCommonUtil.equalsAny(columnData.getColumn().getFieldKind(), |
|
|
|
if (!MyCommonUtil.equalsAny(columnData.getColumn().getFieldKind(), |
|
|
|
FieldKind.CREATE_TIME, FieldKind.CREATE_USER_ID, FieldKind.CREATE_DEPT_ID, FieldKind.TENANT_FILTER)) { |
|
|
|
FieldKind.CREATE_TIME, FieldKind.CREATE_USER_ID, FieldKind.CREATE_DEPT_ID, FieldKind.TENANT_FILTER)) { |
|
|
|
updateColumnList.add(columnData); |
|
|
|
updateColumnList.add(columnData); |
|
|
|
@ -380,6 +389,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (CollUtil.isEmpty(updateColumnList)) { |
|
|
|
if (CollUtil.isEmpty(updateColumnList)) { |
|
|
|
|
|
|
|
this.saveFileColumn(table, this.convertToLongId(dataId), data); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
if (CollUtil.isNotEmpty(maskFieldDataList)) { |
|
|
|
if (CollUtil.isNotEmpty(maskFieldDataList)) { |
|
|
|
@ -388,7 +398,9 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
this.compareAndSetMaskFieldData(table, maskFieldDataList, originalData); |
|
|
|
this.compareAndSetMaskFieldData(table, maskFieldDataList, originalData); |
|
|
|
} |
|
|
|
} |
|
|
|
String dataPermFilter = this.buildDataPermFilter(table); |
|
|
|
String dataPermFilter = this.buildDataPermFilter(table); |
|
|
|
return this.doUpdate(table, updateColumnList, filterList, dataPermFilter); |
|
|
|
boolean updated = this.doUpdate(table, updateColumnList, filterList, dataPermFilter); |
|
|
|
|
|
|
|
this.saveFileColumn(table, this.convertToLongId(dataId), data); |
|
|
|
|
|
|
|
return updated; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@MultiDatabaseWriteMethod |
|
|
|
@MultiDatabaseWriteMethod |
|
|
|
@ -476,6 +488,11 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.doLogicDelete(table, table.getPrimaryKeyColumn(), dataId, dataPermFilter); |
|
|
|
this.doLogicDelete(table, table.getPrimaryKeyColumn(), dataId, dataPermFilter); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Long businessId = this.convertToLongId(dataId); |
|
|
|
|
|
|
|
if (businessId != null) { |
|
|
|
|
|
|
|
// 级联清理该业务记录对应的附件数据。
|
|
|
|
|
|
|
|
onlineFileService.removeByBusinessId(table.getTableId(), businessId); |
|
|
|
|
|
|
|
} |
|
|
|
if (CollUtil.isEmpty(relationList)) { |
|
|
|
if (CollUtil.isEmpty(relationList)) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -494,11 +511,27 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
List<OnlineFilterDto> slaveFilterList = |
|
|
|
List<OnlineFilterDto> slaveFilterList = |
|
|
|
this.makeDefaultFilter(relation.getSlaveTable(), slaveColumn, columnValue); |
|
|
|
this.makeDefaultFilter(relation.getSlaveTable(), slaveColumn, columnValue); |
|
|
|
|
|
|
|
// 先查出从表受影响记录的主键,用于附件清理。
|
|
|
|
|
|
|
|
List<Long> slaveBusinessIdList = new LinkedList<>(); |
|
|
|
|
|
|
|
OnlineColumn slavePkColumn = slaveTable.getPrimaryKeyColumn(); |
|
|
|
|
|
|
|
if (slavePkColumn != null) { |
|
|
|
|
|
|
|
List<Map<String, Object>> slaveRows = onlineOperationMapper.getList(slaveTable.getTableName(), null, slavePkColumn.getColumnName(), slaveFilterList, null, null); |
|
|
|
|
|
|
|
slaveBusinessIdList = slaveRows.stream() |
|
|
|
|
|
|
|
.map(r -> r.get(slavePkColumn.getColumnName())) |
|
|
|
|
|
|
|
.filter(ObjectUtil::isNotEmpty) |
|
|
|
|
|
|
|
.map(v -> this.convertToLongId(v.toString())) |
|
|
|
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
} |
|
|
|
if (slaveTable.getLogicDeleteColumn() == null) { |
|
|
|
if (slaveTable.getLogicDeleteColumn() == null) { |
|
|
|
this.doDelete(slaveTable, slaveFilterList, null); |
|
|
|
this.doDelete(slaveTable, slaveFilterList, null); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.doLogicDelete(slaveTable, slaveColumn, columnValue, null); |
|
|
|
this.doLogicDelete(slaveTable, slaveColumn, columnValue, null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 级联清理从表业务记录对应的附件数据。
|
|
|
|
|
|
|
|
for (Long slaveBusinessId : slaveBusinessIdList) { |
|
|
|
|
|
|
|
onlineFileService.removeByBusinessId(slaveTable.getTableId(), slaveBusinessId); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -560,6 +593,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
this.buildVirtualColumn(resultList, table, toManyRelationList); |
|
|
|
this.buildVirtualColumn(resultList, table, toManyRelationList); |
|
|
|
} |
|
|
|
} |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
|
|
|
|
this.fillFileColumn(resultList, table); |
|
|
|
return resultList.get(0); |
|
|
|
return resultList.get(0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -575,6 +609,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
slaveTable, null, selectFields, filterList, dataPermFilter, null, null); |
|
|
|
slaveTable, null, selectFields, filterList, dataPermFilter, null, null); |
|
|
|
List<Map<String, Object>> resultList = pageData.getDataList(); |
|
|
|
List<Map<String, Object>> resultList = pageData.getDataList(); |
|
|
|
this.buildDataListWithDict(resultList, slaveTable); |
|
|
|
this.buildDataListWithDict(resultList, slaveTable); |
|
|
|
|
|
|
|
this.fillFileColumn(resultList, slaveTable); |
|
|
|
return CollUtil.isEmpty(resultList) ? null : resultList.get(0); |
|
|
|
return CollUtil.isEmpty(resultList) ? null : resultList.get(0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -608,6 +643,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
this.buildVirtualColumn(resultList, table, toManyRelationList); |
|
|
|
this.buildVirtualColumn(resultList, table, toManyRelationList); |
|
|
|
} |
|
|
|
} |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
|
|
|
|
this.fillFileColumn(resultList, table); |
|
|
|
return pageData; |
|
|
|
return pageData; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -694,6 +730,7 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
this.buildDataListWithDict(resultList, slaveTable); |
|
|
|
this.buildDataListWithDict(resultList, slaveTable); |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
this.reformatResultListWithOneToOneRelation(resultList, oneToOneRelationList); |
|
|
|
reformatResultListWithOneToOneRelation2(resultList, slaveTable.getTableName()); |
|
|
|
reformatResultListWithOneToOneRelation2(resultList, slaveTable.getTableName()); |
|
|
|
|
|
|
|
this.fillFileColumn(resultList, slaveTable); |
|
|
|
return pageData; |
|
|
|
return pageData; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1021,7 +1058,12 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} |
|
|
|
} |
|
|
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(onlineForm.getMasterTableId()); |
|
|
|
OnlineTable onlineTable = onlineTableService.getOnlineTableFromCache(onlineForm.getMasterTableId()); |
|
|
|
OnlFormHead onlFormHead = onlFormHeadService.getHeadTableNameCache(onlineTable.getTableName()); |
|
|
|
OnlFormHead onlFormHead = onlFormHeadService.getHeadTableNameCache(onlineTable.getTableName()); |
|
|
|
|
|
|
|
// executePlugin 是所有按钮的统一入口,附件的写入/清理必须按插件类型分别设闸,
|
|
|
|
|
|
|
|
// 否则「审核」这类只提交部分字段的按钮会把附件全量覆盖掉,「删除」则不会清理附件。
|
|
|
|
|
|
|
|
boolean saveOperation = this.containsPlugin(sortDtoList, SaveOperationServicePlugIn.class); |
|
|
|
|
|
|
|
boolean deleteOperation = this.containsPlugin(sortDtoList, DeleteOperationServicePlugIn.class); |
|
|
|
ObjectValue finalObjectValue = null; |
|
|
|
ObjectValue finalObjectValue = null; |
|
|
|
|
|
|
|
List<PendingFileColumn> pendingFileList = new LinkedList<>(); |
|
|
|
if (onlFormHead.getIsomerismMark() != null) { |
|
|
|
if (onlFormHead.getIsomerismMark() != null) { |
|
|
|
finalObjectValue = this.cntEasValue(onlinePluginExecuteDto, |
|
|
|
finalObjectValue = this.cntEasValue(onlinePluginExecuteDto, |
|
|
|
masterData, |
|
|
|
masterData, |
|
|
|
@ -1031,12 +1073,294 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if(masterData != null){ |
|
|
|
if(masterData != null){ |
|
|
|
finalObjectValue = onlineFormService.getObjectValue(masterData, slaveData, onlineTable.getTableName()); |
|
|
|
finalObjectValue = onlineFormService.getObjectValue(masterData, slaveData, onlineTable.getTableName()); |
|
|
|
|
|
|
|
if (saveOperation) { |
|
|
|
|
|
|
|
// 附件上传/图片上传字段:先摘出入参值并把业务列置NULL,等ORM保存回写主键后再落 zz_online_file。
|
|
|
|
|
|
|
|
pendingFileList = this.extractFileColumn(finalObjectValue, onlineTable, slaveData); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
List<OnlinePluginExecuteSortDto> list |
|
|
|
List<OnlinePluginExecuteSortDto> list |
|
|
|
= sortDtoList.stream().sorted(Comparator.comparing(OnlinePluginExecuteSortDto::getOrder)).collect(Collectors.toList()); |
|
|
|
= sortDtoList.stream().sorted(Comparator.comparing(OnlinePluginExecuteSortDto::getOrder)).collect(Collectors.toList()); |
|
|
|
|
|
|
|
|
|
|
|
return exePlugin(list, onlinePluginExecuteDto.getBillId(), onlineTable.getTableName(), finalObjectValue, onlineForm); |
|
|
|
// 删除会被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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 判断当前按钮绑定的插件中是否包含指定插件。 |
|
|
|
|
|
|
|
* <p>按钮与插件的绑定是 widgetJson 中 pluginList[].class 的全限定类名(见 QuickFormWidgetUtil#setSaveButtonEnabled), |
|
|
|
|
|
|
|
* 用类名判断比用中文 buttonName 可靠。</p> |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private boolean containsPlugin(List<OnlinePluginExecuteSortDto> sortDtoList, Class<?> pluginClass) { |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(sortDtoList)) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return sortDtoList.stream().anyMatch(dto -> pluginClass.getName().equals(dto.getClassPath())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 删除前收集待清理附件的业务主键。 |
|
|
|
|
|
|
|
* <p>表头主键取自billId;分录主键必须在删除前查出,因为ORM删除表头时会级联删除分录行, |
|
|
|
|
|
|
|
* 删除后再查就拿不到,附件会在 zz_online_file 里变成孤儿记录。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param masterTable 表头对应的在线数据表。 |
|
|
|
|
|
|
|
* @param billId 表头主键,批量删除时为逗号分隔的多个主键。 |
|
|
|
|
|
|
|
* @return 在线表tableId -> 该表下待清理附件的业务主键列表。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Map<Long, List<Long>> collectFileBusinessIdForRemove(OnlineTable masterTable, String billId) { |
|
|
|
|
|
|
|
Map<Long, List<Long>> businessIdMap = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
if (masterTable == null || StrUtil.isBlank(billId)) { |
|
|
|
|
|
|
|
return businessIdMap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<Long> masterIdList = new LinkedList<>(); |
|
|
|
|
|
|
|
for (String idStr : StrUtil.split(billId, ',')) { |
|
|
|
|
|
|
|
Long businessId = this.convertToLongId(StrUtil.trim(idStr)); |
|
|
|
|
|
|
|
if (businessId != null) { |
|
|
|
|
|
|
|
masterIdList.add(businessId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(masterIdList)) { |
|
|
|
|
|
|
|
return businessIdMap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
businessIdMap.put(masterTable.getTableId(), masterIdList); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
this.collectEntryBusinessIdForRemove(masterTable, masterIdList, businessIdMap); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
// 分录主键查询失败不影响表头附件清理,仅记录日志。
|
|
|
|
|
|
|
|
log.error("删除前查询分录主键失败,分录附件可能残留,table={}, billId={}", masterTable.getTableName(), billId, e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return businessIdMap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 从ORM实体元数据中找出分录表(relationType=1),按表头主键查出各分录行主键。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void collectEntryBusinessIdForRemove(OnlineTable masterTable, List<Long> masterIdList, Map<Long, List<Long>> businessIdMap) { |
|
|
|
|
|
|
|
EntityTable entityTable = ormGenDataSourceUtil.getEntityTable(masterTable.getTableName()); |
|
|
|
|
|
|
|
if (entityTable == null || CollUtil.isEmpty(entityTable.getEntityColumnList())) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 分录表名 -> 在线表tableId,用于把查询结果里的分录行归到对应的在线表。
|
|
|
|
|
|
|
|
Map<String, Long> entryTableIdMap = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
Selector selector = new Selector(); |
|
|
|
|
|
|
|
selector.getList().add(new SelectorItem("id")); |
|
|
|
|
|
|
|
for (EntityColumn entityColumn : entityTable.getEntityColumnList()) { |
|
|
|
|
|
|
|
if (!(entityColumn instanceof LinkEntityColumn)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
EntityLinkRelation relation = ((LinkEntityColumn) entityColumn).getEntityLinkRelation(); |
|
|
|
|
|
|
|
if (relation == null || relation.getRelationType() == null || !relation.getRelationType().equals(1)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String entryTableName = relation.getSuperTable().getTableName(); |
|
|
|
|
|
|
|
OnlineTable entryTable = onlineTableService.getOne(new LambdaQueryWrapper<OnlineTable>().eq(OnlineTable::getTableName, entryTableName)); |
|
|
|
|
|
|
|
if (entryTable == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
entryTableIdMap.put(entryTableName, entryTable.getTableId()); |
|
|
|
|
|
|
|
// 只取分录主键,不需要其它字段。
|
|
|
|
|
|
|
|
selector.getList().add(new SelectorItem(relation.getRelationName() + ".id")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (MapUtil.isEmpty(entryTableIdMap)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Filter filter = new Filter(); |
|
|
|
|
|
|
|
filter.add(new FilterItem("id", FilterItem.INNER, |
|
|
|
|
|
|
|
masterIdList.stream().map(id -> "'" + id + "'").collect(Collectors.joining(",")))); |
|
|
|
|
|
|
|
ObjectCollection collection = ormGenDataSourceUtil.query(masterTable.getTableName(), filter, selector); |
|
|
|
|
|
|
|
for (int i = 0; i < collection.size(); i++) { |
|
|
|
|
|
|
|
Map<String, Object> rowValues = collection.getObject(i).getValues(); |
|
|
|
|
|
|
|
if (MapUtil.isEmpty(rowValues)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (Object value : rowValues.values()) { |
|
|
|
|
|
|
|
if (!(value instanceof ObjectCollection)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ObjectCollection entryCollection = (ObjectCollection) value; |
|
|
|
|
|
|
|
for (int j = 0; j < entryCollection.size(); j++) { |
|
|
|
|
|
|
|
ObjectValue entryRow = entryCollection.getObject(j); |
|
|
|
|
|
|
|
// 分录行自带表名,按表名归类比猜ObjectValue上挂载的key名可靠。
|
|
|
|
|
|
|
|
Long entryTableId = entryTableIdMap.get(entryRow.getTableName()); |
|
|
|
|
|
|
|
if (entryTableId == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object entryIdValue = entryRow.get("id"); |
|
|
|
|
|
|
|
Long entryId = entryIdValue == null ? null : this.convertToLongId(entryIdValue.toString()); |
|
|
|
|
|
|
|
if (entryId != null) { |
|
|
|
|
|
|
|
businessIdMap.computeIfAbsent(entryTableId, k -> new LinkedList<>()).add(entryId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 按收集到的业务主键清理 zz_online_file 中的附件数据。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void removeFileByBusinessIdMap(Map<Long, List<Long>> businessIdMap) { |
|
|
|
|
|
|
|
if (MapUtil.isEmpty(businessIdMap)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
businessIdMap.forEach((onlineTableId, businessIdList) -> { |
|
|
|
|
|
|
|
for (Long businessId : businessIdList) { |
|
|
|
|
|
|
|
onlineFileService.removeByBusinessId(onlineTableId, businessId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 附件字段暂存对象。 |
|
|
|
|
|
|
|
* <p>持有表头/分录行的ObjectValue实例引用:新增时主键由ORM在保存过程中生成并回写到该实例上, |
|
|
|
|
|
|
|
* 保存前拿不到主键,只能保存后按实例读回。</p> |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static class PendingFileColumn { |
|
|
|
|
|
|
|
/** 附件所属的行对象,ORM保存后主键会回写到该实例上。 */ |
|
|
|
|
|
|
|
private final ObjectValue row; |
|
|
|
|
|
|
|
/** 行所属的在线数据表。 */ |
|
|
|
|
|
|
|
private final OnlineTable table; |
|
|
|
|
|
|
|
/** 附件字段的列名。 */ |
|
|
|
|
|
|
|
private final String columnName; |
|
|
|
|
|
|
|
/** 入参中该字段的文件JSON数组字符串,为空表示清空该字段附件。 */ |
|
|
|
|
|
|
|
private final String fileJson; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private PendingFileColumn(ObjectValue row, OnlineTable table, String columnName, String fileJson) { |
|
|
|
|
|
|
|
this.row = row; |
|
|
|
|
|
|
|
this.table = table; |
|
|
|
|
|
|
|
this.columnName = columnName; |
|
|
|
|
|
|
|
this.fileJson = fileJson; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 摘出表头及各分录中附件上传/图片上传字段的入参值,并把业务列统一置NULL。 |
|
|
|
|
|
|
|
* <p>按全量覆盖语义:表中所有 field_kind 为 1/2 的字段一律以入参为准,入参未包含该字段视为清空。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param objectValue 待保存的表头对象,分录以分录表名为key挂在其上。 |
|
|
|
|
|
|
|
* @param masterTable 表头对应的在线数据表。 |
|
|
|
|
|
|
|
* @param slaveData 分录入参,key为分录表的tableId。 |
|
|
|
|
|
|
|
* @return 待落库的附件字段列表。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private List<PendingFileColumn> extractFileColumn(ObjectValue objectValue, OnlineTable masterTable, JSONObject slaveData) { |
|
|
|
|
|
|
|
List<PendingFileColumn> pendingList = new LinkedList<>(); |
|
|
|
|
|
|
|
if (objectValue == null) { |
|
|
|
|
|
|
|
return pendingList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.extractFileColumnFromRow(objectValue, masterTable, pendingList); |
|
|
|
|
|
|
|
if (slaveData == null) { |
|
|
|
|
|
|
|
return pendingList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 分录:slaveData的key为分录表tableId,ObjectValue上以分录表名挂ObjectCollection(见OnlineFormServiceImpl#getObjectValue)。
|
|
|
|
|
|
|
|
for (String tableIdStr : slaveData.keySet()) { |
|
|
|
|
|
|
|
Long entryTableId = this.convertToLongId(tableIdStr); |
|
|
|
|
|
|
|
if (entryTableId == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineTable entryTable = onlineTableService.getOnlineTableFromCache(entryTableId); |
|
|
|
|
|
|
|
if (entryTable == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object collectionObj = objectValue.get(entryTable.getTableName()); |
|
|
|
|
|
|
|
if (!(collectionObj instanceof ObjectCollection)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ObjectCollection collection = (ObjectCollection) collectionObj; |
|
|
|
|
|
|
|
for (int i = 0; i < collection.size(); i++) { |
|
|
|
|
|
|
|
this.extractFileColumnFromRow(collection.getObject(i), entryTable, pendingList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return pendingList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 摘出单行中所有附件字段的值,并把该行对应列置NULL。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void extractFileColumnFromRow(ObjectValue row, OnlineTable table, List<PendingFileColumn> pendingList) { |
|
|
|
|
|
|
|
if (row == null || table == null || MapUtil.isEmpty(table.getColumnMap())) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (OnlineColumn column : table.getColumnMap().values()) { |
|
|
|
|
|
|
|
if (!FieldKind.isFileKind(column.getFieldKind())) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String columnName = column.getColumnName(); |
|
|
|
|
|
|
|
Object value = row.get(columnName); |
|
|
|
|
|
|
|
pendingList.add(new PendingFileColumn(row, table, columnName, value == null ? null : value.toString())); |
|
|
|
|
|
|
|
// 业务列仅作查询回填载体,不落库,统一置NULL。
|
|
|
|
|
|
|
|
row.put(columnName, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 保存完成后把暂存的附件数据落 zz_online_file,业务主键从ORM回写后的行对象上读取。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void flushPendingFileColumn(List<PendingFileColumn> pendingList) { |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(pendingList)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (PendingFileColumn pending : pendingList) { |
|
|
|
|
|
|
|
OnlineColumn primaryKeyColumn = pending.table.getPrimaryKeyColumn(); |
|
|
|
|
|
|
|
if (primaryKeyColumn == null) { |
|
|
|
|
|
|
|
log.warn("附件落库失败,表 [{}] 未配置主键字段", pending.table.getTableName()); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Object idValue = pending.row.get(primaryKeyColumn.getColumnName()); |
|
|
|
|
|
|
|
Long businessId = idValue == null ? null : this.convertToLongId(idValue.toString()); |
|
|
|
|
|
|
|
if (businessId == null) { |
|
|
|
|
|
|
|
log.warn("附件落库失败,保存后未取到业务主键,table={}, column={}", pending.table.getTableName(), pending.columnName); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<OnlineFile> fileList = this.parseOnlineFileList(pending.fileJson, pending.columnName); |
|
|
|
|
|
|
|
onlineFileService.replaceFileList(pending.table.getTableId(), pending.columnName, businessId, fileList); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 把文件字段的JSON数组字符串解析为 OnlineFile 列表。 |
|
|
|
|
|
|
|
* <p>值为空或解析失败时返回空列表,即按清空该字段附件处理。</p> |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private List<OnlineFile> parseOnlineFileList(String fileJson, String columnName) { |
|
|
|
|
|
|
|
List<OnlineFile> fileList = new LinkedList<>(); |
|
|
|
|
|
|
|
if (StrUtil.isBlank(fileJson)) { |
|
|
|
|
|
|
|
return fileList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONArray fileArray; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
fileArray = JSON.parseArray(fileJson); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
log.warn("解析文件字段 [{}] 数据失败,按清空处理,原值={}", columnName, fileJson); |
|
|
|
|
|
|
|
return fileList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (fileArray == null) { |
|
|
|
|
|
|
|
return fileList; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
TokenData tokenData = TokenData.takeFromRequest(); |
|
|
|
|
|
|
|
Long operatorUserId = tokenData == null ? null : tokenData.getUserId(); |
|
|
|
|
|
|
|
for (int i = 0; i < fileArray.size(); i++) { |
|
|
|
|
|
|
|
JSONObject fileItem = fileArray.getJSONObject(i); |
|
|
|
|
|
|
|
if (fileItem == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineFile onlineFile = new OnlineFile(); |
|
|
|
|
|
|
|
onlineFile.setBaseUrl(fileItem.getString("baseUrl")); |
|
|
|
|
|
|
|
onlineFile.setDownloadUri(fileItem.getString("downloadUri")); |
|
|
|
|
|
|
|
onlineFile.setFileName(fileItem.getString("filename")); |
|
|
|
|
|
|
|
onlineFile.setUploadPath(fileItem.getString("uploadPath")); |
|
|
|
|
|
|
|
onlineFile.setName(fileItem.getString("name")); |
|
|
|
|
|
|
|
onlineFile.setUrl(fileItem.getString("url")); |
|
|
|
|
|
|
|
onlineFile.setCreateUserId(operatorUserId); |
|
|
|
|
|
|
|
onlineFile.setUpdateUserId(operatorUserId); |
|
|
|
|
|
|
|
fileList.add(onlineFile); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return fileList; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -2203,6 +2527,152 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { |
|
|
|
return sb.substring(0, sb.length() - 1); |
|
|
|
return sb.substring(0, sb.length() - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 处理附件上传/图片上传字段:将入参中的文件JSON数组解析后存入 zz_online_file,并把业务字段置空。 |
|
|
|
|
|
|
|
* <p>约定:入参未包含该字段或值为null时保留原附件数据;空数组时清空该字段的全部附件。</p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param table 在线数据表对象。 |
|
|
|
|
|
|
|
* @param id 业务记录主键值。 |
|
|
|
|
|
|
|
* @param data 入参数据。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void saveFileColumn(OnlineTable table, Object id, JSONObject data) { |
|
|
|
|
|
|
|
if (id == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Long businessId = this.convertToLongId(id.toString()); |
|
|
|
|
|
|
|
if (businessId == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (OnlineColumn column : table.getColumnMap().values()) { |
|
|
|
|
|
|
|
if (!FieldKind.isFileKind(column.getFieldKind())) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String columnName = column.getColumnName(); |
|
|
|
|
|
|
|
// 入参没有该字段时不做处理,保留原有附件。
|
|
|
|
|
|
|
|
if (!data.containsKey(columnName) || data.get(columnName) == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONArray fileArray; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
fileArray = JSON.parseArray(data.getString(columnName)); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
// 解析失败说明入参格式异常,保留原有附件,不做清理。
|
|
|
|
|
|
|
|
log.warn("解析文件字段 [{}] 数据失败,保留原有附件", columnName); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<OnlineFile> fileList = new LinkedList<>(); |
|
|
|
|
|
|
|
if (fileArray != null) { |
|
|
|
|
|
|
|
for (int i = 0; i < fileArray.size(); i++) { |
|
|
|
|
|
|
|
OnlineFile onlineFile = new OnlineFile(); |
|
|
|
|
|
|
|
JSONObject fileJson = fileArray.getJSONObject(i); |
|
|
|
|
|
|
|
onlineFile.setBaseUrl(fileJson.getString("baseUrl")); |
|
|
|
|
|
|
|
onlineFile.setDownloadUri(fileJson.getString("downloadUri")); |
|
|
|
|
|
|
|
onlineFile.setFileName(fileJson.getString("filename")); |
|
|
|
|
|
|
|
onlineFile.setUploadPath(fileJson.getString("uploadPath")); |
|
|
|
|
|
|
|
onlineFile.setName(fileJson.getString("name")); |
|
|
|
|
|
|
|
onlineFile.setUrl(fileJson.getString("url")); |
|
|
|
|
|
|
|
onlineFile.setCreateUserId(TokenData.takeFromRequest().getUserId()); |
|
|
|
|
|
|
|
onlineFile.setUpdateUserId(TokenData.takeFromRequest().getUserId()); |
|
|
|
|
|
|
|
fileList.add(onlineFile); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 全量替换:先删旧再插入,空数组即清空。
|
|
|
|
|
|
|
|
onlineFileService.replaceFileList(table.getTableId(), columnName, businessId, fileList); |
|
|
|
|
|
|
|
// 业务表字段仅作为查询回填载体,不落库,统一置NULL。
|
|
|
|
|
|
|
|
data.put(columnName, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 查询结果回填:将附件上传/图片上传字段对应的 zz_online_file 数据组装成文件JSON数组回填到字段上。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param resultList 查询结果列表。 |
|
|
|
|
|
|
|
* @param table 在线数据表对象。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void fillFileColumn(List<Map<String, Object>> resultList, OnlineTable table) { |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(resultList)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<OnlineColumn> fileColumnList = table.getColumnMap().values().stream() |
|
|
|
|
|
|
|
.filter(c -> FieldKind.isFileKind(c.getFieldKind())) |
|
|
|
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(fileColumnList)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineColumn primaryKeyColumn = table.getPrimaryKeyColumn(); |
|
|
|
|
|
|
|
if (primaryKeyColumn == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
List<Long> businessIdList = resultList.stream() |
|
|
|
|
|
|
|
.map(r -> r.get(primaryKeyColumn.getColumnName())) |
|
|
|
|
|
|
|
.filter(ObjectUtil::isNotEmpty) |
|
|
|
|
|
|
|
.map(v -> this.convertToLongId(v.toString())) |
|
|
|
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
|
|
|
.distinct() |
|
|
|
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
for (OnlineColumn column : fileColumnList) { |
|
|
|
|
|
|
|
Map<Long, List<OnlineFile>> fileMap = |
|
|
|
|
|
|
|
onlineFileService.getOnlineFileMapByBusinessIds(table.getTableId(), column.getColumnName(), businessIdList); |
|
|
|
|
|
|
|
if (MapUtil.isEmpty(fileMap)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (Map<String, Object> result : resultList) { |
|
|
|
|
|
|
|
Object idValue = result.get(primaryKeyColumn.getColumnName()); |
|
|
|
|
|
|
|
if (ObjectUtil.isEmpty(idValue)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Long businessId = this.convertToLongId(idValue.toString()); |
|
|
|
|
|
|
|
List<OnlineFile> fileList = fileMap.get(businessId); |
|
|
|
|
|
|
|
if (CollUtil.isEmpty(fileList)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONArray fileArray = new JSONArray(); |
|
|
|
|
|
|
|
for (OnlineFile onlineFile : fileList) { |
|
|
|
|
|
|
|
JSONObject fileJson = new JSONObject(); |
|
|
|
|
|
|
|
fileJson.put("baseUrl", onlineFile.getBaseUrl()); |
|
|
|
|
|
|
|
fileJson.put("downloadUri", onlineFile.getDownloadUri()); |
|
|
|
|
|
|
|
fileJson.put("filename", onlineFile.getFileName()); |
|
|
|
|
|
|
|
fileJson.put("uploadPath", onlineFile.getUploadPath()); |
|
|
|
|
|
|
|
fileJson.put("name", onlineFile.getName()); |
|
|
|
|
|
|
|
fileJson.put("url", onlineFile.getUrl()); |
|
|
|
|
|
|
|
fileJson.put("uploadFailed", false); |
|
|
|
|
|
|
|
fileArray.add(fileJson); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
result.put(column.getColumnName(), fileArray); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 将文件字段的值在insert/update的值列表中统一置NULL,避免文件JSON写入业务表。 |
|
|
|
|
|
|
|
* <p>columnValueList与columnDataList对齐(均跳过自增列)。</p> |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void nullifyFileColumnValues(List<ColumnData> columnDataList, List<Object> columnValueList) { |
|
|
|
|
|
|
|
int valueIndex = 0; |
|
|
|
|
|
|
|
for (ColumnData columnData : columnDataList) { |
|
|
|
|
|
|
|
if (BooleanUtil.isTrue(columnData.getColumn().getAutoIncrement())) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (FieldKind.isFileKind(columnData.getColumn().getFieldKind())) { |
|
|
|
|
|
|
|
columnData.setColumnValue(null); |
|
|
|
|
|
|
|
columnValueList.set(valueIndex, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
valueIndex++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Long convertToLongId(String dataId) { |
|
|
|
|
|
|
|
if (StrUtil.isBlank(dataId)) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
return Long.valueOf(dataId); |
|
|
|
|
|
|
|
} catch (NumberFormatException e) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void makeupColumnValue(ColumnData columnData) { |
|
|
|
private void makeupColumnValue(ColumnData columnData) { |
|
|
|
if (BooleanUtil.isTrue(columnData.getColumn().getAutoIncrement())) { |
|
|
|
if (BooleanUtil.isTrue(columnData.getColumn().getAutoIncrement())) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
|