|
|
@@ -0,0 +1,381 @@
|
|
|
+<template>
|
|
|
+ <view class="container">
|
|
|
+ <!-- 未登录 -->
|
|
|
+ <view v-if="!isLoggedIn" class="empty-state">
|
|
|
+ <text class="empty-icon">👤</text>
|
|
|
+ <text class="empty-title">请先登录</text>
|
|
|
+ <text class="empty-desc">登录后即可生成您的专属推广码</text>
|
|
|
+ <button class="btn-login" @click="goLogin">去登录</button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 已登录 -->
|
|
|
+ <view v-else class="content">
|
|
|
+ <!-- 头部 -->
|
|
|
+ <view class="header">
|
|
|
+ <text class="title">分享推广码</text>
|
|
|
+ <text class="subtitle">将二维码分享给好友,扫码注册即成为您的下线</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 我的推广码 -->
|
|
|
+ <view class="code-card">
|
|
|
+ <view class="code-label">
|
|
|
+ <text class="label-text">我的推广码</text>
|
|
|
+ <view class="copy-btn" @click="copyCode">
|
|
|
+ <text class="copy-icon">📋</text>
|
|
|
+ <text class="copy-text">{{ copied ? '已复制' : '复制' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="code-value">{{ referralCode || '加载中...' }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 二维码区域 -->
|
|
|
+ <view class="qrcode-section" v-if="qrLoading || qrBase64">
|
|
|
+ <view class="qrcode-label">
|
|
|
+ <text class="label-text">扫码进入首页</text>
|
|
|
+ </view>
|
|
|
+ <view class="qrcode-wrap">
|
|
|
+ <image
|
|
|
+ v-if="qrBase64"
|
|
|
+ class="qrcode-img"
|
|
|
+ :src="qrBase64"
|
|
|
+ mode="aspectFit"
|
|
|
+ />
|
|
|
+ <view v-else class="qrcode-loading">
|
|
|
+ <text class="loading-spinner">⏳</text>
|
|
|
+ <text class="loading-text">生成中...</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <view class="actions" v-if="qrBase64">
|
|
|
+ <view class="action-btn save-btn" @click="saveQrcode">
|
|
|
+ <text class="action-icon">💾</text>
|
|
|
+ <text class="action-text">保存图片</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btn share-btn" @click="shareToWeixin">
|
|
|
+ <text class="action-icon">📤</text>
|
|
|
+ <text class="action-text">分享给朋友</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 说明 -->
|
|
|
+ <view class="tips">
|
|
|
+ <view class="tip-item">
|
|
|
+ <text class="tip-icon">💡</text>
|
|
|
+ <text class="tip-text">好友扫码后自动绑定推荐关系</text>
|
|
|
+ </view>
|
|
|
+ <view class="tip-item">
|
|
|
+ <text class="tip-icon">💡</text>
|
|
|
+ <text class="tip-text">好友注册后您将获得积分奖励</text>
|
|
|
+ </view>
|
|
|
+ <view class="tip-item">
|
|
|
+ <text class="tip-icon">💡</text>
|
|
|
+ <text class="tip-text">推广码可长期使用,无过期时间</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getReferralCode, extractReferralCode, getShareQrCode } from '../../utils/api.js'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ referralCode: '',
|
|
|
+ qrBase64: '',
|
|
|
+ qrLoading: false,
|
|
|
+ copied: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ isLoggedIn() {
|
|
|
+ return !!uni.getStorageSync('token')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ this.loadReferralCode()
|
|
|
+ this._onLoadFired = true
|
|
|
+ },
|
|
|
+ onShow() {
|
|
|
+ if (this._onLoadFired) {
|
|
|
+ this._onLoadFired = false
|
|
|
+ } else if (this.isLoggedIn && !this.referralCode) {
|
|
|
+ this.loadReferralCode()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async loadReferralCode() {
|
|
|
+ if (!this.isLoggedIn) return
|
|
|
+ try {
|
|
|
+ var res = await getReferralCode()
|
|
|
+ var code = extractReferralCode(res)
|
|
|
+ this.referralCode = code || ''
|
|
|
+ if (this.referralCode) {
|
|
|
+ this.generateQrcode()
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取推广码失败', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ generateQrcode() {
|
|
|
+ if (!this.referralCode) return
|
|
|
+ this.qrLoading = true
|
|
|
+ var scene = 'ref=' + this.referralCode
|
|
|
+ // 首页路径,扫码后进入首页并绑定推荐人
|
|
|
+ getShareQrCode('/pages/index-home/index', scene)
|
|
|
+ .then(function(res) {
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ this.qrBase64 = res.data.qrCodeBase64
|
|
|
+ }
|
|
|
+ }.bind(this))
|
|
|
+ .catch(function(e) {
|
|
|
+ console.error('生成二维码失败', e)
|
|
|
+ uni.showToast({ title: '生成失败,请重试', icon: 'none' })
|
|
|
+ })
|
|
|
+ .finally(function() {
|
|
|
+ this.qrLoading = false
|
|
|
+ }.bind(this))
|
|
|
+ },
|
|
|
+ copyCode() {
|
|
|
+ if (!this.referralCode) return
|
|
|
+ this.copied = true
|
|
|
+ uni.setClipboardData({
|
|
|
+ data: this.referralCode,
|
|
|
+ success: function() {
|
|
|
+ uni.showToast({ title: '推广码已复制', icon: 'success' })
|
|
|
+ setTimeout(function() {
|
|
|
+ this.copied = false
|
|
|
+ }.bind(this), 2000)
|
|
|
+ }.bind(this)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ saveQrcode() {
|
|
|
+ if (!this.qrBase64) return
|
|
|
+ // 将 base64 转为临时文件再保存
|
|
|
+ var self = this
|
|
|
+ var rawBase64 = this.qrBase64.indexOf('base64,') >= 0
|
|
|
+ ? this.qrBase64.split('base64,')[1]
|
|
|
+ : this.qrBase64
|
|
|
+ var fsm = uni.getFileSystemManager()
|
|
|
+ var tempPath = wx.env.USER_DATA_PATH + '/share_qrcode_' + Date.now() + '.png'
|
|
|
+ fsm.writeFileSync(tempPath, rawBase64, 'base64')
|
|
|
+ uni.saveImageToPhotosAlbum({
|
|
|
+ filePath: tempPath,
|
|
|
+ success: function() {
|
|
|
+ uni.showToast({ title: '保存成功', icon: 'success' })
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ uni.showToast({ title: '保存失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ shareToWeixin() {
|
|
|
+ if (!this.referralCode) return
|
|
|
+ // 通过 uni.share 分享小程序卡片
|
|
|
+ var path = '/pages/index-home/index?refCode=' + this.referralCode
|
|
|
+ uni.share({
|
|
|
+ provider: 'weixin',
|
|
|
+ scene: { type: 0 },
|
|
|
+ type: 5,
|
|
|
+ imageUrl: this.qrBase64,
|
|
|
+ path: path,
|
|
|
+ title: '浠艾福 — 邀请你加入',
|
|
|
+ success: function() {
|
|
|
+ uni.showToast({ title: '分享成功', icon: 'success' })
|
|
|
+ },
|
|
|
+ fail: function() {
|
|
|
+ uni.showToast({ title: '分享失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ goLogin() {
|
|
|
+ uni.navigateTo({ url: '/pages/login/login' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.container {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #F8F4EF;
|
|
|
+ padding-bottom: 60rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 未登录 */
|
|
|
+.empty-state {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 70vh;
|
|
|
+ padding: 60rpx;
|
|
|
+}
|
|
|
+.empty-icon { font-size: 100rpx; margin-bottom: 24rpx; }
|
|
|
+.empty-title { font-size: 36rpx; font-weight: bold; color: #333; margin-bottom: 12rpx; }
|
|
|
+.empty-desc { font-size: 26rpx; color: #999; margin-bottom: 40rpx; }
|
|
|
+.btn-login {
|
|
|
+ width: 60%;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ background: linear-gradient(135deg, #667eea, #764ba2);
|
|
|
+ color: #fff;
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ text-align: center;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+.btn-login::after { border: none; }
|
|
|
+
|
|
|
+/* 内容区 */
|
|
|
+.content { padding: 0 30rpx; }
|
|
|
+
|
|
|
+.header {
|
|
|
+ text-align: center;
|
|
|
+ padding: 60rpx 0 40rpx;
|
|
|
+}
|
|
|
+.title {
|
|
|
+ font-size: 44rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #1E293B;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+.subtitle {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+/* 推广码卡片 */
|
|
|
+.code-card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
+}
|
|
|
+.code-label {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+.label-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+.copy-btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8rpx;
|
|
|
+ padding: 8rpx 20rpx;
|
|
|
+ background: #FFF7ED;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ border: 1rpx solid #FED7AA;
|
|
|
+}
|
|
|
+.copy-icon { font-size: 24rpx; }
|
|
|
+.copy-text { font-size: 24rpx; color: #F97316; }
|
|
|
+.code-value {
|
|
|
+ font-size: 48rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #F97316;
|
|
|
+ font-family: monospace;
|
|
|
+ text-align: center;
|
|
|
+ display: block;
|
|
|
+ letter-spacing: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 二维码区域 */
|
|
|
+.qrcode-section {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.qrcode-label {
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+.qrcode-wrap {
|
|
|
+ width: 360rpx;
|
|
|
+ height: 360rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: #FAFAFA;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ border: 2rpx dashed #E5E7EB;
|
|
|
+}
|
|
|
+.qrcode-img {
|
|
|
+ width: 340rpx;
|
|
|
+ height: 340rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+.qrcode-loading {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+.loading-spinner { font-size: 48rpx; }
|
|
|
+.loading-text { font-size: 24rpx; color: #94A3B8; }
|
|
|
+
|
|
|
+/* 操作按钮 */
|
|
|
+.actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+}
|
|
|
+.action-btn {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+}
|
|
|
+.save-btn {
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
+}
|
|
|
+.share-btn {
|
|
|
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+}
|
|
|
+.action-icon { font-size: 48rpx; }
|
|
|
+.action-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+.save-btn .action-text { color: #333; }
|
|
|
+.share-btn .action-text { color: #fff; }
|
|
|
+
|
|
|
+/* 说明 */
|
|
|
+.tips {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ padding: 32rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
+}
|
|
|
+.tip-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 12rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+.tip-item:last-child { margin-bottom: 0; }
|
|
|
+.tip-icon { font-size: 28rpx; flex-shrink: 0; }
|
|
|
+.tip-text {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #64748B;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+</style>
|