问题描述
实现一个查询功能,后端根据输入的名称查询数据库,返回对应的图片链接,
将图片转成pdf后下载
例如:
后端返回数据如下:
其中照片链接是base64加密后的,需要解密
后端参考:https://www.yisu.com/zixun/312294.html
查询
const {proxy}=getCurrentInstance();
const state = reactive({
value: '', // 证书编号
resUrl:'', // 图片结果url
});
const
onSearch = searchValue => {
proxy.axios.get(`http://******************/query/${state.value}`).then((res) => {
message.success('查询成功');
state.resUrl = window.atob(res.data['照片'])
}).catch((err) => {
if(state.value == '') message.warning('请输入查询编号');
else message.error('查询失败');
});
};
下载
需要注意的点
设置'Content-Type': 'multipart/form-data'
,保证格式
设置responseType: "arraybuffer"
, 否则pdf可能是空白
const downloadFile = () => {
const config = {
headers:{
'Content-Type': 'multipart/form-data'
},
responseType: "arraybuffer"
};
const fileUrl = "http://****************/pdf/image/to";
setInitImg(state.resUrl, `${state.value}.jpg`, (file) => {
const fileData ={
'file': file,
}
proxy.axios.post(fileUrl,fileData,config).then((res) => {
// 调用封装好的下载函数
download(res.data, 'application/pdf;charset=UTF-8', `${state.value}.pdf`)
}).catch((err) => {
console.log(err.message);
});
})
};
其中用到了两个函数
setInitImg
通过图片链接转换成file格式,由于参考的文章中用的是form
表单,默认上传file
,不适用于在线图片,因此需要先进行格式转换
新建一个transferFile.js
function setInitImg(url,name,callback){
let img = url;//这里是淘宝上随便找的一张图片
let imgRes
getBase64(img, (dataURL) => {
imgRes = dataURLtoFile(dataURL, name);
callback(imgRes)
});
}
function getBase64(url, callback) {
//通过构造函数来创建的 img 实例,在赋予 src 值后就会立刻下载图片,相比 createElement() 创建 <img> 省去了 append(),也就避免了文档冗余和污染
var Img = new Image(),
dataURL = "";
Img.src = url
Img.setAttribute('crossorigin', 'anonymous'); // 解决控制台跨域报错的问题
Img.onload = function () {
//要先确保图片完整获取到,这是个异步事件
var canvas = document.createElement("canvas"), //创建canvas元素
width = Img.width, //确保canvas的尺寸和图片一样
height = Img.height;
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(Img, 0, 0, width, height); //将图片绘制到canvas中
dataURL = canvas.toDataURL("image/jpeg"); //转换图片为dataURL
callback ? callback(dataURL) : function(){}; //调用回调函数
};
}
function dataURLtoFile(dataurl, filename) {
//将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,.png)
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
export {
setInitImg
}
download
创建a
标签下载pdf文件
新建download.js
文件
export const download = (res, type, filename) => {
// 创建blob对象,解析流数据
const blob = new Blob([res], {
// 设置返回的文件类型
type: type
})
// 这里就是创建一个a标签,等下用来模拟点击事件
const a = document.createElement('a')
// 兼容webkix浏览器,处理webkit浏览器中href自动添加blob前缀,默认在浏览器打开而不是下载
const URL = window.URL || window.webkitURL
// 根据解析后的blob对象创建URL 对象
const herf = URL.createObjectURL(blob)
// 下载链接
a.href = herf
// 下载文件名,如果后端没有返回,可以自己写a.download = '文件.pdf'
a.download = filename
document.body.appendChild(a)
// 点击a标签,进行下载
a.click()
// 收尾工作,在内存中移除URL 对象
document.body.removeChild(a)
window.URL.revokeObjectURL(herf)
}
页面代码
<template>
<div class="container">
<div class="header-div">
<h1>世界珠宝拍卖数据平台</h1>
<p>WORLD JEWELRY AUCTION DATA PLATFORM</p>
<h2>权威 精准 可靠</h2>
<p>追踪来自苏富比、佳士得、富艺斯、邦瀚斯、嘉德、保利、匡时、瀚海等全球知名权威拍卖行的白钻、彩钻、红宝石、
蓝宝石、祖母绿拍卖数据,基于图表形式,为您展示各类宝石的详尽成交数据记录、分析成交信息。</p>
</div>
<div class="main-div">
<div class="illustration">
<h1>证书查询</h1>
<p>高端珠宝收藏报告代表了最高标准的可靠性、一致性和完整性。我们为所有证书报告提供核对服务,让您享受更令人放心的保证。借助证书报告核对服务,您可以方便快捷地确认证书中记载的信息与WJADP证书数据库中存档的信息是否一致。
</p>
<div class="logo"></div>
</div>
<div class="search">
<p>查询证书</p>
<a-input v-model:value="state.value" placeholder="输入证书编号" size="large" />
<a-button type="primary" size="large" @click="onSearch">查询</a-button>
</div>
<div class="picture" v-show="!state.isShow">
<a-carousel :after-change="onChange" dot-position="bottom" arrows dots-class="slick-dots slick-thumb">
<template #customPaging="props">
<a>
<img :src="getImgUrl(props.i)" />
</a>
</template>
<div v-for="item in 6" :key="item">
<img :src="getImgUrl(item-1)" width='400'/>
</div>
</a-carousel>
</div>
<div class="search-data" v-show="state.isShow">
<a-descriptions bordered :column="1">
<a-descriptions-item label="证书编号">{{state.resForm.id}}</a-descriptions-item>
<a-descriptions-item label="出证日期">{{state.resForm.date}}</a-descriptions-item>
<a-descriptions-item label="品种">{{state.resForm.variety}}</a-descriptions-item>
<a-descriptions-item label="重量">{{state.resForm.weight}}</a-descriptions-item>
<a-descriptions-item label="证书下载">
<a-button type="primary" @click="downloadFile">下载</a-button>
</a-descriptions-item>
</a-descriptions>
<a-image
:width="400"
:src="state.resUrl"
/>
</div>
</div>
<div class="footer-div">
<p>需要帮助?</p>
<p>联系我们</p>
<p>常见问题</p>
</div>
</div>
</template>
<script setup>
import { reactive, getCurrentInstance } from 'vue';
import { message } from 'ant-design-vue';
import { setInitImg } from '../src/assets/transferFile'
import { download } from '../src/assets/download'
const {proxy}=getCurrentInstance();
const state = reactive({
value: '', // 证书编号
isShow: false, // 是否显示查询结果
resForm:{}, // 查询结果
resUrl:'', // 图片结果url
});
// 点击查询
const onSearch = searchValue => {
proxy.axios.get(`http://********************/query/${state.value}`).then((res) => {
message.success('查询成功');
state.resForm.id = res.data['编号']
state.resForm.date = res.data['时间']
state.resForm.variety = res.data['拍卖主石']
state.resForm.weight = res.data['重量Ct']
state.resUrl = window.atob(res.data['照片'])
state.isShow = true
console.log(res.data)
}).catch((err) => {
if(state.value == '') message.warning('请输入查询编号');
else message.error('查询失败');
console.log(err);
});
};
// 获取示例图片
const baseUrl = "./assets/imgs/";
const getImgUrl = i => {
return require('./assets/imgs/' + i +'.jpg')
};
const onChange = current => {
console.log(current);
};
// 点击下载
const downloadFile = () => {
const config = {
headers:{
'Content-Type': 'multipart/form-data'
},
responseType: "arraybuffer"
};
const fileUrl = "http://*************************/pdf/image/to";
setInitImg(state.resUrl, `${state.value}.jpg`, (file) => {
console.log(file, file.name, file.size ,'file')
const fileData ={
'file': file,
}
proxy.axios.post(fileUrl,fileData,config).then((res) => {
// 调用封装好的下载函数
download(res.data, 'application/pdf;charset=UTF-8', `${state.value}.pdf`)
}).catch((err) => {
console.log(err.message);
});
})
};
</script>
<style scoped lang="scss">
.container {
text-align: center;
display: flex;
flex-direction: column;
// height: 100vh;
}
.header-div {
background-color: #364d79;
color: rgba(255, 253, 253, 0.788);
padding: 60px 200px;
h1 {
color: #fff;
font-size: 40px;
}
h2 {
color: rgba(255, 253, 253, 0.788);
font-size: 25px;
margin: 50px 0 20px 0;
}
}
.main-div {
padding: 30px 100px;
display: flex;
flex-direction: column;
align-items: center;
.illustration {
display: flex;
flex-direction: column;
align-items: center;
h1 {
margin: 20px;
}
p {
width: 600px
}
.logo {
width: 100px;
height: 100px;
margin: 20px 0;
background: url("./assets/imgs/logo.jpg") no-repeat center;
background-size: 100%;
}
}
.search {
display: flex;
align-items: center;
justify-content: center;
p {
margin: 0;
// width: 100px;
font-weight: 800;
}
input {
width: 300px;
margin: 30px;
}
button {
background: black;
border: none;
// width: 100px;
}
}
.picture {
width: 700px
}
.search-data {
width: 700px
}
}
.footer-div {
background-color: #364d79;
padding: 20px;
color: #fff;
text-align: center;
p {
display: block;
margin: 10px;
}
}
.download-pic {
display: flex;
justify-content: space-between;
.pic {
display: flex;
flex-direction: column;
}
}
.ant-carousel :deep(.slick-dots) {
position: relative;
height: auto;
}
.ant-carousel :deep(.slick-slide img) {
border: 5px solid #fff;
display: block;
margin: auto;
// max-width: 80%;
}
.ant-carousel :deep(.slick-arrow) {
display: none !important;
}
.ant-carousel :deep(.slick-thumb) {
bottom: 0px;
}
.ant-carousel :deep(.slick-thumb li) {
width: 60px;
height: 45px;
}
.ant-carousel :deep(.slick-thumb li img) {
width: 100%;
height: 100%;
filter: grayscale(100%);
display: block;
}
.ant-carousel :deep .slick-thumb li.slick-active img {
filter: grayscale(0%);
}
</style>
结果
查询前
查询后