"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { apiVotePoll, apiClosePoll, apiRefundBounty, apiCloseLottery, apiDrawLottery, apiSolveQuestion, apiReopenQuestion, type PollState, type BountyState, type LotteryState, type QuestionState, } from "@/lib/api"; import { toast } from "@/lib/toast"; import Avatar from "@/components/Avatar"; export default function PostInteractPanels({ postId, question, poll, bounty, lottery, loggedIn, }: { postId: number; question?: QuestionState | null; poll?: PollState | null; bounty?: BountyState | null; lottery?: LotteryState | null; loggedIn: boolean; }) { if (!question && !poll && !bounty && !lottery) return null; return (
{question && } {poll && } {bounty && } {lottery && }
); } function formatEndsAt(iso?: string) { if (!iso) return ""; try { return new Date(iso).toLocaleString("zh-CN"); } catch { return iso; } } function QuestionPanel({ postId, state }: { postId: number; state: QuestionState }) { const router = useRouter(); const [busy, setBusy] = useState(false); const act = async (fn: () => Promise<{ post?: unknown; error?: string }>, ok: string) => { setBusy(true); try { const res = await fn(); if (res.post) { toast(ok, "ok"); router.refresh(); } else toast(res.error || "操作失败", "error"); } finally { setBusy(false); } }; return (

问答 · {state.solved ? "已解决" : "未解决"}

{state.solved ? state.accepted_comment_id ? ( <> 已采纳{" "} #{state.accepted_floor || "?"} ) : "作者已标记为已解决" : "可在评论旁采纳答案,或手动标记已解决"}

{state.can_solve && ( )} {state.can_reopen && ( )}
); } function PollPanel({ postId, state, loggedIn, }: { postId: number; state: PollState; loggedIn: boolean; }) { const router = useRouter(); const [sel, setSel] = useState(state.my_options || []); const [busy, setBusy] = useState(false); const showResults = state.closed || (state.my_options && state.my_options.length > 0); const toggle = (idx: number) => { if (!state.can_vote) return; if (state.multi) { setSel((prev) => prev.includes(idx) ? prev.filter((x) => x !== idx) : [...prev, idx] ); } else { setSel([idx]); } }; const vote = async () => { if (sel.length === 0) { toast("请先选择选项", "error"); return; } setBusy(true); try { const res = await apiVotePoll(String(postId), sel); if (res.post) { toast("投票成功", "ok"); router.refresh(); } else toast(res.error || "投票失败", "error"); } catch { toast("投票失败", "error"); } finally { setBusy(false); } }; const close = async () => { setBusy(true); try { const res = await apiClosePoll(String(postId)); if (res.post) { toast("已结束投票", "ok"); router.refresh(); } else toast(res.error || "操作失败", "error"); } finally { setBusy(false); } }; return (

投票{state.multi ? "(多选)" : "(单选)"} {state.anonymous ? " · 匿名" : " · 实名"}

{state.voters} 人参与 · {state.total_votes} 票 {state.closed ? " · 已结束" : ""}
{state.can_vote && ( )} {!loggedIn && !state.closed && ( 登录后投票 )} {state.can_close && ( )}
); } function BountyPanel({ postId, state }: { postId: number; state: BountyState }) { const router = useRouter(); const [busy, setBusy] = useState(false); const [confirming, setConfirming] = useState(false); const refund = async () => { if (!confirming) { setConfirming(true); window.setTimeout(() => setConfirming(false), 3000); return; } setBusy(true); try { const res = await apiRefundBounty(String(postId)); if (res.post) { toast("悬赏已退回", "ok"); router.refresh(); } else toast(res.error || "退回失败", "error"); } finally { setBusy(false); setConfirming(false); } }; const statusText = state.expired ? "已过期,积分已自动退回" : state.refunded ? "已退回给发帖人" : state.accepted_comment_id ? null : state.escrowed ? "积分已托管,采纳优质回答后发放" : "悬赏未托管"; return (

悬赏 {state.points} 积分

{state.accepted_comment_id ? ( <> 已采纳{" "} #{state.accepted_floor || "?"} ) : ( statusText )} {state.ends_at && !state.settled ? ` · 截止 ${formatEndsAt(state.ends_at)}` : ""}

{state.can_refund && ( )} {state.can_accept && (

在评论旁点击「采纳」发放积分

)}
); } function LotteryPanel({ postId, state, }: { postId: number; state: LotteryState; }) { const router = useRouter(); const [busy, setBusy] = useState(false); const act = async (fn: () => Promise<{ post?: unknown; error?: string }>, ok: string) => { setBusy(true); try { const res = await fn(); if (res.post) { toast(ok, "ok"); router.refresh(); } else toast(res.error || "操作失败", "error"); } finally { setBusy(false); } }; return (

抽奖 · {state.slots} 个名额

已有 {state.entry_count} 名回帖用户参与 {state.drawn ? " · 已开奖" : state.closed ? " · 已截止" : ""} {state.eligible && !state.drawn ? " · 你已在奖池中" : ""} {state.ends_at && !state.drawn ? ` · 截止 ${formatEndsAt(state.ends_at)}` : ""}

{!state.drawn && (

对本帖发表评论即可参与(楼主除外)

)}
{state.can_close && ( )} {state.can_draw && ( )}
{state.drawn && (

{state.winners.length > 0 ? "中奖名单" : "无人回帖,开奖结果为空"}

{state.winners.length > 0 && (
    {state.winners.map((w) => (
  • {w.nickname || w.username}
  • ))}
)}
)}
); }