feat: 添加邀请页面,包含邀请信息和二维码,优化邀请功能和样式

This commit is contained in:
2026-01-17 15:00:08 +07:00
parent 405332b040
commit 1239935b57
4 changed files with 345 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

View File

@@ -39,6 +39,10 @@ const routes: Array<RouteRecordRaw> = [
path: "/signup", path: "/signup",
component: () => import("@/views/signup/index.vue"), component: () => import("@/views/signup/index.vue"),
}, },
{
path: "/invite",
component: () => import("@/views/invite/index.vue"),
},
]; ];
const router = createRouter({ const router = createRouter({

View File

@@ -68,7 +68,7 @@ const router = useRouter();
const quickActions = ref([ const quickActions = ref([
{ id: 1, name: "签到", icon: calendarOutline, color: "#c32120" }, { id: 1, name: "签到", icon: calendarOutline, color: "#c32120" },
{ id: 2, name: "团队中心", icon: peopleOutline, color: "#c32120" }, { id: 2, name: "团队中心", icon: peopleOutline, color: "#c32120" },
{ id: 3, name: "战略改革", icon: rocketOutline, color: "#c32120" }, { id: 3, name: "邀请好友", icon: rocketOutline, color: "#c32120" },
{ id: 4, name: "在线客服", icon: chatbubblesOutline, color: "#c32120" }, { id: 4, name: "在线客服", icon: chatbubblesOutline, color: "#c32120" },
]); ]);
@@ -80,6 +80,9 @@ function handleQuickAction(action: any) {
case 2: case 2:
console.log("团队中心"); console.log("团队中心");
break; break;
case 3:
router.push("/invite");
break;
} }
} }

337
src/views/invite/index.vue Normal file
View File

@@ -0,0 +1,337 @@
<script lang='ts' setup>
import { Clipboard } from "@capacitor/clipboard";
import {
checkmarkCircleOutline,
copyOutline,
downloadOutline,
linkOutline,
peopleOutline,
qrCodeOutline,
shareOutline,
ticketOutline,
} from "ionicons/icons";
// 邀请信息
const inviteInfo = ref({
inviteCode: "ABCD1234",
inviteLink: "https://example.com/invite?code=ABCD1234",
downloadLink: "https://example.com/download",
qrCodeUrl: "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://example.com/invite?code=ABCD1234",
totalInvites: 28,
todayInvites: 3,
});
// 复制状态
const copyStatus = ref({
link: false,
code: false,
download: false,
});
async function handleCopy(text: string, type: "link" | "code" | "download") {
try {
await Clipboard.write({
string: text,
});
// 显示复制成功状态
copyStatus.value[type] = true;
// 2秒后恢复
setTimeout(() => {
copyStatus.value[type] = false;
}, 2000);
console.log(`已复制${type}:`, text);
}
catch (error) {
console.error("复制失败:", error);
// 降级方案使用浏览器API
try {
await navigator.clipboard.writeText(text);
copyStatus.value[type] = true;
setTimeout(() => {
copyStatus.value[type] = false;
}, 2000);
}
catch (err) {
console.error("浏览器复制也失败:", err);
}
}
}
function handleInvite() {
console.log("立即邀请");
// TODO: 实现分享功能
}
function handleDownloadQR() {
console.log("下载二维码");
// TODO: 实现下载二维码功能
}
</script>
<template>
<ion-page>
<ion-content :fullscreen="true">
<!-- 顶部横幅 -->
<img src="@/assets/images/invite-banner.jpg" class="w-full object-cover" alt="邀请横幅">
<div class="ion-padding-horizontal">
<!-- 邀请统计卡片 -->
<section class="mb-4">
<div class="card rounded-2xl shadow-lg p-6">
<div class="flex items-center justify-center gap-2 mb-4">
<ion-icon :icon="peopleOutline" class="text-3xl" />
<div class="text-xl font-bold text-[#1a1a1a]">
邀请统计
</div>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="bg-white/20 backdrop-blur-sm rounded-xl p-4 text-center">
<div class="text-xs opacity-90 mb-1">
累计邀请
</div>
<div class="text-4xl font-bold mb-1">
{{ inviteInfo.totalInvites }}
</div>
<div class="text-xs opacity-80">
</div>
</div>
<div class="bg-white/20 backdrop-blur-sm rounded-xl p-4 text-center">
<div class="text-xs opacity-90 mb-1">
今日邀请
</div>
<div class="text-4xl font-bold mb-1">
{{ inviteInfo.todayInvites }}
</div>
<div class="text-xs opacity-80">
</div>
</div>
</div>
<!-- 立即邀请按钮 -->
<ion-button
expand="block"
@click="handleInvite"
>
<ion-icon slot="start" :icon="shareOutline" class="text-xl" />
立即邀请好友
</ion-button>
</div>
</section>
<section class="mb-4">
<div class="flex items-center gap-2 mb-3">
<img src="@/assets/images/icon.png" class="size-7">
<div class="text-lg font-bold text-[#1a1a1a]">
我的邀请码
</div>
</div>
<!-- 邀请码 -->
<div class="mb-5 flex items-center justify-between bg-gradient-to-r from-[#fff7f0] to-[#ffe8e8] rounded-xl p-4">
<div class="flex items-center gap-3">
<div class="bg-white rounded-lg p-2 shadow-sm">
<ion-icon :icon="ticketOutline" class="text-2xl text-[#c41e3a]" />
</div>
<div>
<div class="text-xs text-[#999] mb-1">
邀请码
</div>
<div class="text-xl font-bold text-[#c41e3a] tracking-wider">
{{ inviteInfo.inviteCode }}
</div>
</div>
</div>
<ion-button
fill="clear"
class="copy-btn"
@click="handleCopy(inviteInfo.inviteCode, 'code')"
>
<ion-icon
slot="icon-only"
:icon="copyStatus.code ? checkmarkCircleOutline : copyOutline"
:class="copyStatus.code ? 'text-green-500' : 'text-[#c41e3a]'"
class="text-2xl"
/>
</ion-button>
</div>
<div class="flex items-center gap-2 mb-3">
<img src="@/assets/images/icon.png" class="size-7">
<div class="text-lg font-bold text-[#1a1a1a]">
推广链接
</div>
</div>
<div class="mb-5 bg-gray-50 rounded-xl p-4">
<div class="flex items-center justify-between gap-3">
<div class="flex-1 overflow-hidden">
<div class="text-xs text-[#999] mb-1">
分享此链接邀请好友
</div>
<div class="text-sm text-[#333] truncate">
{{ inviteInfo.inviteLink }}
</div>
</div>
<ion-button
fill="solid"
size="small"
class="copy-link-btn"
@click="handleCopy(inviteInfo.inviteLink, 'link')"
>
<ion-icon
slot="icon-only"
:icon="copyStatus.link ? checkmarkCircleOutline : copyOutline"
class="text-lg"
/>
</ion-button>
</div>
</div>
<div class="flex items-center gap-2 mb-3">
<img src="@/assets/images/icon.png" class="size-7">
<div class="text-lg font-bold text-[#1a1a1a]">
下载链接
</div>
</div>
<div class="mb-5 bg-gray-50 rounded-xl p-4">
<div class="flex items-center justify-between gap-3">
<div class="flex-1 overflow-hidden">
<div class="text-xs text-[#999] mb-1">
分享下载地址
</div>
<div class="text-sm text-[#333] truncate">
{{ inviteInfo.downloadLink }}
</div>
</div>
<ion-button
fill="solid"
size="small"
class="copy-link-btn"
@click="handleCopy(inviteInfo.downloadLink, 'download')"
>
<ion-icon
slot="icon-only"
:icon="copyStatus.download ? checkmarkCircleOutline : copyOutline"
class="text-lg"
/>
</ion-button>
</div>
</div>
</section>
<!-- 邀请二维码 -->
<section class="mb-5">
<div class="card rounded-2xl shadow-lg p-5">
<div class="flex items-center gap-2 mb-3">
<img src="@/assets/images/icon.png" class="size-7">
<div class="text-lg font-bold text-[#1a1a1a]">
邀请二维码
</div>
</div>
<div class="flex flex-col items-center">
<div class="bg-white p-4 rounded-2xl shadow-md mb-4 border-4 border-[#c41e3a]/20">
<img
:src="inviteInfo.qrCodeUrl"
alt="邀请二维码"
class="w-50 h-50"
>
</div>
<p class="text-xs text-[#999] text-center mb-3">
扫描二维码或长按保存分享给好友
</p>
<ion-button
expand="block"
fill="outline"
class="download-qr-btn w-full"
@click="handleDownloadQR"
>
<ion-icon slot="start" :icon="downloadOutline" />
下载二维码
</ion-button>
</div>
</div>
</section>
<!-- 邀请说明 -->
<section class="mb-5">
<div class="bg-gradient-to-br from-[#fff7f0] to-[#ffe8e8] rounded-2xl p-5">
<h4 class="text-base font-bold text-[#c41e3a] mb-3">
邀请奖励说明
</h4>
<div class="space-y-2 text-sm text-[#666]">
<div class="flex items-start gap-2">
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 flex-shrink-0" />
<span>每邀请1位好友注册即可获得10积分奖励</span>
</div>
<div class="flex items-start gap-2">
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 flex-shrink-0" />
<span>好友完成首次申购您将获得额外20积分</span>
</div>
<div class="flex items-start gap-2">
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 flex-shrink-0" />
<span>邀请越多奖励越丰厚上不封顶</span>
</div>
</div>
</div>
</section>
</div>
</ion-content>
</ion-page>
</template>
<style lang='css' scoped>
.card {
background: linear-gradient(180deg, #ffeef1, #ffffff 15%);
}
.invite-btn {
--background: white;
--color: #c41e3a;
--border-radius: 12px;
--box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
font-weight: 700;
font-size: 16px;
height: 50px;
text-transform: none;
}
.invite-btn::part(native) {
font-weight: 700;
}
.copy-btn {
--padding-start: 8px;
--padding-end: 8px;
margin: 0;
}
.copy-link-btn {
--background: #c41e3a;
--background-activated: #8b1a2e;
--border-radius: 8px;
--padding-start: 12px;
--padding-end: 12px;
height: 36px;
min-width: 36px;
}
.download-qr-btn {
--border-color: #c41e3a;
--color: #c41e3a;
--border-radius: 12px;
--border-width: 2px;
font-weight: 600;
font-size: 14px;
height: 44px;
text-transform: none;
}
.download-qr-btn::part(native) {
font-weight: 600;
}
</style>