index.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <script lang="ts" setup>
  2. import { VabRoute } from '/#/router'
  3. import { isExternal } from '@/utils/validate'
  4. import { translate } from '@/i18n'
  5. import { useRoutesStore } from '@/store/modules/routes'
  6. import { defaultOpeneds, openFirstMenu, uniqueOpened } from '@/config'
  7. import { useSettingsStore } from '@/store/modules/settings'
  8. import variables from '@vab/styles/variables/variables.module.scss'
  9. const route: VabRoute = useRoute()
  10. const router = useRouter()
  11. const settingsStore = useSettingsStore()
  12. const { theme, collapse } = storeToRefs(settingsStore)
  13. const { foldSideBar, openSideBar } = settingsStore
  14. const routesStore = useRoutesStore()
  15. const {
  16. getTab: tab,
  17. getTabMenu: tabMenu,
  18. getActiveMenu: activeMenu,
  19. getRoutes: routes,
  20. getPartialRoutes: partialRoutes,
  21. }: any = storeToRefs(routesStore)
  22. const handleTabClick = () => {
  23. nextTick(() => {
  24. if (isExternal(tabMenu.value.path)) {
  25. window.open(tabMenu.value.path)
  26. setTimeout(() => {
  27. router.push('/')
  28. }, 1000)
  29. } else if (openFirstMenu)
  30. router.push(tabMenu.value.redirect || tabMenu.value)
  31. })
  32. }
  33. watchEffect(() => {
  34. const foldUnfold: any = document.querySelector(
  35. '.fold-unfold'
  36. ) as HTMLElement
  37. if (theme.value.layout === 'column' && route.meta.noColumn) {
  38. foldSideBar()
  39. if (foldUnfold) foldUnfold.style = 'display:none'
  40. } else {
  41. openSideBar()
  42. if (foldUnfold) foldUnfold.style = ''
  43. }
  44. })
  45. </script>
  46. <template>
  47. <el-scrollbar
  48. class="vab-column-bar-container"
  49. :class="{
  50. 'is-collapse': collapse,
  51. ['vab-column-bar-container-' + theme.columnStyle]: true,
  52. }"
  53. >
  54. <vab-logo />
  55. <el-tabs v-model="tab.data" tab-position="left" @tab-click="handleTabClick">
  56. <template v-for="(item, index) in routes" :key="index + item.name">
  57. <el-tab-pane :name="item.name">
  58. <template #label>
  59. <div
  60. class="vab-column-grid"
  61. :class="{
  62. ['vab-column-grid-' + theme.columnStyle]: true,
  63. }"
  64. :title="translate(item.meta.title)"
  65. >
  66. <div>
  67. <vab-icon
  68. v-if="item.meta.icon"
  69. :icon="item.meta.icon"
  70. :is-custom-svg="item.meta.isCustomSvg"
  71. />
  72. <span>
  73. {{ translate(item.meta.title) }}
  74. </span>
  75. </div>
  76. </div>
  77. </template>
  78. </el-tab-pane>
  79. </template>
  80. </el-tabs>
  81. <el-menu
  82. :background-color="variables['column-second-menu-background']"
  83. :default-active="activeMenu.data"
  84. :default-openeds="defaultOpeneds"
  85. mode="vertical"
  86. :unique-opened="uniqueOpened"
  87. >
  88. <el-divider>
  89. {{ translate(tabMenu ? tabMenu.meta.title : tabMenu) }}
  90. </el-divider>
  91. <template v-for="item in partialRoutes" :key="item.path">
  92. <vab-menu v-if="!item.meta.hidden" :item="item" />
  93. </template>
  94. </el-menu>
  95. </el-scrollbar>
  96. </template>
  97. <style lang="scss" scoped>
  98. @use 'sass:math';
  99. @mixin active {
  100. &:hover {
  101. color: var(--el-color-primary);
  102. background-color: $base-column-second-menu-active !important;
  103. i,
  104. svg {
  105. color: var(--el-color-primary);
  106. }
  107. }
  108. &.is-active {
  109. color: var(--el-color-primary);
  110. background-color: $base-column-second-menu-active !important;
  111. }
  112. }
  113. .vab-column-bar-container {
  114. position: fixed;
  115. top: 0;
  116. bottom: 0;
  117. left: 0;
  118. width: var(--el-left-menu-width);
  119. height: 100vh;
  120. overflow: hidden;
  121. background: $base-column-second-menu-background;
  122. box-shadow: $base-box-shadow;
  123. :deep() {
  124. * {
  125. transition: $base-transition;
  126. }
  127. .el-tabs {
  128. box-shadow: $base-box-shadow;
  129. }
  130. }
  131. &-vertical,
  132. &-card,
  133. &-arrow {
  134. :deep() {
  135. .el-tabs + .el-menu {
  136. left: $base-left-menu-width-min;
  137. width: calc(var(--el-left-menu-width) - #{$base-left-menu-width-min});
  138. border: 0;
  139. }
  140. }
  141. }
  142. &-horizontal {
  143. :deep() {
  144. .logo-container-column {
  145. .logo {
  146. width: $base-left-menu-width-min * 1.3 !important;
  147. }
  148. .title {
  149. margin-left: $base-left-menu-width-min * 1.3 !important;
  150. }
  151. }
  152. .el-tabs + .el-menu {
  153. left: $base-left-menu-width-min * 1.3;
  154. width: calc(
  155. var(--el-left-menu-width) - #{$base-left-menu-width-min} * 1.3
  156. );
  157. border: 0;
  158. }
  159. }
  160. }
  161. &-card {
  162. :deep() {
  163. .el-tabs {
  164. .el-tabs__item {
  165. padding: 5px !important;
  166. .vab-column-grid {
  167. width: $base-left-menu-width-min - 10 !important;
  168. height: $base-left-menu-width-min - 10 !important;
  169. border-radius: 5px;
  170. }
  171. &.is-active {
  172. background: transparent !important;
  173. .vab-column-grid {
  174. background: var(--el-color-primary);
  175. }
  176. }
  177. }
  178. }
  179. .el-tabs + .el-menu {
  180. left: $base-left-menu-width-min + 10;
  181. width: calc(
  182. var(--el-left-menu-width) - #{$base-left-menu-width-min} - 20px
  183. );
  184. }
  185. .el-sub-menu .el-sub-menu__title,
  186. .el-menu-item {
  187. min-width: 180px;
  188. margin-bottom: 5px;
  189. border-radius: 5px;
  190. }
  191. }
  192. }
  193. &-arrow {
  194. :deep() {
  195. .el-tabs {
  196. .el-tabs__item {
  197. &.is-active {
  198. background: transparent !important;
  199. .vab-column-grid {
  200. background: transparent !important;
  201. &:after {
  202. position: absolute;
  203. right: 0;
  204. width: 0;
  205. height: 0;
  206. overflow: hidden;
  207. content: '';
  208. border-color: transparent #{var(--el-color-white)} transparent
  209. transparent;
  210. border-style: solid dashed dashed;
  211. border-width: 8px;
  212. }
  213. }
  214. }
  215. }
  216. }
  217. .el-tabs + .el-menu {
  218. left: $base-left-menu-width-min + 10;
  219. width: calc(
  220. var(--el-left-menu-width) - #{$base-left-menu-width-min} - 20px
  221. );
  222. }
  223. .el-sub-menu .el-sub-menu__title,
  224. .el-menu-item {
  225. min-width: 180px;
  226. margin-bottom: 5px;
  227. border-radius: 5px;
  228. }
  229. }
  230. }
  231. .vab-column-grid {
  232. display: flex;
  233. align-items: center;
  234. width: $base-left-menu-width-min;
  235. overflow: hidden;
  236. text-align: center;
  237. text-overflow: ellipsis;
  238. word-break: break-all;
  239. white-space: nowrap;
  240. &-vertical,
  241. &-card,
  242. &-arrow {
  243. justify-content: center;
  244. height: $base-left-menu-width-min;
  245. > div {
  246. svg {
  247. position: relative;
  248. top: 8px;
  249. display: block;
  250. width: $base-font-size-default + 4;
  251. height: $base-font-size-default + 4;
  252. }
  253. [class*='ri-'] {
  254. display: block;
  255. height: 20px;
  256. }
  257. }
  258. }
  259. &-horizontal {
  260. justify-content: left;
  261. width: $base-left-menu-width-min * 1.3;
  262. height: #{math.div($base-left-menu-width-min, 1.3)};
  263. padding-left: #{math.div($base-padding, 2)};
  264. }
  265. }
  266. :deep() {
  267. .el-scrollbar__wrap {
  268. overflow-x: hidden;
  269. }
  270. .el-tabs {
  271. position: fixed;
  272. .el-tabs__header.is-left {
  273. margin-right: 0 !important;
  274. .el-tabs__nav-wrap.is-left {
  275. margin-right: 0 !important;
  276. background: $base-column-first-menu-background;
  277. .el-tabs__nav-scroll {
  278. height: 100%;
  279. overflow-y: auto;
  280. &::-webkit-scrollbar {
  281. width: 0;
  282. height: 0;
  283. }
  284. }
  285. }
  286. }
  287. .el-tabs__nav {
  288. height: calc(100vh - #{$base-logo-height});
  289. background: $base-column-first-menu-background;
  290. }
  291. .el-tabs__item {
  292. height: auto;
  293. padding: 0;
  294. color: var(--el-color-white);
  295. &.is-active {
  296. background: var(--el-color-primary);
  297. }
  298. }
  299. }
  300. .el-tabs__active-bar.is-left,
  301. .el-tabs--left .el-tabs__nav-wrap.is-left::after {
  302. display: none;
  303. }
  304. .el-menu {
  305. border: 0;
  306. .el-divider {
  307. margin: 0 0 $base-margin 0;
  308. background-color: #f6f6f6;
  309. &__text {
  310. color: var(--el-color-black);
  311. }
  312. }
  313. .el-menu-item,
  314. .el-sub-menu__title {
  315. height: $base-menu-item-height;
  316. overflow: hidden;
  317. line-height: $base-menu-item-height;
  318. text-overflow: ellipsis;
  319. white-space: nowrap;
  320. vertical-align: middle;
  321. @include active;
  322. }
  323. }
  324. }
  325. &.is-collapse {
  326. :deep() {
  327. width: 0;
  328. }
  329. }
  330. }
  331. </style>