@ -760,7 +760,11 @@ public class OnlineFormController {
@@ -760,7 +760,11 @@ public class OnlineFormController {
boolean changed = false ;
// === Diff 新增字段 ===
// 这里是取pc 的 还要取一下 moblie的
Set < String > widgetColumnNames = collectAllBindColumnNames ( widgetJson ) ;
// 收集 mobile 端的列名(遍历 childWidgetList 路径)
widgetColumnNames . addAll ( collectMobileBindColumnNames ( widgetJson ) ) ;
List < OnlFormField > existingFields = onlFormFieldService . list (
new LambdaQueryWrapper < OnlFormField > ( ) . eq ( OnlFormField : : getHeadId , onlFormHead . getId ( ) ) ) ;
Set < String > existingFieldNames = existingFields . stream ( )
@ -786,12 +790,17 @@ public class OnlineFormController {
@@ -786,12 +790,17 @@ public class OnlineFormController {
}
if ( ! newColumnNames . isEmpty ( ) ) {
Map < String , JSONObject > nameToWidget = mapColumnNameToWidget ( widgetJson ) ;
// 收集 mobile 端的 widget 映射(遍历 childWidgetList 路径)
Map < String , JSONObject > mobileNameToWidget = mapMobileColumnNameToWidget ( 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 ;
@ -804,6 +813,9 @@ public class OnlineFormController {
@@ -804,6 +813,9 @@ public class OnlineFormController {
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 ;
@ -829,15 +841,26 @@ public class OnlineFormController {
@@ -829,15 +841,26 @@ public class OnlineFormController {
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" ) ;
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 ) ;
}
}
}
@ -968,12 +991,35 @@ public class OnlineFormController {
@@ -968,12 +991,35 @@ public class OnlineFormController {
}
}
//step2 : 不存在的附表,新增
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , newSubTableNames ) ;
} else {
// tableIdAndPropMap 为空,说明走 tableId 取值没取到,兜底通过 tableName 收集附表并创建
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , new HashSet < > ( ) ) ;
}
// === Diff mobile 端子表 ===
// 路径: mobile -> widgetList -> [widgetType=102] -> bindData -> tableName/tableId
changed | = syncMobileSubTables ( widgetJson , onlFormHead , datasource ) ;
return changed ? widgetJson : null ;
}
/ * *
* 创建不存在的附表 : 新建 OnlFormHead / OnlineTable 、 绑定数据源关系 、 回填 relationId 并追加 childName 。
* 若 newSubTableNames 为空 ( tableIdAndPropMap 走 tableId 取值没取到 ) , 兜底通过 tableName 收集附表 。
*
* @param widgetJson 表单 JSON
* @param onlFormHead 主表
* @param datasource 数据源
* @param newSubTableNames 附表名集合 ( 可为空 )
* @return 是否有变更
* /
private boolean createNewSubTables ( JSONObject widgetJson , OnlFormHead onlFormHead , OnlineDatasource datasource , Set < String > newSubTableNames ) {
if ( newSubTableNames . isEmpty ( ) ) {
// 如果他为空,说明我们走tableId取值没取到,我们就去一下 tableName;
newSubTableNames = this . collectSubTableName ( widgetJson ) ;
}
if ( ! newSubTableNames . isEmpty ( ) ) {
if ( newSubTableNames . isEmpty ( ) ) {
return false ;
}
for ( String subTableName : newSubTableNames ) {
OnlFormHead subHead = onlFormHeadService . createMetaAndSync ( subTableName , onlFormHead . getTableTxt ( ) + "附表" , CustomUtil . MetaType_Entry , onlFormHead . getTableName ( ) ) ;
// 获取子表的 OnlineTable
@ -1001,10 +1047,7 @@ public class OnlineFormController {
@@ -1001,10 +1047,7 @@ public class OnlineFormController {
onlFormHead . setChildName ( newSubTableName ) ;
}
onlFormHeadService . updateById ( onlFormHead ) ;
changed = true ;
}
}
return changed ? widgetJson : null ;
return true ;
}
@ -1232,4 +1275,271 @@ public class OnlineFormController {
@@ -1232,4 +1275,271 @@ public class OnlineFormController {
}
}
// ============ mobile 端子表同步相关方法 ============
/ * *
* 同步 mobile 端的子表 ( 新增子表 + 已有子表的新增字段 ) 。
* 子表 : 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 ;
}
JSONArray mobileWidgetList = mobile . getJSONArray ( "widgetList" ) ;
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 ;
}
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
String tableName = bindData . getString ( "tableName" ) ;
String tableIdStr = bindData . getString ( "tableId" ) ;
if ( StrUtil . isNotEmpty ( tableName ) & & StrUtil . isEmpty ( tableIdStr ) ) {
newSubTableNames . add ( tableName ) ;
} else if ( StrUtil . isNotEmpty ( tableIdStr ) ) {
existingSubTableIds . add ( Long . valueOf ( tableIdStr ) ) ;
}
}
// 处理新子表: 创建后回写 tableId + masterColumnName
if ( ! newSubTableNames . isEmpty ( ) ) {
changed | = createNewSubTables ( widgetJson , onlFormHead , datasource , newSubTableNames ) ;
backfillMobileSubTableId ( widgetJson , newSubTableNames ) ;
}
// 处理已有子表的新增字段
if ( ! existingSubTableIds . isEmpty ( ) ) {
changed | = syncMobileSubTableNewFields ( widgetJson , datasource , existingSubTableIds ) ;
}
return changed ;
}
/ * *
* 回写 mobile 端子表的 tableId 和 masterColumnName 。
* 路径 : mobile - > widgetList - > [ widgetType = 102 ] - > bindData
* /
private void backfillMobileSubTableId ( JSONObject widgetJson , Set < String > newSubTableNames ) {
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
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 ;
}
JSONObject bindData = widget . getJSONObject ( "bindData" ) ;
if ( bindData = = null ) {
continue ;
}
String tableName = bindData . getString ( "tableName" ) ;
if ( StrUtil . isEmpty ( tableName ) | | ! newSubTableNames . contains ( tableName ) ) {
continue ;
}
// createNewSubTables 已通过 backfillRelationId 回写了 tableId,这里只需补 masterColumnName
if ( ! bindData . containsKey ( "tableId" ) ) {
OnlineTable subTable = onlineTableService . getOne ( new LambdaQueryWrapper < OnlineTable > ( ) . eq ( OnlineTable : : getTableName , tableName . toLowerCase ( ) ) ) ;
if ( subTable ! = null ) {
bindData . put ( "tableId" , subTable . getTableId ( ) ) ;
}
}
bindData . put ( "masterColumnName" , "id" ) ;
}
}
/ * *
* 同步 mobile 端已有子表的新增字段 。
* 字段路径 : 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 ;
}
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" ) ;
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 ( newFieldWidgets . isEmpty ( ) ) {
continue ;
}
// 创建字段记录
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" ) ;
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 ;
}
/ * *
* 遍历 mobile 端 widget 树 , 收集所有 bindData . columnName 值 。
* 路径 : mobile - > tableWidget - > childWidgetList - > childWidgetList - > bindData - > columnName
* /
private Set < String > collectMobileBindColumnNames ( JSONObject widgetJson ) {
Set < String > names = new HashSet < > ( ) ;
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
if ( mobile = = null ) {
return names ;
}
JSONObject tableWidget = mobile . getJSONObject ( "tableWidget" ) ;
if ( tableWidget = = null ) {
return names ;
}
JSONArray cardList = tableWidget . getJSONArray ( "childWidgetList" ) ;
if ( cardList = = null ) {
return names ;
}
for ( int i = 0 ; i < cardList . size ( ) ; i + + ) {
JSONObject cardWidget = cardList . getJSONObject ( i ) ;
JSONArray fieldList = cardWidget . getJSONArray ( "childWidgetList" ) ;
if ( fieldList = = null ) {
continue ;
}
for ( int j = 0 ; j < fieldList . size ( ) ; j + + ) {
JSONObject fieldWidget = fieldList . getJSONObject ( j ) ;
JSONObject bindData = fieldWidget . getJSONObject ( "bindData" ) ;
if ( bindData ! = null & & bindData . containsKey ( "columnName" ) ) {
String name = bindData . getString ( "columnName" ) ;
if ( StrUtil . isNotEmpty ( name ) ) {
names . add ( name ) ;
}
}
}
}
return names ;
}
/ * *
* 构建 mobile 端 columnName → widget 的映射 。
* 路径 : mobile - > tableWidget - > childWidgetList - > childWidgetList - > bindData - > columnName
* /
private Map < String , JSONObject > mapMobileColumnNameToWidget ( JSONObject widgetJson ) {
Map < String , JSONObject > map = new HashMap < > ( ) ;
JSONObject mobile = widgetJson . getJSONObject ( "mobile" ) ;
if ( mobile = = null ) {
return map ;
}
JSONObject tableWidget = mobile . getJSONObject ( "tableWidget" ) ;
if ( tableWidget = = null ) {
return map ;
}
JSONArray cardList = tableWidget . getJSONArray ( "childWidgetList" ) ;
if ( cardList = = null ) {
return map ;
}
for ( int i = 0 ; i < cardList . size ( ) ; i + + ) {
JSONObject cardWidget = cardList . getJSONObject ( i ) ;
JSONArray fieldList = cardWidget . getJSONArray ( "childWidgetList" ) ;
if ( fieldList = = null ) {
continue ;
}
for ( int j = 0 ; j < fieldList . size ( ) ; j + + ) {
JSONObject fieldWidget = fieldList . getJSONObject ( j ) ;
JSONObject bindData = fieldWidget . getJSONObject ( "bindData" ) ;
if ( bindData ! = null & & bindData . containsKey ( "columnName" ) ) {
String name = bindData . getString ( "columnName" ) ;
if ( StrUtil . isNotEmpty ( name ) ) {
map . put ( name , fieldWidget ) ;
}
}
}
}
return map ;
}
}