feat(web): Home page ui upgrade
This commit is contained in:
@@ -136,3 +136,7 @@ export const getExperienceConfig = (share_token: string) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// Get workspace API call statistics
|
||||||
|
export const getWorkspaceApiStatistics = (data: { start_date: number; end_date: number; }) => {
|
||||||
|
return request.get(`/apps/workspace/api-statistics`, data)
|
||||||
|
}
|
||||||
@@ -33,90 +33,70 @@ export const useNavigationBreadcrumbs = (source: 'space' | 'manage' = 'manage')
|
|||||||
const currentPath = location.pathname;
|
const currentPath = location.pathname;
|
||||||
const menus = allMenus[source] || [];
|
const menus = allMenus[source] || [];
|
||||||
|
|
||||||
/** Find matching menu item and build key path */
|
const pathMatches = (pattern: string, path: string): boolean => {
|
||||||
const findMenuKeyPath = (menuList: any[], parentKeys: string[] = []): string[] | null => {
|
const normalized = pattern[0] !== '/' ? '/' + pattern : pattern;
|
||||||
let bestMatch: { path: string; parentId?: string; score: number } | null = null;
|
if (normalized === path) return true;
|
||||||
|
if (normalized.includes(':')) {
|
||||||
for (const menu of menuList) {
|
const regex = new RegExp('^' + normalized.replace(/:[\\w-]+/g, '[^/]+') + '$');
|
||||||
/** Check submenus */
|
return regex.test(path);
|
||||||
if (menu.subs && menu.subs.length > 0) {
|
|
||||||
const menuPath = menu.path ? (menu.path[0] !== '/' ? '/' + menu.path : menu.path) : '';
|
|
||||||
for (const sub of menu.subs) {
|
|
||||||
if (sub.path) {
|
|
||||||
const subPath = sub.path[0] !== '/' ? '/' + sub.path : sub.path;
|
|
||||||
|
|
||||||
/** Exact match has priority */
|
|
||||||
if (subPath === currentPath) {
|
|
||||||
return [sub.path, `${menu.id}`];
|
|
||||||
}
|
|
||||||
console.log('menuPath', menuPath)
|
|
||||||
/** Dynamic route matching */
|
|
||||||
if (subPath.includes(':')) {
|
|
||||||
/** Check if under parent menu */
|
|
||||||
if (menuPath && currentPath.startsWith(menuPath + '/')) {
|
|
||||||
const relativePath = currentPath.replace(menuPath, '');
|
|
||||||
const pathSegments = subPath.split('/');
|
|
||||||
const relativeSegments = relativePath.split('/');
|
|
||||||
if (pathSegments.length === relativeSegments.length) {
|
|
||||||
const pathPattern = subPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
||||||
const regex = new RegExp(`^${pathPattern}$`);
|
|
||||||
if (regex.test(relativePath)) {
|
|
||||||
return [sub.path, `${menu.id}`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** Direct match submenu path */
|
|
||||||
const pathSegments = subPath.split('/');
|
|
||||||
const currentSegments = currentPath.split('/');
|
|
||||||
if (pathSegments.length === currentSegments.length) {
|
|
||||||
const pathPattern = subPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
||||||
const regex = new RegExp(`^${pathPattern}$`);
|
|
||||||
if (regex.test(currentPath)) {
|
|
||||||
return [sub.path, `${menu.id}`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check main menu */
|
|
||||||
if (menu.path) {
|
|
||||||
const menuPath = menu.path[0] !== '/' ? '/' + menu.path : menu.path;
|
|
||||||
/** Exact match has priority */
|
|
||||||
if (menuPath === currentPath) {
|
|
||||||
return [menu.path, ...parentKeys].reverse();
|
|
||||||
}
|
|
||||||
/** Dynamic route matching */
|
|
||||||
if (menuPath.includes(':')) {
|
|
||||||
const pathSegments = menuPath.split('/');
|
|
||||||
const currentSegments = currentPath.split('/');
|
|
||||||
if (pathSegments.length === currentSegments.length) {
|
|
||||||
const pathPattern = menuPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
||||||
const regex = new RegExp(`^${pathPattern}$`);
|
|
||||||
if (regex.test(currentPath)) {
|
|
||||||
const score = menuPath.split('/').length;
|
|
||||||
if (!bestMatch || score > bestMatch.score) {
|
|
||||||
bestMatch = { path: menu.path, score };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (currentPath.startsWith(menuPath + '/')) {
|
|
||||||
const score = menuPath.split('/').length;
|
|
||||||
if (!bestMatch || score > bestMatch.score) {
|
|
||||||
bestMatch = { path: menu.path, score };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
if (bestMatch) {
|
/**
|
||||||
return bestMatch.parentId ? [bestMatch.path, bestMatch.parentId] : [bestMatch.path];
|
* Recursively search menu tree, returns keyPath or null.
|
||||||
|
* keyPath format:
|
||||||
|
* - 1-level: [path]
|
||||||
|
* - 2-level: [subPath, parentId]
|
||||||
|
* - 3-level: [subSubPath, subId, parentId]
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* parentId: the group's id when recursing into group subs
|
||||||
|
* keyPath format:
|
||||||
|
* - 1-level: [path]
|
||||||
|
* - 2-level: [subPath, parentId]
|
||||||
|
* - 3-level: [subSubPath, subId, parentId]
|
||||||
|
*/
|
||||||
|
const findKeyPath = (menuList: any[], groupId?: string): string[] | null => {
|
||||||
|
for (const menu of menuList) {
|
||||||
|
/** Group menus: recurse into subs, passing group id */
|
||||||
|
if (menu.type === 'group' && menu.subs?.length) {
|
||||||
|
const result = findKeyPath(menu.subs, `${menu.id}`);
|
||||||
|
if (result) return result;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu.subs?.length) {
|
||||||
|
for (const sub of menu.subs) {
|
||||||
|
/** Check third-level subs */
|
||||||
|
if (sub.subs?.length) {
|
||||||
|
for (const subSub of sub.subs) {
|
||||||
|
if (subSub.path && pathMatches(subSub.path, currentPath)) {
|
||||||
|
return [subSub.path, `${sub.id}`, `${menu.id}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Second-level match: sub is a leaf under menu */
|
||||||
|
if (sub.path && pathMatches(sub.path, currentPath)) {
|
||||||
|
/** If menu is inside a group, return 3-level: [subPath, menuId, groupId] */
|
||||||
|
return groupId
|
||||||
|
? [sub.path, `${menu.id}`, groupId]
|
||||||
|
: [sub.path, `${menu.id}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** First-level / group-child match */
|
||||||
|
if (menu.path && pathMatches(menu.path, currentPath)) {
|
||||||
|
return groupId ? [menu.path, groupId] : [menu.path];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const keyPath = findMenuKeyPath(menus);
|
const keyPath = findKeyPath(menus);
|
||||||
|
|
||||||
|
console.log('keyPath', keyPath)
|
||||||
if (keyPath) {
|
if (keyPath) {
|
||||||
updateBreadcrumbs(keyPath, source);
|
updateBreadcrumbs(keyPath, source);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ export const en = {
|
|||||||
ontology: 'Ontology Engineering',
|
ontology: 'Ontology Engineering',
|
||||||
prompt: 'Prompt Engineering',
|
prompt: 'Prompt Engineering',
|
||||||
skills: 'Skill Library',
|
skills: 'Skill Library',
|
||||||
|
workbench: 'Workbench',
|
||||||
|
memoryRelated: 'Memory-Related',
|
||||||
|
advancedSettings: 'Advanced Settings',
|
||||||
|
promptHistory: 'My history',
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
total_models: 'Available Models',
|
total_models: 'Available Models',
|
||||||
@@ -185,19 +189,14 @@ export const en = {
|
|||||||
|
|
||||||
extractMemoryContent: 'Extract Memory Content',
|
extractMemoryContent: 'Extract Memory Content',
|
||||||
createNewMemorySummary: 'Create New Memory Entry',
|
createNewMemorySummary: 'Create New Memory Entry',
|
||||||
|
|
||||||
createNewApplication: 'Create New Application',
|
createNewApplication: 'Create New Application',
|
||||||
createNewApplicationDesc: 'Build an app in just 3 minutes with zero-code drag-and-drop.',
|
createNewApplicationDesc: 'Build an app in 3 minutes, no code.',
|
||||||
|
|
||||||
createNewKnowledge: 'Create New Knowledge',
|
createNewKnowledge: 'Create New Knowledge',
|
||||||
createNewKnowledgeDesc: 'Transform your data into a fully searchable, dedicated knowledge base in seconds.',
|
createNewKnowledgeDesc: 'Create a searchable knowledge base instantly.',
|
||||||
|
|
||||||
memoryConversation: 'Memory Conversation',
|
memoryConversation: 'Memory Conversation',
|
||||||
memoryConversationDesc: 'The more you use it, the better AI understands you.',
|
memoryConversationDesc: 'The more you use it, the better AI knows you.',
|
||||||
helpCenter: 'Help Center',
|
helpCenter: 'Help Center',
|
||||||
helpCenterDesc: 'One-stop support to answer your questions and get you started fast.',
|
helpCenterDesc: 'One place to get help and start fast.',
|
||||||
memorySummary: 'View Memory Summary',
|
|
||||||
memorySummaryDesc: 'View Memory Summary Report',
|
|
||||||
|
|
||||||
activityEmpty: 'There is currently no memory activity',
|
activityEmpty: 'There is currently no memory activity',
|
||||||
tagEmpty: 'There are no tag records at the moment~',
|
tagEmpty: 'There are no tag records at the moment~',
|
||||||
@@ -214,7 +213,12 @@ export const en = {
|
|||||||
dialogue: 'Dialogue',
|
dialogue: 'Dialogue',
|
||||||
chunk: 'Chunk',
|
chunk: 'Chunk',
|
||||||
statement: 'Statement',
|
statement: 'Statement',
|
||||||
entity: 'Entity'
|
entity: 'Entity',
|
||||||
|
|
||||||
|
apiCallTrends: 'Api Call Trends',
|
||||||
|
total_calls: 'Total API Calls',
|
||||||
|
app_calls: 'Application API Calls',
|
||||||
|
service_calls: 'Service API Calls',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
totalRecords: 'Total {{total}} Articles'
|
totalRecords: 'Total {{total}} Articles'
|
||||||
@@ -1041,7 +1045,7 @@ export const en = {
|
|||||||
forgetting_interval_hours: 'Forgetting Interval Hours'
|
forgetting_interval_hours: 'Forgetting Interval Hours'
|
||||||
},
|
},
|
||||||
application: {
|
application: {
|
||||||
searchPlaceholder: 'Search for applications or clusters',
|
searchPlaceholder: 'Search for applications',
|
||||||
createApplication: 'Create Application',
|
createApplication: 'Create Application',
|
||||||
type: 'Type',
|
type: 'Type',
|
||||||
source: 'Source',
|
source: 'Source',
|
||||||
@@ -1052,6 +1056,7 @@ export const en = {
|
|||||||
applicationName: 'Application Name',
|
applicationName: 'Application Name',
|
||||||
applicationIcon: 'Application Icon',
|
applicationIcon: 'Application Icon',
|
||||||
applicationType: 'Application Type',
|
applicationType: 'Application Type',
|
||||||
|
allType: 'All types',
|
||||||
|
|
||||||
agent: 'Agent',
|
agent: 'Agent',
|
||||||
agentDesc: 'Create a single intelligent agent',
|
agentDesc: 'Create a single intelligent agent',
|
||||||
@@ -1117,6 +1122,7 @@ export const en = {
|
|||||||
dialogueHistoricalMemory: 'Conversation History Memory',
|
dialogueHistoricalMemory: 'Conversation History Memory',
|
||||||
dialogueHistoricalMemoryDesc: 'Enable this to select memory content from memory management.',
|
dialogueHistoricalMemoryDesc: 'Enable this to select memory content from memory management.',
|
||||||
toolConfiguration: 'Tool Configuration',
|
toolConfiguration: 'Tool Configuration',
|
||||||
|
toolManagement: 'Tool Management',
|
||||||
webSearch: 'Web Search',
|
webSearch: 'Web Search',
|
||||||
webSearchDesc: 'Allow the Agent to access the Internet for real-time search',
|
webSearchDesc: 'Allow the Agent to access the Internet for real-time search',
|
||||||
codeExecutor: 'Code Executor',
|
codeExecutor: 'Code Executor',
|
||||||
@@ -1126,8 +1132,8 @@ export const en = {
|
|||||||
variableConfiguration: 'Variable Configuration',
|
variableConfiguration: 'Variable Configuration',
|
||||||
selectMemoryContent: 'Select Memory Content',
|
selectMemoryContent: 'Select Memory Content',
|
||||||
selectMemoryContentDesc: 'From Memory Management Select the memory content to be used in the conversation',
|
selectMemoryContentDesc: 'From Memory Management Select the memory content to be used in the conversation',
|
||||||
VariableManagement: 'Variable Management',
|
variableManagement: 'Variable Management',
|
||||||
VariableManagementDesc: 'Configure the available variables for the Agent',
|
variableManagementDesc: 'Configure the available variables for the Agent',
|
||||||
addVariables: 'Add Variables',
|
addVariables: 'Add Variables',
|
||||||
variablesEmpty: 'There are currently no variables available',
|
variablesEmpty: 'There are currently no variables available',
|
||||||
debuggingEmpty: 'No models available for debugging.',
|
debuggingEmpty: 'No models available for debugging.',
|
||||||
@@ -1172,7 +1178,7 @@ export const en = {
|
|||||||
VersionInformation: 'Version Information',
|
VersionInformation: 'Version Information',
|
||||||
publishedOn: 'Published on',
|
publishedOn: 'Published on',
|
||||||
publisher: 'Published by',
|
publisher: 'Published by',
|
||||||
DetailsOfVersion: 'Version Details: {{version}}',
|
detailsOfVersion: 'Version Details: {{version}}',
|
||||||
exportDSLFile: 'Export DSL file',
|
exportDSLFile: 'Export DSL file',
|
||||||
willRollToThisVersion: 'Will roll to this version',
|
willRollToThisVersion: 'Will roll to this version',
|
||||||
share: 'Share',
|
share: 'Share',
|
||||||
@@ -1371,6 +1377,7 @@ export const en = {
|
|||||||
gotoDetail: 'View Details',
|
gotoDetail: 'View Details',
|
||||||
dify: 'Dify',
|
dify: 'Dify',
|
||||||
pleaseUploadFile: 'Please upload workflow file',
|
pleaseUploadFile: 'Please upload workflow file',
|
||||||
|
promptOptimizationEmpty: 'The prompt words for conversation optimization will be displayed here',
|
||||||
},
|
},
|
||||||
userMemory: {
|
userMemory: {
|
||||||
userMemory: 'User Memory',
|
userMemory: 'User Memory',
|
||||||
@@ -1970,10 +1977,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
answer: 'Answer',
|
answer: 'Answer',
|
||||||
aiAndCognitiveProcessing: 'AI & Cognitive Processing',
|
aiAndCognitiveProcessing: 'AI & Cognitive Processing',
|
||||||
llm: 'Large Language Model (LLM)',
|
llm: 'Large Language Model (LLM)',
|
||||||
model_selection: 'Multi-Model Selection',
|
|
||||||
model_voting: 'Multi-Model Voting',
|
|
||||||
'knowledge-retrieval': 'Knowledge Retrieval (RAG)',
|
'knowledge-retrieval': 'Knowledge Retrieval (RAG)',
|
||||||
classification: 'Intelligent Classification',
|
|
||||||
'parameter-extractor': 'Parameter Extraction',
|
'parameter-extractor': 'Parameter Extraction',
|
||||||
flowControl: 'Flow Control',
|
flowControl: 'Flow Control',
|
||||||
'if-else': 'Conditional Branch',
|
'if-else': 'Conditional Branch',
|
||||||
@@ -1983,7 +1987,6 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
'cycle-start': '',
|
'cycle-start': '',
|
||||||
break: 'Break Loop',
|
break: 'Break Loop',
|
||||||
assigner: 'Variable Assignment',
|
assigner: 'Variable Assignment',
|
||||||
parallel: 'Parallel Execution',
|
|
||||||
'var-aggregator': 'Variable Aggregator',
|
'var-aggregator': 'Variable Aggregator',
|
||||||
externalInteraction: 'External Interaction',
|
externalInteraction: 'External Interaction',
|
||||||
"http-request": 'HTTP Request',
|
"http-request": 'HTTP Request',
|
||||||
@@ -1993,20 +1996,6 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
cognitiveUpgrading: 'Cognitive Upgrading (Innovation)',
|
cognitiveUpgrading: 'Cognitive Upgrading (Innovation)',
|
||||||
'memory-read': 'Memory Retrieval',
|
'memory-read': 'Memory Retrieval',
|
||||||
'memory-write': 'Memory Storage',
|
'memory-write': 'Memory Storage',
|
||||||
task_planning: 'Task Planning',
|
|
||||||
reasoning_control: 'Reasoning Control',
|
|
||||||
self_reflection: 'Self Reflection',
|
|
||||||
memory_enhancement: 'Memory Enhancement',
|
|
||||||
agentCollaborationNode: 'Agent Collaboration Nodes',
|
|
||||||
agent_scheduling: 'Agent Scheduling',
|
|
||||||
agent_collaboration: 'Agent Collaboration',
|
|
||||||
agent_arbitration: 'Agent Arbitration',
|
|
||||||
safetyAndCompliance: 'Safety & Compliance',
|
|
||||||
sensitive_detection: 'Sensitive Detection',
|
|
||||||
output_audit: 'Output Audit',
|
|
||||||
evolutionAndGovernance: 'Evolution & Governance',
|
|
||||||
self_optimization: 'Self Optimization',
|
|
||||||
process_evolution: 'Process Evolution',
|
|
||||||
unknown: 'Unknown Node',
|
unknown: 'Unknown Node',
|
||||||
|
|
||||||
clickToConfigure: 'Click to configure node parameters',
|
clickToConfigure: 'Click to configure node parameters',
|
||||||
@@ -2029,6 +2018,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
inner: 'Built-in',
|
inner: 'Built-in',
|
||||||
messagesPlaceholder: 'Write prompts here, type "{" to insert variables, type "insert" to insert',
|
messagesPlaceholder: 'Write prompts here, type "{" to insert variables, type "insert" to insert',
|
||||||
vision: 'Vision',
|
vision: 'Vision',
|
||||||
|
parameterSettings: 'Parameter Settings',
|
||||||
},
|
},
|
||||||
start: {
|
start: {
|
||||||
variables: 'Input Fields',
|
variables: 'Input Fields',
|
||||||
@@ -2115,7 +2105,9 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
"eq": 'Is',
|
"eq": 'Is',
|
||||||
"ne": 'Is Not',
|
"ne": 'Is Not',
|
||||||
},
|
},
|
||||||
else_desc: 'Used to define the logic that should be executed when the if condition is not met.'
|
else_desc: 'Used to define the logic that should be executed when the if condition is not met.',
|
||||||
|
unset: 'Condition Not Set',
|
||||||
|
set: 'Set',
|
||||||
},
|
},
|
||||||
'http-request': {
|
'http-request': {
|
||||||
auth: 'Authentication',
|
auth: 'Authentication',
|
||||||
@@ -2151,7 +2143,9 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
categories: 'Categories',
|
categories: 'Categories',
|
||||||
user_supplement_prompt: 'Instruction',
|
user_supplement_prompt: 'Instruction',
|
||||||
class_name: 'Classification',
|
class_name: 'Classification',
|
||||||
addClassName: 'Add Classification'
|
addClassName: 'Add Classification',
|
||||||
|
unset: 'Classification Not Set',
|
||||||
|
set: 'Set',
|
||||||
},
|
},
|
||||||
loop: {
|
loop: {
|
||||||
cycle_vars: 'Loop Variables',
|
cycle_vars: 'Loop Variables',
|
||||||
@@ -2640,8 +2634,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
|||||||
file: 'Import File',
|
file: 'Import File',
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
|
promptDesc: 'Input your original prompt, and AI will help you refine it into a more professional version',
|
||||||
|
chatTitle: 'Multi-turn dialogue',
|
||||||
editor: 'Prompt Generator',
|
editor: 'Prompt Generator',
|
||||||
history: 'My History',
|
history: 'My History',
|
||||||
|
historyDesc: 'View and manage your prompt optimization history',
|
||||||
historySearchPlaceholder: 'Search by name',
|
historySearchPlaceholder: 'Search by name',
|
||||||
model: 'Model',
|
model: 'Model',
|
||||||
you: 'You',
|
you: 'You',
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ export const zh = {
|
|||||||
ontology: '本体工程',
|
ontology: '本体工程',
|
||||||
prompt: '提示词工程',
|
prompt: '提示词工程',
|
||||||
skills: '技能库',
|
skills: '技能库',
|
||||||
|
workbench: '工作台',
|
||||||
|
memoryRelated: '记忆相关',
|
||||||
|
advancedSettings: '高级设置',
|
||||||
|
promptHistory: '我的历史',
|
||||||
},
|
},
|
||||||
knowledgeBase: {
|
knowledgeBase: {
|
||||||
home: '首页',
|
home: '首页',
|
||||||
@@ -427,7 +431,7 @@ export const zh = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
application: {
|
application: {
|
||||||
searchPlaceholder: '搜索应用或集群',
|
searchPlaceholder: '搜索应用',
|
||||||
createApplication: '创建应用',
|
createApplication: '创建应用',
|
||||||
type: '类型',
|
type: '类型',
|
||||||
source: '来源',
|
source: '来源',
|
||||||
@@ -438,6 +442,7 @@ export const zh = {
|
|||||||
applicationName: '应用名称',
|
applicationName: '应用名称',
|
||||||
applicationIcon: '应用图标',
|
applicationIcon: '应用图标',
|
||||||
applicationType: '应用类型',
|
applicationType: '应用类型',
|
||||||
|
allType: '全部类型',
|
||||||
|
|
||||||
agent: 'Agent',
|
agent: 'Agent',
|
||||||
agentDesc: '创建单个智能代理',
|
agentDesc: '创建单个智能代理',
|
||||||
@@ -502,6 +507,7 @@ export const zh = {
|
|||||||
dialogueHistoricalMemory: '对话历史记忆',
|
dialogueHistoricalMemory: '对话历史记忆',
|
||||||
dialogueHistoricalMemoryDesc: '激活后,可以选择记忆管理中的记忆内容',
|
dialogueHistoricalMemoryDesc: '激活后,可以选择记忆管理中的记忆内容',
|
||||||
toolConfiguration: '工具配置',
|
toolConfiguration: '工具配置',
|
||||||
|
toolManagement: '工具管理',
|
||||||
webSearch: '网络搜索',
|
webSearch: '网络搜索',
|
||||||
webSearchDesc: '允许Agent访问互联网进行实时搜索',
|
webSearchDesc: '允许Agent访问互联网进行实时搜索',
|
||||||
codeExecutor: '代码执行器',
|
codeExecutor: '代码执行器',
|
||||||
@@ -511,8 +517,8 @@ export const zh = {
|
|||||||
variableConfiguration: '变量配置',
|
variableConfiguration: '变量配置',
|
||||||
selectMemoryContent: '选择记忆内容',
|
selectMemoryContent: '选择记忆内容',
|
||||||
selectMemoryContentDesc: '从记忆管理中选择要在对话中使用的记忆内容',
|
selectMemoryContentDesc: '从记忆管理中选择要在对话中使用的记忆内容',
|
||||||
VariableManagement: '变量管理',
|
variableManagement: '变量管理',
|
||||||
VariableManagementDesc: '配置Agent可用的变量',
|
variableManagementDesc: '配置Agent可用的变量',
|
||||||
addVariables: '添加变量',
|
addVariables: '添加变量',
|
||||||
variablesEmpty: '目前没有可用的变量',
|
variablesEmpty: '目前没有可用的变量',
|
||||||
debuggingEmpty: '目前没有可用的调试模型',
|
debuggingEmpty: '目前没有可用的调试模型',
|
||||||
@@ -557,7 +563,7 @@ export const zh = {
|
|||||||
VersionInformation: '版本信息',
|
VersionInformation: '版本信息',
|
||||||
publishedOn: '发布于',
|
publishedOn: '发布于',
|
||||||
publisher: '发布者',
|
publisher: '发布者',
|
||||||
DetailsOfVersion: '{{version}}版本详情',
|
detailsOfVersion: '{{version}} 版本详情',
|
||||||
exportDSLFile: '导出DSL文件',
|
exportDSLFile: '导出DSL文件',
|
||||||
willRollToThisVersion: '将回滚到此版本',
|
willRollToThisVersion: '将回滚到此版本',
|
||||||
share: '分享',
|
share: '分享',
|
||||||
@@ -755,6 +761,7 @@ export const zh = {
|
|||||||
gotoDetail: '查看详情',
|
gotoDetail: '查看详情',
|
||||||
dify: 'Dify',
|
dify: 'Dify',
|
||||||
pleaseUploadFile: '请上传工作流文件',
|
pleaseUploadFile: '请上传工作流文件',
|
||||||
|
promptOptimizationEmpty: '对话优化提示词将显示在这里',
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
totalRecords: '共 {{total}} 条记录'
|
totalRecords: '共 {{total}} 条记录'
|
||||||
@@ -828,19 +835,14 @@ export const zh = {
|
|||||||
|
|
||||||
extractMemoryContent: '提取记忆内容',
|
extractMemoryContent: '提取记忆内容',
|
||||||
createNewMemorySummary: '创建新记忆条目',
|
createNewMemorySummary: '创建新记忆条目',
|
||||||
|
|
||||||
createNewApplication: '创建新应用',
|
createNewApplication: '创建新应用',
|
||||||
createNewApplicationDesc: '零代码拖拽3分钟创应用',
|
createNewApplicationDesc: '零代码,3 分钟搭建应用',
|
||||||
|
|
||||||
createNewKnowledge: '创建知识库',
|
createNewKnowledge: '创建知识库',
|
||||||
createNewKnowledgeDesc: '秒变可搜索的专属知识库',
|
createNewKnowledgeDesc: '秒级生成可搜索知识库',
|
||||||
|
|
||||||
memoryConversation: '记忆对话',
|
memoryConversation: '记忆对话',
|
||||||
memoryConversationDesc: '让AI越用越懂你',
|
memoryConversationDesc: '越用越懂你的 AI',
|
||||||
helpCenter: '帮助中心',
|
helpCenter: '帮助中心',
|
||||||
helpCenterDesc: '一站式解决疑问快速上手',
|
helpCenterDesc: '一站式上手与支持',
|
||||||
memorySummary: '查看记忆摘要',
|
|
||||||
memorySummaryDesc: '查看记忆摘要报告',
|
|
||||||
|
|
||||||
activityEmpty: '目前没有记忆活动',
|
activityEmpty: '目前没有记忆活动',
|
||||||
tagEmpty: '目前没有标签记录~',
|
tagEmpty: '目前没有标签记录~',
|
||||||
@@ -857,7 +859,12 @@ export const zh = {
|
|||||||
dialogue: '对话',
|
dialogue: '对话',
|
||||||
chunk: '分块',
|
chunk: '分块',
|
||||||
statement: '语句',
|
statement: '语句',
|
||||||
entity: '实体'
|
entity: '实体',
|
||||||
|
|
||||||
|
apiCallTrends: 'Api调用趋势',
|
||||||
|
total_calls: 'Api 总调用量',
|
||||||
|
app_calls: '应用Api调用量',
|
||||||
|
service_calls: '服务Api调用量',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
userInfo: '用户信息',
|
userInfo: '用户信息',
|
||||||
@@ -1966,10 +1973,7 @@ export const zh = {
|
|||||||
answer: '回复(Answer)',
|
answer: '回复(Answer)',
|
||||||
aiAndCognitiveProcessing: 'AI与认知处理',
|
aiAndCognitiveProcessing: 'AI与认知处理',
|
||||||
llm: '大语言模型 (LLM)',
|
llm: '大语言模型 (LLM)',
|
||||||
model_selection: '多模型选择',
|
|
||||||
model_voting: '多模型投票',
|
|
||||||
'knowledge-retrieval': '知识检索 (RAG)',
|
'knowledge-retrieval': '知识检索 (RAG)',
|
||||||
classification: '智能分类',
|
|
||||||
'parameter-extractor': '参数提取',
|
'parameter-extractor': '参数提取',
|
||||||
flowControl: '流程控制',
|
flowControl: '流程控制',
|
||||||
'if-else': '条件分支',
|
'if-else': '条件分支',
|
||||||
@@ -1979,7 +1983,6 @@ export const zh = {
|
|||||||
'cycle-start': '',
|
'cycle-start': '',
|
||||||
break: '退出循环',
|
break: '退出循环',
|
||||||
assigner: '变量赋值',
|
assigner: '变量赋值',
|
||||||
parallel: '并行执行',
|
|
||||||
'var-aggregator': '变量聚合器',
|
'var-aggregator': '变量聚合器',
|
||||||
externalInteraction: '外部交互',
|
externalInteraction: '外部交互',
|
||||||
"http-request": 'HTTP请求',
|
"http-request": 'HTTP请求',
|
||||||
@@ -1989,20 +1992,6 @@ export const zh = {
|
|||||||
cognitiveUpgrading: '认知升级(创新)',
|
cognitiveUpgrading: '认知升级(创新)',
|
||||||
'memory-read': '记忆提取',
|
'memory-read': '记忆提取',
|
||||||
'memory-write': '记忆储存',
|
'memory-write': '记忆储存',
|
||||||
task_planning: '任务规划',
|
|
||||||
reasoning_control: '推理控制',
|
|
||||||
self_reflection: '自我反思',
|
|
||||||
memory_enhancement: '记忆增强',
|
|
||||||
agentCollaborationNode: 'Agent 协作节点',
|
|
||||||
agent_scheduling: 'Agent 调度',
|
|
||||||
agent_collaboration: 'Agent 协同',
|
|
||||||
agent_arbitration: 'Agent 仲裁',
|
|
||||||
safetyAndCompliance: '安全与合规',
|
|
||||||
sensitive_detection: '敏感识别',
|
|
||||||
output_audit: '输出审计',
|
|
||||||
evolutionAndGovernance: '演化与治理',
|
|
||||||
self_optimization: '自我优化',
|
|
||||||
process_evolution: '流程演化',
|
|
||||||
unknown: '未知节点',
|
unknown: '未知节点',
|
||||||
|
|
||||||
clickToConfigure: '点击配置节点参数',
|
clickToConfigure: '点击配置节点参数',
|
||||||
@@ -2025,6 +2014,7 @@ export const zh = {
|
|||||||
inner: '内置',
|
inner: '内置',
|
||||||
messagesPlaceholder: '在此处编写提示,输入“{”插入变量,输入“insert”插入',
|
messagesPlaceholder: '在此处编写提示,输入“{”插入变量,输入“insert”插入',
|
||||||
vision: '视觉',
|
vision: '视觉',
|
||||||
|
parameterSettings: '参数设置',
|
||||||
},
|
},
|
||||||
start: {
|
start: {
|
||||||
variables: '输入字段',
|
variables: '输入字段',
|
||||||
@@ -2111,7 +2101,9 @@ export const zh = {
|
|||||||
"eq": '是',
|
"eq": '是',
|
||||||
"ne": '不是',
|
"ne": '不是',
|
||||||
},
|
},
|
||||||
else_desc: '用于定义当 if 条件不满足时应执行的逻辑。'
|
else_desc: '用于定义当 if 条件不满足时应执行的逻辑。',
|
||||||
|
unset: '条件未设置',
|
||||||
|
set: '已设置',
|
||||||
},
|
},
|
||||||
'http-request': {
|
'http-request': {
|
||||||
auth: '鉴权',
|
auth: '鉴权',
|
||||||
@@ -2147,7 +2139,9 @@ export const zh = {
|
|||||||
categories: '分类',
|
categories: '分类',
|
||||||
user_supplement_prompt: '指令',
|
user_supplement_prompt: '指令',
|
||||||
class_name: '分类',
|
class_name: '分类',
|
||||||
addClassName: '添加分类'
|
addClassName: '添加分类',
|
||||||
|
unset: '分类未设置',
|
||||||
|
set: '已设置',
|
||||||
},
|
},
|
||||||
loop: {
|
loop: {
|
||||||
cycle_vars: '循环变量',
|
cycle_vars: '循环变量',
|
||||||
@@ -2640,8 +2634,10 @@ export const zh = {
|
|||||||
file: '导入文件',
|
file: '导入文件',
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
|
promptDesc: 'Input your original prompt, and AI will help you refine it into a more professional version',
|
||||||
editor: '提示词生成器',
|
editor: '提示词生成器',
|
||||||
history: '我的历史',
|
history: '我的历史',
|
||||||
|
historyDesc: 'View and manage your prompt optimization history',
|
||||||
historySearchPlaceholder: '按名称搜索',
|
historySearchPlaceholder: '按名称搜索',
|
||||||
model: '模型',
|
model: '模型',
|
||||||
you: '你',
|
you: '你',
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ const componentMap: Record<string, LazyExoticComponent<ComponentType<object>>> =
|
|||||||
Ontology: lazy(() => import('@/views/Ontology')),
|
Ontology: lazy(() => import('@/views/Ontology')),
|
||||||
OntologyDetail: lazy(() => import('@/views/Ontology/pages/Detail')),
|
OntologyDetail: lazy(() => import('@/views/Ontology/pages/Detail')),
|
||||||
Prompt: lazy(() => import('@/views/Prompt')),
|
Prompt: lazy(() => import('@/views/Prompt')),
|
||||||
|
PromptHistory: lazy(() => import('@/views/Prompt/pages/History')),
|
||||||
Skills: lazy(() => import('@/views/Skills')),
|
Skills: lazy(() => import('@/views/Skills')),
|
||||||
SkillConfig: lazy(() => import('@/views/Skills/pages/SkillConfig')),
|
SkillConfig: lazy(() => import('@/views/Skills/pages/SkillConfig')),
|
||||||
Jump: lazy(() => import('@/views/JumpPage')),
|
Jump: lazy(() => import('@/views/JumpPage')),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
{ "path": "/space-config", "element": "SpaceConfig" },
|
{ "path": "/space-config", "element": "SpaceConfig" },
|
||||||
{ "path": "/ontology", "element": "Ontology" },
|
{ "path": "/ontology", "element": "Ontology" },
|
||||||
{ "path": "/prompt", "element": "Prompt" },
|
{ "path": "/prompt", "element": "Prompt" },
|
||||||
|
{ "path": "/prompt/history", "element": "PromptHistory" },
|
||||||
{ "path": "/no-permission", "element": "NoPermission" },
|
{ "path": "/no-permission", "element": "NoPermission" },
|
||||||
{ "path": "/*", "element": "NotFound" }
|
{ "path": "/*", "element": "NotFound" }
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -124,56 +124,40 @@
|
|||||||
],
|
],
|
||||||
"space": [
|
"space": [
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 1,
|
||||||
"parent": 0,
|
"parent": 0,
|
||||||
"code": "dashboard",
|
"code": "workbench",
|
||||||
"label": "记忆看板",
|
"label": "workbench",
|
||||||
"i18nKey": "menu.home",
|
"i18nKey": "menu.workbench",
|
||||||
"path": "/",
|
"path": "/",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": true,
|
"display": true,
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"subs": null
|
"type": "group",
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "application",
|
|
||||||
"label": "应用管理",
|
|
||||||
"i18nKey": "menu.applicationManagement",
|
|
||||||
"path": "/application",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "knowledge",
|
|
||||||
"label": "知识库",
|
|
||||||
"i18nKey": "menu.knowledgeManagement",
|
|
||||||
"path": "/knowledge-base",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": [
|
"subs": [
|
||||||
{
|
{
|
||||||
"id": 61,
|
"id": 11,
|
||||||
"parent": 6,
|
"parent": 1,
|
||||||
"code": "knowledgePrivate",
|
"code": "dashboard",
|
||||||
"label": "Private",
|
"label": "记忆看板",
|
||||||
"i18nKey": "menu.knowledgePrivate",
|
"i18nKey": "menu.home",
|
||||||
"path": "/knowledge-base/:knowledgeBaseId/private",
|
"path": "/",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": false,
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"parent": 1,
|
||||||
|
"code": "application",
|
||||||
|
"label": "应用管理",
|
||||||
|
"i18nKey": "menu.applicationManagement",
|
||||||
|
"path": "/application",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"icon": null,
|
"icon": null,
|
||||||
@@ -181,261 +165,338 @@
|
|||||||
"subs": null
|
"subs": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 62,
|
"id": 13,
|
||||||
"parent": 6,
|
"parent": 1,
|
||||||
"code": "knowledgeShare",
|
"code": "knowledge",
|
||||||
"label": "Share",
|
"label": "知识库",
|
||||||
"i18nKey": "menu.knowledgeShare",
|
"i18nKey": "menu.knowledgeManagement",
|
||||||
"path": "/knowledge-base/:knowledgeBaseId/share",
|
"path": "/knowledge-base",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": false,
|
"display": true,
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"icon": null,
|
"icon": null,
|
||||||
"iconActive": null,
|
"iconActive": null,
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 63,
|
|
||||||
"parent": 6,
|
|
||||||
"code": "knowledgeCreateDataset",
|
|
||||||
"label": "CreateDataset",
|
|
||||||
"i18nKey": "menu.knowledgeCreateDataset",
|
|
||||||
"path": "/knowledge-base/:knowledgeBaseId/create-dataset",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 64,
|
|
||||||
"parent": 6,
|
|
||||||
"code": "knowledgeDocumentDetails",
|
|
||||||
"label": "DocumentDetails",
|
|
||||||
"i18nKey": "menu.knowledgeDocumentDetails",
|
|
||||||
"path": "/knowledge-base/:knowledgeBaseId/DocumentDetails",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 7,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "memory",
|
|
||||||
"label": "记忆管理",
|
|
||||||
"i18nKey": "menu.memoryManagement",
|
|
||||||
"path": "/memory",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": [
|
|
||||||
{
|
|
||||||
"id": 71,
|
|
||||||
"parent": 7,
|
|
||||||
"code": "forgettingEngine",
|
|
||||||
"label": "遗忘引擎",
|
|
||||||
"i18nKey": "menu.forgettingEngine",
|
|
||||||
"path": "/forgetting-engine/:id",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 72,
|
|
||||||
"parent": 7,
|
|
||||||
"code": "memoryExtractionEngine",
|
|
||||||
"label": "记忆萃取引擎",
|
|
||||||
"i18nKey": "menu.memoryExtractionEngine",
|
|
||||||
"path": "/memory-extraction-engine/:id",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 72,
|
|
||||||
"parent": 7,
|
|
||||||
"code": "emotionEngine",
|
|
||||||
"label": "情感引擎",
|
|
||||||
"i18nKey": "menu.emotionEngine",
|
|
||||||
"path": "/emotion-engine/:id",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 72,
|
|
||||||
"parent": 7,
|
|
||||||
"code": "selfReflectionEngine",
|
|
||||||
"label": "反思引擎",
|
|
||||||
"i18nKey": "menu.selfReflectionEngine",
|
|
||||||
"path": "/reflection-engine/:id",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 8,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "userMemory",
|
|
||||||
"label": "",
|
|
||||||
"i18nKey": "menu.userMemory",
|
|
||||||
"path": "/user-memory",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 1,
|
|
||||||
"menuDesc": "管理用户记忆",
|
|
||||||
"subs": [
|
|
||||||
{
|
|
||||||
"id": 81,
|
|
||||||
"parent": 8,
|
|
||||||
"code": "userMemoryDetail",
|
|
||||||
"label": "记忆详情",
|
|
||||||
"i18nKey": "menu.userMemoryDetail",
|
|
||||||
"path": "/user-memory/neo4j/:id",
|
|
||||||
"enable": true,
|
|
||||||
"display": false,
|
|
||||||
"level": 2,
|
|
||||||
"sort": 0,
|
|
||||||
"subs": [
|
"subs": [
|
||||||
{
|
{
|
||||||
"id": 811,
|
"id": 131,
|
||||||
"parent": 81,
|
"parent": 13,
|
||||||
"code": "statementDetail",
|
"code": "knowledgePrivate",
|
||||||
"label": "记忆详情",
|
"label": "Private",
|
||||||
"i18nKey": "menu.statementDetail",
|
"i18nKey": "menu.knowledgePrivate",
|
||||||
"path": "/statement/:id",
|
"path": "/knowledge-base/:knowledgeBaseId/private",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 132,
|
||||||
|
"parent": 13,
|
||||||
|
"code": "knowledgeShare",
|
||||||
|
"label": "Share",
|
||||||
|
"i18nKey": "menu.knowledgeShare",
|
||||||
|
"path": "/knowledge-base/:knowledgeBaseId/share",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 133,
|
||||||
|
"parent": 13,
|
||||||
|
"code": "knowledgeCreateDataset",
|
||||||
|
"label": "CreateDataset",
|
||||||
|
"i18nKey": "menu.knowledgeCreateDataset",
|
||||||
|
"path": "/knowledge-base/:knowledgeBaseId/create-dataset",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 134,
|
||||||
|
"parent": 13,
|
||||||
|
"code": "knowledgeDocumentDetails",
|
||||||
|
"label": "DocumentDetails",
|
||||||
|
"i18nKey": "menu.knowledgeDocumentDetails",
|
||||||
|
"path": "/knowledge-base/:knowledgeBaseId/DocumentDetails",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"parent": 1,
|
||||||
|
"code": "prompt",
|
||||||
|
"label": "提示词",
|
||||||
|
"i18nKey": "menu.prompt",
|
||||||
|
"path": "/prompt",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": [
|
||||||
|
{
|
||||||
|
"id": 141,
|
||||||
|
"parent": 14,
|
||||||
|
"code": "promptHistory",
|
||||||
|
"label": "promptHistory",
|
||||||
|
"i18nKey": "menu.promptHistory",
|
||||||
|
"path": "/prompt/history",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": false,
|
"display": false,
|
||||||
"level": 3,
|
"level": 3,
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"parent": 0,
|
||||||
|
"code": "memoryRelated",
|
||||||
|
"label": "memoryRelated",
|
||||||
|
"i18nKey": "menu.memoryRelated",
|
||||||
|
"path": "/",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"type": "group",
|
||||||
|
"subs": [
|
||||||
|
{
|
||||||
|
"id": 21,
|
||||||
|
"parent": 2,
|
||||||
|
"code": "memory",
|
||||||
|
"label": "记忆管理",
|
||||||
|
"i18nKey": "menu.memoryManagement",
|
||||||
|
"path": "/memory",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": [
|
||||||
|
{
|
||||||
|
"id": 211,
|
||||||
|
"parent": 21,
|
||||||
|
"code": "forgettingEngine",
|
||||||
|
"label": "遗忘引擎",
|
||||||
|
"i18nKey": "menu.forgettingEngine",
|
||||||
|
"path": "/forgetting-engine/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 212,
|
||||||
|
"parent": 21,
|
||||||
|
"code": "memoryExtractionEngine",
|
||||||
|
"label": "记忆萃取引擎",
|
||||||
|
"i18nKey": "menu.memoryExtractionEngine",
|
||||||
|
"path": "/memory-extraction-engine/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 213,
|
||||||
|
"parent": 21,
|
||||||
|
"code": "emotionEngine",
|
||||||
|
"label": "情感引擎",
|
||||||
|
"i18nKey": "menu.emotionEngine",
|
||||||
|
"path": "/emotion-engine/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 214,
|
||||||
|
"parent": 21,
|
||||||
|
"code": "selfReflectionEngine",
|
||||||
|
"label": "反思引擎",
|
||||||
|
"i18nKey": "menu.selfReflectionEngine",
|
||||||
|
"path": "/reflection-engine/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
"subs": null
|
"subs": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 81,
|
"id": 22,
|
||||||
"parent": 8,
|
"parent": 2,
|
||||||
"code": "userMemoryDetail",
|
"code": "userMemory",
|
||||||
"label": "记忆详情",
|
"label": "",
|
||||||
"i18nKey": "menu.userMemoryDetail",
|
"i18nKey": "menu.userMemory",
|
||||||
"path": "/user-memory/:id",
|
"path": "/user-memory",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": false,
|
"display": true,
|
||||||
"level": 2,
|
"level": 1,
|
||||||
"sort": 0
|
"sort": 1,
|
||||||
|
"menuDesc": "管理用户记忆",
|
||||||
|
"subs": [
|
||||||
|
{
|
||||||
|
"id": 221,
|
||||||
|
"parent": 22,
|
||||||
|
"code": "userMemoryDetail",
|
||||||
|
"label": "记忆详情",
|
||||||
|
"i18nKey": "menu.userMemoryDetail",
|
||||||
|
"path": "/user-memory/neo4j/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 2,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": [
|
||||||
|
{
|
||||||
|
"id": 2211,
|
||||||
|
"parent": 221,
|
||||||
|
"code": "statementDetail",
|
||||||
|
"label": "记忆详情",
|
||||||
|
"i18nKey": "menu.statementDetail",
|
||||||
|
"path": "/statement/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 3,
|
||||||
|
"sort": 0,
|
||||||
|
"subs": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 222,
|
||||||
|
"parent": 22,
|
||||||
|
"code": "userMemoryDetail",
|
||||||
|
"label": "记忆详情",
|
||||||
|
"i18nKey": "menu.userMemoryDetail",
|
||||||
|
"path": "/user-memory/:id",
|
||||||
|
"enable": true,
|
||||||
|
"display": false,
|
||||||
|
"level": 2,
|
||||||
|
"sort": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 23,
|
||||||
|
"parent": 2,
|
||||||
|
"code": "ontology",
|
||||||
|
"label": "本体工程",
|
||||||
|
"i18nKey": "menu.ontology",
|
||||||
|
"path": "/ontology",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 24,
|
||||||
|
"parent": 2,
|
||||||
|
"code": "memoryConversation",
|
||||||
|
"label": "记忆验证",
|
||||||
|
"i18nKey": "menu.memoryConversation",
|
||||||
|
"path": "/memory-conversation",
|
||||||
|
"enable": true,
|
||||||
|
"display": true,
|
||||||
|
"level": 1,
|
||||||
|
"sort": 0,
|
||||||
|
"icon": null,
|
||||||
|
"iconActive": null,
|
||||||
|
"subs": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 21,
|
"id": 3,
|
||||||
"parent": 0,
|
"parent": 0,
|
||||||
"code": "ontology",
|
"code": "advancedSettings",
|
||||||
"label": "本体工程",
|
"label": "advancedSettings",
|
||||||
"i18nKey": "menu.ontology",
|
"i18nKey": "menu.advancedSettings",
|
||||||
"path": "/ontology",
|
"path": "/",
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"display": true,
|
"display": true,
|
||||||
"level": 1,
|
"level": 1,
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
"icon": null,
|
"type": "group",
|
||||||
"iconActive": null,
|
"subs": [
|
||||||
"subs": null
|
{
|
||||||
},
|
"id": 31,
|
||||||
{
|
"parent": 3,
|
||||||
"id": 10,
|
"code": "apiKey",
|
||||||
"parent": 0,
|
"label": "API KEY管理",
|
||||||
"code": "memoryConversation",
|
"i18nKey": "menu.apiKeyManagement",
|
||||||
"label": "记忆验证",
|
"path": "/api-key",
|
||||||
"i18nKey": "menu.memoryConversation",
|
"enable": true,
|
||||||
"path": "/memory-conversation",
|
"display": true,
|
||||||
"enable": true,
|
"level": 1,
|
||||||
"display": true,
|
"sort": 0,
|
||||||
"level": 1,
|
"icon": null,
|
||||||
"sort": 0,
|
"iconActive": null,
|
||||||
"icon": null,
|
"subs": null
|
||||||
"iconActive": null,
|
},
|
||||||
"subs": null
|
{
|
||||||
},
|
"id": 32,
|
||||||
{
|
"parent": 3,
|
||||||
"id": 11,
|
"code": "member",
|
||||||
"parent": 0,
|
"label": "成员管理",
|
||||||
"code": "apiKey",
|
"i18nKey": "menu.memberManagement",
|
||||||
"label": "API KEY管理",
|
"path": "/member",
|
||||||
"i18nKey": "menu.apiKeyManagement",
|
"enable": true,
|
||||||
"path": "/api-key",
|
"display": true,
|
||||||
"enable": true,
|
"level": 1,
|
||||||
"display": true,
|
"sort": 0,
|
||||||
"level": 1,
|
"icon": null,
|
||||||
"sort": 0,
|
"iconActive": null,
|
||||||
"icon": null,
|
"subs": null
|
||||||
"iconActive": null,
|
},
|
||||||
"subs": null
|
{
|
||||||
},
|
"id": 33,
|
||||||
{
|
"parent": 3,
|
||||||
"id": 20,
|
"code": "spaceConfig",
|
||||||
"parent": 0,
|
"label": "空间配置",
|
||||||
"code": "prompt",
|
"i18nKey": "menu.spaceConfig",
|
||||||
"label": "提示词",
|
"path": "/space-config",
|
||||||
"i18nKey": "menu.prompt",
|
"enable": true,
|
||||||
"path": "/prompt",
|
"display": true,
|
||||||
"enable": true,
|
"level": 1,
|
||||||
"display": true,
|
"sort": 0,
|
||||||
"level": 1,
|
"icon": null,
|
||||||
"sort": 0,
|
"iconActive": null,
|
||||||
"icon": null,
|
"subs": null
|
||||||
"iconActive": null,
|
}
|
||||||
"subs": null
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 19,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "member",
|
|
||||||
"label": "成员管理",
|
|
||||||
"i18nKey": "menu.memberManagement",
|
|
||||||
"path": "/member",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 12,
|
|
||||||
"parent": 0,
|
|
||||||
"code": "spaceConfig",
|
|
||||||
"label": "空间配置",
|
|
||||||
"i18nKey": "menu.spaceConfig",
|
|
||||||
"path": "/space-config",
|
|
||||||
"enable": true,
|
|
||||||
"display": true,
|
|
||||||
"level": 1,
|
|
||||||
"sort": 0,
|
|
||||||
"icon": null,
|
|
||||||
"iconActive": null,
|
|
||||||
"subs": null
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-02 16:33:34
|
* @Date: 2026-02-02 16:33:34
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-02 16:33:34
|
* @Last Modified time: 2026-02-04 10:31:14
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Menu Store
|
* Menu Store
|
||||||
@@ -42,6 +42,7 @@ export interface MenuItem {
|
|||||||
master?: string | null;
|
master?: string | null;
|
||||||
disposable?: boolean;
|
disposable?: boolean;
|
||||||
appSystem?: string | null;
|
appSystem?: string | null;
|
||||||
|
type?: 'group' | string;
|
||||||
subs?: MenuItem[] | null;
|
subs?: MenuItem[] | null;
|
||||||
onClick?: (e?: React.MouseEvent) => void | boolean;
|
onClick?: (e?: React.MouseEvent) => void | boolean;
|
||||||
}
|
}
|
||||||
@@ -90,19 +91,26 @@ export const useMenu = create<MenuState>((set, get) => ({
|
|||||||
const menus = allMenus[source] || []
|
const menus = allMenus[source] || []
|
||||||
let result: MenuItem[] = []
|
let result: MenuItem[] = []
|
||||||
|
|
||||||
console.log('updateBreadcrumbs paths:', paths);
|
/** Flatten group menus so top-level items are always real menu entries */
|
||||||
|
const flatMenus = menus.flatMap(m => m.type === 'group' ? (m.subs || []) : [m]);
|
||||||
|
|
||||||
|
const findById = (list: MenuItem[], id: string) => list.find(m => `${m.id}` === id);
|
||||||
|
/** Find menu by id in both original menus and flatMenus (handles group ids) */
|
||||||
|
const findMenuById = (id: string) => findById(menus, id) || findById(flatMenus, id);
|
||||||
|
const pathMatches = (pattern: string, path: string) => {
|
||||||
|
const n = pattern[0] !== '/' ? '/' + pattern : pattern;
|
||||||
|
if (n === path) return true;
|
||||||
|
if (n.includes(':')) return new RegExp('^' + n.replace(/:[\w-]+/g, '[^/]+') + '$').test(path);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
if (paths.length === 3) {
|
if (paths.length === 3) {
|
||||||
/** Three-level menu: [subSubPath, subId, menuId] */
|
/** Three-level: [subSubPath, subId, menuId] */
|
||||||
const menuId = paths[2];
|
const matchedMenu = findMenuById(paths[2]);
|
||||||
const subId = paths[1];
|
if (matchedMenu?.subs) {
|
||||||
const subSubPath = paths[0];
|
const matchedSub = findById(matchedMenu.subs, paths[1]);
|
||||||
|
if (matchedSub?.subs) {
|
||||||
const matchedMenu = menus.find(menu => `${menu.id}` === menuId);
|
const matchedSubSub = matchedSub.subs.find(s => s.path === paths[0] || pathMatches(s.path || '', paths[0]));
|
||||||
if (matchedMenu && matchedMenu.subs) {
|
|
||||||
const matchedSub = matchedMenu.subs.find(sub => `${sub.id}` === subId);
|
|
||||||
if (matchedSub && matchedSub.subs) {
|
|
||||||
const matchedSubSub = matchedSub.subs.find(subSub => subSub.path === subSubPath);
|
|
||||||
if (matchedSubSub) {
|
if (matchedSubSub) {
|
||||||
result = [
|
result = [
|
||||||
{ ...matchedMenu, subs: null },
|
{ ...matchedMenu, subs: null },
|
||||||
@@ -113,20 +121,13 @@ export const useMenu = create<MenuState>((set, get) => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/** Original logic for one-level and two-level menus */
|
const matchedMenu = flatMenus.find(m => m.path === paths[0] || `${m.id}` === paths[1]);
|
||||||
const matchedMenu: MenuItem | undefined = menus.find(menu => menu.path === paths[paths.length - 1] || `${menu.id}` === paths[1]);
|
|
||||||
|
|
||||||
if (matchedMenu) {
|
if (matchedMenu) {
|
||||||
let matchedSubMenu: MenuItem | undefined = undefined;
|
let matchedSubMenu: MenuItem | undefined;
|
||||||
if (paths.length > 1 && matchedMenu?.subs?.length) {
|
if (paths.length > 1 && matchedMenu.subs?.length) {
|
||||||
matchedSubMenu = matchedMenu.subs.find(menu => menu.path === paths[0]);
|
matchedSubMenu = matchedMenu.subs.find(m => m.path === paths[0]);
|
||||||
}
|
}
|
||||||
result = [
|
result = [{ ...matchedMenu, subs: null }, matchedSubMenu].filter(Boolean) as MenuItem[];
|
||||||
{ ...matchedMenu, subs: null },
|
|
||||||
matchedSubMenu
|
|
||||||
].filter(item => item !== undefined) as MenuItem[]
|
|
||||||
} else {
|
|
||||||
result = [] as MenuItem[]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,87 +3,99 @@ import type { ThemeConfig } from 'antd';
|
|||||||
// 浅色主题配置
|
// 浅色主题配置
|
||||||
export const lightTheme: ThemeConfig = {
|
export const lightTheme: ThemeConfig = {
|
||||||
token: {
|
token: {
|
||||||
colorPrimary: '#155EEF',
|
colorPrimary: '#171719',
|
||||||
colorBgBase: '#ffffff',
|
colorBgBase: '#ffffff',
|
||||||
colorTextBase: '#212332',
|
colorTextBase: '#171719',
|
||||||
colorBorder: '#DFE4ED',
|
colorBorder: '#DFE4ED',
|
||||||
colorBgLayout: '#ffffff',
|
colorBgLayout: '#ffffff',
|
||||||
colorBgContainer: '#ffffff',
|
colorBgContainer: '#ffffff',
|
||||||
colorText: '#212332',
|
colorText: '#171719',
|
||||||
colorTextSecondary: '#6b7280',
|
colorTextSecondary: '#6b7280',
|
||||||
borderRadius: 6,
|
borderRadius: 8,
|
||||||
colorSplit: '#DFE4ED',
|
colorSplit: '#DFE4ED',
|
||||||
colorBorderBg: '#DFE4ED',
|
colorBorderBg: '#DFE4ED',
|
||||||
colorBgContainerDisabled: '#F6F8FC',
|
colorBgContainerDisabled: '#F6F6F6',
|
||||||
colorTextDisabled: '#5B6167',
|
colorTextDisabled: '#5B6167',
|
||||||
// Card 用到
|
// Card 用到
|
||||||
borderRadiusLG: 12,
|
borderRadiusLG: 12,
|
||||||
|
borderRadiusSM: 8,
|
||||||
colorBorderSecondary: '#DFE4ED',
|
colorBorderSecondary: '#DFE4ED',
|
||||||
// colorBgContainer: '#FBFDFF',
|
// colorBgContainer: '#FBFDFF',
|
||||||
colorError: '#FF5D34',
|
colorError: '#FF5D34',
|
||||||
sizeSM: 12,
|
sizeSM: 12,
|
||||||
fontSizeSM: 12,
|
fontSizeSM: 12,
|
||||||
|
boxShadow: 'none',
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Layout: {
|
Layout: {
|
||||||
headerBg: 'transparent',
|
headerBg: 'transparent',
|
||||||
bodyBg: '#FBFDFF',
|
bodyBg: '#EEEFF4',
|
||||||
siderBg: 'transparent',
|
siderBg: '#FAFCFF',
|
||||||
headerPadding: '16px 46px 16px 21px',
|
headerPadding: '0 24px 0 20px',
|
||||||
headerHeight: 64,
|
headerHeight: 64,
|
||||||
headerColor: '#212332',
|
headerColor: '#212332',
|
||||||
},
|
},
|
||||||
Menu: {
|
Menu: {
|
||||||
itemColor: '#5B6167',
|
fontSize: 13,
|
||||||
itemSelectedColor: '#212332',
|
itemColor: '#171719',
|
||||||
subMenuItemSelectedColor: '#212332',
|
itemSelectedColor: '#FFFFFF',
|
||||||
|
subMenuItemSelectedColor: '#FFFFFF',
|
||||||
|
|
||||||
itemHoverColor: '#212332',
|
itemHoverColor: '#171719',
|
||||||
itemHoverBg: '#FFFFFF',
|
itemHoverBg: 'rgba(223,228,237,0.5)',
|
||||||
|
|
||||||
itemBg: 'transparent',
|
itemBg: 'transparent',
|
||||||
itemSelectedBg: '#FFFFFF',
|
itemSelectedBg: '#171719',
|
||||||
|
|
||||||
subMenuItemBg: 'transparent',
|
subMenuItemBg: 'transparent',
|
||||||
|
|
||||||
itemPaddingInline: 12,
|
itemPaddingInline: 10,
|
||||||
|
|
||||||
itemHeight: 32,
|
itemHeight: 38,
|
||||||
itemMarginBlock: 8,
|
itemMarginBlock: 8,
|
||||||
horizontalLineHeight: 32,
|
horizontalLineHeight: 32,
|
||||||
itemMarginInline: 12,
|
itemMarginInline: 12,
|
||||||
itemBorderRadius: 6,
|
itemBorderRadius: 8,
|
||||||
|
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
iconMarginInlineEnd: 8,
|
iconMarginInlineEnd: 10,
|
||||||
collapsedIconSize: 12,
|
collapsedIconSize: 12,
|
||||||
collapsedWidth: '64px',
|
collapsedWidth: '64px',
|
||||||
|
|
||||||
popupBg: '#FBFDFF',
|
popupBg: '#FBFDFF',
|
||||||
|
groupTitleFontSize: 12,
|
||||||
|
groupTitleColor: '#5B6167',
|
||||||
|
groupTitleLineHeight: '17px',
|
||||||
},
|
},
|
||||||
Button: {
|
Button: {
|
||||||
defaultColor: '#5B6167',
|
defaultColor: '#171719',
|
||||||
defaultBorderColor: '#EBEBEB',
|
defaultBorderColor: '#EBEBEB',
|
||||||
defaultShadow: 'none',
|
defaultShadow: 'none',
|
||||||
primaryShadow: 'none',
|
primaryShadow: 'none',
|
||||||
dangerShadow: 'none'
|
dangerShadow: 'none',
|
||||||
|
defaultGhostBorderColor: '#EBEBEB',
|
||||||
|
defaultHoverColor: 'rgba(23, 23, 25, 0.7)',
|
||||||
|
defaultHoverBorderColor: 'rgba(23, 23, 25, 0.7)',
|
||||||
},
|
},
|
||||||
Form: {
|
Form: {
|
||||||
labelColor: '#212332',
|
labelColor: '#171719',
|
||||||
|
itemMarginBottom: 16,
|
||||||
},
|
},
|
||||||
Slider: {
|
Slider: {
|
||||||
// dotSize: 10,
|
// dotSize: 10,
|
||||||
controlSize: 8,
|
controlSize: 6,
|
||||||
railSize: 8,
|
railSize: 6,
|
||||||
handleSize: 10,
|
handleSize: 10,
|
||||||
handleSizeHover: 10,
|
handleSizeHover: 10,
|
||||||
handleColor: '#155EEF',
|
handleColor: '#171719',
|
||||||
trackBg: '#155EEF',
|
handleActiveOutlineColor: '#171719',
|
||||||
railBg: '#E1E2E7',
|
trackBg: '#171719',
|
||||||
|
railBg: '#EBEBEB',
|
||||||
},
|
},
|
||||||
Table: {
|
Table: {
|
||||||
borderColor: '#DFE4ED',
|
headerColor: '#5B6167',
|
||||||
headerBg: '#FBFDFF',
|
borderColor: '#EBEBEB',
|
||||||
|
headerBg: '#FFFFFF',
|
||||||
rowHoverBg: '#F0F3F8',
|
rowHoverBg: '#F0F3F8',
|
||||||
rowSelectedBg: '#E9F1FF',
|
rowSelectedBg: '#E9F1FF',
|
||||||
rowSelectedHoverBg: '#F0F3F8',
|
rowSelectedHoverBg: '#F0F3F8',
|
||||||
@@ -95,19 +107,36 @@ export const lightTheme: ThemeConfig = {
|
|||||||
},
|
},
|
||||||
Breadcrumb: {
|
Breadcrumb: {
|
||||||
itemColor: '#5B6167',
|
itemColor: '#5B6167',
|
||||||
lastItemColor: '#212332',
|
lastItemColor: '#171719',
|
||||||
linkColor: '#5B6167',
|
linkColor: '#5B6167',
|
||||||
linkHoverColor: '#212332',
|
linkHoverColor: '#171719',
|
||||||
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
Input: {
|
Input: {
|
||||||
inputFontSizeSM: 12,
|
inputFontSizeSM: 12,
|
||||||
controlHeightSM: 26
|
controlHeightSM: 26,
|
||||||
|
activeShadow: 'none',
|
||||||
|
},
|
||||||
|
InputNumber: {
|
||||||
|
activeShadow: 'none',
|
||||||
},
|
},
|
||||||
Select: {
|
Select: {
|
||||||
lineHeightSM: 26
|
lineHeightSM: 26,
|
||||||
},
|
},
|
||||||
Upload: {
|
Upload: {
|
||||||
pictureCardSize: 96,
|
pictureCardSize: 96,
|
||||||
|
},
|
||||||
|
Switch: {
|
||||||
|
trackHeight: 24,
|
||||||
|
trackHeightSM: 18,
|
||||||
|
handleSize: 20,
|
||||||
|
handleSizeSM: 14,
|
||||||
|
innerMinMarginSM: 8,
|
||||||
|
innerMaxMarginSM: 27,
|
||||||
|
},
|
||||||
|
Cascader: {
|
||||||
|
optionSelectedBg: '#F6F6F6',
|
||||||
|
optionSelectedColor: '#212332'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
5
web/src/styles/common.css
Normal file
5
web/src/styles/common.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.rb-border { border: 1px solid #DFE4ED; }
|
||||||
|
.rb-border-t { border-top: 1px solid #DFE4ED; }
|
||||||
|
.rb-border-r { border-right: 1px solid #DFE4ED; }
|
||||||
|
.rb-border-b { border-bottom: 1px solid #DFE4ED; }
|
||||||
|
.rb-border-l { border-left: 1px solid #DFE4ED; }
|
||||||
@@ -1,5 +1,65 @@
|
|||||||
@import "tailwindcss" prefix(rb);
|
@import "tailwindcss" prefix(rb);
|
||||||
@plugin "@tailwindcss/typography";
|
@plugin "@tailwindcss/typography";
|
||||||
|
@import "./common.css";
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Bold';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Bold.woff2') format('woff2');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}@font-face {
|
||||||
|
font-family: 'MiSans-Demibold';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Demibold.woff2') format('woff2');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}@font-face {
|
||||||
|
font-family: 'MiSans-ExtraLight';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-ExtraLight.woff2') format('woff2');
|
||||||
|
font-weight: 200;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Heavy';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Heavy.woff2') format('woff2');
|
||||||
|
font-weight: 900;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Light';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Light.woff2') format('woff2');
|
||||||
|
font-weight: 300;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Medium';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Medium.woff2') format('woff2');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Normal';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Normal.woff2') format('woff2');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Regular';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Regular.woff2') format('woff2');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Semibold';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Semibold.woff2') format('woff2');
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MiSans-Thin';
|
||||||
|
src: url('@/assets/font/MiSans/MiSans-Thin.woff2') format('woff2');
|
||||||
|
font-weight: 100;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
html, body, #root {
|
html, body, #root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -31,7 +91,7 @@ body {
|
|||||||
.ant-menu-light>.ant-menu .ant-menu-item-selected,
|
.ant-menu-light>.ant-menu .ant-menu-item-selected,
|
||||||
.ant-menu-light:not(.ant-menu-horizontal) .ant-menu-item:not(.ant-menu-item-selected):hover,
|
.ant-menu-light:not(.ant-menu-horizontal) .ant-menu-item:not(.ant-menu-item-selected):hover,
|
||||||
.ant-menu-light>.ant-menu:not(.ant-menu-horizontal) .ant-menu-item:not(.ant-menu-item-selected):hover {
|
.ant-menu-light>.ant-menu:not(.ant-menu-horizontal) .ant-menu-item:not(.ant-menu-item-selected):hover {
|
||||||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.15);
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
.ant-menu-light .ant-menu-item-selected,
|
.ant-menu-light .ant-menu-item-selected,
|
||||||
.ant-menu-light>.ant-menu .ant-menu-item-selected {
|
.ant-menu-light>.ant-menu .ant-menu-item-selected {
|
||||||
@@ -47,8 +107,14 @@ body {
|
|||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
color: #212332;
|
color: #212332;
|
||||||
}
|
}
|
||||||
|
.ant-menu-inline-collapsed>.ant-menu-item,
|
||||||
|
.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-item,
|
||||||
|
.ant-menu-inline-collapsed>.ant-menu-item-group>.ant-menu-item-group-list>.ant-menu-submenu>.ant-menu-submenu-title,
|
||||||
|
.ant-menu-inline-collapsed>.ant-menu-submenu>.ant-menu-submenu-title {
|
||||||
|
padding-inline: calc(50% - 6px - 14px);
|
||||||
|
}
|
||||||
.ant-slider .ant-slider-handle::after {
|
.ant-slider .ant-slider-handle::after {
|
||||||
background-color: #155EEF;
|
background-color: #171719;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
@@ -56,6 +122,34 @@ body {
|
|||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
.ant-slider-horizontal .ant-slider-handle {
|
||||||
|
inset-block-start: 3px;
|
||||||
|
}
|
||||||
|
.ant-slider.small {
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
.ant-slider-horizontal.small .ant-slider-handle {
|
||||||
|
inset-block-start: 5px;
|
||||||
|
}
|
||||||
|
.ant-slider.small .ant-slider-handle::after {
|
||||||
|
background-color: #171719;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
.ant-slider.small .ant-slider-handle::before {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
.ant-slider.small .ant-slider-handle:hover::after,
|
||||||
|
.ant-slider.small .ant-slider-handle:active::after,
|
||||||
|
.ant-slider.small .ant-slider-handle:focus::after {
|
||||||
|
outline: 2px solid #171719;
|
||||||
|
}
|
||||||
|
.ant-slider.small .ant-slider-rail,
|
||||||
|
.ant-slider.small .ant-slider-track {
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
.ant-table-container {
|
.ant-table-container {
|
||||||
border: 1px solid #DFE4ED;
|
border: 1px solid #DFE4ED;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -83,6 +177,16 @@ body {
|
|||||||
.ant-table-wrapper .ant-table-thead>tr>td {
|
.ant-table-wrapper .ant-table-thead>tr>td {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-title,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-footer,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-cell,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-thead>tr>th,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-tbody>tr>th,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small .ant-table-tbody>tr>td,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small tfoot>tr>th,
|
||||||
|
.ant-table-wrapper .ant-table.ant-table-small tfoot>tr>td {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
.ant-table-wrapper .ant-table-pagination.ant-pagination {
|
.ant-table-wrapper .ant-table-pagination.ant-pagination {
|
||||||
margin: 24px 0 32px 0;
|
margin: 24px 0 32px 0;
|
||||||
}
|
}
|
||||||
@@ -165,13 +269,7 @@ body {
|
|||||||
.infinite-scroll-component {
|
.infinite-scroll-component {
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden !important;
|
||||||
}
|
}
|
||||||
.ant-slider-horizontal .ant-slider-handle {
|
|
||||||
inset-block-start: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
.ant-breadcrumb a:hover {
|
.ant-breadcrumb a:hover {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
@@ -183,6 +281,34 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ͼ2 .cm-gutters {
|
.ͼ2 .cm-gutters {
|
||||||
background-color: #FFFFFF;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #DFE4ED;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #DFE4ED;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-focused.ant-select-outlined:not(.ant-select-disabled):not(.ant-select-customize-input):not(.ant-pagination-size-changer) .ant-select-selector {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.ant-select-dropdown .ant-select-item {
|
||||||
|
color: #212332;
|
||||||
|
}
|
||||||
|
.ant-select-dropdown .ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
|
||||||
|
color: #212332;
|
||||||
|
background: #F6F6F6;
|
||||||
|
}
|
||||||
77
web/src/views/Home/components/ApiLineCard.tsx
Normal file
77
web/src/views/Home/components/ApiLineCard.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 17:17:05
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-10 11:35:52
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Line Chart Card Component
|
||||||
|
* Displays time-series data with ECharts line chart
|
||||||
|
* Supports multiple series and date range selection
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { type FC, useEffect, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Select } from 'antd'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
import Card from './Card'
|
||||||
|
import { getWorkspaceApiStatistics } from '@/api/application'
|
||||||
|
import LineChart, { type ChartData } from '@/components/Charts/LineChart'
|
||||||
|
|
||||||
|
const seriesList = ['total_calls', 'app_calls', 'service_calls']
|
||||||
|
const ApiLineCard: FC = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const options = [
|
||||||
|
{ label: t('dashboard.lastDays', { days: 7 }), value: 7 },
|
||||||
|
{ label: t('dashboard.lastDays', { days: 30 }), value: 30 },
|
||||||
|
{ label: t('dashboard.lastDays', { days: 90 }), value: 90 },
|
||||||
|
{ label: t('dashboard.lastHalfYear'), value: 180 },
|
||||||
|
{ label: t('dashboard.lastYear'), value: 365 },
|
||||||
|
]
|
||||||
|
const [chartData, setChartData] = useState<ChartData[]>([])
|
||||||
|
const [query, setQuery] = useState(7)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getWorkspaceApiStatistics({
|
||||||
|
start_date: dayjs().subtract(query - 1, 'd').startOf('d').valueOf(),
|
||||||
|
end_date: dayjs().endOf('d').valueOf(),
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
setChartData(res as ChartData[])
|
||||||
|
})
|
||||||
|
}, [query])
|
||||||
|
|
||||||
|
/** Format series list for legend */
|
||||||
|
const formatSeriesList = () => {
|
||||||
|
const list: Record<string, string> = {}
|
||||||
|
seriesList.forEach(key => {
|
||||||
|
list[key] = t(`dashboard.${key}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={t(`dashboard.apiCallTrends`)}
|
||||||
|
headerOperate={
|
||||||
|
<Select
|
||||||
|
value={query}
|
||||||
|
options={options}
|
||||||
|
onChange={(value) => setQuery(value)}
|
||||||
|
className="rb:w-35!"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
className={`rb:pb-6`}
|
||||||
|
>
|
||||||
|
<LineChart
|
||||||
|
chartData={chartData}
|
||||||
|
seriesList={formatSeriesList()}
|
||||||
|
height={239}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApiLineCard
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:27:28
|
* @Date: 2026-02-03 17:27:28
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:27:28
|
* @Last Modified time: 2026-02-26 11:16:09
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Card Component
|
* Card Component
|
||||||
@@ -21,15 +21,19 @@ interface CardProps {
|
|||||||
title: string;
|
title: string;
|
||||||
headerOperate?: ReactNode;
|
headerOperate?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
bodyClassName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Card: FC<CardProps> = ({ children, title, headerOperate, className }) => {
|
const Card: FC<CardProps> = ({ children, title, headerOperate, className, bodyClassName }) => {
|
||||||
return (
|
return (
|
||||||
<RbCard
|
<RbCard
|
||||||
headerType="borderless"
|
headerType="borderless"
|
||||||
title={title}
|
title={title}
|
||||||
extra={headerOperate}
|
extra={headerOperate}
|
||||||
className={`rb:h-full! ${className}`}
|
variant="borderless"
|
||||||
|
className={`rb:h-full! rb:bg-[#FFFFFF]! ${className}`}
|
||||||
|
bodyClassName={bodyClassName}
|
||||||
|
headerClassName="rb:min-h-[58px]!"
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</RbCard>
|
</RbCard>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:17:05
|
* @Date: 2026-02-03 17:17:05
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:18:32
|
* @Last Modified time: 2026-02-10 11:59:10
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Line Chart Card Component
|
* Line Chart Card Component
|
||||||
@@ -10,21 +10,18 @@
|
|||||||
* Supports multiple series and date range selection
|
* Supports multiple series and date range selection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type FC, useRef } from 'react'
|
import { type FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Select } from 'antd'
|
import { Select } from 'antd'
|
||||||
import ReactEcharts from 'echarts-for-react';
|
|
||||||
import * as echarts from 'echarts';
|
|
||||||
|
|
||||||
import { formatDateTime } from '@/utils/format';
|
|
||||||
import Empty from '@/components/Empty'
|
|
||||||
import Card from './Card'
|
import Card from './Card'
|
||||||
|
import AreaLineChart, { type ChartData } from '@/components/Charts/AreaLineChart';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component props
|
* Component props
|
||||||
*/
|
*/
|
||||||
interface LineCardProps {
|
interface LineCardProps {
|
||||||
chartData: Array<Record<string, string | number>>;
|
chartData: ChartData[];
|
||||||
limit: number;
|
limit: number;
|
||||||
onChange: (value: string, type: string) => void;
|
onChange: (value: string, type: string) => void;
|
||||||
type: string;
|
type: string;
|
||||||
@@ -32,30 +29,8 @@ interface LineCardProps {
|
|||||||
seriesList: string[];
|
seriesList: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ECharts series configuration */
|
|
||||||
const SeriesConfig = {
|
|
||||||
type: 'line',
|
|
||||||
stack: 'Total',
|
|
||||||
smooth: true,
|
|
||||||
lineStyle: {
|
|
||||||
width: 3
|
|
||||||
},
|
|
||||||
showSymbol: false,
|
|
||||||
label: {
|
|
||||||
show: true,
|
|
||||||
position: 'top'
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
focus: 'series'
|
|
||||||
},
|
|
||||||
data: [220, 302, 181, 234, 210, 290, 150]
|
|
||||||
}
|
|
||||||
/** Chart color palette */
|
|
||||||
const Colors = ['#FFB048', '#4DA8FF', '#155EEF']
|
|
||||||
|
|
||||||
const LineCard: FC<LineCardProps> = ({ chartData, limit, onChange, type, className, seriesList }) => {
|
const LineCard: FC<LineCardProps> = ({ chartData, limit, onChange, type, className, seriesList }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const chartRef = useRef<ReactEcharts>(null);
|
|
||||||
const options = [
|
const options = [
|
||||||
{ label: t('dashboard.lastDays', { days: 7 }), value: 7 },
|
{ label: t('dashboard.lastDays', { days: 7 }), value: 7 },
|
||||||
{ label: t('dashboard.lastDays', { days: 30 }), value: 30 },
|
{ label: t('dashboard.lastDays', { days: 30 }), value: 30 },
|
||||||
@@ -63,39 +38,15 @@ const LineCard: FC<LineCardProps> = ({ chartData, limit, onChange, type, classNa
|
|||||||
{ label: t('dashboard.lastHalfYear'), value: 180 },
|
{ label: t('dashboard.lastHalfYear'), value: 180 },
|
||||||
{ label: t('dashboard.lastYear'), value: 365 },
|
{ label: t('dashboard.lastYear'), value: 365 },
|
||||||
]
|
]
|
||||||
|
/** Format series list for legend */
|
||||||
/** Generate series data with gradient colors */
|
const formatSeriesList = () => {
|
||||||
const getSeries = () => {
|
const list: Record<string, string> = {}
|
||||||
const list = seriesList.map((key, index) => {
|
seriesList.forEach(key => {
|
||||||
return {
|
list[key] = t(`dashboard.${key}`)
|
||||||
...SeriesConfig,
|
|
||||||
name: t(`dashboard.${key}`),
|
|
||||||
data: chartData.map(vo => vo[key]),
|
|
||||||
areaStyle: {
|
|
||||||
opacity: 0.8,
|
|
||||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
||||||
{
|
|
||||||
offset: 0,
|
|
||||||
color: Colors[index]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#FFFFFF'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
/** Format series list for legend */
|
|
||||||
const formatSeriesList = () => {
|
|
||||||
return seriesList.map(key => ({
|
|
||||||
...SeriesConfig,
|
|
||||||
name: t(`dashboard.${key}`),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@@ -105,78 +56,17 @@ const LineCard: FC<LineCardProps> = ({ chartData, limit, onChange, type, classNa
|
|||||||
value={limit}
|
value={limit}
|
||||||
options={options}
|
options={options}
|
||||||
onChange={(value) => onChange(String(value), type)}
|
onChange={(value) => onChange(String(value), type)}
|
||||||
style={{ width: '150px' }}
|
className="rb:w-35!"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
className={`rb:pb-6 ${className}`}
|
className={`rb:pb-6 ${className}`}
|
||||||
>
|
>
|
||||||
{chartData && chartData.length > 0 ? (
|
<AreaLineChart
|
||||||
<ReactEcharts
|
xAxisKey="date"
|
||||||
ref={chartRef}
|
chartData={chartData}
|
||||||
option={{
|
seriesList={formatSeriesList()}
|
||||||
color: Colors,
|
height={239}
|
||||||
tooltip: {
|
/>
|
||||||
trigger: 'axis',
|
|
||||||
extraCssText: 'box-shadow: 0px 2px 6px 0px rgba(33,35,50,0.16); border-radius: 8px;',
|
|
||||||
axisPointer: {
|
|
||||||
type: 'line',
|
|
||||||
crossStyle: {
|
|
||||||
color: '#5F6266',
|
|
||||||
},
|
|
||||||
lineStyle: {
|
|
||||||
color: '#5F6266',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
data: formatSeriesList(),
|
|
||||||
textStyle: {
|
|
||||||
color: '#5B6167',
|
|
||||||
fontFamily: 'PingFangSC, PingFang SC',
|
|
||||||
lineHeight: 16,
|
|
||||||
},
|
|
||||||
itemGap: 32,
|
|
||||||
padding: 0,
|
|
||||||
itemWidth: 26,
|
|
||||||
itemHeight: 10,
|
|
||||||
left: 'center'
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: 4,
|
|
||||||
right: '3%',
|
|
||||||
bottom: 0,
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: chartData.map(item => formatDateTime(item.created_at, 'DD/MM')),
|
|
||||||
boundaryGap: false,
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value',
|
|
||||||
axisLabel: {
|
|
||||||
color: '#A8A9AA',
|
|
||||||
fontFamily: 'PingFangSC, PingFang SC',
|
|
||||||
align: 'right',
|
|
||||||
lineHeight: 17,
|
|
||||||
},
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#EBEBEB',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
series: getSeries()
|
|
||||||
}}
|
|
||||||
style={{ height: '265px', width: '100%', minWidth: '100%', boxSizing: 'border-box' }}
|
|
||||||
opts={{ renderer: 'canvas' }}
|
|
||||||
notMerge={true}
|
|
||||||
lazyUpdate={true}
|
|
||||||
/>
|
|
||||||
) : <Empty size={120} className="rb:mt-12 rb:mb-20.25" />}
|
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,137 +1,39 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:16:45
|
* @Date: 2026-02-03 17:16:45
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:16:45
|
* @Last Modified time: 2026-02-10 11:57:35
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Pie Chart Card Component
|
* Pie Chart Card Component
|
||||||
* Displays knowledge base type distribution with ECharts donut chart
|
* Displays knowledge base type distribution with ECharts donut chart
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type FC, useRef, useEffect } from 'react'
|
import { type FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import ReactEcharts from 'echarts-for-react';
|
|
||||||
|
|
||||||
import Card from './Card'
|
import Card from './Card'
|
||||||
import Loading from '@/components/Empty/Loading'
|
import Loading from '@/components/Empty/Loading'
|
||||||
import Empty from '@/components/Empty'
|
import PieChart, { type ChartData } from '@/components/Charts/PieChart'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component props
|
* Component props
|
||||||
*/
|
*/
|
||||||
interface PieCardProps {
|
interface PieCardProps {
|
||||||
chartData: Array<Record<string, string | number>>;
|
chartData: ChartData[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
/** Chart color palette */
|
|
||||||
const Colors = ['#155EEF', '#31E8FF', '#AD88FF', '#FFB048', '#4DA8FF', '#03BDFF']
|
|
||||||
|
|
||||||
const PieCard: FC<PieCardProps> = ({ chartData, loading }) => {
|
const PieCard: FC<PieCardProps> = ({ chartData, loading }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const chartRef = useRef<ReactEcharts>(null);
|
|
||||||
const resizeScheduledRef = useRef(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleResize = () => {
|
|
||||||
if (chartRef.current && !resizeScheduledRef.current) {
|
|
||||||
resizeScheduledRef.current = true
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
chartRef.current?.getEchartsInstance().resize();
|
|
||||||
resizeScheduledRef.current = false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(handleResize)
|
|
||||||
const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement
|
|
||||||
if (chartElement) {
|
|
||||||
resizeObserver.observe(chartElement)
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
resizeObserver.disconnect()
|
|
||||||
}
|
|
||||||
}, [chartData])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t('dashboard.knowledgeBaseTypeDistribution')}
|
title={t('dashboard.knowledgeBaseTypeDistribution')}
|
||||||
>
|
>
|
||||||
{loading
|
{loading
|
||||||
? <Loading size={249} />
|
? <Loading size={249} />
|
||||||
: !chartData || chartData.length === 0
|
: <PieChart chartData={chartData} />
|
||||||
? <Empty size={120} className="rb:mt-12 rb:mb-20.25" />
|
|
||||||
: <ReactEcharts
|
|
||||||
option={{
|
|
||||||
color: Colors,
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item',
|
|
||||||
textStyle: {
|
|
||||||
color: '#5B6167',
|
|
||||||
fontSize: 12,
|
|
||||||
width: 27,
|
|
||||||
height: 16,
|
|
||||||
},
|
|
||||||
formatter: '{d}%',
|
|
||||||
padding: [8, 5],
|
|
||||||
backgroundColor: '#FFFFFF',
|
|
||||||
borderColor: '#DFE4ED',
|
|
||||||
extraCssText: 'width: 36px; height: 36px; box-shadow: 0px 2px 4px 0px rgba(33,35,50,0.12);border-radius: 36px;'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
right: 20 ,
|
|
||||||
top: 'middle',
|
|
||||||
padding: 0,
|
|
||||||
itemWidth: 12,
|
|
||||||
itemHeight: 12,
|
|
||||||
borderRadius: 2,
|
|
||||||
orient: 'vertical',
|
|
||||||
textStyle: {
|
|
||||||
color: '#5B6167',
|
|
||||||
fontFamily: 'PingFangSC, PingFang SC',
|
|
||||||
lineHeight: 16,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: 'Access From',
|
|
||||||
type: 'pie',
|
|
||||||
radius: ['60%', '100%'],
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
percentPrecision: 0,
|
|
||||||
padAngle: 4,
|
|
||||||
width: 200,
|
|
||||||
height: 200,
|
|
||||||
left: '10%',
|
|
||||||
top: 'middle',
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: 0
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: 'center'
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
show: true,
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#212332',
|
|
||||||
formatter: '{d}%\n{b}',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
labelLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
data: chartData
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
style={{ height: '265px', width: '100%', minWidth: '400px' }}
|
|
||||||
notMerge={true}
|
|
||||||
lazyUpdate={true}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:16:38
|
* @Date: 2026-02-03 17:16:38
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:16:38
|
* @Last Modified time: 2026-02-11 14:57:35
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Quick Operation Component
|
* Quick Operation Component
|
||||||
@@ -11,15 +11,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { type FC } from 'react'
|
import { type FC } from 'react'
|
||||||
|
import clsx from 'clsx';
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Flex } from 'antd';
|
||||||
|
|
||||||
import Card from './Card';
|
import Card from './Card';
|
||||||
import applicationIcon from '@/assets/images/menu/application_active.svg';
|
import applicationIcon from '@/assets/images/home/application.svg';
|
||||||
import knowledgeIcon from '@/assets/images/menu/knowledge_active.svg';
|
import knowledgeIcon from '@/assets/images/home/knowledge.svg';
|
||||||
import memoryConversationIcon from '@/assets/images/menu/memoryConversation_active.svg';
|
import memoryConversationIcon from '@/assets/images/home/memoryConversation.svg';
|
||||||
import helpCenterIcon from '@/assets/images/menu/helpCenter_active.svg'
|
import helpCenterIcon from '@/assets/images/menu/helpCenter_active.svg'
|
||||||
import arrowTopRight from '@/assets/images/home/arrow_top_right.svg';
|
|
||||||
|
|
||||||
/** Quick operation items configuration */
|
/** Quick operation items configuration */
|
||||||
const quickOperations = [
|
const quickOperations = [
|
||||||
@@ -29,6 +30,13 @@ const quickOperations = [
|
|||||||
{ key: 'helpCenter', url: '' },
|
{ key: 'helpCenter', url: '' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const bgStyleList = [
|
||||||
|
'rb:bg-[rgba(21,94,239,0.1)]',
|
||||||
|
'rb:bg-[rgba(156,111,255,0.1)]',
|
||||||
|
'rb:bg-[rgba(255,176,72,0.1)]',
|
||||||
|
'rb:bg-[rgba(77,168,255,0.1)]'
|
||||||
|
]
|
||||||
|
|
||||||
/** Icon mapping for quick operations */
|
/** Icon mapping for quick operations */
|
||||||
const quickOperationIcons: {[key: string]: string | undefined} = {
|
const quickOperationIcons: {[key: string]: string | undefined} = {
|
||||||
createNewApplication: applicationIcon,
|
createNewApplication: applicationIcon,
|
||||||
@@ -62,17 +70,19 @@ const QuickOperation:FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t('dashboard.quickOperation')}
|
title={t('dashboard.quickOperation')}
|
||||||
|
bodyClassName="rb:pt-0! rb:pb-[14px]! rb:px-4!"
|
||||||
>
|
>
|
||||||
<div className="rb:grid rb:grid-cols-4 rb:gap-4">
|
<div className="rb:grid rb:grid-cols-1 rb:gap-3">
|
||||||
{quickOperations.map(item => (
|
{quickOperations.map((item, index) => (
|
||||||
<div key={item.key} className="rb:rounded-lg rb:p-[20px_16px] rb:border rb:border-[#DFE4ED] rb:cursor-pointer rb:hover:border-[#155EEF]" onClick={() => handleJump(item.url)}>
|
<Flex key={item.key} align="center" gap={20} className={clsx("rb:relative rb:rounded-xl rb:py-2! rb:px-3! rb:cursor-pointer", bgStyleList[index])} onClick={() => handleJump(item.url)}>
|
||||||
<div className="rb:flex rb:justify-between">
|
<div className="rb:size-8 rb:rounded-lg rb:p-1 rb:bg-[#FFFFFF]">
|
||||||
<img className="rb:w-8 rb:h-8" src={quickOperationIcons[item.key]} />
|
<img className="rb:size-6" src={quickOperationIcons[item.key]} />
|
||||||
<img className="rb:w-4 rb:h-4" src={arrowTopRight} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="rb:mt-6 rb:text-[#212332] rb:text-[16px] rb:leading-5 rb:font-medium">{t(`dashboard.${item.key}`)}</div>
|
<div>
|
||||||
<div className="rb:mt-2 rb:text-[#5B6167] rb:text-[12px] rb:font-regular">{t(`dashboard.${item.key}Desc`)}</div>
|
<div className="rb:text-[14px] rb:leading-5 rb:font-medium">{t(`dashboard.${item.key}`)}</div>
|
||||||
</div>
|
<div className="rb:mt-0.5 rb:text-[#5B6167] rb:text-[12px] rb:font-regular">{t(`dashboard.${item.key}Desc`)}</div>
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:15:33
|
* @Date: 2026-02-03 17:15:33
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:15:33
|
* @Last Modified time: 2026-02-11 14:48:31
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Recent Activity Component
|
* Recent Activity Component
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
import { type FC, useEffect, useState } from 'react'
|
import { type FC, useEffect, useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Skeleton } from 'antd';
|
import { Skeleton, Flex } from 'antd';
|
||||||
|
|
||||||
import chunkCountIcon from '@/assets/images/home/chunk_count.svg';
|
import chunkCountIcon from '@/assets/images/home/chunk_count.svg';
|
||||||
import statementsCountIcon from '@/assets/images/home/statements_count.svg';
|
import statementsCountIcon from '@/assets/images/home/statements_count.svg';
|
||||||
@@ -79,30 +79,31 @@ const RecentActivity:FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t('dashboard.recentMemoryActivities')}
|
title={t('dashboard.recentMemoryActivities')}
|
||||||
|
bodyClassName="rb:pt-0! rb:pb-[14px]! rb:px-4!"
|
||||||
>
|
>
|
||||||
{loading
|
{loading
|
||||||
? <Skeleton />
|
? <Skeleton />
|
||||||
: !recentActivities || Object.keys(recentActivities).length === 0
|
: !recentActivities || Object.keys(recentActivities).length === 0
|
||||||
? <Empty url={activityEmpty} subTitle={t('dashboard.activityEmpty')} size={120} className="rb:mt-11.25 rb:mb-20.25" />
|
? <Empty url={activityEmpty} subTitle={t('dashboard.activityEmpty')} size={120} className="rb:mt-11.25 rb:mb-20.25" />
|
||||||
: activityList.map((item, index) => (
|
: <Flex vertical gap={24} justify="space-around">
|
||||||
<div key={item.key} className={clsx("rb:flex rb:justify-between rb:items-center rb:not-italic", {
|
{activityList.map((item) => (
|
||||||
'rb:mt-6': index !== 0
|
<Flex key={item.key} align="center" justify="space-between" className={clsx("rb:not-italic")}>
|
||||||
})}>
|
<Flex align="center" gap={20}>
|
||||||
<div className="rb:flex rb:items-center rb:text-[#060419] rb:text-[16px] rb:font-medium">
|
<img className="rb:size-10" src={item.icon} />
|
||||||
<img className="rb:w-10 rb:h-10 rb:mr-4" src={item.icon} />
|
<div>
|
||||||
<div>
|
<div className="rb:text-[16px] rb:leading-5.5 rb:font-medium">{t(`dashboard.${item.key}`)}</div>
|
||||||
{t(`dashboard.${item.key}`)}
|
<div className="rb:text-[#7B8085] rb:text-[14px] rb:font-regular rb:mt-1 rb:leading-4.5">
|
||||||
<div className="rb:text-[#5B6167] rb:text-[14px] rb:font-normal">
|
{item.key === 'triplet_count'
|
||||||
{item.key === 'triplet_count'
|
? t(`dashboard.${item.key}_desc`, { entities_count: recentActivities.triplet_entities_count, relations_count: recentActivities.triplet_relations_count })
|
||||||
? t(`dashboard.${item.key}_desc`, { entities_count: recentActivities.triplet_entities_count, relations_count: recentActivities.triplet_relations_count })
|
: t(`dashboard.${item.key}_desc`, { count: recentActivities[item.key as keyof RecentActivities] })
|
||||||
: t(`dashboard.${item.key}_desc`, { count: recentActivities[item.key as keyof RecentActivities] })
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Flex>
|
||||||
</div>
|
<div className="rb:text-[#7B8085] rb:text-right rb:whitespace-nowrap">{data?.latest_relative || ''}</div>
|
||||||
<div className="rb:text-[#5F6266] rb:text-right rb:whitespace-nowrap">{data?.latest_relative || ''}</div>
|
</Flex>
|
||||||
</div>
|
))}
|
||||||
))
|
</Flex>
|
||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:15:04
|
* @Date: 2026-02-03 17:15:04
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:15:04
|
* @Last Modified time: 2026-02-26 11:15:15
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Tag List Component
|
* Tag List Component
|
||||||
@@ -12,13 +12,24 @@
|
|||||||
import { type FC, useEffect, useState } from 'react'
|
import { type FC, useEffect, useState } from 'react'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Skeleton } from 'antd';
|
import { Skeleton, Flex } from 'antd';
|
||||||
|
|
||||||
import tagEmpty from '@/assets/images/home/tagEmpty.svg'
|
import tagEmpty from '@/assets/images/home/tagEmpty.svg'
|
||||||
import Empty from '@/components/Empty';
|
import Empty from '@/components/Empty';
|
||||||
import Card from './Card';
|
import Card from './Card';
|
||||||
import { getHotMemoryTags } from '@/api/memory';
|
import { getHotMemoryTags } from '@/api/memory';
|
||||||
|
|
||||||
|
const btnStyleList = [
|
||||||
|
'rb:bg-[rgba(21,94,239,0.06)]',
|
||||||
|
'rb:bg-[rgba(33,35,50,0.06)]',
|
||||||
|
'rb:bg-[rgba(156,111,255,0.06)]'
|
||||||
|
]
|
||||||
|
const numStyleList = [
|
||||||
|
'rb:bg-[#155EEF]',
|
||||||
|
'rb:bg-[#212332]',
|
||||||
|
'rb:bg-[#9C6FFF]'
|
||||||
|
]
|
||||||
|
|
||||||
const TagList:FC = () => {
|
const TagList:FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [loading, setLoading] = useState<boolean>(false)
|
const [loading, setLoading] = useState<boolean>(false)
|
||||||
@@ -38,23 +49,24 @@ const TagList:FC = () => {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t('dashboard.popularMemoryTags')}
|
title={t('dashboard.popularMemoryTags')}
|
||||||
|
bodyClassName='rb:overflow-hidden! rb:pt-0! rb:pb-4! rb:pl-4! rb:pr-3.25!'
|
||||||
|
className="rb:min-h-[calc(100vh-744px)]"
|
||||||
>
|
>
|
||||||
{loading
|
{loading
|
||||||
? <Skeleton />
|
? <Skeleton />
|
||||||
: !tagList || tagList.length === 0
|
: !tagList || tagList.length === 0
|
||||||
? <Empty url={tagEmpty} title={t('dashboard.activityEmpty')} size={120} className="rb:mt-9 rb:mb-20.25" />
|
? <Empty url={tagEmpty} title={t('dashboard.activityEmpty')} size={120} className="rb:mt-9 rb:mb-20.25" />
|
||||||
: <div className="rb:gap-3 rb:flex rb:flex-wrap">
|
: <Flex wrap className="rb:gap-x-3! rb:gap-y-2.5!">
|
||||||
{tagList.map((item, index) => (
|
{tagList.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={item.name}
|
key={item.name}
|
||||||
className={clsx("rb:pt-1.5 rb:pb-1.5 rb:pr-5.75 rb:pl-5 rb:border rb:leading-5 rb:bg-white rb:rounded-[17px]", {
|
className={clsx("rb:rounded-[17px] rb:py-1.5 rb:pl-3 rb:pr-2", btnStyleList[index % 3])}
|
||||||
'rb:border-[rgba(21,94,239,0.4)] rb:text-[#155EEF]': index % 3 === 0,
|
>
|
||||||
'rb:border-[rgba(255,138,76,0.4)] rb:text-[#FF5D34]': index % 3 === 1,
|
{item.name}
|
||||||
'rb:border-[rgba(54,159,33,0.4)] rb:text-[#369F21]': index % 3 === 2,
|
<span className={clsx('rb:px-2 rb:py-0.5 rb:rounded-[10px] rb:text-[#FFFFFF] rb:text-[12px] rb:font-bold rb:font-[MiSans-Demibold] rb:ml-2', numStyleList[index % 3])}>{item.frequency}</span>
|
||||||
})}
|
</div>
|
||||||
>{item.name} {item.frequency}</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</Flex>
|
||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
112
web/src/views/Home/components/TopCardList.tsx
Normal file
112
web/src/views/Home/components/TopCardList.tsx
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* @Author: ZhaoYing
|
||||||
|
* @Date: 2026-02-03 17:28:07
|
||||||
|
* @Last Modified by: ZhaoYing
|
||||||
|
* @Last Modified time: 2026-02-11 14:57:55
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Top Card List Component
|
||||||
|
* Displays dashboard summary cards for key metrics
|
||||||
|
* Shows total memory capacity, applications, knowledge bases, and API calls
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { type FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { Flex } from 'antd';
|
||||||
|
|
||||||
|
import totalMemoryCapacity from '@/assets/images/home/totalMemoryCapacity.svg';
|
||||||
|
import userMemory from '@/assets/images/home/userMemory.svg';
|
||||||
|
import knowledgeBaseCount from '@/assets/images/home/knowledgeBaseCount.svg';
|
||||||
|
import apiCallCount from '@/assets/images/home/apiCallCount.svg';
|
||||||
|
import type { DashboardData } from '../index'
|
||||||
|
|
||||||
|
/** Card configuration with styling */
|
||||||
|
const list = [
|
||||||
|
{
|
||||||
|
key: 'totalMemoryCapacity',
|
||||||
|
icon: totalMemoryCapacity,
|
||||||
|
// value: '45,678',
|
||||||
|
// trendValue: '12.5%',
|
||||||
|
// trend: 'up',
|
||||||
|
// trendDesc: 'comparedToYesterday',
|
||||||
|
background: 'rb:bg-[url("@/assets/images/home/totalMemoryCapacity.png")] rb:bg-cover rb:bg-no-repeat',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'application',
|
||||||
|
icon: userMemory,
|
||||||
|
// value: '32,145',
|
||||||
|
// trendValue: '12.5%',
|
||||||
|
// trend: 'down',
|
||||||
|
// trendDesc: 'comparedToYesterday',
|
||||||
|
// background: 'linear-gradient( 180deg, #F1FBF5 0%, #F9FDFF 100%)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'knowledgeBaseCount',
|
||||||
|
icon: knowledgeBaseCount,
|
||||||
|
// value: '13,533',
|
||||||
|
// trendValue: '15.7%',
|
||||||
|
// trend: 'up',
|
||||||
|
// trendDesc: 'thisWeek',
|
||||||
|
// background: 'linear-gradient( 180deg, #E6F5FE 0%, #FBFDFF 100%)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'apiCallCount',
|
||||||
|
icon: apiCallCount,
|
||||||
|
// value: '856.2k',
|
||||||
|
// trendValue: '23.1%',
|
||||||
|
// trend: 'up',
|
||||||
|
// trendDesc: 'comparedToYesterday',
|
||||||
|
// background: 'linear-gradient( 180deg, #F8F6F5 0%, #FAFDFF 100%)',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
/**
|
||||||
|
* Component props
|
||||||
|
* @param data - Dashboard statistics data
|
||||||
|
*/
|
||||||
|
const TopCardList: FC<{data?: DashboardData}> = ({ data }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
return (
|
||||||
|
<div className="rb:grid rb:grid-cols-2 rb:gap-3">
|
||||||
|
{list.map((item) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={item.key}
|
||||||
|
className={`rb:rounded-2xl rb:bg-[#FFFFFF] rb:py-4 rb:px-3 ${item.background || ''}`}
|
||||||
|
>
|
||||||
|
<div className={clsx("rb:text-[12px] rb:leading-4", {
|
||||||
|
'rb:text-[#FFFFFF]': item.key === 'totalMemoryCapacity',
|
||||||
|
'rb:text-[#5B6167]': item.key !== 'totalMemoryCapacity',
|
||||||
|
})}>{t(`dashboard.${item.key}`)}</div>
|
||||||
|
|
||||||
|
<div className={clsx("rb:text-[20px] rb:font-bold rb:leading-7 rb:mt-1 rb:font-[MiSans-Bold]", {
|
||||||
|
'rb:text-[#FFFFFF]': item.key === 'totalMemoryCapacity',
|
||||||
|
// 'rb:text-[#171719]': item.key !== 'totalMemoryCapacity',
|
||||||
|
})}>
|
||||||
|
{data?.[item.key as keyof DashboardData] || 0}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Flex align="center" className={clsx('rb:font-medium rb:mt-7.5!', {
|
||||||
|
'rb:text-[#FFFFFF]': item.key === 'totalMemoryCapacity',
|
||||||
|
'rb:text-[#369F21]': item.key !== 'totalMemoryCapacity',
|
||||||
|
})}>
|
||||||
|
0%
|
||||||
|
<div className={clsx("rb:size-3.5 rb:cursor-pointer rb:bg-cover", {
|
||||||
|
"rb:bg-[url('@/assets/images/home/arrow_up.svg')]": item.key === 'totalMemoryCapacity',
|
||||||
|
"rb:bg-[url('@/assets/images/home/arrow_up_success.svg')]": item.key !== 'totalMemoryCapacity',
|
||||||
|
})}></div>
|
||||||
|
</Flex>
|
||||||
|
<div className={clsx("rb:text-[12px] rb:leading-4 rb:mt-0.5", {
|
||||||
|
'rb:text-[#FFFFFF]': item.key === 'totalMemoryCapacity',
|
||||||
|
'rb:text-[#5B6167]': item.key !== 'totalMemoryCapacity',
|
||||||
|
})}>
|
||||||
|
{t('dashboard.comparedToYesterday')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TopCardList
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
.card {
|
|
||||||
border-radius: 12px;
|
|
||||||
border: 1px solid #DFE4ED;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
padding: 20px;
|
|
||||||
line-height: 44px;
|
|
||||||
font-family: PingFangSC, PingFang SC;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #5B6167;
|
|
||||||
font-style: normal;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid #DFE4ED;
|
|
||||||
}
|
|
||||||
.avatar {
|
|
||||||
width: 44px;
|
|
||||||
height: 44px;
|
|
||||||
background: #FFFFFF;
|
|
||||||
box-shadow: 0px 2px 6px 0px rgba(33, 35, 50, 0.1);
|
|
||||||
border-radius: 22px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
.avatar img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
padding: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-family: Gilroy, Gilroy;
|
|
||||||
font-weight: 800;
|
|
||||||
font-size: 28px;
|
|
||||||
color: #212332;
|
|
||||||
text-align: left;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
.content-right {
|
|
||||||
text-align: right;
|
|
||||||
font-family: PingFangSC, PingFang SC;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #5F6266;
|
|
||||||
line-height: 16px;
|
|
||||||
font-style: normal;
|
|
||||||
row-gap: 4px;
|
|
||||||
}
|
|
||||||
.trend {
|
|
||||||
font-family: PingFangSC, PingFang SC;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 16px;
|
|
||||||
font-style: normal;
|
|
||||||
padding-left: 15px;
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.trend::before {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 1px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
.trend.up {
|
|
||||||
color: #369F21;
|
|
||||||
}
|
|
||||||
.trend.up::before {
|
|
||||||
background-image: url('@/assets/images/home/arrow_up_success.svg');
|
|
||||||
}
|
|
||||||
.trend.down {
|
|
||||||
color: #FF5D34;
|
|
||||||
}
|
|
||||||
.trend.down::before {
|
|
||||||
background-image: url('@/assets/images/home/arrow_down.png');
|
|
||||||
}
|
|
||||||
|
|
||||||
.trend-desc {
|
|
||||||
font-family: PingFangSC, PingFang SC;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #155EEF;
|
|
||||||
line-height: 16px;
|
|
||||||
text-align: left;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: ZhaoYing
|
|
||||||
* @Date: 2026-02-03 17:28:07
|
|
||||||
* @Last Modified by: ZhaoYing
|
|
||||||
* @Last Modified time: 2026-02-03 17:28:07
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Top Card List Component
|
|
||||||
* Displays dashboard summary cards for key metrics
|
|
||||||
* Shows total memory capacity, applications, knowledge bases, and API calls
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { type FC } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
import totalMemoryCapacity from '@/assets/images/home/totalMemoryCapacity.svg';
|
|
||||||
import userMemory from '@/assets/images/home/userMemory.svg';
|
|
||||||
import knowledgeBaseCount from '@/assets/images/home/knowledgeBaseCount.svg';
|
|
||||||
import apiCallCount from '@/assets/images/home/apiCallCount.svg';
|
|
||||||
import styles from './index.module.css'
|
|
||||||
import type { DashboardData } from '../../index'
|
|
||||||
|
|
||||||
/** Card configuration with styling */
|
|
||||||
const list = [
|
|
||||||
{
|
|
||||||
key: 'totalMemoryCapacity',
|
|
||||||
icon: totalMemoryCapacity,
|
|
||||||
// value: '45,678',
|
|
||||||
// trendValue: '12.5%',
|
|
||||||
// trend: 'up',
|
|
||||||
// trendDesc: 'comparedToYesterday',
|
|
||||||
background: 'linear-gradient(180deg, #E6EFFE 0%, #F9FDFF 100%)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'application',
|
|
||||||
icon: userMemory,
|
|
||||||
// value: '32,145',
|
|
||||||
// trendValue: '12.5%',
|
|
||||||
// trend: 'down',
|
|
||||||
// trendDesc: 'comparedToYesterday',
|
|
||||||
background: 'linear-gradient( 180deg, #F1FBF5 0%, #F9FDFF 100%)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'knowledgeBaseCount',
|
|
||||||
icon: knowledgeBaseCount,
|
|
||||||
// value: '13,533',
|
|
||||||
// trendValue: '15.7%',
|
|
||||||
// trend: 'up',
|
|
||||||
// trendDesc: 'thisWeek',
|
|
||||||
background: 'linear-gradient( 180deg, #E6F5FE 0%, #FBFDFF 100%)',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'apiCallCount',
|
|
||||||
icon: apiCallCount,
|
|
||||||
// value: '856.2k',
|
|
||||||
// trendValue: '23.1%',
|
|
||||||
// trend: 'up',
|
|
||||||
// trendDesc: 'comparedToYesterday',
|
|
||||||
background: 'linear-gradient( 180deg, #F8F6F5 0%, #FAFDFF 100%)',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
/**
|
|
||||||
* Component props
|
|
||||||
* @param data - Dashboard statistics data
|
|
||||||
*/
|
|
||||||
const TopCardList: FC<{data?: DashboardData}> = ({ data }) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
return (
|
|
||||||
<div className="rb:grid rb:grid-cols-4 rb:gap-4">
|
|
||||||
{list.map((item) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={item.key}
|
|
||||||
className={styles.card}
|
|
||||||
style={{
|
|
||||||
background: item.background,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<div className={styles.avatar}><img src={item.icon} /></div>
|
|
||||||
<div className={styles.headerTitle}>{t(`dashboard.${item.key}`)}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.content}>
|
|
||||||
{data?.[item.key as keyof DashboardData] || 0}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TopCardList
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:12:43
|
* @Date: 2026-02-03 17:12:43
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:26:04
|
* @Last Modified time: 2026-02-10 11:57:58
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Home Dashboard Page
|
* Home Dashboard Page
|
||||||
@@ -19,6 +19,7 @@ import { getDashboardData, getMemoryIncrement, getKbTypes } from '@/api/memory';
|
|||||||
import RecentActivity from './components/RecentActivity'
|
import RecentActivity from './components/RecentActivity'
|
||||||
import TagList from './components/TagList'
|
import TagList from './components/TagList'
|
||||||
import QuickOperation from './components/QuickOperation'
|
import QuickOperation from './components/QuickOperation'
|
||||||
|
import ApiLineCard from './components/ApiLineCard'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard statistics data
|
* Dashboard statistics data
|
||||||
@@ -120,42 +121,39 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rb:pb-6">
|
<Row gutter={[12, 12]}>
|
||||||
<TopCardList data={dashboardData} />
|
<Col span={8}>
|
||||||
|
<TopCardList data={dashboardData} />
|
||||||
<Row className="rb:mt-4" gutter={16}>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={8}>
|
||||||
<LineCard
|
<LineCard
|
||||||
chartData={memoryIncrement}
|
chartData={memoryIncrement}
|
||||||
limit={limit}
|
limit={limit}
|
||||||
onChange={handleRangeChange}
|
onChange={handleRangeChange}
|
||||||
type="memoryGrowthTrend"
|
type="memoryGrowthTrend"
|
||||||
seriesList={['total_num']}
|
seriesList={['total_num']}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={8}>
|
||||||
<PieCard
|
<ApiLineCard
|
||||||
loading={loading.knowledgeTypeDistribution}
|
/>
|
||||||
chartData={knowledgeTypeDistribution}
|
</Col>
|
||||||
/>
|
<Col span={8}>
|
||||||
</Col>
|
<PieCard
|
||||||
</Row>
|
loading={loading.knowledgeTypeDistribution}
|
||||||
|
chartData={knowledgeTypeDistribution}
|
||||||
<Row className="rb:mt-4" gutter={16}>
|
/>
|
||||||
<Col span={12}>
|
</Col>
|
||||||
<RecentActivity />
|
<Col span={8}>
|
||||||
</Col>
|
<RecentActivity />
|
||||||
<Col span={12}>
|
</Col>
|
||||||
<TagList />
|
<Col span={8}>
|
||||||
</Col>
|
<QuickOperation />
|
||||||
</Row>
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
<Row className="rb:mt-4" gutter={16}>
|
<TagList />
|
||||||
<Col span={24}>
|
</Col>
|
||||||
<QuickOperation />
|
</Row>
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user