feat: 更新用户转账二维码
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang='ts' setup>
|
||||
import { cardOutline, documentOutline, documentTextOutline } from "ionicons/icons";
|
||||
import { cardOutline, documentOutline, documentTextOutline, swapHorizontal } from "ionicons/icons";
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
@@ -28,6 +28,12 @@ const { t } = useI18n();
|
||||
{{ t('trade.settings.myIssues') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-1 flex-col-center gap-2" @click="$router.push('/trade-settings/my-issues')">
|
||||
<ion-icon :icon="swapHorizontal" />
|
||||
<div class="text-xs">
|
||||
发起转账
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script lang='ts' setup>
|
||||
import { Directory, Filesystem } from "@capacitor/filesystem";
|
||||
import { Share } from "@capacitor/share";
|
||||
import { loadingController, toastController } from "@ionic/vue";
|
||||
import { useQRCode } from "@vueuse/integrations/useQRCode";
|
||||
import html2canvas from "html2canvas";
|
||||
import MaterialSymbolsDownload from "~icons/material-symbols/download";
|
||||
import MaterialSymbolsUpload from "~icons/material-symbols/upload";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userProfile } = storeToRefs(userStore);
|
||||
const url = computed(() => {
|
||||
return `riwaapp://onchain-address?user=${userProfile.value?.user.email}`;
|
||||
return `/transfer_to_user/${userProfile.value?.uid}`;
|
||||
});
|
||||
const qrcode = useQRCode(url, {
|
||||
type: "image/webp",
|
||||
@@ -14,6 +18,167 @@ const qrcode = useQRCode(url, {
|
||||
quality: 1,
|
||||
},
|
||||
});
|
||||
const { share, isSupported } = useShare();
|
||||
const platform = usePlatform();
|
||||
const qrcodeContainer = ref<HTMLElement>();
|
||||
|
||||
async function captureQRCode(): Promise<string> {
|
||||
if (!qrcodeContainer.value) {
|
||||
throw new Error("QR code container not found");
|
||||
}
|
||||
|
||||
// 克隆元素避免修改原始DOM
|
||||
const clone = qrcodeContainer.value.cloneNode(true) as HTMLElement;
|
||||
|
||||
// 设置固定尺寸和简单样式,避免 oklch 颜色问题
|
||||
clone.style.width = "400px";
|
||||
clone.style.height = "400px";
|
||||
clone.style.backgroundColor = "#ffffff";
|
||||
clone.style.padding = "20px";
|
||||
clone.style.borderRadius = "14px";
|
||||
clone.style.border = "1px solid #e5e7eb";
|
||||
clone.style.position = "absolute";
|
||||
clone.style.left = "-9999px";
|
||||
clone.style.top = "0";
|
||||
|
||||
// 临时添加到 DOM
|
||||
document.body.appendChild(clone);
|
||||
|
||||
try {
|
||||
const canvas = await html2canvas(clone, {
|
||||
backgroundColor: "#ffffff",
|
||||
scale: 2,
|
||||
logging: false,
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
});
|
||||
|
||||
return canvas.toDataURL("image/png");
|
||||
}
|
||||
finally {
|
||||
// 清理克隆的元素
|
||||
document.body.removeChild(clone);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleShare() {
|
||||
const loading = await loadingController.create({
|
||||
message: "准备分享...",
|
||||
});
|
||||
await loading.present();
|
||||
|
||||
try {
|
||||
const dataUrl = await captureQRCode();
|
||||
|
||||
if (platform === "browser") {
|
||||
// 浏览器环境使用 Web Share API
|
||||
if (isSupported.value) {
|
||||
// 将 base64 转换为 blob
|
||||
const blob = await (await fetch(dataUrl)).blob();
|
||||
const file = new File([blob], "qrcode.png", { type: "image/png" });
|
||||
|
||||
await share({
|
||||
title: "我的转账二维码",
|
||||
text: `我的 ID: ${userProfile.value?.uid}`,
|
||||
files: [file],
|
||||
});
|
||||
}
|
||||
else {
|
||||
// 不支持则提示复制链接
|
||||
await navigator.clipboard.writeText(url.value);
|
||||
const toast = await toastController.create({
|
||||
message: "链接已复制到剪贴板",
|
||||
duration: 2000,
|
||||
color: "success",
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 原生环境使用 Capacitor Share
|
||||
// 先保存到临时目录
|
||||
const fileName = `qrcode-${Date.now()}.png`;
|
||||
const base64Data = dataUrl.split(",")[1];
|
||||
|
||||
const result = await Filesystem.writeFile({
|
||||
path: fileName,
|
||||
data: base64Data,
|
||||
directory: Directory.Cache,
|
||||
});
|
||||
|
||||
await Share.share({
|
||||
title: "我的转账二维码",
|
||||
text: `我的 ID: ${userProfile.value?.uid}`,
|
||||
url: result.uri,
|
||||
dialogTitle: "分享二维码",
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Share error:", error);
|
||||
const toast = await toastController.create({
|
||||
message: "分享失败",
|
||||
duration: 2000,
|
||||
color: "danger",
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
finally {
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载二维码
|
||||
*/
|
||||
async function handleDownload() {
|
||||
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 = `riwa-qrcode-${Date.now()}.png`;
|
||||
|
||||
await Filesystem.writeFile({
|
||||
path: fileName,
|
||||
data: base64Data,
|
||||
directory: Directory.Documents, // iOS 使用 Documents 目录
|
||||
});
|
||||
|
||||
const toast = await toastController.create({
|
||||
message: "二维码已保存到文件",
|
||||
duration: 2000,
|
||||
color: "success",
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Download error:", error);
|
||||
const toast = await toastController.create({
|
||||
message: "保存失败",
|
||||
duration: 2000,
|
||||
color: "danger",
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
finally {
|
||||
await loading.dismiss();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -23,12 +188,15 @@ const qrcode = useQRCode(url, {
|
||||
<ion-buttons slot="start">
|
||||
<ui-back-button />
|
||||
</ion-buttons>
|
||||
<ion-title>我的二维码</ion-title>
|
||||
<ion-title>转账二维码</ion-title>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent :fullscreen="true" class="ion-padding">
|
||||
<div class="flex justify-center items-center flex-col mt-20">
|
||||
<div class="w-[80vw] h-[80vw] bg-gray-50 max-w-130 max-h-130 rounded-[14px] p-4 flex flex-col justify-center items-center relative border border-text-900">
|
||||
<div
|
||||
ref="qrcodeContainer"
|
||||
class="w-[80vw] h-[80vw] bg-gray-50 max-w-130 max-h-130 rounded-[14px] p-4 flex flex-col justify-center items-center relative border border-text-900"
|
||||
>
|
||||
<div class="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center">
|
||||
<div class="p-1 rounded-full w-fit">
|
||||
<ui-avatar class="size-18 border border-text-900" />
|
||||
@@ -41,13 +209,13 @@ const qrcode = useQRCode(url, {
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<ion-text color="secondary">
|
||||
<div class="text-sm text-text-400">
|
||||
Onchain address
|
||||
<div class="text-sm text-text-400 font-semibold">
|
||||
我的 ID
|
||||
</div>
|
||||
</ion-text>
|
||||
<ion-text>
|
||||
<div class="mt-4px text-md font-semibold break-all">
|
||||
0x1234567890abcdef1234
|
||||
{{ userProfile?.uid }}
|
||||
</div>
|
||||
</ion-text>
|
||||
</div>
|
||||
@@ -55,7 +223,7 @@ const qrcode = useQRCode(url, {
|
||||
</div>
|
||||
|
||||
<div class="ion-text-center flex justify-between gap-6 w-[50%] mt-14">
|
||||
<div class="button">
|
||||
<div class="button" @click="handleShare">
|
||||
<div class="icon">
|
||||
<MaterialSymbolsUpload class="text-xl" />
|
||||
</div>
|
||||
@@ -63,12 +231,12 @@ const qrcode = useQRCode(url, {
|
||||
Share
|
||||
</div>
|
||||
</div>
|
||||
<div class="button">
|
||||
<div class="button" @click="handleDownload">
|
||||
<div class="icon">
|
||||
<MaterialSymbolsDownload class="text-xl" />
|
||||
</div>
|
||||
<div class="text">
|
||||
Copy
|
||||
Download
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +249,7 @@ const qrcode = useQRCode(url, {
|
||||
@reference "tailwindcss";
|
||||
|
||||
.button {
|
||||
@apply flex flex-col items-center gap-2 text-[text-500] font-medium;
|
||||
@apply flex flex-col items-center gap-2 text-[text-500] font-medium cursor-pointer;
|
||||
}
|
||||
.icon {
|
||||
@apply p-2.5 bg-(--ion-color-faint) rounded-full;
|
||||
|
||||
Reference in New Issue
Block a user