import { App, Button, Input, Select, Space, Tag, Tooltip } from "antd"; import type { ColumnsType } from "antd/es/table"; import { RefreshCw, Trash2 } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { useDebouncedValue } from "@/hooks/use-debounced-value"; import { agentLessonCategoryLabel, deleteAdminAgentLesson, listAdminAgentLessons, type AdminAgentLesson } from "@/services/api/admin-agent-lessons"; import { listAdminUsers, type AdminUser } from "@/services/api/auth"; import { AdminDataTable, AdminStatusBadge, AdminTableEmpty } from "./admin-ui"; function authorLabel(record: AdminAgentLesson) { if (record.authorDisplayName && record.authorUsername) return `${record.authorDisplayName}(${record.authorUsername})`; return record.authorDisplayName || record.authorUsername || record.authorUserId || "未知用户"; } export default function AgentLessonsPanel() { const { message, modal } = App.useApp(); const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); const [status, setStatus] = useState("all"); const [keyword, setKeyword] = useState(""); const [userId, setUserId] = useState(); const [users, setUsers] = useState([]); const [userSearch, setUserSearch] = useState(""); const [searchingUsers, setSearchingUsers] = useState(false); const debouncedKeyword = useDebouncedValue(keyword.trim(), 250); const debouncedUserSearch = useDebouncedValue(userSearch.trim(), 250); const seqRef = useRef(0); const userSearchRef = useRef(0); const load = useCallback(async () => { const seq = ++seqRef.current; setLoading(true); try { const data = await listAdminAgentLessons({ status: status === "all" ? undefined : status, userId, keyword: debouncedKeyword || undefined, limit: 100, }); if (seq !== seqRef.current) return; setItems(data.lessons || []); } catch (error) { if (seq === seqRef.current) message.error(error instanceof Error ? error.message : "读取记忆失败"); } finally { if (seq === seqRef.current) setLoading(false); } }, [debouncedKeyword, message, status, userId]); useEffect(() => { void load(); }, [load]); useEffect(() => { const requestId = ++userSearchRef.current; setSearchingUsers(true); void listAdminUsers({ keyword: debouncedUserSearch || undefined, page: 1, pageSize: 50 }) .then((result) => { if (requestId !== userSearchRef.current) return; setUsers((current) => { const selected = current.find((user) => user.id === userId); if (selected && !result.users.some((user) => user.id === selected.id)) return [selected, ...result.users]; return result.users; }); }) .catch((error) => { if (requestId === userSearchRef.current) message.error(error instanceof Error ? error.message : "搜索用户失败"); }) .finally(() => { if (requestId === userSearchRef.current) setSearchingUsers(false); }); }, [debouncedUserSearch, message, userId]); const remove = (record: AdminAgentLesson) => { modal.confirm({ title: `删除「${record.topic}」`, content: `这是 ${authorLabel(record)} 的个人记忆。删除后该用户的 Agent 也无法召回。确认删除?`, okText: "删除", okButtonProps: { danger: true }, onOk: async () => { await deleteAdminAgentLesson(record.id); message.success("已删除"); await load(); }, }); }; const columns: ColumnsType = [ { title: "用户", key: "author", width: 168, render: (_, record) => (
{authorLabel(record)} {record.authorUserId ? {record.authorUserId} : null}
), }, { title: "分类", dataIndex: "category", width: 92, render: (value: string) => {agentLessonCategoryLabel(value)}, }, { title: "主题", dataIndex: "topic", width: 180, render: (value: string, record) => (
{value} {record.source ? 来源:{record.source} : null}
), }, { title: "适用场景 / 做法", dataIndex: "situation", render: (_: string, record) => { const steps = record.steps || []; return (
{record.situation} {record.lesson ? {record.lesson} : null} {steps.length ? (
    {steps.map((step, index) => (
  1. {step.tool} {" — "} {step.action} {step.note ? ({step.note}) : null}
  2. ))}
) : null}
); }, }, { title: "状态", dataIndex: "status", width: 96, render: (value: string) => , }, { title: ( 注入 ), dataIndex: "injected", width: 64, render: (value: number) => {value ?? 0}, }, { title: ( 查阅 ), dataIndex: "hits", width: 64, render: (value: number) => {value ?? 0}, }, { title: "操作", key: "actions", width: 72, render: (_, record) => ( 共 {items.length} 条 } table={{ rowKey: "id", size: "small", loading, columns, dataSource: items, pagination: { defaultPageSize: 20, showSizeChanger: true }, }} empty={} /> ); }