From 5e851678cc02257bbbd179446de36082430ca5bc Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期一, 13 四月 2026 15:12:04 +0800
Subject: [PATCH] feat(MES): 添加Mes_Log扩展逻辑

---
 Code/docs/superpowers/specs/2026-04-13-mes-api-log-page-design.md |  896 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 896 insertions(+), 0 deletions(-)

diff --git a/Code/docs/superpowers/specs/2026-04-13-mes-api-log-page-design.md b/Code/docs/superpowers/specs/2026-04-13-mes-api-log-page-design.md
new file mode 100644
index 0000000..81592ec
--- /dev/null
+++ b/Code/docs/superpowers/specs/2026-04-13-mes-api-log-page-design.md
@@ -0,0 +1,896 @@
+# MES 鎺ュ彛璋冪敤鏃ュ織椤甸潰璁捐鏂囨。
+
+**鏃ユ湡:** 2026-04-13
+**浣滆��:** Claude
+**鐗堟湰:** v0.3
+**鐘舵��:** 宸叉壒鍑�
+
+---
+
+## 1. 姒傝堪
+
+### 1.1 鐩爣
+
+鍦� WMS 绯荤粺涓坊鍔� MES 鎺ュ彛璋冪敤鏃ュ織鏌ョ湅椤甸潰锛屾彁渚涚患鍚堟�х殑鏃ュ織鏌ヨ銆佺粺璁″拰绠$悊鍔熻兘銆�
+
+### 1.2 鑼冨洿
+
+- 鍚庣锛欰PI 鎺ュ彛銆佹湇鍔″眰鎵╁睍
+- 鍓嶇锛氭棩蹇楀垪琛ㄩ〉闈€�佺粺璁″崱鐗囥�丣SON 璇︽儏鏌ョ湅鍣�
+- 鏁版嵁搴擄細鑿滃崟閰嶇疆銆佹暟鎹瓧鍏�
+
+---
+
+## 2. 鍚庣璁捐
+
+### 2.1 Controller 鎺ュ彛
+
+**鏂囦欢璺緞:** `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Mes/MesLogController.cs`
+
+**娉ㄦ剰:** 姝ゆ帶鍒跺櫒涓嶇户鎵� `ApiBaseController`锛屽洜涓� MES 鏃ュ織鏄彧璇昏褰曪紝涓嶉渶瑕佸畬鏁寸殑 CRUD 鎿嶄綔銆備粎鎻愪緵鏌ヨ銆佺粺璁″拰瀵煎嚭鍔熻兘銆�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| POST | `/api/MesLog/page` | 鍒嗛〉鏌ヨ锛屾敮鎸佹墍鏈夌瓫閫夋潯浠� |
+| GET | `/api/MesLog/{id}` | 鑾峰彇鍗曟潯鏃ュ織瀹屾暣淇℃伅 |
+| GET | `/api/MesLog/statistics` | 鑾峰彇缁熻鏁版嵁 |
+| POST | `/api/MesLog/export` | 瀵煎嚭鏌ヨ缁撴灉涓� Excel (浣跨敤妗嗘灦鍐呯疆瀵煎嚭) |
+
+### 2.2 鏁版嵁浼犺緭瀵硅薄
+
+#### 2.2.1 鏌ヨ璇锋眰 DTO
+
+```csharp
+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 瀛楁鏄犲皠锛歞ateRange[0] 鈫� StartTime锛�
+        /// </summary>
+        public DateTime? StartTime { get; set; }
+
+        /// <summary>
+        /// 缁撴潫鏃堕棿锛堝墠绔� dateRange 瀛楁鏄犲皠锛歞ateRange[1] 鈫� EndTime锛�
+        /// </summary>
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 鍒涘缓浜猴紙鎿嶄綔浜猴級
+        /// </summary>
+        public string Creator { get; set; }
+
+        /// <summary>
+        /// 鏈�灏忚�楁椂锛堟绉掞級锛堝墠绔� elapsedRange 瀛楁鏄犲皠锛歟lapsedRange[0] 鈫� MinElapsedMs锛�
+        /// </summary>
+        public int? MinElapsedMs { get; set; }
+
+        /// <summary>
+        /// 鏈�澶ц�楁椂锛堟绉掞級锛堝墠绔� elapsedRange 瀛楁鏄犲皠锛歟lapsedRange[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; }
+    }
+}
+```
+
+#### 2.2.2 缁熻鏁版嵁 DTO
+
+```csharp
+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>
+        /// 鍚勬帴鍙g被鍨嬭皟鐢ㄦ鏁扮粺璁�
+        /// </summary>
+        public Dictionary<string, int> ApiTypeCounts { get; set; }
+    }
+}
+```
+
+#### 2.2.3 鍒嗛〉鍝嶅簲 DTO
+
+```csharp
+namespace WIDESEA_DTO.MES
+{
+    /// <summary>
+    /// MES鏃ュ織鍒楄〃椤笵TO
+    /// </summary>
+    public class MesLogListItemDto
+    {
+        public long Id { get; set; }
+        public string ApiType { get; set; }
+        public bool IsSuccess { get; set; }
+        public string RequestJsonPreview { get; set; }  // 鍓�200瀛楃棰勮
+        public string ResponseJsonPreview { get; set; } // 鍓�200瀛楃棰勮
+        public string ErrorMessage { get; set; }
+        public int ElapsedMs { get; set; }
+        public DateTime CreateDate { get; set; }
+        public string Creator { get; set; }
+    }
+
+    /// <summary>
+    /// MES鏃ュ織璇︽儏DTO
+    /// </summary>
+    public class MesLogDetailDto : MesLogListItemDto
+    {
+        public string RequestJson { get; set; }   // 瀹屾暣JSON
+        public string ResponseJson { get; set; }  // 瀹屾暣JSON
+        public DateTime? ModifyDate { get; set; }
+        public string Modifier { get; set; }
+    }
+}
+```
+
+### 2.3 Service 鎺ュ彛鎵╁睍
+
+**鏂囦欢璺緞:** `WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs`
+
+```csharp
+namespace WIDESEA_IMesService
+{
+    public interface IMesLogService : IDependency
+    {
+        // 鐜版湁鏂规硶
+        Task<bool> LogAsync(MesApiLogDto log);
+        Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50);
+
+        // 鏂板鏂规硶
+        /// <summary>
+        /// 鍒嗛〉鏌ヨMES鏃ュ織
+        /// </summary>
+        Task<(List<MesLogListItemDto> items, int total)> GetPageAsync(MesLogQueryDto query, int page, int pageSize);
+
+        /// <summary>
+        /// 鑾峰彇鍗曟潯鏃ュ織璇︽儏
+        /// </summary>
+        Task<MesLogDetailDto> GetDetailAsync(long id);
+
+        /// <summary>
+        /// 鑾峰彇缁熻鏁版嵁
+        /// </summary>
+        Task<MesLogStatisticsDto> GetStatisticsAsync(MesLogQueryDto query);
+
+        /// <summary>
+        /// 瀵煎嚭鏃ュ織鏁版嵁
+        /// </summary>
+        Task<byte[]> ExportAsync(MesLogQueryDto query);
+    }
+}
+```
+
+### 2.4 Controller 瀹炵幇妗嗘灦
+
+```csharp
+namespace WIDESEA_WMSServer.Controllers.Mes
+{
+    [Route("api/MesLog")]
+    [ApiController]
+    public class MesLogController : ControllerBase
+    {
+        private readonly IMesLogService _mesLogService;
+
+        public MesLogController(IMesLogService mesLogService)
+        {
+            _mesLogService = mesLogService;
+        }
+
+        /// <summary>
+        /// 鍒嗛〉鏌ヨMES鏃ュ織
+        /// </summary>
+        [HttpPost("page")]
+        public async Task<WebResponseContent> GetPage([FromBody] MesLogQueryDto query, [FromQuery] int page = 1, [FromQuery] int pageSize = 20)
+        {
+            // 瀹炵幇鍒嗛〉鏌ヨ
+        }
+
+        /// <summary>
+        /// 鑾峰彇鏃ュ織璇︽儏
+        /// </summary>
+        [HttpGet("{id}")]
+        public async Task<WebResponseContent> GetDetail(long id)
+        {
+            // 瀹炵幇璇︽儏鏌ヨ
+        }
+
+        /// <summary>
+        /// 鑾峰彇缁熻鏁版嵁
+        /// </summary>
+        [HttpGet("statistics")]
+        public async Task<WebResponseContent> GetStatistics([FromQuery] MesLogQueryDto query)
+        {
+            // 瀹炵幇缁熻鏌ヨ
+        }
+
+        /// <summary>
+        /// 瀵煎嚭鏃ュ織 - 浣跨敤妗嗘灦鍐呯疆 ServiceBase.Export() 鏂规硶
+        /// 閫氳繃 HttpHelper.Post() 璋冪敤妗嗘灦鐨勯�氱敤瀵煎嚭鎺ュ彛
+        /// </summary>
+        [HttpPost("export")]
+        public async Task<IActionResult> Export([FromBody] MesLogQueryDto query)
+        {
+            // 璋冪敤 _mesLogService.ExportAsync() 鐢熸垚鏁版嵁
+            // 浣跨敤妗嗘灦鍐呯疆鐨� ExcelExporter 瀵煎嚭
+        }
+    }
+}
+```
+
+### 2.5 鏈嶅姟娉ㄥ唽
+
+**娉ㄦ剰:** `IMesLogService` 宸插疄鐜� `IDependency` 鎺ュ彛锛屾棤闇�鎵嬪姩娉ㄥ唽銆傛鏋朵細閫氳繃 `AutofacModuleRegister` 鑷姩娉ㄥ唽鎵�鏈� `IDependency` 瀹炵幇銆�
+
+---
+
+## 3. 鍓嶇璁捐
+
+### 3.1 鏂囦欢缁撴瀯
+
+```
+src/
+鈹溾攢鈹� views/
+鈹�   鈹斺攢鈹� system/
+鈹�       鈹斺攢鈹� Mes_Log.vue              # 涓婚〉闈�
+鈹溾攢鈹� extension/
+鈹�   鈹斺攢鈹� system/
+鈹�       鈹斺攢鈹� Mes_Log.jsx              # 涓氬姟鎵╁睍閫昏緫
+鈹溾攢鈹� components/
+鈹�   鈹斺攢鈹� MesJsonViewer.vue            # JSON 璇︽儏鏌ョ湅鍣ㄧ粍浠�
+鈹斺攢鈹� router/
+    鈹斺攢鈹� viewGird.js                  # 娣诲姞璺敱閰嶇疆
+```
+
+### 3.2 Mes_Log.vue 閰嶇疆
+
+**娉ㄦ剰:** `view-grid` 缁勪欢涓嶆敮鎸� `toolbar` 鎻掓Ы锛岀粺璁″崱鐗囬渶瑕佹斁鍦� `view-grid` 澶栭儴銆�
+
+```vue
+<template>
+  <div class="mes-log-page">
+    <!-- 缁熻鍗$墖鍖哄煙锛堜綅浜� view-grid 涓婃柟锛� -->
+    <mes-log-statistics ref="statistics" @refresh="onStatsRefresh" />
+
+    <!-- 鏃ュ織鍒楄〃 -->
+    <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 { ref, defineComponent } from "vue";
+
+export default defineComponent({
+  setup() {
+    const table = ref({
+      key: "Id",
+      cnName: "MES鎺ュ彛鏃ュ織",
+      name: "Mes_Log",
+      url: "/api/MesLog/",
+      sortName: "Id DESC",
+    });
+
+    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,
+        formatter: (row) => previewJson(row.requestJson)
+      },
+      {
+        field: "responseJson",
+        title: "鍝嶅簲鍐呭",
+        width: 200,
+        link: true,
+        formatter: (row) => previewJson(row.responseJson)
+      },
+      { field: "errorMessage", title: "閿欒淇℃伅", width: 200 },
+      { field: "elapsedMs", title: "鑰楁椂(ms)", width: 100, sortable: true },
+      { field: "createDate", title: "璋冪敤鏃堕棿", width: 160, sortable: true },
+      { field: "creator", title: "鎿嶄綔浜�", width: 100 }
+    ]);
+
+    // JSON 鍐呭棰勮杈呭姪鍑芥暟锛堝湪 Mes_Log.jsx 涓疄鐜帮級
+    const 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) + '...';
+      }
+    };
+
+    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, searchFormOptions, extend, /* ... */ };
+  }
+});
+</script>
+```
+
+### 3.3 MesJsonViewer.vue 缁勪欢
+
+**娉ㄦ剰:** 涓嶄娇鐢ㄥ閮� JSON 鏌ョ湅鍣ㄥ簱锛岄噰鐢ㄥ師鐢� `<pre>` 鏍囩 + `JSON.stringify()` 鏍煎紡鍖栨樉绀恒��
+
+```vue
+<template>
+  <el-dialog
+    v-model="visible"
+    :title="title"
+    width="800px"
+    :close-on-click-modal="false"
+  >
+    <el-tabs v-model="activeTab">
+      <el-tab-pane label="璇锋眰" name="request">
+        <div class="json-container">
+          <el-button
+            size="small"
+            class="copy-btn"
+            @click="copyToClipboard(formattedRequest)"
+          >
+            澶嶅埗
+          </el-button>
+          <pre class="json-content">{{ formattedRequest }}</pre>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="鍝嶅簲" name="response">
+        <div class="json-container">
+          <el-button
+            size="small"
+            class="copy-btn"
+            @click="copyToClipboard(formattedResponse)"
+          >
+            澶嶅埗
+          </el-button>
+          <pre class="json-content">{{ formattedResponse }}</pre>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+
+    <template #footer>
+      <el-button @click="visible = false">鍏抽棴</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script>
+import { computed, ref } from 'vue';
+
+export default {
+  name: "MesJsonViewer",
+  props: {
+    modelValue: Boolean,
+    title: String,
+    requestJson: [String, Object],
+    responseJson: [String, Object]
+  },
+  emits: ["update:modelValue"],
+  setup(props) {
+    const activeTab = ref('request');
+
+    const formattedRequest = computed(() => {
+      try {
+        const obj = typeof props.requestJson === 'string'
+          ? JSON.parse(props.requestJson)
+          : props.requestJson;
+        return JSON.stringify(obj, null, 2);
+      } catch {
+        return props.requestJson || '{}';
+      }
+    });
+
+    const formattedResponse = computed(() => {
+      try {
+        const obj = typeof props.responseJson === 'string'
+          ? JSON.parse(props.responseJson)
+          : props.responseJson;
+        return JSON.stringify(obj, null, 2);
+      } catch {
+        return props.responseJson || '{}';
+      }
+    });
+
+    const copyToClipboard = (text) => {
+      // 浼樺厛浣跨敤鐜颁唬 Clipboard API锛堥渶瑕� HTTPS 鎴� localhost锛�
+      if (navigator.clipboard && navigator.clipboard.writeText) {
+        navigator.clipboard.writeText(text).catch(() => {
+          // 濡傛灉澶辫触锛屼娇鐢ㄩ檷绾ф柟妗�
+          fallbackCopy(text);
+        });
+      } else {
+        // 闄嶇骇鏂规锛氬吋瀹� HTTP 鐜鍜屾棫娴忚鍣�
+        fallbackCopy(text);
+      }
+    };
+
+    const fallbackCopy = (text) => {
+      const textarea = document.createElement('textarea');
+      textarea.value = text;
+      textarea.style.position = 'fixed';
+      textarea.style.opacity = '0';
+      document.body.appendChild(textarea);
+      textarea.select();
+      try {
+        document.execCommand('copy');
+      } catch (err) {
+        console.error('澶嶅埗澶辫触:', err);
+      }
+      document.body.removeChild(textarea);
+    };
+
+    return {
+      visible: props.modelValue,
+      activeTab,
+      formattedRequest,
+      formattedResponse,
+      copyToClipboard
+    };
+  }
+};
+</script>
+
+<style scoped>
+.json-container {
+  position: relative;
+}
+
+.copy-btn {
+  position: absolute;
+  top: 8px;
+  right: 8px;
+  z-index: 10;
+}
+
+.json-content {
+  background: #f5f7fa;
+  padding: 16px;
+  border-radius: 4px;
+  max-height: 500px;
+  overflow: auto;
+  font-size: 12px;
+  line-height: 1.5;
+}
+</style>
+```
+
+### 3.4 缁熻鍗$墖缁勪欢
+
+**鏂囦欢璺緞:** `src/components/MesLogStatistics.vue`
+
+**娉ㄦ剰:** 褰撳墠椤圭洰 Element Plus 鐗堟湰涓� 2.2.14锛屼笉鏀寔 `el-statistic` 缁勪欢锛堥渶瑕� 2.3+锛夈�傞噰鐢ㄨ嚜瀹氫箟鍗$墖瀹炵幇銆�
+
+```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 axios from '@/api/axios';
+
+export default {
+  name: "MesLogStatistics",
+  setup() {
+    const statistics = ref({
+      totalCount: 0,
+      successCount: 0,
+      failedCount: 0,
+      successRate: 0,
+      avgElapsedMs: 0,
+      todayCount: 0
+    });
+
+    const fetchStatistics = async () => {
+      const res = await axios.post('/api/MesLog/statistics', {});
+      if (res.status) {
+        statistics.value = res.data;
+      }
+    };
+
+    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>
+```
+
+### 3.5 鑷姩鍒锋柊鍔熻兘
+
+**UX 璇存槑:**
+- 鍒锋柊鎺у埗浣嶄簬椤甸潰鍙充笂瑙掞紝涓庢煡璇㈡潯浠跺苟鍒�
+- 褰撶敤鎴锋墦寮�绛涢�夐潰鏉裤�佺紪杈戞煡璇㈡潯浠舵垨鏌ョ湅璇︽儏鏃讹紝鑷姩鍒锋柊鏆傚仠
+- 鐢ㄦ埛鎵嬪姩鐐瑰嚮鏌ヨ/鍒锋柊鎸夐挳鍚庯紝鑷姩鍒锋柊閲嶆柊璁℃椂
+
+```javascript
+// 鍦� Mes_Log.jsx 涓疄鐜�
+const refreshOptions = [
+  { label: "鍏抽棴", value: 0 },
+  { label: "10绉�", value: 10 },
+  { label: "30绉�", value: 30 },
+  { label: "1鍒嗛挓", value: 60 },
+  { label: "5鍒嗛挓", value: 300 }
+];
+
+let refreshTimer = null;
+
+const setAutoRefresh = (interval) => {
+  if (refreshTimer) {
+    clearInterval(refreshTimer);
+    refreshTimer = null;
+  }
+  if (interval > 0) {
+    refreshTimer = setInterval(() => {
+      // 浠呭湪鐢ㄦ埛鏈氦浜掓椂鍒锋柊鍒楄〃鏁版嵁
+      if (!isUserInteracting) {
+        refresh();
+      }
+    }, interval * 1000);
+  }
+};
+
+// 鐢ㄦ埛浜や簰鏃舵殏鍋滃埛鏂�
+const onUserInteractionStart = () => {
+  isUserInteracting = true;
+};
+
+const onUserInteractionEnd = () => {
+  isUserInteracting = false;
+};
+```
+
+---
+
+## 4. 鏁版嵁瀛楀吀閰嶇疆
+
+### 4.1 鎺ュ彛绫诲瀷瀛楀吀 (mesApiType)
+
+| 鍊� | 鏄剧ず鏂囨湰 | 璇存槑 |
+|---|---------|------|
+| BindContainer | 鐢佃姱缁戝畾 | 鎵樼洏鐢佃姱缁戝畾鎿嶄綔 |
+| UnBindContainer | 鐢佃姱瑙g粦 | 鎵樼洏鐢佃姱瑙g粦鎿嶄綔 |
+| ContainerNgReport | NG涓婃姤 | 鎵樼洏NG鐢佃姱涓婃姤 |
+| InboundInContainer | 鎵樼洏杩涚珯 | 鎵樼洏杩涚珯鎿嶄綔 |
+| OutboundInContainer | 鎵樼洏鍑虹珯 | 鎵樼洏鍑虹珯鎿嶄綔 |
+
+### 4.2 璋冪敤鐘舵�佸瓧鍏� (mesApiStatus)
+
+| 鍊� | 鏄剧ず鏂囨湰 | 棰滆壊 |
+|---|---------|------|
+| true | 鎴愬姛 | 缁胯壊 |
+| false | 澶辫触 | 绾㈣壊 |
+
+---
+
+## 5. 鏉冮檺涓庤彍鍗�
+
+### 5.1 鑿滃崟閰嶇疆
+
+鍦� `Dt_Menu` 琛ㄤ腑娣诲姞锛�
+
+| 瀛楁 | 鍊� |
+|------|-----|
+| ParentId | (绯荤粺绠$悊鑿滃崟鐨� ID) |
+| MenuName | MES鎺ュ彛鏃ュ織 |
+| Url | /Mes_Log |
+| Component | views/system/Mes_Log |
+| Permission | Mes_Log:view |
+| Sort | (鎺掑湪 Sys_Log 涔嬪悗) |
+| Icon | el-icon-document |
+
+### 5.2 鏉冮檺鐐�
+
+- `Mes_Log:view` - 鏌ョ湅鏃ュ織鍒楄〃
+- `Mes_Log:detail` - 鏌ョ湅鏃ュ織璇︽儏
+- `Mes_Log:export` - 瀵煎嚭鏃ュ織
+
+---
+
+## 6. 瀹炵幇姝ラ
+
+### 6.1 鍚庣瀹炵幇
+
+1. 鎵╁睍 `IMesLogService` 鎺ュ彛锛堟坊鍔犲垎椤点�佺粺璁°�佸鍑烘柟娉曪級
+2. 瀹炵幇 `MesLogService` 鐨勬墿灞曟柟娉�
+3. 鍒涘缓 DTO 鏂囦欢锛坄MesLogQueryDto.cs`, `MesLogStatisticsDto.cs`, `MesLogListItemDto.cs`锛�
+4. 鍒涘缓 `MesLogController.cs`
+5. **娉ㄦ剰:** 鏈嶅姟娉ㄥ唽鑷姩瀹屾垚锛坄IMesLogService` 宸插疄鐜� `IDependency`锛�
+
+### 6.2 鍓嶇瀹炵幇
+
+1. 鍒涘缓 `MesJsonViewer.vue` 缁勪欢锛堜娇鐢ㄥ師鐢� `<pre>` 鏍囩锛屾棤澶栭儴渚濊禆锛�
+2. 鍒涘缓 `MesLogStatistics.vue` 缁勪欢锛堜娇鐢� `el-card` 鑷畾涔夊疄鐜帮級
+3. 鍒涘缓 `Mes_Log.jsx` 鎵╁睍閫昏緫
+4. 鍒涘缓 `Mes_Log.vue` 椤甸潰
+5. 鍦� `viewGird.js` 娣诲姞璺敱
+6. 鍦� `extension` 鐩綍娣诲姞鎵╁睍鏂囦欢
+
+### 6.3 鏁版嵁搴撻厤缃�
+
+1. 纭 `Dt_MesApiLog` 琛ㄥ凡瀛樺湪锛堝弬瑙� `Database/Scripts/20260412_MesApiLog.sql`锛�
+2. 鍒涘缓鏁版嵁搴撶储寮曪紙鍙傝 6.4 鑺傦級
+3. 鎻掑叆鑿滃崟璁板綍鍒� `Dt_Menu` 琛�
+4. 鎻掑叆鏁版嵁瀛楀吀璁板綍鍒� `Dt_Dictionary` 琛�
+5. 鍒嗛厤鏉冮檺缁欒鑹�
+
+### 6.4 鏁版嵁搴撶储寮�
+
+鎵ц浠ヤ笅 SQL 鍒涘缓绱㈠紩浠ヤ紭鍖栨煡璇㈡�ц兘锛�
+
+```sql
+-- 鎺ュ彛绫诲瀷绱㈠紩锛堢敤浜庢寜绫诲瀷绛涢�夛級
+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
+```
+
+---
+
+## 7. 鎶�鏈鐐�
+
+### 7.1 JSON 鍐呭鎼滅储
+
+鐢变簬 SQL Server 瀵� JSON 瀛楁鏀寔鏈夐檺锛岄噰鐢� `LIKE` 鎼滅储锛�
+- 閫傜敤浜庡叧閿瓧鎼滅储
+- 娉ㄦ剰鎬ц兘褰卞搷锛屽缓璁厤鍚堟椂闂磋寖鍥寸瓫閫�
+- 鎼滅储瀛楁锛歚RequestJson`銆乣ResponseJson`銆乣ErrorMessage`
+
+### 7.2 鍒嗛〉鎬ц兘
+
+- 鍒╃敤绱㈠紩锛堝弬瑙� 6.4 鑺傛暟鎹簱绱㈠紩锛�
+- 澶ф暟鎹噺鏃跺缓璁鍔犳椂闂磋寖鍥撮檺鍒讹紙榛樿鏄剧ず鏈�杩� 7 澶╋級
+- 鑰冭檻娣诲姞 `TOP 1000` 闄愬埗闃叉鍏ㄨ〃鎵弿
+
+### 7.3 瀵煎嚭鍔熻兘
+
+- 浣跨敤妗嗘灦鍐呯疆鐨� `ServiceBase.Export()` 鏂规硶
+- 閫氳繃 `Magicodes.ExporterAndImporter.Excel` 搴撳疄鐜�
+- 瀵煎嚭鏂囦欢鍛藉悕锛歚MES鎺ュ彛鏃ュ織_YYYYMMDD_HHMMSS.xlsx`
+- 鏀寔涓庡綋鍓嶆煡璇㈡潯浠朵竴鑷寸殑瀵煎嚭
+
+### 7.4 鍓嶇瀛楁鏄犲皠
+
+| 鍓嶇瀛楁 | 鍚庣 DTO 瀛楁 | 璇存槑 |
+|---------|--------------|------|
+| dateRange[0] | StartTime | 寮�濮嬫椂闂� |
+| dateRange[1] | EndTime | 缁撴潫鏃堕棿 |
+| elapsedRange[0] | MinElapsedMs | 鏈�灏忚�楁椂 |
+| elapsedRange[1] | MaxElapsedMs | 鏈�澶ц�楁椂 |
+| jsonKeyword | JsonRequestKeyword, JsonResponseKeyword | 鍚屾椂鎼滅储璇锋眰鍜屽搷搴� |
+
+---
+
+## 8. 娴嬭瘯瑕佺偣
+
+1. **鍒嗛〉鏌ヨ** - 楠岃瘉鍚勭绛涢�夋潯浠剁殑缁勫悎
+2. **缁熻鍑嗙‘鎬�** - 楠岃瘉缁熻鏁版嵁涓庡疄闄呮暟鎹竴鑷�
+3. **JSON灞曠ず** - 楠岃瘉鏍煎紡鍖栥�佹姌鍙犮�佸鍒跺姛鑳�
+4. **鑷姩鍒锋柊** - 楠岃瘉瀹氭椂鍒锋柊鍔熻兘姝e父宸ヤ綔
+5. **瀵煎嚭鍔熻兘** - 楠岃瘉 Excel 鏂囦欢鍐呭姝g‘
+6. **鏉冮檺鎺у埗** - 楠岃瘉鏃犳潈闄愮敤鎴锋棤娉曡闂�
+
+---
+
+## 9. 鍚庣画浼樺寲寤鸿
+
+1. **鏃ュ織褰掓。** - 鑰冭檻瀹氭湡褰掓。鏃ф棩蹇楋紝淇濇寔涓昏〃鎬ц兘
+2. **瀹炴椂鐩戞帶** - 闆嗘垚 SignalR 瀹炵幇瀹炴椂鏃ュ織鎺ㄩ��
+3. **寮傚父鍛婅** - 澶辫触鐜囪秴杩囬槇鍊兼椂鍙戦�佸憡璀�
+4. **鎬ц兘鍒嗘瀽** - 娣诲姞鑰楁椂瓒嬪娍鍥捐〃
+5. **鎺ュ彛瀵规瘮** - 鏀寔鍚岀被鎺ュ彛璋冪敤鐨勫姣斿垎鏋�

--
Gitblit v1.9.3