Fundamental_Analysis/frontend/src/app/report/[symbol]/components/AnalysisContent.tsx
Lv, Qi 4fef6bf35b refactor: 拆分 ReportPage 为组件和 Hooks
- 将庞大的 page.tsx 拆分为多个独立组件 (components/)
- 提取业务逻辑到 Hooks (hooks/)
- 提取工具函数到 utils.ts
- 优化代码结构和可维护性
2025-11-19 06:51:46 +08:00

116 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { Spinner } from '@/components/ui/spinner';
import { Button } from '@/components/ui/button';
import { CheckCircle, XCircle, RotateCw } from 'lucide-react';
import { normalizeMarkdown, removeTitleFromContent } from '../utils';
interface AnalysisContentProps {
analysisType: string;
state: {
content: string;
loading: boolean;
error: string | null;
};
financials: any;
analysisConfig: any;
retryAnalysis: (type: string) => void;
currentAnalysisTask: string | null;
}
export function AnalysisContent({
analysisType,
state,
financials,
analysisConfig,
retryAnalysis,
currentAnalysisTask,
}: AnalysisContentProps) {
const analysisName = analysisType === 'company_profile'
? '公司简介'
: (analysisConfig?.analysis_modules?.[analysisType]?.name || analysisType);
const modelName = analysisConfig?.analysis_modules?.[analysisType]?.model;
// Process content
const contentWithoutTitle = removeTitleFromContent(state.content, analysisName);
const normalizedContent = normalizeMarkdown(contentWithoutTitle);
return (
<div className="space-y-4">
<h2 className="text-lg font-medium">{analysisName} {modelName || 'AI'}</h2>
{!financials && (
<p className="text-sm text-muted-foreground">...</p>
)}
{financials && (
<>
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-3 text-sm">
{state.loading ? (
<Spinner className="size-4" />
) : state.error ? (
<XCircle className="size-4 text-red-500" />
) : state.content ? (
<CheckCircle className="size-4 text-green-600" />
) : null}
<div className="text-muted-foreground">
{state.loading
? `正在生成${analysisName}...`
: state.error
? '生成失败'
: state.content
? '生成完成'
: '待开始'}
</div>
</div>
{/* 始终可见的"重新生成分析"按钮 */}
{!state.loading && (
<Button
variant="ghost"
size="sm"
onClick={() => retryAnalysis(analysisType)}
disabled={currentAnalysisTask !== null}
>
<RotateCw className="size-4" />
</Button>
)}
</div>
{state.error && (
<p className="text-red-500">: {state.error}</p>
)}
{(state.loading || state.content) && (
<div className="space-y-4">
<div className="border rounded-lg p-6 bg-card">
<article className="markdown-body" style={{
boxSizing: 'border-box',
minWidth: '200px',
maxWidth: '980px',
margin: '0 auto',
padding: '0'
}}>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
>
{normalizedContent}
</ReactMarkdown>
{state.loading && (
<span className="inline-flex items-center gap-2 mt-2 text-muted-foreground">
<Spinner className="size-3" />
<span className="text-sm">...</span>
</span>
)}
</article>
</div>
</div>
)}
</>
)}
</div>
);
}