cloud-web-corejs 1.1.0-dev.10 → 1.1.0-dev.13

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 (34) hide show
  1. package/package.json +1 -1
  2. package/src/components/VabUpload/view.vue +25 -25
  3. package/src/components/excelExport/exportColumnMemory.js +118 -0
  4. package/src/components/excelExport/exportFieldDialog.vue +50 -38
  5. package/src/components/excelExport/index.js +30 -13
  6. package/src/components/excelExport/mixins.js +390 -64
  7. package/src/components/excelImport/mixins.js +898 -850
  8. package/src/components/mobile/wf/addTaskUserdialog.vue +100 -100
  9. package/src/components/mobile/wf/content.vue +5 -5
  10. package/src/components/mobile/wf/deleteTaskUserDialog.vue +73 -73
  11. package/src/components/mobile/wf/selectUserDialog.vue +8 -12
  12. package/src/components/mobile/wf/setCandidateDialog.vue +69 -69
  13. package/src/components/mobile/wf/urgingDialog.vue +75 -75
  14. package/src/components/table/index.js +14 -1
  15. package/src/components/table/vxeFilter/mixin.js +28 -18
  16. package/src/components/xform/docs/2026-07 table/344/270/216excelExport/344/277/256/345/244/215/345/217/212/345/257/274/345/207/272/344/274/230/345/214/226.md" +64 -57
  17. package/src/components/xform/docs/2026-09 /346/235/241/344/273/266/345/257/274/345/207/272/345/244/247/346/225/260/346/215/256/351/207/217/345/264/251/346/272/203/346/216/222/346/237/245.md" +389 -0
  18. package/src/components/xform/form-designer/form-widget/container-widget/detail-h5-widget.vue +243 -243
  19. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-pane-widget.vue +228 -228
  20. package/src/components/xform/form-designer/form-widget/container-widget/h5-card-widget.vue +165 -165
  21. package/src/components/xform/form-designer/form-widget/dialog/importDialogMixin.js +61 -2
  22. package/src/components/xform/form-designer/form-widget/field-widget/select-export-item-button-widget.vue +3 -0
  23. package/src/components/xform/form-designer/form-widget/field-widget/singleUpload-widget.vue +145 -145
  24. package/src/components/xform/form-render/container-item/data-table-item.vue +350 -347
  25. package/src/components/xform/form-render/container-item/data-table-mixin.js +240 -37
  26. package/src/components/xform/form-render/container-item/detail-h5-item.vue +1 -1
  27. package/src/components/xform/form-render/container-item/list-h5-item.vue +1 -1
  28. package/src/components/xform/styles/h5.scss +483 -459
  29. package/src/components/xform/utils/dynamicSchemaUtil.js +385 -361
  30. package/src/layout/components/TagsView/index.vue +325 -323
  31. package/src/store/modules/tagsView.js +241 -217
  32. package/src/utils/importLimit.js +72 -0
  33. package/src/utils/pdfUtil.js +6 -1
  34. package/src/utils/request.js +17 -0
@@ -1,323 +1,325 @@
1
- <template>
2
- <div id="tags-view-container" class="navbar-tag">
3
- <div @click="$baseEventBus.$emit('triggerMenu')" class="telescopMenuIcon"><i class="iconfont" :class="isMenu?'icon-shouqi':'icon-shouqi-copy'"></i></div>
4
- <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
5
- <router-link
6
- v-for="tag in visitedViews"
7
- ref="tag"
8
- :key="viewKey(tag)"
9
- :class="isActive(tag)?'active':''"
10
- :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
11
- tag="span"
12
- class="tags-view-item"
13
- @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
14
- @contextmenu.prevent.native="openMenu(tag,$event)"
15
- >
16
- <i class="el-icon-s-home" v-if="tag.name =='home'"></i>
17
- {{ getMenuName(tag) }}
18
-
19
- <span v-if="!!tag.meta.user_affix" class="el-icon-close is-disabled"/>
20
- <span v-else-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)"/>
21
- </router-link>
22
- </scroll-pane>
23
- <div class="tags-operBox">
24
- <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('左移')" placement="bottom">
25
- <i class="el-icon-arrow-left" layadmin-event="leftPage"
26
- one-link-mark="yes" @click="$refs.scrollPane.handleScrollLeft()"/>
27
- </el-tooltip>
28
- <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('右移')" placement="bottom" l>
29
- <i class="el-icon-arrow-right" ayadmin-event="rightPage"
30
- one-link-mark="yes" @click="$refs.scrollPane.handleScrollRight()"/>
31
- </el-tooltip>
32
- <el-dropdown >
33
- <span class="el-dropdown-link" style="padding-right:10px;padding-left:4px;">
34
- <i class="el-icon-more el-icon--right"></i>
35
- </span>
36
- <el-dropdown-menu slot="dropdown">
37
- <el-dropdown-item @click.native="refreshSelectedTag($route)" :disabled="getIsLock()">
38
- <i class="el-icon-refresh"/><span>{{ $t1('刷新') }}</span>
39
- </el-dropdown-item>
40
- <el-dropdown-item @click.native="closeAllTags($route)">
41
- <i class="el-icon-close"/><span>{{ $t1('全部关闭') }}</span>
42
- </el-dropdown-item>
43
- </el-dropdown-menu>
44
- </el-dropdown>
45
- <!-- <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('刷新')" placement="bottom">
46
- <i class="el-icon-refresh" @click="refreshSelectedTag($route)"/>
47
- </el-tooltip>
48
- <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('全部关闭')" placement="bottom">
49
- <i class="el-icon-close" @click="closeAllTags(selectedTag)"/>
50
- </el-tooltip> -->
51
- </div>
52
- <!-- <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
53
- <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
54
- <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
55
- <li @click="closeOthersTags">Close Others</li>
56
- <li @click="closeAllTags(selectedTag)">Close All</li>
57
- </ul> -->
58
- </div>
59
- </template>
60
-
61
- <script>
62
- import ScrollPane from './ScrollPane'
63
- import path from 'path'
64
- import { viewKey, isRepeatable } from '@base/utils/repeatOpen'
65
-
66
- export default {
67
- components: {ScrollPane},
68
- props: {
69
- isMenu: {
70
- type: Boolean
71
- }
72
- },
73
- data() {
74
- return {
75
- visible: false,
76
- top: 0,
77
- left: 0,
78
- selectedTag: {},
79
- affixTags: []
80
- }
81
- },
82
- computed: {
83
- visitedViews() {
84
- return this.$store.state.tagsView.visitedViews
85
- },
86
- routes() {
87
- return this.$store.state.permission.routes
88
- }
89
- },
90
- watch: {
91
- $route() {
92
- this.addTags()
93
- this.moveToCurrentTag()
94
- },
95
- visible(value) {
96
- if (value) {
97
- document.body.addEventListener('click', this.closeMenu)
98
- } else {
99
- document.body.removeEventListener('click', this.closeMenu)
100
- }
101
- }
102
- },
103
- mounted() {
104
- this.initTags()
105
- this.addTags()
106
- },
107
- methods: {
108
- getMenuName(item) {
109
- let locale = this.$i18n?.locale;
110
- let zhTitle = item.meta?.title || "";
111
- let enTitle = item.meta?.enTitle || '';
112
- let title;
113
- if (locale == "en") {
114
- title = enTitle || zhTitle;
115
- } else {
116
- title = zhTitle
117
- }
118
- if (!enTitle || locale !== "en") {
119
- title = zhTitle
120
- }
121
- if (this.$t1) {
122
- title = this.$t1(title)
123
- }
124
- if (item.repeatIndex > 1) {
125
- title = `${title} (${item.repeatIndex})`
126
- }
127
- return title;
128
- },
129
- viewKey(view) {
130
- return viewKey(view)
131
- },
132
- isActive(route) {
133
- return viewKey(route) === viewKey(this.$route)
134
- },
135
- isAffix(tag) {
136
- return tag.meta && tag.meta.affix
137
- },
138
- filterAffixTags(routes, basePath = '/') {
139
- let tags = []
140
- routes.forEach(route => {
141
- if (route.meta && route.meta.affix) {
142
- const tagPath = path.resolve(basePath, route.path)
143
- tags.push({
144
- fullPath: tagPath,
145
- path: tagPath,
146
- name: route.name,
147
- meta: {...route.meta}
148
- })
149
- }
150
- if (route.children) {
151
- const tempTags = this.filterAffixTags(route.children, route.path)
152
- if (tempTags.length >= 1) {
153
- tags = [...tags, ...tempTags]
154
- }
155
- }
156
- })
157
- return tags
158
- },
159
- initTags() {
160
- const affixTags = this.affixTags = this.filterAffixTags(this.routes)
161
- for (const tag of affixTags) {
162
- // Must have tag name
163
- if (tag.name) {
164
- this.$store.dispatch('tagsView/addVisitedView', tag)
165
- }
166
- }
167
- },
168
- addTags() {
169
- const {name} = this.$route
170
- if (name) {
171
- this.$store.dispatch('tagsView/addView', this.$route)
172
- }
173
- return false
174
- },
175
- moveToCurrentTag() {
176
- const tags = this.$refs.tag
177
- this.$nextTick(() => {
178
- const routeIsRepeat = isRepeatable(this.$route)
179
- for (const tag of tags) {
180
- const matched = routeIsRepeat
181
- ? tag.to.fullPath === this.$route.fullPath
182
- : tag.to.path === this.$route.path
183
- if (matched) {
184
- this.$refs.scrollPane.moveToTarget(tag)
185
- // when query is different then update
186
- if (tag.to.fullPath !== this.$route.fullPath) {
187
- this.$store.dispatch('tagsView/updateVisitedView', this.$route)
188
- }
189
- break
190
- }
191
- }
192
- })
193
- },
194
- refreshSelectedTag(view) {
195
- this.$baseEventBus.$emit("reflushRouteView", view);
196
- /* if(this.$route.name=="outLink"){
197
- let a = this.$baseEventBus.$emit("getAppMain");
198
- let t = this.$parent.$refs["appMain"].$refs["ref_"+this.$route.path][0];
199
- t.$baseReload();
200
- }else{
201
- this.$store.dispatch('tagsView/delCachedView', view).then(() => {
202
- const { fullPath } = view
203
- this.$nextTick(() => {
204
- this.$router.replace({
205
- path: '/redirect' + fullPath
206
- })
207
- })
208
- })
209
- } */
210
- },
211
- closeSelectedTag(view) {
212
- if(view.meta.user_affix)return
213
- this.$store.dispatch('tagsView/delView', view).then(({visitedViews}) => {
214
- if (this.isActive(view)) {
215
- this.toLastView(visitedViews, view)
216
- }
217
- })
218
- },
219
- closeOthersTags() {
220
- this.$router.push(this.selectedTag)
221
- this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
222
- this.moveToCurrentTag()
223
- })
224
- },
225
- closeAllTags(view) {
226
- this.$baseConfirm(this.$t1('您确定要全部关闭吗?')).then(() => {
227
- this.$store.dispatch('tagsView/delAllViews').then(({visitedViews}) => {
228
- if (this.affixTags.some(tag => tag.path === view.path)) {
229
- return
230
- }
231
- this.toLastView(visitedViews, view)
232
- })
233
- })
234
- },
235
- toLastView(visitedViews, view) {
236
- const latestView = visitedViews.slice(-1)[0]
237
- if (latestView) {
238
- this.$router.push(latestView.fullPath)
239
- } else {
240
- // now the default is to redirect to the home page if there is no tags-view,
241
- // you can adjust it according to your needs.
242
- if (view.name === 'Dashboard') {
243
- // to reload home page
244
- this.$router.replace({path: '/redirect' + view.fullPath})
245
- } else {
246
- this.$router.push('/')
247
- }
248
- }
249
- },
250
- openMenu(tag, e) {
251
- const menuMinWidth = 105
252
- const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
253
- const offsetWidth = this.$el.offsetWidth // container width
254
- const maxLeft = offsetWidth - menuMinWidth // left boundary
255
- const left = e.clientX - offsetLeft + 15 // 15: margin right
256
-
257
- if (left > maxLeft) {
258
- this.left = maxLeft
259
- } else {
260
- this.left = left
261
- }
262
-
263
- this.top = e.clientY
264
- this.visible = true
265
- this.selectedTag = tag
266
- },
267
- closeMenu() {
268
- this.visible = false
269
- },
270
- handleScroll() {
271
- this.closeMenu()
272
- },
273
- getIsLock() {
274
- let path = this.$route.path;
275
- let visitedViews = this.$store.state.tagsView.visitedViews
276
- let currentItem = visitedViews.find(item => item.path == path)
277
- return !!currentItem?.meta?.user_affix;
278
- },
279
- }
280
- }
281
- </script>
282
-
283
- <style scoped lang="scss">
284
- @import '~@/styles/variables.scss';
285
-
286
- .navbar-tag .tags-view-item.active {
287
- background: $baseColor !important;
288
- }
289
- </style>
290
- <style lang="scss">
291
- //reset element css of el-icon-close
292
- span.el-icon-close.is-disabled{
293
- cursor: not-allowed;
294
- }
295
- .tags-view-wrapper {
296
- .tags-view-item {
297
- .el-icon-close {
298
- width: 14px;
299
- height: 14px;
300
- vertical-align: text-bottom;
301
- line-height: 12px;
302
- border-radius: 50%;
303
- text-align: center;
304
- transition: all .3s cubic-bezier(.645, .045, .355, 1);
305
- transform-origin: 100% 50%;
306
- display: none;
307
- position: absolute;
308
- right: 12px;
309
- top: 8px;
310
-
311
- &:before {
312
- transform: scale(.84);
313
- display: inline-block;
314
- vertical-align: -1.8px;
315
- }
316
- }
317
-
318
- &:hover .el-icon-close {
319
- display: block;
320
- }
321
- }
322
- }
323
- </style>
1
+ <template>
2
+ <div id="tags-view-container" class="navbar-tag">
3
+ <div @click="$baseEventBus.$emit('triggerMenu')" class="telescopMenuIcon"><i class="iconfont" :class="isMenu?'icon-shouqi':'icon-shouqi-copy'"></i></div>
4
+ <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
5
+ <router-link
6
+ v-for="tag in visitedViews"
7
+ ref="tag"
8
+ :key="viewKey(tag)"
9
+ :class="isActive(tag)?'active':''"
10
+ :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
11
+ tag="span"
12
+ class="tags-view-item"
13
+ @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
14
+ @contextmenu.prevent.native="openMenu(tag,$event)"
15
+ >
16
+ <i class="el-icon-s-home" v-if="tag.name =='home'"></i>
17
+ {{ getMenuName(tag) }}
18
+
19
+ <span v-if="!!tag.meta.user_affix" class="el-icon-close is-disabled"/>
20
+ <span v-else-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)"/>
21
+ </router-link>
22
+ </scroll-pane>
23
+ <div class="tags-operBox">
24
+ <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('左移')" placement="bottom">
25
+ <i class="el-icon-arrow-left" layadmin-event="leftPage"
26
+ one-link-mark="yes" @click="$refs.scrollPane.handleScrollLeft()"/>
27
+ </el-tooltip>
28
+ <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('右移')" placement="bottom" l>
29
+ <i class="el-icon-arrow-right" ayadmin-event="rightPage"
30
+ one-link-mark="yes" @click="$refs.scrollPane.handleScrollRight()"/>
31
+ </el-tooltip>
32
+ <el-dropdown >
33
+ <span class="el-dropdown-link" style="padding-right:10px;padding-left:4px;">
34
+ <i class="el-icon-more el-icon--right"></i>
35
+ </span>
36
+ <el-dropdown-menu slot="dropdown">
37
+ <el-dropdown-item @click.native="refreshSelectedTag($route)" :disabled="getIsLock()">
38
+ <i class="el-icon-refresh"/><span>{{ $t1('刷新') }}</span>
39
+ </el-dropdown-item>
40
+ <el-dropdown-item @click.native="closeAllTags($route)">
41
+ <i class="el-icon-close"/><span>{{ $t1('全部关闭') }}</span>
42
+ </el-dropdown-item>
43
+ </el-dropdown-menu>
44
+ </el-dropdown>
45
+ <!-- <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('刷新')" placement="bottom">
46
+ <i class="el-icon-refresh" @click="refreshSelectedTag($route)"/>
47
+ </el-tooltip>
48
+ <el-tooltip :enterable="false" class="item" effect="dark" :content="$t1('全部关闭')" placement="bottom">
49
+ <i class="el-icon-close" @click="closeAllTags(selectedTag)"/>
50
+ </el-tooltip> -->
51
+ </div>
52
+ <!-- <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
53
+ <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
54
+ <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
55
+ <li @click="closeOthersTags">Close Others</li>
56
+ <li @click="closeAllTags(selectedTag)">Close All</li>
57
+ </ul> -->
58
+ </div>
59
+ </template>
60
+
61
+ <script>
62
+ import ScrollPane from './ScrollPane'
63
+ import path from 'path'
64
+ import { viewKey, isRepeatable } from '@base/utils/repeatOpen'
65
+
66
+ export default {
67
+ components: {ScrollPane},
68
+ props: {
69
+ isMenu: {
70
+ type: Boolean
71
+ }
72
+ },
73
+ data() {
74
+ return {
75
+ visible: false,
76
+ top: 0,
77
+ left: 0,
78
+ selectedTag: {},
79
+ affixTags: []
80
+ }
81
+ },
82
+ computed: {
83
+ visitedViews() {
84
+ return this.$store.state.tagsView.visitedViews
85
+ },
86
+ routes() {
87
+ return this.$store.state.permission.routes
88
+ }
89
+ },
90
+ watch: {
91
+ $route() {
92
+ this.addTags()
93
+ this.moveToCurrentTag()
94
+ },
95
+ visible(value) {
96
+ if (value) {
97
+ document.body.addEventListener('click', this.closeMenu)
98
+ } else {
99
+ document.body.removeEventListener('click', this.closeMenu)
100
+ }
101
+ }
102
+ },
103
+ mounted() {
104
+ this.initTags()
105
+ this.addTags()
106
+ },
107
+ methods: {
108
+ getMenuName(item) {
109
+ let locale = this.$i18n?.locale;
110
+ let zhTitle = item.meta?.title || "";
111
+ let enTitle = item.meta?.enTitle || '';
112
+ let title;
113
+ if (locale == "en") {
114
+ title = enTitle || zhTitle;
115
+ } else {
116
+ title = zhTitle
117
+ }
118
+ if (!enTitle || locale !== "en") {
119
+ title = zhTitle
120
+ }
121
+ if (this.$t1) {
122
+ title = this.$t1(title)
123
+ }
124
+ if (item.repeatIndex > 1) {
125
+ title = `${title} (${item.repeatIndex})`
126
+ }
127
+ return title;
128
+ },
129
+ viewKey(view) {
130
+ return viewKey(view)
131
+ },
132
+ isActive(route) {
133
+ return viewKey(route) === viewKey(this.$route)
134
+ },
135
+ isAffix(tag) {
136
+ return tag.meta && tag.meta.affix
137
+ },
138
+ filterAffixTags(routes, basePath = '/') {
139
+ let tags = []
140
+ routes.forEach(route => {
141
+ if (route.meta && route.meta.affix) {
142
+ const tagPath = path.resolve(basePath, route.path)
143
+ tags.push({
144
+ fullPath: tagPath,
145
+ path: tagPath,
146
+ name: route.name,
147
+ meta: {...route.meta}
148
+ })
149
+ }
150
+ if (route.children) {
151
+ const tempTags = this.filterAffixTags(route.children, route.path)
152
+ if (tempTags.length >= 1) {
153
+ tags = [...tags, ...tempTags]
154
+ }
155
+ }
156
+ })
157
+ return tags
158
+ },
159
+ initTags() {
160
+ const affixTags = this.affixTags = this.filterAffixTags(this.routes)
161
+ for (const tag of affixTags) {
162
+ // Must have tag name
163
+ if (tag.name) {
164
+ this.$store.dispatch('tagsView/addVisitedView', tag)
165
+ }
166
+ }
167
+ },
168
+ addTags() {
169
+ const {name} = this.$route
170
+ if (name) {
171
+ this.$store.dispatch('tagsView/addView', this.$route)
172
+ }
173
+ return false
174
+ },
175
+ moveToCurrentTag() {
176
+ const tags = this.$refs.tag
177
+ this.$nextTick(() => {
178
+ const routeIsRepeat = isRepeatable(this.$route)
179
+ for (const tag of tags) {
180
+ const matched = routeIsRepeat
181
+ ? tag.to.fullPath === this.$route.fullPath
182
+ : tag.to.path === this.$route.path
183
+ if (matched) {
184
+ this.$refs.scrollPane.moveToTarget(tag)
185
+ // when query is different then update
186
+ if (tag.to.fullPath !== this.$route.fullPath) {
187
+ this.$store.dispatch('tagsView/updateVisitedView', this.$route)
188
+ }
189
+ break
190
+ }
191
+ }
192
+ })
193
+ },
194
+ refreshSelectedTag(view) {
195
+ this.$baseEventBus.$emit("reflushRouteView", view);
196
+ /* if(this.$route.name=="outLink"){
197
+ let a = this.$baseEventBus.$emit("getAppMain");
198
+ let t = this.$parent.$refs["appMain"].$refs["ref_"+this.$route.path][0];
199
+ t.$baseReload();
200
+ }else{
201
+ this.$store.dispatch('tagsView/delCachedView', view).then(() => {
202
+ const { fullPath } = view
203
+ this.$nextTick(() => {
204
+ this.$router.replace({
205
+ path: '/redirect' + fullPath
206
+ })
207
+ })
208
+ })
209
+ } */
210
+ },
211
+ closeSelectedTag(view) {
212
+ if(view.meta.user_affix)return
213
+ this.$store.dispatch('tagsView/delView', view).then(({visitedViews}) => {
214
+ if (this.isActive(view)) {
215
+ this.toLastView(visitedViews, view)
216
+ }
217
+ })
218
+ },
219
+ closeOthersTags() {
220
+ this.$router.push(this.selectedTag)
221
+ this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
222
+ this.moveToCurrentTag()
223
+ })
224
+ },
225
+ closeAllTags(view) {
226
+ this.$baseConfirm(this.$t1('您确定要全部关闭吗?')).then(() => {
227
+ this.$store.dispatch('tagsView/delAllViews').then(({visitedViews}) => {
228
+ if (this.affixTags.some(tag => tag.path === view.path)) {
229
+ return
230
+ }
231
+ this.toLastView(visitedViews, view)
232
+ })
233
+ })
234
+ },
235
+ toLastView(visitedViews, view) {
236
+ const latestView = visitedViews.slice(-1)[0]
237
+ if (latestView) {
238
+ this.$router.push(latestView.fullPath)
239
+ } else {
240
+ // now the default is to redirect to the home page if there is no tags-view,
241
+ // you can adjust it according to your needs.
242
+ if (view.name === 'Dashboard') {
243
+ // to reload home page
244
+ this.$router.replace({path: '/redirect' + view.fullPath})
245
+ } else {
246
+ this.$router.push('/')
247
+ }
248
+ }
249
+ },
250
+ openMenu(tag, e) {
251
+ const menuMinWidth = 105
252
+ const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
253
+ const offsetWidth = this.$el.offsetWidth // container width
254
+ const maxLeft = offsetWidth - menuMinWidth // left boundary
255
+ const left = e.clientX - offsetLeft + 15 // 15: margin right
256
+
257
+ if (left > maxLeft) {
258
+ this.left = maxLeft
259
+ } else {
260
+ this.left = left
261
+ }
262
+
263
+ this.top = e.clientY
264
+ this.visible = true
265
+ this.selectedTag = tag
266
+ },
267
+ closeMenu() {
268
+ this.visible = false
269
+ },
270
+ handleScroll() {
271
+ this.closeMenu()
272
+ },
273
+ getIsLock() {
274
+ // 按 viewKey 而不是 path 定位:可重复打开时同一 path 有多个页签,
275
+ // path 找到的可能是另一个实例(锁的是 A,却把 B 的刷新按钮禁掉)
276
+ let key = viewKey(this.$route)
277
+ let visitedViews = this.$store.state.tagsView.visitedViews
278
+ let currentItem = visitedViews.find(item => viewKey(item) === key)
279
+ return !!currentItem?.meta?.user_affix;
280
+ },
281
+ }
282
+ }
283
+ </script>
284
+
285
+ <style scoped lang="scss">
286
+ @import '~@/styles/variables.scss';
287
+
288
+ .navbar-tag .tags-view-item.active {
289
+ background: $baseColor !important;
290
+ }
291
+ </style>
292
+ <style lang="scss">
293
+ //reset element css of el-icon-close
294
+ span.el-icon-close.is-disabled{
295
+ cursor: not-allowed;
296
+ }
297
+ .tags-view-wrapper {
298
+ .tags-view-item {
299
+ .el-icon-close {
300
+ width: 14px;
301
+ height: 14px;
302
+ vertical-align: text-bottom;
303
+ line-height: 12px;
304
+ border-radius: 50%;
305
+ text-align: center;
306
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
307
+ transform-origin: 100% 50%;
308
+ display: none;
309
+ position: absolute;
310
+ right: 12px;
311
+ top: 8px;
312
+
313
+ &:before {
314
+ transform: scale(.84);
315
+ display: inline-block;
316
+ vertical-align: -1.8px;
317
+ }
318
+ }
319
+
320
+ &:hover .el-icon-close {
321
+ display: block;
322
+ }
323
+ }
324
+ }
325
+ </style>