diff --git a/frontend_nuxt/components/HeaderComponent.vue b/frontend_nuxt/components/HeaderComponent.vue index 5aec0bb28..0d2d1d020 100644 --- a/frontend_nuxt/components/HeaderComponent.vue +++ b/frontend_nuxt/components/HeaderComponent.vue @@ -29,6 +29,12 @@ +
+ + 邀请 + +
+
@@ -66,6 +72,11 @@ import { authState, clearToken, loadCurrentUser } from '~/utils/auth' import { fetchUnreadCount, notificationState } from '~/utils/notification' import { useIsMobile } from '~/utils/screen' import { themeState, cycleTheme, ThemeMode } from '~/utils/theme' +import { toast } from '~/main' +import { getToken } from '~/utils/auth' +const config = useRuntimeConfig() +const API_BASE_URL = config.public.apiBaseUrl +const WEBSITE_BASE_URL = config.public.websiteBaseUrl const props = defineProps({ showMenuBtn: { @@ -82,6 +93,7 @@ const showSearch = ref(false) const searchDropdown = ref(null) const userMenu = ref(null) const menuBtn = ref(null) +const isCopying = ref(false) const search = () => { showSearch.value = true @@ -100,6 +112,35 @@ const goToLogin = () => { const goToSettings = () => { navigateTo('/settings', { replace: true }) } + +const copyInviteLink = async () => { + isCopying.value = true + const token = getToken() + if (!token) { + toast.error('请先登录') + return + } + try { + const res = await fetch(`${API_BASE_URL}/api/invite/generate`, { + method: 'POST', + headers: { Authorization: `Bearer ${token}` }, + }) + if (res.ok) { + const data = await res.json() + const inviteLink = data.token ? `${WEBSITE_BASE_URL}/signup?invite_token=${data.token}` : '' + await navigator.clipboard.writeText(inviteLink) + toast.success('邀请链接已复制') + } else { + const data = await res.json().catch(() => ({})) + toast.error(data.error || '生成邀请链接失败') + } + } catch (e) { + toast.error('生成邀请链接失败') + } finally { + isCopying.value = false + } +} + const goToProfile = async () => { if (!authState.loggedIn) { navigateTo('/login', { replace: true }) @@ -224,7 +265,7 @@ onMounted(async () => { margin-left: auto; flex-direction: row; align-items: center; - gap: 20px; + gap: 30px; } .auth-btns { @@ -315,6 +356,16 @@ onMounted(async () => { cursor: pointer; } +.invite_text { + font-size: 12px; + cursor: pointer; + color: var(--primary-color); +} + +.invite_text:hover { + text-decoration: underline; +} + .new-post-icon { font-size: 18px; cursor: pointer;