日期: 2026-04-12
项目: WIDESEA WMS
作者: Claude Code
为WMS库存信息页面和库存明细页面添加操作列,调用MES系统的出站/入站/绑定/解绑/NG上报接口,实现WMS与MES的数据同步。
库存信息页面(stockInfo.vue)- 托盘级别:
- 托盘进站(调用MES InboundInContainer接口)
- 托盘出站(调用MES OutboundInContainer接口)
库存明细页面(stockInfoDetail.vue)- 电芯级别:
- 托盘电芯绑定(调用MES BindContainer接口)
- 托盘电芯解绑(调用MES UnBindContainer接口)
- 托盘NG电芯上报(调用MES ContainerNgReport接口)
┌─────────────────────────────────────────────────────────────────┐
│ 前端 (Vue 3) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
│ │ stockInfo.vue │ │stockInfoDetail │ │ MesDialog.vue │ │
│ │ (库存信息) │ │ .vue(库存明细) │ │ (确认对话框) │ │
│ │ + 操作列 │ │ + 操作列 │ │ │ │
│ └────────┬─────────┘ └────────┬─────────┘ └────────┬───────┘ │
│ │ │ │ │
│ └─────────────────────┴──────────────────────┘ │
│ │ │
└──────────────────────────────┼───────────────────────────────────┘
│ HTTP API
┌──────────────────────────────┼───────────────────────────────────┐
│ ▼ 后端 (.NET) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
│ │ StockController │→ │ MesController │ │ MesLogService │ │
│ │ │ │ │ │ │ │
│ └──────────────────┘ └────────┬─────────┘ └────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │
│ │ IMesService │→ │ MesService │ │Dt_MesApiLog │ │
│ │ (接口定义) │ │ (HTTP调用) │ │ (日志表) │ │
│ └──────────────────┘ └──────────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────┐
│ MES系统 │
│ (外部接口) │
└──────────────┘
表格列配置:javascript { field: "actions", title: "操作", width: 200, fixed: "right", align: "center", formatter: (row) => renderActions(row) }
按钮定义:
- 进站按钮:调用托盘进站接口
- 出站按钮:调用托盘出站接口
按钮显示规则:
| 库存状态 | 进站 | 出站 |
|---|---|---|
| 待入库 (0) | ✓ | ✗ |
| 在库 (1) | ✗ | ✓ |
| 出库中 (2) | ✗ | ✓ |
| 锁定 (3) | ✗ | ✗ |
表格列配置:javascript { field: "actions", title: "操作", width: 280, fixed: "right", align: "center", formatter: (row) => renderActions(row) }
按钮定义:
- 绑定按钮:调用托盘电芯绑定接口
- 解绑按钮:调用托盘电芯解绑接口
- NG上报按钮:调用托盘NG电芯上报接口
按钮显示规则:
| 电芯状态 | 绑定 | 解绑 | NG上报 |
|---|---|---|---|
| 正常 (1) | ✓ | ✓ | ✓ |
| 异常 (2) | ✓ | ✓ | ✓ |
| 已锁定 (99) | ✗ | ✗ | ✗ |
组件职责:
- 显示即将执行的操作信息
- 展示关键参数(托盘码、设备编码等)
- 提供确认/取消按钮
- 显示调用结果(成功/失败)
Props定义:typescript interface MesConfirmDialogProps { visible: boolean; operationType: 'inbound' | 'outbound' | 'bind' | 'unbind' | 'ngReport'; palletCode: string; stockInfo?: any; detailInfo?: any; }
用户点击操作按钮
│
▼
检查登录状态 ──────→ 未登录 ────→ 提示"请先登录"
│
▼ 已登录
检查操作权限 ──────→ 无权限 ────→ 提示"无权限执行此操作"
│
▼ 有权限
弹出确认对话框
│
▼
用户点击"确认执行"
│
▼
显示loading状态
│
▼
调用后端API
│
├─→ 成功 ────→ 显示成功提示 ────→ 刷新列表
│
└─→ 失败 ────→ 显示错误提示 + "重试"按钮
托盘进站csharp /// <summary> /// 托盘进站 - 调用MES接口 /// </summary> [HttpPost("inboundInContainer")] public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto)
请求DTO:
```csharp
public class InboundInContainerRequestDto
{
///
/// <summary>
/// 库存ID
/// </summary>
public long StockId { get; set; }
}
```
托盘出站csharp /// <summary> /// 托盘出站 - 调用MES接口 /// </summary> [HttpPost("outboundInContainer")] public async Task<WebResponseContent> OutboundInContainer([FromBody] OutboundInContainerRequestDto dto)
请求DTO:
```csharp
public class OutboundInContainerRequestDto
{
///
/// <summary>
/// 库存ID
/// </summary>
public long StockId { get; set; }
/// <summary>
/// 产品参数列表(可选)
/// </summary>
public List<ParamItemDto> ParamList { get; set; }
}
```
托盘电芯绑定csharp /// <summary> /// 托盘电芯绑定 - 调用MES接口 /// </summary> [HttpPost("bindContainer")] public async Task<WebResponseContent> BindContainer([FromBody] BindContainerRequestDto dto)
请求DTO:
```csharp
public class BindContainerRequestDto
{
///
/// <summary>
/// 电芯码列表
/// </summary>
public List<string> SfcList { get; set; }
/// <summary>
/// 位置信息
/// </summary>
public string Location { get; set; }
/// <summary>
/// 操作类型:0-默认 1-进站 2-出站 3-进出站
/// </summary>
public int OperationType { get; set; } = 1;
}
```
托盘电芯解绑csharp /// <summary> /// 托盘电芯解绑 - 调用MES接口 /// </summary> [HttpPost("unbindContainer")] public async Task<WebResponseContent> UnbindContainer([FromBody] UnbindContainerRequestDto dto)
请求DTO:
```csharp
public class UnbindContainerRequestDto
{
///
/// <summary>
/// 电芯码列表
/// </summary>
public List<string> SfcList { get; set; }
}
```
托盘NG电芯上报csharp /// <summary> /// 托盘NG电芯上报 - 调用MES接口 /// </summary> [HttpPost("containerNgReport")] public async Task<WebResponseContent> ContainerNgReport([FromBody] ContainerNgReportRequestDto dto)
请求DTO:
```csharp
public class ContainerNgReportRequestDto
{
///
/// <summary>
/// NG电芯列表
/// </summary>
public List<NgSfcItemDto> NgSfcList { get; set; }
}
public class NgSfcItemDto
{
///
/// <summary>
/// NG代码
/// </summary>
public string NgCode { get; set; }
/// <summary>
/// NG设备
/// </summary>
public string NgEquipmentCode { get; set; }
/// <summary>
/// NG资源
/// </summary>
public string NgResourceCode { get; set; }
}
```
CREATE TABLE Dt_MesApiLog (
Id BIGINT PRIMARY KEY IDENTITY(1,1),
ApiType NVARCHAR(50) NOT NULL, -- 接口类型
RequestJson NVARCHAR(MAX) NULL, -- 请求JSON
ResponseJson NVARCHAR(MAX) NULL, -- 响应JSON
IsSuccess BIT NOT NULL DEFAULT 0, -- 是否成功
ErrorMessage NVARCHAR(500) NULL, -- 错误信息
ElapsedMs INT NOT NULL DEFAULT 0, -- 耗时(毫秒)
CreateDate DATETIME NOT NULL, -- 创建时间
Creator NVARCHAR(50) NULL, -- 创建人
INDEX IX_MesApiLog_ApiType (ApiType),
INDEX IX_MesApiLog_CreateDate (CreateDate)
);
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| Id | bigint | 主键 |
| ApiType | string(50) | 接口类型:InboundInContainer, OutboundInContainer, BindContainer, UnbindContainer, ContainerNgReport |
| RequestJson | string(MAX) | MES接口请求JSON |
| ResponseJson | string(MAX) | MES接口响应JSON |
| IsSuccess | bool | 调用是否成功 |
| ErrorMessage | string(500) | 失败时的错误信息 |
| ElapsedMs | int | 接口调用耗时(毫秒) |
| CreateDate | datetime | 创建时间 |
| Creator | string(50) | 创建人 |
-- 在 Dt_SystemConfig 表中新增MES配置项
INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate)
VALUES
('MES_EquipmentCode', 'WCS_001', 'MES设备编码', GETDATE()),
('MES_ResourceCode', 'RESOURCE_001', 'MES资源编码', GETDATE()),
('MES_ApiBaseUrl', 'http://mes-server/api', 'MES接口地址', GETDATE()),
('MES_TimeoutSeconds', '30', 'MES接口超时时间(秒)', GETDATE());
/// <summary>
/// MES接口日志服务接口
/// </summary>
public interface IMesLogService : IDependency
{
/// <summary>
/// 记录MES接口调用日志
/// </summary>
Task<bool> LogAsync(MesApiLogDto log);
/// <summary>
/// 获取最近的MES接口调用记录
/// </summary>
Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50);
}
/// <summary>
/// MES接口日志服务实现
/// </summary>
public class MesLogService : IMesLogService
{
private readonly ISqlSugarClient _db;
public async Task<bool> LogAsync(MesApiLogDto log)
{
var entity = new Dt_MesApiLog
{
ApiType = log.ApiType,
RequestJson = log.RequestJson,
ResponseJson = log.ResponseJson,
IsSuccess = log.IsSuccess,
ErrorMessage = log.ErrorMessage,
ElapsedMs = log.ElapsedMs,
CreateDate = DateTime.Now,
Creator = log.Creator
};
return await _db.Insertable(entity).ExecuteCommandAsync() > 0;
}
public async Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50)
{
return await _db.Queryable<Dt_MesApiLog>()
.Where(x => x.ApiType == apiType)
.OrderByDescending(x => x.CreateDate)
.Take(count)
.ToListAsync();
}
}
用户点击"进站"按钮
│
▼
前端弹出确认对话框(显示托盘码、设备编码等)
│
▼
用户确认
│
▼
前端调用 POST /api/StockInfo/inboundInContainer
│
▼
后端 StockInfoController.InboundInContainer()
│
├─→ 1. 验证库存状态(仅"待入库"状态允许进站)
│
├─→ 2. 获取系统配置(设备编码、资源编码)
│
├─→ 3. 构造MES请求对象
│
├─→ 4. 调用 IMesService.InboundInContainer()
│ │
│ ├─→ 记录开始时间
│ ├─→ 发送HTTP请求到MES
│ ├─→ 记录响应、耗时
│ └─→ 保存日志到 Dt_MesApiLog
│
├─→ 5. 返回结果给前端
│
└─→ 前端显示成功/失败提示
用户点击"绑定"按钮
│
▼
前端弹出确认对话框(显示托盘码、电芯码列表)
│
▼
用户确认
│
▼
前端调用 POST /api/StockInfoDetail/bindContainer
│
▼
后端 StockInfoDetailController.BindContainer()
│
├─→ 1. 验证电芯状态(非"已锁定"状态允许绑定)
│
├─→ 2. 获取系统配置
│
├─→ 3. 构造MES请求对象(包含电芯码列表)
│
├─→ 4. 调用 IMesService.BindContainer()
│ │
│ ├─→ 记录开始时间
│ ├─→ 发送HTTP请求到MES
│ ├─→ 记录响应、耗时
│ └─→ 保存日志到 Dt_MesApiLog
│
├─→ 5. 返回结果给前端
│
└─→ 前端显示成功/失败提示
| 错误类型 | 说明 | 处理方式 |
|---|---|---|
| 网络超时 | MES服务器无响应或连接超时 | 显示错误提示,提供"重试"按钮 |
| 业务校验失败 | 托盘不存在、电芯已绑定等 | 显示MES返回的错误信息 |
| 认证失败 | MES接口认证信息过期 | 显示"MES认证失败,请联系管理员" |
| 参数错误 | 请求参数不完整或格式错误 | 显示"参数错误:{具体错误}" |
| 未知错误 | MES系统返回异常响应 | 显示"MES系统异常,请稍后重试" |
// 成功提示
ElMessage.success('托盘进站成功');
// 失败提示
ElMessage.error({
message: 'MES服务器连接超时,请检查网络后重试',
showRetry: true,
onRetry: () => retryOperation()
});
try
{
// 调用MES接口
}
catch (HttpRequestException ex)
{
// 网络异常
await _mesLogService.LogAsync(new MesApiLogDto
{
ApiType = "InboundInContainer",
IsSuccess = false,
ErrorMessage = $"网络异常: {ex.Message}",
ElapsedMs = elapsedMs
});
return ResponseContent.Error("MES服务器连接失败,请检查网络");
}
catch (Exception ex)
{
// 其他异常
_logger.LogError(ex, "调用MES接口异常");
return ResponseContent.Error($"MES接口调用失败: {ex.Message}");
}
建议在系统中新增以下功能权限:
| 权限代码 | 权限名称 | 说明 |
|---|---|---|
| MES_INBOUND | MES进站操作 | 允许执行托盘进站操作 |
| MES_OUTBOUND | MES出站操作 | 允许执行托盘出站操作 |
| MES_BIND | MES绑定操作 | 允许执行电芯绑定操作 |
| MES_UNBIND | MES解绑操作 | 允许执行电芯解绑操作 |
| MES_NG_REPORT | MES NG上报 | 允许执行NG上报操作 |
[HttpPost("inboundInContainer")]
[Permission("MES_INBOUND")]
public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto)
{
// 接口实现
}
WMS/WIDESEA_WMSClient/src/
├── views/stock/
│ ├── stockInfo.vue # 修改:添加操作列
│ └── stockInfoDetail.vue # 修改:添加操作列
├── components/
│ └── MesConfirmDialog.vue # 新增:MES确认对话框
└── api/
└── mes.js # 新增:MES API调用
WMS/WIDESEA_WMSServer/
├── Controllers/
│ └── Stock/
│ ├── StockInfoController.cs # 修改:添加进站/出站接口
│ └── StockInfoDetailController.cs # 修改:添加绑定/解绑/NG上报接口
├── Services/
│ └── Mes/
│ ├── IMesLogService.cs # 新增:日志服务接口
│ └── MesLogService.cs # 新增:日志服务实现
└── DTO/
├── Mes/
│ ├── MesApiLogDto.cs # 新增:日志DTO
│ ├── InboundInContainerRequestDto.cs # 新增:进站请求DTO
│ ├── OutboundInContainerRequestDto.cs # 新增:出站请求DTO
│ ├── BindContainerRequestDto.cs # 新增:绑定请求DTO
│ ├── UnbindContainerRequestDto.cs # 新增:解绑请求DTO
│ └── ContainerNgReportRequestDto.cs # 新增:NG上报请求DTO
└── Models/
└── Mes/
└── Dt_MesApiLog.cs # 新增:日志实体
Database/
└── Scripts/
└── 20260412_MesApiLog.sql # 新增:日志表创建脚本
| 测试场景 | 预期结果 |
|---|---|
| 待入库状态托盘点击进站 | 弹出确认对话框,确认后成功调用 |
| 在库状态托盘点击进站 | 进站按钮不显示 |
| 网络中断时点击操作 | 显示网络错误提示,提供重试按钮 |
| MES返回业务错误 | 显示MES返回的具体错误信息 |
| 点击操作后刷新页面 | 操作记录已保存到日志表 |
| 指标 | 目标值 |
|---|---|
| MES接口响应时间 | < 2秒 |
| 前端按钮点击响应 | < 100ms |
| 日志写入耗时 | < 50ms |
文档版本: 1.0
最后更新: 2026-04-12