feat: 添加二维码下载功能,优化邀请页面的用户体验

This commit is contained in:
2026-01-24 19:04:26 +07:00
parent 8aeb6024e9
commit 3f9d3d3510
2 changed files with 71 additions and 10 deletions

2
auto-imports.d.ts vendored
View File

@@ -451,8 +451,6 @@ declare module 'vue' {
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly showSuccessToast: UnwrapRef<typeof import('vant/es')['showSuccessToast']>
readonly showToast: UnwrapRef<typeof import('vant/es')['showToast']>
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>

View File

@@ -1,5 +1,8 @@
<script lang='ts' setup>
import { Clipboard } from "@capacitor/clipboard";
import { Directory, Filesystem } from "@capacitor/filesystem";
import { loadingController, toastController } from "@ionic/vue";
import html2canvas from "html2canvas";
import {
checkmarkCircleOutline,
copyOutline,
@@ -20,6 +23,8 @@ const qrCodeUrl = computed(() => {
});
const { share, isSupported } = useShare();
const { data: leader } = safeClient(() => client.api.team.leader.get(), { silent: true });
const qrcodeContainer = useTemplateRef<HTMLElement>("qrcodeContainer");
const platform = usePlatform();
// 复制状态
const copyStatus = ref({
@@ -81,6 +86,64 @@ function handleInvite() {
function handleBindReferralCode() {
router.push("/bind_invite");
}
async function captureQRCode(): Promise<string> {
if (!qrcodeContainer.value) {
throw new Error("QR code container not found");
}
try {
const canvas = await html2canvas(qrcodeContainer.value, {
backgroundColor: "#ffffff",
scale: 2,
logging: false,
useCORS: true,
allowTaint: true,
});
return canvas.toDataURL("image/png");
}
catch (error) {
console.error("Capture error:", error);
throw error;
}
}
async function handleDownloadQR() {
const loading = await loadingController.create({
message: "正在保存二维码...",
});
await loading.present();
try {
const dataUrl = await captureQRCode();
if (platform === "browser") {
// 浏览器环境直接下载
const link = document.createElement("a");
link.download = `qrcode-${userProfile.value?.uid}.png`;
link.href = dataUrl;
link.click();
}
else {
// 原生环境保存到文档目录
const base64Data = dataUrl.split(",")[1];
const fileName = `financial-${Date.now()}.png`;
await Filesystem.writeFile({
path: fileName,
data: base64Data,
directory: Directory.Documents, // iOS 使用 Documents 目录
});
showToast("二维码已保存到您的相册");
}
}
catch (error) {
console.error("Download error:", error);
showToast("保存二维码失败,请重试");
}
finally {
await loading.dismiss();
}
}
</script>
<template>
@@ -207,7 +270,7 @@ function handleBindReferralCode() {
</div>
<!-- 邀请码 -->
<div class="mb-5 flex items-center justify-between bg-gradient-to-r from-[#fff7f0] to-[#ffe8e8] rounded-xl p-4">
<div class="mb-5 flex items-center justify-between bg-linear-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]" />
@@ -309,7 +372,7 @@ function handleBindReferralCode() {
</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">
<div ref="qrcodeContainer" class="bg-white p-4 rounded-2xl shadow-md mb-4 border-4 border-[#f7d4da]">
<img
:src="qrCodeUrl"
alt="邀请二维码"
@@ -319,7 +382,7 @@ function handleBindReferralCode() {
<p class="text-xs text-[#999] text-center mb-3">
扫描二维码或长按保存分享给好友
</p>
<!-- <ion-button
<ion-button
expand="block"
fill="outline"
class="download-qr-btn w-full"
@@ -327,28 +390,28 @@ function handleBindReferralCode() {
>
<ion-icon slot="start" :icon="downloadOutline" />
下载二维码
</ion-button> -->
</ion-button>
</div>
</div>
</section>
<!-- 邀请说明 -->
<section class="mb-5">
<div class="bg-gradient-to-br from-[#fff7f0] to-[#ffe8e8] rounded-2xl p-5">
<div class="bg-linear-to-br from-[#fff7f0] to-[#ffe8e8] rounded-2xl p-5">
<div class="text-base font-bold text-[#c41e3a] mb-3">
邀请奖励说明
</div>
<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" />
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 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" />
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 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" />
<div class="w-1.5 h-1.5 rounded-full bg-[#c41e3a] mt-1.5 shrink-0" />
<span>邀请越多奖励越丰厚上不封顶</span>
</div>
</div>