From 5ad77f8491b3137238bafe30c2e2d83c60558bdb Mon Sep 17 00:00:00 2001 From: kyy <3283105747@qq.com> Date: 星期四, 31 七月 2025 16:23:14 +0800 Subject: [PATCH] 修改sop获取数据 --- MESApplication/Controllers/RealTimeInventory/RealTimeInventoryController.cs | 74 +++++++++++++- MESApplication/Controllers/PLM/PLMController.cs | 225 +++++++++++++++++++++++++++++--------------- 2 files changed, 216 insertions(+), 83 deletions(-) diff --git a/MESApplication/Controllers/PLM/PLMController.cs b/MESApplication/Controllers/PLM/PLMController.cs index 404c901..cc87770 100644 --- a/MESApplication/Controllers/PLM/PLMController.cs +++ b/MESApplication/Controllers/PLM/PLMController.cs @@ -13,13 +13,13 @@ public class PLMController : ControllerBase { private readonly IConfiguration _configuration; - private readonly PLMManager m = new(); - private readonly WarehouseDownloadDoc wdd = new(); + private readonly PLMManager _plmManager = new(); + private readonly WarehouseDownloadDoc _warehouseDownloadDoc = new(); public PLMController(IConfiguration configuration) { _configuration = configuration; - } // RetrieveDrawings 璋冨彇鍥剧焊 + } [HttpPost("RetrieveDrawings")] public async Task<ResponseResult> RetrieveDrawings(PurchaseInventory dto) @@ -27,70 +27,66 @@ try { dynamic resultInfos = new ExpandoObject(); - var retrieveDrawings = - m.RetrieveDrawings(dto.ItemNo); // 鑷畾涔変繚瀛樻牴鐩綍 - // string saveRootDirectory = @"D:\LTSMES\PLM"; + var drawings = _plmManager.RetrieveDrawings(dto.ItemNo); var saveRootDirectory = @"E:\SOPimage"; - var - saveDirectory = - Path.Combine(saveRootDirectory, - dto.ItemNo); // 鍦ㄥ惊鐜鐞嗘墍鏈� PDF 鏂囦欢涔嬪墠锛屽鏋滆 itemNo 宸插瓨鍦ㄨ〃涓紝鍒欒繘琛屽垹闄ゆ搷浣� - await DeleteRecordsByItemNo(dto.ItemNo); - // 鍦ㄥ惊鐜鐞嗘墍鏈� PDF 鏂囦欢涔嬪墠锛屾鏌ュ苟鍒犻櫎鏃ф枃浠跺す锛堝鏋滃瓨鍦級锛岀劧鍚庨噸鏂板垱寤� + var saveDirectory = Path.Combine(saveRootDirectory, dto.ItemNo); + + // 鍏堝垹闄ゅ綋鍓嶄骇绾�(cx)鐨勬暟鎹拰瀵瑰簲鏂囦欢澶� + await DeleteRecordsByProductionLine(dto.Cx); // 鏂板锛氭寜浜х嚎鍒犻櫎璁板綍 + if (Directory.Exists(saveDirectory)) Directory.Delete(saveDirectory, true); Directory.CreateDirectory(saveDirectory); - foreach (var retrieveDrawing in retrieveDrawings) + + // 澶勭悊姣忎釜鍥剧焊 + foreach (var drawing in drawings) { - var streamFile = wdd.SendRequest("Download", - retrieveDrawing.FRelevantObject); - var fileStreamResult = File(streamFile, - "application/octet-stream", retrieveDrawing.FName); - var saveResult = await SavePdfAsync(fileStreamResult, - saveRootDirectory, dto.ItemNo, dto.Cx, - retrieveDrawing.FName); + var streamFile = _warehouseDownloadDoc.SendRequest("Download", drawing.FRelevantObject); + var fileStreamResult = File(streamFile, "application/octet-stream", drawing.FName); + await SavePdfAsync(fileStreamResult, saveRootDirectory, dto.ItemNo, dto.Cx, drawing.FName); } - return new ResponseResult - { status = 0, message = "OK", data = resultInfos }; + return new ResponseResult { status = 0, message = "OK", data = resultInfos }; } catch (Exception ex) { return ResponseResult.ResponseError(ex); } - } // 鉁� 鐩存帴淇濆瓨 PDF锛屼笉鍐嶈浆鎹负鍥剧墖 + } - private async Task<dynamic> SavePdfAsync(FileStreamResult fileStreamResult, - string saveRootDirectory, - string itemNo, string cx, string fPhysicalFileName) + private async Task<dynamic> SavePdfAsync(FileStreamResult fileStreamResult, string saveRootDirectory, + string itemNo, string cx, string fileName) { try { - // 纭繚鐩綍瀛樺湪 var saveDirectory = Path.Combine(saveRootDirectory, itemNo); if (!Directory.Exists(saveDirectory)) - Directory.CreateDirectory(saveDirectory); // 淇濆瓨 PDF 鏂囦欢 + Directory.CreateDirectory(saveDirectory); var outputFilePath = Path.Combine(saveDirectory, - $"{Path.GetFileNameWithoutExtension(fPhysicalFileName)}.pdf"); - using (var fileStream = new FileStream(outputFilePath, - FileMode.Create, FileAccess.Write)) + $"{Path.GetFileNameWithoutExtension(fileName)}.pdf"); + + using (var fileStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write)) { await fileStreamResult.FileStream.CopyToAsync(fileStream); } - Console.WriteLine( - $"PDF 鏂囦欢宸蹭繚瀛�: {outputFilePath}"); // 鐢熸垚鏂扮殑 URL锛堟寚鍚� PDF 鏂囦欢锛� - var - url = - $"http://192.168.1.92:89/{itemNo}/{Path.GetFileName(outputFilePath)}"; // 鎻愬彇鏂囦欢鍚嶄腑鐨勬渶鍚庝竴涓�'_'鍒�'.pdf'涔嬮棿鐨勫瓧姣嶆暟瀛楅儴鍒嗭紝骞跺姞涓娾�滃伐搴忊�濆墠缂� - var extractedNumber = ExtractNumberFromFileName(fPhysicalFileName); - var - process = string.IsNullOrEmpty(extractedNumber) - ? string.Empty - : $"宸ュ簭{extractedNumber}"; // 鉁� 鎻掑叆鏁版嵁搴擄紙URL 鎸囧悜 PDF锛屽苟鏇存柊宸ュ簭瀛楁锛� - await InsertUrlIntoDatabase(url, itemNo, cx, process); + Console.WriteLine($"PDF 鏂囦欢宸蹭繚瀛�: {outputFilePath}"); + + var url = $"http://192.168.1.92:89/{itemNo}/{Path.GetFileName(outputFilePath)}"; + var extractedNumber = ExtractNumberFromFileName(fileName); + var process = string.IsNullOrEmpty(extractedNumber) ? string.Empty : $"宸ュ簭{extractedNumber}"; + + // 鎻掑叆璁板綍骞惰幏鍙朓D + var newRecordId = await InsertUrlIntoDatabase(url, itemNo, cx, process); + + // 濡傛灉鎻掑叆鎴愬姛锛屾煡璇㈠苟鏇存柊MAC鍦板潃 + if (newRecordId > 0) + { + await UpdateMacAddress(newRecordId, cx, process); + } + return new { PdfFilePath = outputFilePath }; } catch (Exception ex) @@ -98,64 +94,137 @@ Console.WriteLine($"PDF 淇濆瓨澶辫触: {ex.Message}"); return new { ErrorMessage = "PDF 淇濆瓨澶辫触", Exception = ex.Message }; } - } // 鎻愬彇鏂囦欢鍚嶄腑鐨勬渶鍚庝竴涓�'_'鍒�'.pdf'涔嬮棿鐨勫瓧姣嶆暟瀛楅儴鍒嗭紝蹇界暐鎷彿绛夊唴瀹� + } private string ExtractNumberFromFileName(string fileName) { - // 浣跨敤姝e垯琛ㄨ揪寮忔彁鍙栨渶鍚庝竴涓�'_'鍒�'.pdf'涔嬮棿鐨勫瓧姣嶆暟瀛楅儴鍒嗭紝蹇界暐鎷彿绛夊瓧绗� var match = Regex.Match(fileName, @"_([A-Za-z0-9]+)(?=\(?\.pdf$)"); - if (match.Success) - // 濡傛灉鍖归厤鎴愬姛锛岃繑鍥炴彁鍙栫殑閮ㄥ垎 - return match.Groups[1].Value; + return match.Success ? match.Groups[1].Value : string.Empty; + } - // 濡傛灉娌℃湁鎵惧埌绗﹀悎鏉′欢鐨勯儴鍒嗭紝杩斿洖绌哄瓧绗︿覆 - return string.Empty; - } // 灏� URL銆乮temNo銆乧x 鍜屽伐搴忓瓧娈垫彃鍏ュ埌鏁版嵁搴撲腑 - - - private async Task InsertUrlIntoDatabase(string url, string itemNo, - string cx, string gx) + private async Task<long> InsertUrlIntoDatabase(string url, string itemNo, string cx, string gx) { var connectionString = _configuration["AppSettings:DataBaseConn"]; using (var connection = new OracleConnection(connectionString)) { await connection.OpenAsync(); - var insertQuery = - "INSERT INTO MES_SOP_URL_TABLE (id, URL, ITEM_NO, CX, GX, CREATE_DATE) VALUES (SEQ_SOP_URL.NEXTVAL, :url, :item_no, :cx, :gx, :create_date)"; - using (var insertCommand = - new OracleCommand(insertQuery, connection)) + + // 浣跨敤浜嬪姟纭繚鏁版嵁涓�鑷存�� + using (var transaction = connection.BeginTransaction()) { - // 浣跨敤 Parameters.Add 鏂规硶娣诲姞鍙傛暟 - insertCommand.Parameters.Add("url", OracleDbType.Varchar2) - .Value = url; - insertCommand.Parameters.Add("item_no", OracleDbType.Varchar2) - .Value = itemNo; - insertCommand.Parameters.Add("cx", OracleDbType.Varchar2) - .Value = cx; - insertCommand.Parameters.Add("gx", OracleDbType.Varchar2) - .Value = gx; - insertCommand.Parameters.Add("create_date", OracleDbType.Date) - .Value = DateTime.Now; - await insertCommand.ExecuteNonQueryAsync(); + try + { + // 鍏堣幏鍙栧簭鍒楀�� + var getSeqQuery = "SELECT SEQ_SOP_URL.NEXTVAL FROM DUAL"; + using (var seqCommand = new OracleCommand(getSeqQuery, connection)) + { + seqCommand.Transaction = transaction; + var newId = Convert.ToInt64(await seqCommand.ExecuteScalarAsync()); + + // 鎻掑叆璁板綍 + var insertQuery = @"INSERT INTO MES_SOP_URL_TABLE + (id, URL, ITEM_NO, CX, GX, CREATE_DATE, MAC) + VALUES (:id, :url, :item_no, :cx, :gx, :create_date, null)"; + + using (var insertCommand = new OracleCommand(insertQuery, connection)) + { + insertCommand.Transaction = transaction; + insertCommand.Parameters.Add("id", OracleDbType.Int64).Value = newId; + insertCommand.Parameters.Add("url", OracleDbType.Varchar2).Value = url; + insertCommand.Parameters.Add("item_no", OracleDbType.Varchar2).Value = itemNo; + insertCommand.Parameters.Add("cx", OracleDbType.Varchar2).Value = cx; + insertCommand.Parameters.Add("gx", OracleDbType.Varchar2).Value = gx; + insertCommand.Parameters.Add("create_date", OracleDbType.Date).Value = DateTime.Now; + + await insertCommand.ExecuteNonQueryAsync(); + } + + transaction.Commit(); + return newId; + } + } + catch (Exception) + { + transaction.Rollback(); + throw; + } } } - } // 鍒犻櫎鎸囧畾 itemNo 鐨勮褰� + } + private async Task UpdateMacAddress(long recordId, string cx, string gx) + { + var connectionString = _configuration["AppSettings:DataBaseConn"]; + using (var connection = new OracleConnection(connectionString)) + { + await connection.OpenAsync(); + + // 浠庢瘮杈冭〃鏌ヨMAC鍦板潃 + var selectQuery = @"SELECT MAC FROM MES_SOP_URL_TABLE_COMPARE + WHERE CX = :cx AND GX = :gx"; + + using (var selectCommand = new OracleCommand(selectQuery, connection)) + { + selectCommand.Parameters.Add("cx", OracleDbType.Varchar2).Value = cx; + selectCommand.Parameters.Add("gx", OracleDbType.Varchar2).Value = gx; + + var macAddress = await selectCommand.ExecuteScalarAsync() as string; + + // 濡傛灉鎵惧埌MAC鍦板潃锛屽垯鏇存柊鍒颁富琛� + if (!string.IsNullOrEmpty(macAddress)) + { + var updateQuery = @"UPDATE MES_SOP_URL_TABLE + SET MAC = :mac + WHERE id = :id"; + + using (var updateCommand = new OracleCommand(updateQuery, connection)) + { + updateCommand.Parameters.Add("mac", OracleDbType.Varchar2).Value = macAddress; + updateCommand.Parameters.Add("id", OracleDbType.Int64).Value = recordId; + + await updateCommand.ExecuteNonQueryAsync(); + Console.WriteLine($"宸叉洿鏂癐D涓� {recordId} 鐨勮褰曠殑MAC鍦板潃: {macAddress}"); + } + } + else + { + Console.WriteLine($"鏈壘鍒癈X={cx}, GX={gx}瀵瑰簲鐨凪AC鍦板潃"); + } + } + } + } + + // 鏂板锛氭寜浜х嚎(cx)鍒犻櫎璁板綍 + private async Task DeleteRecordsByProductionLine(string cx) + { + var connectionString = _configuration["AppSettings:DataBaseConn"]; + using (var connection = new OracleConnection(connectionString)) + { + await connection.OpenAsync(); + var deleteQuery = "DELETE FROM MES_SOP_URL_TABLE WHERE CX = :cx"; + using (var deleteCommand = new OracleCommand(deleteQuery, connection)) + { + deleteCommand.Parameters.Add("cx", OracleDbType.Varchar2).Value = cx; + int deletedCount = await deleteCommand.ExecuteNonQueryAsync(); + Console.WriteLine($"宸插垹闄や骇绾� {cx} 鐨� {deletedCount} 鏉¤褰�"); + } + } + } + + // 淇濈暀鍘熸寜ItemNo鍒犻櫎鐨勬柟娉曪紝浠ュ涓嶆椂涔嬮渶 private async Task DeleteRecordsByItemNo(string itemNo) { var connectionString = _configuration["AppSettings:DataBaseConn"]; using (var connection = new OracleConnection(connectionString)) { await connection.OpenAsync(); - var deleteQuery = - "DELETE FROM MES_SOP_URL_TABLE WHERE ITEM_NO = :item_no"; - using (var deleteCommand = - new OracleCommand(deleteQuery, connection)) + var deleteQuery = "DELETE FROM MES_SOP_URL_TABLE WHERE ITEM_NO = :item_no"; + using (var deleteCommand = new OracleCommand(deleteQuery, connection)) { - deleteCommand.Parameters.Add("item_no", OracleDbType.Varchar2) - .Value = itemNo; + deleteCommand.Parameters.Add("item_no", OracleDbType.Varchar2).Value = itemNo; await deleteCommand.ExecuteNonQueryAsync(); } } } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/MESApplication/Controllers/RealTimeInventory/RealTimeInventoryController.cs b/MESApplication/Controllers/RealTimeInventory/RealTimeInventoryController.cs index 7993a32..fdd951b 100644 --- a/MESApplication/Controllers/RealTimeInventory/RealTimeInventoryController.cs +++ b/MESApplication/Controllers/RealTimeInventory/RealTimeInventoryController.cs @@ -6,25 +6,45 @@ namespace MESApplication.Controllers.RealTimeInventory; +/// <summary> +/// 瀹炴椂搴撳瓨鎺у埗鍣� +/// 璐熻矗鍚屾绗笁鏂圭郴缁熷簱瀛樻暟鎹埌鏈湴鏁版嵁搴� +/// </summary> [Route("api/[controller]")] [ApiController] public class RealTimeInventoryController : ControllerBase { + // K3Cloud绯荤粺鐨勫熀纭�API鍦板潃 private readonly string _baseUrl = "http://122.227.249.70:5050/k3cloud"; + // 鏁版嵁搴撹繛鎺ュ瓧绗︿覆 private readonly string _connectionString; + /// <summary> + /// 鏋勯�犲嚱鏁� + /// 閫氳繃渚濊禆娉ㄥ叆鑾峰彇閰嶇疆淇℃伅 + /// </summary> + /// <param name="configuration">閰嶇疆瀵硅薄</param> public RealTimeInventoryController(IConfiguration configuration) { + // 浠庨厤缃腑鑾峰彇鏁版嵁搴撹繛鎺ュ瓧绗︿覆 _connectionString = configuration["AppSettings:DataBaseConn"]; } + /// <summary> + /// 鍚屾搴撳瓨鏁版嵁API + /// 浠嶬3Cloud绯荤粺鑾峰彇搴撳瓨鏁版嵁骞跺悓姝ュ埌鏈湴鏁版嵁搴� + /// </summary> + /// <returns>鍚屾缁撴灉</returns> [HttpPost("syncInventory")] public async Task<IActionResult> SyncInventory() { + // 鍒涘缓鑷畾涔塇TTP瀹㈡埛绔疄渚� var httpClient = new HttpClientEx(); + // 璁剧疆韬唤楠岃瘉API鍦板潃 httpClient.Url = $"{_baseUrl}/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc"; + // 鍑嗗鐧诲綍鍙傛暟 var parameters = new List<object> { "6654201b47f099", // 甯愬Id @@ -33,66 +53,92 @@ 2052 // 璇█锛堜腑鏂囷級 }; + // 搴忓垪鍖栧弬鏁板苟璁剧疆涓鸿姹傚唴瀹� httpClient.Content = JsonConvert.SerializeObject(parameters); + // 鍙戦�佺櫥褰曡姹傚苟瑙f瀽缁撴灉 var result = JObject.Parse(httpClient.AsyncRequest())["LoginResultType"] .Value<int>(); + // 鐧诲綍澶辫触杩斿洖閿欒淇℃伅 if (result != 1) return BadRequest("鐧诲綍澶辫触"); + // 鑾峰彇闇�瑕佸悓姝ョ殑浠撳簱浠g爜鍒楄〃 var depotCodes = FetchDepotCodes(); if (depotCodes.Count == 0) return NotFound("鏈壘鍒版湁鏁堢殑DEPOTS_CODE"); + // 娓呯┖鐜版湁搴撳瓨鏁版嵁 DeleteInventoryData(); + // 灏嗕粨搴撲唬鐮佸垪琛ㄨ浆鎹负閫楀彿鍒嗛殧鐨勫瓧绗︿覆 var depotCodesStr = string.Join(",", depotCodes); var hasMoreData = true; var pageIndex = 1; + // 鍒嗛〉鑾峰彇鎵�鏈夊簱瀛樻暟鎹� while (hasMoreData) { + // 鏋勫缓搴撳瓨鏌ヨ鍙傛暟妯″瀷 var model = new InventoryParamModel { - fstocknumbers = depotCodesStr, - isshowauxprop = true, - isshowstockloc = true, - pageindex = pageIndex, - pagerows = 10000 + fstocknumbers = depotCodesStr, // 浠撳簱浠g爜 + isshowauxprop = true, // 鏄惁鏄剧ず杈呭姪灞炴�� + isshowstockloc = true, // 鏄惁鏄剧ず搴撳瓨浣嶇疆 + pageindex = pageIndex, // 褰撳墠椤电爜 + pagerows = 10000 // 姣忛〉璁板綍鏁� }; + // 璁剧疆搴撳瓨鏌ヨAPI鍦板潃 httpClient.Url = $"{_baseUrl}/Kingdee.K3.SCM.WebApi.ServicesStub.InventoryQueryService.GetInventoryData.common.kdsvc"; + // 搴忓垪鍖栨煡璇㈠弬鏁� httpClient.Content = JsonConvert.SerializeObject(new List<object> { model }); + // 鍙戦�佹煡璇㈣姹� var response = httpClient.AsyncRequest(); + // 鍙嶅簭鍒楀寲搴撳瓨鏁版嵁 var inventoryData = JsonConvert.DeserializeObject<InventoryResponse>(response); + // 妫�鏌ユ槸鍚﹁繕鏈夋暟鎹� if (inventoryData?.Data == null || inventoryData.Data.Count == 0) { hasMoreData = false; } else { + // 灏嗗綋鍓嶉〉鏁版嵁鎻掑叆鏁版嵁搴� InsertInventoryData(inventoryData); + // 鍑嗗鑾峰彇涓嬩竴椤垫暟鎹� pageIndex++; } } + // 杩斿洖鍚屾瀹屾垚娑堟伅 return Ok("搴撳瓨鏁版嵁瀵煎叆瀹屾垚"); } + /// <summary> + /// 浠庢湰鍦版暟鎹簱鑾峰彇浠撳簱浠g爜鍒楄〃 + /// 鎺掗櫎鐗瑰畾浠撳簱浠g爜('MJ','CY-MJ') + /// </summary> + /// <returns>浠撳簱浠g爜鍒楄〃</returns> private List<string> FetchDepotCodes() { var depotCodes = new List<string>(); + // 浣跨敤Oracle杩炴帴 using (var connection = new OracleConnection(_connectionString)) { try { + // 鎵撳紑鏁版嵁搴撹繛鎺� connection.Open(); + // 鏌ヨ鏈夋晥浠撳簱浠g爜鐨凷QL var query = "SELECT DEPOTS_CODE FROM MES_INV_ITEM_STOCKS WHERE DEPOTS_CODE IS NOT NULL AND DEPOTS_CODE NOT IN ('MJ','CY-MJ') GROUP BY DEPOTS_CODE"; + + // 鎵ц鏌ヨ骞惰鍙栫粨鏋� using (var cmd = new OracleCommand(query, connection)) using (var reader = cmd.ExecuteReader()) { @@ -109,6 +155,10 @@ return depotCodes; } + /// <summary> + /// 娓呯┖ERPKCPC琛ㄤ腑鐨勭幇鏈夊簱瀛樻暟鎹� + /// 浣跨敤浜嬪姟纭繚鎿嶄綔鐨勫師瀛愭�� + /// </summary> private void DeleteInventoryData() { using (var connection = new OracleConnection(_connectionString)) @@ -116,14 +166,17 @@ try { connection.Open(); + // 寮�濮嬫暟鎹簱浜嬪姟 using (var transaction = connection.BeginTransaction()) { + // 鎵ц鍒犻櫎鎿嶄綔 using (var deleteCmd = new OracleCommand("DELETE FROM ERPKCPC", connection)) { deleteCmd.ExecuteNonQuery(); } + // 鎻愪氦浜嬪姟 transaction.Commit(); } } @@ -134,6 +187,11 @@ } } + /// <summary> + /// 灏嗗簱瀛樻暟鎹彃鍏ュ埌ERPKCPC琛ㄤ腑 + /// 浣跨敤浜嬪姟纭繚鎵�鏈夋暟鎹涔堝叏閮ㄦ彃鍏ユ垚鍔燂紝瑕佷箞鍏ㄩ儴澶辫触 + /// </summary> + /// <param name="inventoryData">搴撳瓨鏁版嵁鍝嶅簲瀵硅薄</param> private void InsertInventoryData(InventoryResponse inventoryData) { using (var connection = new OracleConnection(_connectionString)) @@ -141,10 +199,13 @@ try { connection.Open(); + // 寮�濮嬫暟鎹簱浜嬪姟 using (var transaction = connection.BeginTransaction()) { + // 閬嶅巻姣忔潯搴撳瓨鏁版嵁 foreach (var item in inventoryData.Data) { + // 鎻掑叆SQL璇彞 var query = "INSERT INTO ERPKCPC (ITEM_ID, DEPOT_CODE, FQTY, ITEM_NO, ORGID,Fstockstatusnumber,Fstockstatusname) VALUES (:ITEM_ID, :DEPOT_CODE, :FQTY, :ITEM_NO, :ORGID,:Fstockstatusnumber,:Fstockstatusname)"; using (var cmd = new OracleCommand(query, connection)) @@ -159,10 +220,12 @@ try { + // 鎵ц鎻掑叆鍛戒护 cmd.ExecuteNonQuery(); } catch (Exception ex) { + // 鍑洪敊鏃跺洖婊氫簨鍔� transaction.Rollback(); Console.WriteLine("鎻掑叆搴撳瓨鏁版嵁鏃跺嚭閿�: " + ex.Message); return; @@ -170,6 +233,7 @@ } } + // 鎵�鏈夋暟鎹彃鍏ユ垚鍔燂紝鎻愪氦浜嬪姟 transaction.Commit(); } } -- Gitblit v1.9.3