| | import { useCallback } from 'react'; |
| | import { Toast, Modal } from '@douyinfe/semi-ui'; |
| | import { useTranslation } from 'react-i18next'; |
| | import { getTextContent } from '../helpers'; |
| | import { ERROR_MESSAGES } from '../constants/playground.constants'; |
| |
|
| | export const useMessageActions = (message, setMessage, onMessageSend, saveMessages) => { |
| | const { t } = useTranslation(); |
| |
|
| | |
| | const handleMessageCopy = useCallback((targetMessage) => { |
| | const textToCopy = getTextContent(targetMessage); |
| |
|
| | if (!textToCopy) { |
| | Toast.warning({ |
| | content: t(ERROR_MESSAGES.NO_TEXT_CONTENT), |
| | duration: 2, |
| | }); |
| | return; |
| | } |
| |
|
| | const copyToClipboard = async (text) => { |
| | if (navigator.clipboard?.writeText) { |
| | try { |
| | await navigator.clipboard.writeText(text); |
| | Toast.success({ |
| | content: t('消息已复制到剪贴板'), |
| | duration: 2, |
| | }); |
| | } catch (err) { |
| | console.error('Clipboard API 复制失败:', err); |
| | fallbackCopy(text); |
| | } |
| | } else { |
| | fallbackCopy(text); |
| | } |
| | }; |
| |
|
| | const fallbackCopy = (text) => { |
| | try { |
| | const textArea = document.createElement('textarea'); |
| | textArea.value = text; |
| | textArea.style.cssText = ` |
| | position: fixed; |
| | top: -9999px; |
| | left: -9999px; |
| | opacity: 0; |
| | pointer-events: none; |
| | z-index: -1; |
| | `; |
| | textArea.setAttribute('readonly', ''); |
| |
|
| | document.body.appendChild(textArea); |
| | textArea.select(); |
| | textArea.setSelectionRange(0, text.length); |
| |
|
| | const successful = document.execCommand('copy'); |
| | document.body.removeChild(textArea); |
| |
|
| | if (successful) { |
| | Toast.success({ |
| | content: t('消息已复制到剪贴板'), |
| | duration: 2, |
| | }); |
| | } else { |
| | throw new Error('execCommand copy failed'); |
| | } |
| | } catch (err) { |
| | console.error('回退复制方案也失败:', err); |
| |
|
| | let errorMessage = t(ERROR_MESSAGES.COPY_FAILED); |
| | if (window.location.protocol === 'http:' && window.location.hostname !== 'localhost') { |
| | errorMessage = t(ERROR_MESSAGES.COPY_HTTPS_REQUIRED); |
| | } else if (!navigator.clipboard && !document.execCommand) { |
| | errorMessage = t(ERROR_MESSAGES.BROWSER_NOT_SUPPORTED); |
| | } |
| |
|
| | Toast.error({ |
| | content: errorMessage, |
| | duration: 4, |
| | }); |
| | } |
| | }; |
| |
|
| | copyToClipboard(textToCopy); |
| | }, [t]); |
| |
|
| | |
| | const handleMessageReset = useCallback((targetMessage) => { |
| | setMessage(prevMessages => { |
| | |
| | let messageIndex = prevMessages.findIndex(msg => msg === targetMessage); |
| |
|
| | |
| | if (messageIndex === -1) { |
| | messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id); |
| | } |
| |
|
| | if (messageIndex === -1) return prevMessages; |
| |
|
| | if (targetMessage.role === 'user') { |
| | const newMessages = prevMessages.slice(0, messageIndex); |
| | const contentToSend = getTextContent(targetMessage); |
| |
|
| | setTimeout(() => { |
| | onMessageSend(contentToSend); |
| | }, 100); |
| |
|
| | return newMessages; |
| | } else if (targetMessage.role === 'assistant' || targetMessage.role === 'system') { |
| | let userMessageIndex = messageIndex - 1; |
| | while (userMessageIndex >= 0 && prevMessages[userMessageIndex].role !== 'user') { |
| | userMessageIndex--; |
| | } |
| |
|
| | if (userMessageIndex >= 0) { |
| | const userMessage = prevMessages[userMessageIndex]; |
| | const newMessages = prevMessages.slice(0, userMessageIndex); |
| | const contentToSend = getTextContent(userMessage); |
| |
|
| | setTimeout(() => { |
| | onMessageSend(contentToSend); |
| | }, 100); |
| |
|
| | return newMessages; |
| | } |
| | } |
| |
|
| | return prevMessages; |
| | }); |
| | }, [setMessage, onMessageSend]); |
| |
|
| | |
| | const handleMessageDelete = useCallback((targetMessage) => { |
| | Modal.confirm({ |
| | title: t('确认删除'), |
| | content: t('确定要删除这条消息吗?'), |
| | okText: t('确定'), |
| | cancelText: t('取消'), |
| | okButtonProps: { |
| | type: 'danger', |
| | }, |
| | onOk: () => { |
| | setMessage(prevMessages => { |
| | |
| | let messageIndex = prevMessages.findIndex(msg => msg === targetMessage); |
| |
|
| | |
| | if (messageIndex === -1) { |
| | messageIndex = prevMessages.findIndex(msg => msg.id === targetMessage.id); |
| | } |
| |
|
| | if (messageIndex === -1) return prevMessages; |
| |
|
| | let updatedMessages; |
| | if (targetMessage.role === 'user' && messageIndex < prevMessages.length - 1) { |
| | const nextMessage = prevMessages[messageIndex + 1]; |
| | if (nextMessage.role === 'assistant') { |
| | Toast.success({ |
| | content: t('已删除消息及其回复'), |
| | duration: 2, |
| | }); |
| | updatedMessages = prevMessages.filter((_, index) => |
| | index !== messageIndex && index !== messageIndex + 1 |
| | ); |
| | } else { |
| | Toast.success({ |
| | content: t('消息已删除'), |
| | duration: 2, |
| | }); |
| | updatedMessages = prevMessages.filter(msg => msg.id !== targetMessage.id); |
| | } |
| | } else { |
| | Toast.success({ |
| | content: t('消息已删除'), |
| | duration: 2, |
| | }); |
| | updatedMessages = prevMessages.filter(msg => msg.id !== targetMessage.id); |
| | } |
| |
|
| | |
| | setTimeout(() => saveMessages(updatedMessages), 0); |
| | return updatedMessages; |
| | }); |
| | }, |
| | }); |
| | }, [setMessage, t, saveMessages]); |
| |
|
| | |
| | const handleRoleToggle = useCallback((targetMessage) => { |
| | if (!(targetMessage.role === 'assistant' || targetMessage.role === 'system')) { |
| | return; |
| | } |
| |
|
| | const newRole = targetMessage.role === 'assistant' ? 'system' : 'assistant'; |
| |
|
| | setMessage(prevMessages => { |
| | const updatedMessages = prevMessages.map(msg => { |
| | if (msg.id === targetMessage.id && |
| | (msg.role === 'assistant' || msg.role === 'system')) { |
| | return { ...msg, role: newRole }; |
| | } |
| | return msg; |
| | }); |
| |
|
| | |
| | setTimeout(() => saveMessages(updatedMessages), 0); |
| | return updatedMessages; |
| | }); |
| |
|
| | Toast.success({ |
| | content: t(`已切换为${newRole === 'system' ? 'System' : 'Assistant'}角色`), |
| | duration: 2, |
| | }); |
| | }, [setMessage, t, saveMessages]); |
| |
|
| | return { |
| | handleMessageCopy, |
| | handleMessageReset, |
| | handleMessageDelete, |
| | handleRoleToggle, |
| | }; |
| | }; |