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/main/java/jnpf/bizcommon/audit/service/sign/AuditSignEvidenceReader.java | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 200 insertions(+), 0 deletions(-)
diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/sign/AuditSignEvidenceReader.java b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/sign/AuditSignEvidenceReader.java
new file mode 100644
index 0000000..190e713
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/sign/AuditSignEvidenceReader.java
@@ -0,0 +1,200 @@
+package jnpf.bizcommon.audit.service.sign;
+
+import jnpf.audit.diff.AuditFieldDiff;
+import jnpf.bizcommon.audit.service.listener.AuditVisualLogListener;
+import jnpf.bizcommon.audit.service.title.AuditTitleSpec;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 璇诲彇鐢靛瓙绛惧悕鍑瘉浜嬪疄銆�
+ *
+ * <p><b>涓轰粈涔堢‖缂栫爜 {@code lims_sign} 鑰屼笉鍋氭垚閰嶇疆</b>锛氱鍚嶅皢鏁翠綋鎸繘閫氱敤鏈嶅姟
+ * 锛堣鍒掍腑鐨� {@code jnpf-biz-common} 涔嬬被锛夛紝閰嶇疆鍖栨槸涓轰竴涓凡璁″垝搴熷純鐨勪腑闂存�佷拱鍗曘��
+ * 鎵�浠ユ妸鑰﹀悎<b>鏀跺湪鏈被涓�澶�</b>锛氬澶栧彧鏈� {@link #read}锛屽眾鏃舵崲鏈被瀹炵幇鍗冲彲锛岃皟鐢ㄦ柟闆舵敼鍔ㄣ��
+ *
+ * <p><b>鎵归噺璇伙紝涓嶉�愪釜鏌�</b>锛氫笌 {@code AuditFieldValueResolver} 鐨� SPI 绾﹀畾鍚屽彛寰勨�斺��
+ * 灞� 0 璺戝湪 MQ 娑堣垂绾跨▼涓婏紝閫� ID 鏌ュ簱浼氭妸娑堣垂閫熺巼鎷栧灝銆�
+ */
+@Slf4j
+@Component
+public class AuditSignEvidenceReader {
+
+ /**
+ * 绛惧悕鍑瘉琛ㄣ�傛尓鍒伴�氱敤鏈嶅姟鏃舵敼杩欓噷锛堣繛鍚屼笅闈㈢殑鍒楀悕锛夈��
+ *
+ * <p><b>public 鏄埢鎰忕殑</b>锛氱鍚嶄簨浠剁殑 {@code target_table} 鍐欑殑鏄畠锛岃�� A1-b 鐨勫巻鍙插弽鏌�
+ * 锛坽@code selectRecordedSignIds}锛夎鎸夊悓涓�涓�煎幓鏌モ�斺�斾袱澶勫垎鍒啓涓�浠藉瓧闈㈤噺锛屾敼琛ㄥ悕鏃�
+ * 婕忔帀涓�澶勫氨浼氳鍙嶆煡鎭掓煡涓嶅埌銆佸巻鍙茬鍚嶉噸鏂拌褰撴垚鏈绛剧殑锛岃�屼笖涓嶆姤浠讳綍閿欍��
+ */
+ public static final String SIGN_TABLE = "lims_sign";
+
+ /** 鍗曟 IN 鐨勪笂闄愩�備竴浠借〃鍗曚笂鐨勭鍚嶅瓧娈典釜浣嶆暟锛岃秴浜嗚鏄庡垽瀹氳窇鍋忥紝瀹佸彲灏戞煡涔熶笉鎵撶垎搴撱�� */
+ private static final int MAX_IDS = 20;
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ /**
+ * 鏈浜嬩欢閲屻�屽彲鑳芥槸绛惧悕瀛楁銆嶇殑鍊欓�夛紙灏忓啓銆佸幓閲嶃�佺ǔ瀹氶『搴忥級銆�
+ *
+ * <p>涓夋潯鏉ユ簮锛屾寜浼樺厛绾ф帓鍒椻�斺�攞@code ordered} 鏄� {@link LinkedHashSet}锛堜繚搴忥級锛�
+ * {@link #MAX_IDS} 椤舵牸鎴柇鏃跺厛淇濅綇鎺掑湪鍓嶉潰鐨勶細
+ * <ol>
+ * <li>{@code configuredFields}锛圖4 鏉冨▉鏉ユ簮锛岃
+ * {@link jnpf.bizcommon.audit.service.AuditFormRegistry#resolveSignFields}锛夛細琛ㄥ崟閰嶇疆
+ * {@code confirmBtnConfig}/{@code reviewBtnConfig} 閲屾樉寮忔寚瀹氱殑 {@code biz_sign_field}銆�
+ * 澶氫汉绛惧悕鍦烘櫙涓嬪瓧娈靛悕鍙互鏄换鎰忕殑锛屽繀椤�<b>鏈�鍏�</b>鏀捐繘鍊欓�夐泦锛屽惁鍒欎細琚悗涓ゆ潯鏉ユ簮
+ * 鎸ゅ埌 20 涓婇檺涔嬪锛�</li>
+ * <li>鍛藉悕瑙勫垯鍛戒腑 {@code isCredentialReference} 鐨勫瓧娈碘�斺�旀亽涓哄�欓�夛紝涓嶉渶瑕佸嬀閫夛紝
+ * 杩欐壒瀛楁鏈氨宸茶寮哄埗鑴辨晱锛堝懡鍚嶈鍒�+鎾炲簱鍏滃簳锛岃鐩栭厤缃病鎻愬埌鐨勫瓧娈碉級锛�</li>
+ * <li>琛ㄥ崟涓婂嬀浜� {@code biz_log_enabled} 鐨勪富琛ㄥ瓧娈碘�斺�旀槸涓嶆槸绛惧悕鐢� {@link #read}
+ * 鏌ヨ〃瀹氾紝鏈柟娉曞彧璐熻矗鎸戝嚭"鍊煎緱鍘绘煡涓�涓�"鐨勯偅浜涖��</li>
+ * </ol>
+ *
+ * <p><b>鍊间负绌虹殑涓�寰嬩笉杩涘�欓��</b>锛氱┖鍊兼煡绛惧悕琛ㄧ函灞炴氮璐癸紝杩樹細鎶婄┖涓插杩� IN 鍙傛暟銆�
+ */
+ public static List<String> candidateFields(Map<String, Object> row, AuditTitleSpec spec,
+ List<String> configuredFields) {
+ if (row == null || row.isEmpty()) {
+ return Collections.emptyList();
+ }
+ Set<String> ordered = new LinkedHashSet<String>();
+ if (configuredFields != null) {
+ for (String field : configuredFields) {
+ if (field == null) {
+ continue;
+ }
+ String lowerField = field.toLowerCase(Locale.ROOT);
+ if (hasValue(valueOf(row, lowerField))) {
+ ordered.add(lowerField);
+ }
+ }
+ }
+ for (Map.Entry<String, Object> entry : row.entrySet()) {
+ String field = entry.getKey();
+ if (field != null && AuditVisualLogListener.isCredentialReference(field)
+ && hasValue(entry.getValue())) {
+ ordered.add(field.toLowerCase(Locale.ROOT));
+ }
+ }
+ if (spec != null) {
+ for (String field : spec.mainFields()) {
+ if (field == null) {
+ continue;
+ }
+ String lower = field.toLowerCase(Locale.ROOT);
+ if (hasValue(valueOf(row, lower))) {
+ ordered.add(lower);
+ }
+ }
+ }
+ return ordered.isEmpty() ? Collections.<String>emptyList()
+ : Collections.unmodifiableList(new ArrayList<String>(ordered));
+ }
+
+ /**
+ * 鎸夌鍚� id 鎵归噺璇诲彇绛惧悕浜嬪疄銆傛煡涓嶅埌鐨� id 涓嶅嚭鐜板湪缁撴灉閲岋紙= 閭d釜瀛楁涓嶆槸绛惧悕瀛楁锛夈��
+ *
+ * <p>浠讳綍寮傚父閮借繑鍥炵┖ Map 骞跺憡璀︼細绛惧悕浜嬪疄璇讳笉鍒版椂锛屽畞鍙繖娆′笉浜у嚭绛惧悕浜嬩欢锛�
+ * 涔熶笉鑳藉洜姝や涪鎺変笟鍔′簨浠垛�斺�斿璁$殑绾㈢嚎鏄�岃繖娆℃敼杩囦笉鑳界己銆嶃��
+ *
+ * <p>馃敶 <b>鎸夌鎴锋敹绐�</b>锛�2026-08-05 鎵� D锛夛細{@code lims_sign} 涓婚敭鏄�
+ * {@code (f_id, f_tenant_id)}锛�<b>{@code f_id} 鍗曞垪鍞竴涓嶆槸鏁版嵁搴撲笉鍙橀噺</b>鈥斺�斻�岄洩鑺� id
+ * 鍏ㄥ眬鍞竴銆嶆槸瀹炵幇绾﹀畾涓嶆槸绾︽潫銆傛壒 A 宸茬粡鍦ㄥ巻鍙插弽鏌ヤ晶锛坽@code selectRecordedSignIds}锛�
+ * 閽夎繃杩欎竴鏉★紝浣�<b>璇诲彇渚ц繖涓�鍗婂綋鏃舵紡浜�</b>锛氫笉鏀剁獎鐨勮瘽锛岃姹傞噷濉炰竴涓埆鐨勭鎴风殑 signId
+ * 鐓ф牱鑳借鍑洪偅涓�琛岋紝鐒跺悗琚綋鎴愭湰娆℃搷浣滅殑绛惧悕鍑瘉鍐欒繘 append-only 鐨勫璁¤〃銆�
+ * 瀹炴煡褰撳墠搴� 1306 鏉$鍚嶅叏鍦ㄧ鎴� '0'銆�0 涓法绉熸埛閲嶅鐨� f_id鈥斺�旀槸鍩嬬潃鐨勯櫡闃变笉鏄椿鐨勬晠闅滐紝
+ * 浣嗕袱渚у彛寰勫繀椤讳竴鑷达紝鍚﹀垯涓嬩竴涓汉鍙細鐪嬪埌銆屽弽鏌ユ寜绉熸埛銆佽鍙栦笉鎸夈�嶈�屾棤浠庡垽鏂摢涓槸瀵圭殑銆�
+ *
+ * @param tenantId 璋冪敤鏂圭殑绉熸埛锛坽@code AuditCtx.tenantId}锛屾案涓嶄负 null锛岃鍏堕粯璁ゅ�硷級
+ */
+ public Map<String, AuditSignEvidence> read(Collection<String> signIds, String tenantId) {
+ if (signIds == null || signIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ List<String> ids = new ArrayList<String>();
+ for (String id : signIds) {
+ if (id != null && !id.trim().isEmpty() && ids.size() < MAX_IDS) {
+ ids.add(id.trim());
+ }
+ }
+ if (ids.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ StringBuilder sql = new StringBuilder(
+ "SELECT f_id, account_name, f_creator_user_id, note, op_type, f_creator_time, meta_data FROM ")
+ .append(SIGN_TABLE).append(" WHERE f_id IN (");
+ for (int i = 0; i < ids.size(); i++) {
+ sql.append(i == 0 ? "?" : ",?");
+ }
+ sql.append(") AND f_tenant_id = ?");
+ List<Object> args = new ArrayList<Object>(ids);
+ args.add(tenantId);
+ try {
+ List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), args.toArray());
+ Map<String, AuditSignEvidence> out = new LinkedHashMap<String, AuditSignEvidence>();
+ for (Map<String, Object> r : rows) {
+ String id = str(r.get("f_id"));
+ if (id == null) {
+ continue;
+ }
+ out.put(id, new AuditSignEvidence(id,
+ str(r.get("account_name")),
+ str(r.get("f_creator_user_id")),
+ str(r.get("note")),
+ str(r.get("op_type")),
+ date(r.get("f_creator_time")),
+ str(r.get("meta_data"))));
+ }
+ return out;
+ } catch (Throwable t) {
+ log.error("[AUDIT-L0] 璇诲彇绛惧悕鍑瘉澶辫触锛屾湰娆′笉浜у嚭绛惧悕浜嬩欢锛堜笟鍔′簨浠朵笉鍙楀奖鍝嶏級ids={}",
+ ids.size(), t);
+ return Collections.emptyMap();
+ }
+ }
+
+ private static Object valueOf(Map<String, Object> row, String lowerField) {
+ for (Map.Entry<String, Object> entry : row.entrySet()) {
+ if (entry.getKey() != null
+ && lowerField.equals(entry.getKey().toLowerCase(Locale.ROOT))) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ private static boolean hasValue(Object value) {
+ return !AuditFieldDiff.stringify(value).trim().isEmpty();
+ }
+
+ private static String str(Object value) {
+ if (value == null) {
+ return null;
+ }
+ String s = value.toString().trim();
+ return s.isEmpty() ? null : s;
+ }
+
+ private static Date date(Object value) {
+ if (value instanceof Timestamp) {
+ return new Date(((Timestamp) value).getTime());
+ }
+ return value instanceof Date ? (Date) value : null;
+ }
+}
--
Gitblit v1.8.0