Files
lingji-work-fe/src/layouts/components/siderBar/index.vue
2025-09-11 12:04:54 +08:00

266 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script lang="tsx">
import { Dropdown, Layout, Menu } from 'ant-design-vue';
import { useRoute } from 'vue-router';
import SvgIcon from '@/components/svg-icon/index.vue';
import { useAppStore, useUserStore } from '@/stores';
import { useSidebarStore } from '@/stores/modules/side-bar';
import type { typeMenuItem } from './menu-list';
import { MENU_LIST } from './menu-list';
import { handleUserHome } from '@/utils/user';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import icon1 from '@/assets/img/agent/icon1.png';
export default defineComponent({
emit: ['collapse'],
setup() {
// const appStore = useAppStore();
const router = useRouter();
const route = useRoute();
const sidebarStore = useSidebarStore();
const appStore = useAppStore();
const userStore = useUserStore();
const enterpriseStore = useEnterpriseStore();
// const currentMenuList = ref<typeMenuItem[]>([]);
const currentMenuModInfo = ref<typeMenuItem>({});
const currentRouteName = computed(() => route.name as string);
const currentRouteGroup = computed(() => route.meta?.group ?? 'GroupMain');
const isHomeRoute = computed(() => currentRouteName.value === 'Home');
const showAiSearch = computed(() => !route.meta?.hideAiSearch);
const currentMenuList = computed(() => sidebarStore.currentMenuList);
const hasOpenEnterprise = computed(() => enterpriseStore.isOpenEnterprise);
const collapsed = computed(() => {
return sidebarStore.menuCollapse;
});
const setCollapsed = (val) => {
appStore.updateSettings({ menuCollapse: val });
};
const getCollapseMenuKey = (routeName: string): string => {
let _key: string;
for (let i = 0; i < currentMenuList.value.length; i++) {
const menuItem = currentMenuList.value[i];
// 检查是否有list子级
if (menuItem.children?.length > 0) {
for (let j = 0; j < menuItem.children.length; j++) {
const subMenuItem = menuItem.children[j];
if (subMenuItem.activeMatch?.includes(routeName)) {
currentMenuModInfo.value = menuItem;
_key = menuItem.key;
break;
}
}
} else {
// 没有list子级直接检查当前项
if (menuItem.routeName === routeName) {
currentMenuModInfo.value = menuItem;
_key = menuItem.key;
break;
}
}
}
return _key;
};
const onClickItem = (item: typeMenuItem) => {
let targetRoute = item.routeName;
if (item.children?.length) {
targetRoute = item.children[0].routeName;
}
router.push({ name: targetRoute });
};
const renderMenuItem = ({
item,
hideLabel = false,
menuItemClass = '',
}: {
item: typeMenuItem;
hideLabel?: boolean;
menuItemClass?: string;
}) => {
const getMenuItemClass = () => {
const hasChildren = item.children?.length;
let target = '';
if (hasChildren) {
target += getCollapseMenuKey(currentRouteName.value) === item.key ? 'active' : '';
} else {
target += item.activeMatch?.includes(currentRouteName.value) ? 'active' : '';
}
return target;
};
return (
<Menu.Item class={`menu-item ${getMenuItemClass()} ${menuItemClass}`} onClick={() => onClickItem(item)}>
{(() => {
const isActive = getMenuItemClass().includes('active');
const iconName = Array.isArray(item.icon)
? isActive
? item.icon[1] ?? item.icon[0]
: item.icon[0]
: item.icon;
return <SvgIcon size="18" name={iconName as any} alt="状态图标" class="color-#55585F flex-shrink-0" />;
})()}
{!hideLabel && <span class="cts label">{item.label}</span>}
</Menu.Item>
);
};
const renderMenuList = () => {
return currentMenuList.value.map((item) => {
if (!item.children) {
return renderMenuItem({ item, hideLabel: collapsed.value });
}
return (
<Dropdown
overlayClassName="layout-sider-dropdown-xt"
placement="rightTop"
align={{ offset: [8, 0] }}
v-slots={{
overlay: () => {
return (
<div class="p-8px bg-#fff container w-139px">
{item.children.map((child) => {
return renderMenuItem({ item: child, menuItemClass: 'sub-menu-item' });
})}
</div>
);
},
}}
>
{renderMenuItem({ item, hideLabel: collapsed.value })}
</Dropdown>
);
});
};
const initMenuList = () => {
let groupMenuList = MENU_LIST?.[currentRouteGroup.value as string] ?? [];
// 如果企业未开通,过滤掉 requireAuth 为 true 的菜单项
if (!hasOpenEnterprise.value) {
groupMenuList = groupMenuList.filter((item) => {
if (item.requireAuth === true) {
return false;
}
if (item.children && item.children.length > 0) {
const filteredChildren = item.children.filter((child) => !child.requireAuth);
if (filteredChildren.length === 0 && !item.routeName) {
return false;
}
item.children = filteredChildren;
}
return true;
});
}
sidebarStore.setCurrentMenuList(groupMenuList);
};
const initCollapse = () => {
getCollapseMenuKey(currentRouteName.value);
if (currentMenuModInfo.value) {
sidebarStore.setActiveMenuKey(currentMenuModInfo.value?.key);
}
};
const init = () => {
// 初始化菜单数据
initMenuList();
// 初始化菜单展开项
initCollapse();
};
watch(
() => currentRouteGroup.value,
() => {
init();
},
{ immediate: false, deep: true },
);
onMounted(() => {
init();
});
return () => (
<Layout.Sider
v-model={collapsed.value}
width={sidebarStore.sidebarWidth}
collapsible
trigger
onCollapse={setCollapsed}
>
<Menu class={`siderBar-wrap w-full flex flex-col px-16px pt-16px ${collapsed.value ? 'menu-fold' : ''}`}>
{showAiSearch.value && (
<>
<Menu.Item class={`menu-item !mb-0 ${isHomeRoute.value ? 'active' : ''}`} onClick={handleUserHome}>
<img src={icon1} width={18} height={18} />
{!collapsed.value && <span class="cts label">开始工作</span>}
</Menu.Item>
<div class="line w-full h-1px bg-#211F24 my-12px"></div>
</>
)}
<div class="flex flex-col flex-1">
<div class="menu-list flex-1">{renderMenuList()}</div>
</div>
</Menu>
<div
class={`bg-#F6F5FC flex items-center absolute bottom-0 w-full pt-8px px-16px pb-16px right-0 ${
collapsed.value ? 'justify-center' : 'justify-end'
}`}
>
<div
class="flex fold-btn items-center cursor-pointer h-22px "
onClick={() => {
sidebarStore.setMenuCollapse();
}}
>
{collapsed.value ? (
<icon-menu-unfold size={16} class="color-#55585F icon mr-4px" />
) : (
<icon-menu-fold size={16} class="color-#55585F icon mr-4px" />
)}
{!collapsed.value && <span class="cts !color-#55585F flex-shrink-0">收起</span>}
</div>
</div>
</Layout.Sider>
);
},
});
</script>
<style lang="scss" scoped>
@import './style.scss';
</style>
<style lang="scss">
@import './style.scss';
.layout-sider-dropdown-xt {
.container {
border-radius: 8px;
background: var(--BG-White, #fff);
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
.menu-item {
@include menu-item;
padding: 8px;
&:hover {
background-color: rgba(109, 76, 254, 0.08) !important;
color: #6d4cfe !important;
.svg-icon {
color: #6d4cfe !important;
}
}
}
}
}
</style>