清除业务契约双读:抽奖/草稿/时间戳/邮件只认新格式,并删除 legacy 短代码改写。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-23 02:20:42 +08:00
parent 3b550f2124
commit 96314893bb
9 changed files with 23 additions and 281 deletions

View File

@@ -69,8 +69,6 @@ type ComposeDraft = {
tags: string;
boardId: number;
postType?: string;
/** @deprecated 旧草稿仅有 JSON 字符串;新草稿用 typeForm */
typeMeta?: string;
typeForm?: TypeFormSnapshot;
updatedAt: number;
};
@@ -90,70 +88,12 @@ function serializeTags(tags: string[]): string {
return tags.join(", ");
}
/** 从旧版 typeMeta JSON 尽量还原类型表单(不完整则用默认) */
function typeFormFromMeta(
postType: PostTypeValue,
raw: string | undefined
): Partial<TypeFormSnapshot> {
if (!raw?.trim()) return {};
try {
const m = JSON.parse(raw) as Record<string, unknown>;
const out: Partial<TypeFormSnapshot> = {};
const endsAt = typeof m.ends_at === "string" ? m.ends_at : "";
const expireDays = Number(m.expire_days);
if (endsAt) {
const t = Date.parse(endsAt);
if (Number.isFinite(t)) {
out.deadlineMode = "custom";
out.customEndsLocal = toLocalInputValue(new Date(t));
}
} else if (Number.isFinite(expireDays) && expireDays > 0) {
out.deadlineMode = "preset";
}
if (postType === "poll") {
if (Array.isArray(m.options)) {
const opts = m.options.map((o) => String(o ?? ""));
out.pollOptions = opts.length >= 2 ? opts : ["", ""];
}
out.pollMulti = !!m.multi;
out.pollAnonymous = m.anonymous !== false;
if ((POLL_EXPIRE_DAYS as readonly number[]).includes(expireDays)) {
out.pollExpireDays = expireDays;
}
} else if (postType === "bounty") {
const p = Number(m.points);
out.bountyPoints = p > 0 ? Math.floor(p) : "";
if ((BOUNTY_EXPIRE_DAYS as readonly number[]).includes(expireDays)) {
out.bountyExpireDays = expireDays;
}
} else if (postType === "lottery") {
const prizes = Array.isArray(m.prizes)
? (m.prizes as { name?: string; count?: number }[]).map((p) => ({
name: String(p.name || "").slice(0, 32),
count:
typeof p.count === "number" && p.count >= 1
? Math.floor(p.count)
: ("" as const),
}))
: [];
out.lotteryPrizes =
prizes.length > 0 ? prizes : [{ name: "", count: "" as const }];
if ((LOTTERY_EXPIRE_DAYS as readonly number[]).includes(expireDays)) {
out.lotteryExpireDays = expireDays;
}
}
return out;
} catch {
return {};
}
}
function draftHasContent(d: ComposeDraft): boolean {
if (d.title.trim() || d.content.trim() || d.tags.trim()) return true;
if (d.boardId > 0) return true;
const pt = normalizePostType(d.postType);
if (pt !== "discussion") return true;
if (d.typeForm || (d.typeMeta && d.typeMeta.trim())) return true;
if (d.typeForm) return true;
return false;
}
@@ -177,8 +117,14 @@ function readDraft(): ComposeDraft | null {
try {
const raw = localStorage.getItem(DRAFT_KEY);
if (!raw) return null;
const d = JSON.parse(raw) as ComposeDraft;
const d = JSON.parse(raw) as ComposeDraft & { typeMeta?: string };
if (!d || typeof d !== "object") return null;
// 仅含旧 typeMeta、无 typeForm 的草稿已废弃
if (d.typeMeta && !d.typeForm) {
clearDraft();
return null;
}
delete d.typeMeta;
return d;
} catch {
return null;
@@ -295,7 +241,6 @@ export default function PostComposer(props: PostComposerProps) {
try {
const raw = JSON.parse(props.initialTypeMeta || "{}") as {
prizes?: { name?: string; count?: number }[];
slots?: number;
};
if (Array.isArray(raw.prizes) && raw.prizes.length > 0) {
return raw.prizes.map((p) => ({
@@ -303,9 +248,6 @@ export default function PostComposer(props: PostComposerProps) {
count: Math.max(1, Number(p.count) || 1),
}));
}
// 旧数据仅有 slots:数量可回填,名称留空让作者补全
const slots = Number(raw.slots);
if (slots > 0) return [{ name: "", count: slots }];
return [{ name: "", count: "" }];
} catch {
return [{ name: "", count: "" }];
@@ -573,9 +515,7 @@ export default function PostComposer(props: PostComposerProps) {
const nextType = normalizePostType(draftBanner.postType);
setPostType(nextType);
const fromMeta = typeFormFromMeta(nextType, draftBanner.typeMeta);
const snap: Partial<TypeFormSnapshot> = {
...fromMeta,
...(draftBanner.typeForm || {}),
};
@@ -615,9 +555,7 @@ export default function PostComposer(props: PostComposerProps) {
}
if (snap.customEndsLocal) setCustomEndsLocal(snap.customEndsLocal);
// 编辑态用的 typeMeta 字符串一并同步,避免后续误用空串
if (draftBanner.typeMeta) setTypeMeta(draftBanner.typeMeta);
else if (draftBanner.typeForm) setTypeMeta("");
if (draftBanner.typeForm) setTypeMeta("");
setDraftBanner(null);
skipDraftSave.current = false;

View File

@@ -574,11 +574,7 @@ function LotteryPanel({
}
};
const prizes = state.prizes?.length
? state.prizes
: state.slots > 0
? [{ name: "奖品", count: state.slots }]
: [];
const prizes = state.prizes?.length ? state.prizes : [];
const statusBadge = state.drawn
? { cls: "badge-status badge-status-closed", label: "已开奖" }