From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master

---
 jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditQuerySemanticsProbe.java |  201 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 201 insertions(+), 0 deletions(-)

diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditQuerySemanticsProbe.java b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditQuerySemanticsProbe.java
new file mode 100644
index 0000000..3dca94e
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/test/java/jnpf/bizcommon/audit/service/AuditQuerySemanticsProbe.java
@@ -0,0 +1,201 @@
+package jnpf.bizcommon.audit.service;
+
+import jnpf.audit.diff.AuditFieldDiff;
+import jnpf.bizcommon.audit.entity.AuditEventEntity;
+import jnpf.bizcommon.audit.entity.model.AuditEventListVO;
+import jnpf.bizcommon.audit.entity.model.AuditOperationGroupRow;
+import jnpf.bizcommon.audit.service.impl.AuditQueryServiceImpl;
+import jnpf.bizcommon.audit.service.support.AuditEventCategories;
+import jnpf.bizcommon.audit.service.support.AuditQueryResponseSanitizer;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** 鍙戝竷琛ㄥ崟/COMMENT fallback 涓庢煡璇㈣劚鏁忕函 JVM 鎺㈤拡銆� */
+public final class AuditQuerySemanticsProbe {
+
+    private static int passed;
+    private static int failed;
+
+    public static void main(String[] args) {
+        String fields = "[{\"vModel\":\"status\",\"config\":{\"label\":\"琛ㄥ崟鐘舵�乗","
+                + "\"jnpfKey\":\"select\",\"dataType\":\"dynamic\",\"children\":["
+                + "{\"vModel\":\"child_name\",\"config\":{\"label\":\"瀛愰」鍚嶇О\","
+                + "\"jnpfKey\":\"input\",\"dataType\":\"static\"}}]}},"
+                + "{\"vModel\":\"sampleCode\",\"config\":{\"label\":\"鏍峰搧缂栫爜\","
+                + "\"jnpfKey\":\"input\",\"dataType\":\"static\"}}]";
+        String formData = "{\"fields\":" + quote(fields) + "}";
+        Map<String, AuditFieldDiff.FieldMeta> published =
+                AuditFormRegistry.parsePublishedFieldMetadata(formData);
+        check("鍙戝竷琛ㄥ崟瑙f瀽 vModel -> label", "琛ㄥ崟鐘舵��".equals(published.get("status").label()),
+                String.valueOf(published));
+        check("鍙戝竷琛ㄥ崟閫掑綊瑙f瀽 children", "瀛愰」鍚嶇О".equals(published.get("child_name").label()),
+                String.valueOf(published));
+        check("鍔ㄦ�� select 鏍囪 nameModified", Boolean.TRUE.equals(published.get("status").nameModified()),
+                String.valueOf(published.get("status").nameModified()));
+        Map<String, Object> camelCaseRow = new LinkedHashMap<>();
+        camelCaseRow.put("sampleCode", "S-001");
+        String camelCaseDiff = AuditFieldDiff.diff(
+                Collections.emptyMap(), camelCaseRow, Collections.emptySet(), published);
+        check("camelCase vModel 鍙尮閰嶅皬鍐欏厓鏁版嵁閿�",
+                camelCaseDiff.contains("\"fieldName\":\"鏍峰搧缂栫爜\""), camelCaseDiff);
+
+        Map<String, AuditFieldDiff.FieldMeta> comments = new LinkedHashMap<>();
+        comments.put("status", new AuditFieldDiff.FieldMeta("COMMENT 鐘舵��", null, null));
+        comments.put("comment_only", new AuditFieldDiff.FieldMeta("COMMENT 涓撳睘瀛楁", null, null));
+        Map<String, AuditFieldDiff.FieldMeta> merged =
+                AuditFormRegistry.mergeFieldMetadata(comments, published);
+        check("鍙戝竷琛ㄥ崟鍚嶇О浼樺厛浜� COMMENT", "琛ㄥ崟鐘舵��".equals(merged.get("status").label()),
+                merged.get("status").label());
+        check("琛ㄥ崟缂哄け鏃朵娇鐢� COMMENT fallback",
+                "COMMENT 涓撳睘瀛楁".equals(merged.get("comment_only").label()),
+                merged.get("comment_only").label());
+
+        Map<String, AuditFieldDiff.FieldMeta> event = new LinkedHashMap<>();
+        event.put("status", new AuditFieldDiff.FieldMeta("浜嬩欢褰撴椂鐘舵��", "select", true));
+        Map<String, AuditFieldDiff.FieldMeta> finalMeta =
+                AuditFormRegistry.mergeFieldMetadata(merged, event);
+        check("浜嬩欢 listLog 浼樺厛浜庡綋鍓嶅彂甯冭〃鍗�",
+                "浜嬩欢褰撴椂鐘舵��".equals(finalMeta.get("status").label()), finalMeta.get("status").label());
+
+        String diffs = "[{\"field\":\"status\",\"fieldName\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"},"
+                + "{\"field\":\"unknown_col\",\"fieldName\":\"unknown_col\",\"oldData\":\"a\",\"newData\":\"b\"},"
+                + "{\"field\":\"biz_sign\",\"fieldName\":\"biz_sign\",\"oldData\":\"secret-1\",\"newData\":\"secret-2\"}]";
+        String sanitized = AuditQueryResponseSanitizer.sanitizeFieldDiffs(diffs, finalMeta);
+        check("鍘嗗彶鎶�鏈悕鎸夊綋鍓嶅厓鏁版嵁瑁呴グ", sanitized.contains("\"fieldName\":\"浜嬩欢褰撴椂鐘舵�乗""), sanitized);
+        check("鍏冩暟鎹拰 COMMENT 閮界己澶辨椂鍥炶惤鏁版嵁搴撳瓧娈靛悕",
+                sanitized.contains("\"fieldName\":\"unknown_col\""), sanitized);
+        check("biz_sign 鍦ㄥ巻鍙� diff 涓笉鏆撮湶", !sanitized.contains("secret-1")
+                && !sanitized.contains("secret-2") && sanitized.contains("鐢靛瓙绛惧悕宸插叧鑱�"), sanitized);
+
+        String json = "{\"biz_sign\":\"credential\",\"nested\":{\"approveSignId\":\"credential-2\","
+                + "\"targetId\":\"business-id\"}}";
+        String safeJson = AuditQueryResponseSanitizer.sanitizeJson(json);
+        check("extra/snapshot 娣卞害鑴辨晱绛惧悕鍑瘉", !safeJson.contains("credential")
+                && safeJson.contains("business-id"), safeJson);
+        String childDiff = "[{\"field\":\"tableField1\",\"jnpfKey\":\"table\","
+                + "\"chidField\":[{\"prop\":\"item_name\",\"label\":\"椤圭洰\"},"
+                + "{\"prop\":\"review_sign\",\"label\":\"澶嶅绛惧悕\",\"jnpfKey\":\"sign\"}],"
+                + "\"chidData\":[{\"item_name\":\"鍚噺\",\"review_sign\":\"child-secret-new\","
+                + "\"jnpf_old_review_sign\":\"child-secret-old\",\"jnpf_type\":1}]}]";
+        String safeChildDiff = AuditQueryResponseSanitizer.sanitizeFieldDiffs(
+                childDiff, Collections.emptyMap());
+        check("瀛愯〃绛惧悕鍒楃殑鏂版棫鍑瘉鍧囪劚鏁忎笖鏅�氬垪淇濈暀",
+                safeChildDiff != null && !safeChildDiff.contains("child-secret")
+                        && safeChildDiff.contains("鍚噺") && safeChildDiff.contains("\"masked\":true"),
+                safeChildDiff);
+        check("lims_sign targetId 涓嶈繑鍥炴櫘閫氭煡璇�",
+                AuditQueryResponseSanitizer.hidesTargetId("LIMS_SIGN"), "鏈懡涓�");
+
+        String missing = AuditQueryResponseSanitizer.sanitizeFieldDiffs(
+                "[{\"field\":\"x\",\"fieldName\":\"x\"}]", Collections.emptyMap());
+        check("绌哄厓鏁版嵁鍥炶惤鏁版嵁搴撳瓧娈靛悕", missing != null && missing.contains("\"fieldName\":\"x\""), missing);
+
+        Map<String, AuditFieldDiff.FieldMeta> databaseMeta = new LinkedHashMap<>();
+        databaseMeta.put("biz_status", new AuditFieldDiff.FieldMeta("涓氬姟鐘舵��", null, null));
+        databaseMeta.put("creator_time", new AuditFieldDiff.FieldMeta(null, null, null));
+        String historical = AuditQueryResponseSanitizer.sanitizeFieldDiffs(
+                "[{\"field\":\"bizStatus\",\"fieldName\":\"bizStatus\"},"
+                        + "{\"field\":\"creatorTime\",\"fieldName\":\"creatorTime\"}]",
+                databaseMeta);
+        check("鍘嗗彶 Java 灞炴�у悕鍙槧灏勬暟鎹簱澶囨敞", historical.contains("\"fieldName\":\"涓氬姟鐘舵�乗""), historical);
+        check("鍘嗗彶 Java 灞炴�у悕鍦ㄥ娉ㄤ负绌烘椂鍥炶惤鏁版嵁搴撳垪鍚�",
+                historical.contains("\"fieldName\":\"creator_time\""), historical);
+
+        String repeatedFields = "[{\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"},"
+                + "{\"field\":\"status\",\"oldData\":\"b\",\"newData\":\"c\"},"
+                + "{\"field\":\"amount\",\"oldData\":1,\"newData\":2}]";
+        check("閲嶅瀛楁鎸夊瓧娈靛苟闆嗚鏁�",
+                AuditQueryResponseSanitizer.effectiveDiffCount(repeatedFields) == 2,
+                String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(repeatedFields)));
+
+        String sameFieldAcrossTables = "[{\"targetTable\":\"main_table\",\"field\":\"status\","
+                + "\"oldData\":\"a\",\"newData\":\"b\"},"
+                + "{\"targetTable\":\"child_table\",\"field\":\"status\","
+                + "\"oldData\":\"x\",\"newData\":\"y\"},"
+                + "{\"targetTable\":\"child_table\",\"field\":\"status\","
+                + "\"oldData\":\"y\",\"newData\":\"z\"}]";
+        check("涓诲瓙琛ㄥ悓鍚嶅瓧娈垫寜鐗╃悊琛ㄥ垎鍒鏁�",
+                AuditQueryResponseSanitizer.effectiveDiffCount(sameFieldAcrossTables) == 2,
+                String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(sameFieldAcrossTables)));
+
+        String batchSameField = "[{\"targetTable\":\"lims_task\",\"targetId\":\"row-1\","
+                + "\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"},"
+                + "{\"targetTable\":\"lims_task\",\"targetId\":\"row-2\","
+                + "\"field\":\"status\",\"oldData\":\"x\",\"newData\":\"b\"}]";
+        check("鎵归噺閫愯褰曞樊寮傜殑鎽樿浠嶆寜琛ㄥ拰瀛楁璁′负涓�涓�",
+                AuditQueryResponseSanitizer.effectiveDiffCount(batchSameField) == 1,
+                String.valueOf(AuditQueryResponseSanitizer.effectiveDiffFields(batchSameField)));
+
+        verifyOperationDisplayGrouping();
+
+        System.out.println("=== 鏌ヨ璇箟鏂█锛�" + passed + " 閫氳繃 / " + failed + " 澶辫触 ===");
+        System.exit(failed == 0 ? 0 : 1);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void verifyOperationDisplayGrouping() {
+        AuditEventEntity business = event(101L, AuditEventCategories.BUSINESS, "BIZ_ACTION",
+                "[{\"field\":\"status\",\"oldData\":\"a\",\"newData\":\"b\"}]");
+        AuditEventEntity primary = event(102L, AuditEventCategories.PRIMARY_SIGN, "E_SIGNATURE",
+                "[{\"field\":\"sign_a\"},{\"field\":\"sign_b\"}]");
+        AuditEventEntity review = event(103L, AuditEventCategories.REVIEW_SIGN, "E_SIGNATURE", null);
+        AuditOperationGroupRow group = new AuditOperationGroupRow();
+        group.setGid("op-display-1");
+
+        try {
+            Method method = AuditQueryServiceImpl.class.getDeclaredMethod(
+                    "buildOperationRows", List.class, List.class);
+            method.setAccessible(true);
+            List<AuditEventListVO> rows = (List<AuditEventListVO>) method.invoke(
+                    new AuditQueryServiceImpl(), Collections.singletonList(group),
+                    Arrays.asList(primary, business, review));
+            AuditEventListVO main = rows.isEmpty() ? null : rows.get(0);
+            check("operationId 鍒楄〃鍙繑鍥� BUSINESS 涓昏",
+                    rows.size() == 1 && main != null && Long.valueOf(101L).equals(main.getId()),
+                    String.valueOf(rows));
+            check("涓荤鍚嶄笌澶嶅绛惧悕浣滀负涓ゆ潯鍏宠仈鏄庣粏",
+                    main != null && main.getSubEvents() != null && main.getSubEvents().size() == 2
+                            && "PRIMARY".equals(main.getSubEvents().get(0).getSignatureRole())
+                            && "REVIEW".equals(main.getSubEvents().get(1).getSignatureRole()),
+                    main == null ? "null" : String.valueOf(main.getSubEvents()));
+            check("鏌ヨ灞備笉绱姞绛惧悕宸紓鏁�",
+                    main != null && Integer.valueOf(1).equals(main.getDiffCount()),
+                    main == null ? "null" : String.valueOf(main.getDiffCount()));
+        } catch (ReflectiveOperationException ex) {
+            throw new AssertionError("鏃犳硶鎵ц operationId 灞曠ず缁勮鎺㈤拡", ex);
+        }
+    }
+
+    private static AuditEventEntity event(Long id, String category, String eventType, String fieldDiffs) {
+        AuditEventEntity event = new AuditEventEntity();
+        event.setId(id);
+        event.setOperationId("op-display-1");
+        event.setClientEventId("client-" + id);
+        event.setEventCategory(category);
+        event.setEventType(eventType);
+        event.setFieldDiffs(fieldDiffs);
+        return event;
+    }
+
+    private static String quote(String value) {
+        return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
+    }
+
+    private static void check(String name, boolean ok, String detail) {
+        if (ok) {
+            passed++;
+            System.out.println("  [PASS] " + name);
+        } else {
+            failed++;
+            System.out.println("  [FAIL] " + name + " -- " + detail);
+        }
+    }
+
+    private AuditQuerySemanticsProbe() {
+    }
+}

--
Gitblit v1.8.0