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 => { // 使用引用查找索引,防止重复 id 造成误匹配 let messageIndex = prevMessages.findIndex(msg => msg === targetMessage); // 回退到 id 匹配(兼容不同引用场景) 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 => { // 使用引用查找索引,防止重复 id 造成误匹配 let messageIndex = prevMessages.findIndex(msg => msg === targetMessage); // 回退到 id 匹配(兼容不同引用场景) 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, }; };