"use client"; import { CalendarDays, Clock3 } from "lucide-react"; /** 发帖截止时间:快捷天数 + 指定时刻(分栏 + 快捷芯片) */ export type DeadlineMode = "preset" | "custom"; function pad2(n: number) { return String(n).padStart(2, "0"); } /** datetime-local 值(本地时区) */ export function toLocalInputValue(d: Date): string { return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}T${pad2(d.getHours())}:${pad2(d.getMinutes())}`; } /** 默认自定义:从现在起 +N 天 */ export function defaultCustomLocal(days = 7): string { const d = new Date(); d.setDate(d.getDate() + days); d.setHours(18, 0, 0, 0); return toLocalInputValue(d); } /** 本地 datetime-local → RFC3339(UTC) */ export function localInputToRFC3339(local: string): string | null { const t = Date.parse(local); if (!Number.isFinite(t)) return null; return new Date(t).toISOString().replace(/\.\d{3}Z$/, "Z"); } export function formatLocalPreview(local: string): string { const t = Date.parse(local); if (!Number.isFinite(t)) return ""; try { return new Date(t).toLocaleString("zh-CN", { year: "numeric", month: "long", day: "numeric", weekday: "short", hour: "2-digit", minute: "2-digit", hour12: false, }); } catch { return local; } } function splitLocal(v: string): { date: string; time: string } { const [date = "", rawTime = ""] = (v || "").split("T"); const time = (rawTime || "18:00").slice(0, 5); return { date, time: /^\d{2}:\d{2}$/.test(time) ? time : "18:00" }; } function joinLocal(date: string, time: string): string { if (!date) return ""; const t = /^\d{2}:\d{2}$/.test(time) ? time : "18:00"; return `${date}T${t}`; } function startOfDay(d: Date): Date { const x = new Date(d); x.setHours(0, 0, 0, 0); return x; } function withTime(base: Date, hours: number, minutes: number): Date { const d = new Date(base); d.setHours(hours, minutes, 0, 0); return d; } /** 至少晚于当前 1 小时;不满足则推到合法时刻 */ function ensureMinLead(d: Date): Date { const min = new Date(Date.now() + 60 * 60 * 1000); min.setSeconds(0, 0); return d.getTime() < min.getTime() ? min : d; } type QuickSet = { id: string; label: string; build: () => Date }; function buildQuickSets(): QuickSet[] { const now = new Date(); return [ { id: "tonight", label: "今晚 22:00", build: () => ensureMinLead(withTime(now, 22, 0)), }, { id: "tomorrow-noon", label: "明天中午", build: () => { const d = new Date(now); d.setDate(d.getDate() + 1); return withTime(d, 12, 0); }, }, { id: "plus3-eve", label: "3 天后晚", build: () => { const d = new Date(now); d.setDate(d.getDate() + 3); return withTime(d, 21, 0); }, }, { id: "sunday-eve", label: "本周日晚", build: () => { const d = startOfDay(now); const day = d.getDay(); // 0=日 const add = day === 0 ? 7 : 7 - day; d.setDate(d.getDate() + add); return ensureMinLead(withTime(d, 21, 0)); }, }, ]; } const TIME_CHIPS = ["09:00", "12:00", "18:00", "21:00", "22:00", "23:59"] as const; export default function DeadlinePicker({ label = "截止时间", presets, mode, onModeChange, days, onDaysChange, customLocal, onCustomLocalChange, disabled, hint, }: { label?: string; presets: readonly number[]; mode: DeadlineMode; onModeChange: (m: DeadlineMode) => void; days: number; onDaysChange: (d: number) => void; customLocal: string; onCustomLocalChange: (v: string) => void; disabled?: boolean; hint?: string; }) { const minDate = toLocalInputValue(new Date()).slice(0, 10); const maxDate = toLocalInputValue(new Date(Date.now() + 90 * 24 * 60 * 60 * 1000)).slice(0, 10); const { date, time } = splitLocal(customLocal); const quickSets = buildQuickSets(); const applyCustom = (next: Date) => { onCustomLocalChange(toLocalInputValue(ensureMinLead(next))); }; const patchDate = (nextDate: string) => { onCustomLocalChange(joinLocal(nextDate, time || "18:00")); }; const patchTime = (nextTime: string) => { const baseDate = date || toLocalInputValue(new Date()).slice(0, 10); onCustomLocalChange(joinLocal(baseDate, nextTime)); }; const enterCustom = () => { onModeChange("custom"); if (!customLocal) onCustomLocalChange(defaultCustomLocal(days || 7)); }; return (
将于 {formatLocalPreview(customLocal)} 截止
) : null}{hint}
: null}