Files
zhgh_cqgmy/src/main/resources/static/components/plugins/sysSignature/pc.vue
T
2026-10-30 19:02:48 +08:00

164 lines
4.8 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.log(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>