feat:删除settings 启用
This commit is contained in:
1 parent
71794ed7fd
commit
3326dcbe12
10 files changed
+40
-114
No files matched your search
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() };
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
### 修复
|
||||
|
||||
@@ -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` 模块提供签到时间配置
|
||||
@@ -3,7 +3,7 @@
|
||||
## 职责
|
||||
- 维护系统级配置(如日志保留天数)
|
||||
- 为使用日志与面板提供统一配置读取
|
||||
- 维护定时签到的开关与执行时间
|
||||
- 维护定时签到执行时间
|
||||
|
||||
## 接口定义
|
||||
- `GET /api/settings` 读取设置
|
||||
@@ -13,7 +13,7 @@
|
||||
- 配置写入后即时生效
|
||||
- 未配置时使用环境变量默认值
|
||||
- 定时签到时间使用 `HH:mm` 格式(默认 `00:10`,中国时间)
|
||||
- 更新签到时间或开关后会触发 `CheckinScheduler` 重新调度
|
||||
- 更新签到时间后会触发 `CheckinScheduler` 重新调度
|
||||
- 若更新后当前时间已超过新签到时间,当日可再次触发自动签到
|
||||
|
||||
## 依赖关系
|
||||
|
||||
Reference in new issue
Block a user