package jnpf.elnService.cross.impl; import cn.hutool.core.util.IdUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import jnpf.elnEntity.field.ElnFieldDefEntity; import jnpf.elnEntity.field.ElnFieldVersionEntity; import jnpf.elnEntity.template.ElnTemplateBindingEntity; import jnpf.elnEntity.template.ElnTemplateCrossReferenceEntity; import jnpf.elnEntity.template.ElnTemplateForms; import jnpf.elnEntity.template.ElnTemplateVersionEntity; import jnpf.elnEntity.template.ElnTemplateVos; import jnpf.elnMapper.ElnFieldDefMapper; import jnpf.elnMapper.ElnFieldVersionMapper; import jnpf.elnMapper.ElnTemplateBindingMapper; import jnpf.elnMapper.ElnTemplateCrossReferenceMapper; import jnpf.elnMapper.ElnTemplateMapper; import jnpf.elnService.cross.ElnCrossTemplateScalarReferencePolicy; import jnpf.elnService.cross.ElnCrossTemplateScalarReferenceService; import jnpf.elnService.template.ElnTemplateBindingService; import jnpf.elnService.template.TemplateAnnotationAuthorization; import jnpf.exception.DataException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @Service public class ElnCrossTemplateScalarReferenceServiceImpl implements ElnCrossTemplateScalarReferenceService { private final ElnTemplateMapper templateMapper; private final ElnTemplateBindingMapper bindingMapper; private final ElnFieldDefMapper fieldMapper; private final ElnFieldVersionMapper versionMapper; private final ElnTemplateCrossReferenceMapper referenceMapper; private final ElnTemplateBindingService bindingService; public ElnCrossTemplateScalarReferenceServiceImpl(ElnTemplateMapper templateMapper, ElnTemplateBindingMapper bindingMapper, ElnFieldDefMapper fieldMapper, ElnFieldVersionMapper versionMapper, ElnTemplateCrossReferenceMapper referenceMapper, ElnTemplateBindingService bindingService) { this.templateMapper = templateMapper; this.bindingMapper = bindingMapper; this.fieldMapper = fieldMapper; this.versionMapper = versionMapper; this.referenceMapper = referenceMapper; this.bindingService = bindingService; } @Override public List sourceTemplates( TemplateAnnotationAuthorization authorization) { String tenantId = authorization.getTenantId(); String targetId = authorization.getTemplateId(); String targetTemplateCode = targetTemplateCode(tenantId, targetId); List result = new ArrayList<>(); List templates = templateMapper.selectList( Wrappers.lambdaQuery().eq(ElnTemplateVersionEntity::getFTenantId, tenantId) .eq(ElnTemplateVersionEntity::getBizStatus, "PUBLISHED") .eq(ElnTemplateVersionEntity::getBizEnabled, "enabled") .and(q -> q.isNull(ElnTemplateVersionEntity::getFDeleteMark) .or().eq(ElnTemplateVersionEntity::getFDeleteMark, 0))); for (ElnTemplateVersionEntity template : templates == null ? Collections.emptyList() : templates) { if (!eligibleSourceTemplate(tenantId, targetId, targetTemplateCode, template, null)) continue; ElnTemplateVos.CrossTemplateSourceTemplate item = new ElnTemplateVos.CrossTemplateSourceTemplate(); item.setSourceTemplateId(template.getId()); item.setSourceTemplateCode(template.getMubanBianhao()); result.add(item); } return result; } @Override public List candidates( TemplateAnnotationAuthorization authorization, String sourceTemplateId) { if (!StringUtils.hasText(sourceTemplateId)) return Collections.emptyList(); String tenantId = authorization.getTenantId(); String targetId = authorization.getTemplateId(); String targetTemplateCode = targetTemplateCode(tenantId, targetId); String actualSourceTemplateId = sourceTemplateId.trim(); ElnTemplateVersionEntity template = templateMapper.selectOne( Wrappers.lambdaQuery() .eq(ElnTemplateVersionEntity::getFTenantId, tenantId) .eq(ElnTemplateVersionEntity::getId, actualSourceTemplateId) .eq(ElnTemplateVersionEntity::getBizStatus, "PUBLISHED") .eq(ElnTemplateVersionEntity::getBizEnabled, "enabled") .and(q -> q.isNull(ElnTemplateVersionEntity::getFDeleteMark) .or().eq(ElnTemplateVersionEntity::getFDeleteMark, 0))); if (!eligibleSourceTemplate(tenantId, targetId, targetTemplateCode, template, actualSourceTemplateId)) { return Collections.emptyList(); } List result = new ArrayList<>(); List bindings = bindingMapper.selectList( Wrappers.lambdaQuery() .eq(ElnTemplateBindingEntity::getFTenantId, tenantId) .eq(ElnTemplateBindingEntity::getMubanId, actualSourceTemplateId) .eq(ElnTemplateBindingEntity::getBangdingZhuangtai, "ACTIVE") .eq(ElnTemplateBindingEntity::getKongjianJuese, "PRIMARY") .and(q -> q.isNull(ElnTemplateBindingEntity::getFDeleteMark) .or().eq(ElnTemplateBindingEntity::getFDeleteMark, 0))); for (ElnTemplateBindingEntity binding : bindings == null ? Collections.emptyList() : bindings) { ElnFieldDefEntity field = fieldMapper.selectById(binding.getZiduanDingyiId()); ElnFieldVersionEntity version = versionMapper.selectById(binding.getZiduanBanbenId()); if (field == null || version == null || !tenantId.equals(binding.getFTenantId()) || !tenantId.equals(field.getFTenantId()) || !tenantId.equals(version.getFTenantId()) || deleted(binding.getFDeleteMark()) || deleted(field.getFDeleteMark()) || deleted(version.getFDeleteMark()) || !"enabled".equals(field.getBizEnabled()) || !binding.getZiduanDingyiId().equals(version.getZiduanDingyiId()) || !ElnCrossTemplateScalarReferencePolicy.isEligible(targetId, template.getId(), template.getBizStatus(), field.getZuoyongFanwei(), version, binding)) continue; ElnTemplateVos.CrossTemplateScalarCandidate item = new ElnTemplateVos.CrossTemplateScalarCandidate(); item.setSourceTemplateId(template.getId()); item.setSourceTemplateCode(template.getMubanBianhao()); item.setSourceFieldId(field.getId()); item.setSourceFieldCode(field.getZiduanBianma()); item.setSourceFieldVersionId(version.getId()); item.setSourceFieldName(version.getZiduanMingcheng()); item.setSourceFieldType(version.getShujuLeixing()); result.add(item); } return result; } private String targetTemplateCode(String tenantId, String targetId) { ElnTemplateVersionEntity target = templateMapper.selectById(targetId); return target != null && tenantId.equals(target.getFTenantId()) ? target.getMubanBianhao() : null; } private static boolean eligibleSourceTemplate(String tenantId, String targetId, String targetTemplateCode, ElnTemplateVersionEntity template, String expectedId) { return template != null && tenantId.equals(template.getFTenantId()) && (expectedId == null || expectedId.equals(template.getId())) && !targetId.equals(template.getId()) && (!StringUtils.hasText(targetTemplateCode) || !targetTemplateCode.equals(template.getMubanBianhao())) && "PUBLISHED".equals(template.getBizStatus()) && "enabled".equals(template.getBizEnabled()) && !deleted(template.getFDeleteMark()) && StringUtils.hasText(template.getMubanBianhao()); } @Override @Transactional(rollbackFor = Exception.class) public ElnTemplateVos.Binding reserve(TemplateAnnotationAuthorization authorization, ElnTemplateForms.ReserveCrossTemplateScalarBinding form) { if (form != null && StringUtils.hasText(form.getCheckboxGroupCode())) { throw new DataException("跨模板只读字段不能加入选择组"); } if (form == null || !StringUtils.hasText(form.getSourceTemplateId()) || !StringUtils.hasText(form.getSourceTemplateCode()) || !StringUtils.hasText(form.getSourceFieldId()) || !StringUtils.hasText(form.getSourceFieldVersionId())) { throw new DataException("跨模板字段来源不能为空"); } ElnTemplateVos.CrossTemplateScalarCandidate selected = null; for (ElnTemplateVos.CrossTemplateScalarCandidate item : candidates(authorization, form.getSourceTemplateId())) { if (form.getSourceTemplateId().trim().equals(item.getSourceTemplateId()) && form.getSourceTemplateCode().trim().equals(item.getSourceTemplateCode()) && form.getSourceFieldId().trim().equals(item.getSourceFieldId()) && form.getSourceFieldVersionId().trim().equals(item.getSourceFieldVersionId())) { selected = item; break; } } if (selected == null) throw new DataException("跨模板文本字段来源无效或已失效"); form.setFieldId(selected.getSourceFieldId()); form.setFieldVersionId(selected.getSourceFieldVersionId()); form.setRepeatRequest(false); ElnTemplateVos.Binding binding = bindingService.reservePrimary(authorization, form); ElnTemplateCrossReferenceEntity existing = referenceMapper.selectOne( Wrappers.lambdaQuery().eq(ElnTemplateCrossReferenceEntity::getFTenantId, authorization.getTenantId()) .eq(ElnTemplateCrossReferenceEntity::getMubanBangdingId, binding.getId())); if (existing != null) { if (!selected.getSourceTemplateCode().equals(existing.getLaiyuanMubanBianhao()) || !selected.getSourceFieldVersionId().equals(existing.getLaiyuanZiduanBanbenId())) { throw new DataException("绑定操作码已用于其他跨模板来源"); } markReadOnly(binding); return binding; } ElnTemplateCrossReferenceEntity reference = new ElnTemplateCrossReferenceEntity(); reference.setId(IdUtil.getSnowflakeNextIdStr()); reference.setMubanBangdingId(binding.getId()); reference.setLaiyuanMubanId(selected.getSourceTemplateId()); reference.setLaiyuanMubanBianhao(selected.getSourceTemplateCode()); reference.setLaiyuanZiduanDingyiId(selected.getSourceFieldId()); reference.setLaiyuanZiduanBanbenId(selected.getSourceFieldVersionId()); reference.setFTenantId(authorization.getTenantId()); reference.setFDeleteMark(0); if (referenceMapper.insert(reference) != 1) throw new DataException("跨模板字段规则保存失败"); markReadOnly(binding); return binding; } @Override public ElnTemplateVos.AnnotationContext decorate( TemplateAnnotationAuthorization authorization, ElnTemplateVos.AnnotationContext context) { if (context == null || context.getBindings() == null || context.getBindings().isEmpty()) { return context; } Set bindingIds = new LinkedHashSet<>(); for (ElnTemplateVos.Binding binding : context.getBindings()) { if (binding != null && StringUtils.hasText(binding.getId())) bindingIds.add(binding.getId()); } if (bindingIds.isEmpty()) return context; List references = referenceMapper.selectList( Wrappers.lambdaQuery() .eq(ElnTemplateCrossReferenceEntity::getFTenantId, authorization.getTenantId()) .in(ElnTemplateCrossReferenceEntity::getMubanBangdingId, bindingIds) .eq(ElnTemplateCrossReferenceEntity::getFDeleteMark, 0)); Set crossBindingIds = new LinkedHashSet<>(); for (ElnTemplateCrossReferenceEntity reference : references == null ? Collections.emptyList() : references) { if (reference != null) crossBindingIds.add(reference.getMubanBangdingId()); } for (ElnTemplateVos.Binding binding : context.getBindings()) { if (binding != null && crossBindingIds.contains(binding.getId())) markReadOnly(binding); } return context; } private static void markReadOnly(ElnTemplateVos.Binding binding) { binding.setValueSource("CROSS_TEMPLATE"); binding.setReadOnly(true); } private static boolean deleted(Integer deleteMark) { return deleteMark != null && deleteMark != 0; } }