vue2-client 1.8.166 → 1.8.167

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/.env +19 -19
  2. package/.eslintrc.js +90 -90
  3. package/CHANGELOG.md +824 -824
  4. package/Components.md +60 -60
  5. package/babel.config.js +21 -21
  6. package/docs/index.md +30 -30
  7. package/index.js +31 -31
  8. package/jest-transform-stub.js +8 -8
  9. package/jest.config.js +21 -21
  10. package/jest.setup.js +7 -7
  11. package/package.json +97 -97
  12. package/public/index.html +27 -27
  13. package/src/App.vue +164 -164
  14. package/src/ReportView.js +19 -19
  15. package/src/assets/img/querySlotDemo.svg +15 -15
  16. package/src/assets/svg/badtwo.svg +1 -1
  17. package/src/assets/svg/goodtwo.svg +1 -1
  18. package/src/base-client/components/common/AMisRender/index.js +3 -3
  19. package/src/base-client/components/common/AMisRender/index.vue +263 -263
  20. package/src/base-client/components/common/AddressSearchCombobox/AddressSearchCombobox.vue +316 -316
  21. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  22. package/src/base-client/components/common/CitySelect/index.js +3 -3
  23. package/src/base-client/components/common/CitySelect/index.md +109 -109
  24. package/src/base-client/components/common/CreateQuery/CreateQuery.vue +669 -669
  25. package/src/base-client/components/common/CreateQuery/CreateQueryItem.vue +1014 -1014
  26. package/src/base-client/components/common/CreateQuery/index.js +3 -3
  27. package/src/base-client/components/common/CreateQuery/index.md +42 -42
  28. package/src/base-client/components/common/CreateSimpleFormQuery/CreateSimpleFormQuery.vue +452 -452
  29. package/src/base-client/components/common/CreateSimpleFormQuery/CreateSimpleFormQueryItem.vue +511 -511
  30. package/src/base-client/components/common/CreateSimpleFormQuery/index.js +3 -3
  31. package/src/base-client/components/common/CreateSimpleFormQuery/index.md +42 -42
  32. package/src/base-client/components/common/FormGroupEdit/FormGroupEdit.vue +149 -149
  33. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  34. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  35. package/src/base-client/components/common/FormGroupQuery/FormGroupQuery.vue +166 -166
  36. package/src/base-client/components/common/FormGroupQuery/index.js +3 -3
  37. package/src/base-client/components/common/FormGroupQuery/index.md +43 -43
  38. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  39. package/src/base-client/components/common/PersonSetting/PersonSetting.vue +208 -208
  40. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  41. package/src/base-client/components/common/Tree/Tree.vue +149 -149
  42. package/src/base-client/components/common/Tree/index.js +2 -2
  43. package/src/base-client/components/common/Upload/Upload.vue +197 -197
  44. package/src/base-client/components/common/Upload/index.js +3 -3
  45. package/src/base-client/components/common/XAddForm/XAddForm.vue +92 -92
  46. package/src/base-client/components/common/XAddNativeForm/XAddNativeForm.vue +502 -502
  47. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  48. package/src/base-client/components/common/XAddNativeFormOA/XAddNativeFormOA.vue +303 -303
  49. package/src/base-client/components/common/XAddNativeFormOA/index.js +3 -3
  50. package/src/base-client/components/common/XAddNativeFormOA/index.md +146 -146
  51. package/src/base-client/components/common/XBadge/XBadge.vue +78 -78
  52. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  53. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  54. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  55. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  56. package/src/base-client/components/common/XDescriptions/XDescriptions.vue +117 -117
  57. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  58. package/src/base-client/components/common/XDescriptions/index.md +83 -83
  59. package/src/base-client/components/common/XForm/XForm.vue +253 -253
  60. package/src/base-client/components/common/XForm/XFormItem.vue +545 -545
  61. package/src/base-client/components/common/XForm/XTreeSelect.vue +191 -191
  62. package/src/base-client/components/common/XForm/index.md +178 -178
  63. package/src/base-client/components/common/XFormCol/XFormCol.vue +38 -38
  64. package/src/base-client/components/common/XFormTable/XFormTable.vue +418 -418
  65. package/src/base-client/components/common/XFormTable/index.md +98 -98
  66. package/src/base-client/components/common/XImportExcel/XImportExcel.vue +131 -131
  67. package/src/base-client/components/common/XReport/XReport.vue +694 -694
  68. package/src/base-client/components/common/XReport/XReportDesign.vue +423 -414
  69. package/src/base-client/components/common/XReport/XReportTrGroup.vue +602 -596
  70. package/src/base-client/components/common/XReport/index.js +3 -3
  71. package/src/base-client/components/common/XReport/index.md +44 -44
  72. package/src/base-client/components/common/XReportSlot/XReportSlot.vue +110 -110
  73. package/src/base-client/components/common/XReportSlot/index.js +3 -3
  74. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  75. package/src/base-client/components/common/XStepView/index.js +3 -3
  76. package/src/base-client/components/common/XStepView/index.md +31 -31
  77. package/src/base-client/components/common/XTable/XTable.vue +549 -549
  78. package/src/base-client/components/common/XTable/index.md +255 -255
  79. package/src/base-client/components/common/XTree/XTree.vue +76 -76
  80. package/src/base-client/components/common/XTree/index.js +3 -3
  81. package/src/base-client/components/common/XTree/index.md +36 -36
  82. package/src/base-client/components/index.js +47 -47
  83. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  84. package/src/base-client/components/system/QueryParamsDetailsView/QueryParamsDetailsView.vue +281 -281
  85. package/src/base-client/plugins/AppData.js +115 -115
  86. package/src/base-client/plugins/Config.js +19 -19
  87. package/src/base-client/plugins/GetLoginInfoService.js +182 -182
  88. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  89. package/src/bootstrap.js +39 -39
  90. package/src/components/CodeMirror/inedx.vue +118 -118
  91. package/src/components/CodeMirror/setting.js +40 -40
  92. package/src/components/FilePreview/FilePreview.vue +166 -166
  93. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  94. package/src/components/STable/index.js +323 -323
  95. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  96. package/src/components/checkbox/ImgCheckbox.vue +163 -163
  97. package/src/components/menu/SideMenu.vue +75 -75
  98. package/src/components/menu/menu.js +273 -273
  99. package/src/components/tool/AStepItem.vue +60 -60
  100. package/src/config/CreateQueryConfig.js +322 -322
  101. package/src/config/default/antd.config.js +89 -89
  102. package/src/config/default/setting.config.js +53 -53
  103. package/src/font-style/font.css +4 -4
  104. package/src/layouts/CommonLayout.vue +56 -56
  105. package/src/layouts/PageLayout.vue +151 -151
  106. package/src/layouts/SinglePageView.vue +138 -138
  107. package/src/layouts/header/AdminHeader.vue +132 -132
  108. package/src/layouts/header/HeaderNotice.vue +177 -177
  109. package/src/layouts/tabs/TabsHead.vue +189 -189
  110. package/src/layouts/tabs/TabsView.vue +387 -387
  111. package/src/lib.js +1 -1
  112. package/src/main.js +26 -26
  113. package/src/mock/extend/index.js +84 -84
  114. package/src/mock/goods/index.js +108 -108
  115. package/src/pages/AMisDemo/AMisDemo.vue +325 -325
  116. package/src/pages/AMisDemo/AMisDemo2.vue +74 -74
  117. package/src/pages/DynamicStatistics/ChartSelector.vue +331 -331
  118. package/src/pages/DynamicStatistics/DataTabs.vue +83 -83
  119. package/src/pages/DynamicStatistics/DynamicTable.vue +128 -128
  120. package/src/pages/DynamicStatistics/EvaluationArea.vue +69 -69
  121. package/src/pages/DynamicStatistics/FavoriteList.vue +51 -51
  122. package/src/pages/DynamicStatistics/QuestionHistoryAndFavorites.vue +591 -591
  123. package/src/pages/DynamicStatistics/SearchBar.vue +192 -192
  124. package/src/pages/DynamicStatistics/index.vue +282 -282
  125. package/src/pages/Example/index.vue +1432 -1305
  126. package/src/pages/ServiceReview/index.vue +284 -284
  127. package/src/pages/XReportView/index.vue +62 -62
  128. package/src/pages/login/Login.vue +378 -378
  129. package/src/pages/login/LoginV3.vue +389 -389
  130. package/src/pages/resourceManage/orgListManage.vue +98 -98
  131. package/src/pages/system/dictionary/index.vue +44 -44
  132. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  133. package/src/pages/system/monitor/operLog/index.vue +37 -37
  134. package/src/pages/system/settings/modifyPassword.vue +117 -117
  135. package/src/pages/system/ticket/index.vue +480 -480
  136. package/src/pages/system/ticket/submitTicketSuccess.vue +484 -484
  137. package/src/router/async/config.async.js +32 -32
  138. package/src/router/async/router.map.js +98 -98
  139. package/src/router/guards.js +214 -214
  140. package/src/router/index.js +27 -27
  141. package/src/router.js +18 -18
  142. package/src/services/api/TicketDetailsViewApi.js +46 -46
  143. package/src/services/api/cas.js +79 -79
  144. package/src/services/api/common.js +274 -274
  145. package/src/services/api/entity.js +18 -18
  146. package/src/services/api/index.js +17 -17
  147. package/src/services/api/restTools.js +46 -46
  148. package/src/services/apiService.js +14 -14
  149. package/src/services/user.js +71 -71
  150. package/src/store/modules/setting.js +119 -119
  151. package/src/theme/default/style.less +57 -57
  152. package/src/utils/authority-utils.js +85 -85
  153. package/src/utils/errorCode.js +6 -6
  154. package/src/utils/htmlToPDF.js +108 -108
  155. package/src/utils/htmlToPDFApi.js +5 -5
  156. package/src/utils/indexedDB.js +201 -201
  157. package/src/utils/login.js +141 -141
  158. package/src/utils/map-utils.js +47 -47
  159. package/src/utils/request.js +343 -343
  160. package/src/utils/routerUtil.js +428 -428
  161. package/src/utils/util.js +231 -231
  162. package/src/utils/waterMark.js +31 -31
  163. package/test/Amis.spec.js +163 -163
  164. package/test/Tree.spec.js +167 -167
  165. package/test/myDialog.spec.js +46 -46
  166. package/vue.config.js +166 -166
  167. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
@@ -1,387 +1,387 @@
1
- <template>
2
- <div id="TabsView">
3
- <admin-layout>
4
- <contextmenu :itemList="menuItemList" :visible.sync="menuVisible" @select="onMenuSelect" />
5
- <tabs-head
6
- v-if="multiPage"
7
- :active="activePage"
8
- :page-list="pageList"
9
- @change="changePage"
10
- @close="remove"
11
- @refresh="refresh"
12
- @contextmenu="onContextmenu"
13
- />
14
- <div :class="['tabs-view-content', layout, pageWidth]" :style="`margin-top: ${multiPage ? -24 : 0}px`">
15
- <page-toggle-transition v-show="!$route.meta.singlePage" :disabled="animate.disabled" :animate="animate.name" :direction="animate.direction">
16
- <a-keep-alive :exclude-keys="excludeKeys" v-if="multiPage && cachePage" v-model="clearCaches">
17
- <router-view v-if="!refreshing" ref="tabContent" :key="$route.fullPath" />
18
- </a-keep-alive>
19
- <router-view ref="tabContent" v-else-if="!refreshing" />
20
- </page-toggle-transition>
21
- <template v-for="page in single">
22
- <single-page-view
23
- v-show="page.meta.singlePage === $route.meta.singlePage"
24
- :single-page-url="page.meta.singlePage"
25
- :full-path="page.fullPath"
26
- :key="page.meta.singlePage"
27
- @load="onSinglePageLoad" />
28
- </template>
29
- </div>
30
- </admin-layout>
31
- </div>
32
- </template>
33
-
34
- <script>
35
- import AdminLayout from '@vue2-client/layouts/AdminLayout'
36
- import Contextmenu from '@vue2-client/components/menu/Contextmenu'
37
- import PageToggleTransition from '@vue2-client/components/transition/PageToggleTransition'
38
- import { mapState, mapMutations } from 'vuex'
39
- import { getI18nKey } from '@vue2-client/utils/routerUtil'
40
- import AKeepAlive from '@vue2-client/components/cache/AKeepAlive'
41
- import TabsHead from '@vue2-client/layouts/tabs/TabsHead'
42
- import SinglePageView from '../SinglePageView'
43
-
44
- export default {
45
- name: 'TabsView',
46
- i18n: require('./i18n'),
47
- components: { SinglePageView, TabsHead, PageToggleTransition, Contextmenu, AdminLayout, AKeepAlive },
48
- data () {
49
- return {
50
- clearCaches: [],
51
- pageList: [],
52
- activePage: '',
53
- menuVisible: false,
54
- refreshing: false,
55
- allSinglePages: [],
56
- excludeKeys: []
57
- }
58
- },
59
- computed: {
60
- ...mapState('setting', ['multiPage', 'cachePage', 'animate', 'layout', 'pageWidth']),
61
- ...mapState('account', ['single']),
62
- menuItemList () {
63
- return [
64
- { key: '1', icon: 'vertical-right', text: this.$t('closeLeft') },
65
- { key: '2', icon: 'vertical-left', text: this.$t('closeRight') },
66
- { key: '3', icon: 'close', text: this.$t('closeOthers') },
67
- { key: '4', icon: 'sync', text: this.$t('refresh') }
68
- ]
69
- },
70
- tabsOffset () {
71
- return this.multiPage ? 24 : 0
72
- }
73
- },
74
- created () {
75
- this.loadCacheConfig(this.$router?.options?.routes)
76
- this.loadCachedTabs()
77
- // 解决单页面为首页时首次登录不加载问题
78
- if (this.$route.meta.singlePage && this.single.length === 0) {
79
- this.allSinglePages.forEach(item => {
80
- if (this.$route.fullPath.includes(item.fullPath)) {
81
- this.setSingle(item)
82
- }
83
- })
84
- }
85
- const route = this.$route
86
- if (this.pageList.findIndex(item => item.path === route.fullPath) === -1) {
87
- this.pageList.push(this.createPage(route))
88
- }
89
- this.activePage = route.fullPath
90
- if (this.multiPage) {
91
- this.$nextTick(() => {
92
- this.setCachedKey(route)
93
- })
94
- this.addListener()
95
- }
96
- },
97
- mounted () {
98
- this.correctPageMinHeight(-this.tabsOffset)
99
- },
100
- beforeDestroy () {
101
- this.removeListener()
102
- this.correctPageMinHeight(this.tabsOffset)
103
- },
104
- watch: {
105
- '$router.options.routes': function (val) {
106
- this.excludeKeys = []
107
- this.loadCacheConfig(val)
108
- },
109
- $route: function (newRoute) {
110
- this.activePage = newRoute.fullPath
111
- const page = this.pageList.find(item => item.path === newRoute.fullPath)
112
- if (!this.multiPage) {
113
- this.pageList = [this.createPage(newRoute)]
114
- } else if (page) {
115
- page.fullPath = newRoute.fullPath
116
- } else if (!page) {
117
- this.pageList.push(this.createPage(newRoute))
118
- }
119
- if (this.multiPage) {
120
- this.$nextTick(() => {
121
- this.setCachedKey(newRoute)
122
- })
123
- }
124
- },
125
- multiPage: function (newVal) {
126
- if (!newVal) {
127
- this.pageList = [this.createPage(this.$route)]
128
- this.removeListener()
129
- } else {
130
- this.addListener()
131
- }
132
- },
133
- tabsOffset (newVal, oldVal) {
134
- this.correctPageMinHeight(oldVal - newVal)
135
- }
136
- },
137
- methods: {
138
- changePage (key) {
139
- this.activePage = key
140
- const page = this.pageList.find(item => item.path === key)
141
- this.$router.push(page.fullPath)
142
- },
143
- remove (key, next) {
144
- if (this.pageList.length === 1) {
145
- return this.$message.warning(this.$t('warn'))
146
- }
147
- this.setSingle({ path: key, delete: true })
148
- // 清除缓存
149
- let index = this.pageList.findIndex(item => item.path === key)
150
- this.clearCaches = this.pageList.splice(index, 1).map(page => page.cachedKey)
151
- if (next) {
152
- this.$router.push(next)
153
- } else if (key === this.activePage) {
154
- index = index >= this.pageList.length ? this.pageList.length - 1 : index
155
- this.activePage = this.pageList[index].path
156
- this.$router.push(this.activePage)
157
- }
158
- },
159
- refresh (key, page) {
160
- page = page || this.pageList.find(item => item.path === key)
161
- page.loading = true
162
- // 单页面刷新
163
- const singlePage = this.allSinglePages.find(item => item.fullPath === key)
164
- if (singlePage) {
165
- window.frames[singlePage.fullPath].location.reload()
166
- return
167
- }
168
- this.clearCache(page)
169
- if (key === this.activePage) {
170
- // eslint-disable-next-line no-return-assign
171
- this.reloadContent(() => page.loading = false)
172
- } else {
173
- // 其实刷新很快,加这个延迟纯粹为了 loading 状态多展示一会儿,让用户感知刷新这一过程
174
- // eslint-disable-next-line no-return-assign
175
- setTimeout(() => page.loading = false, 500)
176
- }
177
- },
178
- onSinglePageLoad (fullPath) {
179
- const page = this.pageList.find(item => item.fullPath === fullPath)
180
- page.loading = false
181
- },
182
- onContextmenu (pageKey, e) {
183
- if (pageKey) {
184
- e.preventDefault()
185
- e.meta = pageKey
186
- this.menuVisible = true
187
- }
188
- },
189
- onMenuSelect (key, target, pageKey) {
190
- switch (key) {
191
- case '1': this.closeLeft(pageKey); break
192
- case '2': this.closeRight(pageKey); break
193
- case '3': this.closeOthers(pageKey); break
194
- case '4': this.refresh(pageKey); break
195
- default: break
196
- }
197
- },
198
- closeOthers (pageKey) {
199
- // 清除缓存
200
- const clearPages = this.pageList.filter(item => item.path !== pageKey && !item.unclose)
201
- this.clearCaches = clearPages.map(item => item.cachedKey)
202
- this.pageList = this.pageList.filter(item => !clearPages.includes(item))
203
- // 判断跳转
204
- if (this.activePage !== pageKey) {
205
- this.activePage = pageKey
206
- this.$router.push(this.activePage)
207
- }
208
- },
209
- closeLeft (pageKey) {
210
- const index = this.pageList.findIndex(item => item.path === pageKey)
211
- // 清除缓存
212
- const clearPages = this.pageList.filter((item, i) => i < index && !item.unclose)
213
- this.clearCaches = clearPages.map(item => item.cachedKey)
214
- this.pageList = this.pageList.filter(item => !clearPages.includes(item))
215
- // 判断跳转
216
- if (!this.pageList.find(item => item.path === this.activePage)) {
217
- this.activePage = pageKey
218
- this.$router.push(this.activePage)
219
- }
220
- },
221
- closeRight (pageKey) {
222
- // 清除缓存
223
- const index = this.pageList.findIndex(item => item.path === pageKey)
224
- const clearPages = this.pageList.filter((item, i) => i > index && !item.unclose)
225
- this.clearCaches = clearPages.map(item => item.cachedKey)
226
- this.pageList = this.pageList.filter(item => !clearPages.includes(item))
227
- // 判断跳转
228
- if (!this.pageList.find(item => item.path === this.activePage)) {
229
- this.activePage = pageKey
230
- this.$router.push(this.activePage)
231
- }
232
- },
233
- clearCache (page) {
234
- page._init_ = false
235
- this.clearCaches = [page.cachedKey]
236
- },
237
- reloadContent (onLoaded) {
238
- this.refreshing = true
239
- setTimeout(() => {
240
- this.refreshing = false
241
- this.$nextTick(() => {
242
- this.setCachedKey(this.$route)
243
- if (typeof onLoaded === 'function') {
244
- onLoaded.apply(this, [])
245
- }
246
- })
247
- }, 200)
248
- },
249
- pageName (page) {
250
- return this.$t(getI18nKey(page.keyPath))
251
- },
252
- /**
253
- * 添加监听器
254
- */
255
- addListener () {
256
- window.addEventListener('page:close', this.closePageListener)
257
- window.addEventListener('page:refresh', this.refreshPageListener)
258
- window.addEventListener('unload', this.unloadListener)
259
- },
260
- /**
261
- * 移出监听器
262
- */
263
- removeListener () {
264
- window.removeEventListener('page:close', this.closePageListener)
265
- window.removeEventListener('page:refresh', this.refreshPageListener)
266
- window.removeEventListener('unload', this.unloadListener)
267
- },
268
- /**
269
- * 页签关闭事件监听
270
- * @param event 页签关闭事件
271
- */
272
- closePageListener (event) {
273
- const { closeRoute, nextRoute } = event.detail
274
- const closePath = typeof closeRoute === 'string' ? closeRoute : closeRoute.path
275
- const path = closePath && closePath.split('?')[0]
276
- this.remove(path, nextRoute)
277
- },
278
- /**
279
- * 页面刷新事件监听
280
- * @param event 页签关闭事件
281
- */
282
- refreshPageListener (event) {
283
- const { pageKey } = event.detail
284
- const path = pageKey && pageKey.split('?')[0]
285
- this.refresh(path)
286
- },
287
- /**
288
- * 页面 unload 事件监听器,添加页签到 session 缓存,用于刷新时保留页签
289
- */
290
- unloadListener () {
291
- const tabs = this.pageList.map(item => ({ ...item, _init_: false }))
292
- sessionStorage.setItem(process.env.VUE_APP_TBAS_KEY, JSON.stringify(tabs))
293
- },
294
- createPage (route) {
295
- return {
296
- keyPath: route.matched[route.matched.length - 1].path,
297
- fullPath: route.fullPath,
298
- loading: false,
299
- path: route.fullPath,
300
- title: route.meta && route.meta.page && route.meta.page.title,
301
- unclose: route.meta && route.meta.page && (route.meta.page.closable === false)
302
- }
303
- },
304
- /**
305
- * 设置页面缓存的key
306
- * @param route 页面对应的路由
307
- */
308
- setCachedKey (route) {
309
- const page = this.pageList.find(item => item.path === route.path)
310
- page.unclose = route.meta && route.meta.page && (route.meta.page.closable === false)
311
- if (!page._init_) {
312
- const vnode = this.$refs.tabContent.$vnode
313
- page.cachedKey = vnode.key + vnode.componentOptions.Ctor.cid
314
- page._init_ = true
315
- }
316
- },
317
- /**
318
- * 加载缓存的 tabs
319
- */
320
- loadCachedTabs () {
321
- const cachedTabsStr = sessionStorage.getItem(process.env.VUE_APP_TBAS_KEY)
322
- if (cachedTabsStr) {
323
- try {
324
- // 加载缓存的单页面
325
- const allCachedPath = JSON.parse(cachedTabsStr).map(str => { return str.fullPath })
326
- this.allSinglePages.forEach(item => {
327
- if (allCachedPath.includes(item.fullPath)) {
328
- // 如果缓存中有单页面 加载到 state.single
329
- this.setSingle(item)
330
- }
331
- })
332
- const cachedTabs = JSON.parse(cachedTabsStr)
333
- if (cachedTabs.length > 0) {
334
- this.pageList = cachedTabs
335
- }
336
- } catch (e) {
337
- console.warn('failed to load cached tabs, got exception:', e)
338
- } finally {
339
- sessionStorage.removeItem(process.env.VUE_APP_TBAS_KEY)
340
- }
341
- }
342
- },
343
- loadCacheConfig (routes, pCache = true) {
344
- routes.forEach(item => {
345
- const cacheAble = item.meta?.page?.cacheAble ?? pCache ?? true
346
- if (item.meta && item.meta.singlePage) {
347
- // 找到所有单页面添加到 allSinglePages 中
348
- this.allSinglePages.push(item)
349
- }
350
- if (!cacheAble) {
351
- this.excludeKeys.push(new RegExp(`${item.path.replace(/:[^/]*/g, '[^/]*')}(\\?.*)?\\d*$`))
352
- }
353
- if (item.children) {
354
- this.loadCacheConfig(item.children, cacheAble)
355
- }
356
- })
357
- },
358
- ...mapMutations('setting', ['correctPageMinHeight']),
359
- ...mapMutations('account', ['setSingle'])
360
- }
361
- }
362
- </script>
363
-
364
- <style lang="less">
365
- #TabsView {
366
- .tabs-view {
367
- margin: -16px auto 8px;
368
- &.head.fixed {
369
- max-width: 100%;
370
- }
371
- }
372
- .tabs-view-content {
373
- position: relative;
374
- &.head.fixed {
375
- width: 100%;
376
- margin: 0 auto;
377
- }
378
- > div > div > .ant-card:first-of-type > .ant-card-body {
379
- max-height: calc(100vh - 64px - 48px - 24px);
380
- overflow-y: auto;
381
- &::-webkit-scrollbar {
382
- display: none;
383
- }
384
- }
385
- }
386
- }
387
- </style>
1
+ <template>
2
+ <div id="TabsView">
3
+ <admin-layout>
4
+ <contextmenu :itemList="menuItemList" :visible.sync="menuVisible" @select="onMenuSelect" />
5
+ <tabs-head
6
+ v-if="multiPage"
7
+ :active="activePage"
8
+ :page-list="pageList"
9
+ @change="changePage"
10
+ @close="remove"
11
+ @refresh="refresh"
12
+ @contextmenu="onContextmenu"
13
+ />
14
+ <div :class="['tabs-view-content', layout, pageWidth]" :style="`margin-top: ${multiPage ? -24 : 0}px`">
15
+ <page-toggle-transition v-show="!$route.meta.singlePage" :disabled="animate.disabled" :animate="animate.name" :direction="animate.direction">
16
+ <a-keep-alive :exclude-keys="excludeKeys" v-if="multiPage && cachePage" v-model="clearCaches">
17
+ <router-view v-if="!refreshing" ref="tabContent" :key="$route.fullPath" />
18
+ </a-keep-alive>
19
+ <router-view ref="tabContent" v-else-if="!refreshing" />
20
+ </page-toggle-transition>
21
+ <template v-for="page in single">
22
+ <single-page-view
23
+ v-show="page.meta.singlePage === $route.meta.singlePage"
24
+ :single-page-url="page.meta.singlePage"
25
+ :full-path="page.fullPath"
26
+ :key="page.meta.singlePage"
27
+ @load="onSinglePageLoad" />
28
+ </template>
29
+ </div>
30
+ </admin-layout>
31
+ </div>
32
+ </template>
33
+
34
+ <script>
35
+ import AdminLayout from '@vue2-client/layouts/AdminLayout'
36
+ import Contextmenu from '@vue2-client/components/menu/Contextmenu'
37
+ import PageToggleTransition from '@vue2-client/components/transition/PageToggleTransition'
38
+ import { mapState, mapMutations } from 'vuex'
39
+ import { getI18nKey } from '@vue2-client/utils/routerUtil'
40
+ import AKeepAlive from '@vue2-client/components/cache/AKeepAlive'
41
+ import TabsHead from '@vue2-client/layouts/tabs/TabsHead'
42
+ import SinglePageView from '../SinglePageView'
43
+
44
+ export default {
45
+ name: 'TabsView',
46
+ i18n: require('./i18n'),
47
+ components: { SinglePageView, TabsHead, PageToggleTransition, Contextmenu, AdminLayout, AKeepAlive },
48
+ data () {
49
+ return {
50
+ clearCaches: [],
51
+ pageList: [],
52
+ activePage: '',
53
+ menuVisible: false,
54
+ refreshing: false,
55
+ allSinglePages: [],
56
+ excludeKeys: []
57
+ }
58
+ },
59
+ computed: {
60
+ ...mapState('setting', ['multiPage', 'cachePage', 'animate', 'layout', 'pageWidth']),
61
+ ...mapState('account', ['single']),
62
+ menuItemList () {
63
+ return [
64
+ { key: '1', icon: 'vertical-right', text: this.$t('closeLeft') },
65
+ { key: '2', icon: 'vertical-left', text: this.$t('closeRight') },
66
+ { key: '3', icon: 'close', text: this.$t('closeOthers') },
67
+ { key: '4', icon: 'sync', text: this.$t('refresh') }
68
+ ]
69
+ },
70
+ tabsOffset () {
71
+ return this.multiPage ? 24 : 0
72
+ }
73
+ },
74
+ created () {
75
+ this.loadCacheConfig(this.$router?.options?.routes)
76
+ this.loadCachedTabs()
77
+ // 解决单页面为首页时首次登录不加载问题
78
+ if (this.$route.meta.singlePage && this.single.length === 0) {
79
+ this.allSinglePages.forEach(item => {
80
+ if (this.$route.fullPath.includes(item.fullPath)) {
81
+ this.setSingle(item)
82
+ }
83
+ })
84
+ }
85
+ const route = this.$route
86
+ if (this.pageList.findIndex(item => item.path === route.fullPath) === -1) {
87
+ this.pageList.push(this.createPage(route))
88
+ }
89
+ this.activePage = route.fullPath
90
+ if (this.multiPage) {
91
+ this.$nextTick(() => {
92
+ this.setCachedKey(route)
93
+ })
94
+ this.addListener()
95
+ }
96
+ },
97
+ mounted () {
98
+ this.correctPageMinHeight(-this.tabsOffset)
99
+ },
100
+ beforeDestroy () {
101
+ this.removeListener()
102
+ this.correctPageMinHeight(this.tabsOffset)
103
+ },
104
+ watch: {
105
+ '$router.options.routes': function (val) {
106
+ this.excludeKeys = []
107
+ this.loadCacheConfig(val)
108
+ },
109
+ $route: function (newRoute) {
110
+ this.activePage = newRoute.fullPath
111
+ const page = this.pageList.find(item => item.path === newRoute.fullPath)
112
+ if (!this.multiPage) {
113
+ this.pageList = [this.createPage(newRoute)]
114
+ } else if (page) {
115
+ page.fullPath = newRoute.fullPath
116
+ } else if (!page) {
117
+ this.pageList.push(this.createPage(newRoute))
118
+ }
119
+ if (this.multiPage) {
120
+ this.$nextTick(() => {
121
+ this.setCachedKey(newRoute)
122
+ })
123
+ }
124
+ },
125
+ multiPage: function (newVal) {
126
+ if (!newVal) {
127
+ this.pageList = [this.createPage(this.$route)]
128
+ this.removeListener()
129
+ } else {
130
+ this.addListener()
131
+ }
132
+ },
133
+ tabsOffset (newVal, oldVal) {
134
+ this.correctPageMinHeight(oldVal - newVal)
135
+ }
136
+ },
137
+ methods: {
138
+ changePage (key) {
139
+ this.activePage = key
140
+ const page = this.pageList.find(item => item.path === key)
141
+ this.$router.push(page.fullPath)
142
+ },
143
+ remove (key, next) {
144
+ if (this.pageList.length === 1) {
145
+ return this.$message.warning(this.$t('warn'))
146
+ }
147
+ this.setSingle({ path: key, delete: true })
148
+ // 清除缓存
149
+ let index = this.pageList.findIndex(item => item.path === key)
150
+ this.clearCaches = this.pageList.splice(index, 1).map(page => page.cachedKey)
151
+ if (next) {
152
+ this.$router.push(next)
153
+ } else if (key === this.activePage) {
154
+ index = index >= this.pageList.length ? this.pageList.length - 1 : index
155
+ this.activePage = this.pageList[index].path
156
+ this.$router.push(this.activePage)
157
+ }
158
+ },
159
+ refresh (key, page) {
160
+ page = page || this.pageList.find(item => item.path === key)
161
+ page.loading = true
162
+ // 单页面刷新
163
+ const singlePage = this.allSinglePages.find(item => item.fullPath === key)
164
+ if (singlePage) {
165
+ window.frames[singlePage.fullPath].location.reload()
166
+ return
167
+ }
168
+ this.clearCache(page)
169
+ if (key === this.activePage) {
170
+ // eslint-disable-next-line no-return-assign
171
+ this.reloadContent(() => page.loading = false)
172
+ } else {
173
+ // 其实刷新很快,加这个延迟纯粹为了 loading 状态多展示一会儿,让用户感知刷新这一过程
174
+ // eslint-disable-next-line no-return-assign
175
+ setTimeout(() => page.loading = false, 500)
176
+ }
177
+ },
178
+ onSinglePageLoad (fullPath) {
179
+ const page = this.pageList.find(item => item.fullPath === fullPath)
180
+ page.loading = false
181
+ },
182
+ onContextmenu (pageKey, e) {
183
+ if (pageKey) {
184
+ e.preventDefault()
185
+ e.meta = pageKey
186
+ this.menuVisible = true
187
+ }
188
+ },
189
+ onMenuSelect (key, target, pageKey) {
190
+ switch (key) {
191
+ case '1': this.closeLeft(pageKey); break
192
+ case '2': this.closeRight(pageKey); break
193
+ case '3': this.closeOthers(pageKey); break
194
+ case '4': this.refresh(pageKey); break
195
+ default: break
196
+ }
197
+ },
198
+ closeOthers (pageKey) {
199
+ // 清除缓存
200
+ const clearPages = this.pageList.filter(item => item.path !== pageKey && !item.unclose)
201
+ this.clearCaches = clearPages.map(item => item.cachedKey)
202
+ this.pageList = this.pageList.filter(item => !clearPages.includes(item))
203
+ // 判断跳转
204
+ if (this.activePage !== pageKey) {
205
+ this.activePage = pageKey
206
+ this.$router.push(this.activePage)
207
+ }
208
+ },
209
+ closeLeft (pageKey) {
210
+ const index = this.pageList.findIndex(item => item.path === pageKey)
211
+ // 清除缓存
212
+ const clearPages = this.pageList.filter((item, i) => i < index && !item.unclose)
213
+ this.clearCaches = clearPages.map(item => item.cachedKey)
214
+ this.pageList = this.pageList.filter(item => !clearPages.includes(item))
215
+ // 判断跳转
216
+ if (!this.pageList.find(item => item.path === this.activePage)) {
217
+ this.activePage = pageKey
218
+ this.$router.push(this.activePage)
219
+ }
220
+ },
221
+ closeRight (pageKey) {
222
+ // 清除缓存
223
+ const index = this.pageList.findIndex(item => item.path === pageKey)
224
+ const clearPages = this.pageList.filter((item, i) => i > index && !item.unclose)
225
+ this.clearCaches = clearPages.map(item => item.cachedKey)
226
+ this.pageList = this.pageList.filter(item => !clearPages.includes(item))
227
+ // 判断跳转
228
+ if (!this.pageList.find(item => item.path === this.activePage)) {
229
+ this.activePage = pageKey
230
+ this.$router.push(this.activePage)
231
+ }
232
+ },
233
+ clearCache (page) {
234
+ page._init_ = false
235
+ this.clearCaches = [page.cachedKey]
236
+ },
237
+ reloadContent (onLoaded) {
238
+ this.refreshing = true
239
+ setTimeout(() => {
240
+ this.refreshing = false
241
+ this.$nextTick(() => {
242
+ this.setCachedKey(this.$route)
243
+ if (typeof onLoaded === 'function') {
244
+ onLoaded.apply(this, [])
245
+ }
246
+ })
247
+ }, 200)
248
+ },
249
+ pageName (page) {
250
+ return this.$t(getI18nKey(page.keyPath))
251
+ },
252
+ /**
253
+ * 添加监听器
254
+ */
255
+ addListener () {
256
+ window.addEventListener('page:close', this.closePageListener)
257
+ window.addEventListener('page:refresh', this.refreshPageListener)
258
+ window.addEventListener('unload', this.unloadListener)
259
+ },
260
+ /**
261
+ * 移出监听器
262
+ */
263
+ removeListener () {
264
+ window.removeEventListener('page:close', this.closePageListener)
265
+ window.removeEventListener('page:refresh', this.refreshPageListener)
266
+ window.removeEventListener('unload', this.unloadListener)
267
+ },
268
+ /**
269
+ * 页签关闭事件监听
270
+ * @param event 页签关闭事件
271
+ */
272
+ closePageListener (event) {
273
+ const { closeRoute, nextRoute } = event.detail
274
+ const closePath = typeof closeRoute === 'string' ? closeRoute : closeRoute.path
275
+ const path = closePath && closePath.split('?')[0]
276
+ this.remove(path, nextRoute)
277
+ },
278
+ /**
279
+ * 页面刷新事件监听
280
+ * @param event 页签关闭事件
281
+ */
282
+ refreshPageListener (event) {
283
+ const { pageKey } = event.detail
284
+ const path = pageKey && pageKey.split('?')[0]
285
+ this.refresh(path)
286
+ },
287
+ /**
288
+ * 页面 unload 事件监听器,添加页签到 session 缓存,用于刷新时保留页签
289
+ */
290
+ unloadListener () {
291
+ const tabs = this.pageList.map(item => ({ ...item, _init_: false }))
292
+ sessionStorage.setItem(process.env.VUE_APP_TBAS_KEY, JSON.stringify(tabs))
293
+ },
294
+ createPage (route) {
295
+ return {
296
+ keyPath: route.matched[route.matched.length - 1].path,
297
+ fullPath: route.fullPath,
298
+ loading: false,
299
+ path: route.fullPath,
300
+ title: route.meta && route.meta.page && route.meta.page.title,
301
+ unclose: route.meta && route.meta.page && (route.meta.page.closable === false)
302
+ }
303
+ },
304
+ /**
305
+ * 设置页面缓存的key
306
+ * @param route 页面对应的路由
307
+ */
308
+ setCachedKey (route) {
309
+ const page = this.pageList.find(item => item.path === route.path)
310
+ page.unclose = route.meta && route.meta.page && (route.meta.page.closable === false)
311
+ if (!page._init_) {
312
+ const vnode = this.$refs.tabContent.$vnode
313
+ page.cachedKey = vnode.key + vnode.componentOptions.Ctor.cid
314
+ page._init_ = true
315
+ }
316
+ },
317
+ /**
318
+ * 加载缓存的 tabs
319
+ */
320
+ loadCachedTabs () {
321
+ const cachedTabsStr = sessionStorage.getItem(process.env.VUE_APP_TBAS_KEY)
322
+ if (cachedTabsStr) {
323
+ try {
324
+ // 加载缓存的单页面
325
+ const allCachedPath = JSON.parse(cachedTabsStr).map(str => { return str.fullPath })
326
+ this.allSinglePages.forEach(item => {
327
+ if (allCachedPath.includes(item.fullPath)) {
328
+ // 如果缓存中有单页面 加载到 state.single
329
+ this.setSingle(item)
330
+ }
331
+ })
332
+ const cachedTabs = JSON.parse(cachedTabsStr)
333
+ if (cachedTabs.length > 0) {
334
+ this.pageList = cachedTabs
335
+ }
336
+ } catch (e) {
337
+ console.warn('failed to load cached tabs, got exception:', e)
338
+ } finally {
339
+ sessionStorage.removeItem(process.env.VUE_APP_TBAS_KEY)
340
+ }
341
+ }
342
+ },
343
+ loadCacheConfig (routes, pCache = true) {
344
+ routes.forEach(item => {
345
+ const cacheAble = item.meta?.page?.cacheAble ?? pCache ?? true
346
+ if (item.meta && item.meta.singlePage) {
347
+ // 找到所有单页面添加到 allSinglePages 中
348
+ this.allSinglePages.push(item)
349
+ }
350
+ if (!cacheAble) {
351
+ this.excludeKeys.push(new RegExp(`${item.path.replace(/:[^/]*/g, '[^/]*')}(\\?.*)?\\d*$`))
352
+ }
353
+ if (item.children) {
354
+ this.loadCacheConfig(item.children, cacheAble)
355
+ }
356
+ })
357
+ },
358
+ ...mapMutations('setting', ['correctPageMinHeight']),
359
+ ...mapMutations('account', ['setSingle'])
360
+ }
361
+ }
362
+ </script>
363
+
364
+ <style lang="less">
365
+ #TabsView {
366
+ .tabs-view {
367
+ margin: -16px auto 8px;
368
+ &.head.fixed {
369
+ max-width: 100%;
370
+ }
371
+ }
372
+ .tabs-view-content {
373
+ position: relative;
374
+ &.head.fixed {
375
+ width: 100%;
376
+ margin: 0 auto;
377
+ }
378
+ > div > div > .ant-card:first-of-type > .ant-card-body {
379
+ max-height: calc(100vh - 64px - 48px - 24px);
380
+ overflow-y: auto;
381
+ &::-webkit-scrollbar {
382
+ display: none;
383
+ }
384
+ }
385
+ }
386
+ }
387
+ </style>