Skip to content

Commit

Permalink
feat: 聊天记录展示窗口
Browse files Browse the repository at this point in the history
  • Loading branch information
ldq1220 committed Dec 2, 2024
1 parent 3b2aa64 commit 06879f0
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.chatContainer {
width: 520px;
max-height: 520px;
overflow-y: auto;
padding: 12px;
}

.messageItem {
display: flex;
margin-bottom: 12px;
}

.messageItemSender {
flex-direction: row-reverse;
}

.messageContent {
max-width: 300px;
margin: 0 0 0 12px;
padding: 8px 12px;
border-radius: 8px;
word-break: break-all;
line-height: 1.5;
background-color: #f0f0f0;
}

.messageContentSender {
margin: 0 12px 0 0;
background-color: #e6f7ff;
}

.avatar {
flex-shrink: 0;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/

import React from 'react';
import { Avatar } from 'antd';
import styles from '../assets/css/chatMessage.css';
import classNames from 'classnames';

interface ChatMessage {
speakerRole: 'human' | 'ai';
content: string;
}

const ChatMessages: React.FC<{ messages: ChatMessage[] }> = ({ messages }) => {
// 将换行符转换为<br/>
const formatContent = (content: string) => {
if (!content) return null;
return content.split('\n').map((text, index) => (
<React.Fragment key={index}>
{text}
{index !== content.split('\n').length - 1 && <br />}
</React.Fragment>
));
};

return (
<div className={styles.chatContainer}>
{messages.map((message, index) => {
const isHuman = message.speakerRole === 'human';

return (
<div key={index} className={classNames(styles.messageItem, isHuman && styles.messageItemSender)}>
<Avatar
className={styles.avatar}
size="small"
style={{
backgroundColor: isHuman ? '#1890ff' : '#87d068',
}}
>
{isHuman ? 'AI' : 'U'}
</Avatar>
<div className={classNames(styles.messageContent, isHuman && styles.messageContentSender)}>
{formatContent(message.content)}
</div>
</div>
);
})}
</div>
);
};

export default ChatMessages;
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
*/

import React, { FC, useState, useEffect, useRef } from 'react';
import { Input, Button, Modal, Flex } from 'antd';
import { Input, Button, Modal, Flex, message } from 'antd';
import { useInquiryRecord } from '../context/InquiryRecordContext';

const { TextArea } = Input;

const ReplyCustomer: FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const { inquiryMaterialsData, selectedRecords, setSelectedRecord } = useInquiryRecord();
const [replyContent, setReplyContent] = useState('');
const initialized = useRef(false);
Expand All @@ -30,18 +31,20 @@ const ReplyCustomer: FC = () => {
});
initialized.current = true;
}
}, [inquiryMaterialsData]);
}, [inquiryMaterialsData, setSelectedRecord]);

const handleGenerateContent = () => {
if (Object.keys(selectedRecords).length <= 0) return messageApi.error('请先选择参考数据');

// 根据选中记录生成回复内容
useEffect(() => {
const content = Object.entries(selectedRecords)
.map(([tabKey, record]) => {
return `物料: ${tabKey} -- 价格: ${record.price || '暂无'} 库存状况: ${record.store_status || '暂无'}`;
})
.join('\n');

setReplyContent(content);
}, [selectedRecords]);
setReplyContent((prev) => (prev ? `${prev}\n\n${content}` : content));
messageApi.success('回复文案已生成,请检查关键信息。');
};

const handleReply = () => {
Modal.confirm({
Expand All @@ -56,13 +59,17 @@ const ReplyCustomer: FC = () => {

return (
<Flex vertical gap="middle" style={{ padding: '16px' }}>
{contextHolder}
<TextArea
value={replyContent}
onChange={(e) => setReplyContent(e.target.value)}
placeholder="请输入回复内容..."
rows={6}
/>
<Flex justify="flex-end">
<Flex justify="flex-end" gap="20px">
<Button type="default" onClick={handleGenerateContent}>
生成文案
</Button>
<Button type="primary" onClick={handleReply}>
回复客户
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/

import React, { FC, useState } from 'react';
import React, { FC } from 'react';
import { useInquiryRecord } from '../context/InquiryRecordContext';
import { Table, Tag, Divider } from 'antd';
import { Table, Tag, Divider, Popover } from 'antd';
import { supplierInquiryRecordStatusMap } from '../utils';
import type { TableProps } from 'antd';
import ReplyCustomer from './ReplyCustomer';
import ChatMessages from './ChatMessage';
import chatMessagesIcon from '../assets/svg/chatMessages.svg';

const SupplierInquiryRecordTable: FC<{ dataSource: any[]; tabKey: string }> = ({ dataSource, tabKey }) => {
const { loading, selectedRecords, setSelectedRecord } = useInquiryRecord();
Expand All @@ -26,7 +28,7 @@ const SupplierInquiryRecordTable: FC<{ dataSource: any[]; tabKey: string }> = ({
};

// 表格列配置
const columns = [
const columns: any = [
{
title: '供应商',
render: (_, record) => {
Expand All @@ -42,23 +44,32 @@ const SupplierInquiryRecordTable: FC<{ dataSource: any[]; tabKey: string }> = ({
},
{
title: '价格',
align: 'center',
render: (_, record) => {
return <span>{record.price}</span>;
},
},
{
title: '库存状况',
align: 'center',
render: (_, record) => {
return <span>{record.store_status}</span>;
},
},
{
title: '聊天记录',
align: 'center',
render: (_, record) => {
return <span>{JSON.stringify(record.chat_messages)}</span>;
return (
<Popover content={<ChatMessages messages={record.chat_messages || []} />} trigger="hover" placement="left">
{/* <a>查看聊天记录</a> */}
<img src={chatMessagesIcon} alt="查看聊天记录" style={{ cursor: 'pointer' }} />
</Popover>
);
},
},
];

return (
<div style={{ marginTop: 16 }}>
<Table
Expand Down
Loading

0 comments on commit 06879f0

Please sign in to comment.