修复:AI问答模块

This commit is contained in:
2025-07-09 13:47:01 +08:00
parent 6b36f83861
commit a88377bf32
6 changed files with 77 additions and 116 deletions

View File

@@ -3,7 +3,7 @@ import {pageCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model"; import {CmsArticle} from "@/api/cms/cmsArticle/model";
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {useRouter} from '@tarojs/taro' import {useRouter} from '@tarojs/taro'
import {Image} from '@nutui/nutui-react-taro' import {Image,InfiniteLoading} from '@nutui/nutui-react-taro'
import {getCmsNavigation} from "@/api/cms/cmsNavigation"; import {getCmsNavigation} from "@/api/cms/cmsNavigation";
import {CmsNavigation} from "@/api/cms/cmsNavigation/model"; import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
@@ -39,7 +39,7 @@ const Index = () => {
}, []) }, [])
return ( return (
<div className={'bg-red-200 h-full'}> <InfiniteLoading className={'bg-red-200 h-full'}>
<div style={{padding: navigation?.span + 'px'}}> <div style={{padding: navigation?.span + 'px'}}>
<Image src={navigation?.style} width={'100%'} <Image src={navigation?.style} width={'100%'}
height={'auto'}/> height={'auto'}/>
@@ -91,7 +91,7 @@ const Index = () => {
} }
</div> </div>
</div> </div>
</div> </InfiniteLoading>
) )
} }
export default Index export default Index

View File

@@ -3,7 +3,7 @@ import {pageCmsArticle} from "@/api/cms/cmsArticle";
import {CmsArticle} from "@/api/cms/cmsArticle/model"; import {CmsArticle} from "@/api/cms/cmsArticle/model";
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {useRouter} from '@tarojs/taro' import {useRouter} from '@tarojs/taro'
import {Image} from '@nutui/nutui-react-taro' import {Image,InfiniteLoading} from '@nutui/nutui-react-taro'
import {getCmsNavigation} from "@/api/cms/cmsNavigation"; import {getCmsNavigation} from "@/api/cms/cmsNavigation";
import {CmsNavigation} from "@/api/cms/cmsNavigation/model"; import {CmsNavigation} from "@/api/cms/cmsNavigation/model";
@@ -22,7 +22,7 @@ const List = () => {
// 当前栏目信息 // 当前栏目信息
const navs = await getCmsNavigation(categoryId); const navs = await getCmsNavigation(categoryId);
// 终极新闻列表 // 终极新闻列表
const articles = await pageCmsArticle({categoryId,limit: 50}); const articles = await pageCmsArticle({categoryId, limit: 50});
// 当前栏目信息 // 当前栏目信息
if (navs) { if (navs) {
@@ -39,7 +39,7 @@ const List = () => {
}, []) }, [])
return ( return (
<div className={'bg-red-200 h-full'}> <InfiniteLoading className={'bg-red-200'} style={{height: '100vh'}}>
<div style={{padding: navigation?.span + 'px'}}> <div style={{padding: navigation?.span + 'px'}}>
<Image src={navigation?.style} width={'100%'} <Image src={navigation?.style} width={'100%'}
height={'auto'}/> height={'auto'}/>
@@ -52,7 +52,7 @@ const List = () => {
backgroundSize: '100%', backgroundSize: '100%',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
width: '100%', width: '100%',
height: '70px', height: '67px',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center' justifyContent: 'center'
@@ -60,7 +60,7 @@ const List = () => {
> >
{/* 标题 */} {/* 标题 */}
<div <div
className={'absolute z-50 text-sm text-center text-[#F2FE03] font-bold leading-tight px-1'} className={'z-50 text-sm text-center text-[#F2FE03] font-bold leading-tight px-1'}
> >
{navigation?.categoryName} {navigation?.categoryName}
</div> </div>
@@ -85,19 +85,16 @@ const List = () => {
> >
{ {
// 图片容器 // 图片容器
item.image && ( item.image ? (
<div className={'w-full m-3 flex justify-center'} <div className={'w-full m-3 flex justify-center'}
style={{ style={{
width: '108px', width: '108px',
height: '160px', height: '160px',
}}> }}>
<img <Image className={'object-cover'} src={item.image}/>
className={'object-cover'}
src={item.image}
alt={item.title || ''}
/>
</div> </div>
) ) :
<div className={'px-2'}></div>
} }
{/* 标题 */} {/* 标题 */}
<div className={'flex flex-col items-start my-3 text-sm leading-tight'} style={{ <div className={'flex flex-col items-start my-3 text-sm leading-tight'} style={{
@@ -117,7 +114,7 @@ const List = () => {
} }
</div> </div>
</div> </div>
</div> </InfiniteLoading>
) )
} }
export default List export default List

View File

@@ -2,7 +2,7 @@ import {useEffect, useState, useRef} from "react";
import {View, Textarea} from '@tarojs/components'; import {View, Textarea} from '@tarojs/components';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import {Button} from '@nutui/nutui-react-taro'; import {Button} from '@nutui/nutui-react-taro';
import {User, ArrowUp} from '@nutui/icons-react-taro'; import {User, ArrowUp, Home} from '@nutui/icons-react-taro';
import {sendAiMessage, stopAiMessage} from '@/api/ai'; import {sendAiMessage, stopAiMessage} from '@/api/ai';
import {createWebSocket} from '@/utils/websocket'; import {createWebSocket} from '@/utils/websocket';
import {getAiToken} from '@/utils/aiToken'; import {getAiToken} from '@/utils/aiToken';
@@ -29,6 +29,7 @@ const AiChat = () => {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [currentTaskId, setCurrentTaskId] = useState<string>(''); const [currentTaskId, setCurrentTaskId] = useState<string>('');
const [wsConnected, setWsConnected] = useState(false); const [wsConnected, setWsConnected] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null); const messagesEndRef = useRef<HTMLDivElement>(null);
const wsRef = useRef<any>(null); const wsRef = useRef<any>(null);
@@ -45,6 +46,18 @@ const AiChat = () => {
return getAiToken(); return getAiToken();
}; };
// 调试函数:检查输入框状态
const debugInputStatus = () => {
console.log('输入框状态调试:', {
isInitialized,
isLoading,
wsConnected,
inputValue,
inputDisabled: !isInitialized || isLoading,
sendButtonDisabled: !isInitialized || !inputValue.trim()
});
};
// 滚动到底部 // 滚动到底部
const scrollToBottom = () => { const scrollToBottom = () => {
// 检查并确保AI_TOKEN存在 // 检查并确保AI_TOKEN存在
@@ -57,7 +70,9 @@ const AiChat = () => {
// 初始化WebSocket连接 // 初始化WebSocket连接
const initWebSocket = () => { const initWebSocket = () => {
wsRef.current = createWebSocket(WSS_API_URL + "/chat/" + Taro.getStorageSync('AI_TOKEN')); const userToken = Taro.getStorageSync('AI_TOKEN') || 'anonymous';
console.log(WSS_API_URL + "/chat/" + userToken, 'wsUrl');
wsRef.current = createWebSocket(WSS_API_URL + "/chat/" + userToken);
wsRef.current.onMessage((data: any) => { wsRef.current.onMessage((data: any) => {
console.log('收到WebSocket消息:', data); console.log('收到WebSocket消息:', data);
@@ -145,10 +160,25 @@ const AiChat = () => {
useEffect(() => { useEffect(() => {
// 初始化时检查并生成AI Token // 初始化时检查并生成AI Token
checkAiToken(); const token = checkAiToken();
console.log('AI Token初始化完成:', token);
// 检查userToken
const userToken = Taro.getStorageSync('AI_TOKEN');
console.log('当前UserToken:', userToken || 'anonymous');
// 初始化WebSocket
initWebSocket(); initWebSocket();
Taro.hideTabBar(); Taro.hideTabBar();
// 标记初始化完成
setIsInitialized(true);
// 延迟调试,确保状态更新完成
setTimeout(() => {
debugInputStatus();
}, 100);
return () => { return () => {
if (wsRef.current) { if (wsRef.current) {
wsRef.current.close(); wsRef.current.close();
@@ -190,7 +220,7 @@ const AiChat = () => {
type: 'user', type: 'user',
query: content.trim(), query: content.trim(),
timestamp: Date.now(), timestamp: Date.now(),
user: `${Taro.getStorageSync('AI_TOKEN')}` user: `${Taro.getStorageSync('AI_TOKEN') || 'anonymous'}`
}; };
// 立即添加用户消息 // 立即添加用户消息
@@ -211,7 +241,7 @@ const AiChat = () => {
try { try {
await sendAiMessage({ await sendAiMessage({
query: content.trim(), query: content.trim(),
user: `${Taro.getStorageSync('AI_TOKEN')}`, user: `${Taro.getStorageSync('AI_TOKEN') || 'anonymous'}`,
responseMode: 'streaming', responseMode: 'streaming',
aiToken: aiToken, // 包含AI Token aiToken: aiToken, // 包含AI Token
}); });
@@ -257,6 +287,14 @@ const AiChat = () => {
// 处理快捷问题点击 // 处理快捷问题点击
const handleQuickQuestion = (question: string) => { const handleQuickQuestion = (question: string) => {
if (!isInitialized) {
Taro.showToast({
title: '正在初始化,请稍候...',
icon: 'none',
duration: 2000
});
return;
}
handleSendMessage(question); handleSendMessage(question);
}; };
@@ -339,10 +377,13 @@ const AiChat = () => {
<Textarea <Textarea
className="message-input" className="message-input"
value={inputValue} value={inputValue}
placeholder={isLoading ? "AI正在回复中..." : "请输入您的问题..."} placeholder={
!isInitialized ? "正在初始化..." :
isLoading ? "AI正在回复中..." :
"请输入您的问题..."
}
onInput={(e) => setInputValue(e.detail.value)} onInput={(e) => setInputValue(e.detail.value)}
onConfirm={() => handleSendMessage(inputValue)} onConfirm={() => handleSendMessage(inputValue)}
disabled={isLoading}
autoHeight autoHeight
maxlength={500} maxlength={500}
/> />
@@ -360,7 +401,7 @@ const AiChat = () => {
<Button <Button
type="primary" type="primary"
onClick={() => handleSendMessage(inputValue)} onClick={() => handleSendMessage(inputValue)}
disabled={!inputValue.trim()} disabled={!isInitialized || !inputValue.trim()}
icon={<ArrowUp/>} icon={<ArrowUp/>}
className="send-button" className="send-button"
> >
@@ -368,6 +409,9 @@ const AiChat = () => {
)} )}
</View> </View>
</View> </View>
<View className="fixed top-2 left-3" onClick={() => Taro.reLaunch({'url': '/pages/index/index'})}>
<Home/>
</View>
</View> </View>
); );
}; };

View File

@@ -8,77 +8,11 @@ import Menu from "./Menu";
import TabBar from "@/components/TabBar"; import TabBar from "@/components/TabBar";
import Image from "./Image"; import Image from "./Image";
export interface Market {
// 自增ID
id?: number;
latitude?: number;
longitude?: number;
name?: string;
title?: string;
}
function Home() { function Home() {
const [loading, setLoading] = useState<boolean>(false) const [loading, setLoading] = useState<boolean>(false)
const [IsLogin, setIsLogin] = useState<boolean>(true) const [IsLogin, setIsLogin] = useState<boolean>(true)
const [search, setSearch] = useState(false) const [search, setSearch] = useState(false)
// useShareTimeline(() => {
// return {
// title: '注册即可开通 - webSoft云应用',
// path: `/pages/index/index`
// };
// });
// useShareAppMessage(() => {
// return {
// title: '注册即可开通 - webSoft云应用',
// path: `/pages/index/index`,
// success: function (res) {
// console.log('分享成功', res);
// },
// fail: function (res) {
// console.log('分享失败', res);
// }
// };
// });
// const reloadMore = async () => {
// setPage(page + 1)
// }
// const showAuthModal = () => {
// Taro.showModal({
// title: '授权提示',
// content: '需要获取您的用户信息',
// confirmText: '去授权',
// cancelText: '取消',
// success: (res) => {
// if (res.confirm) {
// // 用户点击确认,打开授权设置页面
// openSetting();
// }
// }
// });
// };
// const openSetting = () => {
// // Taro.openSetting调起客户端小程序设置界面返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
// Taro.openSetting({
// success: (res) => {
// if (res.authSetting['scope.userInfo']) {
// // 用户授权成功,可以获取用户信息
// reload();
// } else {
// // 用户拒绝授权,提示授权失败
// Taro.showToast({
// title: '授权失败',
// icon: 'none'
// });
// }
// }
// });
// };
// 登录成功后回调 // 登录成功后回调
const handleLogin = () => { const handleLogin = () => {
setIsLogin(true) setIsLogin(true)
@@ -95,6 +29,7 @@ function Home() {
}; };
useEffect(() => { useEffect(() => {
Taro.showTabBar()
// 获取站点信息 // 获取站点信息
getSiteInfo().then((data) => { getSiteInfo().then((data) => {
console.log(data, 'siteInfo') console.log(data, 'siteInfo')
@@ -102,23 +37,6 @@ function Home() {
setSearch(false); setSearch(false);
} }
}) })
// Taro.getSetting获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
// Taro.getSetting({
// success: (res) => {
// if (res.authSetting['scope.userInfo']) {
// // 用户已经授权过,可以直接获取用户信息
// console.log('用户已经授权过,可以直接获取用户信息')
// reload().then(() => {
// setLoading(false)
// });
// } else {
// // 用户未授权,需要弹出授权窗口
// console.log('用户未授权,需要弹出授权窗口')
// // showAuthModal();
// }
// }
// });
// 获取用户信息
}, []); }, []);
return ( return (

View File

@@ -43,13 +43,13 @@ function UserCard() {
} }
{ {
!IsLogin && ( !IsLogin && (
<Avatar size="large" onClick={() => Taro.navigateTo({url: '/passport/sms-login'})} <Avatar size="large"
src={userInfo?.avatar} shape="round"/> src={userInfo?.avatar} shape="round"/>
) )
} }
<div className={'user-info flex flex-col px-1'}> <div className={'user-info flex flex-col px-1'}>
{!IsLogin ? ( {!IsLogin ? (
<div className={'p-1 text-sm text-white'}>{'点击登录'}</div> <div className={'p-1 text-sm text-white'}></div>
) : ) :
<div className={'p-1 text-sm text-white'}>{userInfo?.mobile}</div> <div className={'p-1 text-sm text-white'}>{userInfo?.mobile}</div>
} }

View File

@@ -37,10 +37,12 @@ export class WebSocketManager {
}; };
this.ws.onmessage = (event) => { this.ws.onmessage = (event) => {
console.log(event,'event>>>')
try { try {
if(event.data !== '连接成功'){
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
console.log(data,'data>>>')
this.onMessageCallback?.(data); this.onMessageCallback?.(data);
}
} catch (error) { } catch (error) {
console.error('解析WebSocket消息失败:', error); console.error('解析WebSocket消息失败:', error);
} }