feat(posts): 类型帖截止时间、抽奖奖品表与悬赏发帖体验

统一投票/悬赏/抽奖截止与状态展示,抽奖支持多奖品行;发帖页悬赏积分对齐表格输入,并在余额不足时于底部就地提示。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 10:21:05 +08:00
parent 6b772380c9
commit b2d3d6dd26
23 changed files with 2711 additions and 1007 deletions

View File

@@ -5,7 +5,7 @@ export const POST_TYPES = [
{ value: "question", label: "问答", hint: "提问求解" },
{ value: "poll", label: "投票", hint: "发起投票,读者可参与" },
{ value: "bounty", label: "悬赏", hint: "发布时托管积分,采纳后发放" },
{ value: "lottery", label: "抽奖", hint: "回帖即参与,截止自动开奖" },
{ value: "lottery", label: "抽奖", hint: "奖品类型+数量入池,评论后锁定奖品" },
] as const;
export type PostTypeValue = (typeof POST_TYPES)[number]["value"];
@@ -21,6 +21,7 @@ export type ContentAccessValue = (typeof CONTENT_ACCESS)[number]["value"];
export const BOUNTY_EXPIRE_DAYS = [3, 7, 14, 30] as const;
export const LOTTERY_EXPIRE_DAYS = [1, 3, 7, 14] as const;
export const POLL_EXPIRE_DAYS = [1, 3, 7, 14] as const;
export function normalizePostType(t?: string): PostTypeValue {
if (!t) return "discussion";
@@ -74,12 +75,13 @@ export function typeStatusClass(postType?: string, typeStatus?: string): string
break;
case "bounty":
if (s === "solved") kind = "solved";
else if (s === "expired") kind = "expired";
// 已过期:与投票「已结束」同色(灰胶囊,标识已到期)
else if (s === "expired") kind = "closed";
else kind = "open";
break;
case "lottery":
if (s === "drawn") kind = "drawn";
else if (s === "closed") kind = "closed";
// 已开奖 / 已截止:与投票「已结束」同色(灰胶囊)
if (s === "drawn" || s === "closed") kind = "closed";
else kind = "open";
break;
default: