Browse Source

fix : 完善左侧导航栏的显示效果。
Fixes #3

sw 1 week ago
parent
commit
5d02684b05

+ 3 - 3
src/layouts/BasicLayout.tsx

@@ -139,13 +139,13 @@ const BasicLayout: React.FC<BasicLayoutProps> = () => {
           className="xxl:h-[90vh] xl:h-[90vh] lg:h-[90vh] md:h-[90vh] sm:h-[90vh] xs:h-[90vh]"
         >
           {/* 导航区域 */}
-          <Col xl={4} lg={4} md={0} sm={0} xs={0} style={{ flex: 1 }}>
+          <Col xl={2} lg={2} md={0} sm={0} xs={0}>
             <NavMenu onMenuClick={handleMenuClick} />
           </Col>
           {/* 内容区域 */}
           <Col
-            xl={20}
-            lg={20}
+            xl={22}
+            lg={22}
             xs={24}
             md={24}
             sm={24}

+ 52 - 58
src/layouts/BusinessZone.tsx

@@ -12,10 +12,9 @@ import MeButton from '../pages/security/components/MeButton';
 
 interface BusinessZoneProps {
   onMenuClick?: (key: string) => void;
-  collapsed: boolean;
 }
 
-const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick, collapsed }) => {
+const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick }) => {
   const items = [
     {
       key: 'patient_management',
@@ -124,6 +123,7 @@ const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick, collapsed }) =
   ];
 
   const [visibleItems, setVisibleItems] = useState(items);
+  const [floatingMenuVisible, setFloatingMenuVisible] = useState(false);
   const businessZoneRef = useRef<HTMLDivElement>(null);
 
   useEffect(() => {
@@ -134,7 +134,9 @@ const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick, collapsed }) =
         const systemZoneHeight = 100; // Assuming SystemZone height is fixed
 
         if (businessZoneHeight + systemZoneHeight > windowHeight) {
-          const visibleCount = Math.floor((windowHeight - systemZoneHeight) / 50); // Assuming each button height is 50px
+          const visibleCount = Math.floor(
+            (windowHeight - systemZoneHeight) / 50
+          ); // Assuming each button height is 50px
           setVisibleItems(items.slice(0, visibleCount));
         } else {
           setVisibleItems(items);
@@ -150,67 +152,59 @@ const BusinessZone: React.FC<BusinessZoneProps> = ({ onMenuClick, collapsed }) =
     };
   }, [items]);
 
-  return (
-    <div style={{ width: '100%', overflow: 'hidden', position: 'relative' }} className='grid grid-rows-[1fr] h-0 flex-grow'>
-      <div className='overflow-y-auto'>
-        {/* <p>1. 这里内容很多,会撑高。</p>
-        <p>2. 这里内容很多,会撑高。</p>
-        <p>3. 这里内容很多,会撑高。</p>
-        <p>4. 这里内容很多,会撑高。</p>
-        <p>5. 这里内容很多,会撑高。</p>
-        <p>6. 这里内容很多,会撑高。</p>
-        <p>7. 这里内容很多,会撑高。</p>
-        <p>8. 这里内容很多,会撑高。</p>
-        <p>9. 这里内容很多,会撑高。</p>
-        <p>10. 这里内容很多,会撑高。</p>
-        <p>11. 这里内容很多,会撑高。</p>
-        <p>12. 这里内容很多,会撑高。</p>
-        <p>13. 这里内容很多,会撑高。</p>
-        <p>14. 这里内容很多,会撑高。</p>
-        <p>15. 这里内容很多,会撑高。</p>
-        <p>12. 这里内容很多,会撑高。</p>
-        <p>13. 这里内容很多,会撑高。</p>
-        <p>14. 这里内容很多,会撑高。</p>
-        <p>15. 这里内容很多,会撑高。</p>
-        <p>12. 这里内容很多,会撑高。</p>
-        <p>13. 这里内容很多,会撑高。</p>
-        <p>14. 这里内容很多,会撑高。</p>
-        <p>15. 这里内容很多,会撑高。</p>
-        <p>12. 这里内容很多,会撑高。</p>
-        <p>13. 这里内容很多,会撑高。</p>
-        <p>14. 这里内容很多,会撑高。</p>
-        <p>15. 这里内容很多,会撑高。</p>
-        <p>12. 这里内容很多,会撑高。</p>
-        <p>13. 这里内容很多,会撑高。</p>
-        <p>14. 这里内容很多,会撑高。</p>
-        <p>1852. 这里内容很多,会撑高。</p> */}
+  const handlePatientManagementClick = () => {
+    setFloatingMenuVisible(!floatingMenuVisible);
+  };
 
-        {/* <div>444444</div> */}
+  return (
+    <div
+      style={{ width: '100%', overflow: 'hidden', position: 'relative' }}
+      className="grid grid-rows-[1fr] h-0 flex-grow"
+    >
+      <div className="overflow-y-auto">
         <Space direction="vertical">
-          {visibleItems.map((item) => (
-            <div key={item.key}>
-              <MeButton
-                icon={item.icon}
-                onClick={() => onMenuClick?.(item.key)}
-                username={typeof item.label === 'string' ? item.label : undefined}
+          {visibleItems.map((item) =>
+            item.type === 'divider' ? (
+              <hr
+                key="divider"
+                style={{
+                  width: '100%',
+                  borderTop: '1px solid #f0f0f0',
+                  margin: '8px 0',
+                }}
               />
-              {item.children && (
-                <Space direction="vertical" style={{ marginLeft: 20 }}>
-                  {item.children.map((child) => (
-                    <MeButton
-                      key={child.key}
-                      onClick={() => onMenuClick?.(child.key)}
-                      username={typeof child.label === 'string' ? child.label : undefined}
-                    />
-                  ))}
-                </Space>
-              )}
-            </div>
-          ))}
+            ) : (
+              <div key={item.key}>
+                <MeButton
+                  icon={item.icon}
+                  onClick={
+                    item.key === 'patient_management'
+                      ? handlePatientManagementClick
+                      : () => onMenuClick?.(item.key ?? 'error')
+                  }
+                  username={item.label}
+                />
+                {item.key === 'patient_management' && floatingMenuVisible && (
+                  <Space direction="vertical" style={{ marginLeft: 20 }}>
+                    {item.children?.map((child) => (
+                      <MeButton
+                        key={child.key}
+                        onClick={() => onMenuClick?.(child.key)}
+                        username={
+                          typeof child.label === 'string'
+                            ? child.label
+                            : undefined
+                        }
+                      />
+                    ))}
+                  </Space>
+                )}
+              </div>
+            )
+          )}
         </Space>
       </div>
     </div>
-
   );
 };
 

+ 3 - 45
src/layouts/NavMenu.tsx

@@ -1,10 +1,7 @@
-import React, { useState, useEffect, useRef } from 'react';
-import { Button, Tooltip } from 'antd';
-import { EllipsisOutlined } from '@ant-design/icons';
+import React, { useRef } from 'react';
 import BusinessZone from './BusinessZone';
 import SystemZone from './SystemZone';
-import { useSelector, useDispatch } from 'react-redux';
-import { RootState } from '@/states/store';
+import { useDispatch } from 'react-redux';
 import { setBusinessFlow } from '@/states/BusinessFlowSlice';
 
 interface NavMenuProps {
@@ -13,8 +10,6 @@ interface NavMenuProps {
 
 const NavMenu: React.FC<NavMenuProps> = ({ onMenuClick }) => {
   const dispatch = useDispatch();
-  const [collapsed, setCollapsed] = useState(false);
-  const businessZoneRef = useRef<HTMLDivElement>(null);
   const systemZoneRef = useRef<HTMLDivElement>(null);
 
   const onClick = (key: string) => {
@@ -22,46 +17,9 @@ const NavMenu: React.FC<NavMenuProps> = ({ onMenuClick }) => {
     onMenuClick?.(key);
   };
 
-  const toggleCollapse = () => {
-    setCollapsed(!collapsed);
-  };
-
-  useEffect(() => {
-    const handleResize = () => {
-      if (businessZoneRef.current && systemZoneRef.current) {
-        const businessZoneHeight = businessZoneRef.current.offsetHeight;
-        const systemZoneHeight = systemZoneRef.current.offsetHeight;
-        const windowHeight = window.innerHeight;
-
-        if (businessZoneHeight + systemZoneHeight > windowHeight) {
-          setCollapsed(true);
-        } else {
-          setCollapsed(false);
-        }
-      }
-    };
-
-    window.addEventListener('resize', handleResize);
-    handleResize(); // Initial check
-
-    return () => {
-      window.removeEventListener('resize', handleResize);
-    };
-  }, []);
-
   return (
     <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
-        <BusinessZone onMenuClick={onClick} collapsed={collapsed} />
-        {/* {collapsed && (
-          <Tooltip title="更多">
-            <Button
-              shape="circle"
-              icon={<EllipsisOutlined />}
-              onClick={toggleCollapse}
-              style={{ margin: '10px 0' }}
-            />
-          </Tooltip>
-        )} */}
+      <BusinessZone onMenuClick={onClick} />
       <SystemZone ref={systemZoneRef} onMenuClick={onClick} />
     </div>
   );

+ 44 - 36
src/layouts/SystemZone.tsx

@@ -1,5 +1,5 @@
 import React, { forwardRef } from 'react';
-import { Space, Button, Row } from 'antd';
+import { Space, Row } from 'antd';
 import { ToolOutlined } from '@ant-design/icons';
 import MeButton from '../pages/security/components/MeButton';
 import { useSelector } from 'react-redux';
@@ -10,32 +10,32 @@ interface SystemZoneProps {
   onMenuClick?: (key: string) => void;
 }
 
-const SystemZone = forwardRef<HTMLDivElement, SystemZoneProps>(({ onMenuClick }, ref) => {
-  const login = useSelector((state: RootState) => isLoggedIn(state.userInfo));
-  const username = useSelector((state: RootState) => state.userInfo.name);
-  const avatarUrl = useSelector((state: RootState) => state.userInfo.avatar);
+const SystemZone = forwardRef<HTMLDivElement, SystemZoneProps>(
+  ({ onMenuClick }, ref) => {
+    const login = useSelector((state: RootState) => isLoggedIn(state.userInfo));
+    const username = useSelector((state: RootState) => state.userInfo.name);
+    const avatarUrl = useSelector((state: RootState) => state.userInfo.avatar);
 
-  return (
-    <Row
-      ref={ref}
-      style={{
-        position: 'sticky',
-        flex: '0 0 auto',
-        bottom: 0,
-        left: 0,
-        width: '100%',
-        justifyContent: 'center',
-        backgroundColor: '#fff',
-        padding: '16px 0',
-        boxShadow: '0 -2px 5px rgba(0,0,0,0.1)',
-      }}
-    >
-      <Space
-        direction="vertical"
-        align="start"
-        style={{ width: '100%', paddingLeft: 20 }}
+    return (
+      <Row
+        ref={ref}
+        style={{
+          position: 'sticky',
+          flex: '0 0 auto',
+          bottom: 0,
+          left: 0,
+          width: '100%',
+          justifyContent: 'center',
+          padding: '16px 0',
+          boxShadow: '0 -2px 5px rgba(0,0,0,0.1)',
+        }}
       >
-        <Space>
+        <Space
+          direction="vertical"
+          align="start"
+          style={{ width: '100%', paddingLeft: 20 }}
+        >
+          {/* <Space>
           <Button
             shape="circle"
             size="large"
@@ -49,17 +49,25 @@ const SystemZone = forwardRef<HTMLDivElement, SystemZoneProps>(({ onMenuClick },
             onClick={() => onMenuClick?.('settings')}
           />
           <span>配置</span>
+        </Space> */}
+          <MeButton
+            size="large"
+            icon={<ToolOutlined />}
+            avatarUrl={avatarUrl || undefined}
+            username={'配置'}
+            onClick={() => onMenuClick?.('settings')}
+          />
+          <MeButton
+            size="large"
+            isLogin={login}
+            avatarUrl={avatarUrl || undefined}
+            username={login ? username : '未登录'}
+            onClick={() => onMenuClick?.('me')}
+          />
         </Space>
-        <MeButton
-          size="large"
-          isLogin={login}
-          avatarUrl={avatarUrl || undefined}
-          username={login ? username : '未登录'}
-          onClick={() => onMenuClick?.('me')}
-        />
-      </Space>
-    </Row>
-  );
-});
+      </Row>
+    );
+  }
+);
 
 export default SystemZone;

+ 12 - 1
src/pages/security/components/MeButton.tsx

@@ -8,7 +8,17 @@ interface MeButtonProps extends AvatarProps {
   username?: React.ReactNode;
   icon?: React.ReactNode;
 }
-
+/**
+ * 没有传递isLogin时,当作普通按钮使用
+ * @param param0 - MeButtonProps
+ * @param param0.isLogin - 是否登录
+ * @param param0.avatarUrl - 头像URL
+ * @param param0.onClick - 点击事件处理函数
+ * @param param0.username - 用户名
+ * @param param0.icon - 图标
+ * @param param0.props - 其他AvatarProps属性
+ * @returns
+ */
 const MeButton: React.FC<MeButtonProps> = ({
   isLogin = false,
   avatarUrl,
@@ -32,6 +42,7 @@ const MeButton: React.FC<MeButtonProps> = ({
       {isLogin ? (
         <Avatar
           src={avatarUrl}
+          icon={!!avatarUrl === false ? icon || <UserOutlined /> : undefined} // 如果avatarUrl为false,则使用icon或默认UserOutlined图标
           size={props.size}
           style={{ marginRight: username ? 8 : 0 }}
         />