diff --git a/web/src/api/common.ts b/web/src/api/common.ts index 7637ccd3..9a33fd9a 100644 --- a/web/src/api/common.ts +++ b/web/src/api/common.ts @@ -1 +1,33 @@ import { request } from "@/utils/request"; +// 列表查询参数 +export interface Query { + page?: number; + pagesize?: number; + orderby?: string; + desc?: boolean; + keywords?: string; + [key: string]: unknown; +} +export interface DataResponse { + total_models: Number; + total_llm: Number; + total_embedding: Number; + model_week_growth_rate: Number; + active_workspaces: Number; + new_workspaces_this_week: Number; + workspace_week_growth_rate: Number; + total_users: Number; + new_users_this_week: Number; + user_week_growth_rate: Number; + running_apps: Number; + new_apps_this_week: Number; + app_week_growth_rate: Number +} +// 首页数据统计 +export const getDashboardData = `/home-page/workspaces` + +// 首页数据看板统计 +export const getDashboardStatistics = async () => { + const response = await request.get(`/home-page/statistics`); + return response as DataResponse; +}; \ No newline at end of file diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 7f83e352..07f36071 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -9,6 +9,8 @@ export const en = { viewDetails: 'View Details', changeLog: 'Change Log', latestUpdate: 'Latest Update', + appCount: 'Number of Spaces', + userCount: 'Number of Users', latestUpdateDesc: 'Version v0.2.0 release: Added visual workflow editor, model performance monitoring panel, and multi tenant permission management system.', getStarted: 'Getting Started', startedDesc: 'Understand the core functions of the platform and quickly get started through graphic guidance and video tutorials. Includes a full process demonstration from creating a space to publishing an application.', @@ -95,11 +97,11 @@ export const en = { total_models: 'Total number of available models', total_spaces: 'Number of active spaces', total_users: 'Total number of users', - total_apps_runs: 'Number of application runs', + total_running_apps: 'Number of application runs', desc_models: 'Contains {{ account }} LLMs and {{ nums }} Embeddings', - desc_spaces: 'more than yesterday', + desc_spaces: 'more than last week', desc_users: 'New additions this week', - desc_apps_runs: "Today's success rate", + desc_running_apps: "Today's success rate", totalMemoryCapacity: 'Total Memory Capacity', userMemory: 'User Memory', knowledgeBaseCount: 'Knowledge Base Count', @@ -718,6 +720,7 @@ export const en = { graphTitle: 'Knowledge Graph: The Network of Entity, Relationship and Attribute Associations', graphTips: 'Explore the entity nodes in the knowledge base and their relationship networks', sourceDocuments: 'Source Documents', + rebuildGraph: 'Rebuild Graph', createForm:{ name: 'Name', embedding_id: 'Embedding', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index f261ba15..92fada41 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -10,6 +10,8 @@ export const zh = { changeLog: '变更日志', getStarted:'快速开始', latestUpdate: '最新更新', + appCount: '应用数量', + userCount: '用户数量', latestUpdateDesc: '版本 v0.2.0 发布:新增了可视化工作流编辑器、模型性能监控面板以及多租户权限管理系统。', startedDesc: '了解该平台的核心功能,并通过图形指引和视频教程快速上手。包含从创建空间到发布应用程序的整个操作流程演示。', spaceTitle:'记忆熊智能空间管理平台', @@ -330,6 +332,7 @@ export const zh = { sourceDocuments: '来源文档', graphTitle: '知识图谱:实体、关系与属性的关联网络', graphTips: '探索知识库中的实体节点及其关系脉络', + rebuildGraph: '重建图谱', createForm: { name: '名称', embedding_id: '嵌入模型', @@ -667,11 +670,11 @@ export const zh = { total_models: '可用模型总数', total_spaces: '活跃空间数量', total_users: '用户总数', - total_apps_runs: '应用运行次数', + total_running_apps: '应用运行次数', desc_models: '包含 {{ account }} 个大语言模型和 {{ nums }} 个嵌入模型', - desc_spaces: '比昨天多', + desc_spaces: '多于上周', desc_users: '本周新增', - desc_apps_runs: '今日成功率', + desc_running_apps: '今日成功率', totalMemoryCapacity: '总记忆容量', userMemory: '用户记忆', knowledgeBaseCount: '知识库数量', diff --git a/web/src/views/Index/components/TopCardList/index.tsx b/web/src/views/Index/components/TopCardList/index.tsx index 86973598..273ce936 100644 --- a/web/src/views/Index/components/TopCardList/index.tsx +++ b/web/src/views/Index/components/TopCardList/index.tsx @@ -9,7 +9,7 @@ import arrowDownDb from '@/assets/images/index/arrow_down_d.svg' import arrowUp from '@/assets/images/index/arrow_up.svg' import arrowDown from '@/assets/images/index/arrow_down.svg' import styles from './index.module.css' -import type { DashboardData } from '../../types' +import { type DataResponse } from '@/api/common' const list = [ { @@ -46,7 +46,7 @@ const list = [ background: 'linear-gradient( 136deg, rgba(77,168,255,0.06) 0%, rgba(251,253,255,0) 100%)', }, { - key: 'apps_runs', + key: 'running_apps', icon: totalApps, value: '12.8k', trendValue: '98.7%', @@ -57,7 +57,7 @@ const list = [ background: 'linear-gradient( 136deg, rgba(156,111,255,0.06) 0%, rgba(251,253,255,0) 100%)', }, ] -const TopCardList: FC<{data?: DashboardData}> = ({ data }) => { +const TopCardList: FC<{data?: DataResponse}> = ({ data }) => { const { t } = useTranslation() return (
@@ -76,30 +76,53 @@ const TopCardList: FC<{data?: DashboardData}> = ({ data }) => {
- {data?.[`total_${item.key}` as keyof DashboardData] || item.value || 0} + {item.key === 'spaces' && String(data?.active_workspaces)} + {item.key !== 'spaces' && String(data?.[`total_${item.key}` as keyof DataResponse] || item.value || 0)}
{item.key === 'models' ? (
- {t(`dashboard.${'desc_' + item.key}`, { account: 18, nums: 6 })} + {t(`dashboard.${'desc_' + item.key}`, { account: data?.total_llm, nums: data?.total_embedding })}
) : (<>
- - {item.trendValue} + {item.key === 'spaces' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_workspaces_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_workspaces_this_week || 0))} + )} + {item.key === 'users' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_users_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_users_this_week || 0))} + )} + {item.key === 'running_apps' && (<> + = 0 ? arrowUpDb : arrowDownDb} className='rb:size-3'/> + = 0 ? 'rb:text-[#369F21]' : 'rb:text-[#FF5D34]'}>{Number(data?.new_apps_this_week || 0) >= 0 ? '+' : '-'}{Math.abs(Number(data?.new_apps_this_week || 0))} + )} +
{t(`dashboard.${'desc_' + item.key}`)}
)}
-
- - {item.rateValue} - {(item.key === 'models' || item.key === 'users') && ({t('dashboard.thisWeek')})} - {item.key === 'apps_runs' && ({t('dashboard.failureRate')})} - {item.key === 'spaces' && ({t('dashboard.thisDay')})} -
+ + {item.key === 'models' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.model_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'spaces' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.workspace_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'users' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.user_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + {item.key === 'running_apps' && (
= 0 ? 'rb:text-[#369F21] rb:border-[#369F21] rb:bg-[rgba(54, 159, 33, 0.25)]' : 'rb:text-[#FF5D34] rb:border-[#FF5D34] rb:bg-[rgba(255, 93, 52, 0.25)]'}`}> + = 0 ? arrowUp : arrowDown} className='rb:size-3'/> + {Math.abs(Number(data?.app_week_growth_rate || 0))}% {t('dashboard.thisWeek')} +
)} + ) })} diff --git a/web/src/views/Index/index.tsx b/web/src/views/Index/index.tsx index 759bbed2..e6265d3b 100644 --- a/web/src/views/Index/index.tsx +++ b/web/src/views/Index/index.tsx @@ -1,59 +1,79 @@ import { useEffect, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; import { Row, Col, Space, Button } from 'antd'; import TopCardList from './components/TopCardList'; import GuideCard from './components/GuideCard'; import VersionCard from './components/VersionCard'; import QuickActions from './components/QuickActions'; import bgImg from '@/assets/images/index/index_bg@2x.png' -import type { DashboardData } from './types'; import Table, { type TableRef } from '@/components/Table' import type { ColumnsType } from 'antd/es/table'; import { formatDateTime } from '@/utils/format'; +import { + getDashboardData, + getDashboardStatistics, + type DataResponse } from '@/api/common'; +import { switchWorkspace } from '@/api/workspaces' const Index = () => { const { t } = useTranslation(); - const [dashboardData, setDashboardData] = useState({ - total_models: 24, - total_spaces: 156, - total_users: 1248, - total_apps_runs: '12.8k', - }); + const navigate = useNavigate() + const [dashboardData, setDashboardData] = useState(); const tableRef = useRef(null); - const tableApi = '/workspaces'; - const [loading, setLoading] = useState({ - knowledgeTypeDistribution: true, - }); - const [knowledgeTypeDistribution, setKnowledgeTypeDistribution] = useState>([]); - const [memoryIncrement, setMemoryIncrement] = useState>([]); - const [limit, setLimit] = useState(7); + const tableApi = getDashboardData; + const getDashboardCount = async () => { + try{ + const res = await getDashboardStatistics(); + setDashboardData(res); + }catch(e) { + console.log(e) + } + } + const handleJump = (id: string) => { + switchWorkspace(id) + .then(() => { + localStorage.removeItem('user') + navigate('/') + }) + } const columns: ColumnsType = [ { title: t('space.spaceName'), dataIndex: 'name', key: 'name', }, - // { - // title: t('space.associated') + ' ' + t('memorySummary.user'), - // dataIndex: 'name', - // key: 'name', - // }, + { title: t('space.spaceIcon'), dataIndex: 'icon', key: 'icon', - render:(value:string) => { - return( + render:(value: string, record: any) => { + return value ? ( icon + ) : ( +
+ {record.name?.charAt(0)?.toUpperCase() || '?'} +
) } }, + { + title: t('index.appCount'), + dataIndex: 'app_count', + key: 'app_count', + }, + { + title: t('index.userCount'), + dataIndex: 'user_count', + key: 'user_count', + }, { title: t('apiKey.createdAt'), dataIndex: 'created_at', key: 'created_at', render:(value:string) => { return( - {formatDateTime(Number(value) * 1000 ,'YYYY-MM-DD HH:mm:ss')} + {formatDateTime(Number(value) ,'YYYY-MM-DD HH:mm:ss')} ) } }, @@ -64,16 +84,18 @@ const Index = () => { width: 100, render: (_, record) => ( - + ), }, ] - // 模拟API获取数据 + useEffect(() => { tableRef.current?.loadData(); }, [tableApi]); - + useEffect(() => { + getDashboardCount(); + }, []) return ( diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx index 65ca05e8..d6d5ee4f 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx @@ -400,7 +400,7 @@ const Private: FC = () => { graphrag: { use_graphrag: false, scene_name: '', - entity_types: '', + entity_types: [], method: '', resolution: false, community: false @@ -725,7 +725,10 @@ const Private: FC = () => {
{isGraph ? ( - + modalRef.current?.handleOpen(knowledgeBase, 'rebuild')} + /> ) : ( (({ const [loading, setLoading] = useState(false); const [activeTab, setActiveTab] = useState('basic'); const [generatingEntityTypes, setGeneratingEntityTypes] = useState(false); + const [isRebuildMode, setIsRebuildMode] = useState(false); // 监听 parser_config.graphrag 相关字段的变化 const parserConfig = Form.useWatch('parser_config', form); @@ -45,6 +46,7 @@ const CreateModal = forwardRef(({ form.resetFields(); setLoading(false); setActiveTab('basic'); + setIsRebuildMode(false); // 重置重建模式标识 setVisible(false); }; @@ -224,6 +226,15 @@ const CreateModal = forwardRef(({ setDatasets(record || null); const nextType = type || currentType; setCurrentType(nextType as any); + setIsRebuildMode(type === 'rebuild'); // 设置重建模式标识 + + // 如果是重建模式,默认切换到知识图谱标签页 + if (type === 'rebuild') { + setActiveTab('knowledgeGraph'); + } else { + setActiveTab('basic'); + } + setBaseFields(record || null, nextType); getTypeList(record || null); setVisible(true); @@ -320,6 +331,9 @@ const CreateModal = forwardRef(({ // 根据 type 获取标题 const getTitle = () => { + if (isRebuildMode) { + return t('knowledgeBase.rebuildGraph') + ' - ' + (datasets?.name || ''); + } if (datasets?.id) { return t('knowledgeBase.edit') + ' ' + datasets.name; } diff --git a/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx b/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx index 1e05554a..a485bacc 100644 --- a/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx +++ b/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx @@ -4,33 +4,40 @@ * @Author: yujiangping * @Date: 2025-12-30 15:07:37 * @LastEditors: yujiangping - * @LastEditTime: 2026-01-04 20:15:12 + * @LastEditTime: 2026-01-05 16:18:53 */ import React, { useState, useEffect } from 'react' import { useTranslation } from 'react-i18next'; -import { Row } from 'antd' +import { Button } from 'antd'; import KnowledgeGraph, { type KnowledgeGraphResponse } from './KnowledgeGraph' import { getKnowledgeGraph } from '@/api/knowledgeBase'; - +import { type KnowledgeBase } from '../types'; +import Empty from '@/components/Empty'; interface KnowledgeGraphCardProps { - knowledgeBaseId?: string; + knowledgeBase?: KnowledgeBase; + onRebuildGraph?: () => void; // 添加重建图谱的回调函数 } -const KnowledgeGraphCard: React.FC = ({ knowledgeBaseId }) => { +const KnowledgeGraphCard: React.FC = ({ knowledgeBase, onRebuildGraph }) => { const { t } = useTranslation(); const [data, setData] = useState() const [loading, setLoading] = useState(true) - + const handleRebuildGraph = () => { + // 调用父组件传递的回调函数来打开CreateModal并传递重建标识 + if (onRebuildGraph) { + onRebuildGraph(); + } + } useEffect(() => { const fetchData = async () => { - if (!knowledgeBaseId) { + if (!knowledgeBase?.id) { setLoading(false) return } setLoading(true) try { - const res = await getKnowledgeGraph(knowledgeBaseId) + const res = await getKnowledgeGraph(knowledgeBase?.id) setData(res as KnowledgeGraphResponse) } catch (error) { console.error('获取知识图谱数据失败:', error) @@ -40,23 +47,28 @@ const KnowledgeGraphCard: React.FC = ({ knowledgeBaseId } fetchData() - }, [knowledgeBaseId]) + }, [knowledgeBase?.id]) return ( -
-
+
+
{t('knowledgeBase.graphTitle')}
{t('knowledgeBase.graphTips')}
-
- +
+ + {knowledgeBase?.parser_config?.graphrag?.scene_name} + +
-
- +
+ {knowledgeBase?.parser_config?.graphrag?.use_graphrag ? () : }