diff --git a/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataOrmService.java b/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataOrmService.java index 724926e..f97a3c0 100644 --- a/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataOrmService.java +++ b/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataOrmService.java @@ -13,6 +13,7 @@ import apelet.common.online.model.constant.FieldFilterType; import apelet.common.online.model.constant.RelationType; import apelet.common.orm.impl.*; import apelet.common.orm.parser.FilterParser; +import apelet.common.online.util.WidgetJsonUtil; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ReUtil; @@ -20,9 +21,12 @@ import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -32,6 +36,7 @@ import java.util.stream.Collectors; * @version 1.0 * Create by 2024/10/24 10:46 */ +@Slf4j public class ListDataOrmService extends ListDataService { public ListDataOrmService(OnlineEventPluginExecuteDto dto) { super(dto); @@ -76,20 +81,34 @@ public class ListDataOrmService extends ListDataService { JSONObject widgetList = widgetJson.getJSONObject("pc").getJSONObject("tableWidget"); Set selectorSet = new TreeSet<>(); getOrmSelector(widgetList, selectorSet, masterTable, new HashMap<>()); - Filter filter = buildFilter(); + Filter filter = buildFilter(onlineForm); Sorter sorter = new Sorter(); - if (orderParam != null) { + // 排序:前端传了排序 → 按前端排(保留 create_time 兜底);没传且表单配了 sortField → 用它(值带方向则解析,默认 desc);否则 create_time DESC 兜底。 + if (CollUtil.isNotEmpty(orderParam)) { for (MyOrderParam.OrderInfo orderInfo : orderParam) { SorterItem sorterItem = new SorterItem(orderInfo.getFieldName()); sorterItem.setSortType(orderInfo.getAsc() ? SortType._ASC : SortType._DESC); sorter.add(sorterItem); } - } - if (!sorter.startsWithKey("create_time")) { - SorterItem sorterItem = new SorterItem("create_time"); - sorterItem.setSortType(SortType._DESC); - sorter.add(sorterItem); + if (!sorter.startsWithKey("create_time")) { + SorterItem sorterItem = new SorterItem("create_time"); + sorterItem.setSortType(SortType._DESC); + sorter.add(sorterItem); + } + } else { + // 排序优先级:关联组件(402).sortField > tableWidget.sortField > create_time DESC 兜底。 + String sortField = this.getRelativeFormSortFilter().get("sortField"); + if (StrUtil.isBlank(sortField)) { + sortField = this.getTableWidgetSortField(onlineForm); + } + if (StrUtil.isNotBlank(sortField)) { + sorter.add(this.buildSorterItemFromSortField(sortField)); + } else { + SorterItem sorterItem = new SorterItem("create_time"); + sorterItem.setSortType(SortType._DESC); + sorter.add(sorterItem); + } } Selector selector = new Selector(); selectorSet.forEach(f -> selector.getList().add(new SelectorItem(f))); @@ -115,14 +134,16 @@ public class ListDataOrmService extends ListDataService { /** * 构建列表查询过滤条件:用户过滤条件 + 数据权限规则(与 loadGridData 共用)。 */ - private Filter buildFilter() { + private Filter buildFilter(OnlineForm onlineForm) { // 根据当前用户角色 + 当前表单匹配权限规则:非空→基础数据权限,为空→列表权限 List ruleSchemaList = this.getRuleSchemaListByCurrentRole(); String conditionExpression = null; if (CollUtil.isNotEmpty(ruleSchemaList)) { List filtered = new ArrayList<>(); if (StrUtil.isNotBlank(metaCode)) { - filtered = ruleSchemaList.stream().filter(s -> DataRuleType.BASIC_DATA == s.getRuleType() && metaCode.equals(s.getMetaCode())).collect(Collectors.toList()); + filtered = ruleSchemaList.stream().filter(s -> DataRuleType.BASIC_DATA == s.getRuleType() + && metaCode.equals(s.getMetaCode()) + && this.matchBaseFormId(s.getFormIdList())).collect(Collectors.toList()); } if (CollUtil.isEmpty(filtered)) { filtered = ruleSchemaList.stream().filter(s -> DataRuleType.LIST == s.getRuleType()).collect(Collectors.toList()); @@ -139,6 +160,28 @@ public class ListDataOrmService extends ListDataService { Filter parsed = FilterParser.parse(conditionExpression); filter = filter.and(parsed); } + // 表单 tableWidget 配置的默认过滤条件(如 name = ${userName}),占位符取 tokenData,拼接到查询条件后面。 + String filterField = this.getTableWidgetFilterField(onlineForm); + if (StrUtil.isNotBlank(filterField)) { + try { + String resolved = this.resolveFilterFieldPlaceholders(filterField, TokenData.takeFromRequest()); + Filter parsed = FilterParser.parse(resolved); + filter = filter.and(parsed); + } catch (Exception e) { + log.warn("tableWidget 默认过滤条件解析失败,跳过。filterField={}", filterField, e); + } + } + // 关联组件(402)配置的默认过滤条件,从 baseFormId 表单里匹配 onlineFormId == formId 的组件读取。 + String relativeFilterField = this.getRelativeFormSortFilter().get("filterField"); + if (StrUtil.isNotBlank(relativeFilterField)) { + try { + String resolved = this.resolveFilterFieldPlaceholders(relativeFilterField, TokenData.takeFromRequest()); + Filter parsed = FilterParser.parse(resolved); + filter = filter.and(parsed); + } catch (Exception e) { + log.warn("关联组件默认过滤条件解析失败,跳过。filterField={}", relativeFilterField, e); + } + } return filter; } @@ -149,7 +192,7 @@ public class ListDataOrmService extends ListDataService { */ public int countGridData() { OnlineTable masterTable = datasourceResult.getData().getMasterTable(); - return ormDataSourceUtil.count(masterTable.getTableName(), buildFilter()); + return ormDataSourceUtil.count(masterTable.getTableName(), buildFilter(this.getCurrentOnlineForm())); } /** @@ -160,7 +203,7 @@ public class ListDataOrmService extends ListDataService { */ public BigDecimal sumGridData(String sumColumn) { OnlineTable masterTable = datasourceResult.getData().getMasterTable(); - return ormDataSourceUtil.sum(masterTable.getTableName(), sumColumn, buildFilter()); + return ormDataSourceUtil.sum(masterTable.getTableName(), sumColumn, buildFilter(this.getCurrentOnlineForm())); } /** @@ -179,6 +222,79 @@ public class ListDataOrmService extends ListDataService { } /** + * 读取表单 tableWidget 组件配置的默认排序字段(props.sortField),读取失败返回 null。 + */ + private String getTableWidgetSortField(OnlineForm onlineForm) { + return this.getTableWidgetConfig(onlineForm, "sortField"); + } + + /** + * 读取表单 tableWidget 组件配置的默认过滤条件(props.filterField),读取失败返回 null。 + */ + private String getTableWidgetFilterField(OnlineForm onlineForm) { + return this.getTableWidgetConfig(onlineForm, "filterField"); + } + + /** + * 从 zz_online_form.widgetJson 的 tableWidget.props 读取指定配置项。 + */ + private String getTableWidgetConfig(OnlineForm onlineForm, String key) { + if (onlineForm == null || StrUtil.isBlank(onlineForm.getWidgetJson())) { + return null; + } + return WidgetJsonUtil.getTableWidgetConfig(onlineForm.getWidgetJson(), key); + } + + /** + * 取当前请求对应的在线表单(count/sum 等无 widgetJson 入口时使用)。 + */ + private OnlineForm getCurrentOnlineForm() { + return onlineFormService.getOnlineFormFromCache(dto.getFormId()); + } + + /** + * 读取关联组件(402)配置的默认排序/过滤:从 baseFormId 表单的 widgetJson 里匹配 onlineFormId == formId 的组件。 + */ + private Map getRelativeFormSortFilter() { + if (baseFormId == null) { + return Collections.emptyMap(); + } + OnlineForm baseForm = onlineFormService.getOnlineFormFromCache(baseFormId); + if (baseForm == null || StrUtil.isBlank(baseForm.getWidgetJson())) { + return Collections.emptyMap(); + } + return WidgetJsonUtil.getRelativeOnlineFormSortFilter(baseForm.getWidgetJson(), dto.getFormId()); + } + + /** + * 解析 sortField 成 SorterItem:值带方向("field desc"/"field asc")则用之,没带默认 desc。 + */ + private SorterItem buildSorterItemFromSortField(String sortField) { + String[] parts = sortField.trim().split("\\s+"); + String fieldName = parts[0]; + boolean asc = parts.length > 1 && "asc".equalsIgnoreCase(parts[1]); + SorterItem sorterItem = new SorterItem(fieldName); + sorterItem.setSortType(asc ? SortType._ASC : SortType._DESC); + return sorterItem; + } + + /** + * 解析 filterField 表达式中的 ${字段名} 占位符,取值转成带引号的字符串(满足 FilterParser 值只接受字符串/null)。 + * 兼容已带引号('${xxx}')与未带引号(${xxx})两种存法。 + */ + private String resolveFilterFieldPlaceholders(String expression, TokenData tokenData) { + Matcher matcher = Pattern.compile("'?\\$\\{(\\w+)\\}'?").matcher(expression); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + Object value = BeanUtil.getProperty(tokenData, matcher.group(1)); + String replacement = value == null ? "null" : "'" + value.toString().replace("'", "''") + "'"; + matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); + } + matcher.appendTail(sb); + return sb.toString(); + } + + /** * 根据当前登录用户角色查询启用的数据规则,并按当前表单匹配。 * 兜底:角色未绑定任何数据规则时返回空列表,不做数据权限过滤。 */ @@ -214,7 +330,11 @@ public class ListDataOrmService extends ListDataService { if (!Objects.equals(rule.getFormHeadId(), onlFormHead.getId())) { return false; } - // 2. 再按 form_id_list 筛选 + // 2. 基础数据权限:form_id_list 存的是「适用基础在线表单id」,由 buildFilter 按 baseFormId 匹配,这里不拦 + if (DataRuleType.BASIC_DATA == rule.getRuleType()) { + return true; + } + // 3. 列表权限:再按 form_id_list 筛选目标表单 if (StrUtil.isBlank(rule.getFormIdList())) { return true; } @@ -225,6 +345,17 @@ public class ListDataOrmService extends ListDataService { return StrUtil.split(rule.getFormIdList(), ',').stream().map(Long::valueOf).collect(Collectors.toSet()).contains(currentFormId); } + /** + * 判断基础数据权限规则的 form_id_list(逗号分隔集合,存「适用基础在线表单id」)是否匹配请求的 baseFormId。 + * form_id_list 未配置或请求未传 baseFormId 时视为匹配(兼容旧规则)。 + */ + private boolean matchBaseFormId(String ruleFormIdList) { + if (StrUtil.isBlank(ruleFormIdList) || baseFormId == null) { + return true; + } + return StrUtil.split(ruleFormIdList, ',').stream().map(Long::valueOf).collect(Collectors.toSet()).contains(baseFormId); + } + public void getOrmSelector(JSONObject jsonObject, Set selectorSet, OnlineTable masterTable, Map entryIdMap) { Map columnMap = masterTable.getColumnMap(); JSONArray array = jsonObject.getJSONArray("childWidgetList"); diff --git a/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataService.java b/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataService.java index f9cde9e..ce38939 100644 --- a/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataService.java +++ b/common/common-online/src/main/java/apelet/common/online/abstractplugin/ListDataService.java @@ -38,6 +38,7 @@ public abstract class ListDataService { protected TraceParamDto traceParamDto; protected OnlFormHead onlFormHead; protected String metaCode; + protected Long baseFormId; protected OrmDataSourceUtil ormDataSourceUtil; @@ -64,6 +65,7 @@ public abstract class ListDataService { datasourceResult = (ResponseResult) listParams.get("datasourceResult"); metaCode = (String) listParams.get("metaCode"); + baseFormId = (Long) listParams.get("baseFormId"); onlineFormService = ApplicationContextHolder.getBean("onlineFormService"); onlFormFieldService = ApplicationContextHolder.getBean("onlFormFieldServiceImpl"); diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java index 6c9787b..f98c056 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineFormController.java @@ -1424,4 +1424,22 @@ public class OnlineFormController { return ResponseResult.success(formList); } + @PostMapping("/queryListFormByFormName") + public ResponseResult> queryListFormByFormName(@MyRequestBody String formName) { + List formList = onlineFormService.queryByFormName(formName); + if (CollUtil.isEmpty(formList)) { + return ResponseResult.success(new ArrayList<>()); + } + formList.forEach(item -> { + item.setWidgetJson(null); + item.setParamsJson(null); + item.setCreateTime(null); + item.setUpdateTime(null); + item.setCreateUserId(null); + item.setUpdateUserId(null); + }); + return ResponseResult.success(formList); + } + + } diff --git a/common/common-online/src/main/java/apelet/common/online/controller/OnlineOperationController.java b/common/common-online/src/main/java/apelet/common/online/controller/OnlineOperationController.java index 3874e13..6c3ddf2 100644 --- a/common/common-online/src/main/java/apelet/common/online/controller/OnlineOperationController.java +++ b/common/common-online/src/main/java/apelet/common/online/controller/OnlineOperationController.java @@ -39,10 +39,13 @@ import apelet.common.online.model.constant.RelationType; import apelet.common.online.service.*; import apelet.common.online.util.OnlineConstant; import apelet.common.online.util.OnlineOperationHelper; +import apelet.common.online.util.WidgetJsonUtil; import apelet.common.online.vo.OnlineEventPluginExecuteVo; import apelet.common.orm.impl.*; +import apelet.common.orm.parser.FilterParser; import apelet.common.redis.cache.SessionCacheHelper; import apelet.common.redis.util.CommonRedisUtil; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.text.StrFormatter; @@ -69,6 +72,8 @@ import java.io.IOException; import java.io.Serializable; import java.math.BigDecimal; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -818,7 +823,8 @@ public class OnlineOperationController { @MyRequestBody String ignoreMaskFields, @MyRequestBody TraceParamDto traceParamDto, @MyRequestBody OnlineEventPluginExecuteDto onlineEventPluginExecuteDto, - @MyRequestBody String metaCode + @MyRequestBody String metaCode, + @MyRequestBody(required = true) Long baseFormId ) { // 1. 验证数据源及其关联 ResponseResult datasourceResult = @@ -830,7 +836,7 @@ public class OnlineOperationController { if (!filterDtoListResult.isSuccess()) { return ResponseResult.errorFrom(filterDtoListResult); } - // 透传 metaCode 到 ListDataOrmService,用于权限规则类型过滤 + // 透传 metaCode、baseFormId 到 ListDataOrmService,用于权限规则类型过滤及关联组件过滤排序 if (onlineEventPluginExecuteDto == null) { onlineEventPluginExecuteDto = new OnlineEventPluginExecuteDto(); } @@ -840,6 +846,7 @@ public class OnlineOperationController { onlineEventPluginExecuteDto.setListParams(listParams); } listParams.put("metaCode", metaCode); + listParams.put("baseFormId", baseFormId); OnlFormHead onlFormHead = onlFormHeadService.getFormHeadByDatasource(datasourceId); GridData pluginData = this.exeListPlugin(formId,filterDtoList,orderParam,pageParam, traceParamDto,onlFormHead,datasourceResult,onlineEventPluginExecuteDto @@ -1062,10 +1069,39 @@ public class OnlineOperationController { JSONObject jsonObject = (JSONObject) l; getOrmSelector(jsonObject, selectorSet, masterTable, entryIdMap); }); + // 收集各分录组件配置的默认排序/过滤条件(pc/mobile 控件树,按 bindData.tableId 区分主表与分录表)。 + Map entryFilterFieldMap = new HashMap<>(); + Map entrySortFieldMap = new HashMap<>(); + WidgetJsonUtil.collectSubTableSortFilter(widgetJson, masterTable.getTableId(), + tableId -> { + OnlineTable t = onlineTableService.getOnlineTableFromCache(tableId); + return t == null ? null : t.getTableName(); + }, + entryFilterFieldMap, entrySortFieldMap); + // 附表过滤(SQL 层):列名限定为 分录表名.列名,解析后拼接到查询条件。 + for (Map.Entry entry : entryFilterFieldMap.entrySet()) { + try { + String resolved = this.resolveFilterFieldPlaceholders(entry.getValue(), TokenData.takeFromRequest()); + String qualified = this.qualifyProperties(resolved, entry.getKey()); + filter = filter.and(FilterParser.parse(qualified)); + } catch (Exception e) { + log.warn("附表过滤条件解析失败,跳过。tableName={}, filterField={}", entry.getKey(), entry.getValue(), e); + } + } Selector selector = getSelector(selectorSet, masterTable,true); + // 附表排序(SQL 层):配置了 sortField 的分录表按 分录表名.字段 排序。 + Sorter sorter = null; + if (!entrySortFieldMap.isEmpty()) { + sorter = new Sorter(); + for (Map.Entry entry : entrySortFieldMap.entrySet()) { + sorter.add(this.buildSorterItemFromSortField(entry.getValue(), entry.getKey())); + } + } HashMap rowData = new HashMap<>(); HashMap listData = new HashMap<>(); - ObjectCollection collection = ormGenDataSourceUtil.query(masterTable.getTableName(), filter, selector); + ObjectCollection collection = (sorter != null && sorter.size() > 0) + ? ormGenDataSourceUtil.query(masterTable.getTableName(), filter, selector, sorter) + : ormGenDataSourceUtil.query(masterTable.getTableName(), filter, selector); if (collection.isEmpty()) { JSONObject jsonObject = new JSONObject(); rowData.put("id", id); @@ -1088,12 +1124,15 @@ public class OnlineOperationController { ObjectCollection entryCollection = (ObjectCollection) map.get(k); List> entryList = new ArrayList<>(); onlineOperationService.collectionToJson(entryCollection, entryList); - String sort = "seq"; - entryList = entryList.stream().sorted( - Comparator.comparing(m -> m.containsKey(sort) && m.get(sort) != null && StringUtils.isNotBlank(m.get(sort).toString()) - ? Double.valueOf(m.get(sort).toString()) : null, - Comparator.nullsLast(Double::compareTo))) - .collect(Collectors.toList()); + // 附表配置了 sortField 时已在 SQL 层排序,这里不再按 seq 内存排序。 + if (!entrySortFieldMap.containsKey(k)) { + String sort = "seq"; + entryList = entryList.stream().sorted( + Comparator.comparing(m -> m.containsKey(sort) && m.get(sort) != null && StringUtils.isNotBlank(m.get(sort).toString()) + ? Double.valueOf(m.get(sort).toString()) : null, + Comparator.nullsLast(Double::compareTo))) + .collect(Collectors.toList()); + } // 分录的附件上传/图片上传字段同样回填,online_table_id 用分录表自己的tableId。 Object entryTableId = entryIdMap.get(k); if (entryTableId != null) { @@ -1172,6 +1211,49 @@ public class OnlineOperationController { } + /** + * 解析过滤表达式中的 ${字段名} 占位符,取值转成带引号的字符串(满足 FilterParser 值只接受字符串/null)。 + * 兼容已带引号('${xxx}')与未带引号(${xxx})两种存法。 + */ + public String resolveFilterFieldPlaceholders(String expression, TokenData tokenData) { + Matcher matcher = Pattern.compile("'?\\$\\{(\\w+)\\}'?").matcher(expression); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + Object value = BeanUtil.getProperty(tokenData, matcher.group(1)); + String replacement = value == null ? "null" : "'" + value.toString().replace("'", "''") + "'"; + matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); + } + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * 把过滤表达式中的列名限定为 表名.列名(已带点限定的列跳过),供附表 SQL 过滤使用。 + */ + public String qualifyProperties(String expression, String tableName) { + Pattern p = Pattern.compile("(^|[(]|\\b(?:and|or)\\s+)([A-Za-z_]\\w*)(?=\\s*(?:=|!=|<=|>=|<|>|like|not\\s+like|in|not\\s+in|exists|not\\s+exists|is\\s+null|is\\s+not\\s+null)\\b)"); + Matcher m = p.matcher(expression); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + m.appendReplacement(sb, Matcher.quoteReplacement(m.group(1) + tableName + "." + m.group(2))); + } + m.appendTail(sb); + return sb.toString(); + } + + /** + * 解析 sortField 成 SorterItem:值带方向("field desc"/"field asc")则用之,没带默认 desc;可选加表名前缀。 + */ + public SorterItem buildSorterItemFromSortField(String sortField, String tablePrefix) { + String[] parts = sortField.trim().split("\\s+"); + String fieldName = parts[0]; + boolean asc = parts.length > 1 && "asc".equalsIgnoreCase(parts[1]); + String fullName = StrUtil.isBlank(tablePrefix) ? fieldName : tablePrefix + "." + fieldName; + SorterItem sorterItem = new SorterItem(fullName); + sorterItem.setSortType(asc ? SortType._ASC : SortType._DESC); + return sorterItem; + } + public Selector getSelector(Set selectorSet, OnlineTable masterTable,boolean b) { Selector selector = new Selector(); EntityTable entityTable = ormGenDataSourceUtil.getEntityTable(masterTable.getTableName()); diff --git a/common/common-online/src/main/java/apelet/common/online/service/OnlineFormService.java b/common/common-online/src/main/java/apelet/common/online/service/OnlineFormService.java index 8a6cda5..1b8b205 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/OnlineFormService.java +++ b/common/common-online/src/main/java/apelet/common/online/service/OnlineFormService.java @@ -157,4 +157,13 @@ public interface OnlineFormService extends IBaseService { * @see apelet.common.online.model.constant.FormType */ List queryByTableName(String tableName, int formType); + + + /** + * 根据表单名称查询表单 + * + * @param formName 表单名称 + * @return 表单 + */ + List queryByFormName(String formName); } diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFormServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFormServiceImpl.java index 2a36b66..8b92056 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFormServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineFormServiceImpl.java @@ -518,6 +518,14 @@ public class OnlineFormServiceImpl extends BaseService impleme return Collections.emptyList(); } + + @Override + public List queryByFormName(String formName) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.likeRight(StringUtils.isNotBlank(formName), OnlineForm::getFormName, formName); + return onlineFormMapper.selectList(queryWrapper); + } + /** * 设置关联表字段转换为对象 * diff --git a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineOperationServiceImpl.java b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineOperationServiceImpl.java index a2d03ae..e9ddef6 100644 --- a/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineOperationServiceImpl.java +++ b/common/common-online/src/main/java/apelet/common/online/service/impl/OnlineOperationServiceImpl.java @@ -77,6 +77,7 @@ import javax.annotation.Resource; import java.io.File; import java.io.Serializable; import java.sql.Connection; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @@ -696,7 +697,16 @@ public class OnlineOperationServiceImpl implements OnlineOperationService { }else if(objectValue.get(string) == null){ jsonObject.put(string, ""); }else if(objectValue.get(string) instanceof Date){ - jsonObject.put(string,DateTimeUtils.format((Date) objectValue.get(string) ,"yyyy-MM-dd")); + Date date = (Date) objectValue.get(string); + String timeStr = new SimpleDateFormat("HH:mm:ss").format(date); + String value = null; + // 判断时间是否为 00:00:00 + if ("00:00:00".equals(timeStr)) { + value = DateTimeUtils.format(date, "yyyy-MM-dd"); + } else { + value = DateTimeUtils.format(date, "yyyy-MM-dd HH:mm:ss"); + } + jsonObject.put(string, value); }else{ jsonObject.put(string, values.get(string)); } diff --git a/common/common-online/src/main/java/apelet/common/online/util/WidgetJsonUtil.java b/common/common-online/src/main/java/apelet/common/online/util/WidgetJsonUtil.java index 199d6ee..e7ceec6 100644 --- a/common/common-online/src/main/java/apelet/common/online/util/WidgetJsonUtil.java +++ b/common/common-online/src/main/java/apelet/common/online/util/WidgetJsonUtil.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; /** * widgetJson 数据操作工具类。 @@ -96,6 +97,198 @@ public class WidgetJsonUtil { } /** + * 读取 pc/mobile 端 tableWidget 组件 props 中的配置项(如 sortField/filterField)。 + * 优先 pc,pc 未配置时回退 mobile,与列表查询读取保持一致。 + * + * @param widgetJson 在线表单的 widgetJson。 + * @param key props 中的配置项 key。 + * @return 配置值,widgetJson 为空或两端的 tableWidget/props 均不存在时返回 null。 + */ + public static String getTableWidgetConfig(String widgetJson, String key) { + if (StrUtil.isBlank(widgetJson) || StrUtil.isBlank(key)) { + return null; + } + try { + JSONObject root = JSON.parseObject(widgetJson); + String value = readTableWidgetConfig(root.getJSONObject("pc"), key); + if (StrUtil.isNotBlank(value)) { + return value; + } + return readTableWidgetConfig(root.getJSONObject("mobile"), key); + } catch (Exception e) { + return null; + } + } + + private static String readTableWidgetConfig(JSONObject modeObj, String key) { + if (modeObj == null) { + return null; + } + JSONObject tableWidget = modeObj.getJSONObject("tableWidget"); + if (tableWidget == null) { + return null; + } + JSONObject props = tableWidget.getJSONObject("props"); + if (props == null) { + return null; + } + return props.getString(key); + } + + /** + * 收集子表控件配置的默认排序/过滤条件(props.sortField / props.filterField)。 + * 递归遍历 pc/mobile 两端的 widgetList 及 tableWidget.childWidgetList, + * 按 bindData.tableId != 主表 tableId 识别子表控件;以子表物理表名为 key 回填两个 Map(仅含非空配置)。 + * 子表物理表名优先用 tableNameResolver 解析,缺失时兜底 bindData.tableName。 + * 同一子表在 pc/mobile 均出现时,以先遍历到的 pc 配置为准(putIfAbsent)。 + * + * @param widgetJson 在线表单的 widgetJson。 + * @param masterTableId 主表 tableId,用于排除主表字段控件。 + * @param tableNameResolver 子表 tableId → 物理表名 的解析函数,可传 null。 + * @param filterFieldMap 输出:子表物理表名 → filterField。 + * @param sortFieldMap 输出:子表物理表名 → sortField。 + */ + public static void collectSubTableSortFilter(JSONObject widgetJson, Long masterTableId, + Function tableNameResolver, + Map filterFieldMap, Map sortFieldMap) { + if (widgetJson == null) { + return; + } + for (String mode : new String[]{"pc", "mobile"}) { + JSONObject modeObj = widgetJson.getJSONObject(mode); + if (modeObj == null) { + continue; + } + collectSubTableSortFilter(modeObj.getJSONArray("widgetList"), masterTableId, tableNameResolver, filterFieldMap, sortFieldMap); + JSONObject tableWidget = modeObj.getJSONObject("tableWidget"); + if (tableWidget != null) { + collectSubTableSortFilter(tableWidget.getJSONArray("childWidgetList"), masterTableId, tableNameResolver, filterFieldMap, sortFieldMap); + } + } + } + + private static void collectSubTableSortFilter(JSONArray widgetList, Long masterTableId, + Function tableNameResolver, + Map filterFieldMap, Map sortFieldMap) { + if (CollUtil.isEmpty(widgetList)) { + return; + } + for (int i = 0; i < widgetList.size(); i++) { + JSONObject widget = widgetList.getJSONObject(i); + if (widget == null) { + continue; + } + JSONArray childList = widget.getJSONArray("childWidgetList"); + if (CollUtil.isNotEmpty(childList)) { + collectSubTableSortFilter(childList, masterTableId, tableNameResolver, filterFieldMap, sortFieldMap); + } + JSONObject bindData = widget.getJSONObject("bindData"); + if (bindData == null || bindData.isEmpty() || !bindData.containsKey("tableId")) { + continue; + } + Long tableId = bindData.getLong("tableId"); + if (tableId == null || tableId.equals(masterTableId)) { + continue; + } + JSONObject props = widget.getJSONObject("props"); + if (props == null) { + continue; + } + String tableName = tableNameResolver == null ? null : tableNameResolver.apply(tableId); + if (StrUtil.isEmpty(tableName)) { + tableName = bindData.getString("tableName"); + } + if (StrUtil.isEmpty(tableName)) { + continue; + } + String filterField = props.getString("filterField"); + String sortField = props.getString("sortField"); + if (StrUtil.isNotBlank(filterField)) { + filterFieldMap.putIfAbsent(tableName, filterField); + } + if (StrUtil.isNotBlank(sortField)) { + sortFieldMap.putIfAbsent(tableName, sortField); + } + } + } + + /** + * 读取关联组件(widgetType=402,props.relativeTable.relativeFormType==6 且 onlineFormId 匹配)上配置的默认排序/过滤。 + * 遍历 pc/mobile 的 widgetList 及 tableWidget.childWidgetList。 + * + * @param widgetJson 在线表单的 widgetJson。 + * @param targetFormId 目标在线表单id,匹配 relativeTable.onlineFormId。 + * @return Map:key 为 sortField/filterField(仅含非空项),找不到返回空 map。 + */ + public static Map getRelativeOnlineFormSortFilter(String widgetJson, Long targetFormId) { + Map config = new HashMap<>(); + if (StrUtil.isBlank(widgetJson) || targetFormId == null) { + return config; + } + try { + JSONObject root = JSON.parseObject(widgetJson); + for (String mode : new String[]{"pc", "mobile"}) { + JSONObject modeObj = root.getJSONObject(mode); + if (modeObj == null) { + continue; + } + collectRelativeOnlineFormSortFilter(modeObj.getJSONArray("widgetList"), targetFormId, config); + JSONObject tableWidget = modeObj.getJSONObject("tableWidget"); + if (tableWidget != null) { + collectRelativeOnlineFormSortFilter(tableWidget.getJSONArray("childWidgetList"), targetFormId, config); + } + } + } catch (Exception e) { + // 忽略解析异常,返回已收集到的配置 + } + return config; + } + + private static void collectRelativeOnlineFormSortFilter(JSONArray widgetList, Long targetFormId, Map config) { + if (CollUtil.isEmpty(widgetList)) { + return; + } + for (int i = 0; i < widgetList.size(); i++) { + JSONObject widget = widgetList.getJSONObject(i); + if (widget == null) { + continue; + } + JSONArray childList = widget.getJSONArray("childWidgetList"); + if (CollUtil.isNotEmpty(childList)) { + collectRelativeOnlineFormSortFilter(childList, targetFormId, config); + } + Integer widgetType = widget.getInteger("widgetType"); + if (widgetType == null || widgetType != 402) { + continue; + } + JSONObject props = widget.getJSONObject("props"); + if (props == null) { + continue; + } + JSONObject relativeTable = props.getJSONObject("relativeTable"); + if (relativeTable == null) { + continue; + } + Integer formType = relativeTable.getInteger("relativeFormType"); + String onlineFormId = relativeTable.getString("onlineFormId"); + if (formType == null || formType != 6 || StrUtil.isBlank(onlineFormId)) { + continue; + } + if (!targetFormId.toString().equals(onlineFormId)) { + continue; + } + String sortField = props.getString("sortField"); + String filterField = props.getString("filterField"); + if (StrUtil.isNotBlank(sortField)) { + config.putIfAbsent("sortField", sortField); + } + if (StrUtil.isNotBlank(filterField)) { + config.putIfAbsent("filterField", filterField); + } + } + } + + /** * 收集子表控件(widgetType=100) bindData.tableName 的名称集合。 * * @param widgetJson 在线表单的 widgetJson。