package jnpf.dmsService;
|
|
import jnpf.base.entity.VisualdevEntity;
|
import jnpf.flowable.WorkFlowApi;
|
import jnpf.flowable.entity.TemplateJsonEntity;
|
import jnpf.flowable.entity.TemplateNodeEntity;
|
import jnpf.flowable.enums.NodeEnum;
|
import jnpf.flowable.model.templatenode.nodejson.NodeModel;
|
import jnpf.onlinedev.VisualdevOnlineApi;
|
import jnpf.util.JsonUtil;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
|
/** Discovers fields from configured published workflows using the shared display schema. */
|
@org.springframework.stereotype.Service
|
@RequiredArgsConstructor
|
@Slf4j
|
public class DmsQianpiyeCatalogService {
|
|
private final jnpf.dmsService.DmsQianpiyeProperties properties;
|
private final WorkFlowApi workFlowApi;
|
private final VisualdevOnlineApi visualdevOnlineApi;
|
private final DmsQianpiyeDocxPropertiesReader docxPropertiesReader;
|
|
public Map<String, Object> load() {
|
return load(Collections.emptyMap());
|
}
|
|
public Map<String, Object> loadForDocument(String fileType, String fileId, boolean refresh) {
|
Map<String, String> saved = refresh ? Collections.emptyMap() : docxPropertiesReader.read(fileType, fileId);
|
return load(DmsQianpiyeDocxPropertiesReader.hasCompleteFlowVersions(saved) ? saved : Collections.emptyMap());
|
}
|
|
private Map<String, Object> load(Map<String, String> savedVersions) {
|
List<FlowCatalog> catalogs = new ArrayList<>();
|
List<Map<String, Object>> fieldCatalog = new ArrayList<>();
|
Map<String, String> publishedVersions = new LinkedHashMap<>();
|
for (jnpf.dmsService.DmsQianpiyeProperties.Flow configured : properties.getFlows()) {
|
if (configured.getTemplateId() == null || configured.getTemplateId().isBlank())
|
throw new jnpf.exception.DataException("签批页适用流程缺少模板 ID");
|
FlowDefinition flow = new FlowDefinition(configured.getKey(), configured.getTemplateId());
|
List<TemplateJsonEntity> versions = workFlowApi.getFlowIdsByTemplate(flow.templateId);
|
String savedVersionId = "new".equals(flow.key)
|
? DmsQianpiyeDocxPropertiesReader.newFlowVersionId(savedVersions)
|
: "revision".equals(flow.key)
|
? DmsQianpiyeDocxPropertiesReader.revisionFlowVersionId(savedVersions) : null;
|
TemplateJsonEntity version = resolveVersion(versions, savedVersionId, flow.key);
|
if (version == null) {
|
continue;
|
}
|
publishedVersions.put(configured.getKey(), version.getId());
|
List<StepDefinition> steps = new ArrayList<>();
|
Set<String> formIds = new LinkedHashSet<>();
|
List<TemplateNodeEntity> nodes = DmsQianpiyeNodeOrder.order(version.getFlowXml(),
|
workFlowApi.getNodesByFlowId(version.getId()));
|
for (TemplateNodeEntity node : nodes) {
|
if (org.springframework.util.StringUtils.hasText(node.getFormId())) formIds.add(node.getFormId());
|
String role = NodeEnum.START.getType().equals(node.getNodeType()) ? "START"
|
: NodeEnum.APPROVER.getType().equals(node.getNodeType()) ? "APPROVE" : null;
|
if (role == null) {
|
continue;
|
}
|
NodeModel model = JsonUtil.getJsonToBean(node.getNodeJson(), NodeModel.class);
|
String nodeName = model == null || !org.springframework.util.StringUtils.hasText(model.getNodeName())
|
? node.getNodeCode() : model.getNodeName();
|
if (!org.springframework.util.StringUtils.hasText(nodeName)) {
|
continue;
|
}
|
steps.add(new StepDefinition(role, nodeName));
|
}
|
catalogs.add(new FlowCatalog(flow, steps, Collections.emptyList()));
|
if (!"new".equals(flow.key) && !"revision".equals(flow.key)) {
|
continue;
|
}
|
for (String formId : formIds) {
|
VisualdevEntity form = visualdevOnlineApi.getFormConfig(formId);
|
if (form == null) throw new jnpf.exception.DataException("表单配置不存在: " + formId);
|
for (jnpf.onlinedev.model.FormDisplaySchema.Field field :
|
jnpf.onlinedev.model.FormDisplaySchema.parse(form.getFormData())) {
|
if (!field.isSupported()) {
|
continue;
|
}
|
Map<String, Object> item = new LinkedHashMap<>();
|
item.put("flowKey", flow.key);
|
item.put("key", field.getPath());
|
item.put("label", field.getLabel());
|
item.put("path", field.getPath());
|
item.put("table", field.getTable());
|
item.put("column", field.getColumn());
|
item.put("signature", field.displaySignature());
|
fieldCatalog.add(item);
|
}
|
}
|
}
|
Map<String, Object> result = new LinkedHashMap<>();
|
result.put("workflowSteps", mergeSteps(catalogs));
|
result.put("formFields", mergeCompatibleFields(fieldCatalog));
|
result.put("newFlowVersionId", publishedVersions.get("new"));
|
result.put("revisionFlowVersionId", publishedVersions.get("revision"));
|
return result;
|
}
|
|
private TemplateJsonEntity resolveVersion(List<TemplateJsonEntity> versions, String savedVersionId,
|
String flowKey) {
|
if (versions == null) versions = Collections.emptyList();
|
if (org.springframework.util.StringUtils.hasText(savedVersionId)) {
|
for (TemplateJsonEntity version : versions) {
|
if (savedVersionId.equals(version.getId())) return version;
|
}
|
throw new jnpf.exception.DataException("签批页保存的" + flowKey + "流程版本不存在,请点击刷新后重新保存");
|
}
|
return versions.stream().filter(item -> Integer.valueOf(1).equals(item.getState()))
|
.max((left, right) -> compareVersion(left.getVersion(), right.getVersion())).orElse(null);
|
}
|
|
private static List<Map<String, Object>> mergeCompatibleFields(List<Map<String, Object>> fields) {
|
Map<String, List<Map<String, Object>>> grouped = new LinkedHashMap<>();
|
for (Map<String, Object> field : fields)
|
grouped.computeIfAbsent(String.valueOf(field.get("path")), key -> new ArrayList<>()).add(field);
|
List<Map<String, Object>> result = new ArrayList<>();
|
for (List<Map<String, Object>> group : grouped.values()) {
|
Map<String, Object> first = group.get(0);
|
Set<Object> flowKeys = new LinkedHashSet<>();
|
for (Map<String, Object> field : group) {
|
flowKeys.add(field.get("flowKey"));
|
}
|
if (!flowKeys.equals(Set.of("new", "revision"))) {
|
continue;
|
}
|
boolean compatible = group.stream().allMatch(field ->
|
java.util.Objects.equals(first.get("signature"), field.get("signature")));
|
if (!compatible) {
|
continue;
|
}
|
Map<String, Object> common = new LinkedHashMap<>();
|
common.put("key", first.get("path"));
|
common.put("tag", "dms.qianpiye.form." + first.get("path"));
|
common.put("label", first.get("label"));
|
common.put("formId", "common");
|
common.put("table", first.get("table"));
|
common.put("column", first.get("column"));
|
result.add(common);
|
}
|
return result;
|
}
|
|
/**
|
* 节点编码只在单个流程版本中有效。签批页模板需要跨新增/修订复用,因此按角色内顺序生成稳定步骤键。
|
*/
|
private static List<Map<String, String>> mergeSteps(List<FlowCatalog> catalogs) {
|
Map<String, Map<String, String>> result = new LinkedHashMap<>();
|
for (FlowCatalog catalog : catalogs) {
|
List<Map<String, String>> steps = new ArrayList<>();
|
appendMergedSteps(steps, "START", "start", stepsFor(catalog, "START"), Collections.emptyList());
|
appendMergedSteps(steps, "APPROVE", "approve", stepsFor(catalog, "APPROVE"), Collections.emptyList());
|
for (Map<String, String> step : steps) {
|
Map<String, String> existing = result.putIfAbsent(step.get("key"), step);
|
if (existing != null && !existing.get("label").equals(step.get("label")))
|
existing.put("label", existing.get("label") + " / " + step.get("label"));
|
}
|
}
|
return new ArrayList<>(result.values());
|
}
|
|
private static void appendMergedSteps(List<Map<String, String>> result, String role, String keyPrefix,
|
List<StepDefinition> newSteps, List<StepDefinition> revisionSteps) {
|
int count = Math.max(newSteps.size(), revisionSteps.size());
|
for (int index = 0; index < count; index++) {
|
StepDefinition newStep = index < newSteps.size() ? newSteps.get(index) : null;
|
StepDefinition revisionStep = index < revisionSteps.size() ? revisionSteps.get(index) : null;
|
String key = "START".equals(role) && index == 0 ? keyPrefix : keyPrefix + "-" + (index + 1);
|
Map<String, String> item = new LinkedHashMap<>();
|
item.put("key", key);
|
item.put("label", stepLabel(newStep, revisionStep));
|
item.put("role", role);
|
result.add(item);
|
}
|
}
|
|
private static String stepLabel(StepDefinition newStep, StepDefinition revisionStep) {
|
if (newStep == null) return revisionStep.name;
|
if (revisionStep == null || newStep.name.equals(revisionStep.name)) return newStep.name;
|
return newStep.name + " / " + revisionStep.name;
|
}
|
|
private static List<StepDefinition> stepsFor(FlowCatalog catalog, String role) {
|
if (catalog == null) return Collections.emptyList();
|
List<StepDefinition> result = new ArrayList<>();
|
for (StepDefinition step : catalog.steps) if (role.equals(step.role)) result.add(step);
|
return result;
|
}
|
|
private static int compareVersion(String left, String right) {
|
if (left == null) {
|
return right == null ? 0 : -1;
|
}
|
if (right == null) {
|
return 1;
|
}
|
String[] leftParts = left.split("\\.");
|
String[] rightParts = right.split("\\.");
|
int size = Math.max(leftParts.length, rightParts.length);
|
for (int index = 0; index < size; index++) {
|
int comparison = Integer.compare(versionPart(leftParts, index), versionPart(rightParts, index));
|
if (comparison != 0) {
|
return comparison;
|
}
|
}
|
return left.compareTo(right);
|
}
|
|
private static int versionPart(String[] parts, int index) {
|
if (index >= parts.length) {
|
return 0;
|
}
|
try {
|
return Integer.parseInt(parts[index]);
|
} catch (NumberFormatException e) {
|
return 0;
|
}
|
}
|
|
private static final class FlowDefinition {
|
private final String key;
|
private final String templateId;
|
|
private FlowDefinition(String key, String templateId) {
|
this.key = key;
|
this.templateId = templateId;
|
}
|
}
|
|
private static final class FlowCatalog {
|
private final FlowDefinition definition;
|
private final List<StepDefinition> steps;
|
private final List<FormField> formFields;
|
|
private FlowCatalog(FlowDefinition definition, List<StepDefinition> steps, List<FormField> formFields) {
|
this.definition = definition;
|
this.steps = steps;
|
this.formFields = formFields;
|
}
|
}
|
|
private static final class StepDefinition {
|
private final String role;
|
private final String name;
|
|
private StepDefinition(String role, String name) {
|
this.role = role;
|
this.name = name;
|
}
|
}
|
|
private static final class FormField {
|
private final String path;
|
private final String label;
|
|
private FormField(String path, String label) {
|
this.path = path;
|
this.label = label;
|
}
|
}
|
}
|