chuangte_bike_newxcx/page_shanghu/guanli/tuiguang_qrcode.vue

374 lines
7.8 KiB
Vue
Raw Normal View History

2026-01-28 18:00:39 +08:00
<template>
<view class="page">
<u-navbar title="推广二维码" :border-bottom="false" :background="bgc" back-icon-color="#111827" title-color="#111827"
title-size="34" title-bold height="44"></u-navbar>
<view class="wrap">
<!-- 说明 -->
<!-- <view class="tip">
<view class="tip-left">
<u-icon name="info-circle" size="28" color="#4297F3"></u-icon>
<text class="tip-text">点击卡片可进入详情编辑</text>
</view>
<text class="tip-id">ID{{ id }}</text>
</view> -->
<!-- 二维码卡片整块可点击去详情 -->
<view class="qr-card" @click="goDetail">
<view class="qr-title">
<text class="qr-title-main">备注{{detail.remark || '未设置'}}</text>
<view class="badge" :class="[detail.status == '1' ? 'badge-on' : 'badge-off']">
{{ detail.status == '1' ? '启用' : (detail.status == '2' ? '禁用' : '未知') }}
</view>
</view>
<view class="qr-sub">
<text class="sub-item">手机号{{ detail.userPhone || '未设置' }}</text>
<text class="sub-item">分成{{ (pointInt === 0 || pointInt) ? (pointInt + '%') : '未设置' }}</text>
</view>
<view class="qr-box" @click.stop>
<canvas id="qrcode" canvas-id="qrcode" class="qr-canvas" />
</view>
<!-- <view class="qr-link" @click.stop="copyLink">
<text class="link-text">{{ qrData }}</text>
<view class="copy-btn">复制</view>
</view>
<view class="hint">
<text>提示可复制链接去定制专属二维码</text>
</view> -->
</view>
<!-- 底部按钮 -->
<view class="btn-row">
<!-- <view class="btn ghost" @click="goDetail">
<u-icon name="edit-pen" size="28" color="#4297F3"></u-icon>
<text>进入详情</text>
</view> -->
<view class="btn primary" @click="saveQrcode">
<u-icon name="download" size="28" color="#fff"></u-icon>
<text>保存二维码</text>
</view>
</view>
</view>
</view>
</template>
<script>
import UQRCode from 'uqrcodejs';
export default {
data() {
return {
bgc: {
backgroundColor: "#F7F8FA",
},
id: '',
areaId: '',
qrData: '',
detail: {},
pointInt: null
}
},
onLoad(option) {
this.id = option.id || ''
this.areaId = option.areaId || ''
if (!this.id) {
uni.showToast({
title: '缺少推广ID',
icon: 'none'
})
return
}
this.buildQrData()
if (this.qrData) {
this.generateQrcode()
}
this.getDetail()
},
methods: {
buildQrData() {
const cfg = (this.$store && this.$store.state && this.$store.state.app && this.$store.state.app.urlConfig) ? this.$store.state.app.urlConfig : {}
let prefix = cfg.areaPromotionPrefix || ''
// 兜底:如果全局没配,按你给的默认路径生成(避免 uqrcode data 为空报错)
if (!prefix) {
prefix = 'https://wx.ccttiot.com/x/t'
}
if (!prefix) {
this.qrData = ''
return
}
// 期望格式https://wx.ccttiot.com/x/t?i=2
// 如果前缀已包含参数,则用 &i= 拼接;否则用 ?i=
if (prefix.indexOf('?') === -1) {
this.qrData = prefix + '?i=' + this.id
} else if (prefix.slice(-1) === '?' || prefix.slice(-1) === '&') {
this.qrData = prefix + 'i=' + this.id
} else {
this.qrData = prefix + '&i=' + this.id
}
},
// 取详情用于展示(不影响二维码生成)
getDetail() {
if (!this.id) return
this.$u.get('/bst/areaPromotion/' + this.id).then(res => {
if (res.code === 200) {
this.detail = res.data || {}
if (this.detail.point === 0 || this.detail.point) {
this.pointInt = Math.round(this.detail.point * 100)
} else {
this.pointInt = null
}
}
})
},
generateQrcode() {
if (!this.qrData) {
uni.showToast({
title: '二维码链接为空',
icon: 'none'
})
return
}
const qr = new UQRCode();
const qrSizeRpx = 520;
const qrSizePx = uni.upx2px(qrSizeRpx);
qr.data = this.qrData;
qr.size = qrSizePx;
const ctx = uni.createCanvasContext('qrcode', this);
qr.canvasContext = ctx;
qr.make();
qr.drawCanvas();
// 二维码下方加一行说明
setTimeout(() => {
ctx.setFontSize(22);
ctx.setFillStyle('#111827');
ctx.setTextAlign('center');
ctx.fillText( qrSizePx / 2, qrSizePx + 36);
ctx.draw(true);
}, 120);
},
saveQrcode() {
uni.canvasToTempFilePath({
canvasId: 'qrcode',
x: 0,
y: 0,
width: uni.upx2px(520),
height: uni.upx2px(560),
success: (res) => {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({
title: '保存成功',
icon: 'success'
})
},
fail: () => {
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
fail: () => {
uni.showToast({
title: '生成二维码失败',
icon: 'none'
})
}
})
},
copyLink() {
uni.setClipboardData({
data: this.qrData || '',
success: () => {
uni.showToast({
title: '已复制',
icon: 'success'
})
}
})
},
goDetail() {
if (!this.id) return
uni.navigateTo({
url: '/page_shanghu/guanli/tuiguang_detail?id=' + this.id + '&areaId=' + this.areaId
})
}
}
}
</script>
<style lang="scss">
page {
background: #F7F8FA;
min-height: 100vh;
}
.page {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.wrap {
padding: 24rpx 32rpx 40rpx;
}
.tip {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18rpx 20rpx;
background: #FFFFFF;
border-radius: 16rpx;
box-shadow: 0 8rpx 24rpx rgba(17, 24, 39, 0.06);
margin-bottom: 20rpx;
.tip-left {
display: flex;
align-items: center;
}
.tip-text {
margin-left: 10rpx;
font-size: 26rpx;
color: #374151;
}
.tip-id {
font-size: 24rpx;
color: #9CA3AF;
}
}
.qr-card {
background: linear-gradient(180deg, #FFFFFF 0%, #FDFEFF 100%);
border-radius: 24rpx;
padding: 28rpx 24rpx;
box-shadow: 0 14rpx 36rpx rgba(17, 24, 39, 0.08);
border: 1rpx solid rgba(66, 151, 243, 0.12);
}
.qr-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10rpx;
.qr-title-main {
font-size: 34rpx;
font-weight: 700;
color: #111827;
letter-spacing: 1rpx;
}
.badge {
padding: 6rpx 16rpx;
border-radius: 999rpx;
font-size: 22rpx;
}
.badge-on {
background: linear-gradient(135deg, #E8F8EE 0%, #D4F4E2 100%);
color: #16A34A;
}
.badge-off {
background: #F3F4F6;
color: #6B7280;
}
}
.qr-sub {
display: flex;
justify-content: space-between;
margin-bottom: 18rpx;
.sub-item {
font-size: 24rpx;
color: #6B7280;
}
}
.qr-box {
width: 100%;
display: flex;
justify-content: center;
padding: 16rpx 0 8rpx;
}
.qr-canvas {
width: 520rpx;
height: 560rpx;
}
.qr-link {
margin-top: 12rpx;
background: #F9FAFB;
border-radius: 16rpx;
padding: 14rpx 16rpx;
display: flex;
align-items: center;
justify-content: space-between;
.link-text {
flex: 1;
font-size: 22rpx;
color: #4B5563;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.copy-btn {
margin-left: 14rpx;
padding: 10rpx 18rpx;
border-radius: 999rpx;
background: linear-gradient(135deg, #4297F3 0%, #2B76E5 100%);
color: #fff;
font-size: 24rpx;
}
}
.hint {
margin-top: 14rpx;
text-align: center;
font-size: 22rpx;
color: #9CA3AF;
}
.btn-row {
display: flex;
gap: 20rpx;
margin-top: 24rpx;
}
.btn {
height: 92rpx;
border-radius: 999rpx;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
font-size: 30rpx;
font-weight: 700;
text {
margin-left: 10rpx;
}
}
.ghost {
background: #FFFFFF;
border: 2rpx solid rgba(66, 151, 243, 0.35);
color: #4297F3;
}
.primary {
background: linear-gradient(135deg, #4297F3 0%, #2B76E5 100%);
color: #FFFFFF;
box-shadow: 0 10rpx 22rpx rgba(66, 151, 243, 0.28);
}
</style>