eventsource 支持服务器主动推送信息给客户端;不支持双向推送。
//过程就是 pc端点击扫描按钮 请求到一个唯一id,用id及其他需要的参数通过一个接口让后端生成一个二维码返回给前台,前台拿到二维码数据展示给用户并同时开启eventsource服务(后端会根据这个id每隔一段时间去查询某个表中是否有这个id对应的记录 如果有就推送给前台,没有就过一段时间继续查), 手机扫描跳转到一个上传文件页面,手机上传完毕后提交需要的数据给后端,后端将数据以及这个唯一id生成一条记录用于source接口查询;
<template>
<div style="margin-left:10px;width:50%;">
<p style="line-height:40px"><el-button type="primary" class="smallbtn" style="font-size: 12px;" @click="getcode">扫描上传</el-button></p>
<el-dialog title="扫描上传" :close-on-click-modal="false" :modal="false" id="code_dialog" center @close='setCodedata' :visible.sync="code_dialog" width="800px">
<p style="text-align:center"><img :src="codeImg" alt="" style="margin:0 auto"></p>
<span slot="footer" class="dialog-footer" style="padding:0 24px;">
<el-button style="width:120px;" ref="closebtn" @click="closecode">关闭</el-button>
</span>
</el-dialog>
<ul>
<li v-for="(item,index) in sendFileArr" :key="index">
<span class="l_span" :title="item.fileName">{{ item.fileName }}</span> <span class="delbt" @click="del(index)" style="font-size:12px;margin-left:20px;cursor:pointer">删除</span>
</li>
</ul>
</div>
</template>
<script>
import {mapState, mapGetters} from 'vuex'
export default {
props:['filetypeArr','uploadurl','clearfn','htref'], //
data () {
return {
code_dialog:false,
codeImg:'',
openbool:false,
sendFileArr:[]
}
},
components: {},
watch:{
//这里通过弹窗开启关闭时更改值,来置空组件数据
clearfn:function(val){
this.sendFileArr=[]
this.$emit('sendsuccess',[])
}
},
computed: {
userId:function(){
return localStorage.getItem('session_id')||''
}
},
methods: {
// 获取唯一id
getcodeid(){
return new Promise((resolve,reject)=>{
this.axios.post('xxxxxx').then(res=>{
if(res.data.code===200){
resolve(res.data.data.codeid)
}else{
this.$message.error('获取二维码失败') //生成不了id就不去生成二维码了
}
}).catch(err=>{
this.$message.error('获取二维码失败')
})
})
},
setCodedata(){
this.codeImg=''
},
// 获取二维码图片
async getcode(){
if(typeof EventSource==='undefined'){
this.$message.error('当前浏览器不支持手机传送数据到电脑功能,请更换浏览器或者使用电脑上传')
return
}
let codeid=await this.getcodeid()
//如果参数是汉字类对象数组,这么写:encodeURIComponent(encodeURIComponent(JSON.stringify(sendtypeArr)))
this.axios.get(`xxxxx?a=xxxx}`, {
responseType: 'arraybuffer' // 指定返回数据的格式为blob
}
).then(res => {
//拼成src
this.codeImg = 'data:image/png;base64,' + btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), ''))
this.code_dialog=true
this.opensource(codeid)
}).catch(err => {
this.$message.error('获取二维码失败')
})
},
// 开启eventsource //
opensource(codeid){
this.openbool=true
let that=this
//因为需要在点击页面某个按钮来关闭接收服务,直接在这里申明变量的话在其他方法中访问不到,所有把source实例挂到了当前方法的内部属性,这里的this.opensource就是我们当前定义的methods方法名
this.opensource.source = new EventSource(`${this.api.basePath}/Api/contract/uploadmessage/getDate?codeid=${codeid}&bookNumber=${this.bookNumber}&token=${this.userId}`)
this.opensource.source.onopen = function (event) { // 与服务器连接成功回调
console.log('成功与服务器连接')
}
this.opensource.source.onmessage = function (event) { // 监听未命名事件
console.log('接收到数据')
if(event.data){
that.openbool=false
that.$emit('sendsuccess',JSON.parse(event.data))
that.sendFileArr=JSON.parse(event.data)
that.closecode()
that.opensource.source.close()
console.log('服务器连接关闭')
}
}
this.opensource.source.onerror = function (error) { // 监听错误
console.log('错误')
}
// console.log(this.opensource.source.readyState) //服务状态,可查看eventsource api
},
// 关闭弹窗 关闭eventsource
closecode:function(){
// console.log(this.opensource.source.readyState)
// 如果已接收到数据,直接关闭弹窗
if(!this.openbool){
this.code_dialog=false
return
}
// 服务正在开启 则openbool改成false 关闭服务 关闭弹窗
this.$confirm('确定要关闭吗',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'}).then(()=>{
// console.log(this.opensource.source.close)
this.opensource.source.close()
this.opensource.source=null
this.openbool=false
this.code_dialog=false
}).catch(()=>{
this.$message.success('已取消')
})
},
del(index){ //可删除
this.sendFileArr.splice(index,1)
this.$emit('sendsuccess',this.sendFileArr)
}
},
mounted(){
}
}
</script>
<style lang='scss' scoped>
ul{
width:100%;
margin-left:10px;
// margin-top:10px;
li{
display:flex;
justify-content: space-between;
align-items: center;
line-height:26px;
margin-top:5px;
.l_span{
width:80%;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
}
}
li:nth-of-type(1){
margin-top:10px
}
li:hover{
background-color: #F5F7FA;
.delbt{
color:#409EFF
}
}
}
</style>