feat: award表单页面

This commit is contained in:
2026-01-19 17:07:05 +08:00
parent a0a751c661
commit a48e517e76
10 changed files with 2658 additions and 1971 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -427,10 +427,15 @@ const routes: Array<RouteRecordRaw> = [
component: () => import("@/views/AwardPage/container.vue"),
children:[
{
path:'index',
path:'',
name:'AwardIndex',
component:()=>import('@/views/AwardPage/index.vue')
},
{
path:'index',
name:'AwardIndexAlt',
component:()=>import('@/views/AwardPage/index.vue')
},
{
path:'apply',
name:'Apply',

View File

@@ -327,7 +327,8 @@ export const Https = {
searchAllSubscribePlan: '/api/subscription_plan/searchByPage', // 分页查询所有订阅计划
searchSubscribeByOrg: '/api/subscription_plan/searchByOrganizationIdAndStatus', // 不分页查询
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
switchSubAccountSubscribePlan: '/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
switchSubAccountSubscribePlan:
'/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
//云生成
designCloud: `/api/design/designCloud`, //创建云生成
@@ -444,6 +445,11 @@ export const Https = {
// 画布
segAnything: `/api/python/segAnything`, //分割Anything
// award页面
uploadPDF: '/api/global-award/uploads/pdf', // 上传pdf
uploadVideo: '/api/global-award/uploads/video', // 上传video
},
axiosGet(url, config) {

View File

@@ -1,7 +1,9 @@
<template>
<div class="apply-container">
<div class="banner">
<div class="slogan">BLOOM YOUR CREATIVITY AiDA GLOBAL FASHION AWARD 2026</div>
<div class="slogan">
BLOOM YOUR CREATIVITY AiDA GLOBAL FASHION AWARD 2026
</div>
<div class="title poppins-medium">Application Form</div>
<div class="form-header">
<div class="form-title poppins-bold">Email Verification</div>
@@ -16,17 +18,33 @@
layout="vertical"
:model="form"
:rules="rulesRef"
autocomplete="off">
autocomplete="off"
>
<div class="email-box full-row">
<a-form-item name="email" required label="Email Address">
<a-form-item
name="email"
required
label="Email Address"
>
<div class="email-wrapper flex align-center">
<a-input v-model:value="form.email" />
<div
class="code-btn"
:class="{ disabled: isCountingDown }"
@click="handleSendCode">
{{ isCountingDown ? formatCountdown(countdown) : 'Send Code' }}
@click="handleSendCode"
>
{{
isCountingDown
? formatCountdown(countdown)
: 'Send Code'
}}
</div>
<img
v-if="hasValidEmail"
src="@/assets/images/award/checked.png"
alt=""
class="checked-icon"
/>
</div>
<div class="tips">
Please use the email address you registered with AiDA.
@@ -38,12 +56,16 @@
<div class="desc">Tell us about yourself</div>
</div>
<div class="user-info flex">
<template v-for="item in formKeys" :key="item.key">
<template
v-for="item in formKeys"
:key="item.key"
>
<a-form-item
v-if="item.key !== 'email'"
:required="item.required"
:label="item.label"
:name="item.key">
:name="item.key"
>
<a-input v-model:value="form[item.key]" />
</a-form-item>
</template>
@@ -52,12 +74,25 @@
<div class="form-title poppins-bold">Design Information</div>
<div class="desc">Share your creative vision</div>
</div>
<a-form-item class="full-row design-title" name="designTitle" label="Design Title" required>
<a-form-item
class="full-row design-title"
name="designTitle"
label="Design Title"
required
>
<a-input v-model:value="form.designTitle" />
</a-form-item>
<a-form-item class="full-row design-desc" name="description" label="Design description" required>
<a-textarea class="textarea" v-model:value="form.description"
placeholder="Briefly describe your design concept, inspiration, and creative direction..." />
<a-form-item
class="full-row design-desc"
name="description"
label="Design description"
required
>
<a-textarea
class="textarea"
v-model:value="form.description"
placeholder="Briefly describe your design concept, inspiration, and creative direction..."
/>
</a-form-item>
<div class="form-row full-row">
<div class="form-title poppins-bold">Submission Files</div>
@@ -87,52 +122,184 @@
</ul>
</div>
<div class="upload-container full-row">
<a-form-item class="full-row" name="pdfFile" required label="How will you use AiDA in your design process?">
<a-upload-dragger v-model:fileList="pdfList" name="file" action=""
@change="info => handleFileChange(info, 'pdf')">
<img src="@/assets/images/award/upload.png" alt="" class="upload-icon" />
<a-form-item
class="full-row"
name="pdfPath"
required
label="How will you use AiDA in your design process?"
>
<div
v-if="
pdfUploadStatus === 'idle' ||
pdfUploadStatus === 'error'
"
>
<a-upload-dragger
v-model:fileList="pdfList"
:showUploadList="false"
@change="info => handleFileChange(info, 'pdf')"
:customRequest="handleUploadPdf"
:beforeUpload="beforeUploadPdf"
accept=".pdf"
>
<img
src="@/assets/images/award/upload.png"
alt=""
class="upload-icon"
/>
<p class="desc">Click to upload or drag and drop</p>
<p class="limit">PDF file, max 20MB</p>
</a-upload-dragger>
</div>
<div
v-else
class="uploading-container"
>
<UploadStatus
:status="pdfUploadStatus"
type="pdf"
/>
</div>
<div
class="progress-bar-container"
v-if="pdfUploadStatus === 'uploading'"
>
<div
class="progress-bar"
:style="{ width: `${uploadProgressPdf}%` }"
></div>
</div>
</a-form-item>
</div>
<div class="upload-container full-row">
<a-form-item class="full-row" name="videoFile" required
label="How will you use AiDA in your design process?">
<a-upload-dragger v-model:fileList="videoList" name="file" action=""
@change="info => handleFileChange(info, 'video')">
<img src="@/assets/images/award/upload.png" alt="" class="upload-icon" />
<a-form-item
class="full-row"
name="videoPath"
required
label="How will you use AiDA in your design process?"
>
<div
v-if="
videoUploadStatus === 'idle' ||
videoUploadStatus === 'error'
"
>
<a-upload-dragger
v-model:fileList="videoList"
:showUploadList="false"
@change="info => handleFileChange(info, 'video')"
:customRequest="handleUploadVideo"
:beforeUpload="beforeUploadVideo"
accept=".mp4,.mov"
>
<img
src="@/assets/images/award/upload.png"
alt=""
class="upload-icon"
/>
<p class="desc">Click to upload or drag and drop</p>
<p class="limit">Video file(MP4, MOV), max 20MB</p>
<p class="limit">
Video file (MP4, MOV), 1080p, max 100MB
</p>
</a-upload-dragger>
</div>
<div
v-else
class="uploading-container"
>
<UploadStatus
:status="videoUploadStatus"
type="video"
/>
</div>
<div
class="progress-bar-container"
v-if="videoUploadStatus === 'uploading'"
>
<div
class="progress-bar"
:style="{ width: `${uploadProgressVideo}%` }"
></div>
</div>
</a-form-item>
</div>
</a-form>
<div class="conditions">
<div class="confitions-title poppins-bold">Terms & Conditions</div>
<div class="condition-list flex flex-col">
<div class="condition-item flex align-center" v-for="item in conditionsList" :key="item.id">
<div
class="condition-item flex align-center"
v-for="item in conditionsList"
:key="item.id"
>
<a-checkbox v-model:checked="item.check" />
<span>{{ item.text }}</span>
<span>
{{ item.text }}
<span
class="required"
v-if="item.required"
>
*
</span>
</span>
</div>
</div>
</div>
<div class="submit-container">
<div
class="submit-btn poppins-bold"
@click="handleSubmitForm"
>
Submit your Design
</div>
<div class="desc">
The link in the AiDA in-platform message will save your unfinished
form.
</div>
</div>
</div>
</div>
</div>
<a-modal v-model:visible="showModal" :footer="null" :maskClosable="false" :closable="false"
<a-modal
v-model:visible="showModal"
:footer="null"
:maskClosable="false"
:closable="false"
wrapClassName="code-modal"
forceRender :keyboard="false" :style="{ top: '29.3rem' }">
forceRender
:keyboard="false"
:style="{ top: '29.3rem' }"
>
<div class="verify-container flex flex-col align-center">
<img src="@/assets/images/award/close.svg" class="close-icon" @click="handleCloseModal" />
<img
src="@/assets/images/award/close.svg"
class="close-icon"
@click="handleCloseModal"
/>
<div class="title poppins-bold">Check your email</div>
<div class="desc">Enter the 6-digital code sent to</div>
<div class="email">{{ form.email }}</div>
<div class="code-box">
<VerifycationCodeInput :ct="emailCode" @sendCaptcha="setVerifyCode" />
<VerifycationCodeInput
:ct="emailCode"
@sendCaptcha="setVerifyCode"
/>
</div>
<div class="verify-btn" @click="handleVerifyCode">Verify</div>
<div class="cutdown" :class="{ disabled: isCountingDown }" @click="handleSendCode">
{{ isCountingDown ? `Resend Code in ${formatCountdown(countdown)}` : 'Resend' }}
<div
class="verify-btn"
@click="handleVerifyCode"
>
Verify
</div>
<div
class="cutdown"
:class="{ disabled: isCountingDown }"
@click="handleSendCode"
>
{{
isCountingDown
? `Resend Code in ${formatCountdown(countdown)}`
: 'Resend'
}}
</div>
</div>
</a-modal>
@@ -145,9 +312,11 @@ import { debounce } from 'lodash-es'
import type { Rule } from 'ant-design-vue/es/form'
import { message } from 'ant-design-vue'
import type { UploadChangeParam } from 'ant-design-vue'
// import VerificationCodeInput from './components/VerificationCodeInput.vue'
import VerifycationCodeInput from './components/verificationCodeInput.vue'
import { Https } from '@/tool/https'
import UploadStatus from './components/UploadStatus.vue'
const hasValidEmail = ref(true)
const formRef = ref(null)
const form = ref({
email: '',
@@ -162,8 +331,8 @@ const form = ref({
// code: '',
designTitle: '',
description: '',
pdfFile: null,
videoFile: null
pdfPath: null,
videoPath: null
})
// 验证码输入组件引用
@@ -219,7 +388,9 @@ const rulesRef = {
firstName: [
{ required: true, message: 'Please input your first name', trigger: 'blur' }
],
lastName: [{ required: true, message: 'Please input your last name', trigger: 'blur' }]
lastName: [
{ required: true, message: 'Please input your last name', trigger: 'blur' }
]
}
const formKeys = ref([
@@ -336,6 +507,22 @@ const handleCloseModal = () => {
showModal.value = false
}
const handleSubmitForm = () => {
const validCondition = conditionsList.value.filter(
item => item.required && !item.check
)
if (validCondition.length > 0) {
message.error('Please check the terms and conditions')
return
}
formRef.value.validate().then(res => {
console.log(res)
}).catch(err => {
console.log(err)
message.error('Please fill in all the required fields')
})
}
const handleVerifyCode = () => {
if (verifyCode.value.length !== 6) {
message.error('Please enter the complete 6-digit verification code')
@@ -350,36 +537,212 @@ const handleVerifyCode = () => {
const pdfList = ref([])
const videoList = ref([])
const isUploadingPdf = ref(false)
const uploadProgressPdf = ref(0)
const isUploadingVideo = ref(false)
const uploadProgressVideo = ref(0)
const pdfUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle')
const videoUploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle')
// 统一的文件上传前验证
const beforeUploadFile = (type: FileType, file: File) => {
if (!hasValidEmail.value) {
message.error('Please verify your email first')
return false
}
let maxSize: number
let allowedExtensions: string[]
let allowedMimeTypes: string[]
let errorMessage: string
if (type === 'pdf') {
maxSize = 20 * 1024 * 1024 // 20MB
allowedExtensions = ['pdf']
allowedMimeTypes = ['application/pdf']
errorMessage = 'Please upload a PDF file only.'
} else if (type === 'video') {
maxSize = 100 * 1024 * 1024 // 100MB
allowedExtensions = ['mp4', 'mov']
allowedMimeTypes = ['video/mp4', 'video/quicktime']
errorMessage = 'Please upload a MP4 or MOV file only.'
} else {
return false
}
// 验证文件类型
const fileExtension = file.name.split('.').pop()?.toLowerCase()
const isValidType =
allowedExtensions.includes(fileExtension || '') ||
allowedMimeTypes.includes(file.type)
if (!isValidType) {
message.error(errorMessage)
// 从文件列表中移除
if (type === 'pdf') {
const index = pdfList.value.findIndex(item => item.uid === file.uid)
if (index > -1) {
pdfList.value.splice(index, 1)
}
} else {
const index = videoList.value.findIndex(item => item.uid === file.uid)
if (index > -1) {
videoList.value.splice(index, 1)
}
}
return false // 阻止上传
}
// 验证文件大小
if (file.size > maxSize) {
const sizeLimit = type === 'pdf' ? '20MB' : '100MB'
message.error(
`File size exceeds ${sizeLimit} limit. Please upload a smaller file.`
)
// 从文件列表中移除
if (type === 'pdf') {
const index = pdfList.value.findIndex(item => item.uid === file.uid)
if (index > -1) {
pdfList.value.splice(index, 1)
}
} else {
const index = videoList.value.findIndex(item => item.uid === file.uid)
if (index > -1) {
videoList.value.splice(index, 1)
}
}
return false // 阻止上传
}
return true // 允许上传
}
// PDF文件上传前验证
const beforeUploadPdf = (file: File) => {
return beforeUploadFile('pdf', file)
}
// Video文件上传前验证
const beforeUploadVideo = (file: File) => {
return beforeUploadFile('video', file)
}
type FileType = 'pdf' | 'video'
const handleFileChange = (info: UploadChangeParam, type: FileType) => {
console.log('change---------')
const status = info.file.status
if (status !== 'uploading') {
console.log('file:', info.file)
}
if (status === 'done') {
message.success(`${info.file.name} file uploaded successfully.`)
if (type === 'pdf') {
isUploadingPdf.value = false
uploadProgressPdf.value = 0
pdfUploadStatus.value = 'success'
} else if (type === 'video') {
isUploadingVideo.value = false
uploadProgressVideo.value = 0
videoUploadStatus.value = 'success'
}
} else if (status === 'error') {
message.error(`${info.file.name} file upload failed.`)
if (type === 'pdf') {
isUploadingPdf.value = false
uploadProgressPdf.value = 0
pdfUploadStatus.value = 'error'
} else if (type === 'video') {
isUploadingVideo.value = false
uploadProgressVideo.value = 0
videoUploadStatus.value = 'error'
}
}
}
// 统一的上传处理函数
const handleUploadFile = (option: any, type: FileType) => {
console.log(option, type)
const file = option.file
// 根据类型设置上传状态和进度
if (type === 'pdf') {
isUploadingPdf.value = true
uploadProgressPdf.value = 0
pdfUploadStatus.value = 'uploading'
} else if (type === 'video') {
isUploadingVideo.value = true
uploadProgressVideo.value = 0
videoUploadStatus.value = 'uploading'
}
const params = new FormData()
params.append('file', file)
params.append('email', form.value.email)
// 根据类型选择不同的上传接口
const uploadUrl = Https.httpUrls.uploadAvatar
// const uploadUrl =
// type === 'pdf' ? Https.httpUrls.uploadPDF : Https.httpUrls.uploadVideo
Https.axiosPost(uploadUrl, params, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: progressEvent => {
if (progressEvent.total) {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
if (type === 'pdf') {
uploadProgressPdf.value = percentCompleted
} else if (type === 'video') {
uploadProgressVideo.value = percentCompleted
}
}
}
})
.then(res => {
console.log(res)
if (type === 'pdf') pdfUploadStatus.value = 'success'
if (type === 'video') videoUploadStatus.value = 'success'
option.onSuccess(res, option.file)
})
.catch(error => {
console.error('Upload error:', error)
option.onError(error)
if (type === 'pdf') {
isUploadingPdf.value = false
uploadProgressPdf.value = 0
pdfUploadStatus.value = 'error'
} else if (type === 'video') {
isUploadingVideo.value = false
uploadProgressVideo.value = 0
videoUploadStatus.value = 'error'
}
})
}
// PDF上传处理
const handleUploadPdf = (option: any) => {
return handleUploadFile(option, 'pdf')
}
// Video上传处理
const handleUploadVideo = (option: any) => {
return handleUploadFile(option, 'video')
}
const conditionsList = ref([
{
check: false,
required: true,
text: 'I confirm that all submitted work is original and created by me.',
id: 'first'
},
{
check: false,
required: true,
text: 'I understand that Code-Create has marketing and promotional rights to all submitted designs and videos.',
id: 'second'
},
{
check: false,
required: true,
text: 'I agree to participate in finalist activities if selected, including AiDA training and award ceremony.',
id: 'third'
},
@@ -552,6 +915,13 @@ onUnmounted(() => {
.email-wrapper {
border-radius: 0.8rem;
border: 0.2rem solid #d5d5d5;
position: relative;
.checked-icon {
position: absolute;
right: -6rem;
width: 4rem;
height: 4rem;
}
}
.code-btn {
@@ -655,6 +1025,41 @@ onUnmounted(() => {
}
}
}
.uploading-container {
height: 32rem;
display: flex;
align-items: center;
justify-content: center;
border: 0.2rem solid #d5d5d5;
border-radius: 0.8rem;
background-color: #fafafa;
.uploading-text {
color: #585858;
font-family: 'Arial';
font-weight: 400;
font-size: 2.4rem;
}
}
.progress-bar-container {
width: 100%;
height: 1rem;
background-color: #f0f0f0;
border-radius: 0.8rem;
margin-top: 2rem;
overflow: hidden;
position: absolute;
bottom: 0;
.progress-bar {
height: 100%;
background-color: #c7342c;
border-radius: 0.8rem;
transition: width 0.3s ease;
}
}
}
.conditions {
@@ -680,28 +1085,64 @@ onUnmounted(() => {
font-size: 1.8rem;
padding-left: 1.5rem;
column-gap: 2.5rem;
.required {
color: #c7342c;
}
}
:deep(.ant-checkbox-inner) {
border: 0.2rem solid #585858;
:deep(.ant-checkbox-wrapper) {
.ant-checkbox-inner {
//修改边框的颜色
width: 2rem;
height: 2rem;
border: 0.2rem solid #585858 !important;
border-radius: 0.4rem;
}
:deep(.ant-checkbox-wrapper:hover .ant-checkbox-inner,
.ant-checkbox:hover .ant-checkbox-inner,
.ant-checkbox-input:focus + .ant-checkbox-inner) {
.ant-checkbox-checked .ant-checkbox-inner {
//修改选中框的背景颜色
background-color: #fff !important;
/* 将背景颜色修改为白色 */
//修改边框颜色
border-color: #585858 !important;
/* 将边框颜色修改为黑色 */
}
:deep(.ant-checkbox-wrapper:hover .ant-checkbox-inner,
.ant-checkbox:hover .ant-checkbox-inner,
.ant-checkbox-input:focus+.ant-checkbox-inner) {
border-color: #585858 !important;
.ant-checkbox-checked .ant-checkbox-inner::after {
//antd的checkbox组件的选中框里面的透明的钩子是通过设置底部边框和右边框的颜色再旋转得到的钩子
// 所以设置底部边框和右边框的样式就可以修改钩子的样式
border-bottom: 0.2rem solid #585858;
border-right: 0.2rem solid #585858;
width: 0.65rem;
height: 1rem;
left: 21.895%;
}
}
}
}
:deep(.ant-checkbox-checked .ant-checkbox-inner) {
border-color: #000 !important;
background-color: #000 !important;
.submit-container {
margin-top: 12rem;
.submit-btn {
height: 5rem;
background-color: #454545;
border-radius: 0.8rem;
color: #fff;
line-height: 5rem;
text-align: center;
font-size: 1.6rem;
cursor: pointer;
}
.desc {
// font-family: 'instrument';
font-family: revert-layer;
font-weight: 400;
font-size: 1.6rem;
color: #6d6d6d;
text-align: center;
margin-top: 2rem;
}
}

View File

@@ -0,0 +1,79 @@
<template>
<div class="upload-status">
<div class="upload-status-item">
<div class="upload-status-item-icon">
<img
v-if="status === 'uploading'"
src="@/assets/images/award/progress.png"
alt=""
class="progress-icon"
/>
<img
v-if="status === 'success'"
src="@/assets/images/award/successful.png"
alt=""
class="progress-icon successful-icon"
/>
</div>
<div class="text">{{ text }}</div>
<div class="tips">{{ tips }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
const props = defineProps<{
status: string
type: 'pdf' | 'video'
}>()
const textMap: Record<string, string> = {
idle: '',
uploading: 'Upload in progress…',
success: 'Uploaded Successfully',
error: 'Upload failed'
}
const tips = computed(() => {
if (props.type === 'pdf') {
return 'PDF file, max 20MB'
} else if (props.type === 'video') {
return 'Video file (MP4, MOV), 1080p, max 100MB'
}
return ''
})
const text = computed(() => {
return textMap[props.status] ?? textMap.uploading
})
</script>
<style scoped lang="less">
.upload-status {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.upload-status-item {
display: flex;
flex-direction: column;
align-items: center;
.progress-icon {
width: 12rem;
height: 12rem;
}
.text {
font-family: Arial;
font-weight: 400;
color: #585858;
font-size: 2.4rem;
}
.tips{
font-family: Arial;
font-weight: 400;
font-size: 1.8rem;
color: #aaa;
}
}
}
</style>

View File

@@ -2,38 +2,100 @@
<div class="award-container">
<div class="header flex align-center space-between">
<div class="header-left">
<img src="@/assets/images/award/code_create_logo.png" class="logo" />
<img
src="@/assets/images/award/code_create_logo.png"
class="logo"
/>
</div>
<div class="header-right flex align-center">
<div class="text">Submit your Application</div>
<img src="@/assets/images/award/arrow.png" alt="" class="arrow" />
<img
src="@/assets/images/award/arrow.png"
alt=""
class="arrow"
/>
</div>
</div>
<RouterView />
<router-view />
<div class="footer flex space-between align-center">
<div class="social-list flex">
<a href="https://xhslink.com/m/5Ony2FapizV" target="_blank">
<img src="@/assets/images/award/xiaohongshu.svg" alt="" />
<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
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
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
href="https://www.tiktok.com/@aida_codecreate"
target="_blank"
>
<img
src="@/assets/images/award/tiktok.svg"
alt=""
/>
</a>
<a href="https://www.tiktok.com/@aida_codecreate" target="_blank">
<img src="@/assets/images/award/weichat.svg" alt="" />
<a
href="javascript:void(0)"
@click="showQRcode = true"
>
<img
src="@/assets/images/award/weichat.svg"
alt=""
/>
</a>
</div>
<div class="copyright">© Code-Create 2026</div>
</div>
<div
class="qrcode-mask flex flex-center"
v-if="showQRcode"
>
<div class="code-wrapper flex flex-col align-center">
<img
src="@/assets/images/award/close.svg"
class="close-icon"
@click="handleCloseQRcode"
/>
<div class="code-title">WeChat Official Account</div>
<img
src="@/assets/images/award/qrcode.jpg"
class="qrcode"
/>
<div class="tips">Scan the QR code in WeChat</div>
</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { ref } from 'vue'
const showQRcode = ref(false)
const handleCloseQRcode = () => {
showQRcode.value = false
}
</script>
<style lang="less" scoped>
.award-container {
@@ -90,4 +152,45 @@
font-size: 1.2rem;
}
}
.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;
}
}
}
</style>

View File

@@ -1,9 +1,16 @@
<template>
<div class="award-page">
<div class="banner">
<div class="submit-btn flex flex-center" @click="handleSubmitApplication">
<div
class="submit-btn flex flex-center"
@click="handleSubmitApplication"
>
<div>Submit your Application</div>
<img src="@/assets/images/award/arrow_right.png" alt="" class="arrow" />
<img
src="@/assets/images/award/arrow_right.png"
alt=""
class="arrow"
/>
<div class="ddl">Application Deadline:15th March 2026</div>
</div>
</div>
@@ -19,40 +26,58 @@
</div>
<div class="block-item flex flex-col flex-center">
<div class="number">
<img src="@/assets/images/award/∞.png" alt="" class="infinity" />
<img
src="@/assets/images/award/∞.png"
alt=""
class="infinity"
/>
</div>
<div class="label">Possibilites</div>
</div>
</div>
<div class="bloom container flex flex-col align-center">
<div class="title">Bloom Your Creativity</div>
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="season">Theme of 2026</div>
<div class="desc">
Where imagination meets innovation, creativity blooms. This theme celebrates AI as
a catalyst for fashion design, allowing your vision to flourish beyond traditional
boundaries. Let your ideas blossom into extraordinary designs that merge human
artistry with artificial intelligence.
Where imagination meets innovation, creativity blooms. This theme
celebrates AI as a catalyst for fashion design, allowing your vision to
flourish beyond traditional boundaries. Let your ideas blossom into
extraordinary designs that merge human artistry with artificial
intelligence.
</div>
</div>
<div class="design-container container">
<div class="design-title limit">Design Without Borders</div>
<div class="limit">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
</div>
<div class="global limit">Global Opportunity</div>
<div class="desc">
Open to visionary designers across the globe. From Seoul to Singapore, New York to
Shanghai, we're seeking the next generation of fashion innovators who dare to
reimagine the future of design.
Open to visionary designers across the globe. From Seoul to Singapore, New
York to Shanghai, we're seeking the next generation of fashion innovators
who dare to reimagine the future of design.
</div>
</div>
<div class="timeline-container container flex flex-col align-center">
<div class="timeline-title">Competition Timeline</div>
<img src="@/assets/images/award/bloom_logo.png" alt="" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
alt=""
class="logo"
/>
<div class="desc">Shaping the Future</div>
<div class="timeline-point">
<img src="@/assets/images/award/timeline_line.png" class="line-bg" />
<img
src="@/assets/images/award/timeline_line.png"
class="line-bg"
/>
<div class="labels-row flex align-center">
<div
class="item-label flex flex-col"
@@ -60,7 +85,12 @@
:key="'label-' + item.time"
>
<div class="main-label">{{ item.label }}</div>
<div class="sub-label" v-if="item.subLabel">{{ item.subLabel }}</div>
<div
class="sub-label"
v-if="item.subLabel"
>
{{ item.subLabel }}
</div>
</div>
</div>
<!-- Icons row -->
@@ -76,7 +106,11 @@
<!-- Times row -->
<div class="times-row flex align-center">
<div class="item-time" v-for="item in points" :key="'time-' + item.time">
<div
class="item-time"
v-for="item in points"
:key="'time-' + item.time"
>
{{ item.time }}
</div>
</div>
@@ -97,7 +131,10 @@
<div class="prizes-container container flex align-center">
<div class="left flex flex-col flex-center">
<div class="title">Award & Prizes</div>
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="desc">Recongnition</div>
</div>
<div class="right">
@@ -109,7 +146,12 @@
<div class="prize-money">{{ item.money }}</div>
<div class="prize-name">{{ item.name }}</div>
<div class="prize-desc flex flex-col flex-center">
<div class="desc-item" v-for="el in item.desc">{{ el }}</div>
<div
class="desc-item"
v-for="el in item.desc"
>
{{ el }}
</div>
</div>
</div>
</div>
@@ -119,22 +161,42 @@
<div class="sub-title">Requirments</div>
<div class="requirments-list flex">
<div class="left flex flex-col space-between">
<div class="item-box" v-for="item in leftRequirment" :key="item.type">
<div
class="item-box"
v-for="item in leftRequirment"
:key="item.type"
>
<div class="item-header flex align-center">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="item-title">{{ item.type }}</div>
</div>
<div class="context" v-for="el in item.desc">{{ el }}</div>
<div
class="context"
v-for="el in item.desc"
>
{{ el }}
</div>
</div>
</div>
<div class="right">
<div class="item-box">
<div class="item-box">
<div class="item-header flex align-center">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="item-title">{{ rightRequirment.type }}</div>
</div>
<div class="context" v-for="el in rightRequirment.desc">{{ el }}</div>
<div
class="context"
v-for="el in rightRequirment.desc"
>
{{ el }}
</div>
</div>
</div>
</div>
@@ -142,7 +204,10 @@
</div>
<div class="selection-container container flex flex-col align-center">
<div class="title">Selection Criteria</div>
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="sub-title">Evaluation</div>
<div class="criteria-list flex">
<div
@@ -150,7 +215,11 @@
v-for="item in criteriaList"
:key="item.name"
>
<img :src="item.icon" class="icon" :style="item.style" />
<img
:src="item.icon"
class="icon"
:style="item.style"
/>
<div class="name">{{ item.name }}</div>
<div class="desc">{{ item.desc }}</div>
</div>
@@ -158,7 +227,10 @@
</div>
<div class="judges-container flex flex-col align-center">
<div class="title">Panel of Judges</div>
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<img
src="@/assets/images/award/bloom_logo.png"
class="logo"
/>
<div class="sub-title">Expertise</div>
<div class="judgement-list">
<div
@@ -166,7 +238,10 @@
v-for="item in judgements"
:key="item.name"
>
<img :src="item.picture" class="picture" />
<img
:src="item.picture"
class="picture"
/>
<div class="name">{{ item.name }}</div>
<div class="desc">{{ item.desc }}</div>
</div>
@@ -344,33 +419,10 @@ const judgements = [
</script>
<style lang="less" scoped>
.container {
height: 97rem;
}
// .header {
// height: 8rem;
// background-color: #232323;
// padding-left: 21.5rem;
// padding-right: 8.6rem;
// .header-left {
// .logo {
// width: 13rem;
// height: 5rem;
// }
// }
// .header-right {
// column-gap: 1rem;
// .text {
// font-size: 1.6rem;
// color: #fff;
// }
// .arrow {
// width: 2.4rem;
// height: 2.4rem;
// }
// }
// }
.logo {
width: 2.4rem;
height: 2.4rem;
@@ -671,7 +723,8 @@ const judgements = [
background-size: 100% 100%;
}
&:nth-of-type(4) {
background: url('@/assets/images/award/certification_bg.png') no-repeat;
background: url('@/assets/images/award/certification_bg.png')
no-repeat;
background-size: 100% 100%;
}
.prize-money {