123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import React, { useState, useRef } from 'react';
- import { Menu, Button, Drawer } from 'antd';
- import {
- MenuUnfoldOutlined,
- UserOutlined,
- FileSearchOutlined,
- AlertOutlined,
- ToolOutlined,
- PrinterOutlined,
- } from '@ant-design/icons';
- import type { MenuProps } from 'antd';
- interface NavbarFloatProps {
- position?: 'left' | 'right';
- className?: string;
- }
- const NavbarFloat: React.FC<NavbarFloatProps> = ({
- position = 'left',
- className,
- }) => {
- const [open, setOpen] = useState(false);
- const [btnPos, setBtnPos] = useState({ x: 100, y: 100 });
- React.useEffect(() => {
- // 组件挂载后再安全访问 window
- setBtnPos({
- x: window.innerWidth - 96,
- y: window.innerHeight - 96,
- });
- }, []);
- const [dragged, setDragged] = useState(false);
- const dragging = useRef(false);
- const offset = useRef({ x: 0, y: 0 });
- // 拖拽事件
- const onMouseDown = (e: React.MouseEvent) => {
- dragging.current = true;
- setDragged(false);
- offset.current = {
- x: e.clientX - btnPos.x,
- y: e.clientY - btnPos.y,
- };
- document.addEventListener('mousemove', onMouseMove);
- document.addEventListener('mouseup', onMouseUp);
- };
- const onMouseMove = (e: MouseEvent) => {
- if (!dragging.current) return;
- let x = e.clientX - offset.current.x;
- let y = e.clientY - offset.current.y;
- // 限制在窗口内
- x = Math.max(0, Math.min(window.innerWidth - 80, x));
- y = Math.max(0, Math.min(window.innerHeight - 80, y));
- setBtnPos({ x, y });
- setDragged(true); // 标记为拖拽
- };
- const onMouseUp = () => {
- dragging.current = false;
- setTimeout(() => setDragged(false), 100); // 短暂延迟后重置
- document.removeEventListener('mousemove', onMouseMove);
- document.removeEventListener('mouseup', onMouseUp);
- };
- const menuItems = [
- {
- key: 'patient',
- icon: <Button shape="circle" icon={<UserOutlined />} />,
- label: '患者',
- },
- {
- key: 'examination',
- icon: <Button shape="circle" icon={<FileSearchOutlined />} />,
- label: '检查',
- },
- {
- key: 'emergency',
- icon: <Button shape="circle" icon={<AlertOutlined />} />,
- label: '急诊',
- },
- {
- key: 'process',
- icon: <Button shape="circle" icon={<ToolOutlined />} />,
- label: '处理',
- },
- {
- key: 'print',
- icon: <Button shape="circle" icon={<PrinterOutlined />} />,
- label: '打印',
- },
- ];
- const handleClick: MenuProps['onClick'] = (e) => {
- console.log('clicked ', e.key);
- setOpen(false); // 点击菜单后自动关闭抽屉
- };
- const drawerPlacement = position === 'right' ? 'right' : 'left';
- return (
- <>
- {!open && (
- <div
- style={{
- position: 'fixed',
- left: undefined,
- top: undefined,
- right: window.innerWidth - btnPos.x,
- bottom: window.innerHeight - btnPos.y,
- zIndex: 1100,
- cursor: 'grab',
- }}
- className={className}
- onMouseDown={onMouseDown}
- >
- <Button
- type="primary"
- shape="circle"
- size="large"
- icon={<MenuUnfoldOutlined style={{ fontSize: 32 }} />}
- onClick={(e) => {
- e.stopPropagation();
- if (dragged) return; // 拖拽后不弹抽屉
- setOpen(true);
- }}
- style={{
- width: 64,
- height: 64,
- backgroundColor: '#fff',
- color: '#333',
- boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- userSelect: 'none',
- }}
- />
- </div>
- )}
- <Drawer
- placement={drawerPlacement}
- open={open}
- onClose={() => setOpen(false)}
- closable={false}
- width={120}
- maskClosable={true}
- style={{
- top: 0,
- height: '100vh',
- }}
- >
- <Menu
- mode="vertical"
- onClick={handleClick}
- items={menuItems}
- style={{ border: 'none', backgroundColor: 'transparent' }}
- />
- </Drawer>
- </>
- );
- };
- export default NavbarFloat;
|