package jnpf.elnService.formula.impl;
|
|
import cn.dev33.satoken.stp.StpUtil;
|
import cn.hutool.core.util.IdUtil;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import jnpf.audit.model.AuditEventDTO;
|
import jnpf.audit.sdk.AuditClient;
|
import jnpf.base.UserInfo;
|
import jnpf.database.util.TenantDataSourceUtil;
|
import jnpf.elnEntity.formula.ElnFormulaDefEntity;
|
import jnpf.elnEntity.formula.ElnFormulaForms;
|
import jnpf.elnEntity.formula.ElnFormulaParameterSlotEntity;
|
import jnpf.elnEntity.formula.ElnFormulaVersionEntity;
|
import jnpf.elnEntity.formula.ElnFormulaVos;
|
import jnpf.elnEntity.formula.ElnTemplateFormulaBindingEntity;
|
import jnpf.elnEntity.template.ElnTemplateVersionEntity;
|
import jnpf.elnFormula.FormulaParser;
|
import jnpf.elnFormula.FormulaType;
|
import jnpf.elnMapper.ElnFormulaDefMapper;
|
import jnpf.elnMapper.ElnFormulaParameterSlotMapper;
|
import jnpf.elnMapper.ElnFormulaVersionMapper;
|
import jnpf.elnMapper.ElnTemplateMapper;
|
import jnpf.elnMapper.ElnTemplateFormulaBindingMapper;
|
import jnpf.elnService.formula.ElnFormulaAvailability;
|
import jnpf.elnService.formula.ElnFormulaCatalogService;
|
import jnpf.elnService.formula.FormulaValidationService;
|
import jnpf.elnService.impl.ElnFieldCodeGenerator;
|
import jnpf.exception.DataException;
|
import jnpf.model.tenant.TenantVO;
|
import jnpf.util.JsonUtil;
|
import jnpf.util.UserProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.dao.DuplicateKeyException;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.Comparator;
|
import java.util.Date;
|
import java.util.HashSet;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.function.BooleanSupplier;
|
import java.util.function.Consumer;
|
import java.util.function.Supplier;
|
|
@Service
|
@Transactional(rollbackFor = Exception.class)
|
public class ElnFormulaCatalogServiceImpl
|
implements ElnFormulaCatalogService, ElnFormulaAvailability {
|
|
private static final String MENU_PERMISSION = "dianziJiluGongshiGuanli";
|
private static final String ENABLED = "enabled";
|
private static final String DISABLED = "disabled";
|
private static final String DRAFT = "DRAFT";
|
private static final String PRE_RELEASE = "PRE_RELEASE";
|
private static final String PUBLISHED = "PUBLISHED";
|
private static final String CANCELLED = "CANCELLED";
|
private static final String ACTIVE = "ACTIVE";
|
private static final String PENDING = "PENDING";
|
private static final int CODE_RETRY_LIMIT = 3;
|
|
private final FormulaCatalogStore store;
|
private final FormulaValidationService validationService;
|
private final DraftTemplateReferenceChecker referenceChecker;
|
private final Supplier<UserContext> userContextSupplier;
|
private final Supplier<String> idSupplier;
|
private final ElnFieldCodeGenerator codeGenerator;
|
private final Consumer<AuditEventDTO> auditRecorder;
|
private final BooleanSupplier maintainPermission;
|
|
@Autowired
|
public ElnFormulaCatalogServiceImpl(ElnFormulaDefMapper definitionMapper,
|
ElnFormulaVersionMapper versionMapper,
|
ElnFormulaParameterSlotMapper slotMapper,
|
ElnTemplateMapper templateMapper,
|
ElnTemplateFormulaBindingMapper templateFormulaBindingMapper,
|
FormulaValidationService validationService,
|
ObjectProvider<AuditClient> auditClientProvider,
|
ObjectProvider<DraftTemplateReferenceChecker> checkerProvider) {
|
this(new MyBatisFormulaCatalogStore(definitionMapper, versionMapper, slotMapper,
|
templateMapper, templateFormulaBindingMapper),
|
validationService, checker(checkerProvider),
|
ElnFormulaCatalogServiceImpl::currentUserContext,
|
IdUtil::getSnowflakeNextIdStr,
|
new ElnFieldCodeGenerator(() -> IdUtil.fastSimpleUUID().substring(0, 8), 8),
|
event -> {
|
AuditClient client = auditClientProvider.getIfAvailable();
|
if (client != null) {
|
client.record(event);
|
}
|
}, ElnFormulaCatalogServiceImpl::hasMaintainPermission);
|
}
|
|
ElnFormulaCatalogServiceImpl(FormulaCatalogStore store,
|
FormulaValidationService validationService,
|
DraftTemplateReferenceChecker referenceChecker,
|
Supplier<UserContext> userContextSupplier,
|
Supplier<String> idSupplier,
|
ElnFieldCodeGenerator codeGenerator,
|
Consumer<AuditEventDTO> auditRecorder,
|
BooleanSupplier maintainPermission) {
|
this.store = store;
|
this.validationService = validationService;
|
this.referenceChecker = resolveChecker(referenceChecker);
|
this.userContextSupplier = userContextSupplier;
|
this.idSupplier = idSupplier;
|
this.codeGenerator = codeGenerator;
|
this.auditRecorder = auditRecorder;
|
this.maintainPermission = maintainPermission;
|
}
|
|
@Override
|
public ElnFormulaVos.Detail create(ElnFormulaForms.Create form) {
|
UserContext context = requireCatalogAccess();
|
validateDefinition(form == null ? null : form.getGongshiMingcheng(),
|
form == null ? null : form.getYewuYongtu(), form == null ? null : form.getBeizhu());
|
validateVersionRules(form);
|
|
ElnFormulaDefEntity definition = insertDefinition(context, form);
|
audit("ELN_FORMULA_CREATE", "eln_formula_def", definition.getId(), context,
|
null, definition, null);
|
|
ElnFormulaVersionEntity version = newVersion(context, definition.getId(), 1);
|
applyVersion(version, form);
|
store.insertVersion(version);
|
List<ElnFormulaParameterSlotEntity> slots = replaceDraftSlots(
|
context, version, Collections.emptyList(), form.getParameters());
|
audit("ELN_FORMULA_VERSION_CREATE", "eln_formula_version", version.getId(), context,
|
null, versionSnapshot(version, slots), null);
|
return toDetail(definition, Collections.singletonList(version));
|
}
|
|
@Override
|
public ElnFormulaVos.Detail createDraft(ElnFormulaForms.CreateDraft form) {
|
UserContext context = requireCatalogAccess();
|
validateDefinition(form == null ? null : form.getGongshiMingcheng(),
|
form == null ? null : form.getYewuYongtu(), form == null ? null : form.getBeizhu());
|
List<ElnFormulaForms.Parameter> parameters = form == null ? null : form.getParameters();
|
if (parameters != null) {
|
for (ElnFormulaForms.Parameter parameter : parameters) {
|
validateParameter(parameter);
|
}
|
}
|
|
ElnFormulaForms.Create definitionForm = new ElnFormulaForms.Create();
|
definitionForm.setGongshiMingcheng(form.getGongshiMingcheng());
|
definitionForm.setYewuYongtu(form.getYewuYongtu());
|
definitionForm.setBeizhu(form.getBeizhu());
|
ElnFormulaDefEntity definition = insertDefinition(context, definitionForm);
|
audit("ELN_FORMULA_CREATE", "eln_formula_def", definition.getId(), context,
|
null, definition, null);
|
|
ElnFormulaVersionEntity version = newVersion(context, definition.getId(), 1);
|
version.setBiaodashi("");
|
version.setJieguoLeixing(FormulaType.DECIMAL.name());
|
version.setXiuyueXiaoshuWei(null);
|
version.setXiuyueMoshi(null);
|
store.insertVersion(version);
|
List<ElnFormulaParameterSlotEntity> slots = replaceDraftSlots(
|
context, version, Collections.emptyList(), parameters);
|
audit("ELN_FORMULA_VERSION_CREATE", "eln_formula_version", version.getId(), context,
|
null, versionSnapshot(version, slots), null);
|
return toDetail(definition, Collections.singletonList(version));
|
}
|
|
@Override
|
public ElnFormulaVos.Detail updateDefinition(String formulaId,
|
ElnFormulaForms.UpdateDefinition form) {
|
UserContext context = requireCatalogAccess();
|
validateDefinition(form == null ? null : form.getGongshiMingcheng(),
|
form == null ? null : form.getYewuYongtu(), form == null ? null : form.getBeizhu());
|
ElnFormulaDefEntity definition = requireDefinition(context.getTenantId(), formulaId, true);
|
ElnFormulaDefEntity before = copyDefinition(definition);
|
definition.setGongshiMingcheng(form.getGongshiMingcheng().trim());
|
definition.setYewuYongtu(trimToNull(form.getYewuYongtu()));
|
definition.setBeizhu(trimToNull(form.getBeizhu()));
|
definition.setFLastModifyUserId(context.getUserId());
|
definition.setFLastModifyTime(new Date());
|
store.updateDefinition(definition);
|
audit("ELN_FORMULA_UPDATE", "eln_formula_def", definition.getId(), context,
|
before, definition, null);
|
return toDetail(definition, store.listVersions(context.getTenantId(), definition.getId()));
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public IPage<ElnFormulaVos.ListItem> page(ElnFormulaForms.Query query) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaForms.Query actual = query == null ? new ElnFormulaForms.Query() : query;
|
if (actual.getCurrentPage() < 1 || actual.getPageSize() < 1) {
|
throw new DataException("分页参数必须大于 0");
|
}
|
IPage<ElnFormulaDefEntity> source = store.page(context.getTenantId(), actual);
|
Set<String> definitionIds = ids(source.getRecords());
|
Map<String, Integer> referenceCounts = referenceCounts(
|
store.listLiveTemplateFormulaBindings(context.getTenantId(), definitionIds));
|
Map<String, List<ElnFormulaVersionEntity>> versionsByDefinition = new LinkedHashMap<>();
|
for (ElnFormulaVersionEntity version : store.listVersionsByDefinitionIds(
|
context.getTenantId(), definitionIds)) {
|
versionsByDefinition.computeIfAbsent(version.getGongshiDingyiId(),
|
key -> new ArrayList<>()).add(version);
|
}
|
List<ElnFormulaVos.ListItem> records = new ArrayList<>();
|
for (ElnFormulaDefEntity definition : source.getRecords()) {
|
ElnFormulaVos.ListItem item = toListItem(definition,
|
versionsByDefinition.getOrDefault(definition.getId(), Collections.emptyList()));
|
item.setMubanYinyongShu(referenceCounts.getOrDefault(definition.getId(), 0));
|
records.add(item);
|
}
|
return new Page<ElnFormulaVos.ListItem>(source.getCurrent(), source.getSize(), source.getTotal())
|
.setRecords(records);
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public ElnFormulaVos.Detail detail(String formulaId) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaDefEntity definition = requireDefinition(context.getTenantId(), formulaId, false);
|
return toDetail(definition, store.listVersions(context.getTenantId(), definition.getId()));
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public IPage<ElnFormulaVos.ReferenceSummary> pageTemplateReferences(
|
String formulaId, ElnFormulaForms.ReferenceQuery query) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaDefEntity definition = requireDefinition(
|
context.getTenantId(), formulaId, false);
|
ElnFormulaForms.ReferenceQuery actual = query == null
|
? new ElnFormulaForms.ReferenceQuery() : query;
|
if (actual.getCurrentPage() < 1 || actual.getPageSize() < 1) {
|
throw new DataException("分页参数必须大于 0");
|
}
|
actual.setKeyword(trimToNull(actual.getKeyword()));
|
return pageReferenceSummaries(context.getTenantId(), definition.getId(), actual);
|
}
|
|
@Override
|
@Transactional(readOnly = true)
|
public boolean isEnabled(String tenantId, String formulaId) {
|
if (!StringUtils.hasText(tenantId) || !StringUtils.hasText(formulaId)) {
|
return false;
|
}
|
ElnFormulaDefEntity definition = store.findDefinition(
|
tenantId.trim(), formulaId.trim(), false);
|
return definition != null && ENABLED.equals(definition.getBizEnabled());
|
}
|
|
@Override
|
public ElnFormulaVos.Version createVersion(String formulaId,
|
ElnFormulaForms.CreateVersion form) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaDefEntity definition = requireDefinition(context.getTenantId(), formulaId, true);
|
requireEnabled(definition);
|
if (form == null || !StringUtils.hasText(form.getSourceVersionId())) {
|
throw new DataException("复制版本必须指定来源版本");
|
}
|
ElnFormulaVersionEntity source = requireVersion(
|
context.getTenantId(), form.getSourceVersionId(), false);
|
requireSameDefinition(definition, source);
|
if (!PRE_RELEASE.equals(source.getBizStatus()) && !PUBLISHED.equals(source.getBizStatus())) {
|
throw new DataException("只能基于预发布或已发布版本创建新版本");
|
}
|
ElnFormulaVersionEntity created = newVersion(context, definition.getId(),
|
nextVersionNumber(context.getTenantId(), definition.getId()));
|
copyVersionRules(source, created);
|
store.insertVersion(created);
|
List<ElnFormulaParameterSlotEntity> copied = new ArrayList<>();
|
for (ElnFormulaParameterSlotEntity sourceSlot
|
: store.listSlots(context.getTenantId(), source.getId())) {
|
ElnFormulaParameterSlotEntity slot = newSlot(context, created.getId());
|
slot.setCanshuBianma(sourceSlot.getCanshuBianma());
|
copySlotRules(sourceSlot, slot);
|
store.insertSlot(slot);
|
copied.add(slot);
|
}
|
audit("ELN_FORMULA_VERSION_CREATE", "eln_formula_version", created.getId(), context,
|
null, versionSnapshot(created, copied), null);
|
return toVersion(created, copied);
|
}
|
|
@Override
|
public ElnFormulaVos.Version updateDraft(String versionId,
|
ElnFormulaForms.UpdateVersion form) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaVersionEntity version = requireVersion(context.getTenantId(), versionId, true);
|
if (!DRAFT.equals(version.getBizStatus())) {
|
throw new DataException("只有草稿版本可以修改");
|
}
|
ElnFormulaDefEntity definition = requireDefinition(
|
context.getTenantId(), version.getGongshiDingyiId(), true);
|
requireEnabled(definition);
|
validateVersionRules(form);
|
List<ElnFormulaParameterSlotEntity> beforeSlots = store.listSlots(
|
context.getTenantId(), version.getId());
|
Object before = versionSnapshot(copyVersion(version), copySlots(beforeSlots));
|
applyVersion(version, form);
|
version.setFLastModifyUserId(context.getUserId());
|
version.setFLastModifyTime(new Date());
|
store.updateVersion(version);
|
List<ElnFormulaParameterSlotEntity> afterSlots = replaceDraftSlots(
|
context, version, beforeSlots, form.getParameters());
|
audit("ELN_FORMULA_VERSION_UPDATE", "eln_formula_version", version.getId(), context,
|
before, versionSnapshot(version, afterSlots), null);
|
return toVersion(version, afterSlots);
|
}
|
|
@Override
|
public void preRelease(String versionId) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaVersionEntity version = requireVersion(context.getTenantId(), versionId, true);
|
if (!DRAFT.equals(version.getBizStatus())) {
|
throw new DataException("只有草稿版本可以提交预发布");
|
}
|
ElnFormulaDefEntity definition = requireDefinition(
|
context.getTenantId(), version.getGongshiDingyiId(), true);
|
requireEnabled(definition);
|
List<ElnFormulaParameterSlotEntity> slots = store.listSlots(
|
context.getTenantId(), version.getId());
|
validateStoredFormula(version, slots);
|
changeVersionStatus(version, slots, PRE_RELEASE, null, context,
|
"ELN_FORMULA_VERSION_PRE_RELEASE");
|
}
|
|
@Override
|
public void publish(String versionId) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaVersionEntity version = requireVersion(context.getTenantId(), versionId, true);
|
if (!PRE_RELEASE.equals(version.getBizStatus())) {
|
throw new DataException("只有预发布版本可以发布");
|
}
|
ElnFormulaDefEntity definition = requireDefinition(
|
context.getTenantId(), version.getGongshiDingyiId(), true);
|
requireEnabled(definition);
|
List<ElnFormulaParameterSlotEntity> slots = store.listSlots(
|
context.getTenantId(), version.getId());
|
Object before = publishSnapshot(copyDefinition(definition), copyVersion(version), slots);
|
version.setBizStatus(PUBLISHED);
|
version.setFLastModifyUserId(context.getUserId());
|
version.setFLastModifyTime(new Date());
|
store.updateVersion(version);
|
definition.setDangqianGongshiBanbenId(version.getId());
|
definition.setFLastModifyUserId(context.getUserId());
|
definition.setFLastModifyTime(new Date());
|
store.updateDefinition(definition);
|
audit("ELN_FORMULA_VERSION_PUBLISH", "eln_formula_version", version.getId(), context,
|
before, publishSnapshot(definition, version, slots), null);
|
}
|
|
@Override
|
public void cancel(String versionId, String reason) {
|
UserContext context = requireCatalogAccess();
|
String actualReason = requireReason(reason);
|
ElnFormulaVersionEntity version = requireVersion(context.getTenantId(), versionId, true);
|
if (!DRAFT.equals(version.getBizStatus()) && !PRE_RELEASE.equals(version.getBizStatus())) {
|
throw new DataException("只有草稿或预发布版本可以作废");
|
}
|
if (PRE_RELEASE.equals(version.getBizStatus())
|
&& referenceChecker.hasDraftReferences(context.getTenantId(), version.getId())) {
|
throw new DataException("预发布公式版本仍被草稿模板引用,不能作废");
|
}
|
List<ElnFormulaParameterSlotEntity> slots = store.listSlots(
|
context.getTenantId(), version.getId());
|
changeVersionStatus(version, slots, CANCELLED, actualReason, context,
|
"ELN_FORMULA_VERSION_CANCEL");
|
}
|
|
@Override
|
public void switchCurrent(String formulaId, String versionId, String reason) {
|
UserContext context = requireCatalogAccess();
|
String actualReason = requireReason(reason);
|
ElnFormulaDefEntity definition = requireDefinition(context.getTenantId(), formulaId, true);
|
requireEnabled(definition);
|
ElnFormulaVersionEntity version = requireVersion(context.getTenantId(), versionId, false);
|
requireSameDefinition(definition, version);
|
if (!PUBLISHED.equals(version.getBizStatus())) {
|
throw new DataException("当前版本只能切换到已发布版本");
|
}
|
ElnFormulaDefEntity before = copyDefinition(definition);
|
definition.setDangqianGongshiBanbenId(version.getId());
|
definition.setFLastModifyUserId(context.getUserId());
|
definition.setFLastModifyTime(new Date());
|
store.updateDefinition(definition);
|
audit("ELN_FORMULA_SWITCH_CURRENT", "eln_formula_def", definition.getId(), context,
|
before, definition, actualReason);
|
}
|
|
@Override
|
public void enable(String formulaId, String reason) {
|
changeEnabled(formulaId, ENABLED, requireReason(reason), "ELN_FORMULA_ENABLE");
|
}
|
|
@Override
|
public void disable(String formulaId, String reason) {
|
changeEnabled(formulaId, DISABLED, requireReason(reason), "ELN_FORMULA_DISABLE");
|
}
|
|
private ElnFormulaDefEntity insertDefinition(UserContext context, ElnFormulaForms.Create form) {
|
DuplicateKeyException collision = null;
|
for (int attempt = 0; attempt < CODE_RETRY_LIMIT; attempt++) {
|
ElnFormulaDefEntity definition = new ElnFormulaDefEntity();
|
initializeBase(definition, context);
|
definition.setGongshiBianma(codeGenerator.generateSegmented(
|
form.getGongshiMingcheng(), "formula", "f"));
|
definition.setGongshiMingcheng(form.getGongshiMingcheng().trim());
|
definition.setYewuYongtu(trimToNull(form.getYewuYongtu()));
|
definition.setBizEnabled(ENABLED);
|
definition.setBeizhu(trimToNull(form.getBeizhu()));
|
try {
|
store.insertDefinition(definition);
|
return definition;
|
} catch (DuplicateKeyException duplicate) {
|
collision = duplicate;
|
}
|
}
|
throw new DataException(collision == null ? "公式编码生成失败" : "公式编码生成冲突,请重试");
|
}
|
|
private List<ElnFormulaParameterSlotEntity> replaceDraftSlots(
|
UserContext context, ElnFormulaVersionEntity version,
|
List<ElnFormulaParameterSlotEntity> existing,
|
List<ElnFormulaForms.Parameter> requested) {
|
Map<String, ElnFormulaParameterSlotEntity> remaining = new LinkedHashMap<>();
|
for (ElnFormulaParameterSlotEntity slot : existing) {
|
remaining.put(slot.getId(), slot);
|
}
|
List<ElnFormulaParameterSlotEntity> result = new ArrayList<>();
|
List<ElnFormulaForms.Parameter> forms = requested == null
|
? Collections.emptyList() : requested;
|
int index = 0;
|
for (ElnFormulaForms.Parameter form : forms) {
|
validateParameter(form);
|
ElnFormulaParameterSlotEntity slot;
|
if (StringUtils.hasText(form.getId())) {
|
slot = remaining.remove(form.getId().trim());
|
if (slot == null) {
|
throw new DataException("参数槽不属于当前草稿版本");
|
}
|
applySlot(slot, form, index, context);
|
store.updateSlot(slot);
|
} else {
|
slot = insertGeneratedSlot(context, version.getId(), form, index);
|
}
|
result.add(slot);
|
index++;
|
}
|
for (ElnFormulaParameterSlotEntity removed : remaining.values()) {
|
store.deleteSlot(removed);
|
}
|
result.sort(Comparator.comparing(ElnFormulaParameterSlotEntity::getPaixu));
|
return result;
|
}
|
|
private ElnFormulaParameterSlotEntity insertGeneratedSlot(
|
UserContext context, String versionId, ElnFormulaForms.Parameter form, int index) {
|
DuplicateKeyException collision = null;
|
for (int attempt = 0; attempt < CODE_RETRY_LIMIT; attempt++) {
|
ElnFormulaParameterSlotEntity slot = newSlot(context, versionId);
|
slot.setCanshuBianma(codeGenerator.generate(
|
form.getCanshuMingcheng(), "parameter", "p"));
|
if (FormulaParser.isReservedParameterCode(slot.getCanshuBianma())) {
|
continue;
|
}
|
applySlot(slot, form, index, context);
|
try {
|
store.insertSlot(slot);
|
return slot;
|
} catch (DuplicateKeyException duplicate) {
|
collision = duplicate;
|
}
|
}
|
throw new DataException(collision == null ? "参数编码生成失败" : "参数编码生成冲突,请重试");
|
}
|
|
private void validateStoredFormula(ElnFormulaVersionEntity version,
|
List<ElnFormulaParameterSlotEntity> slots) {
|
List<FormulaValidationService.ParameterSlot> parameters = new ArrayList<>();
|
for (ElnFormulaParameterSlotEntity slot : slots) {
|
parameters.add(new FormulaValidationService.ParameterSlot(slot.getCanshuBianma(),
|
slot.getCanshuMingcheng(), formulaType(slot.getShujuLeixing(), "参数类型无效")));
|
}
|
FormulaValidationService.ValidationResult result = validationService.validate(
|
new FormulaValidationService.FormulaValidationRequest(version.getBiaodashi(),
|
parameters, formulaType(version.getJieguoLeixing(), "结果类型无效"),
|
version.getXiuyueXiaoshuWei(), version.getXiuyueMoshi()));
|
if (result.hasErrors()) {
|
throw new DataException("公式校验存在错误,不能提交预发布");
|
}
|
}
|
|
private void changeEnabled(String formulaId, String target, String reason, String action) {
|
UserContext context = requireCatalogAccess();
|
ElnFormulaDefEntity definition = requireDefinition(context.getTenantId(), formulaId, true);
|
if (target.equals(definition.getBizEnabled())) {
|
throw new DataException(ENABLED.equals(target) ? "公式已经启用" : "公式已经停用");
|
}
|
ElnFormulaDefEntity before = copyDefinition(definition);
|
definition.setBizEnabled(target);
|
definition.setFLastModifyUserId(context.getUserId());
|
definition.setFLastModifyTime(new Date());
|
store.updateDefinition(definition);
|
audit(action, "eln_formula_def", definition.getId(), context, before, definition, reason);
|
}
|
|
private void changeVersionStatus(ElnFormulaVersionEntity version,
|
List<ElnFormulaParameterSlotEntity> slots,
|
String status, String reason, UserContext context,
|
String action) {
|
Object before = versionSnapshot(copyVersion(version), copySlots(slots));
|
version.setBizStatus(status);
|
version.setZuofeiYuanyin(reason);
|
version.setFLastModifyUserId(context.getUserId());
|
version.setFLastModifyTime(new Date());
|
store.updateVersion(version);
|
audit(action, "eln_formula_version", version.getId(), context,
|
before, versionSnapshot(version, slots), reason);
|
}
|
|
private static void validateDefinition(String name, String purpose, String remark) {
|
requireText(name, 200, "公式名称不能为空", "公式名称不能超过 200 个字符");
|
maxLength(purpose, 500, "业务用途不能超过 500 个字符");
|
maxLength(remark, 500, "备注不能超过 500 个字符");
|
}
|
|
private static void validateVersionRules(ElnFormulaForms.VersionRule form) {
|
if (form == null) {
|
throw new DataException("公式版本内容不能为空");
|
}
|
requireText(form.getBiaodashi(), 8192, "公式表达式不能为空", "公式表达式不能超过 8192 个字符");
|
FormulaType resultType = formulaType(form.getJieguoLeixing(), "结果类型无效");
|
if (resultType != FormulaType.DECIMAL && resultType != FormulaType.TEXT
|
&& resultType != FormulaType.BOOLEAN) {
|
throw new DataException("结果类型无效");
|
}
|
if ((form.getXiuyueXiaoshuWei() == null) != (form.getXiuyueMoshi() == null)) {
|
throw new DataException("修约位数和模式必须同时提供");
|
}
|
if (form.getXiuyueXiaoshuWei() != null) {
|
if (resultType != FormulaType.DECIMAL || form.getXiuyueXiaoshuWei() < 0
|
|| form.getXiuyueXiaoshuWei() > 12
|
|| !("HALF_UP".equals(form.getXiuyueMoshi())
|
|| "HALF_EVEN".equals(form.getXiuyueMoshi())
|
|| "UP".equals(form.getXiuyueMoshi())
|
|| "DOWN".equals(form.getXiuyueMoshi()))) {
|
throw new DataException("修约配置无效");
|
}
|
}
|
if (form.getParameters() != null) {
|
Set<String> ids = new HashSet<>();
|
for (ElnFormulaForms.Parameter parameter : form.getParameters()) {
|
validateParameter(parameter);
|
if (StringUtils.hasText(parameter.getId()) && !ids.add(parameter.getId().trim())) {
|
throw new DataException("参数槽不能重复提交");
|
}
|
}
|
}
|
}
|
|
private static void validateParameter(ElnFormulaForms.Parameter parameter) {
|
if (parameter == null) {
|
throw new DataException("参数项不能为空");
|
}
|
requireText(parameter.getCanshuMingcheng(), 200,
|
"参数名称不能为空", "参数名称不能超过 200 个字符");
|
FormulaType type = formulaType(parameter.getShujuLeixing(), "参数类型无效");
|
if (type == FormulaType.NULL) {
|
throw new DataException("参数类型无效");
|
}
|
maxLength(parameter.getDanwei(), 50, "参数单位不能超过 50 个字符");
|
if (parameter.getShifouBitian() != null && parameter.getShifouBitian() != 0
|
&& parameter.getShifouBitian() != 1) {
|
throw new DataException("参数必填标志只能为 0 或 1");
|
}
|
}
|
|
private ElnFormulaDefEntity requireDefinition(String tenantId, String id, boolean forUpdate) {
|
if (!StringUtils.hasText(id)) {
|
throw new DataException("公式 id 不能为空");
|
}
|
ElnFormulaDefEntity definition = store.findDefinition(tenantId, id.trim(), forUpdate);
|
if (definition == null) {
|
throw new DataException("公式不存在");
|
}
|
return definition;
|
}
|
|
private ElnFormulaVersionEntity requireVersion(String tenantId, String id, boolean forUpdate) {
|
if (!StringUtils.hasText(id)) {
|
throw new DataException("公式版本 id 不能为空");
|
}
|
ElnFormulaVersionEntity version = store.findVersion(tenantId, id.trim(), forUpdate);
|
if (version == null) {
|
throw new DataException("公式版本不存在");
|
}
|
return version;
|
}
|
|
private UserContext requireCatalogAccess() {
|
UserContext context = userContextSupplier.get();
|
if (context == null || !StringUtils.hasText(context.getTenantId())
|
|| !StringUtils.hasText(context.getUserId())) {
|
throw new DataException("请先登录后再维护公式目录");
|
}
|
if (!maintainPermission.getAsBoolean()) {
|
throw new DataException("没有公式维护权限");
|
}
|
return context;
|
}
|
|
private static void requireEnabled(ElnFormulaDefEntity definition) {
|
if (!ENABLED.equals(definition.getBizEnabled())) {
|
throw new DataException("公式已停用,不能执行该操作");
|
}
|
}
|
|
private static void requireSameDefinition(ElnFormulaDefEntity definition,
|
ElnFormulaVersionEntity version) {
|
if (!definition.getId().equals(version.getGongshiDingyiId())) {
|
throw new DataException("公式版本不属于当前公式");
|
}
|
}
|
|
private int nextVersionNumber(String tenantId, String definitionId) {
|
int max = 0;
|
for (ElnFormulaVersionEntity version : store.listVersions(tenantId, definitionId)) {
|
if (version.getBanbenHao() != null && version.getBanbenHao() > max) {
|
max = version.getBanbenHao();
|
}
|
}
|
return max + 1;
|
}
|
|
private ElnFormulaVersionEntity newVersion(UserContext context, String definitionId,
|
int versionNumber) {
|
ElnFormulaVersionEntity version = new ElnFormulaVersionEntity();
|
initializeBase(version, context);
|
version.setGongshiDingyiId(definitionId);
|
version.setBanbenHao(versionNumber);
|
version.setBizStatus(DRAFT);
|
return version;
|
}
|
|
private ElnFormulaParameterSlotEntity newSlot(UserContext context, String versionId) {
|
ElnFormulaParameterSlotEntity slot = new ElnFormulaParameterSlotEntity();
|
initializeBase(slot, context);
|
slot.setGongshiBanbenId(versionId);
|
return slot;
|
}
|
|
private void initializeBase(Object target, UserContext context) {
|
Date now = new Date();
|
if (target instanceof ElnFormulaDefEntity) {
|
ElnFormulaDefEntity entity = (ElnFormulaDefEntity) target;
|
entity.setId(idSupplier.get());
|
entity.setFTenantId(context.getTenantId());
|
entity.setFVersion(0);
|
entity.setFDeleteMark(0);
|
entity.setFCreatorUserId(context.getUserId());
|
entity.setFLastModifyUserId(context.getUserId());
|
entity.setFCreatorTime(now);
|
entity.setFLastModifyTime(now);
|
} else if (target instanceof ElnFormulaVersionEntity) {
|
ElnFormulaVersionEntity entity = (ElnFormulaVersionEntity) target;
|
entity.setId(idSupplier.get());
|
entity.setFTenantId(context.getTenantId());
|
entity.setFVersion(0);
|
entity.setFDeleteMark(0);
|
entity.setFCreatorUserId(context.getUserId());
|
entity.setFLastModifyUserId(context.getUserId());
|
entity.setFCreatorTime(now);
|
entity.setFLastModifyTime(now);
|
} else {
|
ElnFormulaParameterSlotEntity entity = (ElnFormulaParameterSlotEntity) target;
|
entity.setId(idSupplier.get());
|
entity.setFTenantId(context.getTenantId());
|
entity.setFVersion(0);
|
entity.setFDeleteMark(0);
|
entity.setFCreatorUserId(context.getUserId());
|
entity.setFLastModifyUserId(context.getUserId());
|
entity.setFCreatorTime(now);
|
entity.setFLastModifyTime(now);
|
}
|
}
|
|
private static void applyVersion(ElnFormulaVersionEntity target,
|
ElnFormulaForms.VersionRule source) {
|
target.setBiaodashi(source.getBiaodashi().trim());
|
target.setJieguoLeixing(source.getJieguoLeixing().trim());
|
target.setXiuyueXiaoshuWei(source.getXiuyueXiaoshuWei());
|
target.setXiuyueMoshi(trimToNull(source.getXiuyueMoshi()));
|
}
|
|
private static void copyVersionRules(ElnFormulaVersionEntity source,
|
ElnFormulaVersionEntity target) {
|
target.setBiaodashi(source.getBiaodashi());
|
target.setJieguoLeixing(source.getJieguoLeixing());
|
target.setXiuyueXiaoshuWei(source.getXiuyueXiaoshuWei());
|
target.setXiuyueMoshi(source.getXiuyueMoshi());
|
}
|
|
private static void applySlot(ElnFormulaParameterSlotEntity target,
|
ElnFormulaForms.Parameter source, int index,
|
UserContext context) {
|
target.setCanshuMingcheng(source.getCanshuMingcheng().trim());
|
target.setShujuLeixing(source.getShujuLeixing().trim());
|
target.setDanwei(trimToNull(source.getDanwei()));
|
target.setShifouBitian(source.getShifouBitian() == null ? 1 : source.getShifouBitian());
|
target.setPaixu(source.getPaixu() == null ? index : source.getPaixu());
|
target.setFLastModifyUserId(context.getUserId());
|
target.setFLastModifyTime(new Date());
|
}
|
|
private static void copySlotRules(ElnFormulaParameterSlotEntity source,
|
ElnFormulaParameterSlotEntity target) {
|
target.setCanshuMingcheng(source.getCanshuMingcheng());
|
target.setShujuLeixing(source.getShujuLeixing());
|
target.setDanwei(source.getDanwei());
|
target.setShifouBitian(source.getShifouBitian());
|
target.setPaixu(source.getPaixu());
|
}
|
|
private ElnFormulaVos.Detail toDetail(ElnFormulaDefEntity definition,
|
List<ElnFormulaVersionEntity> versions) {
|
ElnFormulaVos.Detail result = new ElnFormulaVos.Detail();
|
result.setId(definition.getId());
|
result.setGongshiBianma(definition.getGongshiBianma());
|
result.setGongshiMingcheng(definition.getGongshiMingcheng());
|
result.setYewuYongtu(definition.getYewuYongtu());
|
result.setDangqianGongshiBanbenId(definition.getDangqianGongshiBanbenId());
|
result.setBizEnabled(definition.getBizEnabled());
|
result.setBeizhu(definition.getBeizhu());
|
ElnFormulaForms.ReferenceQuery referenceQuery = new ElnFormulaForms.ReferenceQuery();
|
referenceQuery.setPageSize(5);
|
IPage<ElnFormulaVos.ReferenceSummary> references = pageReferenceSummaries(
|
definition.getFTenantId(), definition.getId(), referenceQuery);
|
result.setMubanYinyongShu(Math.toIntExact(references.getTotal()));
|
result.setTemplateReferences(references.getRecords());
|
versions.sort(Comparator.comparing(ElnFormulaVersionEntity::getBanbenHao));
|
for (ElnFormulaVersionEntity version : versions) {
|
result.getVersions().add(toVersion(version,
|
store.listSlots(definition.getFTenantId(), version.getId())));
|
}
|
return result;
|
}
|
|
private IPage<ElnFormulaVos.ReferenceSummary> pageReferenceSummaries(
|
String tenantId, String definitionId, ElnFormulaForms.ReferenceQuery query) {
|
IPage<ElnTemplateFormulaBindingEntity> source =
|
store.pageLiveTemplateFormulaBindings(tenantId, definitionId, query);
|
List<ElnTemplateFormulaBindingEntity> bindings = source.getRecords();
|
if (bindings.isEmpty()) {
|
return new Page<ElnFormulaVos.ReferenceSummary>(
|
source.getCurrent(), source.getSize(), source.getTotal())
|
.setRecords(Collections.emptyList());
|
}
|
Map<String, ElnTemplateVersionEntity> templates = new LinkedHashMap<>();
|
for (ElnTemplateVersionEntity template : store.listTemplates(tenantId, templateIds(bindings))) {
|
templates.put(template.getId(), template);
|
}
|
List<ElnFormulaVos.ReferenceSummary> result = new ArrayList<>();
|
for (ElnTemplateFormulaBindingEntity binding : bindings) {
|
ElnTemplateVersionEntity template = templates.get(binding.getMubanId());
|
ElnFormulaVos.ReferenceSummary summary = new ElnFormulaVos.ReferenceSummary();
|
summary.setBindingId(binding.getId());
|
summary.setTemplateId(binding.getMubanId());
|
summary.setTemplateName(template == null ? null : template.getJianyanXiangmu());
|
summary.setTemplateStatus(template == null ? null : template.getBizStatus());
|
summary.setBindingStatus(binding.getBangdingZhuangtai());
|
summary.setFormulaVersionId(binding.getGongshiBanbenId());
|
result.add(summary);
|
}
|
return new Page<ElnFormulaVos.ReferenceSummary>(
|
source.getCurrent(), source.getSize(), source.getTotal()).setRecords(result);
|
}
|
|
private static Map<String, Integer> referenceCounts(
|
List<ElnTemplateFormulaBindingEntity> bindings) {
|
Map<String, Integer> result = new LinkedHashMap<>();
|
for (ElnTemplateFormulaBindingEntity binding : bindings) {
|
String formulaId = binding.getGongshiDingyiId();
|
result.put(formulaId, result.containsKey(formulaId) ? result.get(formulaId) + 1 : 1);
|
}
|
return result;
|
}
|
|
private static Set<String> ids(List<ElnFormulaDefEntity> definitions) {
|
Set<String> result = new HashSet<>();
|
for (ElnFormulaDefEntity definition : definitions) {
|
result.add(definition.getId());
|
}
|
return result;
|
}
|
|
private static Set<String> templateIds(List<ElnTemplateFormulaBindingEntity> bindings) {
|
Set<String> result = new HashSet<>();
|
for (ElnTemplateFormulaBindingEntity binding : bindings) {
|
if (StringUtils.hasText(binding.getMubanId())) {
|
result.add(binding.getMubanId());
|
}
|
}
|
return result;
|
}
|
|
private ElnFormulaVos.ListItem toListItem(ElnFormulaDefEntity definition,
|
List<ElnFormulaVersionEntity> versions) {
|
ElnFormulaVos.ListItem result = new ElnFormulaVos.ListItem();
|
result.setId(definition.getId());
|
result.setGongshiBianma(definition.getGongshiBianma());
|
result.setGongshiMingcheng(definition.getGongshiMingcheng());
|
result.setYewuYongtu(definition.getYewuYongtu());
|
result.setDangqianGongshiBanbenId(definition.getDangqianGongshiBanbenId());
|
result.setBizEnabled(definition.getBizEnabled());
|
result.setGengxinShijian(definition.getFLastModifyTime());
|
int latestPublished = 0;
|
for (ElnFormulaVersionEntity version : versions) {
|
if (PUBLISHED.equals(version.getBizStatus()) && version.getBanbenHao() != null) {
|
latestPublished = Math.max(latestPublished, version.getBanbenHao());
|
}
|
if (version.getId().equals(definition.getDangqianGongshiBanbenId())) {
|
result.setDangqianBanbenHao(version.getBanbenHao());
|
}
|
}
|
result.setZuixinFabuBanbenHao(latestPublished == 0 ? null : latestPublished);
|
return result;
|
}
|
|
private static ElnFormulaVos.Version toVersion(ElnFormulaVersionEntity source,
|
List<ElnFormulaParameterSlotEntity> slots) {
|
ElnFormulaVos.Version result = new ElnFormulaVos.Version();
|
result.setId(source.getId());
|
result.setGongshiDingyiId(source.getGongshiDingyiId());
|
result.setBanbenHao(source.getBanbenHao());
|
result.setBiaodashi(source.getBiaodashi());
|
result.setJieguoLeixing(source.getJieguoLeixing());
|
result.setXiuyueXiaoshuWei(source.getXiuyueXiaoshuWei());
|
result.setXiuyueMoshi(source.getXiuyueMoshi());
|
result.setBizStatus(source.getBizStatus());
|
result.setZuofeiYuanyin(source.getZuofeiYuanyin());
|
result.setChuangjianShijian(source.getFCreatorTime());
|
result.setGengxinShijian(source.getFLastModifyTime());
|
slots.sort(Comparator.comparing(ElnFormulaParameterSlotEntity::getPaixu));
|
for (ElnFormulaParameterSlotEntity slot : slots) {
|
result.getParameters().add(toParameter(slot));
|
}
|
return result;
|
}
|
|
private static ElnFormulaVos.Parameter toParameter(ElnFormulaParameterSlotEntity source) {
|
ElnFormulaVos.Parameter result = new ElnFormulaVos.Parameter();
|
result.setId(source.getId());
|
result.setGongshiBanbenId(source.getGongshiBanbenId());
|
result.setCanshuBianma(source.getCanshuBianma());
|
result.setCanshuMingcheng(source.getCanshuMingcheng());
|
result.setShujuLeixing(source.getShujuLeixing());
|
result.setDanwei(source.getDanwei());
|
result.setShifouBitian(source.getShifouBitian());
|
result.setPaixu(source.getPaixu());
|
return result;
|
}
|
|
private void audit(String actionCode, String table, String targetId, UserContext context,
|
Object before, Object after, String reason) {
|
Map<String, Object> snapshot = new LinkedHashMap<>();
|
snapshot.put("before", before);
|
snapshot.put("after", after);
|
AuditEventDTO event = AuditEventDTO.builder()
|
.tenantId(context.getTenantId()).operatorId(context.getUserId())
|
.eventTime(new Date()).eventType("DATA_CHANGE")
|
.actionCode(actionCode).actionLabel(actionCode).bizModule("eln")
|
.bizType("eln_formula_def".equals(table) ? "eln_formula" : "eln_formula_version")
|
.targetTable(table).targetId(targetId).reason(reason)
|
.dataSnapshot(JsonUtil.getObjectToString(snapshot)).build();
|
auditRecorder.accept(event);
|
}
|
|
private static Object versionSnapshot(ElnFormulaVersionEntity version,
|
List<ElnFormulaParameterSlotEntity> slots) {
|
Map<String, Object> result = new LinkedHashMap<>();
|
result.put("version", version);
|
result.put("parameters", slots);
|
return result;
|
}
|
|
private static Object publishSnapshot(ElnFormulaDefEntity definition,
|
ElnFormulaVersionEntity version,
|
List<ElnFormulaParameterSlotEntity> slots) {
|
Map<String, Object> result = new LinkedHashMap<>();
|
result.put("definition", definition);
|
result.put("version", version);
|
result.put("parameters", slots);
|
return result;
|
}
|
|
private static ElnFormulaDefEntity copyDefinition(ElnFormulaDefEntity source) {
|
return JsonUtil.getJsonToBean(source, ElnFormulaDefEntity.class);
|
}
|
|
private static ElnFormulaVersionEntity copyVersion(ElnFormulaVersionEntity source) {
|
return JsonUtil.getJsonToBean(source, ElnFormulaVersionEntity.class);
|
}
|
|
private static List<ElnFormulaParameterSlotEntity> copySlots(
|
List<ElnFormulaParameterSlotEntity> source) {
|
List<ElnFormulaParameterSlotEntity> result = new ArrayList<>();
|
for (ElnFormulaParameterSlotEntity slot : source) {
|
result.add(JsonUtil.getJsonToBean(slot, ElnFormulaParameterSlotEntity.class));
|
}
|
return result;
|
}
|
|
private static FormulaType formulaType(String value, String message) {
|
if (!StringUtils.hasText(value)) {
|
throw new DataException(message);
|
}
|
try {
|
return FormulaType.valueOf(value.trim());
|
} catch (IllegalArgumentException exception) {
|
throw new DataException(message);
|
}
|
}
|
|
private static void requireText(String value, int maxLength, String emptyMessage,
|
String lengthMessage) {
|
if (!StringUtils.hasText(value)) {
|
throw new DataException(emptyMessage);
|
}
|
if (value.trim().length() > maxLength) {
|
throw new DataException(lengthMessage);
|
}
|
}
|
|
private static void maxLength(String value, int maxLength, String message) {
|
if (value != null && value.trim().length() > maxLength) {
|
throw new DataException(message);
|
}
|
}
|
|
private static String requireReason(String reason) {
|
if (!StringUtils.hasText(reason)) {
|
throw new DataException("操作原因不能为空");
|
}
|
String value = reason.trim();
|
if (value.length() > 500) {
|
throw new DataException("操作原因不能超过 500 个字符");
|
}
|
return value;
|
}
|
|
private static String trimToNull(String value) {
|
return StringUtils.hasText(value) ? value.trim() : null;
|
}
|
|
private static DraftTemplateReferenceChecker checker(
|
ObjectProvider<DraftTemplateReferenceChecker> provider) {
|
return resolveChecker(provider.getIfAvailable());
|
}
|
|
static DraftTemplateReferenceChecker resolveChecker(
|
DraftTemplateReferenceChecker checker) {
|
if (checker != null) {
|
return checker;
|
}
|
return (tenantId, versionId) -> {
|
throw new DataException("引用检查能力不可用");
|
};
|
}
|
|
static int nextVersionAfterUpdate(int affectedRows, Integer expectedVersion,
|
String conflictMessage) {
|
if (affectedRows != 1 || expectedVersion == null) {
|
throw new DataException(conflictMessage);
|
}
|
return expectedVersion + 1;
|
}
|
|
private static UserContext currentUserContext() {
|
UserInfo user = UserProvider.getUser();
|
String tenantId = null;
|
TenantVO routed = TenantDataSourceUtil.getTenantInfo();
|
if (routed != null && StringUtils.hasText(routed.getEnCode())) {
|
tenantId = routed.getEnCode().trim();
|
} else if (user != null && StringUtils.hasText(user.getTenantId())) {
|
tenantId = user.getTenantId().trim();
|
}
|
if (!StringUtils.hasText(tenantId)) {
|
tenantId = "0";
|
}
|
return new UserContext(tenantId, user == null ? null : trimToNull(user.getUserId()));
|
}
|
|
private static boolean hasMaintainPermission() {
|
UserInfo user = UserProvider.getUser();
|
return user != null && (Boolean.TRUE.equals(user.getIsAdministrator())
|
|| StpUtil.hasPermission(MENU_PERMISSION));
|
}
|
|
@FunctionalInterface
|
public interface DraftTemplateReferenceChecker {
|
boolean hasDraftReferences(String tenantId, String versionId);
|
}
|
|
static final class UserContext {
|
private final String tenantId;
|
private final String userId;
|
|
UserContext(String tenantId, String userId) {
|
this.tenantId = tenantId;
|
this.userId = userId;
|
}
|
|
String getTenantId() {
|
return tenantId;
|
}
|
|
String getUserId() {
|
return userId;
|
}
|
}
|
|
interface FormulaCatalogStore {
|
void insertDefinition(ElnFormulaDefEntity entity);
|
void insertVersion(ElnFormulaVersionEntity entity);
|
void insertSlot(ElnFormulaParameterSlotEntity entity);
|
ElnFormulaDefEntity findDefinition(String tenantId, String id, boolean forUpdate);
|
ElnFormulaVersionEntity findVersion(String tenantId, String id, boolean forUpdate);
|
List<ElnFormulaVersionEntity> listVersions(String tenantId, String definitionId);
|
List<ElnFormulaVersionEntity> listVersionsByDefinitionIds(
|
String tenantId, Collection<String> definitionIds);
|
List<ElnFormulaParameterSlotEntity> listSlots(String tenantId, String versionId);
|
List<ElnTemplateFormulaBindingEntity> listLiveTemplateFormulaBindings(
|
String tenantId, Collection<String> definitionIds);
|
IPage<ElnTemplateFormulaBindingEntity> pageLiveTemplateFormulaBindings(
|
String tenantId, String definitionId, ElnFormulaForms.ReferenceQuery query);
|
List<ElnTemplateVersionEntity> listTemplates(String tenantId, Collection<String> templateIds);
|
IPage<ElnFormulaDefEntity> page(String tenantId, ElnFormulaForms.Query query);
|
void updateDefinition(ElnFormulaDefEntity entity);
|
void updateVersion(ElnFormulaVersionEntity entity);
|
void updateSlot(ElnFormulaParameterSlotEntity entity);
|
void deleteSlot(ElnFormulaParameterSlotEntity entity);
|
}
|
|
private static final class MyBatisFormulaCatalogStore implements FormulaCatalogStore {
|
private final ElnFormulaDefMapper definitionMapper;
|
private final ElnFormulaVersionMapper versionMapper;
|
private final ElnFormulaParameterSlotMapper slotMapper;
|
private final ElnTemplateMapper templateMapper;
|
private final ElnTemplateFormulaBindingMapper templateFormulaBindingMapper;
|
|
private MyBatisFormulaCatalogStore(ElnFormulaDefMapper definitionMapper,
|
ElnFormulaVersionMapper versionMapper,
|
ElnFormulaParameterSlotMapper slotMapper,
|
ElnTemplateMapper templateMapper,
|
ElnTemplateFormulaBindingMapper templateFormulaBindingMapper) {
|
this.definitionMapper = definitionMapper;
|
this.versionMapper = versionMapper;
|
this.slotMapper = slotMapper;
|
this.templateMapper = templateMapper;
|
this.templateFormulaBindingMapper = templateFormulaBindingMapper;
|
}
|
|
@Override
|
public void insertDefinition(ElnFormulaDefEntity entity) {
|
if (definitionMapper.insertIgnoreCode(entity) != 1) {
|
throw new DuplicateKeyException("公式编码已存在");
|
}
|
}
|
|
@Override
|
public void insertVersion(ElnFormulaVersionEntity entity) {
|
versionMapper.insert(entity);
|
}
|
|
@Override
|
public void insertSlot(ElnFormulaParameterSlotEntity entity) {
|
if (slotMapper.insertIgnoreCode(entity) != 1) {
|
throw new DuplicateKeyException("参数编码已存在");
|
}
|
}
|
|
@Override
|
public ElnFormulaDefEntity findDefinition(String tenantId, String id, boolean forUpdate) {
|
LambdaQueryWrapper<ElnFormulaDefEntity> query = Wrappers.<ElnFormulaDefEntity>lambdaQuery()
|
.eq(ElnFormulaDefEntity::getFTenantId, tenantId)
|
.eq(ElnFormulaDefEntity::getId, id)
|
.and(item -> item.isNull(ElnFormulaDefEntity::getFDeleteMark)
|
.or().eq(ElnFormulaDefEntity::getFDeleteMark, 0));
|
if (forUpdate) {
|
query.last("FOR UPDATE");
|
}
|
return definitionMapper.selectOne(query);
|
}
|
|
@Override
|
public ElnFormulaVersionEntity findVersion(String tenantId, String id, boolean forUpdate) {
|
LambdaQueryWrapper<ElnFormulaVersionEntity> query = Wrappers
|
.<ElnFormulaVersionEntity>lambdaQuery()
|
.eq(ElnFormulaVersionEntity::getFTenantId, tenantId)
|
.eq(ElnFormulaVersionEntity::getId, id)
|
.and(item -> item.isNull(ElnFormulaVersionEntity::getFDeleteMark)
|
.or().eq(ElnFormulaVersionEntity::getFDeleteMark, 0));
|
if (forUpdate) {
|
query.last("FOR UPDATE");
|
}
|
return versionMapper.selectOne(query);
|
}
|
|
@Override
|
public List<ElnFormulaVersionEntity> listVersions(String tenantId, String definitionId) {
|
return versionMapper.selectList(Wrappers.<ElnFormulaVersionEntity>lambdaQuery()
|
.eq(ElnFormulaVersionEntity::getFTenantId, tenantId)
|
.eq(ElnFormulaVersionEntity::getGongshiDingyiId, definitionId)
|
.and(item -> item.isNull(ElnFormulaVersionEntity::getFDeleteMark)
|
.or().eq(ElnFormulaVersionEntity::getFDeleteMark, 0))
|
.orderByAsc(ElnFormulaVersionEntity::getBanbenHao));
|
}
|
|
@Override
|
public List<ElnFormulaVersionEntity> listVersionsByDefinitionIds(
|
String tenantId, Collection<String> definitionIds) {
|
if (definitionIds == null || definitionIds.isEmpty()) {
|
return Collections.emptyList();
|
}
|
return versionMapper.selectList(Wrappers.<ElnFormulaVersionEntity>lambdaQuery()
|
.eq(ElnFormulaVersionEntity::getFTenantId, tenantId)
|
.in(ElnFormulaVersionEntity::getGongshiDingyiId, definitionIds)
|
.and(item -> item.isNull(ElnFormulaVersionEntity::getFDeleteMark)
|
.or().eq(ElnFormulaVersionEntity::getFDeleteMark, 0))
|
.orderByAsc(ElnFormulaVersionEntity::getGongshiDingyiId)
|
.orderByAsc(ElnFormulaVersionEntity::getBanbenHao));
|
}
|
|
@Override
|
public List<ElnFormulaParameterSlotEntity> listSlots(String tenantId, String versionId) {
|
return slotMapper.selectList(Wrappers.<ElnFormulaParameterSlotEntity>lambdaQuery()
|
.eq(ElnFormulaParameterSlotEntity::getFTenantId, tenantId)
|
.eq(ElnFormulaParameterSlotEntity::getGongshiBanbenId, versionId)
|
.and(item -> item.isNull(ElnFormulaParameterSlotEntity::getFDeleteMark)
|
.or().eq(ElnFormulaParameterSlotEntity::getFDeleteMark, 0))
|
.orderByAsc(ElnFormulaParameterSlotEntity::getPaixu));
|
}
|
|
@Override
|
public List<ElnTemplateFormulaBindingEntity> listLiveTemplateFormulaBindings(
|
String tenantId, Collection<String> definitionIds) {
|
if (definitionIds == null || definitionIds.isEmpty()) {
|
return Collections.emptyList();
|
}
|
return templateFormulaBindingMapper.selectList(
|
Wrappers.<ElnTemplateFormulaBindingEntity>lambdaQuery()
|
.eq(ElnTemplateFormulaBindingEntity::getFTenantId, tenantId)
|
.in(ElnTemplateFormulaBindingEntity::getGongshiDingyiId, definitionIds)
|
.in(ElnTemplateFormulaBindingEntity::getBangdingZhuangtai,
|
ACTIVE, PENDING)
|
.and(item -> item.isNull(ElnTemplateFormulaBindingEntity::getFDeleteMark)
|
.or().eq(ElnTemplateFormulaBindingEntity::getFDeleteMark, 0)));
|
}
|
|
@Override
|
public IPage<ElnTemplateFormulaBindingEntity> pageLiveTemplateFormulaBindings(
|
String tenantId, String definitionId, ElnFormulaForms.ReferenceQuery form) {
|
LambdaQueryWrapper<ElnTemplateFormulaBindingEntity> query = Wrappers
|
.<ElnTemplateFormulaBindingEntity>lambdaQuery()
|
.eq(ElnTemplateFormulaBindingEntity::getFTenantId, tenantId)
|
.eq(ElnTemplateFormulaBindingEntity::getGongshiDingyiId, definitionId)
|
.in(ElnTemplateFormulaBindingEntity::getBangdingZhuangtai, ACTIVE, PENDING)
|
.and(item -> item.isNull(ElnTemplateFormulaBindingEntity::getFDeleteMark)
|
.or().eq(ElnTemplateFormulaBindingEntity::getFDeleteMark, 0));
|
if (StringUtils.hasText(form.getKeyword())) {
|
String keyword = form.getKeyword().trim();
|
List<ElnTemplateVersionEntity> templates = templateMapper.selectList(
|
Wrappers.<ElnTemplateVersionEntity>lambdaQuery()
|
.eq(ElnTemplateVersionEntity::getFTenantId, tenantId)
|
.like(ElnTemplateVersionEntity::getJianyanXiangmu, keyword)
|
.and(item -> item.isNull(ElnTemplateVersionEntity::getFDeleteMark)
|
.or().eq(ElnTemplateVersionEntity::getFDeleteMark, 0)));
|
Set<String> matchedTemplateIds = new HashSet<>();
|
for (ElnTemplateVersionEntity template : templates) {
|
matchedTemplateIds.add(template.getId());
|
}
|
query.and(item -> {
|
item.like(ElnTemplateFormulaBindingEntity::getMubanId, keyword);
|
if (!matchedTemplateIds.isEmpty()) {
|
item.or().in(ElnTemplateFormulaBindingEntity::getMubanId, matchedTemplateIds);
|
}
|
});
|
}
|
query.orderByAsc(ElnTemplateFormulaBindingEntity::getMubanId)
|
.orderByAsc(ElnTemplateFormulaBindingEntity::getGongshiBanbenId)
|
.orderByAsc(ElnTemplateFormulaBindingEntity::getBangdingZhuangtai)
|
.orderByAsc(ElnTemplateFormulaBindingEntity::getId);
|
return templateFormulaBindingMapper.selectPage(
|
new Page<>(form.getCurrentPage(), form.getPageSize()), query);
|
}
|
|
@Override
|
public List<ElnTemplateVersionEntity> listTemplates(
|
String tenantId, Collection<String> templateIds) {
|
if (templateIds == null || templateIds.isEmpty()) {
|
return Collections.emptyList();
|
}
|
return templateMapper.selectList(Wrappers.<ElnTemplateVersionEntity>lambdaQuery()
|
.eq(ElnTemplateVersionEntity::getFTenantId, tenantId)
|
.in(ElnTemplateVersionEntity::getId, templateIds)
|
.and(item -> item.isNull(ElnTemplateVersionEntity::getFDeleteMark)
|
.or().eq(ElnTemplateVersionEntity::getFDeleteMark, 0)));
|
}
|
|
@Override
|
public IPage<ElnFormulaDefEntity> page(String tenantId, ElnFormulaForms.Query form) {
|
LambdaQueryWrapper<ElnFormulaDefEntity> query = Wrappers.<ElnFormulaDefEntity>lambdaQuery()
|
.eq(ElnFormulaDefEntity::getFTenantId, tenantId)
|
.and(item -> item.isNull(ElnFormulaDefEntity::getFDeleteMark)
|
.or().eq(ElnFormulaDefEntity::getFDeleteMark, 0));
|
if (StringUtils.hasText(form.getBizEnabled())) {
|
query.eq(ElnFormulaDefEntity::getBizEnabled, form.getBizEnabled().trim());
|
}
|
if (StringUtils.hasText(form.getKeyword())) {
|
String keyword = form.getKeyword().trim();
|
query.and(item -> item.like(ElnFormulaDefEntity::getGongshiBianma, keyword)
|
.or().like(ElnFormulaDefEntity::getGongshiMingcheng, keyword)
|
.or().like(ElnFormulaDefEntity::getYewuYongtu, keyword));
|
}
|
query.orderByDesc(ElnFormulaDefEntity::getFLastModifyTime)
|
.orderByDesc(ElnFormulaDefEntity::getFCreatorTime);
|
return definitionMapper.selectPage(
|
new Page<>(form.getCurrentPage(), form.getPageSize()), query);
|
}
|
|
@Override
|
public void updateDefinition(ElnFormulaDefEntity entity) {
|
Integer expectedVersion = entity.getFVersion();
|
int affected = definitionMapper.updateMutableByTenantAndVersion(
|
entity, expectedVersion);
|
entity.setFVersion(nextVersionAfterUpdate(affected, expectedVersion,
|
"公式状态已变化,请刷新后重试"));
|
}
|
|
@Override
|
public void updateVersion(ElnFormulaVersionEntity entity) {
|
Integer expectedVersion = entity.getFVersion();
|
int affected = versionMapper.updateMutableByTenantAndVersion(entity, expectedVersion);
|
entity.setFVersion(nextVersionAfterUpdate(affected, expectedVersion,
|
"公式版本状态已变化,请刷新后重试"));
|
}
|
|
@Override
|
public void updateSlot(ElnFormulaParameterSlotEntity entity) {
|
Integer expectedVersion = entity.getFVersion();
|
int affected = slotMapper.updateMutableByTenantAndVersion(entity, expectedVersion);
|
entity.setFVersion(nextVersionAfterUpdate(affected, expectedVersion,
|
"参数槽状态已变化,请刷新后重试"));
|
}
|
|
@Override
|
public void deleteSlot(ElnFormulaParameterSlotEntity entity) {
|
int count = slotMapper.deleteByTenantAndVersion(entity, entity.getFVersion());
|
if (count != 1) {
|
throw new DataException("参数槽状态已变化,请刷新后重试");
|
}
|
}
|
}
|
}
|