Parcourir la source

Merge branch 'gyj' of SH-Arbitrate/miniapp into dev

gaogaoyujie il y a 2 ans
Parent
révision
835dbac9cd

+ 43
- 21
pages/handlecase/component/list.vue Voir le fichier

@@ -153,17 +153,27 @@
153 153
 					batchNumber:"",
154 154
 					caseFlowId:this.defalutVal.caseFlowId
155 155
 				}
156
-				caseAppSubmit(onsubmitVal).then(res => {
157
-					uni.showToast({
158
-						title: '提交成功',
159
-						icon: 'none',
160
-						duration: 1000
161
-					})
162
-					uni.navigateTo({
163
-						url:'/pages/handlecase/index'
164
-					})
165
-					//this.$emit("getList");
166
-				})
156
+				uni.showModal({
157
+				  title: '提示',
158
+				  content: '您确定要提交案件',
159
+				  success: function (res) {
160
+				    if (res.confirm) {
161
+				      // console.log('用户点击确定');
162
+					   caseAppSubmit(onsubmitVal).then(res => {
163
+					   	uni.showToast({
164
+					   		title: '提交成功',
165
+					   		icon: 'none',
166
+					   		duration: 1000
167
+					   	})
168
+					   	uni.navigateTo({
169
+					   		url:'/pages/handlecase/index'
170
+					   	})
171
+					   })
172
+				    } else if (res.cancel) {
173
+				      // console.log('用户点击取消');
174
+				    }
175
+				  }
176
+				});
167 177
 			},
168 178
 			// 修改
169 179
 			modify() {
@@ -178,16 +188,28 @@
178 188
 					batchNumber:"",
179 189
 					caseFlowId:this.defalutVal.caseFlowId
180 190
 				}
181
-				caseDelete(objValue).then(res =>{
182
-					uni.showToast({
183
-						title: '删除成功',
184
-						icon: 'none',
185
-						duration: 1000
186
-					})
187
-					uni.navigateTo({
188
-						url:'/pages/handlecase/index'
189
-					})
190
-				}) 
191
+				uni.showModal({
192
+				  title: '提示',
193
+				  content: '您确定要删除案件',
194
+				  success: function (res) {
195
+				    if (res.confirm) {
196
+				      // console.log('用户点击确定');
197
+					  caseDelete(objValue).then(res =>{
198
+					    	uni.showToast({
199
+					    		title: '删除成功',
200
+					    		icon: 'none',
201
+					    		duration: 1000
202
+					    	})
203
+					    	uni.navigateTo({
204
+					    		url:'/pages/handlecase/index'
205
+					    	})
206
+					    }) 
207
+				    } else if (res.cancel) {
208
+				      // console.log('用户点击取消');
209
+				    }
210
+				  }
211
+				});
212
+				
191 213
 			},
192 214
 		},
193 215
 		created() {

+ 1
- 1
pages/handlecase/component/newlyAddedCase.vue Voir le fichier

@@ -385,7 +385,7 @@
385 385
 				uni.navigateBack({
386 386
 					delta: 1
387 387
 				})
388
-			}
388
+			},
389 389
 		},
390 390
 		onLoad(data) {
391 391
 			this.ids = data.id

+ 114
- 0
uni_modules/lsj-upload/changelog.md Voir le fichier

@@ -0,0 +1,114 @@
1
+## 2.2.9(2023-06-01)
2
+优化:将是否多选与count字段解绑(原逻辑是count>1为允许多选),改为新增multiple属性控制是否多选。
3
+## 2.2.8(2023-06-01)
4
+修复上版本提交时accept测试值未删除导致h5端只能选择图片的问题。
5
+## 2.2.7(2023-05-06)
6
+应群友建议,当instantly为true时,触发change事件后延迟1000毫秒再自动上传,方便动态修改参数,其实个人还是建议想在change事件动态设置参数的伙伴将instantly设置为false,修改参数后手动调用upload()
7
+## 2.2.6(2023-02-09)
8
+修复多个文件同时选择时返回多次change回调的问题
9
+## 2.2.5(2022-12-27)
10
+1.修复多选文件时未能正常校验数量的问题;
11
+2.app端与H5端支持单选或多选文件,通过count数量控制,超过1开启多选。
12
+## 2.2.4(2022-12-27)
13
+1.修复多选文件时未能正常校验数量的问题;
14
+2.app端修复多选只取到第一个文件的问题。
15
+## 2.2.3(2022-12-06)
16
+修复手动调用show()导致count失效的问题
17
+## 2.2.2(2022-12-01)
18
+Vue3自行修改兼容
19
+## 2.2.1(2022-10-19)
20
+修复childId警告提示
21
+## 2.2.0(2022-10-10)
22
+更新app端webview窗口参数clidId,默认值添加时间戳保证唯一性
23
+## 2.1.9(2022-07-13)
24
+[修复] app端选择文件后初始化设置的文件列表被清空问题
25
+## 2.1.8(2022-07-13)
26
+[新增] ref方法初始化文件列表,用于已提交后再次编辑时需带入已上传文件:setFiles(files),可传入数组或Map对象,传入格式请与组件选择返回格式保持一致,且name为必须属性。
27
+## 2.1.7(2022-07-12)
28
+修复ios端偶现创建webview初始化参数未生效的问题
29
+## 2.1.6(2022-07-11)
30
+[修复]:修复上个版本更新导致nvue窗口组件不能选择文件的问题;
31
+[新增]:
32
+1.应群友建议(填写禁止格式太多)格式限制formats由原来填写禁止选择的格式改为填写允许被选择的格式;
33
+2.应群友建议(增加上传结束回调事件),上传结束回调事件@uploadEnd
34
+3.如能帮到你请留下你的免费好评,组件使用过程中有问题可以加QQ群交流,至于Map对象怎么使用这类前端基础问题请自行百度
35
+## 2.1.5(2022-07-01)
36
+app端组件销毁时添加自动销毁webview功能,避免v-if销毁组件的情况控件还能被点击的问题
37
+## 2.1.4(2022-07-01)
38
+修复小程序端回显问题
39
+## 2.1.3(2022-06-30)
40
+回调事件返回参数新增path字段(文件临时地址),用于回显
41
+## 2.1.2(2022-06-16)
42
+修复APP端Tabbar窗口无法选择文件的问题
43
+## 2.1.1(2022-06-16)
44
+优化:
45
+1.组件优化为允许在v-if中使用;
46
+2.允许option直接在data赋值,不再强制在onRead中初始化;
47
+## 2.1.0(2022-06-13)
48
+h5 pc端更改为单次可多选
49
+## 2.0.9(2022-06-10)
50
+更新演示内容,部分同学不知道怎么获取服务端返回的数据
51
+## 2.0.8(2022-06-09)
52
+优化动态更新上传参数函数,具体查看下方说明:动态更新参数演示
53
+## 2.0.7(2022-06-07)
54
+新增wxFileType属性,用于小程序端选择附件时可选文件类型
55
+## 2.0.6(2022-06-07)
56
+修复小程序端真机选择文件提示失败的问题
57
+## 2.0.5(2022-06-02)
58
+优化小程序端调用hide()后未阻止触发文件选择问题
59
+## 2.0.4(2022-06-01)
60
+优化APP端选择器初始定位
61
+## 2.0.3(2022-05-31)
62
+修复nvue窗口选择文件报错问题 
63
+## 2.0.2(2022-05-20)
64
+修复ios端opiton设置过早未传入webview导致不自动上传问题
65
+## 2.0.1(2022-05-19)
66
+修复APP端子窗口点击选择文件不响应问题
67
+## 2.0.0(2022-05-18)
68
+此次组件更新至2.0版本,与1.0版本使用上略有差异,已使用1.0的同学请自行斟酌是否需要升级!
69
+部分差异:
70
+一、 2.0新增异步触发上传功能;
71
+二、2.0新增文件批量上传功能;
72
+三、2.0优化option,剔除属性,只保留上传接口所需字段,且允许异步更改option的值;
73
+四、组件增加size(文件大小限制)、count(文件个数限制)、formats(文件后缀限制)、accept(文件类型限制)、instantly(是否立即自动上传)、debug(日志打印)等属性;
74
+五、回调事件取消input事件、callback事件,新增change事件和progress事件;
75
+六、ref事件新增upload事件、clear事件;
76
+七、优化组件代码,show和hide函数改为显示隐藏,不再重复开关webview;
77
+
78
+## 1.2.3(2022-03-22)
79
+修复Demo里传入待完善功能[手动上传属性manual=true]导致不自动上传的问题,手动提交上传待下个版本更新
80
+## 1.2.2(2022-02-21)
81
+修复上版本APP优化导致H5和小程序端不自动初始化的问题,此次更新仅修复此问题。异步提交功能下个版本更新~
82
+## 1.2.1(2022-01-25)
83
+QQ1群已满,已开放2群:469580165
84
+## 1.2.0(2021-12-09)
85
+优化APP端页面中DOM重排后每次需要重新定位的问题
86
+## 1.1.1(2021-12-09)
87
+优化,与上版本使用方式有改变,请检查后确认是否需要更新,create更名为show,  close更名为hide,取消初始化时手动create, 传参方式改为props=>option
88
+## 1.1.0(2021-12-09)
89
+新增refresh方法,用于DOM发生重排时重新定位控件(APP端)
90
+## 1.0.9(2021-07-15)
91
+修复上传进度未同步渲染,直接返回100%的BUG
92
+## 1.0.8(2021-07-12)
93
+修复H5端传入height和width未生效的bug
94
+## 1.0.7(2021-07-07)
95
+修复h5和小程序端上传完成callback未返回fileName字段问题
96
+## 1.0.6(2021-07-07)
97
+修复h5端提示信息debug
98
+## 1.0.5(2021-06-29)
99
+感谢小伙伴找出bug,上传成功回调success未置为true,已修复
100
+## 1.0.4(2021-06-28)
101
+新增兼容APP,H5,小程序手动关闭控件,关闭后不再弹出文件选择框,需要重新create再次开启
102
+## 1.0.3(2021-06-28)
103
+close增加条件编译,除app端外不需要close
104
+## 1.0.2(2021-06-28)
105
+1.修复页面滚动位置后再create控件导致控件位置不正确的问题;
106
+2.修复nvue无法create控件;
107
+3.示例项目新增nvue使用案例;
108
+## 1.0.1(2021-06-28)
109
+因为有的朋友不清楚app端切换tab时应该怎么处理webview,现重新上传一版示例项目,需要做tab切换的朋友可以导入示例项目查看
110
+## 1.0.0(2021-06-25)
111
+此插件为l-file插件中上传功能改版,更新内容为:
112
+1. 按钮内嵌入页面,不再强制固定底部,可跟随页面滚动
113
+2.无需再单独弹框点击上传,减去中间层
114
+3.通过slot自定义按钮样式

+ 401
- 0
uni_modules/lsj-upload/components/lsj-upload/LsjFile.js Voir le fichier

@@ -0,0 +1,401 @@
1
+export class LsjFile {
2
+	constructor(data) {
3
+		this.dom = null;
4
+		// files.type = waiting(等待上传)|| loading(上传中)|| success(成功) || fail(失败)
5
+		this.files = new Map();
6
+		this.debug = data.debug || false;
7
+		this.id = data.id;
8
+		this.width = data.width;
9
+		this.height = data.height;
10
+		this.option = data.option;
11
+		this.instantly = data.instantly;
12
+		this.prohibited = data.prohibited;
13
+		this.onchange = data.onchange;
14
+		this.onprogress = data.onprogress;
15
+		this.uploadHandle = this._uploadHandle;
16
+		// #ifdef MP-WEIXIN
17
+		this.uploadHandle = this._uploadHandleWX;
18
+		// #endif
19
+	}
20
+	
21
+	
22
+	/**
23
+	 * 创建File节点
24
+	 * @param {string}path webview地址
25
+	 */
26
+	create(path) {
27
+		if (!this.dom) {
28
+			// #ifdef H5
29
+				let dom = document.createElement('input');
30
+				dom.type = 'file'
31
+				dom.value = ''
32
+				dom.style.height = this.height
33
+				dom.style.width = this.width
34
+				dom.style.position = 'absolute'
35
+				dom.style.top = 0
36
+				dom.style.left = 0
37
+				dom.style.right = 0
38
+				dom.style.bottom = 0
39
+				dom.style.opacity = 0
40
+				dom.style.zIndex = 999
41
+				dom.accept = this.prohibited.accept;
42
+				if (this.prohibited.multiple) {
43
+				dom.multiple = 'multiple';
44
+				}
45
+				dom.onchange = event => {
46
+					for (let file of event.target.files) {
47
+						if (this.files.size >= this.prohibited.count) {
48
+							this.toast(`只允许上传${this.prohibited.count}个文件`);
49
+							this.dom.value = '';
50
+							break;
51
+						}
52
+						this.addFile(file);
53
+					}
54
+					
55
+					this._uploadAfter();
56
+					
57
+					this.dom.value = '';
58
+				};
59
+				this.dom = dom;
60
+			// #endif
61
+		
62
+			// #ifdef APP-PLUS
63
+				let styles = {
64
+					top: '-200px',
65
+					left: 0,
66
+					width: '1px',
67
+					height: '200px',
68
+					background: 'transparent' 
69
+				};
70
+				let extras = {
71
+					debug: this.debug,
72
+					instantly: this.instantly,
73
+					prohibited: this.prohibited,
74
+				}
75
+				this.dom = plus.webview.create(path, this.id, styles,extras);
76
+				this.setData(this.option); 
77
+				this._overrideUrlLoading();
78
+			// #endif
79
+			return this.dom;
80
+		}
81
+	}
82
+	
83
+	
84
+	/**
85
+	 * 设置上传参数
86
+	 * @param {object|string}name 上传参数,支持a.b 和 a[b]
87
+	 */
88
+	setData() {
89
+		let [name,value = ''] = arguments;
90
+		if (typeof name === 'object') {
91
+			Object.assign(this.option,name);
92
+		}
93
+		else {
94
+			this._setValue(this.option,name,value);
95
+		}
96
+		
97
+		this.debug&&console.log(JSON.stringify(this.option));
98
+		
99
+		// #ifdef APP-PLUS
100
+			this.dom.evalJS(`vm.setData('${JSON.stringify(this.option)}')`);
101
+		// #endif
102
+	}
103
+	
104
+	/**
105
+	 * 上传
106
+	 * @param {string}name 文件名称
107
+	 */
108
+	async upload(name='') {
109
+		if (!this.option.url) {
110
+			throw Error('未设置上传地址');
111
+		}
112
+		
113
+		// #ifndef APP-PLUS
114
+			if (name && this.files.has(name)) {
115
+				await this.uploadHandle(this.files.get(name));
116
+			}
117
+			else {
118
+				for (let item of this.files.values()) {
119
+					if (item.type === 'waiting' || item.type === 'fail') {
120
+						await this.uploadHandle(item);
121
+					}
122
+				}
123
+			}
124
+		// #endif
125
+		
126
+		// #ifdef APP-PLUS
127
+			this.dom&&this.dom.evalJS(`vm.upload('${name}')`);
128
+		// #endif
129
+	}
130
+	
131
+	// 选择文件change
132
+	addFile(file,isCallChange) {
133
+		
134
+		let name = file.name;
135
+		this.debug&&console.log('文件名称',name,'大小',file.size);
136
+		
137
+		if (file) {
138
+			// 限制文件格式
139
+			let path = '';
140
+			let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase();
141
+			let formats = this.prohibited.formats.toLowerCase();
142
+			
143
+			
144
+			// #ifndef MP-WEIXIN
145
+				path = URL.createObjectURL(file);
146
+			// #endif
147
+			// #ifdef MP-WEIXIN
148
+				path = file.path;
149
+			// #endif
150
+			if (formats&&!formats.includes(suffix)) {
151
+				this.toast(`不支持上传${suffix.toUpperCase()}格式文件`);
152
+				return false;
153
+			}
154
+			// 限制文件大小
155
+			if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) {
156
+				this.toast(`附件大小请勿超过${this.prohibited.size}M`)
157
+				return false;
158
+			}
159
+			this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'});
160
+			return true;
161
+		}
162
+	}
163
+	
164
+	/**
165
+	 * 移除文件
166
+	 * @param {string}name 不传name默认移除所有文件,传入name移除指定name的文件
167
+	 */
168
+	clear(name='') {
169
+		// #ifdef APP-PLUS
170
+		this.dom&&this.dom.evalJS(`vm.clear('${name}')`);
171
+		// #endif
172
+		
173
+		if (!name) {
174
+			this.files.clear();
175
+		}
176
+		else {
177
+			this.files.delete(name); 
178
+		}
179
+		return this.onchange(this.files);
180
+	}
181
+	
182
+	/**
183
+	 * 提示框
184
+	 * @param {string}msg 轻提示内容
185
+	 */
186
+	toast(msg) {
187
+		uni.showToast({
188
+			title: msg,
189
+			icon: 'none'
190
+		});
191
+	}
192
+	
193
+	/**
194
+	 * 微信小程序选择文件
195
+	 * @param {number}count 可选择文件数量
196
+	 */
197
+	chooseMessageFile(type,count) {
198
+		wx.chooseMessageFile({
199
+			count: count,
200
+			type: type,
201
+			success: ({ tempFiles }) => {
202
+				for (let file of tempFiles) {
203
+					this.addFile(file);
204
+				}
205
+				this._uploadAfter();
206
+			},
207
+			fail: (e) => {
208
+				this.toast(`打开失败`);
209
+				console.log(e)
210
+			}
211
+		})
212
+	}
213
+	
214
+	_copyObject(obj) {
215
+		if (typeof obj !== "undefined") {
216
+			return JSON.parse(JSON.stringify(obj));
217
+		} else {
218
+			return obj;
219
+		}
220
+	}
221
+	
222
+	/**
223
+	 * 自动根据字符串路径设置对象中的值 支持.和[]
224
+	 * @param	{Object} dataObj 数据源
225
+	 * @param	{String} name 支持a.b 和 a[b]
226
+	 * @param	{String} value 值
227
+	 * setValue(dataObj, name, value);
228
+	 */
229
+	_setValue(dataObj, name, value) {
230
+		// 通过正则表达式  查找路径数据
231
+		let dataValue;
232
+		if (typeof value === "object") {
233
+			dataValue = this._copyObject(value);
234
+		} else {
235
+			dataValue = value;
236
+		}
237
+		let regExp = new RegExp("([\\w$]+)|\\[(:\\d)\\]", "g");
238
+		const patten = name.match(regExp);
239
+		// 遍历路径  逐级查找  最后一级用于直接赋值
240
+		for (let i = 0; i < patten.length - 1; i++) {
241
+			let keyName = patten[i];
242
+			if (typeof dataObj[keyName] !== "object") dataObj[keyName] = {};
243
+			dataObj = dataObj[keyName];
244
+		}
245
+		// 最后一级
246
+		dataObj[patten[patten.length - 1]] = dataValue;
247
+		this.debug&&console.log('参数更新后',JSON.stringify(this.option));
248
+	}
249
+	
250
+	_uploadAfter() {
251
+		this.onchange(this.files);
252
+		setTimeout(()=>{
253
+			this.instantly&&this.upload();
254
+		},1000)
255
+	}
256
+	
257
+	_overrideUrlLoading() {
258
+		this.dom.overrideUrlLoading({ mode: 'reject' }, e => {
259
+			let {retype,item,files,end} = this._getRequest(
260
+				e.url
261
+			);
262
+			let _this = this;
263
+			switch (retype) {
264
+				case 'updateOption':
265
+					this.dom.evalJS(`vm.setData('${JSON.stringify(_this.option)}')`);
266
+					break
267
+				case 'change':
268
+					try {
269
+						_this.files = new Map([..._this.files,...JSON.parse(unescape(files))]);
270
+					} catch (e) {
271
+						return console.error('出错了,请检查代码')
272
+					}
273
+					_this.onchange(_this.files);
274
+					break
275
+				case 'progress':
276
+					try {
277
+						item = JSON.parse(unescape(item));
278
+					} catch (e) {
279
+						return console.error('出错了,请检查代码')
280
+					}
281
+					_this._changeFilesItem(item,end);
282
+					break
283
+				default:
284
+					break
285
+			}
286
+		})
287
+	}
288
+	
289
+	_getRequest(url) {
290
+		let theRequest = new Object()
291
+		let index = url.indexOf('?')
292
+		if (index != -1) {
293
+			let str = url.substring(index + 1)
294
+			let strs = str.split('&')
295
+			for (let i = 0; i < strs.length; i++) {
296
+				theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
297
+			}
298
+		}
299
+		return theRequest
300
+	}
301
+	
302
+	_changeFilesItem(item,end=false) {
303
+		this.debug&&console.log('onprogress',JSON.stringify(item));
304
+		this.onprogress(item,end);
305
+		this.files.set(item.name,item);
306
+	}
307
+	
308
+	_uploadHandle(item) {
309
+		item.type = 'loading';
310
+		delete item.responseText;
311
+		return new Promise((resolve,reject)=>{
312
+			this.debug&&console.log('option',JSON.stringify(this.option));
313
+			let {url,name,method='POST',header,formData} = this.option;
314
+			let form = new FormData();
315
+			for (let keys in formData) {
316
+				form.append(keys, formData[keys])
317
+			}
318
+			form.append(name, item.file);
319
+			let xmlRequest = new XMLHttpRequest();
320
+			xmlRequest.open(method, url, true);
321
+			for (let keys in header) {
322
+				xmlRequest.setRequestHeader(keys, header[keys])
323
+			}
324
+			
325
+			xmlRequest.upload.addEventListener(
326
+				'progress',
327
+				event => {
328
+					if (event.lengthComputable) {
329
+						let progress = Math.ceil((event.loaded * 100) / event.total)
330
+						if (progress <= 100) {
331
+							item.progress = progress;
332
+							this._changeFilesItem(item);
333
+						}
334
+					}
335
+				},
336
+				false
337
+			);
338
+			
339
+			xmlRequest.ontimeout = () => {
340
+				console.error('请求超时')
341
+				item.type = 'fail';
342
+				this._changeFilesItem(item,true);
343
+				return resolve(false);
344
+			}
345
+			
346
+			xmlRequest.onreadystatechange = ev => {
347
+				if (xmlRequest.readyState == 4) {
348
+					if (xmlRequest.status == 200) {
349
+						this.debug&&console.log('上传完成:' + xmlRequest.responseText)
350
+						item['responseText'] = xmlRequest.responseText;
351
+						item.type = 'success';
352
+						this._changeFilesItem(item,true);
353
+						return resolve(true);
354
+					} else if (xmlRequest.status == 0) {
355
+						console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配,服务端已正确开启跨域,并且nginx未拦截阻止请求')
356
+					}
357
+					console.error('--ERROR--:status = ' + xmlRequest.status)
358
+					item.type = 'fail';
359
+					this._changeFilesItem(item,true);
360
+					return resolve(false);
361
+				}
362
+			}
363
+			xmlRequest.send(form)
364
+		});
365
+	}
366
+	
367
+	_uploadHandleWX(item) {
368
+		item.type = 'loading';
369
+		delete item.responseText;
370
+		return new Promise((resolve,reject)=>{
371
+			this.debug&&console.log('option',JSON.stringify(this.option));
372
+			let form = {filePath: item.file.path,...this.option };
373
+			form['fail'] = ({ errMsg = '' }) => {
374
+				console.error('--ERROR--:' + errMsg)
375
+				item.type = 'fail';
376
+				this._changeFilesItem(item,true);
377
+				return resolve(false);
378
+			}
379
+			form['success'] = res => {
380
+				if (res.statusCode == 200) {
381
+					this.debug&&console.log('上传完成,微信端返回不一定是字符串,根据接口返回格式判断是否需要JSON.parse:' + res.data)
382
+					item['responseText'] = res.data;
383
+					item.type = 'success';
384
+					this._changeFilesItem(item,true);
385
+					return resolve(true);
386
+				}
387
+				item.type = 'fail';
388
+				this._changeFilesItem(item,true);
389
+				return resolve(false);
390
+			}
391
+			
392
+			let xmlRequest = uni.uploadFile(form);
393
+			xmlRequest.onProgressUpdate(({ progress = 0 }) => {
394
+				if (progress <= 100) {
395
+					item.progress = progress;
396
+					this._changeFilesItem(item);
397
+				}
398
+			})
399
+		});
400
+	}
401
+}

+ 321
- 0
uni_modules/lsj-upload/components/lsj-upload/lsj-upload.vue Voir le fichier

@@ -0,0 +1,321 @@
1
+<template>
2
+	<view class="lsj-file" :style="[getStyles]">
3
+		<view ref="lsj" class="hFile" :style="[getStyles]" @click="onClick">
4
+			<slot><view class="defview" :style="[getStyles]">附件上传</view></slot>
5
+		</view>
6
+	</view>
7
+</template>
8
+
9
+<script>
10
+// 查看文档:https://ext.dcloud.net.cn/plugin?id=5459
11
+import {LsjFile} from './LsjFile.js' 
12
+export default {
13
+	name: 'Lsj-upload',
14
+	props: {
15
+		// 打印日志
16
+		debug: {type: Boolean,default: false},
17
+		// 自动上传
18
+		instantly: {type: Boolean,default: false},
19
+		// 上传接口参数设置
20
+		option: {type: Object,default: ()=>{}},
21
+		// 文件大小上限
22
+		size: { type: Number, default: 10 },
23
+		// 文件选择个数上限,超出后不触发点击
24
+		count: { type: Number, default: 9 },
25
+		// 是否允许多选文件
26
+		multiple: {type:Boolean, default: true},
27
+		// 允许上传的文件格式(多个以逗号隔开)
28
+		formats: { type: String, default:''},
29
+		// input file选择限制
30
+		accept: {type: String,default: ''},
31
+		// 微信选择文件类型 
32
+		//all=从所有文件选择,
33
+		//video=只能选择视频文件,
34
+		//image=只能选择图片文件,
35
+		//file=可以选择除了图片和视频之外的其它的文件
36
+		wxFileType: { type: String, default: 'all' },
37
+		// webviewID需唯一,不同窗口也不要同Id
38
+		childId: { type: String, default: 'lsjUpload'  },
39
+		// 文件选择触发面宽度
40
+		width: { type: String, default: '100%' },
41
+		// 文件选择触发面高度
42
+		height: { type: String, default: '80rpx' },
43
+		
44
+		// top,left,bottom,right仅position=absolute时才需要传入
45
+		top: { type: [String, Number], default: '' },
46
+		left: { type: [String, Number], default: '' },
47
+		bottom: { type: [String, Number], default: '' },
48
+		right: { type: [String, Number], default: '' },
49
+		// nvue不支持跟随窗口滚动
50
+		position: { 
51
+			type: String,
52
+			// #ifdef APP-NVUE
53
+			 default: 'absolute',
54
+			// #endif
55
+			// #ifndef APP-NVUE
56
+			default: 'static',
57
+			// #endif
58
+		},
59
+	},
60
+	data() {
61
+		return {
62
+			
63
+		}
64
+	},
65
+	watch: {
66
+		option(v) {
67
+			// #ifdef APP-PLUS
68
+			this.lsjFile&&this.show();
69
+			// #endif
70
+		}
71
+	},
72
+	updated() {
73
+		// #ifdef APP-PLUS
74
+			if (this.isShow) {
75
+				this.lsjFile&&this.show();
76
+			}
77
+		// #endif
78
+	},
79
+	computed: {
80
+		getStyles() {
81
+			let styles = {
82
+				width: this.width,
83
+				height: this.height
84
+			}
85
+			if (this.position == 'absolute') {
86
+				styles['top'] = this.top
87
+				styles['bottom'] = this.bottom
88
+				styles['left'] = this.left
89
+				styles['right'] = this.right
90
+				styles['position'] = 'fixed'
91
+			}
92
+
93
+			return styles
94
+		}
95
+	},
96
+	mounted() {
97
+		this._size = 0;
98
+		let WEBID = this.childId + new Date().getTime();
99
+		this.lsjFile = new LsjFile({
100
+			id: WEBID,
101
+			debug: this.debug,
102
+			width: this.width,
103
+			height: this.height,
104
+			option: this.option,
105
+			instantly: this.instantly,
106
+			// 限制条件
107
+			prohibited: {
108
+				// 大小
109
+				size: this.size,
110
+				// 允许上传的格式
111
+				formats: this.formats,
112
+				// 限制选择的格式
113
+				accept: this.accept,
114
+				count: this.count,
115
+				// 是否多选
116
+				multiple: this.multiple,
117
+			},
118
+			onchange: this.onchange,
119
+			onprogress: this.onprogress,
120
+		});
121
+		this.create();
122
+		// 需判断是否当前页显示
123
+		uni.$on('lsjShow',this.show);
124
+	},
125
+	beforeDestroy() {
126
+		uni.$off('lsjShow',this.show);
127
+		
128
+		// #ifdef APP-PLUS
129
+		this.lsjFile.dom.close();
130
+		// #endif
131
+	},
132
+	methods: {
133
+		setFiles(array) {
134
+			if (array instanceof Map) {
135
+				for (let [key, item] of array) {
136
+					item['progress'] = 100;
137
+					item['type'] = 'success';
138
+					this.lsjFile.files.set(key,item);
139
+				}
140
+			}
141
+			else if (Array.isArray(array)) {
142
+				array.forEach(item=>{
143
+					if (item.name) { 
144
+						item['progress'] = 100;
145
+						item['type'] = 'success';
146
+						this.lsjFile.files.set(item.name,item);
147
+					}
148
+				});
149
+			}
150
+			this.onchange(this.lsjFile.files);
151
+		},
152
+		setData() {
153
+			this.lsjFile&&this.lsjFile.setData(...arguments);
154
+		},
155
+		getDomStyles(callback) {
156
+			// #ifndef APP-NVUE
157
+			let view = uni
158
+				.createSelectorQuery()
159
+				.in(this)
160
+				.select('.lsj-file')
161
+			view.fields(
162
+				{
163
+					size: true,
164
+					rect: true
165
+				},
166
+				({ height, width, top, left, right, bottom }) => {
167
+					uni.createSelectorQuery()
168
+					.selectViewport()
169
+					.scrollOffset(({ scrollTop }) => {
170
+						return callback({
171
+							top: parseInt(top) + parseInt(scrollTop) + 'px',
172
+							left: parseInt(left) + 'px',
173
+							width: parseInt(width) + 'px',
174
+							height: parseInt(height) + 'px'
175
+						})
176
+					})
177
+					.exec()
178
+				}
179
+			).exec()
180
+			// #endif
181
+			// #ifdef APP-NVUE
182
+			const dom = weex.requireModule('dom')
183
+			dom.getComponentRect(this.$refs.lsj, ({ size: { height, width, top, left, right, bottom } }) => {
184
+				return callback({
185
+					top: parseInt(top) + 'px',
186
+					left: parseInt(left) + 'px',
187
+					width: parseInt(width) + 'px',
188
+					height: parseInt(height) + 'px',
189
+					right: parseInt(right) + 'px',
190
+					bottom: parseInt(bottom) + 'px'
191
+				})
192
+			})
193
+			// #endif
194
+		},
195
+		show() {
196
+			if (this._size && (this._size >= this.count)) {
197
+				return;
198
+			}
199
+			this.isShow = true;
200
+			// #ifdef APP-PLUS
201
+			this.lsjFile&&this.getDomStyles(styles => {
202
+				this.lsjFile.dom.setStyle(styles)
203
+			});
204
+			// #endif
205
+			// #ifdef H5
206
+			this.lsjFile.dom.style.display = 'inline'
207
+			// #endif
208
+		},
209
+		hide() {
210
+			this.isShow = false;
211
+			// #ifdef APP-PLUS
212
+			this.lsjFile&&this.lsjFile.dom.setStyle({
213
+				top: '-100px',
214
+				left:'0px',
215
+				width: '1px',
216
+				height: '100px',
217
+			});
218
+			// #endif
219
+			// #ifdef H5
220
+			this.lsjFile.dom.style.display = 'none'
221
+			// #endif
222
+		},
223
+		/**
224
+		 * 手动提交上传
225
+		 * @param {string}name 文件名称,不传则上传所有type等于waiting和fail的文件
226
+		 */
227
+		upload(name) {
228
+			this.lsjFile&&this.lsjFile.upload(name);
229
+		},
230
+		/**
231
+		 * @returns {Map} 已选择的文件Map集
232
+		 */
233
+		onchange(files) {
234
+			this.$emit('change',files);
235
+			this._size = files.size;
236
+			return files.size >= this.count ? this.hide() : this.show();
237
+		},
238
+		/**
239
+		 * @returns {object} 当前上传中的对象
240
+		 */
241
+		onprogress(item,end=false) {
242
+			this.$emit('progress',item);
243
+			if (end) {
244
+				setTimeout(()=>{
245
+					this.$emit('uploadEnd',item);
246
+				},0);
247
+			}
248
+		},
249
+		/**
250
+		 * 移除组件内缓存的某条数据
251
+		 * @param {string}name 文件名称,不指定默认清除所有文件
252
+		 */
253
+		clear(name) {
254
+			this.lsjFile.clear(name);
255
+		},
256
+		// 创建选择器
257
+		create() {
258
+			// 若iOS端服务端处理不了跨域就将hybrid目录内的html放到服务端去,并将此处path改成服务器上的地址
259
+			let path = '/uni_modules/lsj-upload/hybrid/html/uploadFile.html';
260
+			let dom = this.lsjFile.create(path);
261
+			// #ifdef H5
262
+			this.$refs.lsj.$el.appendChild(dom);
263
+			// #endif
264
+			// #ifndef APP-PLUS
265
+			this.show();
266
+			// #endif
267
+			// #ifdef APP-PLUS
268
+			dom.setStyle({position: this.position});
269
+			dom.loadURL(path);
270
+			setTimeout(()=>{
271
+				// #ifdef APP-NVUE
272
+				plus.webview.currentWebview().append(dom);
273
+				// #endif
274
+				// #ifndef APP-NVUE
275
+				this.$root.$scope.$getAppWebview().append(dom);
276
+				// #endif
277
+				this.show();
278
+			},300)
279
+			// #endif
280
+		},
281
+		// 点击选择附件
282
+		onClick() {
283
+			if (this._size >= this.count) {
284
+				this.toast(`只允许上传${this.count}个文件`);
285
+				return;
286
+			}
287
+			
288
+			// #ifdef MP-WEIXIN
289
+			if (!this.isShow) {return;}
290
+			let count = this.count - this._size;
291
+			this.lsjFile.chooseMessageFile(this.wxFileType,count);
292
+			// #endif
293
+		},
294
+		toast(msg) {
295
+			uni.showToast({
296
+				title: msg,
297
+				icon: 'none'
298
+			});
299
+		}
300
+	}
301
+}
302
+</script>
303
+
304
+<style scoped>
305
+.lsj-file {
306
+	display: inline-block;
307
+}
308
+.defview {
309
+	background-color: #007aff;
310
+	color: #fff;
311
+	border-radius: 10rpx;
312
+	display: flex;
313
+	align-items: center;
314
+	justify-content: center;
315
+	font-size: 28rpx;
316
+}
317
+.hFile {
318
+	position: relative;
319
+	overflow: hidden;
320
+}
321
+</style>

+ 8
- 0
uni_modules/lsj-upload/hybrid/html/js/vue.min.js
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 198
- 0
uni_modules/lsj-upload/hybrid/html/uploadFile.html Voir le fichier

@@ -0,0 +1,198 @@
1
+<!DOCTYPE html>
2
+<html lang="zh-cn">
3
+
4
+	<head>
5
+		<meta charset="UTF-8">
6
+		<title class="title">[文件管理器]</title>
7
+		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
8
+		<style type="text/css">
9
+			.content {background: transparent;}
10
+			.btn {position: relative;top: 0;left: 0;bottom: 0;right: 0;}
11
+			.btn .file {position: fixed;z-index: 93;left: 0;right: 0;top: 0;bottom: 0;width: 100%;opacity: 0;}
12
+		</style>
13
+	</head>
14
+
15
+	<body>
16
+		
17
+		<div id="content" class="content">
18
+			<div class="btn">
19
+				<input :multiple="multiple" @change="onChange" :accept="accept" ref="file" class="file" type="file" />
20
+			</div>
21
+		</div>
22
+		
23
+		<script type="text/javascript" src="js/vue.min.js"></script>
24
+		<script type="text/javascript">
25
+			let _this;
26
+			var vm = new Vue({
27
+				el: '#content',
28
+				data: {
29
+					accept: '',
30
+					multiple: true,
31
+				},
32
+				mounted() {
33
+					console.log('加载webview');
34
+					_this = this;
35
+					this.files = new Map();
36
+					document.addEventListener('plusready', (e)=>{
37
+					let {debug,instantly,prohibited} = plus.webview.currentWebview();
38
+					this.debug = debug;
39
+					this.instantly = instantly;
40
+					this.prohibited = prohibited;
41
+					this.accept = prohibited.accept; 
42
+					if (prohibited.multiple === 'false') {
43
+						prohibited.multiple = false;
44
+					}
45
+					this.multiple = prohibited.multiple;
46
+					location.href = 'callback?retype=updateOption';
47
+					}, false);
48
+				},
49
+				methods: {
50
+					toast(msg) {
51
+						plus.nativeUI.toast(msg);
52
+					},
53
+					clear(name) {
54
+						if (!name) {
55
+							this.files.clear();
56
+							return;
57
+						}
58
+						this.files.delete(name);
59
+					},
60
+					setData(option='{}') {
61
+						this.debug&&console.log('更新参数:'+option);
62
+						try{
63
+							_this.option = JSON.parse(option);
64
+						}catch(e){
65
+							console.error('参数设置错误')
66
+						}
67
+					},
68
+					async upload(name=''){
69
+						if (name && this.files.has(name)) {
70
+							await this.createUpload(this.files.get(name));
71
+						}
72
+						else {
73
+							for (let item of this.files.values()) {
74
+								if (item.type === 'waiting' || item.type === 'fail') {
75
+									await this.createUpload(item);
76
+								}
77
+							}
78
+						}
79
+					},
80
+					onChange(e) {
81
+						let fileDom = this.$refs.file;
82
+						for (let file of fileDom.files) {
83
+							if (this.files.size >= this.prohibited.count) {
84
+								this.toast(`只允许上传${this.prohibited.count}个文件`);
85
+								fileDom.value = '';
86
+								break;
87
+							}
88
+							this.addFile(file);
89
+						}
90
+						this.uploadAfter();
91
+						fileDom.value = '';
92
+					},
93
+					addFile(file) {
94
+						if (file) {
95
+							let name = file.name;
96
+							this.debug&&console.log('文件名称',name,'大小',file.size);
97
+							// 限制文件格式
98
+							let suffix = name.substring(name.lastIndexOf(".")+1).toLowerCase();
99
+							let formats = this.prohibited.formats.toLowerCase();
100
+							if (formats&&!formats.includes(suffix)) {
101
+								this.toast(`不支持上传${suffix.toUpperCase()}格式文件`);
102
+								return;
103
+							}
104
+							// 限制文件大小
105
+							if (file.size > 1024 * 1024 * Math.abs(this.prohibited.size)) {
106
+								this.toast(`附件大小请勿超过${this.prohibited.size}M`)
107
+								return;
108
+							}
109
+							// let itemBlob = new Blob([file]);
110
+							let path = URL.createObjectURL(file);
111
+							this.files.set(file.name,{file,path,name: file.name,size: file.size,progress: 0,type: 'waiting'});
112
+						}
113
+					},
114
+					/**
115
+					 * @returns {Map} 已选择的文件Map集
116
+					 */
117
+					callChange() {
118
+						location.href = 'callback?retype=change&files=' + escape(JSON.stringify([...this.files]));
119
+					},
120
+					/**
121
+					 * @returns {object} 正在处理的当前对象
122
+					 */
123
+					changeFilesItem(item,end='') {
124
+						this.files.set(item.name,item);
125
+						location.href = 'callback?retype=progress&end='+ end +'&item=' + escape(JSON.stringify(item));
126
+					},
127
+					uploadAfter() {
128
+						this.callChange();
129
+						setTimeout(()=>{
130
+							this.instantly&&this.upload();
131
+						},1000)
132
+					},
133
+					createUpload(item) {
134
+						this.debug&&console.log('准备上传,option=:'+JSON.stringify(this.option));
135
+						item.type = 'loading';
136
+						delete item.responseText;
137
+						return new Promise((resolve,reject)=>{
138
+							let {url,name,method='POST',header={},formData={}} = this.option;
139
+							let form = new FormData();
140
+							for (let keys in formData) {
141
+								form.append(keys, formData[keys])
142
+							}
143
+							form.append(name, item.file);
144
+							let xmlRequest = new XMLHttpRequest();
145
+							xmlRequest.open(method, url, true);
146
+							for (let keys in header) {
147
+								xmlRequest.setRequestHeader(keys, header[keys])
148
+							}
149
+							xmlRequest.upload.addEventListener(
150
+								'progress',
151
+								event => {
152
+									if (event.lengthComputable) {
153
+										let progress = Math.ceil((event.loaded * 100) / event.total)
154
+										if (progress <= 100) {
155
+											item.progress = progress;
156
+											this.changeFilesItem(item);
157
+										}
158
+									}
159
+								},
160
+								false
161
+							);
162
+							
163
+							xmlRequest.ontimeout = () => {
164
+								console.error('请求超时')
165
+								item.type = 'fail';
166
+								this.changeFilesItem(item,true);
167
+								return resolve(false);
168
+							}
169
+							
170
+							xmlRequest.onreadystatechange = ev => {
171
+								if (xmlRequest.readyState == 4) {
172
+									this.debug && console.log('接口是否支持跨域',xmlRequest.withCredentials); 
173
+									if (xmlRequest.status == 200) {
174
+										this.debug && console.log('上传完成:' + xmlRequest.responseText)
175
+										item['responseText'] = xmlRequest.responseText;
176
+										item.type = 'success';
177
+										this.changeFilesItem(item,true);
178
+										return resolve(true);
179
+									} else if (xmlRequest.status == 0) {
180
+										console.error('status = 0 :请检查请求头Content-Type与服务端是否匹配,服务端已正确开启跨域,并且nginx未拦截阻止请求')
181
+									}
182
+									console.error('--ERROR--:status = ' + xmlRequest.status) 
183
+									item.type = 'fail';
184
+									this.changeFilesItem(item,true);
185
+									return resolve(false);
186
+								}
187
+							}
188
+							xmlRequest.send(form)
189
+						});
190
+						
191
+					}
192
+				}
193
+			});
194
+			
195
+		</script>
196
+	</body>
197
+
198
+</html>

+ 78
- 0
uni_modules/lsj-upload/package.json Voir le fichier

@@ -0,0 +1,78 @@
1
+{
2
+    "id": "lsj-upload",
3
+    "displayName": "全文件上传选择非原生2.0版",
4
+    "version": "2.2.9",
5
+    "description": "文件选择上传-支持APP-H5网页-微信小程序",
6
+    "keywords": [
7
+        "附件",
8
+        "file",
9
+        "upload",
10
+        "上传",
11
+        "文件管理器"
12
+    ],
13
+    "repository": "",
14
+    "engines": {
15
+    },
16
+    "dcloudext": {
17
+        "sale": {
18
+            "regular": {
19
+                "price": "0.00"
20
+            },
21
+            "sourcecode": {
22
+                "price": "0.00"
23
+            }
24
+        },
25
+        "contact": {
26
+            "qq": ""
27
+        },
28
+        "declaration": {
29
+            "ads": "无",
30
+            "data": "无",
31
+            "permissions": "无"
32
+        },
33
+        "npmurl": "",
34
+        "type": "component-vue"
35
+    },
36
+    "uni_modules": {
37
+        "platforms": {
38
+            "cloud": {
39
+                "tcb": "y",
40
+                "aliyun": "y"
41
+            },
42
+            "client": {
43
+                "App": {
44
+                    "app-vue": "y",
45
+                    "app-nvue": "y"
46
+                },
47
+                "H5-mobile": {
48
+                    "Safari": "y",
49
+                    "Android Browser": "y",
50
+                    "微信浏览器(Android)": "y",
51
+                    "QQ浏览器(Android)": "y"
52
+                },
53
+                "H5-pc": {
54
+                    "Chrome": "y",
55
+                    "IE": "y",
56
+                    "Edge": "y",
57
+                    "Firefox": "y",
58
+                    "Safari": "y"
59
+                },
60
+                "小程序": {
61
+                    "微信": "y",
62
+                    "阿里": "u",
63
+                    "百度": "u",
64
+                    "字节跳动": "u",
65
+                    "QQ": "u"
66
+                },
67
+                "快应用": {
68
+                    "华为": "y",
69
+                    "联盟": "y"
70
+                },
71
+                "Vue": {
72
+                    "vue2": "y",
73
+                    "vue3": "y"
74
+                }
75
+            }
76
+        }
77
+    }
78
+}

+ 353
- 0
uni_modules/lsj-upload/readme.md Voir le fichier

@@ -0,0 +1,353 @@
1
+# lsj-upload
2
+
3
+### 插件地址:https://ext.dcloud.net.cn/plugin?id=5459
4
+
5
+### 不清楚使用方式可点击右侧导入示例项目运行完整示例
6
+### 此次更新2.0与1.0使用方式略有差异,已使用1.0的同学自行斟酌是否更新到2.0版本!!!
7
+
8
+使用插件有任何问题欢迎加入QQ讨论群:
9
+- 群1:701468256(已满)
10
+- 群2:469580165(已满)
11
+- 群3:667530868
12
+
13
+若能帮到你请高抬贵手点亮5颗星~
14
+------
15
+## 重要提示
16
+### 组件是窗口级滚动,不要在scroll-view内使用!!
17
+### 组件是窗口级滚动,不要在scroll-view内使用!!
18
+### 组件是窗口级滚动,不要在scroll-view内使用!!
19
+
20
+### 控件的height高度应与slot自定义内容高度保持一致
21
+### nvue窗口只能使用固定模式position=absolute
22
+### show() 当DOM重排后在this.$nextTick内调用show(),控件定位会更加准确
23
+### hide() APP端webview层级比view高,如不希望触发点击时,应调用hide隐藏控件,反之调用show
24
+### 若iOS端跨域服务端同学实在配置不好,可把hybrid下html目录放到服务器去,同源则不存在跨域问题。
25
+### 小程序端因hybrid不能使用本地HTML,所以插件提供的是从微信消息列表拉取文件并选择,请知悉。
26
+### file对象不是object对象,也不能转json字符串,如果你打印file那就是{},可以打印file.name和file.size。
27
+### 返回的path是个blob类型,仅供用于文件回显,插件已内置好上传函数,调用上传会自动提交待上传文件,若非要自己拿path去搞上传那你自己处理。
28
+------
29
+
30
+## 使用说明
31
+| 属性		| 是否必填	|  值类型	| 默认值	| 说明			|
32
+| --------- | -------- 	| -----: 	| --: 	| :------------:|
33
+| width		|	否 		| String	|100%	| 容器宽度		|
34
+| height	|	是 		| String	|80rpx	| 容器高度		|
35
+| debug		|	否 		| Boolean	|false	| 打印调试日志	|
36
+| option	|	是 		| Object	|-		| [文件上传接口相关参数](#p1)|
37
+| instantly	|	否 		| Boolean	|false	| true=自动上传	|
38
+| count		|	否 		| Number	|10		| 附件选择上限(个)|
39
+| size		|	否 		| Number	|10		| 附件大小上限(M)|
40
+| wxFileType	|	否 		| String	|all		| 微信小程序文件选择器格式限制(all=从所有文件选择,video=只能选择视频文件,image=只能选择图片文件,file=可以选择除了图片和视频之外的其它的文件)|
41
+| accept	|	否 		| String	|-		| 文件选择器input file格式限制(部分机型不兼容,建议使用formats)|
42
+| formats	|	否 		| String	|-		| 限制允许上传的格式,空串=不限制,默认为空,多个格式以逗号隔开,例如png,jpg,pdf|
43
+| childId	|	否 		| String	|lsjUpload| 控件的id(仅APP有效,应用内每个控件命名一个唯一Id,不同窗口也不要同名Id)|
44
+| position	|	否 		| String	|static	| 控件的定位模式(static=控件随页面滚动;absolute=控件在页面中绝对定位,不随窗口内容滚动)|
45
+| top,left,right,bottom	|	否 		| [Number,String]	|0		| 设置控件绝对位置,position=absolute时有效|
46
+| @change	|	否 		| Function	|Map	| 选择文件触发,返回所有已选择文件Map集合|
47
+| @progress	|	否 		| Function	|Object	| 上传过程中发生状态变化的文件对象,需通过set更新至Map集合|
48
+| @uploadEnd|	否 		| Function	|Object	| 上传结束回调,返回参数与progress一致|
49
+
50
+## <a id="p1">option说明</a>
51
+|参数 | 是否必填 |  说明|
52
+|---- | ---- | :--: |
53
+|url  |	是	| 上传接口地址|
54
+|name| 否	|上传接口文件key,默认为file|
55
+|header| 否	|上传接口请求头|
56
+|formData| 否	|上传接口额外参数|
57
+
58
+## ref调用
59
+|作用 | 方法名| 传入参数|  说明|
60
+|---- | --------- | -------- | :--: |
61
+|显示控件| show|-| 控件显示状态下可触发点击|
62
+|隐藏控件| hide|-| 控件隐藏状态下不触发点击|
63
+|动态设置文件列表| setFiles|[Array,Map] files| 传入格式请与组件选择返回格式保持一致,且name为必须属性,可查看下方演示|
64
+|动态更新参数| setData|[String] name,[any] value| name支持a.b 和 a[b],可查看下方演示|
65
+|移除选择的文件| clear|[String] name| 不传参数清空所有文件,传入文件name时删除该name的文件|
66
+|手动上传| upload|[String] name| 不传参数默认依次上传所有type=waiting的文件,传入文件name时不关心type是否为waiting,单独上传指定name的文件|
67
+
68
+## progress返回对象字段说明
69
+|字段 |  说明|
70
+|---- | :--: |
71
+|file | 文件对象|
72
+|name |文件名称|
73
+|size |文件大小|
74
+|type |文件上传状态:waiting(等待上传)、loading(上传中)、success(成功) 、fail(失败)|
75
+|responseText|上传成功后服务端返回数据(仅type为success时存在)|
76
+
77
+## 以下演示为vue窗口使用方式,nvue使用区别是必须传入控件绝对位置如top,bottom,left,right,且position只能为absolute,如不清楚可点击右侧导入示例项目有详细演示代码。
78
+
79
+### vue:
80
+``` javascript
81
+<lsj-upload 
82
+	ref="lsjUpload"
83
+	childId="upload1"
84
+	:width="width"
85
+	:height="height"
86
+	:option="option"
87
+	:size="size"
88
+	:formats="formats"
89
+	:debug="debug"
90
+	:instantly="instantly"
91
+	@uploadEnd="onuploadEnd"
92
+	@progress="onprogre"
93
+	@change="onChange">
94
+		<view class="btn" :style="{width: width,height: height}">选择附件</view>
95
+</lsj-upload>
96
+
97
+
98
+<view class="padding">
99
+			
100
+	<view>已选择文件列表:</view>
101
+	
102
+	<!-- #ifndef MP-WEIXIN -->
103
+	<view v-for="(item,index) in files.values()" :key="index">
104
+		<image style="width: 100rpx;height: 100rpx;" :src="item.path" mode="widthFix"></image>
105
+		<text>提示:【path主要用于图片视频类文件回显,他用自行处理】:{{item.path}}</text>
106
+		<text>{{item.name}}</text>
107
+		<text style="margin-left: 10rpx;">大小:{{item.size}}</text>
108
+		<text style="margin-left: 10rpx;">状态:{{item.type}}</text>
109
+		<text style="margin-left: 10rpx;">进度:{{item.progress}}</text>
110
+		<text style="margin-left: 10rpx;" v-if="item.responseText">服务端返回演示:{{item.responseText}}</text>
111
+		<text @click="resetUpload(item.name)" v-if="item.type=='fail'" style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #007AFF;">重新上传</text>
112
+		<text @click="clear(item.name)" style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #007AFF;">删除</text>
113
+	</view>
114
+	<!-- #endif -->
115
+	
116
+	<!-- #ifdef MP-WEIXIN -->
117
+	<view v-for="(item,index) in wxFiles" :key="index">
118
+		<text>{{item.name}}</text>
119
+		<text style="margin-left: 10rpx;">大小:{{item.size}}</text>
120
+		<text style="margin-left: 10rpx;">状态:{{item.type}}</text>
121
+		<text style="margin-left: 10rpx;">进度:{{item.progress}}</text>
122
+		<view>
123
+			<button @click="resetUpload(item.name)">重新上传</button>
124
+			<button @click="clear(item.name)">删除</button>
125
+		</view>
126
+	</view>
127
+	<!-- #endif -->
128
+	
129
+</view>
130
+
131
+
132
+```
133
+
134
+---
135
+* 函数说明
136
+
137
+
138
+``` javascript
139
+export default {
140
+	data() {
141
+		return {
142
+			// 上传接口参数
143
+			option: {
144
+				// 上传服务器地址,需要替换为你的接口地址
145
+				url: 'http://hl.j56.com/dropbox/document/upload', // 该地址非真实路径,需替换为你项目自己的接口地址
146
+				// 上传附件的key
147
+				name: 'file',
148
+				// 根据你接口需求自定义请求头,默认不要写content-type,让浏览器自适配
149
+				header: {
150
+					// 示例参数可删除
151
+					'Authorization': 'bearer eyJhbGciOiJSUzI1NiIsI',
152
+					'uid': '99',
153
+					'client': 'app',
154
+					'accountid': 'DP',
155
+				},
156
+				// 根据你接口需求自定义body参数
157
+				formData: {
158
+					// 'orderId': 1000
159
+				}
160
+			},
161
+			// 选择文件后是否立即自动上传,true=选择后立即上传
162
+			instantly: true,
163
+			// 必传宽高且宽高应与slot宽高保持一致
164
+			width: '180rpx',
165
+			height: '180rpx',
166
+			// 限制允许上传的格式,空串=不限制,默认为空
167
+			formats: '',
168
+			// 文件上传大小限制
169
+			size: 30,
170
+			// 文件数量限制
171
+			count: 2,
172
+			// 文件回显列表
173
+			files: new Map(),
174
+			// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
175
+			wxFiles: [],
176
+			// 是否打印日志
177
+			debug: true,
178
+			
179
+			
180
+			// 演示用
181
+			tabIndex: 0,
182
+			list:[], 
183
+		}
184
+	},
185
+	onReady() {
186
+		setTimeout(()=>{
187
+			console.log('----演示动态更新参数-----');
188
+			this.$refs['lsjUpload'+this.tabIndex].setData('formData.orderId','动态设置的参数'); 
189
+			
190
+			console.log('以下注释内容为-动态更新参数更多演示,放开后可查看演示效果');
191
+			// 修改option对象的name属性
192
+			// this.$refs.lsjUpload.setData('name','myFile');
193
+			
194
+			// 修改option对象的formData内的属性
195
+			// this.$refs.lsjUpload.setData('formData.appid','1111');
196
+			
197
+			// 替换option对象的formData
198
+			// this.$refs.lsjUpload.setData('formData',{appid:'222'});
199
+			
200
+			// option对象的formData新增属性
201
+			// this.$refs.lsjUpload.setData('formData.newkey','新插入到formData的属性');
202
+			
203
+			
204
+			// ---------演示初始化值,用于已提交后再次编辑时需带入已上传文件-------
205
+			// 方式1=传入数组
206
+			// let files1 = [{name: '1.png'},{name: '2.png',}];
207
+			
208
+			// 方式2=传入Map对象
209
+			// let files2 = new Map();
210
+			// files2.set('1.png',{name: '1.png'})
211
+			
212
+			// 此处调用setFiles设置初始files
213
+			// this.$refs.lsjUpload.setFiles(files1);
214
+			
215
+			// 初始化tab
216
+			this.onTab(0);
217
+		},2000)
218
+	},
219
+	methods: {
220
+		// 某文件上传结束回调(成功失败都回调)
221
+		onuploadEnd(item) {
222
+			console.log(`${item.name}已上传结束,上传状态=${item.type}`);
223
+			
224
+			// 更新当前窗口状态变化的文件
225
+			this.files.set(item.name,item);
226
+			
227
+			// ---可删除--演示上传完成后取服务端数据
228
+			if (item['responseText']) {
229
+				console.log('演示服务器返回的字符串JSON转Object对象');
230
+				this.files.get(item.name).responseText = JSON.parse(item.responseText);
231
+			}
232
+			
233
+			// 微信小程序Map对象for循环不显示,所以转成普通数组,
234
+			// 如果你用不惯Map对象,也可以像这样转普通数组,组件使用Map主要是避免反复文件去重操作
235
+			// #ifdef MP-WEIXIN
236
+			this.wxFiles = [...this.files.values()];
237
+			// #endif
238
+			
239
+			// 强制更新视图
240
+			this.$forceUpdate();
241
+			
242
+			
243
+			// ---可删除--演示判断是否所有文件均已上传成功
244
+			let isAll = [...this.files.values()].find(item=>item.type!=='success');
245
+			if (!isAll) {
246
+				console.log('已全部上传完毕');
247
+			}
248
+			else {
249
+				console.log(isAll.name+'待上传');
250
+			}
251
+			
252
+		},
253
+		// 上传进度回调,如果网页上md文档没有渲染出事件名称onprogre,请复制代码的小伙伴自行添加上哈,没有哪个事件是只(item)的
254
+		onprogre(item) {
255
+			// 更新当前状态变化的文件
256
+			this.files.set(item.name,item);
257
+			
258
+			console.log('打印对象',JSON.stringify(this.files.get(item.name)));
259
+			// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
260
+			// #ifdef MP-WEIXIN
261
+			this.wxFiles = [...this.files.values()];
262
+			// #endif
263
+			
264
+			// 强制更新视图
265
+			this.$forceUpdate();
266
+			
267
+		},
268
+		// 文件选择回调
269
+		onChange(files) {
270
+			console.log('当前选择的文件列表:',JSON.stringify([...files.values()]));
271
+			// 更新选择的文件 
272
+			this.files = files;
273
+			// 强制更新视图
274
+			this.$forceUpdate();
275
+			
276
+			// 微信小程序Map对象for循环不显示,所以转成普通数组,不要问为什么,我也不知道
277
+			// #ifdef MP-WEIXIN
278
+			this.wxFiles = [...this.files.values()];
279
+			// #endif
280
+			
281
+			// ---可删除--演示重新定位覆盖层控件
282
+			this.$nextTick(()=>{
283
+				console.log('演示重新定位');
284
+				this.$refs.lsjUpload0.show();
285
+				this.$refs.lsjUpload1.show();
286
+				this.$refs.lsjUpload2.show();
287
+			});
288
+			
289
+		},
290
+		// 手动上传
291
+		upload() {
292
+			// name=指定文件名,不指定则上传所有type等于waiting和fail的文件
293
+			this.$refs['lsjUpload'+this.tabIndex].upload();
294
+		},
295
+		// 指定上传某个文件
296
+		resetUpload(name) {
297
+			this.$refs['lsjUpload'+this.tabIndex].upload(name);
298
+		},
299
+		// 移除某个文件
300
+		clear(name) {
301
+			// name=指定文件名,不传name默认移除所有文件
302
+			this.$refs['lsjUpload'+this.tabIndex].clear(name);
303
+		},
304
+		/**
305
+		 * ---可删除--演示在组件上方添加新内容DOM变化
306
+		 * DOM重排演示,重排后组件内部updated默认会触发show方法,若特殊情况未能触发updated也可以手动调用一次show()
307
+		 * 什么是DOM重排?自行百度去
308
+		 */
309
+		add() {
310
+			this.list.push('DOM重排测试');
311
+		},
312
+		/**
313
+		 * ---可删除--演示Tab切换时覆盖层是否能被点击
314
+		 * APP端因为是webview,层级比view高,此时若不希望点击触发选择文件,需要手动调用hide()
315
+		 * 手动调用hide后,需要调用show()才能恢复覆盖层的点击
316
+		 */
317
+		onTab(tabIndex) {
318
+			this.$refs.lsjUpload0.hide();
319
+			this.$refs.lsjUpload1.hide();
320
+			
321
+			this.tabIndex = tabIndex;
322
+			
323
+			this.$nextTick(()=>{
324
+				this.$refs['lsjUpload'+this.tabIndex].show();
325
+			})
326
+			
327
+		},
328
+		/**
329
+		 * 打开nvue窗口查看非跟随窗口滚动效果
330
+		 */
331
+		open() {
332
+			uni.navigateTo({
333
+				url: '/pages/nvue-demo/nvue-demo'
334
+			});
335
+		}
336
+	}
337
+}
338
+
339
+```
340
+
341
+## 温馨提示
342
+	
343
+* 文件上传
344
+0. 如说明表达还不够清楚,不清楚怎么使用可导入完整示例项目运行体验和查看	
345
+1. APP端请优先联调Android,上传成功后再运行iOS端,如iOS返回status=0则需要后端开启允许跨域;
346
+2. header的Content-Type类型需要与服务端要求一致,否则收不到附件(服务端若没有明文规定则可不写,使用默认匹配)
347
+3. 服务端不清楚怎么配置跨域可加群咨询,具体百度~
348
+4. 欢迎加入QQ讨论群:701468256(已满)
349
+5. 欢迎加入QQ讨论群:469580165(已满)
350
+6. 欢迎加入QQ讨论群:667530868
351
+7. 若能帮到你还请点亮5颗小星星以作鼓励哈~
352
+8. 若能帮到你还请点亮5颗小星星以作鼓励哈~
353
+9. 若能帮到你还请点亮5颗小星星以作鼓励哈~

+ 1
- 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/main.js.map
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 1
- 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/runtime.js.map
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 1
- 1
unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 1
- 1
unpackage/dist/dev/.sourcemap/mp-weixin/uni_modules/uni-icons/components/uni-icons/uni-icons.js.map
Fichier diff supprimé car celui-ci est trop grand
Voir le fichier


+ 28
- 35
unpackage/dist/dev/mp-weixin/project.config.json Voir le fichier

@@ -1,36 +1,29 @@
1
-{
2
-  "description": "项目配置文件。",
3
-  "packOptions": {
4
-    "ignore": []
5
-  },
6
-  "setting": {
7
-    "urlCheck": false,
8
-    "es6": false,
9
-    "postcss": true,
10
-    "minified": true,
11
-    "newFeature": true,
12
-    "bigPackageSizeSupport": true
13
-  },
14
-  "compileType": "miniprogram",
15
-  "libVersion": "",
16
-  "appid": "wx91cb8459dca561b4",
17
-  "projectname": "智慧仲裁",
18
-  "condition": {
19
-    "search": {
20
-      "current": -1,
21
-      "list": []
22
-    },
23
-    "conversation": {
24
-      "current": -1,
25
-      "list": []
26
-    },
27
-    "game": {
28
-      "current": -1,
29
-      "list": []
30
-    },
31
-    "miniprogram": {
32
-      "current": -1,
33
-      "list": []
34
-    }
35
-  }
1
+{
2
+  "description": "项目配置文件。",
3
+  "packOptions": {
4
+    "ignore": [],
5
+    "include": []
6
+  },
7
+  "setting": {
8
+    "urlCheck": false,
9
+    "es6": false,
10
+    "postcss": true,
11
+    "minified": true,
12
+    "newFeature": true,
13
+    "bigPackageSizeSupport": true,
14
+    "babelSetting": {
15
+      "ignore": [],
16
+      "disablePlugins": [],
17
+      "outputPath": ""
18
+    }
19
+  },
20
+  "compileType": "miniprogram",
21
+  "libVersion": "3.3.2",
22
+  "appid": "wx91cb8459dca561b4",
23
+  "projectname": "智慧仲裁",
24
+  "condition": {},
25
+  "editorSetting": {
26
+    "tabIndent": "insertSpaces",
27
+    "tabSize": 2
28
+  }
36 29
 }