feat: 添加二维码下载功能,优化邀请页面的用户体验
This commit is contained in:
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@@ -451,8 +451,6 @@ declare module 'vue' {
|
|||||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
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 storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
||||||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
import { Clipboard } from "@capacitor/clipboard";
|
import { Clipboard } from "@capacitor/clipboard";
|
||||||
|
import { Directory, Filesystem } from "@capacitor/filesystem";
|
||||||
|
import { loadingController, toastController } from "@ionic/vue";
|
||||||
|
import html2canvas from "html2canvas";
|
||||||
import {
|
import {
|
||||||
checkmarkCircleOutline,
|
checkmarkCircleOutline,
|
||||||
copyOutline,
|
copyOutline,
|
||||||
@@ -20,6 +23,8 @@ const qrCodeUrl = computed(() => {
|
|||||||
});
|
});
|
||||||
const { share, isSupported } = useShare();
|
const { share, isSupported } = useShare();
|
||||||
const { data: leader } = safeClient(() => client.api.team.leader.get(), { silent: true });
|
const { data: leader } = safeClient(() => client.api.team.leader.get(), { silent: true });
|
||||||
|
const qrcodeContainer = useTemplateRef<HTMLElement>("qrcodeContainer");
|
||||||
|
const platform = usePlatform();
|
||||||
|
|
||||||
// 复制状态
|
// 复制状态
|
||||||
const copyStatus = ref({
|
const copyStatus = ref({
|
||||||
@@ -81,6 +86,64 @@ function handleInvite() {
|
|||||||
function handleBindReferralCode() {
|
function handleBindReferralCode() {
|
||||||
router.push("/bind_invite");
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -207,7 +270,7 @@ function handleBindReferralCode() {
|
|||||||
</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="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="flex items-center gap-3">
|
||||||
<div class="bg-white rounded-lg p-2 shadow-sm">
|
<div class="bg-white rounded-lg p-2 shadow-sm">
|
||||||
<ion-icon :icon="ticketOutline" class="text-2xl text-[#c41e3a]" />
|
<ion-icon :icon="ticketOutline" class="text-2xl text-[#c41e3a]" />
|
||||||
@@ -309,7 +372,7 @@ function handleBindReferralCode() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-center">
|
<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
|
<img
|
||||||
:src="qrCodeUrl"
|
:src="qrCodeUrl"
|
||||||
alt="邀请二维码"
|
alt="邀请二维码"
|
||||||
@@ -319,7 +382,7 @@ function handleBindReferralCode() {
|
|||||||
<p class="text-xs text-[#999] text-center mb-3">
|
<p class="text-xs text-[#999] text-center mb-3">
|
||||||
扫描二维码或长按保存分享给好友
|
扫描二维码或长按保存分享给好友
|
||||||
</p>
|
</p>
|
||||||
<!-- <ion-button
|
<ion-button
|
||||||
expand="block"
|
expand="block"
|
||||||
fill="outline"
|
fill="outline"
|
||||||
class="download-qr-btn w-full"
|
class="download-qr-btn w-full"
|
||||||
@@ -327,28 +390,28 @@ function handleBindReferralCode() {
|
|||||||
>
|
>
|
||||||
<ion-icon slot="start" :icon="downloadOutline" />
|
<ion-icon slot="start" :icon="downloadOutline" />
|
||||||
下载二维码
|
下载二维码
|
||||||
</ion-button> -->
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- 邀请说明 -->
|
<!-- 邀请说明 -->
|
||||||
<section class="mb-5">
|
<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 class="text-base font-bold text-[#c41e3a] mb-3">
|
||||||
邀请奖励说明
|
邀请奖励说明
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2 text-sm text-[#666]">
|
<div class="space-y-2 text-sm text-[#666]">
|
||||||
<div class="flex items-start gap-2">
|
<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>
|
<span>每邀请1位好友注册,即可获得10积分奖励</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start gap-2">
|
<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>
|
<span>好友完成首次申购,您将获得额外20积分</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start gap-2">
|
<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>
|
<span>邀请越多,奖励越丰厚,上不封顶</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user