@ -6,6 +6,7 @@ import apelet.common.core.cache.CacheConfig;
@@ -6,6 +6,7 @@ import apelet.common.core.cache.CacheConfig;
import apelet.common.core.cache.CacheKey ;
import apelet.common.core.constant.AppDeviceType ;
import apelet.common.core.constant.ErrorCodeEnum ;
import apelet.common.core.constant.GlobalDeletedFlag ;
import apelet.common.core.object.* ;
import apelet.common.core.util.MyCommonUtil ;
import apelet.common.core.util.MyModelUtil ;
@ -32,7 +33,6 @@ import apelet.common.online.util.WidgetFieldTypeMapping;
@@ -32,7 +33,6 @@ import apelet.common.online.util.WidgetFieldTypeMapping;
import apelet.common.online.util.WidgetJsonUtil ;
import apelet.common.online.vo.OnlineFormVo ;
import cn.hutool.core.collection.CollUtil ;
import cn.hutool.core.map.MapUtil ;
import cn.hutool.core.util.BooleanUtil ;
import cn.hutool.core.util.ObjectUtil ;
import cn.hutool.core.util.StrUtil ;
@ -57,6 +57,7 @@ import org.springframework.web.bind.annotation.*;
@@ -57,6 +57,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource ;
import javax.validation.groups.Default ;
import java.util.* ;
import java.util.function.Consumer ;
import java.util.function.Function ;
import java.util.stream.Collectors ;
@ -229,116 +230,6 @@ public class OnlineFormController {
@@ -229,116 +230,6 @@ public class OnlineFormController {
. eq ( OnlineDatasourceRelation : : getRelationType , 0 )
. eq ( OnlineDatasourceRelation : : getDatasourceId , onlineFormDto . getDatasourceIdList ( ) . get ( 0 ) ) ) ;
}
// for (int i = 0; i < jsonArray.size(); i++) {
// JSONObject object = jsonArray.getJSONObject(i);
// Integer widgetType = object.getInteger("widgetType");
// //外键id
// String columnId = object.getJSONObject("bindData").getString("columnId");
// //主表id
// String tableId = object.getJSONObject("bindData").getString("tableId");
// OnlineTable onlineTable = onlineTableService.getById(tableId);
// //从表名称
// String slaveTableName = object.getJSONObject("bindData").getString("slaveTableName");
// if (402 == widgetType){
// if (object.getJSONObject("props") != null && object.getJSONObject("props").getJSONObject("relativeTable") != null){
// String relationId = object.getJSONObject("props").getJSONObject("relativeTable").getString("relationId");//关联id
// if(StringUtils.isNotEmpty(relationId)){
// OnlineDatasourceRelation onlineDatasourceRelation = onlineDatasourceRelationService.getById(Long.valueOf(relationId));
// if(onlineDatasourceRelation != null){
// OnlineTable sTable = onlineTableService.getById(onlineDatasourceRelation.getSlaveTableId());
// if( ! (onlineDatasourceRelation.getMasterColumnId() == Long.valueOf(columnId)
// && onlineDatasourceRelation.getRelationType() == 0
// && onlineDatasourceRelation.getDatasourceId() == onlineFormDto.getDatasourceIdList().get(0)
// && sTable.getTableName().equals(slaveTableName) )
// ){//已存在关联关系,不符合规则
// onlineDatasourceRelationService.remove(onlineDatasourceRelation.getRelationId());
// }
// }
// }
// }
// OnlineDatasourceRelation onr = onlineDatasourceRelationService.getOne(new LambdaQueryWrapper<OnlineDatasourceRelation>()
// .eq(OnlineDatasourceRelation::getMasterColumnId,columnId)
// .eq(OnlineDatasourceRelation::getRelationType,0)
// .eq(OnlineDatasourceRelation::getDatasourceId,onlineFormDto.getDatasourceIdList().get(0)));
// if(slaveTableName == null){
// errorMessage = "关联控件校验失败,字段绑定表";
// return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
// }
// if(onr != null){
// OnlineTable sTable = onlineTableService.getById(onr.getSlaveTableId());
// if(onr != null && !slaveTableName.equals(sTable.getTableName())){
// errorMessage = "关联控件校验失败,字段关联多张表";
// return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
// }
// if(onr != null && slaveTableName.equals(sTable.getTableName())) {
// if (object.getJSONObject("props") != null && object.getJSONObject("props").getJSONObject("relativeTable") != null) {
// if (object.getJSONObject("props").getJSONObject("relativeTable").getString("relativeFormType").equals("2")) {//关联查询数据源\
// OnlineDatasource datasource = onlineDatasourceService.getById(onlineFormDto.getDatasourceIdList().get(0));
// object.getJSONObject("props").getJSONObject("relativeTable").put("datasourceId", onlineFormDto.getDatasourceIdList().get(0));
// object.getJSONObject("props").getJSONObject("relativeTable").put("variableName",datasource.getVariableName() );
// object.getJSONObject("props").getJSONObject("relativeTable").put("relationId",onr.getRelationId());
// object.getJSONObject("props").getJSONObject("relativeTable").put("relativeTableName",slaveTableName);
// }
// }
// continue;
// }
// }
// //先删除对应关联关系
// onlineDatasourceRelationService.remove(new LambdaQueryWrapper<OnlineDatasourceRelation>()
// .eq(OnlineDatasourceRelation::getMasterColumnId,columnId)
// .eq(OnlineDatasourceRelation::getRelationType,0)
// .eq(OnlineDatasourceRelation::getDatasourceId,onlineFormDto.getDatasourceIdList().get(0)));
// OnlineDatasourceRelationDto onlineDatasourceRelationDto = new OnlineDatasourceRelationDto();
// onlineDatasourceRelationDto.setDatasourceId(onlineFormDto.getDatasourceIdList().get(0));
// //关联名称
// onlineDatasourceRelationDto.setRelationName(object.getString("showName"));
// //关联标识-组件标识
// onlineDatasourceRelationDto.setVariableName(onlineTable.getTableName()+"_"+object.getString("variableName")+"_"+slaveTableName);
// //关联类型
// onlineDatasourceRelationDto.setRelationType(0);
// //主键字段id
// onlineDatasourceRelationDto.setMasterColumnId(Long.valueOf(columnId));
// //从表名称
// onlineDatasourceRelationDto.setSlaveTableName(slaveTableName);
// //从表字段名称
// onlineDatasourceRelationDto.setSlaveColumnName("id");
// //是否级联删除
// onlineDatasourceRelationDto.setCascadeDelete(false);
// //是否左连接查询
// onlineDatasourceRelationDto.setLeftJoin(true);
// OnlineDatasourceRelation onlineDatasourceRelation =
// MyModelUtil.copyTo(onlineDatasourceRelationDto, OnlineDatasourceRelation.class);
// SqlTable slaveTable = onlineDblinkService.getDblinkTable(
// onlineDblink, onlineDatasourceRelationDto.getSlaveTableName());
// if (slaveTable == null) {
// errorMessage = "关联控件建立一对一关系失败:数据验证失败,指定的数据表不存在!";
// return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
// }
// SqlTableColumn slaveColumn = null;
// for (SqlTableColumn column : slaveTable.getColumnList()) {
// if (column.getColumnName().equals(onlineDatasourceRelationDto.getSlaveColumnName())) {
// slaveColumn = column;
// break;
// }
// }
// if (slaveColumn == null) {
// errorMessage = "关联控件建立一对一关系失败:数据验证失败,指定的数据表字段 [" + onlineDatasourceRelationDto.getSlaveColumnName() + "] 不存在!";
// return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
// }
// onlineDatasourceRelation = onlineDatasourceRelationService.saveNew(onlineDatasourceRelation, slaveTable, slaveColumn);
// if (object.getJSONObject("props") != null && object.getJSONObject("props").getJSONObject("relativeTable") != null){
// if (object.getJSONObject("props").getJSONObject("relativeTable").getString("relativeFormType").equals("2")) {//关联查询数据源\
// OnlineDatasource datasource = onlineDatasourceService.getById(onlineFormDto.getDatasourceIdList().get(0));
// object.getJSONObject("props").getJSONObject("relativeTable").put("datasourceId", onlineFormDto.getDatasourceIdList().get(0));
// object.getJSONObject("props").getJSONObject("relativeTable").put("variableName",datasource.getVariableName() );
// object.getJSONObject("props").getJSONObject("relativeTable").put("relativeTableName",slaveTableName);
// }
// object.getJSONObject("props").getJSONObject("relativeTable").put("relationId",onlineDatasourceRelation.getRelationId());
// }
//
//
// }
// }
onlineForm . setWidgetJson ( jsonObject . toJSONString ( ) ) ;
}
@ -707,256 +598,98 @@ public class OnlineFormController {
@@ -707,256 +598,98 @@ public class OnlineFormController {
* @return 修改后的 widgetJson ( 含回填的 columnId / relationId ) , 无变更则返回 null
* /
private JSONObject syncNewFieldsAndSubTables ( OnlineForm form , OnlineFormDto dto , JSONObject widgetJson ) {
// 1. 获取数据源 → OnlineTable → OnlFormH ead
// 1. 获取数据源 → 主表 → 主表 h ead
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 ;
}
OnlineTable masterTable = onlineTableService . getById ( datasource . getMasterTableId ( ) ) ;
OnlFormHead masterHead = onlFormHeadService . getOne ( new LambdaQueryWrapper < OnlFormHead > ( ) . eq ( OnlFormHead : : getTableName , masterTable . getTableName ( ) ) ) ;
if ( masterHead = = null ) return null ;
boolean changed = false ;
// === Diff 新增字段 ===
// 收集 pc/mobile 端所有绑定的字段列名
Set < String > widgetColumnNames = WidgetJsonUtil . collectBindColumnNames ( 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 ) ;
// 主表/单表已有字段:如果绑定了从表(slaveTableId),同步更新 refPropert
Map < String , JSONObject > fieldNameToWidget = WidgetJsonUtil . buildFieldNameWidgetMap ( widgetJson ) ;
for ( OnlFormField existingField : existingFields ) {
JSONObject widget = fieldNameToWidget . get ( existingField . getFieldName ( ) ) ;
if ( widget = = null ) {
continue ;
}
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
String slaveTableId = bindData . getString ( "slaveTableId" ) ;
if ( StrUtil . isNotEmpty ( slaveTableId ) ) {
existingField . setRefPropert ( Long . valueOf ( slaveTableId ) ) ;
onlFormFieldService . updateById ( existingField ) ;
}
}
if ( ! newColumnNames . isEmpty ( ) ) {
Map < String , JSONObject > nameToWidget = WidgetJsonUtil . buildColumnNameWidgetMap ( widgetJson ) ;
// 收集 mobile 端的 widget 映射(遍历 childWidgetList 路径)
Map < String , JSONObject > mobileNameToWidget = WidgetJsonUtil . buildMobileColumnNameWidgetMap ( widgetJson ) ;
OnlineDblink dblink = onlineDblinkService . getById ( datasource . getDblinkId ( ) ) ;
// 预校验:过滤掉 widgetType 不在映射中的控件,避免 getFieldTypeId 抛异常导致部分数据已入库
Set < String > validColumnNames = new LinkedHashSet < > ( ) ;
for ( String fieldName : newColumnNames ) {
JSONObject widget = nameToWidget . get ( fieldName ) ;
if ( widget = = null ) {
widget = mobileNameToWidget . 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 ) ;
if ( widget = = null ) {
widget = mobileNameToWidget . get ( fieldName ) ;
}
// 从 widget 的 bindData.columnComment 设置字段备注
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
String ref = bindData . containsKey ( "slaveTableId" ) ? bindData . getString ( "slaveTableId" ) : null ;
this . saveField ( widget . getInteger ( "widgetType" ) , bindData . getString ( "columnComment" ) , widget . getString ( "showName" ) , onlFormHead , fieldName , ref ) ;
}
// 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 ) {
JSONObject widget = nameToWidget . get ( fieldName ) ;
JSONObject mobileWidget = mobileNameToWidget . get ( fieldName ) ;
String showName = widget ! = null ? widget . getString ( "showName" ) : ( mobileWidget ! = null ? mobileWidget . getString ( "showName" ) : null ) ;
long columnId = onlineColumnService . saveBySqlTable ( sqlCol , onlineTable . getTableId ( ) , showName ) ;
// 回写 pc 端 widget
if ( widget ! = null ) {
JSONObject bindData2 = widget . getJSONObject ( "bindData" ) ;
if ( bindData2 ! = null ) {
bindData2 . put ( "columnId" , columnId ) ;
bindData2 . put ( "tableId" , onlineTable . getTableId ( ) ) ;
bindData2 . put ( "columnFieldName" , fieldName ) ;
}
}
// 回写 mobile 端 widget
if ( mobileWidget ! = null ) {
JSONObject mobileBindData = mobileWidget . getJSONObject ( "bindData" ) ;
if ( mobileBindData ! = null ) {
mobileBindData . put ( "columnId" , columnId ) ;
mobileBindData . put ( "tableId" , onlineTable . getTableId ( ) ) ;
mobileBindData . put ( "columnFieldName" , fieldName ) ;
}
// === 统一取值:pc/mobile 所有"表-字段"绑定关系(表标识 → 字段名 → 控件) ===
Map < String , Map < String , JSONObject > > tableFieldMap = WidgetJsonUtil . buildTableFieldMap ( widgetJson ) ;
// === 新增表:widgetType=100 且无 tableId(只有 tableName)的表统一先建表 ===
Set < String > newTableNames = WidgetJsonUtil . collectNewSubTableNames ( widgetJson ) ;
if ( ! newTableNames . isEmpty ( ) ) changed | = createNewSubTables ( widgetJson , masterHead , datasource , newTableNames ) ;
// === 逐表 diff 新增字段 ===
for ( Map . Entry < String , Map < String , JSONObject > > entry : tableFieldMap . entrySet ( ) ) {
String tableKey = entry . getKey ( ) ;
Map < String , JSONObject > columnWidgetMap = entry . getValue ( ) ;
if ( columnWidgetMap . isEmpty ( ) ) continue ;
// 解析表:纯数字 → 已有表(主表/单表/附表统一处理);字符串 → 刚创建的新表
OnlineTable table = tableKey . matches ( "\\d+" ) ? onlineTableService . getById ( Long . valueOf ( tableKey ) ) : onlineTableService . getOne ( new LambdaQueryWrapper < OnlineTable > ( ) . eq ( OnlineTable : : getTableName , tableKey . toLowerCase ( ) ) ) ;
if ( table = = null ) continue ;
OnlFormHead head = onlFormHeadService . getOne ( new LambdaQueryWrapper < OnlFormHead > ( ) . eq ( OnlFormHead : : getTableName , table . getTableName ( ) ) ) ;
if ( head = = null ) continue ;
List < OnlFormField > existingFields = onlFormFieldService . list ( new LambdaQueryWrapper < OnlFormField > ( ) . eq ( OnlFormField : : getHeadId , head . getId ( ) ) ) ;
Map < String , OnlFormField > fieldByColumnName = existingFields . stream ( ) . collect ( Collectors . toMap ( OnlFormField : : getFieldName , Function . identity ( ) , ( a , b ) - > a ) ) ;
List < String > newColumnNames = new ArrayList < > ( ) ;
for ( Map . Entry < String , JSONObject > columnEntry : columnWidgetMap . entrySet ( ) ) {
String columnName = columnEntry . getKey ( ) ;
JSONObject widget = columnEntry . getValue ( ) ;
OnlFormField existingField = fieldByColumnName . get ( columnName ) ;
if ( existingField ! = null ) {
// 已有字段:带 slaveTableId 则更新 refPropert(子表列仅关联列 comType=402 生效)
boolean isTableColumn = ! widget . containsKey ( "bindData" ) ;
Integer comType = widget . getInteger ( "comType" ) ;
boolean isAssociation = ! isTableColumn | | ( comType ! = null & & comType = = 402 ) ;
String slaveTableId = extractSlaveTableId ( widget ) ;
if ( isAssociation & & StrUtil . isNotEmpty ( slaveTableId ) ) {
existingField . setRefPropert ( Long . valueOf ( slaveTableId ) ) ;
onlFormFieldService . updateById ( existingField ) ;
changed = true ;
}
continue ;
}
}
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 = WidgetJsonUtil . collectSubTableProps ( 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 ) ) ;
// 新增字段:识别"字段控件"还是"子表列",非数据控件跳过
boolean isTableColumn = ! widget . containsKey ( "bindData" ) ;
Integer widgetType = widget . getInteger ( "widgetType" ) ;
if ( ! isTableColumn & & ( widgetType = = null | | ! WidgetFieldTypeMapping . isDataWidget ( widgetType ) ) ) continue ;
if ( isTableColumn ) {
// 子表列:字段类型沿用现状,硬编码 750
this . saveField ( 750 , widget . getString ( "showName" ) , null , head , columnName , extractSlaveTableId ( widget ) ) ;
} else {
newSubTableNames . add ( tableId ) ;
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
String ref = bindData . containsKey ( "slaveTableId" ) ? bindData . getString ( "slaveTableId" ) : null ;
this . saveField ( widgetType , bindData . getString ( "columnComment" ) , widget . getString ( "showName" ) , head , columnName , ref ) ;
}
}
//分两步,
//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 = WidgetJsonUtil . buildSubTableColumnWidgetMap ( 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" ) ;
String ref = columnInfoJson . containsKey ( "slaveTableId" ) ? columnInfoJson . getString ( "slaveTableId" ) : null ;
// 默认是字符串类型
this . saveField ( 750 , showName , null , entryHead , newSubColumnName , ref ) ;
newColumnNames . add ( columnName ) ;
changed = true ;
}
if ( ! newColumnNames . isEmpty ( ) ) {
// ALTER TABLE ADD COLUMN
onlFormHeadService . syncDB ( head , 0L ) ;
// 批量获取列信息,避免 N+1
OnlineDblink dblink = onlineDblinkService . getById ( datasource . getDblinkId ( ) ) ;
List < SqlTableColumn > allColumns = onlineDblinkService . getDblinkTableColumnList ( dblink , table . 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 ) ;
}
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 ) ;
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 ;
}
// 附表已有字段:检查 tableColumnList 中 comType=402 的列是否有 slaveTableId,同步更新 refPropert
for ( Long tableId : existingSubTableIdSet ) {
String tableName = tableIdAndNameMap . get ( tableId ) ;
if ( tableName = = null ) {
continue ;
}
OnlFormHead subHead = tableNameAndHeadIdMap . get ( tableName ) ;
if ( subHead = = null ) {
continue ;
}
List < OnlFormField > subFields = onlFormFieldService . list (
new LambdaQueryWrapper < OnlFormField > ( ) . eq ( OnlFormField : : getHeadId , subHead . getId ( ) ) ) ;
JSONObject props = tableIdAndPropMap . get ( String . valueOf ( tableId ) ) ;
JSONArray tableColumnList = props ! = null ? props . getJSONArray ( "tableColumnList" ) : null ;
if ( tableColumnList = = null ) {
continue ;
}
for ( OnlFormField field : subFields ) {
for ( int i = 0 ; i < tableColumnList . size ( ) ; i + + ) {
JSONObject col = tableColumnList . getJSONObject ( i ) ;
// 匹配 showFieldName,兼容 showName
String showFieldName = col . getString ( "showFieldName" ) ;
if ( StrUtil . isEmpty ( showFieldName ) ) {
showFieldName = col . getString ( "showName" ) ;
}
if ( ! field . getFieldName ( ) . equals ( showFieldName ) ) {
continue ;
}
// 只有 comType=402(关联选择器)才有 slaveTableId
Integer comType = col . getInteger ( "comType" ) ;
if ( comType ! = null & & comType = = 402 ) {
String slaveTableId = col . getString ( "slaveTableId" ) ;
if ( StrUtil . isNotEmpty ( slaveTableId ) ) {
field . setRefPropert ( Long . valueOf ( slaveTableId ) ) ;
onlFormFieldService . updateById ( field ) ;
changed = true ;
}
}
break ;
}
}
// 增量创建 OnlineColumn + 回填 columnId 到所有匹配控件
for ( String columnName : newColumnNames ) {
SqlTableColumn sqlCol = columnMap . get ( columnName . toLowerCase ( ) ) ;
if ( sqlCol = = null ) continue ;
long columnId = onlineColumnService . saveBySqlTable ( sqlCol , table . getTableId ( ) , columnWidgetMap . get ( columnName ) . getString ( "showName" ) ) ;
WidgetJsonUtil . backfillColumnId ( widgetJson , columnName , columnId , table . getTableId ( ) , table . getTableName ( ) ) ;
}
}
//step2 : 不存在的附表,新增
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , newSubTableNames ) ;
} else {
// tableIdAndPropMap 为空,说明走 tableId 取值没取到,兜底通过 tableName 收集附表并创建
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , new HashSet < > ( ) ) ;
// 删除缓存
redissonClient . getBucket ( OnlineRedisKeyUtil . makeOnlineTableKey ( table . getTableId ( ) ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeTableKey ( table . getTableName ( ) ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeChildFieldListKey ( head . getId ( ) ) ) . delete ( ) ;
metaCacheService . removeData ( table . getTableName ( ) ) ;
}
// === Diff mobile 端子表 ===
// 路径: mobile -> widgetList -> [widgetType=102] -> bindData -> tableName/tableId
changed | = syncMobileSubTables ( widgetJson , onlForm Head, datasource ) ;
// === mobile 端子表(widgetType=102)专用同步,保持原有逻辑 ===
changed | = syncMobileSubTables ( widgetJson , masterHead , datasource ) ;
return changed ? widgetJson : null ;
}
@ -1009,6 +742,21 @@ public class OnlineFormController {
@@ -1009,6 +742,21 @@ public class OnlineFormController {
}
/ * *
* 提取控件 / 子表列绑定的从表 id ( slaveTableId ) 。
* 字段控件在 bindData 下 ; 子表列对象直接挂在顶层 。
* /
private String extractSlaveTableId ( JSONObject widget ) {
if ( widget = = null ) {
return null ;
}
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData ! = null ) {
return bindData . containsKey ( "slaveTableId" ) ? bindData . getString ( "slaveTableId" ) : null ;
}
return widget . getString ( "slaveTableId" ) ;
}
private void saveField ( Integer widgetType , String columnComment , String showName , OnlFormHead onlFormHead , String fieldName , String refPropert ) {
OnlFormField field = new OnlFormField ( ) ;
field . setHeadId ( onlFormHead . getId ( ) ) ;
@ -1025,6 +773,12 @@ public class OnlineFormController {
@@ -1025,6 +773,12 @@ public class OnlineFormController {
field . setIsDefault ( 0 ) ;
field . setRowDisabled ( 0 ) ;
field . setSyncFlag ( 0 ) ;
// 逻辑删除标记:默认正常(1),onl_form_field 未配置 @TableLogic,需显式写入
field . setDeletedFlag ( GlobalDeletedFlag . NORMAL ) ;
field . setCreateTime ( new Date ( ) ) ;
field . setUpdateTime ( new Date ( ) ) ;
field . setCreateUserId ( TokenData . takeFromRequest ( ) . getUserId ( ) ) ;
field . setUpdateUserId ( TokenData . takeFromRequest ( ) . getUserId ( ) ) ;
// 从 widget 的 bindData.columnComment 设置字段备注
field . setFieldRemark ( columnComment ) ;
@ -1037,31 +791,41 @@ public class OnlineFormController {
@@ -1037,31 +791,41 @@ public class OnlineFormController {
// ============ mobile 端子表同步相关方法 ============
/ * *
* 递归遍历 mobile 控件树 ( childWidgetList ) , 收集所有 widgetType = 102 的子表组件 。
* 102 可嵌套在分组 / 卡片等容器内 。
* /
private void walkMobileSubTableWidgets ( JSONArray widgetList , Consumer < JSONObject > consumer ) {
if ( CollUtil . isEmpty ( widgetList ) ) return ;
for ( int i = 0 ; i < widgetList . size ( ) ; i + + ) {
JSONObject widget = widgetList . getJSONObject ( i ) ;
if ( widget = = null ) continue ;
Integer widgetType = widget . getInteger ( "widgetType" ) ;
if ( widgetType ! = null & & widgetType = = 102 ) {
consumer . accept ( widget ) ;
continue ;
}
JSONArray childWidgetList = widget . getJSONArray ( "childWidgetList" ) ;
if ( CollUtil . isNotEmpty ( childWidgetList ) ) walkMobileSubTableWidgets ( childWidgetList , consumer ) ;
}
}
/ * *
* 同步 mobile 端的子表 ( 新增子表 + 已有子表的新增字段 ) 。
* 规则 : bindData 有 tableId → 已有表 , 向下找字段 ; 只有 tableName → 新增表 , 不找字段 , 建表后回写 tableId 。
* 子表 : mobile - > widgetList - > [ widgetType = 102 ] - > bindData - > tableName / tableId
* 字段 : mobile - > widgetList - > childWidgetList - > childWidgetList - > bindData - > columnName
* /
private boolean syncMobileSubTables ( JSONObject widgetJson , OnlFormHead onlFormHead , OnlineDatasource datasource ) {
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
if ( mobile = = null ) {
return false ;
}
if ( mobile = = null ) return false ;
JSONArray mobileWidgetList = mobile . getJSONArray ( "widgetList" ) ;
if ( mobileWidgetList = = null ) {
return false ;
}
if ( mobileWidgetList = = null ) return false ;
boolean changed = false ;
Set < String > newSubTableNames = new LinkedHashSet < > ( ) ;
Set < Long > existingSubTableIds = new LinkedHashSet < > ( ) ;
for ( int i = 0 ; i < mobileWidgetList . size ( ) ; i + + ) {
JSONObject widget = mobileWidgetList . getJSONObject ( i ) ;
if ( widget . getInteger ( "widgetType" ) = = null | | widget . getInteger ( "widgetType" ) ! = 102 ) {
continue ;
}
walkMobileSubTableWidgets ( mobileWidgetList , widget - > {
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
if ( bindData = = null ) return ;
String tableName = bindData . getString ( "tableName" ) ;
String tableIdStr = bindData . getString ( "tableId" ) ;
if ( StrUtil . isNotEmpty ( tableName ) & & StrUtil . isEmpty ( tableIdStr ) ) {
@ -1069,7 +833,7 @@ public class OnlineFormController {
@@ -1069,7 +833,7 @@ public class OnlineFormController {
} else if ( StrUtil . isNotEmpty ( tableIdStr ) ) {
existingSubTableIds . add ( Long . valueOf ( tableIdStr ) ) ;
}
}
} ) ;
// 处理新子表: 创建后回写 tableId + masterColumnName
if ( ! newSubTableNames . isEmpty ( ) ) {
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , newSubTableNames ) ;
@ -1088,35 +852,21 @@ public class OnlineFormController {
@@ -1088,35 +852,21 @@ public class OnlineFormController {
* /
private void backfillMobileSubTableId ( JSONObject widgetJson , Set < String > newSubTableNames ) {
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
if ( mobile = = null ) {
return ;
}
if ( mobile = = null ) return ;
JSONArray mobileWidgetList = mobile . getJSONArray ( "widgetList" ) ;
if ( mobileWidgetList = = null ) {
return ;
}
for ( int i = 0 ; i < mobileWidgetList . size ( ) ; i + + ) {
JSONObject widget = mobileWidgetList . getJSONObject ( i ) ;
if ( widget . getInteger ( "widgetType" ) = = null | | widget . getInteger ( "widgetType" ) ! = 102 ) {
continue ;
}
if ( mobileWidgetList = = null ) return ;
walkMobileSubTableWidgets ( mobileWidgetList , widget - > {
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
if ( bindData = = null ) return ;
String tableName = bindData . getString ( "tableName" ) ;
if ( StrUtil . isEmpty ( tableName ) | | ! newSubTableNames . contains ( tableName ) ) {
continue ;
}
// createNewSubTables 已通过 WidgetJsonUtil.backfillTableId 回写了 tableId,这里只需补 masterColumnName
if ( StrUtil . isEmpty ( tableName ) | | ! newSubTableNames . contains ( tableName ) ) return ;
// createNewSubTables 只回写了 100 组件的 tableId,102 组件的在这里补
if ( ! bindData . containsKey ( "tableId" ) ) {
OnlineTable subTable = onlineTableService . getOne ( new LambdaQueryWrapper < OnlineTable > ( ) . eq ( OnlineTable : : getTableName , tableName . toLowerCase ( ) ) ) ;
if ( subTable ! = null ) {
bindData . put ( "tableId" , subTable . getTableId ( ) ) ;
}
if ( subTable ! = null ) bindData . put ( "tableId" , subTable . getTableId ( ) ) ;
}
bindData . put ( "masterColumnName" , "id" ) ;
}
} ) ;
}
/ * *
@ -1124,105 +874,92 @@ public class OnlineFormController {
@@ -1124,105 +874,92 @@ public class OnlineFormController {
* 字段路径 : mobile - > widgetList - > [ widgetType = 102 ] - > childWidgetList - > childWidgetList - > bindData - > columnName
* /
private boolean syncMobileSubTableNewFields ( JSONObject widgetJson , OnlineDatasource datasource , Set < Long > existingSubTableIds ) {
// 查询已有子表信息
List < OnlineTable > subTables = onlineTableService . listByIds ( existingSubTableIds ) ;
if ( CollUtil . isEmpty ( subTables ) ) {
return false ;
}
if ( CollUtil . isEmpty ( subTables ) ) return false ;
Map < Long , String > tableIdToName = subTables . stream ( ) . collect ( Collectors . toMap ( OnlineTable : : getTableId , OnlineTable : : getTableName ) ) ;
List < String > tableNames = subTables . stream ( ) . map ( OnlineTable : : getTableName ) . collect ( Collectors . toList ( ) ) ;
List < OnlFormHead > subHeads = onlFormHeadService . list ( new LambdaQueryWrapper < OnlFormHead > ( ) . in ( OnlFormHead : : getTableName , tableNames ) ) ;
Map < String , OnlFormHead > tableNameToHead = subHeads . stream ( ) . collect ( Collectors . toMap ( OnlFormHead : : getTableName , Function . identity ( ) ) ) ;
OnlineDblink dblink = onlineDblinkService . getById ( datasource . getDblinkId ( ) ) ;
// 遍历 mobile 端已有子表 widget, 搜集新增字段
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
if ( mobile = = null ) return false ;
JSONArray mobileWidgetList = mobile . getJSONArray ( "widgetList" ) ;
boolean changed = false ;
for ( int i = 0 ; i < mobileWidgetList . size ( ) ; i + + ) {
JSONObject widget = mobileWidgetList . getJSONObject ( i ) ;
if ( widget . getInteger ( "widgetType" ) = = null | | widget . getInteger ( "widgetType" ) ! = 102 ) {
continue ;
}
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
String tableIdStr = bindData . getString ( "tableId" ) ;
if ( StrUtil . isEmpty ( tableIdStr ) ) {
continue ;
}
Long tableId = Long . valueOf ( tableIdStr ) ;
String tableName = tableIdToName . get ( tableId ) ;
if ( tableName = = null ) {
continue ;
}
OnlFormHead subHead = tableNameToHead . get ( tableName ) ;
if ( subHead = = null ) {
continue ;
}
// 搜集该子表下无 columnId 的字段
List < JSONObject > newFieldWidgets = new ArrayList < > ( ) ;
JSONArray cardList = widget . getJSONArray ( "childWidgetList" ) ;
if ( cardList ! = null ) {
for ( int j = 0 ; j < cardList . size ( ) ; j + + ) {
JSONObject card = cardList . getJSONObject ( j ) ;
JSONArray fieldList = card . getJSONArray ( "childWidgetList" ) ;
if ( fieldList = = null ) {
continue ;
}
for ( int k = 0 ; k < fieldList . size ( ) ; k + + ) {
JSONObject field = fieldList . getJSONObject ( k ) ;
JSONObject fieldBd = field . getJSONObject ( "bindData" ) ;
if ( fieldBd ! = null & & fieldBd . containsKey ( "columnName" ) & & ! fieldBd . containsKey ( "columnId" ) ) {
newFieldWidgets . add ( field ) ;
}
if ( mobileWidgetList = = null ) return false ;
boolean [ ] changed = { false } ;
walkMobileSubTableWidgets ( mobileWidgetList , widget - > {
if ( syncMobileSubTableNewFieldForWidget ( widget , tableIdToName , tableNameToHead , dblink ) ) changed [ 0 ] = true ;
} ) ;
return changed [ 0 ] ;
}
/ * *
* 处理单个已有子表 ( widgetType = 102 ) 下的新增字段 , 返回是否有变更 。
* /
private boolean syncMobileSubTableNewFieldForWidget ( JSONObject widget , Map < Long , String > tableIdToName , Map < String , OnlFormHead > tableNameToHead , OnlineDblink dblink ) {
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) return false ;
String tableIdStr = bindData . getString ( "tableId" ) ;
if ( StrUtil . isEmpty ( tableIdStr ) ) return false ;
Long tableId = Long . valueOf ( tableIdStr ) ;
String tableName = tableIdToName . get ( tableId ) ;
if ( tableName = = null ) return false ;
OnlFormHead subHead = tableNameToHead . get ( tableName ) ;
if ( subHead = = null ) return false ;
// 搜集该子表下无 columnId 的字段
List < JSONObject > newFieldWidgets = new ArrayList < > ( ) ;
JSONArray cardList = widget . getJSONArray ( "childWidgetList" ) ;
if ( cardList ! = null ) {
for ( int j = 0 ; j < cardList . size ( ) ; j + + ) {
JSONObject card = cardList . getJSONObject ( j ) ;
JSONArray fieldList = card . getJSONArray ( "childWidgetList" ) ;
if ( fieldList = = null ) continue ;
for ( int k = 0 ; k < fieldList . size ( ) ; k + + ) {
JSONObject field = fieldList . getJSONObject ( k ) ;
JSONObject fieldBd = field . getJSONObject ( "bindData" ) ;
if ( fieldBd ! = null & & fieldBd . containsKey ( "columnName" ) & & ! fieldBd . containsKey ( "columnId" ) ) {
newFieldWidgets . add ( field ) ;
}
}
}
if ( newFieldWidgets . isEmpty ( ) ) {
continue ;
}
// 创建字段记录
for ( JSONObject fieldWidget : newFieldWidgets ) {
JSONObject fieldBd = fieldWidget . getJSONObject ( "bindData" ) ;
String columnName = fieldBd . getString ( "columnName" ) ;
}
if ( newFieldWidgets . isEmpty ( ) ) return false ;
// 创建字段记录
for ( JSONObject fieldWidget : newFieldWidgets ) {
JSONObject fieldBd = fieldWidget . getJSONObject ( "bindData" ) ;
String columnName = fieldBd . getString ( "columnName" ) ;
String showName = fieldWidget . getString ( "showName" ) ;
this . saveField ( fieldWidget . getInteger ( "widgetType" ) , fieldBd . getString ( "columnComment" ) , showName , subHead , columnName , null ) ;
}
// ALTER TABLE ADD COLUMN
onlFormHeadService . syncDB ( subHead , 0L ) ;
// 批量获取列信息
List < SqlTableColumn > allColumns = onlineDblinkService . getDblinkTableColumnList ( dblink , tableName ) ;
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 + 回写
for ( JSONObject fieldWidget : newFieldWidgets ) {
JSONObject fieldBd = fieldWidget . getJSONObject ( "bindData" ) ;
String columnName = fieldBd . getString ( "columnName" ) ;
SqlTableColumn sqlCol = columnMap . get ( columnName . toLowerCase ( ) ) ;
if ( sqlCol ! = null ) {
String showName = fieldWidget . getString ( "showName" ) ;
this . saveField ( fieldWidget . getInteger ( "widgetType" ) , fieldBd . getString ( "columnComment" ) , showName , subHead , columnName , null ) ;
}
// ALTER TABLE ADD COLUMN
onlFormHeadService . syncDB ( subHead , 0L ) ;
// 批量获取列信息
List < SqlTableColumn > allColumns = onlineDblinkService . getDblinkTableColumnList ( dblink , tableName ) ;
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 + 回写
for ( JSONObject fieldWidget : newFieldWidgets ) {
JSONObject fieldBd = fieldWidget . getJSONObject ( "bindData" ) ;
String columnName = fieldBd . getString ( "columnName" ) ;
SqlTableColumn sqlCol = columnMap . get ( columnName . toLowerCase ( ) ) ;
if ( sqlCol ! = null ) {
String showName = fieldWidget . getString ( "showName" ) ;
long columnId = onlineColumnService . saveBySqlTable ( sqlCol , tableId , showName ) ;
fieldBd . put ( "columnId" , columnId ) ;
fieldBd . put ( "tableId" , tableId ) ;
fieldBd . put ( "columnFieldName" , columnName ) ;
}
long columnId = onlineColumnService . saveBySqlTable ( sqlCol , tableId , showName ) ;
fieldBd . put ( "columnId" , columnId ) ;
fieldBd . put ( "tableId" , tableId ) ;
fieldBd . put ( "columnFieldName" , columnName ) ;
}
// 删除缓存
redissonClient . getBucket ( OnlineRedisKeyUtil . makeOnlineTableKey ( tableId ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeTableKey ( tableName ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeChildFieldListKey ( subHead . getId ( ) ) ) . delete ( ) ;
metaCacheService . removeData ( tableName ) ;
changed = true ;
}
return changed ;
// 删除缓存
redissonClient . getBucket ( OnlineRedisKeyUtil . makeOnlineTableKey ( tableId ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeTableKey ( tableName ) ) . delete ( ) ;
redissonClient . getBucket ( CacheKey . makeChildFieldListKey ( subHead . getId ( ) ) ) . delete ( ) ;
metaCacheService . removeData ( tableName ) ;
return true ;
}
/ * *