|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
import { ChatContext } from '@/app/chat-context'; |
|
|
|
|
import { apiInterceptors, getAppInfo, getChatHistory, getDialogueList, postChatModeParamsList } from '@/client/api'; |
|
|
|
|
import { apiInterceptors, getAppInfo, getChatHistory, getDialogueList, postChatModeParamsList, doLogin, getVerifyCode } from '@/client/api'; |
|
|
|
|
import useUser from '@/hooks/use-user'; |
|
|
|
|
import { IApp } from '@/types/app'; |
|
|
|
|
import { ChatHistoryResponse } from '@/types/chat'; |
|
|
|
@ -7,13 +7,15 @@ import { getUserId } from '@/utils'; |
|
|
|
|
import { HEADER_USER_ID_KEY } from '@/utils/constants/index'; |
|
|
|
|
import { EventStreamContentType, fetchEventSource } from '@microsoft/fetch-event-source'; |
|
|
|
|
import { useRequest } from 'ahooks'; |
|
|
|
|
import { Spin } from 'antd'; |
|
|
|
|
import { Spin, Modal, Input, message } from 'antd'; |
|
|
|
|
import dynamic from 'next/dynamic'; |
|
|
|
|
import { useSearchParams } from 'next/navigation'; |
|
|
|
|
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'; |
|
|
|
|
import Header from './components/Header'; |
|
|
|
|
import InputContainer from './components/InputContainer'; |
|
|
|
|
|
|
|
|
|
import { STORAGE_USERINFO_KEY, STORAGE_USERINFO_VALID_TIME_KEY } from '@/utils/constants/index'; |
|
|
|
|
|
|
|
|
|
const Content = dynamic(() => import('@/pages/mobile/chat/components/Content'), { ssr: false }); |
|
|
|
|
|
|
|
|
|
interface MobileChatProps { |
|
|
|
@ -46,12 +48,12 @@ export const MobileChatContext = createContext<MobileChatProps>({ |
|
|
|
|
model: '', |
|
|
|
|
temperature: 0.5, |
|
|
|
|
resource: null, |
|
|
|
|
setModel: () => {}, |
|
|
|
|
setTemperature: () => {}, |
|
|
|
|
setResource: () => {}, |
|
|
|
|
setModel: () => { }, |
|
|
|
|
setTemperature: () => { }, |
|
|
|
|
setResource: () => { }, |
|
|
|
|
scene: '', |
|
|
|
|
history: [], |
|
|
|
|
setHistory: () => {}, |
|
|
|
|
setHistory: () => { }, |
|
|
|
|
scrollViewRef: { current: null }, |
|
|
|
|
appInfo: {} as IApp, |
|
|
|
|
conv_uid: '', |
|
|
|
@ -59,16 +61,84 @@ export const MobileChatContext = createContext<MobileChatProps>({ |
|
|
|
|
order: { current: 1 }, |
|
|
|
|
handleChat: () => Promise.resolve(), |
|
|
|
|
canAbort: false, |
|
|
|
|
setCarAbort: () => {}, |
|
|
|
|
setCarAbort: () => { }, |
|
|
|
|
canNewChat: false, |
|
|
|
|
setCanNewChat: () => {}, |
|
|
|
|
setCanNewChat: () => { }, |
|
|
|
|
ctrl: { current: undefined }, |
|
|
|
|
userInput: '', |
|
|
|
|
setUserInput: () => {}, |
|
|
|
|
getChatHistoryRun: () => {}, |
|
|
|
|
setUserInput: () => { }, |
|
|
|
|
getChatHistoryRun: () => { }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const MobileChat: React.FC = () => { |
|
|
|
|
const [isLoginReady, setIsLoginReady] = useState(false); |
|
|
|
|
|
|
|
|
|
const [loginVisible, setLoginVisible] = useState<boolean>(false); |
|
|
|
|
const [captchaImage, setCaptchaImage] = useState<string>(''); |
|
|
|
|
const [captchaId, setCaptchaId] = useState<string>(''); |
|
|
|
|
const [captchaInput, setCaptchaInput] = useState<string>(''); |
|
|
|
|
|
|
|
|
|
// 初始检测是否有token,没有就弹窗登录
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const token = localStorage.getItem(STORAGE_USERINFO_KEY); |
|
|
|
|
if (!token) { |
|
|
|
|
fetchCaptcha(); // 拉验证码
|
|
|
|
|
setLoginVisible(true); |
|
|
|
|
} else { |
|
|
|
|
getAppInfoRun({ chat_scene: chatScene, app_code: appCode }); |
|
|
|
|
} |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
const fetchCaptcha = async () => { |
|
|
|
|
try { |
|
|
|
|
const [, res] = await apiInterceptors(getVerifyCode()); |
|
|
|
|
|
|
|
|
|
setCaptchaImage(res?.captcha_image); |
|
|
|
|
setCaptchaId(res?.captcha_id); |
|
|
|
|
} catch { |
|
|
|
|
message.error('验证码获取失败'); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleLogin = async () => { |
|
|
|
|
try { |
|
|
|
|
const [, res] = await apiInterceptors( |
|
|
|
|
doLogin({ |
|
|
|
|
username: 'cjyadmin', |
|
|
|
|
password: 'Cjy@1303!', |
|
|
|
|
catcha_id: captchaId, |
|
|
|
|
verificationCode: captchaInput, |
|
|
|
|
}) |
|
|
|
|
); |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
if (res) { |
|
|
|
|
const user = { |
|
|
|
|
token: res, |
|
|
|
|
user_channel: `CJY`, |
|
|
|
|
user_no: `001`, |
|
|
|
|
nick_name: 'cjyadmin', |
|
|
|
|
}; |
|
|
|
|
localStorage.setItem(STORAGE_USERINFO_KEY, JSON.stringify(user)); |
|
|
|
|
localStorage.setItem(STORAGE_USERINFO_VALID_TIME_KEY, Date.now().toString()); |
|
|
|
|
|
|
|
|
|
message.success('验证码已通过'); |
|
|
|
|
setLoginVisible(false); |
|
|
|
|
setIsLoginReady(true); // 登录成功之后设置为true
|
|
|
|
|
|
|
|
|
|
// 登录成功后再执行初始化接口
|
|
|
|
|
getAppInfoRun({ chat_scene: chatScene, app_code: appCode }); |
|
|
|
|
getChatHistoryRun(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
fetchCaptcha(); // 登录失败刷新验证码
|
|
|
|
|
} |
|
|
|
|
} catch { |
|
|
|
|
|
|
|
|
|
message.error('登录失败,请重试'); |
|
|
|
|
fetchCaptcha(); // 登录失败刷新验证码
|
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
// 从url上获取基本参数
|
|
|
|
|
const searchParams = useSearchParams(); |
|
|
|
|
const chatScene = searchParams?.get('chat_scene') ?? ''; |
|
|
|
@ -161,16 +231,17 @@ const MobileChat: React.FC = () => { |
|
|
|
|
|
|
|
|
|
// 获取应用信息
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (chatScene && appCode && modelList.length) { |
|
|
|
|
if (isLoginReady && chatScene && appCode && modelList.length) { |
|
|
|
|
getAppInfoRun({ chat_scene: chatScene, app_code: appCode }); |
|
|
|
|
} |
|
|
|
|
}, [appCode, chatScene, getAppInfoRun, modelList]); |
|
|
|
|
}, [isLoginReady, chatScene, appCode, modelList]); |
|
|
|
|
|
|
|
|
|
// 设置历史会话记录
|
|
|
|
|
useEffect(() => { |
|
|
|
|
appCode && getChatHistoryRun(); |
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, [appCode]); |
|
|
|
|
if (isLoginReady && appCode) { |
|
|
|
|
getChatHistoryRun(); |
|
|
|
|
} |
|
|
|
|
}, [isLoginReady, appCode]); |
|
|
|
|
|
|
|
|
|
// 设置默认模型
|
|
|
|
|
useEffect(() => { |
|
|
|
@ -294,53 +365,74 @@ const MobileChat: React.FC = () => { |
|
|
|
|
|
|
|
|
|
// 如果是原生应用,拉取会话列表获取资源参数
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (chatScene && chatScene !== 'chat_agent') { |
|
|
|
|
if (isLoginReady && chatScene && chatScene !== 'chat_agent') { |
|
|
|
|
getDialogueListRun(); |
|
|
|
|
} |
|
|
|
|
}, [chatScene, getDialogueListRun]); |
|
|
|
|
}, [isLoginReady, chatScene]); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<MobileChatContext.Provider |
|
|
|
|
value={{ |
|
|
|
|
model, |
|
|
|
|
resource, |
|
|
|
|
setModel, |
|
|
|
|
setTemperature, |
|
|
|
|
setResource, |
|
|
|
|
temperature, |
|
|
|
|
appInfo: appInfo as IApp, |
|
|
|
|
conv_uid, |
|
|
|
|
scene: chatScene, |
|
|
|
|
history, |
|
|
|
|
scrollViewRef, |
|
|
|
|
setHistory, |
|
|
|
|
resourceList: data, |
|
|
|
|
order, |
|
|
|
|
handleChat, |
|
|
|
|
setCanNewChat, |
|
|
|
|
ctrl, |
|
|
|
|
canAbort, |
|
|
|
|
setCarAbort, |
|
|
|
|
canNewChat, |
|
|
|
|
userInput, |
|
|
|
|
setUserInput, |
|
|
|
|
getChatHistoryRun, |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<Spin |
|
|
|
|
size='large' |
|
|
|
|
className='flex h-screen w-screen justify-center items-center max-h-screen' |
|
|
|
|
spinning={historyLoading || appInfoLoading || resourceLoading || dialogueListLoading} |
|
|
|
|
<> |
|
|
|
|
<MobileChatContext.Provider |
|
|
|
|
value={{ |
|
|
|
|
model, |
|
|
|
|
resource, |
|
|
|
|
setModel, |
|
|
|
|
setTemperature, |
|
|
|
|
setResource, |
|
|
|
|
temperature, |
|
|
|
|
appInfo: appInfo as IApp, |
|
|
|
|
conv_uid, |
|
|
|
|
scene: chatScene, |
|
|
|
|
history, |
|
|
|
|
scrollViewRef, |
|
|
|
|
setHistory, |
|
|
|
|
resourceList: data, |
|
|
|
|
order, |
|
|
|
|
handleChat, |
|
|
|
|
setCanNewChat, |
|
|
|
|
ctrl, |
|
|
|
|
canAbort, |
|
|
|
|
setCarAbort, |
|
|
|
|
canNewChat, |
|
|
|
|
userInput, |
|
|
|
|
setUserInput, |
|
|
|
|
getChatHistoryRun, |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
<div className='flex flex-col h-screen bg-gradient-light dark:bg-gradient-dark p-4 pt-0'> |
|
|
|
|
<div ref={scrollViewRef} className='flex flex-col flex-1 overflow-y-auto mb-3'> |
|
|
|
|
<Header /> |
|
|
|
|
<Content /> |
|
|
|
|
<Spin |
|
|
|
|
size='large' |
|
|
|
|
className='flex h-screen w-screen justify-center items-center max-h-screen' |
|
|
|
|
spinning={historyLoading || appInfoLoading || resourceLoading || dialogueListLoading} |
|
|
|
|
> |
|
|
|
|
<div className='flex flex-col h-screen bg-gradient-light dark:bg-gradient-dark p-4 pt-0'> |
|
|
|
|
<div ref={scrollViewRef} className='flex flex-col flex-1 overflow-y-auto mb-3'> |
|
|
|
|
<Header /> |
|
|
|
|
<Content /> |
|
|
|
|
</div> |
|
|
|
|
{appInfo?.app_code && <InputContainer />} |
|
|
|
|
</div> |
|
|
|
|
{appInfo?.app_code && <InputContainer />} |
|
|
|
|
</Spin> |
|
|
|
|
</MobileChatContext.Provider> |
|
|
|
|
<Modal |
|
|
|
|
open={loginVisible} |
|
|
|
|
title="请输入验证码" |
|
|
|
|
onOk={handleLogin} |
|
|
|
|
onCancel={() => { }} |
|
|
|
|
okText="确定" |
|
|
|
|
cancelButtonProps={{ style: { display: 'none' } }} |
|
|
|
|
> |
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
|
|
|
|
<img src={captchaImage} alt="验证码" style={{ height: 40, marginRight: 10 }} /> |
|
|
|
|
<Input |
|
|
|
|
placeholder="输入验证码" |
|
|
|
|
value={captchaInput} |
|
|
|
|
onChange={(e) => setCaptchaInput(e.target.value)} |
|
|
|
|
maxLength={6} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</Spin> |
|
|
|
|
</MobileChatContext.Provider> |
|
|
|
|
</Modal> |
|
|
|
|
</> |
|
|
|
|
|
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|