124 lines
2.9 KiB
Vue
124 lines
2.9 KiB
Vue
<template>
|
|
<div class="poster-page">
|
|
<section class="poster-wrap">
|
|
<img v-if="posterImage" class="poster" :src="posterImage" alt="邀请注册海报" />
|
|
<div v-else class="empty" v-text="message" />
|
|
</section>
|
|
<div v-if="posterImage" class="actions">
|
|
<t-button class="bg-white" variant="outline" theme="primary" block @click="copyLink">复制链接</t-button>
|
|
<t-button theme="primary" block :loading="isDownloading" @click="savePoster">保存海报</t-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { Toast } from "tdesign-mobile-vue";
|
|
import { createInvitePosterImage, downloadInvitePoster } from "@/utils/qrCode";
|
|
|
|
defineOptions({ name: "UserInvitePoster" });
|
|
|
|
const route = useRoute();
|
|
const posterImage = ref("");
|
|
const isDownloading = ref(false);
|
|
const message = ref("邀请海报参数无效");
|
|
const code = String(route.query.code || "");
|
|
const expireAt = Number(route.query.expireAt || 0);
|
|
const storeName = String(route.query.storeName || "");
|
|
const roleName = String(route.query.roleName || "");
|
|
const inviterName = String(route.query.inviterName || "未命名用户");
|
|
const registerLink = `${window.location.origin}/gao/invite/register?code=${encodeURIComponent(code)}`;
|
|
const posterOptions = computed(() => ({
|
|
code: registerLink,
|
|
storeName,
|
|
roleName,
|
|
inviterName,
|
|
expireAt
|
|
}));
|
|
|
|
function createPoster(): void {
|
|
if (!/^\w{10}$/.test(code) || !expireAt) {
|
|
return;
|
|
}
|
|
posterImage.value = createInvitePosterImage(posterOptions.value);
|
|
}
|
|
|
|
async function savePoster(): Promise<void> {
|
|
if (isDownloading.value) {
|
|
return;
|
|
}
|
|
isDownloading.value = true;
|
|
try {
|
|
await downloadInvitePoster(posterOptions.value, "GAO-邀请注册海报.png");
|
|
Toast.success("海报已保存");
|
|
} catch {
|
|
Toast.error("海报保存失败");
|
|
} finally {
|
|
isDownloading.value = false;
|
|
}
|
|
}
|
|
|
|
async function copyLink(): Promise<void> {
|
|
try {
|
|
await navigator.clipboard.writeText(registerLink);
|
|
Toast.success("注册链接已复制");
|
|
} catch {
|
|
Toast.error("复制失败,请检查浏览器权限");
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
try {
|
|
createPoster();
|
|
} catch {
|
|
message.value = "海报生成失败,请重新生成";
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.poster-page {
|
|
gap: 1rem;
|
|
min-height: 100vh;
|
|
padding: calc(var(--app-nav-height) + 1rem) 1rem 6rem;
|
|
display: flex;
|
|
align-items: center;
|
|
flex-direction: column;
|
|
|
|
.poster-wrap {
|
|
width: min(100%, 28rem);
|
|
padding: .5rem;
|
|
background: #fff;
|
|
box-shadow: 0 .75rem 2rem rgba(15, 118, 110, .2);
|
|
border-radius: 1.25rem;
|
|
|
|
.poster {
|
|
width: 100%;
|
|
display: block;
|
|
border-radius: .875rem;
|
|
}
|
|
}
|
|
|
|
.empty {
|
|
padding: 5rem 1rem;
|
|
color: var(--td-text-color-secondary);
|
|
text-align: center;
|
|
}
|
|
|
|
.actions {
|
|
gap: .75rem;
|
|
left: 1rem;
|
|
right: 1rem;
|
|
bottom: calc(.75rem + env(safe-area-inset-bottom, 0));
|
|
display: grid;
|
|
position: fixed;
|
|
grid-template-columns: 1fr 1fr;
|
|
}
|
|
}
|
|
|
|
:global(html.theme-dark) .poster-page {
|
|
.poster-wrap {
|
|
background: #0f172a;
|
|
}
|
|
}
|
|
</style>
|