diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss index 95c26fd0..e65d7823 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/MessageEnter.module.scss @@ -227,3 +227,250 @@ min-width: 60px; } } + +// AI 加载动效样式 +.aiLoadingContainer { + display: flex; + align-items: center; + justify-content: center; + height: 190px; + background: linear-gradient(135deg, #f8f9ff 0%, #fef5ff 100%); + border-radius: 8px; + margin: 8px 0; + position: relative; + overflow: hidden; + + &::before { + content: ""; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + 45deg, + transparent 30%, + rgba(138, 99, 210, 0.05) 50%, + transparent 70% + ); + animation: shimmer 3s infinite; + } +} + +@keyframes shimmer { + 0% { + transform: translateX(-100%) translateY(-100%) rotate(45deg); + } + 100% { + transform: translateX(100%) translateY(100%) rotate(45deg); + } +} + +.aiLoadingContent { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + position: relative; + z-index: 1; +} + +.aiLoadingIcon { + position: relative; + display: flex; + align-items: center; + justify-content: center; + gap: 0; + height: 60px; +} + +.brainIcon { + font-size: 36px; + animation: float 2s ease-in-out infinite; + filter: drop-shadow(0 4px 8px rgba(138, 99, 210, 0.3)); + position: relative; + z-index: 2; + margin: 0 12px; +} + +@keyframes float { + 0%, + 100% { + transform: translateY(0) scale(1); + } + 50% { + transform: translateY(-8px) scale(1.05); + } +} + +// WiFi波纹容器 - 左侧 +.waveLeft { + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: center; + gap: 5px; +} + +// WiFi波纹容器 - 右侧 +.waveRight { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 5px; +} + +// 波纹条样式 +.wave1, +.wave2, +.wave3 { + height: 3px; + background: #8a63d2; + border-radius: 2px; + animation: waveExpand 1.5s ease-out infinite; +} + +.wave1 { + width: 12px; + animation-delay: 0s; +} + +.wave2 { + width: 20px; + animation-delay: 0.25s; +} + +.wave3 { + width: 28px; + animation-delay: 0.5s; +} + +@keyframes waveExpand { + 0% { + opacity: 0; + transform: scaleX(0.3); + } + 40% { + opacity: 1; + } + 100% { + opacity: 0; + transform: scaleX(1.2); + } +} + +.aiLoadingText { + display: flex; + align-items: center; + gap: 2px; + font-size: 16px; + font-weight: 500; + color: #333; +} + +.loadingTextMain { + background: linear-gradient(90deg, #8a63d2 0%, #b794f6 50%, #8a63d2 100%); + background-size: 200% auto; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: textShine 2s linear infinite; +} + +@keyframes textShine { + 0% { + background-position: 0% center; + } + 100% { + background-position: 200% center; + } +} + +.loadingDots { + display: inline-flex; + gap: 2px; + + span { + animation: dotFlashing 1.4s infinite; + color: #8a63d2; + font-weight: bold; + + &:nth-child(1) { + animation-delay: 0s; + } + &:nth-child(2) { + animation-delay: 0.2s; + } + &:nth-child(3) { + animation-delay: 0.4s; + } + } +} + +@keyframes dotFlashing { + 0%, + 80%, + 100% { + opacity: 0.3; + transform: scale(0.8); + } + 40% { + opacity: 1; + transform: scale(1.2); + } +} + +.aiLoadingSubText { + font-size: 12px; + color: #999; + animation: fadeInOut 2s ease-in-out infinite; +} + +@keyframes fadeInOut { + 0%, + 100% { + opacity: 0.5; + } + 50% { + opacity: 1; + } +} + +// 加载文字和取消按钮同行容器 +.aiLoadingTextRow { + display: flex; + align-items: center; + gap: 12px; +} + +// 取消AI按钮(显眼版) +.cancelAiButton { + height: 28px; + padding: 0 12px; + font-size: 13px; + border-radius: 6px; + border: 1px solid #ff7875; + background: #fff; + color: #ff4d4f; + font-weight: 500; + transition: all 0.2s ease; + box-shadow: 0 2px 4px rgba(255, 77, 79, 0.15); + + &:hover { + color: #fff; + background: #ff4d4f; + border-color: #ff4d4f; + box-shadow: 0 4px 8px rgba(255, 77, 79, 0.3); + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + box-shadow: 0 2px 4px rgba(255, 77, 79, 0.2); + } + + .anticon { + font-size: 12px; + } +} diff --git a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx index 73391f5e..b6733e5c 100644 --- a/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx +++ b/Touchkebao/src/pages/pc/ckbox/weChat/components/ChatWindow/components/MessageEnter/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { Layout, Input, Button, Modal, Spin } from "antd"; +import { Layout, Input, Button, Modal, message } from "antd"; import { SendOutlined, FolderOutlined, @@ -7,7 +7,6 @@ import { ExportOutlined, CloseOutlined, MessageOutlined, - LoadingOutlined, } from "@ant-design/icons"; import { ContractData, weChatGroup, ChatRecord } from "@/pages/pc/ckbox/data"; import { useWebSocketStore } from "@/store/module/websocket/websocket"; @@ -47,12 +46,27 @@ const MessageEnter: React.FC = ({ contract }) => { state => state.quoteMessageContent, ); const isLoadingAiChat = useWeChatStore(state => state.isLoadingAiChat); + const updateIsLoadingAiChat = useWeChatStore( + state => state.updateIsLoadingAiChat, + ); + const updateQuoteMessageContent = useWeChatStore( + state => state.updateQuoteMessageContent, + ); useEffect(() => { if (quoteMessageContent) { setInputValue(quoteMessageContent); } }, [quoteMessageContent]); + // 取消AI生成 + const handleCancelAi = () => { + // 停止AI加载状态 + updateIsLoadingAiChat(false); + // 清空AI回复内容 + updateQuoteMessageContent(""); + message.info("已取消AI生成"); + }; + const handleSend = async () => { if (!inputValue.trim()) return; const messageId = +Date.now(); @@ -199,115 +213,156 @@ const MessageEnter: React.FC = ({ contract }) => { <> {/* 聊天输入 */}