package jnpf.limsService.impl; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.exception.DataException; import jnpf.limsEntity.LimsQingyandanEntity; import jnpf.limsEntity.LimsQingyandanYichangShenqingEntity; import jnpf.limsEntity.LimsQingyandanYichangShenqingZiduanEntity; import jnpf.limsMapper.LimsQingyandanMapper; import jnpf.limsMapper.LimsQingyandanYichangShenqingMapper; import jnpf.limsMapper.LimsQingyandanYichangShenqingZiduanMapper; import jnpf.limsService.LimsQingyandanYichangService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; /** * 请验单异常申请处理服务实现。 */ @Service public class LimsQingyandanYichangServiceImpl implements LimsQingyandanYichangService { private static final String[] DATE_PATTERNS = { "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd" }; private static final Set IMMUTABLE_COLUMNS; private static final Map QINGYANDAN_FIELDS; static { Set immutableColumns = new HashSet<>(); Collections.addAll(immutableColumns, "f_id", "f_tenant_id", "f_flow_id", "f_flow_task_id", "f_flow_state", "f_version", "f_delete_mark", "f_delete_time", "f_delete_user_id", "f_creator_user_id", "f_creator_time", "f_last_modify_user_id", "f_last_modify_time"); IMMUTABLE_COLUMNS = Collections.unmodifiableSet(immutableColumns); QINGYANDAN_FIELDS = buildQingyandanFields(); } @Autowired private LimsQingyandanYichangShenqingMapper shenqingMapper; @Autowired private LimsQingyandanYichangShenqingZiduanMapper ziduanMapper; @Autowired private LimsQingyandanMapper qingyandanMapper; /** * 查询异常申请及其变更字段,并在同一事务中更新关联请验单。 */ @Override @Transactional(rollbackFor = Exception.class) @AuditLog(action = "UPDATE", label = "处理请验单异常申请", bizType = "QINGYANDAN", bizCodeExpr = "#result > 0 ? #flowId : ''", targetTable = "lims_qingyandan", targetIdExpr = "T(jnpf.limsService.support.LimsAuditTargetIds).qingyandanByExceptionFlow(#flowId, #flowTaskId)", diff = true, entityClass = LimsQingyandanEntity.class) public int chuli(String flowId, String flowTaskId) { String resolvedFlowId = requireText(flowId, "流程ID(flow_id)不能为空"); String resolvedFlowTaskId = requireText(flowTaskId, "流程任务ID(flow_task_id)不能为空"); LimsQingyandanYichangShenqingEntity shenqing = getShenqing( resolvedFlowId, resolvedFlowTaskId); if (!StringUtils.hasText(shenqing.getQingyandanId())) { throw new DataException("异常申请未关联请验单"); } LambdaQueryWrapper ziduanQuery = new LambdaQueryWrapper<>(); ziduanQuery.eq(LimsQingyandanYichangShenqingZiduanEntity::getForeignId, shenqing.getId()); List ziduanList = ziduanMapper.selectList(ziduanQuery); if (ziduanList.isEmpty()) { throw new DataException("异常申请没有需要变更的字段"); } Map changes = resolveChanges(ziduanList); UpdateWrapper update = new UpdateWrapper<>(); update.eq("f_id", shenqing.getQingyandanId().trim()); changes.forEach(update::set); int updated = qingyandanMapper.update(null, update); if (updated != 1) { throw new DataException(updated == 0 ? "关联的请验单不存在" : "关联到多条请验单,已取消更新"); } return changes.size(); } private LimsQingyandanYichangShenqingEntity getShenqing(String flowId, String flowTaskId) { LambdaQueryWrapper query = new LambdaQueryWrapper<>(); query.eq(LimsQingyandanYichangShenqingEntity::getFlowId, flowId) .eq(LimsQingyandanYichangShenqingEntity::getFlowTaskId, flowTaskId); List rows = shenqingMapper.selectList(query); if (rows.isEmpty()) { throw new DataException("未找到对应的请验单异常申请"); } if (rows.size() > 1) { throw new DataException("同一流程任务关联了多条请验单异常申请"); } return rows.get(0); } private Map resolveChanges( List ziduanList) { Map changes = new LinkedHashMap<>(); for (int i = 0; i < ziduanList.size(); i++) { LimsQingyandanYichangShenqingZiduanEntity ziduan = ziduanList.get(i); if (ziduan == null || !StringUtils.hasText(ziduan.getKebianZiduan())) { throw new DataException("第" + (i + 1) + "条变更的可变字段不能为空"); } String requestedField = normalize(ziduan.getKebianZiduan()); QingyandanField field = QINGYANDAN_FIELDS.get(requestedField); if (field == null) { throw new DataException("不支持变更请验单字段:" + ziduan.getKebianZiduan()); } Object value = convertValue(ziduan.getBiangenghouShuju(), field, i); changes.put(field.column, value); } return changes; } private Object convertValue(String value, QingyandanField field, int index) { if (field.type == String.class) { return value; } if (!StringUtils.hasText(value)) { return null; } String trimmed = value.trim(); try { if (field.type == Integer.class || field.type == int.class) { return Integer.valueOf(trimmed); } if (field.type == Long.class || field.type == long.class) { return Long.valueOf(trimmed); } if (field.type == BigDecimal.class) { return new BigDecimal(trimmed); } if (field.type == Date.class) { return parseDate(trimmed); } } catch (IllegalArgumentException | ParseException e) { throw new DataException("第" + (index + 1) + "条变更字段[" + field.column + "]的值格式不正确:" + value); } throw new DataException("不支持字段[" + field.column + "]的数据类型:" + field.type.getSimpleName()); } private Date parseDate(String value) throws ParseException { if (value.matches("^-?\\d+$")) { return new Date(Long.parseLong(value)); } for (String pattern : DATE_PATTERNS) { SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.ROOT); format.setLenient(false); try { return format.parse(value); } catch (ParseException ignored) { // Continue with the next supported format. } } throw new ParseException(value, 0); } private static Map buildQingyandanFields() { Map fields = new HashMap<>(); for (Field javaField : LimsQingyandanEntity.class.getDeclaredFields()) { TableField tableField = javaField.getAnnotation(TableField.class); if (tableField == null || !tableField.exist() || !StringUtils.hasText(tableField.value())) { continue; } String column = normalize(tableField.value()); if (IMMUTABLE_COLUMNS.contains(column)) { continue; } QingyandanField metadata = new QingyandanField(column, javaField.getType()); fields.put(column, metadata); fields.put(normalize(javaField.getName()), metadata); } return Collections.unmodifiableMap(fields); } private static String requireText(String value, String message) { if (!StringUtils.hasText(value)) { throw new DataException(message); } return value.trim(); } private static String normalize(String value) { return value == null ? "" : value.trim().toLowerCase(Locale.ROOT); } private static final class QingyandanField { private final String column; private final Class type; private QingyandanField(String column, Class type) { this.column = column; this.type = type; } } }