diff --git a/Service/Jobs/DbBackupJob.cs b/Service/Jobs/DbBackupJob.cs
new file mode 100644
index 0000000..4208fc4
--- /dev/null
+++ b/Service/Jobs/DbBackupJob.cs
@@ -0,0 +1,70 @@
+using Microsoft.Extensions.Hosting;
+using Quartz;
+
+namespace Service.Jobs;
+
+///
+/// 数据库备份任务
+///
+public class DbBackupJob(
+ IHostEnvironment env,
+ ILogger logger) : IJob
+{
+ public Task Execute(IJobExecutionContext context)
+ {
+ try
+ {
+ logger.LogInformation("开始执行数据库备份任务");
+
+ // 数据库文件路径 (基于 appsettings.json 中的配置: database/EmailBill.db)
+ var dbPath = Path.Combine(env.ContentRootPath, "database", "EmailBill.db");
+ var backupDir = Path.Combine(env.ContentRootPath, "database", "backups");
+
+ if (!File.Exists(dbPath))
+ {
+ logger.LogWarning("数据库文件不存在,跳过备份: {Path}", dbPath);
+ return Task.CompletedTask;
+ }
+
+ if (!Directory.Exists(backupDir))
+ {
+ Directory.CreateDirectory(backupDir);
+ }
+
+ // 创建备份
+ var backupFileName = $"EmailBill_backup_{DateTime.Now:yyyyMMdd}.db";
+ var backupPath = Path.Combine(backupDir, backupFileName);
+
+ File.Copy(dbPath, backupPath, true);
+ logger.LogInformation("数据库备份成功: {Path}", backupPath);
+
+ // 清理旧备份 (保留最近20个)
+ var files = new DirectoryInfo(backupDir).GetFiles("EmailBill_backup_*.db")
+ .OrderByDescending(f => f.LastWriteTime) // 使用 LastWriteTime 排序
+ .ToList();
+
+ if (files.Count > 20)
+ {
+ var filesToDelete = files.Skip(20);
+ foreach (var file in filesToDelete)
+ {
+ try
+ {
+ file.Delete();
+ logger.LogInformation("删除过期备份: {Name}", file.Name);
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "删除过期备份失败: {Name}", file.Name);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "数据库备份任务执行失败");
+ }
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/WebApi/Expand.cs b/WebApi/Expand.cs
index e74d1ea..52a9270 100644
--- a/WebApi/Expand.cs
+++ b/WebApi/Expand.cs
@@ -44,6 +44,17 @@ public static class Expand
.WithIdentity("BudgetArchiveTrigger")
.WithCronSchedule("0 0 23 1 * ?") // 每个月1号晚11点执行
.WithDescription("每个月1号晚11点执行预算归档"));
+
+ // 配置数据库备份任务 - 每天早上6点执行
+ var dbBackupJobKey = new JobKey("DbBackupJob");
+ q.AddJob(opts => opts
+ .WithIdentity(dbBackupJobKey)
+ .WithDescription("数据库备份任务"));
+ q.AddTrigger(opts => opts
+ .ForJob(dbBackupJobKey)
+ .WithIdentity("DbBackupTrigger")
+ .WithCronSchedule("0 0 6 * * ?") // 每天早上6点执行
+ .WithDescription("每天早上6点执行数据库备份"));
});
// 添加 Quartz Hosted Service