sh-view 1.7.3 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "1.7.3",
3
+ "version": "1.7.6",
4
4
  "description": "基于vxe-table、view-ui-plus二次封装",
5
5
  "main": "packages/index.js",
6
6
  "scripts": {
@@ -28,7 +28,7 @@
28
28
  "file-saver": "^2.0.5",
29
29
  "jspdf": "^2.5.1",
30
30
  "jszip": "^3.10.1",
31
- "sh-tools": "^1.2.2",
31
+ "sh-tools": "^1.2.6",
32
32
  "tinymce": "^5.10.5",
33
33
  "view-ui-plus": "^1.3.14",
34
34
  "vue": "^3.3.4",
@@ -30,7 +30,7 @@
30
30
 
31
31
  <script>
32
32
  export default {
33
- name: 'ShLayout',
33
+ name: 'ShSplit',
34
34
  components: {},
35
35
  props: {
36
36
  split: {
@@ -1,102 +1,54 @@
1
1
  <template>
2
- <div class="sh-upload" :class="upClass">
3
- <u-list
4
- v-if="listType === 'card'"
5
- :upload-list="uploadList"
6
- :list-type="listType"
7
- :type="type"
8
- :is-form-data="isFormData"
9
- :disabled="disabled"
10
- :preview="preview"
11
- :up-styles="upStyles"
12
- :up-class="upClass"
13
- @delete="handleFileRemove"></u-list>
14
- <div v-show="uploadList.length < limit" class="sh-upload-list" :style="upStyles" :class="upClass">
15
- <Upload
16
- ref="upload"
17
- class="upload-box-component"
18
- :class="upClass"
19
- :action="action"
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
- <template v-else-if="listType === 'card'">
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
- <u-list
45
- v-if="listType === 'list'"
46
- :upload-list="uploadList"
47
- :width="width"
48
- :height="height"
49
- :list-type="listType"
50
- :type="type"
51
- :is-form-data="isFormData"
52
- :disabled="disabled"
53
- :preview="preview"
54
- :up-styles="upStyles"
55
- :up-class="upClass"
56
- @delete="handleFileRemove"></u-list>
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 UList from './components/u-list.vue'
43
+ import mixin from './js/mixin'
62
44
  export default {
63
45
  name: 'ShUpload',
64
- components: {
65
- UList
66
- },
46
+ mixins: [mixin],
67
47
  props: {
68
- isFormData: {
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
- limitBytes: {
113
- type: Number,
114
- default: 2097152
64
+ card: {
65
+ type: Boolean
115
66
  },
116
- accept: {
67
+ drag: {
68
+ type: Boolean
69
+ },
70
+ icon: {
117
71
  type: String,
118
- default: '.doc,.docx,.xls,.xlsx,.txt,.pdf,.jpg,.jpeg,.png,.txt,.7z,.zip,.rar'
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
- inputname: {
127
- type: String,
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', 'progress', 'success', 'error', 'file-delete'],
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.listType === 'card' ? { width: `${this.width}px`, height: `${this.height}px` } : {}
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
- limitBytes: this.limitBytes,
186
- fileSizeError: '文件大小不能超过' + this.limitBytes / (1024 * 1024) + 'M',
187
- fileFormat: this.accept.split(','),
188
- fileTypeError: '格式不正确,请上传' + this.accept + '文件'
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
- uploadList: {
203
- handler: function (val, oldVal) {
204
- this.$emit('update:modelValue', val)
205
- },
206
- immediate: false,
207
- deep: true
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
- uploadProgress(event, file, fileList) {
215
- this.$emit('progress', event, file, fileList)
216
- },
217
- // 上传成功
218
- uploadSuccess(res, file, fileList) {
219
- this.$emit('success', res, file, fileList)
220
- },
221
- // 上传失败
222
- uploadError(error, file, fileList) {
223
- this.$emit('error', error, file, fileList)
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
- return this.action !== '-'
251
- },
252
- // 组件上传formdata进行内部预览图片
253
- handleFilePreviewData(file) {
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 (!that.serverConfig.type) {
264
- that.msgerror('上传未配置请求方式!')
144
+ if (!action) {
145
+ this.msginfo('上传地址不能为空')
265
146
  return
266
147
  }
267
- let axiosData = new FormData()
268
- let axiosHeader = Object.assign({}, that.headers)
269
- axiosHeader['Content-Type'] = 'multipart/form-data'
270
- axiosData.append('file', file)
271
- if (that.params) {
272
- Object.keys(that.params).forEach(key => {
273
- axiosData.append(key, that.params[key])
274
- })
275
- }
276
- try {
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
- handleFileRemove(data) {
290
- const that = this
291
- that.msgconfirm({
292
- content: '确定要删除吗?'
293
- }).then(() => {
294
- const dataIndex = this.uploadList.indexOf(data)
295
- that.uploadList.splice(dataIndex, 1)
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
- .sh-upload-list {
312
- border-radius: 4px;
313
- background: var(--body-background);
314
- position: relative;
315
- &.card {
316
- display: inline-block;
317
- vertical-align: top;
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
- &.list {
325
- & + .sh-upload-list.list {
326
- margin-top: 8px;
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
- img {
330
- width: 100%;
331
- height: 100%;
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
- font-size: 20px;
352
- opacity: 0;
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
- .list-file-item {
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
- display: flex;
368
- align-items: center;
369
- justify-content: space-between;
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
- .file-title {
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
- margin-right: 10px;
379
- line-height: 1.2;
243
+ display: block;
244
+ text-overflow: ellipsis;
245
+ white-space: nowrap;
246
+ overflow: hidden;
380
247
  }
381
- .file-action {
248
+ .upload-list-action {
382
249
  display: inline-flex;
383
- flex-wrap: nowrap;
384
- .file-action-item {
385
- display: inline-block;
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
- color: var(--theme-color);
388
- margin-left: 8px;
258
+ &:hover {
259
+ background-color: var(--theme-active-color);
260
+ }
389
261
  }
390
262
  }
391
- }
392
- .upload-box-component {
393
- border-radius: 4px;
394
- cursor: pointer;
395
- width: 100%;
396
- height: 100%;
397
- &.card {
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>