ÏîÄ¿´úÂë/WCSServices/WIDESEAWCS_SystemServices/Sys_LogService.cs
@@ -131,6 +131,7 @@
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_ISystemRepository;
using WIDESEAWCS_ISystemServices;
@@ -149,12 +150,12 @@
        private const string DbName = "WIDESEA_HF";
        private const string ConnectionString = "Data Source=11.2.30.112;Initial Catalog=WIDESEA_HF;User ID=kuka;Password=kuka;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False";
        private const long MaxMdfSizeBytes = 8L * 1024 * 1024 * 1024; // 8GB
        private const long MaxMdfSizeBytes = 7L * 1024 * 1024 * 1024; // 7GB
        private const int TargetShrinkSizeMB = 4500; // 4.5GB
        private const double FragmentationThreshold = 30.0; // 30%碎片率阈值
        private const int MaintenanceIntervalDays = 15; // 15天执行一次
        private const int BackupRetentionDays = 30; // å¤‡ä»½ä¿ç•™30天
        private const string BackupBasePath = @"D:\DatabaseBackups"; // å¤‡ä»½æ–‡ä»¶å­˜å‚¨ç›®å½•
        private static readonly string BackupBasePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DatabaseBackups");  // å¤‡ä»½æ–‡ä»¶å­˜å‚¨ç›®å½•
        private const bool UseBackupCompression = true; // æ˜¯å¦ä½¿ç”¨å¤‡ä»½åŽ‹ç¼©
        private const bool VerifyBackup = true; // æ˜¯å¦éªŒè¯å¤‡ä»½
        private const int MaxBackupRetryCount = 3; // æœ€å¤§é‡è¯•次数
@@ -163,7 +164,7 @@
        public Sys_LogService(ISys_LogRepository BaseDal) : base(BaseDal)
        {
            // ç¡®ä¿å¤‡ä»½ç›®å½•存在
            EnsureBackupDirectory();
            //EnsureBackupDirectory();
        }
        private void EnsureBackupDirectory()
@@ -237,7 +238,7 @@
                    connection.Open();
                    // 1. å¤‡ä»½æ•°æ®åº“
                    BackupDatabase();
                    //BackupDatabase();
                    // 2. æ£€æŸ¥æ•°æ®åº“文件大小
                    CheckDatabaseFileSize(connection);
@@ -249,7 +250,7 @@
                    UpdateStatistics(connection);
                    // 5. æ¸…理旧备份
                    CleanupOldBackups();
                    //CleanupOldBackups();
                    // æ›´æ–°æœ€åŽæ£€æŸ¥æ—¥æœŸ
                    lock (_fileSizeLock)
@@ -307,14 +308,6 @@
                                fileCount = Convert.ToInt32(reader["FileCount"]);
                            }
                        }
                        // æ£€æŸ¥ç£ç›˜ç©ºé—´æ˜¯å¦è¶³å¤Ÿ
                        if (!CheckDiskSpace(backupFilePath, totalSizeMB))
                        {
                            throw new Exception("磁盘空间不足,无法执行备份");
                        }
                        // æž„建备份SQL语句
                        var backupSql = BuildBackupSql(backupFilePath);
@@ -337,30 +330,6 @@
                    Console.WriteLine($"数据库备份失败: {ex.Message}");
                    throw new Exception($"数据库备份失败: {ex.Message}", ex);
                }
            }
        }
        private bool CheckDiskSpace(string backupFilePath, double estimatedBackupSizeMB)
        {
            try
            {
                var driveInfo = new DriveInfo(Path.GetPathRoot(backupFilePath));
                var freeSpaceMB = driveInfo.AvailableFreeSpace / (1024 * 1024);
                // éœ€è¦è‡³å°‘1.5倍的空间来确保备份顺利进行
                var requiredSpaceMB = estimatedBackupSizeMB * 1.5;
                if (freeSpaceMB < requiredSpaceMB)
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"检查磁盘空间时出错: {ex.Message}");
                return false;
            }
        }
@@ -507,9 +476,8 @@
                {
                    return false;
                }
                // æ£€æŸ¥æ—¶é—´æ˜¯å¦æ˜¯1点左右(允许1:00-1:59)
                if (now.Hour != 1)
                if (now.Hour != 1 && now.Hour != 2)
                {
                    return false;
                }
@@ -767,5 +735,175 @@
                throw;
            }
        }
    }
            /// <summary>
            /// é€’归获取文件信息
            /// </summary>
            /// <param name="dirPath"></param>
            /// <returns></returns>
            private DirInfo GetDirInfo(string dirPath)
            {
                //当前文件夹
                var dirInfo = new DirInfo();
                dirInfo.dirName = Path.GetFileName(dirPath);
                //子文件
                List<FileDataInfo> files = new List<FileDataInfo>();
                foreach (var file in Directory.GetFiles(dirPath))
                {
                    files.Add(new FileDataInfo()
                    {
                        filePath = file,
                        fileName = Path.GetFileName(file)
                    });
                }
                //子文件夹
                var dirs = Directory.GetDirectories(dirPath);
                dirInfo.dirs = new List<DirInfo>();
                foreach (var dir in dirs)
                {
                    dirInfo.dirs.Add(GetDirInfo(dir));
                }
                //子文件夹,与子目录合并
                foreach (var file in files)
                {
                    dirInfo.dirs.Add(new DirInfo() { dirPath = file.filePath, dirName = file.fileName });
                }
                return dirInfo;
            }
            /// <summary>
            /// èŽ·å–æ—¥å¿—æ–‡ä»¶åˆ—è¡¨
            /// </summary>
            /// <returns></returns>
            public WebResponseContent GetLogList()
            {
                WebResponseContent content = new WebResponseContent();
                string path = Path.Combine(AppContext.BaseDirectory, "log");
                if (!Directory.Exists(path))
                {
                    return content.Error("暂无日志文件");
                }
                content.Data = GetDirInfo(path);
                content.OK();
                return content;
            }
            /// <summary>
            /// èŽ·å–æ–‡ä»¶å†…å®¹
            /// </summary>
            /// <param name="parm"></param>
            /// <returns></returns>
            public WebResponseContent GetLogData(GetLogParm parm)
            {
                WebResponseContent content = new WebResponseContent();
                string res = "";
                //是否读取到最后
                bool isEnd = false;
                long startIndex = 0;
                //文件大小
                long len = 0;
                try
                {
                if (!File.Exists(parm.path))
                {
                        throw new Exception($"文件{parm.path}不存在!");
                    }
                    using (FileStream fs = new FileStream(parm.path, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        //最大读取大小
                        int maxsize = (int)(1024 * parm.maxsize_KB);
                        len = fs.Length;
                        long startPos = (long)(len * (parm.percent / 100));//起始位置
                        long readLen = len - startPos;//读取长度
                        //向前加载
                        if (parm.topStartPos != 0)
                        {
                            startPos = parm.topStartPos - maxsize;
                            if (startPos < 0)
                            {
                                //已读到起始位
                                startPos = 0;
                                readLen = parm.topStartPos;
                            }
                            else
                            {
                                readLen = maxsize;
                            }
                        }
                        else
                        {
                            //读取大小是否超出最大长度
                            if (readLen > maxsize)
                            {
                                readLen = maxsize;
                            }
                            else
                            {
                                isEnd = true;
                            }
                        }
                        //加载100%,按最大内容读取
                        if (parm.percent == 100)
                        {
                            if (len < maxsize)
                            {
                                startPos = 0;
                                readLen = len;
                            }
                            else
                            {
                                startPos = len - maxsize;
                                readLen = maxsize;
                            }
                        }
                        fs.Seek(startPos, SeekOrigin.Begin);
                        var buffer = new byte[readLen];
                        fs.Read(buffer, 0, (int)readLen);
                        startIndex = startPos;
                        if (startPos != 0 && (parm.percent != 0 || parm.topStartPos != 0))
                        {
                            //不是从头加载,删除可能不完整的第一行
                            int skipCount = 0;
                            for (int i = 0; i < buffer.Length; i++)
                            {
                                if (buffer[i] == 10)
                                {
                                    skipCount = i;
                                    break;
                                }
                            }
                            if (skipCount != 0)
                            {
                                //去掉换行
                                skipCount++;
                                //下次读取前延
                                startIndex += skipCount;
                            }
                            res = Encoding.UTF8.GetString(buffer.Skip(skipCount).ToArray());
                        }
                        else
                        {
                            res = Encoding.UTF8.GetString(buffer);
                        }
                    }
                }
                catch (Exception ex)
                {
                    return content.Error(ex.Message);
                }
                return content.OK(data: new { content = res, isEnd, startIndex, len });
            }
        }
}