# XLSX 合并接口文档

## 接口地址

**POST** `/fr_epr_reg/api/epr/merge-xlsx`

服务器地址：`http://automation.usaeu.com:8888/`

完整地址：`http://automation.usaeu.com:8888/fr_epr_reg/api/epr/merge-xlsx`

## 功能说明

将多个 XLSX 附件合并为一个文件。以第一个附件为模板底本，从后续文件中提取数据行（第14行，A-AJ列）依次追加到模板中。合并后的文件上传到腾讯云 COS，返回 OSS 访问地址。

## 访问控制

接口受 `internal.network` 中间件保护，仅允许内网（172.16.x.x 子网）请求访问，非内网请求返回 401。

> **注意**：IP 限制默认开启（生产环境，由 `INTERNAL_NETWORK_ENFORCE` 控制，默认 `true`）。本地开发机不在 172.16 子网时，可在 `.env` 设置 `INTERNAL_NETWORK_ENFORCE=false` 临时关闭。

## 请求

### Content-Type

`application/json`

### 请求参数

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| AttachmentIDs | string[] | 是 | `Base_AnnexesFile` 表的 `F_Id` 数组，至少包含 2 个 ID，每个 ID 为 UUID 字符串（最长36位） |

### 请求示例

```json
{
    "AttachmentIDs": [
        "3A7B8C9D-XXXX-YYYY-ZZZZ-111111111111",
        "3A7B8C9D-XXXX-YYYY-ZZZZ-222222222222"
    ]
}
```

## 响应

### 成功响应（200）

```json
{
    "code": 200,
    "msg": "Merge succeeded",
    "data": {
        "oss_url": "https://cos-xxx.myqcloud.com/epr_factory/fr/merged/merged_20260507_143000_abcd1234.xlsx"
    }
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| code | int | 状态码，200 表示成功 |
| msg | string | 响应消息 |
| data.oss_url | string | 合并后 XLSX 文件的腾讯云 COS 访问地址 |

### 参数校验失败（400）

```json
{
    "code": 400,
    "msg": "AttachmentIDs must contain at least 2 IDs",
    "data": null
}
```

### 业务错误（400）

```json
{
    "code": 400,
    "msg": "Attachment IDs not found: 3A7B8C9D-...",
    "data": null
}
```

### 非内网访问（401）

```json
{
    "code": 401,
    "msg": "Unauthorized: internal network only",
    "data": null
}
```

## 参数校验规则

| 规则 | 说明 |
|------|------|
| AttachmentIDs 必填 | 请求体中必须包含此字段 |
| AttachmentIDs 数组类型 | 必须为 JSON 数组 |
| AttachmentIDs 最少2个 | 数组至少包含 2 个附件 ID |
| AttachmentIDs.* 必填 | 数组中每个元素不能为空 |
| AttachmentIDs.* 字符串类型 | 每个元素必须是字符串 |
| AttachmentIDs.* 最大36位 | 每个元素最长 36 个字符（UUID 长度） |

## 业务校验

参数校验通过后，服务层还会进行以下检查：

1. **存在性校验**：所有 `AttachmentIDs` 必须在 `Base_AnnexesFile` 表中存在，缺失的 ID 会返回错误
2. **类型校验**：所有附件的 `F_FileType` 必须为 `xlsx`，非 xlsx 类型会返回错误

## 处理流程

1. 根据 `F_Id` 从源数据库 `Base_AnnexesFile` 查询附件元数据
2. 校验所有 ID 存在且均为 xlsx 类型
3. 将每个 xlsx 文件从 COS 下载到本地临时目录
4. 以第一个文件为底本（保留表头行1-13）
5. 从后续每个文件中提取第14行数据（A-AJ列）
6. 将提取的数据行依次写入底本第 14+i 行
7. 将合并文件保存到本地临时目录
8. 上传合并文件到 COS，路径为 `epr_factory/fr/merged/`
9. 清理所有临时文件
10. 返回 OSS 地址

## 合并文件命名规则

格式：`merged_{YYYYMMDD_HHmmss}_{8位随机字符}.xlsx`

示例：`merged_20260507_143000_abcd1234.xlsx`

## OSS 存储路径

`epr_factory/fr/merged/{filename}.xlsx`

## 注意事项

- 合并保留第一个文件的全部表头（第1-13行）
- 仅从后续文件复制第14行的数据（A-AJ列）
- `AttachmentIDs` 数组的顺序决定合并后各行数据的排列顺序
- 处理完成后所有临时文件（源文件下载和合并结果）都会被清理
- 错误信息记录在 `api_merge_xlsx` 日志通道，路径为 `storage/logs/api/merge-xlsx-YYYY-MM-DD.log`（30 天保留，`LOG_API_DAYS` 环境变量）

## cURL 调用示例

```bash
curl -X POST \
  http://automation.usaeu.com:8888/fr_epr_reg/api/epr/merge-xlsx \
  -H 'Content-Type: application/json' \
  -d '{
    "AttachmentIDs": [
      "3A7B8C9D-XXXX-YYYY-ZZZZ-111111111111",
      "3A7B8C9D-XXXX-YYYY-ZZZZ-222222222222"
    ]
  }'
```