细节优化
This commit is contained in:
parent
107d950771
commit
ecd6cf1c94
@ -1,31 +1,56 @@
|
||||
<template>
|
||||
<div class="grid grid-cols-2 gap-4 md:flex md:flex-wrap">
|
||||
<a
|
||||
v-for="(item, index) in downloadLinks"
|
||||
:key="index"
|
||||
:href="item.link"
|
||||
target="_blank"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
0px 0px 33px 0px #f2f2f280 inset,
|
||||
-3px -4.5px 1.5px -3px #b3b3b3 inset,
|
||||
3px 4.5px 1.5px -3px #b3b3b333 inset,
|
||||
4.5px 4.5px 1.5px -5.25px #ffffff80 inset,
|
||||
-4.5px -4.5px 1.5px -5.25px #ffffff80 inset;
|
||||
border-image-source: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.4) 0%,
|
||||
rgba(255, 255, 255, 0) 30%
|
||||
);
|
||||
border-image-slice: 1;
|
||||
"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
<component :is="item.icon" class="h-[40px] w-[140px] md:h-[50px] md:w-[180px]" />
|
||||
</div>
|
||||
</a>
|
||||
<div class="mx-auto grid grid-cols-2 gap-4 md:flex md:flex-wrap">
|
||||
<template v-for="(item, index) in downloadLinks" :key="index">
|
||||
<router-link
|
||||
v-if="item.isInternal"
|
||||
:to="item.link"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
0px 0px 33px 0px #f2f2f280 inset,
|
||||
-3px -4.5px 1.5px -3px #b3b3b3 inset,
|
||||
3px 4.5px 1.5px -3px #b3b3b333 inset,
|
||||
4.5px 4.5px 1.5px -5.25px #ffffff80 inset,
|
||||
-4.5px -4.5px 1.5px -5.25px #ffffff80 inset;
|
||||
border-image-source: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.4) 0%,
|
||||
rgba(255, 255, 255, 0) 30%
|
||||
);
|
||||
border-image-slice: 1;
|
||||
"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
<component :is="item.icon" class="h-[40px] w-[140px] md:h-[50px] md:w-[180px]" />
|
||||
</div>
|
||||
</router-link>
|
||||
<a
|
||||
v-else
|
||||
:href="item.link"
|
||||
target="_blank"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
0px 0px 33px 0px #f2f2f280 inset,
|
||||
-3px -4.5px 1.5px -3px #b3b3b3 inset,
|
||||
3px 4.5px 1.5px -3px #b3b3b333 inset,
|
||||
4.5px 4.5px 1.5px -5.25px #ffffff80 inset,
|
||||
-4.5px -4.5px 1.5px -5.25px #ffffff80 inset;
|
||||
border-image-source: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.4) 0%,
|
||||
rgba(255, 255, 255, 0) 30%
|
||||
);
|
||||
border-image-slice: 1;
|
||||
"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
<component :is="item.icon" class="h-[40px] w-[140px] md:h-[50px] md:w-[180px]" />
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -38,7 +63,7 @@ import Icon4 from './Group 108.svg?component'
|
||||
// 定义下载链接数据
|
||||
const downloadLinks = [
|
||||
{ icon: Icon1, link: 'https://apple.com/...' },
|
||||
{ icon: Icon2, link: 'https://down.hi.com/win' },
|
||||
{ icon: Icon2, link: '/help', isInternal: true },
|
||||
{ icon: Icon3, link: 'https://down.hi.com/apk' },
|
||||
{ icon: Icon4, link: 'https://down.hi.com/mac' },
|
||||
]
|
||||
|
||||
@ -102,6 +102,7 @@ const handleLogin = () => {
|
||||
})
|
||||
.then((res) => {
|
||||
localStorage.setItem('Authorization', res.token)
|
||||
localStorage.setItem('UserEmail', email.value)
|
||||
router.push({ path: '/user-center' })
|
||||
})
|
||||
}
|
||||
|
||||
@ -30,7 +30,16 @@
|
||||
<!-- Mobile Logo -->
|
||||
<MobileLogo alt="Hi快VPN" class="ml-6 block h-[28px] w-[67px] md:hidden" />
|
||||
</div>
|
||||
<div v-if="isLoggedIn" class="flex items-center">
|
||||
<router-link
|
||||
to="/user-center"
|
||||
class="mr-2 flex size-[48px] items-center justify-center rounded-full bg-[#A8FF53] text-xl font-bold text-black shadow-lg transition hover:scale-105 md:size-[60px] md:text-3xl"
|
||||
>
|
||||
{{ userLetter }}
|
||||
</router-link>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
@click="openLoginModal"
|
||||
class="flex h-[48px] items-center rounded-full bg-[#70C877] px-6 text-sm font-bold backdrop-blur-md transition hover:scale-[0.97] hover:bg-white/30 md:text-2xl"
|
||||
>
|
||||
@ -106,8 +115,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import type { LocationQueryValue } from 'vue-router'
|
||||
import LoginFormModal from './components/LoginFormModal.vue'
|
||||
import DownloadButton from './components/DownloadButton.vue'
|
||||
@ -115,16 +125,39 @@ import Logo from './logo.svg?component'
|
||||
import MobileLogo from './mobile-logo.svg?component'
|
||||
import ScreenshotMobile from './screenshot-mobile.png'
|
||||
import ScreenshotDesktop from './screenshot-desktop.png'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const loginModalRef = ref<InstanceType<typeof LoginFormModal> | null>(null)
|
||||
const token = useLocalStorage('Authorization', '')
|
||||
const userEmail = useLocalStorage('UserEmail', '')
|
||||
|
||||
const openLoginModal = () => {
|
||||
loginModalRef.value?.show()
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const userLetter = computed(() => {
|
||||
if (!userEmail.value) return '?'
|
||||
return userEmail.value.charAt(0).toUpperCase()
|
||||
})
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
if (!token.value) return
|
||||
|
||||
try {
|
||||
const res = (await request.get('/api/v1/public/user/info')) as any
|
||||
const emailInfo = res.auth_methods?.find((item: any) => item.auth_type === 'email')
|
||||
if (emailInfo) {
|
||||
userEmail.value = emailInfo.auth_identifier
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Failed to fetch user info:', error)
|
||||
if (error?.code === 401 || error?.status === 401) {
|
||||
token.value = ''
|
||||
userEmail.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchUserInfo()
|
||||
if (route.query.login === 'true') {
|
||||
openLoginModal()
|
||||
router.replace({ query: { ...route.query, login: undefined } })
|
||||
@ -140,4 +173,10 @@ watch(
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const loginModalRef = ref<InstanceType<typeof LoginFormModal> | null>(null)
|
||||
|
||||
const openLoginModal = () => {
|
||||
loginModalRef.value?.show()
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -202,6 +202,7 @@ async function init() {
|
||||
const emailInfo = res.auth_methods?.find((item: any) => item.auth_type === 'email')
|
||||
if (emailInfo) {
|
||||
userSubInfo.value.email = emailInfo.auth_identifier
|
||||
localStorage.setItem('UserEmail', emailInfo.auth_identifier)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user