679 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
		
		
			
		
	
	
			679 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
|  | <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, | |||
|  | 		uploadCloudFiles | |||
|  | 	} from './choose-and-upload-file.js' | |||
|  | 	import { | |||
|  | 		get_file_ext, | |||
|  | 		get_extname, | |||
|  | 		get_files_and_is_max, | |||
|  | 		get_file_info, | |||
|  | 		get_file_data | |||
|  | 	} from './utils.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 | |||
|  | 		}, | |||
|  | 		options: { | |||
|  | 			virtualHost: true | |||
|  | 		}, | |||
|  | 		emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'], | |||
|  | 		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'] | |||
|  | 				} | |||
|  | 			}, | |||
|  | 			sourceType: { | |||
|  | 				type: Array, | |||
|  | 				default () { | |||
|  | 					return  ['album', 'camera'] | |||
|  | 				} | |||
|  | 			}, | |||
|  | 			provider: { | |||
|  | 				type: String, | |||
|  | 				default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
 | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		data() { | |||
|  | 			return { | |||
|  | 				files: [], | |||
|  | 				localValue: [] | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		watch: { | |||
|  | 			// #ifndef VUE3
 | |||
|  | 			value: { | |||
|  | 				handler(newVal, oldVal) { | |||
|  | 					this.setValue(newVal, oldVal) | |||
|  | 				}, | |||
|  | 				immediate: true | |||
|  | 			}, | |||
|  | 			// #endif
 | |||
|  | 			// #ifdef VUE3
 | |||
|  | 			modelValue: { | |||
|  | 				handler(newVal, oldVal) { | |||
|  | 					this.setValue(newVal, oldVal) | |||
|  | 				}, | |||
|  | 				immediate: true | |||
|  | 			}, | |||
|  | 			// #endif
 | |||
|  | 		}, | |||
|  | 		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 | |||
|  | 			} | |||
|  | 		}, | |||
|  | 		created() { | |||
|  | 			// TODO 兼容不开通服务空间的情况
 | |||
|  | 			if (!(uniCloud.config && uniCloud.config.provider)) { | |||
|  | 				this.noSpace = true | |||
|  | 				uniCloud.chooseAndUploadFile = chooseAndUploadFile | |||
|  | 			} | |||
|  | 			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: { | |||
|  | 			/** | |||
|  | 			 * 公开用户使用,清空文件 | |||
|  | 			 * @param {Object} index | |||
|  | 			 */ | |||
|  | 			clearFiles(index) { | |||
|  | 				if (index !== 0 && !index) { | |||
|  | 					this.files = [] | |||
|  | 					this.$nextTick(() => { | |||
|  | 						this.setEmit() | |||
|  | 					}) | |||
|  | 				} else { | |||
|  | 					this.files.splice(index, 1) | |||
|  | 				} | |||
|  | 				this.$nextTick(() => { | |||
|  | 					this.setEmit() | |||
|  | 				}) | |||
|  | 			}, | |||
|  | 			/** | |||
|  | 			 * 公开用户使用,继续上传 | |||
|  | 			 */ | |||
|  | 			upload() { | |||
|  | 				let files = [] | |||
|  | 				this.files.forEach((v, index) => { | |||
|  | 					if (v.status === 'ready' || v.status === 'error') { | |||
|  | 						files.push(Object.assign({}, v)) | |||
|  | 					} | |||
|  | 				}) | |||
|  | 				return this.uploadFiles(files) | |||
|  | 			}, | |||
|  | 			async setValue(newVal, oldVal) { | |||
|  | 				const newData =  async (v) => { | |||
|  | 					const reg = /cloud:\/\/([\w.]+\/?)\S*/ | |||
|  | 					let url = '' | |||
|  | 					if(v.fileID){ | |||
|  | 						url = v.fileID | |||
|  | 					}else{ | |||
|  | 						url = v.url | |||
|  | 					} | |||
|  | 					if (reg.test(url)) { | |||
|  | 						v.fileID = url | |||
|  | 						v.url = await this.getTempFileURL(url) | |||
|  | 					} | |||
|  | 					if(v.url) v.path = v.url | |||
|  | 					return v | |||
|  | 				} | |||
|  | 				if (this.returnType === 'object') { | |||
|  | 					if (newVal) { | |||
|  | 						await newData(newVal) | |||
|  | 					} else { | |||
|  | 						newVal = {} | |||
|  | 					} | |||
|  | 				} else { | |||
|  | 					if (!newVal) newVal = [] | |||
|  | 					for(let i =0 ;i < newVal.length ;i++){ | |||
|  | 						let v = newVal[i] | |||
|  | 						await newData(v) | |||
|  | 					} | |||
|  | 				} | |||
|  | 				this.localValue = newVal | |||
|  | 				if (this.form && this.formItem &&!this.is_reset) { | |||
|  | 					this.is_reset = false | |||
|  | 					this.formItem.setValue(this.localValue) | |||
|  | 				} | |||
|  | 				let filesData = Object.keys(newVal).length > 0 ? newVal : []; | |||
|  | 				this.files = [].concat(filesData) | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 选择文件 | |||
|  | 			 */ | |||
|  | 			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 | |||
|  | 				} | |||
|  | 				this.chooseFiles() | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 选择文件并上传 | |||
|  | 			 */ | |||
|  | 			chooseFiles() { | |||
|  | 				const _extname = get_extname(this.fileExtname) | |||
|  | 				// 获取后缀
 | |||
|  | 				uniCloud | |||
|  | 					.chooseAndUploadFile({ | |||
|  | 						type: this.fileMediatype, | |||
|  | 						compressed: false, | |||
|  | 						sizeType: this.sizeType, | |||
|  | 						sourceType: this.sourceType, | |||
|  | 						// TODO 如果为空,video 有问题
 | |||
|  | 						extension: _extname.length > 0 ? _extname : undefined, | |||
|  | 						count: this.limitLength - this.files.length, //默认9
 | |||
|  | 						onChooseFile: this.chooseFileCallback, | |||
|  | 						onUploadProgress: progressEvent => { | |||
|  | 							this.setProgress(progressEvent, progressEvent.index) | |||
|  | 						} | |||
|  | 					}) | |||
|  | 					.then(result => { | |||
|  | 						this.setSuccessAndError(result.tempFiles) | |||
|  | 					}) | |||
|  | 					.catch(err => { | |||
|  | 						console.log('选择失败', err) | |||
|  | 					}) | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 选择文件回调 | |||
|  | 			 * @param {Object} res | |||
|  | 			 */ | |||
|  | 			async chooseFileCallback(res) { | |||
|  | 				const _extname = get_extname(this.fileExtname) | |||
|  | 				const is_one = (Number(this.limitLength) === 1 && | |||
|  | 						this.disablePreview && | |||
|  | 						!this.disabled) || | |||
|  | 					this.returnType === 'object' | |||
|  | 				// 如果这有一个文件 ,需要清空本地缓存数据
 | |||
|  | 				if (is_one) { | |||
|  | 					this.files = [] | |||
|  | 				} | |||
|  | 
 | |||
|  | 				let { | |||
|  | 					filePaths, | |||
|  | 					files | |||
|  | 				} = get_files_and_is_max(res, _extname) | |||
|  | 				if (!(_extname && _extname.length > 0)) { | |||
|  | 					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 get_file_data(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 = [] | |||
|  | 				} | |||
|  | 				res.tempFiles.forEach((fileItem, index) => { | |||
|  | 					this.provider && (fileItem.provider = this.provider); | |||
|  | 					const fileNameSplit = fileItem.name.split('.') | |||
|  | 					const ext = fileNameSplit.pop() | |||
|  | 					const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_') | |||
|  | 					fileItem.cloudPath = fileName + '_' + Date.now() + '_' + index + '.' + ext | |||
|  | 				}) | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 批传 | |||
|  | 			 * @param {Object} e | |||
|  | 			 */ | |||
|  | 			uploadFiles(files) { | |||
|  | 				files = [].concat(files) | |||
|  | 				return uploadCloudFiles.call(this, files, 5, res => { | |||
|  | 						this.setProgress(res, res.index, true) | |||
|  | 					}) | |||
|  | 					.then(result => { | |||
|  | 						this.setSuccessAndError(result) | |||
|  | 						return result; | |||
|  | 					}) | |||
|  | 					.catch(err => { | |||
|  | 						console.log(err) | |||
|  | 					}) | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 成功或失败 | |||
|  | 			 */ | |||
|  | 			async setSuccessAndError(res, fn) { | |||
|  | 				let successData = [] | |||
|  | 				let errorData = [] | |||
|  | 				let tempFilePath = [] | |||
|  | 				let errorTempFilePath = [] | |||
|  | 				for (let i = 0; i < res.length; i++) { | |||
|  | 					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].fileID = item.url | |||
|  | 						const reg = /cloud:\/\/([\w.]+\/?)\S*/ | |||
|  | 						if (reg.test(item.url)) { | |||
|  | 							this.files[index].url = await this.getTempFileURL(item.url) | |||
|  | 						}else{ | |||
|  | 							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].fileID) | |||
|  | 					} | |||
|  | 				} | |||
|  | 
 | |||
|  | 				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', { | |||
|  | 					index, | |||
|  | 					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) | |||
|  | 				} | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 处理返回事件 | |||
|  | 			 */ | |||
|  | 			setEmit() { | |||
|  | 				let data = [] | |||
|  | 				if (this.returnType === 'object') { | |||
|  | 					data = this.backObject(this.files)[0] | |||
|  | 					this.localValue = data?data:null | |||
|  | 				} else { | |||
|  | 					data = this.backObject(this.files) | |||
|  | 					if (!this.localValue) { | |||
|  | 						this.localValue = [] | |||
|  | 					} | |||
|  | 					this.localValue = [...data] | |||
|  | 				} | |||
|  | 				// #ifdef VUE3
 | |||
|  | 				this.$emit('update:modelValue', this.localValue) | |||
|  | 				// #endif
 | |||
|  | 				// #ifndef VUE3
 | |||
|  | 				this.$emit('input', this.localValue) | |||
|  | 				// #endif
 | |||
|  | 			}, | |||
|  | 
 | |||
|  | 			/** | |||
|  | 			 * 处理返回参数 | |||
|  | 			 * @param {Object} files | |||
|  | 			 */ | |||
|  | 			backObject(files) { | |||
|  | 				let newFilesData = [] | |||
|  | 				files.forEach(v => { | |||
|  | 					newFilesData.push({ | |||
|  | 						extname: v.extname, | |||
|  | 						fileType: v.fileType, | |||
|  | 						image: v.image, | |||
|  | 						name: v.name, | |||
|  | 						path: v.path, | |||
|  | 						size: v.size, | |||
|  | 						fileID:v.fileID, | |||
|  | 						url: v.url, | |||
|  | 						// 修改删除一个文件后不能再上传的bug, #694
 | |||
|  |             uuid: v.uuid, | |||
|  |             status: v.status, | |||
|  |             cloudPath: v.cloudPath | |||
|  | 					}) | |||
|  | 				}) | |||
|  | 				return newFilesData | |||
|  | 			}, | |||
|  | 			async getTempFileURL(fileList) { | |||
|  | 				fileList = { | |||
|  | 					fileList: [].concat(fileList) | |||
|  | 				} | |||
|  | 				const urls = await uniCloud.getTempFileURL(fileList) | |||
|  | 				return urls.fileList[0].tempFileURL || '' | |||
|  | 			}, | |||
|  | 			/** | |||
|  | 			 * 获取父元素实例 | |||
|  | 			 */ | |||
|  | 			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; | |||
|  | 			} | |||
|  | 		} | |||
|  | 	} | |||
|  | </script> | |||
|  | 
 | |||
|  | <style> | |||
|  | 	.uni-file-picker { | |||
|  | 		/* #ifndef APP-NVUE */ | |||
|  | 		box-sizing: border-box; | |||
|  | 		overflow: hidden; | |||
|  | 		width: 100%; | |||
|  | 		/* #endif */ | |||
|  | 		flex: 1; | |||
|  | 	} | |||
|  | 
 | |||
|  | 	.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> |