refactor(web): 重构移动端聊天页面的用户认证和请求处理

- 在 use-chat.ts 和 InputContainer.tsx 中添加 debugger 语句以便调试
- 在 AppContent.tsx 中隐藏分享 APP ID 的表单项
- 在 MobileChat.tsx 中改进用户认证逻辑,从本地存储获取 token
- 更新 MobileChat.tsx 中的请求头,使用 Authorization 替代 getUserId()
- 在 MobileChat.tsx 中添加页面关闭时清除用户信息的逻辑
- 调整 MobileChat.tsx 中的验证码提示文本
main
Tuzki 4 months ago
parent ed2a4a023b
commit 8fdcc8b2e1
  1. 1
      web/hooks/use-chat.ts
  2. 3
      web/pages/construct/app/index.tsx
  3. 11
      web/pages/mobile/chat/components/InputContainer.tsx
  4. 46
      web/pages/mobile/chat/index.tsx

@ -22,6 +22,7 @@ type ChatParams = {
onError?: (content: string, error?: Error) => void;
};
let authToken = '';
if (typeof window !== 'undefined') {
const tokenStr = localStorage.getItem(STORAGE_USERINFO_KEY) || '{}';
authToken = JSON.parse(tokenStr)?.token || '';

@ -408,6 +408,7 @@ export default function AppContent() {
//分享相关
const handleSubmitShare = async (values: any) => {
const params = {
...values,
app_ids: isEditShare ? values.app_ids : currentApp?.app_code, // 编辑时使用已有 app_ids
@ -896,7 +897,7 @@ export default function AppContent() {
>
<Input placeholder="https://hbcjy.com" />
</Form.Item>
<Form.Item label="分享APP ID" name="app_ids" >
<Form.Item hidden={true} label="分享APP ID" name="app_ids" >
<Input />
</Form.Item>
</Form>

@ -13,6 +13,8 @@ import { MobileChatContext } from '../';
import ModelSelector from './ModelSelector';
import Resource from './Resource';
import Thermometer from './Thermometer';
import { STORAGE_USERINFO_KEY } from '@/utils/constants/index';
const tagColors = ['magenta', 'orange', 'geekblue', 'purple', 'cyan', 'green'];
@ -43,9 +45,16 @@ const InputContainer: React.FC = () => {
const [isFocus, setIsFocus] = useState<boolean>(false);
// 是否中文输入
const [isZhInput, setIsZhInput] = useState<boolean>(false);
const [authToken, setAuthToken] = useState<string>('');
useEffect(() => {
const tokenStr = localStorage.getItem(STORAGE_USERINFO_KEY) || '{}';
const token = JSON.parse(tokenStr)?.token || '';
setAuthToken(token);
}, []);
// 处理会话
const handleChat = async (content?: string) => {
setUserInput('');
ctrl.current = new AbortController();
const params = {
@ -86,7 +95,7 @@ const InputContainer: React.FC = () => {
method: 'POST',
headers: {
'Content-Type': 'application/json',
[HEADER_USER_ID_KEY]: getUserId() ?? '',
'Authorization': authToken ?? '',
},
signal: ctrl.current.signal,
body: JSON.stringify(params),

@ -1,9 +1,10 @@
'use client';
import { ChatContext } from '@/app/chat-context';
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';
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';
@ -14,10 +15,10 @@ import React, { createContext, useContext, useEffect, useMemo, useRef, useState
import Header from './components/Header';
import InputContainer from './components/InputContainer';
import { useRouter } from 'next/router';
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 {
model: string;
temperature: number;
@ -77,22 +78,25 @@ const MobileChat: React.FC = () => {
const [captchaImage, setCaptchaImage] = useState<string>('');
const [captchaId, setCaptchaId] = useState<string>('');
const [captchaInput, setCaptchaInput] = useState<string>('');
const [authToken, setAuthToken] = useState<string>('');
// 初始检测是否有token,没有就弹窗登录
useEffect(() => {
const token = localStorage.getItem(STORAGE_USERINFO_KEY);
const tokenStr = localStorage.getItem(STORAGE_USERINFO_KEY) || '{}';
const token = JSON.parse(tokenStr)?.token || '';
setAuthToken(token);
if (!token) {
fetchCaptcha(); // 拉验证码
setLoginVisible(true);
} else {
getAppInfoRun({ chat_scene: chatScene, app_code: appCode });
setIsLoginReady(true); // 登录成功之后设置为true
}
}, []);
const fetchCaptcha = async () => {
try {
const [, res] = await apiInterceptors(getVerifyCode());
setCaptchaImage(res?.captcha_image);
setCaptchaId(res?.captcha_id);
} catch {
@ -126,23 +130,28 @@ const MobileChat: React.FC = () => {
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') ?? '';
const appCode = searchParams?.get('app_code') ?? '';
const router = useRouter();
const { chat_scene, app_code, pc_slide } = router.query;
const chatScene = chat_scene ? String(chat_scene) : '';
const appCode = app_code ? String(app_code) : '';
useEffect(() => {
if (router.isReady) {
// 这里可以安全地访问 query 参数
}
}, [router.isReady]);
// 模型列表
const { modelList } = useContext(ChatContext);
@ -252,6 +261,14 @@ const MobileChat: React.FC = () => {
}
}, [modelList, appInfo]);
useEffect(() => {
return () => {
localStorage.removeItem(STORAGE_USERINFO_KEY);
localStorage.removeItem(STORAGE_USERINFO_VALID_TIME_KEY);
console.log('User info cleared when page closed.');
};
}, []);
// 设置默认温度;
useEffect(() => {
// 获取应用信息中的model值
@ -271,6 +288,7 @@ const MobileChat: React.FC = () => {
// 处理会话
const handleChat = async (content?: string) => {
setUserInput('');
ctrl.current = new AbortController();
const params = {
@ -311,7 +329,7 @@ const MobileChat: React.FC = () => {
method: 'POST',
headers: {
'Content-Type': 'application/json',
[HEADER_USER_ID_KEY]: getUserId() ?? '',
'Authorization': authToken ?? '',
},
signal: ctrl.current.signal,
body: JSON.stringify(params),
@ -415,7 +433,7 @@ const MobileChat: React.FC = () => {
</MobileChatContext.Provider>
<Modal
open={loginVisible}
title="请输入验证码"
title="为了确保安全,请输入验证码"
onOk={handleLogin}
onCancel={() => { }}
okText="确定"

Loading…
Cancel
Save