feat: 用户徽章与等级体系,积分经济管理重构

- 新增徽章系统:badge 服务与 handler、管理端配置页、BadgeChip/LevelBadge 展示组件
- 新增等级模型:model/level 及前端 levels 元数据
- 管理端经济模块拆分为 points/badges/levels 独立页面,EconomySettings 迁入设置
- 积分、签到、评论等服务适配等级与徽章逻辑
This commit is contained in:
2026-09-25 16:38:29 +08:00
parent 7b327bc8cc
commit 4ae57d9392
57 changed files with 3939 additions and 147 deletions

View File

@@ -3,7 +3,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { Heart, MessageCircle, CheckCheck, Bell, CheckCircle2, XCircle, AtSign, ClipboardList } from "lucide-react";
import { Heart, MessageCircle, CheckCheck, Bell, CheckCircle2, XCircle, AtSign, ClipboardList, Award } from "lucide-react";
import { apiMarkRead, apiMarkAllRead, type NotificationsResponse, type NotificationItem } from "@/lib/api";
/**
@@ -20,11 +20,13 @@ export default function NotificationsClient({ initialData }: { initialData: Noti
list.map((item) => (item.id === n.id ? { ...item, is_read: true } : item))
);
}
// @提及通知跳到群聊房间;其余跳到帖子/评论
// @提及通知跳到群聊房间;徽章通知无关联帖子(仅标已读);其余跳到帖子/评论
if (n.type === "mention" && n.room_id) {
router.push(`/chat/${n.room_id}`);
} else if (n.type === "pending_review") {
router.push(n.post_id ? `/post/${n.post_id}` : "/admin/content?status=pending");
} else if (n.type === "badge") {
return;
} else {
router.push(`/post/${n.post_id}`);
}
@@ -84,21 +86,27 @@ export default function NotificationsClient({ initialData }: { initialData: Noti
? <AtSign size={16} />
: n.type === "pending_review"
? <ClipboardList size={16} />
: <MessageCircle size={16} />;
: n.type === "badge"
? <Award size={16} />
: <MessageCircle size={16} />;
const iconColor = n.type === "approved"
? "var(--ok)"
: n.type === "rejected" || n.type === "deleted"
? "var(--danger)"
: n.type === "like"
? "var(--clay)"
: "var(--accent)";
: n.type === "badge"
? "var(--gold)"
: "var(--accent)";
const iconBg = n.type === "approved"
? "var(--ok-soft)"
: n.type === "rejected" || n.type === "deleted"
? "var(--danger-soft)"
: n.type === "like"
? "var(--clay-soft)"
: "var(--accent-soft)";
: n.type === "badge"
? "var(--gold-soft)"
: "var(--accent-soft)";
return (
<button
key={n.id}
@@ -145,7 +153,9 @@ export default function NotificationsClient({ initialData }: { initialData: Noti
? "有新内容待审核"
: n.type === "deleted"
? "删除了你的帖子"
: "点赞了你的帖子"}
: n.type === "badge"
? "向你颁布了徽章"
: "点赞了你的帖子"}
</span>
</>
)}