package jnpf.base.service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.base.entity.VisualdevEntity; import jnpf.base.mapper.UploadEditReadMapper; import jnpf.base.model.ColumnDataModel; import jnpf.base.model.form.ModuleFormModel; import jnpf.base.model.uploadedit.UploadEditContext; import jnpf.base.util.UploadEditStateMachine; import jnpf.exception.DataException; import jnpf.permissions.PermissionInterfaceImpl; import jnpf.util.JsonUtil; import jnpf.util.UserProvider; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.*; /** Narrow shared-load reads; native detail rendering and persistence remain unchanged. */ @Service @RequiredArgsConstructor public class UploadEditReadService { private static final ObjectMapper JSON = new ObjectMapper(); private final UploadEditReadMapper mapper; public VisualdevEntity model(String id) { VisualdevEntity model = mapper.releasedModel(id); return model == null ? mapper.designModel(id) : model; } /** Null means the published mapping needs the original native reader, never a failed query. */ public Map dmsAttachment(VisualdevEntity model, UploadEditContext context, Map fieldConfig) { String table = supportedTable(model, context, fieldConfig); if (table == null) return null; boolean child = StringUtils.hasText(context.getParentField()); if (child && !StringUtils.hasText(context.getRowId())) throw new DataException("子表行尚无跟踪 ID"); // Preserve the native menu field boundary; denied/missing fields must not become empty attachments. ColumnDataModel columns = JsonUtil.getJsonToBean(model.getColumnData(), ColumnDataModel.class); if (columns != null && Boolean.TRUE.equals(columns.getUseFormPermission()) && StringUtils.hasText(context.getMenuId())) { Object granted = PermissionInterfaceImpl.getFormMap().get(context.getMenuId()); String key = child ? context.getParentField() + "-" + context.getField() : context.getField(); if (granted == null || JsonUtil.getJsonToList(granted, ModuleFormModel.class).stream() .noneMatch(item -> key.equals(item.getEnCode()))) throw new DataException("没有附件字段查看权限"); } String tenant = UserProvider.getUser().getTenantId(); Map row = mapper.dmsAttachment(table, StringUtils.hasText(tenant) ? tenant : "0", context.getRecordId(), child ? context.getRowId() : null); if (row == null) throw new DataException("原生表单记录不存在"); Map data = new HashMap<>(); data.put("id", row.get("id")); data.put("flowTaskId", row.get("flowTaskId")); List> files = UploadEditStateMachine.files(row.get("fileJson")); if (child) { if (!Objects.equals(context.getRowId(), row.get("rowId"))) throw new DataException("附件所属子表行不存在"); data.put(context.getParentField(), List.of(Map.of("id", row.get("rowId"), context.getField(), files))); } else data.put(context.getField(), files); return data; } /** Only optimize the verified default-source DMS schema; changed mappings retain native support. */ String supportedTable(VisualdevEntity model, UploadEditContext context, Map fieldConfig) { if (!"0".equals(model.getDbLinkId()) || Boolean.TRUE.equals(fieldConfig.get("isVirtualField"))) return null; try { JsonNode form = JSON.readTree(model.getFormData()); String table = form.path("tableName").asText(); if (!Set.of("dms_wenjian_xinzeng_shenhe", "dms_wenjian_xiuding_shenhe").contains(table) || !form.path("logicalDelete").asBoolean() || form.path("primaryKeyPolicy").asInt() != 1 || !table.equals(fieldConfig.get("tableName"))) return null; boolean child = StringUtils.hasText(context.getParentField()); if (child ? !"jilu_mingxi".equals(context.getParentField()) || !"jilu_wenjian".equals(context.getField()) || !(table + "_jilu_mingxi").equals(fieldConfig.get("relationTable")) : !"wenjian".equals(context.getField()) || Boolean.TRUE.equals(fieldConfig.get("isSubTable"))) return null; JsonNode tables = JSON.readTree(model.getVisualTables()); if (tables == null || !tables.isArray()) return null; JsonNode main = null, detail = null; for (JsonNode item : tables) { if ("1".equals(item.path("typeId").asText())) { if (main != null) return null; main = item; } if ((table + "_jilu_mingxi").equals(item.path("table").asText())) detail = item; } if (main == null || !table.equals(main.path("table").asText()) || !standardPrimaryKey(main) || !hasColumns(main, "f_id", "f_tenant_id", "f_delete_mark", "f_flow_task_id", "wenjian")) return null; if (child && (detail == null || !standardPrimaryKey(detail) || !hasColumns(detail, "f_id", "f_tenant_id", "f_delete_mark", "f_foreign_id", "jilu_wenjian") || !"f_foreign_id".equals(detail.path("tableField").asText()) || !"f_id".equals(detail.path("relationField").asText()))) return null; return table; } catch (Exception malformedMapping) { return null; // The existing native reader owns unsupported/malformed metadata errors. } } private boolean standardPrimaryKey(JsonNode table) { List keys = new ArrayList<>(); for (JsonNode field : table.path("fields")) { if (field.path("primaryKey").asInt() == 1 && !"f_tenant_id".equals(field.path("field").asText())) keys.add(field.path("field").asText()); } return keys.equals(List.of("f_id")); } private boolean hasColumns(JsonNode table, String... required) { Set columns = new HashSet<>(); for (JsonNode field : table.path("fields")) columns.add(field.path("field").asText()); return columns.containsAll(Arrays.asList(required)); } }