fix: 增加邀请链接逻辑
This commit is contained in:
@@ -10,9 +10,15 @@
|
|||||||
*/
|
*/
|
||||||
import type { CardFlipRecord, CardFlipStatusOutput, FlipCardOutput } from '@/api/cardFlip/types';
|
import type { CardFlipRecord, CardFlipStatusOutput, FlipCardOutput } from '@/api/cardFlip/types';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { flipCard, generateMyInviteCode, getWeeklyTaskStatus, useInviteCode } from '@/api/cardFlip';
|
import { flipCard, generateMyInviteCode, getWeeklyTaskStatus, useInviteCode } from '@/api/cardFlip';
|
||||||
|
|
||||||
|
// ============ Props ============
|
||||||
|
/** 接收外部传入的邀请码(通过 URL 参数传递) */
|
||||||
|
const props = defineProps<{
|
||||||
|
externalInviteCode?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
// ============ 状态管理 ============
|
// ============ 状态管理 ============
|
||||||
/** 任务数据:包含翻牌记录、次数统计、邀请码等信息 */
|
/** 任务数据:包含翻牌记录、次数统计、邀请码等信息 */
|
||||||
const taskData = ref<CardFlipStatusOutput | null>(null);
|
const taskData = ref<CardFlipStatusOutput | null>(null);
|
||||||
@@ -83,6 +89,29 @@ onMounted(async () => {
|
|||||||
await playShuffleAnimation();
|
await playShuffleAnimation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ============ 监听外部邀请码 ============
|
||||||
|
/**
|
||||||
|
* 监听外部传入的邀请码
|
||||||
|
* 如果有邀请码,自动打开对话框并预填
|
||||||
|
*/
|
||||||
|
watch(
|
||||||
|
() => props.externalInviteCode,
|
||||||
|
(newCode) => {
|
||||||
|
if (newCode && newCode.trim()) {
|
||||||
|
// 延迟500ms,确保页面已经渲染完成
|
||||||
|
setTimeout(() => {
|
||||||
|
inputInviteCode.value = newCode.trim().toUpperCase();
|
||||||
|
inviteCodeDialog.value = true;
|
||||||
|
ElMessage.info({
|
||||||
|
message: '🎁 检测到邀请码,已为您自动填充,请点击确认使用',
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
// ============ 新增:初始洗牌动画 ============
|
// ============ 新增:初始洗牌动画 ============
|
||||||
/**
|
/**
|
||||||
* 初始洗牌动画
|
* 初始洗牌动画
|
||||||
@@ -738,6 +767,52 @@ function copyInviteCode() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成分享链接
|
||||||
|
* 生成包含邀请码的完整 URL
|
||||||
|
*/
|
||||||
|
function generateShareLink(): string {
|
||||||
|
const inviteCode = taskData.value?.myInviteCode;
|
||||||
|
if (!inviteCode) return '';
|
||||||
|
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
|
const path = window.location.pathname;
|
||||||
|
return `${baseUrl}${path}?inviteCode=${inviteCode}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成分享文案
|
||||||
|
* 类似小红书风格的分享内容
|
||||||
|
*/
|
||||||
|
function generateShareContent(): string {
|
||||||
|
const shareLink = generateShareLink();
|
||||||
|
return `🎁 邀请你来翻牌抽奖,赢取Token大奖!
|
||||||
|
|
||||||
|
使用我的邀请码可解锁3次额外翻牌机会,必定中奖,最大奖励翻倍!💰
|
||||||
|
|
||||||
|
👉 点击链接立即参与:
|
||||||
|
${shareLink}
|
||||||
|
|
||||||
|
🍀 快来试试手气吧!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制分享链接和文案
|
||||||
|
*/
|
||||||
|
function copyShareContent() {
|
||||||
|
if (!taskData.value?.myInviteCode) {
|
||||||
|
ElMessage.warning('暂无邀请码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shareContent = generateShareContent();
|
||||||
|
navigator.clipboard.writeText(shareContent).then(() => {
|
||||||
|
ElMessage.success('🎉 分享内容已复制到剪贴板!快去分享给好友吧~');
|
||||||
|
}).catch(() => {
|
||||||
|
ElMessage.error('复制失败,请手动复制');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ============ 工具函数 ============
|
// ============ 工具函数 ============
|
||||||
/**
|
/**
|
||||||
* 格式化 Token 显示(单位:万)
|
* 格式化 Token 显示(单位:万)
|
||||||
@@ -1063,16 +1138,31 @@ function getCardClass(record: CardFlipRecord): string[] {
|
|||||||
<div class="code-box">
|
<div class="code-box">
|
||||||
<span class="code-text">{{ taskData.myInviteCode }}</span>
|
<span class="code-text">{{ taskData.myInviteCode }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-button
|
<div class="button-group">
|
||||||
type="primary"
|
<el-button
|
||||||
icon="CopyDocument"
|
type="primary"
|
||||||
@click="copyInviteCode"
|
icon="CopyDocument"
|
||||||
>
|
@click="copyInviteCode"
|
||||||
复制邀请码
|
>
|
||||||
</el-button>
|
复制邀请码
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
icon="Share"
|
||||||
|
@click="copyShareContent"
|
||||||
|
>
|
||||||
|
复制分享链接
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
<p class="invite-tip">
|
<p class="invite-tip">
|
||||||
💌 分享给好友,好友使用后可解锁最后3次翻牌机会
|
💌 分享给好友,好友使用后可解锁最后3次翻牌机会
|
||||||
</p>
|
</p>
|
||||||
|
<div class="share-preview">
|
||||||
|
<div class="share-preview-title">📱 分享预览</div>
|
||||||
|
<div class="share-preview-content">
|
||||||
|
{{ generateShareContent() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 生成邀请码 -->
|
<!-- 生成邀请码 -->
|
||||||
@@ -1999,16 +2089,68 @@ function getCardClass(record: CardFlipRecord): string[] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-button {
|
.button-group {
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.invite-tip {
|
.invite-tip {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #909399;
|
color: #909399;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
margin: 0;
|
margin: 0 0 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-preview {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.share-preview-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-preview-content {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #606266;
|
||||||
|
line-height: 1.6;
|
||||||
|
white-space: pre-line;
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
/* 自定义滚动条 */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<!-- 头像 -->
|
<!-- 头像 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { ChatLineRound } from '@element-plus/icons-vue';
|
import { ChatLineRound } from '@element-plus/icons-vue';
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
|
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import Popover from '@/components/Popover/index.vue';
|
import Popover from '@/components/Popover/index.vue';
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
@@ -62,6 +63,10 @@ const dialogVisible = ref(false);
|
|||||||
const rechargeLogRef = ref();
|
const rechargeLogRef = ref();
|
||||||
const activeNav = ref('user');
|
const activeNav = ref('user');
|
||||||
|
|
||||||
|
// ============ 邀请码分享功能 ============
|
||||||
|
/** 从 URL 获取的邀请码 */
|
||||||
|
const externalInviteCode = ref<string>('');
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ name: 'user', label: '用户信息', icon: 'User' },
|
{ name: 'user', label: '用户信息', icon: 'User' },
|
||||||
// { name: 'role', label: '角色管理', icon: 'Avatar' },
|
// { name: 'role', label: '角色管理', icon: 'Avatar' },
|
||||||
@@ -73,7 +78,7 @@ const navItems = [
|
|||||||
{ name: 'usageStatistics', label: '用量统计', icon: 'Histogram' },
|
{ name: 'usageStatistics', label: '用量统计', icon: 'Histogram' },
|
||||||
{ name: 'premiumService', label: '尊享服务', icon: 'ColdDrink' },
|
{ name: 'premiumService', label: '尊享服务', icon: 'ColdDrink' },
|
||||||
{ name: 'dailyTask', label: '每日任务(限时)', icon: 'Trophy' },
|
{ name: 'dailyTask', label: '每日任务(限时)', icon: 'Trophy' },
|
||||||
{ name: 'cardFlip', label: '每周邀请(限时)', icon: 'Present' }
|
{ name: 'cardFlip', label: '每周邀请(限时)', icon: 'Present' },
|
||||||
// { name: 'usageStatistics2', label: '用量统计2', icon: 'Histogram' },
|
// { name: 'usageStatistics2', label: '用量统计2', icon: 'Histogram' },
|
||||||
];
|
];
|
||||||
function openDialog() {
|
function openDialog() {
|
||||||
@@ -183,7 +188,61 @@ function openVipGuide() {
|
|||||||
function onProductPackage() {
|
function onProductPackage() {
|
||||||
showProductPackage();
|
showProductPackage();
|
||||||
}
|
}
|
||||||
// 直接调用
|
|
||||||
|
// ============ 监听对话框打开事件,切换到邀请码标签页 ============
|
||||||
|
watch(dialogVisible, (newVal) => {
|
||||||
|
if (newVal && externalInviteCode.value) {
|
||||||
|
// 对话框打开后,切换标签页(已通过 :default-active 绑定,会自动响应)
|
||||||
|
// console.log('[Avatar] watch: 对话框已打开,切换到 cardFlip 标签页');
|
||||||
|
nextTick(() => {
|
||||||
|
activeNav.value = 'cardFlip';
|
||||||
|
// console.log('[Avatar] watch: 已设置 activeNav 为', activeNav.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对话框关闭时,清除邀请码状态和 URL 参数
|
||||||
|
if (!newVal && externalInviteCode.value) {
|
||||||
|
// console.log('[Avatar] watch: 对话框关闭,清除邀请码状态');
|
||||||
|
externalInviteCode.value = '';
|
||||||
|
|
||||||
|
// 清除 URL 中的 inviteCode 参数
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
if (url.searchParams.has('inviteCode')) {
|
||||||
|
url.searchParams.delete('inviteCode');
|
||||||
|
window.history.replaceState({}, '', url.toString());
|
||||||
|
// console.log('[Avatar] watch: 已清除 URL 中的 inviteCode 参数');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ============ 监听 URL 参数,实现邀请码快捷分享 ============
|
||||||
|
onMounted(() => {
|
||||||
|
// 获取 URL 查询参数
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const inviteCode = urlParams.get('inviteCode');
|
||||||
|
|
||||||
|
if (inviteCode && inviteCode.trim()) {
|
||||||
|
// console.log('[Avatar] onMounted: 检测到邀请码', inviteCode);
|
||||||
|
|
||||||
|
// 保存邀请码
|
||||||
|
externalInviteCode.value = inviteCode.trim();
|
||||||
|
|
||||||
|
// 先设置标签页为 cardFlip
|
||||||
|
activeNav.value = 'cardFlip';
|
||||||
|
// console.log('[Avatar] onMounted: 设置 activeNav 为', activeNav.value);
|
||||||
|
|
||||||
|
// 延迟打开对话框,确保状态已更新
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
// console.log('[Avatar] onMounted: 打开用户中心对话框');
|
||||||
|
dialogVisible.value = true;
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注意:不立即清除 URL 参数,保留给登录后使用
|
||||||
|
// URL 参数会在对话框关闭时清除
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -323,6 +382,7 @@ function onProductPackage() {
|
|||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
title="用户中心"
|
title="用户中心"
|
||||||
:nav-items="navItems"
|
:nav-items="navItems"
|
||||||
|
:default-active="activeNav"
|
||||||
@confirm="handleConfirm"
|
@confirm="handleConfirm"
|
||||||
@nav-change="handleNavChange"
|
@nav-change="handleNavChange"
|
||||||
>
|
>
|
||||||
@@ -370,7 +430,7 @@ function onProductPackage() {
|
|||||||
<daily-task />
|
<daily-task />
|
||||||
</template>
|
</template>
|
||||||
<template #cardFlip>
|
<template #cardFlip>
|
||||||
<card-flip-activity />
|
<card-flip-activity :external-invite-code="externalInviteCode" />
|
||||||
</template>
|
</template>
|
||||||
<template #rechargeLog>
|
<template #rechargeLog>
|
||||||
<recharge-log ref="rechargeLogRef" />
|
<recharge-log ref="rechargeLogRef" />
|
||||||
|
|||||||
2
Yi.Ai.Vue3/types/components.d.ts
vendored
2
Yi.Ai.Vue3/types/components.d.ts
vendored
@@ -11,6 +11,7 @@ declare module 'vue' {
|
|||||||
AccountPassword: typeof import('./../src/components/LoginDialog/components/FormLogin/AccountPassword.vue')['default']
|
AccountPassword: typeof import('./../src/components/LoginDialog/components/FormLogin/AccountPassword.vue')['default']
|
||||||
APIKeyManagement: typeof import('./../src/components/userPersonalCenter/components/APIKeyManagement.vue')['default']
|
APIKeyManagement: typeof import('./../src/components/userPersonalCenter/components/APIKeyManagement.vue')['default']
|
||||||
CardFlipActivity: typeof import('./../src/components/userPersonalCenter/components/CardFlipActivity.vue')['default']
|
CardFlipActivity: typeof import('./../src/components/userPersonalCenter/components/CardFlipActivity.vue')['default']
|
||||||
|
CardFlipActivity2: typeof import('./../src/components/userPersonalCenter/components/CardFlipActivity2.vue')['default']
|
||||||
DailyTask: typeof import('./../src/components/userPersonalCenter/components/DailyTask.vue')['default']
|
DailyTask: typeof import('./../src/components/userPersonalCenter/components/DailyTask.vue')['default']
|
||||||
DeepThinking: typeof import('./../src/components/DeepThinking/index.vue')['default']
|
DeepThinking: typeof import('./../src/components/DeepThinking/index.vue')['default']
|
||||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||||
@@ -20,7 +21,6 @@ declare module 'vue' {
|
|||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||||
ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition']
|
|
||||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||||
|
|||||||
Reference in New Issue
Block a user