cpms_operation_platform/src/layouts/BasicLayout.tsx

174 lines
5.1 KiB
TypeScript
Raw Normal View History

2026-07-14 10:31:17 +08:00
import { computed, defineComponent, ref } from 'vue';
import { Layout, Menu, Breadcrumb, Modal, Avatar, Space } from 'ant-design-vue';
import { RouterView, useRouter } from 'vue-router';
2026-07-14 10:31:17 +08:00
import {
MenuFoldOutlined,
MenuUnfoldOutlined,
ReloadOutlined,
SearchOutlined,
BellOutlined,
FullscreenOutlined,
UserOutlined,
2026-07-14 10:31:17 +08:00
} from '@ant-design/icons-vue';
import { useBasicLayout } from '../hooks/useBasicLayout';
import { auth } from '@/hooks/useAuth';
2026-07-14 10:31:17 +08:00
import styles from './BasicLayout.module.less';
// 解构 Layout 组件
const { Header, Sider, Content } = Layout;
2026-07-14 10:31:17 +08:00
/**
*
*
* @description
* CPMS
* - Logo +
* - Header + +
* -
*
* @example
* ```typescript
* // 在路由中使用
* {
* path: '/',
* component: BasicLayout,
* children: [...]
* }
* ```
2026-07-14 10:31:17 +08:00
*/
export default defineComponent({
name: 'BasicLayout',
setup() {
// 使用布局 Hook 获取菜单和面包屑数据
const { breadcrumbItems, menuItems, getActiveMenuKey, getOpenKeys, handleMenuClick } =
useBasicLayout();
2026-07-14 10:31:17 +08:00
// 路由实例,用于退出登录后跳转到登录页
const router = useRouter();
2026-07-14 10:31:17 +08:00
/**
*
* true:
* false: +
*/
const collapsed = ref(false);
2026-07-14 10:31:17 +08:00
/**
* /
*/
2026-07-14 10:31:17 +08:00
const toggleCollapsed = () => {
collapsed.value = !collapsed.value;
};
/**
* 退
* -
* - ->
* - ->
*/
const handleLogout = () => {
Modal.confirm({
title: '确认退出',
content: '确定要退出当前账号吗?',
okText: '确定',
cancelText: '取消',
onOk: () => {
// 清除本地登录态(不调用接口),否则路由守卫会把 /login 重定向回首页
auth.logout();
router.replace('/login');
},
});
};
2026-07-14 10:31:17 +08:00
return () => (
<Layout class={styles.container}>
{/* 左侧侧边栏 */}
<Sider
class={styles.sider}
collapsed={collapsed.value}
trigger={null}
collapsible
width={220}
>
{/* Logo 区域 */}
2026-07-14 10:31:17 +08:00
<div class={styles.logo}>
<div class={styles.logoIcon} />
<span class={styles.logoText}>{collapsed.value ? 'CPMS' : 'CPMS运营平台'}</span>
2026-07-14 10:31:17 +08:00
</div>
{/* 导航菜单 */}
2026-07-14 10:31:17 +08:00
<Menu
theme="light"
2026-07-14 10:31:17 +08:00
mode="inline"
selectedKeys={[getActiveMenuKey()]}
openKeys={getOpenKeys()}
2026-07-14 10:31:17 +08:00
items={menuItems}
onClick={handleMenuClick}
/>
</Sider>
{/* 右侧内容区域 */}
2026-07-14 10:31:17 +08:00
<Layout>
{/* 顶部 Header */}
<Header class={styles.header} style={{ background: '#ffffff' }}>
<div class={styles.headerLeft}>
{/* 折叠/展开按钮 */}
<span class={styles.trigger} onClick={toggleCollapsed}>
{collapsed.value ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</span>
{/* 刷新按钮 */}
{/* <span class={styles.refreshIcon}>
<ReloadOutlined />
</span> */}
{/* 面包屑导航 */}
{breadcrumbItems.value.length > 0 && (
<Breadcrumb class={styles.breadcrumb}>
{breadcrumbItems.value.map((item) => (
<Breadcrumb.Item key={item.key}>{item.title}</Breadcrumb.Item>
))}
</Breadcrumb>
)}
</div>
{/* Header 右侧:用户信息 */}
<div class={styles.headerRight}>
<Space size="middle">
{/* 搜索图标 */}
{/* <span class={styles.headerIcon}>
<SearchOutlined />
</span> */}
{/* 通知图标 */}
{/* <span class={styles.headerIcon}>
<BellOutlined />
</span> */}
{/* 全屏图标 */}
{/* <span class={styles.headerIcon}>
<FullscreenOutlined />
</span> */}
{/* 用户信息:点击弹出退出登录确认 */}
<div class={styles.userInfo} onClick={handleLogout}>
<Avatar size="small" icon={<UserOutlined />} />
<span class={styles.userName}></span>
</div>
</Space>
</div>
2026-07-14 10:31:17 +08:00
</Header>
{/* 内容区域 */}
2026-07-14 10:31:17 +08:00
<Content class={styles.content}>
<div class={styles.pageContent}>
{/* 路由视图:根据当前路由渲染对应页面 */}
<RouterView />
</div>
2026-07-14 10:31:17 +08:00
</Content>
</Layout>
</Layout>
);
},
});