import { type FC, useEffect, useState } from 'react' import clsx from 'clsx' import { useTranslation } from 'react-i18next' import { useParams } from 'react-router-dom' import { Row, Col, Select, Form, Space, Skeleton, Input } from 'antd' import RbCard from '@/components/RbCard/Card' import { getEpisodicOverview, getEpisodicDetail, } from '@/api/memory' import { formatDateTime } from '@/utils/format' import Tag from '@/components/Tag' import RbAlert from '@/components/RbAlert' import Empty from '@/components/Empty' interface EpisodicMemory { id: string; title: string; type: string; created_at: number; } interface EpisodicOverviewData { total: number; total_all: number; episodic_memories: EpisodicMemory[] } interface EpisodicMemoryDetail { id: string; created_at: number; involved_objects: string[]; episodic_type: string; content_records: string[]; emotion: string; } const TAG_COLORS: Record = { conversation: "processing", project_work: "success", learning: "warning", decision: "warning", important_event: "error", } const BG_COLORS: Record = { conversation: "rb:bg-[#155EEF]", project_work: "rb:bg-[#369F21]", learning: "rb:bg-[#FF5D34]", decision: "rb:bg-[#FF5D34]", important_event: "rb:bg-[#5B6167]", } // Map display types to internal keys const getTypeKey = (type: string): string => { const typeMap: Record = { 'Learning': 'learning', 'Project/Work': 'project_work', 'Conversation': 'conversation', 'Decision': 'decision', 'Important Event': 'important_event', } return typeMap[type] || type.toLowerCase().replace(/[^a-z0-9]/g, '_') } const EpisodicDetail: FC = () => { const { t } = useTranslation() const { id } = useParams() const [form] = Form.useForm() const [loading, setLoading] = useState(false) const [data, setData] = useState({} as EpisodicOverviewData) const values = Form.useWatch([], form) const [detailLoading, setDetailLoading] = useState(false) const [detail, setDetail] = useState(null) const [selected, setSelected] = useState(null) useEffect(() => { if (!id) return // getData() }, [id]) // 记忆洞察 const getData = () => { if (!id) return setLoading(true) setSelected(null) setDetail(null) getEpisodicOverview({ end_user_id: id, ...values }).then((res) => { const response = res as EpisodicOverviewData setData(response) if (response.episodic_memories.length > 0) { setSelected(response.episodic_memories[0]) } setLoading(false) }) .finally(() => { setLoading(false) }) } useEffect(() => { getData() }, [values]) useEffect(() => { getDetail() }, [selected]) const getDetail = () => { if (!selected || !selected.id) return setDetailLoading(true) getEpisodicDetail({ end_user_id: id as string, summary_id: selected.id }) .then(res => { setDetail(res as EpisodicMemoryDetail) }) .finally(() => { setDetailLoading(false) }) } return (
{t('episodicDetail.title')}
{data.total_all ?? 0}
{t(`episodicDetail.total_all`)}
{t('episodicDetail.curResult')} ({data.total || 0}{t('episodicDetail.unix')})} headerType="borderless" > {loading ? : !data.episodic_memories || data.episodic_memories.length === 0 ? : ( {data.episodic_memories.map((vo, index) => (
setSelected(vo)} >
{index + 1}
{vo.title} {t(`episodicDetail.${getTypeKey(vo.type)}`)}
{formatDateTime(vo.created_at)}
))}
) }
{detailLoading ? : !selected || !detail ? : (
{t('episodicDetail.created')}
{formatDateTime(detail.created_at)}
{t('episodicDetail.episodic_type')}
{detail.episodic_type}
{detail.involved_objects.length > 0 &&
{t('episodicDetail.involved_objects')}
{detail.involved_objects.map((vo, index) => {vo})} }
{t('episodicDetail.content_records')}
{detail.content_records.map((vo, index) =>
- {vo}
)}
{t('episodicDetail.emotion')}: {t(`statementDetail.${detail.emotion}`)}
) }
) } export default EpisodicDetail