Blame view

ant-design-vue-jeecg/src/components/layouts/TabLayout.vue 13.4 KB
1
<template>
2
  <global-layout @dynamicRouterShow="dynamicRouterShow">
3
4
5
    <!-- update-begin- author:sunjianlei --- date:20191009 --- for: 提升右键菜单的层级 -->
    <contextmenu :itemList="menuItemList" :visible.sync="menuVisible" style="z-index: 9999;" @select="onMenuSelect"/>
    <!-- update-end- author:sunjianlei --- date:20191009 --- for: 提升右键菜单的层级 -->
6
7
8
9
    <a-tabs
      @contextmenu.native="e => onContextmenu(e)"
      v-if="multipage"
      :active-key="activePage"
10
11
      class="tab-layout-tabs"
      style="height:52px"
12
13
14
      :hide-add="true"
      type="editable-card"
      @change="changePage"
15
      @tabClick="tabCallBack"
16
17
18
19
20
      @edit="editPage">
      <a-tab-pane :id="page.fullPath" :key="page.fullPath" v-for="page in pageList">
        <span slot="tab" :pagekey="page.fullPath">{{ page.meta.title }}</span>
      </a-tab-pane>
    </a-tabs>
21
    <div style="margin: 12px 12px 0;">
22
23
      <transition name="page-toggle">
        <keep-alive v-if="multipage">
24
          <router-view v-if="reloadFlag"/>
25
        </keep-alive>
26
27
28
        <template v-else>
          <router-view v-if="reloadFlag"/>
        </template>
29
30
      </transition>
    </div>
31
32
33
34
35
36
  </global-layout>
</template>

<script>
  import GlobalLayout from '@/components/page/GlobalLayout'
  import Contextmenu from '@/components/menu/Contextmenu'
37
  import { mixin, mixinDevice } from '@/utils/mixin.js'
38
  import { triggerWindowResizeEvent } from '@/utils/util'
39
40
41

  const indexKey = '/dashboard/analysis'
42
  export default {
43
    name: 'TabLayout',
44
45
46
47
    components: {
      GlobalLayout,
      Contextmenu
    },
48
49
    mixins: [mixin, mixinDevice],
    data() {
50
51
52
53
54
55
      return {
        pageList: [],
        linkList: [],
        activePage: '',
        menuVisible: false,
        menuItemList: [
56
          { key: '4', icon: 'reload', text: '刷 新' },
57
58
59
          { key: '1', icon: 'arrow-left', text: '关闭左侧' },
          { key: '2', icon: 'arrow-right', text: '关闭右侧' },
          { key: '3', icon: 'close', text: '关闭其它' }
60
61
        ],
        reloadFlag:true
62
63
      }
    },
64
65
66
67
68
69
70
    /* update_begin author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用 ->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
    provide(){
      return{
        closeCurrent:this.closeCurrent
      }
    },
    /* update_end author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
71
    computed: {
72
73
74
75
76
77
78
      multipage() {
        //判断如果是手机模式,自动切换为单页面模式
        if (this.isMobile()) {
          return false
        } else {
          return this.$store.state.app.multipage
        }
79
80
      }
    },
81
82
    created() {
      if (this.$route.path != indexKey) {
83
        this.addIndexToFirst()
84
      }
85
86
87
88
89
90
91
      // update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
      let storeKey = 'route:title:' + this.$route.fullPath
      let routeTitle = this.$ls.get(storeKey)
      if (routeTitle) {
        this.$route.meta.title = routeTitle
      }
      // update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
92
93
94
95
96
      this.pageList.push(this.$route)
      this.linkList.push(this.$route.fullPath)
      this.activePage = this.$route.fullPath
    },
    watch: {
97
      '$route': function(newRoute) {
98
        //console.log("新的路由",newRoute)
99
100
101
        this.activePage = newRoute.fullPath
        if (!this.multipage) {
          this.linkList = [newRoute.fullPath]
102
          this.pageList = [Object.assign({},newRoute)]
103
104
105
106
107
108
109
110
        // update-begin-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
        } else if(indexKey==newRoute.fullPath) {
          //首页时 判断是否缓存 没有缓存 刷新之
          if (newRoute.meta.keepAlive === false) {
            this.routeReload()
          }
        // update-end-author:taoyan date:20200211 for: TASK #3368 【路由缓存】首页的缓存设置有问题,需要根据后台的路由配置来实现是否缓存
        }else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
111
          this.linkList.push(newRoute.fullPath)
112
          this.pageList.push(Object.assign({},newRoute))
113
114
115
116
117
          // update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
          if (newRoute.meta.keepAlive) {
            this.routeReload()
          }
          // update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍
118
119
        } else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
          let oldIndex = this.linkList.indexOf(newRoute.fullPath)
120
121
          let oldPositionRoute = this.pageList[oldIndex]
          this.pageList.splice(oldIndex, 1, Object.assign({},newRoute,{meta:oldPositionRoute.meta}))
122
123
        }
      },
124
125
      'activePage': function(key) {
        let index = this.linkList.lastIndexOf(key)
126
127
        let waitRouter = this.pageList[index]
        this.$router.push(Object.assign({},waitRouter));
128
        this.changeTitle(waitRouter.meta.title)
129
      },
130
      'multipage': function(newVal) {
131
132
133
134
135
        if(this.reloadFlag){
          if (!newVal) {
            this.linkList = [this.$route.fullPath]
            this.pageList = [this.$route]
          }
136
        }
137
138
139
140
141
142
143
144
      },
      // update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
      device() {
        if (this.multipage && this.linkList.indexOf(indexKey) === -1) {
          this.addIndexToFirst()
        }
      },
      // update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
145
146
    },
    methods: {
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
      // update-begin-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG
      // 将首页添加到第一位
      addIndexToFirst() {
        this.pageList.splice(0, 0, {
          name: 'dashboard-analysis',
          path: indexKey,
          fullPath: indexKey,
          meta: {
            icon: 'dashboard',
            title: '首页'
          }
        })
        this.linkList.splice(0, 0, indexKey)
      },
      // update-end-author:sunjianlei date:20191223 for: 修复从单页模式切换回多页模式后首页不居第一位的 BUG

      // update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
      changeTitle(title) {
        let projectTitle = "Jeecg-Boot 企业级快速开发平台"
        // 首页特殊处理
        if (this.$route.path === indexKey) {
          document.title = projectTitle
        } else {
          document.title = title + ' · ' + projectTitle
        }
      },
      // update-end-author:sunjianlei date:20200120 for: 动态更改页面标题
175
      changePage(key) {
176
177
        this.activePage = key
      },
178
179
180
181
182
      tabCallBack() {
        this.$nextTick(() => {
          triggerWindowResizeEvent()
        })
      },
183
      editPage(key, action) {
184
185
        this[action](key)
      },
186
187
      remove(key) {
        if (key == indexKey) {
188
189
190
191
192
193
194
195
196
197
198
199
200
          this.$message.warning('首页不能关闭!')
          return
        }
        if (this.pageList.length === 1) {
          this.$message.warning('这是最后一页,不能再关闭了啦')
          return
        }
        this.pageList = this.pageList.filter(item => item.fullPath !== key)
        let index = this.linkList.indexOf(key)
        this.linkList = this.linkList.filter(item => item !== key)
        index = index >= this.linkList.length ? this.linkList.length - 1 : index
        this.activePage = this.linkList[index]
      },
201
      onContextmenu(e) {
202
203
204
205
206
207
        const pagekey = this.getPageKey(e.target)
        if (pagekey !== null) {
          e.preventDefault()
          this.menuVisible = true
        }
      },
208
      getPageKey(target, depth) {
209
210
211
212
213
214
215
216
        depth = depth || 0
        if (depth > 2) {
          return null
        }
        let pageKey = target.getAttribute('pagekey')
        pageKey = pageKey || (target.previousElementSibling ? target.previousElementSibling.getAttribute('pagekey') : null)
        return pageKey || (target.firstElementChild ? this.getPageKey(target.firstElementChild, ++depth) : null)
      },
217
      onMenuSelect(key, target) {
218
219
220
221
222
223
224
225
226
227
228
        let pageKey = this.getPageKey(target)
        switch (key) {
          case '1':
            this.closeLeft(pageKey)
            break
          case '2':
            this.closeRight(pageKey)
            break
          case '3':
            this.closeOthers(pageKey)
            break
229
230
231
          case '4':
            this.routeReload()
            break
232
233
234
235
          default:
            break
        }
      },
236
237
238
239
240
      /* update_begin author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
      closeCurrent(){
        this.remove(this.activePage);
      },
      /* update_end author:wuxianquan date:20190828 for: 关闭当前tab页,供子页面调用->望菜单能配置外链,直接弹出新页面而不是嵌入iframe #428 */
241
      closeOthers(pageKey) {
242
        let index = this.linkList.indexOf(pageKey)
243
        if (pageKey == indexKey || pageKey.indexOf('?ticke=')>=0) {
244
245
246
          this.linkList = this.linkList.slice(index, index + 1)
          this.pageList = this.pageList.slice(index, index + 1)
          this.activePage = this.linkList[0]
247
248
        } else {
          let indexContent = this.pageList.slice(0, 1)[0]
249
250
          this.linkList = this.linkList.slice(index, index + 1)
          this.pageList = this.pageList.slice(index, index + 1)
251
          this.linkList.unshift(indexContent.fullPath)
252
253
254
255
          this.pageList.unshift(indexContent)
          this.activePage = this.linkList[1]
        }
      },
256
257
      closeLeft(pageKey) {
        if (pageKey == indexKey) {
258
259
          return
        }
260
261
        let tempList = [...this.pageList]
        let indexContent = tempList.slice(0, 1)[0]
262
263
264
        let index = this.linkList.indexOf(pageKey)
        this.linkList = this.linkList.slice(index)
        this.pageList = this.pageList.slice(index)
265
        this.linkList.unshift(indexContent.fullPath)
266
267
268
269
270
        this.pageList.unshift(indexContent)
        if (this.linkList.indexOf(this.activePage) < 0) {
          this.activePage = this.linkList[0]
        }
      },
271
      closeRight(pageKey) {
272
273
274
275
276
277
        let index = this.linkList.indexOf(pageKey)
        this.linkList = this.linkList.slice(0, index + 1)
        this.pageList = this.pageList.slice(0, index + 1)
        if (this.linkList.indexOf(this.activePage < 0)) {
          this.activePage = this.linkList[this.linkList.length - 1]
        }
278
279
280
281
282
283
284
285
      },
      //update-begin-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
      dynamicRouterShow(key,title){
        let keyIndex = this.linkList.indexOf(key)
        if(keyIndex>=0){
          let currRouter = this.pageList[keyIndex]
          let meta = Object.assign({},currRouter.meta,{title:title})
          this.pageList.splice(keyIndex, 1, Object.assign({},currRouter,{meta:meta}))
286
287
288
          if (key === this.activePage) {
            this.changeTitle(title)
          }
289
        }
290
      },
291
      //update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
292
293
294
295
296
297
298
299
300
301
302
303

      //update-begin-author:taoyan date:20191008 for:路由刷新
      routeReload(){
        this.reloadFlag = false
        let ToggleMultipage = "ToggleMultipage"
        this.$store.dispatch(ToggleMultipage,false)
        this.$nextTick(()=>{
          this.$store.dispatch(ToggleMultipage,true)
          this.reloadFlag = true
        })
      }
      //update-end-author:taoyan date:20191008 for:路由刷新
304
    }
305
306
307
  }
</script>
308
<style lang="less">
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

  /*
 * The following styles are auto-applied to elements with
 * transition="page-transition" when their visibility is toggled
 * by Vue.js.
 *
 * You can easily play with the page transition by editing
 * these styles.
 */

  .page-transition-enter {
    opacity: 0;
  }

  .page-transition-leave-active {
    opacity: 0;
  }

  .page-transition-enter .page-transition-container,
  .page-transition-leave-active .page-transition-container {
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
  }
332
333
334
335
336
  /*美化弹出Tab样式*/
  .ant-tabs-nav-container {
    margin-top: 4px;
  }
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385

  /* 修改 ant-tabs 样式 */
  .tab-layout-tabs.ant-tabs {
    border-bottom: 1px solid #ccc;
    border-left: 1px solid #ccc;
    background-color: white;
    padding: 0 20px;

    .ant-tabs-bar {
      margin: 4px 0 0;
      border: none;
    }

  }

  .ant-tabs {

    &.ant-tabs-card .ant-tabs-tab {

      padding: 0 24px !important;
      background-color: white !important;
      margin-right: 10px !important;

      .ant-tabs-close-x {
        width: 12px !important;
        height: 12px !important;
        opacity: 0 !important;
        cursor: pointer !important;
        font-size: 12px !important;
        margin: 0 !important;
        position: absolute;
        top: 36%;
        right: 6px;
      }

      &:hover .ant-tabs-close-x {
        opacity: 1 !important;
      }

    }

  }

  .ant-tabs.ant-tabs-card > .ant-tabs-bar {
    .ant-tabs-tab {
      border: none !important;
      border-bottom: 1px solid transparent !important;
    }
    .ant-tabs-tab-active {
386
      border-color: @primary-color!important;
387
388
389
390
    }
  }
391
</style>