sh-view 2.0.4 → 2.0.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "基于vxe-table二次封装",
5
5
  "main": "packages/index.js",
6
6
  "scripts": {
@@ -37,7 +37,7 @@
37
37
  "vue-masonry": "^0.16.0",
38
38
  "vue-router": "^4.2.2",
39
39
  "vuex": "^4.1.0",
40
- "vxe-table": "^4.5.6",
40
+ "vxe-table": "^4.5.7",
41
41
  "vxe-table-plugin-export-pdf": "^3.0.4",
42
42
  "vxe-table-plugin-export-xlsx": "^3.0.5",
43
43
  "xe-clipboard": "^1.10.2",
@@ -0,0 +1,306 @@
1
+ <template>
2
+ <div class="sh-menu" :class="classes">
3
+ <div v-clickout="handleOut" class="sh-menu-inner">
4
+ <template v-for="(item, index) in options" :key="index">
5
+ <menuGroupContent :menu-item="item" />
6
+ </template>
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <script>
12
+ import menuGroupContent from './menu-group-content.vue'
13
+ export default {
14
+ name: 'ShMenu',
15
+ components: {
16
+ menuGroupContent
17
+ },
18
+ provide() {
19
+ return {
20
+ MenuInstance: this
21
+ }
22
+ },
23
+ props: {
24
+ modelValue: {
25
+ type: String
26
+ },
27
+ mode: {
28
+ type: String,
29
+ default: 'vertical' // horizontal
30
+ },
31
+ indent: {
32
+ type: Number,
33
+ default: 20
34
+ },
35
+ accordion: {
36
+ type: Boolean,
37
+ default: true
38
+ },
39
+ theme: {
40
+ type: Boolean
41
+ },
42
+ fix: {
43
+ type: Boolean
44
+ },
45
+ collapsed: {
46
+ type: Boolean
47
+ },
48
+ options: {
49
+ type: Array,
50
+ default() {
51
+ return []
52
+ }
53
+ },
54
+ labelField: {
55
+ type: String,
56
+ default: 'label'
57
+ },
58
+ labelFormat: {
59
+ type: Function
60
+ }
61
+ },
62
+ emits: ['update:modelValue', 'change', 'expand'],
63
+ data() {
64
+ return {
65
+ activeName: this.modelValue,
66
+ activeNames: [],
67
+ openedNames: []
68
+ }
69
+ },
70
+ computed: {
71
+ classes() {
72
+ return {
73
+ theme: this.theme,
74
+ fix: this.fix,
75
+ collapsed: this.collapsed,
76
+ [`${this.mode}`]: this.mode
77
+ }
78
+ }
79
+ },
80
+ watch: {
81
+ modelValue(to, from) {
82
+ this.resetMenu()
83
+ }
84
+ },
85
+ mounted() {
86
+ this.resetMenu()
87
+ },
88
+ methods: {
89
+ // 重新渲染菜单
90
+ resetMenu() {
91
+ this.activeName = this.modelValue
92
+ this.resetExpand(this.activeName, true)
93
+ },
94
+ resetExpand(menuName, mount) {
95
+ let activeNames = []
96
+ let parentTree = this.$vUtils.searchTree(this.options, item => item.name === menuName)
97
+ this.$vUtils.eachTree(parentTree, item => {
98
+ activeNames.push(item.name)
99
+ })
100
+ if (mount) {
101
+ this.activeNames = activeNames
102
+ if (this.collapsed) return
103
+ }
104
+ if (this.mode !== 'vertical') return
105
+ // 过滤掉所有子节点
106
+ let menuIndex = activeNames.findIndex(item => item === menuName)
107
+ let parentNames = activeNames.filter((item, itemIndex) => menuIndex >= itemIndex)
108
+ if (!this.accordion) parentNames = Array.from(new Set(this.openedNames.concat(parentNames)))
109
+ this.openedNames = parentNames
110
+ },
111
+ onMenuSelect(menu) {
112
+ this.$emit('update:modelValue', menu.name)
113
+ this.$emit('change', menu)
114
+ this.handleOut()
115
+ },
116
+ onMenuExpand(expand, menu) {
117
+ this.$emit('expand', expand, menu)
118
+ if (!expand) {
119
+ this.openedNames = this.openedNames.filter(name => name !== menu.name)
120
+ return
121
+ }
122
+ this.resetExpand(menu.name)
123
+ },
124
+ handleOut() {
125
+ if (!this.collapsed && this.mode === 'vertical') return
126
+ this.openedNames = []
127
+ }
128
+ }
129
+ }
130
+ </script>
131
+
132
+ <style lang="scss">
133
+ $textColor: var(--vxe-font-color);
134
+ $textActive: var(--vxe-primary-color);
135
+ $mainBgColor: var(--vxe-table-body-background-color);
136
+ $expandBgColor: var(--vxe-table-header-background-color);
137
+
138
+ $textDkColor: hsla(0, 0%, 100%, 0.6);
139
+ $textDkActive: #fff;
140
+ $mainDkBgColor: var(--vxe-primary-color);
141
+ $expandDkBgColor: var(--vxe-primary-darken-color);
142
+ .sh-menu {
143
+ position: relative;
144
+ background-color: $mainBgColor;
145
+ &.theme {
146
+ background-color: $mainDkBgColor;
147
+ .sh-menu-group {
148
+ &.is__expand {
149
+ background: $expandDkBgColor;
150
+ & > .sh-menu-item {
151
+ color: $textDkActive;
152
+ }
153
+ }
154
+ &.is__active {
155
+ & > .sh-menu-item {
156
+ color: $textDkActive;
157
+ }
158
+ }
159
+ & > .sh-menu-group-dropdown,
160
+ & > .sh-menu-group-dropright {
161
+ background-color: $mainDkBgColor;
162
+ }
163
+ }
164
+ .sh-menu-item {
165
+ color: $textDkColor;
166
+ &:hover {
167
+ color: $textDkActive;
168
+ background: var(--vxe-primary-lighten-color) !important;
169
+ }
170
+ &.sh-menu-item-active {
171
+ color: $textDkActive;
172
+ background: var(--vxe-primary-lighten-color);
173
+ &:after {
174
+ background: $textDkColor;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ &.fix {
180
+ position: fixed;
181
+ top: 0;
182
+ left: 0;
183
+ right: 0;
184
+ }
185
+ &.horizontal {
186
+ .sh-menu-inner {
187
+ display: flex;
188
+ align-items: center;
189
+ height: 100%;
190
+ }
191
+ .sh-menu-item {
192
+ height: 100%;
193
+ &.sh-menu-item-active {
194
+ &:after {
195
+ width: 100%;
196
+ height: 3px;
197
+ top: auto;
198
+ bottom: 0;
199
+ }
200
+ }
201
+ &.sh-menu-item-level {
202
+ .sh-menu-item-arrow {
203
+ transform: rotate(90deg);
204
+ transform-origin: center;
205
+ }
206
+ }
207
+ }
208
+ .sh-menu-group {
209
+ height: 100%;
210
+ &.is__expand {
211
+ & > .sh-menu-item-level {
212
+ .sh-menu-item-arrow {
213
+ transform: rotate(-90deg);
214
+ transform-origin: center;
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ &.collapsed {
221
+ .sh-menu-item.sh-menu-item-level {
222
+ flex-wrap: wrap;
223
+ text-align: center;
224
+ padding: 5px;
225
+ &.sh-menu-item-active {
226
+ &:after {
227
+ display: none;
228
+ }
229
+ }
230
+ .sh-menu-item-icon {
231
+ margin-right: 0;
232
+ margin-bottom: 3px;
233
+ flex: 1;
234
+ }
235
+ .sh-menu-item-title {
236
+ min-width: 100%;
237
+ }
238
+ }
239
+ }
240
+ .sh-menu-group {
241
+ position: relative;
242
+ &.is__expand {
243
+ background: $expandBgColor;
244
+ & > .sh-menu-item {
245
+ color: $textActive;
246
+ .sh-menu-item-arrow {
247
+ transform: rotate(90deg);
248
+ transform-origin: center;
249
+ }
250
+ }
251
+ }
252
+ &.is__active {
253
+ & > .sh-menu-item {
254
+ color: $textActive;
255
+ }
256
+ }
257
+ & > .sh-menu-group-dropdown,
258
+ & > .sh-menu-group-dropright {
259
+ position: fixed;
260
+ line-height: 1.5;
261
+ background-color: $mainBgColor;
262
+ box-shadow: var(--box-shadow);
263
+ overflow: auto;
264
+ z-index: 1000;
265
+ }
266
+ }
267
+ .sh-menu-item {
268
+ padding: 10px 12px;
269
+ display: flex;
270
+ align-items: center;
271
+ justify-content: flex-start;
272
+ cursor: pointer;
273
+ position: relative;
274
+ user-select: none;
275
+ color: $textColor;
276
+ text-align: left;
277
+ &:hover {
278
+ color: $textActive;
279
+ }
280
+ &.sh-menu-item-active {
281
+ color: $textActive;
282
+ background: var(--primary-weak-color);
283
+ &:after {
284
+ width: 3px;
285
+ content: '';
286
+ position: absolute;
287
+ top: 0;
288
+ right: 0;
289
+ height: 100%;
290
+ background: var(--vxe-primary-color);
291
+ }
292
+ }
293
+ .sh-menu-item-icon {
294
+ margin-right: 8px;
295
+ }
296
+ .sh-menu-item-title {
297
+ flex: 1;
298
+ white-space: nowrap;
299
+ }
300
+ .sh-menu-item-arrow {
301
+ margin-left: 5px;
302
+ transition: 0.1s all ease-in-out;
303
+ }
304
+ }
305
+ }
306
+ </style>
@@ -0,0 +1,122 @@
1
+ <template>
2
+ <div v-if="showChildren(menuItem)" class="sh-menu-group" :class="groupClass">
3
+ <menuItemContent ref="groupItem" :menu-item="menuItem" :menu-level="menuLevel" :arrow="isArrow" @click="onMenuExpand(!expand)" />
4
+ <div v-show="expand" ref="groupList" class="sh-menu-group-list" :class="groupListClass" :style="groupListStyle">
5
+ <template v-for="(item, index) in menuItem.children" :key="`sh-menu-${menuLevel}-${index}`">
6
+ <menuGroupContent :menu-item="item" :menu-level="menuNextLevel" />
7
+ </template>
8
+ </div>
9
+ </div>
10
+ <template v-else>
11
+ <menuItemContent :menu-item="menuItem" :menu-level="menuLevel" @click.stop="onMenuClick" />
12
+ </template>
13
+ </template>
14
+
15
+ <script>
16
+ import menuItemContent from './menu-item-content.vue'
17
+ export default {
18
+ name: 'MenuGroupContent',
19
+ components: {
20
+ menuItemContent
21
+ },
22
+ inject: {
23
+ MenuInstance: {
24
+ default: null
25
+ }
26
+ },
27
+ props: {
28
+ menuLevel: {
29
+ type: Number,
30
+ default: 0
31
+ },
32
+ menuItem: {
33
+ type: Object,
34
+ default() {
35
+ return {}
36
+ }
37
+ }
38
+ },
39
+ data() {
40
+ return {
41
+ expand: false,
42
+ groupListStyle: {}
43
+ }
44
+ },
45
+ computed: {
46
+ menuNextLevel() {
47
+ return this.menuLevel + 1
48
+ },
49
+ isArrow() {
50
+ return this.MenuInstance.collapsed ? !!this.menuLevel : true
51
+ },
52
+ groupClass() {
53
+ return {
54
+ is__level: !this.menuLevel,
55
+ is__active: this.MenuInstance.activeNames.includes(this.menuItem.name),
56
+ is__expand: this.expand
57
+ }
58
+ },
59
+ groupListClass() {
60
+ const { mode, collapsed } = this.MenuInstance
61
+ return {
62
+ 'sh-menu-group-dropdown': mode === 'horizontal',
63
+ 'sh-menu-group-dropright': mode === 'vertical' && collapsed
64
+ }
65
+ }
66
+ },
67
+ watch: {
68
+ 'MenuInstance.openedNames'(names) {
69
+ this.setMenuExpand()
70
+ }
71
+ },
72
+ mounted() {
73
+ this.setMenuExpand()
74
+ },
75
+ methods: {
76
+ setMenuExpand() {
77
+ let names = this.MenuInstance.openedNames
78
+ this.expand = names.includes(this.menuItem.name)
79
+ const { mode, collapsed } = this.MenuInstance
80
+ if (this.expand && this.$refs.groupItem && ((mode === 'vertical' && collapsed) || mode === 'horizontal')) {
81
+ this.$nextTick(() => {
82
+ const { left, right, top, bottom } = this.$refs.groupItem.$refs?.shMenuItem.getBoundingClientRect()
83
+ const { offsetHeight, offsetWidth } = this.$refs.groupList
84
+ const winWidth = window.innerWidth
85
+ const winHeight = window.innerHeight
86
+ if (mode === 'vertical') {
87
+ let groupStyle = { left: `${right}px` }
88
+ if (offsetHeight >= winHeight) {
89
+ groupStyle.top = '10px'
90
+ groupStyle.bottom = '10px'
91
+ } else if (top + offsetHeight >= winHeight) {
92
+ groupStyle.bottom = '10px'
93
+ } else {
94
+ groupStyle.top = `${top}px`
95
+ }
96
+ this.groupListStyle = groupStyle
97
+ } else {
98
+ let groupStyle = { top: `${this.menuLevel ? top : bottom}px` }
99
+ if (right + offsetWidth >= winWidth) {
100
+ groupStyle.right = '10px'
101
+ } else {
102
+ groupStyle.left = `${this.menuLevel ? right : left}px`
103
+ }
104
+ this.groupListStyle = groupStyle
105
+ }
106
+ })
107
+ }
108
+ },
109
+ showChildren(item) {
110
+ return item.children && item.children.length > 0
111
+ },
112
+ onMenuClick() {
113
+ this.MenuInstance.onMenuSelect(this.menuItem)
114
+ },
115
+ onMenuExpand(value) {
116
+ this.MenuInstance.onMenuExpand(value, this.menuItem)
117
+ }
118
+ }
119
+ }
120
+ </script>
121
+
122
+ <style scoped></style>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div ref="shMenuItem" class="sh-menu-item" :class="itemClass" :style="itemStyle">
3
+ <sh-icon v-if="iconType" class="sh-menu-item-icon" :type="iconType"></sh-icon>
4
+ <span class="sh-menu-item-title">{{ formatTitle(menuItem) }}</span>
5
+ <sh-icon v-if="arrow" class="sh-menu-item-arrow" type="ios-arrow-forward"></sh-icon>
6
+ </div>
7
+ </template>
8
+
9
+ <script>
10
+ export default {
11
+ name: 'MenuItemBox',
12
+ inject: {
13
+ MenuInstance: {
14
+ default: null
15
+ }
16
+ },
17
+ props: {
18
+ arrow: Boolean,
19
+ menuLevel: {
20
+ type: Number
21
+ },
22
+ menuItem: {
23
+ type: Object,
24
+ default() {
25
+ return {}
26
+ }
27
+ }
28
+ },
29
+ computed: {
30
+ defaultIcon() {
31
+ if (!this.menuLevel || this.menuLevel < 2) return 'md-folder'
32
+ else if (this.menuLevel === 2) return 'md-bookmark'
33
+ else return ''
34
+ },
35
+ iconType() {
36
+ return this.menuItem.meta?.icon || this.menuItem.icon || this.defaultIcon
37
+ },
38
+ itemClass() {
39
+ return {
40
+ 'sh-menu-item-level': !this.menuLevel,
41
+ 'sh-menu-item-active': this.MenuInstance.activeName === this.menuItem.name
42
+ }
43
+ },
44
+ itemStyle() {
45
+ let result = {}
46
+ const { mode, collapsed, indent } = this.MenuInstance
47
+ if (mode === 'vertical' && !collapsed && this.menuLevel) {
48
+ result.paddingLeft = `${indent * this.menuLevel}px`
49
+ }
50
+ return result
51
+ },
52
+ itemTitle() {
53
+ const { labelField, labelFormat } = this.MenuInstance
54
+ return labelFormat ? labelFormat(this.menuItem) : this.$vUtils.get(this.menuItem, labelField)
55
+ }
56
+ },
57
+ methods: {}
58
+ }
59
+ </script>
60
+
61
+ <style scoped></style>