style(web): translate the comments in the src/views directory into English

This commit is contained in:
zhaoying
2026-02-03 18:38:04 +08:00
parent a191e32f71
commit 9e195ea63b
155 changed files with 4169 additions and 586 deletions

View File

@@ -1,4 +1,15 @@
import { type FC, useEffect, useState, forwardRef, useImperativeHandle } from 'react'
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:34:23
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:34:23
*/
/**
* About Me Component
* Displays user summary, personality, and core values
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton } from 'antd';
@@ -12,6 +23,9 @@ import {
import type { AboutMeRef } from '../types'
/**
* User summary data
*/
interface Data {
user_summary: string;
personality: string;
@@ -30,6 +44,7 @@ const AboutMe = forwardRef<AboutMeRef>((_props, ref) => {
getData()
}, [id])
/** Fetch user summary data */
const getData = () => {
if (!id) return
setLoading(true)
@@ -41,7 +56,7 @@ const AboutMe = forwardRef<AboutMeRef>((_props, ref) => {
setLoading(false)
})
}
// 暴露给父组件的方法
/** Expose methods to parent component */
useImperativeHandle(ref, () => ({
getData,
}));

View File

@@ -1,16 +1,33 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:34:16
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:34:16
*/
import { type FC, useRef, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import ReactEcharts from 'echarts-for-react';
import Loading from '@/components/Empty/Loading'
import Empty from '@/components/Empty'
import RbCard from '@/components/RbCard/Card'
/**
* Props for ActivationMetricsPieCard component
* @property {Array<Record<string, string | number>>} chartData - Activation value distribution data
* @property {boolean} loading - Loading state
*/
interface ActivationMetricsPieCardProps {
chartData: Array<Record<string, string | number>>;
loading: boolean;
}
const Colors = ['#155EEF', '#FFB048', '#FF5D34']
/**
* ActivationMetricsPieCard Component
* Displays activation value distribution as a donut chart with legend
* Shows percentage distribution of different activation levels
*/
const ActivationMetricsPieCard: FC<ActivationMetricsPieCardProps> = ({ chartData, loading }) => {
const { t } = useTranslation()
const chartRef = useRef<ReactEcharts>(null);

View File

@@ -1,6 +1,20 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:34:10
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:34:10
*/
/**
* Card Component
* Reusable card wrapper with theme support
*/
import { type FC, type ReactNode } from 'react'
import clsx from 'clsx'
/**
* Component props
*/
interface CardProps {
title?: string;
children: ReactNode;

View File

@@ -1,10 +1,21 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:34:04
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:34:04
*/
/**
* Conversation Memory Component
* Displays RAG conversation memory content list
*/
import { type FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton } from 'antd';
import { Skeleton, List } from 'antd';
import RbCard from '@/components/RbCard/Card'
import Empty from '@/components/Empty';
import { List } from 'antd';
import Markdown from '@/components/Markdown'
import {
getRagContent
@@ -20,6 +31,7 @@ const ConversationMemory:FC = () => {
if (!id) return
getList()
}, [id])
/** Fetch conversation memory list */
const getList = () => {
if (!id) return
setLoading(true)

View File

@@ -1,10 +1,22 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:44
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:44
*/
import { type FC, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import ReactEcharts from 'echarts-for-react';
import Empty from '@/components/Empty'
import Loading from '@/components/Empty/Loading'
import type { Emotion } from '../pages/GraphDetail'
/**
* Props for EmotionLine component
* @property {Emotion[]} chartData - Emotion data over time
* @property {boolean} [loading] - Loading state
*/
interface EmotionLineProps {
chartData: Emotion[];
loading?: boolean;
@@ -12,6 +24,11 @@ interface EmotionLineProps {
const Colors = ['#369F21', '#155EEF', '#FF5D34']
/**
* EmotionLine Component
* Displays emotion intensity trends over time as a multi-line chart
* Shows different emotion types with smooth lines and area fills
*/
const EmotionLine: FC<EmotionLineProps> = ({ chartData, loading }) => {
const { t } = useTranslation()
const chartRef = useRef<ReactEcharts>(null);

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:39
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:39
*/
import { type FC, useEffect, useState, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -8,10 +14,22 @@ import Empty from '@/components/Empty'
import RbCard from '@/components/RbCard/Card'
import { getWordCloud } from '@/api/memory'
/**
* Tag list data structure
* @property {Array} keywords - List of keywords with emotion data
* @property {number} total_keywords - Total number of keywords
*/
interface TagList {
keywords: Array<{ keyword: string; frequency: number; emotion_type: string; avg_intensity: number; }>;
total_keywords: number;
}
/**
* EmotionTags Component
* Displays emotion-tagged keywords as a word cloud
* Each keyword is colored based on its associated emotion type
* Shows emotion statistics summary at the bottom
*/
const EmotionTags: FC = () => {
const { t } = useTranslation()
const { id } = useParams()
@@ -32,6 +50,11 @@ const EmotionTags: FC = () => {
})
}
/**
* Get color for emotion type
* @param {string} emotionType - Emotion type (joy, anger, sadness, etc.)
* @returns {string} Color hex code
*/
const getEmotionColor = (emotionType: string) => {
const colors: Record<string, string> = {
joy: '#52c41a',

View File

@@ -1,3 +1,14 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:30
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:30
*/
/**
* End User Profile Component
* Displays and manages end user profile information
*/
import { forwardRef, useImperativeHandle, useEffect, useState, useRef, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -11,6 +22,9 @@ import {
import EndUserProfileModal from './EndUserProfileModal'
import type { EndUser, EndUserProfileModalRef, EndUserProfileRef } from '../types'
/**
* Component props
*/
interface EndUserProfileProps {
onDataLoaded?: (data: { other_name?: string; id: string }) => void
}
@@ -27,6 +41,7 @@ const EndUserProfile = forwardRef<EndUserProfileRef, EndUserProfileProps>(({ onD
getData()
}, [id])
/** Fetch profile data */
const getData = () => {
if (!id) return
setLoading(true)
@@ -43,6 +58,7 @@ const EndUserProfile = forwardRef<EndUserProfileRef, EndUserProfileProps>(({ onD
setLoading(false)
})
}
/** Format profile items for display */
const formatItems = useCallback(() => {
return ['other_name', 'position', 'department', 'contact', 'phone', 'hire_date'].map(key => ({
key,
@@ -50,6 +66,7 @@ const EndUserProfile = forwardRef<EndUserProfileRef, EndUserProfileProps>(({ onD
children: key === 'hire_date' && data?.[key] ? dayjs(data[key as keyof EndUser]).format('YYYY-MM-DD') : String(data?.[key as keyof EndUser] || '-'),
}))
}, [data])
/** Open edit modal */
const handleEdit = () => {
if (!data) return
endUserProfileModalRef.current?.handleOpen(data)

View File

@@ -1,14 +1,28 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:21
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:21
*/
/**
* End User Profile Modal
* Modal for editing end user profile information
*/
import { forwardRef, useImperativeHandle, useState } from 'react';
import { Form, Input, App, DatePicker } from 'antd';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import type { EndUser, EndUserProfileModalRef } from '../types'
import RbModal from '@/components/RbModal'
import { updatedEndUserProfile, } from '@/api/memory'
import dayjs from 'dayjs';
const FormItem = Form.Item;
/**
* Component props
*/
interface EndUserProfileModalProps {
refresh: () => void;
}
@@ -24,13 +38,14 @@ const EndUserProfileModal = forwardRef<EndUserProfileModalRef, EndUserProfileMod
const values = Form.useWatch([], form);
// 封装取消方法,添加关闭弹窗逻辑
/** Close modal and reset form */
const handleClose = () => {
setVisible(false);
form.resetFields();
setLoading(false)
};
/** Open modal with user data */
const handleOpen = (user: EndUser) => {
form.setFieldsValue({
...user,
@@ -39,7 +54,7 @@ const EndUserProfileModal = forwardRef<EndUserProfileModalRef, EndUserProfileMod
});
setVisible(true);
};
// 封装保存方法,添加提交逻辑
/** Save profile changes */
const handleSave = () => {
form
.validateFields()
@@ -64,7 +79,7 @@ const EndUserProfileModal = forwardRef<EndUserProfileModalRef, EndUserProfileMod
});
}
// 暴露给父组件的方法
/** Expose methods to parent component */
useImperativeHandle(ref, () => ({
handleOpen,
handleClose

View File

@@ -1,4 +1,10 @@
import { forwardRef, useImperativeHandle, useState, useCallback } from 'react';
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:16
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:16
*/
import { forwardRef, useImperativeHandle, useState } from 'react';
import { useParams } from 'react-router-dom'
import { Descriptions, Skeleton } from 'antd';
import { useTranslation } from 'react-i18next';
@@ -9,6 +15,17 @@ import { formatDateTime } from '@/utils/format'
import type { ExplicitDetailModalRef, EpisodicMemory, SemanticMemory } from '../pages/ExplicitDetail'
/**
* Explicit memory detail data structure
* @property {string} memory_type - Type of memory (episodic or semantic)
* @property {string} title - Memory title
* @property {string} content - Memory content
* @property {string} emotion - Associated emotion
* @property {number} created_at - Creation timestamp
* @property {string} name - Memory name
* @property {string} core_definition - Core definition for semantic memory
* @property {string} detailed_notes - Detailed notes
*/
interface Data {
memory_type: 'episodic' | 'semantic';
title: string;
@@ -20,6 +37,12 @@ interface Data {
core_definition: string;
detailed_notes: string;
}
/**
* ExplicitDetailModal Component
* Modal dialog for displaying detailed information about explicit memories
* Shows different fields based on memory type (episodic vs semantic)
*/
const ExplicitDetailModal = forwardRef<ExplicitDetailModalRef>((_props, ref) => {
const { t } = useTranslation();
const { id } = useParams()
@@ -27,12 +50,18 @@ const ExplicitDetailModal = forwardRef<ExplicitDetailModalRef>((_props, ref) =>
const [loading, setLoading] = useState(false);
const [data, setData] = useState<Data>({} as Data)
// 封装取消方法,添加关闭弹窗逻辑
/**
* Close modal and reset data
*/
const handleClose = () => {
setVisible(false);
setData({} as Data)
};
/**
* Open modal and load memory details
* @param {EpisodicMemory | SemanticMemory} vo - Memory object
*/
const handleOpen = (vo: EpisodicMemory | SemanticMemory) => {
setLoading(true)
getExplicitMemoryDetails({
@@ -48,6 +77,11 @@ const ExplicitDetailModal = forwardRef<ExplicitDetailModalRef>((_props, ref) =>
})
};
/**
* Get color for emotion type
* @param {string} emotionType - Emotion type
* @returns {string} Color hex code
*/
const getEmotionColor = (emotionType: string) => {
const colors: Record<string, string> = {
joy: '#52c41a',
@@ -60,7 +94,9 @@ const ExplicitDetailModal = forwardRef<ExplicitDetailModalRef>((_props, ref) =>
return colors[emotionType] || '#8c8c8c'
}
// 暴露给父组件的方法
/**
* Expose methods to parent component
*/
useImperativeHandle(ref, () => ({
handleOpen,
}));

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:10
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:10
*/
import { forwardRef, useImperativeHandle, useState } from 'react';
import { useParams } from 'react-router-dom'
import { Form, Slider } from 'antd';
@@ -7,10 +13,19 @@ import RbModal from '@/components/RbModal'
import { forgetTrigger } from '@/api/memory'
import type { ForgetRefreshModalRef } from '../pages/ForgetDetail'
/**
* Props for ForgetRefreshModal component
* @property {Function} refresh - Callback function to refresh data
*/
interface ForgetRefreshModalProps {
refresh: (flag: boolean) => void;
}
/**
* ForgetRefreshModal Component
* Modal for triggering memory forgetting process with configurable parameters
* Allows setting max merge batch size and minimum days since access
*/
const ForgetRefreshModal = forwardRef<ForgetRefreshModalRef, ForgetRefreshModalProps>(({
refresh
}, ref) => {
@@ -21,18 +36,26 @@ const ForgetRefreshModal = forwardRef<ForgetRefreshModalRef, ForgetRefreshModalP
const [loading, setLoading] = useState(false)
const values = Form.useWatch([], form);
// 封装取消方法,添加关闭弹窗逻辑
/**
* Close modal and reset form
*/
const handleClose = () => {
setVisible(false);
form.resetFields();
setLoading(false)
};
/**
* Open modal and reset form
*/
const handleOpen = () => {
form.resetFields();
setVisible(true);
};
// 封装保存方法,添加提交逻辑
/**
* Submit form and trigger forget process
*/
const handleSave = () => {
if(!id) return
form
@@ -56,7 +79,9 @@ const ForgetRefreshModal = forwardRef<ForgetRefreshModalRef, ForgetRefreshModalP
});
}
// 暴露给父组件的方法
/**
* Expose methods to parent component
*/
useImperativeHandle(ref, () => ({
handleOpen,
handleClose

View File

@@ -1,13 +1,32 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:06
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:06
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Space, Progress } from 'antd';
import RbCard from '@/components/RbCard/Card'
import Empty from '@/components/Empty'
import {
getImplicitHabits,
} from '@/api/memory'
/**
* Habits item data structure
* @property {string} habit_description - Description of the habit
* @property {string} frequency_pattern - Frequency pattern
* @property {string} time_context - Time context
* @property {number} confidence_level - Confidence level percentage
* @property {string[]} supporting_summaries - Supporting summaries
* @property {string} first_observed - First observation date
* @property {string} last_observed - Last observation date
* @property {boolean} is_current - Whether habit is current
* @property {string[]} specific_examples - Specific examples
*/
interface HabitsItem {
habit_description: string;
frequency_pattern: string;
@@ -20,6 +39,11 @@ interface HabitsItem {
specific_examples: string[];
}
/**
* Habits Component
* Displays user habits with confidence levels and specific examples
* Shows habit descriptions, time context, and supporting evidence
*/
const Habits = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:33:01
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:33:01
*/
import { type FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -7,6 +13,14 @@ import ReactEcharts from 'echarts-for-react'
import Empty from '@/components/Empty'
import RbCard from '@/components/RbCard/Card'
import { getEmotionHealth } from '@/api/memory'
/**
* Health data structure
* @property {number} health_score - Overall health score
* @property {string} level - Health level
* @property {Object} dimensions - Health dimensions (positivity, stability, resilience)
* @property {Object} emotion_distribution - Distribution of emotions
* @property {string} time_range - Time range for analysis
*/
interface Health {
health_score: number;
level: string;
@@ -36,6 +50,12 @@ interface Health {
};
time_range: string;
}
/**
* Health Component
* Displays emotional health score with radar chart and dimension breakdowns
* Shows positivity rate, stability, and resilience metrics
*/
const Health: FC = () => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,16 +1,34 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:57
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:57
*/
import { type FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import ReactEcharts from 'echarts-for-react'
import Empty from '@/components/Empty'
import Loading from '@/components/Empty/Loading'
import type { Interaction } from '../pages/GraphDetail'
/**
* Props for InteractionBar component
* @property {Interaction[]} chartData - Interaction count data over time
* @property {boolean} [loading] - Loading state
*/
interface InteractionBarProps {
chartData: Interaction[];
loading?: boolean;
}
const Colors = ['#155EEF', '#369F21', '#FF5D34']
/**
* InteractionBar Component
* Displays user interaction counts over time as a bar chart
* Shows daily interaction frequency
*/
const InteractionBar: FC<InteractionBarProps> = ({ chartData, loading }) => {
const { t } = useTranslation()

View File

@@ -1,18 +1,43 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:53
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:53
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Progress } from 'antd';
import RbCard from '@/components/RbCard/Card'
import {
getImplicitInterestAreas,
} from '@/api/memory'
/**
* Interest category item structure
* @property {string} category_name - Category name
* @property {number} percentage - Interest percentage
* @property {string[]} evidence - Supporting evidence
* @property {string | null} trending_direction - Trending direction
*/
interface Item {
category_name: string;
percentage: number;
evidence: string[];
trending_direction: string | null;
}
/**
* Interest areas data structure
* @property {string} user_id - User ID
* @property {number | string} analysis_timestamp - Analysis timestamp
* @property {number} total_summaries_analyzed - Total summaries analyzed
* @property {Item} tech - Technology interest
* @property {Item} lifestyle - Lifestyle interest
* @property {Item} music - Music interest
* @property {Item} art - Art interest
*/
interface InterestAreasItem {
user_id: string;
analysis_timestamp: number | string;
@@ -23,6 +48,11 @@ interface InterestAreasItem {
art: Item;
}
/**
* InterestAreas Component
* Displays user interest distribution across different categories
* Shows percentage breakdown for art, music, tech, and lifestyle
*/
const InterestAreas = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,3 +1,14 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:47
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:47
*/
/**
* Interest Distribution Component
* Displays user interest distribution as pie chart with tag list
*/
import { type FC, useRef, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -9,6 +20,7 @@ import Empty from '@/components/Empty';
import Loading from '@/components/Empty/Loading';
import RbCard from '@/components/RbCard/Card';
/** Chart color palette */
const Colors = ['#155EEF', '#4DA8FF', '#03BDFF', '#31E8FF', '#AD88FF', '#FFB048']
const InterestDistribution: FC = () => {
@@ -23,6 +35,7 @@ const InterestDistribution: FC = () => {
useEffect(() => {
getData()
}, [id])
/** Fetch interest distribution data */
const getData = () => {
setLoading(true)
getHotMemoryTagsByUser(id as string).then(res => {

View File

@@ -1,8 +1,20 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:41
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:41
*/
/**
* Memory Insight Component
* Displays memory insights including behavior patterns, key findings, and growth trajectory
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import clsx from 'clsx'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Space } from 'antd';
import RbCard from '@/components/RbCard/Card'
import Empty from '@/components/Empty';
import {
@@ -10,6 +22,9 @@ import {
} from '@/api/memory'
import type { MemoryInsightRef } from '../types'
/**
* Insight data structure
*/
interface Data {
memory_insight?: string;
behavior_pattern?: string;
@@ -30,7 +45,7 @@ const MemoryInsight = forwardRef<MemoryInsightRef>((_props, ref) => {
getData()
}, [id])
// 记忆洞察
/** Fetch memory insight data */
const getData = () => {
if (!id) return
setLoading(true)
@@ -42,7 +57,7 @@ const MemoryInsight = forwardRef<MemoryInsightRef>((_props, ref) => {
setLoading(false)
})
}
// 暴露给父组件的方法
/** Expose methods to parent component */
useImperativeHandle(ref, () => ({
getData,
}));

View File

@@ -1,8 +1,20 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:35
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:35
*/
/**
* Node Statistics Component
* Displays memory node statistics by type with navigation to detail views
*/
import { type FC, useEffect, useState } from 'react'
import clsx from 'clsx'
import { useTranslation } from 'react-i18next'
import { useParams, useNavigate } from 'react-router-dom'
import { Skeleton } from 'antd';
import RbCard from '@/components/RbCard/Card'
import {
getNodeStatistics,
@@ -10,6 +22,7 @@ import {
import type { NodeStatisticsItem } from '../types'
/** Background gradient list */
const BG_LIST = [
'rb:bg-[linear-gradient(316deg,rgba(21,94,239,0.06)_0%,rgba(251,253,255,0)_100%)]',
'rb:bg-[linear-gradient(316deg,rgba(54,159,33,0.06)_0%,rgba(251,253,255,0)_100%)]',
@@ -18,6 +31,7 @@ const BG_LIST = [
'rb:bg-[linear-gradient(313deg,rgba(156,111,255,0.06)_0%,rgba(251,253,255,0)_100%)]',
'rb:bg-[linear-gradient(332deg,rgba(54,159,33,0.06)_0%,rgba(251,253,255,0)_100%)]',
]
/** Memory type configuration */
const typeList = [
{ key: 'PERCEPTUAL_MEMORY', bg: 0 },
{ key: 'WORKING_MEMORY', bg: 1 },
@@ -48,6 +62,7 @@ const NodeStatistics: FC = () => {
getData()
}, [id])
/** Fetch node statistics */
const getData = () => {
if (!id) return
setLoading(true)
@@ -63,9 +78,11 @@ const NodeStatistics: FC = () => {
setLoading(false)
})
}
/** Navigate to detail page */
const handleViewDetail = (type: string) => {
navigate(`/user-memory/detail/${id}/${type}`)
}
/** Render statistics card */
const renderCard = (key: string, bgIndex: number | null, isChild: boolean = false) => {
const item = data.find((item) => item.type === key)
return (

View File

@@ -1,11 +1,26 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:30
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:30
*/
/**
* Page Header Component
* Header with navigation and operation buttons
*/
import { type FC, type ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import { Layout, Space, Button } from 'antd';
import { Layout, Button } from 'antd';
import { useTranslation } from 'react-i18next';
import logoutIcon from '@/assets/images/logout_hover.svg'
const { Header } = Layout;
/**
* Component props
*/
interface ConfigHeaderProps {
name?: string;
operation?: ReactNode;
@@ -21,6 +36,7 @@ const PageHeader: FC<ConfigHeaderProps> = ({
const { t } = useTranslation();
const navigate = useNavigate();
/** Navigate back */
const goBack = () => {
if (source === 'detail') {
navigate('/user-memory', { replace: true })

View File

@@ -1,7 +1,14 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:23
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:23
*/
import { type FC, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Space, Tooltip, Image } from 'antd';
import RbCard from '@/components/RbCard/Card'
import {
getPerceptualLastVisual,
@@ -9,6 +16,22 @@ import {
getPerceptualLastText,
} from '@/api/memory'
/**
* Perceptual last info item structure
* @property {string} id - Item ID
* @property {string} file_name - File name
* @property {string} file_ext - File extension
* @property {string} file_path - File path URL
* @property {number} storage_type - Storage type
* @property {string} summary - Content summary
* @property {string[]} keywords - Keywords
* @property {string} topic - Topic
* @property {string} domain - Domain
* @property {number | string} created_time - Creation time
* @property {string[]} scene - Scene information
* @property {number} speaker_count - Speaker count
* @property {number} section_count - Section count
*/
interface PerceptualLastInfoItem {
id: string;
file_name: string;
@@ -25,12 +48,20 @@ interface PerceptualLastInfoItem {
section_count: number;
}
/**
* Field keys for different perceptual types
*/
const KEYS = {
last_visual: ['summary', 'keywords', 'topic', 'domain', 'scene'],
last_listen: ['summary', 'keywords', 'topic', 'domain', 'speaker_count'],
last_text: ['summary', 'keywords', 'topic', 'domain', 'section_count'],
}
/**
* PerceptualLastInfo Component
* Displays the last perceptual memory (visual, audio, or text)
* Shows file preview and metadata based on perceptual type
*/
const PerceptualLastInfo: FC<{ type: 'last_visual' | 'last_listen' | 'last_text' }> = ({ type }) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,12 +1,27 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:18
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:18
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Progress } from 'antd';
import RbCard from '@/components/RbCard/Card'
import {
getImplicitPortrait,
} from '@/api/memory'
/**
* Portrait dimension item structure
* @property {string} dimension_name - Dimension name
* @property {number} percentage - Percentage value
* @property {string[]} evidence - Supporting evidence
* @property {string} reasoning - Reasoning
* @property {string} confidence_level - Confidence level
*/
interface Item {
dimension_name: string;
percentage: number;
@@ -14,6 +29,18 @@ interface Item {
reasoning: string;
confidence_level: string;
}
/**
* Portrait data structure
* @property {string} user_id - User ID
* @property {number | string} analysis_timestamp - Analysis timestamp
* @property {number} total_summaries_analyzed - Total summaries analyzed
* @property {null} historical_trends - Historical trends
* @property {Item} creativity - Creativity dimension
* @property {Item} aesthetic - Aesthetic dimension
* @property {Item} technology - Technology dimension
* @property {Item} literature - Literature dimension
*/
interface PortraitItem {
user_id: string;
analysis_timestamp: number | string;
@@ -25,6 +52,11 @@ interface PortraitItem {
literature: Item;
}
/**
* Portrait Component
* Displays user portrait analysis across multiple dimensions
* Shows aesthetic, creativity, literature, and technology percentages
*/
const Portrait = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:12
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:12
*/
import { useEffect, useState, useRef, useMemo, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -10,6 +16,17 @@ import RbCard from '@/components/RbCard/Card'
import { getImplicitPreferences } from '@/api/memory'
import detailEmpty from '@/assets/images/userMemory/detail_empty.png'
/**
* Preference item structure
* @property {string} tag_name - Tag name
* @property {number} confidence_score - Confidence score (0-1)
* @property {string[]} supporting_evidence - Supporting evidence
* @property {string} context_details - Context details
* @property {number | string} created_at - Creation timestamp
* @property {number | string} updated_at - Update timestamp
* @property {string[]} conversation_references - Conversation references
* @property {string} category - Category
*/
interface PreferenceItem {
tag_name: string;
confidence_score: number;
@@ -21,8 +38,16 @@ interface PreferenceItem {
category: string;
}
/**
* Default color palette for categories
*/
const DEFAULT_COLORS = ['#FF5D34', '#155EEF', '#9C6FFF', '#369F21', '#4DA8FF', '#FF8C00', '#32CD32', '#FF69B4', '#20B2AA', '#DDA0DD']
/**
* Generate color mapping for categories
* @param {string[]} categories - List of categories
* @returns {Record<string, string>} Category to color mapping
*/
const generateCategoryColors = (categories: string[]) => {
const colors: Record<string, string> = {}
categories.forEach((category, index) => {
@@ -31,6 +56,11 @@ const generateCategoryColors = (categories: string[]) => {
return colors
}
/**
* Preferences Component
* Displays user preferences as an interactive word cloud
* Shows detailed context and evidence when a word is selected
*/
const Preferences = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,11 +1,23 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:07
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:07
*/
import { type FC, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import ReactEcharts from 'echarts-for-react';
import * as echarts from 'echarts';
import Empty from '@/components/Empty'
import Loading from '@/components/Empty/Loading'
import RbCard from '@/components/RbCard/Card'
/**
* Props for RecentTrendsLineCard component
* @property {Array<Record<string, string | number>>} chartData - Trend data over time
* @property {string[]} seriesList - List of series keys to display
* @property {boolean} [loading] - Loading state
*/
interface RecentTrendsLineCardProps {
chartData: Array<Record<string, string | number>>;
seriesList: string[];
@@ -14,6 +26,11 @@ interface RecentTrendsLineCardProps {
const Colors = ['#155EEF', '#FF5D34']
/**
* RecentTrendsLineCard Component
* Displays forgetting trends with dual Y-axis line chart
* Shows merged count and average activation over time
*/
const RecentTrendsLineCard: FC<RecentTrendsLineCardProps> = ({ chartData, seriesList, loading }) => {
const { t } = useTranslation()
const chartRef = useRef<ReactEcharts>(null);

View File

@@ -1,11 +1,23 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:32:00
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:32:00
*/
/**
* Relationship Network Component
* Displays memory relationship graph with node details
* Interactive force-directed graph visualization
*/
import React, { type FC, useEffect, useState, useRef, useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams, useNavigate } from 'react-router-dom'
import { Col, Row, Space, Button } from 'antd'
import dayjs from 'dayjs'
import ReactEcharts from 'echarts-for-react'
import RbCard from '@/components/RbCard/Card'
import ReactEcharts from 'echarts-for-react'
import detailEmpty from '@/assets/images/userMemory/detail_empty.png'
import type { Node, Edge, GraphData, StatementNodeProperties, ExtractedEntityNodeProperties } from '../types'
import {
@@ -14,6 +26,7 @@ import {
import Empty from '@/components/Empty'
import Tag from '@/components/Tag'
/** Node color palette */
const colors = ['#155EEF', '#369F21', '#4DA8FF', '#FF5D34', '#9C6FFF', '#FF8A4C', '#8BAEF7', '#FFB048']
const RelationshipNetwork:FC = () => {
const { t } = useTranslation()
@@ -28,7 +41,7 @@ const RelationshipNetwork:FC = () => {
const navigate = useNavigate()
console.log('categories', categories)
// 关系网络
/** Fetch relationship network data */
const getEdgeData = useCallback(() => {
if (!id) return
setSelectedNode(null)
@@ -134,6 +147,7 @@ const RelationshipNetwork:FC = () => {
}
}, [nodes])
/** Navigate to full graph view */
const handleViewAll = () => {
if (!selectedNode) return
const params = new URLSearchParams({
@@ -343,5 +357,5 @@ const RelationshipNetwork:FC = () => {
</Row>
)
}
// 使用React.memo包装组件,避免不必要的渲染
/** Use React.memo to avoid unnecessary renders */
export default React.memo(RelationshipNetwork)

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:31:50
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:31:50
*/
import { useEffect, useState, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -8,6 +14,11 @@ import { getEmotionSuggestions } from '@/api/memory'
import RbAlert from '@/components/RbAlert'
/**
* Suggestions data structure
* @property {string} health_summary - Overall health summary
* @property {Array} suggestions - List of suggestions with actionable steps
*/
interface Suggestions {
health_summary: string;
suggestions: Array<{
@@ -18,6 +29,12 @@ interface Suggestions {
actionable_steps: string[];
}>;
}
/**
* Suggestions Component
* Displays emotional health suggestions with actionable steps
* Shows health summary and prioritized recommendations
*/
const Suggestions = forwardRef<{ handleRefresh: () => void; }>((_props, ref) => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,8 +1,14 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:31:36
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:31:36
*/
import { type FC, useEffect, useState } from 'react'
import clsx from 'clsx'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { Skeleton, Progress, Space, Tooltip, Divider } from 'antd';
import { Skeleton, Space, Divider } from 'antd';
import RbCard from '@/components/RbCard/Card'
import {
getPerceptualTimeline
@@ -11,6 +17,19 @@ import { formatDateTime } from '@/utils/format';
import Empty from '@/components/Empty'
import Tag from '@/components/Tag'
/**
* Timeline item structure
* @property {string} id - Item ID
* @property {number} perceptual_type - Perceptual type (1: visual, 2: audio, 3: text)
* @property {string} file_path - File path
* @property {string} file_name - File name
* @property {string} summary - Content summary
* @property {number} storage_type - Storage type
* @property {string | number} created_time - Creation time
* @property {string} domain - Domain
* @property {string} topic - Topic
* @property {string[]} keywords - Keywords
*/
interface TimelineItem {
id: string;
perceptual_type: number;
@@ -24,18 +43,20 @@ interface TimelineItem {
keywords: string[]
}
const KEYS = {
last_visual: ['summary', 'keywords', 'topic', 'domain', 'scene'],
last_listen: ['summary', 'keywords', 'topic', 'domain', 'speaker_count'],
last_text: ['summary', 'keywords', 'topic', 'domain', 'section_count'],
}
/**
* Perceptual type mapping
*/
const perceptual_type: Record<number, string> = {
1: 'last_visual',
2: 'last_listen',
3: 'last_text',
}
/**
* Timeline Component
* Displays chronological timeline of perceptual memories
* Shows visual, audio, and text memories with metadata
*/
const Timeline: FC = () => {
const { t } = useTranslation()
const { id } = useParams()

View File

@@ -1,3 +1,9 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 18:31:24
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 18:31:24
*/
import { type FC, useEffect, useState, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
@@ -8,6 +14,11 @@ import Empty from '@/components/Empty'
import RbCard from '@/components/RbCard/Card'
import { getEmotionTags } from '@/api/memory'
/**
* Word cloud data structure
* @property {Array} tags - Emotion tags with statistics
* @property {number} total_count - Total count of tags
*/
interface WordCloud {
tags: Array<{
emotion_type: string;
@@ -17,6 +28,12 @@ interface WordCloud {
}>;
total_count: number;
}
/**
* WordCloud Component
* Displays emotion distribution as radar chart with statistics
* Shows emotion types, counts, percentages, and average intensity
*/
const WordCloud: FC = () => {
const { t } = useTranslation()
const { id } = useParams()