完善角色与消息权限:收紧板管内容处置,彻底删除仅站长,并统一管理删帖/评弹窗。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-20 14:30:08 +08:00
parent 1f2e4b2a33
commit c0462a3500
37 changed files with 1340 additions and 472 deletions

View File

@@ -2,7 +2,7 @@
import { useEffect, useState } from "react";
import Modal from "@/components/Modal";
import { POST_DELETE_TYPES } from "@/lib/api";
import StaffDeleteFields from "@/components/StaffDeleteFields";
export type DeleteCommentPayload = {
delete_type: string;
@@ -12,7 +12,7 @@ export type DeleteCommentPayload = {
/**
* 评论软删弹窗:
* - 评论者自删:必填理由(仅管理可见)
* - 管理删:必选类型;仅「其他」须填理由
* - 管理删:与删帖共用类型表单;仅「其他」须填理由
*/
export default function DeleteCommentModal({
open,
@@ -89,55 +89,31 @@ export default function DeleteCommentModal({
}
>
{isStaff ? (
<>
<p className="mb-2 text-[12.5px] font-medium" style={{ color: "var(--ink)" }}>
删除类型
</p>
<div
className="grid grid-cols-1 sm:grid-cols-2 gap-1.5 mb-1"
role="radiogroup"
aria-label="删除类型"
>
{POST_DELETE_TYPES.map((t) => {
const active = deleteType === t.value;
return (
<button
key={t.value}
type="button"
role="radio"
aria-checked={active}
onClick={() => {
setDeleteType(t.value);
setErr("");
if (t.value !== "other") setReason("");
}}
className="text-left rounded-lg px-3 py-2.5 text-[13px] transition-colors"
style={{
border: `1.5px solid ${active ? "var(--accent)" : "var(--line)"}`,
background: active ? "var(--accent-soft)" : "var(--panel-2)",
color: active ? "var(--accent)" : "var(--ink)",
}}
>
{t.label}
</button>
);
})}
</div>
<p className="meta text-[11.5px] mb-4 leading-relaxed">
选「其他」时需补充理由;其余类型直接按标签展示给读者。
</p>
</>
) : null}
{reasonRequired ? (
<StaffDeleteFields
deleteType={deleteType}
onTypeChange={(value) => {
setDeleteType(value);
setErr("");
if (value !== "other") setReason("");
}}
reason={reason}
onReasonChange={(value) => {
setReason(value);
setErr("");
}}
reasonId="cmt-delete-reason"
reasonPlaceholder="向读者说明删除原因(将展示在占位中)"
typeHint="选「其他」时需补充理由;其余类型直接按标签展示给读者。"
reasonHint="将公开显示在评论占位旁。"
/>
) : (
<>
<label
className="block mb-1.5 text-[12.5px] font-medium"
style={{ color: "var(--ink)" }}
htmlFor="cmt-delete-reason"
>
{isStaff ? "补充理由" : "删除理由"}{" "}
<span style={{ color: "var(--danger)" }}>*</span>
删除理由 <span style={{ color: "var(--danger)" }}>*</span>
</label>
<textarea
id="cmt-delete-reason"
@@ -148,19 +124,13 @@ export default function DeleteCommentModal({
setReason(e.target.value);
setErr("");
}}
placeholder={
isStaff
? "向读者说明删除原因(将展示在占位中)"
: "例如:发错了 / 不想保留(仅管理员可见)"
}
placeholder="例如:发错了 / 不想保留(仅管理员可见)"
maxLength={200}
autoFocus={!isStaff}
autoFocus
/>
<p className="meta text-[11.5px] mt-1.5">
{isStaff ? "将公开显示在评论占位旁。" : "普通读者看不到这条理由。"}
</p>
<p className="meta text-[11.5px] mt-1.5">普通读者看不到这条理由。</p>
</>
) : null}
)}
{err ? (
<p className="mt-2 text-[12px]" style={{ color: "var(--danger)" }}>