feat: 优化分析中心图表生成&markdown内容显示
This commit is contained in:
parent
a191d88ef2
commit
7c2752d074
@ -85,6 +85,12 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.ant-list-item-meta {
|
||||||
|
width: 40vw !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
background: #1890ff;
|
background: #1890ff;
|
||||||
}
|
}
|
||||||
@ -92,6 +98,7 @@
|
|||||||
.chartContainer {
|
.chartContainer {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
width: 40vw;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
||||||
|
@ -29,6 +29,7 @@ import type { UploadFile } from 'antd/es/upload/interface';
|
|||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const { Dragger } = Upload;
|
const { Dragger } = Upload;
|
||||||
@ -107,79 +108,7 @@ const AnalysisCenter: React.FC = () => {
|
|||||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFileAnalysis = async (file: File) => {
|
const handleSend = async () => {
|
||||||
try {
|
|
||||||
const reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = async (e) => {
|
|
||||||
const data = e.target?.result;
|
|
||||||
let textContent = '';
|
|
||||||
|
|
||||||
if (file.name.toLowerCase().endsWith('.csv')) {
|
|
||||||
textContent = data as string;
|
|
||||||
} else {
|
|
||||||
const workbook = XLSX.read(data, { type: 'array' });
|
|
||||||
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
||||||
const jsonData = XLSX.utils.sheet_to_json(firstSheet, { header: 1 });
|
|
||||||
textContent = jsonData.map(row => row.join('\t')).join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch('https://aizex.top/v1/chat/completions', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'Authorization': 'Bearer sk-Bp4AtAw19a6lENrPUQeqfiS9KP46Z5A43j4QkNeX4NRnGKMU'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: 'gpt-4o',
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: 'user',
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
text: `请对以下数据进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解:\n${textContent}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
max_tokens: 2000
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
const userMessage: Message = {
|
|
||||||
type: 'user',
|
|
||||||
content: `已上传文件:${file.name}`,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const assistantMessage: Message = {
|
|
||||||
type: 'assistant',
|
|
||||||
content: result.choices[0].message.content,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
charts: generateMockChart(analysisType),
|
|
||||||
};
|
|
||||||
|
|
||||||
setMessages(prev => [...prev, userMessage, assistantMessage]);
|
|
||||||
setLoading(false);
|
|
||||||
scrollToBottom();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (file.name.toLowerCase().endsWith('.csv')) {
|
|
||||||
reader.readAsText(file);
|
|
||||||
} else {
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('文件处理失败:', error);
|
|
||||||
message.error('文件处理失败');
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSend = async () => {
|
|
||||||
if (!inputValue.trim()) return;
|
if (!inputValue.trim()) return;
|
||||||
|
|
||||||
const userMessage: Message = {
|
const userMessage: Message = {
|
||||||
@ -193,148 +122,295 @@ const AnalysisCenter: React.FC = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 这里应该调用后端API进行分析
|
const response = await fetch('https://aizex.top/v1/chat/completions', {
|
||||||
// const response = await analyzeData({ type: analysisType, message: inputValue });
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer sk-Bp4AtAw19a6lENrPUQeqfiS9KP46Z5A43j4QkNeX4NRnGKMU'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'gpt-4o',
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: '你是一个数据分析专家,请根据用户输入进行分析并生成分析报告和 ECharts 图表配置。图表配置需要包含在 ```json 代码块中。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: `请对以下内容进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解。
|
||||||
|
分析报告之后,请生成一个用于可视化的 ECharts 配置对象(使用 \`\`\`json 包裹),配置中需要包含:
|
||||||
|
1. 标题、图例、提示框等基本配置
|
||||||
|
2. 合适的图表类型(折线图、柱状图、饼图等)
|
||||||
|
3. 坐标轴配置(如果适用)
|
||||||
|
4. 数据系列配置
|
||||||
|
5. 主题色彩配置
|
||||||
|
|
||||||
|
分析内容:${inputValue}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 2000
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
let chartOption;
|
||||||
|
|
||||||
// 模拟API响应
|
try {
|
||||||
setTimeout(() => {
|
const matches = result.choices[0].message.content.match(/```json\n([\s\S]*?)\n```/);
|
||||||
const assistantMessage: Message = {
|
if (matches && matches[1]) {
|
||||||
type: 'assistant',
|
chartOption = JSON.parse(matches[1]);
|
||||||
content: generateMockResponse(analysisType),
|
}
|
||||||
timestamp: Date.now(),
|
} catch (error) {
|
||||||
charts: generateMockChart(analysisType),
|
console.error('解析图表配置失败:', error);
|
||||||
};
|
chartOption = generateMockChart(analysisType);
|
||||||
setMessages(prev => [...prev, assistantMessage]);
|
}
|
||||||
setLoading(false);
|
|
||||||
scrollToBottom();
|
const assistantMessage: Message = {
|
||||||
}, 1500);
|
type: 'assistant',
|
||||||
|
content: result.choices[0].message.content.replace(/```json\n[\s\S]*?\n```/g, '').trim(),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
charts: chartOption,
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, assistantMessage]);
|
||||||
|
setLoading(false);
|
||||||
|
scrollToBottom();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('分析请求失败');
|
message.error('分析请求失败');
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleFileAnalysis = async (file: File) => {
|
||||||
|
try {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
const data = e.target?.result;
|
||||||
|
let textContent = '';
|
||||||
|
|
||||||
|
if (file.name.toLowerCase().endsWith('.csv')) {
|
||||||
|
textContent = data as string;
|
||||||
|
} else {
|
||||||
|
const workbook = XLSX.read(data, { type: 'array' });
|
||||||
|
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||||
|
const jsonData = XLSX.utils.sheet_to_json(firstSheet, { header: 1 });
|
||||||
|
textContent = jsonData.map(row => row.join('\t')).join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch('https://aizex.top/v1/chat/completions', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer sk-Bp4AtAw19a6lENrPUQeqfiS9KP46Z5A43j4QkNeX4NRnGKMU'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'gpt-4o',
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: '你是一个数据分析专家,请根据用户输入的数据进行分析并生成分析报告和 ECharts 图表配置。图表配置需要包含在 ```json 代码块中。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: `请对以下数据进行${analysisOptions.find(opt => opt.value === analysisType)?.label},并给出专业的分析见解。
|
||||||
|
分析报告之后,请生成一个用于可视化的 ECharts 配置对象(使用 \`\`\`json 包裹),配置中需要包含:
|
||||||
|
1. 标题、图例、提示框等基本配置
|
||||||
|
2. 合适的图表类型(折线图、柱状图、饼图等)
|
||||||
|
3. 坐标轴配置(如果适用)
|
||||||
|
4. 数据系列配置
|
||||||
|
5. 主题色彩配置
|
||||||
|
|
||||||
|
数据内容:\n${textContent}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 2000
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
let chartOption;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const matches = result.choices[0].message.content.match(/```json\n([\s\S]*?)\n```/);
|
||||||
|
if (matches && matches[1]) {
|
||||||
|
chartOption = JSON.parse(matches[1]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析图表配置失败:', error);
|
||||||
|
message.error('图表生成失败,使用默认图表');
|
||||||
|
chartOption = generateMockChart(analysisType);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMessage: Message = {
|
||||||
|
type: 'user',
|
||||||
|
content: `已上传文件:${file.name}`,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const assistantMessage: Message = {
|
||||||
|
type: 'assistant',
|
||||||
|
content: marked(result.choices[0].message.content
|
||||||
|
.replace(/```json\n[\s\S]*?\n```/g, '') // 先移除 JSON 代码块
|
||||||
|
.trim()
|
||||||
|
),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
charts: chartOption,
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, userMessage, assistantMessage]);
|
||||||
|
setLoading(false);
|
||||||
|
scrollToBottom();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (file.name.toLowerCase().endsWith('.csv')) {
|
||||||
|
reader.readAsText(file);
|
||||||
|
} else {
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('文件处理失败:', error);
|
||||||
|
message.error('文件处理失败');
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateMockResponse = (type: string) => {
|
const generateMockResponse = (type: string) => {
|
||||||
const responses: { [key: string]: string } = {
|
const responses: { [key: string]: string } = {
|
||||||
predictive: '根据历史数据分析,预计未来三个月的销售增长率将达到15%,主要增长点来自新市场的开拓。',
|
predictive: '根据历史数据分析,预计未来三个月的销售增长率将达到15%,主要增长点来自新市场的开拓。',
|
||||||
descriptive: '数据集中包含1000条记录,平均值为45.6,标准差为12.3,分布呈现正态分布特征。',
|
descriptive: '数据集中包含1000条记录,平均值为45.6,标准差为12.3,分布呈现正态分布特征。',
|
||||||
anomaly: '检测到3个异常值点,主要出现在数据的边缘区域,建议进行进一步核实。',
|
anomaly: '检测到3个异常值点,主要出现在数据的边缘区域,建议进行进一步核实。',
|
||||||
quality: '数据完整性为98.5%,存在少量缺失值,建议对缺失数据进行适当的填充处理。',
|
quality: '数据完整性为98.5%,存在少量缺失值,建议对缺失数据进行适当的填充处理。',
|
||||||
|
};
|
||||||
|
return responses[type] || '分析完成';
|
||||||
};
|
};
|
||||||
return responses[type] || '分析完成';
|
|
||||||
|
return (
|
||||||
|
<PageContainer
|
||||||
|
className={styles.container}
|
||||||
|
title="智能预测分析"
|
||||||
|
subTitle="上传数据,获取专业的数据分析见解"
|
||||||
|
>
|
||||||
|
<Card bordered={false} className={styles.mainCard}>
|
||||||
|
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
||||||
|
<div className={styles.analysisTypeSelector}>
|
||||||
|
{analysisOptions.map(option => (
|
||||||
|
<Tooltip key={option.value} title={option.label}>
|
||||||
|
<Tag
|
||||||
|
className={styles.analysisTag}
|
||||||
|
color={analysisType === option.value ? option.color : 'default'}
|
||||||
|
icon={option.icon}
|
||||||
|
onClick={() => setAnalysisType(option.value)}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card className={styles.uploadCard}>
|
||||||
|
<Dragger
|
||||||
|
fileList={fileList}
|
||||||
|
onChange={({ fileList }) => setFileList(fileList)}
|
||||||
|
beforeUpload={(file) => {
|
||||||
|
const isExcelOrCsv = /\.(xlsx|xls|csv)$/.test(file.name.toLowerCase());
|
||||||
|
if (!isExcelOrCsv) {
|
||||||
|
message.error('只支持 Excel 或 CSV 文件!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setFileList([file]);
|
||||||
|
setLoading(true);
|
||||||
|
handleFileAnalysis(file);
|
||||||
|
return false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<InboxOutlined className={styles.uploadIcon} />
|
||||||
|
</p>
|
||||||
|
<p className="ant-upload-text">点击或拖拽文件上传</p>
|
||||||
|
<p className="ant-upload-hint">支持 Excel (.xlsx, .xls) 或 CSV 文件格式</p>
|
||||||
|
</Dragger>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div className={styles.chatContainer}>
|
||||||
|
<List
|
||||||
|
className={styles.messageList}
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={messages}
|
||||||
|
// 在 List 组件的 renderItem 部分修改
|
||||||
|
renderItem={item => (
|
||||||
|
<List.Item className={item.type === 'user' ? styles.userMessage : styles.assistantMessage}>
|
||||||
|
<Card className={styles.messageCard}>
|
||||||
|
<List.Item.Meta
|
||||||
|
avatar={
|
||||||
|
<Avatar
|
||||||
|
icon={item.type === 'user' ? <UserOutlined /> : <RobotOutlined />}
|
||||||
|
className={styles.avatar}
|
||||||
|
style={{ padding: '8px' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={item.type === 'user' ? '你' : 'AI 助手'}
|
||||||
|
description={
|
||||||
|
<div
|
||||||
|
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.content }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{item.charts && (
|
||||||
|
<div className={styles.chartContainer}>
|
||||||
|
<ReactECharts option={item.charts} style={{ height: 300 }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div ref={messagesEndRef} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<TextArea
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
|
placeholder="请描述您的分析需求..."
|
||||||
|
autoSize={{ minRows: 2, maxRows: 6 }}
|
||||||
|
className={styles.input}
|
||||||
|
onPressEnter={(e) => {
|
||||||
|
if (!e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSend();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SendOutlined />}
|
||||||
|
onClick={handleSend}
|
||||||
|
loading={loading}
|
||||||
|
className={styles.sendButton}
|
||||||
|
>
|
||||||
|
分析
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer
|
|
||||||
className={styles.container}
|
|
||||||
title="智能预测分析"
|
|
||||||
subTitle="上传数据,获取专业的数据分析见解"
|
|
||||||
>
|
|
||||||
<Card bordered={false} className={styles.mainCard}>
|
|
||||||
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
|
||||||
<div className={styles.analysisTypeSelector}>
|
|
||||||
{analysisOptions.map(option => (
|
|
||||||
<Tooltip key={option.value} title={option.label}>
|
|
||||||
<Tag
|
|
||||||
className={styles.analysisTag}
|
|
||||||
color={analysisType === option.value ? option.color : 'default'}
|
|
||||||
icon={option.icon}
|
|
||||||
onClick={() => setAnalysisType(option.value)}
|
|
||||||
>
|
|
||||||
{option.label}
|
|
||||||
</Tag>
|
|
||||||
</Tooltip>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card className={styles.uploadCard}>
|
|
||||||
<Dragger
|
|
||||||
fileList={fileList}
|
|
||||||
onChange={({ fileList }) => setFileList(fileList)}
|
|
||||||
beforeUpload={(file) => {
|
|
||||||
const isExcelOrCsv = /\.(xlsx|xls|csv)$/.test(file.name.toLowerCase());
|
|
||||||
if (!isExcelOrCsv) {
|
|
||||||
message.error('只支持 Excel 或 CSV 文件!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
setFileList([file]);
|
|
||||||
setLoading(true);
|
|
||||||
handleFileAnalysis(file);
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<p className="ant-upload-drag-icon">
|
|
||||||
<InboxOutlined className={styles.uploadIcon} />
|
|
||||||
</p>
|
|
||||||
<p className="ant-upload-text">点击或拖拽文件上传</p>
|
|
||||||
<p className="ant-upload-hint">支持 Excel (.xlsx, .xls) 或 CSV 文件格式</p>
|
|
||||||
</Dragger>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<div className={styles.chatContainer}>
|
|
||||||
<List
|
|
||||||
className={styles.messageList}
|
|
||||||
itemLayout="horizontal"
|
|
||||||
dataSource={messages}
|
|
||||||
renderItem={item => (
|
|
||||||
<List.Item className={item.type === 'user' ? styles.userMessage : styles.assistantMessage}>
|
|
||||||
<Card className={styles.messageCard}>
|
|
||||||
<List.Item.Meta
|
|
||||||
avatar={
|
|
||||||
<Avatar
|
|
||||||
icon={item.type === 'user' ? <UserOutlined /> : <RobotOutlined />}
|
|
||||||
className={styles.avatar}
|
|
||||||
style={{ padding: '8px' }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
title={item.type === 'user' ? '你' : 'AI 助手'}
|
|
||||||
description={
|
|
||||||
<div style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
|
|
||||||
{item.content}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{item.charts && (
|
|
||||||
<div className={styles.chartContainer}>
|
|
||||||
<ReactECharts option={item.charts} style={{ height: 300 }} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Card>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<div ref={messagesEndRef} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<TextArea
|
|
||||||
value={inputValue}
|
|
||||||
onChange={(e) => setInputValue(e.target.value)}
|
|
||||||
placeholder="请描述您的分析需求..."
|
|
||||||
autoSize={{ minRows: 2, maxRows: 6 }}
|
|
||||||
className={styles.input}
|
|
||||||
onPressEnter={(e) => {
|
|
||||||
if (!e.shiftKey) {
|
|
||||||
e.preventDefault();
|
|
||||||
handleSend();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<SendOutlined />}
|
|
||||||
onClick={handleSend}
|
|
||||||
loading={loading}
|
|
||||||
className={styles.sendButton}
|
|
||||||
>
|
|
||||||
分析
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</Card>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user