From fe596f9db05103917c9257348edcbd3ecb5b46e8 Mon Sep 17 00:00:00 2001
From: yanjinhui <3306209981@qq.com>
Date: 星期四, 16 四月 2026 19:12:38 +0800
Subject: [PATCH] Merge branch 'master' of http://115.159.85.185:8098/r/RuiShengZhiNeng/GaoPuLiTiKu

---
 代码管理/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs |  426 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 426 insertions(+), 0 deletions(-)

diff --git "a/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs" "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs"
new file mode 100644
index 0000000..002b48b
--- /dev/null
+++ "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Filter/Log/LogCleanupService.cs"
@@ -0,0 +1,426 @@
+锘縰sing Microsoft.Extensions.Hosting;
+using SqlSugar;
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using WIDESEAWCS_Core.DB;
+using WIDESEAWCS_Core.Seed;
+using WIDESEAWCS_Model.Models;
+
+namespace WIDESEAWCS_Core.LogHelper
+{
+    /// <summary>
+    /// 鏃ュ織鏁版嵁娓呯悊鏈嶅姟
+    /// </summary>
+    public class LogCleanupService : IHostedService, IDisposable
+    {
+        private Timer _cleanupTimer;
+        private bool _isDisposed = false;
+        private readonly object _lockObject = new object();
+
+        /// <summary>
+        /// 鏁版嵁淇濈暀澶╂暟锛堥粯璁�90澶╋級
+        /// </summary>
+        public int RetentionDays { get; set; } = 90;
+
+        /// <summary>
+        /// 娓呯悊闂撮殧锛堝皬鏃讹紝榛樿24灏忔椂锛�
+        /// </summary>
+        public int CleanupIntervalHours { get; set; } = 24;
+
+        /// <summary>
+        /// 娓呯悊鎵ц鏃堕棿锛堝皬鏃讹紝0-23锛岄粯璁ゅ噷鏅�2鐐癸級
+        /// </summary>
+        public int CleanupHour { get; set; } = 2;
+
+        /// <summary>
+        /// 鏄惁鍚敤褰掓。
+        /// </summary>
+        public bool EnableArchive { get; set; } = false;
+
+        /// <summary>
+        /// 鏄惁鍚敤鑷姩娓呯悊
+        /// </summary>
+        public bool EnableAutoCleanup { get; set; } = true;
+
+        /// <summary>
+        /// 鏃ュ織鏂囦欢淇濈暀澶╂暟
+        /// </summary>
+        public int LogRetentionDays { get; set; } = 30;
+        /// <summary>
+        /// 鏃ュ織鏂囦欢璺緞
+        /// </summary>
+        private string LogFilePath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs", "LogCleanup", $"Cleanup_{DateTime.Now:yyyyMMdd}.log");
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            if (EnableAutoCleanup)
+            {
+                // 纭繚鏃ュ織鐩綍瀛樺湪
+                EnsureLogDirectoryExists();
+
+                // 璁$畻鍒颁笅涓�涓竻鐞嗘椂闂寸殑闂撮殧
+                var now = DateTime.Now;
+                var nextCleanupTime = DateTime.Today.AddHours(CleanupHour);
+
+                if (now > nextCleanupTime)
+                {
+                    nextCleanupTime = nextCleanupTime.AddDays(1);
+                }
+
+                var timeToFirstCleanup = nextCleanupTime - now;
+
+                // 璁剧疆瀹氭椂鍣紝鍦ㄦ寚瀹氭椂闂存墽琛屾竻鐞�
+                _cleanupTimer = new Timer(CleanupCallback, null,
+                    timeToFirstCleanup,
+                    TimeSpan.FromHours(CleanupIntervalHours));
+
+                WriteLog($"鏃ュ織娓呯悊鏈嶅姟宸插惎鍔紝棣栨娓呯悊鏃堕棿: {nextCleanupTime:yyyy-MM-dd HH:mm:ss}");
+            }
+
+            return Task.CompletedTask;
+        }
+
+        /// <summary>
+        /// 纭繚鏃ュ織鐩綍瀛樺湪
+        /// </summary>
+        private void EnsureLogDirectoryExists()
+        {
+            try
+            {
+                string logDirectory = Path.GetDirectoryName(LogFilePath);
+                if (!Directory.Exists(logDirectory))
+                {
+                    Directory.CreateDirectory(logDirectory);
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"鍒涘缓鏃ュ織鐩綍澶辫触: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 鍐欏叆鏃ュ織鍒版枃浠�
+        /// </summary>
+        private void WriteLog(string message, bool isError = false)
+        {
+            try
+            {
+                lock (_lockObject)
+                {
+                    EnsureLogDirectoryExists();
+                    string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {(isError ? "[ERROR]" : "[INFO]")} {message}";
+
+                    // 鍐欏叆鏂囦欢
+                    File.AppendAllText(LogFilePath, logMessage + Environment.NewLine);
+
+                    // 鍚屾椂杈撳嚭鍒版帶鍒跺彴锛堝彲閫夛紝渚夸簬璋冭瘯锛�
+                    Console.WriteLine(logMessage);
+
+                    // 鏃ュ織鏂囦欢杩囧ぇ鏃惰嚜鍔ㄦ竻鐞嗭紙淇濈暀鏈�杩�30澶╃殑鏃ュ織鏂囦欢锛�
+                    AutoCleanupLogFiles();
+                }
+            }
+            catch (Exception ex)
+            {
+                // 濡傛灉鏂囦欢鏃ュ織澶辫触锛岃嚦灏戣緭鍑哄埌鎺у埗鍙�
+                Console.WriteLine($"鍐欏叆鏃ュ織鏂囦欢澶辫触: {ex.Message}");
+                Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
+            }
+        }
+
+        /// <summary>
+        /// 鑷姩娓呯悊杩囨湡鐨勬棩蹇楁枃浠讹紙淇濈暀30澶╋級
+        /// </summary>
+        private void AutoCleanupLogFiles()
+        {
+            try
+            {
+                string logDirectory = Path.GetDirectoryName(LogFilePath);
+                if (Directory.Exists(logDirectory))
+                {
+                    var files = Directory.GetFiles(logDirectory, "Cleanup_*.log");
+                    DateTime cutoffDate = DateTime.Now.AddDays(-30);
+
+                    foreach (var file in files)
+                    {
+                        try
+                        {
+                            // 浠庢枃浠跺悕涓彁鍙栨棩鏈�
+                            string fileName = Path.GetFileNameWithoutExtension(file);
+                            if (fileName.StartsWith("Cleanup_"))
+                            {
+                                string dateStr = fileName.Replace("Cleanup_", "");
+                                if (DateTime.TryParseExact(dateStr, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out DateTime fileDate))
+                                {
+                                    if (fileDate < cutoffDate)
+                                    {
+                                        File.Delete(file);
+                                        WriteLog($"鍒犻櫎杩囨湡鏃ュ織鏂囦欢: {Path.GetFileName(file)}");
+                                    }
+                                }
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            Console.WriteLine($"鍒犻櫎杩囨湡鏃ュ織鏂囦欢澶辫触 {file}: {ex.Message}");
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"娓呯悊鏃ュ織鏂囦欢澶辫触: {ex.Message}");
+            }
+        }
+
+        private void CleanupCallback(object state)
+        {
+            Task.Run(() => CleanupAsync());
+        }
+
+        /// <summary>
+        /// 鎵ц娓呯悊
+        /// </summary>
+        public async Task CleanupAsync()
+        {
+            try
+            {
+                WriteLog($"寮�濮嬫竻鐞� {RetentionDays} 澶╁墠鐨勬棩蹇楁暟鎹�");
+
+                using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+                {
+                    ConnectionString = DBContext.GetMainConnectionDb().Connection,
+                    IsAutoCloseConnection = true,
+                    DbType = DBContext.DbType,
+                }))
+                {
+                    DateTime cutoffDate = DateTime.Now.AddDays(-RetentionDays);
+
+                    WriteLog($"鎴鏃ユ湡: {cutoffDate:yyyy-MM-dd HH:mm:ss}");
+
+                    if (EnableArchive)
+                    {
+                        // 鍏堝綊妗e啀鍒犻櫎
+                        await ArchiveDataAsync(sugarClient, cutoffDate);
+                    }
+
+                    // 鍒犻櫎鍘嗗彶鏁版嵁
+                    int deletedCount = await sugarClient.Deleteable<Dt_InterfaceLog>()
+                        .Where(x => x.CreateDate < cutoffDate)
+                        .ExecuteCommandAsync();
+
+                    WriteLog($"娓呯悊瀹屾垚锛屽叡鍒犻櫎 {deletedCount} 鏉¤褰�");
+
+                    // 鍙�夛細璁板綍娓呯悊鏃ュ織鍒版暟鎹簱
+                    await LogCleanupResult(sugarClient, deletedCount, cutoffDate);
+                }
+            }
+            catch (Exception ex)
+            {
+                WriteLog($"娓呯悊澶辫触: {ex.Message}", true);
+                WriteLog($"璇︾粏閿欒: {ex.ToString()}", true);
+            }
+        }
+
+        private async Task ArchiveDataAsync(SqlSugarClient sugarClient, DateTime cutoffDate)
+        {
+            try
+            {
+                string archiveTableName = $"Dt_InterfaceLog_Archive_{DateTime.Now:yyyyMM}";
+
+                WriteLog($"寮�濮嬪綊妗f暟鎹埌琛�: {archiveTableName}");
+
+                // 鍒涘缓褰掓。琛�
+                string createTableSql = $@"
+                    IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='{archiveTableName}' AND xtype='U')
+                    BEGIN
+                        SELECT * INTO {archiveTableName} FROM Dt_InterfaceLog WHERE 1=0
+                        ALTER TABLE {archiveTableName} ADD ArchiveDate datetime DEFAULT GETDATE()
+                    END";
+                await sugarClient.Ado.ExecuteCommandAsync(createTableSql);
+
+                // 褰掓。鏁版嵁
+                string archiveSql = $@"
+                    INSERT INTO {archiveTableName} (Id, ApiCode, ApiName, ApiAddress, PushFrequency, 
+                        PushState, Requestor, RequestParameters, RequestParametersHash, Recipient, 
+                        ResponseParameters, ResponseParametersHash, Remark, CreateTime, ArchiveDate)
+                    SELECT Id, ApiCode, ApiName, ApiAddress, PushFrequency, PushState, 
+                        Requestor, RequestParameters, RequestParametersHash, Recipient, 
+                        ResponseParameters, ResponseParametersHash, Remark, CreateTime, GETDATE()
+                    FROM Dt_InterfaceLog 
+                    WHERE CreateTime < @CutoffDate";
+
+                int archivedCount = await sugarClient.Ado.ExecuteCommandAsync(archiveSql,
+                    new { CutoffDate = cutoffDate });
+
+                WriteLog($"褰掓。瀹屾垚锛屽叡褰掓。 {archivedCount} 鏉¤褰曞埌 {archiveTableName}");
+            }
+            catch (Exception ex)
+            {
+                WriteLog($"褰掓。澶辫触: {ex.Message}", true);
+            }
+        }
+
+        private async Task LogCleanupResult(SqlSugarClient sugarClient, int deletedCount, DateTime cutoffDate)
+        {
+            try
+            {
+                // 鍒涘缓娓呯悊鏃ュ織琛紙濡傛灉涓嶅瓨鍦級
+                string createLogTableSql = @"
+                    IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='LogCleanupHistory' AND xtype='U')
+                    BEGIN
+                        CREATE TABLE LogCleanupHistory (
+                            Id INT IDENTITY(1,1) PRIMARY KEY,
+                            TableName NVARCHAR(100),
+                            DeletedCount INT,
+                            CutoffDate DATETIME,
+                            CleanupTime DATETIME DEFAULT GETDATE()
+                        )
+                    END";
+                await sugarClient.Ado.ExecuteCommandAsync(createLogTableSql);
+
+                // 璁板綍娓呯悊鏃ュ織
+                string insertLogSql = @"
+                    INSERT INTO LogCleanupHistory (TableName, DeletedCount, CutoffDate, CleanupTime)
+                    VALUES ('Dt_InterfaceLog', @DeletedCount, @CutoffDate, GETDATE())";
+
+                await sugarClient.Ado.ExecuteCommandAsync(insertLogSql,
+                    new { DeletedCount = deletedCount, CutoffDate = cutoffDate });
+
+                WriteLog($"娓呯悊璁板綍宸插啓鍏ユ暟鎹簱鏃ュ織琛�");
+            }
+            catch (Exception ex)
+            {
+                WriteLog($"鍐欏叆鏁版嵁搴撴棩蹇楀け璐�: {ex.Message}", true);
+            }
+        }
+
+        /// <summary>
+        /// 鎵嬪姩鎵ц娓呯悊
+        /// </summary>
+        public async Task<int> ManualCleanup(int days = 90)
+        {
+            try
+            {
+                WriteLog($"鎵嬪姩娓呯悊寮�濮嬶紝鍒犻櫎瓒呰繃 {days} 澶╃殑鏁版嵁");
+
+                using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+                {
+                    ConnectionString = DBContext.GetMainConnectionDb().Connection,
+                    IsAutoCloseConnection = true,
+                    DbType = DBContext.DbType,
+                }))
+                {
+                    DateTime cutoffDate = DateTime.Now.AddDays(-days);
+                    int deletedCount = await sugarClient.Deleteable<Dt_InterfaceLog>()
+                        .Where(x => x.CreateDate < cutoffDate)
+                        .ExecuteCommandAsync();
+
+                    WriteLog($"鎵嬪姩娓呯悊瀹屾垚锛屽垹闄� {deletedCount} 鏉¤褰�");
+                    return deletedCount;
+                }
+            }
+            catch (Exception ex)
+            {
+                WriteLog($"鎵嬪姩娓呯悊澶辫触: {ex.Message}", true);
+                return 0;
+            }
+        }
+
+        /// <summary>
+        /// 鑾峰彇娓呯悊缁熻淇℃伅
+        /// </summary>
+        public async Task<CleanupStatistics> GetStatistics()
+        {
+            try
+            {
+                using (SqlSugarClient sugarClient = new SqlSugarClient(new ConnectionConfig()
+                {
+                    ConnectionString = DBContext.GetMainConnectionDb().Connection,
+                    IsAutoCloseConnection = true,
+                    DbType = DBContext.DbType,
+                }))
+                {
+                    var totalCount = await sugarClient.Queryable<Dt_InterfaceLog>().CountAsync();
+                    var oldestLog = await sugarClient.Queryable<Dt_InterfaceLog>()
+                        .OrderBy(x => x.CreateDate)
+                        .FirstAsync();
+                    var newestLog = await sugarClient.Queryable<Dt_InterfaceLog>()
+                        .OrderBy(x => x.CreateDate, OrderByType.Desc)
+                        .FirstAsync();
+
+                    return new CleanupStatistics
+                    {
+                        TotalCount = totalCount,
+                        OldestLogTime = oldestLog?.CreateDate,
+                        NewestLogTime = newestLog?.CreateDate,
+                        RetentionDays = RetentionDays,
+                        LastCleanupTime = GetLastCleanupTime(),
+                        LogFilePath = LogFilePath
+                    };
+                }
+            }
+            catch (Exception ex)
+            {
+                WriteLog($"鑾峰彇缁熻淇℃伅澶辫触: {ex.Message}", true);
+                return null;
+            }
+        }
+
+        private DateTime? GetLastCleanupTime()
+        {
+            try
+            {
+                string logDirectory = Path.GetDirectoryName(LogFilePath);
+                if (Directory.Exists(logDirectory))
+                {
+                    var latestLogFile = Directory.GetFiles(logDirectory, "Cleanup_*.log")
+                        .OrderByDescending(f => f)
+                        .FirstOrDefault();
+
+                    if (latestLogFile != null && File.Exists(latestLogFile))
+                    {
+                        return File.GetLastWriteTime(latestLogFile);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"鑾峰彇涓婃娓呯悊鏃堕棿澶辫触: {ex.Message}");
+            }
+            return null;
+        }
+
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            _cleanupTimer?.Dispose();
+            WriteLog("鏃ュ織娓呯悊鏈嶅姟宸插仠姝�");
+            return Task.CompletedTask;
+        }
+
+        public void Dispose()
+        {
+            if (!_isDisposed)
+            {
+                _cleanupTimer?.Dispose();
+                _isDisposed = true;
+            }
+        }
+    }
+
+    /// <summary>
+    /// 娓呯悊缁熻淇℃伅
+    /// </summary>
+    public class CleanupStatistics
+    {
+        public int TotalCount { get; set; }
+        public DateTime? OldestLogTime { get; set; }
+        public DateTime? NewestLogTime { get; set; }
+        public int RetentionDays { get; set; }
+        public DateTime? LastCleanupTime { get; set; }
+        public string LogFilePath { get; set; }
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3