package jnpf.onlinedev.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import jnpf.exception.DataException; import jnpf.model.visualjson.FieLdsModel; import jnpf.onlinedev.model.FormDisplaySchema; import jnpf.util.JsonUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.*; /** Converts published form values through the platform's existing lookup engine. */ @Service @RequiredArgsConstructor public class FormDisplayValueService { private final OnlineSwapDataUtils converter; private static final ObjectMapper JSON = new ObjectMapper(); public Map convert(String formId, String configuration, Map raw) { List fields = FormDisplaySchema.parse(configuration); List models = new ArrayList<>(); Map> children = new LinkedHashMap<>(); for (FormDisplaySchema.Field field : fields) { if (!field.isSupported()) continue; ObjectNode config = (ObjectNode) field.getConfiguration().deepCopy(); config.put("__vModel__", field.getColumn()); // Approval-page display values use dates, independent of the form editor format. if (Set.of("datePicker", "dateCalculate", "createTime", "modifyTime").contains(field.getType())) config.put("format", "yyyy-MM-dd"); if (field.getType().isEmpty()) ((ObjectNode) config.with("__config__")).put("jnpfKey", "input"); FieLdsModel model = JsonUtil.getJsonToBean(config.toString(), FieLdsModel.class); if (field.getTable().isEmpty()) models.add(model); else children.computeIfAbsent(field.getTable(), k -> new ArrayList<>()).add(model); } for (Map.Entry> table : children.entrySet()) { FieLdsModel model = JsonUtil.getJsonToBean("{\"__vModel__\":\"" + table.getKey() + "\",\"__config__\":{\"jnpfKey\":\"table\"}}", FieLdsModel.class); model.getConfig().setChildren(table.getValue()); models.add(model); } Map data = JsonUtil.stringToMap(JsonUtil.getObjectToString(raw)); for (String table : children.keySet()) { Object value = data.get(table); if (value instanceof String) { try { data.put(table, JsonUtil.getJsonToListMap((String) value)); } catch (Exception e) { throw new DataException("子表数据格式错误: " + table); } } } List> rows = new ArrayList<>(); rows.add(data); converter.getSwapInfoStrict(rows, models, formId); // Strict lookup validation in OnlineSwapDataUtils rejects missing selected IDs. // Also reject silent fallback/empty results from relation/popup resolvers. JsonNode before = JSON.valueToTree(raw), after = JSON.valueToTree(data); for (FormDisplaySchema.Field field : fields) { if (!field.isSupported() || !field.isReference()) continue; if (field.getTable().isEmpty()) check(field, before.get(field.getColumn()), after.get(field.getColumn())); else { JsonNode oldRows = before.path(field.getTable()); if (oldRows.isTextual()) { try { oldRows = JSON.readTree(oldRows.asText()); } catch (Exception e) { throw new DataException("子表数据格式错误: " + field.getTable()); } } for (int i = 0; i < oldRows.size(); i++) check(field, oldRows.path(i).get(field.getColumn()), after.path(field.getTable()).path(i).get(field.getColumn())); } } return data; } private void check(FormDisplaySchema.Field field, JsonNode raw, JsonNode display) { if (raw == null || raw.isNull() || raw.isArray() && raw.isEmpty() || raw.isTextual() && (raw.asText().isBlank() || "[]".equals(raw.asText()))) return; if (display == null || display.isNull() || !display.isValueNode() || display.asText().isBlank()) throw new DataException("无法解析字段显示值: " + field.getLabel() + " (" + field.getPath() + ")"); if (Set.of("relationForm", "popupSelect", "popupTableSelect").contains(field.getType()) && display.equals(raw)) throw new DataException("关联字段未返回显示文本: " + field.getLabel()); } }