From c9461f8b8a586aaa45b3e219466bca61f3312efb Mon Sep 17 00:00:00 2001
From: yexb <553699424@qq.com>
Date: Fri, 17 Apr 2026 16:31:38 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Emms=E6=8E=A5=E5=8D=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 5 +-
entrance/pom.xml | 5 +
tools/README.md | 27 +-
tools/mms-mapping/pom.xml | 122 ++
.../application/MappingTaskAppService.java | 135 ++
.../command/GenerateFromIcdCommand.java | 102 ++
.../command/IndexBindingCommand.java | 51 +
.../command/IndexSelectionGroupCommand.java | 43 +
.../result/GenerateMappingResult.java | 42 +
.../mapping/config/MappingModuleConfig.java | 52 +
.../mapping/controller/MappingController.java | 50 +
.../GenerateMappingFromIcdRequest.java | 89 ++
.../request/IndexBindingRequest.java | 59 +
.../request/IndexSelectionGroupRequest.java | 53 +
.../IndexCandidateReportItemResponse.java | 54 +
.../response/IndexCandidateResponse.java | 71 +
.../response/MappingDocumentResponse.java | 26 +
.../response/MappingTaskResponse.java | 40 +
.../converter/MappingRequestConverter.java | 82 +
.../converter/MappingResponseConverter.java | 70 +
.../domain/model/analysis/IndexAnalysis.java | 20 +
.../domain/model/analysis/IndexCandidate.java | 113 ++
.../analysis/IndexCandidateReportItem.java | 56 +
.../model/analysis/ValidationResult.java | 18 +
.../mapping/domain/model/icd/DataSetNode.java | 17 +
.../domain/model/icd/DoiElementNode.java | 31 +
.../icd/mapping/domain/model/icd/DoiNode.java | 30 +
.../mapping/domain/model/icd/FcdaNode.java | 36 +
.../mapping/domain/model/icd/IcdDocument.java | 46 +
.../icd/mapping/domain/model/icd/IedNode.java | 20 +
.../icd/mapping/domain/model/icd/LnNode.java | 32 +
.../domain/model/icd/LogicalDeviceNode.java | 14 +
.../domain/model/icd/ReportControlNode.java | 29 +
.../intermediate/DataSetSelectionState.java | 103 ++
.../intermediate/ReportAndDataSetState.java | 59 +
.../intermediate/ReportBindingState.java | 73 +
.../model/intermediate/ReportGroupState.java | 100 ++
.../model/mapping/DataSetGroupItem.java | 43 +
.../mapping/domain/model/mapping/DoiItem.java | 120 ++
.../domain/model/mapping/InstItem.java | 43 +
.../domain/model/mapping/MappingDocument.java | 127 ++
.../domain/model/mapping/ReportMapItem.java | 124 ++
.../mapping/domain/model/mapping/SdiItem.java | 43 +
.../domain/model/mapping/TypeItem.java | 29 +
.../model/template/DefaultTemplate.java | 345 ++++
.../domain/service/DefaultTemplateLoader.java | 69 +
.../domain/service/IcdParserService.java | 23 +
.../domain/service/IndexAnalysisService.java | 168 ++
.../service/IndexValidationService.java | 133 ++
.../service/MappingGenerationService.java | 1015 ++++++++++++
.../icd/mapping/enums/GenerateStatus.java | 13 +
.../parser/SclGeneratedModelReader.java | 522 ++++++
.../parser/SclParserAdapter.java | 53 +
.../parser/SclTraversalSupport.java | 61 +
.../generated-com.example.scl.generated.zip | Bin 0 -> 283215 bytes
.../parser/generated-package-replaced.zip | Bin 0 -> 307305 bytes
.../infrastructure/parser/generated/LN0.java | 42 +
.../parser/generated/ObjectFactory.java | 1398 +++++++++++++++++
.../infrastructure/parser/generated/SCL.java | 351 +++++
.../TAbstractConductingEquipment.java | 117 ++
.../generated/TAbstractDataAttribute.java | 325 ++++
.../generated/TAbstractEqFuncSubFunc.java | 150 ++
.../parser/generated/TAccessControl.java | 40 +
.../parser/generated/TAccessPoint.java | 436 +++++
.../parser/generated/TAddress.java | 76 +
.../TAnyContentFromOtherNamespace.java | 113 ++
.../parser/generated/TAnyLN.java | 384 +++++
.../parser/generated/TAssociation.java | 359 +++++
.../generated/TAssociationInitiator.java | 58 +
.../generated/TAssociationKindEnum.java | 58 +
.../parser/generated/TAuthenticationEnum.java | 67 +
.../infrastructure/parser/generated/TBDA.java | 40 +
.../parser/generated/TBaseElement.java | 176 +++
.../infrastructure/parser/generated/TBay.java | 145 ++
.../parser/generated/TBitRateInMbPerSec.java | 136 ++
.../parser/generated/TCert.java | 110 ++
.../parser/generated/TCertificate.java | 167 ++
.../parser/generated/TClientLN.java | 273 ++++
.../parser/generated/TClientServices.java | 623 ++++++++
.../parser/generated/TCommProt.java | 71 +
.../parser/generated/TCommunication.java | 79 +
.../generated/TConductingEquipment.java | 107 ++
.../parser/generated/TConfLNs.java | 100 ++
.../parser/generated/TConnectedAP.java | 287 ++++
.../parser/generated/TConnectivityNode.java | 71 +
.../parser/generated/TControl.java | 157 ++
.../parser/generated/TControlBlock.java | 164 ++
.../parser/generated/TControlWithIEDName.java | 411 +++++
.../generated/TControlWithTriggerOpt.java | 111 ++
.../infrastructure/parser/generated/TDA.java | 198 +++
.../infrastructure/parser/generated/TDAI.java | 254 +++
.../parser/generated/TDAType.java | 175 +++
.../infrastructure/parser/generated/TDO.java | 193 +++
.../infrastructure/parser/generated/TDOI.java | 205 +++
.../parser/generated/TDORef.java | 395 +++++
.../parser/generated/TDOType.java | 177 +++
.../parser/generated/TDataSet.java | 163 ++
.../parser/generated/TDataTypeTemplates.java | 175 +++
.../parser/generated/TDomainLNGroupAEnum.java | 53 +
.../parser/generated/TDomainLNGroupCEnum.java | 55 +
.../parser/generated/TDomainLNGroupFEnum.java | 61 +
.../parser/generated/TDomainLNGroupGEnum.java | 51 +
.../parser/generated/TDomainLNGroupIEnum.java | 55 +
.../parser/generated/TDomainLNGroupKEnum.java | 53 +
.../parser/generated/TDomainLNGroupMEnum.java | 71 +
.../parser/generated/TDomainLNGroupPEnum.java | 103 ++
.../parser/generated/TDomainLNGroupQEnum.java | 55 +
.../parser/generated/TDomainLNGroupREnum.java | 65 +
.../parser/generated/TDomainLNGroupSEnum.java | 65 +
.../parser/generated/TDomainLNGroupTEnum.java | 83 +
.../parser/generated/TDomainLNGroupXEnum.java | 47 +
.../parser/generated/TDomainLNGroupYEnum.java | 51 +
.../parser/generated/TDomainLNGroupZEnum.java | 79 +
.../parser/generated/TDurationInMilliSec.java | 137 ++
.../parser/generated/TDurationInSec.java | 41 +
.../parser/generated/TEnumType.java | 79 +
.../parser/generated/TEnumVal.java | 123 ++
.../parser/generated/TEqFunction.java | 40 +
.../parser/generated/TEqSubFunction.java | 40 +
.../parser/generated/TEquipment.java | 78 +
.../parser/generated/TEquipmentContainer.java | 118 ++
.../parser/generated/TExtControlCheck.java | 61 +
.../parser/generated/TExtCtrl.java | 163 ++
.../parser/generated/TExtRef.java | 357 +++++
.../parser/generated/TFCDA.java | 301 ++++
.../parser/generated/TFileHandling.java | 133 ++
.../parser/generated/TFunction.java | 178 +++
.../parser/generated/TGOOSEcapabilities.java | 133 ++
.../infrastructure/parser/generated/TGSE.java | 100 ++
.../parser/generated/TGSEControl.java | 196 +++
.../parser/generated/TGSEControlTypeEnum.java | 45 +
.../parser/generated/TGSESettings.java | 165 ++
.../parser/generated/TGeneralEquipment.java | 107 ++
.../generated/TGeneralEquipmentContainer.java | 117 ++
.../parser/generated/THeader.java | 441 ++++++
.../parser/generated/THeaderSclRef.java | 79 +
.../parser/generated/THitem.java | 221 +++
.../parser/generated/TIDNaming.java | 113 ++
.../infrastructure/parser/generated/TIED.java | 552 +++++++
.../parser/generated/TIEDSclRef.java | 79 +
.../parser/generated/TInputs.java | 79 +
.../infrastructure/parser/generated/TKDC.java | 124 ++
.../parser/generated/TLDevice.java | 275 ++++
.../parser/generated/TLLN0Enum.java | 55 +
.../infrastructure/parser/generated/TLN.java | 137 ++
.../infrastructure/parser/generated/TLN0.java | 213 +++
.../parser/generated/TLNode.java | 342 ++++
.../parser/generated/TLNodeContainer.java | 84 +
.../parser/generated/TLNodeType.java | 174 ++
.../parser/generated/TLPHDEnum.java | 43 +
.../parser/generated/TLabel.java | 130 ++
.../parser/generated/TLabels.java | 79 +
.../parser/generated/TLine.java | 238 +++
.../infrastructure/parser/generated/TLog.java | 71 +
.../parser/generated/TLogControl.java | 289 ++++
.../parser/generated/TLogSettings.java | 133 ++
.../parser/generated/TMcSecurity.java | 100 ++
.../generated/TMinRequestedSCDFile.java | 50 +
.../generated/TMinRequestedSCDFiles.java | 79 +
.../parser/generated/TNaming.java | 196 +++
.../parser/generated/TOutputs.java | 79 +
.../infrastructure/parser/generated/TP.java | 121 ++
.../parser/generated/TPAPPID.java | 40 +
.../parser/generated/TPC37118IPPort.java | 40 +
.../parser/generated/TPDNSName.java | 40 +
.../infrastructure/parser/generated/TPIP.java | 40 +
.../parser/generated/TPIPClassOfTraffic.java | 40 +
.../parser/generated/TPIPGATEWAY.java | 40 +
.../parser/generated/TPIPIGMPv3Src.java | 40 +
.../parser/generated/TPIPSUBNET.java | 40 +
.../parser/generated/TPIPbase.java | 46 +
.../parser/generated/TPIPv6.java | 40 +
.../parser/generated/TPIPv6Base.java | 45 +
.../generated/TPIPv6ClassOfTraffic.java | 40 +
.../parser/generated/TPIPv6FlowLabel.java | 40 +
.../parser/generated/TPIPv6GATEWAY.java | 40 +
.../parser/generated/TPIPv6IGMPv3Src.java | 40 +
.../parser/generated/TPIPv6SUBNET.java | 40 +
.../parser/generated/TPMACAddress.java | 40 +
.../parser/generated/TPMMSPort.java | 40 +
.../parser/generated/TPOSIAEInvoke.java | 40 +
.../parser/generated/TPOSIAEQualifier.java | 40 +
.../parser/generated/TPOSIAPInvoke.java | 40 +
.../parser/generated/TPOSIAPTitle.java | 50 +
.../parser/generated/TPOSINSAP.java | 47 +
.../parser/generated/TPOSIPSEL.java | 47 +
.../parser/generated/TPOSISSEL.java | 47 +
.../parser/generated/TPOSITSEL.java | 47 +
.../parser/generated/TPPhysConn.java | 97 ++
.../parser/generated/TPPort.java | 46 +
.../parser/generated/TPSNTPPort.java | 40 +
.../parser/generated/TPTCPPort.java | 40 +
.../parser/generated/TPUDPPort.java | 40 +
.../parser/generated/TPVLANID.java | 40 +
.../parser/generated/TPVLANPRIORITY.java | 40 +
.../parser/generated/TPhaseEnum.java | 72 +
.../parser/generated/TPhysConn.java | 107 ++
.../generated/TPowerSystemResource.java | 51 +
.../parser/generated/TPowerTransformer.java | 177 +++
.../generated/TPowerTransformerEnum.java | 43 +
.../TPredefinedAttributeNameEnum.java | 98 ++
.../generated/TPredefinedBasicTypeEnum.java | 165 ++
.../parser/generated/TPredefinedCDCEnum.java | 147 ++
...edefinedCommonConductingEquipmentEnum.java | 93 ++
.../parser/generated/TPredefinedFCEnum.java | 67 +
.../TPredefinedGeneralEquipmentEnum.java | 57 +
.../generated/TPredefinedPTypeEnum.java | 137 ++
.../TPredefinedPTypePhysConnEnum.java | 64 +
.../TPredefinedPhysConnTypeEnum.java | 58 +
.../generated/TPredefinedSCLFileType.java | 53 +
.../TPredefinedTypeOfSecurityEnum.java | 61 +
.../parser/generated/TPrivate.java | 106 ++
.../parser/generated/TProcess.java | 209 +++
.../parser/generated/TProtNs.java | 108 ++
.../parser/generated/TProtocol.java | 91 ++
.../parser/generated/TRedProt.java | 131 ++
.../parser/generated/TRedProtEnum.java | 64 +
.../parser/generated/TReportControl.java | 519 ++++++
.../parser/generated/TReportSettings.java | 257 +++
.../parser/generated/TRightEnum.java | 61 +
.../parser/generated/TRptEnabled.java | 117 ++
.../parser/generated/TSCSM.java | 133 ++
.../infrastructure/parser/generated/TSDI.java | 208 +++
.../infrastructure/parser/generated/TSDO.java | 163 ++
.../infrastructure/parser/generated/TSMV.java | 40 +
.../parser/generated/TSMVDeliveryEnum.java | 61 +
.../parser/generated/TSMVSettings.java | 386 +++++
.../parser/generated/TSMVsc.java | 164 ++
.../generated/TSampledValueControl.java | 538 +++++++
.../generated/TSclFileUUIDReference.java | 220 +++
.../parser/generated/TSecurity.java | 100 ++
.../parser/generated/TServer.java | 357 +++++
.../parser/generated/TServerAt.java | 98 ++
.../generated/TServiceConfReportControl.java | 142 ++
.../generated/TServiceForConfDataSet.java | 71 +
.../parser/generated/TServiceSettings.java | 107 ++
.../generated/TServiceSettingsEnum.java | 61 +
.../generated/TServiceSettingsNoDynEnum.java | 58 +
.../parser/generated/TServiceType.java | 62 +
.../parser/generated/TServiceWithMax.java | 67 +
.../TServiceWithMaxAndMaxAttributes.java | 77 +
.../generated/TServiceWithMaxAndModify.java | 71 +
.../generated/TServiceWithMaxNonZero.java | 63 +
.../generated/TServiceWithOptionalMax.java | 67 +
.../parser/generated/TServiceYesNo.java | 46 +
.../parser/generated/TServices.java | 1059 +++++++++++++
.../parser/generated/TSettingControl.java | 132 ++
.../parser/generated/TSettingGroups.java | 227 +++
.../parser/generated/TSmpMod.java | 61 +
.../parser/generated/TSubEquipment.java | 142 ++
.../parser/generated/TSubFunction.java | 178 +++
.../parser/generated/TSubNetwork.java | 135 ++
.../parser/generated/TSubstation.java | 112 ++
.../parser/generated/TSupSubscription.java | 79 +
.../parser/generated/TSystemLNGroupEnum.java | 72 +
.../parser/generated/TTapChanger.java | 180 +++
.../parser/generated/TTerminal.java | 298 ++++
.../parser/generated/TText.java | 70 +
.../parser/generated/TTimeSyncProt.java | 164 ++
.../parser/generated/TTransformerWinding.java | 167 ++
.../generated/TTransformerWindingEnum.java | 43 +
.../parser/generated/TTrgOps.java | 193 +++
.../parser/generated/TUnNaming.java | 107 ++
.../infrastructure/parser/generated/TVal.java | 100 ++
.../parser/generated/TValKindEnum.java | 63 +
.../parser/generated/TValueHandling.java | 69 +
.../parser/generated/TValueWithUnit.java | 138 ++
.../parser/generated/TVoltage.java | 41 +
.../parser/generated/TVoltageLevel.java | 208 +++
.../parser/generated/package-info.java | 9 +
.../serializer/MappingDocumentSerializer.java | 42 +
.../storage/FileStorageService.java | 32 +
.../gather/icd/mapping/utils/DateUtils.java | 17 +
.../gather/icd/mapping/utils/JsonUtils.java | 22 +
.../main/resources/template/DefaultCfg.txt | 756 +++++++++
tools/pom.xml | 1 +
tools/wave-tool/PARSE_COMTRADE_API.md | 266 ----
.../wave/component/WaveVectorComponent.java | 2 +-
278 files changed, 35097 insertions(+), 271 deletions(-)
create mode 100644 tools/mms-mapping/pom.xml
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/MappingTaskAppService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/GenerateFromIcdCommand.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexBindingCommand.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexSelectionGroupCommand.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/result/GenerateMappingResult.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/config/MappingModuleConfig.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/MappingController.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/GenerateMappingFromIcdRequest.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexBindingRequest.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexSelectionGroupRequest.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateReportItemResponse.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateResponse.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingDocumentResponse.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingTaskResponse.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingRequestConverter.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingResponseConverter.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexAnalysis.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidate.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidateReportItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/ValidationResult.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DataSetNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiElementNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/FcdaNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IcdDocument.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IedNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LnNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LogicalDeviceNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/ReportControlNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/DataSetSelectionState.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportAndDataSetState.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportBindingState.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportGroupState.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DataSetGroupItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DoiItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/InstItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/MappingDocument.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/ReportMapItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/SdiItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/TypeItem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/template/DefaultTemplate.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/DefaultTemplateLoader.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IcdParserService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexAnalysisService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexValidationService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/MappingGenerationService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/enums/GenerateStatus.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/SclGeneratedModelReader.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/SclParserAdapter.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/SclTraversalSupport.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated-com.example.scl.generated.zip
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated-package-replaced.zip
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/LN0.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/ObjectFactory.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/SCL.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAbstractConductingEquipment.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAbstractDataAttribute.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAbstractEqFuncSubFunc.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAccessControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAccessPoint.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAddress.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAnyContentFromOtherNamespace.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAnyLN.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAssociation.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAssociationInitiator.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAssociationKindEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TAuthenticationEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TBDA.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TBaseElement.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TBay.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TBitRateInMbPerSec.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TCert.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TCertificate.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TClientLN.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TClientServices.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TCommProt.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TCommunication.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TConductingEquipment.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TConfLNs.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TConnectedAP.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TConnectivityNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TControlBlock.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TControlWithIEDName.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TControlWithTriggerOpt.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDA.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDAI.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDAType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDO.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDOI.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDORef.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDOType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDataSet.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDataTypeTemplates.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupAEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupCEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupFEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupGEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupIEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupKEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupMEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupPEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupQEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupREnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupSEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupTEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupXEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupYEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDomainLNGroupZEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDurationInMilliSec.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TDurationInSec.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEnumType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEnumVal.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEqFunction.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEqSubFunction.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEquipment.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TEquipmentContainer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TExtControlCheck.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TExtCtrl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TExtRef.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TFCDA.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TFileHandling.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TFunction.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGOOSEcapabilities.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGSE.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGSEControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGSEControlTypeEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGSESettings.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGeneralEquipment.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TGeneralEquipmentContainer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/THeader.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/THeaderSclRef.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/THitem.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TIDNaming.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TIED.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TIEDSclRef.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TInputs.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TKDC.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLDevice.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLLN0Enum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLN.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLN0.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLNode.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLNodeContainer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLNodeType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLPHDEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLabel.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLabels.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLine.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLog.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLogControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TLogSettings.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TMcSecurity.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TMinRequestedSCDFile.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TMinRequestedSCDFiles.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TNaming.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TOutputs.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TP.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPAPPID.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPC37118IPPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPDNSName.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIP.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPClassOfTraffic.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPGATEWAY.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPIGMPv3Src.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPSUBNET.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPbase.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6Base.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6ClassOfTraffic.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6FlowLabel.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6GATEWAY.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6IGMPv3Src.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPIPv6SUBNET.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPMACAddress.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPMMSPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSIAEInvoke.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSIAEQualifier.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSIAPInvoke.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSIAPTitle.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSINSAP.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSIPSEL.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSISSEL.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPOSITSEL.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPPhysConn.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPSNTPPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPTCPPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPUDPPort.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPVLANID.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPVLANPRIORITY.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPhaseEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPhysConn.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPowerSystemResource.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPowerTransformer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPowerTransformerEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedAttributeNameEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedBasicTypeEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedCDCEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedCommonConductingEquipmentEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedFCEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedGeneralEquipmentEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedPTypeEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedPTypePhysConnEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedPhysConnTypeEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedSCLFileType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPredefinedTypeOfSecurityEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TPrivate.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TProcess.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TProtNs.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TProtocol.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TRedProt.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TRedProtEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TReportControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TReportSettings.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TRightEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TRptEnabled.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSCSM.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSDI.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSDO.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSMV.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSMVDeliveryEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSMVSettings.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSMVsc.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSampledValueControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSclFileUUIDReference.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSecurity.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServerAt.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceConfReportControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceForConfDataSet.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceSettings.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceSettingsEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceSettingsNoDynEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceType.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceWithMax.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceWithMaxAndMaxAttributes.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceWithMaxAndModify.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceWithMaxNonZero.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceWithOptionalMax.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServiceYesNo.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TServices.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSettingControl.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSettingGroups.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSmpMod.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSubEquipment.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSubFunction.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSubNetwork.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSubstation.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSupSubscription.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TSystemLNGroupEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTapChanger.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTerminal.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TText.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTimeSyncProt.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTransformerWinding.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTransformerWindingEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TTrgOps.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TUnNaming.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TVal.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TValKindEnum.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TValueHandling.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TValueWithUnit.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TVoltage.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/TVoltageLevel.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/parser/generated/package-info.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/serializer/MappingDocumentSerializer.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/infrastructure/storage/FileStorageService.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/utils/DateUtils.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/utils/JsonUtils.java
create mode 100644 tools/mms-mapping/src/main/resources/template/DefaultCfg.txt
delete mode 100644 tools/wave-tool/PARSE_COMTRADE_API.md
diff --git a/README.md b/README.md
index 841e864..78d6454 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
其中 `tools` 当前包含:
- `activate-tool`
+- `mms-mapping`
- `wave-tool`
## 启动入口
@@ -29,7 +30,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
- `entrance/src/main/java/com/njcn/gather/EntranceApplication.java`
-`entrance` 模块聚合了 `system`、`user`、`detection`、`activate-tool`、`wave-tool`,是当前运行时主入口。
+`entrance` 模块聚合了 `system`、`user`、`detection`、`activate-tool`、`wave-tool`、`mms-mapping`,是当前运行时主入口。
## 技术基线
@@ -74,6 +75,8 @@ P0 已补齐基线文档,建议按以下顺序阅读:
- 当前以通信基础设施为主,包含 WebSocket / Netty 相关组件
- `tools/activate-tool`
- 负责激活码生成、激活码验证、许可证读取等能力
+- `tools/mms-mapping`
+ - 负责 ICD 文件解析与 MMS 映射数据生成能力
- `tools/wave-tool`
- 负责波形文本解析与查看数据组装能力
diff --git a/entrance/pom.xml b/entrance/pom.xml
index ad56706..c5cdff1 100644
--- a/entrance/pom.xml
+++ b/entrance/pom.xml
@@ -38,6 +38,11 @@
wave-tool
1.0.0
+
+ com.njcn.gather
+ mms-mapping
+ 1.0.0
+
diff --git a/tools/README.md b/tools/README.md
index 37b3426..8f877d2 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -7,18 +7,22 @@
当前真实保留的子模块有:
- `activate-tool`
+- `mms-mapping`
- `wave-tool`
-因此,`tools` 现阶段仍然是聚合模块,但当前已实际承载激活工具和波形查看工具两个子模块。
+因此,`tools` 现阶段仍然是聚合模块,但当前已实际承载激活工具、ICD/MMS 映射工具和波形查看工具三个子模块。
## 当前结构
```text
tools/
├── activate-tool/
+├── mms-mapping/
└── wave-tool/
```
+其中 `tools/mms-mapping` 当前 Maven `artifactId` 为 `mms-mapping`。
+
## activate-tool 的职责
`activate-tool` 当前提供的能力主要围绕设备授权与许可证:
@@ -42,6 +46,24 @@ tools/
从接口层看,当前主要围绕 `/wave/*` 路径提供能力。
+## mms-mapping 的职责
+
+`mms-mapping` 当前提供的能力主要围绕 ICD 文件解析与 MMS 映射数据生成:
+
+- 解析 ICD / SCL 文件结构
+- 校验索引选择与绑定关系
+- 生成映射任务结果与文档数据
+
+从接口层看,当前主要围绕 `/api/mms-mapping` 路径提供能力。
+
+## mms-mapping 配置
+
+`mms-mapping` 当前支持以下配置项:
+
+- `icd.mapping.default-template-path`:默认模板资源路径,默认值为 `template/DefaultCfg.txt`
+- `icd.mapping.default-author`:请求未传作者时使用的默认作者,默认值为 `system`
+- `icd.mapping.default-output-dir`:请求开启落盘但未指定目录时使用的默认输出目录,默认值为空字符串(即当前工作目录)
+
## 模块定位
当前 `activate-tool` 更适合作为平台级基础能力模块,而不是业务检测模块的一部分。
@@ -54,7 +76,7 @@ tools/
## 依赖关系
-`tools/activate-tool` 与 `tools/wave-tool` 当前主要依赖:
+`tools/activate-tool`、`tools/mms-mapping` 与 `tools/wave-tool` 当前主要依赖:
- `com.njcn:njcn-common`
- `com.njcn:spingboot2.3.12`
@@ -71,4 +93,3 @@ tools/
- 同步更新 `tools/pom.xml`
- 同步更新本说明文档
- 在 `docs` 下补充模块边界与职责说明
-
diff --git a/tools/mms-mapping/pom.xml b/tools/mms-mapping/pom.xml
new file mode 100644
index 0000000..f61b169
--- /dev/null
+++ b/tools/mms-mapping/pom.xml
@@ -0,0 +1,122 @@
+
+
+ 4.0.0
+
+
+ com.njcn.gather
+ tools
+ 1.0.0
+
+
+ mms-mapping
+ jar
+
+
+
+ com.njcn
+ njcn-common
+ 0.0.1
+
+
+
+ com.njcn
+ spingboot2.3.12
+ 2.3.12
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.83
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.12.0
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.12.0
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.12.0
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 2.3.3
+
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ 2.3.3
+
+
+
+ org.apache.poi
+ poi-scratchpad
+ 4.1.2
+
+
+ org.apache.poi
+ poi
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml-schemas
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.2
+
+
+
+ org.docx4j
+ docx4j
+ 6.1.0
+
+
+
+ commons-net
+ commons-net
+ 3.10.0
+
+
+
+
+ mms-mapping
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/MappingTaskAppService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/MappingTaskAppService.java
new file mode 100644
index 0000000..41ed340
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/MappingTaskAppService.java
@@ -0,0 +1,135 @@
+package com.njcn.gather.icd.mapping.application;
+
+import com.njcn.gather.icd.mapping.application.command.GenerateFromIcdCommand;
+import com.njcn.gather.icd.mapping.application.result.GenerateMappingResult;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexAnalysis;
+import com.njcn.gather.icd.mapping.domain.model.analysis.ValidationResult;
+import com.njcn.gather.icd.mapping.domain.model.icd.IcdDocument;
+import com.njcn.gather.icd.mapping.domain.model.mapping.MappingDocument;
+import com.njcn.gather.icd.mapping.domain.model.template.DefaultTemplate;
+import com.njcn.gather.icd.mapping.domain.service.DefaultTemplateLoader;
+import com.njcn.gather.icd.mapping.domain.service.IcdParserService;
+import com.njcn.gather.icd.mapping.domain.service.IndexAnalysisService;
+import com.njcn.gather.icd.mapping.domain.service.IndexValidationService;
+import com.njcn.gather.icd.mapping.domain.service.MappingGenerationService;
+import com.njcn.gather.icd.mapping.enums.GenerateStatus;
+import com.njcn.gather.icd.mapping.infrastructure.serializer.MappingDocumentSerializer;
+import com.njcn.gather.icd.mapping.infrastructure.storage.FileStorageService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 生成任务应用服务。
+ *
+ * 完整流程:
+ * 1. 解析 ICD;
+ * 2. 读取 DefaultCfg.txt;
+ * 3. 按业务分组生成候选项;
+ * 4. 如果用户未提交绑定关系,返回 NEED_INDEX_SELECTION;
+ * 5. 如果提交了绑定关系,先做合法性校验;
+ * 6. 校验通过后生成正式 MappingDocument;
+ * 7. 序列化并按需落盘。
+ */
+@Service
+public class MappingTaskAppService {
+
+ private final IcdParserService icdParserService;
+ private final DefaultTemplateLoader defaultTemplateLoader;
+ private final IndexAnalysisService indexAnalysisService;
+ private final IndexValidationService indexValidationService;
+ private final MappingGenerationService mappingGenerationService;
+ private final MappingDocumentSerializer mappingDocumentSerializer;
+ private final FileStorageService fileStorageService;
+
+ public MappingTaskAppService(IcdParserService icdParserService,
+ DefaultTemplateLoader defaultTemplateLoader,
+ IndexAnalysisService indexAnalysisService,
+ IndexValidationService indexValidationService,
+ MappingGenerationService mappingGenerationService,
+ MappingDocumentSerializer mappingDocumentSerializer,
+ FileStorageService fileStorageService) {
+ this.icdParserService = icdParserService;
+ this.defaultTemplateLoader = defaultTemplateLoader;
+ this.indexAnalysisService = indexAnalysisService;
+ this.indexValidationService = indexValidationService;
+ this.mappingGenerationService = mappingGenerationService;
+ this.mappingDocumentSerializer = mappingDocumentSerializer;
+ this.fileStorageService = fileStorageService;
+ }
+
+ public GenerateMappingResult generateFromIcd(GenerateFromIcdCommand command) {
+ GenerateMappingResult result = new GenerateMappingResult();
+ try {
+ // 1. 解析 ICD
+ IcdDocument icdDocument = icdParserService.parse(command.getFileBytes(), command.getFileName());
+ result.setIedName(icdDocument.getIedName());
+ result.setLdInst(icdDocument.getLdInst());
+
+ // 2. 加载 DefaultCfg.txt
+ DefaultTemplate template = defaultTemplateLoader.load();
+ result.getProblems().addAll(template.verify());
+
+ // 3. 分析索引候选
+ IndexAnalysis indexAnalysis = indexAnalysisService.analyze(icdDocument, template);
+ result.setIndexAnalysis(indexAnalysis);
+ result.getProblems().addAll(indexAnalysis.getProblems());
+
+ // 4. 如果没有提交任何绑定关系,则直接返回待匹配项
+ if (command.getIndexSelection() == null || command.getIndexSelection().isEmpty()) {
+ result.setStatus(GenerateStatus.NEED_INDEX_SELECTION);
+ result.setMessage("索引配置缺失或不合法,请根据候选信息完成标签与数字索引的绑定后重新提交");
+ return result;
+ }
+
+ // 5. 校验用户提交的绑定关系
+ ValidationResult validationResult = indexValidationService.validate(indexAnalysis, command.getIndexSelection());
+ if (!validationResult.isValid()) {
+ result.setStatus(GenerateStatus.NEED_INDEX_SELECTION);
+ result.setMessage("索引配置缺失或不合法,请根据候选信息完成标签与数字索引的绑定后重新提交");
+ result.getProblems().addAll(validationResult.getProblems());
+ return result;
+ }
+
+ // 6. 生成正式映射结构
+ MappingDocument mappingDocument = mappingGenerationService.generate(
+ icdDocument,
+ template,
+ indexAnalysis,
+ command.getIndexSelection(),
+ command.getVersion(),
+ command.getAuthor()
+ );
+ result.setMappingDocument(mappingDocument);
+
+ // 7. 序列化输出
+ String mappingJson = command.isPrettyJson()
+ ? mappingDocumentSerializer.toPrettyJson(mappingDocument)
+ : mappingDocumentSerializer.toCompactJson(mappingDocument);
+ result.setMappingJson(mappingJson);
+
+ if (command.isSaveToDisk()) {
+ String fileName = buildOutputFileName(icdDocument, command.isPrettyJson());
+ String savedPath = fileStorageService.save(fileName, mappingJson, command.getOutputDir());
+ result.setSavedPath(savedPath);
+ }
+
+ result.setStatus(GenerateStatus.SUCCESS);
+ result.setMessage("映射生成成功");
+ return result;
+ } catch (Exception ex) {
+ result.setStatus(GenerateStatus.FAILED);
+ result.setMessage("映射生成失败:" + ex.getMessage());
+ result.getProblems().add(ex.getMessage());
+ return result;
+ }
+ }
+
+ private String buildOutputFileName(IcdDocument icdDocument, boolean prettyJson) {
+ String baseName = icdDocument.getIedName() == null ? "mapping" : icdDocument.getIedName();
+ // 落盘文件名只保留安全字符,避免 IED 名称携带路径分隔符导致越界写入。
+ String safeBaseName = baseName.replaceAll("[\\\\/:*?\"<>|]+", "_").trim();
+ if (safeBaseName.isEmpty()) {
+ safeBaseName = "mapping";
+ }
+ return safeBaseName + (prettyJson ? "-mapping-pretty.json" : "-mapping.json");
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/GenerateFromIcdCommand.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/GenerateFromIcdCommand.java
new file mode 100644
index 0000000..23d7479
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/GenerateFromIcdCommand.java
@@ -0,0 +1,102 @@
+package com.njcn.gather.icd.mapping.application.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 生成命令对象。
+ *
+ * 说明:
+ * controller 层不要把 MultipartFile 和 request 直接传进领域服务;
+ * 统一转成 command,便于应用层做流程编排。
+ */
+public class GenerateFromIcdCommand {
+
+ /** 原始文件名。 */
+ private String fileName;
+
+ /** ICD 文件字节数组。 */
+ private byte[] fileBytes;
+
+ /** 输出版本号。 */
+ private String version;
+
+ /** 作者。 */
+ private String author;
+
+ /** 是否保存到磁盘。 */
+ private boolean saveToDisk;
+
+ /** 是否输出美化 JSON。 */
+ private boolean prettyJson;
+
+ /** 输出目录。 */
+ private String outputDir;
+
+ /** 用户上送的索引选择结果。 */
+ private List indexSelection = new ArrayList();
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public byte[] getFileBytes() {
+ return fileBytes;
+ }
+
+ public void setFileBytes(byte[] fileBytes) {
+ this.fileBytes = fileBytes;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public boolean isSaveToDisk() {
+ return saveToDisk;
+ }
+
+ public void setSaveToDisk(boolean saveToDisk) {
+ this.saveToDisk = saveToDisk;
+ }
+
+ public boolean isPrettyJson() {
+ return prettyJson;
+ }
+
+ public void setPrettyJson(boolean prettyJson) {
+ this.prettyJson = prettyJson;
+ }
+
+ public String getOutputDir() {
+ return outputDir;
+ }
+
+ public void setOutputDir(String outputDir) {
+ this.outputDir = outputDir;
+ }
+
+ public List getIndexSelection() {
+ return indexSelection;
+ }
+
+ public void setIndexSelection(List indexSelection) {
+ this.indexSelection = indexSelection;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexBindingCommand.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexBindingCommand.java
new file mode 100644
index 0000000..44a065b
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexBindingCommand.java
@@ -0,0 +1,51 @@
+package com.njcn.gather.icd.mapping.application.command;
+
+/**
+ * 应用层单条绑定命令。
+ */
+public class IndexBindingCommand {
+
+ /** 报告名。 */
+ private String reportName;
+
+ /** 数据集名。 */
+ private String dataSetName;
+
+ /** 标签。 */
+ private String label;
+
+ /** 绑定到的 lnInst 数字。 */
+ private String lnInst;
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getLnInst() {
+ return lnInst;
+ }
+
+ public void setLnInst(String lnInst) {
+ this.lnInst = lnInst;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexSelectionGroupCommand.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexSelectionGroupCommand.java
new file mode 100644
index 0000000..ad7e239
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/command/IndexSelectionGroupCommand.java
@@ -0,0 +1,43 @@
+package com.njcn.gather.icd.mapping.application.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 应用层分组选择命令。
+ */
+public class IndexSelectionGroupCommand {
+
+ /** 分组唯一键。 */
+ private String groupKey;
+
+ /** 分组中文描述。 */
+ private String groupDesc;
+
+ /** 当前分组下的多条绑定关系。 */
+ private List bindings = new ArrayList();
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public List getBindings() {
+ return bindings;
+ }
+
+ public void setBindings(List bindings) {
+ this.bindings = bindings;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/result/GenerateMappingResult.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/result/GenerateMappingResult.java
new file mode 100644
index 0000000..1330121
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/application/result/GenerateMappingResult.java
@@ -0,0 +1,42 @@
+package com.njcn.gather.icd.mapping.application.result;
+
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexAnalysis;
+import com.njcn.gather.icd.mapping.domain.model.mapping.MappingDocument;
+import com.njcn.gather.icd.mapping.enums.GenerateStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 应用层返回对象。统一封装成功、需要选择索引、失败三类结果。
+ */
+public class GenerateMappingResult {
+ private GenerateStatus status;
+ private String message;
+ private String iedName;
+ private String ldInst;
+ private IndexAnalysis indexAnalysis;
+ private MappingDocument mappingDocument;
+ private String mappingJson;
+ private String savedPath;
+ private List problems = new ArrayList();
+
+ public GenerateStatus getStatus() { return status; }
+ public void setStatus(GenerateStatus status) { this.status = status; }
+ public String getMessage() { return message; }
+ public void setMessage(String message) { this.message = message; }
+ public String getIedName() { return iedName; }
+ public void setIedName(String iedName) { this.iedName = iedName; }
+ public String getLdInst() { return ldInst; }
+ public void setLdInst(String ldInst) { this.ldInst = ldInst; }
+ public IndexAnalysis getIndexAnalysis() { return indexAnalysis; }
+ public void setIndexAnalysis(IndexAnalysis indexAnalysis) { this.indexAnalysis = indexAnalysis; }
+ public MappingDocument getMappingDocument() { return mappingDocument; }
+ public void setMappingDocument(MappingDocument mappingDocument) { this.mappingDocument = mappingDocument; }
+ public String getMappingJson() { return mappingJson; }
+ public void setMappingJson(String mappingJson) { this.mappingJson = mappingJson; }
+ public String getSavedPath() { return savedPath; }
+ public void setSavedPath(String savedPath) { this.savedPath = savedPath; }
+ public List getProblems() { return problems; }
+ public void setProblems(List problems) { this.problems = problems; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/config/MappingModuleConfig.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/config/MappingModuleConfig.java
new file mode 100644
index 0000000..3021ca7
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/config/MappingModuleConfig.java
@@ -0,0 +1,52 @@
+package com.njcn.gather.icd.mapping.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * 模块配置。
+ * 模块配置类。集中管理默认作者、默认模板路径等可配置项。
+ *
+ * 说明:
+ * 1. 这里把模板路径、输出目录、默认作者等集中管理。
+ * 2. 当前先用 @Value + 默认值,后续你也可以改成 @ConfigurationProperties。
+ */
+@Component
+public class MappingModuleConfig {
+
+ /** 默认模板资源路径。 */
+ @Value("${icd.mapping.default-template-path:template/DefaultCfg.txt}")
+ private String defaultTemplatePath;
+
+ /** 默认作者。 */
+ @Value("${icd.mapping.default-author:system}")
+ private String defaultAuthor;
+
+ /** 默认输出目录。 */
+ @Value("${icd.mapping.default-output-dir:}")
+ private String defaultOutputDir;
+
+ public String getDefaultTemplatePath() {
+ return defaultTemplatePath;
+ }
+
+ public void setDefaultTemplatePath(String defaultTemplatePath) {
+ this.defaultTemplatePath = defaultTemplatePath;
+ }
+
+ public String getDefaultAuthor() {
+ return defaultAuthor;
+ }
+
+ public void setDefaultAuthor(String defaultAuthor) {
+ this.defaultAuthor = defaultAuthor;
+ }
+
+ public String getDefaultOutputDir() {
+ return defaultOutputDir;
+ }
+
+ public void setDefaultOutputDir(String defaultOutputDir) {
+ this.defaultOutputDir = defaultOutputDir;
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/MappingController.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/MappingController.java
new file mode 100644
index 0000000..292057d
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/MappingController.java
@@ -0,0 +1,50 @@
+package com.njcn.gather.icd.mapping.controller;
+
+import com.njcn.gather.icd.mapping.application.MappingTaskAppService;
+import com.njcn.gather.icd.mapping.application.command.GenerateFromIcdCommand;
+import com.njcn.gather.icd.mapping.application.result.GenerateMappingResult;
+import com.njcn.gather.icd.mapping.controller.request.GenerateMappingFromIcdRequest;
+import com.njcn.gather.icd.mapping.controller.response.MappingTaskResponse;
+import com.njcn.gather.icd.mapping.converter.MappingRequestConverter;
+import com.njcn.gather.icd.mapping.converter.MappingResponseConverter;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * ICD 映射接口。
+ */
+@RestController
+@RequestMapping("/api/mms-mapping")
+public class MappingController {
+
+ private final MappingTaskAppService mappingTaskAppService;
+ private final MappingRequestConverter requestConverter;
+ private final MappingResponseConverter responseConverter;
+
+ public MappingController(MappingTaskAppService mappingTaskAppService,
+ MappingRequestConverter requestConverter,
+ MappingResponseConverter responseConverter) {
+ this.mappingTaskAppService = mappingTaskAppService;
+ this.requestConverter = requestConverter;
+ this.responseConverter = responseConverter;
+ }
+
+ /**
+ * 上传 ICD 并生成映射。
+ *
+ * 表单参数:
+ * 1. icdFile:ICD 文件
+ * 2. request:JSON 请求体
+ */
+ @PostMapping(value = "/generate-from-icd", consumes = {"multipart/form-data"})
+ public MappingTaskResponse generateFromIcd(@RequestPart("icdFile") MultipartFile icdFile,
+ @Validated @RequestPart("request") GenerateMappingFromIcdRequest request) {
+ GenerateFromIcdCommand command = requestConverter.toCommand(icdFile, request);
+ GenerateMappingResult result = mappingTaskAppService.generateFromIcd(command);
+ return responseConverter.fromResult(result);
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/GenerateMappingFromIcdRequest.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/GenerateMappingFromIcdRequest.java
new file mode 100644
index 0000000..e9f86de
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/GenerateMappingFromIcdRequest.java
@@ -0,0 +1,89 @@
+package com.njcn.gather.icd.mapping.controller.request;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 生成映射接口请求体。
+ *
+ * 说明:
+ * 1. 旧版结构中,indexSelection 是 Map,只能表达“一个报告对应一个值”,
+ * 无法表达“一个业务分组下有多个报告、一个报告下又有多条标签绑定”的真实场景。
+ * 2. 新版结构改成 List,用来完整承载用户在前端完成的绑定结果。
+ * 3. 第一次只上传 ICD 时,这个字段可以为空;第二次用户确认绑定后再把完整结构上送即可。
+ */
+public class GenerateMappingFromIcdRequest {
+
+ /** 输出版本号。为空时后端默认补 1.0。 */
+ private String version;
+
+ /** 作者。为空时默认空字符串。 */
+ private String author;
+
+ /** 是否保存到磁盘。 */
+ private boolean saveToDisk;
+
+ /** 是否返回美化 JSON。 */
+ private boolean prettyJson;
+
+ /** 输出目录。saveToDisk=true 时才会用到。 */
+ private String outputDir;
+
+ /**
+ * 索引选择结果。
+ *
+ * 说明:
+ * 1. 每一个元素代表一个“业务分组”,例如:实时数据、统计数据、波动闪变。
+ * 2. 每个业务分组下面又包含多条绑定关系。
+ * 3. 允许为空;为空时后端返回 NEED_INDEX_SELECTION,给前端候选参考项。
+ */
+ private List indexSelection = new ArrayList();
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public boolean isSaveToDisk() {
+ return saveToDisk;
+ }
+
+ public void setSaveToDisk(boolean saveToDisk) {
+ this.saveToDisk = saveToDisk;
+ }
+
+ public boolean isPrettyJson() {
+ return prettyJson;
+ }
+
+ public void setPrettyJson(boolean prettyJson) {
+ this.prettyJson = prettyJson;
+ }
+
+ public String getOutputDir() {
+ return outputDir;
+ }
+
+ public void setOutputDir(String outputDir) {
+ this.outputDir = outputDir;
+ }
+
+ public List getIndexSelection() {
+ return indexSelection;
+ }
+
+ public void setIndexSelection(List indexSelection) {
+ this.indexSelection = indexSelection;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexBindingRequest.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexBindingRequest.java
new file mode 100644
index 0000000..7f64576
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexBindingRequest.java
@@ -0,0 +1,59 @@
+package com.njcn.gather.icd.mapping.controller.request;
+
+/**
+ * 单条索引绑定请求。
+ *
+ * 一条绑定只表达一个最小关系:
+ * 某个报告(reportName)下,使用某个标签(label)与某个 lnInst 数字做绑定。
+ *
+ * 这样做的好处:
+ * 1. 一个报告可以出现多次,对应多个标签。
+ * 2. 一个业务分组下也可以有多个报告。
+ * 3. 后端校验、生成映射时都更容易逐条处理。
+ */
+public class IndexBindingRequest {
+
+ /** 绑定发生在哪个报告上,例如:brcbStHarm。 */
+ private String reportName;
+
+ /** 绑定发生在哪个数据集上,例如:dsStHarm。 */
+ private String dataSetName;
+
+ /** 业务标签,例如:最大值、最小值、实时数据。 */
+ private String label;
+
+ /** 当前标签最终绑定到的 lnInst 数字,例如:1、2、8。 */
+ private String lnInst;
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getLnInst() {
+ return lnInst;
+ }
+
+ public void setLnInst(String lnInst) {
+ this.lnInst = lnInst;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexSelectionGroupRequest.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexSelectionGroupRequest.java
new file mode 100644
index 0000000..5d2b77e
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/request/IndexSelectionGroupRequest.java
@@ -0,0 +1,53 @@
+package com.njcn.gather.icd.mapping.controller.request;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 单个业务分组的索引选择请求。
+ *
+ * 例如:
+ * - groupKey = REALTIME_DATA
+ * - groupDesc = 实时数据
+ * - bindings = 多条“报告 + 标签 + lnInst”的绑定关系
+ */
+public class IndexSelectionGroupRequest {
+
+ /**
+ * 分组唯一键。
+ *
+ * 说明:
+ * 这个值由后端在 NEED_INDEX_SELECTION 时返回,前端原样带回即可,避免仅靠中文描述做匹配。
+ */
+ private String groupKey;
+
+ /** 分组中文描述,例如:实时数据、统计数据。 */
+ private String groupDesc;
+
+ /** 当前业务分组下,用户最终确认的绑定关系。 */
+ private List bindings = new ArrayList();
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public List getBindings() {
+ return bindings;
+ }
+
+ public void setBindings(List bindings) {
+ this.bindings = bindings;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateReportItemResponse.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateReportItemResponse.java
new file mode 100644
index 0000000..687b7ff
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateReportItemResponse.java
@@ -0,0 +1,54 @@
+package com.njcn.gather.icd.mapping.controller.response;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 索引候选分组下的单个报告响应。
+ */
+public class IndexCandidateReportItemResponse {
+
+ /** 报告名称。 */
+ private String reportName;
+
+ /** 数据集名称。 */
+ private String dataSetName;
+
+ /** 报告描述。 */
+ private String reportDesc;
+
+ /** 当前报告可选的 lnInst 数字。 */
+ private List availableLnInstValues = new ArrayList();
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getReportDesc() {
+ return reportDesc;
+ }
+
+ public void setReportDesc(String reportDesc) {
+ this.reportDesc = reportDesc;
+ }
+
+ public List getAvailableLnInstValues() {
+ return availableLnInstValues;
+ }
+
+ public void setAvailableLnInstValues(List availableLnInstValues) {
+ this.availableLnInstValues = availableLnInstValues;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateResponse.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateResponse.java
new file mode 100644
index 0000000..d6c9f74
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/IndexCandidateResponse.java
@@ -0,0 +1,71 @@
+package com.njcn.gather.icd.mapping.controller.response;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 索引候选返回对象。
+ *
+ * 说明:
+ * 这是给前端“待匹配界面”使用的正式结构:
+ * - 一个候选就是一个业务分组;
+ * - 分组下面再挂多个报告;
+ * - 前端根据 templateLabels 与 reports[*].availableLnInstValues 做人工绑定。
+ */
+public class IndexCandidateResponse {
+
+ /** 分组唯一键。 */
+ private String groupKey;
+
+ /** 分组中文描述。 */
+ private String groupDesc;
+
+ /** 当前分组包含的报告数。 */
+ private int reportCount;
+
+ /** 模板里配置的可选标签。 */
+ private List templateLabels = new ArrayList();
+
+ /** 当前分组下的报告候选列表。 */
+ private List reports = new ArrayList();
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public int getReportCount() {
+ return reportCount;
+ }
+
+ public void setReportCount(int reportCount) {
+ this.reportCount = reportCount;
+ }
+
+ public List getTemplateLabels() {
+ return templateLabels;
+ }
+
+ public void setTemplateLabels(List templateLabels) {
+ this.templateLabels = templateLabels;
+ }
+
+ public List getReports() {
+ return reports;
+ }
+
+ public void setReports(List reports) {
+ this.reports = reports;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingDocumentResponse.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingDocumentResponse.java
new file mode 100644
index 0000000..31fcfd9
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingDocumentResponse.java
@@ -0,0 +1,26 @@
+package com.njcn.gather.icd.mapping.controller.response;
+
+/**
+ * 映射摘要响应。
+ * 映射摘要响应 DTO。用于把最终映射的关键信息单独封装返回。
+ */
+public class MappingDocumentResponse {
+ private String version;
+ private String author;
+ private String ied;
+ private String ld;
+ private int reportCount;
+ private int dataSetCount;
+ public String getVersion() { return version; }
+ public void setVersion(String version) { this.version = version; }
+ public String getAuthor() { return author; }
+ public void setAuthor(String author) { this.author = author; }
+ public String getIed() { return ied; }
+ public void setIed(String ied) { this.ied = ied; }
+ public String getLd() { return ld; }
+ public void setLd(String ld) { this.ld = ld; }
+ public int getReportCount() { return reportCount; }
+ public void setReportCount(int reportCount) { this.reportCount = reportCount; }
+ public int getDataSetCount() { return dataSetCount; }
+ public void setDataSetCount(int dataSetCount) { this.dataSetCount = dataSetCount; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingTaskResponse.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingTaskResponse.java
new file mode 100644
index 0000000..1b10c01
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/controller/response/MappingTaskResponse.java
@@ -0,0 +1,40 @@
+package com.njcn.gather.icd.mapping.controller.response;
+
+import com.njcn.gather.icd.mapping.enums.GenerateStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 第一个接口统一响应。
+ * 接口统一响应 DTO。返回生成状态、映射内容、候选索引、问题列表等。
+ */
+public class MappingTaskResponse {
+ private GenerateStatus status;
+ private String message;
+ private String iedName;
+ private String ldInst;
+ private String mappingJson;
+ private String savedPath;
+ private MappingDocumentResponse mappingDocument;
+ private List indexCandidates = new ArrayList();
+ private List problems = new ArrayList();
+ public GenerateStatus getStatus() { return status; }
+ public void setStatus(GenerateStatus status) { this.status = status; }
+ public String getMessage() { return message; }
+ public void setMessage(String message) { this.message = message; }
+ public String getIedName() { return iedName; }
+ public void setIedName(String iedName) { this.iedName = iedName; }
+ public String getLdInst() { return ldInst; }
+ public void setLdInst(String ldInst) { this.ldInst = ldInst; }
+ public String getMappingJson() { return mappingJson; }
+ public void setMappingJson(String mappingJson) { this.mappingJson = mappingJson; }
+ public String getSavedPath() { return savedPath; }
+ public void setSavedPath(String savedPath) { this.savedPath = savedPath; }
+ public MappingDocumentResponse getMappingDocument() { return mappingDocument; }
+ public void setMappingDocument(MappingDocumentResponse mappingDocument) { this.mappingDocument = mappingDocument; }
+ public List getIndexCandidates() { return indexCandidates; }
+ public void setIndexCandidates(List indexCandidates) { this.indexCandidates = indexCandidates; }
+ public List getProblems() { return problems; }
+ public void setProblems(List problems) { this.problems = problems; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingRequestConverter.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingRequestConverter.java
new file mode 100644
index 0000000..d57d816
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingRequestConverter.java
@@ -0,0 +1,82 @@
+package com.njcn.gather.icd.mapping.converter;
+
+import com.njcn.gather.icd.mapping.application.command.GenerateFromIcdCommand;
+import com.njcn.gather.icd.mapping.application.command.IndexBindingCommand;
+import com.njcn.gather.icd.mapping.application.command.IndexSelectionGroupCommand;
+import com.njcn.gather.icd.mapping.config.MappingModuleConfig;
+import com.njcn.gather.icd.mapping.controller.request.GenerateMappingFromIcdRequest;
+import com.njcn.gather.icd.mapping.controller.request.IndexBindingRequest;
+import com.njcn.gather.icd.mapping.controller.request.IndexSelectionGroupRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 请求转换器。
+ *
+ * 作用:
+ * 1. 把接口层 request 转成应用层 command。
+ * 2. 统一处理 null 和空集合,避免后面业务层到处判空。
+ */
+@Component
+public class MappingRequestConverter {
+
+ private final MappingModuleConfig moduleConfig;
+
+ public MappingRequestConverter(MappingModuleConfig moduleConfig) {
+ this.moduleConfig = moduleConfig;
+ }
+
+ public GenerateFromIcdCommand toCommand(MultipartFile icdFile, GenerateMappingFromIcdRequest request) {
+ try {
+ if (icdFile == null || icdFile.isEmpty()) {
+ throw new IllegalArgumentException("ICD 文件不能为空");
+ }
+ GenerateFromIcdCommand command = new GenerateFromIcdCommand();
+ command.setFileName(icdFile.getOriginalFilename());
+ command.setFileBytes(icdFile.getBytes());
+ command.setVersion(request == null ? null : request.getVersion());
+ command.setAuthor(resolveText(request == null ? null : request.getAuthor(), moduleConfig.getDefaultAuthor()));
+ command.setSaveToDisk(request != null && request.isSaveToDisk());
+ command.setPrettyJson(request == null || request.isPrettyJson());
+ command.setOutputDir(resolveText(request == null ? null : request.getOutputDir(), moduleConfig.getDefaultOutputDir()));
+
+ if (request != null && request.getIndexSelection() != null) {
+ for (IndexSelectionGroupRequest groupRequest : request.getIndexSelection()) {
+ if (groupRequest == null) {
+ continue;
+ }
+ IndexSelectionGroupCommand groupCommand = new IndexSelectionGroupCommand();
+ groupCommand.setGroupKey(groupRequest.getGroupKey());
+ groupCommand.setGroupDesc(groupRequest.getGroupDesc());
+
+ if (groupRequest.getBindings() != null) {
+ for (IndexBindingRequest bindingRequest : groupRequest.getBindings()) {
+ if (bindingRequest == null) {
+ continue;
+ }
+ IndexBindingCommand bindingCommand = new IndexBindingCommand();
+ bindingCommand.setReportName(bindingRequest.getReportName());
+ bindingCommand.setDataSetName(bindingRequest.getDataSetName());
+ bindingCommand.setLabel(bindingRequest.getLabel());
+ bindingCommand.setLnInst(bindingRequest.getLnInst());
+ groupCommand.getBindings().add(bindingCommand);
+ }
+ }
+
+ command.getIndexSelection().add(groupCommand);
+ }
+ }
+
+ return command;
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("请求转换失败:" + ex.getMessage(), ex);
+ }
+ }
+
+ private String resolveText(String value, String defaultValue) {
+ if (value != null && !value.trim().isEmpty()) {
+ return value.trim();
+ }
+ return defaultValue == null ? null : defaultValue.trim();
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingResponseConverter.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingResponseConverter.java
new file mode 100644
index 0000000..ff6844a
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/converter/MappingResponseConverter.java
@@ -0,0 +1,70 @@
+package com.njcn.gather.icd.mapping.converter;
+
+import com.njcn.gather.icd.mapping.application.result.GenerateMappingResult;
+import com.njcn.gather.icd.mapping.controller.response.IndexCandidateReportItemResponse;
+import com.njcn.gather.icd.mapping.controller.response.IndexCandidateResponse;
+import com.njcn.gather.icd.mapping.controller.response.MappingDocumentResponse;
+import com.njcn.gather.icd.mapping.controller.response.MappingTaskResponse;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidate;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidateReportItem;
+import org.springframework.stereotype.Component;
+
+/**
+ * 响应转换器。
+ *
+ * 作用:
+ * 1. 把应用层结果转换成接口层响应对象;
+ * 2. 对待匹配索引场景,输出新的“按业务分组返回”的结构。
+ */
+@Component
+public class MappingResponseConverter {
+
+ public MappingTaskResponse fromResult(GenerateMappingResult result) {
+ MappingTaskResponse response = new MappingTaskResponse();
+ response.setStatus(result.getStatus());
+ response.setMessage(result.getMessage());
+ response.setIedName(result.getIedName());
+ response.setLdInst(result.getLdInst());
+ response.setMappingJson(result.getMappingJson());
+ response.setSavedPath(result.getSavedPath());
+ response.getProblems().addAll(result.getProblems());
+
+ if (result.getIndexAnalysis() != null && result.getIndexAnalysis().getCandidates() != null) {
+ for (IndexCandidate candidate : result.getIndexAnalysis().getCandidates()) {
+ IndexCandidateResponse candidateResponse = new IndexCandidateResponse();
+ candidateResponse.setGroupKey(candidate.getGroupKey());
+ candidateResponse.setGroupDesc(candidate.getGroupDesc());
+ candidateResponse.setReportCount(candidate.getReportCount());
+ candidateResponse.getTemplateLabels().addAll(candidate.getTemplateLabels());
+
+ if (candidate.getReports() != null) {
+ for (IndexCandidateReportItem item : candidate.getReports()) {
+ IndexCandidateReportItemResponse itemResponse = new IndexCandidateReportItemResponse();
+ itemResponse.setReportName(item.getReportName());
+ itemResponse.setDataSetName(item.getDataSetName());
+ itemResponse.setReportDesc(item.getReportDesc());
+ itemResponse.getAvailableLnInstValues().addAll(item.getAvailableLnInstValues());
+ candidateResponse.getReports().add(itemResponse);
+ }
+ }
+
+ response.getIndexCandidates().add(candidateResponse);
+ }
+ }
+
+ if (result.getMappingDocument() != null) {
+ MappingDocumentResponse doc = new MappingDocumentResponse();
+ doc.setVersion(result.getMappingDocument().getVersion());
+ doc.setAuthor(result.getMappingDocument().getAuthor());
+ doc.setIed(result.getMappingDocument().getIed());
+ doc.setLd(result.getMappingDocument().getLd());
+ doc.setReportCount(result.getMappingDocument().getReportMap() == null
+ ? 0 : result.getMappingDocument().getReportMap().size());
+ doc.setDataSetCount(result.getMappingDocument().getDataSetList() == null
+ ? 0 : result.getMappingDocument().getDataSetList().size());
+ response.setMappingDocument(doc);
+ }
+
+ return response;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexAnalysis.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexAnalysis.java
new file mode 100644
index 0000000..dd3f714
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexAnalysis.java
@@ -0,0 +1,20 @@
+package com.njcn.gather.icd.mapping.domain.model.analysis;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 索引分析结果。
+ * 索引分析结果模型。保存每个报告可选的 lnInst 候选列表及问题清单。
+ *
+ * key = reportName
+ */
+public class IndexAnalysis {
+ private List candidates = new ArrayList();
+ private List problems = new ArrayList();
+
+ public List getCandidates() { return candidates; }
+ public void setCandidates(List candidates) { this.candidates = candidates; }
+ public List getProblems() { return problems; }
+ public void setProblems(List problems) { this.problems = problems; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidate.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidate.java
new file mode 100644
index 0000000..957ca83
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidate.java
@@ -0,0 +1,113 @@
+package com.njcn.gather.icd.mapping.domain.model.analysis;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 索引候选分组。
+ *
+ * 说明:
+ * 1. 一条候选对应一个业务分组,例如:统计数据、实时数据;
+ * 2. 一个业务分组下可以包含多个报告;
+ * 3. 这里不仅保存返回给前端的候选项,也保存从 DefaultCfg.ReportList 带下来的配置项,
+ * 供后续 MappingGenerationService 直接使用,避免“二次查模板”失败。
+ */
+public class IndexCandidate {
+
+ /** 分组唯一键。 */
+ private String groupKey;
+
+ /** 分组描述。 */
+ private String groupDesc;
+
+ /** 该分组下实际匹配到的报告数量。 */
+ private int reportCount;
+
+ /** DefaultCfg.txt 中该分组可用的标签模板。 */
+ private List templateLabels = new ArrayList();
+
+ /** 当前分组下匹配到的报告列表。 */
+ private List reports = new ArrayList();
+
+ /**
+ * DefaultCfg.ReportList.inst
+ * 例如:01 / 02 / 03 / 04
+ */
+ private String reportInst;
+
+ /**
+ * DefaultCfg.ReportList.Select
+ * 例如:DataStatFileMap / DataRealFileMap / FlickerFileMap
+ */
+ private String select;
+
+ /**
+ * DefaultCfg.ReportList.TrgOps
+ * 例如:40 / 96
+ */
+ private String trgOps;
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public int getReportCount() {
+ return reportCount;
+ }
+
+ public void setReportCount(int reportCount) {
+ this.reportCount = reportCount;
+ }
+
+ public List getTemplateLabels() {
+ return templateLabels;
+ }
+
+ public void setTemplateLabels(List templateLabels) {
+ this.templateLabels = templateLabels;
+ }
+
+ public List getReports() {
+ return reports;
+ }
+
+ public void setReports(List reports) {
+ this.reports = reports;
+ }
+
+ public String getReportInst() {
+ return reportInst;
+ }
+
+ public void setReportInst(String reportInst) {
+ this.reportInst = reportInst;
+ }
+
+ public String getSelect() {
+ return select;
+ }
+
+ public void setSelect(String select) {
+ this.select = select;
+ }
+
+ public String getTrgOps() {
+ return trgOps;
+ }
+
+ public void setTrgOps(String trgOps) {
+ this.trgOps = trgOps;
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidateReportItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidateReportItem.java
new file mode 100644
index 0000000..3620ae7
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/IndexCandidateReportItem.java
@@ -0,0 +1,56 @@
+package com.njcn.gather.icd.mapping.domain.model.analysis;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 候选分组下的单个报告项。
+ *
+ * 这个对象专门给前端展示“这个分组下面有哪些报告,以及每个报告对应哪些可用 lnInst 数字”。
+ */
+public class IndexCandidateReportItem {
+
+ /** 报告名称。 */
+ private String reportName;
+
+ /** 数据集名称。 */
+ private String dataSetName;
+
+ /** 报告中文描述。一般和分组描述相同,保留它是为了前端渲染更灵活。 */
+ private String reportDesc;
+
+ /** 当前报告在 ICD 中解析出来的所有可选 lnInst 数字。 */
+ private List availableLnInstValues = new ArrayList();
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getReportDesc() {
+ return reportDesc;
+ }
+
+ public void setReportDesc(String reportDesc) {
+ this.reportDesc = reportDesc;
+ }
+
+ public List getAvailableLnInstValues() {
+ return availableLnInstValues;
+ }
+
+ public void setAvailableLnInstValues(List availableLnInstValues) {
+ this.availableLnInstValues = availableLnInstValues;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/ValidationResult.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/ValidationResult.java
new file mode 100644
index 0000000..1ed5c89
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/analysis/ValidationResult.java
@@ -0,0 +1,18 @@
+package com.njcn.gather.icd.mapping.domain.model.analysis;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 校验结果。
+ * 索引校验结果模型。保存是否通过以及问题列表。
+ */
+public class ValidationResult {
+ private boolean valid;
+ private List problems = new ArrayList();
+
+ public boolean isValid() { return valid; }
+ public void setValid(boolean valid) { this.valid = valid; }
+ public List getProblems() { return problems; }
+ public void setProblems(List problems) { this.problems = problems; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DataSetNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DataSetNode.java
new file mode 100644
index 0000000..04e7a31
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DataSetNode.java
@@ -0,0 +1,17 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DataSet 节点。
+ * 数据集模型。用于承接 DataSet 下的 FCDA 列表。
+ */
+public class DataSetNode {
+ private String name;
+ private List fcdas = new ArrayList();
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public List getFcdas() { return fcdas; }
+ public void setFcdas(List fcdas) { this.fcdas = fcdas; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiElementNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiElementNode.java
new file mode 100644
index 0000000..23cf301
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiElementNode.java
@@ -0,0 +1,31 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DOI/SDI/DAI 统一节点。
+ * DOI/SDI/DAI 细项模型。用于递归承接 DOI 树明细。
+ *
+ * kind 常见值:
+ * - SDI
+ * - DAI
+ */
+public class DoiElementNode {
+ private String kind;
+ private String name;
+ private Long ix;
+ private List values = new ArrayList();
+ private List children = new ArrayList();
+
+ public String getKind() { return kind; }
+ public void setKind(String kind) { this.kind = kind; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public Long getIx() { return ix; }
+ public void setIx(Long ix) { this.ix = ix; }
+ public List getValues() { return values; }
+ public void setValues(List values) { this.values = values; }
+ public List getChildren() { return children; }
+ public void setChildren(List children) { this.children = children; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiNode.java
new file mode 100644
index 0000000..51f7a37
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/DoiNode.java
@@ -0,0 +1,30 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DOI 节点。
+ * DOI 模型。表示逻辑节点下的一个数据对象节点。
+ */
+public class DoiNode {
+ private String name;
+ private Long ix;
+ private String lnClass;
+ private String lnInst;
+ private int sequenceCount;
+ private List children = new ArrayList();
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public Long getIx() { return ix; }
+ public void setIx(Long ix) { this.ix = ix; }
+ public String getLnClass() { return lnClass; }
+ public void setLnClass(String lnClass) { this.lnClass = lnClass; }
+ public String getLnInst() { return lnInst; }
+ public void setLnInst(String lnInst) { this.lnInst = lnInst; }
+ public int getSequenceCount() { return sequenceCount; }
+ public void setSequenceCount(int sequenceCount) { this.sequenceCount = sequenceCount; }
+ public List getChildren() { return children; }
+ public void setChildren(List children) { this.children = children; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/FcdaNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/FcdaNode.java
new file mode 100644
index 0000000..db985bf
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/FcdaNode.java
@@ -0,0 +1,36 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+/**
+ * FCDA 节点。
+ * FCDA 模型。保存 lnClass、lnInst、doName、daName、fc、ix 等信息。
+ */
+public class FcdaNode {
+ private String ldInst;
+ private String prefix;
+ private String lnClass;
+ private String lnInst;
+ private String doName;
+ private String daName;
+ private String fc;
+ private Long ix;
+ private int sequenceCount;
+
+ public String getLdInst() { return ldInst; }
+ public void setLdInst(String ldInst) { this.ldInst = ldInst; }
+ public String getPrefix() { return prefix; }
+ public void setPrefix(String prefix) { this.prefix = prefix; }
+ public String getLnClass() { return lnClass; }
+ public void setLnClass(String lnClass) { this.lnClass = lnClass; }
+ public String getLnInst() { return lnInst; }
+ public void setLnInst(String lnInst) { this.lnInst = lnInst; }
+ public String getDoName() { return doName; }
+ public void setDoName(String doName) { this.doName = doName; }
+ public String getDaName() { return daName; }
+ public void setDaName(String daName) { this.daName = daName; }
+ public String getFc() { return fc; }
+ public void setFc(String fc) { this.fc = fc; }
+ public Long getIx() { return ix; }
+ public void setIx(Long ix) { this.ix = ix; }
+ public int getSequenceCount() { return sequenceCount; }
+ public void setSequenceCount(int sequenceCount) { this.sequenceCount = sequenceCount; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IcdDocument.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IcdDocument.java
new file mode 100644
index 0000000..d3aed97
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IcdDocument.java
@@ -0,0 +1,46 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ICD 文档聚合根。
+ * ICD 统一领域模型的聚合根。承接 IED、LDevice、ReportControl、DataSet、LN 等解析结果。
+ *
+ * 说明:
+ * 1. 这是系统内部统一的 ICD 模型。
+ * 2. 外部 JAXB generated 类只在 parser 层使用。
+ * 3. 业务层全部依赖这个标准化模型,便于后续替换解析实现。
+ */
+public class IcdDocument {
+ private String fileName;
+ private String iedName;
+ private String ldInst;
+ private String ldPrefix;
+ private IedNode primaryIed;
+ private LogicalDeviceNode logicalDevice;
+ private List logicalNodes = new ArrayList();
+ private List reportControls = new ArrayList();
+ private Map dataSets = new LinkedHashMap();
+
+ public String getFileName() { return fileName; }
+ public void setFileName(String fileName) { this.fileName = fileName; }
+ public String getIedName() { return iedName; }
+ public void setIedName(String iedName) { this.iedName = iedName; }
+ public String getLdInst() { return ldInst; }
+ public void setLdInst(String ldInst) { this.ldInst = ldInst; }
+ public String getLdPrefix() { return ldPrefix; }
+ public void setLdPrefix(String ldPrefix) { this.ldPrefix = ldPrefix; }
+ public IedNode getPrimaryIed() { return primaryIed; }
+ public void setPrimaryIed(IedNode primaryIed) { this.primaryIed = primaryIed; }
+ public LogicalDeviceNode getLogicalDevice() { return logicalDevice; }
+ public void setLogicalDevice(LogicalDeviceNode logicalDevice) { this.logicalDevice = logicalDevice; }
+ public List getLogicalNodes() { return logicalNodes; }
+ public void setLogicalNodes(List logicalNodes) { this.logicalNodes = logicalNodes; }
+ public List getReportControls() { return reportControls; }
+ public void setReportControls(List reportControls) { this.reportControls = reportControls; }
+ public Map getDataSets() { return dataSets; }
+ public void setDataSets(Map dataSets) { this.dataSets = dataSets; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IedNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IedNode.java
new file mode 100644
index 0000000..efc1a35
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/IedNode.java
@@ -0,0 +1,20 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * IED 节点。
+ * IED 节点模型。保存 IED 名称以及其下逻辑设备引用。
+ */
+public class IedNode {
+ private String name;
+ private List accessPointNames = new ArrayList();
+ private List lDeviceInstList = new ArrayList();
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public List getAccessPointNames() { return accessPointNames; }
+ public void setAccessPointNames(List accessPointNames) { this.accessPointNames = accessPointNames; }
+ public List getLDeviceInstList() { return lDeviceInstList; }
+ public void setLDeviceInstList(List lDeviceInstList) { this.lDeviceInstList = lDeviceInstList; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LnNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LnNode.java
new file mode 100644
index 0000000..f106aa4
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LnNode.java
@@ -0,0 +1,32 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 逻辑节点。
+ * 逻辑节点模型。保存 lnClass、lnInst、prefix、DOI 等信息。
+ *
+ * LN0 和 LN 最终都统一抽象为这个模型。
+ */
+public class LnNode {
+ private boolean ln0;
+ private String prefix;
+ private String lnClass;
+ private String lnInst;
+ private String lnType;
+ private List doiList = new ArrayList();
+
+ public boolean isLn0() { return ln0; }
+ public void setLn0(boolean ln0) { this.ln0 = ln0; }
+ public String getPrefix() { return prefix; }
+ public void setPrefix(String prefix) { this.prefix = prefix; }
+ public String getLnClass() { return lnClass; }
+ public void setLnClass(String lnClass) { this.lnClass = lnClass; }
+ public String getLnInst() { return lnInst; }
+ public void setLnInst(String lnInst) { this.lnInst = lnInst; }
+ public String getLnType() { return lnType; }
+ public void setLnType(String lnType) { this.lnType = lnType; }
+ public List getDoiList() { return doiList; }
+ public void setDoiList(List doiList) { this.doiList = doiList; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LogicalDeviceNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LogicalDeviceNode.java
new file mode 100644
index 0000000..07a47c2
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/LogicalDeviceNode.java
@@ -0,0 +1,14 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+/**
+ * 逻辑设备节点。
+ * 逻辑设备模型。保存 inst、prefix 以及其下 LN/LN0 列表。
+ */
+public class LogicalDeviceNode {
+ private String inst;
+ private String ldName;
+ public String getInst() { return inst; }
+ public void setInst(String inst) { this.inst = inst; }
+ public String getLdName() { return ldName; }
+ public void setLdName(String ldName) { this.ldName = ldName; }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/ReportControlNode.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/ReportControlNode.java
new file mode 100644
index 0000000..476295d
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/icd/ReportControlNode.java
@@ -0,0 +1,29 @@
+package com.njcn.gather.icd.mapping.domain.model.icd;
+
+/**
+ * ReportControl 节点。
+ * 报告控制块模型。用于保存报告名称、关联 DataSet、缓冲属性等。
+ */
+public class ReportControlNode {
+ private String name;
+ private String rptId;
+ private boolean buffered;
+ private String dataSetName;
+ private String trgOps;
+ private String confRev;
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getRptId() { return rptId; }
+ public void setRptId(String rptId) { this.rptId = rptId; }
+ public boolean isBuffered() { return buffered; }
+ public void setBuffered(boolean buffered) { this.buffered = buffered; }
+ public String getDataSetName() { return dataSetName; }
+ public void setDataSetName(String dataSetName) { this.dataSetName = dataSetName; }
+ public String getTrgOps() { return trgOps; }
+ public void setTrgOps(String trgOps) { this.trgOps = trgOps; }
+ public String getConfRev() { return confRev; }
+ public void setConfRev(String confRev) { this.confRev = confRev; }
+ public Boolean getBuffered() { return buffered; }
+ public void setBuffered(Boolean buffered) { this.buffered = buffered; }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/DataSetSelectionState.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/DataSetSelectionState.java
new file mode 100644
index 0000000..14d8f84
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/DataSetSelectionState.java
@@ -0,0 +1,103 @@
+package com.njcn.gather.icd.mapping.domain.model.intermediate;
+
+import com.njcn.gather.icd.mapping.domain.model.icd.LnNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终参与生成 DataSetList 的选择状态。
+ *
+ * 关键修正:
+ * 旧版本一个绑定只保存一个 LnNode,导致:
+ * - MSQI 整组丢失
+ * - MHAI 只生成一半
+ *
+ * 新版本改成:
+ * 一个绑定可以关联多个 LnNode,后续生成阶段再逐个展开。
+ */
+public class DataSetSelectionState {
+
+ /** 所属分组 key。 */
+ private String groupKey;
+
+ /** 所属分组 desc。 */
+ private String groupDesc;
+
+ /** 报告名。 */
+ private String reportName;
+
+ /** 数据集名。 */
+ private String dataSetName;
+
+ /** 绑定标签。 */
+ private String label;
+
+ /** 绑定的 lnInst。 */
+ private String lnInst;
+
+ /**
+ * 当前绑定最终命中的 LN 节点列表。
+ *
+ * 说明:
+ * 同一个 lnInst 在不同 lnClass 下可能都需要展开,
+ * 例如:MMXU / MSQI / MHAI。
+ */
+ private List lnNodes = new ArrayList();
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getLnInst() {
+ return lnInst;
+ }
+
+ public void setLnInst(String lnInst) {
+ this.lnInst = lnInst;
+ }
+
+ public List getLnNodes() {
+ return lnNodes;
+ }
+
+ public void setLnNodes(List lnNodes) {
+ this.lnNodes = lnNodes;
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportAndDataSetState.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportAndDataSetState.java
new file mode 100644
index 0000000..d4b7950
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportAndDataSetState.java
@@ -0,0 +1,59 @@
+package com.njcn.gather.icd.mapping.domain.model.intermediate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 中间态总对象。
+ *
+ * 作用:
+ * 1. 对应原 C# 里“先形成中间态,再做最终 JSON 组装”的思路;
+ * 2. 把业务分组、用户绑定、最终 DataSet 选择结果集中保存;
+ * 3. 避免在 MappingGenerationService 里直接边遍历边拼 JSON,便于后续扩展和排查。
+ */
+public class ReportAndDataSetState {
+
+ /** IED 名称。 */
+ private String iedName;
+
+ /** LD 实例名。 */
+ private String ldInst;
+
+ /** 分组状态列表。 */
+ private List reportGroups = new ArrayList();
+
+ /** 数据集选择状态列表。 */
+ private List dataSetSelections = new ArrayList();
+
+ public String getIedName() {
+ return iedName;
+ }
+
+ public void setIedName(String iedName) {
+ this.iedName = iedName;
+ }
+
+ public String getLdInst() {
+ return ldInst;
+ }
+
+ public void setLdInst(String ldInst) {
+ this.ldInst = ldInst;
+ }
+
+ public List getReportGroups() {
+ return reportGroups;
+ }
+
+ public void setReportGroups(List reportGroups) {
+ this.reportGroups = reportGroups;
+ }
+
+ public List getDataSetSelections() {
+ return dataSetSelections;
+ }
+
+ public void setDataSetSelections(List dataSetSelections) {
+ this.dataSetSelections = dataSetSelections;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportBindingState.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportBindingState.java
new file mode 100644
index 0000000..e433073
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportBindingState.java
@@ -0,0 +1,73 @@
+package com.njcn.gather.icd.mapping.domain.model.intermediate;
+
+/**
+ * 单条最终有效绑定关系的中间态。
+ */
+public class ReportBindingState {
+
+ /** 分组 key。 */
+ private String groupKey;
+
+ /** 分组描述。 */
+ private String groupDesc;
+
+ /** 报告名。 */
+ private String reportName;
+
+ /** 数据集名。 */
+ private String dataSetName;
+
+ /** 标签。 */
+ private String label;
+
+ /** 绑定的 lnInst 数字。 */
+ private String lnInst;
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public String getReportName() {
+ return reportName;
+ }
+
+ public void setReportName(String reportName) {
+ this.reportName = reportName;
+ }
+
+ public String getDataSetName() {
+ return dataSetName;
+ }
+
+ public void setDataSetName(String dataSetName) {
+ this.dataSetName = dataSetName;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getLnInst() {
+ return lnInst;
+ }
+
+ public void setLnInst(String lnInst) {
+ this.lnInst = lnInst;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportGroupState.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportGroupState.java
new file mode 100644
index 0000000..385c303
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/intermediate/ReportGroupState.java
@@ -0,0 +1,100 @@
+package com.njcn.gather.icd.mapping.domain.model.intermediate;
+
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidateReportItem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 单个业务分组的中间态。
+ */
+public class ReportGroupState {
+
+ /** 分组唯一键。 */
+ private String groupKey;
+
+ /** 分组描述。 */
+ private String groupDesc;
+
+ /** 当前分组匹配到的报告数量。 */
+ private int reportCount;
+
+ /** 报表 inst(来自 DefaultCfg.ReportList.inst)。 */
+ private String reportInst;
+
+ /** Select(来自 DefaultCfg.ReportList.Select)。 */
+ private String select;
+
+ /** TrgOps(来自 DefaultCfg.ReportList.TrgOps)。 */
+ private String trgOps;
+
+ /** 当前分组包含的报告列表。 */
+ private List reportItems = new ArrayList();
+
+ /** 用户最终确认的绑定关系。 */
+ private List bindings = new ArrayList();
+
+ public String getGroupKey() {
+ return groupKey;
+ }
+
+ public void setGroupKey(String groupKey) {
+ this.groupKey = groupKey;
+ }
+
+ public String getGroupDesc() {
+ return groupDesc;
+ }
+
+ public void setGroupDesc(String groupDesc) {
+ this.groupDesc = groupDesc;
+ }
+
+ public int getReportCount() {
+ return reportCount;
+ }
+
+ public void setReportCount(int reportCount) {
+ this.reportCount = reportCount;
+ }
+
+ public String getReportInst() {
+ return reportInst;
+ }
+
+ public void setReportInst(String reportInst) {
+ this.reportInst = reportInst;
+ }
+
+ public String getSelect() {
+ return select;
+ }
+
+ public void setSelect(String select) {
+ this.select = select;
+ }
+
+ public String getTrgOps() {
+ return trgOps;
+ }
+
+ public void setTrgOps(String trgOps) {
+ this.trgOps = trgOps;
+ }
+
+ public List getReportItems() {
+ return reportItems;
+ }
+
+ public void setReportItems(List reportItems) {
+ this.reportItems = reportItems;
+ }
+
+ public List getBindings() {
+ return bindings;
+ }
+
+ public void setBindings(List bindings) {
+ this.bindings = bindings;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DataSetGroupItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DataSetGroupItem.java
new file mode 100644
index 0000000..e6cf35f
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DataSetGroupItem.java
@@ -0,0 +1,43 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终映射中的 DataSetList 单项。
+ */
+public class DataSetGroupItem {
+
+ /** 分组描述。一般来自 LnClassList.desc。 */
+ private String desc;
+
+ /** lnClass。 */
+ private String lnClass;
+
+ /** 该 lnClass 下的 inst 列表。 */
+ private List instList = new ArrayList();
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getLnClass() {
+ return lnClass;
+ }
+
+ public void setLnClass(String lnClass) {
+ this.lnClass = lnClass;
+ }
+
+ public List getInstList() {
+ return instList;
+ }
+
+ public void setInstList(List instList) {
+ this.instList = instList;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DoiItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DoiItem.java
new file mode 100644
index 0000000..1aa5f35
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/DoiItem.java
@@ -0,0 +1,120 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终映射中的 doiList 单项。
+ */
+public class DoiItem {
+
+ /** DOI 名称。 */
+ private String name;
+
+ /** DOI 描述。 */
+ private String desc;
+
+ /** 起始序号。 */
+ private int start;
+
+ /** 结束序号。 */
+ private int end;
+
+ /** 单位。 */
+ private String unit;
+
+ /** 系数。 */
+ private float coefficient;
+
+ /** 基波标志。 */
+ private int baseflag;
+
+ /** 基波数量。 */
+ private int basecount;
+
+ /** ICD 实际序列数。 */
+ private int icdcout;
+
+ /** SDI 列表。 */
+ private List sdiList = new ArrayList();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public void setStart(int start) {
+ this.start = start;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public void setEnd(int end) {
+ this.end = end;
+ }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ public float getCoefficient() {
+ return coefficient;
+ }
+
+ public void setCoefficient(float coefficient) {
+ this.coefficient = coefficient;
+ }
+
+ public int getBaseflag() {
+ return baseflag;
+ }
+
+ public void setBaseflag(int baseflag) {
+ this.baseflag = baseflag;
+ }
+
+ public int getBasecount() {
+ return basecount;
+ }
+
+ public void setBasecount(int basecount) {
+ this.basecount = basecount;
+ }
+
+ public int getIcdcout() {
+ return icdcout;
+ }
+
+ public void setIcdcout(int icdcout) {
+ this.icdcout = icdcout;
+ }
+
+ public List getSdiList() {
+ return sdiList;
+ }
+
+ public void setSdiList(List sdiList) {
+ this.sdiList = sdiList;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/InstItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/InstItem.java
new file mode 100644
index 0000000..5e30e02
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/InstItem.java
@@ -0,0 +1,43 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终映射中的 instList 单项。
+ */
+public class InstItem {
+
+ /** lnInst。 */
+ private String inst;
+
+ /** 该 inst 的描述。通常使用当前绑定的 label。 */
+ private String desc;
+
+ /** DOI 列表。 */
+ private List doiList = new ArrayList();
+
+ public String getInst() {
+ return inst;
+ }
+
+ public void setInst(String inst) {
+ this.inst = inst;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public List getDoiList() {
+ return doiList;
+ }
+
+ public void setDoiList(List doiList) {
+ this.doiList = doiList;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/MappingDocument.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/MappingDocument.java
new file mode 100644
index 0000000..a029389
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/MappingDocument.java
@@ -0,0 +1,127 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终映射文档。
+ *
+ * 关键说明:
+ * 1. Java 字段统一使用 lowerCamelCase,避免 Jackson 同时输出 ied/IED 这类重复字段。
+ * 2. JSON 输出名通过 @JsonProperty 显式指定,确保与原 C# 输出格式一致。
+ */
+public class MappingDocument {
+
+ @JsonProperty("version")
+ private String version;
+
+ @JsonProperty("author")
+ private String author;
+
+ @JsonProperty("IED")
+ private String ied;
+
+ @JsonProperty("LD")
+ private String ld;
+
+ /**
+ * 原 C# mainFrom.txt 固定调用:
+ * Set_WaveTimeFlag("BeiJing")
+ */
+ @JsonProperty("WaveTimeFlag")
+ private String waveTimeFlag;
+
+ /**
+ * 原 C# mainFrom.txt 固定调用:
+ * Set_DataType("1")
+ */
+ @JsonProperty("DataType")
+ private String dataType;
+
+ /**
+ * 原 C# mainFrom.txt 固定调用:
+ * Set_unit("1")
+ */
+ @JsonProperty("unit")
+ private String unit;
+
+ @JsonProperty("ReportMap")
+ private List reportMap = new ArrayList();
+
+ @JsonProperty("DataSetList")
+ private List dataSetList = new ArrayList();
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getIed() {
+ return ied;
+ }
+
+ public void setIed(String ied) {
+ this.ied = ied;
+ }
+
+ public String getLd() {
+ return ld;
+ }
+
+ public void setLd(String ld) {
+ this.ld = ld;
+ }
+
+ public String getWaveTimeFlag() {
+ return waveTimeFlag;
+ }
+
+ public void setWaveTimeFlag(String waveTimeFlag) {
+ this.waveTimeFlag = waveTimeFlag;
+ }
+
+ public String getDataType() {
+ return dataType;
+ }
+
+ public void setDataType(String dataType) {
+ this.dataType = dataType;
+ }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ public List getReportMap() {
+ return reportMap;
+ }
+
+ public void setReportMap(List reportMap) {
+ this.reportMap = reportMap;
+ }
+
+ public List getDataSetList() {
+ return dataSetList;
+ }
+
+ public void setDataSetList(List dataSetList) {
+ this.dataSetList = dataSetList;
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/ReportMapItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/ReportMapItem.java
new file mode 100644
index 0000000..0063d7b
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/ReportMapItem.java
@@ -0,0 +1,124 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * 最终映射中的 ReportMap 单项。
+ *
+ * 关键说明:
+ * 1. 原 C# 不是把同组报告合并成一条,而是组内每个报告各自输出一条。
+ * 2. 但 reportCount 仍然写该分组总数。
+ * 3. buffered 不是 boolean,而是:
+ * - true -> BR
+ * - false -> RP
+ */
+public class ReportMapItem {
+
+ @JsonProperty("desc")
+ private String desc;
+
+ @JsonProperty("reportCount")
+ private int reportCount;
+
+ @JsonProperty("rptID")
+ private String rptId;
+
+ @JsonProperty("name")
+ private String name;
+
+ @JsonProperty("buffered")
+ private String buffered;
+
+ @JsonProperty("inst")
+ private String inst;
+
+ /**
+ * 原 C# Set_FlickerFlag() 当前固定写 "0"
+ */
+ @JsonProperty("FlickerFlag")
+ private String flickerFlag;
+
+ /**
+ * 原 C# 来自 DefaultCfg.ReportList.Select
+ */
+ @JsonProperty("Select")
+ private String select;
+
+ /**
+ * 原 C# 来自 DefaultCfg.ReportList.TrgOps
+ */
+ @JsonProperty("TrgOps")
+ private String trgOps;
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public int getReportCount() {
+ return reportCount;
+ }
+
+ public void setReportCount(int reportCount) {
+ this.reportCount = reportCount;
+ }
+
+ public String getRptId() {
+ return rptId;
+ }
+
+ public void setRptId(String rptId) {
+ this.rptId = rptId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getBuffered() {
+ return buffered;
+ }
+
+ public void setBuffered(String buffered) {
+ this.buffered = buffered;
+ }
+
+ public String getInst() {
+ return inst;
+ }
+
+ public void setInst(String inst) {
+ this.inst = inst;
+ }
+
+ public String getFlickerFlag() {
+ return flickerFlag;
+ }
+
+ public void setFlickerFlag(String flickerFlag) {
+ this.flickerFlag = flickerFlag;
+ }
+
+ public String getSelect() {
+ return select;
+ }
+
+ public void setSelect(String select) {
+ this.select = select;
+ }
+
+ public String getTrgOps() {
+ return trgOps;
+ }
+
+ public void setTrgOps(String trgOps) {
+ this.trgOps = trgOps;
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/SdiItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/SdiItem.java
new file mode 100644
index 0000000..71c5aae
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/SdiItem.java
@@ -0,0 +1,43 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 最终映射中的 sdiList 单项。
+ */
+public class SdiItem {
+
+ /** SDI 名称。 */
+ private String name;
+
+ /** SDI 描述。 */
+ private String desc;
+
+ /** 类型列表。 */
+ private List typeList = new ArrayList();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public List getTypeList() {
+ return typeList;
+ }
+
+ public void setTypeList(List typeList) {
+ this.typeList = typeList;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/TypeItem.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/TypeItem.java
new file mode 100644
index 0000000..81c133f
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/mapping/TypeItem.java
@@ -0,0 +1,29 @@
+package com.njcn.gather.icd.mapping.domain.model.mapping;
+
+/**
+ * 最终映射中的 typeList 单项。
+ */
+public class TypeItem {
+
+ /** 类型名称。 */
+ private String name;
+
+ /** 类型描述。 */
+ private String desc;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/template/DefaultTemplate.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/template/DefaultTemplate.java
new file mode 100644
index 0000000..b369b60
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/model/template/DefaultTemplate.java
@@ -0,0 +1,345 @@
+package com.njcn.gather.icd.mapping.domain.model.template;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+/**
+ * 默认模板。
+ * 默认模板模型。把 default-template.json 解析成可直接使用的对象。
+ *
+ * 当前只保留第一个接口真正会用到的部分。
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class DefaultTemplate {
+
+ @JsonProperty("ReportList")
+ private List reportList = new ArrayList();
+
+ @JsonProperty("LnClassList")
+ private List lnClassList = new ArrayList();
+
+ @JsonProperty("PhaseList")
+ private List phaseList = new ArrayList();
+
+ @JsonProperty("MultiplierList")
+ private List multiplierList = new ArrayList();
+
+ @JsonProperty("UnitList")
+ private List unitList = new ArrayList();
+
+ @JsonProperty("TypeList")
+ private List typeList = new ArrayList();
+
+ @JsonProperty("DataObjectsList")
+ private List dataObjectsList = new ArrayList();
+
+ /**
+ * 基础校验。
+ *
+ * 返回问题列表;为空表示通过。
+ */
+ public List verify() {
+ List problems = new ArrayList();
+ ensureDuplicateNames("LnClassList", extractNames(lnClassList), problems);
+ ensureDuplicateNames("PhaseList", extractNames(phaseList), problems);
+ ensureDuplicateNames("MultiplierList", extractNames(multiplierList), problems);
+ ensureDuplicateNames("UnitList", extractNames(unitList), problems);
+ ensureDuplicateNames("TypeList", extractNames(typeList), problems);
+ ensureDuplicateObjectNames(problems);
+ if (reportList == null || reportList.isEmpty()) {
+ problems.add("DefaultCfg.ReportList 为空");
+ }
+ return problems;
+ }
+
+ private List extractNames(List extends NameListSupport> list) {
+ List names = new ArrayList();
+ if (list == null) {
+ return names;
+ }
+ for (NameListSupport item : list) {
+ if (item.getNameList() != null) {
+ names.addAll(item.getNameList());
+ }
+ }
+ return names;
+ }
+
+ private void ensureDuplicateNames(String section, List names, List problems) {
+ Set set = new HashSet();
+ for (String name : names) {
+ if (name == null) {
+ continue;
+ }
+ String key = name.trim();
+ if (!set.add(key)) {
+ problems.add(section + " 中存在重复配置项:" + key);
+ }
+ }
+ }
+
+ private void ensureDuplicateObjectNames(List problems) {
+ if (dataObjectsList == null) {
+ return;
+ }
+ for (DataObjectCfgItem dataObject : dataObjectsList) {
+ List names = new ArrayList();
+ if (dataObject.getObjectList() != null) {
+ for (ObjectCfgItem object : dataObject.getObjectList()) {
+ if (object.getNameList() != null) {
+ names.addAll(object.getNameList());
+ }
+ }
+ }
+ ensureDuplicateNames("DataObjectsList[" + dataObject.getDesc() + "]", names, problems);
+ }
+ }
+
+ public List getReportList() {
+ return reportList;
+ }
+
+ public void setReportList(List reportList) {
+ this.reportList = reportList;
+ }
+
+ public List getLnClassList() {
+ return lnClassList;
+ }
+
+ public void setLnClassList(List lnClassList) {
+ this.lnClassList = lnClassList;
+ }
+
+ public List getPhaseList() {
+ return phaseList;
+ }
+
+ public void setPhaseList(List phaseList) {
+ this.phaseList = phaseList;
+ }
+
+ public List getMultiplierList() {
+ return multiplierList;
+ }
+
+ public void setMultiplierList(List multiplierList) {
+ this.multiplierList = multiplierList;
+ }
+
+ public List getUnitList() {
+ return unitList;
+ }
+
+ public void setUnitList(List unitList) {
+ this.unitList = unitList;
+ }
+
+ public List getTypeList() {
+ return typeList;
+ }
+
+ public void setTypeList(List typeList) {
+ this.typeList = typeList;
+ }
+
+ public List getDataObjectsList() {
+ return dataObjectsList;
+ }
+
+ public void setDataObjectsList(List dataObjectsList) {
+ this.dataObjectsList = dataObjectsList;
+ }
+
+ /** 统一抽象:凡是有 nameList 的配置项都实现它。 */
+ public interface NameListSupport {
+ List getNameList();
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class ReportCfgItem {
+
+ /**
+ * 报告分组描述,例如:统计数据、实时数据、波动闪变
+ */
+ @JsonProperty("desc")
+ private String desc;
+
+ /**
+ * 报告 inst,例如:01
+ */
+ @JsonProperty("inst")
+ private String inst;
+
+ /**
+ * 原始配置中的 TrgOps。
+ * 例如:40 / 96
+ *
+ * 这里必须显式加 @JsonProperty("TrgOps"),
+ * 否则在当前项目里很容易反序列化后为 null。
+ */
+ @JsonProperty("TrgOps")
+ private String trgOps;
+
+ /**
+ * 原始配置中的 Select。
+ * 例如:DataStatFileMap / DataRealFileMap / FlickerFileMap
+ *
+ * 这里必须显式加 @JsonProperty("Select"),
+ * 否则在当前项目里很容易反序列化后为 null。
+ */
+ @JsonProperty("Select")
+ private String select;
+
+ /**
+ * 该分组覆盖的数据集名称列表
+ */
+ @JsonProperty("DataSetList")
+ private List dataSetList = new ArrayList();
+
+ /**
+ * 该分组可配置的标签模板列表
+ */
+ @JsonProperty("LnInstList")
+ private List lnInstList = new ArrayList();
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getInst() {
+ return inst;
+ }
+
+ public void setInst(String inst) {
+ this.inst = inst;
+ }
+
+ public String getTrgOps() {
+ return trgOps;
+ }
+
+ public void setTrgOps(String trgOps) {
+ this.trgOps = trgOps;
+ }
+
+ public String getSelect() {
+ return select;
+ }
+
+ public void setSelect(String select) {
+ this.select = select;
+ }
+
+ public List getDataSetList() {
+ return dataSetList;
+ }
+
+ public void setDataSetList(List dataSetList) {
+ this.dataSetList = dataSetList;
+ }
+
+ public List getLnInstList() {
+ return lnInstList;
+ }
+
+ public void setLnInstList(List lnInstList) {
+ this.lnInstList = lnInstList;
+ }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class LnClassCfgItem implements NameListSupport {
+ private String desc;
+ private List nameList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class PhaseCfgItem implements NameListSupport {
+ private String desc;
+ private List nameList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class MultiplierCfgItem implements NameListSupport {
+ private int multiplier;
+ private List nameList = new ArrayList();
+ public int getMultiplier() { return multiplier; }
+ public void setMultiplier(int multiplier) { this.multiplier = multiplier; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class UnitCfgItem implements NameListSupport {
+ private String desc;
+ private List nameList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class TypeCfgItem implements NameListSupport {
+ private String desc;
+ private List nameList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class DataObjectCfgItem {
+ private String desc;
+ @JsonProperty("LnInstList")
+ private List lnInstList = new ArrayList();
+ @JsonProperty("ObjectList")
+ private List objectList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public List getLnInstList() { return lnInstList; }
+ public void setLnInstList(List lnInstList) { this.lnInstList = lnInstList; }
+ public List getObjectList() { return objectList; }
+ public void setObjectList(List objectList) { this.objectList = objectList; }
+ }
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class ObjectCfgItem implements NameListSupport {
+ private String desc;
+ private int baseflag;
+ private int basecount;
+ private int queuecount;
+ private List nameList = new ArrayList();
+ private List queueList = new ArrayList();
+ public String getDesc() { return desc; }
+ public void setDesc(String desc) { this.desc = desc; }
+ public int getBaseflag() { return baseflag; }
+ public void setBaseflag(int baseflag) { this.baseflag = baseflag; }
+ public int getBasecount() { return basecount; }
+ public void setBasecount(int basecount) { this.basecount = basecount; }
+ public int getQueuecount() { return queuecount; }
+ public void setQueuecount(int queuecount) { this.queuecount = queuecount; }
+ public List getNameList() { return nameList; }
+ public void setNameList(List nameList) { this.nameList = nameList; }
+ public List getQueueList() { return queueList; }
+ public void setQueueList(List queueList) { this.queueList = queueList; }
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/DefaultTemplateLoader.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/DefaultTemplateLoader.java
new file mode 100644
index 0000000..852ea08
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/DefaultTemplateLoader.java
@@ -0,0 +1,69 @@
+package com.njcn.gather.icd.mapping.domain.service;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.njcn.gather.icd.mapping.config.MappingModuleConfig;
+import com.njcn.gather.icd.mapping.domain.model.template.DefaultTemplate;
+import com.njcn.gather.icd.mapping.utils.JsonUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * 默认配置加载器。
+ *
+ * 说明:
+ * 1. 直接读取 DefaultCfg.txt。
+ * 2. 读取后按 DefaultTemplate 原始模型反序列化。
+ */
+@Service
+public class DefaultTemplateLoader {
+
+ private final MappingModuleConfig moduleConfig;
+ private final ObjectMapper objectMapper;
+
+ public DefaultTemplateLoader(MappingModuleConfig moduleConfig) {
+ this.moduleConfig = moduleConfig;
+ this.objectMapper = new ObjectMapper();
+ this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+
+ public DefaultTemplate load() {
+ try {
+ ClassPathResource resource = new ClassPathResource(moduleConfig.getDefaultTemplatePath());
+ if (!resource.exists()) {
+ throw new IllegalArgumentException("默认模板文件不存在:" + moduleConfig.getDefaultTemplatePath());
+ }
+ byte[] bytes = readAllBytes(resource);
+ if (bytes.length == 0) {
+ throw new IllegalArgumentException("默认模板文件为空");
+ }
+ String json = new String(bytes, StandardCharsets.UTF_8);
+ json = JsonUtils.sanitizeJson(json);
+ DefaultTemplate template = objectMapper.readValue(json, DefaultTemplate.class);
+ List problems = template.verify();
+ if (!problems.isEmpty()) {
+ throw new IllegalArgumentException("DefaultCfg.txt 校验失败:" + String.join(";", problems));
+ }
+ return template;
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("加载 DefaultCfg.txt 失败:" + ex.getMessage(), ex);
+ }
+ }
+
+ private byte[] readAllBytes(ClassPathResource resource) throws Exception {
+ try (InputStream inputStream = resource.getInputStream();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[4096];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ outputStream.write(buffer, 0, length);
+ }
+ return outputStream.toByteArray();
+ }
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IcdParserService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IcdParserService.java
new file mode 100644
index 0000000..729fd63
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IcdParserService.java
@@ -0,0 +1,23 @@
+package com.njcn.gather.icd.mapping.domain.service;
+
+import com.njcn.gather.icd.mapping.domain.model.icd.IcdDocument;
+import com.njcn.gather.icd.mapping.infrastructure.parser.SclParserAdapter;
+import org.springframework.stereotype.Service;
+
+/**
+ * ICD 解析服务。
+ * ICD 解析领域服务门面。对应用层隐藏底层 JAXB 解析细节。
+ */
+@Service
+public class IcdParserService {
+
+ private final SclParserAdapter parserAdapter;
+
+ public IcdParserService(SclParserAdapter parserAdapter) {
+ this.parserAdapter = parserAdapter;
+ }
+
+ public IcdDocument parse(byte[] bytes, String fileName) {
+ return parserAdapter.parse(bytes, fileName);
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexAnalysisService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexAnalysisService.java
new file mode 100644
index 0000000..3365211
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexAnalysisService.java
@@ -0,0 +1,168 @@
+package com.njcn.gather.icd.mapping.domain.service;
+
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexAnalysis;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidate;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidateReportItem;
+import com.njcn.gather.icd.mapping.domain.model.icd.DataSetNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.FcdaNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.IcdDocument;
+import com.njcn.gather.icd.mapping.domain.model.icd.ReportControlNode;
+import com.njcn.gather.icd.mapping.domain.model.template.DefaultTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * 索引候选分析服务。
+ *
+ * 说明:
+ * 1. 新版不再按“单个报告”平铺返回,而是按 DefaultCfg.ReportList 的业务配置项聚合。
+ * 2. 一个业务配置项下可能包含多个报告,因此这里会计算 reportCount,并返回 reports 子列表。
+ * 3. templateLabels 只是模板参考,不要求与 ICD 解析到的 lnInst 数量完全一一对应。
+ * 4. 关键修正:
+ * 在这里就把 DefaultCfg.ReportList 的 inst / Select / TrgOps 一并带入 IndexCandidate,
+ * 后续正式生成阶段直接使用,不再重新查模板。
+ */
+@Service
+public class IndexAnalysisService {
+
+ public IndexAnalysis analyze(IcdDocument icdDocument, DefaultTemplate template) {
+ IndexAnalysis analysis = new IndexAnalysis();
+ if (icdDocument == null) {
+ analysis.getProblems().add("ICD 文档为空");
+ return analysis;
+ }
+ if (template == null || template.getReportList() == null) {
+ analysis.getProblems().add("DefaultCfg.ReportList 为空");
+ return analysis;
+ }
+
+ // 先按模板分组聚合
+ for (DefaultTemplate.ReportCfgItem reportCfg : template.getReportList()) {
+ List matchedReports = collectMatchedReports(icdDocument, reportCfg);
+ if (matchedReports.isEmpty()) {
+ continue;
+ }
+
+ IndexCandidate candidate = new IndexCandidate();
+ candidate.setGroupKey(buildGroupKey(reportCfg));
+ candidate.setGroupDesc(reportCfg.getDesc());
+ candidate.setReportCount(matchedReports.size());
+
+ // 关键:把 DefaultCfg.ReportList 的配置项直接带入候选对象
+ candidate.setReportInst(reportCfg.getInst());
+ candidate.setSelect(reportCfg.getSelect());
+ candidate.setTrgOps(reportCfg.getTrgOps());
+
+ if (reportCfg.getLnInstList() != null) {
+ candidate.getTemplateLabels().addAll(reportCfg.getLnInstList());
+ }
+
+ for (ReportControlNode reportControl : matchedReports) {
+ IndexCandidateReportItem item = new IndexCandidateReportItem();
+ item.setReportName(reportControl.getName());
+ item.setDataSetName(reportControl.getDataSetName());
+ item.setReportDesc(reportCfg.getDesc());
+ item.getAvailableLnInstValues().addAll(collectLnInstValues(icdDocument, reportControl.getDataSetName()));
+ candidate.getReports().add(item);
+ }
+
+ analysis.getCandidates().add(candidate);
+ }
+
+ // 再检查是否有 ICD 报告没有被模板覆盖
+ if (icdDocument.getReportControls() != null) {
+ for (ReportControlNode reportControl : icdDocument.getReportControls()) {
+ if (!isCoveredByTemplate(reportControl, template)) {
+ analysis.getProblems().add(
+ "报告 " + reportControl.getName()
+ + " 未在 DefaultCfg.ReportList 中匹配到配置;dataSet=" + reportControl.getDataSetName()
+ );
+ }
+ }
+ }
+
+ return analysis;
+ }
+
+ private List collectMatchedReports(IcdDocument icdDocument, DefaultTemplate.ReportCfgItem reportCfg) {
+ List result = new ArrayList();
+ if (icdDocument.getReportControls() == null || reportCfg.getDataSetList() == null) {
+ return result;
+ }
+ for (ReportControlNode reportControl : icdDocument.getReportControls()) {
+ if (reportCfg.getDataSetList().contains(reportControl.getDataSetName())) {
+ result.add(reportControl);
+ }
+ }
+ return result;
+ }
+
+ private boolean isCoveredByTemplate(ReportControlNode reportControl, DefaultTemplate template) {
+ if (template == null || template.getReportList() == null) {
+ return false;
+ }
+ for (DefaultTemplate.ReportCfgItem reportCfg : template.getReportList()) {
+ if (reportCfg.getDataSetList() != null && reportCfg.getDataSetList().contains(reportControl.getDataSetName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private List collectLnInstValues(IcdDocument icdDocument, String dataSetName) {
+ if (icdDocument.getDataSets() == null) {
+ return Collections.emptyList();
+ }
+
+ DataSetNode dataSetNode = icdDocument.getDataSets().get(dataSetName);
+ if (dataSetNode == null || dataSetNode.getFcdas() == null) {
+ return Collections.emptyList();
+ }
+
+ Set unique = new LinkedHashSet();
+ for (FcdaNode fcda : dataSetNode.getFcdas()) {
+ if (fcda == null || fcda.getLnInst() == null) {
+ continue;
+ }
+ String lnInst = fcda.getLnInst().trim();
+ if (!lnInst.isEmpty()) {
+ unique.add(lnInst);
+ }
+ }
+
+ List result = new ArrayList(unique);
+ Collections.sort(result, new Comparator() {
+ @Override
+ public int compare(String left, String right) {
+ try {
+ return Integer.valueOf(left).compareTo(Integer.valueOf(right));
+ } catch (Exception ex) {
+ return left.compareTo(right);
+ }
+ }
+ });
+ return result;
+ }
+
+ private String buildGroupKey(DefaultTemplate.ReportCfgItem reportCfg) {
+ String desc = reportCfg.getDesc() == null ? "GROUP" : reportCfg.getDesc();
+ String firstDataSet = (reportCfg.getDataSetList() == null || reportCfg.getDataSetList().isEmpty())
+ ? "DEFAULT" : reportCfg.getDataSetList().get(0);
+ return normalize(desc) + "__" + normalize(firstDataSet);
+ }
+
+ private String normalize(String value) {
+ return value.replaceAll("[^0-9A-Za-z\\u4e00-\\u9fa5]+", "_")
+ .replaceAll("_+", "_")
+ .replaceAll("^_", "")
+ .replaceAll("_$", "")
+ .toUpperCase(Locale.ROOT);
+ }
+}
\ No newline at end of file
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexValidationService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexValidationService.java
new file mode 100644
index 0000000..eb10544
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/IndexValidationService.java
@@ -0,0 +1,133 @@
+package com.njcn.gather.icd.mapping.domain.service;
+
+import com.njcn.gather.icd.mapping.application.command.IndexBindingCommand;
+import com.njcn.gather.icd.mapping.application.command.IndexSelectionGroupCommand;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexAnalysis;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidate;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidateReportItem;
+import com.njcn.gather.icd.mapping.domain.model.analysis.ValidationResult;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 索引绑定校验服务。
+ *
+ * 校验原则:
+ * 1. 只校验用户明确提交的绑定项;
+ * 2. 不要求模板里的所有标签都必须配置;
+ * 3. label 必须属于当前业务分组的 templateLabels;
+ * 4. lnInst 必须属于当前报告对应的 ICD 候选数字。
+ */
+@Service
+public class IndexValidationService {
+
+ public ValidationResult validate(IndexAnalysis analysis, List selections) {
+ ValidationResult result = new ValidationResult();
+
+ if (analysis == null || analysis.getCandidates() == null || analysis.getCandidates().isEmpty()) {
+ result.getProblems().add("当前 ICD 未解析出任何可配置的候选分组");
+ return result;
+ }
+
+ if (selections == null || selections.isEmpty()) {
+ for (IndexCandidate candidate : analysis.getCandidates()) {
+ result.getProblems().add(
+ "报告组【" + candidate.getGroupDesc() + "】未提交绑定关系,请根据 templateLabels 与 reports[*].availableLnInstValues 完成配置"
+ );
+ }
+ return result;
+ }
+
+ for (IndexSelectionGroupCommand selection : selections) {
+ IndexCandidate candidate = findCandidate(analysis, selection.getGroupKey(), selection.getGroupDesc());
+ if (candidate == null) {
+ result.getProblems().add("未找到分组配置:groupKey=" + selection.getGroupKey() + ", groupDesc=" + selection.getGroupDesc());
+ continue;
+ }
+
+ if (selection.getBindings() == null || selection.getBindings().isEmpty()) {
+ result.getProblems().add("分组【" + candidate.getGroupDesc() + "】没有任何绑定关系");
+ continue;
+ }
+
+ for (IndexBindingCommand binding : selection.getBindings()) {
+ validateBinding(candidate, binding, result);
+ }
+ }
+
+ if (result.getProblems().isEmpty()) {
+ result.setValid(true);
+ }
+ return result;
+ }
+
+ private void validateBinding(IndexCandidate candidate, IndexBindingCommand binding, ValidationResult result) {
+ if (binding == null) {
+ result.getProblems().add("存在空的绑定项");
+ return;
+ }
+
+ if (isBlank(binding.getLabel())) {
+ result.getProblems().add("分组【" + candidate.getGroupDesc() + "】存在未填写 label 的绑定项");
+ } else if (!candidate.getTemplateLabels().contains(binding.getLabel())) {
+ result.getProblems().add("分组【" + candidate.getGroupDesc() + "】中 label【" + binding.getLabel() + "】不在模板候选中");
+ }
+
+ IndexCandidateReportItem reportItem = findReport(candidate, binding.getReportName(), binding.getDataSetName());
+ if (reportItem == null) {
+ result.getProblems().add(
+ "分组【" + candidate.getGroupDesc() + "】中未找到报告:reportName=" + binding.getReportName()
+ + ", dataSetName=" + binding.getDataSetName()
+ );
+ return;
+ }
+
+ if (isBlank(binding.getLnInst())) {
+ result.getProblems().add("报告【" + reportItem.getReportName() + "】未填写 lnInst");
+ } else if (!reportItem.getAvailableLnInstValues().contains(binding.getLnInst())) {
+ result.getProblems().add(
+ "报告【" + reportItem.getReportName() + "】的 lnInst【" + binding.getLnInst() + "】不在可选数字中:"
+ + reportItem.getAvailableLnInstValues()
+ );
+ }
+ }
+
+ private IndexCandidate findCandidate(IndexAnalysis analysis, String groupKey, String groupDesc) {
+ for (IndexCandidate candidate : analysis.getCandidates()) {
+ if (same(candidate.getGroupKey(), groupKey)) {
+ return candidate;
+ }
+ if (same(candidate.getGroupDesc(), groupDesc)) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+
+ private IndexCandidateReportItem findReport(IndexCandidate candidate, String reportName, String dataSetName) {
+ if (candidate.getReports() == null) {
+ return null;
+ }
+ for (IndexCandidateReportItem item : candidate.getReports()) {
+ if (same(item.getReportName(), reportName) && (isBlank(dataSetName) || same(item.getDataSetName(), dataSetName))) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ private boolean same(String left, String right) {
+ if (left == null && right == null) {
+ return true;
+ }
+ if (left == null || right == null) {
+ return false;
+ }
+ return left.trim().equals(right.trim());
+ }
+
+ private boolean isBlank(String value) {
+ return value == null || value.trim().isEmpty();
+ }
+}
diff --git a/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/MappingGenerationService.java b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/MappingGenerationService.java
new file mode 100644
index 0000000..0451a79
--- /dev/null
+++ b/tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/domain/service/MappingGenerationService.java
@@ -0,0 +1,1015 @@
+package com.njcn.gather.icd.mapping.domain.service;
+
+import com.njcn.gather.icd.mapping.application.command.IndexBindingCommand;
+import com.njcn.gather.icd.mapping.application.command.IndexSelectionGroupCommand;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexAnalysis;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidate;
+import com.njcn.gather.icd.mapping.domain.model.analysis.IndexCandidateReportItem;
+import com.njcn.gather.icd.mapping.domain.model.icd.DataSetNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.DoiElementNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.DoiNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.FcdaNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.IcdDocument;
+import com.njcn.gather.icd.mapping.domain.model.icd.LnNode;
+import com.njcn.gather.icd.mapping.domain.model.icd.ReportControlNode;
+import com.njcn.gather.icd.mapping.domain.model.intermediate.DataSetSelectionState;
+import com.njcn.gather.icd.mapping.domain.model.intermediate.ReportAndDataSetState;
+import com.njcn.gather.icd.mapping.domain.model.intermediate.ReportBindingState;
+import com.njcn.gather.icd.mapping.domain.model.intermediate.ReportGroupState;
+import com.njcn.gather.icd.mapping.domain.model.mapping.DataSetGroupItem;
+import com.njcn.gather.icd.mapping.domain.model.mapping.DoiItem;
+import com.njcn.gather.icd.mapping.domain.model.mapping.InstItem;
+import com.njcn.gather.icd.mapping.domain.model.mapping.MappingDocument;
+import com.njcn.gather.icd.mapping.domain.model.mapping.ReportMapItem;
+import com.njcn.gather.icd.mapping.domain.model.mapping.SdiItem;
+import com.njcn.gather.icd.mapping.domain.model.mapping.TypeItem;
+import com.njcn.gather.icd.mapping.domain.model.template.DefaultTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 正式映射生成服务。
+ *
+ * 说明:
+ * 1. 本服务不再使用“单报告 + 单字符串选择”的简化模型;
+ * 2. 而是按“业务分组 + 多条绑定关系”的结构生成正式 MappingDocument;
+ * 3. 生成时只使用用户明确提交的绑定项,不强制要求模板里的所有标签都必须配置。
+ */
+@Service
+public class MappingGenerationService {
+
+ public MappingDocument generate(IcdDocument icdDocument,
+ DefaultTemplate template,
+ IndexAnalysis analysis,
+ List selections,
+ String version,
+ String author) {
+ ReportAndDataSetState state = buildState(icdDocument, template, analysis, selections);
+ MappingDocument document = new MappingDocument();
+ // 原 C# 的 Set_Version() 默认写当天日期,而不是 "1.0"
+ document.setVersion(resolveVersion(version));
+ document.setAuthor(author == null ? "" : author);
+ // 顶层字段严格按原 C# 输出规则生成。
+ document.setIed(icdDocument.getIedName());
+ // LD:只输出前缀,不带数字尾号。
+ document.setLd(icdDocument.getLdPrefix());
+ // 固定值,保持和原 C# mainFrom -> IcdCfg 一致
+ document.setWaveTimeFlag("BeiJing");
+ document.setDataType("1");
+ document.setUnit("1");
+
+ // 生成 ReportMap
+ // 1. 先按 DefaultCfg.ReportList 分组
+ // 2. reportCount 写组内总数
+ // 3. 组内每个报告单独生成一条 ReportMapItem
+ for (ReportGroupState groupState : state.getReportGroups()) {
+ if (groupState.getReportItems() == null || groupState.getReportItems().isEmpty()) {
+ continue;
+ }
+
+ // 原 C# 的 reportCount:<=1 时写 0,大于 1 才写实际数量
+ int reportCount = resolveReportCount(groupState.getReportItems().size());
+
+ for (IndexCandidateReportItem reportItem : groupState.getReportItems()) {
+ ReportMapItem item = new ReportMapItem();
+ item.setDesc(groupState.getGroupDesc());
+ item.setReportCount(reportCount);
+
+ // 单个报告自己的 rptID / name
+ item.setRptId(resolveSingleRptId(icdDocument, reportItem.getReportName()));
+ item.setName(reportItem.getReportName());
+
+ // buffered 按原 C# 转成 BR / RP
+ item.setBuffered(resolveBufferedCode(icdDocument, reportItem.getReportName()));
+
+ // inst / Select / TrgOps 直接来自当前分组匹配到的 DefaultCfg.ReportList 项
+ item.setInst(resolveReportInst(groupState.getReportInst()));
+ item.setSelect(groupState.getSelect());
+ item.setTrgOps(resolveTrgOps(groupState.getTrgOps()));
+
+ // 原 C# 当前固定写 0
+ item.setFlickerFlag("0");
+
+ document.getReportMap().add(item);
+ }
+ }
+
+ // 2. 生成 DataSetList
+ Map dataSetGroupMap = new LinkedHashMap();
+ for (DataSetSelectionState selectionState : state.getDataSetSelections()) {
+ if (selectionState.getLnNodes() == null || selectionState.getLnNodes().isEmpty()) {
+ continue;
+ }
+
+ // 一个绑定现在可能命中多个 LN,需要逐个展开
+ for (LnNode lnNode : selectionState.getLnNodes()) {
+ if (lnNode == null) {
+ continue;
+ }
+
+ DefaultTemplate.LnClassCfgItem lnClassCfg = findLnClassCfg(template, lnNode.getLnClass());
+ if (lnClassCfg == null) {
+ continue;
+ }
+
+ String groupKey = lnClassCfg.getDesc() + "__" + lnNode.getLnClass();
+ DataSetGroupItem groupItem = dataSetGroupMap.get(groupKey);
+ if (groupItem == null) {
+ groupItem = new DataSetGroupItem();
+ groupItem.setDesc(lnClassCfg.getDesc());
+ groupItem.setLnClass(lnNode.getLnClass());
+ dataSetGroupMap.put(groupKey, groupItem);
+ }
+
+ InstItem instItem = findOrCreateInst(groupItem, selectionState.getLnInst(), selectionState.getLabel());
+
+ // 关键:把当前正在处理的 lnNode 传进去,而不是只用一个旧的 lnNode
+ buildDoiItems(instItem, selectionState, lnNode, icdDocument, template);
+ }
+ }
+
+ document.getDataSetList().addAll(dataSetGroupMap.values());
+ return document;
+ }
+
+ private ReportAndDataSetState buildState(IcdDocument icdDocument,
+ DefaultTemplate template,
+ IndexAnalysis analysis,
+ List selections) {
+ ReportAndDataSetState state = new ReportAndDataSetState();
+ state.setIedName(icdDocument.getIedName());
+ state.setLdInst(icdDocument.getLdInst());
+
+ if (selections == null) {
+ return state;
+ }
+
+ for (IndexSelectionGroupCommand selectionGroup : selections) {
+ IndexCandidate candidate = findCandidate(analysis, selectionGroup.getGroupKey(), selectionGroup.getGroupDesc());
+ if (candidate == null) {
+ continue;
+ }
+
+ ReportGroupState groupState = new ReportGroupState();
+ groupState.setGroupKey(candidate.getGroupKey());
+ groupState.setGroupDesc(candidate.getGroupDesc());
+ groupState.setReportCount(candidate.getReportCount());
+
+ // 关键修正:
+ // 不再在这里重新查 DefaultCfg.ReportList,
+ // 直接使用 IndexAnalysisService 已经匹配好的配置项
+ groupState.setReportInst(candidate.getReportInst());
+ groupState.setSelect(candidate.getSelect());
+ groupState.setTrgOps(candidate.getTrgOps());
+
+ groupState.getReportItems().addAll(candidate.getReports());
+
+ if (selectionGroup.getBindings() != null) {
+ for (IndexBindingCommand command : selectionGroup.getBindings()) {
+ ReportBindingState bindingState = new ReportBindingState();
+ bindingState.setGroupKey(candidate.getGroupKey());
+ bindingState.setGroupDesc(candidate.getGroupDesc());
+ bindingState.setReportName(command.getReportName());
+ bindingState.setDataSetName(command.getDataSetName());
+ bindingState.setLabel(command.getLabel());
+ bindingState.setLnInst(command.getLnInst());
+ groupState.getBindings().add(bindingState);
+
+ DataSetSelectionState dataSetSelectionState = new DataSetSelectionState();
+ dataSetSelectionState.setGroupKey(candidate.getGroupKey());
+ dataSetSelectionState.setGroupDesc(candidate.getGroupDesc());
+ dataSetSelectionState.setReportName(command.getReportName());
+ dataSetSelectionState.setDataSetName(command.getDataSetName());
+ dataSetSelectionState.setLabel(command.getLabel());
+ dataSetSelectionState.setLnInst(command.getLnInst());
+ // 旧版本只找一个 LN,容易丢掉整组数据。
+ // 新版本改成收集所有匹配 LN。
+ dataSetSelectionState.getLnNodes().addAll(findMatchedLnNodes(icdDocument, command));
+ state.getDataSetSelections().add(dataSetSelectionState);
+ }
+ }
+
+ state.getReportGroups().add(groupState);
+ }
+
+ return state;
+ }
+
+ /**
+ * 查找当前绑定命中的所有 LN。
+ *
+ * 旧逻辑只返回一个 LN,会导致:
+ * - MSQI 整组缺失
+ * - MHAI 只生成一半
+ *
+ * 新逻辑:
+ * 1. 先从当前 DataSet 的 FCDA 中,找出与 lnInst 相同的所有 lnClass;
+ * 2. 再回到 ICD 逻辑节点列表中,收集这些 lnClass + lnInst 对应的 LN;
+ * 3. 如果仍然找不到,再退化为按 lnInst 收集全部 LN。
+ */
+ private List findMatchedLnNodes(IcdDocument icdDocument, IndexBindingCommand command) {
+ List