diff --git a/website/src/App.jsx b/website/src/App.jsx index edd8438..dcb861d 100644 --- a/website/src/App.jsx +++ b/website/src/App.jsx @@ -35,6 +35,10 @@ import Tasks from './user/Tasks'; import TaskDetail from './user/TaskDetail'; import Enterprise from './platform/Enterprise'; import ParkCenter from './platform/ParkCenter'; +import MyBookings from './user/MyBookings'; +import MyTasks from './user/MyTasks'; +import MyPark from './user/MyPark'; +import MyCert from './user/MyCert'; /* 公开路由(无需登录) */ const PUBLIC_ROUTES = [ @@ -54,7 +58,11 @@ const PUBLIC_ROUTES = [ { path: 'task-detail', Page: TaskDetail }, { path: 'enterprise', Page: Enterprise }, { path: 'park-center', Page: ParkCenter }, - { path: 'profile', Page: Profile } + { path: 'profile', Page: Profile }, + { path: 'my-bookings', Page: MyBookings }, + { path: 'my-tasks', Page: MyTasks }, + { path: 'my-park', Page: MyPark }, + { path: 'my-cert', Page: MyCert } ]; /* 内部路由(/pine,需登录) */ diff --git a/website/src/components/organisms/index.jsx b/website/src/components/organisms/index.jsx index b16e06f..a1ae50b 100644 --- a/website/src/components/organisms/index.jsx +++ b/website/src/components/organisms/index.jsx @@ -1,24 +1,37 @@ import React from 'react'; import { Logo } from '../atoms'; import { NAV, PINE_NAV } from '../../data/site'; -import { logout, getUser } from '../../services/auth'; +import { logout, getUser, isAuthed } from '../../services/auth'; -/* ---------- 组织:Header(含移动端汉堡 + 菜单) ---------- */ +/* 用户下拉菜单项:个人中心 / 我的报名 / 我的任务 / 我的园区 / 认证中心 */ +const USER_MENU = [ + ['个人中心', '#/profile'], + ['我的报名', '#/my-bookings'], + ['我的任务', '#/my-tasks'], + ['我的园区', '#/my-park'], + ['认证中心', '#/my-cert'], +]; + +/* ---------- 组织:Header(含移动端汉堡 + 菜单 + 用户下拉) ---------- */ export function Header({ active }) { const [open, setOpen] = React.useState(false); + const [menuOpen, setMenuOpen] = React.useState(false); + const menuRef = React.useRef(null); const pine = !!active && active.startsWith('pine'); const nav = pine ? PINE_NAV : NAV; - const user = pine ? null : getUser(); // 公开端显示登录昵称(像素字) + const user = pine ? null : getUser(); // 公开端显示登录昵称 React.useEffect(() => { - const onKey = (e) => { if (e.key === 'Escape') setOpen(false); }; + const onKey = (e) => { if (e.key === 'Escape') { setOpen(false); setMenuOpen(false); } }; const onResize = () => { if (window.innerWidth > 720) setOpen(false); }; + const onDown = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false); }; window.addEventListener('keydown', onKey); window.addEventListener('resize', onResize); - return () => { window.removeEventListener('keydown', onKey); window.removeEventListener('resize', onResize); }; + window.addEventListener('mousedown', onDown); + return () => { window.removeEventListener('keydown', onKey); window.removeEventListener('resize', onResize); window.removeEventListener('mousedown', onDown); }; }, []); - const doLogout = () => { setOpen(false); logout(); window.location.hash = '#/'; }; + const doLogout = () => { setOpen(false); setMenuOpen(false); logout(); window.location.hash = '#/'; }; return ( <> @@ -33,13 +46,32 @@ export function Header({ active }) {
{pine ? ( + ) : isAuthed() ? ( +
+ + {menuOpen && ( +
+ {USER_MENU.map(([label, href]) => ( + setMenuOpen(false)}>{label} + ))} + 退出登录 +
+ )} +
) : ( - <> - {user && user.role === 'service' && 企业中心} - {user && user.role === 'carrier' && 园区管理} - {user && {user.name}} - 个人中心 - + 登录 / 注册 )}