package jnpf.bizcommon.audit.service.title;
|
|
import jnpf.util.JsonUtil;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Locale;
|
import java.util.Map;
|
|
/**
|
* 从已发布表单 JSON({@code base_visual_release.F_FORM_DATA})解析
|
* {@code __config__.biz_log_enabled} 勾选。
|
*
|
* <p><b>纯静态、无依赖、永不抛异常</b>:解析失败一律返回 {@link AuditTitleSpec#EMPTY}。
|
* 层 0 的 handler 外层虽有 {@code catch(Throwable)} 兜底(L002),但那会丢掉**整条事件**——
|
* 标题解析失败只该让标题缺席,不该让"这次改过"缺席。
|
*
|
* <p><b>递归规则</b>:布局容器(栅格 row / 标签页 tab / 卡片 card / 表格布局 tableGridTr…)的
|
* children 是主表字段,必须继续往下收;只有 {@code jnpfKey=table}(子表控件)的 children
|
* 才是另一张表的字段,独立成组且**不再往主表收**。
|
*/
|
public final class AuditTitleSpecParser {
|
|
/** 子表控件的 jnpfKey,与 {@code AuditFieldDiff.JNPF_KEY_TABLE} 同值。 */
|
private static final String JNPF_KEY_TABLE = "table";
|
|
private AuditTitleSpecParser() {
|
}
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
public static AuditTitleSpec parse(String formDataJson) {
|
if (formDataJson == null || formDataJson.trim().isEmpty()) {
|
return AuditTitleSpec.EMPTY;
|
}
|
try {
|
Map<String, Object> root = JsonUtil.stringToMap(formDataJson);
|
if (root == null) {
|
return AuditTitleSpec.EMPTY;
|
}
|
List<?> fields = asList(root.get("fields"));
|
if (fields.isEmpty()) {
|
return AuditTitleSpec.EMPTY;
|
}
|
List<String> main = new ArrayList<String>();
|
List<AuditTitleSpec.SubTableSpec> subs = new ArrayList<AuditTitleSpec.SubTableSpec>();
|
collect(fields, main, subs);
|
if (main.isEmpty() && subs.isEmpty()) {
|
return AuditTitleSpec.EMPTY;
|
}
|
return new AuditTitleSpec(main, subs);
|
} catch (Throwable t) {
|
// 这段文本解析不了就是解析不了,返回 EMPTY = 不产出标题。不记日志:
|
// 同一个表单每次保存都会走到这里,报错会把日志刷爆;调用方按 EMPTY 写 extra 留痕。
|
return AuditTitleSpec.EMPTY;
|
}
|
}
|
|
@SuppressWarnings("rawtypes")
|
private static void collect(List<?> fields, List<String> main,
|
List<AuditTitleSpec.SubTableSpec> subs) {
|
for (Object raw : fields) {
|
if (!(raw instanceof Map)) {
|
continue;
|
}
|
Map item = (Map) raw;
|
Map config = config(item);
|
if (config == null) {
|
continue;
|
}
|
// 子表 vModel 保留原始大小写(如 tableField6da682):Task 4 要拿它去 newData 里
|
// 按键取子表明细,newData 的键就是表单设计器写的原样,lower() 过就永远查不到。
|
// 主表字段则要小写——见 AuditTitleSpec.mainFields() 的口径。
|
String rawVModel = str(item.containsKey("vModel")
|
? item.get("vModel") : item.get("__vModel__"));
|
String vModel = lower(rawVModel);
|
String jnpfKey = str(config.get("jnpfKey"));
|
List<?> children = asList(config.get("children"));
|
|
if (JNPF_KEY_TABLE.equals(jnpfKey)) {
|
List<String> subFields = new ArrayList<String>();
|
collectEnabledFlat(children, subFields);
|
if (rawVModel != null && !subFields.isEmpty()) {
|
subs.add(new AuditTitleSpec.SubTableSpec(
|
rawVModel, lower(str(config.get("tableName"))), subFields));
|
}
|
continue; // 子表 children 已单独处理,绝不能再往主表收
|
}
|
|
if (vModel != null && enabled(config)) {
|
main.add(vModel);
|
}
|
if (!children.isEmpty()) {
|
collect(children, main, subs); // 布局容器:children 仍是主表字段
|
}
|
}
|
}
|
|
/** 子表内部不再嵌套子表(平台不支持),故只收一层勾选字段。 */
|
@SuppressWarnings("rawtypes")
|
private static void collectEnabledFlat(List<?> fields, List<String> out) {
|
for (Object raw : fields) {
|
if (!(raw instanceof Map)) {
|
continue;
|
}
|
Map item = (Map) raw;
|
Map config = config(item);
|
if (config == null) {
|
continue;
|
}
|
String vModel = lower(str(item.containsKey("vModel")
|
? item.get("vModel") : item.get("__vModel__")));
|
if (vModel != null && enabled(config)) {
|
out.add(vModel);
|
}
|
List<?> children = asList(config.get("children"));
|
if (!children.isEmpty()) {
|
collectEnabledFlat(children, out); // 子表里的布局容器
|
}
|
}
|
}
|
|
@SuppressWarnings("rawtypes")
|
private static Map config(Map item) {
|
Object raw = item.containsKey("config") ? item.get("config") : item.get("__config__");
|
return raw instanceof Map ? (Map) raw : null;
|
}
|
|
@SuppressWarnings("rawtypes")
|
private static boolean enabled(Map config) {
|
Object raw = config.get("biz_log_enabled");
|
if (raw instanceof Boolean) {
|
return (Boolean) raw;
|
}
|
// 跨 JVM / 存量表单里可能是字符串 "true";认不出就当没勾——**不猜**,
|
// 猜错的方向是把没勾的字段写进明文标题列。
|
return raw != null && "true".equalsIgnoreCase(String.valueOf(raw).trim());
|
}
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
private static List<?> asList(Object raw) {
|
if (raw instanceof List) {
|
return (List<?>) raw;
|
}
|
if (raw == null || String.valueOf(raw).trim().isEmpty()) {
|
return Collections.emptyList();
|
}
|
List<Map> parsed = JsonUtil.getJsonToList(String.valueOf(raw), Map.class);
|
return parsed == null ? Collections.emptyList() : parsed;
|
}
|
|
private static String str(Object value) {
|
if (value == null) {
|
return null;
|
}
|
String s = value.toString().trim();
|
return s.isEmpty() ? null : s;
|
}
|
|
private static String lower(String value) {
|
return value == null ? null : value.toLowerCase(Locale.ROOT);
|
}
|
}
|