371 lines
16 KiB
TypeScript
371 lines
16 KiB
TypeScript
"use client";
|
|||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import { FileText, Download, Eye, Edit, Plus, Trash2, CheckSquare, Square } from "lucide-react";
|
||
|
|
|
||
|
|
interface ReportTemplate {
|
||
|
|
id: string;
|
||
|
|
name: string;
|
||
|
|
description: string;
|
||
|
|
sections: string[];
|
||
|
|
created_at: string;
|
||
|
|
usage_count: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface GeneratedReport {
|
||
|
|
template_name: string;
|
||
|
|
generated_at: string;
|
||
|
|
content: {
|
||
|
|
title: string;
|
||
|
|
sections: Array<{
|
||
|
|
name: string;
|
||
|
|
content: string;
|
||
|
|
}>;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function ReportAssistantPage() {
|
||
|
|
const [activeTab, setActiveTab] = useState<"generate" | "templates">("generate");
|
||
|
|
const [selectedTemplate, setSelectedTemplate] = useState<string>("");
|
||
|
|
const [projectInfo, setProjectInfo] = useState({
|
||
|
|
customer_name: "远东新能源公交公司",
|
||
|
|
project_type: "对公新能源",
|
||
|
|
amount: 3.0,
|
||
|
|
risk_level: "medium"
|
||
|
|
});
|
||
|
|
|
||
|
|
const [loading, setLoading] = useState(false);
|
||
|
|
const [generatedReport, setGeneratedReport] = useState<GeneratedReport | null>(null);
|
||
|
|
|
||
|
|
// 模拟报告模板数据
|
||
|
|
const [templates] = useState<ReportTemplate[]>([
|
||
|
|
{
|
||
|
|
id: "TPL-001",
|
||
|
|
name: "标准风险评审报告",
|
||
|
|
description: "适用于常规项目的风险评审报告,包含完整的风险分析和建议",
|
||
|
|
sections: ["项目概况", "风险识别", "财务分析", "法律合规性", "综合评审意见", "审批建议"],
|
||
|
|
created_at: "2025-01-15",
|
||
|
|
usage_count: 156
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "TPL-002",
|
||
|
|
name: "新能源项目专项报告",
|
||
|
|
description: "针对新能源行业的专项评审报告,关注政策补贴和行业风险",
|
||
|
|
sections: ["项目概况", "行业政策分析", "技术可行性", "财务测算", "风险评估", "审批建议"],
|
||
|
|
created_at: "2025-02-10",
|
||
|
|
usage_count: 89
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "TPL-003",
|
||
|
|
name: "大额授信专项报告",
|
||
|
|
description: "5亿元以上大额授信项目的详细评审报告",
|
||
|
|
sections: ["项目概况", "企业背景调查", "深度财务分析", "抵押物评估", "风险缓释措施", "总部审批建议"],
|
||
|
|
created_at: "2025-01-20",
|
||
|
|
usage_count: 34
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: "TPL-004",
|
||
|
|
name: "快速审批简报",
|
||
|
|
description: "低风险项目的快速审批简报,简化流程",
|
||
|
|
sections: ["项目基本信息", "快速风险评估", "审批建议"],
|
||
|
|
created_at: "2025-02-01",
|
||
|
|
usage_count: 203
|
||
|
|
}
|
||
|
|
]);
|
||
|
|
|
||
|
|
const handleGenerateReport = async () => {
|
||
|
|
if (!selectedTemplate) {
|
||
|
|
alert("请先选择报告模板");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
setLoading(true);
|
||
|
|
setGeneratedReport(null);
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 模拟生成报告
|
||
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
||
|
|
|
||
|
|
const template = templates.find(t => t.id === selectedTemplate)!;
|
||
|
|
|
||
|
|
const mockReport: GeneratedReport = {
|
||
|
|
template_name: template.name,
|
||
|
|
generated_at: new Date().toLocaleString('zh-CN'),
|
||
|
|
content: {
|
||
|
|
title: `${projectInfo.customer_name} - ${template.name}`,
|
||
|
|
sections: template.sections.map(sectionName => ({
|
||
|
|
name: sectionName,
|
||
|
|
content: generateMockSectionContent(sectionName, projectInfo)
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
setGeneratedReport(mockReport);
|
||
|
|
} catch (error) {
|
||
|
|
alert("生成报告失败");
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const generateMockSectionContent = (sectionName: string, info: any): string => {
|
||
|
|
switch (sectionName) {
|
||
|
|
case "项目概况":
|
||
|
|
return `客户名称:${info.customer_name}\n项目类型:${info.project_type}\n授信金额:${info.amount}亿元\n风险等级:${info.risk_level === 'high' ? '高风险' : info.risk_level === 'medium' ? '中风险' : '低风险'}\n\n本项目为${info.project_type}类型融资租赁项目,客户${info.customer_name}申请授信金额${info.amount}亿元。经初步评估,项目风险等级为${info.risk_level === 'high' ? '高风险' : info.risk_level === 'medium' ? '中风险' : '低风险'}。`;
|
||
|
|
|
||
|
|
case "风险识别":
|
||
|
|
case "风险评估":
|
||
|
|
return `基于双轨驱动分析(规则引擎+历史数据),识别出以下主要风险点:\n\n1. 财务风险:资产负债率接近行业警戒线,需关注偿债能力\n2. 信用风险:征信查询次数偏高,需核实融资需求真实性\n3. 法律风险:存在未结案涉诉记录,需评估潜在影响\n\n历史数据显示,类似项目的通过率为73%,其中60%需要附加风控措施。`;
|
||
|
|
|
||
|
|
case "财务分析":
|
||
|
|
case "深度财务分析":
|
||
|
|
return `关键财务指标分析:\n\n• 资产负债率:65%(行业平均60%)\n• 流动比率:1.2(良好)\n• 净资产收益率:8.5%(中等)\n• 现金流覆盖倍数:1.8倍\n\n综合评估:财务状况整体可控,但需关注债务结构优化。`;
|
||
|
|
|
||
|
|
case "审批建议":
|
||
|
|
case "综合评审意见":
|
||
|
|
return `综合评审意见:\n\n建议:附加条件通过\n\n理由:\n1. 客户基本面良好,行业前景明朗\n2. 财务指标整体可控,但需加强风险缓释\n3. 历史同类案例成功率较高\n\n附加条件:\n• 建议降低授信额度10-15%\n• 要求增加抵押物或第三方担保\n• 设置季度财务监控机制`;
|
||
|
|
|
||
|
|
case "行业政策分析":
|
||
|
|
return `${info.project_type}行业政策环境:\n\n• 国家政策支持力度大,补贴政策稳定\n• 地方政府配套措施完善\n• 行业准入门槛提高,竞争格局改善\n• 需关注补贴退坡风险`;
|
||
|
|
|
||
|
|
case "技术可行性":
|
||
|
|
return `技术方案评估:\n\n• 技术路线成熟,市场验证充分\n• 设备供应商资质良好\n• 运营团队经验丰富\n• 维护保养体系完善`;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return `${sectionName}相关内容...\n\n[此部分内容由AI根据项目实际情况和历史数据自动生成]`;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 text-white p-6">
|
||
|
|
{/* Header */}
|
||
|
|
<header className="mb-8">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div>
|
||
|
|
<h1 className="text-3xl font-bold mb-2 bg-gradient-to-r from-purple-400 to-pink-300 bg-clip-text text-transparent">
|
||
|
|
报告助手
|
||
|
|
</h1>
|
||
|
|
<p className="text-slate-400">智能报告生成与模板管理</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
{/* Tab Navigation */}
|
||
|
|
<div className="mb-6 flex gap-2">
|
||
|
|
<button
|
||
|
|
onClick={() => setActiveTab("generate")}
|
||
|
|
className={`px-6 py-3 rounded-lg font-medium transition-colors ${
|
||
|
|
activeTab === "generate"
|
||
|
|
? "bg-purple-600 text-white"
|
||
|
|
: "bg-slate-800 text-slate-400 hover:bg-slate-700"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
生成报告
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => setActiveTab("templates")}
|
||
|
|
className={`px-6 py-3 rounded-lg font-medium transition-colors ${
|
||
|
|
activeTab === "templates"
|
||
|
|
? "bg-purple-600 text-white"
|
||
|
|
: "bg-slate-800 text-slate-400 hover:bg-slate-700"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
模板管理
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Generate Report Tab */}
|
||
|
|
{activeTab === "generate" && (
|
||
|
|
<div className="space-y-6">
|
||
|
|
{/* Project Info Form */}
|
||
|
|
<div className="p-6 bg-slate-800/50 backdrop-blur-sm rounded-xl border border-slate-700">
|
||
|
|
<h2 className="text-xl font-bold mb-4 text-purple-400">项目信息</h2>
|
||
|
|
<div className="grid grid-cols-2 gap-4">
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm text-slate-400 mb-2">客户名称</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
value={projectInfo.customer_name}
|
||
|
|
onChange={e => setProjectInfo({ ...projectInfo, customer_name: e.target.value })}
|
||
|
|
className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:border-purple-500"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm text-slate-400 mb-2">项目类型</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
value={projectInfo.project_type}
|
||
|
|
onChange={e => setProjectInfo({ ...projectInfo, project_type: e.target.value })}
|
||
|
|
className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:border-purple-500"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm text-slate-400 mb-2">授信金额(亿元)</label>
|
||
|
|
<input
|
||
|
|
type="number"
|
||
|
|
step="0.1"
|
||
|
|
value={projectInfo.amount}
|
||
|
|
onChange={e => setProjectInfo({ ...projectInfo, amount: parseFloat(e.target.value) })}
|
||
|
|
className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:border-purple-500"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<label className="block text-sm text-slate-400 mb-2">风险等级</label>
|
||
|
|
<select
|
||
|
|
value={projectInfo.risk_level}
|
||
|
|
onChange={e => setProjectInfo({ ...projectInfo, risk_level: e.target.value })}
|
||
|
|
className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:border-purple-500"
|
||
|
|
>
|
||
|
|
<option value="low">低风险</option>
|
||
|
|
<option value="medium">中风险</option>
|
||
|
|
<option value="high">高风险</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Template Selection */}
|
||
|
|
<div className="p-6 bg-slate-800/50 backdrop-blur-sm rounded-xl border border-slate-700">
|
||
|
|
<h2 className="text-xl font-bold mb-4 text-purple-400">选择报告模板</h2>
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
|
|
{templates.map(template => (
|
||
|
|
<div
|
||
|
|
key={template.id}
|
||
|
|
onClick={() => setSelectedTemplate(template.id)}
|
||
|
|
className={`p-4 rounded-lg border-2 cursor-pointer transition-all ${
|
||
|
|
selectedTemplate === template.id
|
||
|
|
? "border-purple-500 bg-purple-900/30"
|
||
|
|
: "border-slate-700 bg-slate-900/50 hover:border-slate-600"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<div className="flex items-start justify-between mb-2">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
{selectedTemplate === template.id ? (
|
||
|
|
<CheckSquare className="w-5 h-5 text-purple-400" />
|
||
|
|
) : (
|
||
|
|
<Square className="w-5 h-5 text-slate-600" />
|
||
|
|
)}
|
||
|
|
<h3 className="font-bold text-white">{template.name}</h3>
|
||
|
|
</div>
|
||
|
|
<span className="text-xs text-slate-500">{template.id}</span>
|
||
|
|
</div>
|
||
|
|
<p className="text-sm text-slate-400 mb-3">{template.description}</p>
|
||
|
|
<div className="flex items-center gap-4 text-xs text-slate-500">
|
||
|
|
<span>使用次数: {template.usage_count}</span>
|
||
|
|
<span>创建: {template.created_at}</span>
|
||
|
|
</div>
|
||
|
|
<div className="mt-2 text-xs text-slate-500">
|
||
|
|
章节: {template.sections.join(" · ")}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<button
|
||
|
|
onClick={handleGenerateReport}
|
||
|
|
disabled={loading || !selectedTemplate}
|
||
|
|
className={`mt-6 w-full py-3 rounded-lg font-bold text-lg transition-all ${
|
||
|
|
loading || !selectedTemplate
|
||
|
|
? "bg-slate-700 text-slate-500 cursor-not-allowed"
|
||
|
|
: "bg-gradient-to-r from-purple-600 to-pink-600 hover:shadow-xl hover:scale-[1.02]"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{loading ? "🔄 正在生成报告..." : "📝 生成评审报告"}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Generated Report */}
|
||
|
|
{generatedReport && (
|
||
|
|
<div className="p-6 bg-slate-800/50 backdrop-blur-sm rounded-xl border border-slate-700">
|
||
|
|
<div className="flex items-center justify-between mb-6">
|
||
|
|
<div>
|
||
|
|
<h2 className="text-xl font-bold text-purple-400">{generatedReport.content.title}</h2>
|
||
|
|
<p className="text-sm text-slate-400">生成时间: {generatedReport.generated_at}</p>
|
||
|
|
</div>
|
||
|
|
<div className="flex gap-2">
|
||
|
|
<button className="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg text-sm font-medium flex items-center gap-2 transition-colors">
|
||
|
|
<Eye className="w-4 h-4" />
|
||
|
|
预览
|
||
|
|
</button>
|
||
|
|
<button className="px-4 py-2 bg-green-600 hover:bg-green-700 rounded-lg text-sm font-medium flex items-center gap-2 transition-colors">
|
||
|
|
<Download className="w-4 h-4" />
|
||
|
|
导出
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="space-y-6">
|
||
|
|
{generatedReport.content.sections.map((section, idx) => (
|
||
|
|
<div key={idx} className="p-4 bg-slate-900/50 rounded-lg">
|
||
|
|
<h3 className="text-lg font-bold text-white mb-3">{section.name}</h3>
|
||
|
|
<p className="text-sm text-slate-300 whitespace-pre-line leading-relaxed">
|
||
|
|
{section.content}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Templates Tab */}
|
||
|
|
{activeTab === "templates" && (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<div className="flex justify-between items-center">
|
||
|
|
<h2 className="text-xl font-bold text-purple-400">报告模板库</h2>
|
||
|
|
<button className="px-4 py-2 bg-purple-600 hover:bg-purple-700 rounded-lg font-medium flex items-center gap-2 transition-colors">
|
||
|
|
<Plus className="w-4 h-4" />
|
||
|
|
新建模板
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="grid grid-cols-1 gap-4">
|
||
|
|
{templates.map(template => (
|
||
|
|
<div
|
||
|
|
key={template.id}
|
||
|
|
className="p-6 bg-slate-800/50 backdrop-blur-sm rounded-xl border border-slate-700"
|
||
|
|
>
|
||
|
|
<div className="flex items-start justify-between mb-4">
|
||
|
|
<div className="flex-1">
|
||
|
|
<div className="flex items-center gap-3 mb-2">
|
||
|
|
<FileText className="w-5 h-5 text-purple-400" />
|
||
|
|
<h3 className="text-lg font-bold text-white">{template.name}</h3>
|
||
|
|
<span className="text-xs text-slate-500 font-mono">{template.id}</span>
|
||
|
|
</div>
|
||
|
|
<p className="text-sm text-slate-400">{template.description}</p>
|
||
|
|
</div>
|
||
|
|
<div className="flex gap-2">
|
||
|
|
<button className="p-2 text-slate-400 hover:text-blue-400 hover:bg-slate-700 rounded-lg transition-colors">
|
||
|
|
<Edit className="w-4 h-4" />
|
||
|
|
</button>
|
||
|
|
<button className="p-2 text-slate-400 hover:text-red-400 hover:bg-slate-700 rounded-lg transition-colors">
|
||
|
|
<Trash2 className="w-4 h-4" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex flex-wrap gap-2 mb-3">
|
||
|
|
{template.sections.map((section, idx) => (
|
||
|
|
<span
|
||
|
|
key={idx}
|
||
|
|
className="px-2 py-1 bg-slate-700 rounded text-xs text-slate-300"
|
||
|
|
>
|
||
|
|
{section}
|
||
|
|
</span>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center gap-6 text-xs text-slate-500">
|
||
|
|
<span>使用次数: {template.usage_count}</span>
|
||
|
|
<span>创建时间: {template.created_at}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|