165 lines
4.9 KiB
Vue
165 lines
4.9 KiB
Vue
<template>
|
|
<el-card shadow="never" class="pc-signature-card">
|
|
<div class="pc-signature">
|
|
<el-link type="primary">扫描下方二维码进行签字</el-link>
|
|
<div class="signature-body" v-loading="loading">
|
|
<QrCode v-if="!signatureContent" :options="{ width: 126 }" :value="signatureAddress"
|
|
class="signature-qrcode"></QrCode>
|
|
<el-image v-if="signatureContent" :src="signatureContent" class="signature-image"></el-image>
|
|
</div>
|
|
<el-link type="danger" icon="el-icon-edit" @click="signatureAgain" v-if="signatureContent">重签</el-link>
|
|
</div>
|
|
</el-card>
|
|
</template>
|
|
|
|
<script>
|
|
module.exports = {
|
|
name: "sysSignaturePc",
|
|
store,
|
|
props: {
|
|
value: {
|
|
type: String,
|
|
default: ""
|
|
}
|
|
},
|
|
watch: {
|
|
value: {
|
|
handler(val) {
|
|
if (val) {
|
|
this.signatureContent = val
|
|
this.$emit("input", this.signatureContent)
|
|
}
|
|
},
|
|
immediate: true
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
// 二维码携带本次组件实例的标识,与服务端当前登录用户共同确定签字记录。
|
|
id: new Date().getTime() + Math.floor(Math.random() * 10000) + 1,
|
|
signatureAddress: null,
|
|
interval: null,
|
|
connectionWaitResolve: null,
|
|
unsubscribeSignature: null,
|
|
signatureContent: null,
|
|
loading: true,
|
|
}
|
|
},
|
|
methods: {
|
|
/**
|
|
* 无请求参数,返回 Promise;响应 code 为0表示成功,data.signature 为已有签字图片地址。
|
|
* 请求结束后由 mounted 的 finally 统一关闭 loading。
|
|
*/
|
|
init() {
|
|
this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id
|
|
// 打印当前二维码的签字入口,便于从控制台复制地址进行签字测试。
|
|
console.info("signatureAddress:", this.signatureAddress)
|
|
return this.$axios.post("/platform/signature/get")
|
|
.then((res) => {
|
|
if (this._isBeingDestroyed || this._isDestroyed) {
|
|
return
|
|
}
|
|
if (res.code !== 0) {
|
|
throw new Error("签字信息加载失败")
|
|
}
|
|
this.signatureContent = res.data && res.data.signature
|
|
this.$emit("input", this.signatureContent)
|
|
})
|
|
},
|
|
// 返回等待完成的 Promise;连接成功、等待30秒或组件销毁时结束等待。
|
|
waitForConnection() {
|
|
return new Promise((resolve) => {
|
|
const startedAt = Date.now()
|
|
this.connectionWaitResolve = resolve
|
|
const checkReady = () => {
|
|
this.interval = null
|
|
if (this._isBeingDestroyed || this._isDestroyed ||
|
|
(webSocketPubSub.ws && webSocketPubSub.ws.readyState === WebSocket.OPEN)) {
|
|
this.connectionWaitResolve = null
|
|
resolve()
|
|
return
|
|
}
|
|
if (Date.now() - startedAt >= 30000) {
|
|
this.connectionWaitResolve = null
|
|
this.$message.warning("签字消息连接超时,请刷新页面重试")
|
|
resolve()
|
|
return
|
|
}
|
|
this.interval = setTimeout(checkReady, 100)
|
|
}
|
|
checkReady()
|
|
})
|
|
},
|
|
signatureAgain() {
|
|
const val = sessionStorage.getItem("h5-scan-code-signature-" + this.id)
|
|
this.signatureContent = val
|
|
this.$emit("input", val)
|
|
}
|
|
},
|
|
mounted() {
|
|
this.loading = true
|
|
// 先登记消息回调,连接成功后由公共连接加入房间,避免请求期间遗漏订阅。
|
|
this.unsubscribeSignature = webSocketPubSub.subscribe("h5-scan-code-signature", (data) => {
|
|
this.signatureContent = data.value
|
|
this.$emit("input", data.value)
|
|
})
|
|
this.init()
|
|
.then(() => {
|
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
|
return this.waitForConnection()
|
|
}
|
|
})
|
|
.catch(() => {
|
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
|
this.$message.error("签字信息加载失败,请刷新页面重试")
|
|
}
|
|
})
|
|
.finally(() => {
|
|
if (!this._isBeingDestroyed && !this._isDestroyed) {
|
|
this.loading = false
|
|
}
|
|
})
|
|
},
|
|
beforeDestroy() {
|
|
// pjax 切换页面时取消轮询和订阅,旧组件不得继续接收签字消息。
|
|
clearTimeout(this.interval)
|
|
this.interval = null
|
|
if (this.connectionWaitResolve) {
|
|
this.connectionWaitResolve()
|
|
this.connectionWaitResolve = null
|
|
}
|
|
if (this.unsubscribeSignature) {
|
|
this.unsubscribeSignature()
|
|
this.unsubscribeSignature = null
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.pc-signature-card {
|
|
border: 1px solid var(--border-color-base);
|
|
}
|
|
|
|
.pc-signature {
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
row-gap: 20px;
|
|
}
|
|
|
|
.signature-body {
|
|
position: relative;
|
|
}
|
|
|
|
.signature-qrcode {
|
|
transition: opacity 0.5s ease;
|
|
}
|
|
|
|
.signature-image {
|
|
height: 100px;
|
|
width: auto;
|
|
}
|
|
</style>
|