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.
@@ -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
+ }
@@ -0,0 +1,257 @@
1
+ // 上传组件通用方法
2
+
3
+ import ajax from './ajax'
4
+
5
+ export default {
6
+ props: {
7
+ modelValue: {
8
+ type: Array,
9
+ default() {
10
+ return []
11
+ }
12
+ },
13
+ action: {
14
+ type: String,
15
+ default: 'fileservice/v2/upload'
16
+ },
17
+ headers: {
18
+ type: Object,
19
+ default() {
20
+ return {}
21
+ }
22
+ },
23
+ disabled: {
24
+ type: Boolean,
25
+ default: false
26
+ },
27
+ maxSize: {
28
+ type: Number,
29
+ default: 1024 * 2 // 文件大小限制,单位 kb
30
+ },
31
+ accept: {
32
+ type: String,
33
+ default: '.doc,.docx,.xls,.xlsx,.txt,.pdf,.jpg,.jpeg,.png,.txt,.7z,.zip,.rar'
34
+ },
35
+ name: {
36
+ type: String,
37
+ default: 'file'
38
+ },
39
+ beforeUpload: {
40
+ type: Function
41
+ },
42
+ webkitdirectory: {
43
+ type: Boolean,
44
+ default: false // 是否开启选择文件夹,部分浏览器适用
45
+ },
46
+ withCredentials: {
47
+ type: Boolean,
48
+ default: false // 支持发送 cookie 凭证信息
49
+ },
50
+ paste: {
51
+ type: Boolean,
52
+ default: false // 是否支持粘贴上传文件
53
+ },
54
+ format: {
55
+ type: Array,
56
+ default() {
57
+ return []
58
+ }
59
+ },
60
+ onFormatError: {
61
+ type: Function
62
+ },
63
+ onExceededSize: {
64
+ type: Function
65
+ },
66
+ onProgress: {
67
+ type: Function,
68
+ default() {}
69
+ },
70
+ onSuccess: {
71
+ type: Function,
72
+ default() {}
73
+ },
74
+ onError: {
75
+ type: Function,
76
+ default() {}
77
+ },
78
+ onRemove: {
79
+ type: Function,
80
+ default() {}
81
+ },
82
+ onPreview: {
83
+ type: Function,
84
+ default() {}
85
+ },
86
+ onDownload: {
87
+ type: Function,
88
+ default() {}
89
+ }
90
+ },
91
+ data() {
92
+ return {
93
+ tempIndex: 1,
94
+ dragOver: false,
95
+ fileList: []
96
+ }
97
+ },
98
+ methods: {
99
+ progressConfig(file) {
100
+ return {
101
+ textInside: true,
102
+ strokeWidth: 20,
103
+ percent: parseInt(file.percentage, 10),
104
+ status: file.status
105
+ }
106
+ },
107
+ handleClick() {
108
+ if (this.disabled) return
109
+ this.$refs.input.click()
110
+ },
111
+ handleChange(e) {
112
+ const files = e.target.files
113
+ if (!files) return
114
+ this.uploadFiles(files)
115
+ this.$refs.input.value = null
116
+ },
117
+ handleStart(file) {
118
+ file.uid = Date.now() + this.tempIndex++
119
+ const _file = {
120
+ status: 'active',
121
+ name: file.name,
122
+ size: file.size,
123
+ percentage: 0,
124
+ uid: file.uid,
125
+ showProgress: true
126
+ }
127
+ this.fileList.push(_file)
128
+ },
129
+ handlePaste(e) {
130
+ if (this.disabled) return
131
+ if (this.paste) {
132
+ this.uploadFiles(e.clipboardData.files)
133
+ }
134
+ },
135
+ handleProgress(e, file) {
136
+ const _file = this.getFile(file)
137
+ this.onProgress(e, _file, this.fileList)
138
+ _file.percentage = e.percent || 0
139
+ },
140
+ handleSuccess(res, file) {
141
+ const _file = this.getFile(file)
142
+ if (_file) {
143
+ _file.status = 'success'
144
+ _file.response = res
145
+ this.emitValue()
146
+ this.onSuccess(res, _file, this.fileList)
147
+ setTimeout(() => {
148
+ _file.showProgress = false
149
+ }, 1000)
150
+ }
151
+ },
152
+ handleError(err, response, file) {
153
+ const _file = this.getFile(file)
154
+ const fileList = this.fileList
155
+ _file.status = 'wrong'
156
+ fileList.splice(fileList.indexOf(_file), 1)
157
+ this.onError(err, response, file)
158
+ },
159
+ handleRemove(file) {
160
+ const fileList = this.fileList
161
+ fileList.splice(fileList.indexOf(file), 1)
162
+ this.emitValue()
163
+ this.onRemove(file, fileList)
164
+ },
165
+ handlePreview(file) {
166
+ const fileList = this.fileList
167
+ fileList.splice(fileList.indexOf(file), 1)
168
+ this.onRemove(file, fileList)
169
+ },
170
+ handleDownload(file) {
171
+ const fileList = this.fileList
172
+ fileList.splice(fileList.indexOf(file), 1)
173
+ this.onDownload(file, fileList)
174
+ },
175
+ onDrop(e) {
176
+ this.dragOver = false
177
+ if (this.disabled) return
178
+ this.uploadFiles(e.dataTransfer.files)
179
+ },
180
+ uploadFiles(files) {
181
+ let postFiles = Array.prototype.slice.call(files)
182
+ if (!this.multiple) postFiles = postFiles.slice(0, 1)
183
+ if (postFiles.length === 0) return
184
+ postFiles.forEach(file => {
185
+ this.upload(file)
186
+ })
187
+ },
188
+ upload(file) {
189
+ if (!this.beforeUpload) {
190
+ return this.post(file)
191
+ }
192
+ const before = this.beforeUpload(file)
193
+ if (before && before.then) {
194
+ before.then(processedFile => {
195
+ if (Object.prototype.toString.call(processedFile) === '[object File]') {
196
+ this.post(processedFile)
197
+ } else {
198
+ this.post(file)
199
+ }
200
+ })
201
+ } else if (before !== false) {
202
+ this.post(file)
203
+ }
204
+ },
205
+ async post(file) {
206
+ let { headers, name, params, action, withCredentials } = this
207
+ if (this.validateFile) {
208
+ let valResult = this.validateFile(file)
209
+ if (!valResult) return
210
+ }
211
+ this.handleStart(file)
212
+ ajax({
213
+ headers: headers,
214
+ withCredentials: withCredentials,
215
+ file: file,
216
+ data: params,
217
+ filename: name,
218
+ action: action,
219
+ onProgress: e => {
220
+ this.handleProgress(e, file)
221
+ },
222
+ onSuccess: res => {
223
+ this.handleSuccess(res, file)
224
+ },
225
+ onError: (err, response) => {
226
+ this.handleError(err, response, file)
227
+ }
228
+ })
229
+ },
230
+ getFile(file) {
231
+ const fileList = this.fileList
232
+ let target
233
+ fileList.every(item => {
234
+ target = file.uid === item.uid ? item : null
235
+ return !target
236
+ })
237
+ return target
238
+ },
239
+ clearFiles() {
240
+ this.fileList = []
241
+ this.emitValue()
242
+ },
243
+ emitValue() {
244
+ let list = this.getModelValue ? this.getModelValue() : this.fileList
245
+ this.$emit('update:modelValue', list)
246
+ }
247
+ },
248
+ watch: {
249
+ modelValue: {
250
+ handler(fileList) {
251
+ this.fileList = fileList
252
+ },
253
+ immediate: true,
254
+ deep: true
255
+ }
256
+ }
257
+ }
@@ -51,38 +51,34 @@ const shMethods = {
51
51
  // 初始化
52
52
  initCreated() {
53
53
  this.initFormItems()
54
- this.initFormData()
55
54
  },
56
55
  // 初始化表单字段
57
56
  initFormData() {
58
- const that = this
59
- that.$vUtils.eachTree(that.items, item => {
57
+ const { items, data, $vUtils } = this
58
+ $vUtils.eachTree(items, item => {
60
59
  let renderProps = item.renderProps || item.itemRender?.props || {}
61
- if (!that.$vUtils.isNone(renderProps?.defaultValue) && that.$vUtils.isNone(that.$vUtils.get(that.data, item.field))) {
62
- that.$vUtils.set(that.data, item.field, renderProps.defaultValue || null)
60
+ if (!$vUtils.isNone(renderProps?.defaultValue) && $vUtils.isNone($vUtils.get(data, item.field))) {
61
+ $vUtils.set(data, item.field, renderProps.defaultValue)
63
62
  }
64
63
  })
65
64
  },
66
65
  // 初始化表单项
67
66
  initFormItems(items) {
68
- const that = this
69
- let originItems = items || that.items
70
- let formItemsArr = [] // 表单项
71
- let rules = {} // 校验规则
72
- that.generateFormItem(originItems, formItemsArr, rules)
73
- that.initEditRules(rules)
74
- that.formItems = formItemsArr
67
+ let originItems = items || this.items
68
+ let { formItemsArr, rules } = this.generateFormItem(originItems)
69
+ this.initEditRules(rules)
70
+ this.formItems = formItemsArr
75
71
  this.initFormData()
76
72
  },
77
73
  // 初始化验证规则
78
74
  initEditRules(rules) {
79
- const that = this
80
- if (rules && that.$vUtils.isPlainObject(rules)) {
75
+ const { formRules, $vUtils } = this
76
+ if (rules && $vUtils.isPlainObject(rules)) {
81
77
  Object.keys(rules).forEach(key => {
82
- if (that.formRules[key]) {
83
- that.formRules[key] = Array.from(new Set(that.formRules[key].concat(rules[key])))
78
+ if (formRules[key]) {
79
+ formRules[key] = Array.from(new Set(formRules[key].concat(rules[key])))
84
80
  } else {
85
- that.formRules[key] = rules[key]
81
+ formRules[key] = rules[key]
86
82
  }
87
83
  })
88
84
  }
@@ -102,64 +98,55 @@ const shMethods = {
102
98
  isTrue(value) {
103
99
  return String(value) === '1' || String(value).toLowerCase() === 'true'
104
100
  },
105
- // 生成全表头
106
- generateColumnsAll(columns, resultColumns = []) {
107
- columns.forEach((column, index) => {
108
- if (column.children && Array.isArray(column.children) && column.children.length) {
109
- this.generateColumnsAll(column.children, resultColumns)
110
- } else {
111
- resultColumns.push(column)
112
- }
113
- })
114
- return resultColumns
115
- },
116
101
  // 自动生成表单渲染项
117
- generateFormItem(formItems = [], itemArr = [], rules = {}) {
118
- const that = this
119
- formItems.forEach(ori => {
120
- let tar = Object.assign({}, that.itemConfigDefault, ori)
102
+ generateFormItem(items = []) {
103
+ const { itemConfigDefault, isItemTitle, titleConfigDefault, readonly, disabled, isTrue, getDefaultMessage, $vUtils } = this
104
+ let formItemsArr = []
105
+ let rules = {}
106
+ $vUtils.eachTree(items, ori => {
107
+ let tar = Object.assign({}, itemConfigDefault, ori)
121
108
  if (ori.children && ori.children.length > 0) {
122
109
  let childrenArr = []
123
- that.generateFormItem(ori.children, childrenArr, rules)
124
- if (that.isItemTitle) {
110
+ if (isItemTitle) {
125
111
  // 补入标题渲染器
126
- let groupTitleRender = Object.assign({}, that.titleConfigDefault, tar, { span: 24, field: '' })
112
+ let groupTitleRender = Object.assign({}, titleConfigDefault, tar, { span: 24, field: '' })
127
113
  delete groupTitleRender.children
128
114
  childrenArr.unshift(groupTitleRender)
129
115
  }
130
116
  tar.children = childrenArr
131
117
  if (!tar.span) tar.span = 24
132
- itemArr.push(tar)
118
+ formItemsArr.push(tar)
133
119
  } else {
134
120
  let renderConfig = {
135
121
  name: ori.renderName || '$vInput',
136
122
  props: Object.assign({}, ori.renderProps || {})
137
123
  }
138
- if (that.readonly || that.disabled) {
124
+ if (readonly || disabled) {
139
125
  renderConfig.props.disabled = true
140
126
  }
141
127
  tar.itemRender = Object.assign({}, renderConfig, ori.itemRender || {})
142
128
  // 首先提取校验配置
143
- if (that.isTrue(ori['renderRequire'])) {
129
+ if (isTrue(ori['renderRequire'])) {
144
130
  // 若配置了校验参数则走校验参数,没配置则给默认校验条件
145
131
  if (ori['requireProps'] && Array.isArray(ori['requireProps']) && ori['requireProps'].length > 0) {
146
132
  rules[ori['field']] = ori['requireProps']
147
133
  } else {
148
134
  let dataType = 'string'
149
135
  let arrayType = ['$vCheckgroup', '$vUpload', '$vTable']
150
- if (arrayType.includes(ori['renderName']) || ((ori['renderName'] === '$vSelect' || ori['renderName'] === '$vTree') && that.isTrue(renderConfig.props.multiple))) {
136
+ if (arrayType.includes(ori['renderName']) || ((ori['renderName'] === '$vSelect' || ori['renderName'] === '$vTree') && isTrue(renderConfig.props.multiple))) {
151
137
  dataType = 'array'
152
138
  }
153
- rules[ori['field']] = [{ required: true, message: that.getDefaultMessage(ori['renderName'], ori['title']), type: dataType }]
139
+ rules[ori['field']] = [{ required: true, message: getDefaultMessage(ori['renderName'], ori['title']), type: dataType }]
154
140
  }
155
141
  }
156
142
  // 表单不支持编辑渲染过滤
157
143
  let notRenderName = ['seq', 'checkbox', 'radio', '$vImg', '$vHref', '$vGlobalOption']
158
144
  if (!((ori.renderName && notRenderName.includes(ori.renderName)) || notRenderName.includes(ori.type))) {
159
- itemArr.push(tar)
145
+ formItemsArr.push(tar)
160
146
  }
161
147
  }
162
148
  })
149
+ return { formItemsArr, rules }
163
150
  }
164
151
  }
165
152
 
@@ -1,16 +1,23 @@
1
1
  <template>
2
2
  <div class="sh-list">
3
3
  <template v-if="$slots.header"><slot name="header"></slot></template>
4
- <vxe-list ref="vxeList" :data="dataSourse" :size="size" :class-name="className" :loading="loading" :height="height" :auto-resize="autoResize" :sync-resize="syncResize" :scroll-y="scrollY">
4
+ <vxe-list ref="vxeList" v-bind="listConfig">
5
5
  <template #default="{ items }">
6
6
  <sh-empty v-if="items.length === 0 && !loading" :no-data-icon="noDataIcon" :no-data-text="noDataText"></sh-empty>
7
- <Row :gutter="grid.gutter">
7
+ <Row v-if="grid" :gutter="grid.gutter">
8
8
  <Col v-for="(item, itemindex) in items" :key="itemindex" v-bind="grid">
9
9
  <div class="sh-list-item" :class="itemClassName">
10
- <slot name="item" :item="item"></slot>
10
+ <slot name="item" v-bind="item"></slot>
11
11
  </div>
12
12
  </Col>
13
13
  </Row>
14
+ <template v-else>
15
+ <template v-for="(item, itemindex) in items" :key="itemindex">
16
+ <div class="sh-list-item" :class="itemClassName">
17
+ <slot name="item" v-bind="item"></slot>
18
+ </div>
19
+ </template>
20
+ </template>
14
21
  </template>
15
22
  </vxe-list>
16
23
  <template v-if="$slots.footer"><slot name="footer"></slot></template>
@@ -67,7 +74,7 @@ export default {
67
74
  type: String
68
75
  },
69
76
  grid: {
70
- type: Object,
77
+ type: [Object, Boolean],
71
78
  default() {
72
79
  return { gutter: 0, span: 24 }
73
80
  }
@@ -84,7 +91,20 @@ export default {
84
91
  listPagerConfig: {}
85
92
  }
86
93
  },
87
- computed: {},
94
+ computed: {
95
+ listConfig() {
96
+ return {
97
+ data: this.dataSourse,
98
+ size: this.size,
99
+ className: this.className,
100
+ loading: this.loading,
101
+ height: this.height,
102
+ autoResize: this.autoResize,
103
+ syncResize: this.syncResize,
104
+ scrollY: this.scrollY
105
+ }
106
+ }
107
+ },
88
108
  watch: {
89
109
  pagerConfig: {
90
110
  handler(newvalue, oldValue) {