From 413b120c404fa3e20f8339a758b1f89365207864 Mon Sep 17 00:00:00 2001 From: maojindao55 Date: Thu, 27 Mar 2025 19:24:55 +0800 Subject: [PATCH] update --- functions/api/_middleware.js | 27 ++-- functions/api/init.ts | 4 +- functions/api/login.ts | 6 +- functions/api/user/info.ts | 60 ++++++++ functions/api/user/update.ts | 88 ++++++++++++ src/pages/chat/components/Sidebar.tsx | 2 +- src/pages/chat/components/UserSection.tsx | 164 +++++++++++++++++----- src/pages/login/index.jsx | 8 ++ 8 files changed, 302 insertions(+), 57 deletions(-) create mode 100644 functions/api/user/info.ts create mode 100644 functions/api/user/update.ts diff --git a/functions/api/_middleware.js b/functions/api/_middleware.js index cfa42fb..170f1bd 100644 --- a/functions/api/_middleware.js +++ b/functions/api/_middleware.js @@ -47,32 +47,27 @@ async function verifyToken(token, env) { // 中间件函数 export async function onRequest(context) { try { - //获取环境变量中的AUTH_ACCESS const authAccess = context.env.AUTH_ACCESS; console.log('authAccess', authAccess); - //如果AUTH_ACCESS为0则跳过权限校验 - if (!authAccess || authAccess === '0') { + + if (!authAccess || authAccess === '0' || context.request.url.includes('/login') || context.request.url.includes('/sendcode') || context.request.url.includes('/test-db')) { console.log('跳过权限校验'); - return await context.next(); + context.data = { user: null }; + return context.next(); } - const request = context.request; - const env = context.env; - //跳过登录页面 - if (request.url.includes('/login') || request.url.includes('/sendcode') || request.url.includes('/login') || request.url.includes('/test-db')) { - return await context.next(); - } - const authHeader = request.headers.get('Authorization'); + + const authHeader = context.request.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { throw new Error('No token provided'); } const token = authHeader.split(' ')[1]; - const payload = await verifyToken(token, env); + const payload = await verifyToken(token, context.env); - // 将用户信息添加到上下文中 - context.user = payload; - - return await context.next(); + // 直接在原有的 request 对象上添加 context + context.data = { user: payload }; + console.log('context.request.user', context.data); + return context.next(); } catch (error) { console.error(error.message, context.request.url); return new Response(JSON.stringify({ error: error.message }), { diff --git a/functions/api/init.ts b/functions/api/init.ts index 68495b0..2aee297 100644 --- a/functions/api/init.ts +++ b/functions/api/init.ts @@ -1,13 +1,13 @@ import {generateAICharacters } from '../../src/config/aiCharacters'; import { groups } from '../../src/config/groups'; -export async function onRequestGet({ env, request }) { - console.log('init'); +export async function onRequestGet(context) { try { return Response.json({ code: 200, data: { groups: groups, characters: generateAICharacters('#groupName#', '#allTags#'), + user: context.data.user || null } }); } catch (error) { diff --git a/functions/api/login.ts b/functions/api/login.ts index 288d049..b213faf 100644 --- a/functions/api/login.ts +++ b/functions/api/login.ts @@ -98,7 +98,7 @@ export const onRequestPost: PagesFunction = async (context) => { `).bind(phone).first(); // 生成 token - const token = await generateToken(phone, env); + const token = await generateToken(userId, env); // 删除验证码 await env.bgkv.delete(`sms:${phone}`); @@ -139,14 +139,14 @@ export const onRequestPost: PagesFunction = async (context) => { }; // 修改为 async 函数 -async function generateToken(phone: string, env: Env): Promise { +async function generateToken(userId: string, env: Env): Promise { const header = { alg: 'HS256', typ: 'JWT' }; const payload = { - phone, + userId, exp: Math.floor(Date.now() / 1000) + (7 * 24 * 60 * 60), // 7天过期 iat: Math.floor(Date.now() / 1000) }; diff --git a/functions/api/user/info.ts b/functions/api/user/info.ts new file mode 100644 index 0000000..e7de286 --- /dev/null +++ b/functions/api/user/info.ts @@ -0,0 +1,60 @@ +interface Env { + bgdb: D1Database; +} + +export const onRequestGet: PagesFunction = async (context) => { + try { + const { env, data } = context; + + // 从数据库获取用户信息 + const db = env.bgdb; + const userInfo = await db.prepare(` + SELECT id, phone, nickname, avatar_url, status + FROM users + WHERE id = ? + `).bind(data.user.userId).first(); + + if (!userInfo) { + return new Response( + JSON.stringify({ + success: false, + message: '用户不存在' + }), + { + status: 404, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } + + return new Response( + JSON.stringify({ + success: true, + data: userInfo + }), + { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + + } catch (error) { + console.error(error); + return new Response( + JSON.stringify({ + success: false, + message: '服务器错误' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } +}; \ No newline at end of file diff --git a/functions/api/user/update.ts b/functions/api/user/update.ts new file mode 100644 index 0000000..e82b28c --- /dev/null +++ b/functions/api/user/update.ts @@ -0,0 +1,88 @@ +interface Env { + bgdb: D1Database; +} + +export const onRequestPost: PagesFunction = async (context) => { + try { + const { env, data, request } = context; + + // 解析请求体 + const body = await request.json(); + const { nickname } = body; + + // 验证昵称 + if (!nickname || typeof nickname !== 'string' || nickname.length > 32) { + return new Response( + JSON.stringify({ + success: false, + message: '昵称格式不正确' + }), + { + status: 400, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } + + // 更新数据库中的昵称 + const db = env.bgdb; + const result = await db.prepare(` + UPDATE users + SET nickname = ?, + updated_at = DATETIME('now') + WHERE id = ? + `).bind(nickname, data.user.userId).run(); + + if (!result.success) { + return new Response( + JSON.stringify({ + success: false, + message: '更新失败' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } + + // 获取更新后的用户信息 + const userInfo = await db.prepare(` + SELECT id, phone, nickname, avatar_url, status + FROM users + WHERE id = ? + `).bind(data.user.userId).first(); + + return new Response( + JSON.stringify({ + success: true, + data: userInfo + }), + { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + + } catch (error) { + console.error(error); + return new Response( + JSON.stringify({ + success: false, + message: '服务器错误' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + } + ); + } +}; \ No newline at end of file diff --git a/src/pages/chat/components/Sidebar.tsx b/src/pages/chat/components/Sidebar.tsx index 70b960f..e054bf5 100644 --- a/src/pages/chat/components/Sidebar.tsx +++ b/src/pages/chat/components/Sidebar.tsx @@ -145,7 +145,7 @@ const Sidebar = ({ isOpen, toggleSidebar, selectedGroupIndex = 0, onSelectGroup, {isOpen && ( -
+
= ({ isOpen }) => { const [isHovering, setIsHovering] = useState(false); - + const [userInfo, setUserInfo] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isEditing, setIsEditing] = useState(false); + const [newNickname, setNewNickname] = useState(''); + + useEffect(() => { + const fetchUserInfo = async () => { + if (!isOpen) return; + + try { + setIsLoading(true); + const response = await request('/api/user/info'); + const { data } = await response.json(); + console.log('data', data); + setUserInfo(data); + } catch (error) { + console.error('获取用户信息失败:', error); + } finally { + setIsLoading(false); + } + }; + + fetchUserInfo(); + }, [isOpen]); + + // 添加更新昵称的函数 + const updateNickname = async () => { + if (!newNickname.trim()) return; + + try { + setIsLoading(true); + const response = await request('/api/user/update', { + method: 'POST', + body: JSON.stringify({ nickname: newNickname.trim() }) + }); + const { data } = await response.json(); + setUserInfo(data); + setIsEditing(false); + } catch (error) { + console.error('更新昵称失败:', error); + } finally { + setIsLoading(false); + } + }; + if (!isOpen) return null; return (
setIsHovering(true)} @@ -23,7 +74,9 @@ export const UserSection: React.FC = ({ isOpen }) => { {/* 头像区域 */}
- + + {isLoading ? '...' : userInfo?.nickname?.[0] || '我'} +
{/* 头像hover效果 */}
@@ -33,40 +86,81 @@ export const UserSection: React.FC = ({ isOpen }) => { {/* 用户信息区域 */}
-
- - 游客用户 - - +
+ {isEditing ? ( +
+ setNewNickname(e.target.value)} + className="text-sm px-2 border rounded-md w-full" + placeholder={userInfo?.nickname || '输入新昵称'} + onKeyDown={(e) => { + if (e.key === 'Enter') updateNickname(); + if (e.key === 'Escape') setIsEditing(false); + }} + autoFocus + /> +
+ + +
+
+ ) : ( + <> + + {isLoading ? '加载中...' : userInfo?.nickname || '游客用户'} + + { + setIsEditing(true); + setNewNickname(userInfo?.nickname || ''); + }} + /> + + )}
{/* 退出登录按钮 */} -
{ - // 这里添加退出登录的处理逻辑 - console.log('退出登录'); - }} - > - - - 退出登录 - -
+ "flex items-center gap-0.5 mt-1 text-xs text-muted-foreground/70", + "hover:text-rose-500 transition-all duration-200 group", + "rounded-md cursor-pointer" + )} + onClick={() => { + localStorage.removeItem('token'); + window.location.href = '/login'; + }} + > + + + 退出登录 + +
+ )}
); diff --git a/src/pages/login/index.jsx b/src/pages/login/index.jsx index 35f7b8b..aa4a2a4 100644 --- a/src/pages/login/index.jsx +++ b/src/pages/login/index.jsx @@ -1,3 +1,4 @@ +import React from 'react'; import { useNavigate } from 'react-router-dom'; import PhoneLogin from './comonents/PhoneLogin'; @@ -9,6 +10,13 @@ export default function Login() { navigate('/'); }; + React.useEffect(() => { + const isLogin = localStorage.getItem('token'); + if (isLogin) { + window.location.href = '/'; // 由于是 Vite 多页面,这里使用 window.location.href + } + }, []); + return (