|
|
|
@ -3,6 +3,7 @@ package apelet.common.online.controller; |
|
|
|
import apelet.common.core.annotation.MyRequestBody; |
|
|
|
import apelet.common.core.annotation.MyRequestBody; |
|
|
|
import apelet.common.core.annotation.NoAuthInterface; |
|
|
|
import apelet.common.core.annotation.NoAuthInterface; |
|
|
|
import apelet.common.core.cache.CacheConfig; |
|
|
|
import apelet.common.core.cache.CacheConfig; |
|
|
|
|
|
|
|
import apelet.common.core.cache.CacheKey; |
|
|
|
import apelet.common.core.constant.AppDeviceType; |
|
|
|
import apelet.common.core.constant.AppDeviceType; |
|
|
|
import apelet.common.core.constant.ErrorCodeEnum; |
|
|
|
import apelet.common.core.constant.ErrorCodeEnum; |
|
|
|
import apelet.common.core.object.*; |
|
|
|
import apelet.common.core.object.*; |
|
|
|
@ -12,16 +13,21 @@ import apelet.common.core.util.MyPageUtil; |
|
|
|
import apelet.common.core.validator.UpdateGroup; |
|
|
|
import apelet.common.core.validator.UpdateGroup; |
|
|
|
import apelet.common.dbutil.object.SqlTable; |
|
|
|
import apelet.common.dbutil.object.SqlTable; |
|
|
|
import apelet.common.dbutil.object.SqlTableColumn; |
|
|
|
import apelet.common.dbutil.object.SqlTableColumn; |
|
|
|
|
|
|
|
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.IOnlFormHeadService; |
|
|
|
import apelet.common.generator.service.IOnlFormHeadService; |
|
|
|
|
|
|
|
import apelet.common.generator.utils.CustomUtil; |
|
|
|
|
|
|
|
import apelet.common.generator.utils.cache.MetaCacheService; |
|
|
|
import apelet.common.log.annotation.OperationLog; |
|
|
|
import apelet.common.log.annotation.OperationLog; |
|
|
|
import apelet.common.log.model.constant.SysOperationLogType; |
|
|
|
import apelet.common.log.model.constant.SysOperationLogType; |
|
|
|
import apelet.common.online.config.OnlineProperties; |
|
|
|
import apelet.common.online.config.OnlineProperties; |
|
|
|
import apelet.common.online.dto.*; |
|
|
|
|
|
|
|
import apelet.common.online.dto.OnlineEventPluginExecuteDto; |
|
|
|
import apelet.common.online.dto.OnlineEventPluginExecuteDto; |
|
|
|
|
|
|
|
import apelet.common.online.dto.OnlineFormDto; |
|
|
|
import apelet.common.online.model.*; |
|
|
|
import apelet.common.online.model.*; |
|
|
|
import apelet.common.online.service.*; |
|
|
|
import apelet.common.online.service.*; |
|
|
|
import apelet.common.online.util.OnlineRedisKeyUtil; |
|
|
|
import apelet.common.online.util.OnlineRedisKeyUtil; |
|
|
|
|
|
|
|
import apelet.common.online.util.WidgetFieldTypeMapping; |
|
|
|
import apelet.common.online.vo.OnlineFormVo; |
|
|
|
import apelet.common.online.vo.OnlineFormVo; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.collection.CollUtil; |
|
|
|
import cn.hutool.core.map.MapUtil; |
|
|
|
import cn.hutool.core.map.MapUtil; |
|
|
|
@ -47,8 +53,9 @@ import org.springframework.web.bind.annotation.*; |
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
import javax.annotation.Resource; |
|
|
|
import javax.validation.groups.Default; |
|
|
|
import javax.validation.groups.Default; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
import java.util.function.Consumer; |
|
|
|
|
|
|
|
import java.util.function.Function; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -83,12 +90,17 @@ public class OnlineFormController { |
|
|
|
@Autowired |
|
|
|
@Autowired |
|
|
|
IOnlFormHeadService onlFormHeadService; |
|
|
|
IOnlFormHeadService onlFormHeadService; |
|
|
|
@Autowired |
|
|
|
@Autowired |
|
|
|
|
|
|
|
IOnlFormFieldService onlFormFieldService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
OnlinePageService onlinePageService; |
|
|
|
OnlinePageService onlinePageService; |
|
|
|
@Autowired |
|
|
|
@Autowired |
|
|
|
private OnlineProperties properties; |
|
|
|
private OnlineProperties properties; |
|
|
|
@Resource(name = "caffeineCacheManager") |
|
|
|
@Resource(name = "caffeineCacheManager") |
|
|
|
private CacheManager cacheManager; |
|
|
|
private CacheManager cacheManager; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
|
|
private MetaCacheService metaCacheService; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 新增在线表单数据。 |
|
|
|
* 新增在线表单数据。 |
|
|
|
* |
|
|
|
* |
|
|
|
@ -326,6 +338,13 @@ public class OnlineFormController { |
|
|
|
onlineForm.setWidgetJson(jsonObject.toJSONString()); |
|
|
|
onlineForm.setWidgetJson(jsonObject.toJSONString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ★ 新增: 处理新增字段和子表
|
|
|
|
|
|
|
|
JSONObject updatedJson = syncNewFieldsAndSubTables(onlineForm, onlineFormDto, JSON.parseObject(onlineForm.getWidgetJson())); |
|
|
|
|
|
|
|
if (updatedJson != null) { |
|
|
|
|
|
|
|
onlineForm.setWidgetJson(updatedJson.toJSONString()); |
|
|
|
|
|
|
|
onlineFormDto.setWidgetJson(updatedJson.toJSONString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!onlineFormService.update(onlineForm, originalOnlineForm, datasourceIdSet)) { |
|
|
|
if (!onlineFormService.update(onlineForm, originalOnlineForm, datasourceIdSet)) { |
|
|
|
redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineFormKey(onlineForm.getFormId())).delete(); |
|
|
|
redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineFormKey(onlineForm.getFormId())).delete(); |
|
|
|
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); |
|
|
|
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); |
|
|
|
@ -685,4 +704,404 @@ public class OnlineFormController { |
|
|
|
} |
|
|
|
} |
|
|
|
return ResponseResult.success(onlineFormList); |
|
|
|
return ResponseResult.success(onlineFormList); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 字段diff+同步 相关私有方法 ============
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 对比 widgetJson 与现有 OnlFormField / OnlFormHead 识别新增字段和子表, |
|
|
|
|
|
|
|
* 创建 OnlFormField 记录、同步数据库、创建 OnlineColumn、回填 columnId/relationId。 |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return 修改后的 widgetJson (含回填的 columnId/relationId),无变更则返回 null |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private JSONObject syncNewFieldsAndSubTables(OnlineForm form, OnlineFormDto dto, JSONObject widgetJson) { |
|
|
|
|
|
|
|
// 1. 获取数据源 → OnlineTable → OnlFormHead
|
|
|
|
|
|
|
|
OnlineDatasource datasource = onlineDatasourceService.getById(dto.getDatasourceIdList().get(0)); |
|
|
|
|
|
|
|
OnlineTable onlineTable = onlineTableService.getById(datasource.getMasterTableId()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OnlFormHead onlFormHead = onlFormHeadService.getOne( |
|
|
|
|
|
|
|
new LambdaQueryWrapper<OnlFormHead>() |
|
|
|
|
|
|
|
.eq(OnlFormHead::getTableName, onlineTable.getTableName())); |
|
|
|
|
|
|
|
if (onlFormHead == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean changed = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Diff 新增字段 ===
|
|
|
|
|
|
|
|
Set<String> widgetColumnNames = collectAllBindColumnNames(widgetJson); |
|
|
|
|
|
|
|
List<OnlFormField> existingFields = onlFormFieldService.list( |
|
|
|
|
|
|
|
new LambdaQueryWrapper<OnlFormField>().eq(OnlFormField::getHeadId, onlFormHead.getId())); |
|
|
|
|
|
|
|
Set<String> existingFieldNames = existingFields.stream() |
|
|
|
|
|
|
|
.map(OnlFormField::getFieldName).collect(Collectors.toSet()); |
|
|
|
|
|
|
|
Set<String> newColumnNames = new HashSet<>(widgetColumnNames); |
|
|
|
|
|
|
|
newColumnNames.removeAll(existingFieldNames); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!newColumnNames.isEmpty()) { |
|
|
|
|
|
|
|
Map<String, JSONObject> nameToWidget = mapColumnNameToWidget(widgetJson); |
|
|
|
|
|
|
|
OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 预校验:过滤掉 widgetType 不在映射中的控件,避免 getFieldTypeId 抛异常导致部分数据已入库
|
|
|
|
|
|
|
|
Set<String> validColumnNames = new LinkedHashSet<>(); |
|
|
|
|
|
|
|
for (String fieldName : newColumnNames) { |
|
|
|
|
|
|
|
JSONObject widget = nameToWidget.get(fieldName); |
|
|
|
|
|
|
|
Integer widgetType = widget != null ? widget.getInteger("widgetType") : null; |
|
|
|
|
|
|
|
if (widgetType == null || !WidgetFieldTypeMapping.isDataWidget(widgetType)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
validColumnNames.add(fieldName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (validColumnNames.isEmpty()) { |
|
|
|
|
|
|
|
return changed ? widgetJson : null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (String fieldName : validColumnNames) { |
|
|
|
|
|
|
|
JSONObject widget = nameToWidget.get(fieldName); |
|
|
|
|
|
|
|
// 从 widget 的 bindData.columnComment 设置字段备注
|
|
|
|
|
|
|
|
JSONObject bindData = widget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
this.saveField(widget.getInteger("widgetType"), bindData.getString("columnComment"), widget.getString("showName"), onlFormHead, fieldName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ALTER TABLE ADD COLUMN
|
|
|
|
|
|
|
|
onlFormHeadService.syncDB(onlFormHead, 0L); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 批量获取所有列信息,避免 N+1 查询
|
|
|
|
|
|
|
|
List<SqlTableColumn> allColumns = onlineDblinkService.getDblinkTableColumnList( |
|
|
|
|
|
|
|
dblink, onlineTable.getTableName()); |
|
|
|
|
|
|
|
Map<String, SqlTableColumn> columnMap = new HashMap<>(); |
|
|
|
|
|
|
|
if (CollUtil.isNotEmpty(allColumns)) { |
|
|
|
|
|
|
|
for (SqlTableColumn col : allColumns) { |
|
|
|
|
|
|
|
if (col.getColumnName() != null) { |
|
|
|
|
|
|
|
columnMap.put(col.getColumnName().toLowerCase(), col); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 增量创建 OnlineColumn + 回填 columnId 到 widgetJson
|
|
|
|
|
|
|
|
for (String fieldName : validColumnNames) { |
|
|
|
|
|
|
|
SqlTableColumn sqlCol = columnMap.get(fieldName.toLowerCase()); |
|
|
|
|
|
|
|
if (sqlCol != null) { |
|
|
|
|
|
|
|
// 回填 columnId 到 widgetJson
|
|
|
|
|
|
|
|
JSONObject widget = nameToWidget.get(fieldName); |
|
|
|
|
|
|
|
String showName = widget == null ? null : widget.getString("showName"); |
|
|
|
|
|
|
|
long columnId = onlineColumnService.saveBySqlTable(sqlCol, onlineTable.getTableId(), showName); |
|
|
|
|
|
|
|
if (widget != null) { |
|
|
|
|
|
|
|
JSONObject bindData2 = widget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData2 != null) { |
|
|
|
|
|
|
|
bindData2.put("columnId", columnId); |
|
|
|
|
|
|
|
bindData2.put("tableId", onlineTable.getTableId()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineTableKey(onlineTable.getTableId())).delete(); |
|
|
|
|
|
|
|
redissonClient.getBucket(CacheKey.makeTableKey(onlineTable.getTableName())).delete(); |
|
|
|
|
|
|
|
redissonClient.getBucket(CacheKey.makeChildFieldListKey(onlFormHead.getId())).delete(); |
|
|
|
|
|
|
|
metaCacheService.removeData(onlineTable.getTableName()); |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// === Diff 新增子表 ===
|
|
|
|
|
|
|
|
// 取 widgetList->bindData -> tableId 在去 zz_online_table 查询,这样就可以判断哪些是新增,哪些是 已有的表
|
|
|
|
|
|
|
|
// 如果存在附表
|
|
|
|
|
|
|
|
Map<String, JSONObject> tableIdAndPropMap = collectSubTableAndPropMap(widgetJson); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (MapUtil.isNotEmpty(tableIdAndPropMap)) { |
|
|
|
|
|
|
|
//搜集的所有tableId, 要么是 tableId(已存在),要么是 tableName(不存在)
|
|
|
|
|
|
|
|
Set<String> allTableIdSet = tableIdAndPropMap.keySet(); |
|
|
|
|
|
|
|
Set<String> newSubTableNames = new HashSet<>(); |
|
|
|
|
|
|
|
Set<Long> existingSubTableIdSet = new HashSet<>(); |
|
|
|
|
|
|
|
for (String tableId : allTableIdSet) { |
|
|
|
|
|
|
|
if (tableId.matches("\\d+")) { |
|
|
|
|
|
|
|
existingSubTableIdSet.add(Long.parseLong(tableId)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
newSubTableNames.add(tableId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//分两步,
|
|
|
|
|
|
|
|
//step1 : 看看存在的附表,是否存在不存在的字段
|
|
|
|
|
|
|
|
if (!existingSubTableIdSet.isEmpty()) { |
|
|
|
|
|
|
|
// 拿到tableId 下面的所有字段,先查询 zz_online_table ,在根据 tableName 查询 onl_form_head 表
|
|
|
|
|
|
|
|
List<OnlineTable> tableList = onlineTableService.listByIds(existingSubTableIdSet); |
|
|
|
|
|
|
|
Map<Long, String> tableIdAndNameMap = tableList.stream().collect(Collectors.toMap(OnlineTable::getTableId, OnlineTable::getTableName)); |
|
|
|
|
|
|
|
List<String> tableNames = tableList.stream().map(OnlineTable::getTableName).collect(Collectors.toList()); |
|
|
|
|
|
|
|
List<OnlFormHead> onlFormHeadList = onlFormHeadService.list(new LambdaQueryWrapper<OnlFormHead>().in(OnlFormHead::getTableName, tableNames)); |
|
|
|
|
|
|
|
Map<String, OnlFormHead> tableNameAndHeadIdMap = onlFormHeadList.stream().collect(Collectors.toMap(OnlFormHead::getTableName, Function.identity())); |
|
|
|
|
|
|
|
//因为这里是zz_online_column.column_id 的id和 列名的混合,我只要列名
|
|
|
|
|
|
|
|
Map<String, JSONObject> nameToWidget = mapColumnIdAndWidget(widgetJson); |
|
|
|
|
|
|
|
Set<String> newSubColumnNameSet = nameToWidget.keySet().stream().filter(s -> !s.matches("\\d+")).collect(Collectors.toSet()); |
|
|
|
|
|
|
|
//这里要走 新增逻辑
|
|
|
|
|
|
|
|
if (!newSubColumnNameSet.isEmpty()) { |
|
|
|
|
|
|
|
// ALTER TABLE ADD COLUMN, 这里取第一个就行,因为绑定的是一个表
|
|
|
|
|
|
|
|
JSONObject columnInfo = nameToWidget.values().iterator().next(); |
|
|
|
|
|
|
|
Long tableId = columnInfo.getLong("tableId"); |
|
|
|
|
|
|
|
String tableName = tableIdAndNameMap.get(tableId); |
|
|
|
|
|
|
|
OnlFormHead entryHead = tableNameAndHeadIdMap.get(tableName); |
|
|
|
|
|
|
|
for (String newSubColumnName : newSubColumnNameSet) { |
|
|
|
|
|
|
|
//这里取出来的结构是 widgetList -》 props -》 tableColumnList
|
|
|
|
|
|
|
|
JSONObject columnInfoJson = nameToWidget.get(newSubColumnName); |
|
|
|
|
|
|
|
//step 1 : 先保存 field 表
|
|
|
|
|
|
|
|
String showName = columnInfoJson.getString("showName"); |
|
|
|
|
|
|
|
// 默认是字符串类型
|
|
|
|
|
|
|
|
this.saveField(750, showName, null, entryHead, newSubColumnName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
onlFormHeadService.syncDB(entryHead, 0L); |
|
|
|
|
|
|
|
//step 2 :在保存 OnlineColumn 表
|
|
|
|
|
|
|
|
OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); |
|
|
|
|
|
|
|
List<SqlTableColumn> allColumns = onlineDblinkService.getDblinkTableColumnList(dblink, tableName); |
|
|
|
|
|
|
|
Map<String, SqlTableColumn> columnMap = new HashMap<>(); |
|
|
|
|
|
|
|
if (CollUtil.isNotEmpty(allColumns)) { |
|
|
|
|
|
|
|
columnMap = allColumns.stream().collect(Collectors.toMap(SqlTableColumn::getColumnName, Function.identity())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (String fieldName : newSubColumnNameSet) { |
|
|
|
|
|
|
|
SqlTableColumn sqlCol = columnMap.get(fieldName.toLowerCase()); |
|
|
|
|
|
|
|
if (sqlCol != null) { |
|
|
|
|
|
|
|
// 回填 columnId 到 widgetJson
|
|
|
|
|
|
|
|
JSONObject widget = nameToWidget.get(fieldName); |
|
|
|
|
|
|
|
String showName = widget == null ? null : widget.getString("showName"); |
|
|
|
|
|
|
|
long columnId = onlineColumnService.saveBySqlTable(sqlCol, tableId, showName); |
|
|
|
|
|
|
|
if (widget != null) { |
|
|
|
|
|
|
|
//step 3 :回填 columnId + showFieldName 到 json里面去
|
|
|
|
|
|
|
|
widget.put("columnId", columnId); |
|
|
|
|
|
|
|
widget.put("showFieldName", fieldName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//step 4 :删除缓存
|
|
|
|
|
|
|
|
redissonClient.getBucket(OnlineRedisKeyUtil.makeOnlineTableKey(tableId)).delete(); |
|
|
|
|
|
|
|
redissonClient.getBucket(CacheKey.makeTableKey(tableName)).delete(); |
|
|
|
|
|
|
|
redissonClient.getBucket(CacheKey.makeChildFieldListKey(entryHead.getId())).delete(); |
|
|
|
|
|
|
|
metaCacheService.removeData(tableName); |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//step2 : 不存在的附表,新增
|
|
|
|
|
|
|
|
if (newSubTableNames.isEmpty()) { |
|
|
|
|
|
|
|
//如果他为空,说明我们走tableId取值没取到,我们就去一下 tableName;
|
|
|
|
|
|
|
|
newSubTableNames = this.collectSubTableName(widgetJson); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!newSubTableNames.isEmpty()) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (String subTableName : newSubTableNames) { |
|
|
|
|
|
|
|
OnlFormHead subHead = onlFormHeadService.createMetaAndSync(subTableName, onlFormHead.getTableTxt() + "附表", CustomUtil.MetaType_Entry, onlFormHead.getTableName()); |
|
|
|
|
|
|
|
// 获取子表的 OnlineTable
|
|
|
|
|
|
|
|
OnlineTable subOnlineTable = onlineTableService.getOne(new LambdaQueryWrapper<OnlineTable>().eq(OnlineTable::getTableName, subTableName.toLowerCase())); |
|
|
|
|
|
|
|
if (subOnlineTable == null) { |
|
|
|
|
|
|
|
// 从DB获取表结构并创建 OnlineTable
|
|
|
|
|
|
|
|
SqlTable subSqlTable = onlineDblinkService.getDblinkTable(onlineDblinkService.getById(datasource.getDblinkId()), subTableName); |
|
|
|
|
|
|
|
if (subSqlTable != null) { |
|
|
|
|
|
|
|
subOnlineTable = onlineTableService.saveNewFromSqlTable(subSqlTable); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
OnlineDblink dblink = onlineDblinkService.getById(datasource.getDblinkId()); |
|
|
|
|
|
|
|
onlineDatasourceRelationService.addOnlineDatasourceRelation(onlFormHead, datasource, null, dblink); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (subOnlineTable != null) { |
|
|
|
|
|
|
|
backfillRelationId(widgetJson, subTableName, subOnlineTable.getTableId()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return changed ? widgetJson : null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void saveField(Integer widgetType, String columnComment, String showName, OnlFormHead onlFormHead, String fieldName) { |
|
|
|
|
|
|
|
OnlFormField field = new OnlFormField(); |
|
|
|
|
|
|
|
field.setHeadId(onlFormHead.getId()); |
|
|
|
|
|
|
|
field.setFieldName(fieldName); |
|
|
|
|
|
|
|
field.setFieldType(WidgetFieldTypeMapping.getFieldTypeId(widgetType)); |
|
|
|
|
|
|
|
Integer length = WidgetFieldTypeMapping.getDefaultLength(widgetType); |
|
|
|
|
|
|
|
if (length != null) { |
|
|
|
|
|
|
|
field.setFieldLength(length); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
field.setIsEmpty(1); |
|
|
|
|
|
|
|
field.setIsDefault(0); |
|
|
|
|
|
|
|
field.setRowDisabled(0); |
|
|
|
|
|
|
|
field.setSyncFlag(0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 从 widget 的 bindData.columnComment 设置字段备注
|
|
|
|
|
|
|
|
field.setFieldRemark(columnComment); |
|
|
|
|
|
|
|
if (StringUtils.isNotBlank(showName) && (StringUtils.isBlank(field.getFieldRemark()) || StringUtils.equals("null", field.getFieldRemark()))) { |
|
|
|
|
|
|
|
field.setFieldRemark(showName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
onlFormFieldService.save(field); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 遍历 pc/mobile 的 widget 树,收集所有 bindData.columnName 值。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Set<String> collectAllBindColumnNames(JSONObject widgetJson) { |
|
|
|
|
|
|
|
Set<String> names = new HashSet<>(); |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
JSONObject bindData = widget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData != null && bindData.containsKey("columnName")) { |
|
|
|
|
|
|
|
String name = bindData.getString("columnName"); |
|
|
|
|
|
|
|
if (StrUtil.isNotEmpty(name)) { |
|
|
|
|
|
|
|
names.add(name); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
return names; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 遍历 pc/mobile 的 widget 树,收集 widgetType=100 (TableContainer) 的 bindData 下的 tableId |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Map<String, JSONObject> collectSubTableAndPropMap(JSONObject widgetJson) { |
|
|
|
|
|
|
|
Map<String, JSONObject> resultMap = new HashMap<>(); |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
JSONArray widgetList = widget.getJSONArray("widgetList"); |
|
|
|
|
|
|
|
if (widgetList != null) { |
|
|
|
|
|
|
|
for (int i = 0; i < widgetList.size(); i++) { |
|
|
|
|
|
|
|
JSONObject childWidget = widgetList.getJSONObject(i); |
|
|
|
|
|
|
|
// 只处理widgetType为100的子表
|
|
|
|
|
|
|
|
Integer widgetType = childWidget.getInteger("widgetType"); |
|
|
|
|
|
|
|
if (widgetType == null || widgetType != 100) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject bindData = childWidget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String tableId = bindData.getString("tableId"); |
|
|
|
|
|
|
|
if (StrUtil.isBlank(tableId)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject props = childWidget.getJSONObject("props"); |
|
|
|
|
|
|
|
if (props != null) { |
|
|
|
|
|
|
|
resultMap.put(tableId, props); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
return resultMap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Set<String> collectSubTableName(JSONObject widgetJson) { |
|
|
|
|
|
|
|
Set<String> tableNameSet = new HashSet<>(); |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
JSONArray widgetList = widget.getJSONArray("widgetList"); |
|
|
|
|
|
|
|
if (widgetList != null) { |
|
|
|
|
|
|
|
for (int i = 0; i < widgetList.size(); i++) { |
|
|
|
|
|
|
|
JSONObject childWidget = widgetList.getJSONObject(i); |
|
|
|
|
|
|
|
// 只处理widgetType为100的子表
|
|
|
|
|
|
|
|
Integer widgetType = childWidget.getInteger("widgetType"); |
|
|
|
|
|
|
|
if (widgetType == null || widgetType != 100) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject bindData = childWidget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (bindData.containsKey("tableName")) { |
|
|
|
|
|
|
|
tableNameSet.add(bindData.getString("tableName")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
return tableNameSet; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 构建 columnName → widget 的映射。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private Map<String, JSONObject> mapColumnNameToWidget(JSONObject widgetJson) { |
|
|
|
|
|
|
|
Map<String, JSONObject> map = new HashMap<>(); |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
JSONObject bindData = widget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData != null && bindData.containsKey("columnName")) { |
|
|
|
|
|
|
|
String name = bindData.getString("columnName"); |
|
|
|
|
|
|
|
if (StrUtil.isNotEmpty(name)) { |
|
|
|
|
|
|
|
map.put(name, widget); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
return map; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Map<String, JSONObject> mapColumnIdAndWidget(JSONObject widgetJson) { |
|
|
|
|
|
|
|
Map<String, JSONObject> resultMap = new HashMap<>(); |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
JSONArray widgetList = widget.getJSONArray("widgetList"); |
|
|
|
|
|
|
|
if (widgetList != null) { |
|
|
|
|
|
|
|
for (int i = 0; i < widgetList.size(); i++) { |
|
|
|
|
|
|
|
JSONObject childWidget = widgetList.getJSONObject(i); |
|
|
|
|
|
|
|
// 只处理widgetType为100的子表
|
|
|
|
|
|
|
|
Integer widgetType = childWidget.getInteger("widgetType"); |
|
|
|
|
|
|
|
if (widgetType == null || widgetType != 100) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject bindData = childWidget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (bindData == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String tableId = bindData.getString("tableId"); |
|
|
|
|
|
|
|
if (StrUtil.isBlank(tableId)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject props = childWidget.getJSONObject("props"); |
|
|
|
|
|
|
|
if (props == null) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
JSONArray tableColumnList = props.getJSONArray("tableColumnList"); |
|
|
|
|
|
|
|
for (int j = 0; j < tableColumnList.size(); j++) { |
|
|
|
|
|
|
|
JSONObject tableColumn = tableColumnList.getJSONObject(j); |
|
|
|
|
|
|
|
resultMap.put(tableColumn.getString("columnId"), tableColumn); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
return resultMap; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 在 widgetJson 中查找匹配 tableName 的 TableContainer 控件,回填 tableId。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void backfillRelationId(JSONObject widgetJson, String tableName, Long tableId) { |
|
|
|
|
|
|
|
walkAllModes(widgetJson, widget -> { |
|
|
|
|
|
|
|
if (widget.getInteger("widgetType") != null && 100 == widget.getInteger("widgetType")) { |
|
|
|
|
|
|
|
JSONObject props = widget.getJSONObject("bindData"); |
|
|
|
|
|
|
|
if (props != null && tableName.equals(props.getString("tableName"))) { |
|
|
|
|
|
|
|
props.put("tableId", tableId); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 遍历 "pc" 和 "mobile" 两个模式的控件树。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void walkAllModes(JSONObject widgetJson, Consumer<JSONObject> visitor) { |
|
|
|
|
|
|
|
for (String mode : new String[]{"pc", "mobile"}) { |
|
|
|
|
|
|
|
JSONObject modeObj = widgetJson.getJSONObject(mode); |
|
|
|
|
|
|
|
if (modeObj != null) { |
|
|
|
|
|
|
|
walkWidgets(modeObj, visitor); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 递归遍历控件树,访问每个控件及其子控件(widgetList)。 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void walkWidgets(JSONObject node, Consumer<JSONObject> visitor) { |
|
|
|
|
|
|
|
if (node == null) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
visitor.accept(node); |
|
|
|
|
|
|
|
JSONArray children = node.getJSONArray("widgetList"); |
|
|
|
|
|
|
|
if (children != null) { |
|
|
|
|
|
|
|
for (int i = 0; i < children.size(); i++) { |
|
|
|
|
|
|
|
walkWidgets(children.getJSONObject(i), visitor); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|