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-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsOperationalMessagePublisher.java |  243 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 243 insertions(+), 0 deletions(-)

diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsOperationalMessagePublisher.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsOperationalMessagePublisher.java
new file mode 100644
index 0000000..7470257
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/limsService/impl/LimsOperationalMessagePublisher.java
@@ -0,0 +1,243 @@
+package jnpf.limsService.impl;
+
+import jnpf.base.UserInfo;
+import jnpf.limsEntity.BaogaoShenheJibie;
+import jnpf.limsEntity.LimsJianyanAssignItem;
+import jnpf.limsEntity.LimsJianyanXiangEntity;
+import jnpf.limsEntity.LimsLiuyangJiluEntity;
+import jnpf.limsEntity.LimsMessageEvent;
+import jnpf.limsEntity.LimsMessageRequest;
+import jnpf.limsEntity.LimsQingyandanEntity;
+import jnpf.limsEntity.LimsRecipientRef;
+import jnpf.limsMapper.LimsMessageAudienceMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+public class LimsOperationalMessagePublisher {
+    private static final String QC_SUPERVISOR = "ROLE.003";
+
+    private final LimsMessageAfterCommitPublisher publisher;
+    private final LimsMessageAudienceMapper audienceMapper;
+
+    public void taskAssigned(LimsJianyanXiangEntity existing, LimsJianyanAssignItem item,
+                             UserInfo operator, Date assignedAt) {
+        boolean external = "yes".equalsIgnoreCase(existing.getShifouWaijian());
+        String oldAssignee = external ? existing.getWaijianLururen() : existing.getJianchaRen();
+        String newAssignee = external ? item.getWaijianLururen() : item.getJianchaRen();
+        if (!StringUtils.hasText(newAssignee) || newAssignee.equals(oldAssignee)) {
+            return;
+        }
+        Map<String, Object> parameters = baseInspectionParameters(existing);
+        parameters.put("assignmentType", StringUtils.hasText(oldAssignee) ? "REASSIGN" : "ASSIGN");
+        parameters.put("inspectionItemName", value(existing.getJianyanXiangmuMingcheng()));
+        parameters.put("dueDate", date(item.getWanchengRiqi()));
+        parameters.put("assignerName", userName(operator));
+        parameters.put("externalInspection", external);
+        publish(LimsMessageEvent.INSPECTION_TASK_ASSIGNED, tenant(operator, existing.getTenantId()),
+                existing.getId(), "ASSIGNED",
+                LimsMessageEvent.INSPECTION_TASK_ASSIGNED.getCode() + ":" + existing.getId() + ":"
+                        + assignedAt.getTime() + ":" + newAssignee,
+                Collections.singletonList(LimsRecipientRef.user(newAssignee)), parameters);
+    }
+
+    public void inspectionResultsPendingReview(List<LimsJianyanXiangEntity> rows,
+                                               UserInfo submitter, Date submittedAt) {
+        Map<String, List<LimsJianyanXiangEntity>> byReviewer = new LinkedHashMap<>();
+        for (LimsJianyanXiangEntity row : rows) {
+            if (!StringUtils.hasText(row.getJianchaBanzu())) {
+                continue;
+            }
+            List<String> reviewers = audienceMapper.selectOrganizationRoleUsers(
+                    tenant(submitter, row.getTenantId()), row.getJianchaBanzu(), QC_SUPERVISOR);
+            String submitterId = assignee(row);
+            for (String reviewer : reviewers) {
+                if (StringUtils.hasText(reviewer) && !reviewer.equals(submitterId)) {
+                    byReviewer.computeIfAbsent(reviewer, key -> new ArrayList<>()).add(row);
+                }
+            }
+        }
+        for (Map.Entry<String, List<LimsJianyanXiangEntity>> entry : byReviewer.entrySet()) {
+            List<LimsJianyanXiangEntity> assigned = entry.getValue();
+            Map<String, Object> parameters = new LinkedHashMap<>();
+            parameters.put("reviewerUserId", entry.getKey());
+            parameters.put("inspectionCount", assigned.size());
+            parameters.put("inspectionNos", join(assigned, LimsJianyanXiangEntity::getJianyanLiushuihao));
+            parameters.put("inspectionItemNames", join(assigned,
+                    LimsJianyanXiangEntity::getJianyanXiangmuMingcheng));
+            parameters.put("submitterName", userName(submitter));
+            parameters.put("submittedAt", dateTime(submittedAt));
+            LimsJianyanXiangEntity first = assigned.get(0);
+            publish(LimsMessageEvent.INSPECTION_RESULT_REVIEW_PENDING,
+                    tenant(submitter, first.getTenantId()), first.getId(), "PENDING_REVIEW",
+                    LimsMessageEvent.INSPECTION_RESULT_REVIEW_PENDING.getCode() + ":"
+                            + entry.getKey() + ":" + submittedAt.getTime(),
+                    Collections.singletonList(LimsRecipientRef.user(entry.getKey())), parameters);
+        }
+    }
+
+    public void inspectionResultsRejected(List<LimsJianyanXiangEntity> rows, String reason,
+                                          UserInfo rejector, Date rejectedAt) {
+        for (LimsJianyanXiangEntity row : rows) {
+            String recipient = assignee(row);
+            if (!StringUtils.hasText(recipient)) {
+                continue;
+            }
+            Map<String, Object> parameters = baseInspectionParameters(row);
+            parameters.put("inspectionNo", value(row.getJianyanLiushuihao()));
+            parameters.put("inspectionItemName", value(row.getJianyanXiangmuMingcheng()));
+            parameters.put("rejectReason", value(reason));
+            parameters.put("rejectorName", userName(rejector));
+            parameters.put("externalInspection", "yes".equalsIgnoreCase(row.getShifouWaijian()));
+            long round = row.getJieguoLuruRiqi() == null
+                    ? rejectedAt.getTime() : row.getJieguoLuruRiqi().getTime();
+            publish(LimsMessageEvent.INSPECTION_RESULT_REJECTED,
+                    tenant(rejector, row.getTenantId()), row.getId(), "REJECTED",
+                    LimsMessageEvent.INSPECTION_RESULT_REJECTED.getCode() + ":" + row.getId() + ":" + round,
+                    Collections.singletonList(LimsRecipientRef.user(recipient)), parameters);
+        }
+    }
+
+    public void reportPendingReview(LimsQingyandanEntity report, UserInfo compiler, Date submittedAt) {
+        List<String> recipients = authorized(report, BaogaoShenheJibie.SHENHE.getCode(),
+                Collections.singleton(compiler.getUserId()));
+        Map<String, Object> parameters = baseReportParameters(report);
+        parameters.put("compilerName", userName(compiler));
+        parameters.put("submittedAt", dateTime(submittedAt));
+        publishUsers(LimsMessageEvent.REPORT_REVIEW_PENDING, report, submittedAt, "PENDING_REVIEW",
+                recipients, parameters);
+    }
+
+    public void reportPendingApproval(LimsQingyandanEntity report, UserInfo reviewer, Date reviewedAt) {
+        Set<String> excluded = new LinkedHashSet<>();
+        excluded.add(report.getBaogaoRen());
+        excluded.add(reviewer.getUserId());
+        List<String> recipients = authorized(report, BaogaoShenheJibie.QIANFA.getCode(), excluded);
+        Map<String, Object> parameters = baseReportParameters(report);
+        parameters.put("compilerName", value(audienceMapper.selectUserDisplayName(
+                report.getTenantId(), report.getBaogaoRen())));
+        parameters.put("reviewerName", userName(reviewer));
+        parameters.put("reviewedAt", dateTime(reviewedAt));
+        publishUsers(LimsMessageEvent.REPORT_APPROVAL_PENDING, report, reviewedAt, "PENDING_APPROVAL",
+                recipients, parameters);
+    }
+
+    public void reportRejected(LimsQingyandanEntity report, List<LimsJianyanXiangEntity> items,
+                               String fromStatus, String reason, UserInfo rejector, Date rejectedAt) {
+        Set<String> userIds = new LinkedHashSet<>();
+        if (StringUtils.hasText(report.getBaogaoRen())) {
+            userIds.add(report.getBaogaoRen());
+        }
+        items.stream().map(this::assignee).filter(StringUtils::hasText).forEach(userIds::add);
+        Map<String, Object> parameters = baseReportParameters(report);
+        parameters.put("rejectReason", value(reason));
+        parameters.put("rejectorName", userName(rejector));
+        parameters.put("rejectedFromStatus", value(fromStatus));
+        publishUsers(LimsMessageEvent.REPORT_REJECTED, report, rejectedAt, "REJECTED",
+                new ArrayList<>(userIds), parameters);
+    }
+
+    public void retainSamplePendingReceive(LimsLiuyangJiluEntity record, LimsQingyandanEntity request,
+                                           UserInfo sampler) {
+        Map<String, Object> parameters = new LinkedHashMap<>();
+        parameters.put("bizId", record.getId());
+        parameters.put("requestId", request.getId());
+        parameters.put("inspectionNo", value(request.getJianyanLiushuihao()));
+        parameters.put("receiveNo", value(record.getJieshouBianhao()));
+        parameters.put("sampleName", value(record.getYangpinMingcheng()));
+        parameters.put("sampleCode", value(record.getYangpinBianma()));
+        parameters.put("batchNo", value(record.getPihao()));
+        parameters.put("retainQuantity", value(record.getLiuyangLiangShiji()));
+        parameters.put("unit", value(record.getLiuyangDanwei()));
+        parameters.put("samplerName", userName(sampler));
+        parameters.put("sampledAt", dateTime(request.getQuyangRiqi()));
+        publish(LimsMessageEvent.RETAIN_SAMPLE_RECEIVE_PENDING,
+                tenant(sampler, record.getTenantId()), record.getId(), "PENDING_RECEIVE",
+                LimsMessageEvent.RETAIN_SAMPLE_RECEIVE_PENDING.getCode() + ":" + record.getId(),
+                Collections.singletonList(LimsRecipientRef.roleEnCode("ROLE.005")), parameters);
+    }
+
+    private List<String> authorized(LimsQingyandanEntity report, String level, Set<String> excluded) {
+        List<String> users = audienceMapper.selectReportAuthorizedUsers(
+                value(report.getTenantId()), level, report.getBizType());
+        return users.stream().filter(StringUtils::hasText).filter(id -> !excluded.contains(id))
+                .distinct().collect(Collectors.toList());
+    }
+
+    private void publishUsers(LimsMessageEvent event, LimsQingyandanEntity report, Date actionTime,
+                              String stage, List<String> users, Map<String, Object> parameters) {
+        List<LimsRecipientRef> refs = users.stream().map(LimsRecipientRef::user).collect(Collectors.toList());
+        publish(event, value(report.getTenantId()), report.getId(), stage,
+                event.getCode() + ":" + report.getId() + ":" + actionTime.getTime(), refs, parameters);
+    }
+
+    private Map<String, Object> baseInspectionParameters(LimsJianyanXiangEntity row) {
+        Map<String, Object> parameters = new LinkedHashMap<>();
+        parameters.put("bizId", row.getId());
+        parameters.put("productName", value(row.getChanpinMingcheng()));
+        parameters.put("batchNo", value(row.getPihao()));
+        return parameters;
+    }
+
+    private Map<String, Object> baseReportParameters(LimsQingyandanEntity report) {
+        Map<String, Object> parameters = new LinkedHashMap<>();
+        parameters.put("bizId", report.getId());
+        parameters.put("inspectionNo", value(report.getJianyanLiushuihao()));
+        parameters.put("reportNo", value(report.getBaogaoBianhao()));
+        parameters.put("productName", value(report.getChanpinMingcheng()));
+        parameters.put("batchNo", value(report.getPihao()));
+        parameters.put("reportCategory", value(report.getBizType()));
+        return parameters;
+    }
+
+    private void publish(LimsMessageEvent event, String tenantId, String bizId, String stage,
+                         String occurrenceKey, List<LimsRecipientRef> recipients,
+                         Map<String, Object> parameters) {
+        publisher.publish(LimsMessageRequest.builder().event(event).tenantId(tenantId).bizId(bizId)
+                .remindStage(stage).occurrenceKey(occurrenceKey).recipients(recipients)
+                .parameters(parameters).build());
+    }
+
+    private String assignee(LimsJianyanXiangEntity row) {
+        return "yes".equalsIgnoreCase(row.getShifouWaijian())
+                ? row.getWaijianLururen() : row.getJianchaRen();
+    }
+
+    private String tenant(UserInfo user, String fallback) {
+        return user != null && StringUtils.hasText(user.getTenantId()) ? user.getTenantId() : value(fallback);
+    }
+
+    private String userName(UserInfo user) {
+        return user == null ? "" : value(user.getUserName());
+    }
+
+    private String date(Date value) {
+        return value == null ? "" : new SimpleDateFormat("yyyy-MM-dd").format(value);
+    }
+
+    private String dateTime(Date value) {
+        return value == null ? "" : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value);
+    }
+
+    private String join(List<LimsJianyanXiangEntity> rows,
+                        java.util.function.Function<LimsJianyanXiangEntity, String> getter) {
+        return rows.stream().map(getter).filter(StringUtils::hasText).distinct().collect(Collectors.joining("銆�"));
+    }
+
+    private String value(String value) {
+        return value == null ? "" : value;
+    }
+}

--
Gitblit v1.8.0