diff --git a/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx b/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx
index ccf8b41ae9..d581612384 100644
--- a/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx
+++ b/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx
@@ -139,6 +139,37 @@ const S3Settings: FC = () => {
{t('settings.data.s3.title.help')}
+ {/* 覆盖式单文件备份,仅在自动备份开启且保留份数=1时推荐启用 */}
+
+
+ {t('settings.data.backup.singleFileOverwrite.title') || '覆盖式单文件备份(同名覆盖)'}
+
+ 0 && maxBackups === 1)}
+ />
+
+
+
+ {t('settings.data.backup.singleFileOverwrite.help') ||
+ '当自动备份开启且保留份数为1时,使用固定文件名每次覆盖。S3 会直接覆盖同键对象。'}
+
+
+
+ {t('settings.data.backup.singleFileName.title') || '自定义文件名(可选)'}
+ ..zip'
+ }
+ value={singleFileName}
+ onChange={(e) => setSingleFileName(e.target.value)}
+ onBlur={onSingleFileNameBlur}
+ style={{ width: 300 }}
+ disabled={!singleFileOverwrite || !(syncInterval > 0 && maxBackups === 1)}
+ />
+
+
{t('settings.data.s3.endpoint.label')}
0) {
+ // 覆盖式单文件备份启用时(且=1),不进行清理,避免误删历史。后续不会再增长。
+ if (
+ s3Config.maxBackups > 0 &&
+ !(autoBackupProcess && s3Config.maxBackups === 1 && s3Config.singleFileOverwrite)
+ ) {
try {
// 获取所有备份文件
const files = await window.api.backup.listS3Files(s3Config)
@@ -951,7 +955,9 @@ export async function backupToLocal({
const {
localBackupDir: localBackupDirSetting,
localBackupMaxBackups,
- localBackupSkipBackupFile
+ localBackupSkipBackupFile,
+ localSingleFileOverwrite,
+ localSingleFileName
} = store.getState().settings
const localBackupDir = await window.api.resolvePath(localBackupDirSetting)
let deviceType = 'unknown'
@@ -963,7 +969,11 @@ export async function backupToLocal({
logger.error('Failed to get device type or hostname:', error as Error)
}
const timestamp = dayjs().format('YYYYMMDDHHmmss')
- const backupFileName = customFileName || `cherry-studio.${timestamp}.${hostname}.${deviceType}.zip`
+ let backupFileName = customFileName || `cherry-studio.${timestamp}.${hostname}.${deviceType}.zip`
+ if (autoBackupProcess && localBackupMaxBackups === 1 && localSingleFileOverwrite) {
+ const base = (localSingleFileName || `cherry-studio.${hostname}.${deviceType}`).trim()
+ backupFileName = base.endsWith('.zip') ? base : `${base}.zip`
+ }
const finalFileName = backupFileName.endsWith('.zip') ? backupFileName : `${backupFileName}.zip`
const backupData = await getBackupData()
@@ -993,8 +1003,11 @@ export async function backupToLocal({
})
}
- // Clean up old backups if maxBackups is set
- if (localBackupMaxBackups > 0) {
+ // 覆盖式单文件备份启用时(且=1),不进行清理
+ if (
+ localBackupMaxBackups > 0 &&
+ !(autoBackupProcess && localBackupMaxBackups === 1 && localSingleFileOverwrite)
+ ) {
try {
// Get all backup files
const files = await window.api.backup.listLocalBackupFiles(localBackupDir)