feat:删除settings 启用

This commit is contained in:
lsy committed 2026-02-25 17:49:19 +08:00
1 parent 71794ed7fd
commit 3326dcbe12
10 files changed
+40 -114

No files matched your search

-4
View File
@@ -231,9 +231,6 @@ const App = () => {
log_retention_days: String(data.settings.log_retention_days ?? 30),
session_ttl_hours: String(data.settings.session_ttl_hours ?? 12),
admin_password: "",
checkin_schedule_enabled: Boolean(
data.settings.checkin_schedule_enabled ?? false,
),
checkin_schedule_time: data.settings.checkin_schedule_time ?? "00:10",
});
}, [data.settings]);
@@ -499,7 +496,6 @@ const App = () => {
const payload: Record<string, number | string | boolean> = {
log_retention_days: retention,
session_ttl_hours: sessionTtlHours,
checkin_schedule_enabled: settingsForm.checkin_schedule_enabled,
checkin_schedule_time:
settingsForm.checkin_schedule_time.trim() || "00:10",
};
-1
View File
@@ -42,6 +42,5 @@ export const initialSettingsForm: SettingsForm = {
log_retention_days: "30",
session_ttl_hours: "12",
admin_password: "",
checkin_schedule_enabled: false,
checkin_schedule_time: "00:10",
};
-2
View File
@@ -80,7 +80,6 @@ export type Settings = {
log_retention_days: number;
session_ttl_hours: number;
admin_password_set?: boolean;
checkin_schedule_enabled?: boolean;
checkin_schedule_time?: string;
};
@@ -139,7 +138,6 @@ export type SettingsForm = {
log_retention_days: string;
session_ttl_hours: string;
admin_password: string;
checkin_schedule_enabled: boolean;
checkin_schedule_time: string;
};
-24
View File
@@ -73,30 +73,6 @@ export const SettingsView = ({
}}
/>
</div>
<div>
<label
class="mb-1.5 block text-xs uppercase tracking-widest text-stone-500"
for="checkin-schedule-enabled"
>
定时签到
</label>
<div class="flex items-center gap-3 rounded-lg border border-stone-200 bg-white px-3 py-2.5">
<input
class="h-4 w-4 accent-stone-900"
id="checkin-schedule-enabled"
name="checkin_schedule_enabled"
type="checkbox"
checked={settingsForm.checkin_schedule_enabled}
onChange={(event) => {
const target = event.currentTarget as HTMLInputElement | null;
onFormChange({
checkin_schedule_enabled: Boolean(target?.checked),
});
}}
/>
<span class="text-sm text-stone-700">启用(中国时间)</span>
</div>
</div>
<div>
<label
class="mb-1.5 block text-xs uppercase tracking-widest text-stone-500"
+9 -38
View File
@@ -1,12 +1,12 @@
import { Hono } from "hono";
import type { AppEnv } from "../env";
import {
getCheckinSchedule,
getCheckinScheduleTime,
getRetentionDays,
getSessionTtlHours,
isAdminPasswordSet,
setAdminPasswordHash,
setCheckinSchedule,
setCheckinScheduleTime,
setRetentionDays,
setSessionTtlHours,
} from "../services/settings";
@@ -26,13 +26,12 @@ settings.get("/", async (c) => {
const retention = await getRetentionDays(c.env.DB);
const sessionTtlHours = await getSessionTtlHours(c.env.DB);
const adminPasswordSet = await isAdminPasswordSet(c.env.DB);
const checkinSchedule = await getCheckinSchedule(c.env.DB);
const checkinScheduleTime = await getCheckinScheduleTime(c.env.DB);
return c.json({
log_retention_days: retention,
session_ttl_hours: sessionTtlHours,
admin_password_set: adminPasswordSet,
checkin_schedule_enabled: checkinSchedule.enabled,
checkin_schedule_time: checkinSchedule.time,
checkin_schedule_time: checkinScheduleTime,
});
});
@@ -83,34 +82,9 @@ settings.put("/", async (c) => {
touched = true;
}
if (
body.checkin_schedule_enabled !== undefined ||
body.checkin_schedule_time !== undefined
) {
const current = await getCheckinSchedule(c.env.DB);
const enabledRaw = body.checkin_schedule_enabled;
const enabled =
enabledRaw === undefined
? current.enabled
: enabledRaw === true || enabledRaw === "true";
if (
enabledRaw !== undefined &&
enabledRaw !== true &&
enabledRaw !== false
) {
if (enabledRaw !== "true" && enabledRaw !== "false") {
return jsonError(
c,
400,
"invalid_checkin_schedule_enabled",
"invalid_checkin_schedule_enabled",
);
}
}
const timeValue =
body.checkin_schedule_time !== undefined
? String(body.checkin_schedule_time).trim()
: current.time;
if (body.checkin_schedule_time !== undefined) {
const currentTime = await getCheckinScheduleTime(c.env.DB);
const timeValue = String(body.checkin_schedule_time).trim();
if (!/^\d{2}:\d{2}$/.test(timeValue)) {
return jsonError(
c,
@@ -135,13 +109,10 @@ settings.put("/", async (c) => {
"invalid_checkin_schedule_time",
);
}
await setCheckinSchedule(c.env.DB, { enabled, time: timeValue });
await setCheckinScheduleTime(c.env.DB, timeValue);
touched = true;
scheduleTouched = true;
scheduleReset = shouldResetLastRun(current, {
enabled,
time: timeValue,
});
scheduleReset = shouldResetLastRun(currentTime, timeValue);
}
if (!touched) {
+9 -26
View File
@@ -3,7 +3,7 @@ import type {
DurableObjectState,
} from "@cloudflare/workers-types";
import type { Bindings } from "../env";
import { getCheckinSchedule } from "./settings";
import { getCheckinScheduleTime } from "./settings";
import { runCheckinAll } from "./checkin-runner";
import {
beijingDateString,
@@ -31,17 +31,9 @@ export const shouldRunCheckin = (
};
export const shouldResetLastRun = (
current: { enabled: boolean; time: string },
next: { enabled: boolean; time: string },
) => {
if (!next.enabled) {
return false;
}
if (current.enabled !== next.enabled) {
return next.enabled;
}
return current.time !== next.time;
};
currentTime: string,
nextTime: string,
) => currentTime !== nextTime;
export const computeNextAlarmAt = (
now: Date,
@@ -59,7 +51,6 @@ export const computeNextAlarmAt = (
};
type RescheduleResult = {
enabled: boolean;
nextRunAt: string | null;
};
@@ -107,14 +98,10 @@ export class CheckinScheduler {
private async handleAlarm(): Promise<void> {
const now = new Date();
const schedule = await getCheckinSchedule(this.env.DB);
if (!schedule.enabled) {
await this.state.storage.deleteAlarm();
return;
}
const scheduleTime = await getCheckinScheduleTime(this.env.DB);
const lastRunDate =
(await this.state.storage.get<string>(LAST_RUN_DATE_KEY)) ?? null;
if (shouldRunCheckin(now, schedule.time, lastRunDate)) {
if (shouldRunCheckin(now, scheduleTime, lastRunDate)) {
await runCheckinAll(this.env.DB, now);
await this.state.storage.put(LAST_RUN_DATE_KEY, beijingDateString(now));
}
@@ -125,16 +112,12 @@ export class CheckinScheduler {
now: Date = new Date(),
reset = false,
): Promise<RescheduleResult> {
const schedule = await getCheckinSchedule(this.env.DB);
if (!schedule.enabled) {
await this.state.storage.deleteAlarm();
return { enabled: false, nextRunAt: null };
}
const scheduleTime = await getCheckinScheduleTime(this.env.DB);
if (reset) {
await this.state.storage.delete(LAST_RUN_DATE_KEY);
}
const nextRun = computeNextAlarmAt(now, schedule.time, reset);
const nextRun = computeNextAlarmAt(now, scheduleTime, reset);
await this.state.storage.setAlarm(nextRun.getTime());
return { enabled: true, nextRunAt: nextRun.toISOString() };
return { nextRunAt: nextRun.toISOString() };
}
}
+9 -14
View File
@@ -7,7 +7,6 @@ const DEFAULT_CHECKIN_SCHEDULE_TIME = "00:10";
const RETENTION_KEY = "log_retention_days";
const SESSION_TTL_KEY = "session_ttl_hours";
const ADMIN_PASSWORD_HASH_KEY = "admin_password_hash";
const CHECKIN_SCHEDULE_ENABLED_KEY = "checkin_schedule_enabled";
const CHECKIN_SCHEDULE_TIME_KEY = "checkin_schedule_time";
async function readSetting(
@@ -113,24 +112,20 @@ export async function isAdminPasswordSet(db: D1Database): Promise<boolean> {
return Boolean(hash);
}
export async function getCheckinSchedule(db: D1Database): Promise<{
enabled: boolean;
time: string;
}> {
const enabledRaw = await readSetting(db, CHECKIN_SCHEDULE_ENABLED_KEY);
export async function getCheckinScheduleTime(
db: D1Database,
): Promise<string> {
const timeRaw = await readSetting(db, CHECKIN_SCHEDULE_TIME_KEY);
const enabled = enabledRaw ? enabledRaw === "true" : false;
const time =
timeRaw && timeRaw.length > 0 ? timeRaw : DEFAULT_CHECKIN_SCHEDULE_TIME;
return { enabled, time };
return timeRaw && timeRaw.length > 0
? timeRaw
: DEFAULT_CHECKIN_SCHEDULE_TIME;
}
export async function setCheckinSchedule(
export async function setCheckinScheduleTime(
db: D1Database,
input: { enabled: boolean; time: string },
time: string,
): Promise<void> {
await upsertSetting(db, CHECKIN_SCHEDULE_ENABLED_KEY, String(input.enabled));
await upsertSetting(db, CHECKIN_SCHEDULE_TIME_KEY, input.time);
await upsertSetting(db, CHECKIN_SCHEDULE_TIME_KEY, time);
}
/**
+8
View File
@@ -89,6 +89,14 @@
- 类型: 微调(无方案包)
- 文件: apps/worker/src/routes/proxy.ts
## [0.8.4] - 2026-02-25
### 变更
- **[checkin/settings]**: 定时签到改为始终启用,仅保留签到时间配置
- 方案: [202602251706_checkin-always-on](archive/2026-02/202602251706_checkin-always-on/)
- **[admin-ui]**: 设置页移除定时签到启用开关
- 方案: [202602251706_checkin-always-on](archive/2026-02/202602251706_checkin-always-on/)
## [0.8.3] - 2026-02-25
### 修复
+3 -3
View File
@@ -16,8 +16,8 @@
- `checkin_sites` CRUD 接口已移除,签到字段统一由 `channels` 承载
- 一键签到会跳过 `last_checkin_date` 已是北京时间当日且状态为成功/已签的站点
- 定时签到由 `CheckinScheduler` Durable Object 触发,每天最多执行一次
- 定时签到在 `settings.checkin_schedule_enabled=true` 且到达设定时间时执行
- 当签到时间或开关变更且已到新时间时,允许当日再次执行一次
- 定时签到始终启用,仅按 `settings.checkin_schedule_time` 到点执行
- 当签到时间变更且已到新时间时,允许当日再次执行一次
- 手动签到优先打开 `checkin_url`,为空则打开 `base_url`
- 签到执行使用 `checkin_url`(若为空则回退 `base_url`)拼接 `/api/user/checkin`
- 请求头必须携带 `New-Api-User`(值来自站点的 `userid` 配置)
@@ -26,4 +26,4 @@
## 依赖关系
- `worker` 路由与 D1 数据表 `channels`
- `admin-ui` 负责前端交互与结果展示
- `settings` 模块提供签到时间与开关配置
- `settings` 模块提供签到时间配置
+2 -2
View File
@@ -3,7 +3,7 @@
## 职责
- 维护系统级配置(如日志保留天数)
- 为使用日志与面板提供统一配置读取
- 维护定时签到的开关与执行时间
- 维护定时签到执行时间
## 接口定义
- `GET /api/settings` 读取设置
@@ -13,7 +13,7 @@
- 配置写入后即时生效
- 未配置时使用环境变量默认值
- 定时签到时间使用 `HH:mm` 格式(默认 `00:10`,中国时间)
- 更新签到时间或开关后会触发 `CheckinScheduler` 重新调度
- 更新签到时间后会触发 `CheckinScheduler` 重新调度
- 若更新后当前时间已超过新签到时间,当日可再次触发自动签到
## 依赖关系