"use client"; import { useEffect, useState } from "react"; import { RefreshCcw } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { opsApi } from "@/lib/ops-api"; import type { OpsAuditEvent } from "@/types/ops"; function compactDate(value?: string) { if (!value) return "--"; return value.slice(0, 19).replace("T", " "); } function actionLabel(action?: string) { const key = String(action || "").trim().toLowerCase(); if (key === "manual_points_grant") return "手动补分"; if (key === "feedback_reward_grant") return "反馈奖励"; if (key === "subscription_manual_grant") return "手动开通"; if (key === "subscription_manual_extend") return "会员延期"; if (key === "refund_case_create") return "创建退款工单"; if (key === "refund_case_update") return "更新退款工单"; return key || "未知操作"; } export function AuditLogPageClient() { const [loading, setLoading] = useState(true); const [events, setEvents] = useState([]); const load = async () => { setLoading(true); try { const payload = (await opsApi.auditLog(150)) as { events?: OpsAuditEvent[] }; setEvents(payload.events ?? []); } catch { setEvents([]); } setLoading(false); }; useEffect(() => { void load(); }, []); return (

审计日志

管理员操作 ({events.length}) {loading ? (
加载中...
) : events.length === 0 ? (
暂无审计事件
) : (
{events.map((event) => ( ))}
时间 操作 管理员 对象 详情
{compactDate(event.created_at)} {actionLabel(event.action)} {event.actor_email || "--"}
{event.target_email || event.target_user_id || event.target_id || "--"}
{event.target_type || "--"}
{JSON.stringify(event.payload ?? {})}
)}
); }