feat(admin): 运营数据 - 增加余额消耗统计、通知排序与用户积分汇总
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { App, Button, DatePicker, Form, Input, Modal, Popconfirm, Switch } from "antd";
|
||||
import { App, Button, DatePicker, Form, Input, InputNumber, Modal, Popconfirm, Switch } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import { Trash2, Edit3, Search } from "lucide-react";
|
||||
import dayjs, { type Dayjs } from "dayjs";
|
||||
@@ -29,6 +29,7 @@ type FormValues = {
|
||||
noticeType: BannerNoticeType;
|
||||
link?: string;
|
||||
status: boolean;
|
||||
sortOrder?: number;
|
||||
dateRange?: [Dayjs | null, Dayjs | null] | null;
|
||||
};
|
||||
|
||||
@@ -90,6 +91,7 @@ export default function AdminBannerAnnouncementsPanel({
|
||||
form.setFieldsValue({
|
||||
noticeType: BANNER_NOTICE_DEFAULT_TYPE,
|
||||
status: true,
|
||||
sortOrder: 0,
|
||||
});
|
||||
setDialog({ mode: "create" });
|
||||
}, [form]);
|
||||
@@ -112,6 +114,7 @@ export default function AdminBannerAnnouncementsPanel({
|
||||
noticeType: type,
|
||||
link: banner.link || undefined,
|
||||
status: banner.status === "active",
|
||||
sortOrder: banner.sortOrder ?? 0,
|
||||
dateRange: banner.startsAt || banner.endsAt ? [banner.startsAt ? dayjs(banner.startsAt) : null, banner.endsAt ? dayjs(banner.endsAt) : null] : null,
|
||||
});
|
||||
setDialog({ mode: "edit", banner });
|
||||
@@ -187,6 +190,7 @@ export default function AdminBannerAnnouncementsPanel({
|
||||
noticeType: selectedNoticeType,
|
||||
link: values.link?.trim() || undefined,
|
||||
status: (values.status ? "active" : "disabled") as "active" | "disabled",
|
||||
sortOrder: values.sortOrder || 0,
|
||||
startsAt,
|
||||
endsAt,
|
||||
};
|
||||
@@ -428,6 +432,9 @@ export default function AdminBannerAnnouncementsPanel({
|
||||
<Form.Item name="status" label="发布状态" valuePropName="checked">
|
||||
<Switch checkedChildren="启用" unCheckedChildren="禁用" />
|
||||
</Form.Item>
|
||||
<Form.Item name="sortOrder" label="展示顺序" extra="数字越小越靠前;相同顺序按创建时间倒序">
|
||||
<InputNumber min={0} max={999999} precision={0} className="w-full" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="dateRange" label="有效期(可选)" extra="留空表示长期有效;设置时间段后仅在有效期内于前台展示">
|
||||
<DatePicker.RangePicker showTime format="YYYY-MM-DD HH:mm" className="w-full" />
|
||||
|
||||
@@ -122,6 +122,8 @@ export function AdminUserDetailDrawer({ userId, onClose, previousUserId, nextUse
|
||||
{ key: "role", label: "角色", children: detail.user.role === "admin" ? "管理员" : "普通用户" },
|
||||
{ key: "status", label: "状态", children: <AdminStatusBadge label={detail.user.status === "active" ? "启用" : "停用"} tone={detail.user.status === "active" ? "success" : "neutral"} /> },
|
||||
{ key: "available", label: "可用积分", children: formatCredits(detail.account.availableMicrocredits) },
|
||||
{ key: "recharge", label: "累计充值积分", children: formatCredits(detail.counts.rechargeMicrocredits) },
|
||||
{ key: "checkin", label: "累计签到积分", children: formatCredits(detail.counts.checkinMicrocredits) },
|
||||
{ key: "reserved", label: "冻结积分", children: formatCredits(detail.account.reservedMicrocredits) },
|
||||
{ key: "created", label: "注册时间", children: formatTime(detail.user.createdAt) },
|
||||
{ key: "login", label: "最后登录", children: formatTime(detail.user.lastLoginAt) },
|
||||
|
||||
@@ -300,6 +300,8 @@ export default function AnalyticsPanel({ users, channels }: Props) {
|
||||
trend={formatCountDelta(currentTrend?.activeUsers, previousTrend?.activeUsers)}
|
||||
detail={data ? `日 ${formatNumber(data.kpi.dau)} · 周 ${formatNumber(data.kpi.wau)} · 月 ${formatNumber(data.kpi.mau)}` : undefined}
|
||||
/>
|
||||
<AnalyticsHealthCard icon={<CircleDollarSign className="size-4" />} label="用户总余额" value={data ? formatCredits(data.kpi.totalBalanceMicrocredits ?? 0) : "--"} detail="当前所有用户可用积分余额" />
|
||||
<AnalyticsHealthCard icon={<CircleDollarSign className="size-4" />} label="范围消耗" value={data ? formatCredits(data.kpi.totalConsumedMicrocredits ?? 0) : "--"} detail="筛选范围内已计费调用" />
|
||||
<AnalyticsHealthCard
|
||||
icon={<Workflow className="size-4" />}
|
||||
label="生成任务"
|
||||
|
||||
@@ -87,6 +87,7 @@ export type BannerAnnouncement = {
|
||||
noticeType?: BannerNoticeType;
|
||||
link?: string;
|
||||
status: "active" | "disabled";
|
||||
sortOrder?: number;
|
||||
startsAt?: string;
|
||||
endsAt?: string;
|
||||
createdBy: string;
|
||||
@@ -107,6 +108,7 @@ export type AdminBannerPayload = {
|
||||
noticeType?: BannerNoticeType;
|
||||
link?: string;
|
||||
status: "active" | "disabled";
|
||||
sortOrder?: number;
|
||||
startsAt?: string;
|
||||
endsAt?: string;
|
||||
};
|
||||
|
||||
@@ -126,7 +126,7 @@ export type AdminAuditEvent = {
|
||||
export type AdminUserDetail = {
|
||||
user: LocalUser;
|
||||
account: { userId: string; availableMicrocredits: number; reservedMicrocredits: number; version: number };
|
||||
counts: { ledgerEntries: number; tasks: number; apiCalls: number; auditEvents: number };
|
||||
counts: { ledgerEntries: number; tasks: number; apiCalls: number; auditEvents: number; rechargeMicrocredits: number; checkinMicrocredits: number };
|
||||
storageUsage: {
|
||||
assetCount: number;
|
||||
assetBytes: number;
|
||||
@@ -188,9 +188,11 @@ export type AdminAnalytics = {
|
||||
successRate: number;
|
||||
p95DurationMs: number;
|
||||
currentQueuedTasks: number;
|
||||
totalBalanceMicrocredits?: number;
|
||||
totalConsumedMicrocredits?: number;
|
||||
finance?: AnalyticsFinance | null;
|
||||
};
|
||||
trend: Array<{ day: string; tasks: number; requests: number; activeUsers: number; requestSuccessRate: number }>;
|
||||
trend: Array<{ day: string; tasks: number; requests: number; activeUsers: number; requestSuccessRate: number; consumedMicrocredits?: number }>;
|
||||
models: Array<{
|
||||
model: string;
|
||||
capability: string;
|
||||
|
||||
Reference in New Issue
Block a user