Skip to main content

yggdrasil/pages/admin/settings/
backup_section.rs

1//! 自动备份分区:调度开关、执行时间、保留份数、是否包含 uploads。
2//!
3//! 备份操作(创建、恢复、删除)在「系统」页。执行时间按浏览器本地时间编辑,
4//! 服务端以 UTC 存储;写入后唤醒调度任务立即重排。
5
6use leptos::prelude::*;
7
8use super::kit::{use_section, SettingRow, SettingsCard, SwitchRow};
9use super::SettingsSection;
10use crate::api::error::ApiError;
11use crate::api::settings::{get_backup_settings, update_backup_settings};
12use crate::components::forms::{NumberInput, TimePicker};
13use crate::models::settings::BackupSettings;
14use crate::utils::time::{local_hhmm_to_utc, utc_hhmm_to_local};
15
16/// 草稿里的执行时间是本地时间。
17fn to_local(mut s: BackupSettings) -> BackupSettings {
18    s.time_utc = utc_hhmm_to_local(&s.time_utc);
19    s
20}
21
22async fn load() -> Result<BackupSettings, ApiError> {
23    get_backup_settings().await.map(|v| to_local(v.settings))
24}
25
26async fn save(d: BackupSettings) -> Result<BackupSettings, ApiError> {
27    update_backup_settings(
28        d.auto_enabled,
29        local_hhmm_to_utc(&d.time_utc),
30        d.retention_count,
31        d.include_uploads,
32    )
33    .await
34    .map(|v| to_local(v.settings))
35}
36
37/// 自动备份分区组件。
38#[component]
39pub fn BackupSection() -> impl IntoView {
40    let st = use_section(SettingsSection::Backup, load, save);
41    view! {
42        <SettingsCard
43            section=SettingsSection::Backup
44            description="每天定时备份数据库。创建、恢复与删除备份在「系统」页。"
45            ready=st.ready()
46            load_failed=st.load_failed()
47            failed=st.failed()
48        >
49            <SwitchRow
50                label="启用定时备份"
51                hint="保存后调度任务立即按新时间重排。"
52                checked=st.field(|d| d.auto_enabled)
53                ontoggle=move |()| st.edit(|d| d.auto_enabled = !d.auto_enabled)
54            />
55            <SettingRow label="执行时间" html_for="backup-time" hint="按本地时间显示与编辑,服务端以 UTC 保存。">
56                <TimePicker
57                    id="backup-time"
58                    value=st.field(|d| d.time_utc.clone())
59                    onchange=move |v: String| st.edit(|d| d.time_utc = v)
60                />
61            </SettingRow>
62            <SettingRow label="保留份数" html_for="backup-retention">
63                <NumberInput
64                    id="backup-retention"
65                    value=st.field(|d| i64::from(d.retention_count))
66                    min=1
67                    max=365
68                    unit="份"
69                    hint="超出后最旧的自动备份连同 uploads 包一起删除;手动备份不会自动删除。"
70                    onchange=move |v: i64| st.edit(|d| d.retention_count = v as i32)
71                />
72            </SettingRow>
73            <SwitchRow
74                label="包含 uploads"
75                hint="同时打包上传的素材(tar.gz,跳过可重建的缓存)。"
76                checked=st.field(|d| d.include_uploads)
77                ontoggle=move |()| st.edit(|d| d.include_uploads = !d.include_uploads)
78            />
79        </SettingsCard>
80    }
81}