diff --git a/src/assets/icons/CFile.svg b/src/assets/icons/CFile.svg new file mode 100644 index 00000000..e824de6e --- /dev/null +++ b/src/assets/icons/CFile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/images/award/upload_video_icon.png b/src/assets/images/award/upload_video_icon.png new file mode 100644 index 00000000..dbc1ed68 Binary files /dev/null and b/src/assets/images/award/upload_video_icon.png differ diff --git a/src/component/Detail/detailRight/editPrintElement.vue b/src/component/Detail/detailRight/editPrintElement.vue index 05805d3f..1b8c393d 100644 --- a/src/component/Detail/detailRight/editPrintElement.vue +++ b/src/component/Detail/detailRight/editPrintElement.vue @@ -89,8 +89,8 @@ - - + +
- +
- - - +
+
@@ -157,19 +171,15 @@ :validate-trigger="[]" label="How will you use AiDA in your design process?" > -
+

Click to upload or drag and drop

PDF file, max 20MB

+
-
-
+ class="progress-bar-container" + v-if="pdfUploadStatus === 'uploading'" + > +
+
@@ -209,23 +242,19 @@ :validate-trigger="[]" label="How will you use AiDA in your design process?" > -
+
@@ -233,25 +262,48 @@

Video file (MP4, MOV), 1080p, max 100MB

+
-
-
+ class="progress-bar-container" + v-if="videoUploadStatus === 'uploading'" + > +
+
@@ -342,7 +394,7 @@ import { ref, onUnmounted, onMounted, computed } from 'vue' import { debounce } from 'lodash-es' import type { Rule } from 'ant-design-vue/es/form' - import { message } from 'ant-design-vue' + import { message, Upload } from 'ant-design-vue' import { Https } from '@/tool/https' import { useRoute } from 'vue-router' import type { UploadChangeParam } from 'ant-design-vue' @@ -359,7 +411,7 @@ const route = useRoute() const isCompleted = ref(false) - const hasValidEmail = ref(false) + const readOnly = computed(() => { if (route.query.id && !hasValidEmail.value) { return true @@ -383,7 +435,10 @@ designDescription: '', pdfPath: '', videoPath: '', - secureToken: null + secureToken: '' + }) + const hasValidEmail = computed(() => { + return !!form.value.secureToken }) // 验证码输入组件引用 @@ -620,7 +675,6 @@ console.log('coderes', res) form.value.secureToken = res.data.secureToken - hasValidEmail.value = true message.success('Verification successful!') showModal.value = false @@ -675,7 +729,7 @@ const beforeUploadFile = (type: FileType, file: File) => { if (!hasValidEmail.value) { message.error('Please verify your email first') - return false + return Upload.LIST_IGNORE } let maxSize: number let allowedExtensions: string[] @@ -693,7 +747,7 @@ allowedMimeTypes = ['video/mp4', 'video/quicktime'] errorMessage = 'Please upload a MP4 or MOV file only.' } else { - return false + return Upload.LIST_IGNORE } // 验证文件类型 @@ -705,18 +759,18 @@ 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 (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 Upload.LIST_IGNORE } // 验证文件大小 @@ -726,21 +780,21 @@ `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 // 阻止上传 + // 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 Upload.LIST_IGNORE } - return true // 允许上传 + return true } // PDF文件上传前验证 @@ -822,18 +876,22 @@ } const completeChunkUpload = async (type: FileType, file: File) => { - const endpoint = - type === 'pdf' - ? Https.httpUrls.uploadPDFComplete - : Https.httpUrls.uploadVideoComplete + try { + const endpoint = + type === 'pdf' + ? Https.httpUrls.uploadPDFComplete + : Https.httpUrls.uploadVideoComplete - return Https.axiosPost(endpoint, { - uploadId: chunkUploadState[type].uploadId, - email: form.value.email, - fileName: file.name, - totalSize: file.size, - secureToken: form.value.secureToken - }) + return Https.axiosPost(endpoint, { + uploadId: chunkUploadState[type].uploadId, + email: form.value.email, + fileName: file.name, + totalSize: file.size, + secureToken: form.value.secureToken + }) + } catch (error) { + console.log('complete错误', error) + } } type FileType = 'pdf' | 'video' @@ -922,10 +980,12 @@ isUploadingPdf.value = false uploadProgressPdf.value = 0 pdfUploadStatus.value = 'error' + pdfList.value = [] } else { isUploadingVideo.value = false uploadProgressVideo.value = 0 videoUploadStatus.value = 'error' + videoList.value = [] } } } @@ -940,6 +1000,18 @@ return handleUploadFile(option, 'video') } + const handleRemoveFile = (type: 'video' | 'pdf') => { + if (type === 'pdf') { + form.value.pdfPath = '' + pdfUploadStatus.value = 'idle' + uploadProgressPdf.value = 0 + } else if (type === 'video') { + form.value.videoPath = '' + videoUploadStatus.value = 'idle' + uploadProgressVideo.value = 0 + } + } + const conditionsList = ref([ { check: false, @@ -1137,14 +1209,26 @@ line-height: 6rem; } } - :deep(.ant-select-arrow) { - height: 4rem; - width: 6.2rem; - justify-content: center; - display: flex; - align-items: center; - border-left: 0.1rem solid #d5d5d5; - } + // :deep(.ant-select-arrow) { + + // justify-content: center; + // display: flex; + // align-items: center; + // } + } + } + .select-container { + position: relative; + .arrow-wrapper { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 6rem; + height: 4rem; + box-sizing: border-box; + border-left: 0.1rem solid #d5d5d5; + pointer-events: none; } } @@ -1238,9 +1322,10 @@ .upload-container { margin-top: 6rem; - + position: relative; :deep(.ant-upload-drag) { height: 32rem; + border-radius: 0.8rem; .ant-upload-btn { padding: 0; @@ -1276,9 +1361,13 @@ display: flex; align-items: center; justify-content: center; - border: 0.2rem solid #d5d5d5; + border: 0.2rem dashed #d5d5d5; border-radius: 0.8rem; background-color: #fafafa; + position: absolute; + top: 0; + left: 0; + width: 100%; .uploading-text { color: #585858; @@ -1306,7 +1395,20 @@ } } } - + .custom-upload-list { + padding: 0.4rem 1rem; + margin-top: 1rem; + &:hover { + background-color: #f5f5f5; + border-radius: 0.4rem; + } + .c-svg { + width: fit-content; + } + .delete-file { + cursor: pointer; + } + } .conditions { margin-top: 12rem; @@ -1462,9 +1564,12 @@ diff --git a/src/views/AwardPage/components/ApplySection.vue b/src/views/AwardPage/components/ApplySection.vue index 27e58e05..ca120cfb 100644 --- a/src/views/AwardPage/components/ApplySection.vue +++ b/src/views/AwardPage/components/ApplySection.vue @@ -463,7 +463,7 @@ .item-desc { font-family: 'Instrument'; font-weight: 400; - font-size: 24px; + font-size: 2.4rem; color: #585858; &.indent { padding-left: 3.8rem; diff --git a/src/views/AwardPage/components/Success.vue b/src/views/AwardPage/components/Success.vue index 4c42df4c..aee43d9e 100644 --- a/src/views/AwardPage/components/Success.vue +++ b/src/views/AwardPage/components/Success.vue @@ -35,7 +35,7 @@ return { icon: expiredIcon, title: 'Application Deadline Passed', - desc: 'The submission deadline for AIDA Global Fashion Award 2026 has ended.\nWe are no longer accepting new applications. ' + desc: 'The submission deadline for AiDA Global Fashion Award 2026 has ended.\nWe are no longer accepting new applications. ' } } else { return { diff --git a/src/views/AwardPage/components/TimeLine.vue b/src/views/AwardPage/components/TimeLine.vue index 528beaff..9f1701d5 100644 --- a/src/views/AwardPage/components/TimeLine.vue +++ b/src/views/AwardPage/components/TimeLine.vue @@ -5,10 +5,14 @@ >
Competition Timeline
Shaping the Future
-
-
+
+ +
@@ -21,31 +25,35 @@
- -
+ +
- + > + +
- - -
+ +
{{ item.time }}
- -
+ + +
@@ -63,12 +71,13 @@ import { gsap } from 'gsap' const containerRef = ref(null) + const timelineRef = ref(null) const hasAnimated = ref(false) const points = ref([ { label: 'Application', - subLabel:'Deadline', + subLabel: 'Deadline', time: 'Jul 15', desc: 'Application deadline and\nentry review process\nbegins.' }, @@ -86,16 +95,16 @@ }, { label: 'Receiving Outfits', - subLabel:'from Finallists', + subLabel: 'from Finallists', time: 'October', desc: 'AiDA receives physical\noutfits from all 20\nfinalists.' }, { label: 'Award', - subLabel:'Ceremony', + subLabel: 'Ceremony', time: 'Nov 12', desc: 'Award Ceremony &\nCommunity Gathering\n– Soho House.' - }, + } ]) const playAnimation = () => { @@ -120,7 +129,7 @@ }, { clipPath: 'inset(0 0% 0 0)', - duration: 1.6, + duration: 1.3, ease: 'power1.out' }, 'start' @@ -157,16 +166,14 @@ ) } - // 行内文字(标签、时间、描述)与 start 同步开始 - const textItems = containerRef.value.querySelectorAll( - '.item-label, .item-time, .item-desc .txt' - ) + // 行内文字(标签、时间、描述、图标)与 start 同步开始 + const textItems = containerRef.value.querySelectorAll('.grid-cell') if (textItems && textItems.length) { tl.from( textItems, { - autoAlpha: 0.5, - duration: 0.6, + // autoAlpha: 0.5, + duration: 0.7, stagger: 0.08, ease: 'power2.out' }, @@ -174,22 +181,6 @@ ) } - // 所有文字与线条完成后,立即开始点图标动画(按顺序出现) - const icons = containerRef.value.querySelectorAll('.point-icon') - if (icons && icons.length) { - // 与 'start' 标签同步开始:改为纯淡入动画(移除缩放) - tl.from( - icons, - { - autoAlpha: 0, - duration: 2, - stagger: 0.12, - ease: 'power2.out' - }, - 'start+=0.3' - ) - } - hasAnimated.value = true } @@ -199,8 +190,8 @@ await nextTick() if (!containerRef.value) return observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { + entries => { + entries.forEach(entry => { if (entry.isIntersecting) { playAnimation() } @@ -224,7 +215,7 @@ background: url('@/assets/images/award/timeline_bg.png') no-repeat; background-size: 100% 100%; position: relative; - padding-top: 12.8rem; + padding: 12.8rem 0 15.9rem; width: 100%; color: #fff; .timeline-title { @@ -248,42 +239,45 @@ will-change: clip-path; flex: 1; width: 100%; - margin-top: 12rem; - padding: 0 21.2rem 0 22rem; + margin-top: 11rem; + padding: 0 13.8rem; position: relative; z-index: 2; - .labels-row { - position: relative; - z-index: 2; - margin-bottom: 8rem; - .item-label { - flex: 1; - color: #fff; - font-family: 'PoppinsBold'; - font-weight: 600; - font-size: 2.8rem; - text-align: center; - white-space: pre-line; - // height: 6rem; - justify-content: center; - } + // 主网格布局:5列 + display: grid; + grid-template-columns: repeat(5, 1fr); + grid-template-rows: auto auto auto auto; + grid-column-gap: 0; + grid-row-gap: 0; + + // 所有 grid 子行的通用样式 + .grid-row { + display: grid; + grid-template-columns: repeat(5, 1fr); + grid-column: 1 / -1; } + .grid-cell { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + } + + // 图标行 .icons-row { - margin-bottom: 1.6rem; + align-items: center; + height: 6.4rem; position: relative; z-index: 2; - .point-icon { - width: 6.4rem; - height: 6.4rem; - display: block; - margin: 0 auto; - z-index: 2; - } + margin-bottom: 1.6rem; + .timeline-line { - width: calc(100% + 22rem + 21.2rem); + position: absolute; + top: 50%; left: -22rem; + right: -21.2rem; height: 0.15rem; background: linear-gradient( 90deg, @@ -293,40 +287,78 @@ rgba(199, 52, 44, 0.762376) 75.96%, rgba(199, 52, 44, 0) 100% ); - position: absolute; - bottom: 50%; transform: translateY(-50%); z-index: 1; + pointer-events: none; + } + + .icon-cell { + position: relative; + .point-icon { + width: 6.4rem; + height: 6.4rem; + display: block; + position: relative; + z-index: 2; + } } } + // 标签行 + .labels-row { + margin-bottom: 8rem; + position: relative; + z-index: 2; + .label-cell { + flex-direction: column; + color: #fff; + font-family: 'PoppinsBold'; + font-weight: 600; + font-size: 2.8rem; + white-space: pre-line; + justify-content: center; + min-height: 6rem; + + // .sub-label { + // font-family: 'Arial'; + // font-weight: 400; + // font-size: 1.4rem; + // color: rgba(255, 255, 255, 0.8); + // margin-top: 0.4rem; + // } + } + } + + // 时间行 .times-row { margin-bottom: 6rem; z-index: 2; position: relative; - .item-time { - flex: 1; + .time-cell { color: #f95750; font-family: 'Arial'; font-weight: 400; font-size: 2.8rem; line-height: 4.5rem; - text-align: center; } } + // 描述行 .descs-row { - .item-desc { - flex: 1; + .desc-cell { .txt { font-family: 'Arial'; font-weight: 400; font-size: 2rem; text-align: center; color: #e0e0e0; - width: 31.2rem; - height: 10.2rem; + width: 100%; + max-width: 31.2rem; + min-height: 10.2rem; white-space: pre-line; + display: flex; + align-items: center; + justify-content: center; } } } diff --git a/src/views/AwardPage/index.vue b/src/views/AwardPage/index.vue index d430e30b..92327a6a 100644 --- a/src/views/AwardPage/index.vue +++ b/src/views/AwardPage/index.vue @@ -63,7 +63,7 @@ height: 2.4rem; } .banner { - height: 108rem; + height: 100rem; // background: url('@/assets/images/award/banner.png') no-repeat; // background-size: cover; position: relative;