From b965c9d9c1ca4157fdae9f9ef19df1915196852c Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Mon, 1 Jun 2026 09:15:10 +0800 Subject: [PATCH] =?UTF-8?q?QC=E7=94=9F=E4=BA=A7=E8=BD=A6=E9=97=B4=E8=B4=9F?= =?UTF-8?q?=E8=B4=A3=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../erf/controller/ErfExpApplyController.java | 6 +- .../sys/modules/erf/data/ErfExpApplyData.java | 10 + .../sys/modules/erf/entity/ErfExpApply.java | 10 + .../erf/service/ErfExpApplyService.java | 2 +- .../service/impl/ErfExpApplyServiceImpl.java | 190 ++++++++++++++++-- .../mapper/erf/ErfExpApplyMapper.xml | 8 + 6 files changed, 209 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java b/src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java index e36f9063..5b2c55ba 100644 --- a/src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java +++ b/src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java @@ -160,7 +160,7 @@ public class ErfExpApplyController extends AbstractController { } /** - * 获取负责人列表(PJM负责人 + 生产车间负责人) + * 获取负责人列表(PJM负责人 + 生产车间负责人 + QC车间负责人) * * @param data 包含buNo * @return 负责人列表 @@ -173,10 +173,12 @@ public class ErfExpApplyController extends AbstractController { Map>> leaderMap = erfExpApplyService.getPjmLeaderList(buNo); List> pjmLeaderList = leaderMap.getOrDefault("pjmLeaderList", Collections.emptyList()); List> workshopLeaderList = leaderMap.getOrDefault("workshopLeaderList", Collections.emptyList()); + List> qcWorkshopLeaderList = leaderMap.getOrDefault("qcWorkshopLeaderList", Collections.emptyList()); return R.ok() .put("list", pjmLeaderList) .put("pjmLeaderList", pjmLeaderList) - .put("workshopLeaderList", workshopLeaderList); + .put("workshopLeaderList", workshopLeaderList) + .put("qcWorkshopLeaderList", qcWorkshopLeaderList); } catch (Exception e) { log.error("获取负责人列表失败: " + e.getMessage(), e); return R.error("获取负责人列表失败: " + e.getMessage()); diff --git a/src/main/java/com/xujie/sys/modules/erf/data/ErfExpApplyData.java b/src/main/java/com/xujie/sys/modules/erf/data/ErfExpApplyData.java index ca3080c5..db9fa659 100644 --- a/src/main/java/com/xujie/sys/modules/erf/data/ErfExpApplyData.java +++ b/src/main/java/com/xujie/sys/modules/erf/data/ErfExpApplyData.java @@ -230,6 +230,16 @@ public class ErfExpApplyData implements Serializable { */ private String workshopLeaderName; + /** + * QC车间负责人用户ID(支持多选,英文逗号分隔) + */ + private String qcWorkshopLeaderUserId; + + /** + * QC车间负责人姓名 + */ + private String qcWorkshopLeaderName; + /** * 联系方式 */ diff --git a/src/main/java/com/xujie/sys/modules/erf/entity/ErfExpApply.java b/src/main/java/com/xujie/sys/modules/erf/entity/ErfExpApply.java index 09ba99b7..8ec16588 100644 --- a/src/main/java/com/xujie/sys/modules/erf/entity/ErfExpApply.java +++ b/src/main/java/com/xujie/sys/modules/erf/entity/ErfExpApply.java @@ -115,6 +115,16 @@ public class ErfExpApply implements Serializable { */ private String workshopLeaderName; + /** + * QC车间负责人用户ID(支持多选,英文逗号分隔) + */ + private String qcWorkshopLeaderUserId; + + /** + * QC车间负责人姓名 + */ + private String qcWorkshopLeaderName; + /** * 联系方式 */ diff --git a/src/main/java/com/xujie/sys/modules/erf/service/ErfExpApplyService.java b/src/main/java/com/xujie/sys/modules/erf/service/ErfExpApplyService.java index 01df7a6b..6372f121 100644 --- a/src/main/java/com/xujie/sys/modules/erf/service/ErfExpApplyService.java +++ b/src/main/java/com/xujie/sys/modules/erf/service/ErfExpApplyService.java @@ -61,7 +61,7 @@ public interface ErfExpApplyService extends IService { Map getSubmitApprovers(Long userId, String buNo); /** - * 获取负责人列表(PJM负责人 + 生产车间负责人) + * 获取负责人列表(PJM负责人 + 生产车间负责人 + QC车间负责人) * * @param buNo 事业部编码(可为空,为空时不按BU过滤) * @return 负责人列表映射 diff --git a/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java b/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java index 71fa5d26..aecac517 100644 --- a/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java @@ -64,6 +64,9 @@ public class ErfExpApplyServiceImpl extends ServiceImpl>> getPjmLeaderList(String buNo) { log.info("获取负责人列表: buNo={}", buNo); Map>> result = new HashMap<>(); - result.put("pjmLeaderList", convertManagerList(sysUserDao.getManagerListByRoleNameAndBu("产品文档收集 - PjM", buNo))); - result.put("workshopLeaderList", convertManagerList(sysUserDao.getManagerListByRoleNameAndBu("生产车间负责人", buNo))); + result.put("pjmLeaderList", convertManagerList(sysUserDao.getManagerListByRoleNameAndBu(ROLE_PJM_LEADER, buNo))); + result.put("workshopLeaderList", convertManagerList(sysUserDao.getManagerListByRoleNameAndBu(ROLE_WORKSHOP_LEADER, buNo))); + result.put("qcWorkshopLeaderList", convertManagerList(sysUserDao.getManagerListByRoleNameAndBu(ROLE_QC_WORKSHOP_LEADER, buNo))); return result; } @@ -1328,9 +1337,9 @@ public class ErfExpApplyServiceImpl extends ServiceImpl roles = sysUserDao.getUserRolesByRoleNames( - data.getPjmLeaderUserId(), List.of("产品文档收集 - PjM")); + data.getPjmLeaderUserId(), List.of(ROLE_PJM_LEADER)); if (roles == null || roles.isEmpty()) { - throw new XJException("PJM负责人必须是【产品文档收集 - PjM】角色用户"); + throw new XJException("PJM负责人必须是【" + ROLE_PJM_LEADER + "】角色用户"); } if (StringUtils.isBlank(data.getPjmLeaderName())) { String pjmDisplay = sysUserDao.getUserDisplayById(data.getPjmLeaderUserId()); @@ -1344,19 +1353,16 @@ public class ErfExpApplyServiceImpl extends ServiceImpl workshopLeaderIds = parseUserIdCsv(data.getWorkshopLeaderUserId(), "生产车间负责人", true); if (workshopLeaderIds.isEmpty()) { - data.setWorkshopLeaderUserId(""); - data.setWorkshopLeaderName(""); - return; + throw new XJException("请选择生产车间负责人"); } List inputNameList = parseNameCsv(data.getWorkshopLeaderName()); @@ -1365,9 +1371,9 @@ public class ErfExpApplyServiceImpl extends ServiceImpl roles = sysUserDao.getUserRolesByRoleNames( - workshopLeaderId, List.of("生产车间负责人")); + workshopLeaderId, List.of(ROLE_WORKSHOP_LEADER)); if (roles == null || roles.isEmpty()) { - throw new XJException("生产车间负责人必须是【生产车间负责人】角色用户"); + throw new XJException("生产车间负责人必须是【" + ROLE_WORKSHOP_LEADER + "】角色用户"); } String workshopDisplay = sysUserDao.getUserDisplayById(workshopLeaderId); @@ -1386,6 +1392,52 @@ public class ErfExpApplyServiceImpl extends ServiceImpl qcWorkshopLeaderIds = parseUserIdCsv(data.getQcWorkshopLeaderUserId(), "QC车间负责人", true); + if (qcWorkshopLeaderIds.isEmpty()) { + data.setQcWorkshopLeaderUserId(""); + data.setQcWorkshopLeaderName(""); + return; + } + + List inputNameList = parseNameCsv(data.getQcWorkshopLeaderName()); + List resolvedNameList = new ArrayList<>(); + + for (int i = 0; i < qcWorkshopLeaderIds.size(); i++) { + Long qcWorkshopLeaderId = qcWorkshopLeaderIds.get(i); + List roles = sysUserDao.getUserRolesByRoleNames( + qcWorkshopLeaderId, List.of(ROLE_QC_WORKSHOP_LEADER)); + if (roles == null || roles.isEmpty()) { + throw new XJException("QC车间负责人必须是【" + ROLE_QC_WORKSHOP_LEADER + "】角色用户"); + } + + String qcWorkshopDisplay = sysUserDao.getUserDisplayById(qcWorkshopLeaderId); + if (StringUtils.isBlank(qcWorkshopDisplay) && i < inputNameList.size()) { + qcWorkshopDisplay = inputNameList.get(i); + } + if (StringUtils.isBlank(qcWorkshopDisplay)) { + qcWorkshopDisplay = String.valueOf(qcWorkshopLeaderId); + } + resolvedNameList.add(qcWorkshopDisplay); + } + + data.setQcWorkshopLeaderUserId(qcWorkshopLeaderIds.stream() + .map(String::valueOf) + .collect(Collectors.joining(","))); + data.setQcWorkshopLeaderName(String.join(",", resolvedNameList)); + } + /** * 解析逗号分隔用户ID串 */ @@ -2782,6 +2834,74 @@ public class ErfExpApplyServiceImpl extends ServiceImpl qcWorkshopLeaderList = resolveQcWorkshopLeaderEmailInfos(entity); + if (qcWorkshopLeaderList.isEmpty()) { + log.info("未维护QC车间负责人或无法解析邮箱,跳过审批通过通知: applyNo={}", entity.getApplyNo()); + return; + } + + MailSendAddressData mailSendData = qcMapper.getSendMailFromAddress(); + if (mailSendData == null) { + log.error("邮件发送配置未设置,无法发送QC车间负责人审批通过通知"); + return; + } + + String todayStr = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()); + String expectedFinishDateStr = entity.getExpectedFinishDate() != null + ? DateTimeFormatter.ofPattern("yyyy-MM-dd") + .format(entity.getExpectedFinishDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()) + : todayStr; + + String subject = String.format("【工程试验申请审批通过】%s - %s", + entity.getApplyNo(), entity.getTitle() != null ? entity.getTitle() : ""); + String tableBody = buildPlannerNotificationTable(entity, todayStr, expectedFinishDateStr); + List attachments = collectErfApplyMailAttachments(entity.getApplyNo()); + + List successEmailList = new ArrayList<>(); + for (UserEmailInfoDto qcWorkshopLeader : qcWorkshopLeaderList) { + String email = qcWorkshopLeader.getEmail(); + if (StringUtils.isBlank(email)) { + log.warn("QC车间负责人 {} 未配置邮箱,跳过审批通过通知", qcWorkshopLeader.getUsername()); + continue; + } + + String displayName = StringUtils.isNotBlank(qcWorkshopLeader.getUsername()) + ? qcWorkshopLeader.getUsername() + : String.valueOf(qcWorkshopLeader.getUserId()); + + String body = "" + + "

尊敬的 " + displayName + ":

" + + "

您好!以下工程试验单的三类经理审批已全部完成,您作为QC车间负责人请知悉并关注后续排产执行。

" + + "

当前流程已进入计划员排产环节。

" + + "
" + tableBody + + "

发送时间:" + + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + + "

"; + + MailUtil.sendMail(subject, body, new String[]{email}, mailSendData, attachments); + successEmailList.add(email); + log.info("已向QC车间负责人 {} ({}) 发送审批通过通知,试验单: {}", + displayName, email, entity.getApplyNo()); + } + + if (!successEmailList.isEmpty()) { + SendMailRecord mailRecord = new SendMailRecord(); + mailRecord.setType("工程试验申请QC车间负责人审批通过通知"); + mailRecord.setDocumentNo(entity.getApplyNo()); + mailRecord.setRecipient(String.join(";", successEmailList)); + mailRecord.setSendDate(new Date()); + qcMapper.saveSendMailRecord(mailRecord); + } + } catch (Exception e) { + log.error("发送QC车间负责人审批通过邮件失败,试验单: {}, 错误: {}", entity.getApplyNo(), e.getMessage(), e); + } + } + /** * 查询并构建工程试验单附件(sys_oss: order_ref1=ERF, order_ref2=applyNo, order_ref6=EXP_APPLY) */ @@ -2935,6 +3055,48 @@ public class ErfExpApplyServiceImpl extends ServiceImpl resolveQcWorkshopLeaderEmailInfos(ErfExpApply entity) { + if (entity == null) { + return Collections.emptyList(); + } + + List qcWorkshopLeaderList = new ArrayList<>(); + Set userIdSet = new LinkedHashSet<>(); + + List qcWorkshopLeaderIds = parseUserIdCsv(entity.getQcWorkshopLeaderUserId(), "QC车间负责人", false); + for (Long qcWorkshopLeaderId : qcWorkshopLeaderIds) { + UserEmailInfoDto qcWorkshopLeader = sysUserDao.getUserEmailInfoById(qcWorkshopLeaderId); + if (qcWorkshopLeader != null && userIdSet.add(qcWorkshopLeader.getUserId())) { + qcWorkshopLeaderList.add(qcWorkshopLeader); + } + } + + for (String qcWorkshopLeaderName : parseNameCsv(entity.getQcWorkshopLeaderName())) { + SysUserEntity userByName = sysUserDao.queryByUserName(qcWorkshopLeaderName); + if (userByName == null) { + userByName = getFirstUserByDisplay(qcWorkshopLeaderName); + } + if (userByName == null || !userIdSet.add(userByName.getUserId())) { + continue; + } + + UserEmailInfoDto qcWorkshopLeader = sysUserDao.getUserEmailInfoById(userByName.getUserId()); + if (qcWorkshopLeader != null) { + qcWorkshopLeaderList.add(qcWorkshopLeader); + } + } + + if (qcWorkshopLeaderList.isEmpty() && StringUtils.isNotBlank(entity.getQcWorkshopLeaderUserId())) { + log.warn("QC车间负责人字段无法解析有效用户,applyNo={}, qcWorkshopLeaderUserId={}, qcWorkshopLeaderName={}", + entity.getApplyNo(), entity.getQcWorkshopLeaderUserId(), entity.getQcWorkshopLeaderName()); + } + + return qcWorkshopLeaderList; + } + /** * 按显示名查询首个用户(按user_id升序),避免使用OFFSET语法 */ diff --git a/src/main/resources/mapper/erf/ErfExpApplyMapper.xml b/src/main/resources/mapper/erf/ErfExpApplyMapper.xml index 86b757c7..5d96ef66 100644 --- a/src/main/resources/mapper/erf/ErfExpApplyMapper.xml +++ b/src/main/resources/mapper/erf/ErfExpApplyMapper.xml @@ -23,6 +23,8 @@ + + @@ -65,6 +67,8 @@ pjm_leader_name, workshop_leader_user_id, workshop_leader_name, + qc_workshop_leader_user_id, + qc_workshop_leader_name, contact_method, process_requirement, actual_finish_date, @@ -155,6 +159,8 @@ pjm_leader_name, workshop_leader_user_id, workshop_leader_name, + qc_workshop_leader_user_id, + qc_workshop_leader_name, contact_method, process_requirement, actual_finish_date, @@ -198,6 +204,8 @@ a.pjm_leader_name, a.workshop_leader_user_id, a.workshop_leader_name, + a.qc_workshop_leader_user_id, + a.qc_workshop_leader_name, a.contact_method, a.process_requirement, a.actual_finish_date,