Selaa lähdekoodia

前端孟祥旭

mxx 3 vuotta sitten
vanhempi
commit
16c3f11bc4

+ 141 - 0
pageA/product/Identity_switching.vue

@@ -0,0 +1,141 @@
+<template>
+	<view class="center">
+		<view v-for="(item , index) in lists" :Key="index">
+			<view>
+				<view class="company">{{item.customerType}}</view>
+				<view class="guess-item" @click="navToDetailPage(item)">
+					<view class="infos">
+
+						<view class="info">{{item.customerName}}
+							<view class='cu-tag radius line-pink but'>{{item.authenticationStatus}}</view>
+						</view>
+						<view class="info">{{item.customerPhone}}</view>
+						<label>
+							<checkbox /><text>设置默认</text>
+						</label>
+						
+					</view>
+
+				</view>
+			</view>
+		</view>
+	</view>
+
+	</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	export default {
+		name: "buy",
+		data() {
+			return {
+				lists:[],
+				PageCur: "buy",
+				buyInfo: [],
+				pages: 1, //页数
+				limit: 10, //每次取条目数
+				loadStatus: 'loading', //加载样式:more-加载前样式,loading-加载中样式,nomore-没有数据样式
+				isLoadMore: false, //是否加载中
+				showTran: true,
+				scrollTop: 0,
+				TabCur: 0,
+				current: 1,
+				identityAuthenticationInfo: {
+					pageSize: 10,
+					currentPage: 1,
+					commonId: "",
+					
+					
+				},
+			};
+		},
+		onLoad() {
+			this.getList()
+		},
+		computed: {
+			...mapState(['hasLogin', 'userInfo'])
+		},
+		methods: {
+			getList() {
+				this.identityAuthenticationInfo.commonId = this.userInfo.id
+				console.log(12313)
+				this.$api.doRequest('get', '/identityAuthenticationInfo/selectIdentityAuthenticationInfo', {
+						pageSize: 10,
+						currentPage: 1,
+						commonId: this.userInfo.id
+					}, 'application/json;charset=UTF-8').then(res => {
+						console.log("成功连接123")
+						this.lists = res.data.data.records
+					})
+					.catch(res => {
+						uni.showToast({
+							title: res.errmsg,
+							icon: 'none',
+							duration: 2000
+						})
+					});
+			},
+			// adddriver(index) {
+			// 	if (index == 1) {
+			// 		uni.navigateTo({
+			// 			url: `/pageD/identity/companyIdentity`
+			// 		})
+			// 	} else {
+			// 		uni.navigateTo({
+			// 			url: `/pageD/identity/driverIdentity`
+			// 		})
+			// 	}
+			// },
+			navToDetailPage(item) {
+				// if (index == 1) {
+					uni.navigateTo({
+						url: `/pageA/product/business_buy?id=${item.id}&customerName=${item.customerName}`
+					})
+					},
+				// } else {
+				// 	uni.navigateTo({
+				// 		url: `/pageD/identity/driverIdentityLook`
+				// 	})
+				
+
+			// }
+		}
+	}
+</script>
+
+<style>
+	.center {
+		padding: 10px 20px;
+	}
+
+	.title {
+		font-size: 18px;
+		font-weight: 900;
+		margin-right: 20px;
+		display: initial;
+	}
+
+	.company {
+		font-size: 16px;
+		margin-top: 10px;
+	}
+
+	.infos {
+		/* margin: 10px 20px; */
+		width: 100%;
+		display: inline-table;
+	}
+
+	.info {
+		line-height: 20px;
+	}
+
+	.but {
+		right: 3px;
+		float: right;
+	}
+</style>

+ 28 - 0
uni_modules/uni-file-picker/changelog.md

@@ -0,0 +1,28 @@
+## 0.2.2(2021-07-27)
+- 修复 vue3 下赋值错误的Bug
+- 优化 h5平台下上传文件导致页面卡死的问题
+## 0.2.0(2021-07-13)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+## 0.1.1(2021-07-02)
+- 修复 sourceType 缺少默认值导致 ios 无法选择文件
+## 0.1.0(2021-06-30)
+- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改
+## 0.0.11(2021-06-30)
+- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
+## 0.0.10(2021-06-29)
+- 优化 文件上传后进度条消失时机
+## 0.0.9(2021-06-29)
+- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug
+## 0.0.8(2021-06-15)
+- 修复 删除文件时无法触发 v-model 的Bug
+## 0.0.7(2021-05-12)
+- 新增 组件示例地址
+## 0.0.6(2021-04-09)
+- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
+## 0.0.5(2021-04-09)
+- 优化 更新组件示例
+## 0.0.4(2021-04-09)
+- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
+## 0.0.3(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug

+ 142 - 0
uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js

@@ -0,0 +1,142 @@
+'use strict';
+
+// Object.defineProperty(exports, '__esModule', { value: true });
+
+const ERR_MSG_OK = 'chooseAndUploadFile:ok';
+const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
+function chooseImage(opts) {
+		const { count, sizeType, sourceType = ['album', 'camera'], extension } = opts
+    return new Promise((resolve, reject) => {
+        uni.chooseImage({
+            count,
+            sizeType,
+            sourceType,
+            extension,
+            success(res) {
+                resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+            },
+            fail(res) {
+                reject({
+                    errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+                });
+            },
+        });
+    });
+}
+function chooseVideo(opts) {
+    const { camera, compressed, maxDuration, sourceType = ['album', 'camera'], extension } = opts;
+    return new Promise((resolve, reject) => {
+        uni.chooseVideo({
+            camera,
+            compressed,
+            maxDuration,
+            sourceType,
+            extension,
+            success(res) {
+                const { tempFilePath, duration, size, height, width } = res;
+                resolve(normalizeChooseAndUploadFileRes({
+                    errMsg: 'chooseVideo:ok',
+                    tempFilePaths: [tempFilePath],
+                    tempFiles: [
+                        {
+                            name: (res.tempFile && res.tempFile.name) || '',
+                            path: tempFilePath,
+                            size,
+                            type: (res.tempFile && res.tempFile.type) || '',
+                            width,
+                            height,
+                            duration,
+                            fileType: 'video',
+                            cloudPath: '',
+                        },
+                    ],
+                }, 'video'));
+            },
+            fail(res) {
+                reject({
+                    errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+                });
+            },
+        });
+    });
+}
+function chooseAll(opts) {
+    const { count, extension } = opts;
+    return new Promise((resolve, reject) => {
+        let chooseFile = uni.chooseFile;
+        if (typeof wx !== 'undefined' &&
+            typeof wx.chooseMessageFile === 'function') {
+            chooseFile = wx.chooseMessageFile;
+        }
+        if (typeof chooseFile !== 'function') {
+            return reject({
+                errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
+            });
+        }
+        chooseFile({
+            type: 'all',
+            count,
+            extension,
+            success(res) {
+                resolve(normalizeChooseAndUploadFileRes(res));
+            },
+            fail(res) {
+                reject({
+                    errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
+                });
+            },
+        });
+    });
+}
+function normalizeChooseAndUploadFileRes(res, fileType) {
+    res.tempFiles.forEach((item, index) => {
+        if (!item.name) {
+            item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
+        }
+        if (fileType) {
+            item.fileType = fileType;
+        }
+        item.cloudPath =
+            Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
+    });
+    // wx.chooseMessageFile
+    if (!res.tempFilePaths) {
+        res.tempFilePaths = res.tempFiles.map((file) => file.path);
+    }
+    return res;
+}
+function uploadCloudFiles(res, max = 5, onUploadProgress) {}
+function uploadFiles(choosePromise, { onChooseFile, onUploadProgress }) {
+    return choosePromise
+        .then((res) => {
+        if (onChooseFile) {
+            const customChooseRes = onChooseFile(res);
+            if (typeof customChooseRes !== 'undefined') {
+                return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? res : chooseRes);
+            }
+        }
+        return res;
+    })
+        .then((res) => {
+        if (res === false) {
+            return {
+                errMsg: ERR_MSG_OK,
+                tempFilePaths: [],
+                tempFiles: [],
+            };
+        }
+		return res
+        // return uploadCloudFiles(res, 5, onUploadProgress);
+    })
+}
+function chooseAndUploadFile(opts = { type: 'all' }) {
+    if (opts.type === 'image') {
+        return uploadFiles(chooseImage(opts), opts);
+    }
+    else if (opts.type === 'video') {
+        return uploadFiles(chooseVideo(opts), opts);
+    }
+    return uploadFiles(chooseAll(opts), opts);
+}
+
+export {chooseAndUploadFile};

+ 740 - 0
uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue

@@ -0,0 +1,740 @@
+<template>
+	<view class="uni-file-picker">
+		<view v-if="title" class="uni-file-picker__header">
+			<text class="file-title">{{ title }}</text>
+			<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
+		</view>
+		<upload-image
+			v-if="fileMediatype === 'image' && showType === 'grid'"
+			:readonly="readonly"
+			:image-styles="imageStyles"
+			:files-list="filesList"
+			:limit="limitLength"
+			:disablePreview="disablePreview"
+			:delIcon="delIcon"
+			@uploadFiles="uploadFiles"
+			@choose="choose"
+			@delFile="delFile"
+		>
+			<slot>
+				<view class="is-add">
+					<view class="icon-add"></view>
+					<view class="icon-add rotate"></view>
+				</view>
+			</slot>
+		</upload-image>
+		<upload-file
+			v-if="fileMediatype !== 'image' || showType !== 'grid'"
+			:readonly="readonly"
+			:list-styles="listStyles"
+			:files-list="filesList"
+			:showType="showType"
+			:delIcon="delIcon"
+			@uploadFiles="uploadFiles"
+			@choose="choose"
+			@delFile="delFile"
+		>
+			<slot><button type="primary" size="mini">选择文件</button></slot>
+		</upload-file>
+	</view>
+</template>
+
+<script>
+	import {chooseAndUploadFile} from './choose-and-upload-file.js'
+	import uploadImage from './upload-image.vue'
+	import uploadFile from './upload-file.vue'
+	let fileInput = null
+/**
+ * FilePicker 文件选择上传
+ * @description 文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=4079
+ * @property {Object|Array}	value	组件数据,通常用来回显 ,类型由return-type属性决定
+ * @property {Boolean}	disabled=[true|false]	组件禁用
+ * 	@value true 	禁用
+ * 	@value false 	取消禁用
+ * @property {Boolean}	readonly=[true|false]	组件只读,不可选择,不显示进度,不显示删除按钮
+ * 	@value true 	只读
+ * 	@value false 	取消只读
+ * @property {String}	return-type=[array|object]	限制 value 格式,当为 object 时 ,组件只能单选,且会覆盖
+ * 	@value array	规定 value 属性的类型为数组
+ * 	@value object	规定 value 属性的类型为对象
+ * @property {Boolean}	disable-preview=[true|false]	禁用图片预览,仅 mode:grid 时生效
+ * 	@value true 	禁用图片预览
+ * 	@value false 	取消禁用图片预览
+ * @property {Boolean}	del-icon=[true|false]	是否显示删除按钮
+ * 	@value true 	显示删除按钮
+ * 	@value false 	不显示删除按钮
+ * @property {Boolean}	auto-upload=[true|false]	是否自动上传,值为true则只触发@select,可自行上传
+ * 	@value true 	自动上传
+ * 	@value false 	取消自动上传
+ * @property {Number|String}	limit	最大选择个数 ,h5 会自动忽略多选的部分
+ * @property {String}	title	组件标题,右侧显示上传计数
+ * @property {String}	mode=[list|grid]	选择文件后的文件列表样式
+ * 	@value list 	列表显示
+ * 	@value grid 	宫格显示
+ * @property {String}	file-mediatype=[image|video|all]	选择文件类型
+ * 	@value image	只选择图片
+ * 	@value video	只选择视频
+ * 	@value all		选择所有文件
+ * @property {Array}	file-extname	选择文件后缀,根据 file-mediatype 属性而不同
+ * @property {Object}	list-style	mode:list 时的样式
+ * @property {Object}	image-styles	选择文件后缀,根据 file-mediatype 属性而不同
+ * @event {Function} select 	选择文件后触发
+ * @event {Function} progress 文件上传时触发
+ * @event {Function} success 	上传成功触发
+ * @event {Function} fail 		上传失败触发
+ * @event {Function} delete 	文件从列表移除时触发
+ */
+export default {
+	name: 'uniFilePicker',
+	components: {
+		uploadImage,
+		uploadFile
+	},
+	props: {
+		// #ifdef VUE3
+		modelValue: {
+			type: [Array, Object],
+			default() {
+				return []
+			}
+		},
+		// #endif
+
+		// #ifndef VUE3
+		value: {
+			type: [Array, Object],
+			default() {
+				return []
+			}
+		},
+		// #endif
+
+		disabled: {
+			type: Boolean,
+			default: false
+		},
+		disablePreview: {
+			type: Boolean,
+			default: false
+		},
+		delIcon: {
+			type: Boolean,
+			default: true
+		},
+		// 自动上传
+		autoUpload: {
+			type: Boolean,
+			default: true
+		},
+		// 最大选择个数 ,h5只能限制单选或是多选
+		limit: {
+			type: [Number, String],
+			default: 9
+		},
+		// 列表样式 grid | list | list-card
+		mode: {
+			type: String,
+			default: 'grid'
+		},
+		// 选择文件类型  image/video/all
+		fileMediatype: {
+			type: String,
+			default: 'image'
+		},
+		// 文件类型筛选
+		fileExtname: {
+			type: [Array, String],
+			default() {
+				return []
+			}
+		},
+		title: {
+			type: String,
+			default: ''
+		},
+		listStyles: {
+			type: Object,
+			default() {
+				return {
+					// 是否显示边框
+					border: true,
+					// 是否显示分隔线
+					dividline: true,
+					// 线条样式
+					borderStyle: {}
+				}
+			}
+		},
+		imageStyles: {
+			type: Object,
+			default() {
+				return {
+					width: 'auto',
+					height: 'auto'
+				}
+			}
+		},
+		readonly: {
+			type: Boolean,
+			default: false
+		},
+		returnType: {
+			type: String,
+			default: 'array'
+		},
+		sizeType:{
+			type: Array,
+			default(){
+				return ['original','compressed']
+			}
+		}
+	},
+	watch: {
+		// #ifndef VUE3
+		value: {
+			handler(newVal) {
+				this.setValue(newVal)
+			},
+			immediate: true
+		},
+		// #endif
+		// #ifdef VUE3
+		modelValue:{
+			handler(newVal) {
+				this.setValue(newVal)
+			},
+			immediate: true
+		},
+		// #endif
+
+	},
+	data() {
+		return {
+			files: [],
+		}
+	},
+	computed: {
+		filesList() {
+			let files = []
+			this.files.forEach(v => {
+				files.push(v)
+			})
+			return files
+		},
+		showType() {
+			if (this.fileMediatype === 'image') {
+				return this.mode
+			}
+			return 'list'
+		},
+		limitLength() {
+			if (this.returnType === 'object') {
+				return 1
+			}
+			if (!this.limit) {
+				return 1
+			}
+			if (this.limit >= 9) {
+				return 9
+			}
+			return this.limit
+		},
+		extname(){
+			if (!Array.isArray(this.fileExtname)) {
+				let extname = this.fileExtname.replace(/(\[|\])/g,'')
+				return extname.split(',')
+			} else {
+				return this.fileExtname
+			}
+			return []
+		}
+	},
+	created() {
+		// TODO 兼容不开通服务空间的情况
+		if(!(uniCloud.config && uniCloud.config.provider)){
+			this.noSpace = true
+			uniCloud.chooseAndUploadFile = chooseAndUploadFile
+		}
+		this.tempData = {}
+		this.form = this.getForm('uniForms')
+		this.formItem = this.getForm('uniFormsItem')
+		if (this.form && this.formItem) {
+			if (this.formItem.name) {
+				this.rename = this.formItem.name
+				this.form.inputChildrens.push(this)
+			}
+		}
+	},
+	methods: {
+		setValue(newVal){
+			let newFils = []
+			let newData = [].concat(newVal || [])
+			newData.forEach(v => {
+				const files = this.files.find(i => i.url === v.url)
+				const reg = /cloud:\/\/([\w.]+\/?)\S*/
+				if (!v.path) {
+					v.path = v.url
+				}
+				if (reg.test(v.url)) {
+					this.getTempFileURL(v, v.url)
+				}
+				newFils.push(files ? files : v)
+			})
+			let data  = null
+			if (this.returnType === 'object') {
+				data = this.backObject(newFils)[0]
+			} else {
+				data = this.backObject(newFils)
+			}
+			this.formItem && this.formItem.setValue(data)
+			if(newFils.length){
+				this.files = newFils
+			}
+		},
+		/**
+		 * 获取父元素实例
+		 */
+		getForm(name = 'uniForms') {
+			let parent = this.$parent;
+			let parentName = parent.$options.name;
+			while (parentName !== name) {
+				parent = parent.$parent;
+				if (!parent) return false;
+				parentName = parent.$options.name;
+			}
+			return parent;
+		},
+		/**
+		 * 继续上传
+		 */
+		upload() {
+			// TODO 先放弃这个实现 ,不能全部上传
+			// if (this.$uploadFiles) {
+			// 	this.$uploadFiles()
+			// } else {
+			// 	uni.showToast({
+			// 		title: '请先选择文件',
+			// 		icon: 'none'
+			// 	})
+			// }
+			let files = []
+			this.files.forEach((v, index) => {
+				if (v.status === 'ready' || v.status === 'error') {
+					files.push(Object.assign({}, v))
+				}
+			})
+
+			this.uploadFiles(files)
+		},
+		/**
+		 * 选择文件
+		 */
+		choose() {
+
+			if (this.disabled) return
+			if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType === 'array') {
+				uni.showToast({
+					title: `您最多选择 ${this.limitLength} 个文件`,
+					icon: 'none'
+				})
+				return
+			}
+			// uni.showActionSheet({
+			// 	itemList: ['填写 url 地址', '选择文件'],
+			// 	success: (res) => {
+			// 		if (res.tapIndex === 1) {
+			// 			this.chooseFiles()
+			// 		}
+			// 	},
+			// 	fail: function(res) {}
+			// });
+			this.chooseFiles()
+		},
+
+		/**
+		 * 选择文件并上传
+		 */
+		chooseFiles() {
+
+			uniCloud
+				.chooseAndUploadFile({
+					type: this.fileMediatype,
+					compressed: false,
+					sizeType:this.sizeType,
+					// TODO 如果为空,video 有问题
+					extension: this.extname.length > 0 ? this.extname : undefined,
+					count: this.limitLength - this.files.length, //默认9
+					onChooseFile: async res => {
+						if ((Number(this.limitLength) === 1 && this.disablePreview && !this.disabled) || this.returnType === 'object') {
+							this.files = []
+						}
+						let filePaths = []
+						let files = []
+						if (this.extname && this.extname.length > 0) {
+							res.tempFiles.forEach(v => {
+								let fileFullName = this.getFileExt(v.name)
+								const extname = fileFullName.ext.toLowerCase()
+								if (this.extname.indexOf(extname) !== -1) {
+									files.push(v)
+									filePaths.push(v.path)
+								}
+							})
+							if (files.length !== res.tempFiles.length) {
+								uni.showToast({
+									title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
+									icon: 'none',
+									duration: 5000
+								})
+							}
+						} else {
+							filePaths = res.tempFilePaths
+							files = res.tempFiles
+						}
+
+						let currentData = []
+						for (let i = 0; i < files.length; i++) {
+							if (this.limitLength - this.files.length <= 0) break
+							files[i].uuid = Date.now()
+							let filedata = await this.getFileData(files[i], this.fileMediatype)
+							filedata.progress = 0
+							filedata.status = 'ready'
+							this.files.push(filedata)
+							currentData.push({...filedata,file:files[i]})
+						}
+						this.$emit('select', {
+							tempFiles: currentData,
+							tempFilePaths: filePaths
+						})
+						res.tempFiles = files
+						// 停止自动上传
+						if (!this.autoUpload || this.noSpace) {
+							res.tempFiles = []
+							// TODO 先放弃这个实现 ,不能全部上传
+							// return new Promise((resolve) => {
+							// 	this.$uploadFiles = () => {
+							// 		// this._is_uploading = true
+							// 		resolve(res)
+							// 	}
+							// })
+						}
+					},
+					onUploadProgress: progressEvent => {
+						this.setProgress(progressEvent, progressEvent.index)
+					}
+				})
+				.then(result => {
+					this.setSuccessAndError(result.tempFiles)
+				})
+				.catch(err => {
+					console.log('选择失败', err)
+				})
+		},
+
+		/**
+		 * 批传
+		 * @param {Object} e
+		 */
+		uploadFiles(files) {
+			files = [].concat(files)
+			this.uploadCloudFiles(files, 5, res => {
+				this.setProgress(res, res.index, true)
+			})
+				.then(result => {
+					this.setSuccessAndError(result)
+				})
+				.catch(err => {
+					console.log('err', err)
+				})
+		},
+
+		/**
+		 * 成功或失败
+		 */
+		async setSuccessAndError(res, fn) {
+			let successData = []
+			let errorData = []
+			let tempFilePath = []
+			let errorTempFilePath = []
+			for (let i = 0; i < res.length; i++) {
+				// const index  = item.index
+				const item = res[i]
+				const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index
+				if (index === -1 || !this.files) break
+				if (item.errMsg === 'request:fail') {
+					this.files[index].url = item.path
+					this.files[index].status = 'error'
+					this.files[index].errMsg = item.errMsg
+					// this.files[index].progress = -1
+					errorData.push(this.files[index])
+					errorTempFilePath.push(this.files[index].url)
+				} else {
+					this.files[index].errMsg = ''
+					this.files[index].url = item.url
+					this.files[index].status = 'success'
+					this.files[index].progress += 1
+					successData.push(this.files[index])
+					tempFilePath.push(this.files[index].url)
+				}
+			}
+
+			if (successData.length > 0) {
+				this.setEmit()
+				// 状态改变返回
+				this.$emit('success', {
+					tempFiles: this.backObject(successData),
+					tempFilePaths: tempFilePath
+				})
+			}
+
+			if (errorData.length > 0) {
+				this.$emit('fail', {
+					tempFiles: this.backObject(errorData),
+					tempFilePaths: errorTempFilePath
+				})
+			}
+		},
+
+		/**
+		 * 获取进度
+		 * @param {Object} progressEvent
+		 * @param {Object} index
+		 * @param {Object} type
+		 */
+		setProgress(progressEvent, index, type) {
+			const fileLenth = this.files.length
+			const percentNum = (index / fileLenth) * 100
+			const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
+			let idx = index
+			if (!type) {
+				idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid)
+			}
+			if (idx === -1 || !this.files[idx]) return
+			// fix by mehaotian 100 就会消失,-1 是为了让进度条消失
+			this.files[idx].progress = percentCompleted - 1
+			// 上传中
+			this.$emit('progress', {
+				index: idx,
+				progress: parseInt(percentCompleted),
+				tempFile: this.files[idx]
+			})
+		},
+
+		/**
+		 * 删除
+		 * @param {Object} index
+		 */
+		delFile(index) {
+			this.$emit('delete', {
+				tempFile: this.files[index],
+				tempFilePath: this.files[index].url
+			})
+			this.files.splice(index, 1)
+			this.$nextTick(()=>{
+				this.setEmit()
+			})
+		},
+
+		/**
+		 * 获取文件名和后缀
+		 * @param {Object} name
+		 */
+		getFileExt(name) {
+			const last_len = name.lastIndexOf('.')
+			const len = name.length
+			return {
+				name: name.substring(0, last_len),
+				ext: name.substring(last_len + 1, len)
+			}
+		},
+
+		/**
+		 * 获取图片信息
+		 * @param {Object} filepath
+		 */
+		getFileInfo(filepath) {
+			return new Promise((resolve, reject) => {
+				uni.getImageInfo({
+					src: filepath,
+					success(res) {
+						resolve(res)
+					},
+					fail(err) {
+						reject(err)
+					}
+				})
+			})
+		},
+
+		/**
+		 * 获取封装数据
+		 */
+		async getFileData(files, type = 'image') {
+			// 最终需要上传数据库的数据
+			let fileFullName = this.getFileExt(files.name)
+			const extname = fileFullName.ext.toLowerCase()
+			let filedata = {
+				name: files.name,
+				uuid: files.uuid,
+				extname: extname || '',
+				cloudPath: files.cloudPath,
+				fileType: files.fileType,
+				url: files.path || files.path,
+				size: files.size, //单位是字节
+				image: {},
+				path: files.path,
+				video: {}
+			}
+			if (type === 'image') {
+				const imageinfo = await this.getFileInfo(files.path)
+				delete filedata.video
+				filedata.image.width = imageinfo.width
+				filedata.image.height = imageinfo.height
+				filedata.image.location = imageinfo.path
+			}else{
+				delete filedata.image
+			}
+			return filedata
+		},
+
+		/**
+		 * 批量上传
+		 */
+		uploadCloudFiles(files, max = 5, onUploadProgress) {
+			files = JSON.parse(JSON.stringify(files))
+			const len = files.length
+			let count = 0
+			let self = this
+			return new Promise(resolve => {
+				while (count < max) {
+					next()
+				}
+
+				function next() {
+					let cur = count++
+					if (cur >= len) {
+						!files.find(item => !item.url && !item.errMsg) && resolve(files)
+						return
+					}
+					const fileItem = files[cur]
+					const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
+					fileItem.url = ''
+					delete fileItem.errMsg
+
+					uniCloud
+						.uploadFile({
+							filePath: fileItem.path,
+							cloudPath: fileItem.cloudPath,
+							fileType: fileItem.fileType,
+							onUploadProgress: res => {
+								res.index = index
+								onUploadProgress && onUploadProgress(res)
+							}
+						})
+						.then(res => {
+							fileItem.url = res.fileID
+							fileItem.index = index
+							if (cur < len) {
+								next()
+							}
+						})
+						.catch(res => {
+							fileItem.errMsg = res.errMsg || res.message
+							fileItem.index = index
+							if (cur < len) {
+								next()
+							}
+						})
+				}
+			})
+		},
+		setEmit() {
+			let data = []
+			if (this.returnType === 'object') {
+				data = this.backObject(this.files)[0]
+			} else {
+				data = this.backObject(this.files)
+			}
+			// #ifdef VUE3
+			this.$emit('update:modelValue',data)
+			// #endif
+			// #ifndef VUE3
+			this.$emit('input', data)
+			// #endif
+		},
+		backObject(files) {
+			let newFilesData = JSON.parse(JSON.stringify(files))
+			newFilesData.map(v => {
+				delete v.path
+				delete v.uuid
+				delete v.video
+				delete v.progress
+				delete v.errMsg
+				delete v.status
+				delete v.cloudPath
+				return v
+			})
+			return newFilesData
+		},
+		async getTempFileURL(file, fileList) {
+			fileList = {
+				fileList: [].concat(fileList)
+			}
+			const urls = await uniCloud.getTempFileURL(fileList)
+			file.path = urls.fileList[0].tempFileURL || ''
+			const index = this.files.findIndex(v => v.path === file.path)
+			if (index !== -1) {
+				this.$set(this.files, index, file)
+			}
+		}
+	}
+}
+</script>
+
+<style>
+.uni-file-picker {
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	overflow: hidden;
+	/* #endif */
+}
+
+.uni-file-picker__header {
+	padding-top: 5px;
+	padding-bottom: 10px;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	justify-content: space-between;
+}
+
+.file-title {
+	font-size: 14px;
+	color: #333;
+}
+
+.file-count {
+	font-size: 14px;
+	color: #999;
+}
+
+.is-add {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	align-items: center;
+	justify-content: center;
+}
+
+.icon-add {
+	width: 50px;
+	height: 5px;
+	background-color: #f1f1f1;
+	border-radius: 2px;
+}
+
+.rotate {
+	position: absolute;
+	transform: rotate(90deg);
+}
+</style>

+ 324 - 0
uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue

@@ -0,0 +1,324 @@
+<template>
+	<view class="uni-file-picker__files">
+		<view v-if="!readonly" class="files-button" @click="choose">
+			<slot></slot>
+		</view>
+		<!-- :class="{'is-text-box':showType === 'list'}" -->
+		<view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
+			<!-- ,'is-list-card':showType === 'list-card' -->
+
+			<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
+				'files-border':index !== 0 && styles.dividline}"
+			 :style="index !== 0 && styles.dividline &&borderLineStyle">
+				<view class="uni-file-picker__item">
+					<!-- :class="{'is-text-image':showType === 'list'}" -->
+					<!-- 	<view class="files__image is-text-image">
+						<image class="header-image" :src="item.logo" mode="aspectFit"></image>
+					</view> -->
+					<view class="files__name">{{item.name}}</view>
+					<view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)">
+						<view class="icon-del icon-files"></view>
+						<view class="icon-del rotate"></view>
+					</view>
+				</view>
+				<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
+					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
+					 :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
+				</view>
+				<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
+					点击重试
+				</view>
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "uploadFile",
+		props: {
+			filesList: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			delIcon: {
+				type: Boolean,
+				default: true
+			},
+			limit: {
+				type: [Number, String],
+				default: 9
+			},
+			showType: {
+				type: String,
+				default: ''
+			},
+			listStyles: {
+				type: Object,
+				default () {
+					return {
+						// 是否显示边框
+						border: true,
+						// 是否显示分隔线
+						dividline: true,
+						// 线条样式
+						borderStyle: {}
+					}
+				}
+			},
+			readonly:{
+				type:Boolean,
+				default:false
+			}
+		},
+		computed: {
+			list() {
+				let files = []
+				this.filesList.forEach(v => {
+					files.push(v)
+				})
+				return files
+			},
+			styles() {
+				let styles = {
+					border: true,
+					dividline: true,
+					'border-style': {}
+				}
+				return Object.assign(styles, this.listStyles)
+			},
+			borderStyle() {
+				let {
+					borderStyle,
+					border
+				} = this.styles
+				let obj = {}
+				if (!border) {
+					obj.border = 'none'
+				} else {
+					let width = (borderStyle && borderStyle.width) || 1
+					width = this.value2px(width)
+					let radius = (borderStyle && borderStyle.radius) || 5
+					radius = this.value2px(radius)
+					obj = {
+						'border-width': width,
+						'border-style': (borderStyle && borderStyle.style) || 'solid',
+						'border-color': (borderStyle && borderStyle.color) || '#eee',
+						'border-radius': radius
+					}
+				}
+				let classles = ''
+				for (let i in obj) {
+					classles += `${i}:${obj[i]};`
+				}
+				return classles
+			},
+			borderLineStyle() {
+				let obj = {}
+				let {
+					borderStyle
+				} = this.styles
+				if (borderStyle && borderStyle.color) {
+					obj['border-color'] = borderStyle.color
+				}
+				if (borderStyle && borderStyle.width) {
+					let width = borderStyle && borderStyle.width || 1
+					let style = borderStyle && borderStyle.style || 0
+					if (typeof width === 'number') {
+						width += 'px'
+					} else {
+						width = width.indexOf('px') ? width : width + 'px'
+					}
+					obj['border-width'] = width
+
+					if (typeof style === 'number') {
+						style += 'px'
+					} else {
+						style = style.indexOf('px') ? style : style + 'px'
+					}
+					obj['border-top-style'] = style
+				}
+				let classles = ''
+				for (let i in obj) {
+					classles += `${i}:${obj[i]};`
+				}
+				return classles
+			}
+		},
+
+		methods: {
+			uploadFiles(item, index) {
+				this.$emit("uploadFiles", {
+					item,
+					index
+				})
+			},
+			choose() {
+				this.$emit("choose")
+			},
+			delFile(index) {
+				this.$emit('delFile', index)
+			},
+			value2px(value) {
+				if (typeof value === 'number') {
+					value += 'px'
+				} else {
+					value = value.indexOf('px') !== -1 ? value : value + 'px'
+				}
+				return value
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.uni-file-picker__files {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: flex-start;
+	}
+
+	.files-button {
+		// border: 1px red solid;
+	}
+
+	.uni-file-picker__lists {
+		position: relative;
+		margin-top: 5px;
+		overflow: hidden;
+	}
+
+	.file-picker__mask {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		position: absolute;
+		right: 0;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		color: #fff;
+		font-size: 14px;
+		background-color: rgba(0, 0, 0, 0.4);
+	}
+
+	.uni-file-picker__lists-box {
+		position: relative;
+	}
+
+	.uni-file-picker__item {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+		padding: 8px 10px;
+		padding-right: 5px;
+		padding-left: 10px;
+	}
+
+	.files-border {
+		border-top: 1px #eee solid;
+	}
+
+	.files__name {
+		flex: 1;
+		font-size: 14px;
+		color: #666;
+		margin-right: 25px;
+		/* #ifndef APP-NVUE */
+		word-break: break-all;
+		word-wrap: break-word;
+		/* #endif */
+	}
+
+	.icon-files {
+		/* #ifndef APP-NVUE */
+		position: static;
+		background-color: initial;
+		/* #endif */
+	}
+
+	// .icon-files .icon-del {
+	// 	background-color: #333;
+	// 	width: 12px;
+	// 	height: 1px;
+	// }
+
+
+	.is-list-card {
+		border: 1px #eee solid;
+		margin-bottom: 5px;
+		border-radius: 5px;
+		box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
+		padding: 5px;
+	}
+
+	.files__image {
+		width: 40px;
+		height: 40px;
+		margin-right: 10px;
+	}
+
+	.header-image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.is-text-box {
+		border: 1px #eee solid;
+		border-radius: 5px;
+	}
+
+	.is-text-image {
+		width: 25px;
+		height: 25px;
+		margin-left: 5px;
+	}
+
+	.rotate {
+		position: absolute;
+		transform: rotate(90deg);
+	}
+
+	.icon-del-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		margin: auto 0;
+		/* #endif */
+		align-items: center;
+		justify-content: center;
+		position: absolute;
+		top: 0px;
+		bottom: 0;
+		right: 5px;
+		height: 26px;
+		width: 26px;
+		// border-radius: 50%;
+		// background-color: rgba(0, 0, 0, 0.5);
+		z-index: 2;
+		transform: rotate(-45deg);
+	}
+
+	.icon-del {
+		width: 15px;
+		height: 1px;
+		background-color: #333;
+		// border-radius: 1px;
+	}
+
+	/* #ifdef H5 */
+	@media all and (min-width: 768px) {
+		.uni-file-picker__files {
+			max-width: 375px;
+		}
+	}
+
+	/* #endif */
+</style>

+ 289 - 0
uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue

@@ -0,0 +1,289 @@
+<template>
+	<view class="uni-file-picker__container">
+		<view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle">
+			<view class="file-picker__box-content" :style="borderStyle">
+				<image class="file-image" :src="item.path" mode="aspectFill" @click.stop="prviewImage(item,index)"></image>
+				<view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)">
+					<view class="icon-del"></view>
+					<view class="icon-del rotate"></view>
+				</view>
+				<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
+					<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
+					 :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
+				</view>
+				<view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
+					点击重试
+				</view>
+			</view>
+		</view>
+		<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
+			<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
+				<slot>
+					<view class="icon-add"></view>
+					<view class="icon-add rotate"></view>
+				</slot>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "uploadImage",
+		props: {
+			filesList: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			disabled:{
+				type: Boolean,
+				default: false
+			},
+			disablePreview: {
+				type: Boolean,
+				default: false
+			},
+			limit: {
+				type: [Number, String],
+				default: 9
+			},
+			imageStyles: {
+				type: Object,
+				default () {
+					return {
+						width: 'auto',
+						height: 'auto',
+						border: {}
+					}
+				}
+			},
+			delIcon: {
+				type: Boolean,
+				default: true
+			},
+			readonly:{
+				type:Boolean,
+				default:false
+			}
+		},
+		computed: {
+			styles() {
+				let styles = {
+					width: 'auto',
+					height: 'auto',
+					border: {}
+				}
+				return Object.assign(styles, this.imageStyles)
+			},
+			boxStyle() {
+				const {
+					width = 'auto',
+						height = 'auto'
+				} = this.styles
+				let obj = {}
+				if (height === 'auto') {
+					if (width !== 'auto') {
+						obj.height = this.value2px(width)
+						obj['padding-top'] = 0
+					} else {
+						obj.height = 0
+					}
+				} else {
+					obj.height = this.value2px(height)
+					obj['padding-top'] = 0
+				}
+
+				if (width === 'auto') {
+					if (height !== 'auto') {
+						obj.width = this.value2px(height)
+					} else {
+						obj.width = '33.3%'
+					}
+				} else {
+					obj.width = this.value2px(width)
+				}
+
+				let classles = ''
+				for(let i in obj){
+					classles+= `${i}:${obj[i]};`
+				}
+				return classles
+			},
+			borderStyle() {
+				let {
+					border
+				} = this.styles
+				let obj = {}
+				if (typeof border === 'boolean') {
+					obj.border = border ? '1px #eee solid' : 'none'
+				} else {
+					let width = (border && border.width) || 1
+					width = this.value2px(width)
+					let radius = (border && border.radius) || 5
+					radius = this.value2px(radius)
+					obj = {
+						'border-width': width,
+						'border-style': (border && border.style) || 'solid',
+						'border-color': (border && border.color) || '#eee',
+						'border-radius': radius
+					}
+				}
+				let classles = ''
+				for(let i in obj){
+					classles+= `${i}:${obj[i]};`
+				}
+				return classles
+			}
+		},
+		methods: {
+			uploadFiles(item, index) {
+				this.$emit("uploadFiles", item)
+			},
+			choose() {
+				this.$emit("choose")
+			},
+			delFile(index) {
+				this.$emit('delFile', index)
+			},
+			prviewImage(img, index) {
+				let urls = []
+				if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
+					this.$emit("choose")
+				}
+				if(this.disablePreview) return
+				this.filesList.forEach(i => {
+					urls.push(i.path)
+				})
+
+				uni.previewImage({
+					urls: urls,
+					current: index
+				});
+			},
+			value2px(value) {
+				if (typeof value === 'number') {
+					value += 'px'
+				} else {
+					if (value.indexOf('%') === -1) {
+						value = value.indexOf('px') !== -1 ? value : value + 'px'
+					}
+				}
+				return value
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.uni-file-picker__container {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		box-sizing: border-box;
+		/* #endif */
+		flex-wrap: wrap;
+		margin: -5px;
+	}
+
+	.file-picker__box {
+		position: relative;
+		// flex: 0 0 33.3%;
+		width: 33.3%;
+		height: 0;
+		padding-top: 33.33%;
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		/* #endif */
+	}
+
+	.file-picker__box-content {
+		position: absolute;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		left: 0;
+		margin: 5px;
+		border: 1px #eee solid;
+		border-radius: 8px;
+		overflow: hidden;
+	}
+
+	.file-picker__progress {
+		position: absolute;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		/* border: 1px red solid; */
+		z-index: 2;
+	}
+
+	.file-picker__progress-item {
+		width: 100%;
+	}
+
+	.file-picker__mask {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		position: absolute;
+		right: 0;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		color: #fff;
+		font-size: 12px;
+		background-color: rgba(0, 0, 0, 0.4);
+	}
+
+	.file-image {
+		width: 100%;
+		height: 100%;
+	}
+
+	.is-add {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+		justify-content: center;
+	}
+
+	.icon-add {
+		width: 50px;
+		height: 5px;
+		background-color: #f1f1f1;
+		border-radius: 2px;
+	}
+
+	.rotate {
+		position: absolute;
+		transform: rotate(90deg);
+	}
+
+	.icon-del-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		align-items: center;
+		justify-content: center;
+		position: absolute;
+		top: 5px;
+		right: 5px;
+		height: 26px;
+		width: 26px;
+		border-radius: 50%;
+		background-color: rgba(0, 0, 0, 0.5);
+		z-index: 2;
+		transform: rotate(-45deg);
+	}
+
+	.icon-del {
+		width: 15px;
+		height: 2px;
+		background-color: #fff;
+		border-radius: 2px;
+	}
+</style>

+ 82 - 0
uni_modules/uni-file-picker/package.json

@@ -0,0 +1,82 @@
+{
+  "id": "uni-file-picker",
+  "displayName": "uni-file-picker 文件选择上传",
+  "version": "0.2.2",
+  "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "图片上传",
+    "文件上传"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "n"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        }
+      }
+    }
+  }
+}

+ 301 - 0
uni_modules/uni-file-picker/readme.md

@@ -0,0 +1,301 @@
+
+## FilePicker 文件选择上传
+
+> **组件名:uni-file-picker**
+>  代码块: `uFilePicker`
+
+
+文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 如不绑定服务空间,`autoUpload`默认为`false`且不可更改
+> - 选择文件目前只支持 `H5` 和 `微信小程序平台` ,且 `微信小程序平台` 使用 `wx.chooseMessageFile()`
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+
+## API
+
+### FilePicker Props
+
+| 属性名					| 类型			| 默认值	| 可选值								| 说明																	|
+| :-:						| :-:			| :-:		| :-:									| :-:																	|
+| v-model/value	| Array\Object	| -			| -						| 组件数据,通常用来回显 ,类型由`return-type`属性决定	,**格式见下文**	|
+| disabled			| Boolean	| false	| -										| 组件禁用								|
+| readonly			| Boolean	| false	| -										| 组件只读,不可选择,不显示进度,不显示删除按钮								|
+| return-type		| String	| array	| array/object				| 限制 `value` 格式,当为 `object`	 时	,组件只能单选,且会覆盖	|
+| disable-preview| Boolean	| false	| -									| 禁用图片预览,仅	`mode:grid`生效	|
+| del-icon			| Boolean	| true	| -										| 是否显示删除按钮	|
+| auto-upload		| Boolean	| true	| -										| 是否自动上传,值为`true`则只触发@select,可自行上传|
+| limit					| Number\String	| 9	| -									| 最大选择个数 ,h5 会自动忽略多选的部分			|
+| title					| String	| -			| -										| 组件标题,右侧显示上传计数			|
+| mode					| String	| list	| list/grid						| 选择文件后的文件列表样式								|
+| file-mediatype| String	| image	| image/video/all			| 选择文件类型,all 只支持 H5 和微信小程序平台	|
+| file-extname	| Array\String		| -			| -						| 选择文件后缀,字符串的情况下需要用逗号分隔(推荐使用字符串),根据 `file-mediatype` 属性而不同|
+| list-styles	  | Object	| -			| -										| `mode:list` 时的样式			|
+| image-styles	| Object	| -			| -										| `mode:grid` 时的样式	|
+
+
+### value 格式 
+
+三个属性必填,否则影响组件显示
+
+```json 
+[
+	{
+		"name":"file.txt",
+		"extname":"txt",
+		"url":"https://xxxx",
+		// ...
+	}
+]
+
+```
+
+### list-styles 格式 
+
+```json 
+{
+	"borderStyle":{
+		"color":"#eee",		// 边框颜色
+		"width":"1px",		// 边框宽度
+		"style":"solid", 	// 边框样式
+		"radius":"5px" 		// 边框圆角,不支持百分比
+	},
+	"border":false, // 是否显示边框
+	"dividline":true // 是否显示分隔线
+}
+```
+
+### image-styles 格式 
+
+```json 
+{
+	"height": 60,	// 边框高度
+	"width": 60,	// 边框宽度
+	"border":{ // 如果为 Boolean 值,可以控制边框显示与否
+		"color":"#eee",		// 边框颜色
+		"width":"1px",		// 边框宽度
+		"style":"solid", 	// 边框样式
+		"radius":"50%" 		// 边框圆角,支持百分比
+	}
+}
+```
+
+### FilePicker Events
+
+|事件称名		|说明							|	返回值	|					
+|:-:			|:-:							|	:-:	|
+|@select	| 选择文件后触发 		| 见下文|
+|@progress|文件上传时触发			| 见下文|
+|@success	|上传成功触发				| 见下文|
+|@fail		|上传失败触发				| 见下文|
+|@delete	|文件从列表移除时触发| 见下文|
+
+
+#### Callback Params
+
+```json
+{
+	"progress"			: Number, 		// 上传进度 ,仅 @progress 事件包含此字段
+	"index"				: Number, 		// 上传文件索引 ,仅 @progress 事件包含此字段
+	"tempFile"			: file, 		// 当前文件对象 ,包含文件流,文件大小,文件名称等,仅 @progress 事件包含此字段
+	"tempFiles"			: files, 		// 文件列表,包含文件流,文件大小,文件名称等
+	"tempFilePaths"		: filePaths, 	// 文件地址列表,@sucess 事件为上传后的线上文件地址
+}
+
+```
+
+
+### FilePicker Methods
+
+通过 `$ref` 调用
+
+| 方法称名						| 说明			|		参数 		|				
+| :-:								| :-:		  |		:-:		  |				
+| upload						| 手动上传 	,如`autoUpload`为`false`  ,必须调用此方法| - |
+
+### FilePicker Slots
+
+插槽可定义上传按钮显示样式 
+
+|	插槽名 	| 说明 |
+| :-:			| :-:		  |
+|	default	|默认插槽|
+
+## 组件用法
+
+### 基础用法
+
+```html
+<uni-file-picker 
+	v-model="imageValue" 
+	fileMediatype="image" 
+	mode="grid" 
+	@select="select" 
+	@progress="progress" 
+	@success="success" 
+	@fail="fail" 
+/>
+```
+
+```javascript
+export default {
+		data() {
+			return {
+				imageValue:[]
+			}
+		},
+		methods:{
+			// 获取上传状态
+			select(e){
+				console.log('选择文件:',e)
+			}
+			// 获取上传进度
+			progress(e){
+				console.log('上传进度:',e)
+			},
+			
+			// 上传成功
+			success(e){
+				console.log('上传成功')
+			},
+			
+			// 上传失败
+			fail(e){
+				console.log('上传失败:',e)
+			}
+		}
+}
+
+```
+
+### 选择指定后缀图片,且限制选择个数
+
+配置 `file-mediatype` 属性为 `image`,限定只选择图片
+
+配置 `file-extname` 属性为 `'png,jpg'`,限定只选择 `png`和`jpg`后缀的图片
+
+配置 `limit` 属性为 1 ,则最多选择一张图片
+
+配置 `mode` 属性为 `grid` ,可以使用九宫格样式选择图片
+
+
+```html
+<uni-file-picker 
+	v-model="imageValue"  
+	file-mediatype="image"
+	mode="grid"
+	file-extname="png,jpg"
+	:limit="1"
+	@progress="progress" 
+	@success="success" 
+	@fail="fail" 
+	@select="select"
+/>
+```
+
+### 手动上传
+
+配置 `auto-upload` 属性为 `false` ,可以停止自动上传,通过`ref`调用`upload`方法自行选择上传时机
+
+```html
+<view>
+	<uni-file-picker  ref="files" :auto-upload="false"/>
+	<button @click="upload">上传文件</button>
+</view>
+```
+
+```javascript
+export default {
+		data() {},
+		methods:{
+			upload(){
+				this.$refs.files.upload()
+			}
+		}
+}
+
+```
+
+### 单选图片且点击再次选择
+
+配置 `disable-preview` 属性为 `true`,禁用点击预览图片功能
+
+配置 `del-icon` 属性为 `false`,隐藏删除按钮
+
+配置 `return-type` 属性为 `object`,设置 `value` 类型 ,如需绑定 `array`类型 ,则设置`limit:1`,可达到一样的效果
+
+
+
+```html
+<uni-file-picker 
+	disable-preview
+	:del-icon="false"
+	return-type="object"
+>选择头像</uni-file-picker>
+```
+
+### 自定义样式
+
+配置 `image-styles` 属性,可以自定义`mode:image`时的回显样式
+
+配置 `list-styles` 属性,可以自定义`mode:video|| mode:all`时的回显样式
+
+```html
+<view>
+	<uni-file-picker fileMediatype="image" :image-styles="imageStyles"/>
+	<uni-file-picker fileMediatype="all" :list-styles="listStyles"/>
+</view>
+```
+
+```javascript
+export default {
+		data() {
+			imageStyles:{
+				width:64,
+				height:64,
+				border:{
+					color:"#ff5a5f",
+					width:2,
+					style:'dashed',
+					radius:'2px'
+				}
+			},
+			listStyles:{
+				// 是否显示边框
+				border: true,
+				// 是否显示分隔线
+				dividline: true,
+				// 线条样式
+				borderStyle: {
+					width:1,
+					color:'blue',
+					radius:2
+				}
+			}
+		}
+}
+
+```
+
+
+
+### 使用插槽 
+
+使用默认插槽可以自定义选择文件按钮样式
+
+```html
+<uni-file-picker 
+	v-model="value" file-mediatype="all">
+	<button>选择文件</button>
+</uni-file-picker>
+```
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker](https://hellouniapp.dcloud.net.cn/pages/extUI/file-picker/file-picker)