diff --git a/app/components/dify-chat/chat-message.tsx b/app/components/dify-chat/chat-message.tsx index 8e5207d..4c0f6c3 100644 --- a/app/components/dify-chat/chat-message.tsx +++ b/app/components/dify-chat/chat-message.tsx @@ -1,4 +1,5 @@ -import { Button, Card, Spin } from 'antd'; +import { LikeOutlined, LikeFilled, DislikeOutlined, DislikeFilled, CopyOutlined } from '@ant-design/icons'; +import { Button, Card, Spin, Tooltip } from 'antd'; import { useState } from 'react'; import type { ChatItem, Feedbacktype } from '~/api/dify-chat'; import '../../styles/components/chat-with-llm/chat-message.css'; @@ -26,6 +27,20 @@ export default function ChatMessage({ const [feedback, setFeedback] = useState<'like' | 'dislike' | null>( message.feedback?.rating || null ); + const [copied, setCopied] = useState(false); + + /** + * 处理复制 + */ + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(content); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch (err) { + console.error('复制失败:', err); + } + }; const { id, content, isAnswer, agent_thoughts, message_files, isOpeningStatement, suggestedQuestions, more, retriever_resources } = message; const isAgentMode = !!agent_thoughts && agent_thoughts.length > 0; @@ -168,6 +183,13 @@ export default function ChatMessage({ ); } + // 判断是否可以显示反馈按钮(AI回答、非占位符、非正在响应) + const canShowFeedback = isAnswer && + !id.startsWith('placeholder-') && + !id.startsWith('opening-') && + !id.startsWith('response-') && + !isResponding; + return (
@@ -184,6 +206,36 @@ export default function ChatMessage({ )}
+ {/* 反馈按钮 - 仅在AI回答且非占位符时显示 */} + {canShowFeedback && ( +
+ +
+ + )} diff --git a/app/routes/api.messages.$messageId.feedbacks.tsx b/app/routes/api.messages.$messageId.feedbacks.tsx index 4200f53..09ff907 100644 --- a/app/routes/api.messages.$messageId.feedbacks.tsx +++ b/app/routes/api.messages.$messageId.feedbacks.tsx @@ -16,7 +16,7 @@ export async function action({ request, params }: ActionFunctionArgs) { // 检查 JWT 是否存在 if (!frontendJWT) { - console.error('❌ [API] Message Feedback - JWT不存在'); + console.error('[API] Message Feedback - JWT不存在'); return new Response( JSON.stringify({ error: 'JWT认证失败,请重新登录' }), { @@ -40,21 +40,21 @@ export async function action({ request, params }: ActionFunctionArgs) { const body = await request.json(); const { rating } = body; - console.log('👍 [API] Message Feedback - 提交反馈:', { + console.log('[API] Message Feedback - 提交反馈:', { messageId, rating, }); const result = await difyClient.updateMessageFeedback(messageId, rating, frontendJWT); - console.log('✅ [API] Message Feedback - Success'); + console.log('[API] Message Feedback - Success'); return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json' }, }); } catch (error: any) { - console.error('❌ [API] Message Feedback - Error:', error.message); + console.error('[API] Message Feedback - Error:', error.message); const status = error.message?.includes('JWT认证失败') ? 401 : 500; return new Response( JSON.stringify({ error: error.message || 'Failed to submit feedback' }), diff --git a/app/styles/components/chat-with-llm/chat-message.css b/app/styles/components/chat-with-llm/chat-message.css index 5cca393..0eb3d98 100644 --- a/app/styles/components/chat-with-llm/chat-message.css +++ b/app/styles/components/chat-with-llm/chat-message.css @@ -106,6 +106,65 @@ gap: 8px; } +/* 消息反馈按钮 */ +.message-feedback { + display: flex; + gap: 4px; + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid rgba(0, 0, 0, 0.06); + justify-content: space-between; + align-items: center; +} + +.message-copy-btn { + color: #52c41a !important; + transition: all 0.2s ease; +} + +.message-copy-btn:hover { + color: #00684a !important; + background: rgba(0, 104, 74, 0.1) !important; +} + +.message-copy-btn.copied { + color: #00684a !important; +} + +.feedback-actions-right { + display: flex; + gap: 4px; + align-items: center; +} + +.message-feedback .ant-btn { + color: #8c8c8c; + transition: all 0.2s ease; +} + +.message-feedback .ant-btn:hover { + color: #52c41a; + background: rgba(24, 144, 255, 0.1); +} + +.message-feedback .feedback-active-like { + color: #52c41a !important; +} + +.message-feedback .feedback-active-like:hover { + color: #52c41a !important; + background: rgba(82, 196, 26, 0.1); +} + +.message-feedback .feedback-active-dislike { + color: #ff4d4f !important; +} + +.message-feedback .feedback-active-dislike:hover { + color: #ff4d4f !important; + background: rgba(255, 77, 79, 0.1); +} + /* 建议问题 */ .suggested-questions { margin-top: 16px;