Files
jiang13-bbs/frontend/app/admin/points/PointsTabs.tsx
freefire 5270fee2b7 feat: 评论/帖子编辑历史与编辑标记,内容锁定
- 新增 smartDiff 差异计算与 EditHistoryModal 编辑历史弹窗,替换原 CommentEditHistoryModal
- 新增 PostEditedMark 编辑标记展示
- 新增内容锁定机制(content_lock)防止并发编辑冲突
- 审核与通知服务适配
2026-09-25 23:41:45 +08:00

94 lines
2.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useCallback, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { AdminSegmented } from "@/components/admin";
import type { EconomyStats, PublicSettings } from "@/lib/api";
import EconomyOverview from "./EconomyOverview";
import EconomySettings from "../settings/EconomySettings";
import UserPointsTab from "./UserPointsTab";
type TabKey = "overview" | "rules" | "users";
const TAB_OPTIONS = [
{ key: "overview", label: "经济总览" },
{ key: "rules", label: "积分规则" },
{ key: "users", label: "用户积分" },
];
/**
* 积分管理页标签壳:经济总览(管理员及以上)/ 积分规则 + 用户积分(超管/站长)。
* tab 记在 URL query(?tab=)便于刷新/分享保持;三个面板保持挂载、用 display 切换,
* 避免切标签丢失规则的未保存修改与用户列表状态。
*/
export default function PointsTabs({
stats,
settings,
canManage,
}: {
stats: EconomyStats | null;
settings: PublicSettings | null;
canManage: boolean;
}) {
const router = useRouter();
const searchParams = useSearchParams();
const queryTab = searchParams.get("tab");
const [tab, setTab] = useState<TabKey>(() => {
const t = queryTab;
if (canManage && (t === "rules" || t === "users")) return t;
return "overview";
});
const switchTab = useCallback(
(next: string) => {
setTab(next as TabKey);
const params = new URLSearchParams(searchParams.toString());
if (next === "overview") params.delete("tab");
else params.set("tab", next);
const qs = params.toString();
router.replace(qs ? `?${qs}` : "?", { scroll: false });
},
[router, searchParams]
);
const options = canManage
? TAB_OPTIONS
: TAB_OPTIONS.filter((o) => o.key === "overview");
return (
<div className={tab === "users" ? "admin-points-users-tab" : undefined}>
{canManage ? (
<div className="mb-4">
<AdminSegmented
options={options}
value={tab}
onChange={(v) => switchTab(String(v))}
ariaLabel="积分管理标签"
/>
</div>
) : null}
{/* 各面板保持挂载(display 切换):规则未保存修改与用户列表状态不因切标签丢失 */}
<div style={tab === "overview" ? undefined : { display: "none" }}>
{stats ? (
<EconomyOverview stats={stats} />
) : (
<div className="panel p-8 text-center">
<p className="meta">暂时无法加载积分数据</p>
</div>
)}
</div>
{canManage ? (
<>
<div style={tab === "rules" ? undefined : { display: "none" }}>
{settings ? <EconomySettings initial={settings} /> : null}
</div>
<div style={tab === "users" ? undefined : { display: "none" }}>
<UserPointsTab />
</div>
</>
) : null}
</div>
);
}