diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx new file mode 100644 index 00000000..e69de29b diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss new file mode 100644 index 00000000..b8085ce9 --- /dev/null +++ b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/index.module.scss @@ -0,0 +1,147 @@ +.chatFooter { + background: #f7f7f7; + border-top: 1px solid #e1e1e1; + padding: 0; + height: auto; + border-radius: 8px; +} + +.inputContainer { + padding: 8px 12px; + display: flex; + flex-direction: column; + gap: 6px; +} + +.inputToolbar { + display: flex; + align-items: center; + padding: 4px 0; +} + +.leftTool { + display: flex; + gap: 4px; + align-items: center; +} + +.toolbarButton { + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + color: #666; + font-size: 16px; + transition: all 0.15s; + border: none; + background: transparent; + + &:hover { + background: #e6e6e6; + color: #333; + } + + &:active { + background: #d9d9d9; + } +} + +.inputArea { + display: flex; + flex-direction: column; + padding: 4px 0; +} + +.inputWrapper { + border: 1px solid #d1d1d1; + border-radius: 4px; + background: #fff; + overflow: hidden; + + &:focus-within { + border-color: #07c160; + } +} + +.messageInput { + width: 100%; + border: none; + resize: none; + font-size: 13px; + line-height: 1.4; + padding: 8px 10px; + background: transparent; + + &:focus { + box-shadow: none; + outline: none; + } + + &::placeholder { + color: #b3b3b3; + } +} + +.sendButtonArea { + padding: 8px 10px; + display: flex; + justify-content: flex-end; + gap: 8px; +} + +.sendButton { + height: 32px; + border-radius: 4px; + font-weight: normal; + min-width: 60px; + font-size: 13px; + background: #07c160; + border-color: #07c160; + + &:hover { + background: #06ad56; + border-color: #06ad56; + } + + &:active { + background: #059748; + border-color: #059748; + } + + &:disabled { + background: #b3b3b3; + border-color: #b3b3b3; + opacity: 1; + } +} + +.hintButton { + border: none; + background: transparent; + color: #666; + font-size: 12px; + + &:hover { + color: #333; + } +} + +.inputHint { + font-size: 11px; + color: #999; + text-align: right; + margin-top: 2px; +} + +@media (max-width: 768px) { + .inputToolbar { + flex-wrap: wrap; + gap: 8px; + } + + .sendButtonArea { + justify-content: space-between; + } +} diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss new file mode 100644 index 00000000..fee50c0a --- /dev/null +++ b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.module.scss @@ -0,0 +1,265 @@ +.stepContent { + .stepHeader { + margin-bottom: 20px; + + h3 { + font-size: 18px; + font-weight: 600; + color: #1a1a1a; + margin: 0 0 8px 0; + } + + p { + font-size: 14px; + color: #666; + margin: 0; + } + } +} + +.step3Content { + display: flex; + gap: 24px; + align-items: flex-start; + + .leftColumn { + flex: 1; + display: flex; + flex-direction: column; + gap: 20px; + } + + .rightColumn { + width: 400px; + flex: 1; + display: flex; + flex-direction: column; + gap: 20px; + } + + .messagePreview { + border: 2px dashed #52c41a; + border-radius: 8px; + padding: 20px; + background: #f6ffed; + + .previewTitle { + font-size: 14px; + color: #52c41a; + font-weight: 500; + margin-bottom: 12px; + } + + .messageBubble { + min-height: 60px; + padding: 12px; + background: #fff; + border-radius: 6px; + color: #666; + font-size: 14px; + line-height: 1.6; + + .currentEditingLabel { + font-size: 12px; + color: #999; + margin-bottom: 8px; + } + + .messageText { + color: #333; + white-space: pre-wrap; + word-break: break-word; + } + } + } + + .savedScriptGroups { + .scriptGroupTitle { + font-size: 14px; + font-weight: 500; + color: #333; + margin-bottom: 12px; + } + + .scriptGroupItem { + border: 1px solid #e8e8e8; + border-radius: 8px; + padding: 12px; + margin-bottom: 12px; + background: #fff; + + .scriptGroupHeader { + display: flex; + justify-content: space-between; + align-items: center; + + .scriptGroupLeft { + display: flex; + align-items: center; + gap: 8px; + flex: 1; + + :global(.ant-radio) { + margin-right: 4px; + } + + .scriptGroupName { + font-size: 14px; + font-weight: 500; + color: #333; + } + + .messageCount { + font-size: 12px; + color: #999; + margin-left: 8px; + } + } + + .scriptGroupActions { + display: flex; + gap: 4px; + + .actionButton { + padding: 4px; + color: #666; + + &:hover { + color: #1890ff; + } + } + } + } + + .scriptGroupContent { + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid #f0f0f0; + font-size: 13px; + color: #666; + } + } + } + + .messageInputArea { + .messageInput { + margin-bottom: 12px; + } + + .attachmentButtons { + display: flex; + gap: 8px; + margin-bottom: 12px; + } + + .aiRewriteSection { + display: flex; + align-items: center; + margin-bottom: 8px; + } + + .messageHint { + font-size: 12px; + color: #999; + } + } + + .settingsPanel { + border: 1px solid #e8e8e8; + border-radius: 8px; + padding: 20px; + background: #fafafa; + + .settingsTitle { + font-size: 14px; + font-weight: 500; + color: #1a1a1a; + margin-bottom: 16px; + } + + .settingItem { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + + .settingLabel { + font-size: 14px; + font-weight: 500; + color: #1a1a1a; + margin-bottom: 12px; + } + + .settingControl { + display: flex; + align-items: center; + gap: 8px; + + span { + font-size: 14px; + color: #666; + min-width: 80px; + } + } + } + } + + .tagSection { + .settingLabel { + font-size: 14px; + font-weight: 500; + color: #1a1a1a; + margin-bottom: 12px; + } + } + + .pushPreview { + border: 1px solid #e8e8e8; + border-radius: 8px; + padding: 20px; + background: #f0f7ff; + + .previewTitle { + font-size: 14px; + font-weight: 500; + color: #1a1a1a; + margin-bottom: 12px; + } + + ul { + list-style: none; + padding: 0; + margin: 0; + + li { + font-size: 14px; + color: #666; + line-height: 1.8; + } + } + } +} + +@media (max-width: 1200px) { + .step3Content { + .rightColumn { + width: 350px; + } + } +} + +@media (max-width: 768px) { + .step3Content { + flex-direction: column; + + .leftColumn { + width: 100%; + } + + .rightColumn { + width: 100%; + } + } +} + diff --git a/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx new file mode 100644 index 00000000..082831d5 --- /dev/null +++ b/Moncter/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/index.tsx @@ -0,0 +1,6 @@ +import ContentSelection from "@/components/ContentSelection"; +import { ContentItem } from "@/components/ContentSelection/data"; +import InputMessage from "./InputMessage/InputMessage"; +import styles from "./index.module.scss"; + +interface StepSendMessageProps { diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/ContentLibrarySelector.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/ContentLibrarySelector.tsx new file mode 100644 index 00000000..574ec9dd --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/ContentLibrarySelector.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import ContentSelection from "@/components/ContentSelection"; +import type { ContentItem } from "@/components/ContentSelection/data"; +import styles from "./index.module.scss"; + +interface ContentLibrarySelectorProps { + selectedContentLibraries: ContentItem[]; + onSelectedContentLibrariesChange: (selectedItems: ContentItem[]) => void; +} + +const ContentLibrarySelector: React.FC = ({ + selectedContentLibraries, + onSelectedContentLibrariesChange, +}) => { + return ( +
+
+
内容库选择
+
+ 选择内容库可快速引用现有话术 +
+
+ +
+ ); +}; + +export default ContentLibrarySelector; diff --git a/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx b/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx new file mode 100644 index 00000000..baadd6b4 --- /dev/null +++ b/Touchkebao/src/pages/pc/ckbox/powerCenter/message-push-assistant/create-push-task/components/StepSendMessage/InputMessage/InputMessage.tsx @@ -0,0 +1,251 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { Button, Input, message as antdMessage } from "antd"; +import { FolderOutlined, PictureOutlined } from "@ant-design/icons"; + +import { EmojiPicker } from "@/components/EmojiSeclection"; +import { EmojiInfo } from "@/components/EmojiSeclection/wechatEmoji"; +import SimpleFileUpload from "@/components/Upload/SimpleFileUpload"; +import AudioRecorder from "@/components/Upload/AudioRecorder"; + +import styles from "./index.module.scss"; + +const { TextArea } = Input; + +type FileTypeValue = 1 | 2 | 3 | 4 | 5; + +interface InputMessageProps { + defaultValue?: string; + onContentChange?: (value: string) => void; + onSend?: (value: string) => void; + clearOnSend?: boolean; + placeholder?: string; + hint?: React.ReactNode; +} + +const FileType: Record = { + TEXT: 1, + IMAGE: 2, + VIDEO: 3, + AUDIO: 4, + FILE: 5, +}; + +const getMsgTypeByFileFormat = (filePath: string): number => { + const extension = filePath.toLowerCase().split(".").pop() || ""; + const imageFormats = [ + "jpg", + "jpeg", + "png", + "gif", + "bmp", + "webp", + "svg", + "ico", + ]; + if (imageFormats.includes(extension)) { + return 3; + } + + const videoFormats = [ + "mp4", + "avi", + "mov", + "wmv", + "flv", + "mkv", + "webm", + "3gp", + "rmvb", + ]; + if (videoFormats.includes(extension)) { + return 43; + } + + return 49; +}; + +const InputMessage: React.FC = ({ + defaultValue = "", + onContentChange, + onSend, + clearOnSend = false, + placeholder = "输入消息...", + hint, +}) => { + const [inputValue, setInputValue] = useState(defaultValue); + + useEffect(() => { + if (defaultValue !== inputValue) { + setInputValue(defaultValue); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [defaultValue]); + + useEffect(() => { + onContentChange?.(inputValue); + }, [inputValue, onContentChange]); + + const handleInputChange = useCallback( + (e: React.ChangeEvent) => { + setInputValue(e.target.value); + }, + [], + ); + + const handleSend = useCallback(() => { + const content = inputValue.trim(); + if (!content) { + return; + } + onSend?.(content); + if (clearOnSend) { + setInputValue(""); + } + antdMessage.success("已添加消息内容"); + }, [clearOnSend, inputValue, onSend]); + + const handleKeyPress = useCallback( + (e: React.KeyboardEvent) => { + if (e.key !== "Enter") { + return; + } + + if (e.ctrlKey || e.metaKey) { + e.preventDefault(); + const target = e.currentTarget; + const { selectionStart, selectionEnd, value } = target; + const nextValue = + value.slice(0, selectionStart) + "\n" + value.slice(selectionEnd); + setInputValue(nextValue); + requestAnimationFrame(() => { + const cursorPosition = selectionStart + 1; + target.selectionStart = cursorPosition; + target.selectionEnd = cursorPosition; + }); + return; + } + + if (!e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }, + [handleSend], + ); + + const handleEmojiSelect = useCallback((emoji: EmojiInfo) => { + setInputValue(prev => prev + `[${emoji.name}]`); + }, []); + + const handleFileUploaded = useCallback( + ( + filePath: { url: string; name: string; durationMs?: number }, + fileType: FileTypeValue, + ) => { + let msgType = 1; + let content: string | Record = filePath.url; + if ([FileType.TEXT].includes(fileType)) { + msgType = getMsgTypeByFileFormat(filePath.url); + } else if ([FileType.IMAGE].includes(fileType)) { + msgType = 3; + } else if ([FileType.AUDIO].includes(fileType)) { + msgType = 34; + content = JSON.stringify({ + url: filePath.url, + durationMs: filePath.durationMs, + }); + } else if ([FileType.FILE].includes(fileType)) { + msgType = getMsgTypeByFileFormat(filePath.url); + if (msgType === 49) { + content = JSON.stringify({ + type: "file", + title: filePath.name, + url: filePath.url, + }); + } + } + + console.log("模拟上传内容: ", { + msgType, + content, + }); + antdMessage.success("附件上传成功,可在推送时使用"); + }, + [], + ); + + const handleAudioUploaded = useCallback( + (audioData: { name: string; url: string; durationMs?: number }) => { + handleFileUploaded( + { + name: audioData.name, + url: audioData.url, + durationMs: audioData.durationMs, + }, + FileType.AUDIO, + ); + }, + [handleFileUploaded], + ); + + return ( +
+
+
+
+ + + + handleFileUploaded(fileInfo, FileType.IMAGE) + } + maxSize={10} + type={1} + slot={ +
+
+ +
+
+