For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task.
目标: 在 WMS 系统中添加 MES 接口调用日志查看页面,提供综合性的日志查询、统计和管理功能。
架构: 后端使用 C# / ASP.NET Core,前端使用 Vue 3 + Element Plus。复用现有 view-grid 模式,添加自定义统计卡片。
技术栈: .NET 8, SqlSugar, Vue 3, Element Plus 2.2.14, Vite
版本: v0.3 (修订版 - 修复审查问题)
参考: docs/superpowers/specs/2026-04-13-mes-api-log-page-design.md
WMS/WIDESEA_WMSServer/
├── WIDESEA_DTO/MES/
│ ├── MesLogQueryDto.cs # 查询请求 DTO
│ ├── MesLogStatisticsDto.cs # 统计数据 DTO
│ ├── MesLogListItemDto.cs # 列表项 DTO
│ └── MesLogDetailDto.cs # 详情 DTO
├── WIDESEA_IMesService/
│ └── IMesLogService.cs # 扩展服务接口
├── WIDESEA_MesService/
│ └── MesLogService.cs # 服务实现
└── WIDESEA_WMSServer/Controllers/Mes/
└── MesLogController.cs # API 控制器
WMS/WIDESEA_WMSClient/src/
├── components/
│ └── MesLogStatistics.vue # 统计卡片组件
├── views/system/
│ └── Mes_Log.vue # 日志页面
└── extension/system/
└── Mes_Log.jsx # 业务扩展逻辑
WMS/WIDESEA_WMSClient/src/
└── router/viewGird.js # 添加路由配置
Files:
- Create: WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/MesLogQueryDto.cs
- Create: WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/MesLogStatisticsDto.cs
- Create: WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/MesLogListItemDto.cs
- Create: WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/MesLogDetailDto.cs
using System;
namespace WIDESEA_DTO.MES
{
/// <summary>
/// MES日志查询请求DTO
/// </summary>
public class MesLogQueryDto
{
/// <summary>
/// 接口类型: BindContainer, UnBindContainer, ContainerNgReport, InboundInContainer, OutboundInContainer
/// </summary>
public string ApiType { get; set; }
/// <summary>
/// 成功状态: null-全部, true-成功, false-失败
/// </summary>
public bool? IsSuccess { get; set; }
/// <summary>
/// 开始时间(前端 dateRange 字段映射:dateRange[0] → StartTime)
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 结束时间(前端 dateRange 字段映射:dateRange[1] → EndTime)
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 创建人(操作人)
/// </summary>
public string Creator { get; set; }
/// <summary>
/// 最小耗时(毫秒)(前端 elapsedRange 字段映射:elapsedRange[0] → MinElapsedMs)
/// </summary>
public int? MinElapsedMs { get; set; }
/// <summary>
/// 最大耗时(毫秒)(前端 elapsedRange 字段映射:elapsedRange[1] → MaxElapsedMs)
/// </summary>
public int? MaxElapsedMs { get; set; }
/// <summary>
/// 错误信息关键字
/// </summary>
public string ErrorKeyword { get; set; }
/// <summary>
/// 请求JSON关键字
/// </summary>
public string JsonRequestKeyword { get; set; }
/// <summary>
/// 响应JSON关键字
/// </summary>
public string JsonResponseKeyword { get; set; }
}
}
using System;
using System.Collections.Generic;
namespace WIDESEA_DTO.MES
{
/// <summary>
/// MES日志统计数据DTO
/// </summary>
public class MesLogStatisticsDto
{
/// <summary>
/// 总调用次数
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 成功次数
/// </summary>
public int SuccessCount { get; set; }
/// <summary>
/// 成功率(百分比)
/// </summary>
public double SuccessRate { get; set; }
/// <summary>
/// 失败次数
/// </summary>
public int FailedCount { get; set; }
/// <summary>
/// 平均耗时(毫秒)
/// </summary>
public double AvgElapsedMs { get; set; }
/// <summary>
/// 最大耗时(毫秒)
/// </summary>
public int MaxElapsedMs { get; set; }
/// <summary>
/// 今日调用次数
/// </summary>
public int TodayCount { get; set; }
/// <summary>
/// 各接口类型调用次数统计
/// </summary>
public Dictionary<string, int> ApiTypeCounts { get; set; }
}
}
using System;
namespace WIDESEA_DTO.MES
{
/// <summary>
/// MES日志列表项DTO
/// </summary>
public class MesLogListItemDto
{
/// <summary>
/// 主键ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 接口类型
/// </summary>
public string ApiType { get; set; }
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 请求JSON预览(前200字符)
/// </summary>
public string RequestJsonPreview { get; set; }
/// <summary>
/// 响应JSON预览(前200字符)
/// </summary>
public string ResponseJsonPreview { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 耗时(毫秒)
/// </summary>
public int ElapsedMs { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateDate { get; set; }
/// <summary>
/// 创建人
/// </summary>
public string Creator { get; set; }
}
}
using System;
namespace WIDESEA_DTO.MES
{
/// <summary>
/// MES日志详情DTO
/// </summary>
public class MesLogDetailDto : MesLogListItemDto
{
/// <summary>
/// 完整请求JSON
/// </summary>
public string RequestJson { get; set; }
/// <summary>
/// 完整响应JSON
/// </summary>
public string ResponseJson { get; set; }
/// <summary>
/// 修改时间
/// </summary>
public DateTime? ModifyDate { get; set; }
/// <summary>
/// 修改人
/// </summary>
public string Modifier { get; set; }
}
}
git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/MES/MesLog*.cs
git commit -m "feat(MES): 添加MES日志查询DTO文件
- MesLogQueryDto: 查询请求参数
- MesLogStatisticsDto: 统计数据
- MesLogListItemDto: 列表项
- MesLogDetailDto: 详情
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Modify: WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs
cat WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs
在现有接口中添加以下方法:
/// <summary>
/// 分页查询MES日志
/// </summary>
/// <param name="query">查询条件</param>
/// <param name="page">页码</param>
/// <param name="pageSize">每页数量</param>
/// <returns>日志列表和总数</returns>
Task<(List<MesLogListItemDto> items, int total)> GetPageAsync(MesLogQueryDto query, int page, int pageSize);
/// <summary>
/// 获取单条日志详情
/// </summary>
/// <param name="id">日志ID</param>
/// <returns>日志详情</returns>
Task<MesLogDetailDto> GetDetailAsync(long id);
/// <summary>
/// 获取统计数据
/// </summary>
/// <param name="query">查询条件</param>
/// <returns>统计数据</returns>
Task<MesLogStatisticsDto> GetStatisticsAsync(MesLogQueryDto query);
/// <summary>
/// 导出日志数据
/// </summary>
/// <param name="query">查询条件</param>
/// <returns>Excel文件字节数组</returns>
Task<byte[]> ExportAsync(MesLogQueryDto query);
确保文件顶部有:csharp using WIDESEA_DTO.MES;
git add WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs
git commit -m "feat(MES): 扩展IMesLogService接口
- 添加分页查询方法 GetPageAsync
- 添加详情查询方法 GetDetailAsync
- 添加统计查询方法 GetStatisticsAsync
- 添加导出方法 ExportAsync
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Modify: WMS/WIDESEA_WMSServer/WIDESEA_MesService/MesLogService.cs
cat WMS/WIDESEA_WMSServer/WIDESEA_MesService/MesLogService.cs
/// <summary>
/// 分页查询MES日志
/// </summary>
public async Task<(List<MesLogListItemDto> items, int total)> GetPageAsync(MesLogQueryDto query, int page, int pageSize)
{
var dbQuery = _db.Queryable<WIDESEA_Model.Models.Mes.Dt_MesApiLog>();
// 动态条件筛选
if (!string.IsNullOrEmpty(query.ApiType))
{
dbQuery = dbQuery.Where(x => x.ApiType == query.ApiType);
}
if (query.IsSuccess.HasValue)
{
dbQuery = dbQuery.Where(x => x.IsSuccess == query.IsSuccess.Value);
}
if (query.StartTime.HasValue)
{
dbQuery = dbQuery.Where(x => x.CreateDate >= query.StartTime.Value);
}
if (query.EndTime.HasValue)
{
dbQuery = dbQuery.Where(x => x.CreateDate <= query.EndTime.Value);
}
if (!string.IsNullOrEmpty(query.Creator))
{
dbQuery = dbQuery.Where(x => x.Creator.Contains(query.Creator));
}
if (query.MinElapsedMs.HasValue)
{
dbQuery = dbQuery.Where(x => x.ElapsedMs >= query.MinElapsedMs.Value);
}
if (query.MaxElapsedMs.HasValue)
{
dbQuery = dbQuery.Where(x => x.ElapsedMs <= query.MaxElapsedMs.Value);
}
if (!string.IsNullOrEmpty(query.ErrorKeyword))
{
dbQuery = dbQuery.Where(x => x.ErrorMessage.Contains(query.ErrorKeyword));
}
if (!string.IsNullOrEmpty(query.JsonRequestKeyword))
{
dbQuery = dbQuery.Where(x => x.RequestJson.Contains(query.JsonRequestKeyword));
}
if (!string.IsNullOrEmpty(query.JsonResponseKeyword))
{
dbQuery = dbQuery.Where(x => x.ResponseJson.Contains(query.JsonResponseKeyword));
}
// 获取总数
var total = await dbQuery.CountAsync();
// 分页查询
var entities = await dbQuery
.OrderByDescending(x => x.CreateDate)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
// 映射到 DTO
var items = entities.Select(e => new MesLogListItemDto
{
Id = e.Id,
ApiType = e.ApiType,
IsSuccess = e.IsSuccess,
RequestJsonPreview = e.RequestJson?.Length > 200 ? e.RequestJson.Substring(0, 200) + "..." : e.RequestJson,
ResponseJsonPreview = e.ResponseJson?.Length > 200 ? e.ResponseJson.Substring(0, 200) + "..." : e.ResponseJson,
ErrorMessage = e.ErrorMessage,
ElapsedMs = e.ElapsedMs,
CreateDate = e.CreateDate,
Creator = e.Creator
}).ToList();
return (items, total);
}
/// <summary>
/// 获取单条日志详情
/// </summary>
public async Task<MesLogDetailDto> GetDetailAsync(long id)
{
var entity = await _db.Queryable<WIDESEA_Model.Models.Mes.Dt_MesApiLog>()
.FirstAsync(x => x.Id == id);
if (entity == null)
{
return null;
}
return new MesLogDetailDto
{
Id = entity.Id,
ApiType = entity.ApiType,
IsSuccess = entity.IsSuccess,
RequestJson = entity.RequestJson,
ResponseJson = entity.ResponseJson,
RequestJsonPreview = entity.RequestJson?.Length > 200 ? entity.RequestJson.Substring(0, 200) + "..." : entity.RequestJson,
ResponseJsonPreview = entity.ResponseJson?.Length > 200 ? entity.ResponseJson.Substring(0, 200) + "..." : entity.ResponseJson,
ErrorMessage = entity.ErrorMessage,
ElapsedMs = entity.ElapsedMs,
CreateDate = entity.CreateDate,
Creator = entity.Creator,
ModifyDate = entity.ModifyDate,
Modifier = entity.Modifier
};
}
/// <summary>
/// 获取统计数据
/// </summary>
public async Task<MesLogStatisticsDto> GetStatisticsAsync(MesLogQueryDto query)
{
var dbQuery = _db.Queryable<WIDESEA_Model.Models.Mes.Dt_MesApiLog>();
// 应用相同的筛选条件(但不分页)
if (!string.IsNullOrEmpty(query.ApiType))
{
dbQuery = dbQuery.Where(x => x.ApiType == query.ApiType);
}
if (query.IsSuccess.HasValue)
{
dbQuery = dbQuery.Where(x => x.IsSuccess == query.IsSuccess.Value);
}
if (query.StartTime.HasValue)
{
dbQuery = dbQuery.Where(x => x.CreateDate >= query.StartTime.Value);
}
if (query.EndTime.HasValue)
{
dbQuery = dbQuery.Where(x => x.CreateDate <= query.EndTime.Value);
}
var allData = await dbQuery.ToListAsync();
// 今日数据
var today = DateTime.Today;
var todayData = allData.Where(x => x.CreateDate >= today).ToList();
// 计算统计数据
var totalCount = allData.Count;
var successCount = allData.Count(x => x.IsSuccess);
var failedCount = totalCount - successCount;
var successRate = totalCount > 0 ? (successCount * 100.0 / totalCount) : 0;
return new MesLogStatisticsDto
{
TotalCount = totalCount,
SuccessCount = successCount,
FailedCount = failedCount,
SuccessRate = Math.Round(successRate, 2),
AvgElapsedMs = totalCount > 0 ? allData.Average(x => x.ElapsedMs) : 0,
MaxElapsedMs = totalCount > 0 ? allData.Max(x => x.ElapsedMs) : 0,
TodayCount = todayData.Count,
ApiTypeCounts = allData.GroupBy(x => x.ApiType)
.ToDictionary(g => g.Key, g => g.Count())
};
}
/// <summary>
/// 导出日志数据
/// </summary>
public async Task<byte[]> ExportAsync(MesLogQueryDto query)
{
// 获取所有符合条件的数据(不分页)
var (items, _) = await GetPageAsync(query, 1, int.MaxValue);
// 使用框架内置的 Excel 导出功能
// 注意:这里需要根据项目实际使用的导出库调整
// 参考 ServiceBase.Export() 的实现方式
// 临时方案:使用 CSV 格式
using var memoryStream = new MemoryStream();
using var writer = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
// CSV 头部
writer.WriteLine("ID,接口类型,状态,耗时(ms),错误信息,创建时间,创建人");
// CSV 数据行
foreach (var item in items)
{
writer.WriteLine($"{item.Id},{item.ApiType},{(item.IsSuccess ? "成功" : "失败")},{item.ElapsedMs},\"{item.ErrorMessage?.Replace("\"", "\"\"")}\",{item.CreateDate:yyyy-MM-dd HH:mm:ss},{item.Creator}");
}
writer.Flush();
return memoryStream.ToArray();
}
确保文件顶部有:csharp using WIDESEA_DTO.MES;
git add WMS/WIDESEA_WMSServer/WIDESEA_MesService/MesLogService.cs
git commit -m "feat(MES): 实现MesLogService查询方法
- 实现分页查询 GetPageAsync
- 实现详情查询 GetDetailAsync
- 实现统计查询 GetStatisticsAsync
- 实现导出 ExportAsync (CSV格式)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Create: WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Mes/MesLogController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_DTO.MES;
using WIDESEA_IBasicService;
using WIDESEA_IMesService;
namespace WIDESEA_WMSServer.Controllers.Mes
{
/// <summary>
/// MES接口日志控制器
/// </summary>
[Route("api/MesLog")]
[ApiController]
[Authorize]
public class MesLogController : ControllerBase
{
private readonly IMesLogService _mesLogService;
/// <summary>
/// 构造函数
/// </summary>
public MesLogController(IMesLogService mesLogService)
{
_mesLogService = mesLogService;
}
/// <summary>
/// 分页查询MES日志
/// </summary>
/// <param name="query">查询条件</param>
/// <param name="page">页码,默认1</param>
/// <param name="pageSize">每页数量,默认20</param>
/// <returns>分页结果</returns>
[HttpPost("page")]
public async Task<WebResponseContent> GetPage([FromBody] MesLogQueryDto query, [FromQuery] int page = 1, [FromQuery] int pageSize = 20)
{
var response = new WebResponseContent();
try
{
var (items, total) = await _mesLogService.GetPageAsync(query, page, pageSize);
return response.OK(null, new { rows = items, total = total });
}
catch (Exception ex)
{
return response.Error($"查询失败: {ex.Message}");
}
}
/// <summary>
/// 获取日志详情
/// </summary>
/// <param name="id">日志ID</param>
/// <returns>日志详情</returns>
[HttpGet("{id}")]
public async Task<WebResponseContent> GetDetail(long id)
{
var response = new WebResponseContent();
try
{
var detail = await _mesLogService.GetDetailAsync(id);
if (detail == null)
{
return response.Error("日志不存在");
}
return response.OK(null, detail);
}
catch (Exception ex)
{
return response.Error($"查询失败: {ex.Message}");
}
}
/// <summary>
/// 获取统计数据
/// </summary>
/// <param name="query">查询条件(可选)</param>
/// <returns>统计数据</returns>
[HttpGet("statistics")]
public async Task<WebResponseContent> GetStatistics([FromQuery] MesLogQueryDto query)
{
var response = new WebResponseContent();
try
{
var statistics = await _mesLogService.GetStatisticsAsync(query ?? new MesLogQueryDto());
return response.OK(null, statistics);
}
catch (Exception ex)
{
return response.Error($"查询失败: {ex.Message}");
}
}
/// <summary>
/// 导出日志
/// </summary>
/// <param name="query">查询条件</param>
/// <returns>Excel文件</returns>
[HttpPost("export")]
public async Task<IActionResult> Export([FromBody] MesLogQueryDto query)
{
try
{
var data = await _mesLogService.ExportAsync(query ?? new MesLogQueryDto());
var fileName = $"MES接口日志_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
return File(data, "text/csv; charset=utf-8", fileName);
}
catch (Exception ex)
{
return BadRequest(new { error = ex.Message });
}
}
}
}
git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Mes/MesLogController.cs
git commit -m "feat(MES): 添加MesLogController控制器
- POST /api/MesLog/page - 分页查询
- GET /api/MesLog/{id} - 详情查询
- GET /api/MesLog/statistics - 统计数据
- POST /api/MesLog/export - 导出CSV
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Create: WMS/WIDESEA_WMSClient/src/components/MesLogStatistics.vue
<template>
<div class="mes-log-statistics">
<el-row :gutter="16">
<el-col :span="6">
<el-card shadow="hover" class="stat-card stat-primary">
<div class="stat-content">
<div class="stat-label">总调用次数</div>
<div class="stat-value">{{ statistics.totalCount }}</div>
<div class="stat-unit">次</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card" :class="statistics.successRate >= 90 ? 'stat-success' : 'stat-warning'">
<div class="stat-content">
<div class="stat-label">成功率</div>
<div class="stat-value">{{ statistics.successRate }}%</div>
<div class="stat-sub">
成功: {{ statistics.successCount }} / 失败: {{ statistics.failedCount }}
</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card stat-info">
<div class="stat-content">
<div class="stat-label">平均耗时</div>
<div class="stat-value">{{ Math.round(statistics.avgElapsedMs) }}</div>
<div class="stat-unit">ms</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card stat-secondary">
<div class="stat-content">
<div class="stat-label">今日调用</div>
<div class="stat-value">{{ statistics.todayCount }}</div>
<div class="stat-unit">次</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { ref, onMounted } from "vue";
import http from "@/api/axios";
export default {
name: "MesLogStatistics",
emits: ["refresh"],
setup(props, { emit }) {
const statistics = ref({
totalCount: 0,
successCount: 0,
failedCount: 0,
successRate: 0,
avgElapsedMs: 0,
todayCount: 0
});
const fetchStatistics = async () => {
try {
const res = await http.get("/api/MesLog/statistics");
if (res.status) {
statistics.value = res.data;
emit("refresh");
}
} catch (error) {
console.error("获取统计数据失败:", error);
}
};
onMounted(() => {
fetchStatistics();
});
return {
statistics,
fetchStatistics
};
}
};
</script>
<style scoped>
.mes-log-statistics {
margin-bottom: 16px;
}
.stat-card {
text-align: center;
}
.stat-content {
padding: 8px 0;
}
.stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
.stat-value {
font-size: 28px;
font-weight: bold;
margin-bottom: 4px;
}
.stat-unit {
font-size: 12px;
color: #909399;
}
.stat-sub {
font-size: 12px;
color: #606266;
margin-top: 4px;
}
.stat-primary .stat-value { color: #409EFF; }
.stat-success .stat-value { color: #67C23A; }
.stat-warning .stat-value { color: #E6A23C; }
.stat-info .stat-value { color: #909399; }
.stat-secondary .stat-value { color: #909399; }
</style>
git add WMS/WIDESEA_WMSClient/src/components/MesLogStatistics.vue
git commit -m "feat(MES): 添加MesLogStatistics统计卡片组件
- 显示总调用次数、成功率、平均耗时、今日调用
- 使用 el-card 自定义实现(兼容 Element Plus 2.2.14)
- 颜色标识:蓝色/绿色/橙色/灰色
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Create: WMS/WIDESEA_WMSClient/src/extension/system/Mes_Log.jsx
import { h, resolveComponent } from 'vue';
let extension = {
components: {
// 动态扩充组件或组件路径
gridHeader: "",
gridBody: '',
gridFooter: "",
modelHeader: "",
modelBody: "",
modelFooter: ""
},
buttons: [], // 扩展的按钮
methods: {
// 事件扩展
onInit() {
console.log("mes_log init");
this.setFiexdSearchForm(true);
},
onInited() {
this.height = this.height - 240; // 为统计卡片预留空间
// 添加预览方法
this.previewJson = (jsonStr) => {
if (!jsonStr) return '-';
try {
const obj = JSON.parse(jsonStr);
return JSON.stringify(obj, null, 2).substring(0, 200) + '...';
} catch {
return String(jsonStr).substring(0, 200) + '...';
}
};
},
// 行点击事件 - 显示 JSON 详情
rowClick({ row, column }) {
// 如果点击的是请求或响应列,显示详情弹窗
if (column.property === 'requestJson' || column.property === 'responseJson') {
this.showJsonDetail(row);
}
},
// 显示 JSON 详情弹窗
showJsonDetail(row) {
const elDialog = resolveComponent('el-dialog');
// 创建临时弹窗
this.$alert('', 'JSON 详情', {
message: h('div', { class: 'json-detail-dialog' }, [
h('el-tabs', { modelValue: 'request' }, [
h('el-tab-pane', { label: '请求', name: 'request' }, [
h('pre', { class: 'json-content' }, this.formatJson(row.requestJson))
]),
h('el-tab-pane', { label: '响应', name: 'response' }, [
h('pre', { class: 'json-content' }, this.formatJson(row.responseJson))
])
])
]),
customClass: 'mes-json-detail-dialog',
dangerouslyUseHTMLString: false
});
},
// 格式化 JSON
formatJson(jsonStr) {
if (!jsonStr) return '{}';
try {
const obj = typeof jsonStr === 'string' ? JSON.parse(jsonStr) : jsonStr;
return JSON.stringify(obj, null, 2);
} catch {
return String(jsonStr);
}
}
}
};
export default extension;
git add WMS/WIDESEA_WMSClient/src/extension/system/Mes_Log.jsx
git commit -m "feat(MES): 添加Mes_Log扩展逻辑
- 添加 previewJson 辅助函数
- 添加行点击事件处理
- 添加 JSON 详情显示功能
- 调整高度为统计卡片预留空间
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Create: WMS/WIDESEA_WMSClient/src/views/system/Mes_Log.vue
<!--
*Author:System
*Contact:-
*代码由框架生成,任何更改都可能导致被代码生成器覆盖
*业务请在@/extension/system/Mes_Log.jsx此处编写
-->
<template>
<div class="mes-log-page">
<!-- 统计卡片区域 -->
<mes-log-statistics ref="statistics" />
<!-- 日志列表 -->
<view-grid
ref="grid"
:columns="columns"
:detail="detail"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
/>
</div>
</template>
<script>
import extend from "@/extension/system/Mes_Log.jsx";
import MesLogStatistics from "@/components/MesLogStatistics.vue";
import { ref, defineComponent } from "vue";
export default defineComponent({
name: "Mes_Log",
components: {
MesLogStatistics
},
setup() {
const table = ref({
key: "Id",
cnName: "MES接口日志",
name: "Mes_Log",
url: "/Mes_Log/",
sortName: "Id"
});
const columns = ref([
{ field: "id", title: "ID", width: 80, hidden: true },
{
field: "apiType",
title: "接口类型",
width: 130,
bind: { key: "mesApiType", data: [] }
},
{
field: "isSuccess",
title: "状态",
width: 80,
bind: { key: "mesApiStatus", data: [] }
},
{
field: "requestJson",
title: "请求内容",
width: 200,
link: true
},
{
field: "responseJson",
title: "响应内容",
width: 200,
link: true
},
{ field: "errorMessage", title: "错误信息", width: 250 },
{ field: "elapsedMs", title: "耗时(ms)", width: 100, sortable: true },
{ field: "createDate", title: "调用时间", width: 160, sortable: true },
{ field: "creator", title: "操作人", width: 100 }
]);
const detail = ref({
cnName: "MES日志详情",
columns: [],
sortName: "Id",
key: "Id"
});
const editFormFields = ref({});
const editFormOptions = ref([]);
const searchFormFields = ref({
apiType: "",
isSuccess: "",
dateRange: "",
creator: "",
elapsedRange: "",
errorKeyword: "",
jsonKeyword: ""
});
const searchFormOptions = ref([
[
{ field: "apiType", title: "接口类型", type: "select" },
{ field: "isSuccess", title: "状态", type: "select" },
{ field: "dateRange", title: "时间范围", type: "datetimeRange" }
],
[
{ field: "creator", title: "操作人", type: "text" },
{
field: "elapsedRange",
title: "耗时范围(ms)",
type: "numberRange",
placeholder: ["最小", "最大"]
}
],
[
{ field: "errorKeyword", title: "错误关键字", type: "text" },
{ field: "jsonKeyword", title: "JSON内容关键字", type: "text" }
]
]);
return {
table,
columns,
detail,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
extend
};
}
});
</script>
<style scoped>
.mes-log-page {
padding: 16px;
}
</style>
git add WMS/WIDESEA_WMSClient/src/views/system/Mes_Log.vue
git commit -m "feat(MES): 添加Mes_Log日志页面
- 使用 view-grid 组件
- 集成统计卡片组件
- 配置搜索表单和列表列
- 支持多维度筛选
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
Files:
- Modify: WMS/WIDESEA_WMSClient/src/router/viewGird.js
cat WMS/WIDESEA_WMSClient/src/router/viewGird.js | head -50
在 viewGird.js 的路由数组中,找到 path: '/Sys_Log' 配置块(大约在文件开头),在其后添加:
{
path: '/Sys_Log',
name: 'sys_Log',
component: () => import('@/views/system/Sys_Log.vue')
},
{
path: '/Mes_Log', // ← 添加此块
name: 'mes_Log',
component: () => import('@/views/system/Mes_Log.vue')
},
{
path: '/Sys_User', // 下一个路由
name: 'Sys_User',
component: () => import('@/views/system/Sys_User.vue')
},
插入位置:在 Sys_Log 路由块之后,Sys_User 路由块之前
git add WMS/WIDESEA_WMSClient/src/router/viewGird.js
git commit -m "feat(MES): 添加Mes_Log路由配置
- 添加 /Mes_Log 路由
- 指向 views/system/Mes_Log.vue
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
-- 在 SQL Server Management Studio 中执行
-- 接口类型索引
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_MesApiLog_ApiType' AND object_id = OBJECT_ID('Dt_MesApiLog'))
BEGIN
CREATE INDEX IX_MesApiLog_ApiType ON Dt_MesApiLog(ApiType);
END
-- 创建时间索引
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_MesApiLog_CreateDate' AND object_id = OBJECT_ID('Dt_MesApiLog'))
BEGIN
CREATE INDEX IX_MesApiLog_CreateDate ON Dt_MesApiLog(CreateDate DESC);
END
-- 成功状态索引
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_MesApiLog_IsSuccess' AND object_id = OBJECT_ID('Dt_MesApiLog'))
BEGIN
CREATE INDEX IX_MesApiLog_IsSuccess ON Dt_MesApiLog(IsSuccess);
END
-- 创建人索引
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_MesApiLog_Creator' AND object_id = OBJECT_ID('Dt_MesApiLog'))
BEGIN
CREATE INDEX IX_MesApiLog_Creator ON Dt_MesApiLog(Creator);
END
-- 先查询系统管理菜单的 ID
SELECT Id, MenuName FROM Dt_Menu WHERE MenuName LIKE '%系统%' OR MenuName LIKE '%System%';
-- 假设系统管理菜单 ID 为 XXX,插入 MES 接口日志菜单
INSERT INTO Dt_Menu (ParentId, MenuName, Url, Component, Permission, Sort, Icon, CreateDate, Modifier)
VALUES (
XXX, -- 替换为实际的系统管理菜单 ID
'MES接口日志',
'/Mes_Log',
'views/system/Mes_Log',
'Mes_Log:view',
(SELECT ISNULL(MAX(Sort), 0) + 1 FROM Dt_Menu WHERE ParentId = XXX),
'el-icon-document',
GETDATE(),
'System'
);
-- 接口类型字典
DECLARE @DictId INT;
SELECT @DictId = Id FROM Dt_Dictionary WHERE DictKey = 'mesApiType';
IF @DictId IS NULL
BEGIN
INSERT INTO Dt_Dictionary (DictKey, DictValue, CreateDate, Modifier)
VALUES ('mesApiType', 'MES接口类型', GETDATE(), 'System');
SET @DictId = SCOPE_IDENTITY();
END
-- 添加接口类型选项
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @DictId, '电芯绑定', 'BindContainer', 1, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @DictId AND [Key] = 'BindContainer');
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @DictId, '电芯解绑', 'UnBindContainer', 2, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @DictId AND [Key] = 'UnBindContainer');
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @DictId, 'NG上报', 'ContainerNgReport', 3, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @DictId AND [Key] = 'ContainerNgReport');
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @DictId, '托盘进站', 'InboundInContainer', 4, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @DictId AND [Key] = 'InboundInContainer');
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @DictId, '托盘出站', 'OutboundInContainer', 5, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @DictId AND [Key] = 'OutboundInContainer');
-- 调用状态字典
DECLARE @StatusDictId INT;
SELECT @StatusDictId = Id FROM Dt_Dictionary WHERE DictKey = 'mesApiStatus';
IF @StatusDictId IS NULL
BEGIN
INSERT INTO Dt_Dictionary (DictKey, DictValue, CreateDate, Modifier)
VALUES ('mesApiStatus', 'MES接口状态', GETDATE(), 'System');
SET @StatusDictId = SCOPE_IDENTITY();
END
-- 添加状态选项
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @StatusDictId, '成功', 'true', 1, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @StatusDictId AND [Key] = 'true');
INSERT INTO Dt_DictionaryList (DictId, Value, Key, DisplayOrder, CreateDate, Modifier)
SELECT @StatusDictId, '失败', 'false', 2, GETDATE(), 'System'
WHERE NOT EXISTS (SELECT 1 FROM Dt_DictionaryList WHERE DictId = @StatusDictId AND [Key] = 'false');
# 将上述 SQL 脚本保存到文件
cat > WMS/WIDESEA_WMSServer/Database/Scripts/20260413_MesLogPage_Config.sql << 'EOF'
-- 这里粘贴上面的 SQL 脚本
EOF
git add WMS/WIDESEA_WMSServer/Database/Scripts/20260413_MesLogPage_Config.sql
git commit -m "feat(MES): 添加MES日志页面数据库配置
- 创建性能索引
- 添加菜单记录
- 添加数据字典(接口类型、状态)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
cd WMS/WIDESEA_WMSServer
dotnet build WIDESEA_WMSServer.sln
预期输出:编译成功,无错误
cd WMS/WIDESEA_WMSClient
npm install
npm run build
预期输出:编译成功,无错误
git status
git log --oneline -10
确认所有任务已完成,功能测试通过
docs/superpowers/specs/2026-04-13-mes-api-log-page-design.mdWMS/WIDESEA_WMSClient/src/views/system/Sys_Log.vueWMS/WIDESEA_WMSClient/src/extension/system/Sys_Log.jsxWMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Mes/Dt_MesApiLog.cs