feat(ui): 管家 Tab 空状态增加引导文案 + 立即分析按钮
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

- 无数据时显示友好引导文案
- 分析按钮要求至少 2 条对话
- 分析中显示加载状态
This commit is contained in:
iven
2026-04-11 12:58:27 +08:00
parent ce10befff1
commit 730d50bc63

View File

@@ -1,4 +1,6 @@
import { useState } from 'react';
import { useButlerInsights } from '../../hooks/useButlerInsights';
import { useChatStore } from '../../store/chatStore';
import { InsightsSection } from './InsightsSection';
import { ProposalsSection } from './ProposalsSection';
import { MemorySection } from './MemorySection';
@@ -9,6 +11,21 @@ interface ButlerPanelProps {
export function ButlerPanel({ agentId }: ButlerPanelProps) {
const { painPoints, proposals, loading, error, refresh } = useButlerInsights(agentId);
const messageCount = useChatStore((s) => s.messages.length);
const [analyzing, setAnalyzing] = useState(false);
const hasData = (painPoints?.length ?? 0) > 0 || (proposals?.length ?? 0) > 0;
const canAnalyze = messageCount >= 2;
const handleAnalyze = async () => {
if (!canAnalyze || analyzing) return;
setAnalyzing(true);
try {
await refresh();
} finally {
setAnalyzing(false);
}
};
if (!agentId) {
return (
@@ -32,23 +49,51 @@ export function ButlerPanel({ agentId }: ButlerPanelProps) {
</div>
)}
{/* Insights section */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2">
</h3>
<InsightsSection painPoints={painPoints} onGenerate={refresh} />
</div>
{!loading && !hasData && (
<div className="flex flex-col items-center justify-center py-8 text-center">
<div className="text-gray-400 dark:text-gray-500 mb-3">
<svg className="w-12 h-12 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" />
</svg>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-3">
</p>
<button
onClick={handleAnalyze}
disabled={!canAnalyze || analyzing}
className={`text-xs px-3 py-1.5 rounded-lg transition-colors ${
canAnalyze && !analyzing
? 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 hover:bg-blue-100 dark:hover:bg-blue-900/30'
: 'bg-gray-100 dark:bg-gray-800 text-gray-400 dark:text-gray-500 cursor-not-allowed'
}`}
>
{analyzing ? '分析中...' : canAnalyze ? '立即分析对话' : '至少需要 2 条对话才能分析'}
</button>
</div>
)}
{/* Proposals section */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2">
</h3>
<ProposalsSection proposals={proposals} onStatusChange={refresh} />
</div>
{(hasData || loading) && (
<>
{/* Insights section */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2">
</h3>
<InsightsSection painPoints={painPoints} onGenerate={refresh} />
</div>
{/* Memory section */}
{/* Proposals section */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2">
</h3>
<ProposalsSection proposals={proposals} onStatusChange={refresh} />
</div>
</>
)}
{/* Memory section (always show) */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2">