介绍:vant版本2.3.3
流程:input选取file=>append到FormData中=>提交后台。
利用FormData上传,这个流程无论换什么ui框架,或者自己写都走得通,亲测有效。(自己手写的上传就不拿出来分享了,主要是太乱,自己都看半天)
效果:
代码如下:
//v-if中的条件不重要
<p class="txt mb10" v-if="$route.query.clockStage%4 != 0">购药发票</p>
<p :class="['img','mb15',$route.query.clockId&&detail.status!=2&&detail.invoiceAud!=2?'noLook':'']">
<van-uploader
//只是禁用,还是显示上传按钮,使用noLook解决
:disabled='$route.query.clockId&&detail.status!=1&&detail.invoiceAud!=2?true:false'
:max-count="5"
//右上角删除
:deletable='$route.query.clockId&&detail.invoiceAud!=2?false:true'
v-model="form2.invoiceUrl"
:after-read="afterRead2"
v-if="$route.query.clockStage%4 != 0"
/>
<span class="show colore5" v-if="detail.invoiceAud==2">{{detail.invoiceRemarks}}</span>
</p>
<p class="txt mb10" v-if="$route.query.clockStage%4 != 0">购药证明</p>
<p :class="['img','mb15',$route.query.clockId&&detail.status!=2&&detail.invoiceProveAud!=2?'noLook':'']">
<van-uploader
:disabled='$route.query.clockId&&detail.status!=1&&detail.invoiceProveAud!=2?true:false'
:max-count="5"
:deletable='$route.query.clockId&&detail.invoiceProveAud!=2?false:true'
v-model="form2.invoiceProveUrl"
:after-read="afterRead8"
v-if="$route.query.clockStage%4 != 0"
/>
<span class="show colore5" v-if="detail.invoiceProveAud==2">{{detail.invoiceProveRemarks}}</span>
</p>
<van-button type="primary" class="w100 submit ml20 mr20 mt30 mb10" @click="submit">{{detail.status==2?'重新打卡':'打卡'}}</van-button>
data(){
return {
form2:{
invoiceUrl:[],
invoiceProveUrl:[],
detail:{}
},
}
},
created () {
const {clockId,clockStage} = this.$route.query;
if(clockId) this.getDetail(clockId);
},
methods: {
getDetail(id){ //用于回显默认数据
axios.get(this.$my.api+"/voluntee/selectClockInfo?id="+id,)
.then((res)=>{
if (res.data) {
if (res.data.code == 200) {
let val = res.data.data
this.detail =val
let setVal = (arr)=>{
let newArr = []
arr = arr?arr.split(','):[]
arr.map((item)=>{
if(item){
newArr.push({url:item})
}
})
return newArr
}
this.form2 = {
...this.form2,
invoiceUrl: setVal(val.invoiceUrl),
invoiceProveUrl:setVal(val.invoiceProveUrl),
}
} else {
this.$toast(res.data.message);
}
}
})
.catch((error) => {});
},
//上传发票
afterRead2(file){
that.$uploadImg(this.$my.api+'/wechat/upload',file)
.then((res)=>{
let arr = [...this.form2.invoiceUrl]
arr.push({url:res})
this.form2.invoiceUrl = arr.filter((item)=>!('file' in item))
this.$toast.loading({
forbidClick:true,
overlay:true,
duration:1000,
message:'上传完成'
})
})
},
//购药证明
afterRead8(file){
this.$uploadImg(this.$my.api+'/wechat/upload',file)
.then((res)=>{
let arr = [...this.form2.invoiceProveUrl]
arr.push({url:res})
this.form2.invoiceProveUrl = arr.filter((item)=>!('file' in item))
this.$toast.loading({
forbidClick:true,
overlay:true,
duration:1000,
message:'上传完成'
})
})
},
submit(){
let that = this
const {clockStage ,cardId} = this.$route.query;
let rules = {
invoiceUrl:'购药发票',
invoiceProveUrl:'购药证明',
}
if(Object.keys(rules).find(item=>this.form2[item] == '')){
this.$toast(rules[Object.keys(rules).find(item=>this.form2[item] == '')]+'不能为空')
return false
}
let getVal = (arr)=>{
let newArr = []
arr.map((item)=>{
newArr.push(item.url)
})
return newArr.join(',')
}
let val= {
//id:this.detail.status ==2?this.detail.id:'',
//userId:JSON.parse(localStorage.getItem('volunteerInfo')).id,
//userName:JSON.parse(localStorage.getItem('volunteerInfo')).name,
invoiceUrl:getVal(this.form2.invoiceUrl),
invoiceProveUrl:getVal(this.form2.invoiceProveUrl),
}
let url = ["/voluntee/saveOneClock","/voluntee/saveTwoClock","/voluntee/saveTwoClock","/voluntee/saveFourClock"]
this.$toast.loading({
duration:0,
mask: true,
message: '加载中...'
});
axios.post(this.$my.api+url[(clockStage-1)%4], val)
.then((res)=>{
if (res.data) {
if (res.data.code == 200) {
this.$router.go(-1)
this.$toast.loading({
type:'success',
mask: true,
message: res.data.message
});
setTimeout(() => {
this.$toast.clear()
}, 1000);
} else {
this.$toast(res.data.message);
}
}
})
.catch((error) => {});
},
}
//同事封装的,我copy的
import axios from 'axios'
import { Toast } from 'vant'
const compress = (fileObj)=>{
return new Promise((rej,err)=>{
// max 500 * 320
const maxHeight = 2000
const maxWidth = 1200
let img = new Image()
img.src = fileObj
img.onload = () => {
const originHeight = img.height
const originWidth = img.width
let compressedWidth = img.height
let compressedHeight = img.width
if ((originWidth > maxWidth) && (originHeight > maxHeight)) {
// 更宽更高,
if ((originHeight / originWidth) > (maxHeight / maxWidth)) {
// 更加严重的高窄型,确定最大高,压缩宽度
compressedHeight = maxHeight
compressedWidth = maxHeight * (originWidth / originHeight)
} else {
//更加严重的矮宽型, 确定最大宽,压缩高度
compressedWidth = maxWidth
compressedHeight = maxWidth * (originHeight / originWidth)
}
} else if (originWidth > maxWidth && originHeight <= maxHeight) {
// 更宽,但比较矮,以maxWidth作为基准
compressedWidth = maxWidth
compressedHeight = maxWidth * (originHeight / originWidth)
} else if (originWidth <= maxWidth && originHeight > maxHeight) {
// 比较窄,但很高,取maxHight为基准
compressedHeight = maxHeight
compressedWidth = maxHeight * (originWidth / originHeight)
} else {
// 符合宽高限制,不做压缩
}
let compressedCanvas = document.createElement("canvas")
let context = compressedCanvas.getContext("2d")
compressedCanvas.height = compressedHeight
compressedCanvas.width = compressedWidth
context.clearRect(0, 0, compressedWidth, compressedHeight)
context.drawImage(img, 0, 0, compressedWidth, compressedHeight)
let base64_img = compressedCanvas.toDataURL('image/jpeg')
const blobBin = atob(base64_img.split(',')[1]);
let data = [];
for(var i = 0; i < blobBin.length; i++) {
data.push(blobBin.charCodeAt(i));
}
let file = new Blob([new Uint8Array(data)], {type: 'image/png'});
// 上传file 至服务器
//this.uploadFile(file)
rej(file)
}
})
}
export async function postHttp(url,data ={}){
Toast.loading({
forbidClick:true,
overlay:true,
duration:0,
message:'上传当中....'
})
//这个地方,如果多选请自行修改,参考第一版
const device = [data]
let formData = new FormData();
let a = new FileReader()
device.map((item)=>{
formData.append('files', item.file ,item.file.name);
})
//压缩
//let formData = new FormData();
//let file = await compress(data.content)
//formData.append('files',file);
return new Promise((resolve,reject)=>{
axios.post(url, formData, {headers:{'Content-Type':'multipart/form-data'}})
.then(res=>{
resolve(res.data)
},(err) =>{
reject(err)
Toast.loading({
forbidClick:true,
overlay:true,
duration:1000,
message:'上传失败,请重新上传'
})
})
})
}
.img >>> .van-uploader__preview{ margin: 0 .2rem .1rem 0;position: relative;}
.noLook >>> .van-uploader__upload{display: none;}//隐藏上传按钮
<div class="flex justs alic lh60">
<span>上传身份证:</span>
<span class="colorf3 flex alic" @click="isShowHelp = true;helpType = 'card'"><van-icon name="question" color="#F3665E" class="mr5"/>帮助说明</span>
</div>
<div class="flex justs">
<p :class="['cardImg','boxImg','w100',form.cardFrontUrl.length>0?'flexImg':'',(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2 || ($route.query.giveId?false:true)?'':'noLook']" @click="activec = 'cardFrontUrl'">
<!-- capture='camera' -->
<van-uploader
:max-count="2"
:deletable='(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2 || ($route.query.giveId?false:true)?true:false'
v-model="form.cardFrontUrl"
:after-read="afterRead"
upload-text='身份证'
image-fit='fill'
/>
<!-- :disabled='(detail.status==2&&detail.isOld==1) || detail.cardFrontAud==2?false:true' -->
<span class="show colore5 remark" v-if="detail.status==2 && detail.cardFrontAud==2">{{detail.cardFrontRemarks}}</span>
</p>
</div>
<div class="flex justs alic lh60">
<span>上传发票:<van-button type="primary" v-if="isVolun&&invoiceObj.flag == 'Y'&&detail.status!=1&&detail.status!=0" size="small" @click="showInvoice = true">已上传,选择发票</van-button></span>
<span class="colorf3 flex alic" @click="isShowHelp = true;helpType = 'invoice'"><van-icon name="question" color="#F3665E" class="mr5"/>帮助说明</span>
</div>
<div class="flex justs">
<p :class="['invoiceImg','boxImg' ,'w100',(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud==2 || ($route.query.giveId?false:true)?'':'noLook']" @click="activec = 'invoiceOneUrl'">
<van-uploader
:max-count="9"
:deletable='(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud==2 || ($route.query.giveId?false:true)?true:false'
v-model="form.invoiceOneUrl"
:after-read="afterRead"
upload-text='购药发票'
image-fit='fill'
/>
<!-- :disabled='(detail.status==2&&detail.isOld==1) || detail.invoiceOneAud!=2?false:true' -->
<span class="show colore5" v-if="detail.status==2 && detail.invoiceOneAud==2">{{detail.invoiceOneRemarks}}</span>
</p>
</div>
//data数据
form:{
cardFrontUrl:[],
invoiceOneUrl:[],
},
detail:{},
activec:'',
//method
afterRead(file){
this.$upload.uploadImg(this.$config.api+'/wechat/upload',file)
.then((res)=>{
if(res){
let arr = [...this.form[this.activec]]
arr.push({url:res,isImage: true})
this.form[this.activec] = arr.filter((item)=>!('file' in item))
this.$toast.loading({
forbidClick:true,
overlay:true,
duration:1000,
message:'上传完成'
})
}
},err=>{
this.form[this.activec].pop() //处理500情况下,删除组件自动选择图片
})
},
其他代码,和上面一样。只是把多个afterRead写到一个里面,节省代码。