feat(web): 路由和菜单集成 + 10 页面占位
Some checks failed
CI / security-audit (push) Has been cancelled
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled

- App.tsx 添加 10 条 lazy 路由(患者/医护/预约/随访/咨询)
- MainLayout.tsx 添加健康管理菜单组(7 项菜单 + 10 条标题映射)
- 创建 10 个页面占位组件
This commit is contained in:
iven
2026-04-25 00:42:12 +08:00
parent 6296ce22d2
commit cdbf381060
12 changed files with 162 additions and 0 deletions

View File

@@ -24,6 +24,18 @@ const PluginGraphPage = lazy(() => import('./pages/PluginGraphPage').then((m) =>
const PluginDashboardPage = lazy(() => import('./pages/PluginDashboardPage').then((m) => ({ default: m.PluginDashboardPage })));
const PluginKanbanPage = lazy(() => import('./pages/PluginKanbanPage'));
// 健康管理模块
const PatientList = lazy(() => import('./pages/health/PatientList'));
const PatientDetail = lazy(() => import('./pages/health/PatientDetail'));
const PatientTagManage = lazy(() => import('./pages/health/PatientTagManage'));
const DoctorList = lazy(() => import('./pages/health/DoctorList'));
const AppointmentList = lazy(() => import('./pages/health/AppointmentList'));
const DoctorSchedule = lazy(() => import('./pages/health/DoctorSchedule'));
const FollowUpTaskList = lazy(() => import('./pages/health/FollowUpTaskList'));
const FollowUpRecordList = lazy(() => import('./pages/health/FollowUpRecordList'));
const ConsultationList = lazy(() => import('./pages/health/ConsultationList'));
const ConsultationDetail = lazy(() => import('./pages/health/ConsultationDetail'));
function PrivateRoute({ children }: { children: React.ReactNode }) {
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
return isAuthenticated ? <>{children}</> : <Navigate to="/login" replace />;
@@ -153,6 +165,17 @@ export default function App() {
<Route path="/plugins/:pluginId/dashboard" element={<PluginDashboardPage />} />
<Route path="/plugins/:pluginId/kanban/:entityName" element={<PluginKanbanPage />} />
<Route path="/plugins/:pluginId/:entityName" element={<PluginCRUDPage />} />
{/* 健康管理 */}
<Route path="/health/patients" element={<PatientList />} />
<Route path="/health/patients/:id" element={<PatientDetail />} />
<Route path="/health/tags" element={<PatientTagManage />} />
<Route path="/health/doctors" element={<DoctorList />} />
<Route path="/health/appointments" element={<AppointmentList />} />
<Route path="/health/schedules" element={<DoctorSchedule />} />
<Route path="/health/follow-up-tasks" element={<FollowUpTaskList />} />
<Route path="/health/follow-up-records" element={<FollowUpRecordList />} />
<Route path="/health/consultations" element={<ConsultationList />} />
<Route path="/health/consultations/:id" element={<ConsultationDetail />} />
</Routes>
</Suspense>
</ErrorBoundary>

View File

@@ -19,6 +19,11 @@ import {
TableOutlined,
TagsOutlined,
RightOutlined,
HeartOutlined,
CalendarOutlined,
PhoneOutlined,
CommentOutlined,
MedicineBoxOutlined,
} from '@ant-design/icons';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAppStore } from '../stores/app';
@@ -47,6 +52,16 @@ const bizMenuItems: MenuItem[] = [
{ key: '/messages', icon: <MessageOutlined />, label: '消息中心' },
];
const healthMenuItems: MenuItem[] = [
{ key: '/health/patients', icon: <TeamOutlined />, label: '患者管理' },
{ key: '/health/doctors', icon: <MedicineBoxOutlined />, label: '医护管理' },
{ key: '/health/appointments', icon: <CalendarOutlined />, label: '预约排班' },
{ key: '/health/schedules', icon: <HeartOutlined />, label: '排班管理' },
{ key: '/health/follow-up-tasks', icon: <PhoneOutlined />, label: '随访管理' },
{ key: '/health/consultations', icon: <CommentOutlined />, label: '咨询管理' },
{ key: '/health/tags', icon: <TagsOutlined />, label: '标签管理' },
];
const sysMenuItems: MenuItem[] = [
{ key: '/settings', icon: <SettingOutlined />, label: '系统设置' },
{ key: '/plugins/admin', icon: <AppstoreOutlined />, label: '插件管理' },
@@ -61,6 +76,16 @@ const routeTitleMap: Record<string, string> = {
'/messages': '消息中心',
'/settings': '系统设置',
'/plugins/admin': '插件管理',
'/health/patients': '患者管理',
'/health/patients/:id': '患者详情',
'/health/tags': '标签管理',
'/health/doctors': '医护管理',
'/health/appointments': '预约排班',
'/health/schedules': '排班管理',
'/health/follow-up-tasks': '随访管理',
'/health/follow-up-records': '随访记录',
'/health/consultations': '咨询管理',
'/health/consultations/:id': '咨询详情',
};
// 侧边栏菜单项 - 提取为独立组件避免重复渲染
@@ -263,6 +288,20 @@ export default function MainLayout({ children }: { children: React.ReactNode })
))}
</div>
{/* 菜单组:健康管理 */}
{!sidebarCollapsed && <div className="erp-sidebar-group"></div>}
<div className="erp-sidebar-menu">
{healthMenuItems.map((item) => (
<SidebarMenuItem
key={item.key}
item={item}
isActive={currentPath === item.key}
collapsed={sidebarCollapsed}
onClick={() => navigate(item.key)}
/>
))}
</div>
{/* 菜单组:插件 */}
{pluginMenuGroups.length > 0 && (
<>

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function AppointmentList() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function ConsultationDetail() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function ConsultationList() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function DoctorList() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function DoctorSchedule() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function FollowUpRecordList() {
return (
<Card>
<Typography.Title level={4}>访</Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function FollowUpTaskList() {
return (
<Card>
<Typography.Title level={4}>访</Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function PatientDetail() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function PatientList() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}

View File

@@ -0,0 +1,10 @@
import { Card, Typography } from 'antd';
export default function PatientTagManage() {
return (
<Card>
<Typography.Title level={4}></Typography.Title>
<Typography.Text type="secondary"></Typography.Text>
</Card>
);
}