GlobalLayout.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. <template>
  2. <a-layout class="layout" :class="[device]">
  3. <!-- 侧栏菜单 -->
  4. <template v-if="layoutMode === 'sidemenu'">
  5. <a-drawer
  6. v-if="device === 'mobile'"
  7. :wrapClassName="'drawer-sider ' + navTheme"
  8. placement="left"
  9. @close="() => (this.collapsed = false)"
  10. :closable="false"
  11. :visible="collapsed"
  12. width="200px"
  13. >
  14. <!-- 垂直菜单 横向展示二级三级 -->
  15. <side-menu
  16. mode="inline"
  17. :menus="menus"
  18. @menuSelect="menuSelect()"
  19. :theme="navTheme"
  20. :collapsed="false"
  21. :collapsible="true"
  22. ></side-menu>
  23. </a-drawer>
  24. <side-menu
  25. v-else
  26. mode="inline"
  27. :menus="menus"
  28. @menuSelect="myMenuSelect"
  29. :theme="navTheme"
  30. :collapsed="collapsed"
  31. :collapsible="true"
  32. ></side-menu>
  33. </template>
  34. <!-- 下次优化这些代码 手机-->
  35. <template v-else>
  36. <a-drawer
  37. v-if="device === 'mobile'"
  38. :wrapClassName="'drawer-sider ' + navTheme"
  39. placement="left"
  40. @close="() => (this.collapsed = false)"
  41. :closable="false"
  42. :visible="collapsed"
  43. width="200px"
  44. >
  45. <side-menu
  46. mode="inline"
  47. :menus="menus"
  48. @menuSelect="menuSelect"
  49. :theme="navTheme"
  50. :collapsed="false"
  51. :collapsible="true"
  52. ></side-menu>
  53. </a-drawer>
  54. </template>
  55. <a-layout
  56. :class="[layoutMode, `content-width-${contentWidth}`]"
  57. :style="{ paddingLeft: fixSiderbar && isDesktop() ? `${sidebarOpened ? 200 : 80}px` : '0' }"
  58. >
  59. <!-- layout header -->
  60. <global-header
  61. :mode="layoutMode"
  62. :menus="menus"
  63. :theme="navTheme"
  64. :collapsed="collapsed"
  65. :device="device"
  66. @toggle="toggle"
  67. />
  68. <!-- layout content -->
  69. <a-layout-content :style="{ height: '100%', paddingTop: fixedHeader ? '59px' : '0' }">
  70. <slot></slot>
  71. </a-layout-content>
  72. <!-- layout footer -->
  73. <a-layout-footer style="padding: 0px">
  74. <global-footer />
  75. </a-layout-footer>
  76. </a-layout>
  77. <!-- update-start---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ---- -->
  78. <!--<setting-drawer></setting-drawer>-->
  79. <!-- update-end---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ---- -->
  80. </a-layout>
  81. </template>
  82. <script>
  83. import SideMenu from '@/components/menu/SideMenu'
  84. import GlobalHeader from '@/components/page/GlobalHeader'
  85. import GlobalFooter from '@/components/page/GlobalFooter'
  86. // update-start---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
  87. // import SettingDrawer from '@/components/setting/SettingDrawer'
  88. // 注释这个因为在个人设置模块已经加载了SettingDrawer页面
  89. // update-end ---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
  90. import { triggerWindowResizeEvent } from '@/utils/util'
  91. import { mapState, mapActions } from 'vuex'
  92. import { mixin, mixinDevice } from '@/utils/mixin.js'
  93. export default {
  94. name: 'GlobalLayout',
  95. components: {
  96. SideMenu,
  97. GlobalHeader,
  98. GlobalFooter
  99. // update-start---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
  100. // // SettingDrawer
  101. // 注释这个因为在个人设置模块已经加载了SettingDrawer页面
  102. // update-end ---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
  103. },
  104. mixins: [mixin, mixinDevice],
  105. data () {
  106. return {
  107. collapsed: false,
  108. activeMenu: {},
  109. menus: []
  110. }
  111. },
  112. computed: {
  113. ...mapState({
  114. // 主路由
  115. mainRouters: state => state.permission.addRouters,
  116. // 后台菜单
  117. permissionMenuList: state => state.user.permissionList
  118. })
  119. },
  120. watch: {
  121. sidebarOpened (val) {
  122. this.collapsed = !val
  123. }
  124. },
  125. created () {
  126. // --update-begin----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
  127. // this.menus = this.mainRouters.find((item) => item.path === '/').children;
  128. this.menus = this.permissionMenuList
  129. // 根据后台配置菜单,重新排序加载路由信息
  130. // console.log('----加载菜单逻辑----')
  131. console.log(this.mainRouters)
  132. console.log(this.permissionMenuList)
  133. // console.log('----navTheme------' + this.navTheme)
  134. // --update-end----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
  135. },
  136. methods: {
  137. ...mapActions(['setSidebar']),
  138. toggle () {
  139. this.collapsed = !this.collapsed
  140. this.setSidebar(!this.collapsed)
  141. triggerWindowResizeEvent()
  142. },
  143. menuSelect () {
  144. if (!this.isDesktop()) {
  145. this.collapsed = false
  146. }
  147. },
  148. // update-begin-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
  149. myMenuSelect (value) {
  150. // 此处触发动态路由被点击事件
  151. this.findMenuBykey(this.menus, value.key)
  152. this.$emit('dynamicRouterShow', value.key, this.activeMenu.meta.title)
  153. // update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
  154. let storeKey = 'route:title:' + this.activeMenu.path
  155. this.$ls.set(storeKey, this.activeMenu.meta.title)
  156. // this.activeMenu.meta.children.style = 'red'
  157. // update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
  158. },
  159. findMenuBykey (menus, key) {
  160. for (let i of menus) {
  161. if (i.path == key) {
  162. this.activeMenu = { ...i }
  163. } else if (i.children && i.children.length > 0) {
  164. this.findMenuBykey(i.children, key)
  165. }
  166. }
  167. }
  168. // update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
  169. }
  170. }
  171. </script>
  172. <style lang="less">
  173. body {
  174. // 打开滚动条固定显示
  175. overflow-y: scroll;
  176. &.colorWeak {
  177. filter: invert(80%);
  178. }
  179. }
  180. .layout {
  181. min-height: 100vh !important;
  182. overflow-x: hidden;
  183. &.mobile {
  184. .ant-layout-content {
  185. .content {
  186. margin: 24px 0 0;
  187. }
  188. }
  189. /**
  190. * ant-table-wrapper
  191. * 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
  192. */
  193. .ant-table-wrapper {
  194. .ant-table-content {
  195. overflow-y: auto;
  196. }
  197. .ant-table-body {
  198. min-width: 800px;
  199. }
  200. }
  201. .sidemenu {
  202. .ant-header-fixedHeader {
  203. &.ant-header-side-opened,
  204. &.ant-header-side-closed {
  205. width: 100%;
  206. }
  207. }
  208. }
  209. .topmenu {
  210. /* 必须为 topmenu 才能启用流式布局 */
  211. &.content-width-Fluid {
  212. .header-index-wide {
  213. margin-left: 0;
  214. }
  215. }
  216. }
  217. .header,
  218. .top-nav-header-index {
  219. .user-wrapper .action {
  220. padding: 0 12px;
  221. }
  222. }
  223. }
  224. &.ant-layout-has-sider {
  225. flex-direction: row;
  226. }
  227. .trigger {
  228. font-size: 22px;
  229. line-height: 42px;
  230. padding: 0 18px;
  231. cursor: pointer;
  232. transition: color 300ms, background 300ms;
  233. &:hover {
  234. background: rgba(255, 255, 255, 0.3);
  235. }
  236. }
  237. .topmenu {
  238. .ant-header-fixedHeader {
  239. position: fixed;
  240. top: 0;
  241. right: 0;
  242. z-index: 9;
  243. width: 100%;
  244. transition: width 0.2s;
  245. &.ant-header-side-opened {
  246. width: 100%;
  247. }
  248. &.ant-header-side-closed {
  249. width: 100%;
  250. }
  251. }
  252. /* 必须为 topmenu 才能启用流式布局 */
  253. &.content-width-Fluid {
  254. .header-index-wide {
  255. max-width: unset;
  256. margin-left: 24px;
  257. }
  258. .page-header-index-wide {
  259. max-width: unset;
  260. }
  261. }
  262. }
  263. .sidemenu {
  264. .ant-header-fixedHeader {
  265. position: fixed;
  266. top: 0;
  267. right: 0;
  268. z-index: 9;
  269. width: 100%;
  270. transition: width 0.2s;
  271. &.ant-header-side-opened {
  272. width: calc(100% - 200px);
  273. }
  274. &.ant-header-side-closed {
  275. width: calc(100% - 80px);
  276. }
  277. }
  278. }
  279. .header {
  280. height: 64px;
  281. padding: 0 12px 0 0;
  282. background: #fff;
  283. box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
  284. position: relative;
  285. }
  286. .header,
  287. .top-nav-header-index {
  288. .user-wrapper {
  289. float: right;
  290. height: 100%;
  291. .action {
  292. cursor: pointer;
  293. padding: 0 14px;
  294. display: inline-block;
  295. transition: all 0.3s;
  296. height: 70%;
  297. line-height: 46px;
  298. &.action-full {
  299. height: 100%;
  300. }
  301. &:hover {
  302. background: rgba(255, 255, 255, 0.3);
  303. }
  304. .avatar {
  305. margin: 20px 10px 20px 0;
  306. color: #1890ff;
  307. // color: red;
  308. background: hsla(0, 0%, 100%, 0.85);
  309. vertical-align: middle;
  310. }
  311. .icon {
  312. font-size: 16px;
  313. padding: 4px;
  314. }
  315. .anticon {
  316. color: white;
  317. }
  318. }
  319. }
  320. &.dark {
  321. .user-wrapper {
  322. .action {
  323. color: black;
  324. &:hover {
  325. background: rgba(0, 0, 0, 0.05);
  326. }
  327. .anticon {
  328. color: black;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. &.mobile {
  335. .top-nav-header-index {
  336. .header-index-wide {
  337. .header-index-left {
  338. .trigger {
  339. color: rgba(255, 255, 255, 0.85);
  340. padding: 0 12px;
  341. }
  342. .logo.top-nav-header {
  343. text-align: center;
  344. width: 56px;
  345. line-height: 58px;
  346. }
  347. }
  348. }
  349. .user-wrapper .action .avatar {
  350. margin: 20px 0;
  351. }
  352. &.light {
  353. .header-index-wide {
  354. .header-index-left {
  355. .trigger {
  356. color: rgba(0, 0, 0, 0.65);
  357. }
  358. }
  359. }
  360. //
  361. }
  362. }
  363. }
  364. &.tablet {
  365. // overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
  366. .top-nav-header-index {
  367. .header-index-wide {
  368. .header-index-left {
  369. .logo > a {
  370. overflow: hidden;
  371. text-overflow: ellipsis;
  372. white-space: nowrap;
  373. }
  374. }
  375. }
  376. }
  377. }
  378. .top-nav-header-index {
  379. box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
  380. position: relative;
  381. transition: background 0.3s, width 0.2s;
  382. .header-index-wide {
  383. width: 100%;
  384. margin: auto;
  385. padding: 0 20px 0 0;
  386. display: flex;
  387. height: 59px;
  388. .ant-menu.ant-menu-horizontal {
  389. border: none;
  390. height: 64px;
  391. line-height: 64px;
  392. }
  393. .header-index-left {
  394. flex: 1 1;
  395. display: flex;
  396. .logo.top-nav-header {
  397. width: 165px;
  398. height: 64px;
  399. position: relative;
  400. line-height: 64px;
  401. transition: all 0.3s;
  402. overflow: hidden;
  403. img {
  404. display: inline-block;
  405. vertical-align: middle;
  406. height: 32px;
  407. }
  408. h1 {
  409. color: #fff;
  410. display: inline-block;
  411. vertical-align: top;
  412. font-size: 16px;
  413. margin: 0 0 0 12px;
  414. font-weight: 400;
  415. }
  416. }
  417. }
  418. .header-index-right {
  419. float: right;
  420. height: 59px;
  421. overflow: hidden;
  422. .action:hover {
  423. background-color: rgba(0, 0, 0, 0.05);
  424. }
  425. }
  426. }
  427. &.light {
  428. background-color: #fff;
  429. .header-index-wide {
  430. .header-index-left {
  431. .logo {
  432. h1 {
  433. color: #002140;
  434. }
  435. }
  436. }
  437. }
  438. }
  439. &.dark {
  440. .user-wrapper {
  441. .action {
  442. color: white;
  443. &:hover {
  444. background: rgba(255, 255, 255, 0.3);
  445. }
  446. }
  447. }
  448. .header-index-wide .header-index-left .trigger:hover {
  449. background: rgba(255, 255, 255, 0.3);
  450. }
  451. }
  452. }
  453. // 内容区
  454. .layout-content {
  455. margin: 24px 24px 0px;
  456. height: 64px;
  457. padding: 0 12px 0 0;
  458. }
  459. }
  460. .topmenu {
  461. .page-header-index-wide {
  462. margin: 0 auto;
  463. width: 100%;
  464. }
  465. }
  466. // drawer-sider 自定义
  467. .ant-drawer.drawer-sider {
  468. .sider {
  469. box-shadow: none;
  470. }
  471. &.dark {
  472. .ant-drawer-content {
  473. background-color: rgb(0, 21, 41);
  474. }
  475. }
  476. &.light {
  477. box-shadow: none;
  478. .ant-drawer-content {
  479. background-color: #fff;
  480. }
  481. }
  482. .ant-drawer-body {
  483. padding: 0;
  484. }
  485. }
  486. // 菜单样式
  487. .sider {
  488. box-shadow: 2px 116px 6px 0 rgba(0, 21, 41, 0.35);
  489. position: relative;
  490. z-index: 10;
  491. &.ant-fixed-sidemenu {
  492. position: fixed;
  493. height: 100%;
  494. }
  495. .logo {
  496. height: 64px;
  497. position: relative;
  498. line-height: 64px;
  499. padding-left: 24px;
  500. -webkit-transition: all 0.3s;
  501. transition: all 0.3s;
  502. background: #002140;
  503. overflow: hidden;
  504. img,
  505. h1 {
  506. display: inline-block;
  507. vertical-align: middle;
  508. }
  509. img {
  510. height: 32px;
  511. }
  512. h1 {
  513. color: #fff;
  514. font-size: 18px;
  515. margin: 0 0 0 8px;
  516. font-family: 'Chinese Quote', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
  517. 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
  518. 'Segoe UI Symbol';
  519. font-weight: 600;
  520. }
  521. }
  522. &.light {
  523. // 技能博物馆
  524. background-color: #221140 !important;
  525. // background-color: #fff;
  526. box-shadow: 2px 116px 8px 0 rgba(29, 35, 41, 0.05);
  527. .logo {
  528. background: #fff;
  529. box-shadow: 1px 1px 0 0 #e8e8e8;
  530. h1 {
  531. color: unset;
  532. }
  533. }
  534. .ant-menu-light {
  535. border-right-color: transparent;
  536. // 技能博物馆
  537. background-color: #221140 !important;
  538. color: white;
  539. }
  540. }
  541. }
  542. // 外置的样式控制
  543. .user-dropdown-menu-wrapper.ant-dropdown-menu {
  544. padding: 4px 0;
  545. .ant-dropdown-menu-item {
  546. width: 160px;
  547. }
  548. .ant-dropdown-menu-item > .anticon:first-child,
  549. .ant-dropdown-menu-item > a > .anticon:first-child,
  550. .ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
  551. min-width: 12px;
  552. margin-right: 8px;
  553. }
  554. }
  555. // 数据列表 样式
  556. .table-alert {
  557. margin-bottom: 16px;
  558. }
  559. .table-page-search-wrapper {
  560. .ant-form-inline {
  561. .ant-form-item {
  562. display: flex;
  563. margin-bottom: 24px;
  564. margin-right: 0;
  565. .ant-form-item-control-wrapper {
  566. flex: 1 1;
  567. display: inline-block;
  568. vertical-align: middle;
  569. }
  570. > .ant-form-item-label {
  571. line-height: 32px;
  572. padding-right: 8px;
  573. width: auto;
  574. }
  575. .ant-form-item-control {
  576. height: 32px;
  577. line-height: 32px;
  578. }
  579. }
  580. }
  581. .table-page-search-submitButtons {
  582. display: block;
  583. margin-bottom: 24px;
  584. white-space: nowrap;
  585. }
  586. }
  587. .content {
  588. .table-operator {
  589. margin-bottom: 18px;
  590. button {
  591. margin-right: 8px;
  592. }
  593. }
  594. }
  595. // 未选择菜单项鼠标滑过样式
  596. .ant-menu-submenu-active {
  597. background-color: rgba(142, 202, 230, 0.2);
  598. }
  599. //选中菜单样式
  600. .ant-menu-submenu-selected {
  601. background-color: rgba(142, 202, 230, 0.5);
  602. }
  603. // 技能博物馆
  604. .ant-menu-root>.ant-menu-item:first-child span {
  605. color: white;
  606. }
  607. .ant-menu-root>.ant-menu-item:first-child i {
  608. color: white;
  609. }
  610. </style>