| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510 |
- <template>
- <view>
- <view class='t-toptips' :style="{top: top,background: cubgColor}" :class="[show?'t-top-show':'']">
- <view v-if="loading" class="flex flex-sub">
- <view class="flex flex-sub">
- <view class="cu-progress flex-sub round striped active sm">
- <view :style="{ background: color,width: value + '%'}"></view>
- </view>
- <text class="margin-left">{{value}}%</text>
- </view>
- <view @click="downOnAbort" v-if="value<100" class="close">取消</view>
- </view>
- <block v-else>{{msg}}</block>
- </view>
- <!-- #ifdef H5 -->
- <h5-file
- v-if="showH5"
- ref="h5File"
- :logo="logo"
- :showTip="showTip"
- :progress="value"
- @abort="onAbort"
- @close="onCloseH5"
- ></h5-file>
- <!-- #endif -->
- </view>
- </template>
- <script>
- import h5File from './h5-file.vue';
- export default {
- components: {h5File},
- props: {
- logo: {
- type: String,
- default: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F00%2F00%2F07%2F155788a6d8a5c42.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619847627&t=2da40b583002205c204d980b54b35040'
- },
- top: {
- type: String,
- default: 'auto'
- },
- bgColor: {
- type: String,
- default: 'rgba(49, 126, 243, 0.5)',
- },
- color: {
- type: String,
- default: '#55aa00',
- }
- },
- data() {
- this.uploadTask = null;
- this.downloadTask = null;
- return {
- cubgColor: '',
- loading: false,
- value: 5,
- show: false,
- msg: '执行完毕~',
- showH5: false,
- showTip: false,
- }
- },
- methods: {
- toast(title = '',{ duration = 2000, icon = 'none'} = {}) {
- uni.showToast({title,duration,icon});
- },
- getRequest(url) {
- let theRequest = new Object();
- let index = url.indexOf("?");
- if (index != -1) {
- let str = url.substring(index+1);
- let strs = str.split("&");
- for(let i = 0; i < strs.length; i ++) {
- theRequest[strs[i].split("=")[0]]=unescape(strs[i].split("=")[1]);
- }
- }
- return theRequest;
- },
- /*
- 上传说明:
- url:上传接口地址
- name:上传文件key值
- header: 上传接口请求头
- ...:body内其他参数
- */
- appChooseFile({cuWebview = '',url,name = 'file',header,addName = '',addSize = '',maxSize = 10,...formData} = {}) {
- // #ifdef APP-PLUS
- let wvPath = '/uni_modules/l-file/hybrid/html/index.html';
- let wv = plus.webview.create("",wvPath,{
- 'uni-app': 'none',
- top: 0,
- height: '100%',
- background: 'transparent'
- },{
- url,
- header,
- addName,
- addSize,
- maxSize,
- formData,
- key: name,
- logo: this.logo
- });
- wv.loadURL(wvPath);
- this.$root.$scope.$getAppWebview().append(wv);
- wv.overrideUrlLoading({mode:'reject'},(e)=>{
- let {fileName,size,str} = this.getRequest(e.url);
- fileName = unescape(fileName);
- str = unescape(str);
- return this.handleBack(fileName,str,size);
- });
- // #endif
- },
- wxChooseFile({maxSize = 10,...param}) {
- wx.chooseMessageFile({
- count: 1,
- type: 'file',
- success: ({tempFiles}) => {
- this.setdefUI();
- let file = tempFiles[0];
- if(file.size > (1024*1024 * Math.abs(maxSize))) {
- uni.showToast({
- title:`单个文件请勿超过${maxSize}M,请重新上传`,
- icon: 'none'
- });
- return this.errorHandler('文件选择失败',this.upErr);
- }
- this.handleWXUpload(param,file);
- },
- fail: () => this.errorHandler('文件选择失败',this.upErr)
- })
- },
- h5ChooseFile({maxSize = 10,...param} = {}) {
- this.showH5 = true;
- this.value = 0;
- this.$nextTick(()=>{
- this.$refs.h5File.hFile.onchange = (event) => {
- let file = event.target.files[0];
- if(file.size > (1024*1024 * Math.abs(maxSize))) {
- uni.showToast({
- title:`单个文件请勿超过${maxSize}M,请重新上传`,
- icon: 'none'
- });
- return;
- }
- this.handleH5Upload(param, file);
- }
- })
- },
- handleH5Upload({url,name = 'file',header,addName,addSize,...data} = {},tempFile) {
- let fileName = tempFile.name;
- let formData = new FormData();
- for (let keys in data) {formData.append(keys, data[keys]);}
- if (addName) {formData.append(addName, fileName);}
- if (addSize) {formData.append(addSize, tempFile.size);}
- formData.append(name, tempFile);
- this.uploadTask = new XMLHttpRequest();
- this.uploadTask.open("POST", url, true);
- for (let keys in header) {this.uploadTask.setRequestHeader(keys, header[keys]);}
-
- this.uploadTask.ontimeout = () => {
- setTimeout(()=>{
- this.showTip = false;
- return this.errorHandler('请求超时',this.upErr);
- },1000);
- };
-
- this.uploadTask.upload.addEventListener("progress",(event) => {
- if(event.lengthComputable){
- this.value = Math.ceil(event.loaded * 100 / event.total);
- if (this.value > 100) {this.value=100;}
- this.$forceUpdate();
- }
- }, false);
-
- this.uploadTask.onreadystatechange = (ev) => {
- if(this.uploadTask.readyState == 4) {
- console.log('status:'+this.uploadTask.status);
- if (this.uploadTask.status == 200) {
- return this.handleBack(fileName,this.uploadTask.responseText,tempFile.size);
- }
- else {
- this.showTip = false;
- if (this.uploadTask.status == 0) {
- console.log('请检查请求头Content-Type与服务端是否匹配,并确认服务端已正确开启跨域');
- }
- return this.errorHandler('文件上传失败',this.upErr);
- }
-
- }
- };
- this.showTip = true;
- this.uploadTask.send(formData);
- },
- handleWXUpload({url,name = 'file',header,addName,addSize,...formData} = {},tempFile) {
- let opt = {url,name,formData,header,filePath:tempFile.path};
- if (addName) {opt.formData[addName] = tempFile.name;}
- if (addSize) {opt.formData[addSize] = tempFile.size;}
- let fileName = tempFile.name;
- opt['fail'] = (e) => {
- this.showTip = false;
- return this.errorHandler('文件上传失败',this.upErr)
- };
- opt['success'] = (res) => {
- if (res.statusCode==200) {
- let data = JSON.parse(res.data);
- //可自行添加后台返回状态验证
- return this.onCommit(this.$emit('up-success',{fileName,size:tempFile.size,data}));
- }
- return this.errorHandler('文件上传失败',this.upErr);
- };
- this.showTip = true;
- this.uploadTask = uni.uploadFile(opt);
- this.uploadTask&&this.uploadTask.onProgressUpdate(({progress = 0}) => {
- if (progress <= 100) {
- this.value = progress;
- this.$forceUpdate();
- }
- });
- },
- onCloseH5() {
- this.showH5 = false;
- },
- onAbort() {
- this.uploadTask&&this.uploadTask.abort();
- this.showTip = false;
- },
- downOnAbort() {
- this.downloadTask&&this.downloadTask.abort();
- this.onCommit(false,'已取消');
- },
- // app+h5返回内容,此处按实际项目修改
- handleBack(fileName,str = '{}',size) {
- console.log('可根据需求自行修改emit内容,服务端返回:'+ str);
- try{
- str = JSON.parse(str);
- }catch(e){
- console.log('Tips: responseText are not JSON');
- }
- return this.onCommit(this.$emit('up-success',{statusCode: 200,fileName,size,data:str}));
- },
- /*
- 上传
- */
- upload(param = {}) {
- if (!param.url) {this.toast('上传地址不正确');return;}
- if (this.loading) {this.toast('还有个文件玩命处理中,请稍候..');return;}
-
- // #ifdef APP-PLUS
- return this.appChooseFile(param);
- // #endif
-
- // #ifdef MP-WEIXIN
- return this.wxChooseFile(param);
- // #endif
-
- // #ifdef H5
- this.h5ChooseFile(param);
- // #endif
- },
- /*
- 打开文件
- */
- open(filePath) {
- let system = uni.getSystemInfoSync().platform;
- if(system == 'ios'){filePath = encodeURI(filePath);}
- uni.openDocument({
- filePath,
- success: (res) => {console.log('打开文档成功');}
- });
- },
- /*
- APP自定义保存
- */
- plusSaveFile({url,customName='',opt}) {
- return new Promise((resolve,reject)=>{
- // 可自行修改参数
- // 参数api: http://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.DownloadOptions
- let downloadOptions = {
- method: "GET",
- timeout: 120,
- retryInterval: 10,
- filename:'file://storage/emulated/0/lFile/' + customName
- };
- downloadOptions = {...downloadOptions,...opt};
- this.downloadTask = plus.downloader.createDownload(url, downloadOptions,(d, status)=>{
- // 下载完成
- if(status == 200){
- let tempFilePath = d.filename;
- this.value = 100;
- this.onCommit(resolve(tempFilePath))
- } else {
- this.errorHandler('下载失败',reject)
- }
- this.downloadTask = null;
- });
- this.downloadTask.addEventListener('statechanged',({downloadedSize=0,state=0,totalSize=0}={})=>{
- if (state===3) {
- let total = totalSize>0?totalSize:fileSize;
- let progressVal = Math.ceil(downloadedSize / total* 100);
- this.value = progressVal>100?100:progressVal;
- this.$forceUpdate()
- }
- },false);
- this.downloadTask.start();
- });
- },
- /*
- 下载
- type: temporary=返回临时地址,save=长期保存到本地
- */
- download({url,type = 'temporary',customName = '',...opt}) {
- if (this.loading) {
- this.toast('还有个文件玩命处理中,请稍候..');
- return;
- }
- this.setdefUI();
-
- // #ifdef APP-PLUS
- if (type == 'save') {
- return this.plusSaveFile({url,customName,opt});
- }
- // #endif
-
- return new Promise((resolve,reject)=>{
- url = encodeURI(url);
- this.downloadTask = uni.downloadFile({
- url,
- ...opt,
- success: ({statusCode,tempFilePath}) => {
- if (statusCode === 200) {
- // #ifndef H5
- if (type == 'save') {
- uni.saveFile({
- tempFilePath,
- success:({savedFilePath}) => this.onCommit(resolve(savedFilePath)),
- fail: () => this.errorHandler('下载失败',reject)
- });
- }
- else {
- this.onCommit(resolve(tempFilePath))
- }
- // #endif
-
- // #ifdef H5
- this.onCommit(resolve(tempFilePath))
- // #endif
- }
- },
- fail: () => this.errorHandler('下载失败',reject)
- });
-
- this.downloadTask.onProgressUpdate(({progress = 0}) => {
- if (progress <= 100) {
- this.value = progress;
- this.$forceUpdate();
- }
- });
- })
-
- },
-
- onCommit(resolve,msg = '执行完毕~') {
- this.msg = msg;
- this.loading = false;
- this.showTip = false;
- this.cubgColor = 'rgba(57, 181, 74, 0.5)';
- this.uploadTask = null;
- this.downloadTask = null;
- setTimeout(()=>{this.show = false;this.showH5 = false;},1500);
- return resolve;
- },
-
- setdefUI() {
- this.cubgColor = this.bgColor;
- this.value = 0;
- this.loading = true;
- this.show = true;
- },
-
- upErr(errText) {
- this.$emit('up-error',errText);
- },
-
- errorHandler(errText,reject) {
- this.msg = errText;
- this.loading = false;
- this.cubgColor = 'rgba(229, 77, 66, 0.5)';
- this.uploadTask = null;
- this.downloadTask = null;
- setTimeout(()=>{this.show = false;},1500);
- return reject(errText);
- }
- }
- }
- </script>
- <style scoped>
- .t-toptips {
- width: 100%;
- padding: 18upx 30upx;
- box-sizing: border-box;
- position: fixed;
- z-index: 90;
- color: #fff;
- font-size: 30upx;
- left: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- word-break: break-all;
- opacity: 0;
- transform: translateZ(0) translateY(-100%);
- transition: all 0.3s ease-in-out;
- }
-
- .close {
- width: 3em;
- text-align: right;
- }
-
- .t-top-show {
- transform: translateZ(0) translateY(0);
- opacity: 1;
- }
-
- .flex {
- display: flex;
- align-items: center;
- }
-
- .flex-sub {
- flex: 1;
- }
-
- .round {
- border-radius: 5000upx;
- }
-
- /* ==================
- 进度条
- ==================== */
-
- .cu-progress {
- overflow: hidden;
- height: 28upx;
- background-color: #ebeef5;
- display: inline-flex;
- align-items: center;
- width: 100%;
- }
-
- .cu-progress+view,
- .cu-progress+text {
- line-height: 1;
- }
-
- .cu-progress.xs {
- height: 10upx;
- }
-
- .cu-progress.sm {
- height: 20upx;
- }
-
- .cu-progress view {
- width: 0;
- height: 100%;
- align-items: center;
- display: flex;
- justify-items: flex-end;
- justify-content: space-around;
- font-size: 20upx;
- color: #ffffff;
- transition: width 0.6s ease;
- }
-
- .cu-progress text {
- align-items: center;
- display: flex;
- font-size: 20upx;
- color: #333333;
- text-indent: 10upx;
- }
-
- .cu-progress.text-progress {
- padding-right: 60upx;
- }
-
- .cu-progress.striped view {
- background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-size: 72upx 72upx;
- }
-
- .cu-progress.active view {
- animation: progress-stripes 2s linear infinite;
- }
-
- @keyframes progress-stripes {
- from {
- background-position: 72upx 0;
- }
-
- to {
- background-position: 0 0;
- }
- }
-
- </style>
|