HomeLease/components/qrcode-modal/qrcode-modal.vue
2025-08-16 16:03:42 +08:00

292 lines
5.9 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>
<view v-if="visible" class="qrcode-modal-overlay" @click="handleOverlayClick">
<view class="qrcode-modal" @click.stop>
<view class="modal-header">
<text class="modal-title">{{ title }}</text>
<text class="modal-close" @click="handleClose">×</text>
</view>
<view class="modal-content">
<view class="qrcode-container">
<image
v-if="qrCodeDataUrl"
class="qrcode-image"
:src="qrCodeDataUrl"
mode="aspectFit"
/>
<view v-else class="qrcode-loading">
<text>生成二维码中...</text>
</view>
</view>
<view class="qrcode-info">
<text class="info-text">{{ description }}</text>
<text class="subscribe-id">预约ID: {{ subscribeId }}</text>
</view>
</view>
<view class="modal-footer">
<button class="btn-secondary" @click="handleClose">关闭</button>
<button class="btn-primary" @click="handleSave">保存到相册</button>
</view>
</view>
</view>
</template>
<script>
import { generateVerificationQRCode } from '@/utils/qrcode.js'
export default {
name: 'QRCodeModal',
props: {
visible: {
type: Boolean,
default: false
},
subscribeId: {
type: String,
required: true
},
title: {
type: String,
default: '核销验证码'
},
description: {
type: String,
default: '请出示此二维码给工作人员进行核销'
}
},
data() {
return {
qrCodeDataUrl: '',
loading: false
}
},
watch: {
visible(newVal) {
if (newVal && this.subscribeId) {
this.generateQRCode()
}
}
},
methods: {
async generateQRCode() {
if (!this.subscribeId) return
this.loading = true
try {
this.qrCodeDataUrl = await generateVerificationQRCode(this.subscribeId, {
width: 300,
margin: 4,
color: {
dark: '#48893B',
light: '#FFFFFF'
}
})
} catch (error) {
console.error('生成二维码失败:', error)
uni.showToast({
title: '生成二维码失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
handleOverlayClick() {
this.handleClose()
},
handleClose() {
this.$emit('close')
},
async handleSave() {
if (!this.qrCodeDataUrl) {
uni.showToast({
title: '二维码未生成',
icon: 'none'
})
return
}
try {
// 保存二维码到相册
await this.saveImageToAlbum(this.qrCodeDataUrl)
uni.showToast({
title: '保存成功',
icon: 'success'
})
} catch (error) {
console.error('保存失败:', error)
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
},
async saveImageToAlbum(base64Data) {
return new Promise((resolve, reject) => {
// 将base64转换为临时文件路径
const base64Data = this.qrCodeDataUrl.split(',')[1]
// #ifdef MP-WEIXIN
const arrayBuffer = uni.base64ToArrayBuffer(base64Data)
const filePath = `${wx.env.USER_DATA_PATH}/qrcode_${Date.now()}.png`
uni.getFileSystemManager().writeFile({
filePath,
data: arrayBuffer,
encoding: 'binary',
success: () => {
// 保存到相册
uni.saveImageToPhotosAlbum({
filePath,
success: () => {
resolve()
},
fail: (err) => {
reject(err)
}
})
},
fail: (err) => {
reject(err)
}
})
// #endif
// #ifndef MP-WEIXIN
// 其他平台的处理方式
uni.showToast({
title: '当前平台不支持保存到相册',
icon: 'none'
})
reject(new Error('平台不支持'))
// #endif
})
},
// Canvas加载完成事件已移除
}
}
</script>
<style lang="scss" scoped>
.qrcode-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
}
.qrcode-modal {
width: 600rpx;
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.3);
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.modal-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.modal-close {
font-size: 40rpx;
color: #999;
padding: 10rpx;
cursor: pointer;
}
.modal-content {
padding: 40rpx;
}
.qrcode-container {
display: flex;
justify-content: center;
margin-bottom: 30rpx;
}
.qrcode-image {
width: 300rpx;
height: 300rpx;
border: 1rpx solid #eee;
border-radius: 10rpx;
}
.qrcode-loading {
width: 300rpx;
height: 300rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
border-radius: 10rpx;
color: #999;
}
.qrcode-info {
text-align: center;
}
.info-text {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 20rpx;
}
.subscribe-id {
display: block;
font-size: 24rpx;
color: #999;
font-family: monospace;
}
.modal-footer {
display: flex;
padding: 30rpx;
border-top: 1rpx solid #eee;
gap: 20rpx;
}
.btn-secondary,
.btn-primary {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
cursor: pointer;
}
.btn-secondary {
background-color: #f5f5f5;
color: #666;
}
.btn-primary {
background-color: #48893B;
color: #fff;
}
</style>