Ant Design Vue和VUE3下的upload组件使用以及文件预览
文章目录
- Ant Design Vue和VUE3下的upload组件使用以及文件预览
- 一、多文件上传
- 1.需求
- 2.样例
- 3.代码
- 二、单文件上传
- 1. 需求
- 2. 样例
- 3.代码
- 二、多文件上传产生的时间超时问题
- 三、文件系统名称更改
- 1. 修改文件`index.html`
- 2. 修改文件`index.js`
- 3. 修改数据库存储的系统名称
- 四、系统登陆后的首页更改
用到技术:Ant Design Vue、VUE3、xlsx的文件预览功能(也可预览txt,csv)
一、多文件上传
1.需求
- 可以多文件上传
- 文件先上传到本地,点击开始上传再通过后端接口继续上传
- 上传后显示全部、正确和错误的数据信息
- 上传后可以下载
注意细节:
- 最开始文件上传到本地时,右边页面不加载,当点击上传后,在右边未获取数据之前,
a.上传组件无法再次上传;
b:右边数据均处于加载中状态;
c.文件下载处于不可编辑状态- 加载出数据后,
a.上传组件可再次上传;
b.文件预览中的全部、正确和错误数据均需显示出对应的数据序号
c.正确和错误的数据,均不显示‘比对结果’,仅全部数据显示- 文件下载接口注意文件类型为‘blob’
2.样例
3.代码
<template><a-row :gutter="8"><a-col :span="8"><a-card title="文件上传"><a-upload-draggerv-model:fileList="fileList"name="files"accept=".txt":multiple="true":action="action":before-upload="beforeUpload":disabled="upLoadDisabled"@remove="handleRemove":showUploadList="{showRemoveIcon: true}"><p class="ant-upload-drag-icon"><inbox-outlined></inbox-outlined></p><p class="ant-upload-text">点击或将文件拖拽到这里上传, 支持扩展名:.txt</p></a-upload-dragger><div style="text-align: right"><a-buttontype="primary":disabled="fileList.length === 0":loading="uploading"style="margin-top: 16px"@click="handleUpload">{{ uploading ? '上传中' : '开始上传' }}</a-button></div></a-card></a-col><a-col :span="16"><a-card><a-spin :spinning="upLoadSpinning" tip="数据加载中..."><a-row :gutter="16"><a-col :span="12"><a-statistic title="正确/错误(个)" :value="trueNum" class="demo-class"><template #suffix><span>/{{ falseNum }}</span></template></a-statistic></a-col><a-col :span="12"><a-statistic title="完善度" :value="wcdPercent" style="margin-right: 50px" /></a-col></a-row></a-spin></a-card><a-card title="文件预览" style="margin-top: 5px"><a-spin :spinning="upLoadSpinning" tip="数据加载中..."><a-tabs v-model:activeKey="activeKey" type="card" @change="tabChange"><a-tab-pane key="0"><template #tab><div>全部</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData0.length > 0"><a-table :columns="columns" :data-source="tableData0" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><a-tab-pane key="1"><template #tab><div>正确</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData1.length > 0"><a-table :columns="columns1" :data-source="tableData1" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><a-tab-pane key="2"><template #tab><div>错误</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData2.length > 0"><a-table :columns="columns1" :data-source="tableData2" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><template #rightExtra><a-button @click="fileDownloadBtn" type="primary" :disabled="fileDownload">文件下载</a-button></template></a-tabs></a-spin></a-card></a-col></a-row>
</template><script setup>import { message } from 'ant-design-vue'import sysConfig from '@/config'import uploadApi from '@/api/auth/uploadApi'import * as XLSX from 'xlsx'import { clone } from 'lodash-es'import fileApi from '@/api/dev/fileApi'const props = defineProps({action: {type: String,default: '/biz/file/upload',required: false}})const action = sysConfig.API_URL + props.actionconst fileList = ref([])const beforeUpload = (file) => {fileList.value = [...(fileList.value || []), file]return false}const handleRemove = (file) => {const index = fileList.value.indexOf(file)const newFileList = fileList.value.slice()newFileList.splice(index, 1)fileList.value = newFileList}const handleUpload = () => {// 可预览upLoadSpinning.value = trueupLoadDisabled.value = truefileDownload.value = trueuploading.value = trueconst fileData = new FormData()fileList.value.forEach((item) => {fileData.append('files', item.originFileObj)})uploadApi.upload(fileData).then((res) => {message.success(`文件上传成功`)previewFile()trueNum.value = res.trueNumfalseNum.value = res.falseNumwcdPercent.value = res.wcdPercent}).catch(() => {message.error(`文件上传失败`)}).finally(() => {//开始上传按钮uploading.value = false//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false//可下载fileDownload.value = false})}const activeKey = ref('0')const uploading = ref(false)const upLoadSpinning = ref(true)const upLoadDisabled = ref(true)const tableData = ref([])const tableData0 = ref([])const tableData1 = ref([])const tableData2 = ref([])const columns = ref({})const columns1 = ref({})const previewFile = () => {uploadApi.download().then((res) => {const reader = new FileReader()reader.readAsBinaryString(res.data)reader.onload = (ev) => {try {const data = ev.target.resultconst wb = XLSX.read(data, {type: 'binary',cellText: false,cellDates: true})const outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])let tableheader = outdata[0]columns.value = [{title: '序号',dataIndex: '序号',key: '序号'}]columns1.value = [{title: '序号',dataIndex: '序号',key: '序号'}]for (let val in tableheader) {if (val !== '__EMPTY') {columns.value.push({title: val,dataIndex: val,key: val})if (val !== '比对结果') {columns1.value.push({title: val,dataIndex: val,key: val})}}}tableData.value = clone(outdata)tabChange(activeKey.value)} catch (e) {return false}}fileDownload.value = false}).catch((error) => {console.log(error)})}const tabChange = (key) => {if (key === '0') {const tableAll = tableData.valuetableAll.forEach((v, i) => {v['序号'] = v.__EMPTY + 1v = { ...v, key: i + 1 }})tableData0.value = tableAll} else if (key === '1') {const tableTrue = tableData.value.filter((item) => item['比对结果'] === 1)tableTrue.forEach((v, i) => {v['序号'] = i + 1})tableData1.value = tableTrue} else if (key === '2') {const tableFalse = tableData.value.filter((item) => item['比对结果'] === 0)tableFalse.forEach((v, i) => {v['序号'] = i + 1})tableData2.value = tableFalse}}const fileDownload = ref(true)const trueNum = ref(0)const falseNum = ref(0)const wcdPercent = ref(0)const fileDownloadBtn = () => {upLoadSpinning.value = trueupLoadDisabled.value = truefileDownload.value = trueuploadApi.download().then((res) => {message.success('文件下载成功')const blob = new Blob([res.data], { type: 'application/octet-stream;charset=UTF-8' })const $link = document.createElement('a')$link.href = URL.createObjectURL(blob)// $link.download = 'xxx.xlsx'$link.download = 'xxx.csv'$link.click()document.body.appendChild($link)document.body.removeChild($link) // 下载完成移除元素window.URL.revokeObjectURL($link.href) // 释放掉blob对象//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false//可下载fileDownload.value = false}).catch((error) => {console.log(error)})}onMounted(() => {//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false})
</script><style scoped>.emptyStyle {height: 200px;background-image: url(../../assets/images/empty1.png);background-position: center;background-repeat: no-repeat;background-size: 200px 200px;cursor: default;}
</style>
二、单文件上传
1. 需求
- 单个文件上传
- 文件直接上传,直接调用后端接口
- 上传后显示全部、正确和错误的数据信息
- 上传后可以下载
注意细节:
- 文件上传未完成时,不可以再次上传,不可以下载,右边需要处于加载状态
- 文件再次上传后,原文件被覆盖,需要清除之前的fileList
- 文件下载接口注意类型为blob
2. 样例
3.代码
<template><a-row :gutter="8"><a-col :span="8"><a-card title="文件上传"><a-upload-draggerv-model:fileList="fileList"name="files"accept=".txt":multiple="false":action="action"@change="handleChange":disabled="upLoadDisabled":showUploadList="{showRemoveIcon: false}"><p class="ant-upload-drag-icon"><inbox-outlined></inbox-outlined></p><p class="ant-upload-text">点击或将文件拖拽到这里上传, 支持扩展名:.txt</p><p class="ant-upload-hint">仅支持单个文件上传</p><template #removeIcon><StarOutlined></StarOutlined></template></a-upload-dragger></a-card></a-col><a-col :span="16"><a-card><a-spin :spinning="upLoadSpinning" tip="文件加载中..."><a-row :gutter="16"><a-col :span="12"><a-statistic title="正确/错误(个)" :value="trueNum" class="demo-class"><template #suffix><span>/{{ falseNum }}</span></template></a-statistic></a-col><a-col :span="12"><a-statistic title="完善度" :value="wcdPercent" style="margin-right: 50px" /></a-col></a-row></a-spin></a-card><a-card title="文件预览" style="margin-top: 5px"><a-spin :spinning="upLoadSpinning" tip="文件加载中..."><a-tabs v-model:activeKey="activeKey" type="card" @change="tabChange"><a-tab-pane key="0"><template #tab><div>全部</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData0.length > 0"><a-table :columns="columns" :data-source="tableData0" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><a-tab-pane key="1"><template #tab><div>正确</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData1.length > 0"><a-table :columns="columns1" :data-source="tableData1" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><a-tab-pane key="2"><template #tab><div>错误</div></template><div style="padding-bottom: 20px; padding-top: 20px"><div v-if="tableData2.length > 0"><a-table :columns="columns1" :data-source="tableData2" bordered> </a-table></div><div v-else><div class="emptyStyle"></div></div></div></a-tab-pane><template #rightExtra><a-button @click="fileDownloadBtn" type="primary" :disabled="fileDownload">文件下载</a-button></template></a-tabs></a-spin></a-card></a-col></a-row>
</template><script setup>import { message } from 'ant-design-vue'import sysConfig from '@/config'import uploadApi from '@/api/auth/uploadApi'import * as XLSX from 'xlsx'import { clone } from 'lodash-es'const props = defineProps({action: {type: String,default: '/biz/file/upload',required: false}})const action = sysConfig.API_URL + props.actionconst fileList = ref([])const handleChange = (info) => {if (fileList.value.length > 1) {fileList.value.shift()}upLoadSpinning.value = trueupLoadDisabled.value = truefileDownload.value = trueconst status = info.file.statusif (status === 'done') {if (info.file.response.code === 200) {message.success(`${info.file.name}上传成功`)trueNum.value = info.file.response.data.trueNumfalseNum.value = info.file.response.data.falseNumwcdPercent.value = info.file.response.data.wcdPercent//文件上传禁选择upLoadDisabled.value = false}//可预览upLoadSpinning.value = false//可下载fileDownload.value = falsepreviewFile(1)} else if (status === 'error') {message.error(`${info.file.name}上传失败`)//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false//可下载fileDownload.value = false} else if (status === 'removed') {//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false//可下载fileDownload.value = false}}const activeKey = ref('0')const upLoadSpinning = ref(true)const upLoadDisabled = ref(true)const tableData = ref([])const tableData0 = ref([])const tableData1 = ref([])const tableData2 = ref([])const columns = ref({})const columns1 = ref({})const previewFile = () => {uploadApi.download().then((res) => {const reader = new FileReader()reader.readAsBinaryString(res.data)reader.onload = (ev) => {try {const data = ev.target.resultconst wb = XLSX.read(data, {type: 'binary',cellText: false,cellDates: true})const outdata = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]])let tableheader = outdata[0]columns.value = [{title: '序号',dataIndex: '序号',key: '序号'}]columns1.value = [{title: '序号',dataIndex: '序号',key: '序号'}]for (let val in tableheader) {if (val !== '__EMPTY') {columns.value.push({title: val,dataIndex: val,key: val})if (val !== '比对结果') {columns1.value.push({title: val,dataIndex: val,key: val})}}}tableData.value = clone(outdata)tabChange(activeKey.value)} catch (e) {return false}}fileDownload.value = falseupLoadDisabled.value = false//可预览upLoadSpinning.value = false}).catch((error) => {console.log(error)})}const tabChange = (key) => {console.log(key, 'key')if (key === '0') {const tableAll = tableData.valuetableAll.forEach((v, i) => {v['序号'] = v.__EMPTY + 1v = { ...v, key: i + 1 }})tableData0.value = tableAll} else if (key === '1') {const tableTrue = tableData.value.filter((item) => item['比对结果'] === 1)tableTrue.forEach((v, i) => {v['序号'] = i + 1})tableData1.value = tableTrue} else if (key === '2') {const tableFalse = tableData.value.filter((item) => item['比对结果'] === 0)tableFalse.forEach((v, i) => {v['序号'] = i + 1})tableData2.value = tableFalse}}const fileDownload = ref(true)const trueNum = ref(0)const falseNum = ref(0)const wcdPercent = ref(0)const fileDownloadBtn = () => {upLoadSpinning.value = trueupLoadDisabled.value = truefileDownload.value = trueuploadApi.download().then((res) => {message.success('文件下载成功')const blob = new Blob([res.data], { type: 'application/octet-stream;charset=UTF-8' })const $link = document.createElement('a')$link.href = URL.createObjectURL(blob)// $link.download = 'xxx.xlsx'$link.download = 'xxx.csv'$link.click()document.body.appendChild($link)document.body.removeChild($link) // 下载完成移除元素window.URL.revokeObjectURL($link.href) // 释放掉blob对象//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false//可下载fileDownload.value = false}).catch((error) => {console.log(error)})}onMounted(() => {//文件上传禁选择upLoadDisabled.value = false//可预览upLoadSpinning.value = false})
</script><style scoped>.emptyStyle {height: 200px;background-image: url(../../assets/images/empty1.png);background-position: center;background-repeat: no-repeat;background-size: 200px 200px;cursor: default;}
</style>
二、多文件上传产生的时间超时问题
当上传文件太多时,需要延长请求时间,以减少报错情况
文件路径:src/config/index.js
修改该文件中的TIMEOUT
以延长请求时间
三、文件系统名称更改
1. 修改文件index.html
文件路径:index.html
,修改这两处,即可修改刷新系统时候,浏览器显示的系统名称
2. 修改文件index.js
文件路径:src/config/index.js
,修改此处即可修改登陆页面系统名称
3. 修改数据库存储的系统名称
四、系统登陆后的首页更改
原始首页为个人首页,若想修改为自己想要的页面,并且面包屑也不显示已去除的个人首页时,需修改文件util.js
文件路径:src/views/auth/login/util.js