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

@@ -254,6 +254,7 @@ export interface QuestionState {
accepted_comment_id: number;
accepted_floor: number;
accepted_answer?: AcceptedAnswer | null;
solved_at?: string;
can_accept: boolean;
can_solve: boolean;
can_reopen: boolean;
@@ -279,6 +280,8 @@ export interface PollState {
multi: boolean;
closed: boolean;
anonymous: boolean;
ends_at?: string;
closed_at?: string;
total_votes: number;
voters: number;
my_options: number[];
@@ -298,7 +301,11 @@ export interface BountyState {
ends_at?: string;
settled: boolean;
can_accept: boolean;
can_refund: boolean;
}
export interface LotteryPrize {
name: string;
count: number;
}
export interface LotteryEntrant {
@@ -309,17 +316,21 @@ export interface LotteryEntrant {
/** 中奖楼层评论 ID(该用户最早主评,每人仅一条) */
comment_id?: number;
floor?: number;
prize_name?: string;
}
export interface LotteryState {
slots: number;
prizes: LotteryPrize[];
drawn: boolean;
closed: boolean;
ends_at?: string;
entry_count: number;
eligible?: boolean;
/** 新号入池冷静期小时数(与发帖冷静期同源,0=关闭) */
cooldown_hours?: number;
can_draw: boolean;
can_close: boolean;
can_edit_prizes?: boolean;
winners: LotteryEntrant[];
}
@@ -938,14 +949,6 @@ export async function apiAcceptBounty(postId: string, commentId: number) {
return res.json();
}
export async function apiRefundBounty(postId: string) {
const res = await fetchWithRefresh(`/api/posts/${postId}/bounty/refund`, {
method: "POST",
headers: clientHeaders(),
});
return res.json();
}
export async function apiAcceptQuestion(postId: string, commentId: number) {
const res = await fetchWithRefresh(`/api/posts/${postId}/question/accept`, {
method: "POST",
@@ -971,14 +974,6 @@ export async function apiReopenQuestion(postId: string) {
return res.json();
}
export async function apiCloseLottery(postId: string) {
const res = await fetchWithRefresh(`/api/posts/${postId}/lottery/close`, {
method: "POST",
headers: clientHeaders(),
});
return res.json();
}
export async function apiDrawLottery(postId: string) {
const res = await fetchWithRefresh(`/api/posts/${postId}/lottery/draw`, {
method: "POST",