shijiplus-web-plugin 0.1.10 → 0.1.12
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 +8 -4
- package/src/App.vue +3 -1
- package/src/components/plus-comp/index.js +15 -0
- package/src/components/plus-comp/permission-component/permission-component.vue +78 -0
- package/src/components/plus-comp/plus-card/plus-card.vue +21 -0
- package/src/components/plus-comp/plus-city-cascader/plus-city-cascader.vue +108 -0
- package/src/components/plus-comp/plus-common-header/plus-common-header.vue +58 -0
- package/src/components/plus-comp/plus-count-down/plus-count-down.vue +51 -0
- package/src/components/plus-comp/plus-drawer/plus-drawer.vue +116 -0
- package/src/components/plus-comp/plus-form/plus-form.vue +149 -0
- package/src/components/plus-comp/plus-icon/plus-icon.vue +91 -0
- package/src/components/plus-comp/plus-modal/plus-modal.vue +281 -0
- package/src/components/plus-comp/plus-poptip/plus-poptip.vue +42 -0
- package/src/components/plus-comp/plus-qr-code/plus-qr-code.vue +110 -0
- package/src/components/plus-comp/plus-remote-selector/plus-remote-selector.vue +126 -0
- package/src/components/plus-comp/plus-scrollview/plus-scrollview.vue +58 -0
- package/src/components/plus-comp/plus-select/plus-select.vue +118 -0
- package/src/components/plus-comp/plus-table/export-mixin.js +78 -0
- package/src/components/plus-comp/plus-table/plus-circle-progress-modal.vue +54 -0
- package/src/components/plus-comp/plus-table/plus-table.vue +568 -0
- package/src/components/plus-comp/plus-tabs/plus-tabs.vue +76 -0
- package/src/directive/index.js +2 -0
- package/src/directive/module/authAccess.js +2 -2
- package/src/extentionPlugin/index.js +5 -5
- package/src/extentionPlugin/string.js +30 -1
- package/src/libs/excel.js +203 -0
- package/src/libs/util.js +184 -0
- package/src/main.js +2 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Icon v-if="type" :type="type" :size="size" :color="color" />
|
|
3
|
+
<span v-else-if="src" ref="plusIconInnerRef" class="plus-icon">
|
|
4
|
+
<img :src="handleSrc(src)" />
|
|
5
|
+
</span>
|
|
6
|
+
</template>
|
|
7
|
+
<script>
|
|
8
|
+
export default {
|
|
9
|
+
props: {
|
|
10
|
+
type: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: ''
|
|
13
|
+
},
|
|
14
|
+
src: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: ''
|
|
17
|
+
},
|
|
18
|
+
color: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: ''
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
type: Number,
|
|
24
|
+
default: 16
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
watch: {
|
|
28
|
+
size: {
|
|
29
|
+
handler(val) {
|
|
30
|
+
if (val) {
|
|
31
|
+
this.$nextTick(() => {
|
|
32
|
+
if (this.$refs.plusIconInnerRef) {
|
|
33
|
+
this.$refs.plusIconInnerRef.style.setProperty(
|
|
34
|
+
'--size',
|
|
35
|
+
val + 'px'
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
deep: true,
|
|
42
|
+
immediate: true
|
|
43
|
+
},
|
|
44
|
+
color: {
|
|
45
|
+
handler(val) {
|
|
46
|
+
if (val) {
|
|
47
|
+
this.$nextTick(() => {
|
|
48
|
+
if (this.$refs.plusIconInnerRef) {
|
|
49
|
+
this.$refs.plusIconInnerRef.style.setProperty(
|
|
50
|
+
'--filterColor',
|
|
51
|
+
val
|
|
52
|
+
)
|
|
53
|
+
this.$refs.plusIconInnerRef.style.setProperty('--vector', -1)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
deep: true,
|
|
59
|
+
immediate: true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
computed: {},
|
|
63
|
+
data() {
|
|
64
|
+
return {}
|
|
65
|
+
},
|
|
66
|
+
methods: {
|
|
67
|
+
handleSrc(src) {
|
|
68
|
+
const ss = src.replace('@/assets', '')
|
|
69
|
+
return require(`@/assets` + ss)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
<style lang="less" scoped>
|
|
75
|
+
.plus-icon {
|
|
76
|
+
display: block;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
--size: 16px;
|
|
79
|
+
--filterColor: transparent;
|
|
80
|
+
--vector: 0;
|
|
81
|
+
width: var(--size);
|
|
82
|
+
height: var(--size);
|
|
83
|
+
img {
|
|
84
|
+
position: relative;
|
|
85
|
+
width: var(--size);
|
|
86
|
+
height: var(--size);
|
|
87
|
+
left: ~'calc(var(--size) * var(--vector))';
|
|
88
|
+
filter: drop-shadow(var(--size) 0px var(--filterColor));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal
|
|
3
|
+
id="plus-modal"
|
|
4
|
+
ref="modal"
|
|
5
|
+
v-model="visiable"
|
|
6
|
+
:closable="closable"
|
|
7
|
+
:mask-closable="false"
|
|
8
|
+
:width="width"
|
|
9
|
+
:transfer="transfer"
|
|
10
|
+
:styles="modalStyles"
|
|
11
|
+
:class-name="className"
|
|
12
|
+
@on-visible-change="visibleChange"
|
|
13
|
+
>
|
|
14
|
+
<div
|
|
15
|
+
v-if="title"
|
|
16
|
+
:style="headerStyles"
|
|
17
|
+
class="plus-modal-header f-s-16 f-w-600"
|
|
18
|
+
slot="header"
|
|
19
|
+
>
|
|
20
|
+
{{ title }}
|
|
21
|
+
</div>
|
|
22
|
+
<div ref="editslotRef" id="editslot" :style="editSlotStyle">
|
|
23
|
+
<slot></slot>
|
|
24
|
+
</div>
|
|
25
|
+
<div
|
|
26
|
+
slot="footer"
|
|
27
|
+
ref="footerRef"
|
|
28
|
+
:class="['plus-modal-footer', 'i-flex-wrap justify-center align-center']"
|
|
29
|
+
>
|
|
30
|
+
<slot name="footer">
|
|
31
|
+
<Button type="primary" @click="handlerClose"> 关闭 </Button>
|
|
32
|
+
</slot>
|
|
33
|
+
</div>
|
|
34
|
+
<Spin v-if="showLoading" fix>
|
|
35
|
+
<Icon type="ios-loading" size="18" class="demo-spin-icon-load"></Icon>
|
|
36
|
+
<div>{{ loadingTip || '正在处理...' }}</div>
|
|
37
|
+
</Spin>
|
|
38
|
+
</Modal>
|
|
39
|
+
</template>
|
|
40
|
+
<script>
|
|
41
|
+
export default {
|
|
42
|
+
name: 'edit-modal',
|
|
43
|
+
props: {
|
|
44
|
+
props: {
|
|
45
|
+
type: Object,
|
|
46
|
+
default() {
|
|
47
|
+
return {
|
|
48
|
+
show: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
closable: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
default: false
|
|
55
|
+
},
|
|
56
|
+
footerHide: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false
|
|
59
|
+
},
|
|
60
|
+
title: {
|
|
61
|
+
default: null
|
|
62
|
+
},
|
|
63
|
+
showLoading: {
|
|
64
|
+
default: false
|
|
65
|
+
},
|
|
66
|
+
loadingTip: {
|
|
67
|
+
default: '正在处理...'
|
|
68
|
+
},
|
|
69
|
+
width: {
|
|
70
|
+
default: 520
|
|
71
|
+
},
|
|
72
|
+
headerCenter: {
|
|
73
|
+
default: false
|
|
74
|
+
},
|
|
75
|
+
transfer: {
|
|
76
|
+
default: true
|
|
77
|
+
},
|
|
78
|
+
fillParent: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
default: false
|
|
81
|
+
},
|
|
82
|
+
styles: {
|
|
83
|
+
type: Object,
|
|
84
|
+
default() {
|
|
85
|
+
return {
|
|
86
|
+
height: 'fit-content'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
padding: {
|
|
91
|
+
type: String,
|
|
92
|
+
default: '16px 24px'
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
watch: {
|
|
96
|
+
'props.show': {
|
|
97
|
+
handler(nValue) {
|
|
98
|
+
this.visiable = nValue
|
|
99
|
+
this.$nextTick(() => {
|
|
100
|
+
if (this.$slots.footer) {
|
|
101
|
+
if (this.$slots.footer[0] && this.$slots.footer[0].elm) {
|
|
102
|
+
if (!this.$slots.footer[0].elm.clientHeight) {
|
|
103
|
+
let height = window
|
|
104
|
+
.getComputedStyle(this.$slots.footer[0].elm)
|
|
105
|
+
.getPropertyValue('height')
|
|
106
|
+
if (!height || parseInt(height) == 0) {
|
|
107
|
+
this.$refs.footerRef.parentElement.style.display = 'none'
|
|
108
|
+
} else {
|
|
109
|
+
this.$refs.footerRef.parentElement.style.display = 'block'
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
this.$refs.footerRef.parentElement.style.display = 'block'
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
},
|
|
118
|
+
deep: true,
|
|
119
|
+
immediate: true
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
data() {
|
|
123
|
+
return {
|
|
124
|
+
visiable: false,
|
|
125
|
+
headerStyles: {
|
|
126
|
+
'text-align': 'center'
|
|
127
|
+
},
|
|
128
|
+
computedPadding: ''
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
computed: {
|
|
132
|
+
modalStyles() {
|
|
133
|
+
return {
|
|
134
|
+
...this.styles
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
className() {
|
|
138
|
+
return (
|
|
139
|
+
'vertical-center-modal fill-parent' +
|
|
140
|
+
(this.footerHide ? ' footerHide' : '') +
|
|
141
|
+
(this.title ? '' : ' headerHide')
|
|
142
|
+
)
|
|
143
|
+
},
|
|
144
|
+
editSlotStyle() {
|
|
145
|
+
let maxHeight =
|
|
146
|
+
document.body.clientHeight -
|
|
147
|
+
(this.footerHide ? 0 : 80) -
|
|
148
|
+
(this.title ? 60 : 0) -
|
|
149
|
+
60 +
|
|
150
|
+
'px'
|
|
151
|
+
return {
|
|
152
|
+
'overflow-y': 'auto',
|
|
153
|
+
'max-height': maxHeight,
|
|
154
|
+
padding: this.computedPadding || this.padding
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
methods: {
|
|
159
|
+
handlerClose() {
|
|
160
|
+
this.props.show = false
|
|
161
|
+
this.$emit('on-close')
|
|
162
|
+
},
|
|
163
|
+
visibleChange(e) {
|
|
164
|
+
this.props.show = e
|
|
165
|
+
if (!e) {
|
|
166
|
+
this.$emit('on-close')
|
|
167
|
+
} else {
|
|
168
|
+
this.$nextTick(() => {
|
|
169
|
+
if (
|
|
170
|
+
this.$refs.editslotRef.scrollHeight >
|
|
171
|
+
this.$refs.editslotRef.clientHeight
|
|
172
|
+
) {
|
|
173
|
+
var styles = window.getComputedStyle(this.$refs.editslotRef)
|
|
174
|
+
|
|
175
|
+
// 如果您只想获取特定方向的padding值,例如padding-top
|
|
176
|
+
var paddingLeft = parseFloat(
|
|
177
|
+
styles.getPropertyValue('padding-left')
|
|
178
|
+
)
|
|
179
|
+
var paddingRight = parseFloat(
|
|
180
|
+
styles.getPropertyValue('padding-right')
|
|
181
|
+
)
|
|
182
|
+
var paddingTop = parseFloat(styles.getPropertyValue('padding-top'))
|
|
183
|
+
var paddingBottom = parseFloat(
|
|
184
|
+
styles.getPropertyValue('padding-bottom')
|
|
185
|
+
)
|
|
186
|
+
this.$refs.editslotRef.style.width = `calc(100% + ${paddingRight}px)`
|
|
187
|
+
this.$refs.editslotRef.style.marginLeft = `-${paddingRight}px`
|
|
188
|
+
this.$refs.editslotRef.style.paddingRight = 0
|
|
189
|
+
this.$refs.editslotRef.style.paddingLeft = `${
|
|
190
|
+
paddingLeft + paddingRight
|
|
191
|
+
}px`
|
|
192
|
+
this.computedPadding = `${paddingTop}px ${0}px ${paddingBottom}px ${
|
|
193
|
+
paddingLeft + paddingRight
|
|
194
|
+
}px`
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
mounted() {}
|
|
201
|
+
}
|
|
202
|
+
</script>
|
|
203
|
+
<style lang="less">
|
|
204
|
+
#plus-modal {
|
|
205
|
+
height: 100%;
|
|
206
|
+
.vertical-center-modal {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
justify-content: center;
|
|
210
|
+
.ivu-modal {
|
|
211
|
+
top: 0;
|
|
212
|
+
/*flex: 0;*/
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
.fill-parent {
|
|
216
|
+
overflow: hidden;
|
|
217
|
+
.ivu-modal {
|
|
218
|
+
height: 98%;
|
|
219
|
+
max-height: 100vh;
|
|
220
|
+
.ivu-modal-content {
|
|
221
|
+
max-height: 100vh;
|
|
222
|
+
height: 100%;
|
|
223
|
+
.ivu-modal-body {
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
height: calc(~'100% - 50px');
|
|
227
|
+
padding: 0;
|
|
228
|
+
#editslot {
|
|
229
|
+
position: relative;
|
|
230
|
+
flex-grow: 1;
|
|
231
|
+
max-height: calc(~'100% - 35px');
|
|
232
|
+
overflow: auto;
|
|
233
|
+
padding: 16px 24px;
|
|
234
|
+
}
|
|
235
|
+
.bottom {
|
|
236
|
+
flex-shrink: 0;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
.ivu-modal-header {
|
|
243
|
+
padding: 0;
|
|
244
|
+
line-height: 60px;
|
|
245
|
+
height: 60px;
|
|
246
|
+
padding: 0;
|
|
247
|
+
// border-bottom: none;
|
|
248
|
+
.plus-modal-header {
|
|
249
|
+
font-family: PingFangSC-SNaNpxibold;
|
|
250
|
+
color: #17233d;
|
|
251
|
+
letter-spacing: 0.44px;
|
|
252
|
+
text-align: center;
|
|
253
|
+
line-height: 60px;
|
|
254
|
+
height: 60px;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
.ivu-modal-footer {
|
|
258
|
+
text-align: center;
|
|
259
|
+
// border-top: none;
|
|
260
|
+
min-height: 80px;
|
|
261
|
+
padding: 0 24px;
|
|
262
|
+
.plus-modal-footer {
|
|
263
|
+
min-height: 80px;
|
|
264
|
+
&.i-flex-wrap {
|
|
265
|
+
* {
|
|
266
|
+
margin-top: 0;
|
|
267
|
+
margin-right: 5px;
|
|
268
|
+
&:last-child {
|
|
269
|
+
margin-right: 0;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
.footerHide {
|
|
276
|
+
.ivu-modal-footer {
|
|
277
|
+
display: none;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Poptip
|
|
3
|
+
class="plus-poptip"
|
|
4
|
+
popper-class="plus-poptip-content"
|
|
5
|
+
:trigger="trigger"
|
|
6
|
+
:padding="padding"
|
|
7
|
+
:width="width"
|
|
8
|
+
>
|
|
9
|
+
<slot></slot>
|
|
10
|
+
<div slot="content">
|
|
11
|
+
<slot name="content"></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</Poptip>
|
|
14
|
+
</template>
|
|
15
|
+
<script>
|
|
16
|
+
export default {
|
|
17
|
+
props: {
|
|
18
|
+
width: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: '150px'
|
|
21
|
+
},
|
|
22
|
+
padding: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: '8px 16px'
|
|
25
|
+
},
|
|
26
|
+
trigger: {
|
|
27
|
+
default: 'hover'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
<style lang="less" scoped>
|
|
33
|
+
.plus-poptip {
|
|
34
|
+
z-index: 1100;
|
|
35
|
+
}
|
|
36
|
+
/deep/.plus-poptip-content {
|
|
37
|
+
&.ivu-poptip-popper {
|
|
38
|
+
min-width: initial;
|
|
39
|
+
}
|
|
40
|
+
z-index: 9999;
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:ref="myRef"
|
|
4
|
+
class="plus-qr-code"
|
|
5
|
+
style="display: flex; justify-content: center"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
class="qrcodeEl"
|
|
9
|
+
:ref="'qrcodeEl'"
|
|
10
|
+
:style="`height:${size}px;width:${size}px;`"
|
|
11
|
+
></div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
<script>
|
|
15
|
+
import html2canvas from 'html2canvas'
|
|
16
|
+
import QRCode from 'qrcodejs2'
|
|
17
|
+
export default {
|
|
18
|
+
props: {
|
|
19
|
+
type: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: 'qrcode' // miniapp
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: 100
|
|
25
|
+
},
|
|
26
|
+
codeContent: {
|
|
27
|
+
default: 'asdasdasdasdasd'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
watch: {
|
|
31
|
+
codeContent: {
|
|
32
|
+
handler(value) {
|
|
33
|
+
this.$nextTick(() => {
|
|
34
|
+
if (value) {
|
|
35
|
+
if (this.type == 'qrcode') {
|
|
36
|
+
new QRCode(this.$refs.qrcodeEl, {
|
|
37
|
+
width: this.size * 2,
|
|
38
|
+
height: this.size * 2 // 高度
|
|
39
|
+
}).makeCode(value) // 二维码内容 // https://h5-dev.shijiplus.com/shop-events
|
|
40
|
+
} else {
|
|
41
|
+
const img = new Image()
|
|
42
|
+
img.src = value
|
|
43
|
+
this.$refs.qrcodeEl.append(img)
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
this.$refs.qrcodeEl.innerHTML = ''
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
deep: true,
|
|
51
|
+
immediate: true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
data() {
|
|
55
|
+
const timeStamp = new Date().getTime()
|
|
56
|
+
return {
|
|
57
|
+
myRef: String(timeStamp)
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
methods: {
|
|
61
|
+
saveCode(name) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
if (this.type != 'qrcode') {
|
|
64
|
+
var a = document.createElement('a')
|
|
65
|
+
var event = new MouseEvent('click')
|
|
66
|
+
a.download = `${name || '二维码'}.png`
|
|
67
|
+
a.href = this.codeContent
|
|
68
|
+
a.dispatchEvent(event)
|
|
69
|
+
resolve()
|
|
70
|
+
} else {
|
|
71
|
+
html2canvas(this.$refs[this.myRef], {
|
|
72
|
+
allowTaint: false,
|
|
73
|
+
// taintTest: false,
|
|
74
|
+
dpi: window.devicePixelRatio * 4,
|
|
75
|
+
useCORS: true,
|
|
76
|
+
scale: 6
|
|
77
|
+
// width: 200,
|
|
78
|
+
// height: 200
|
|
79
|
+
})
|
|
80
|
+
.then((canvas) => {
|
|
81
|
+
var a = document.createElement('a')
|
|
82
|
+
var event = new MouseEvent('click')
|
|
83
|
+
a.download = `${name || '二维码'}.png`
|
|
84
|
+
a.href = canvas.toDataURL('image/png')
|
|
85
|
+
a.dispatchEvent(event)
|
|
86
|
+
resolve()
|
|
87
|
+
})
|
|
88
|
+
.catch((err) => {
|
|
89
|
+
console.error('savecode error', err)
|
|
90
|
+
reject(err)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
</script>
|
|
98
|
+
<style lang="less" scoped>
|
|
99
|
+
.plus-qr-code {
|
|
100
|
+
width: fit-content;
|
|
101
|
+
.qrcodeEl {
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
/deep/img {
|
|
104
|
+
display: block;
|
|
105
|
+
width: 100%;
|
|
106
|
+
height: 100%;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Select
|
|
3
|
+
ref="select"
|
|
4
|
+
filterable
|
|
5
|
+
clearable
|
|
6
|
+
remote
|
|
7
|
+
label-in-value
|
|
8
|
+
:placeholder="placeholder"
|
|
9
|
+
@on-change="valueChange"
|
|
10
|
+
@on-open-change="openChange"
|
|
11
|
+
:remote-method="remoteMethod"
|
|
12
|
+
:loading="loading"
|
|
13
|
+
>
|
|
14
|
+
<Option
|
|
15
|
+
v-for="(option, index) in options"
|
|
16
|
+
:value="option[valueKey]"
|
|
17
|
+
:key="index"
|
|
18
|
+
:label="option.showLabel"
|
|
19
|
+
/>
|
|
20
|
+
</Select>
|
|
21
|
+
</template>
|
|
22
|
+
<script>
|
|
23
|
+
import { throttle } from '../../../libs/util'
|
|
24
|
+
export default {
|
|
25
|
+
name: 'plus-remote-selector',
|
|
26
|
+
model: {
|
|
27
|
+
prop: 'modelValue',
|
|
28
|
+
event: 'change'
|
|
29
|
+
},
|
|
30
|
+
props: {
|
|
31
|
+
modelValue: [Number, String],
|
|
32
|
+
showName: {
|
|
33
|
+
type: [String, Number],
|
|
34
|
+
default: ''
|
|
35
|
+
},
|
|
36
|
+
valueKey: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: 'id'
|
|
39
|
+
},
|
|
40
|
+
labelKeys: {
|
|
41
|
+
type: [String, Array],
|
|
42
|
+
default: 'name'
|
|
43
|
+
},
|
|
44
|
+
placeholder: {
|
|
45
|
+
default: '输入关键字搜索'
|
|
46
|
+
},
|
|
47
|
+
remoteFun: Function
|
|
48
|
+
},
|
|
49
|
+
watch: {
|
|
50
|
+
modelValue: {
|
|
51
|
+
handler(val) {
|
|
52
|
+
if (val) {
|
|
53
|
+
this.$nextTick(() => {
|
|
54
|
+
this.$refs.select.$data.query = this.showName
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
immediate: true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
data() {
|
|
62
|
+
return {
|
|
63
|
+
loading: false,
|
|
64
|
+
options: [],
|
|
65
|
+
keyword: null
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
methods: {
|
|
69
|
+
valueChange(e) {
|
|
70
|
+
if (e) {
|
|
71
|
+
this.$emit('change', e.value)
|
|
72
|
+
this.$emit('change-option', { ...e })
|
|
73
|
+
this.$refs.select.$data.query = e.label
|
|
74
|
+
} else {
|
|
75
|
+
this.$emit('change', null)
|
|
76
|
+
this.$emit('change-option', {})
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
openChange(e) {
|
|
80
|
+
if (!e) {
|
|
81
|
+
this.$refs.select.isFocused = false
|
|
82
|
+
if (this.showName) {
|
|
83
|
+
this.$nextTick(() => {
|
|
84
|
+
this.$refs.select.$data.query = this.showName
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
remoteMethod(query) {
|
|
90
|
+
const fun = () => {
|
|
91
|
+
this.searchLoading = true
|
|
92
|
+
const result = this.remoteFun(query)
|
|
93
|
+
if (result instanceof Promise) {
|
|
94
|
+
result
|
|
95
|
+
.then((resp) => {
|
|
96
|
+
if (resp.data) {
|
|
97
|
+
resp.data.forEach((item) => {
|
|
98
|
+
item.showLabel = ''
|
|
99
|
+
if (this.labelKeys) {
|
|
100
|
+
let tempKeys = this.labelKeys
|
|
101
|
+
if (typeof tempKeys == 'string') {
|
|
102
|
+
tempKeys = this.labelKeys.split(',')
|
|
103
|
+
}
|
|
104
|
+
tempKeys.forEach((key) => {
|
|
105
|
+
item.showLabel += item[key]
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
this.options = resp.data
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
.catch((err) => {
|
|
113
|
+
console.log('-------remoteMethod-------', err)
|
|
114
|
+
})
|
|
115
|
+
.finally(() => {
|
|
116
|
+
this.searchLoading = false
|
|
117
|
+
})
|
|
118
|
+
} else if (!result) {
|
|
119
|
+
throw Error('remoteFun must return promise')
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
throttle(fun, 1000)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
</script>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :id="scrollId" class="scroll-wrap">
|
|
3
|
+
<slot>
|
|
4
|
+
<div class="empty-wrap">暂无数据</div>
|
|
5
|
+
</slot>
|
|
6
|
+
<div v-if="showLoadingBar" class="i-flex-wrap justify-center loading-bar">
|
|
7
|
+
{{ loadText }}
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
<script>
|
|
12
|
+
export default {
|
|
13
|
+
props: {
|
|
14
|
+
loadText: {
|
|
15
|
+
default: '数据加载中...'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
data() {
|
|
19
|
+
return { scrollId: null, showLoadingBar: false }
|
|
20
|
+
},
|
|
21
|
+
mounted() {
|
|
22
|
+
this.scrollId = new Date().getTime()
|
|
23
|
+
this.$nextTick(() => {
|
|
24
|
+
const scrollEle = document.getElementById(this.scrollId)
|
|
25
|
+
scrollEle.addEventListener('scroll', () => {
|
|
26
|
+
if (
|
|
27
|
+
scrollEle.scrollTop > 0 &&
|
|
28
|
+
scrollEle.scrollHeight -
|
|
29
|
+
(scrollEle.scrollTop + scrollEle.clientHeight) <
|
|
30
|
+
1
|
|
31
|
+
) {
|
|
32
|
+
this.showLoadingBar = true
|
|
33
|
+
this.$emit('on-reach-bottom')
|
|
34
|
+
console.log('已滑动到底部')
|
|
35
|
+
// 执行到达底部后的操作
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
<style lang="less" scoped>
|
|
43
|
+
.scroll-wrap {
|
|
44
|
+
overflow: auto;
|
|
45
|
+
.empty-wrap {
|
|
46
|
+
display: flex;
|
|
47
|
+
width: 100%;
|
|
48
|
+
height: 100%;
|
|
49
|
+
align-content: center;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
}
|
|
54
|
+
.loading-bar {
|
|
55
|
+
display: none;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
</style>
|