修复:AI问答模块
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 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
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user