# 小包接口文档

## 1. 接口概述

小包模块提供了一系列RESTful API接口，用于标签替换、扫描记录管理以及相关操作。本文档详细描述了这些接口的使用方法、请求参数和响应格式。

测试环境请求地址：http://172.232.21.79:5002

正式环境请求地址：https://lr.tooexp.com

### 1.1 接口基础信息

- 基础URL：`http://{服务器地址}:{端口}/api/Label`
- 请求方式：POST/GET
- 数据格式：JSON
- 响应格式：JSON

### 1.2 状态码说明

状态码 | 描述
--- | ---
200 | 操作成功
400 | 请求参数错误或操作失败
401 | 身份验证失败
404 | 资源不存在
500 | 服务器内部错误

## 2. 接口详细说明

### 2.1 根据跟踪单号获取标签替换请求记录

接口路径：`/label-replace/tracking/{trackingNumber}`

请求方法：GET

功能描述：根据跟踪单号获取标签替换请求记录

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
trackingNumber | string | 是 | 跟踪单号 | "1Z999AA10123456789"

#### 请求示例

    GET /api/Label/label-replace/tracking/1Z999AA10123456789

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "trackingNumber": "1Z999AA10123456789", "count": 1, "data": [{"Id": 1, "NeutralWaybillNumber": "TEST001", "FinalMileTrackingNumber": "1Z999AA10123456789", "ReplaceStatus": "Y", "CreatedAt": "2026-03-30T10:00:00Z"}]}

失败响应：

    {"status": "error", "message": "Tracking number is required"}

### 2.2 根据中性面单单号获取标签替换请求记录

接口路径：`/label-replace/waybill/{waybillNumber}`

请求方法：GET

功能描述：根据中性面单单号获取标签替换请求记录

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
waybillNumber | string | 是 | 中性面单单号 | "TEST001"

#### 请求示例

    GET /api/Label/label-replace/waybill/TEST001

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "waybillNumber": "TEST001", "data": {"Id": 1, "NeutralWaybillNumber": "TEST001", "FinalMileTrackingNumber": "1Z999AA10123456789", "ReplaceStatus": "Y", "CreatedAt": "2026-03-30T10:00:00Z"}}

失败响应：

    {"status": "error", "message": "Waybill number is required"}

### 2.3 根据中性面单单号获取标签文件并返回字节流

接口路径：`/label-replace/waybill/{waybillNumber}/download`

请求方法：GET

功能描述：根据中性面单单号获取标签文件并返回字节流

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
waybillNumber | string | 是 | 中性面单单号 | "TEST001"

#### 请求示例

    GET /api/Label/label-replace/waybill/TEST001/download

#### 响应格式

成功响应：

- 响应类型：`application/pdf`
- 响应内容：标签文件的PDF字节流
- 文件名：`label_TEST001.pdf`

失败响应：

    {"status": "error", "message": "Label replace request not found for the provided waybill number"}

### 2.4 获取打印预览页面

接口路径：`/print-preview`

请求方法：GET

功能描述：获取打印预览页面

#### 请求参数

无

#### 请求示例

    GET /api/Label/print-preview

#### 响应格式

成功响应：

- 响应类型：`text/html`
- 响应内容：打印预览页面的HTML内容

失败响应：

- 404 Not Found

### 2.5 测试讯通回传接口

接口路径：`/label-scan/test-xuntong-webhook`

请求方法：POST

功能描述：测试讯通回传接口

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
WaybillNumber | string | 是 | 中性面单单号 | "TEST001"
Success | bool | 否 | 是否成功，默认true | true
Description | string | 否 | 描述 | "Test webhook"

#### 请求示例

    {"WaybillNumber": "TEST001", "Success": true, "Description": "Test webhook"}

#### 响应格式

成功响应：

    {"status": "ok", "message": "Test webhook sent successfully"}

失败响应：

    {"status": "error", "message": "Waybill number is required"}

### 2.6 记录标签扫描

接口路径：`/label-scan/record`

请求方法：POST

功能描述：记录标签扫描

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
CustomerId | int | 否 | 客户ID | 1
NeutralWaybillNumber | string | 是 | 中性面单单号 | "TEST001"
Result | int | 是 | 扫描结果 | 0
CreatedBy | string | 是 | 创建人 | "system"
ReferenceNumber | string | 否 | 参考号 | "REF001"
FinalMileTrackingNumber | string | 否 | 尾程跟踪单号 | "1Z999AA10123456789"
Description | string | 否 | 描述 | "标签扫描"

#### 请求示例

    {"CustomerId": 1, "NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system", "ReferenceNumber": "REF001", "FinalMileTrackingNumber": "1Z999AA10123456789", "Description": "标签扫描"}

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "scanRecord": {"Id": 1, "NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system", "CreatedAt": "2026-03-30T12:00:00Z"}}

失败响应：

    {"status": "error", "message": "Neutral waybill number is required"}

### 2.7 根据中性面单查询扫描记录列表

接口路径：`/label-scan/waybill/{waybillNumber}`

请求方法：GET

功能描述：根据中性面单查询扫描记录列表

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
waybillNumber | string | 是 | 中性面单单号 | "TEST001"

#### 请求示例

    GET /api/Label/label-scan/waybill/TEST001

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "waybillNumber": "TEST001", "count": 1, "data": [{"Id": 1, "NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system", "CreatedAt": "2026-03-30T10:00:00Z"}]}

失败响应：

    {"status": "error", "message": "Waybill number is required"}

### 2.8 根据客户ID查询扫描记录列表

接口路径：`/label-scan/customer/{customerId}`

请求方法：GET

功能描述：根据客户ID查询扫描记录列表

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
customerId | int | 是 | 客户ID | 1

#### 请求示例

    GET /api/Label/label-scan/customer/1

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "customerId": 1, "count": 2, "data": [{"Id": 1, "NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system", "CreatedAt": "2026-03-30T10:00:00Z"}, {"Id": 2, "NeutralWaybillNumber": "TEST002", "Result": 0, "CreatedBy": "system", "CreatedAt": "2026-03-30T11:00:00Z"}]}

失败响应：

    {"status": "error", "message": "An unexpected error occurred during scan record retrieval.", "errorDetails": "错误信息"}

### 2.9 获取客户的扫描记录统计

接口路径：`/label-scan/stats/customer/{customerId}`

请求方法：GET

功能描述：获取客户的扫描记录统计

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
customerId | int | 是 | 客户ID | 1

#### 请求示例

    GET /api/Label/label-scan/stats/customer/1

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "customerId": 1, "stats": {"totalScans": 10, "successfulScans": 8, "failedScans": 2}}

失败响应：

    {"status": "error", "message": "An unexpected error occurred during scan statistics retrieval.", "errorDetails": "错误信息"}

### 2.10 批量查询标签替换请求

接口路径：`/label-replace/batch`

请求方法：GET

功能描述：批量查询标签替换请求

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
page | int | 否 | 页码，默认1 | 1
pageSize | int | 否 | 每页数量，默认10 | 10
sortBy | string | 否 | 排序字段，默认CreatedAt | "CreatedAt"
sortOrder | string | 否 | 排序方向，默认desc | "desc"
billOfLadingNumber | string | 否 | 提单号 | "BOL001"
masterPackageNumber | string | 否 | 大包号 | "MP001"
referenceNumber | string | 否 | 参考号 | "REF001"
neutralWaybillNumber | string | 否 | 中性面单单号 | "TEST001"
finalMileTrackingNumber | string | 否 | 尾程跟踪单号 | "1Z999AA10123456789"
replaceStatus | string | 否 | 换单状态 | "Y"
customerId | int | 否 | 客户ID | 1
callback | string | 否 | JSONP回调函数名 | "callback"

#### 请求示例

    GET /api/Label/label-replace/batch?page=1&pageSize=10&sortBy=CreatedAt&sortOrder=desc

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "totalCount": 100, "page": 1, "pageSize": 10, "totalPages": 10, "data": [{"Id": 1, "NeutralWaybillNumber": "TEST001", "FinalMileTrackingNumber": "1Z999AA10123456789", "ReplaceStatus": "Y", "CreatedAt": "2026-03-30T10:00:00Z"}, ...]}

失败响应：

    {"status": "error", "message": "An unexpected error occurred during batch retrieval.", "errorDetails": "错误信息"}

### 2.11 批量查询标签扫描记录

接口路径：`/label-scan/batch`

请求方法：GET

功能描述：批量查询标签扫描记录

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
page | int | 否 | 页码，默认1 | 1
pageSize | int | 否 | 每页数量，默认10 | 10
sortBy | string | 否 | 排序字段，默认CreatedAt | "CreatedAt"
sortOrder | string | 否 | 排序方向，默认desc | "desc"
customerId | int | 否 | 客户ID | 1
referenceNumber | string | 否 | 参考号 | "REF001"
neutralWaybillNumber | string | 否 | 中性面单单号 | "TEST001"
finalMileTrackingNumber | string | 否 | 尾程跟踪单号 | "1Z999AA10123456789"
result | int | 否 | 扫描结果 | 0
callback | string | 否 | JSONP回调函数名 | "callback"

#### 请求示例

    GET /api/Label/label-scan/batch?page=1&pageSize=10&sortBy=CreatedAt&sortOrder=desc

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "totalCount": 50, "page": 1, "pageSize": 10, "totalPages": 5, "data": [{"Id": 1, "NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system", "CreatedAt": "2026-03-30T10:00:00Z"}, ...]}

失败响应：

    {"status": "error", "message": "An unexpected error occurred during batch retrieval.", "errorDetails": "错误信息"}

### 2.12 导出标签替换请求为Excel

接口路径：`/label-replace/export-excel`

请求方法：GET

功能描述：导出标签替换请求为Excel

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
billOfLadingNumber | string | 否 | 提单号 | "BOL001"
masterPackageNumber | string | 否 | 大包号 | "MP001"
referenceNumber | string | 否 | 参考号 | "REF001"
neutralWaybillNumber | string | 否 | 中性面单单号 | "TEST001"
finalMileTrackingNumber | string | 否 | 尾程跟踪单号 | "1Z999AA10123456789"
replaceStatus | string | 否 | 换单状态 | "Y"
customerId | int | 否 | 客户ID | 1

#### 请求示例

    GET /api/Label/label-replace/export-excel?customerId=1&replaceStatus=Y

#### 响应格式

成功响应：

- 响应类型：`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
- 响应内容：Excel文件字节流
- 文件名：`LabelReplaceRequests_20260330_120000.xlsx`

失败响应：

    {"status": "error", "message": "An unexpected error occurred during export.", "errorDetails": "错误信息"}

### 2.13 批量取消订单

接口路径：`/label-replace/batch-cancel`

请求方法：POST

功能描述：批量取消订单

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
CustomerCode | string | 是 | 客户代码 | "TEST"
ApiKey | string | 是 | API密钥 | "api_key_123"
WaybillNumbers | array | 是 | 中性面单单号列表 | ["TEST001", "TEST002"]

#### 请求示例

    {"CustomerCode": "TEST", "ApiKey": "api_key_123", "WaybillNumbers": ["TEST001", "TEST002"]}

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "successCount": 2, "failedCount": 0, "failedItems": [], "message": "Batch cancel completed successfully"}

失败响应：

    {"status": "error", "message": "Waybill numbers are required"}

### 2.14 导出标签扫描记录为Excel

接口路径：`/label-scan/export-excel`

请求方法：GET

功能描述：导出标签扫描记录为Excel

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
customerId | int | 否 | 客户ID | 1
referenceNumber | string | 否 | 参考号 | "REF001"
neutralWaybillNumber | string | 否 | 中性面单单号 | "TEST001"
finalMileTrackingNumber | string | 否 | 尾程跟踪单号 | "1Z999AA10123456789"
result | int | 否 | 扫描结果 | 0

#### 请求示例

    GET /api/Label/label-scan/export-excel?customerId=1&result=0

#### 响应格式

成功响应：

- 响应类型：`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
- 响应内容：Excel文件字节流
- 文件名：`LabelScanRecords_20260330_120000.xlsx`

失败响应：

    {"status": "error", "message": "An unexpected error occurred during export.", "errorDetails": "错误信息"}

### 2.15 获取客户列表

接口路径：`/customers`

请求方法：GET

功能描述：获取客户列表

#### 请求参数

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
callback | string | 否 | JSONP回调函数名 | "callback"

#### 请求示例

    GET /api/Label/customers

#### 响应格式

成功响应：

    {"status": "ok", "timestamp": "2026-03-30T12:00:00Z", "data": [{"Id": 1, "CustomerCode": "TEST", "CustomerName": "测试客户"}, ...]}

失败响应：

    {"status": "error", "message": "An unexpected error occurred during customers retrieval.", "errorDetails": "错误信息"}

### 2.16 批量查询换单状态

接口路径：`/label-replace/status`

请求方法：POST

功能描述：批量查询换单状态

#### 请求参数

请求头：

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
customerCode | string | 是 | 客户代码 | "TEST"
apiKey | string | 是 | API密钥 | "api_key_123"

请求体：

参数名 | 类型 | 必填 | 描述 | 示例值
--- | --- | --- | --- | ---
numbers | array | 是 | 单号列表（中性面单或尾程单号） | ["TEST001", "1Z999AA10123456789"]

#### 请求示例

    {"numbers": ["TEST001", "1Z999AA10123456789"]}

#### 响应格式

成功响应：

    {"code": 200, "timestamp": "2026-03-30T12:00:00Z", "count": 2, "data": [{"number": "TEST001", "status": "Y", "message": "Success"}, {"number": "1Z999AA10123456789", "status": "Y", "message": "Success"}]}

失败响应：

    {"code": 400, "message": "customerCode and apiKey are required in headers"}

## 3. 接口调用示例

### 3.1 使用cURL调用

#### 根据跟踪单号获取标签替换请求记录

    curl -X GET "http://localhost:5002/api/Label/label-replace/tracking/1Z999AA10123456789"

#### 根据中性面单单号获取标签文件

    curl -X GET "http://localhost:5002/api/Label/label-replace/waybill/TEST001/download" -o "label_TEST001.pdf"

#### 记录标签扫描

    curl -X POST "http://localhost:5002/api/Label/label-scan/record" \
      -H "Content-Type: application/json" \
      -d '{"NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system"}'

#### 批量查询换单状态

    curl -X POST "http://localhost:5002/api/Label/label-replace/status" \
      -H "Content-Type: application/json" \
      -H "customerCode: TEST" \
      -H "apiKey: api_key_123" \
      -d '{"numbers": ["TEST001", "1Z999AA10123456789"]}'

### 3.2 使用PowerShell调用

#### 根据跟踪单号获取标签替换请求记录

    Invoke-RestMethod -Uri "http://localhost:5002/api/Label/label-replace/tracking/1Z999AA10123456789" `
      -Method GET

#### 根据中性面单单号获取标签文件

    Invoke-WebRequest -Uri "http://localhost:5002/api/Label/label-replace/waybill/TEST001/download" `
      -Method GET `
      -OutFile "label_TEST001.pdf"

#### 记录标签扫描

    Invoke-RestMethod -Uri "http://localhost:5002/api/Label/label-scan/record" `
      -Method POST `
      -ContentType "application/json" `
      -Body '{"NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system"}'

#### 批量查询换单状态

    Invoke-RestMethod -Uri "http://localhost:5002/api/Label/label-replace/status" `
      -Method POST `
      -ContentType "application/json" `
      -Headers @{"customerCode"="TEST"; "apiKey"="api_key_123"} `
      -Body '{"numbers": ["TEST001", "1Z999AA10123456789"]}'

## 4. 业务流程示例

### 4.1 标签下载流程

1. 查询标签替换记录：根据中性面单单号查询标签替换记录
2. 下载标签文件：获取标签文件并返回字节流
3. 记录扫描：记录标签扫描操作

### 4.2 流程示例

    # 1. 查询标签替换记录
    GET /api/Label/label-replace/waybill/TEST001

    # 2. 下载标签文件
    GET /api/Label/label-replace/waybill/TEST001/download

    # 3. 记录扫描
    POST /api/Label/label-scan/record
    {"NeutralWaybillNumber": "TEST001", "Result": 0, "CreatedBy": "system"}

## 5. 注意事项

### 5.1 接口调用限制

- 批量操作时，建议单次处理数量不超过100个
- 频繁的接口调用可能会影响系统性能，建议合理控制调用频率

### 5.2 数据验证

- 中性面单单号不能为空
- 跟踪单号不能为空
- 批量操作时，单号列表不能为空

### 5.3 认证要求

- 部分接口需要在请求头中提供customerCode和apiKey进行认证
- 请确保使用正确的API凭证进行调用

## 6. 常见问题

### 6.1 标签下载失败

可能原因：

- 中性面单单号不存在
- 标签数据不可用
- 订单被冻结

解决方案：

- 检查中性面单单号是否正确
- 确认订单状态是否正常
- 联系系统管理员获取帮助

### 6.2 认证失败

可能原因：

- customerCode或apiKey不正确
- 认证信息未在请求头中提供

解决方案：

- 确保在请求头中提供正确的customerCode和apiKey
- 联系系统管理员获取正确的API凭证

### 6.3 批量操作失败

可能原因：

- 单号列表为空
- 部分单号不存在或状态异常

解决方案：

- 确保单号列表不为空
- 检查单号是否正确且状态正常

## 7. 接口版本管理

版本 | 变更内容 | 发布日期
--- | --- | ---
v1.0 | 初始版本，包含所有基础接口 | 2026-03-30

## 8. 联系信息

如有接口使用问题，请联系系统管理员或开发团队。