ch-tgr-h5/src/views/Merchant/PayCode.vue
2026-06-11 10:30:24 +08:00

178 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<BasePage>
<div class="paycode-page">
<div class="paycode-wrap">
<!-- 生成后的图片 -->
<div v-if="generatedImage" class="paycode-generated">
<img :src="generatedImage" alt="收款码">
</div>
<!-- 原始元素 -->
<div v-else class="paycode-original" ref="paycodeOriginalRef">
<img src="/img/paycode.jpg" alt="" style="width: 100%; display: block;" class="bg-img" @load="onBgLoad">
<div class="user-info">
<div class="info">
<img :src="$file(shopimg)" alt="">
</div>
<div class="name">
<span>{{ shopname?.length > 8 ? shopname.slice(0, 8) + '...' : shopname }}</span>
</div>
</div>
<div class="code">
<vue-qr v-if="link" :margin="0" :text="link" backgroundColor="rgb(255,255,255)"
colorLight="rgb(255,255,255)"></vue-qr>
</div>
</div>
</div>
<div class="save-btn">
<van-button type="primary" color="#ca2904" round block :loading="loading"> 长按图片保存 </van-button>
</div>
</div>
</BasePage>
</template>
<script>
import { toDataURL, downloadByDataURL } from '@/utils/html2image'
export default {
name: 'PayCode',
data() {
return {
shopname: '',
shopimg: '',
link: '',
loading: false,
generatedImage: '',
bgLoaded: false,
}
},
mounted() {
this.init()
},
methods: {
init() {
const id = this.$route.query.id
this.$get(`/v1/client/DShopsClient/${id}`).then(res => {
this.shopname = res.data.shopname
this.shopimg = res.data.shopimg
this.link = `${location.origin}${location.pathname}#/Checkout?id=${res.data.userid}&RecommendCode=${localStorage.getItem('cellphone')}`
this.$nextTick(() => {
this.generateImage()
})
}).catch(err => {
this.$showFailToast('加载失败')
})
},
onBgLoad() {
this.bgLoaded = true
},
async generateImage() {
if (this.loading) return
this.loading = true
try {
await this.$nextTick()
const el = this.$refs.paycodeOriginalRef
if (!el) throw new Error('Element not found')
// 等待元素内所有 <img>加载完成覆盖背景、商家头像、vue - qr 渲染完成的 img
const imgs = Array.from(el.querySelectorAll('img'))
await Promise.all(imgs.map(img => {
if (img.complete && img.naturalWidth > 0) return
Promise.resolve()
return new Promise(resolve => {
img.onload = img.onerror = resolve
})
}))
// 等 vue-qr 内部的 canvas 真正画出来vue-qr 内部用 canvas 绘图)
await new Promise(resolve => setTimeout(resolve, 100))
this.generatedImage = await toDataURL(el, {
format: 'png',
pixelRatio: 3, useCORS: true
})
} catch (e) {
console.error('生成收款码失败:', e)
this.$showFailToast('生成失败')
} finally {
this.loading = false
}
}
},
}
</script>
<style lang="less" scoped>
.paycode-page {
// min-height: 100vh;
background: #f5f5f5;
padding-bottom: 20px;
}
.paycode-generated {
img {
width: 100%;
display: block;
}
}
.paycode-original {
position: relative;
width: 100%;
font-family: 'PingFang SC';
>img {
width: 100%;
display: block;
}
.user-info {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 32.27vw;
display: flex;
align-items: center;
}
.info {
display: flex;
align-items: center;
img {
width: 6.4vw;
height: 6.4vw;
// border-radius: 50%;
}
}
.name {
margin-left: 2.67vw;
// margin-bottom: 2.4vw;
span {
font-size: 4vw;
color: #333;
}
}
.code {
position: absolute;
top: 42.4vw;
left: 23.33vw;
canvas,
img {
width: 53.33vw;
height: 53.33vw;
}
}
}
.save-btn {
margin: 20px;
}
</style>