| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- // BasicLayout.tsx
- import React from 'react';
- import { useSelector, useDispatch } from 'react-redux';
- import { Layout, Row, Col, ConfigProvider } from 'antd';
- import { TabBar } from 'antd-mobile';
- import logo from '@/assets/imgs/logo-v3.jpg';
- import NavbarFloat from './NavbarFloat';
- import NavMenu from './NavMenu';
- import BottomBar from './BottomBar';
- import StatusBar, { StatusBarProps } from './StateBar';
- import RegisterPage from '@/pages/patient/register';
- import WorklistPage from '@/pages/patient/worklist';
- import HistorylistPage from '@/pages/patient/HistoryList';
- 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 ExamPage from '@/pages/exam/ExamPage';
- import { RootState } from '@/states/store';
- import store from '@/states/store';
- import { setBusinessFlow } from '@/states/BusinessFlowSlice';
- import ImageProcessingPage from '@/pages/view/ImageProcessingPage';
- import PrintPage from '@/pages/output/print/PrintPage';
- import { pageLayoutConfig } from '@/config/pageLayout';
- import selectedWorksToPrint from '@/domain/patient/selectedWorksToPrint';
- import { message } from 'antd';
- // import { Link } from 'react-router-dom';
- // import { MenuOutlined } from '@ant-design/icons';
- // const { Content, Footer } = Layout;
- interface BasicLayoutProps {
- children: React.ReactNode;
- }
- // //自定义breakpoint
- // const breakpoint = {
- // xs: 480, // 小屏幕设备(手机)
- // sm: 576, // 中小屏幕设备(平板)
- // md: 768, // 中等屏幕设备(小桌面显示器)
- // lg: 992, // 大屏幕设备(桌面显示器)
- // xl: 1200, // 超大屏幕设备(大桌面显示器)
- // xxl: 1600 // 超超大屏幕设备(超大桌面显示器)
- // };
- const BasicLayout: React.FC<BasicLayoutProps> = () => {
- const status: StatusBarProps = {
- diskStatus: 'available', // 可用状态
- batteryLevel: 0,
- wifiStrength: 0,
- heatCapacity: 0,
- };
- const dispatch = useDispatch();
- const currentKey = useSelector(
- (state: RootState) => state.BusinessFlow.currentKey
- );
- // key和内容组件的映射
- const contentMap = {
- exam: <ExamPage />,
- process: <ImageProcessingPage />,
- view: <ImageProcessingPage />,
- register: <RegisterPage />,
- worklist: <WorklistPage />,
- historylist: <HistorylistPage />,
- archivelist: <ArchivelistPage />,
- bin: <BinPage />,
- outputlist: <OutputlistPage />,
- patient_management: <PatientManagement />,
- profile: <Profile />, // 需确保已引入 Profile 组件
- print: <PrintPage />,
- };
- //感知菜单项点击
- const handleMenuClick = async (key: string) => {
- // 特殊处理打印按钮
- // todo 这一段逻辑后续可以考虑放到 middleware 里处理,即 businessFlowMiddlewareLogic
- if (key === 'print') {
- if (currentKey === 'worklist' || currentKey === 'historylist') {
- // 获取当前选中的记录
- const state = store.getState();
- const selectedIds =
- currentKey === 'historylist'
- ? state.historySelection.selectedIds
- : currentKey === 'worklist'
- ? state.workSelection.selectedIds
- : [];
- if (selectedIds.length === 0) {
- message.warning('请先选择要打印的项目');
- return;
- }
- try {
- // 调用 selectedWorksToPrint 加载数据并跳转
- await selectedWorksToPrint(selectedIds, currentKey as 'worklist' | 'historylist');
- } catch (error) {
- console.error('[BusinessZone] Print error:', error);
- message.error('加载打印数据失败,请重试');
- }
- } else if(currentKey === 'exam' || currentKey === 'process') {
- // 其他按钮直接切换页面
- dispatch(setBusinessFlow(key));
- }
- }
- else {
- // 其他按钮直接切换页面
- dispatch(setBusinessFlow(key));
- }
- };
- return (
- // ConfigProvider 用于自定义 Ant Design 的主题和 breakpoints
- <ConfigProvider
- theme={
- {
- // token: {
- // // 自定义屏幕尺寸断点,与要求匹配
- // screenXS: 576, // xs: <576px
- // screenSM: 768, // sm: ≥768px
- // screenMD: 992, // md: ≥992px
- // screenLG: 1200, // lg: ≥1200px
- // screenXL: 1400, // xl: ≥1400px
- // screenXXL: 1600, // xxl: ≥1600px
- // },
- }
- }
- >
- <Layout
- style={{
- minHeight: '100vh',
- // border: '1px solid #ccc'
- }}
- className="h-[100vh] xl:text-[48px] lg:text-[40px] md:text-[30px] sm:text-[20px] xs:text-[15px]"
- >
- {/* 第一行:品牌和状态区域 */}
- {pageLayoutConfig.brandAndStatusPosition === 'top' && (
- <Row
- className="xl:h-[9vh] text-[100%]"
- style={{ borderBottom: '1px solid #e5e7eb' }}
- >
- {/* 品牌区域 */}
- <Col xl={4} lg={4} md={5} sm={0} xs={0} className="h-full">
- <img
- data-testid="logo-image"
- src={logo}
- alt="Logo"
- className="h-full w-auto object-contain"
- />
- </Col>
- {/* 状态区域 */}
- <Col
- xl={20}
- lg={20}
- md={19}
- sm={0}
- xs={0}
- className="items-center
- justify-end xl:flex
- lg:flex
- md:flex
- sm:hidden
- xs:hidden
- h-full
- text-[100%]"
- >
- {/* text-[100%] 用于传导父元素的字体大小,最终影响图标大小 */}
- <StatusBar
- diskStatus={status.diskStatus}
- batteryLevel={status.batteryLevel}
- wifiStrength={status.wifiStrength}
- heatCapacity={status.heatCapacity}
- />
- </Col>
- </Row>
- )}
- {/* 第二行:导航区域(第1列)和内容区域(第2列) */}
- <Row
- style={{
- flex: 1,
- display: 'flex',
- // paddingTop: '24px', // 顶部留白
- // border: '1px solid red',
- }}
- className="xxl:h-[90vh] xl:h-[90vh] lg:h-[90vh] md:h-[90vh] sm:h-[90vh] xs:h-[90vh] pt-2"
- >
- {/* 导航区域 */}
- <Col xl={2} lg={0} md={0} sm={0} xs={0} className="h-full">
- <NavMenu onMenuClick={handleMenuClick} />
- </Col>
- {/* 内容区域 */}
- <Col
- xl={22}
- lg={24}
- xs={24}
- md={24}
- sm={24}
- style={{
- flex: 1,
- // border: '1px solid blue'
- }}
- className="h-full"
- >
- {/* {children} */}
- {contentMap[currentKey]}
- </Col>
- </Row>
- {/* 第一行:品牌和状态区域 */}
- {pageLayoutConfig.brandAndStatusPosition === 'bottom' && (
- <Row
- className="xl:h-[9vh] md:h-[9vh] text-[100%]"
- style={{ borderBottom: '1px solid #e5e7eb' }}
- >
- {/* 品牌区域 */}
- <Col xl={8} lg={8} md={5} sm={0} xs={0} className="h-full">
- {/* 底部通栏:仅在桌面端显示 */}
- <BottomBar />
- </Col>
- {/* 状态区域 */}
- <Col
- xl={16}
- lg={16}
- md={19}
- sm={0}
- xs={0}
- className="items-center
- justify-end xl:flex
- lg:flex
- md:flex
- sm:hidden
- xs:hidden
- h-full
- text-[100%]"
- >
- {/* text-[100%] 用于传导父元素的字体大小,最终影响图标大小 */}
- <StatusBar
- diskStatus={status.diskStatus}
- batteryLevel={status.batteryLevel}
- wifiStrength={status.wifiStrength}
- heatCapacity={status.heatCapacity}
- />
- </Col>
- </Row>
- )}
- {/* Tabbar:固定在底部,仅在手机屏幕显示 */}
- <div className="sticky bottom-0 w-full bg-red xl:hidden">
- <TabBar
- className="xl:hidden lg:hidden md:hidden sm:block xs:block"
- onChange={(key) => handleMenuClick(key)}
- >
- <TabBar.Item
- className="text-red-500"
- title="患者管理"
- key="patient_management"
- icon={<div>🏠</div>}
- />
- <TabBar.Item
- className="text-red-500"
- title="检查"
- key="examination"
- icon={<div>👤</div>}
- />
- <TabBar.Item
- className="text-red-500"
- title="急诊"
- key="emergency"
- icon={<div>⚙️</div>}
- />
- <TabBar.Item
- className="text-red-500"
- title="图像处理"
- key="process"
- icon={<div>⚙️</div>}
- />
- <TabBar.Item
- className="text-red-500"
- title="打印"
- 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
- className="fixed hidden sm:hidden xs:hidden md:block lg:block xl:hidden"
- position="left"
- onMenuClick={handleMenuClick}
- />
- </Layout>
- </ConfigProvider>
- );
- };
- export default BasicLayout;
|