164 lines
4.2 KiB
Vue
164 lines
4.2 KiB
Vue
<script setup lang="ts">
|
||
// 布局骨架演示:切换 7 种布局模式,菜单/页签/内容都由本示例以数据注入。
|
||
// 注意:SSR 预渲染下不要在 setup 顶层用 window/document,这里只用静态数据 + ref。
|
||
import { ref } from 'vue'
|
||
import { G3Layout, type G3TabItem, type LayoutType, type NavItem } from '@g3soft/framework'
|
||
|
||
const modes: { value: LayoutType; label: string }[] = [
|
||
{ value: 'sidebar-nav', label: '垂直菜单' },
|
||
{ value: 'header-nav', label: '顶部菜单' },
|
||
{ value: 'sidebar-mixed-nav', label: '双列菜单' },
|
||
{ value: 'mixed-nav', label: '顶+侧' },
|
||
{ value: 'header-sidebar-nav', label: '顶栏+侧栏' },
|
||
{ value: 'header-mixed-nav', label: '顶部混合' },
|
||
{ value: 'full-content', label: '通栏内容' },
|
||
]
|
||
|
||
const layout = ref<LayoutType>('sidebar-nav')
|
||
const activeKey = ref('/dashboard')
|
||
|
||
const menus: NavItem[] = [
|
||
{ key: '/dashboard', title: '工作台', path: '/dashboard' },
|
||
{
|
||
key: '/base',
|
||
title: '基础资料',
|
||
children: [
|
||
{ key: '/base/company', title: '公司档案', path: '/base/company' },
|
||
{ key: '/base/customer', title: '客户档案', path: '/base/customer' },
|
||
{ key: '/base/supplier', title: '供应商', path: '/base/supplier' },
|
||
],
|
||
},
|
||
{
|
||
key: '/biz',
|
||
title: '业务管理',
|
||
children: [
|
||
{ key: '/biz/order', title: '订单', path: '/biz/order' },
|
||
{ key: '/biz/stock', title: '库存', path: '/biz/stock' },
|
||
],
|
||
},
|
||
{
|
||
key: '/system',
|
||
title: '系统设置',
|
||
children: [
|
||
{ key: '/system/menu', title: '菜单管理', path: '/system/menu' },
|
||
{ key: '/system/user', title: '用户管理', path: '/system/user' },
|
||
],
|
||
},
|
||
]
|
||
|
||
const tabs = ref<G3TabItem[]>([
|
||
{ key: '/dashboard', title: '工作台', affix: true },
|
||
{ key: '/base/customer', title: '客户档案' },
|
||
])
|
||
|
||
function onNavigate(payload: { key: string }): void {
|
||
activeKey.value = payload.key
|
||
}
|
||
|
||
function onTabChange(key: string): void {
|
||
activeKey.value = key
|
||
}
|
||
|
||
function onTabClose(key: string): void {
|
||
tabs.value = tabs.value.filter((tab) => tab.key !== key)
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="layout-demo">
|
||
<div class="layout-demo__modes">
|
||
<button
|
||
v-for="mode in modes"
|
||
:key="mode.value"
|
||
type="button"
|
||
class="layout-demo__mode"
|
||
:class="{ 'is-active': layout === mode.value }"
|
||
@click="layout = mode.value"
|
||
>
|
||
{{ mode.label }}
|
||
</button>
|
||
</div>
|
||
|
||
<div class="layout-demo__stage">
|
||
<G3Layout
|
||
:layout="layout"
|
||
:menus="menus"
|
||
:active-key="activeKey"
|
||
:tabs="layout === 'full-content' ? [] : tabs"
|
||
@navigate="onNavigate"
|
||
@tab-change="onTabChange"
|
||
@tab-close="onTabClose"
|
||
>
|
||
<template #logo>
|
||
<span class="layout-demo__logo">G3 FMS</span>
|
||
</template>
|
||
<template #header-right>
|
||
<span class="layout-demo__user">admin</span>
|
||
</template>
|
||
<template #page>
|
||
<div class="layout-demo__page">当前路由:{{ activeKey }}</div>
|
||
</template>
|
||
</G3Layout>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style>
|
||
.layout-demo {
|
||
width: 100%;
|
||
}
|
||
|
||
.layout-demo__modes {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.layout-demo__mode {
|
||
padding: 5px 10px;
|
||
border: 1px solid var(--ui-border, #e5e7eb);
|
||
border-radius: 6px;
|
||
background: var(--ui-bg, #fff);
|
||
color: var(--ui-text-muted, #52525b);
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.layout-demo__mode.is-active {
|
||
border-color: var(--g3-color-primary, #18181b);
|
||
color: var(--g3-color-primary, #18181b);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.layout-demo__stage {
|
||
height: 620px;
|
||
border: 1px solid var(--ui-border, #e5e7eb);
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.layout-demo__logo {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.layout-demo__user {
|
||
font-size: 13px;
|
||
color: var(--g3-color-text-secondary, #52525b);
|
||
}
|
||
|
||
.layout-demo__page {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 200px;
|
||
border: 1px dashed var(--ui-border, #e5e7eb);
|
||
border-radius: 8px;
|
||
background: var(--ui-bg, #fff);
|
||
color: var(--g3-color-text-secondary, #52525b);
|
||
font-size: 14px;
|
||
}
|
||
</style>
|