# mms-mapping

`mms-mapping` 模块负责解析 ICD 文件并生成 MMS 映射数据。当前统一调试入口为 `getIcdMmsJson`，该接口同时覆盖“先解析 ICD 获取索引候选”和“确认索引后生成正式 MMS JSON”两类场景。

## 0. 调试文档

- `getIcdMmsJson`：`API-getIcdMmsJson.md`
- `getXmlFromJson`：`API-getXmlFromJson.md`
- `buildIndexConfirmData` / `buildIndexSelection`：`API-buildIndexDebug.md`

## 1. 接口信息

- 路径：`POST /api/mms-mapping/get-icd-mms-json`
- Content-Type：`multipart/form-data`
- 控制器：`MappingController#getIcdMmsJson`
- 说明：上传 ICD 文件后，后端先解析 ICD，再根据 `request.indexSelection` 决定返回候选结果还是正式映射结果

说明：

- `request.indexSelection` 为空时，接口返回 `NEED_INDEX_SELECTION`，用于指导前端或调试人员完成标签与 `lnInst` 绑定。
- `request.indexSelection` 有效时，接口返回 `SUCCESS`，直接给出 `mappingJson`，必要时同时落盘。
- 该接口每次都会重新解析上传的 ICD 文件，因此二次调试时仍需要重新上传同一个 ICD 文件。

## 2. 调试流程

### 2.1 第一次调试

用途：只上传 ICD，先拿到 `icdDocument` 和 `indexCandidates`。

预期结果：

- `status = NEED_INDEX_SELECTION`
- 返回 `icdDocument`
- 返回 `indexCandidates`

### 2.2 第二次调试

用途：根据第一次返回的 `indexCandidates` 组装 `request.indexSelection`，再次调用同一个接口生成正式 MMS JSON。

预期结果：

- `status = SUCCESS`
- 返回 `mappingJson`
- 当 `saveToDisk=true` 时返回 `savedPath`

## 3. 请求参数

### 3.1 form-data 参数

| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `icdFile` | File | 是 | ICD 文件 |
| `request` | JSON Part | 是 | 生成参数，必须按 `application/json` 发送 |

### 3.2 request JSON 结构

```json
{
  "version": "20260421",
  "author": "debug-user",
  "saveToDisk": false,
  "prettyJson": true,
  "outputDir": "D:/temp/mms-output",
  "indexSelection": [
    {
      "groupKey": "harm",
      "groupDesc": "谐波数据",
      "bindings": [
        {
          "reportName": "brcbStHarm",
          "dataSetName": "dsStHarm",
          "label": "A相",
          "lnInst": "1"
        }
      ]
    }
  ]
}
```

### 3.3 request 字段说明

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `version` | String | 否 | 映射版本号；为空时由后端按当前日期补齐 |
| `author` | String | 否 | 作者；为空时使用模块默认作者 |
| `saveToDisk` | boolean | 否 | 是否将生成结果写入磁盘 |
| `prettyJson` | boolean | 否 | 是否生成格式化 JSON |
| `outputDir` | String | 否 | 输出目录；仅 `saveToDisk=true` 时生效 |
| `indexSelection` | Array | 否 | 标签与 `lnInst` 的最终绑定关系；为空时只返回候选结果 |

### 3.4 indexSelection 字段说明

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `groupKey` | String | 是 | 分组唯一键，必须使用第一次响应里返回的原值 |
| `groupDesc` | String | 否 | 分组描述，便于调试查看 |
| `bindings` | Array | 是 | 当前分组下最终确认的绑定列表 |

### 3.5 bindings 字段说明

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `reportName` | String | 是 | 报告名称 |
| `dataSetName` | String | 是 | 数据集名称 |
| `label` | String | 是 | 模板标签 |
| `lnInst` | String | 是 | 实际绑定的逻辑节点实例值 |

## 4. 调试示例

### 4.1 第一次调用，只获取候选结果

```powershell
curl.exe -X POST "http://localhost:8080/api/mms-mapping/get-icd-mms-json" `
  -H "Accept: application/json" `
  -F 'icdFile=@D:/data/demo.icd' `
  -F 'request={"version":"20260421","author":"debug-user","prettyJson":true,"saveToDisk":false};type=application/json'
```

### 4.2 第二次调用，带索引绑定直接生成 MMS JSON

```powershell
curl.exe -X POST "http://localhost:8080/api/mms-mapping/get-icd-mms-json" `
  -H "Accept: application/json" `
  -F 'icdFile=@D:/data/demo.icd' `
  -F 'request={"version":"20260421","author":"debug-user","prettyJson":true,"saveToDisk":false,"indexSelection":[{"groupKey":"harm","groupDesc":"谐波数据","bindings":[{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"A相","lnInst":"1"},{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"B相","lnInst":"2"},{"reportName":"brcbStHarm","dataSetName":"dsStHarm","label":"C相","lnInst":"3"}]}]};type=application/json'
```

## 5. 响应说明

接口统一返回 `MappingTaskResponse`。由于响应对象使用了 `@JsonInclude(JsonInclude.Include.NON_EMPTY)`，空字段和空集合默认不会出现在最终 JSON 中。

### 5.1 NEED_INDEX_SELECTION

适用场景：未传 `indexSelection`，或绑定关系不完整、不合法。

```json
{
  "status": "NEED_INDEX_SELECTION",
  "message": "索引配置缺失，请根据候选信息完成标签与数字索引的绑定后重新提交",
  "icdDocument": {
    "fileName": "demo.icd",
    "iedName": "IED1",
    "ldInst": "LD0",
    "ldPrefix": "LD",
    "logicalNodes": [
      {
        "lnInst": "1"
      }
    ]
  },
  "indexCandidates": [
    {
      "groupKey": "harm",
      "groupDesc": "谐波数据",
      "reportCount": 1,
      "templateLabels": [
        "A相",
        "B相",
        "C相"
      ],
      "reports": [
        {
          "reportName": "brcbStHarm",
          "dataSetName": "dsStHarm",
          "reportDesc": "谐波报告",
          "availableLnInstValues": [
            "1",
            "2",
            "3"
          ]
        }
      ]
    }
  ]
}
```

说明：

- `icdDocument` 实际返回内容会比示例更大，这里只保留关键字段用于说明结构。
- 如果绑定值非法，还会额外返回 `problems`，提示缺失或不匹配的绑定项。

### 5.2 SUCCESS

适用场景：`indexSelection` 校验通过，映射成功生成。

```json
{
  "status": "SUCCESS",
  "message": "映射生成成功",
  "mappingJson": "{\n  \"ied\": \"IED1\",\n  \"ld\": \"LD\",\n  \"instList\": []\n}"
}
```

说明：

- `mappingJson` 是字符串字段，字段值本身也是一段 JSON 文本。
- 当 `saveToDisk=true` 时，响应中还会返回 `savedPath`，落盘文件名按统一规则追加 `_yyyyMMdd`。

### 5.3 FAILED

适用场景：ICD 解析失败、模板校验失败、文件读取失败或其他运行异常。

```json
{
  "status": "FAILED",
  "message": "映射生成失败：ICD 文件不能为空",
  "problems": [
    "ICD 文件不能为空"
  ]
}
```

## 6. Postman 调试注意事项

- `Body` 选择 `form-data`。
- `icdFile` 类型选择 `File`。
- `request` 类型保持文本，但该 Part 的 `Content-Type` 需要设置为 `application/json`。
- 第一次调试建议不要传 `indexSelection`，先观察 `indexCandidates` 和 `availableLnInstValues`。
- 第二次调试时必须继续上传 ICD 文件，并按第一次返回的 `groupKey`、`reportName`、`dataSetName` 和 `availableLnInstValues` 组装绑定关系。

## 7. 当前限制

- 当前仅补充调试文档，未改动 `mms-mapping` 业务代码。
- 当前未执行 `mvn` 编译、打包或接口联调验证。
- 示例响应中的 `icdDocument` 和 `mappingJson` 为结构化示意，实际字段数量以运行结果为准。
