Files
gloabl_award_front/src/views/AwardPage/container.vue
2026-03-30 15:14:45 +08:00

754 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="award-container">
<div class="header-wrapper">
<div class="header flex align-center space-between">
<div class="header-left">
<img src="@/assets/images/award/code_create_logo.png" class="logo" />
</div>
<div class="header-right flex align-center" v-if="!isMobile">
<div class="contact flex align-center" @click="handleContactClick">
<img src="@/assets/images/award/mail.png" class="contact-icon" />
<div class="text" v-if="!isMobile">{{ $t('AwardsPage.contactUs') }}</div>
</div>
<div class="gap" />
<div class="language flex align-center">
<div
class="text"
:class="{ active: locale === 'CHINESE_SIMPLIFIED' }"
@click="handleChangeLanguage('CHINESE_SIMPLIFIED')"
>
中文
</div>
<span class="text">/</span>
<div
class="text"
:class="{ active: locale === 'ENGLISH' }"
@click="handleChangeLanguage('ENGLISH')"
>
EN
</div>
</div>
<div class="gap" />
<div class="submit flex align-center" @click="handleBtnClick">
<div class="text">{{ btnText }}</div>
<img src="@/assets/images/award/arrow.png" alt="" class="arrow" />
</div>
</div>
<div v-else class="header-right mobile" @click="handleChangeDrawer">
<img
style="width: 5rem; height: 5rem"
v-show="!showDrawer"
src="@/assets/images/award/menu.png"
class="menu-icon"
/>
<img
v-show="showDrawer"
src="@/assets/images/award/close-menu.png"
class="menu-icon close"
@click="handleChangeDrawer"
/>
</div>
</div>
<div class="header-placeholder"></div>
</div>
<router-view />
<div
class="footer flex space-between align-center"
:class="{ mobile: isMobile || isTablet }"
:style="mobileStyle"
>
<div class="social-list flex">
<a href="https://xhslink.com/m/5Ony2FapizV" target="_blank">
<img src="@/assets/images/award/xiaohongshu.svg" alt="" />
</a>
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank">
<img src="@/assets/images/award/linkdin.svg" alt="" />
</a>
<a href="https://www.facebook.com/CodeCreateAI" target="_blank">
<img src="@/assets/images/award/facebook.svg" alt="" />
</a>
<a href="https://www.tiktok.com/@aida_codecreate" target="_blank">
<img src="@/assets/images/award/tiktok.svg" alt="" />
</a>
<a href="javascript:void(0)" @click="showQRcode = true">
<img src="@/assets/images/award/weichat.svg" alt="" />
</a>
<a href="https://www.instagram.com/aida_codecreate?igsh=MzRlODBiNWFlZA==" target="_blank">
<img src="@/assets/images/award/instagram.png" alt="" />
</a>
</div>
<div class="copyright">© Code-Create 2026</div>
</div>
<div class="qrcode-mask flex flex-center" v-if="showQRcode" :class="{ mobile: isMobile }">
<div class="code-wrapper flex flex-col align-center">
<img
v-if="!isMobile"
src="@/assets/images/award/close.svg"
class="close-icon"
@click="handleCloseQRcode"
/>
<div class="code-title" :class="{ 'flex space-between': isMobile }">
<span>{{ $t('AwardsPage.wechatTitle') }}</span>
<img
v-if="isMobile"
src="@/assets/images/award/close.svg"
class="close mobile"
@click="handleCloseQRcode"
/>
</div>
<img src="@/assets/images/award/qrcode.jpg" class="qrcode" />
<div class="tips">{{ $t('AwardsPage.wechatDesc') }}</div>
</div>
</div>
</div>
<div
class="contact-modal flex flex-center"
v-if="showContactModal"
:class="{ mobile: isMobile, tablet: isTablet }"
>
<div class="contact-modal-wrapper">
<img
v-if="!isMobile"
src="@/assets/images/award/close.svg"
class="close-icon"
@click="showContactModal = false"
/>
<div class="header" :class="{ 'flex space-between': isMobile }">
<span>
{{ $t('AwardsPage.contactHeader') }}
</span>
<img
v-if="isMobile"
src="@/assets/images/award/close.svg"
class="close mobile"
@click="showContactModal = false"
/>
</div>
<div class="mobile-mail" v-if="isMobile">awards2026@code-createcom.hk</div>
<div class="desc">
{{ $t('AwardsPage.contactDesc') }}
</div>
<div class="mail flex align-center space-between" v-if="!isMobile">
<div class="mail-address">awards2026@code-createcom.hk</div>
<img src="@/assets/images/award/copy.png" class="copy-icon" @click="handleClickCopyEmail" />
</div>
<div class="send-btn flex flex-center" @click="handleContactUs">
<img v-if="isMobile" src="@/assets/images/award/mail.png" class="contact-icon" />
<span>{{ $t('AwardsPage.sendEmail') }}</span>
</div>
<div v-if="isMobile" class="send-btn copy" @click="handleClickCopyEmail">
{{ $t('AwardsPage.copyMailAddress') }}
</div>
</div>
<!-- <div class="contact-modal-mobile-wrapper"></div> -->
</div>
<div
class="drawer-mask"
:class="{ 'drawer-closing': drawerClosing }"
v-if="showDrawer || drawerClosing"
>
<div class="drawer-wrapper" @animationend="handleDrawerAnimationEnd">
<div class="drawer-item flex align-center space-between" @click="handleBtnClick">
<span class="text">{{ btnText }}</span>
<img src="@/assets/images/award/drawer-arrow.png" class="drawer-icon arrow" />
</div>
<div class="gap" />
<div class="drawer-item flex align-center space-between" @click="handleContactClick">
<span class="text">{{ $t('AwardsPage.contactUs') }}</span>
<img src="@/assets/images/award/drawer-mail.png" class="drawer-icon mail" />
</div>
<div class="gap" />
<div class="drawer-item language flex align-center">
<div
class="text"
:class="{ active: locale === 'CHINESE_SIMPLIFIED' }"
@click="handleChangeLanguage('CHINESE_SIMPLIFIED')"
>
中文
</div>
<span class="line">/</span>
<div
class="text"
:class="{ active: locale === 'ENGLISH' }"
@click="handleChangeLanguage('ENGLISH')"
>
EN
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { getCookie, setCookie } from '@/utils/cookie'
import { useMessage } from '@/components/Message/message'
import { useIsMobile, useIsTablet } from '@/utils/isMobile'
const { isMobile } = useIsMobile()
const { isTablet } = useIsTablet()
const { success, error } = useMessage()
const route = useRoute()
const router = useRouter()
const { locale, t } = useI18n()
const mobileStyle = computed(() => {
if (isMobile) {
return {
padding: '0 6.6rem'
}
} else {
return {}
}
})
onMounted(() => {
// 初始化语言设置
const loginLanguage = localStorage.getItem('loginLanguage')
if (loginLanguage) {
locale.value = loginLanguage
} else {
const userLanguage = getCookie('language')
if (userLanguage) {
locale.value = userLanguage
}
}
})
const showQRcode = ref(false)
const handleCloseQRcode = () => {
showQRcode.value = false
}
type BtnType = 'index' | 'form'
const btnType = ref<BtnType>('index')
const btnText = computed(() => {
if (btnType.value === 'index') {
return t('AwardsPage.submitApplication')
}
if (btnType.value === 'form') {
return t('AwardApply.backToIntroduction')
}
})
watch(
() => route.path,
(val) => {
if (val.includes('contestants')) {
btnType.value = 'form'
} else {
btnType.value = 'index'
}
},
{
immediate: true
}
)
const showDrawer = ref(false)
const drawerClosing = ref(false)
const handleChangeDrawer = () => {
if (showDrawer.value) {
drawerClosing.value = true
} else {
drawerClosing.value = false
showDrawer.value = true
}
}
const handleDrawerAnimationEnd = () => {
if (drawerClosing.value) {
showDrawer.value = false
drawerClosing.value = false
}
}
const showContactModal = ref(false)
const handleContactClick = () => {
if (showDrawer.value) {
handleChangeDrawer()
}
showContactModal.value = true
}
const handleContactUs = () => {
const email = 'awards2026@code-createcom.hk'
const mailtoLink = `mailto:${email}`
// 检测是否有邮件客户端
let hasEmailClient = false
let blurTimer = null
// 监听窗口失去焦点事件(如果打开了邮件客户端,窗口会失去焦点)
const handleBlur = () => {
hasEmailClient = true
if (blurTimer) {
clearTimeout(blurTimer)
}
window.removeEventListener('blur', handleBlur)
}
window.addEventListener('blur', handleBlur)
// 尝试打开邮件客户端(使用临时链接元素,避免页面跳转)
try {
const tempLink = document.createElement('a')
tempLink.href = mailtoLink
tempLink.style.display = 'none'
document.body.appendChild(tempLink)
tempLink.click()
document.body.removeChild(tempLink)
} catch (e) {
// 如果打开失败,直接复制邮箱
hasEmailClient = false
}
// 设置超时检测如果500ms内窗口没有失去焦点说明没有邮件客户端
blurTimer = setTimeout(() => {
window.removeEventListener('blur', handleBlur)
if (!hasEmailClient) {
// 没有邮件客户端,复制邮箱到剪贴板
console.log('没有客户端')
copyToClipboard(email)
error(t('AwardsPage.sendEmailFailed'))
}
}, 2000)
}
const copyToClipboard = (text) => {
if (navigator.clipboard && window.isSecureContext) {
// 使用现代 Clipboard API
navigator.clipboard.writeText(text).catch(() => {
// 如果失败,使用传统方法
fallbackCopyToClipboard(text)
})
} else {
// 使用传统方法
fallbackCopyToClipboard(text)
}
}
const fallbackCopyToClipboard = (text) => {
const textArea = document.createElement('textarea')
textArea.value = text
textArea.style.position = 'fixed'
textArea.style.left = '-999999px'
textArea.style.top = '-999999px'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
document.execCommand('copy')
} catch (err) {
console.error('复制失败:', err)
}
document.body.removeChild(textArea)
}
const handleClickCopyEmail = () => {
copyToClipboard('awards2026@code-createcom.hk')
success(t('AwardsPage.copyMail'))
}
const handleChangeLanguage = (language) => {
if (language === 'CHINESE_SIMPLIFIED') {
locale.value = 'CHINESE_SIMPLIFIED'
} else {
locale.value = 'ENGLISH'
}
localStorage.setItem('loginLanguage', language)
setCookie('language', language)
}
const handleBtnClick = () => {
const lang = route.params.lang ? `/${route.params.lang}` : ''
if (btnType.value === 'index') {
router.push(`${lang}/contestants`)
} else {
router.push(`${lang}/`)
}
}
</script>
<style lang="less" scoped>
.award-container {
height: 100%;
overflow-x: hidden;
}
.header-wrapper {
.header-placeholder {
height: 8rem;
}
.header {
height: 8rem;
background-color: #232323;
padding-left: 21.5rem;
padding-right: 21.4rem;
box-sizing: border-box;
position: fixed;
top: 0;
width: 100%;
z-index: 9;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
}
.header-right {
column-gap: 1.2rem;
color: #fff;
.gap {
width: 0.05rem;
height: 2.4rem;
background-color: #979797;
// border: 0.05rem solid #979797
}
.text {
font-size: 1.6rem;
}
.contact {
column-gap: 1rem;
cursor: pointer;
}
.language {
column-gap: 0.8rem;
padding: 0 1.25rem;
span.text {
user-select: none;
}
div.text {
cursor: pointer;
&.active {
color: #979797;
}
}
}
.submit {
cursor: pointer;
column-gap: 1rem;
.arrow {
width: 2.4rem;
height: 2.4rem;
}
}
&.mobile {
.menu-icon {
width: 5rem;
height: 5rem;
}
}
}
}
}
.footer {
height: 10rem;
padding-left: 21.5rem;
box-sizing: border-box;
padding-right: 22rem;
background-color: #232323;
.social-list {
column-gap: 2rem;
img {
width: 2rem;
height: 2rem;
}
}
.copyright {
color: #fff;
font-family: 'Arial';
font-weight: 400;
font-size: 1.2rem;
}
&.mobile {
padding: 0 6.6rem;
img {
width: 4rem;
height: 4rem;
}
.copyright {
font-size: 2rem;
}
}
}
.drawer-mask {
position: fixed;
top: 8rem;
left: 0;
right: 0;
bottom: 0;
background-color: #00000033;
z-index: 8;
.drawer-wrapper {
padding: 7.8rem 6.6rem 8.2rem;
background-color: #fff;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 2.4rem;
border-bottom-left-radius: 2.4rem;
border-bottom-right-radius: 2.4rem;
animation: drawer-in 0.3s ease-in-out;
.drawer-item {
&.language {
column-gap: 0.8rem;
// padding: 0 1.25rem;
color: #c0c0c0;
.line {
user-select: none;
}
.text {
&.active {
color: #232323;
}
}
}
}
.gap {
border: 1px solid #d5d5d5;
margin: 3.2rem 0;
}
}
}
@keyframes drawer-in {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
@keyframes drawer-out {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
.drawer-closing {
background-color: transparent;
.drawer-wrapper {
animation: drawer-out 0.3s ease-in-out forwards;
}
}
.qrcode-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.45);
.code-wrapper {
width: 60rem;
height: 49.4rem;
background-color: #fff;
position: relative;
border-radius: 0.8rem;
padding-top: 6rem;
.close-icon {
width: 2.4rem;
height: 2.4rem;
position: absolute;
top: 2rem;
right: 2rem;
cursor: pointer;
}
.code-title {
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 3rem;
color: #232323;
}
.qrcode {
width: 25.8rem;
height: 25.8rem;
margin: 3rem 0 1rem;
}
.tips {
font-family: Arial;
font-weight: 400;
font-size: 1.4rem;
color: #585858;
}
}
&.mobile {
align-items: flex-end;
.code-wrapper {
width: 100%;
height: auto;
border-radius: 0;
border-top-left-radius: 2.4rem;
border-top-right-radius: 2.4rem;
padding: 4.8rem 3.2rem 10rem;
}
.code-title {
width: 100%;
border-bottom: 1px solid #e0e0e0;
padding-bottom: 1.6rem;
}
.qrcode {
margin: 7.4rem 0 2rem;
}
.tips {
font-size: 2rem;
}
}
}
.contact-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.45);
z-index: 9;
.contact-modal-wrapper {
width: 60rem;
height: 49.4rem;
background-color: #fff;
border-radius: 0.8rem;
padding: 8.2rem 8.6rem;
position: relative;
.close-icon {
width: 2.4rem;
height: 2.4rem;
position: absolute;
top: 2rem;
right: 2rem;
cursor: pointer;
}
.header {
text-align: center;
font-family: 'PoppinsBold';
font-size: 3rem;
color: #232323;
margin-bottom: 2.2rem;
}
.desc {
text-align: center;
font-family: 'Arial';
font-weight: 400;
font-size: 1.6rem;
color: #585858;
white-space: pre-line;
line-height: 2rem;
margin-bottom: 4rem;
}
.mail {
height: 6rem;
line-height: 6rem;
background-color: #f6f6f4;
border: 0.2rem solid #e6e6e6;
border-radius: 0.8rem;
padding: 0 2rem 0 3rem;
font-family: 'ArialBold';
font-weight: 700;
margin-bottom: 5.3rem;
.copy-icon {
width: 2.4rem;
height: 2.4rem;
cursor: pointer;
}
}
.send-btn {
height: 4.2rem;
line-height: 4.2rem;
text-align: center;
color: #fff;
background-color: #232323;
border-radius: 0.8rem;
font-family: 'ArialBold';
font-weight: 700;
cursor: pointer;
}
}
&.mobile {
align-items: flex-end;
.contact-modal-wrapper {
width: 100%;
height: auto;
padding: 0 3.2rem 3.2rem;
border-radius: 0;
border-top-left-radius: 2.4rem;
border-top-right-radius: 2.4rem;
display: flex;
flex-direction: column;
align-items: center;
.header {
width: 100%;
border-bottom: 1px solid #e0e0e0;
// height: 9.6rem;
padding-top: 4.8rem;
padding-bottom: 1.6rem;
font-size: 2.4rem;
text-align: left;
margin-bottom: 9rem;
.close {
width: 3.2rem;
height: 3.2rem;
}
}
.mobile-mail {
text-align: center;
font-family: 'ArialBold';
font-weight: 700;
font-size: 2.8rem;
color: #232323;
margin-bottom: 2rem;
}
.desc {
width: 46rem;
font-size: 2.2rem;
line-height: 3rem;
margin-bottom: 11rem;
}
.send-btn {
width: 100%;
height: 8rem;
line-height: 8rem;
font-size: 2.4rem;
column-gap: 0.8rem;
.contact-icon {
width: 2.4rem;
// height: 1.8rem;
}
}
.send-btn.copy {
background-color: #f1f1f1;
color: #969696;
margin-top: 1.2rem;
}
}
}
}
@media screen and (max-width: 1200px) {
.header-wrapper {
.header {
padding-left: 6.6rem;
padding-right: 6.6rem;
.header-right {
column-gap: 2rem;
.contact-icon {
width: 3.4rem;
height: 2.6rem;
}
.language {
padding: 0 0.56rem;
}
}
}
}
// .footer {
// row-gap: 0.8rem;
// flex-direction: column;
// justify-content: center;
// }
}
</style>