sh-view 1.7.5 → 1.7.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 +1 -1
- package/packages/components/global-components/{sh-layout → sh-split}/index.vue +1 -1
- package/packages/components/global-components/sh-upload/index.vue +182 -325
- package/packages/components/global-components/sh-upload/js/ajax.js +80 -0
- package/packages/components/global-components/sh-upload/js/mixin.js +257 -0
- package/packages/components/global-components/sh-vxe-form/js/methods.js +28 -41
- package/packages/components/global-components/sh-vxe-list/index.vue +25 -5
- package/packages/components/global-components/sh-vxe-query/index.vue +56 -32
- package/packages/components/global-components/sh-vxe-table/js/methods.js +81 -88
- package/packages/components/global-components/sh-vxe-toolbar/index.vue +3 -3
- package/packages/vxeTable/index.js +5 -6
- package/packages/components/global-components/sh-upload/components/u-img.vue +0 -63
- package/packages/components/global-components/sh-upload/components/u-list.vue +0 -100
package/package.json
CHANGED
|
@@ -1,102 +1,54 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="sh-upload" :class="
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
class="upload-box
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:headers="headers"
|
|
21
|
-
:disabled="disabled"
|
|
22
|
-
:multiple="multiple"
|
|
23
|
-
:type="uploadType"
|
|
24
|
-
:accept="accept"
|
|
25
|
-
:data="params"
|
|
26
|
-
:name="inputname"
|
|
27
|
-
:show-upload-list="false"
|
|
28
|
-
:on-progress="uploadProgress"
|
|
29
|
-
:on-success="uploadSuccess"
|
|
30
|
-
:on-error="uploadError"
|
|
31
|
-
:before-upload="handleBeforeUpload">
|
|
32
|
-
<div v-if="uploadType === 'drag'" class="py-3">
|
|
33
|
-
<sh-icon :type="iconType" size="26"></sh-icon>
|
|
34
|
-
<p class="mt-1">上传附件</p>
|
|
2
|
+
<div class="sh-upload" :class="{ list: !card }">
|
|
3
|
+
<slot name="head"></slot>
|
|
4
|
+
<div
|
|
5
|
+
v-if="!disabled"
|
|
6
|
+
v-show="fileList.length < limit"
|
|
7
|
+
class="upload-component"
|
|
8
|
+
:class="upClass"
|
|
9
|
+
:style="upStyles"
|
|
10
|
+
@click="handleClick"
|
|
11
|
+
@drop.prevent="onDrop"
|
|
12
|
+
@paste="handlePaste"
|
|
13
|
+
@dragover.prevent="dragOver = true"
|
|
14
|
+
@dragleave.prevent="dragOver = false">
|
|
15
|
+
<input ref="input" type="file" class="sh-upload-input" :multiple="multiple" :webkitdirectory="webkitdirectory" :accept="accept" @change="handleChange" />
|
|
16
|
+
<slot>
|
|
17
|
+
<div class="upload-box" :class="{ drag, card }" :style="upStyles">
|
|
18
|
+
<sh-icon v-if="icon" class="upload-box-icon" :type="icon"></sh-icon>
|
|
19
|
+
<span class="upload-box-text">上传附件</span>
|
|
35
20
|
</div>
|
|
36
|
-
|
|
37
|
-
<div class="upload-box-inner" :style="upStyles"><sh-icon :type="iconType" /></div>
|
|
38
|
-
</template>
|
|
39
|
-
<template v-else>
|
|
40
|
-
<Button icon="ios-cloud-upload-outline">上传附件</Button>
|
|
41
|
-
</template>
|
|
42
|
-
</Upload>
|
|
21
|
+
</slot>
|
|
43
22
|
</div>
|
|
44
|
-
<
|
|
45
|
-
v-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
23
|
+
<ul v-if="fileList.length" class="upload-list">
|
|
24
|
+
<li v-for="(file, index) in fileList" :key="index" class="upload-list-item">
|
|
25
|
+
<slot name="fileItem" v-bind="file">
|
|
26
|
+
<div class="upload-list-title" :title="file.name">{{ file.name }}</div>
|
|
27
|
+
<div v-if="file.status !== 'success'" class="upload-list-progress">
|
|
28
|
+
<Progress v-if="file.showProgress" v-bind="progressConfig(file)"></Progress>
|
|
29
|
+
</div>
|
|
30
|
+
<div v-else class="upload-list-action">
|
|
31
|
+
<template v-for="listAct in listActions" :key="listAct.code">
|
|
32
|
+
<span class="action-item" @click="onActionClick(listAct, file)"><sh-icon :type="listAct.icon" :title="listAct.title" size="18" /></span>
|
|
33
|
+
</template>
|
|
34
|
+
</div>
|
|
35
|
+
</slot>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
<slot name="foot"></slot>
|
|
57
39
|
</div>
|
|
58
40
|
</template>
|
|
59
41
|
|
|
60
42
|
<script>
|
|
61
|
-
import
|
|
43
|
+
import mixin from './js/mixin'
|
|
62
44
|
export default {
|
|
63
45
|
name: 'ShUpload',
|
|
64
|
-
|
|
65
|
-
UList
|
|
66
|
-
},
|
|
46
|
+
mixins: [mixin],
|
|
67
47
|
props: {
|
|
68
|
-
|
|
69
|
-
type: Boolean,
|
|
70
|
-
default: true
|
|
71
|
-
},
|
|
72
|
-
// 编辑回显数据
|
|
73
|
-
value: {
|
|
74
|
-
type: [Array],
|
|
75
|
-
default() {
|
|
76
|
-
return []
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
action: {
|
|
80
|
-
type: String,
|
|
81
|
-
default: '-'
|
|
82
|
-
},
|
|
83
|
-
icon: {
|
|
48
|
+
baseUrl: {
|
|
84
49
|
type: String,
|
|
85
50
|
default: ''
|
|
86
51
|
},
|
|
87
|
-
headers: {
|
|
88
|
-
type: Object,
|
|
89
|
-
default() {
|
|
90
|
-
return {}
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
disabled: {
|
|
94
|
-
type: Boolean
|
|
95
|
-
},
|
|
96
|
-
preview: {
|
|
97
|
-
type: Boolean,
|
|
98
|
-
default: true
|
|
99
|
-
},
|
|
100
52
|
width: {
|
|
101
53
|
type: [String, Number],
|
|
102
54
|
default: 80
|
|
@@ -109,13 +61,15 @@ export default {
|
|
|
109
61
|
type: Number,
|
|
110
62
|
default: 1
|
|
111
63
|
},
|
|
112
|
-
|
|
113
|
-
type:
|
|
114
|
-
default: 2097152
|
|
64
|
+
card: {
|
|
65
|
+
type: Boolean
|
|
115
66
|
},
|
|
116
|
-
|
|
67
|
+
drag: {
|
|
68
|
+
type: Boolean
|
|
69
|
+
},
|
|
70
|
+
icon: {
|
|
117
71
|
type: String,
|
|
118
|
-
default: '
|
|
72
|
+
default: 'ios-folder'
|
|
119
73
|
},
|
|
120
74
|
params: {
|
|
121
75
|
type: Object,
|
|
@@ -123,296 +77,199 @@ export default {
|
|
|
123
77
|
return {}
|
|
124
78
|
}
|
|
125
79
|
},
|
|
126
|
-
|
|
127
|
-
type:
|
|
128
|
-
default: 'image'
|
|
129
|
-
},
|
|
130
|
-
type: {
|
|
131
|
-
type: String,
|
|
132
|
-
default: 'img' // img, file 上传图片还是文件
|
|
133
|
-
},
|
|
134
|
-
listType: {
|
|
135
|
-
type: String,
|
|
136
|
-
default: 'card' // card, list 附件列表展示类型
|
|
137
|
-
},
|
|
138
|
-
uploadType: {
|
|
139
|
-
type: String,
|
|
140
|
-
default: 'select' // drag
|
|
141
|
-
},
|
|
142
|
-
beforeUpload: {
|
|
143
|
-
type: Function
|
|
144
|
-
},
|
|
145
|
-
baseUrl: {
|
|
146
|
-
type: String,
|
|
147
|
-
default: ''
|
|
148
|
-
},
|
|
149
|
-
serverConfig: {
|
|
150
|
-
type: Object,
|
|
80
|
+
actionList: {
|
|
81
|
+
type: Array,
|
|
151
82
|
default() {
|
|
152
|
-
return
|
|
153
|
-
type: 'post',
|
|
154
|
-
url: ''
|
|
155
|
-
}
|
|
83
|
+
return ['detail', 'download', 'delete']
|
|
156
84
|
}
|
|
85
|
+
},
|
|
86
|
+
resKey: {
|
|
87
|
+
type: String,
|
|
88
|
+
default: 'data'
|
|
157
89
|
}
|
|
158
90
|
},
|
|
159
|
-
emits: ['update:modelValue', '
|
|
91
|
+
emits: ['update:modelValue', 'action'],
|
|
160
92
|
data() {
|
|
161
|
-
return {
|
|
162
|
-
resultUrl: '',
|
|
163
|
-
uploadList: []
|
|
164
|
-
}
|
|
93
|
+
return {}
|
|
165
94
|
},
|
|
166
95
|
computed: {
|
|
167
96
|
multiple() {
|
|
168
97
|
return this.limit > 1
|
|
169
98
|
},
|
|
170
|
-
iconType() {
|
|
171
|
-
return this.icon || (this.type === 'img' ? 'md-camera' : 'ios-folder')
|
|
172
|
-
},
|
|
173
99
|
upStyles() {
|
|
174
|
-
return this.
|
|
100
|
+
return this.card ? { width: `${this.width}px`, height: `${this.height}px` } : {}
|
|
175
101
|
},
|
|
176
102
|
upClass() {
|
|
177
|
-
return [
|
|
178
|
-
{
|
|
179
|
-
[this.listType]: true
|
|
180
|
-
}
|
|
181
|
-
]
|
|
182
|
-
},
|
|
183
|
-
messageAll() {
|
|
184
103
|
return {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
104
|
+
'sh-upload-list': !this.card,
|
|
105
|
+
'sh-upload-select': !this.drag,
|
|
106
|
+
'sh-upload-drag': this.drag,
|
|
107
|
+
'sh-upload-dragOver': this.drag && this.dragOver
|
|
189
108
|
}
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
watch: {
|
|
193
|
-
modelValue: {
|
|
194
|
-
handler: function (val, oldVal) {
|
|
195
|
-
if (val && Array.isArray(val)) {
|
|
196
|
-
this.uploadList = val
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
immediate: true,
|
|
200
|
-
deep: true
|
|
201
109
|
},
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
110
|
+
fileFormat() {
|
|
111
|
+
return this.format.length ? this.format : this.accept.split(',').map(_ => String(_).replace('.', ''))
|
|
112
|
+
},
|
|
113
|
+
listActions() {
|
|
114
|
+
let list = [
|
|
115
|
+
{ title: '查看文件', icon: 'ios-eye-outline', code: 'detail' },
|
|
116
|
+
{ title: '下载文件', icon: 'ios-download', code: 'download' }
|
|
117
|
+
]
|
|
118
|
+
if (!this.disabled) {
|
|
119
|
+
list.push({ title: '删除文件', icon: 'ios-trash-outline', code: 'delete' })
|
|
120
|
+
}
|
|
121
|
+
return list.filter(item => this.actionList.includes(item.code))
|
|
208
122
|
}
|
|
209
123
|
},
|
|
210
|
-
created() {},
|
|
211
|
-
mounted() {},
|
|
212
124
|
methods: {
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// 文件上传前狗子
|
|
226
|
-
handleBeforeUpload(file) {
|
|
227
|
-
// 文件类型校验
|
|
228
|
-
let type = file.name.substr(file.name.lastIndexOf('.')).toLowerCase() // .jpg
|
|
229
|
-
let imgFileTypeArr = this.messageAll.fileFormat
|
|
230
|
-
let checkType = imgFileTypeArr.some(item => {
|
|
231
|
-
return item === type
|
|
232
|
-
})
|
|
233
|
-
if (this.fileaccept !== '' && !checkType) {
|
|
234
|
-
this.msginfo(this.messageAll.fileTypeError)
|
|
235
|
-
return false
|
|
236
|
-
}
|
|
237
|
-
// 文件大小校验
|
|
238
|
-
const checkMax = file.size < this.messageAll.limitBytes
|
|
239
|
-
if (!checkMax) {
|
|
240
|
-
this.msginfo(this.messageAll.fileSizeError)
|
|
241
|
-
return false
|
|
242
|
-
}
|
|
243
|
-
if (typeof this.beforeUpload === 'function') {
|
|
244
|
-
this.beforeUpload(file)
|
|
245
|
-
} else if (this.isFormData) {
|
|
246
|
-
this.handleFilePreviewData(file)
|
|
247
|
-
} else {
|
|
248
|
-
this.handleFileUpload(file)
|
|
125
|
+
// 上传校验
|
|
126
|
+
validateFile(file) {
|
|
127
|
+
let { fileList, action, fileFormat, maxSize } = this
|
|
128
|
+
// check format
|
|
129
|
+
if (fileFormat.length) {
|
|
130
|
+
const _file_format = file.name.split('.').pop().toLocaleLowerCase()
|
|
131
|
+
const checked = fileFormat.some(item => item.toLocaleLowerCase() === _file_format)
|
|
132
|
+
if (!checked) {
|
|
133
|
+
let errorMsg = `格式不正确,请上传 ${fileFormat.join(' ')} 格式文件`
|
|
134
|
+
this.onFormatError ? this.onFormatError(file, errorMsg, fileList) : this.msginfo(errorMsg)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
249
137
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
this.uploadList.push(file)
|
|
255
|
-
},
|
|
256
|
-
// 组件内文件上传
|
|
257
|
-
async handleFileUpload(file) {
|
|
258
|
-
const that = this
|
|
259
|
-
if (!that.serverConfig.url) {
|
|
260
|
-
that.msgerror('上传未配置请求地址!')
|
|
138
|
+
// check maxSize
|
|
139
|
+
if (maxSize && file.size > maxSize * 1024) {
|
|
140
|
+
let errorMsg = `文件大小不能超过 ${maxSize / 1024} M`
|
|
141
|
+
this.onExceededSize ? this.onExceededSize(file, errorMsg, fileList) : this.msginfo(errorMsg)
|
|
261
142
|
return
|
|
262
143
|
}
|
|
263
|
-
if (!
|
|
264
|
-
|
|
144
|
+
if (!action) {
|
|
145
|
+
this.msginfo('上传地址不能为空')
|
|
265
146
|
return
|
|
266
147
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
let res = await that.$http.request({
|
|
278
|
-
method: that.serverConfig.type,
|
|
279
|
-
url: that.serverConfig.url,
|
|
280
|
-
headers: axiosHeader,
|
|
281
|
-
data: axiosData
|
|
282
|
-
})
|
|
283
|
-
console.log(res)
|
|
284
|
-
} catch (e) {
|
|
285
|
-
that.msgerror('上传失败 ' + e.message || e)
|
|
148
|
+
return true
|
|
149
|
+
},
|
|
150
|
+
// 附件操作点击事件
|
|
151
|
+
onActionClick(obj, file) {
|
|
152
|
+
if (obj.code === 'delete') {
|
|
153
|
+
this.handleRemove(file)
|
|
154
|
+
} else if (obj.code === 'detail') {
|
|
155
|
+
this.handlePreview(file)
|
|
156
|
+
} else if (obj.code === 'download') {
|
|
157
|
+
this.handleDownload(file)
|
|
286
158
|
}
|
|
159
|
+
this.$emit('action', obj)
|
|
287
160
|
},
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
that.$refs.upload.fileList.splice(dataIndex, 1)
|
|
297
|
-
that.$emit('file-delete', data)
|
|
161
|
+
// 获取双向绑定值
|
|
162
|
+
getModelValue() {
|
|
163
|
+
return this.fileList.map(item => {
|
|
164
|
+
let url = this.$vUtils.get(item, `response.${this.resKey}`)
|
|
165
|
+
return {
|
|
166
|
+
name: item.name,
|
|
167
|
+
url: url
|
|
168
|
+
}
|
|
298
169
|
})
|
|
299
170
|
}
|
|
300
171
|
}
|
|
301
172
|
}
|
|
302
173
|
</script>
|
|
303
174
|
|
|
304
|
-
<style lang="scss">
|
|
175
|
+
<style scoped lang="scss">
|
|
305
176
|
.sh-upload {
|
|
306
177
|
display: inline-block;
|
|
178
|
+
vertical-align: top;
|
|
307
179
|
&.list {
|
|
308
180
|
display: block;
|
|
309
181
|
width: 100%;
|
|
310
182
|
}
|
|
311
|
-
.
|
|
312
|
-
border
|
|
313
|
-
background: var(--body-background);
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
text-align: center;
|
|
319
|
-
overflow: hidden;
|
|
320
|
-
& + .sh-upload-list.card {
|
|
321
|
-
margin-left: 4px;
|
|
322
|
-
}
|
|
183
|
+
.upload-component {
|
|
184
|
+
border: 1px solid var(--border-color);
|
|
185
|
+
background-color: var(--body-background);
|
|
186
|
+
border-radius: var(--border-radius);
|
|
187
|
+
cursor: pointer;
|
|
188
|
+
input[type='file'] {
|
|
189
|
+
display: none;
|
|
323
190
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
191
|
+
.upload-box {
|
|
192
|
+
display: inline-block;
|
|
193
|
+
padding: 6px 10px;
|
|
194
|
+
box-sizing: border-box;
|
|
195
|
+
.upload-box-icon {
|
|
196
|
+
margin-right: 5px;
|
|
327
197
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
.list-file-card {
|
|
334
|
-
position: relative;
|
|
335
|
-
height: 100%;
|
|
336
|
-
width: 100%;
|
|
337
|
-
display: flex;
|
|
338
|
-
align-items: center;
|
|
339
|
-
justify-content: center;
|
|
340
|
-
background-color: var(--header-color);
|
|
341
|
-
.list-file-cover {
|
|
342
|
-
display: flex;
|
|
343
|
-
position: absolute;
|
|
344
|
-
top: 0;
|
|
345
|
-
bottom: 0;
|
|
346
|
-
left: 0;
|
|
347
|
-
right: 0;
|
|
348
|
-
background: rgba(0, 0, 0, 0.6);
|
|
198
|
+
&.card,
|
|
199
|
+
&.drag {
|
|
200
|
+
display: inline-flex;
|
|
201
|
+
flex-direction: column;
|
|
349
202
|
align-items: center;
|
|
350
203
|
justify-content: center;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
transition: 0.3s all;
|
|
354
|
-
&:hover {
|
|
355
|
-
opacity: 1;
|
|
356
|
-
}
|
|
357
|
-
i {
|
|
358
|
-
color: #fff;
|
|
359
|
-
font-size: 16px;
|
|
360
|
-
cursor: pointer;
|
|
361
|
-
margin: 0 5px;
|
|
204
|
+
.upload-box-icon {
|
|
205
|
+
margin-bottom: 8px;
|
|
362
206
|
}
|
|
363
207
|
}
|
|
208
|
+
&.drag {
|
|
209
|
+
min-height: 100px;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
&:hover {
|
|
213
|
+
border: 1px solid var(--theme-color);
|
|
364
214
|
}
|
|
365
|
-
|
|
215
|
+
&.sh-upload-select {
|
|
216
|
+
display: inline-block;
|
|
217
|
+
vertical-align: top;
|
|
218
|
+
}
|
|
219
|
+
&.sh-upload-drag {
|
|
220
|
+
text-align: center;
|
|
221
|
+
cursor: pointer;
|
|
366
222
|
position: relative;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
padding: 5px 10px;
|
|
371
|
-
background: var(--hover-color);
|
|
372
|
-
height: 100%;
|
|
373
|
-
& + .list-file-item {
|
|
374
|
-
margin-top: 8px;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
&:hover {
|
|
225
|
+
border: 1px dashed var(--theme-color);
|
|
375
226
|
}
|
|
376
|
-
|
|
227
|
+
}
|
|
228
|
+
&.sh-upload-dragOver {
|
|
229
|
+
border: 2px dashed var(--theme-color);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
.upload-list {
|
|
233
|
+
display: block;
|
|
234
|
+
.upload-list-item {
|
|
235
|
+
display: flex;
|
|
236
|
+
align-items: stretch;
|
|
237
|
+
border: 1px solid var(--border-color);
|
|
238
|
+
background-color: var(--body-background);
|
|
239
|
+
position: relative;
|
|
240
|
+
.upload-list-title {
|
|
241
|
+
padding: 6px 10px;
|
|
377
242
|
flex: 1;
|
|
378
|
-
|
|
379
|
-
|
|
243
|
+
display: block;
|
|
244
|
+
text-overflow: ellipsis;
|
|
245
|
+
white-space: nowrap;
|
|
246
|
+
overflow: hidden;
|
|
380
247
|
}
|
|
381
|
-
.
|
|
248
|
+
.upload-list-action {
|
|
382
249
|
display: inline-flex;
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
250
|
+
align-items: center;
|
|
251
|
+
color: var(--theme-color);
|
|
252
|
+
.action-item {
|
|
253
|
+
display: inline-flex;
|
|
254
|
+
align-items: center;
|
|
255
|
+
padding: 0 5px;
|
|
256
|
+
height: 100%;
|
|
386
257
|
cursor: pointer;
|
|
387
|
-
|
|
388
|
-
|
|
258
|
+
&:hover {
|
|
259
|
+
background-color: var(--theme-active-color);
|
|
260
|
+
}
|
|
389
261
|
}
|
|
390
262
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
display: inline-block;
|
|
399
|
-
vertical-align: top;
|
|
400
|
-
border: 1px dashed var(--border-color);
|
|
401
|
-
text-align: center;
|
|
402
|
-
overflow: hidden;
|
|
403
|
-
}
|
|
404
|
-
&.list {
|
|
405
|
-
}
|
|
406
|
-
.upload-box-inner {
|
|
407
|
-
font-size: 26px;
|
|
408
|
-
display: inline-flex;
|
|
263
|
+
.upload-list-progress {
|
|
264
|
+
position: absolute;
|
|
265
|
+
left: 0;
|
|
266
|
+
right: 0;
|
|
267
|
+
top: 0;
|
|
268
|
+
bottom: 0;
|
|
269
|
+
display: flex;
|
|
409
270
|
align-items: center;
|
|
410
|
-
justify-content: center;
|
|
411
271
|
}
|
|
412
272
|
}
|
|
413
273
|
}
|
|
414
|
-
.ivu-icon {
|
|
415
|
-
font-size: inherit;
|
|
416
|
-
}
|
|
417
274
|
}
|
|
418
275
|
</style>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
function getError(action, option, xhr) {
|
|
2
|
+
const msg = `fail to post ${action} ${xhr.status}'`
|
|
3
|
+
const err = new Error(msg)
|
|
4
|
+
err.status = xhr.status
|
|
5
|
+
err.method = 'post'
|
|
6
|
+
err.url = action
|
|
7
|
+
return err
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getBody(xhr) {
|
|
11
|
+
const text = xhr.responseText || xhr.response
|
|
12
|
+
if (!text) {
|
|
13
|
+
return text
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(text)
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return text
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function upload(option) {
|
|
24
|
+
if (typeof XMLHttpRequest === 'undefined') {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const xhr = new XMLHttpRequest()
|
|
29
|
+
const action = option.action
|
|
30
|
+
|
|
31
|
+
if (xhr.upload) {
|
|
32
|
+
xhr.upload.onprogress = function progress(e) {
|
|
33
|
+
if (e.total > 0) {
|
|
34
|
+
e.percent = (e.loaded / e.total) * 100
|
|
35
|
+
}
|
|
36
|
+
option.onProgress(e)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const formData = new FormData()
|
|
41
|
+
|
|
42
|
+
if (option.data) {
|
|
43
|
+
Object.keys(option.data).map(key => {
|
|
44
|
+
formData.append(key, option.data[key])
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
formData.append(option.filename, option.file)
|
|
49
|
+
|
|
50
|
+
xhr.onerror = function error(e) {
|
|
51
|
+
option.onError(e)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
xhr.onload = function onload() {
|
|
55
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
56
|
+
return option.onError(getError(action, option, xhr), getBody(xhr))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
option.onSuccess(getBody(xhr))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
xhr.open('post', action, true)
|
|
63
|
+
|
|
64
|
+
if (option.withCredentials && 'withCredentials' in xhr) {
|
|
65
|
+
xhr.withCredentials = true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const headers = option.headers || {}
|
|
69
|
+
|
|
70
|
+
// if (headers['X-Requested-With'] !== null) {
|
|
71
|
+
// xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
72
|
+
// }
|
|
73
|
+
|
|
74
|
+
for (let item in headers) {
|
|
75
|
+
if (headers.hasOwnProperty(item) && headers[item] !== null) {
|
|
76
|
+
xhr.setRequestHeader(item, headers[item])
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
xhr.send(formData)
|
|
80
|
+
}
|