style: 表单页面移动端
This commit is contained in:
BIN
src/assets/images/mobile_version_background/banner_bg.png
Normal file
BIN
src/assets/images/mobile_version_background/banner_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 KiB |
@@ -220,6 +220,12 @@ export default {
|
||||
checkYourEmail: 'Check your email',
|
||||
enterSixDigitCode: 'Enter the 6-digit code sent to',
|
||||
verify: 'Verify',
|
||||
verifyCode: 'Verify Code',
|
||||
verifyPlaceholder: 'enter 6-digital code',
|
||||
stepTabVerify: 'Verify',
|
||||
stepTabProfile: 'Profile',
|
||||
stepTabDesign: 'Design Material',
|
||||
stepTabTerms: 'Terms',
|
||||
resendCode: 'Resend',
|
||||
resendCodeIn: 'Resend Code in',
|
||||
// 验证消息
|
||||
@@ -251,6 +257,9 @@ export default {
|
||||
uploadVideoOnly: 'Please upload a MP4 file only.',
|
||||
fileSizeExceeds: 'File size exceeds {sizeLimit} limit. Please upload a smaller file.',
|
||||
videoDurationExceeds: 'Video duration exceeds 60 seconds limit. Please upload a shorter video.',
|
||||
uploadFailed: 'Upload failed'
|
||||
uploadFailed: 'Upload failed',
|
||||
nextStep: 'Next Step',
|
||||
stepTips: 'Please complete this form in one sitting.',
|
||||
backToIntroduction: 'Back to Introduction'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +209,12 @@ export default {
|
||||
checkYourEmail: '请查看您的邮箱',
|
||||
enterSixDigitCode: '请输入发送到邮箱的 6 位验证码',
|
||||
verify: '验证',
|
||||
verifyCode: '验证码',
|
||||
verifyPlaceholder: '输入6位数字的验证码',
|
||||
stepTabVerify: '验证',
|
||||
stepTabProfile: '资料',
|
||||
stepTabDesign: '设计材料',
|
||||
stepTabTerms: '条款',
|
||||
resendCode: '重新发送',
|
||||
resendCodeIn: '重新发送',
|
||||
// 验证消息
|
||||
@@ -240,6 +246,9 @@ export default {
|
||||
uploadVideoOnly: '请仅上传 MP4 文件。',
|
||||
fileSizeExceeds: '文件大小超过 {sizeLimit} 限制。请上传较小的文件。',
|
||||
videoDurationExceeds: '视频时长不可超过60秒',
|
||||
uploadFailed: '上传失败'
|
||||
uploadFailed: '上传失败',
|
||||
nextStep: '下一步',
|
||||
stepTips: '请一次性完成这个表单。',
|
||||
backToIntroduction: '返回赛事介绍'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,25 +6,22 @@ export const useIsMobile = () => {
|
||||
let resizeTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const checkDevice = () => {
|
||||
// 使用防抖避免频繁触发
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer)
|
||||
}
|
||||
resizeTimer = setTimeout(() => {
|
||||
// 1. 现代 Client Hints API(Chrome/Edge 最准)
|
||||
// if (navigator.userAgentData?.mobile !== undefined) {
|
||||
// isMobile.value = navigator.userAgentData.mobile
|
||||
// console.log('使用 userAgentData:', isMobile.value)
|
||||
// }
|
||||
// 2. 综合判断(兼容所有浏览器)
|
||||
const ua = navigator.userAgent.toLowerCase()
|
||||
const mobileRegex = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i
|
||||
const mobileRegex = /android|webos|iphone|ipod|blackberry|iemobile|opera mini/i
|
||||
const tabletRegex = /ipad|tablet|playbook|silk/i
|
||||
|
||||
const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 1
|
||||
const smallScreen = window.innerWidth <= 1200 // 你可以改成 1024 等
|
||||
const smallScreen = window.innerWidth <= 768
|
||||
const tabletScreen = window.innerWidth > 768 && window.innerWidth <= 1200
|
||||
|
||||
const uaCheck = mobileRegex.test(ua)
|
||||
isMobile.value = uaCheck || smallScreen
|
||||
const uaMobile = mobileRegex.test(ua)
|
||||
const uaTablet = tabletRegex.test(ua)
|
||||
|
||||
isMobile.value = (uaMobile && !uaTablet) || smallScreen
|
||||
}, 100)
|
||||
}
|
||||
|
||||
@@ -35,7 +32,7 @@ export const useIsMobile = () => {
|
||||
onMounted(() => {
|
||||
checkDevice()
|
||||
window.addEventListener('resize', handleResize)
|
||||
window.addEventListener('orientationchange', checkDevice) // 手机旋转必备
|
||||
window.addEventListener('orientationchange', checkDevice)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -46,10 +43,55 @@ export const useIsMobile = () => {
|
||||
}
|
||||
})
|
||||
|
||||
// 处理 keep-alive 缓存的组件重新激活场景
|
||||
onActivated(() => {
|
||||
checkDevice()
|
||||
})
|
||||
|
||||
return { isMobile }
|
||||
}
|
||||
|
||||
export const useIsTablet = () => {
|
||||
const isTablet = ref(false)
|
||||
|
||||
let resizeTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const checkDevice = () => {
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer)
|
||||
}
|
||||
resizeTimer = setTimeout(() => {
|
||||
const ua = navigator.userAgent.toLowerCase()
|
||||
const tabletRegex = /ipad|tablet|playbook|silk/i
|
||||
const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0
|
||||
const tabletScreen = window.innerWidth >= 769 && window.innerWidth <= 1200
|
||||
|
||||
const uaTablet = tabletRegex.test(ua)
|
||||
|
||||
isTablet.value = (uaTablet && tabletScreen) || (hasTouch && tabletScreen)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const handleResize = () => {
|
||||
checkDevice()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkDevice()
|
||||
window.addEventListener('resize', handleResize)
|
||||
window.addEventListener('orientationchange', checkDevice)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
window.removeEventListener('orientationchange', checkDevice)
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer)
|
||||
}
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
checkDevice()
|
||||
})
|
||||
|
||||
return { isTablet }
|
||||
}
|
||||
|
||||
162
src/views/AwardPage/components/Step.vue
Normal file
162
src/views/AwardPage/components/Step.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<nav class="step-bar" role="tablist" :aria-label="t('AwardApply.applicationForm')">
|
||||
<button
|
||||
v-for="(key, index) in tabKeys"
|
||||
:key="key"
|
||||
type="button"
|
||||
class="step-item"
|
||||
:class="{ active: modelValue === index }"
|
||||
role="tab"
|
||||
:aria-selected="modelValue === index"
|
||||
:tabindex="modelValue === index ? 0 : -1"
|
||||
@click="onSelect(index)"
|
||||
>
|
||||
<div class="step-cluster">
|
||||
<div class="step-head">
|
||||
<span class="step-badge">{{ index + 1 }}</span>
|
||||
<span class="step-label">{{ t(`AwardApply.${key}`) }}</span>
|
||||
</div>
|
||||
<div class="step-indicator" aria-hidden="true">
|
||||
<span v-if="modelValue === index" class="step-indicator-bar" />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const tabKeys = ['stepTabVerify', 'stepTabProfile', 'stepTabDesign', 'stepTabTerms'] as const
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: number
|
||||
}>(),
|
||||
{ modelValue: 0 }
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [index: number]
|
||||
change: [index: number]
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
function onSelect(index: number) {
|
||||
if (props.modelValue === index) return
|
||||
emit('update:modelValue', index)
|
||||
emit('change', index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@active-red: #c7342c;
|
||||
@label-active: #585858;
|
||||
@label-inactive: #9e9e9e;
|
||||
@badge-inactive-bg: #dcdcdc;
|
||||
@badge-inactive-text: #9f9f9f;
|
||||
@bar-height: 0.4rem;
|
||||
|
||||
.step-bar {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
padding: 0 3rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 1.6rem 0.4rem 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid @active-red;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.step-cluster {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.step-head {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.step-badge {
|
||||
flex-shrink: 0;
|
||||
width: 3.2rem;
|
||||
height: 3.2rem;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'ArialBold';
|
||||
font-weight: 700;
|
||||
font-size: 1.8rem;
|
||||
line-height: 1;
|
||||
background: @badge-inactive-bg;
|
||||
color: @badge-inactive-text;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.step-label {
|
||||
font-family: 'Poppins';
|
||||
font-weight: 400;
|
||||
font-size: 1.6rem;
|
||||
color: @label-inactive;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.step-item.active {
|
||||
.step-badge {
|
||||
background: @active-red;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.step-label {
|
||||
color: @label-active;
|
||||
}
|
||||
}
|
||||
|
||||
.step-indicator {
|
||||
width: 120%;
|
||||
min-height: @bar-height;
|
||||
margin-top: 1.2rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
/* 略宽于上方徽章+文案(与 step-head 同宽基准 + 左右扩展) */
|
||||
.step-indicator-bar {
|
||||
display: block;
|
||||
height: @bar-height;
|
||||
width: calc(100% + 1.2rem);
|
||||
min-width: 0;
|
||||
background: @active-red;
|
||||
border-radius: 0.1rem 0.1rem 0 0;
|
||||
}
|
||||
</style>
|
||||
@@ -132,7 +132,12 @@ type BtnType = 'index' | 'form'
|
||||
const btnType = ref<BtnType>('index')
|
||||
const btnText = computed(() => {
|
||||
if (isMobile.value) {
|
||||
if (btnType.value === 'index') {
|
||||
return t('AwardsPage.submitMobile')
|
||||
}
|
||||
if (btnType.value === 'form') {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED' ? '赛事介绍' : 'Back'
|
||||
}
|
||||
} else {
|
||||
if (btnType.value === 'index') {
|
||||
return t('AwardsPage.submitApplication')
|
||||
@@ -262,6 +267,9 @@ const handleBtnClick = () => {
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.award-container {
|
||||
height: 100%;
|
||||
}
|
||||
.header-wrapper {
|
||||
.header-placeholder {
|
||||
height: 8rem;
|
||||
|
||||
@@ -1,19 +1,51 @@
|
||||
<template>
|
||||
<div class="apply-container">
|
||||
<div class="banner">
|
||||
<div class="slogan">
|
||||
<div class="apply-container" :class="{ mobile: isMobile }">
|
||||
<div class="banner" :class="{ tablet: isTablet, mobile: isMobile && !isTablet }">
|
||||
<div class="slogan" @click="handleTestDate">
|
||||
{{ t('AwardApply.slogan') }}
|
||||
</div>
|
||||
<div class="title poppins-medium">{{ t('AwardApply.applicationForm') }}</div>
|
||||
<div class="form-header" v-if="!isCompleted && !isExpired">
|
||||
<div class="title poppins-medium" @click="handleTestComplete">
|
||||
{{ t('AwardApply.applicationForm') }}
|
||||
</div>
|
||||
<div class="form-header" v-if="!isCompleted && !isExpired && !isMobile && !isTablet">
|
||||
<div class="form-title poppins-bold">
|
||||
{{ t('AwardApply.emailVerification') }}
|
||||
</div>
|
||||
<div class="desc">{{ t('AwardApply.aidaUsersOnly') }}</div>
|
||||
</div>
|
||||
<div class="steps-container" v-if="(isMobile || isTablet) && !isCompleted && !isExpired">
|
||||
<Step v-model="step" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="success-wrapper"
|
||||
v-if="isCompleted || isExpired"
|
||||
:class="{ mobile: isMobile, tablet: isTablet }"
|
||||
>
|
||||
<Success
|
||||
class="success-container"
|
||||
:class="{ mobile: isMobile, tablet: isTablet }"
|
||||
:isExpired="isExpired"
|
||||
/>
|
||||
<div
|
||||
class="step-btn back"
|
||||
v-show="(isCompleted || isExpired) && (isMobile || isTablet)"
|
||||
@click="handleBackToIntroduction"
|
||||
>
|
||||
{{ t('AwardApply.backToIntroduction') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="form-container"
|
||||
v-if="!isCompleted && !isExpired"
|
||||
:class="{ mobile: isMobile, tablet: isTablet }"
|
||||
>
|
||||
<div class="form-header" v-if="showStep(0)">
|
||||
<div class="form-title poppins-bold">
|
||||
{{ t('AwardApply.emailVerification') }}
|
||||
</div>
|
||||
<div class="desc">{{ t('AwardApply.aidaUsersOnly') }}</div>
|
||||
</div>
|
||||
<Success :isExpired="isExpired" v-if="isCompleted || isExpired" />
|
||||
<div class="form-container" v-if="!isCompleted && !isExpired">
|
||||
<div class="form-content">
|
||||
<a-form
|
||||
name="form"
|
||||
@@ -23,7 +55,7 @@
|
||||
:rules="rulesRef"
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="email-box full-row">
|
||||
<div class="email-box full-row" v-show="showStep(0)">
|
||||
<a-form-item name="email" required :label="t('AwardApply.emailAddress')">
|
||||
<div class="email-wrapper flex align-center">
|
||||
<a-input v-model:value="form.email" />
|
||||
@@ -47,13 +79,36 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="form-row full-row">
|
||||
<div
|
||||
v-if="isMobile || isTablet"
|
||||
class="email-box verify-box full-row"
|
||||
v-show="showStep(0)"
|
||||
>
|
||||
<a-form-item name="verify" required :label="t('AwardApply.verifyCode')">
|
||||
<div class="email-wrapper flex align-center">
|
||||
<a-input
|
||||
v-model:value="mobileVerifyCode"
|
||||
:placeholder="t('AwardApply.verifyPlaceholder')"
|
||||
/>
|
||||
<div class="code-btn" @click="handleVerifyCode">
|
||||
{{ t('AwardApply.verify') }}
|
||||
</div>
|
||||
<img
|
||||
v-if="hasValidEmail"
|
||||
src="@/assets/images/award/checked.png"
|
||||
alt=""
|
||||
class="checked-icon"
|
||||
/>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div v-show="showStep(1)" class="form-row full-row" :class="{ mobile: isMobile }">
|
||||
<div class="form-title poppins-bold">
|
||||
{{ t('AwardApply.personalInformation') }}
|
||||
</div>
|
||||
<div class="desc">{{ t('AwardApply.tellUsAboutYourself') }}</div>
|
||||
</div>
|
||||
<div class="user-info flex">
|
||||
<div v-show="showStep(1)" class="user-info flex">
|
||||
<template v-for="item in formKeys" :key="item.key">
|
||||
<a-form-item
|
||||
v-if="item.key !== 'email'"
|
||||
@@ -86,6 +141,7 @@
|
||||
</a-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<template v-if="showStep(2)">
|
||||
<div class="form-row full-row">
|
||||
<div class="form-title poppins-bold">
|
||||
{{ t('AwardApply.designInformation') }}
|
||||
@@ -254,8 +310,13 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
</div>
|
||||
</template>
|
||||
</a-form>
|
||||
<div class="conditions">
|
||||
<div
|
||||
class="conditions"
|
||||
:class="{ mobile: isMobile, tablet: isTablet }"
|
||||
v-show="showStep(3)"
|
||||
>
|
||||
<div class="confitions-title poppins-bold">
|
||||
{{ t('AwardApply.termsAndConditions') }}
|
||||
</div>
|
||||
@@ -273,7 +334,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="submit-container">
|
||||
|
||||
<div class="submit-container" v-if="showStep(3)">
|
||||
<div class="submit-btn poppins-bold" @click="handleSubmitForm">
|
||||
{{ t('AwardApply.submitYourDesign') }}
|
||||
</div>
|
||||
@@ -282,6 +344,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(isMobile || isTablet) && step < 3" class="step-container">
|
||||
<div class="step-btn" @click="handleNextStep">
|
||||
{{ t('AwardApply.nextStep') }}
|
||||
</div>
|
||||
<div class="step-tips">{{ t('AwardApply.stepTips') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal
|
||||
v-model:visible="showModal"
|
||||
@@ -321,6 +389,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onUnmounted, onMounted, computed, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { debounce } from 'lodash-es'
|
||||
import type { Rule } from 'ant-design-vue/es/form'
|
||||
@@ -328,22 +397,52 @@ import { message, Upload } from 'ant-design-vue'
|
||||
import { Https } from '@/utils/request'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { UploadChangeParam } from 'ant-design-vue'
|
||||
import { useIsMobile, useIsTablet } from '@/utils/isMobile'
|
||||
import VerifycationCodeInput from './components/VerificationCodeInput.vue'
|
||||
import UploadStatus from './components/UploadStatus.vue'
|
||||
import Success from './components/Success.vue'
|
||||
import Step from './components/Step.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const { isMobile } = useIsMobile()
|
||||
const { isTablet } = useIsTablet()
|
||||
|
||||
const step = ref(0)
|
||||
const showStep = (val: number) => {
|
||||
if (!isMobile.value && !isTablet.value) {
|
||||
return true
|
||||
} else {
|
||||
return step.value === val
|
||||
}
|
||||
}
|
||||
|
||||
// 是否晚于2026年7月15日
|
||||
const date = ref('2026-07-15')
|
||||
const isExpired = computed(() => {
|
||||
const now = new Date()
|
||||
const targetDate = new Date('2026-07-15')
|
||||
const targetDate = new Date(date.value)
|
||||
return now > targetDate
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const route = useRoute()
|
||||
const isCompleted = ref(false)
|
||||
|
||||
let dateClick = 0
|
||||
const handleTestDate = () => {
|
||||
dateClick++
|
||||
if (dateClick % 2 === 0) {
|
||||
date.value = date.value === '2026-07-15' ? '2026-01-15' : '2026-07-15'
|
||||
}
|
||||
}
|
||||
let completeClick = 0
|
||||
const handleTestComplete = () => {
|
||||
completeClick++
|
||||
if (completeClick % 4 === 0) {
|
||||
isCompleted.value = !isCompleted.value
|
||||
}
|
||||
}
|
||||
|
||||
const readOnly = computed(() => {
|
||||
if (route.query.id && !hasValidEmail.value) {
|
||||
return true
|
||||
@@ -633,11 +732,14 @@ const handleSendCode = debounce(async () => {
|
||||
|
||||
startCountdown()
|
||||
emailCode.value = ['', '', '', '', '', ''] // 重置验证码输入
|
||||
if (!isMobile.value && !isTablet.value) {
|
||||
showModal.value = true
|
||||
}
|
||||
} catch (error) {}
|
||||
}, 300)
|
||||
|
||||
const verifyCode = ref(null)
|
||||
const mobileVerifyCode = ref('')
|
||||
|
||||
const setVerifyCode = (value) => {
|
||||
verifyCode.value = value
|
||||
@@ -646,9 +748,14 @@ const setVerifyCode = (value) => {
|
||||
const handleCloseModal = () => {
|
||||
showModal.value = false
|
||||
}
|
||||
const handleVerifyCode = () => {
|
||||
const handleVerifyCode = async () => {
|
||||
// console.log(verifyCode.value)
|
||||
|
||||
if (isMobile.value || isTablet.value) {
|
||||
await formRef.value.validateFields(['email'])
|
||||
}
|
||||
if (isMobile.value || isTablet.value) {
|
||||
verifyCode.value = mobileVerifyCode.value
|
||||
}
|
||||
if (verifyCode.value.length !== 6) {
|
||||
message.error(t('AwardApply.pleaseEnterCompleteCode'))
|
||||
return
|
||||
@@ -1071,6 +1178,16 @@ const handleEchoForm = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleNextStep = () => {
|
||||
if (step.value < 3) {
|
||||
step.value++
|
||||
}
|
||||
}
|
||||
|
||||
const handleBackToIntroduction = () => {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.id) {
|
||||
handleEchoForm()
|
||||
@@ -1104,7 +1221,22 @@ onUnmounted(() => {
|
||||
background-color: #f5f5f5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.success-wrapper {
|
||||
padding-bottom: 3rem;
|
||||
.success-container {
|
||||
&.mobile {
|
||||
height: auto;
|
||||
top: initial;
|
||||
margin: 4rem 3.8rem 0;
|
||||
padding: 13.5rem 13.2rem;
|
||||
}
|
||||
}
|
||||
&.tablet {
|
||||
.step-btn {
|
||||
margin: 6rem 23.3rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
height: 54.8rem;
|
||||
background: url('@/assets/images/award/form_bg.png') no-repeat;
|
||||
@@ -1125,13 +1257,36 @@ onUnmounted(() => {
|
||||
color: #c7342c;
|
||||
font-size: 8rem;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
height: 16.8rem;
|
||||
width: calc(100% - 42.8rem);
|
||||
left: 21.4rem;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
.steps-container {
|
||||
height: 6.8rem;
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
&.mobile {
|
||||
height: 24.8rem;
|
||||
background: url('@/assets/images/mobile_version_background/banner_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding: 4.1rem 6rem 0;
|
||||
.slogan {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
.title {
|
||||
font-size: 4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-header {
|
||||
height: 16.8rem;
|
||||
background-color: #fff;
|
||||
border-top-left-radius: 0.8rem;
|
||||
border-top-right-radius: 0.8rem;
|
||||
@@ -1151,11 +1306,13 @@ onUnmounted(() => {
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-row {
|
||||
margin-top: 12rem;
|
||||
margin-bottom: 6rem;
|
||||
&.mobile {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
color: #232323;
|
||||
@@ -1307,6 +1464,58 @@ onUnmounted(() => {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
&.mobile,
|
||||
&.tablet {
|
||||
margin-top: 4rem;
|
||||
.form-row {
|
||||
margin-top: 0;
|
||||
}
|
||||
.form-title {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
}
|
||||
&.mobile:not(.tablet) {
|
||||
padding: 0 3.8rem 4rem;
|
||||
.form-header {
|
||||
padding: 3rem 3rem 0;
|
||||
height: auto;
|
||||
padding-bottom: 2.4rem;
|
||||
}
|
||||
.form-content {
|
||||
padding: 0 3rem 20rem;
|
||||
.verify-box {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
.ant-form .ant-form-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step-btn {
|
||||
text-align: center;
|
||||
margin: 6rem 3rem 0;
|
||||
background-color: #454545;
|
||||
height: 5rem;
|
||||
border-radius: 0.8rem;
|
||||
color: #fff;
|
||||
line-height: 5rem;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 2.4rem;
|
||||
cursor: pointer;
|
||||
&.back {
|
||||
margin: 6rem 6.6rem 0;
|
||||
}
|
||||
}
|
||||
.step-tips {
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
font-family: 'Instrument';
|
||||
font-weight: 400;
|
||||
font-size: 1.8rem;
|
||||
color: #6d6d6d;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label) {
|
||||
@@ -1438,7 +1647,9 @@ onUnmounted(() => {
|
||||
}
|
||||
.conditions {
|
||||
margin-top: 12rem;
|
||||
|
||||
&.mobile {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
&-title {
|
||||
color: #232323;
|
||||
font-size: 3rem;
|
||||
@@ -1486,6 +1697,17 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
&.mobile:not(.tablet) {
|
||||
.condition-list {
|
||||
.condition-item {
|
||||
align-items: flex-start;
|
||||
height: auto;
|
||||
min-height: 6rem;
|
||||
line-height: 2.4rem;
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submit-container {
|
||||
|
||||
@@ -43,33 +43,27 @@ import banner from '@/assets/images/award/banner.mp4'
|
||||
import bannerMobile from '@/assets/images/award/banner_mobile.mp4'
|
||||
import bannerZh from '@/assets/images/award/banner_chinese.mp4'
|
||||
import bannerZhMobile from '@/assets/images/award/banner_mobile_chinese.mp4'
|
||||
import { useIsMobile } from '@/utils/isMobile'
|
||||
import { useIsMobile, useIsTablet } from '@/utils/isMobile'
|
||||
const { isMobile } = useIsMobile()
|
||||
const { isTablet } = useIsTablet()
|
||||
const router = useRouter()
|
||||
const { locale } = useI18n()
|
||||
|
||||
provide('isMobile', isMobile)
|
||||
|
||||
const isPad = ref(false)
|
||||
provide('isPad', isPad)
|
||||
provide('isPad', isTablet)
|
||||
|
||||
|
||||
const checkIsPad = () => {
|
||||
const ua = navigator.userAgent.toLowerCase()
|
||||
const padRegex = /ipad|tablet|playbook|silk/i
|
||||
const isPadUA = padRegex.test(ua)
|
||||
const isPadWidth = window.innerWidth > 768 && window.innerWidth <= 1200
|
||||
isPad.value = isPadUA || isPadWidth
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkIsPad()
|
||||
window.addEventListener('resize', checkIsPad)
|
||||
router.replace('/')
|
||||
setTimeout(() => {
|
||||
console.log('是否平板-------', isTablet.value)
|
||||
console.log('是否移动端-------', isMobile.value)
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', checkIsPad)
|
||||
})
|
||||
|
||||
const isZh = computed(() => {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED'
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user