feat(admin): 完善站点设置、内容回收站与后台菜单分组
新增站点设置与内容管理(含已删除恢复/清除),用户页改用独有运营指标,并按概览/内容/成员与经济/站点重组侧栏。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,6 @@ import {
|
||||
X,
|
||||
ExternalLink,
|
||||
Megaphone,
|
||||
FileText,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
apiAdminListAnnouncements,
|
||||
@@ -24,6 +23,7 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { formatDate } from "@/lib/format";
|
||||
import { toast } from "@/lib/toast";
|
||||
import ConfirmDialog from "@/components/ConfirmDialog";
|
||||
|
||||
const COLORS: { value: AnnouncementColor; label: string }[] = [
|
||||
{ value: "blue", label: "蓝色" },
|
||||
@@ -52,6 +52,7 @@ export default function AnnouncementAdmin() {
|
||||
const [form, setForm] = useState<FormState | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [deletingId, setDeletingId] = useState<number | null>(null);
|
||||
const [deleteTarget, setDeleteTarget] = useState<Announcement | null>(null);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -113,7 +114,6 @@ export default function AnnouncementAdmin() {
|
||||
}
|
||||
|
||||
async function remove(a: Announcement) {
|
||||
if (!window.confirm(`确定删除公告「${a.title}」吗?此操作不可撤销。`)) return;
|
||||
setDeletingId(a.id);
|
||||
try {
|
||||
await apiAdminDeleteAnnouncement(a.id);
|
||||
@@ -124,6 +124,7 @@ export default function AnnouncementAdmin() {
|
||||
toast(e instanceof Error ? e.message : "删除失败");
|
||||
} finally {
|
||||
setDeletingId(null);
|
||||
setDeleteTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,10 +151,10 @@ export default function AnnouncementAdmin() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[400px_minmax(0,1fr)] gap-6 items-start">
|
||||
{/* 编辑/新建表单 */}
|
||||
{form ? (
|
||||
<div className="panel p-5 lg:sticky lg:top-24">
|
||||
<div className="grid grid-cols-1 gap-6 items-start">
|
||||
{/* 编辑/新建表单:仅在新建或编辑时展开,空闲不占位 */}
|
||||
{form && (
|
||||
<div className="panel p-5">
|
||||
<p className="font-semibold text-[15px] mb-4" style={{ color: "var(--ink)" }}>
|
||||
{form.id == null ? "新建公告" : "编辑公告"}
|
||||
</p>
|
||||
@@ -257,26 +258,6 @@ export default function AnnouncementAdmin() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="panel p-6 text-center lg:sticky lg:top-24">
|
||||
<span
|
||||
className="inline-flex w-12 h-12 rounded-2xl items-center justify-center mb-3"
|
||||
style={{ background: "var(--accent-soft)", color: "var(--accent)" }}
|
||||
>
|
||||
<FileText size={22} />
|
||||
</span>
|
||||
<p className="text-[14.5px]" style={{ color: "var(--ink)" }}>
|
||||
公告编辑器
|
||||
</p>
|
||||
<p className="meta mt-1.5 text-[12.5px] leading-relaxed">
|
||||
点击右上「新建公告」发布公告,
|
||||
<br />
|
||||
或在右侧列表中选择已有公告进行编辑。
|
||||
</p>
|
||||
<button onClick={startCreate} className="btn btn-primary mt-4">
|
||||
<Plus size={15} /> 新建公告
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 公告列表 */}
|
||||
@@ -350,7 +331,7 @@ export default function AnnouncementAdmin() {
|
||||
<Pencil size={15} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => remove(a)}
|
||||
onClick={() => setDeleteTarget(a)}
|
||||
disabled={deletingId === a.id}
|
||||
className="w-8 h-8 inline-flex items-center justify-center rounded-full transition-colors hover:bg-[var(--danger-soft)] disabled:opacity-50"
|
||||
style={{ color: "var(--ink-3)" }}
|
||||
@@ -367,6 +348,19 @@ export default function AnnouncementAdmin() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
open={!!deleteTarget}
|
||||
title="删除公告"
|
||||
message={deleteTarget ? `确定删除公告「${deleteTarget.title}」吗?此操作不可撤销。` : ""}
|
||||
danger
|
||||
busy={deletingId != null}
|
||||
confirmLabel="删除"
|
||||
onCancel={() => deletingId == null && setDeleteTarget(null)}
|
||||
onConfirm={() => {
|
||||
if (deleteTarget) void remove(deleteTarget);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user