index.vue 10.0 KB

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