完成:项目开发

This commit is contained in:
2025-07-11 13:45:26 +08:00
parent a88377bf32
commit 6f3e634355
12 changed files with 510 additions and 64 deletions

View File

@@ -1,11 +1,14 @@
import {useEffect, useState, useRef} from "react";
import {View, Textarea} from '@tarojs/components';
import {Textarea} from '@tarojs/components';
import Taro from '@tarojs/taro';
import {Button} from '@nutui/nutui-react-taro';
import {User, ArrowUp, Home} from '@nutui/icons-react-taro';
import {sendAiMessage, stopAiMessage} from '@/api/ai';
import {User, Home} from '@nutui/icons-react-taro';
import {sendAiMessage} from '@/api/ai';
import {createWebSocket} from '@/utils/websocket';
import {getAiToken} from '@/utils/aiToken';
import MarkdownRenderer from '@/components/MarkdownRenderer';
// 显示html富文本
import {View, RichText} from '@tarojs/components'
import './index.scss';
import {WSS_API_URL} from "@/utils/server";
@@ -27,7 +30,7 @@ const AiChat = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [inputValue, setInputValue] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [currentTaskId, setCurrentTaskId] = useState<string>('');
// const [currentTaskId, setCurrentTaskId] = useState<string>('');
const [wsConnected, setWsConnected] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
@@ -84,7 +87,7 @@ const AiChat = () => {
msg.isTyping ? {...msg, isTyping: false} : msg
));
setIsLoading(false);
setCurrentTaskId('');
// setCurrentTaskId('');
} else {
// 实时更新AI回复消息
setMessages(prev => {
@@ -109,7 +112,7 @@ const AiChat = () => {
});
if (data.taskId) {
setCurrentTaskId(data.taskId);
// setCurrentTaskId(data.taskId);
}
}
@@ -270,20 +273,20 @@ const AiChat = () => {
};
// 停止AI回复
const handleStopMessage = async () => {
if (currentTaskId) {
try {
await stopAiMessage({taskId: currentTaskId});
setIsLoading(false);
setCurrentTaskId('');
setMessages(prev => prev.map(msg =>
msg.isTyping ? {...msg, isTyping: false} : msg
));
} catch (error) {
console.error('停止消息失败:', error);
}
}
};
// const handleStopMessage = async () => {
// if (currentTaskId) {
// try {
// await stopAiMessage({taskId: currentTaskId});
// setIsLoading(false);
// setCurrentTaskId('');
// setMessages(prev => prev.map(msg =>
// msg.isTyping ? {...msg, isTyping: false} : msg
// ));
// } catch (error) {
// console.error('停止消息失败:', error);
// }
// }
// };
// 处理快捷问题点击
const handleQuickQuestion = (question: string) => {
@@ -341,7 +344,10 @@ const AiChat = () => {
</View>
<View className="message-content">
<View className="message-text">
{message.query || (message.isTyping && message.type === 'ai' ? '正在思考中...' : '')}
<MarkdownRenderer
content={message.query || (message.isTyping && message.type === 'ai' ? '正在思考中...' : '')}
className={`message-markdown ${message.type === 'user' ? 'user-markdown' : 'ai-markdown'}`}
/>
</View>
{message.isTyping && message.type === 'ai' && message.query && (
<View className="typing-cursor">|</View>
@@ -365,7 +371,10 @@ const AiChat = () => {
className="question-item"
onClick={() => handleQuickQuestion(question)}
>
{question}
<RichText
nodes={question}
space="nbsp"
/>
</View>
))}
</View>
@@ -373,45 +382,33 @@ const AiChat = () => {
)}
<View className="input-container">
<View className="input-wrapper">
<Textarea
className="message-input"
value={inputValue}
placeholder={
!isInitialized ? "正在初始化..." :
isLoading ? "AI正在回复中..." :
"请输入您的问题..."
}
onInput={(e) => setInputValue(e.detail.value)}
onConfirm={() => handleSendMessage(inputValue)}
autoHeight
maxlength={500}
/>
</View>
{isLoading ? (
<Button
onClick={handleStopMessage}
type="primary"
className="stop-button"
>
</Button>
) : (
<Button
type="primary"
<div className="input-wrapper flex justify-between items-center">
<Home size={26} className={'bg-white'} onClick={() => Taro.reLaunch({url: '/pages/index/index'})}/>
<div className={'w-full mx-2'}>
<Textarea
className="message-input"
value={inputValue}
placeholder={
!isInitialized ? "正在初始化..." :
isLoading ? "AI正在回复中..." :
"请输入您的问题..."
}
onInput={(e) => setInputValue(e.detail.value)}
onConfirm={() => handleSendMessage(inputValue)}
autoHeight
maxlength={500}
/>
</div>
<div
className={'flex justify-center items-center pr-1'}
onClick={() => handleSendMessage(inputValue)}
disabled={!isInitialized || !inputValue.trim()}
icon={<ArrowUp/>}
className="send-button"
>
</Button>
)}
<img alt={'发送'} src={'https://oss.wsdns.cn/20250709/13424d78bb004352864051d61afe9f0e.png'} width={'30px'} />
</div>
</div>
</View>
</View>
<View className="fixed top-2 left-3" onClick={() => Taro.reLaunch({'url': '/pages/index/index'})}>
<Home/>
</View>
</View>
);
};