这里的二维码组件用的 uv-ui 的二维码 可以按需引入
QRCode 二维码 | 我的资料管理-uv-ui 是全面兼容vue3+2、nvue、app、h5、小程序等多端的uni-app生态框架
<uv-qrcode ref="qrcode" :size="280" :value="payCodeUrl"></uv-qrcode>
<button type="primary" block @click="saveCode">保存收款码</button>
const payCodeUrl = 'https://xxxx/xxx.jpg'
// 获取proxy
const { proxy } = getCurrentInstance()
const wxPayIconUrl = "https://xxx.cn/upload/wxPay.png"; // 微信支付图标
const zfbPayIconUrl = "https://xxx.cn/upload/zfbPay.png"; // 支付宝支付图标
const saveQrCode = () => {
uni.showLoading({ title: '正在生成图片...', mask: true })
console.log('开始生成图片...')
return new Promise((resolve, reject) => {
// 这里用到的proxy 其实和v2的this 是一样的 我这么写才会显示
const ctx = uni.createCanvasContext('qrCanvas', proxy)
console.log('Canvas上下文已创建')
ctx.setFillStyle('#FFFFFF')
ctx.fillRect(0, 0, 600, 800)
console.log('背景绘制完成')
// 先绘制图标 如果没有图表 可以越过这里 直接去写.then后面的
Promise.all([
new Promise((resolve, reject) => {
uni.downloadFile({
url: wxPayIconUrl,
success: resolve,
fail: reject
})
}),
new Promise((resolve, reject) => {
uni.downloadFile({
url: zfbPayIconUrl,
success: resolve,
fail: reject
})
})
]).then(([wxRes, zfbRes]) => {
qrcode.value.toTempFilePath({
success: (res) => {
const qrCodePath = res.tempFilePath
console.log('二维码临时文件获取成功:', qrCodePath)
// 处理Base64数据
const [, format, base64Data] = /data:image\/(\w+);base64,(.+)$/.exec(qrCodePath) || []
if (!base64Data) {
console.error('无法解析Base64数据')
return reject(new Error('无法解析Base64数据'))
}
const tempFilePath = `${wx.env.USER_DATA_PATH}/qrcode_temp.${format || 'png'}`
uni.getFileSystemManager().writeFile({
filePath: tempFilePath,
data: uni.base64ToArrayBuffer(base64Data),
encoding: 'binary',
success: () => {
console.log('Base64 转换为临时文件成功:', tempFilePath)
uni.getImageInfo({
src: tempFilePath,
success: (qrRes) => {
console.log('二维码已绘制到Canvas')
ctx.setFillStyle('#e9edf5')
ctx.fillRect(0, 0, 600, 800)
ctx.drawImage(qrRes.path, 100, 200, 400, 400)
// 绘制标题
ctx.setTextAlign('center')
ctx.setFontSize(32)
ctx.setFillStyle('#000000')
ctx.fillText('扫码支付', 300, 120)
// 绘制金额
ctx.setFontSize(36)
ctx.setFillStyle('#1989fa')
ctx.fillText(`¥${amount.value}`, 300, 180)
// 绘制支付图标
ctx.drawImage(wxRes.tempFilePath, 183, 650, 60, 60) // 微信图标
ctx.drawImage(zfbRes.tempFilePath, 345, 650, 60, 60) // 支付宝图标
// 绘制支付方式文字
ctx.setFontSize(20)
ctx.setFillStyle('#666666')
ctx.fillText('微信支付', 220, 740)
ctx.fillText('支付宝支付', 380, 740)
// 这里的ctx.draw 为什么设置false 我也不理解 有没有大神给讲下 我设置为false就可以正常保存图片了 设置为true就不执行 加setTimeout也不行
ctx.draw(false, () => {
console.log('Canvas绘制完成')
uni.canvasToTempFilePath(
{
canvasId: 'qrCanvas',
destWidth: 600,
destHeight: 800,
quality: 1,
success: (res) => {
console.log('Canvas临时文件生成成功:', res)
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
console.log('图片保存成功')
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
resolve()
},
fail: (err) => {
console.error('保存失败:', err)
uni.hideLoading()
uni.showToast({ title: '保存失败,请检查权限', icon: 'none' })
reject(err)
}
})
},
fail: (err) => {
console.error('转换图片失败:', err)
uni.hideLoading()
uni.showToast({ title: '生成图片失败', icon: 'none' })
reject(err)
}
},
proxy
)
})
},
fail: (err) => {
console.error('获取临时文件图片信息失败:', err)
uni.hideLoading()
uni.showToast({ title: '获取图片信息失败', icon: 'none' })
reject(err)
}
})
},
fail: (err) => {
console.error('Base64 转换临时文件失败:', err)
uni.hideLoading()
uni.showToast({ title: '图片处理失败', icon: 'none' })
reject(err)
}
})
},
fail: (err) => {
console.error('获取二维码临时文件失败:', err)
uni.hideLoading()
uni.showToast({ title: '获取二维码失败', icon: 'none' })
reject(err)
}
})
}).catch(err => {
console.error('下载图标失败:', err)
uni.hideLoading()
uni.showToast({ title: '下载支付图标失败', icon: 'none' })
reject(err)
})
})
}