<template>
<div class="wrap">
<div class="container">
<div class="titleLine">住院费用</div>
<div class="outBlock">
<div class="timeLine blockTitle">
<span>住院发票(必传)</span>
<span>编辑</span>
</div>
<van-uploader class="uploader" multiple v-model="fileList" accept=".png, .jpg, .jpeg" preview-size="50px" :after-read="afterRead" @delete="deleteFile" />
</div>
</div>
<div class="notice">
注:
<br />您最多可上传30张
</div>
<div class="n-uploadMsg" v-show="uploadConf.show">
<div>
<h3>上传中</h3>
<p>请耐心等待</p>
<p>当前进度{{ uploadOk }}/{{ fileList.length }}</p>
<footer>
<button @click="cancelUpload">取消上传</button>
<button v-if="uploadConf.state !== 'pause'" @click="uploadConf.state = 'pause'">暂停</button>
<button v-else @click="uploadAll">继续上传</button>
</footer>
</div>
</div>
<button id="btn" :disabled="!fileList.length" @click="uploadAll">保存并上传</button>
</div>
</template>
<script>
import { Toast, Uploader } from 'vant'
import { reactive, computed } from 'vue'
import { uploadClaimImage } from '@/api/claimApi.js'
export default {
components: {
[Uploader.name]: Uploader
},
beforeMount() {
this.formData = new FormData()
},
setup() {
const fileList = reactive([])
const uploadConf = reactive({
show: false,
state: 'ready'
})
const uploadOk = computed(() => fileList.filter(v => v.status).length)
const afterRead = async item => {
const arr = Object.prototype.toString.call(item) === '[object Array]' ? item : [item]
for (const v of arr) {
if (v.file.size / 1024 / 1024 > 1) {
const q = (1 / v.file.size) * 1024 * 1024
v.url = await compressImg({ src: v.content, q })
if (v.url) {
v.orgContent = v.content
v.content = v.url
v.q = q
v.orgFile = v.file
v.file = base64ToFile(v.url, v.file.name)
console.log(`原始大小:${v.orgFile.size}, 压缩大小${v.file.size}`)
} else v.url = v.content
}
fileList.push(v)
}
console.log(fileList)
}
const uploadAll = async () => {
if (!fileList.length || uploadConf.state === 'uploading') return
uploadConf.show = true
uploadConf.state = 'uploading'
const form = new FormData()
form.set('orderId', 'dd20220622010213912312/BBY012/070008')
for (const item of fileList.filter(v => !v.status)) {
console.log(item)
form.set('file', item.file) //file对象的
form.set('file2', item.url) //base64的
const res = await uploadClaimImage(form).catch(() => false)
if (uploadConf.state !== 'uploading') return
item.status = res ? 'done' : 'failed'
}
Toast('上传完毕')
uploadConf.show = false
uploadConf.state = 'ready'
}
const cancelUpload = () => {
uploadConf.show = false
uploadConf.state = 'ready'
fileList.forEach(v => (v.status = ''))
}
const deleteFile = item => {
const idx = fileList.findIndex(v => v.file === item.file)
idx >= 0 && fileList.splice(idx)
return true
}
const compressImg = async ({ src, q = 1, w, h, type = 'image/jpeg' }) => {
if (q > 1 || q <= 0) q = 1
const [img, c] = [new Image(), document.createElement('canvas')]
img.src = src
img.style.position = 'fixed'
img.style.left = '-9999px'
if (w) img.style.width = w
if (h) img.style.height = h
document.body.appendChild(img)
let res = await new Promise(r => ((img.onload = () => r(1)), (img.onerror = () => r(0))))
if (!res) return false
w = c.width = img.clientWidth * q
h = c.height = img.clientHeight * q
const ctx = c.getContext('2d')
ctx.drawImage(img, 0, 0, w, h)
res = c.toDataURL(type, 1)
document.body.appendChild(img)
img.remove()
c.remove()
return res
}
const base64ToUnit8 = s => {
const arr = s.split(','),
binary = atob(arr[1]),
u8 = new Uint8Array(binary.length)
let i = binary.length
while (i--) {
u8[i] = binary.charCodeAt(i)
}
return u8
}
const base64ToFile = (s, fileName) => {
const arr = s.split(',')
return new File([base64ToUnit8(s)], fileName || `文件.${arr[0].match(/\/([^\\/;]+);/)[1]}`, { type: arr[0].match(/:([^]*);/)[1] })
}
return {
fileList,
picList,
afterRead,
uploadConf,
uploadAll,
uploadOk,
cancelUpload,
deleteFile
}
}
}
</script>
<style lang="less" scoped>
.wrap {
.container {
height: 100%;
font-size: 28/100rem;
color: #808080;
background: #f0f0f0;
.titleLine {
color: #09b6f2;
margin: 0.2rem;
}
.outBlock {
margin: 0 10/100rem 20/100rem 10/100rem;
background: #ffffff;
.timeLine {
padding: 10px 15px;
line-height: 24px;
font-size: 14px;
color: #09b6f2;
height: 24px;
position: relative;
display: flex;
justify-content: space-between;
&:after {
content: ' ';
position: absolute;
pointer-events: none;
box-sizing: border-box;
left: 15px;
right: 0;
bottom: 0;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
border-bottom: 1px solid #ebedf0;
}
}
}
.van-uploader {
padding: 0.26667rem 0.4rem;
}
}
.notice {
padding: 10px 15px;
color: #ff4444;
margin: 0.2rem;
}
#btn {
margin: 0.4rem 7%;
width: 86%;
line-height: 0.8rem;
border-radius: 7px;
color: #fff;
text-align: center;
outline: none;
background: #09b6f2;
border: none;
}
.n-uploadMsg {
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.6);
position: fixed;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
> div {
width: 70vw;
border-radius: 2vw;
overflow: hidden;
background: #fff;
> h3 {
padding: 7vw 0;
color: #000;
font-weight: bold;
font-size: 5vw;
margin: 0;
text-align: center;
}
> p {
font-size: 3.6vw;
margin: 0;
line-height: 1.6;
color: #555;
text-align: center;
}
> footer {
display: flex;
border-top: 1px solid #ddd;
margin-top: 7vw;
height: 10vw;
font-size: 4vw;
color: #09b6f2;
align-items: stretch;
> button {
flex: 0 0 50%;
border: 0;
background: none;
color: inherit;
font-size: inherit;
& + button {
border-left: 1px solid #ddd;
}
}
}
}
}
}
</style>
02-01
397
07-15
1738