From 45a7bf7f1f1c5da428883e7a142b33a9bc82eeea Mon Sep 17 00:00:00 2001
From: tjx <t2856754968@163.com>
Date: 星期一, 13 十月 2025 13:10:26 +0800
Subject: [PATCH] 11111

---
 MESApplication/Controllers/QC/SpiAoiController.cs                             |  228 +++++++
 MESApplication/bin/Debug/net8.0/MES.Service.pdb                               |    0 
 MESApplication/bin/Debug/net8.0/MESApplication.dll                            |    0 
 MES.Service/bin/Debug/net8.0/MES.Service.dll                                  |    0 
 MESApplication/bin/Debug/net8.0/MESApplication.xml                            |  224 ++++--
 MESApplication/bin/Debug/net8.0/MES.Service.dll                               |    0 
 MES.Service/Modes/MesSpiAoiDetail.cs                                          |  220 +++++++
 MES.Service/Modes/MesSpiAoiHeader.cs                                          |  100 +++
 MESApplication/bin/Debug/net8.0/MESApplication.pdb                            |    0 
 MES.Service/service/QC/SpiAoiService.cs                                       |  387 ++++++++++++
 MES.Service/service/QC/SPIAOI.txt                                             |  428 +++++++++++++
 MESApplication/bin/Debug/net8.0/MESApplication.deps.json                      |    2 
 MESApplication/bin/Debug/net8.0/MESApplication.exe                            |    0 
 MESApplication/bin/Debug/net8.0/MESApplication.staticwebassets.endpoints.json |    6 
 MES.Service/Dto/service/SpiAoiDto.cs                                          |  260 ++++++++
 MES.Service/bin/Debug/net8.0/MES.Service.pdb                                  |    0 
 16 files changed, 1,759 insertions(+), 96 deletions(-)

diff --git a/MES.Service/Dto/service/SpiAoiDto.cs b/MES.Service/Dto/service/SpiAoiDto.cs
new file mode 100644
index 0000000..602a5eb
--- /dev/null
+++ b/MES.Service/Dto/service/SpiAoiDto.cs
@@ -0,0 +1,260 @@
+namespace MES.Service.Dto.service;
+
+/// <summary>
+///     SPI/AOI涓婁紶璇锋眰DTO
+/// </summary>
+public class SpiAoiUploadRequest
+{
+    /// <summary>
+    ///     涓昏〃鏁版嵁
+    /// </summary>
+    public SpiAoiHeaderDto Header { get; set; }
+
+    /// <summary>
+    ///     瀛愯〃鏁版嵁鍒楄〃
+    /// </summary>
+    public List<SpiAoiDetailDto> Details { get; set; }
+}
+
+/// <summary>
+///     SPI/AOI涓昏〃DTO
+/// </summary>
+public class SpiAoiHeaderDto
+{
+    /// <summary>
+    ///     娴嬭瘯鏃ユ湡(鏍煎紡锛歽yyy-MM-dd)
+    /// </summary>
+    public string TestDate { get; set; }
+
+    /// <summary>
+    ///     娴嬭瘯鏃堕棿(鏍煎紡锛欻H:mm:ss)
+    /// </summary>
+    public string TestTime { get; set; }
+
+    /// <summary>
+    ///     娴嬭瘯缁撴灉(濡傦細0:0:1;0銆�0;0;0:1銆丗ail绛�)
+    /// </summary>
+    public string TestResult { get; set; }
+
+    /// <summary>
+    ///     鏉块潰(T鎴朆)
+    /// </summary>
+    public string Surface { get; set; }
+
+    /// <summary>
+    ///     娴嬭瘯鐐规暟
+    /// </summary>
+    public int? TotalPoints { get; set; }
+
+    /// <summary>
+    ///     瀹為檯涓嶈壇鐐规暟
+    /// </summary>
+    public int? ActualDefects { get; set; }
+
+    /// <summary>
+    ///     璁惧鍨嬪彿
+    /// </summary>
+    public string? EquipmentModel { get; set; }
+
+    /// <summary>
+    ///     鎵规宸ュ崟
+    /// </summary>
+    public string? WorkOrder { get; set; }
+
+    /// <summary>
+    ///     鏈虹鍚�
+    /// </summary>
+    public string? ProductModel { get; set; }
+
+    /// <summary>
+    ///     鏉$爜
+    /// </summary>
+    public string BoardBarcode { get; set; }
+
+    /// <summary>
+    ///     SMT缁勫埆
+    /// </summary>
+    public string? SmtGroup { get; set; }
+
+    /// <summary>
+    ///     绾垮埆
+    /// </summary>
+    public string? LineName { get; set; }
+}
+
+/// <summary>
+///     SPI/AOI瀛愯〃DTO
+/// </summary>
+public class SpiAoiDetailDto
+{
+    /// <summary>
+    ///     鏈哄櫒鍚嶇О
+    /// </summary>
+    public string? MachineName { get; set; }
+
+    /// <summary>
+    ///     鐢熶骇绾垮悕绉�
+    /// </summary>
+    public string? LineDisplayName { get; set; }
+
+    /// <summary>
+    ///     鍋忎綅鏁伴噺
+    /// </summary>
+    public int OffsetCount { get; set; }
+
+    /// <summary>
+    ///     缂轰欢鏁伴噺
+    /// </summary>
+    public int MissingCount { get; set; }
+
+    /// <summary>
+    ///     鍙嶅悜鏁伴噺
+    /// </summary>
+    public int ReverseCount { get; set; }
+
+    /// <summary>
+    ///     缈樿捣鏁伴噺
+    /// </summary>
+    public int LiftedCount { get; set; }
+
+    /// <summary>
+    ///     娴珮鏁伴噺
+    /// </summary>
+    public int FloatHighCount { get; set; }
+
+    /// <summary>
+    ///     绔嬬鏁伴噺
+    /// </summary>
+    public int TombstoneCount { get; set; }
+
+    /// <summary>
+    ///     缈昏浆鏁伴噺
+    /// </summary>
+    public int FlipCount { get; set; }
+
+    /// <summary>
+    ///     閿欎欢鏁伴噺
+    /// </summary>
+    public int WrongPartCount { get; set; }
+
+    /// <summary>
+    ///     缈樿剼鏁伴噺
+    /// </summary>
+    public int LeadLiftCount { get; set; }
+
+    /// <summary>
+    ///     铏氱剨鏁伴噺
+    /// </summary>
+    public int ColdJointCount { get; set; }
+
+    /// <summary>
+    ///     绌虹剨鏁伴噺
+    /// </summary>
+    public int NoSolderCount { get; set; }
+
+    /// <summary>
+    ///     灏戦敗鏁伴噺
+    /// </summary>
+    public int InsufficientSolderCount { get; set; }
+
+    /// <summary>
+    ///     澶氶敗鏁伴噺
+    /// </summary>
+    public int ExcessSolderCount { get; set; }
+
+    /// <summary>
+    ///     杩為敗鏁伴噺
+    /// </summary>
+    public int BridgeCount { get; set; }
+
+    /// <summary>
+    ///     婕忛摐鏁伴噺
+    /// </summary>
+    public int CopperExposureCount { get; set; }
+
+    /// <summary>
+    ///     鎷夊皷鏁伴噺
+    /// </summary>
+    public int SpikeCount { get; set; }
+
+    /// <summary>
+    ///     寮傜墿鏁伴噺
+    /// </summary>
+    public int ForeignMatterCount { get; set; }
+
+    /// <summary>
+    ///     婧㈣兌鏁伴噺
+    /// </summary>
+    public int GlueOverflowCount { get; set; }
+
+    /// <summary>
+    ///     寮曡剼鍋忎綅鏁伴噺
+    /// </summary>
+    public int PinOffsetCount { get; set; }
+
+    /// <summary>
+    ///     鎶曞叆鏉挎暟
+    /// </summary>
+    public int InputBoards { get; set; }
+
+    /// <summary>
+    ///     OK鏉挎暟
+    /// </summary>
+    public int OkBoards { get; set; }
+
+    /// <summary>
+    ///     閫氳繃鏉挎暟
+    /// </summary>
+    public int PassBoards { get; set; }
+
+    /// <summary>
+    ///     鍚堟牸鐜�(%)
+    /// </summary>
+    public decimal? PassRate { get; set; }
+
+    /// <summary>
+    ///     涓嶈壇鏉挎暟
+    /// </summary>
+    public int DefectBoards { get; set; }
+
+    /// <summary>
+    ///     涓嶈壇鐜�(%)
+    /// </summary>
+    public decimal? DefectRate { get; set; }
+
+    /// <summary>
+    ///     涓嶈壇鐜�(PPM)
+    /// </summary>
+    public int? DefectPpm { get; set; }
+
+    /// <summary>
+    ///     涓嶈壇鐐规暟
+    /// </summary>
+    public int DefectPoints { get; set; }
+
+    /// <summary>
+    ///     瀹炴祴鐐规暟
+    /// </summary>
+    public int MeasuredPoints { get; set; }
+
+    /// <summary>
+    ///     寰呮祴鐐规暟
+    /// </summary>
+    public int PendingPoints { get; set; }
+}
+
+/// <summary>
+///     SPI/AOI涓婁紶鍝嶅簲DTO
+/// </summary>
+public class SpiAoiUploadResponse
+{
+    /// <summary>
+    ///     涓昏〃ID
+    /// </summary>
+    public decimal HeaderId { get; set; }
+
+    /// <summary>
+    ///     鎻掑叆鐨勫瓙琛ㄨ褰曟暟
+    /// </summary>
+    public int DetailCount { get; set; }
+}
diff --git a/MES.Service/Modes/MesSpiAoiDetail.cs b/MES.Service/Modes/MesSpiAoiDetail.cs
new file mode 100644
index 0000000..a492e4e
--- /dev/null
+++ b/MES.Service/Modes/MesSpiAoiDetail.cs
@@ -0,0 +1,220 @@
+using SqlSugar;
+
+namespace MES.Service.Modes;
+
+/// <summary>
+/// SPI/AOI 妫�娴嬫槑缁嗗疄浣擄紝璁板綍缂洪櫡鍒嗙被缁熻鍙婁骇绾挎晥鐜囨寚鏍囥��
+/// </summary>
+[SugarTable("MES_SPI_AOI_DETAIL")]
+public class MesSpiAoiDetail
+{
+    /// <summary>
+    /// 涓婚敭ID锛岀敱 Oracle 搴忓垪 SEQ_SPI_AOI_DETAIL 鐢熸垚銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "ID", IsPrimaryKey = true, OracleSequenceName = "SEQ_SPI_AOI_DETAIL")]
+    public decimal Id { get; set; }
+
+    /// <summary>
+    /// 涓昏〃 ID锛堝閿級锛屽叧鑱� <see cref="MesSpiAoiHeader" />銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "HEADER_ID")]
+    public decimal HeaderId { get; set; }
+
+    /// <summary>
+    /// 鍋忎綅鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "OFFSET_COUNT")]
+    public int OffsetCount { get; set; }
+
+    /// <summary>
+    /// 缂轰欢鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "MISSING_COUNT")]
+    public int MissingCount { get; set; }
+
+    /// <summary>
+    /// 鍙嶅悜瀹夎鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "REVERSE_COUNT")]
+    public int ReverseCount { get; set; }
+
+    /// <summary>
+    /// 缈樿捣鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "LIFTED_COUNT")]
+    public int LiftedCount { get; set; }
+
+    /// <summary>
+    /// 娴珮鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "FLOAT_HIGH_COUNT")]
+    public int FloatHighCount { get; set; }
+
+    /// <summary>
+    /// 绔嬬鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "TOMBSTONE_COUNT")]
+    public int TombstoneCount { get; set; }
+
+    /// <summary>
+    /// 缈昏浆鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "FLIP_COUNT")]
+    public int FlipCount { get; set; }
+
+    /// <summary>
+    /// 閿欎欢鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "WRONG_PART_COUNT")]
+    public int WrongPartCount { get; set; }
+
+    /// <summary>
+    /// 缈樿剼鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "LEAD_LIFT_COUNT")]
+    public int LeadLiftCount { get; set; }
+
+    /// <summary>
+    /// 铏氱剨鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "COLD_JOINT_COUNT")]
+    public int ColdJointCount { get; set; }
+
+    /// <summary>
+    /// 绌虹剨鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "NO_SOLDER_COUNT")]
+    public int NoSolderCount { get; set; }
+
+    /// <summary>
+    /// 灏戦敗鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "INSUFFICIENT_SOLDER_COUNT")]
+    public int InsufficientSolderCount { get; set; }
+
+    /// <summary>
+    /// 澶氶敗鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "EXCESS_SOLDER_COUNT")]
+    public int ExcessSolderCount { get; set; }
+
+    /// <summary>
+    /// 杩為敗鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "BRIDGE_COUNT")]
+    public int BridgeCount { get; set; }
+
+    /// <summary>
+    /// 婕忛摐鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "COPPER_EXPOSURE_COUNT")]
+    public int CopperExposureCount { get; set; }
+
+    /// <summary>
+    /// 鎷夊皷鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "SPIKE_COUNT")]
+    public int SpikeCount { get; set; }
+
+    /// <summary>
+    /// 寮傜墿娈嬬暀鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "FOREIGN_MATTER_COUNT")]
+    public int ForeignMatterCount { get; set; }
+
+    /// <summary>
+    /// 婧㈣兌鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "GLUE_OVERFLOW_COUNT")]
+    public int GlueOverflowCount { get; set; }
+
+    /// <summary>
+    /// 寮曡剼鍋忎綅鏁伴噺銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "PIN_OFFSET_COUNT")]
+    public int PinOffsetCount { get; set; }
+
+    /// <summary>
+    /// 浜х嚎鏄剧ず鍚嶇О銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "LINE_DISPLAY_NAME")]
+    public string? LineDisplayName { get; set; }
+
+    /// <summary>
+    /// 妫�娴嬫満鍙板悕绉般��
+    /// </summary>
+    [SugarColumn(ColumnName = "MACHINE_NAME")]
+    public string? MachineName { get; set; }
+
+    /// <summary>
+    /// 鎶曞叆鏉挎暟閲忋��
+    /// </summary>
+    [SugarColumn(ColumnName = "INPUT_BOARDS")]
+    public int InputBoards { get; set; }
+
+    /// <summary>
+    /// OK 鏉挎暟閲忋��
+    /// </summary>
+    [SugarColumn(ColumnName = "OK_BOARDS")]
+    public int OkBoards { get; set; }
+
+    /// <summary>
+    /// 閫氳繃鏉挎暟閲忋��
+    /// </summary>
+    [SugarColumn(ColumnName = "PASS_BOARDS")]
+    public int PassBoards { get; set; }
+
+    /// <summary>
+    /// 鍚堟牸鐜囷紙鍗曚綅锛�%锛夈��
+    /// </summary>
+    [SugarColumn(ColumnName = "PASS_RATE")]
+    public decimal? PassRate { get; set; }
+
+    /// <summary>
+    /// 涓嶈壇鏉挎暟閲忋��
+    /// </summary>
+    [SugarColumn(ColumnName = "DEFECT_BOARDS")]
+    public int DefectBoards { get; set; }
+
+    /// <summary>
+    /// 涓嶈壇鐜囷紙鍗曚綅锛�%锛夈��
+    /// </summary>
+    [SugarColumn(ColumnName = "DEFECT_RATE")]
+    public decimal? DefectRate { get; set; }
+
+    /// <summary>
+    /// 涓嶈壇鏁帮紙鍗曚綅锛歅PM锛夈��
+    /// </summary>
+    [SugarColumn(ColumnName = "DEFECT_PPM")]
+    public int? DefectPpm { get; set; }
+
+    /// <summary>
+    /// 涓嶈壇鐐规暟銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "DEFECT_POINTS")]
+    public int DefectPoints { get; set; }
+
+    /// <summary>
+    /// 瀹炴祴鐐规暟銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "MEASURED_POINTS")]
+    public int MeasuredPoints { get; set; }
+
+    /// <summary>
+    /// 寰呮祴鐐规暟銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "PENDING_POINTS")]
+    public int PendingPoints { get; set; }
+
+    /// <summary>
+    /// 鍒涘缓鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴炽��
+    /// </summary>
+    [SugarColumn(ColumnName = "CREATED_AT")]
+    public DateTime CreatedAt { get; set; }
+
+    /// <summary>
+    /// 鏇存柊鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴炽��
+    /// </summary>
+    [SugarColumn(ColumnName = "UPDATED_AT")]
+    public DateTime UpdatedAt { get; set; }
+}
diff --git a/MES.Service/Modes/MesSpiAoiHeader.cs b/MES.Service/Modes/MesSpiAoiHeader.cs
new file mode 100644
index 0000000..3b00ce9
--- /dev/null
+++ b/MES.Service/Modes/MesSpiAoiHeader.cs
@@ -0,0 +1,100 @@
+using SqlSugar;
+
+namespace MES.Service.Modes;
+
+/// <summary>
+/// SPI/AOI 妫�娴嬩富琛ㄥ疄浣擄紝鐢ㄤ簬淇濆瓨鍗曞潡 PCB 鐨勬壒娆℃娴嬫瑙堟暟鎹��
+/// </summary>
+[SugarTable("MES_SPI_AOI_HEADER")]
+public class MesSpiAoiHeader
+{
+    /// <summary>
+    /// 涓婚敭ID锛岀敱 Oracle 搴忓垪 SEQ_SPI_AOI_HEADER 鐢熸垚銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "ID", IsPrimaryKey = true, OracleSequenceName = "SEQ_SPI_AOI_HEADER")]
+    public decimal Id { get; set; }
+
+    /// <summary>
+    /// 娴嬭瘯鏃ユ湡锛堣澶囦笂浼犵殑骞存湀鏃ワ級銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "TEST_DATE")]
+    public DateTime TestDate { get; set; }
+
+    /// <summary>
+    /// 娴嬭瘯鏃堕棿锛圚H:mm:ss 鏍煎紡锛屼繚鎸佸師濮嬪�硷級銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "TEST_TIME")]
+    public string TestTime { get; set; } = string.Empty;
+
+    /// <summary>
+    /// 娴嬭瘯缁撴灉鍘熷瀛楃涓诧紝渚嬪 0:0:1;0銆�0;0;0:1銆丗ail銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "TEST_RESULT")]
+    public string TestResult { get; set; } = string.Empty;
+
+    /// <summary>
+    /// 妫�娴嬮潰锛圱 = Top 椤堕潰锛孊 = Bottom 搴曢潰锛夈��
+    /// </summary>
+    [SugarColumn(ColumnName = "SURFACE")]
+    public string Surface { get; set; } = string.Empty;
+
+    /// <summary>
+    /// 璁″垝妫�娴嬬偣鏁般��
+    /// </summary>
+    [SugarColumn(ColumnName = "TOTAL_POINTS")]
+    public int? TotalPoints { get; set; }
+
+    /// <summary>
+    /// 瀹為檯涓嶈壇鐐规暟銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "ACTUAL_DEFECTS")]
+    public int? ActualDefects { get; set; }
+
+    /// <summary>
+    /// 璁惧鍨嬪彿銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "EQUIPMENT_MODEL")]
+    public string? EquipmentModel { get; set; }
+
+    /// <summary>
+    /// 瀵瑰簲鐢熶骇宸ュ崟鎴栨壒娆″彿銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "WORK_ORDER")]
+    public string? WorkOrder { get; set; }
+
+    /// <summary>
+    /// 鏈虹鍚嶇О銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "PRODUCT_MODEL")]
+    public string? ProductModel { get; set; }
+
+    /// <summary>
+    /// 鏉夸欢鏉$爜锛堝敮涓�绾︽潫锛夈��
+    /// </summary>
+    [SugarColumn(ColumnName = "BOARD_BARCODE")]
+    public string BoardBarcode { get; set; } = string.Empty;
+
+    /// <summary>
+    /// SMT 缁勫埆銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "SMT_GROUP")]
+    public string? SmtGroup { get; set; }
+
+    /// <summary>
+    /// 绾垮埆鍚嶇О銆�
+    /// </summary>
+    [SugarColumn(ColumnName = "LINE_NAME")]
+    public string? LineName { get; set; }
+
+    /// <summary>
+    /// 鍒涘缓鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴炽��
+    /// </summary>
+    [SugarColumn(ColumnName = "CREATED_AT")]
+    public DateTime CreatedAt { get; set; }
+
+    /// <summary>
+    /// 鏇存柊鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴炽��
+    /// </summary>
+    [SugarColumn(ColumnName = "UPDATED_AT")]
+    public DateTime UpdatedAt { get; set; }
+}
diff --git a/MES.Service/bin/Debug/net8.0/MES.Service.dll b/MES.Service/bin/Debug/net8.0/MES.Service.dll
index ace4808..54d04c6 100644
--- a/MES.Service/bin/Debug/net8.0/MES.Service.dll
+++ b/MES.Service/bin/Debug/net8.0/MES.Service.dll
Binary files differ
diff --git a/MES.Service/bin/Debug/net8.0/MES.Service.pdb b/MES.Service/bin/Debug/net8.0/MES.Service.pdb
index 1ebf67e..1c43e59 100644
--- a/MES.Service/bin/Debug/net8.0/MES.Service.pdb
+++ b/MES.Service/bin/Debug/net8.0/MES.Service.pdb
Binary files differ
diff --git a/MES.Service/service/QC/SPIAOI.txt b/MES.Service/service/QC/SPIAOI.txt
new file mode 100644
index 0000000..4513b32
--- /dev/null
+++ b/MES.Service/service/QC/SPIAOI.txt
@@ -0,0 +1,428 @@
+锘夸富琛ㄥ瓧娈�
+娴嬭瘯鏃堕棿(骞淬�佹湀銆佹棩),娴嬭瘯鏃堕棿(鏃躲�佸垎銆佺),娴嬭瘯缁撴灉(鍥哄畾涓轰笁绉�:0:0:1;0:娴嬭瘯涓篛K,0;0;0:1:娴嬭瘯涓篎ail,T闈�(鍒員op(涓�)闈�/Bottom(涓�)闈�),娴嬭瘯鐐规暟,瀹為檯涓嶈壇,璁惧鍨嬪彿,鎵规宸ュ崟,鏈虹鍚�,鏉$爜,SMT缁勫埆,绾垮埆
+
+瀛愯〃瀛楁
+鍋忎綅,缂轰欢,鍙嶅悜,缈樿捣,娴珮,绔嬬,缈昏浆,閿欎欢,缈樿剼,铏氱剨,绌虹剨,灏戦敗,澶氶敗,杩為敗,婕忛摐,鎷夊皷,寮傜墿,婧㈣兌,寮曡剼鍋忎綅,鐢熶骇绾垮悕绉�,鏈哄櫒鍚嶇О,鎶曞叆鏉挎暟,OK鏉挎暟,閫氳繃鏉挎暟,鍚堟牸鐜�,涓嶈壇鏉挎暟,涓嶈壇鐜�,涓嶈壇鐜�(PPM),涓嶈壇鐐规暟,瀹炴祴鐐规暟,寰呮祴鐐规暟
+
+鎵ц鐩爣
+- 灏� `MES.Service/service/QC/SPIAOI.txt`:1-7 涓殑 SPI/AOI 妫�娴嬪瓧娈佃浆鍖栦负涓�涓彲璋冪敤鐨� REST API锛屽苟琛ュ厖鏁版嵁搴撳缓琛ㄤ笌鎸佷箙鍖栭�昏緫銆�
+- 鐩爣瑕嗙洊璇锋眰濂戠害銆佹暟鎹牎楠屻�佷富浠庤〃寤烘ā銆佸瓨鍌ㄨ繃绋�/鏈嶅姟淇濆瓨娴佺▼浠ュ強寮傚父涓庢棩蹇楀鐞嗐��
+
+鏁版嵁缁撴瀯鎷嗚В
+- `涓昏〃瀛楁` 鈫� 璁板綍鍗曟 SPI/AOI 妫�娴嬬殑澶翠俊鎭�傚缓璁瓧娈�/绫诲瀷锛�
+  娴嬭瘯鏃ユ湡(`TestDate`/DATE)銆佹祴璇曟椂闂�(`TestTime`/VARCHAR2(8 CHAR))銆佹祴璇曠粨鏋�(`TestResult`/VARCHAR2(12 CHAR)锛屽�煎煙锛歚0:0:1;0`銆乣0;0;0:1`銆乣Fail`)銆侀潰鍒�(`Surface`/CHAR(1)锛屽�煎煙 `T`/`B`)銆佹祴璇曠偣鏁�(`TotalPoints`/NUMBER(6))銆佸疄闄呬笉鑹偣鏁�(`ActualDefects`/NUMBER(6))銆佽澶囧瀷鍙�(`EquipmentModel`/VARCHAR2(64 CHAR))銆佹壒娆″伐鍗�(`WorkOrder`/VARCHAR2(64 CHAR))銆佹満绉嶅悕(`ProductModel`/VARCHAR2(64 CHAR))銆佹潯鐮�(`BoardBarcode`/VARCHAR2(128 CHAR))銆丼MT 缁勫埆(`SmtGroup`/VARCHAR2(32 CHAR))銆佺嚎鍒�(`LineName`/VARCHAR2(32 CHAR))銆�
+- `瀛愯〃瀛楁` 鈫� 璁板綍鍗曟妫�娴嬬殑缂洪櫡缁熻銆傚缓璁瓧娈�/绫诲瀷锛�
+  鍋忎綅(`OffsetCount`/NUMBER(6))銆佺己浠�(`MissingCount`/NUMBER(6))銆佸弽鍚�(`ReverseCount`/NUMBER(6))銆佺繕璧�(`LiftedCount`/NUMBER(6))銆佹诞楂�(`FloatHighCount`/NUMBER(6))銆佺珛纰�(`TombstoneCount`/NUMBER(6))銆佺炕杞�(`FlipCount`/NUMBER(6))銆侀敊浠�(`WrongPartCount`/NUMBER(6))銆佺繕鑴�(`LeadLiftCount`/NUMBER(6))銆佽櫄鐒�(`ColdJointCount`/NUMBER(6))銆佺┖鐒�(`NoSolderCount`/NUMBER(6))銆佸皯閿�(`InsufficientSolderCount`/NUMBER(6))銆佸閿�(`ExcessSolderCount`/NUMBER(6))銆佽繛閿�(`BridgeCount`/NUMBER(6))銆佹紡閾�(`CopperExposureCount`/NUMBER(6))銆佹媺灏�(`SpikeCount`/NUMBER(6))銆佸紓鐗�(`ForeignMatterCount`/NUMBER(6))銆佹孩鑳�(`GlueOverflowCount`/NUMBER(6))銆佸紩鑴氬亸浣�(`PinOffsetCount`/NUMBER(6))銆佺敓浜х嚎鍚嶇О(`LineDisplayName`/VARCHAR2(64 CHAR))銆佹満鍣ㄥ悕绉�(`MachineName`/VARCHAR2(64 CHAR))銆佹姇鍏ユ澘鏁�(`InputBoards`/NUMBER(6))銆丱K鏉挎暟(`OkBoards`/NUMBER(6))銆侀�氳繃鏉挎暟(`PassBoards`/NUMBER(6))銆佸悎鏍肩巼(`PassRate`/NUMBER(5,2))銆佷笉鑹澘鏁�(`DefectBoards`/NUMBER(6))銆佷笉鑹巼(`DefectRate`/NUMBER(5,2))銆佷笉鑹巼PPM(`DefectPpm`/NUMBER(9))銆佷笉鑹偣鏁�(`DefectPoints`/NUMBER(6))銆佸疄娴嬬偣鏁�(`MeasuredPoints`/NUMBER(6))銆佸緟娴嬬偣鏁�(`PendingPoints`/NUMBER(6))銆傛墍鏈夆�滅巼鈥濆瓧娈典互鐧惧垎姣斿瓨鍌紝鍏ュ簱鍓嶈浆涓烘暟鍊煎瀷銆�
+
+鏁版嵁搴撹璁�
+- 鐩爣搴撲负 Oracle 11g锛�11.2锛夛紝鏈」鐩娇鐢� `SqlSugar` 骞堕�氳繃 `[SugarColumn(OracleSequenceName = "...")]` 鑷姩鍙栧彿锛屽洜姝ゅ彧闇�澹版槑涓婚敭鍜屽簭鍒楋紝鏃犻渶瑙﹀彂鍣ㄣ�傜ず渚� DDL锛�
+```
+-- 涓昏〃锛氳褰曟瘡鍧楃數璺澘鐨� SPI/AOI 鎵规妫�娴嬫憳瑕佹暟鎹�
+-- SPI/AOI 涓昏〃锛岃褰曞崟鏉挎壒娆℃娴嬫憳瑕�
+CREATE TABLE MES_SPI_AOI_HEADER (
+    ID               NUMBER(19) NOT NULL,
+    TEST_DATE        DATE        NOT NULL,
+    TEST_TIME        VARCHAR2(8 CHAR) NOT NULL,
+    TEST_RESULT      VARCHAR2(12 CHAR) NOT NULL,
+    SURFACE          CHAR(1)     NOT NULL CHECK (SURFACE IN ('T','B')),
+    TOTAL_POINTS     NUMBER(6),
+    ACTUAL_DEFECTS   NUMBER(6),
+    EQUIPMENT_MODEL  VARCHAR2(64 CHAR),
+    WORK_ORDER       VARCHAR2(64 CHAR),
+    PRODUCT_MODEL    VARCHAR2(64 CHAR),
+    BOARD_BARCODE    VARCHAR2(128 CHAR) NOT NULL,
+    SMT_GROUP        VARCHAR2(32 CHAR),
+    LINE_NAME        VARCHAR2(32 CHAR),
+    CREATED_AT       TIMESTAMP   DEFAULT SYSTIMESTAMP,
+    UPDATED_AT       TIMESTAMP   DEFAULT SYSTIMESTAMP
+);
+ALTER TABLE MES_SPI_AOI_HEADER
+  ADD CONSTRAINT PK_SPI_AOI_HEADER PRIMARY KEY (ID);
+CREATE UNIQUE INDEX IDX_SPI_AOI_BARCODE ON MES_SPI_AOI_HEADER (BOARD_BARCODE);
+
+COMMENT ON TABLE MES_SPI_AOI_HEADER IS 'SPI/AOI 涓昏〃锛岃褰曞崟鏉挎娴嬫憳瑕佹暟鎹�';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.ID IS '涓婚敭ID锛岀敱搴忓垪 SEQ_SPI_AOI_HEADER 鐢熸垚';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.TEST_DATE IS '娴嬭瘯鏃ユ湡锛屾部鐢ㄨ澶囦笂浼犵殑骞存湀鏃�';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.TEST_TIME IS '娴嬭瘯鏃堕棿锛屾部鐢ㄨ澶囦笂浼犵殑 HH:mm:ss';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.TEST_RESULT IS '娴嬭瘯缁撴灉鍘熷瀛楃涓诧紝渚嬪 0:0:1;0銆�0;0;0:1銆丗ail';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.SURFACE IS '妫�娴嬮潰锛孴=Top 椤堕潰锛孊=Bottom 搴曢潰';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.TOTAL_POINTS IS '璁″垝妫�娴嬬偣鏁�';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.ACTUAL_DEFECTS IS '瀹為檯涓嶈壇鐐规暟';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.EQUIPMENT_MODEL IS '璁惧鍨嬪彿';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.WORK_ORDER IS '瀵瑰簲宸ュ崟鎴栨壒娆″彿';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.PRODUCT_MODEL IS '鏈虹鍚嶇О';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.BOARD_BARCODE IS '鏉夸欢鏉$爜锛屾暣鍗曞敮涓�';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.SMT_GROUP IS 'SMT 缁勫埆';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.LINE_NAME IS '绾垮埆鍚嶇О';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.CREATED_AT IS '鍒涘缓鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴�';
+COMMENT ON COLUMN MES_SPI_AOI_HEADER.UPDATED_AT IS '鏇存柊鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴�';
+
+CREATE SEQUENCE SEQ_SPI_AOI_HEADER START WITH 1 INCREMENT BY 1 NOCACHE;
+
+-- SPI/AOI 鏄庣粏琛紝鎷嗗垎缂洪櫡缁熻涓庝骇鑳芥寚鏍�
+CREATE TABLE MES_SPI_AOI_DETAIL (
+    ID                       NUMBER(19) NOT NULL,
+    HEADER_ID                NUMBER(19) NOT NULL,
+    OFFSET_COUNT             NUMBER(6) DEFAULT 0,
+    MISSING_COUNT            NUMBER(6) DEFAULT 0,
+    REVERSE_COUNT            NUMBER(6) DEFAULT 0,
+    LIFTED_COUNT             NUMBER(6) DEFAULT 0,
+    FLOAT_HIGH_COUNT         NUMBER(6) DEFAULT 0,
+    TOMBSTONE_COUNT          NUMBER(6) DEFAULT 0,
+    FLIP_COUNT               NUMBER(6) DEFAULT 0,
+    WRONG_PART_COUNT         NUMBER(6) DEFAULT 0,
+    LEAD_LIFT_COUNT          NUMBER(6) DEFAULT 0,
+    COLD_JOINT_COUNT         NUMBER(6) DEFAULT 0,
+    NO_SOLDER_COUNT          NUMBER(6) DEFAULT 0,
+    INSUFFICIENT_SOLDER_COUNT NUMBER(6) DEFAULT 0,
+    EXCESS_SOLDER_COUNT      NUMBER(6) DEFAULT 0,
+    BRIDGE_COUNT             NUMBER(6) DEFAULT 0,
+    COPPER_EXPOSURE_COUNT    NUMBER(6) DEFAULT 0,
+    SPIKE_COUNT              NUMBER(6) DEFAULT 0,
+    FOREIGN_MATTER_COUNT     NUMBER(6) DEFAULT 0,
+    GLUE_OVERFLOW_COUNT      NUMBER(6) DEFAULT 0,
+    PIN_OFFSET_COUNT         NUMBER(6) DEFAULT 0,
+    LINE_DISPLAY_NAME        VARCHAR2(64 CHAR),
+    MACHINE_NAME             VARCHAR2(64 CHAR),
+    INPUT_BOARDS             NUMBER(6) DEFAULT 0,
+    OK_BOARDS                NUMBER(6) DEFAULT 0,
+    PASS_BOARDS              NUMBER(6) DEFAULT 0,
+    PASS_RATE                NUMBER(5,2),
+    DEFECT_BOARDS            NUMBER(6) DEFAULT 0,
+    DEFECT_RATE              NUMBER(5,2),
+    DEFECT_PPM               NUMBER(9),
+    DEFECT_POINTS            NUMBER(6) DEFAULT 0,
+    MEASURED_POINTS          NUMBER(6) DEFAULT 0,
+    PENDING_POINTS           NUMBER(6) DEFAULT 0,
+    CREATED_AT               TIMESTAMP DEFAULT SYSTIMESTAMP,
+    UPDATED_AT               TIMESTAMP DEFAULT SYSTIMESTAMP
+);
+ALTER TABLE MES_SPI_AOI_DETAIL
+  ADD CONSTRAINT PK_SPI_AOI_DETAIL PRIMARY KEY (ID);
+ALTER TABLE MES_SPI_AOI_DETAIL
+  ADD CONSTRAINT FK_SPI_AOI_DETAIL_HEADER FOREIGN KEY (HEADER_ID)
+  REFERENCES MES_SPI_AOI_HEADER(ID);
+
+CREATE INDEX IDX_SPI_AOI_DETAIL_HEADER ON MES_SPI_AOI_DETAIL (HEADER_ID);
+
+COMMENT ON TABLE MES_SPI_AOI_DETAIL IS 'SPI/AOI 鏄庣粏琛紝璁板綍缂洪櫡鍒嗙被缁熻涓庝骇绾挎晥鐜囨暟鎹�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.ID IS '涓婚敭ID锛岀敱搴忓垪 SEQ_SPI_AOI_DETAIL 鐢熸垚';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.HEADER_ID IS '涓昏〃澶栭敭锛屾寚鍚� MES_SPI_AOI_HEADER.ID';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.OFFSET_COUNT IS '鍋忎綅鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.MISSING_COUNT IS '缂轰欢鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.REVERSE_COUNT IS '鍙嶅悜瀹夎鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.LIFTED_COUNT IS '缈樿捣鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.FLOAT_HIGH_COUNT IS '娴珮鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.TOMBSTONE_COUNT IS '绔嬬鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.FLIP_COUNT IS '缈昏浆鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.WRONG_PART_COUNT IS '閿欎欢鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.LEAD_LIFT_COUNT IS '缈樿剼鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.COLD_JOINT_COUNT IS '铏氱剨鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.NO_SOLDER_COUNT IS '绌虹剨鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.INSUFFICIENT_SOLDER_COUNT IS '灏戦敗鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.EXCESS_SOLDER_COUNT IS '澶氶敗鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.BRIDGE_COUNT IS '杩為敗鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.COPPER_EXPOSURE_COUNT IS '婕忛摐鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.SPIKE_COUNT IS '鎷夊皷鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.FOREIGN_MATTER_COUNT IS '寮傜墿娈嬬暀鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.GLUE_OVERFLOW_COUNT IS '婧㈣兌鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.PIN_OFFSET_COUNT IS '寮曡剼鍋忎綅鏁伴噺';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.LINE_DISPLAY_NAME IS '浜х嚎鏄剧ず鍚嶇О';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.MACHINE_NAME IS '妫�娴嬫満鍙板悕绉�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.INPUT_BOARDS IS '鎶曞叆鏉挎暟閲�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.OK_BOARDS IS 'OK 鏉挎暟閲�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.PASS_BOARDS IS '閫氳繃鏉挎暟閲�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.PASS_RATE IS '鍚堟牸鐜囷紙%锛�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.DEFECT_BOARDS IS '涓嶈壇鏉挎暟閲�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.DEFECT_RATE IS '涓嶈壇鐜囷紙%锛�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.DEFECT_PPM IS '涓嶈壇鏁帮紙PPM锛�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.DEFECT_POINTS IS '涓嶈壇鐐规暟';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.MEASURED_POINTS IS '瀹炴祴鐐规暟';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.PENDING_POINTS IS '寰呮祴鐐规暟';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.CREATED_AT IS '鍒涘缓鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴�';
+COMMENT ON COLUMN MES_SPI_AOI_DETAIL.UPDATED_AT IS '鏇存柊鏃堕棿锛岄粯璁ゅ啓鍏ユ暟鎹簱鏃堕棿鎴�';
+
+CREATE SEQUENCE SEQ_SPI_AOI_DETAIL START WITH 1 INCREMENT BY 1 NOCACHE;
+
+娴嬭瘯缁撴灉璇存槑
+- `TestResult` 瀛楁鐩存帴鎺ユ敹鍘熷瀛楃涓诧紝涓嶅仛鏋氫妇鏍¢獙
+- 甯歌鍊煎弬鑰冿細
+  - "0:0:1;0" (閫氬父琛ㄧず娴嬭瘯閫氳繃)
+  - "0;0;0:1" (閫氬父琛ㄧず娴嬭瘯澶辫触)
+  - "Fail" (閫氬父琛ㄧず娴嬭瘯寮傚父)
+- 鏁版嵁搴撳瓨鍌ㄥ師濮嬪�硷紝鐢变笟鍔″眰鏍规嵁闇�瑕佽В鏋�
+
+鎺ュ彛璁捐
+- URL锛歚POST /api/QC/SpiAoi/Upload`锛堜綅浜� `MESApplication.Controllers.QC` 鍛藉悕绌洪棿锛屾部鐢� `ResponseResult` 杩斿洖鏍煎紡锛夈��
+- 璇锋眰浣撶粨鏋勶細
+```
+{
+  "header": {
+    "testDate": "2025-10-10",
+    "testTime": "14:33:21",
+    "testResult": "0;0;0:1",
+    "surface": "T",
+    "totalPoints": 500,
+    "actualDefects": 3,
+    "equipmentModel": "SPI-9000",
+    "workOrder": "WO20251010-01",
+    "productModel": "MODEL-ABC",
+    "boardBarcode": "BC123456789",
+    "smtGroup": "A1",
+    "lineName": "SMT-01"
+  },
+  "details": [
+    {
+      "machineName": "AOI-01",
+      "lineDisplayName": "SMT-01",
+      "offsetCount": 1,
+      "missingCount": 0,
+      "reverseCount": 0,
+      "liftedCount": 0,
+      "floatHighCount": 0,
+      "tombstoneCount": 0,
+      "flipCount": 0,
+      "wrongPartCount": 0,
+      "leadLiftCount": 0,
+      "coldJointCount": 0,
+      "noSolderCount": 0,
+      "insufficientSolderCount": 1,
+      "excessSolderCount": 0,
+      "bridgeCount": 1,
+      "copperExposureCount": 0,
+      "spikeCount": 0,
+      "foreignMatterCount": 0,
+      "glueOverflowCount": 0,
+      "pinOffsetCount": 0,
+      "inputBoards": 120,
+      "okBoards": 117,
+      "passBoards": 117,
+      "passRate": 97.5,
+      "defectBoards": 3,
+      "defectRate": 2.5,
+      "defectPpm": 25000,
+      "defectPoints": 3,
+      "measuredPoints": 500,
+      "pendingPoints": 0
+    }
+  ]
+}
+```
+- 鍝嶅簲绀轰緥锛�
+```
+{
+  "status": 0,
+  "message": "OK",
+  "data": { "headerId": 12345 }
+}
+```
+
+涓氬姟澶勭悊娴佺▼
+- 鍏ュ彛鎺у埗鍣ㄨ礋璐fā鍨嬬粦瀹氫笌鍩烘湰鏍¢獙锛�
+  - 蹇呭~瀛楁锛歵estDate銆乼estTime銆乼estResult銆乥oardBarcode銆乻urface
+  - 鏋氫妇鍚堟硶鎬э細surface 蹇呴』涓� "T" 鎴� "B"
+  - testResult锛氫笉鍋氭灇涓炬牎楠岋紝鐩存帴鎺ユ敹鍘熷瀛楃涓�
+  - 鏁板�奸潪璐燂細鎵�鏈夎鏁板瓧娈靛繀椤� >= 0
+  - **details 涓嶈兘涓虹┖鎴� null**
+- 灏嗚姹傚鎵樼粰 `SpiAoiService`锛堜綅浜� `MES.Service.service.QC`锛夛紝璇ユ湇鍔′娇鐢� `SqlSugarClient` 鍚姩浜嬪姟锛�
+  1. **鏉$爜鍞竴鎬ф娴�**锛氳嫢 `BOARD_BARCODE` 宸插瓨鍦紝鐩存帴杩斿洖閿欒 `status=1, message="鏉$爜宸插瓨鍦紝涓嶅厑璁搁噸澶嶄笂浼�"`锛堜繚鎸佸敮涓�绱㈠紩绾︽潫锛夈��
+  2. 鎻掑叆澶磋〃璁板綍锛岃繑鍥� `HEADER_ID`锛堝疄浣撻�氳繃 `[SugarColumn(IsPrimaryKey = true, OracleSequenceName = "SEQ_SPI_AOI_HEADER")]` 鑷姩鑾峰彇搴忓垪鍊硷級銆�
+  3. 閬嶅巻 `details`锛屼负姣忔潯濉厖 `HEADER_ID` 骞舵彃鍏ュ瓙琛ㄣ��
+  4. **琛嶇敓瀛楁鏍¢獙**锛堣褰曟棩蹇椾絾涓嶉樆鏂級锛�
+     - `passBoards <= inputBoards`
+     - `defectBoards = inputBoards - passBoards`
+     - `passRate` 涓庤绠楀�� `(passBoards / inputBoards * 100)` 鐨勫亸宸湪 卤1.0 浠ュ唴
+     - 鑻ユ牎楠屽け璐ワ紝璁板綍璀﹀憡鏃ュ織浣嗕笉鍥炴粴浜嬪姟
+  5. 鎻愪氦浜嬪姟锛涘紓甯稿垯鍥炴粴骞惰褰曟棩蹇椼��
+- 鎴愬姛鍚庤繑鍥� `headerId`锛涘け璐ヨ繑鍥� `status=1` 涓庨敊璇俊鎭��
+
+楠岃瘉涓庨敊璇鐞�
+- **杈撳叆鏍¢獙澶辫触**锛氳繑鍥� `status=1`锛宍message` 鎸囨槑瀛楁鍙婂師鍥狅紙濡傦細"boardBarcode 涓嶈兘涓虹┖"銆�"surface 蹇呴』涓� T 鎴� B"锛夈��
+- **鏉$爜閲嶅**锛氳繑鍥� `status=1, message="鏉$爜 {boardBarcode} 宸插瓨鍦紝涓嶅厑璁搁噸澶嶄笂浼�"`銆�
+- **details 涓虹┖**锛氳繑鍥� `status=1, message="details 涓嶈兘涓虹┖"`銆�
+- **鏁版嵁搴撳紓甯�**锛氭崟鑾� `SqlSugar`/Oracle 寮傚父锛岃褰曞埌鐜版湁鏃ュ織锛堝 `LogUtil`锛夛紝鍚屾椂鍐欏叆娑堟伅涓績锛堣嫢闇� ERP 鍚屾锛夋垨鑷畾涔夐敊璇槦鍒椼��
+
+瀹炰綋瀹氫箟绀轰緥
+```csharp
+[SugarTable("MES_SPI_AOI_HEADER")]
+public class SpiAoiHeader
+{
+    [SugarColumn(ColumnName = "ID", IsPrimaryKey = true, OracleSequenceName = "SEQ_SPI_AOI_HEADER")]
+    public long Id { get; set; }
+
+    [SugarColumn(ColumnName = "TEST_DATE")]
+    public DateTime TestDate { get; set; }
+
+    [SugarColumn(ColumnName = "TEST_TIME")]
+    public string TestTime { get; set; }
+
+    [SugarColumn(ColumnName = "TEST_RESULT")]
+    public string TestResult { get; set; }
+
+    [SugarColumn(ColumnName = "SURFACE")]
+    public string Surface { get; set; }
+
+    [SugarColumn(ColumnName = "TOTAL_POINTS")]
+    public int? TotalPoints { get; set; }
+
+    [SugarColumn(ColumnName = "ACTUAL_DEFECTS")]
+    public int? ActualDefects { get; set; }
+
+    [SugarColumn(ColumnName = "EQUIPMENT_MODEL")]
+    public string EquipmentModel { get; set; }
+
+    [SugarColumn(ColumnName = "WORK_ORDER")]
+    public string WorkOrder { get; set; }
+
+    [SugarColumn(ColumnName = "PRODUCT_MODEL")]
+    public string ProductModel { get; set; }
+
+    [SugarColumn(ColumnName = "BOARD_BARCODE")]
+    public string BoardBarcode { get; set; }
+
+    [SugarColumn(ColumnName = "SMT_GROUP")]
+    public string SmtGroup { get; set; }
+
+    [SugarColumn(ColumnName = "LINE_NAME")]
+    public string LineName { get; set; }
+
+    [SugarColumn(ColumnName = "CREATED_AT")]
+    public DateTime CreatedAt { get; set; }
+
+    [SugarColumn(ColumnName = "UPDATED_AT")]
+    public DateTime UpdatedAt { get; set; }
+}
+
+[SugarTable("MES_SPI_AOI_DETAIL")]
+public class SpiAoiDetail
+{
+    [SugarColumn(ColumnName = "ID", IsPrimaryKey = true, OracleSequenceName = "SEQ_SPI_AOI_DETAIL")]
+    public long Id { get; set; }
+
+    [SugarColumn(ColumnName = "HEADER_ID")]
+    public long HeaderId { get; set; }
+
+    [SugarColumn(ColumnName = "OFFSET_COUNT")]
+    public int OffsetCount { get; set; }
+
+    [SugarColumn(ColumnName = "MISSING_COUNT")]
+    public int MissingCount { get; set; }
+
+    [SugarColumn(ColumnName = "REVERSE_COUNT")]
+    public int ReverseCount { get; set; }
+
+    [SugarColumn(ColumnName = "LIFTED_COUNT")]
+    public int LiftedCount { get; set; }
+
+    [SugarColumn(ColumnName = "FLOAT_HIGH_COUNT")]
+    public int FloatHighCount { get; set; }
+
+    [SugarColumn(ColumnName = "TOMBSTONE_COUNT")]
+    public int TombstoneCount { get; set; }
+
+    [SugarColumn(ColumnName = "FLIP_COUNT")]
+    public int FlipCount { get; set; }
+
+    [SugarColumn(ColumnName = "WRONG_PART_COUNT")]
+    public int WrongPartCount { get; set; }
+
+    [SugarColumn(ColumnName = "LEAD_LIFT_COUNT")]
+    public int LeadLiftCount { get; set; }
+
+    [SugarColumn(ColumnName = "COLD_JOINT_COUNT")]
+    public int ColdJointCount { get; set; }
+
+    [SugarColumn(ColumnName = "NO_SOLDER_COUNT")]
+    public int NoSolderCount { get; set; }
+
+    [SugarColumn(ColumnName = "INSUFFICIENT_SOLDER_COUNT")]
+    public int InsufficientSolderCount { get; set; }
+
+    [SugarColumn(ColumnName = "EXCESS_SOLDER_COUNT")]
+    public int ExcessSolderCount { get; set; }
+
+    [SugarColumn(ColumnName = "BRIDGE_COUNT")]
+    public int BridgeCount { get; set; }
+
+    [SugarColumn(ColumnName = "COPPER_EXPOSURE_COUNT")]
+    public int CopperExposureCount { get; set; }
+
+    [SugarColumn(ColumnName = "SPIKE_COUNT")]
+    public int SpikeCount { get; set; }
+
+    [SugarColumn(ColumnName = "FOREIGN_MATTER_COUNT")]
+    public int ForeignMatterCount { get; set; }
+
+    [SugarColumn(ColumnName = "GLUE_OVERFLOW_COUNT")]
+    public int GlueOverflowCount { get; set; }
+
+    [SugarColumn(ColumnName = "PIN_OFFSET_COUNT")]
+    public int PinOffsetCount { get; set; }
+
+    [SugarColumn(ColumnName = "LINE_DISPLAY_NAME")]
+    public string LineDisplayName { get; set; }
+
+    [SugarColumn(ColumnName = "MACHINE_NAME")]
+    public string MachineName { get; set; }
+
+    [SugarColumn(ColumnName = "INPUT_BOARDS")]
+    public int InputBoards { get; set; }
+
+    [SugarColumn(ColumnName = "OK_BOARDS")]
+    public int OkBoards { get; set; }
+
+    [SugarColumn(ColumnName = "PASS_BOARDS")]
+    public int PassBoards { get; set; }
+
+    [SugarColumn(ColumnName = "PASS_RATE")]
+    public decimal? PassRate { get; set; }
+
+    [SugarColumn(ColumnName = "DEFECT_BOARDS")]
+    public int DefectBoards { get; set; }
+
+    [SugarColumn(ColumnName = "DEFECT_RATE")]
+    public decimal? DefectRate { get; set; }
+
+    [SugarColumn(ColumnName = "DEFECT_PPM")]
+    public int? DefectPpm { get; set; }
+
+    [SugarColumn(ColumnName = "DEFECT_POINTS")]
+    public int DefectPoints { get; set; }
+
+    [SugarColumn(ColumnName = "MEASURED_POINTS")]
+    public int MeasuredPoints { get; set; }
+
+    [SugarColumn(ColumnName = "PENDING_POINTS")]
+    public int PendingPoints { get; set; }
+
+    [SugarColumn(ColumnName = "CREATED_AT")]
+    public DateTime CreatedAt { get; set; }
+
+    [SugarColumn(ColumnName = "UPDATED_AT")]
+    public DateTime UpdatedAt { get; set; }
+}
+```
+
+瀹炵幇姝ラ寤鸿
+1. **鍒涘缓鏁版嵁搴撹〃**锛氭墽琛屼笂杩� DDL锛屽垱寤� `MES_SPI_AOI_HEADER`銆乣MES_SPI_AOI_DETAIL` 琛ㄥ強搴忓垪銆�
+2. **瀹氫箟瀹炰綋妯″瀷**锛氬湪 `MES.Service.Modes` 涓嬪垱寤� `SpiAoiHeader.cs` 鍜� `SpiAoiDetail.cs`锛堝弬鑰冧笂杩板疄浣撳畾涔夌ず渚嬶級銆�
+3. **鍒涘缓 DTO**锛�
+   - `SpiAoiHeaderDto.cs`锛堢敤浜庤姹備綋 header 閮ㄥ垎锛�
+   - `SpiAoiDetailDto.cs`锛堢敤浜庤姹備綋 details 鏁扮粍鍏冪礌锛�
+   - `SpiAoiUploadRequest.cs`锛堝寘鍚� Header 鍜� Details 鍒楄〃锛�
+   - `SpiAoiUploadResponse.cs`锛堝寘鍚� headerId锛�
+4. **瀹炵幇鏈嶅姟灞�**锛�
+   - 鍦� `MES.Service.service.QC` 涓嬪垱寤� `SpiAoiService.cs`
+   - 瀹炵幇鏉$爜鍞竴鎬ф鏌ャ�佷簨鍔℃彃鍏ャ�佹暟鎹牎楠岀瓑涓氬姟閫昏緫
+5. **瀹炵幇鎺у埗鍣�**锛�
+   - 鍦� `MESApplication.Controllers.QC` 涓嬪垱寤� `SpiAoiController.cs`
+   - 娣诲姞 `[HttpPost("Upload")]` 鏂规硶锛岃皟鐢ㄦ湇鍔″眰骞惰繑鍥� `ResponseResult`
+6. **娣诲姞鍗曞厓娴嬭瘯**锛堝彲閫夛級锛氶獙璇佹垚鍔熸彃鍏ャ�侀潪娉曟灇涓俱�佹潯鐮侀噸澶嶃�乨etails 涓虹┖銆佷簨鍔″洖婊氱瓑鍦烘櫙銆�
+
+娉ㄦ剰浜嬮」
+- 鎵�鏈夊瓧绗︿覆瀛楁闇�妫�鏌ラ暱搴︽槸鍚﹁秴杩囨暟鎹簱瀹氫箟锛堝 `BOARD_BARCODE` 鏈�澶� 128 瀛楃锛夈��
+- `TestDate` 鍜� `TestTime` 鍒嗗紑瀛樺偍锛屽墠绔渶鍒嗗埆浼犲叆鏃ユ湡鍜屾椂闂村瓧绗︿覆銆�
+- `TestResult` 涓嶅仛鏋氫妇鏍¢獙锛屾帴鏀朵换鎰忓瓧绗︿覆鍊硷紙鏈�澶� 12 瀛楃锛夛紝鍘熸牱瀛樺偍鍒版暟鎹簱銆�
+- 瀵逛簬 `CREATED_AT` 鍜� `UPDATED_AT`锛屽缓璁湪浠g爜涓樉寮忚祴鍊� `DateTime.Now`锛岃�岄潪渚濊禆鏁版嵁搴撻粯璁ゅ�笺��
+- Oracle 11g 闇�纭繚 SqlSugar 鐗堟湰鍏煎锛堟帹鑽� 5.x 鎴栨洿楂樼増鏈級銆�
+- 鏉$爜鍞竴绱㈠紩 `IDX_SPI_AOI_BARCODE` 浼氳嚜鍔ㄩ樆姝㈤噸澶嶆彃鍏ワ紝浣嗗缓璁湪浠g爜涓彁鍓嶆鏌ュ苟杩斿洖鍙嬪ソ閿欒淇℃伅銆�
diff --git a/MES.Service/service/QC/SpiAoiService.cs b/MES.Service/service/QC/SpiAoiService.cs
new file mode 100644
index 0000000..7a2aad8
--- /dev/null
+++ b/MES.Service/service/QC/SpiAoiService.cs
@@ -0,0 +1,387 @@
+using MES.Service.DB;
+using MES.Service.Dto.service;
+using MES.Service.Modes;
+using MES.Service.util;
+
+namespace MES.Service.service.QC;
+
+/// <summary>
+///     SPI/AOI妫�娴嬫暟鎹湇鍔�
+/// </summary>
+public class SpiAoiService
+{
+    /// <summary>
+    ///     涓婁紶SPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="request">涓婁紶璇锋眰DTO</param>
+    /// <returns>涓婁紶鍝嶅簲DTO</returns>
+    public SpiAoiUploadResponse UploadSpiAoiData(SpiAoiUploadRequest request)
+    {
+        // 1. 鍩烘湰鏍¢獙
+        ValidateRequest(request);
+
+        try
+        {
+            SpiAoiUploadResponse response = null;
+
+            SqlSugarHelper.UseTransactionWithOracle(db =>
+            {
+                // 2. 妫�鏌ユ潯鐮佹槸鍚﹀凡瀛樺湪
+                var existingHeader = db.Queryable<MesSpiAoiHeader>()
+                    .Where(x => x.BoardBarcode == request.Header.BoardBarcode)
+                    .First();
+
+                if (existingHeader != null)
+                {
+                    throw new Exception($"鏉$爜 {request.Header.BoardBarcode} 宸插瓨鍦紝涓嶅厑璁搁噸澶嶄笂浼�");
+                }
+
+                // 3. 杞崲骞舵彃鍏ヤ富琛ㄦ暟鎹�
+                var header = ConvertHeaderDtoToEntity(request.Header);
+                header.CreatedAt = DateTime.Now;
+                header.UpdatedAt = DateTime.Now;
+
+                var headerId = db.Insertable(header).ExecuteReturnIdentity();
+
+                // 4. 杞崲骞舵彃鍏ュ瓙琛ㄦ暟鎹�
+                var detailCount = 0;
+                if (request.Details != null && request.Details.Count > 0)
+                {
+                    var details = ConvertDetailDtoListToEntity(request.Details, headerId);
+
+                    // 鏁版嵁鏍¢獙(璁板綍璀﹀憡浣嗕笉闃绘柇)
+                    ValidateDetailData(request.Details);
+
+                    detailCount = db.Insertable(details).ExecuteCommand();
+                }
+
+                response = new SpiAoiUploadResponse
+                {
+                    HeaderId = headerId,
+                    DetailCount = detailCount
+                };
+
+                return 1; // 杩斿洖鍙楀奖鍝嶇殑琛屾暟渚涗簨鍔″垽鏂�
+            });
+
+            if (response == null)
+            {
+                throw new Exception("涓婁紶澶辫触");
+            }
+
+            return response;
+        }
+        catch (Exception ex)
+        {
+            throw new Exception($"涓婁紶SPI/AOI妫�娴嬫暟鎹け璐�: {ex.Message}", ex);
+        }
+    }
+
+    /// <summary>
+    ///     鏍规嵁鏉$爜鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="boardBarcode">鏉$爜</param>
+    /// <returns>妫�娴嬫暟鎹�(涓昏〃+瀛愯〃)</returns>
+    public (MesSpiAoiHeader header, List<MesSpiAoiDetail> details) GetByBarcode(string boardBarcode)
+    {
+        try
+        {
+            var db = SqlSugarHelper.GetInstance();
+
+            var header = db.Queryable<MesSpiAoiHeader>()
+                .Where(x => x.BoardBarcode == boardBarcode)
+                .First();
+
+            if (header == null)
+            {
+                return (null, null);
+            }
+
+            var details = db.Queryable<MesSpiAoiDetail>()
+                .Where(x => x.HeaderId == header.Id)
+                .ToList();
+
+            return (header, details);
+        }
+        catch (Exception ex)
+        {
+            throw new Exception($"鏌ヨSPI/AOI妫�娴嬫暟鎹け璐�: {ex.Message}", ex);
+        }
+    }
+
+    /// <summary>
+    ///     鏍规嵁ID鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="headerId">涓昏〃ID</param>
+    /// <returns>妫�娴嬫暟鎹�(涓昏〃+瀛愯〃)</returns>
+    public (MesSpiAoiHeader header, List<MesSpiAoiDetail> details) GetById(decimal headerId)
+    {
+        try
+        {
+            var db = SqlSugarHelper.GetInstance();
+
+            var header = db.Queryable<MesSpiAoiHeader>()
+                .Where(x => x.Id == headerId)
+                .First();
+
+            if (header == null)
+            {
+                return (null, null);
+            }
+
+            var details = db.Queryable<MesSpiAoiDetail>()
+                .Where(x => x.HeaderId == headerId)
+                .ToList();
+
+            return (header, details);
+        }
+        catch (Exception ex)
+        {
+            throw new Exception($"鏌ヨSPI/AOI妫�娴嬫暟鎹け璐�: {ex.Message}", ex);
+        }
+    }
+
+    /// <summary>
+    ///     鍒嗛〉鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="boardBarcode">鏉$爜(鍙��)</param>
+    /// <param name="workOrder">宸ュ崟(鍙��)</param>
+    /// <param name="surface">鏉块潰(鍙��)</param>
+    /// <param name="startDate">寮�濮嬫棩鏈�(鍙��)</param>
+    /// <param name="endDate">缁撴潫鏃ユ湡(鍙��)</param>
+    /// <param name="pageIndex">椤电爜</param>
+    /// <param name="pageSize">椤靛ぇ灏�</param>
+    /// <returns>鍒嗛〉鏁版嵁</returns>
+    public (List<MesSpiAoiHeader> items, int totalCount) GetPage(
+        string boardBarcode = null,
+        string workOrder = null,
+        string surface = null,
+        DateTime? startDate = null,
+        DateTime? endDate = null,
+        int pageIndex = 1,
+        int pageSize = 20)
+    {
+        try
+        {
+            var db = SqlSugarHelper.GetInstance();
+            var totalCount = 0;
+
+            var data = db.Queryable<MesSpiAoiHeader>()
+                .WhereIF(StringUtil.IsNotNullOrEmpty(boardBarcode),
+                    x => x.BoardBarcode.Contains(boardBarcode))
+                .WhereIF(StringUtil.IsNotNullOrEmpty(workOrder),
+                    x => x.WorkOrder.Contains(workOrder))
+                .WhereIF(StringUtil.IsNotNullOrEmpty(surface),
+                    x => x.Surface == surface)
+                .WhereIF(startDate.HasValue,
+                    x => x.TestDate >= startDate.Value)
+                .WhereIF(endDate.HasValue,
+                    x => x.TestDate <= endDate.Value)
+                .OrderBy(x => x.CreatedAt, SqlSugar.OrderByType.Desc)
+                .ToPageList(pageIndex, pageSize, ref totalCount);
+
+            return (data, totalCount);
+        }
+        catch (Exception ex)
+        {
+            throw new Exception($"鍒嗛〉鏌ヨSPI/AOI妫�娴嬫暟鎹け璐�: {ex.Message}", ex);
+        }
+    }
+
+    #region 绉佹湁鏂规硶
+
+    /// <summary>
+    ///     鏍¢獙璇锋眰鍙傛暟
+    /// </summary>
+    /// <param name="request">璇锋眰DTO</param>
+    private void ValidateRequest(SpiAoiUploadRequest request)
+    {
+        if (request == null)
+        {
+            throw new Exception("璇锋眰鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (request.Header == null)
+        {
+            throw new Exception("header 涓嶈兘涓虹┖");
+        }
+
+        if (request.Details == null || request.Details.Count == 0)
+        {
+            throw new Exception("details 涓嶈兘涓虹┖");
+        }
+
+        // 鏍¢獙蹇呭~瀛楁
+        if (StringUtil.IsNullOrEmpty(request.Header.TestDate))
+        {
+            throw new Exception("testDate 涓嶈兘涓虹┖");
+        }
+
+        if (StringUtil.IsNullOrEmpty(request.Header.TestTime))
+        {
+            throw new Exception("testTime 涓嶈兘涓虹┖");
+        }
+
+        if (StringUtil.IsNullOrEmpty(request.Header.TestResult))
+        {
+            throw new Exception("testResult 涓嶈兘涓虹┖");
+        }
+
+        if (StringUtil.IsNullOrEmpty(request.Header.BoardBarcode))
+        {
+            throw new Exception("boardBarcode 涓嶈兘涓虹┖");
+        }
+
+        if (StringUtil.IsNullOrEmpty(request.Header.Surface))
+        {
+            throw new Exception("surface 涓嶈兘涓虹┖");
+        }
+
+        // 鏍¢獙鏋氫妇鍊�
+        if (request.Header.Surface != "T" && request.Header.Surface != "B")
+        {
+            throw new Exception("surface 蹇呴』涓� T 鎴� B");
+        }
+
+        // 鏍¢獙瀛楃涓查暱搴�
+        if (request.Header.BoardBarcode.Length > 128)
+        {
+            throw new Exception("boardBarcode 闀垮害涓嶈兘瓒呰繃 128 瀛楃");
+        }
+
+        if (request.Header.TestResult.Length > 12)
+        {
+            throw new Exception("testResult 闀垮害涓嶈兘瓒呰繃 12 瀛楃");
+        }
+
+        // 鏍¢獙鏁板�奸潪璐�
+        foreach (var detail in request.Details)
+        {
+            if (detail.OffsetCount < 0 || detail.MissingCount < 0 ||
+                detail.ReverseCount < 0 || detail.LiftedCount < 0 ||
+                detail.FloatHighCount < 0 || detail.TombstoneCount < 0 ||
+                detail.FlipCount < 0 || detail.WrongPartCount < 0 ||
+                detail.LeadLiftCount < 0 || detail.ColdJointCount < 0 ||
+                detail.NoSolderCount < 0 || detail.InsufficientSolderCount < 0 ||
+                detail.ExcessSolderCount < 0 || detail.BridgeCount < 0 ||
+                detail.CopperExposureCount < 0 || detail.SpikeCount < 0 ||
+                detail.ForeignMatterCount < 0 || detail.GlueOverflowCount < 0 ||
+                detail.PinOffsetCount < 0 || detail.InputBoards < 0 ||
+                detail.OkBoards < 0 || detail.PassBoards < 0 ||
+                detail.DefectBoards < 0 || detail.DefectPoints < 0 ||
+                detail.MeasuredPoints < 0 || detail.PendingPoints < 0)
+            {
+                throw new Exception("鎵�鏈夎鏁板瓧娈靛繀椤� >= 0");
+            }
+        }
+    }
+
+    /// <summary>
+    ///     鏍¢獙瀛愯〃鏁版嵁(璁板綍璀﹀憡浣嗕笉闃绘柇)
+    /// </summary>
+    /// <param name="details">瀛愯〃DTO鍒楄〃</param>
+    private void ValidateDetailData(List<SpiAoiDetailDto> details)
+    {
+        foreach (var detail in details)
+        {
+            // 鏍¢獙 passBoards <= inputBoards
+            if (detail.PassBoards > detail.InputBoards)
+            {
+                Console.WriteLine($"[璀﹀憡] passBoards({detail.PassBoards}) 澶т簬 inputBoards({detail.InputBoards})");
+            }
+
+            // 鏍¢獙 defectBoards = inputBoards - passBoards
+            var expectedDefectBoards = detail.InputBoards - detail.PassBoards;
+            if (Math.Abs(detail.DefectBoards - expectedDefectBoards) > 0)
+            {
+                Console.WriteLine($"[璀﹀憡] defectBoards({detail.DefectBoards}) 涓庤绠楀��({expectedDefectBoards})涓嶄竴鑷�");
+            }
+
+            // 鏍¢獙 passRate 鍋忓樊鍦� 卤1.0 浠ュ唴
+            if (detail.InputBoards > 0 && detail.PassRate.HasValue)
+            {
+                var expectedPassRate = (decimal)detail.PassBoards / detail.InputBoards * 100;
+                var deviation = Math.Abs(detail.PassRate.Value - expectedPassRate);
+                if (deviation > 1.0m)
+                {
+                    Console.WriteLine($"[璀﹀憡] passRate({detail.PassRate}) 涓庤绠楀��({expectedPassRate:F2})鍋忓樊瓒呰繃1.0");
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    ///     灏嗕富琛―TO杞崲涓哄疄浣�
+    /// </summary>
+    /// <param name="dto">涓昏〃DTO</param>
+    /// <returns>涓昏〃瀹炰綋</returns>
+    private MesSpiAoiHeader ConvertHeaderDtoToEntity(SpiAoiHeaderDto dto)
+    {
+        return new MesSpiAoiHeader
+        {
+            TestDate = DateTime.Parse(dto.TestDate),
+            TestTime = dto.TestTime,
+            TestResult = dto.TestResult,
+            Surface = dto.Surface,
+            TotalPoints = dto.TotalPoints,
+            ActualDefects = dto.ActualDefects,
+            EquipmentModel = dto.EquipmentModel,
+            WorkOrder = dto.WorkOrder,
+            ProductModel = dto.ProductModel,
+            BoardBarcode = dto.BoardBarcode,
+            SmtGroup = dto.SmtGroup,
+            LineName = dto.LineName
+        };
+    }
+
+    /// <summary>
+    ///     灏嗗瓙琛―TO鍒楄〃杞崲涓哄疄浣撳垪琛�
+    /// </summary>
+    /// <param name="dtoList">瀛愯〃DTO鍒楄〃</param>
+    /// <param name="headerId">涓昏〃ID</param>
+    /// <returns>瀛愯〃瀹炰綋鍒楄〃</returns>
+    private List<MesSpiAoiDetail> ConvertDetailDtoListToEntity(
+        List<SpiAoiDetailDto> dtoList, decimal headerId)
+    {
+        var now = DateTime.Now;
+        return dtoList.Select(dto => new MesSpiAoiDetail
+        {
+            HeaderId = headerId,
+            OffsetCount = dto.OffsetCount,
+            MissingCount = dto.MissingCount,
+            ReverseCount = dto.ReverseCount,
+            LiftedCount = dto.LiftedCount,
+            FloatHighCount = dto.FloatHighCount,
+            TombstoneCount = dto.TombstoneCount,
+            FlipCount = dto.FlipCount,
+            WrongPartCount = dto.WrongPartCount,
+            LeadLiftCount = dto.LeadLiftCount,
+            ColdJointCount = dto.ColdJointCount,
+            NoSolderCount = dto.NoSolderCount,
+            InsufficientSolderCount = dto.InsufficientSolderCount,
+            ExcessSolderCount = dto.ExcessSolderCount,
+            BridgeCount = dto.BridgeCount,
+            CopperExposureCount = dto.CopperExposureCount,
+            SpikeCount = dto.SpikeCount,
+            ForeignMatterCount = dto.ForeignMatterCount,
+            GlueOverflowCount = dto.GlueOverflowCount,
+            PinOffsetCount = dto.PinOffsetCount,
+            LineDisplayName = dto.LineDisplayName,
+            MachineName = dto.MachineName,
+            InputBoards = dto.InputBoards,
+            OkBoards = dto.OkBoards,
+            PassBoards = dto.PassBoards,
+            PassRate = dto.PassRate,
+            DefectBoards = dto.DefectBoards,
+            DefectRate = dto.DefectRate,
+            DefectPpm = dto.DefectPpm,
+            DefectPoints = dto.DefectPoints,
+            MeasuredPoints = dto.MeasuredPoints,
+            PendingPoints = dto.PendingPoints,
+            CreatedAt = now,
+            UpdatedAt = now
+        }).ToList();
+    }
+
+    #endregion
+}
diff --git a/MESApplication/Controllers/QC/SpiAoiController.cs b/MESApplication/Controllers/QC/SpiAoiController.cs
new file mode 100644
index 0000000..1339d59
--- /dev/null
+++ b/MESApplication/Controllers/QC/SpiAoiController.cs
@@ -0,0 +1,228 @@
+using System.Dynamic;
+using MES.Service.Dto.service;
+using MES.Service.Modes;
+using MES.Service.service;
+using MES.Service.service.QC;
+using MES.Service.util;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace MESApplication.Controllers.QC;
+
+/// <summary>
+///     SPI/AOI妫�娴嬫暟鎹帶鍒跺櫒
+/// </summary>
+[Route("api/[controller]")]
+[ApiController]
+public class SpiAoiController : ControllerBase
+{
+    private readonly MessageCenterManager _manager = new();
+    private readonly SpiAoiService _service = new();
+
+    private readonly string METHOD = "POST";
+    private readonly string TableName = "MES_SPI_AOI_HEADER";
+    private readonly string URL = "http://localhost:10054/api/QC/SpiAoi/";
+
+    /// <summary>
+    ///     涓婁紶SPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="request">涓婁紶璇锋眰</param>
+    /// <returns>涓婁紶缁撴灉</returns>
+    [HttpPost("Upload")]
+    public ResponseResult Upload([FromBody] SpiAoiUploadRequest request)
+    {
+        var entity = new MessageCenter();
+        entity.TableName = TableName;
+        entity.Url = URL + "Upload";
+        entity.Method = METHOD;
+        entity.Data = JsonConvert.SerializeObject(request);
+        entity.Status = 1;
+        entity.CreateBy = "SPI_AOI_SYSTEM";
+
+        try
+        {
+            var response = _service.UploadSpiAoiData(request);
+
+            dynamic resultInfos = new ExpandoObject();
+            resultInfos.headerId = response.HeaderId;
+            resultInfos.detailCount = response.DetailCount;
+            resultInfos.message = "SPI/AOI妫�娴嬫暟鎹笂浼犳垚鍔�";
+
+            entity.Result = 1;
+            entity.DealWith = 1;
+            entity.ResultData = JsonConvert.SerializeObject(response);
+            _manager.save(entity);
+
+            return new ResponseResult
+            {
+                status = 0,
+                message = "OK",
+                data = resultInfos
+            };
+        }
+        catch (Exception ex)
+        {
+            entity.Result = 0;
+            entity.DealWith = 0;
+            entity.ResultData = ex.Message;
+            _manager.save(entity);
+
+            return ResponseResult.ResponseError(ex);
+        }
+    }
+
+    /// <summary>
+    ///     鏍规嵁鏉$爜鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="request">璇锋眰鍙傛暟</param>
+    /// <returns>妫�娴嬫暟鎹�</returns>
+    [HttpPost("GetByBarcode")]
+    public ResponseResult GetByBarcode([FromBody] JObject request)
+    {
+        try
+        {
+            var boardBarcode = request["boardBarcode"]?.ToString();
+            if (StringUtil.IsNullOrEmpty(boardBarcode))
+            {
+                return new ResponseResult
+                {
+                    status = 1,
+                    message = "boardBarcode 涓嶈兘涓虹┖",
+                    data = null
+                };
+            }
+
+            var (header, details) = _service.GetByBarcode(boardBarcode);
+
+            if (header == null)
+            {
+                return new ResponseResult
+                {
+                    status = 1,
+                    message = $"鏈壘鍒版潯鐮� {boardBarcode} 鐨勬娴嬫暟鎹�",
+                    data = null
+                };
+            }
+
+            dynamic resultInfos = new ExpandoObject();
+            resultInfos.header = header;
+            resultInfos.details = details;
+
+            return new ResponseResult
+            {
+                status = 0,
+                message = "OK",
+                data = resultInfos
+            };
+        }
+        catch (Exception ex)
+        {
+            return ResponseResult.ResponseError(ex);
+        }
+    }
+
+    /// <summary>
+    ///     鏍规嵁ID鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="request">璇锋眰鍙傛暟</param>
+    /// <returns>妫�娴嬫暟鎹�</returns>
+    [HttpPost("GetById")]
+    public ResponseResult GetById([FromBody] JObject request)
+    {
+        try
+        {
+            var headerId = request["headerId"]?.ToObject<decimal>();
+            if (!headerId.HasValue)
+            {
+                return new ResponseResult
+                {
+                    status = 1,
+                    message = "headerId 涓嶈兘涓虹┖",
+                    data = null
+                };
+            }
+
+            var (header, details) = _service.GetById(headerId.Value);
+
+            if (header == null)
+            {
+                return new ResponseResult
+                {
+                    status = 1,
+                    message = $"鏈壘鍒癐D {headerId} 鐨勬娴嬫暟鎹�",
+                    data = null
+                };
+            }
+
+            dynamic resultInfos = new ExpandoObject();
+            resultInfos.header = header;
+            resultInfos.details = details;
+
+            return new ResponseResult
+            {
+                status = 0,
+                message = "OK",
+                data = resultInfos
+            };
+        }
+        catch (Exception ex)
+        {
+            return ResponseResult.ResponseError(ex);
+        }
+    }
+
+    /// <summary>
+    ///     鍒嗛〉鏌ヨSPI/AOI妫�娴嬫暟鎹�
+    /// </summary>
+    /// <param name="request">鏌ヨ璇锋眰</param>
+    /// <returns>鍒嗛〉鏁版嵁</returns>
+    [HttpPost("GetPage")]
+    public ResponseResult GetPage([FromBody] JObject request)
+    {
+        try
+        {
+            var boardBarcode = request["boardBarcode"]?.ToString();
+            var workOrder = request["workOrder"]?.ToString();
+            var surface = request["surface"]?.ToString();
+            var startDate = request["startDate"]?.ToString();
+            var endDate = request["endDate"]?.ToString();
+            var pageIndex = request["pageIndex"]?.ToObject<int>() ?? 1;
+            var pageSize = request["pageSize"]?.ToObject<int>() ?? 20;
+
+            DateTime? startDateTime = null;
+            DateTime? endDateTime = null;
+
+            if (StringUtil.IsNotNullOrEmpty(startDate) &&
+                DateTime.TryParse(startDate, out var start))
+            {
+                startDateTime = start;
+            }
+
+            if (StringUtil.IsNotNullOrEmpty(endDate) &&
+                DateTime.TryParse(endDate, out var end))
+            {
+                endDateTime = end;
+            }
+
+            var (items, totalCount) = _service.GetPage(
+                boardBarcode, workOrder, surface, startDateTime, endDateTime,
+                pageIndex, pageSize);
+
+            dynamic resultInfos = new ExpandoObject();
+            resultInfos.items = items;
+
+            return new ResponseResult
+            {
+                status = 0,
+                message = "OK",
+                data = resultInfos,
+                TotalCount = totalCount
+            };
+        }
+        catch (Exception ex)
+        {
+            return ResponseResult.ResponseError(ex);
+        }
+    }
+}
diff --git a/MESApplication/bin/Debug/net8.0/MES.Service.dll b/MESApplication/bin/Debug/net8.0/MES.Service.dll
index ace4808..54d04c6 100644
--- a/MESApplication/bin/Debug/net8.0/MES.Service.dll
+++ b/MESApplication/bin/Debug/net8.0/MES.Service.dll
Binary files differ
diff --git a/MESApplication/bin/Debug/net8.0/MES.Service.pdb b/MESApplication/bin/Debug/net8.0/MES.Service.pdb
index 1ebf67e..1c43e59 100644
--- a/MESApplication/bin/Debug/net8.0/MES.Service.pdb
+++ b/MESApplication/bin/Debug/net8.0/MES.Service.pdb
Binary files differ
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.deps.json b/MESApplication/bin/Debug/net8.0/MESApplication.deps.json
index 95a84e5..523a7cc 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.deps.json
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.deps.json
@@ -1413,7 +1413,7 @@
         },
         "runtime": {
           "MES.Service.dll": {
-            "assemblyVersion": "1.0.0",
+            "assemblyVersion": "1.0.0.0",
             "fileVersion": "1.0.0.0"
           }
         }
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.dll b/MESApplication/bin/Debug/net8.0/MESApplication.dll
index 3b9ad49..2d93d6a 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.dll
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.dll
Binary files differ
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.exe b/MESApplication/bin/Debug/net8.0/MESApplication.exe
index 3a126b4..c50ced5 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.exe
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.exe
Binary files differ
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.pdb b/MESApplication/bin/Debug/net8.0/MESApplication.pdb
index d9bfecb..facc967 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.pdb
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.pdb
Binary files differ
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.staticwebassets.endpoints.json b/MESApplication/bin/Debug/net8.0/MESApplication.staticwebassets.endpoints.json
index 2b6c535..5576e88 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.staticwebassets.endpoints.json
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.staticwebassets.endpoints.json
@@ -1,5 +1 @@
-{
-  "Version": 1,
-  "ManifestType": "Build",
-  "Endpoints": []
-}
\ No newline at end of file
+{"Version":1,"ManifestType":"Build","Endpoints":[]}
\ No newline at end of file
diff --git a/MESApplication/bin/Debug/net8.0/MESApplication.xml b/MESApplication/bin/Debug/net8.0/MESApplication.xml
index 3fecfd7..868abcb 100644
--- a/MESApplication/bin/Debug/net8.0/MESApplication.xml
+++ b/MESApplication/bin/Debug/net8.0/MESApplication.xml
@@ -752,111 +752,126 @@
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.GetList">
             <summary>
-            鑾峰彇鎵�鏈�
+                鑾峰彇鎵�鏈�
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.GetById(System.Int32)">
             <summary>
-            鏍规嵁涓婚敭鑾峰彇
+                鏍规嵁涓婚敭鑾峰彇
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.DeleteByIds(System.Object[])">
             <summary>
-            鏍规嵁涓婚敭鍒犻櫎
+                鏍规嵁涓婚敭鍒犻櫎
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.Add(MES.Service.Modes.Organize)">
             <summary>
-            娣诲姞 
+                娣诲姞
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.InsertReturnIdentity(MES.Service.Modes.Organize)">
             <summary>
-            娣诲姞杩斿洖鑷
+                娣诲姞杩斿洖鑷
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.OrganizeController.Update(MES.Service.Modes.Organize)">
             <summary>
-            淇敼
+                淇敼
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.GetList">
             <summary>
-            鑾峰彇鎵�鏈�
+                鑾峰彇鎵�鏈�
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.GetById(System.Int32)">
             <summary>
-            鏍规嵁涓婚敭鑾峰彇
+                鏍规嵁涓婚敭鑾峰彇
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.DeleteByIds(System.Object[])">
             <summary>
-            鏍规嵁涓婚敭鍒犻櫎
+                鏍规嵁涓婚敭鍒犻櫎
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.Add(MES.Service.Modes.SalesDeliveryNotice)">
             <summary>
-            娣诲姞 
+                娣诲姞
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.InsertReturnIdentity(MES.Service.Modes.SalesDeliveryNotice)">
             <summary>
-            娣诲姞杩斿洖鑷
+                娣诲姞杩斿洖鑷
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeController.Update(MES.Service.Modes.SalesDeliveryNotice)">
             <summary>
-            淇敼
+                淇敼
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.GetList">
             <summary>
-            鑾峰彇鎵�鏈�
+                鑾峰彇鎵�鏈�
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.GetById(System.Int32)">
             <summary>
-            鏍规嵁涓婚敭鑾峰彇
+                鏍规嵁涓婚敭鑾峰彇
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.DeleteByIds(System.Object[])">
             <summary>
-            鏍规嵁涓婚敭鍒犻櫎
+                鏍规嵁涓婚敭鍒犻櫎
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.Add(MES.Service.Modes.SalesDeliveryNoticeDetail)">
             <summary>
-            娣诲姞 
+                娣诲姞
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.InsertReturnIdentity(MES.Service.Modes.SalesDeliveryNoticeDetail)">
             <summary>
-            娣诲姞杩斿洖鑷
+                娣诲姞杩斿洖鑷
             </summary>
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.SalesDeliveryNoticeDetailController.Update(MES.Service.Modes.SalesDeliveryNoticeDetail)">
             <summary>
-            淇敼
+                淇敼
             </summary>
             <returns></returns>
+        </member>
+        <member name="T:MESApplication.Controllers.FBSDB.FbsDbController">
+            <summary>
+             璋冩嫧
+            </summary>
+        </member>
+        <member name="M:MESApplication.Controllers.FBSDB.FbsDbController.Save(MES.Service.Dto.webApi.FbsDb.ErpDb)">
+            <summary>
+             鏂板
+            </summary>
+        </member>
+        <member name="M:MESApplication.Controllers.FBSDB.FbsDbController.SaveList(System.Collections.Generic.List{MES.Service.Dto.webApi.FbsDb.ErpDb})">
+            <summary>
+             鏂板鎵归噺
+            </summary>
         </member>
         <member name="M:MESApplication.Controllers.QC.MesLineUserController.GetList">
             <summary>
@@ -893,6 +908,107 @@
                 淇敼
             </summary>
             <returns></returns>
+        </member>
+        <member name="T:MESApplication.Controllers.QC.PcbTestDataController">
+            <summary>
+                PCB妫�娴嬫暟鎹帶鍒跺櫒
+            </summary>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.SaveWholeboardData(MES.Service.Dto.service.WholeboardGenerateDto)">
+            <summary>
+                淇濆瓨鏁存澘妫�娴嬫暟鎹�
+            </summary>
+            <param name="dto">鏁存澘妫�娴嬫暟鎹瓺TO</param>
+            <returns>淇濆瓨缁撴灉</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.SaveSingleBoardData(MES.Service.Dto.service.SingleBoardGenerateDto)">
+            <summary>
+                淇濆瓨鍗曟澘妫�娴嬫暟鎹�
+            </summary>
+            <param name="dto">鍗曟澘妫�娴嬫暟鎹瓺TO</param>
+            <returns>淇濆瓨缁撴灉</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.GetPage(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鍒嗛〉鏌ヨPCB妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">鏌ヨ璇锋眰</param>
+            <returns>鍒嗛〉鏁版嵁</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.GetById(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鏍规嵁ID鑾峰彇PCB妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>PCB妫�娴嬫暟鎹�</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.GetByPcbSn(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鏍规嵁PCB鏉$爜鑾峰彇妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>妫�娴嬫暟鎹垪琛�</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.GetComponentData(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鑾峰彇鍣ㄤ欢妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>鍣ㄤ欢妫�娴嬫暟鎹�</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.GetStatistics(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鑾峰彇妫�娴嬬粺璁℃暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>缁熻鏁版嵁</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.Delete(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鍒犻櫎PCB妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>鍒犻櫎缁撴灉</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.PcbTestDataController.SaveTestData(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                缁熶竴淇濆瓨鎺ュ彛锛堣嚜鍔ㄨ瘑鍒暣鏉挎垨鍗曟澘鏁版嵁锛�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>淇濆瓨缁撴灉</returns>
+        </member>
+        <member name="T:MESApplication.Controllers.QC.SpiAoiController">
+            <summary>
+                SPI/AOI妫�娴嬫暟鎹帶鍒跺櫒
+            </summary>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.SpiAoiController.Upload(MES.Service.Dto.service.SpiAoiUploadRequest)">
+            <summary>
+                涓婁紶SPI/AOI妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">涓婁紶璇锋眰</param>
+            <returns>涓婁紶缁撴灉</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.SpiAoiController.GetByBarcode(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鏍规嵁鏉$爜鏌ヨSPI/AOI妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>妫�娴嬫暟鎹�</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.SpiAoiController.GetById(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鏍规嵁ID鏌ヨSPI/AOI妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">璇锋眰鍙傛暟</param>
+            <returns>妫�娴嬫暟鎹�</returns>
+        </member>
+        <member name="M:MESApplication.Controllers.QC.SpiAoiController.GetPage(Newtonsoft.Json.Linq.JObject)">
+            <summary>
+                鍒嗛〉鏌ヨSPI/AOI妫�娴嬫暟鎹�
+            </summary>
+            <param name="request">鏌ヨ璇锋眰</param>
+            <returns>鍒嗛〉鏁版嵁</returns>
         </member>
         <member name="M:MESApplication.Controllers.QC.XJController.getDaa001(Newtonsoft.Json.Linq.JObject)">
             <summary>
@@ -1152,78 +1268,6 @@
             <returns></returns>
         </member>
         <member name="M:MESApplication.Controllers.Warehouse.MesInvItemInCItemsController.Update(MES.Service.Modes.MesInvItemInCItems)">
-            <summary>
-                淇敼
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.GetList">
-            <summary>
-                鑾峰彇鎵�鏈�
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.GetById(System.Int32)">
-            <summary>
-                鏍规嵁涓婚敭鑾峰彇
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.DeleteByIds(System.Object[])">
-            <summary>
-                鏍规嵁涓婚敭鍒犻櫎
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.Add(MES.Service.Modes.MesInvItemMovesCDetails)">
-            <summary>
-                娣诲姞
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.InsertReturnIdentity(MES.Service.Modes.MesInvItemMovesCDetails)">
-            <summary>
-                娣诲姞杩斿洖鑷
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesCDetailsController.Update(MES.Service.Modes.MesInvItemMovesCDetails)">
-            <summary>
-                淇敼
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.GetList">
-            <summary>
-                鑾峰彇鎵�鏈�
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.GetById(System.Int32)">
-            <summary>
-                鏍规嵁涓婚敭鑾峰彇
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.DeleteByIds(System.Object[])">
-            <summary>
-                鏍规嵁涓婚敭鍒犻櫎
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.Add(MES.Service.Modes.MesInvItemMoves)">
-            <summary>
-                娣诲姞
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.InsertReturnIdentity(MES.Service.Modes.MesInvItemMoves)">
-            <summary>
-                娣诲姞杩斿洖鑷
-            </summary>
-            <returns></returns>
-        </member>
-        <member name="M:MESApplication.Controllers.Warehouse.MesInvItemMovesController.Update(MES.Service.Modes.MesInvItemMoves)">
             <summary>
                 淇敼
             </summary>

--
Gitblit v1.9.3