208 lines
5.1 KiB
Vue
208 lines
5.1 KiB
Vue
<template>
|
||
<div class="menu-wrapper">
|
||
<a-scrollbar>
|
||
<a-menu
|
||
:collapsed="collapsed"
|
||
:selected-keys="selectedKeys"
|
||
:open-keys="openedKeys"
|
||
@menu-item-click="menuItemClick"
|
||
@sub-menu-click="subMenuClick">
|
||
<template v-for="item in menuItems">
|
||
<template v-if="item.children.length > 0">
|
||
<a-sub-menu
|
||
:key="item.key"
|
||
:title="item.label">
|
||
<a-menu-item
|
||
v-for="child in item.children"
|
||
:key="child.key">
|
||
{{ child.label }}
|
||
</a-menu-item>
|
||
</a-sub-menu>
|
||
</template>
|
||
<template v-else>
|
||
<a-menu-item :key="item.key">
|
||
<template #icon>
|
||
<span
|
||
class="menu-svg-icon"
|
||
:class="{ active: selectedKeys.indexOf(item.key) > -1 }"
|
||
v-html="getMenuSvg(item.key)"
|
||
></span>
|
||
</template>
|
||
<div class="menu-item">
|
||
{{ item.label }}
|
||
</div>
|
||
</a-menu-item>
|
||
</template>
|
||
</template>
|
||
</a-menu>
|
||
</a-scrollbar>
|
||
</div>
|
||
</template>
|
||
<script setup>
|
||
import { computed, ref, watch, inject } from 'vue'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { useStore } from 'vuex'
|
||
import cloneDeep from 'lodash-es/cloneDeep'
|
||
import { constantRoutes } from '@/router/index'
|
||
import { generateTitle, generateLang } from '@/utils/i18n'
|
||
|
||
/** 左侧导航仅显示这些路由(name 与 router/index.js 一致) */
|
||
const SIDEBAR_ONLY_ROUTE_NAMES = ['video-gen', 'asset-group-manage', 'asset-manage', 'generatedAssets']
|
||
|
||
defineProps({
|
||
collapsed: Boolean
|
||
})
|
||
|
||
const store = useStore()
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
|
||
const $base = inject('$base')
|
||
const $message = inject('$message')
|
||
|
||
const menuItems = computed(() => {
|
||
const root = constantRoutes.find((d) => d.path === '/')
|
||
const children = root?.children ?? []
|
||
return children
|
||
.filter(
|
||
(r) =>
|
||
r.meta?.menuItem !== false && SIDEBAR_ONLY_ROUTE_NAMES.includes(r.name)
|
||
)
|
||
.map((route) => ({
|
||
key: route.name,
|
||
label: generateTitle(route.meta?.title),
|
||
meta: route.meta,
|
||
icon: route.meta?.icon,
|
||
children: (route.children || []).map((i) => ({
|
||
key: i.name,
|
||
label: generateTitle(i.meta?.title),
|
||
meta: i.meta,
|
||
icon: i.meta?.icon
|
||
}))
|
||
}))
|
||
})
|
||
|
||
const menuSelectedKeys = computed(() => store.getters.selectedKeys)
|
||
|
||
const defaultOpenedKeys = computed(() => {
|
||
let system = store.getters.system
|
||
if (system == 'service') {
|
||
return ['service-order', 'service-permission']
|
||
} else if (system == 'agency') {
|
||
return ['agency-order', 'agency-permission']
|
||
} else {
|
||
return []
|
||
}
|
||
})
|
||
|
||
const selectedKeys = ref([])
|
||
|
||
const openedKeys = computed(() => {
|
||
return store.getters.openedKeys
|
||
})
|
||
|
||
const menuItemClick = (key) => {
|
||
if (key == 'change-face-video') {
|
||
$message.warning(generateLang('isDevelop'))
|
||
}else {
|
||
router.push({ name: key })
|
||
if ($base.isMobile()) {
|
||
store.dispatch('main/closeSideBar')
|
||
}
|
||
}
|
||
}
|
||
|
||
const subMenuClick = (key, _openKeys) => {
|
||
store.dispatch('main/setOpenedKeys', _openKeys)
|
||
}
|
||
|
||
watch(
|
||
() => route.name,
|
||
() => {
|
||
let sk = route.matched.filter((i) => i.meta.menuItem).map((j) => j.name)
|
||
selectedKeys.value = sk
|
||
let matchKeys = route.matched
|
||
.filter((i) => i.meta.menuItem && i.children?.length > 0)
|
||
.map((j) => j.name)
|
||
let cloneOpenedKeys = cloneDeep(openedKeys.value)
|
||
matchKeys.concat(defaultOpenedKeys.value).map((item) => {
|
||
if (!cloneOpenedKeys.includes(item)) {
|
||
cloneOpenedKeys.push(item)
|
||
}
|
||
})
|
||
store.dispatch('main/setOpenedKeys', cloneOpenedKeys)
|
||
},
|
||
{
|
||
immediate: true
|
||
}
|
||
)
|
||
|
||
const servicePolicyCount = computed(() => store.getters.servicePolicyCount)
|
||
const agencyPolicyCount = computed(() => store.getters.agencyPolicyCount)
|
||
const count = (system) => {
|
||
return system === 'service'
|
||
? servicePolicyCount.value
|
||
: agencyPolicyCount.value
|
||
}
|
||
|
||
const getMenuSvg = (key) => {
|
||
if (key === 'video-gen') {
|
||
return '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18Zm-1.5 5.2a.9.9 0 0 1 1.35-.78l4.7 2.7a.9.9 0 0 1 0 1.56l-4.7 2.7a.9.9 0 0 1-1.35-.78V8.2Z"/></svg>'
|
||
}
|
||
if (key === 'third-party-asset') {
|
||
return '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6h7l2 2h7v12H4V6Zm2 4v8h12v-8H6Zm2 2h8v4H8v-4Z"/></svg>'
|
||
}
|
||
if (key === 'generated-assets') {
|
||
return '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2l-5.5 9h11L12 2zm0 3.5L14.5 9h-5L12 5.5zM4 13v8h16v-8H4zm2 2h12v4H6v-4z"/><path d="M7 15h10v2H7z"/></svg>'
|
||
}
|
||
return '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8"/></svg>'
|
||
}
|
||
</script>
|
||
<style lang="less">
|
||
.arco-tooltip-content {
|
||
display: none;
|
||
}
|
||
</style>
|
||
<style lang="less" scoped>
|
||
.menu-wrapper {
|
||
height: 100%;
|
||
|
||
.arco-scrollbar {
|
||
height: 100%;
|
||
|
||
:deep(.arco-scrollbar-container) {
|
||
height: 100%;
|
||
overflow-x: hidden;
|
||
overflow-y: auto;
|
||
}
|
||
}
|
||
}
|
||
|
||
.menu-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.menu-svg-icon {
|
||
width: 22px;
|
||
height: 22px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: rgba(255, 255, 255, 0.74);
|
||
transition: color 0.2s ease;
|
||
}
|
||
|
||
.menu-svg-icon:deep(svg) {
|
||
width: 22px;
|
||
height: 22px;
|
||
display: block;
|
||
fill: currentColor;
|
||
}
|
||
|
||
.menu-svg-icon.active {
|
||
color: #ffffff;
|
||
}
|
||
</style>
|