先说下具体思路,需要实现一个图片,pdf ,图片+pdf,三种类型的上传功能,并且还需要展示和删除。
1.封装上传图片组件
2.传不同的类型,用来校验图片或者PDF上传了几张,图片的大小。
3.因为是上传的有图片和pdf ,所以要区分开来,值放在对应字段中,方便后面的回显
不理解的可以留言
// 上传图片
// tableItem是列表中那一条数据,reportType是要求给后端传的类型,size图片大小M,accept图片类型
<UploadFile v-model="getSendReportData.report.ossFileUploads" :rowInfo="tableItem" reportType="report" :size="10" accept="image/jpeg,image/png" />
// 展示图片 otherData在这里意思是,传PDF的数据,删除图片,PDF必须保留一张,所以后面会相加做判断
<PopList v-model="getSendReportData.report.ossFileUploads" :otherData="getSendReportData.report.ossPDFUploads" fileType="image" />
// 上传pdf
<UploadFile btnTit="选择文件" v-model="getSendReportData.report.ossPDFUploads" :rowInfo="tableItem" reportType="report" :size="50" accept="application/pdf" />
// 展示PDF otherData在这里意思是,传图片的数据,删除图片,PDF必须保留一张,所以后面会相加做判断
<PopList v-model="getSendReportData.report.ossPDFUploads" :otherData="getSendReportData.report.ossFileUploads" fileType="pdf"/>
// 上传图片和PDF
<UploadFile v-model="getSendReportData.conclusion.ossUploads" :rowInfo="tableItem" reportType="conclusion" :size="10" accept="image/jpeg,image/png,application/pdf" />
// 展示图片和PDF 这里不传otherData,因为删除功能没有要求至少保留一张图片,所以删除图片不做限制
<PopList v-model="getSendReportData.conclusion.ossUploads" fileType="imgAndPdf" />
data () {
return {
tableItem: null, // 表格行信息
getSendReportData: {
report: {
itemId: null,
ossFileUploads: [], // 图片
ossPDFUploads: [] // PDF
},
// 是否有总检报告
conclusion: {
itemId: null,
ossUploads: []
}
},
}
}
图片上传组件 UploadFile
<template>
<div class="upload-block">
<el-upload :headers="headers" action="/api/oss/file/upload" :show-file-list="false" :accept="accept" :on-success="handleUploadSuccess" :before-upload="beforeFileUpload">
<div class="t-a-l">
<el-button size="small" type="primary">{{btnTit}}</el-button><br />
</div>
</el-upload>
</div>
</template>
<script>
// Loading图片上传用来加载,Loading存在 vuex了,具体代码可以查看我之前写的
import { Loading } from 'element-ui'
let loadingInstance = null
export default {
name: 'uploadFile',
props: {
btnTit: {
default: '点击上传'
},
// 行信息
rowInfo: {
type: Object,
default: () => ({})
},
// 报告类型 report 结果报告 conclusion 筛查小结报告
reportType: {
default: ''
},
value: {
type: Array,
default: () => ([])
},
accept: {
default: 'image/jpeg,image/png'
},
size: {
default: 10
}
},
data () {
return {
files: [],
headers: {
Authorization: 'Bearer ' + localStorage.getItem('Authorization')
},
len: [] // 用来记录上传了几张
}
},
watch: {
value: {
handler (value) {
this.files = value
// 因为item.deleted为0才是实际的数据,和后端约定的,所以我这里需要过滤出实际的数据,方便后面判断上传了几张
this.len = value.filter(item => item.deleted === 0).length
},
immediate: true
}
},
model: {
prop: 'value',
event: 'handleUploadSuccess'
},
methods: {
beforeFileUpload (file) {
if (this.len >= this.size && this.accept === 'image/jpeg,image/png') { // 图片
this.$message.error(`最多可以上传${this.size}张图片`)
return false
}
if (this.len >= this.size && this.accept === 'application/pdf') { // PDF
this.$message.error(`最多可以上传${this.size}个文件`)
return false
}
if (this.len >= this.size && this.accept === 'image/png,image/jpeg,application/pdf') { // 其它文件类型
this.$message.error(`最多可以上传${this.size}份`) // 其它文件类型
return false
}
// 图片 10M pdf 50M
loadingInstance = Loading.service(this.$store.state.LoadingoOptions)
const fileSize = file.size / 1024 / 1024 < this.size
if (!fileSize) {
if (this.accept === 'image/jpeg,image/png') { // 图片
this.$message.error(`单张图片大小不能超过${this.size}MB!`)
} else if (this.accept === 'application/pdf') { // PDF
this.$message.error(`单个文件大小不能超过${this.size}MB!`)
} else { // 其它文件类型
this.$message.error(`单个文件大小不能超过${this.size}MB!`)
}
loadingInstance.close()
}
return fileSize
},
handleUploadSuccess (res, file) {
if (res.code !== 200) {
this.$message.error(res.msg)
return false
}
const { filePath, thumbnailPath } = res.data
this.files.push({
filePath: filePath,
thumbnailPath: thumbnailPath,
dataId: this.rowInfo.id,
type: this.reportType,
deleted: 0 // 文件上传成功后,均增加一个deleted字段表示 0 保留 1 删除
})
loadingInstance.close()
this.$message.success('上传成功')
this.$emit('handleUploadSuccess', this.files)
}
}
}
</script>
<style lang="less" scoped>
.t-a-l {
text-align: left;
}
</style>
图片/PDF回显组件 PopList
<template>
<div class="itemlist">
<template v-for="(item,index) in imglist">
<li v-if="item.deleted === 0" :key="index">
<img v-if="fileType === 'image'" :src="item.filePath" alt="">
<img v-if="fileType === 'pdf'" :src="item.thumbnailPath" alt="">
<img v-else :src="(item.filePath.indexOf('.pdf') > -1 || item.filePath.indexOf('.PDF') > -1) ? item.thumbnailPath : item.filePath" alt="">
<i class="iconfont icon-shanchu" @click="del(item,index)"></i>
</li>
</template>
</div>
</template>
<script>
export default {
data () {
return {
imglist: []
}
},
props: {
value: {
default: () => []
},
otherData: {
default: () => []
},
fileType: {
default: ''
}
},
watch: {
value: {
deep: true,
immediate: true,
handler (val) {
this.imglist = val
}
}
},
model: {
prop: 'value',
event: 'getValue'
},
methods: {
del (item, index) {
// 拿到图片和pdf的长度
const tablen1 = this.imglist.filter(item => item.deleted === 0).length
const tablen2 = this.otherData.filter(item => item.deleted === 0).length
if (item.id) {
if (this.fileType !== 'imgAndPdf' && (tablen1 + tablen2) <= 1) {
this.$message.error('至少保留一张图片或一个PDF文件')
return false
}
this.imglist[index].deleted = 1
} else {
// 判断是不是imgpdf,如果是,则不需要判断长度,否则需要判断长度
if (this.fileType === 'imgAndPdf') {
this.imglist.splice(index, 1)
} else {
if ((tablen1 + tablen2) > 1) {
this.imglist.splice(index, 1)
} else {
this.$message.error('至少保留一张图片')
return false
}
}
}
this.$emit('getValue', this.imglist)
}
}
}
</script>
<style lang="less" scoped>
.itemlist {
display: flex;
flex-wrap: wrap;
li {
width: 100px;
height: 100px;
border: 1px dashed #ccc;
border-radius: 4px;
overflow: hidden;
margin: 0 10px 10px 0;
position: relative;
img {
width: 100px;
height: 100px;
}
.icon-shanchu {
position: absolute;
top: 4px;
right: 6px;
font-size: 20px;
color: red;
cursor: pointer;
}
}
}
</style>
完整的代码
<!-- 弹窗 -->
<el-dialog title="提交报告" class="upload-dialog" :visible.sync="dialog.one" :close-on-click-modal="false" width="960px">
<el-form :model="conclusionForm" ref="conclusionForm" label-width="120px" class="demo-ruleForm">
<Title title="图片格式" />
<el-form-item label="" prop="选择图片" key="report-img" label-width="10px">
<UploadFile v-model="getSendReportData.report.ossFileUploads" :rowInfo="tableItem" reportType="report" :size="10" accept="image/jpeg,image/png" />
<font class="upload-text">只能上传jpg/png文件,且不超过10M,最多可以上传10张图片</font>
<PopList v-model="getSendReportData.report.ossFileUploads" :otherData="getSendReportData.report.ossPDFUploads" fileType="image" />
</el-form-item>
<Title title="PDF格式" />
<el-form-item label="" prop="选择PDF" label-width="10px">
<UploadFile btnTit="选择文件" v-model="getSendReportData.report.ossPDFUploads" :rowInfo="tableItem" reportType="report" :size="50" accept="application/pdf" />
<font class="upload-text">单个文件不超过50M,最多可以上传10个文件</font>
<PopList v-model="getSendReportData.report.ossPDFUploads" :otherData="getSendReportData.report.ossFileUploads" fileType="pdf" />
</el-form-item>
<!-- <Title title="筛查小结" /> -->
<!-- :rules="conclusionTypeRule" key="screenConclusionType" -->
<el-form-item label="是否有总检报告" prop="screenConclusionType">
<el-radio-group v-model="conclusionForm.screenConclusionType">
<el-radio :label="0">无</el-radio>
<el-radio :label="1">文件类</el-radio>
<el-radio :label="2">文字输入</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="" prop="选择文件" label-width="10px" v-show="conclusionForm.screenConclusionType === 1" key="conclusionFile">
<UploadFile v-model="getSendReportData.conclusion.ossUploads" :rowInfo="tableItem" reportType="conclusion" :size="10" accept="image/jpeg,image/png,application/pdf" />
<font class="upload-text">只能上传jpg/png/pdf文件,且不超过10M,最多可以上传10份</font>
<PopList v-model="getSendReportData.conclusion.ossUploads" fileType="imgAndPdf" />
</el-form-item>
<el-form-item label="" prop="screenConclusionText" :rules="conclusionForm.screenConclusionType === 2 ? conclusionTextRule : undefined" key="screenConclusionText" v-show="conclusionForm.screenConclusionType === 2">
<el-input type="textarea" class="w-500" placeholder="请依据本次检查提供健康指导建议" v-model="conclusionForm.screenConclusionText" :rows="10" :maxlength="300" show-word-limit></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handlerClose">取 消</el-button>
<el-button type="primary" @click="handlerSend">确 定</el-button>
</span>
</el-dialog>
data () {
return {
tableItem: null, // 表格行信息
getSendReportData: {
// 上传报告
report: {
itemId: null,
ossFileUploads: [], // 图片
ossPDFUploads: [] // PDF
},
// 筛查小结
conclusion: {
itemId: null,
ossUploads: []
}
}, // 单条发送报告
conclusionForm: {
screenConclusionType: 0,
screenConclusionText: ''
},
conclusionTypeRule: { required: true, message: '请选择类型', trigger: 'change' },
conclusionTextRule: { required: true, message: '请输入依据本次检查提供健康指导建议', trigger: 'blur' },
dialog: {
one: false
},
}
}
methods: {
// 查看报告
async getSendReportPop (row) {
this.dialog.one = true
this.getSendReportData.report.ossFileUploads = []
this.getSendReportData.report.ossPDFUploads = []
this.tableItem = row
this.conclusionForm = JSON.parse(JSON.stringify(row))
const id = this.tableItem.id
const res = await getScreeningFileList(id, 'report')
const reportRes = res.data
if (reportRes && reportRes.length > 0) {
this.getSendReportData.report.itemId = reportRes[0].dataId
reportRes.forEach((item) => {
if (item.filePath.indexOf('.pdf') > -1 || item.filePath.indexOf('.PDF') > -1) {
// pdf
this.getSendReportData.report.ossPDFUploads.push(item)
} else {
// image
this.getSendReportData.report.ossFileUploads.push(item)
}
})
}
// 如果“筛查小结”的类型是文件类
if (this.conclusionForm.screenConclusionType === 1) {
this.getConclusionInfo() // 获取文件的详情
}
},
// 根据筛查小结类型获取文件数据
async getConclusionInfo () {
const id = this.tableItem.id
this.getSendReportData.conclusion.ossUploads = []
const res = await getScreeningFileList(id, 'conclusion')
const conclusionRes = res.data
if (conclusionRes && conclusionRes.length > 0) {
this.getSendReportData.conclusion.itemId = conclusionRes[0].dataId
conclusionRes.forEach((item) => {
this.getSendReportData.conclusion.ossUploads.push(item)
})
}
},
// 弹窗确定
handlerSend () {
const report = [...this.getSendReportData.report.ossFileUploads, ...this.getSendReportData.report.ossPDFUploads]
const conclusion = [...this.getSendReportData.conclusion.ossUploads]
// 当筛查小结类型切换到文字并操作确定操作时,将筛查小结的deleted标识 都至为1 表示需要删除的数据
const noUseConclusion = this.getSendReportData.conclusion.ossUploads.map(item => {
return {
...item,
deleted: 1
}
})
if (report.length === 0) {
this.$message.error('请至少上传一张图片或一个PDF文件')
return
}
if (this.conclusionForm.screenConclusionType === 1 && conclusion.length === 0) {
this.$message.error('请上传总检报告文件')
return
}
this.$refs.conclusionForm.validate(async valid => {
if (valid) {
const options = {
itemId: this.tableItem.id,
// 类型是文件类 需要上传筛查小结的文件
ossFileUploads: this.conclusionForm.screenConclusionType === 1 ? [...report, ...conclusion] : [...report, ...noUseConclusion],
screenConclusionType: this.conclusionForm.screenConclusionType,
screenConclusionText: this.conclusionForm.screenConclusionType === 2 ? this.conclusionForm.screenConclusionText : ''
}
const res = await sendScreeningFile(options)
if (res.code === 200) {
this.$message.success('操作成功')
this.dialog.one = false
}
this.getTableList()
}
})
},
// 取消上传
handlerClose () {
this.dialog.one = false
// 取消时恢复筛查小结的初始状态
this.conclusionForm.screenConclusionType = this.tableItem.screenConclusionType
}
}