Browse Source

为大、中、小屏幕的导航区域添加登录与配置入口

dengdx 2 months ago
parent
commit
5f7bdf0c13

+ 15 - 0
src/layouts/BasicLayout.tsx

@@ -15,6 +15,8 @@ import ArchivelistPage from '@/pages/patient/ArchiveList';
 import BinPage from '@/pages/patient/Bin';
 import OutputlistPage from '@/pages/patient/OutputList';
 import PatientManagement from '@/pages/patient/PatientManagement';
+import MeButton from '@/pages/security/components/MeButton';
+import Profile from '@/pages/security/Profile';
 
 // import { Link } from 'react-router-dom';
 // import { MenuOutlined } from '@ant-design/icons';
@@ -54,6 +56,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = () => {
     bin: <BinPage />,
     outputlist: <OutputlistPage />,
     patient_management: <PatientManagement />,
+    profile: <Profile />, // 需确保已引入 Profile 组件
   };
   //感知菜单项点击
   const handleMenuClick = (key: string) => {
@@ -184,6 +187,18 @@ const BasicLayout: React.FC<BasicLayoutProps> = () => {
               key="print"
               icon={<div>⚙️</div>}
             />
+            <TabBar.Item
+              title="我的"
+              key="profile"
+              icon={
+                <MeButton
+                  isLogin={true} // TODO: 替换为实际登录状态
+                  avatarUrl={undefined} // TODO: 替换为实际头像
+                  onClick={() => handleMenuClick('profile')}
+                  // 不传递username
+                />
+              }
+            />
           </TabBar>
         </div>
         <NavbarFloat

+ 54 - 9
src/layouts/NavMenu.tsx

@@ -8,6 +8,9 @@ import {
 import type { MenuProps } from 'antd';
 import { Menu } from 'antd';
 import { FormattedMessage } from 'react-intl';
+import { Space, Button, Row } from 'antd';
+import { ToolOutlined } from '@ant-design/icons';
+import MeButton from '../pages/security/components/MeButton';
 
 type MenuItem = Required<MenuProps>['items'][number];
 
@@ -138,15 +141,57 @@ const NavMenu: React.FC<NavMenuProps> = ({ onMenuClick }) => {
   };
 
   return (
-    <Menu
-      openKeys={openKeys}
-      onOpenChange={onOpenChange}
-      onClick={onClick}
-      defaultSelectedKeys={['1']}
-      defaultOpenKeys={['sub1']}
-      mode="inline"
-      items={items}
-    />
+    <>
+      <Menu
+        openKeys={openKeys}
+        onOpenChange={onOpenChange}
+        onClick={onClick}
+        defaultSelectedKeys={['1']}
+        defaultOpenKeys={['sub1']}
+        mode="inline"
+        items={items}
+      />
+      {/* 底部按钮区域 */}
+      <Row
+        style={{
+          position: 'absolute',
+          bottom: 32,
+          left: 0,
+          width: '100%',
+          justifyContent: 'center',
+        }}
+      >
+        <Space
+          direction="vertical"
+          align="start"
+          style={{ width: '100%', paddingLeft: 20 }}
+        >
+          <Space>
+            <Button
+              shape="circle"
+              size="large"
+              icon={<ToolOutlined />}
+              style={{
+                display: 'flex',
+                alignItems: 'center',
+                justifyContent: 'center',
+                userSelect: 'none',
+              }}
+              onClick={() => onMenuClick?.('settings')}
+            />
+            <span>配置</span>
+          </Space>
+          <MeButton
+            size="large"
+            isLogin={true}
+            avatarUrl={undefined}
+            username="未登录"
+            // username={true ? '用户名' : '未登录'} // TODO: 替换为实际登录状态和用户名
+            onClick={() => onMenuClick?.('me')}
+          />
+        </Space>
+      </Row>
+    </>
   );
 };
 

+ 44 - 1
src/layouts/NavbarFloat.tsx

@@ -1,5 +1,5 @@
 import React, { useState, useRef } from 'react';
-import { Menu, Button, Drawer } from 'antd';
+import { Menu, Button, Drawer, Space, Row } from 'antd';
 import {
   MenuUnfoldOutlined,
   UserOutlined,
@@ -9,6 +9,7 @@ import {
   PrinterOutlined,
 } from '@ant-design/icons';
 import type { MenuProps } from 'antd';
+import MeButton from '../pages/security/components/MeButton';
 
 interface NavbarFloatProps {
   position?: 'left' | 'right';
@@ -159,6 +160,48 @@ const NavbarFloat: React.FC<NavbarFloatProps> = ({
           items={menuItems}
           style={{ border: 'none', backgroundColor: 'transparent' }}
         />
+        {/* 底部按钮区域,使用Ant Design组件替代div */}
+        <Row
+          style={{
+            position: 'absolute',
+            bottom: 32,
+            left: 0,
+            width: '100%',
+            justifyContent: 'center',
+          }}
+        >
+          <Space direction="vertical" align="center" style={{ width: '100%' }}>
+            <Space>
+              <Button
+                shape="circle"
+                size="large"
+                icon={<ToolOutlined />}
+                style={{
+                  display: 'flex',
+                  alignItems: 'center',
+                  justifyContent: 'center',
+                  userSelect: 'none',
+                }}
+                onClick={() => {
+                  if (props.onMenuClick) props.onMenuClick('settings');
+                  setOpen(false);
+                }}
+              />
+              <span>配置</span>
+            </Space>
+            <MeButton
+              size="large"
+              isLogin={true}
+              avatarUrl={undefined}
+              username={'未登录'}
+              // username={true ? '用户名' : '未登录'} // TODO: 替换为实际登录状态和用户名
+              onClick={() => {
+                if (props.onMenuClick) props.onMenuClick('me');
+                setOpen(false);
+              }}
+            />
+          </Space>
+        </Row>
       </Drawer>
     </>
   );

+ 21 - 0
src/pages/security/Profile.md

@@ -0,0 +1,21 @@
+# 关于Profile组件
+
+显示用户的profile
+
+# 实现
+
+1. 基于ant design组件库
+2. 组成描述
+   > 上下布局;
+   > 上部显示avatar和用户名,avatar和用户名从左到右排列
+   > 下部显示设置导航条目,每个条目用于导航到详细设置页面。条目包括:
+   1. 硬件管理
+   2. 网络节点
+   3. 检查协议
+   4. 人工智能
+   5. 图像处理
+   6. 任务管理
+   7. 日志清理
+3. 关于下部的详细描述
+   > 使用ant design的List组件作为导航条目的容器
+   > 导航条目响应点击,右侧显示方向向右的箭头,意味着点击后会有下级页面

+ 53 - 0
src/pages/security/Profile.tsx

@@ -0,0 +1,53 @@
+import React from 'react';
+import { Avatar, Typography, List, Space } from 'antd';
+import { UserOutlined, RightOutlined } from '@ant-design/icons';
+
+const { Text } = Typography;
+
+const settings = [
+  { key: 'hardware', label: '硬件管理' },
+  { key: 'network', label: '网络节点' },
+  { key: 'protocol', label: '检查协议' },
+  { key: 'ai', label: '人工智能' },
+  { key: 'image', label: '图像处理' },
+  { key: 'task', label: '任务管理' },
+  { key: 'log', label: '日志清理' },
+];
+
+const Profile: React.FC = () => {
+  // 假设用户名和头像
+  const username = '用户名';
+
+  const handleItemClick = (item: (typeof settings)[0]) => {
+    // TODO: 跳转到对应设置页面
+    // 可以用react-router等
+    // e.g. navigate(`/settings/${item.key}`)
+    console.log(`跳转到设置页面: ${item.label}`);
+  };
+
+  return (
+    <div style={{ maxWidth: 400, margin: '0 auto', padding: 24 }}>
+      <Space align="center" style={{ marginBottom: 32 }}>
+        <Avatar size={64} icon={<UserOutlined />} />
+        <Text strong style={{ fontSize: 20, marginLeft: 16 }}>
+          {username}
+        </Text>
+      </Space>
+      <List
+        itemLayout="horizontal"
+        dataSource={settings}
+        renderItem={(item) => (
+          <List.Item
+            onClick={() => handleItemClick(item)}
+            style={{ cursor: 'pointer' }}
+            actions={[<RightOutlined key="arrow" />]}
+          >
+            <List.Item.Meta title={item.label} />
+          </List.Item>
+        )}
+      />
+    </div>
+  );
+};
+
+export default Profile;

+ 10 - 0
src/pages/security/components/MeButton.md

@@ -0,0 +1,10 @@
+# 关于MeButton组件
+
+1. 提供用户交互,用户点击后进入用户profile页面
+2. 作为tabbar上的一个导航按钮,是为小屏幕准备的组件
+
+# 实现
+
+> 基于ant design组件库
+> 用户没有登录时,显示对应的图标
+> 用户登录后,显示用户的Avatar

+ 50 - 0
src/pages/security/components/MeButton.tsx

@@ -0,0 +1,50 @@
+import React from 'react';
+import { Avatar, Typography, AvatarProps, Button } from 'antd';
+import { UserOutlined } from '@ant-design/icons';
+
+interface MeButtonProps extends AvatarProps {
+  isLogin?: boolean;
+  avatarUrl?: string;
+  username?: string;
+}
+
+const MeButton: React.FC<MeButtonProps> = ({
+  isLogin = false,
+  avatarUrl,
+  onClick,
+  username,
+  ...props
+}) => {
+  return (
+    <Button
+      onClick={onClick}
+      style={{
+        display: 'flex',
+        alignItems: 'center',
+        border: 'none',
+        background: 'none',
+        padding: 0,
+        cursor: 'pointer',
+      }}
+    >
+      {isLogin ? (
+        <Avatar
+          src={avatarUrl}
+          size={props.size}
+          style={{ marginRight: username ? 8 : 0 }}
+        />
+      ) : (
+        <Avatar
+          icon={<UserOutlined />}
+          size={props.size}
+          style={{ marginRight: username ? 8 : 0 }}
+        />
+      )}
+      {username && (
+        <Typography.Text style={{ margin: 0 }}>{username}</Typography.Text>
+      )}
+    </Button>
+  );
+};
+
+export default MeButton;