633 lines
14 KiB
Vue
633 lines
14 KiB
Vue
<template>
|
||
<div class="activity-registration-page">
|
||
<!-- 面包屑导航 -->
|
||
<div class="breadcrumb-container">
|
||
<div class="container">
|
||
<nav class="breadcrumb">
|
||
<router-link to="/" class="breadcrumb-item">首页</router-link>
|
||
<span class="breadcrumb-separator">></span>
|
||
<router-link to="/activities" class="breadcrumb-item">活动</router-link>
|
||
<span class="breadcrumb-separator">></span>
|
||
<span class="breadcrumb-current">全国青少年人工智能创新实践活动</span>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 活动横幅区域 -->
|
||
<div class="hero-banner">
|
||
<div class="banner-image-container">
|
||
<img src="/images/activity/活动报名-切图.png" alt="活动横幅" class="banner-image" />
|
||
</div>
|
||
<div class="hero-content">
|
||
<h2>“与AI共创未来”</h2>
|
||
<p class="hero-content-description">2025年全国青少年人工智能创新实践活动</p>
|
||
<div>
|
||
<p>【主办单位】中国科协青少年科技中心、中国青少年科技教育工作者协会、上海人工智能创新中心、上海市科协</p>
|
||
<p>【支持单位】中国公众科学素质促进联合体</p>
|
||
<p>【协办单位】各省级青少年科技教育活动部门单位、上海市科协科学教育中心</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报名表单区域 -->
|
||
<div class="registration-form-container">
|
||
<div class="container">
|
||
<div class="form-section">
|
||
<div class="form-header">
|
||
<h3 class="form-title">
|
||
<img src="/images/activity/fill.png" alt="填写信息" class="form-title-icon" />
|
||
填写信息
|
||
</h3>
|
||
</div>
|
||
|
||
<form class="registration-form" @submit.prevent="handleSubmit">
|
||
<!-- 姓名 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">姓名:</label>
|
||
<input type="text" v-model="formData.name" class="form-input" placeholder="请输入姓名" required />
|
||
</div>
|
||
|
||
<!-- 性别 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">性别:</label>
|
||
<input type="text" v-model="formData.gender" class="form-input" placeholder="请输入性别" required />
|
||
</div>
|
||
|
||
<!-- 年龄 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">年龄:</label>
|
||
<input type="number" v-model="formData.age" class="form-input" placeholder="请输入年龄" min="0" max="120"
|
||
required />
|
||
</div>
|
||
|
||
<!-- 手机号 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">手机号:</label>
|
||
<div class="input-group">
|
||
<input type="tel" v-model="formData.phone" class="form-input" placeholder="请输入手机号" required />
|
||
<button type="button" class="verify-btn" @click="sendVerificationCode" :disabled="countdown > 0">
|
||
{{ countdown > 0 ? `${countdown}s后重试` : '获取验证码' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
<!-- 验证码 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">验证码:</label>
|
||
<input type="text" v-model="formData.verificationCode" class="form-input" placeholder="请输入验证码" required />
|
||
</div>
|
||
|
||
<!-- 邮箱 -->
|
||
<div class="form-group">
|
||
<label class="form-label">邮箱:</label>
|
||
<input type="email" v-model="formData.email" class="form-input" placeholder="请输入邮箱" />
|
||
</div>
|
||
|
||
<!-- 选择参与组别 -->
|
||
<div class="form-group">
|
||
<label class="form-label required">选择活动组别:</label>
|
||
<select v-model="formData.group" class="form-select" required>
|
||
<option value="">请选择组别</option>
|
||
<option value="ai-art">AI艺术创作营</option>
|
||
<option value="ai-interaction">AI交互设计营</option>
|
||
<option value="ai-practice">人工智能实践营</option>
|
||
<option value="ai-algorithm">AI算法挑战营</option>
|
||
<option value="ai-certificate">AI创新数字素养证书</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 附件上传 -->
|
||
<div class="form-group">
|
||
<label class="form-label annex">附件:</label>
|
||
<div class="file-upload-area">
|
||
<input type="file" ref="fileInput" @change="handleFileUpload" multiple class="file-input"
|
||
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png" />
|
||
<div class="upload-placeholder" @click="triggerFileUpload">
|
||
<div class="upload-icon">
|
||
<img src="/images/activity/upload.png" alt="上传" class="upload-icon-img" />
|
||
</div>
|
||
<p class="upload-text">将文件拖到此处,或<span>点击上传</span></p>
|
||
</div>
|
||
<div v-if="uploadedFiles.length > 0" class="uploaded-files">
|
||
<div v-for="(file, index) in uploadedFiles" :key="index" class="file-item">
|
||
<span class="file-name">{{ file.name }}</span>
|
||
<button type="button" @click="removeFile(index)" class="remove-btn">×</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 提交按钮 -->
|
||
<div class="form-actions">
|
||
<button type="submit" class="submit-btn" :disabled="isSubmitting">
|
||
{{ isSubmitting ? '提交中...' : '提交报名信息' }}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
|
||
const router = useRouter()
|
||
|
||
// 表单数据
|
||
const formData = reactive({
|
||
name: '',
|
||
gender: '',
|
||
age: '',
|
||
phone: '',
|
||
verificationCode: '',
|
||
email: '',
|
||
group: 'ai-art' // 默认选择AI艺术创作营
|
||
})
|
||
|
||
// 文件上传
|
||
const fileInput = ref<HTMLInputElement>()
|
||
const uploadedFiles = ref<File[]>([])
|
||
|
||
// 验证码倒计时
|
||
const countdown = ref(0)
|
||
const isSubmitting = ref(false)
|
||
|
||
// 发送验证码
|
||
const sendVerificationCode = async () => {
|
||
if (!formData.phone) {
|
||
alert('请先输入手机号')
|
||
return
|
||
}
|
||
|
||
// 模拟发送验证码
|
||
countdown.value = 60
|
||
const timer = setInterval(() => {
|
||
countdown.value--
|
||
if (countdown.value <= 0) {
|
||
clearInterval(timer)
|
||
}
|
||
}, 1000)
|
||
|
||
alert('验证码已发送到您的手机')
|
||
}
|
||
|
||
// 触发文件上传
|
||
const triggerFileUpload = () => {
|
||
fileInput.value?.click()
|
||
}
|
||
|
||
// 处理文件上传
|
||
const handleFileUpload = (event: Event) => {
|
||
const target = event.target as HTMLInputElement
|
||
if (target.files) {
|
||
const newFiles = Array.from(target.files)
|
||
uploadedFiles.value.push(...newFiles)
|
||
}
|
||
}
|
||
|
||
// 移除文件
|
||
const removeFile = (index: number) => {
|
||
uploadedFiles.value.splice(index, 1)
|
||
}
|
||
|
||
// 提交表单
|
||
const handleSubmit = async () => {
|
||
isSubmitting.value = true
|
||
|
||
try {
|
||
// 模拟提交
|
||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||
|
||
alert('报名成功!我们会尽快与您联系。')
|
||
router.push('/activity/1') // 返回活动详情页
|
||
} catch (error) {
|
||
alert('报名失败,请稍后重试')
|
||
} finally {
|
||
isSubmitting.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.activity-registration-page {
|
||
min-height: 100vh;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.container {
|
||
width: 1420px;
|
||
margin: 0 auto;
|
||
padding: 0;
|
||
}
|
||
|
||
/* 面包屑导航 */
|
||
.breadcrumb-container {
|
||
background: white;
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.breadcrumb-item {
|
||
color: #333;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
color: #999;
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
color: #333;
|
||
}
|
||
|
||
/* 活动横幅区域 */
|
||
.hero-banner {
|
||
margin: auto;
|
||
width: 1420px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hero-content {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
left: 100px;
|
||
}
|
||
|
||
.hero-content h2 {
|
||
font-family: AlimamaShuHeiTi, AlimamaShuHeiTi, '黑体';
|
||
font-weight: bold;
|
||
font-size: 48px;
|
||
color: #FFFFFF;
|
||
line-height: 57px;
|
||
text-align: justify;
|
||
font-style: normal;
|
||
}
|
||
|
||
.hero-content .hero-content-description {
|
||
margin-top: 12px;
|
||
margin-bottom: 40px;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 500;
|
||
font-size: 32px;
|
||
color: #FFFFFF;
|
||
line-height: 45px;
|
||
text-align: justify;
|
||
font-style: normal;
|
||
}
|
||
|
||
.hero-content div p {
|
||
margin-bottom: 2px;
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #FFFFFF;
|
||
line-height: 20px;
|
||
text-align: justify;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
.banner-image-container {
|
||
margin: auto;
|
||
width: 1420px;
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.banner-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
object-position: center;
|
||
}
|
||
|
||
.activity-description {
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.activity-description p {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.banner-illustration {
|
||
flex: 1;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.illustration-placeholder {
|
||
width: 300px;
|
||
height: 200px;
|
||
position: relative;
|
||
}
|
||
|
||
.ai-characters {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200"><defs><linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:rgba(255,255,255,0.2)"/><stop offset="100%" style="stop-color:rgba(255,255,255,0.1)"/></linearGradient></defs><circle cx="80" cy="80" r="30" fill="rgba(255,255,255,0.3)"/><circle cx="220" cy="120" r="25" fill="rgba(255,255,255,0.2)"/><rect x="120" y="60" width="60" height="80" rx="10" fill="url(%23grad1)"/></svg>') center/contain no-repeat;
|
||
}
|
||
|
||
/* 报名表单区域 */
|
||
.registration-form-container {
|
||
padding: 40px 0;
|
||
}
|
||
|
||
.form-section {
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
background: white;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.form-header {}
|
||
|
||
.form-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.form-title-icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.registration-form {
|
||
padding: 30px 220px;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
margin-bottom: 24px;
|
||
gap: 10px;
|
||
}
|
||
|
||
.form-label {
|
||
width: 180px;
|
||
font-size: 16px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.annex {
|
||
align-items: start;
|
||
}
|
||
|
||
.form-label.required {
|
||
color: #333;
|
||
}
|
||
|
||
.form-label.required::before {
|
||
content: '*';
|
||
color: #ff4d4f;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
height: 56px;
|
||
padding: 0 12px;
|
||
border: 1px solid #D8D8D8;
|
||
font-size: 16px;
|
||
transition: border-color 0.3s;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.form-input:focus {
|
||
border-color: #1890ff;
|
||
outline: none;
|
||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
.input-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
width: 100%;
|
||
position: relative;
|
||
}
|
||
|
||
.input-group .form-input {
|
||
flex: 1;
|
||
}
|
||
|
||
.verify-btn {
|
||
position: absolute;
|
||
right: 0;
|
||
top: 25%;
|
||
transform: translateY(-25%);
|
||
background: none;
|
||
color: #0389D1;
|
||
border: none;
|
||
padding: 0 16px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
white-space: nowrap;
|
||
transition: background-color 0.3s;
|
||
height: 56px;
|
||
align-self: flex-start;
|
||
}
|
||
|
||
.verify-btn:hover:not(:disabled) {
|
||
background: #40a9ff;
|
||
color: white;
|
||
}
|
||
|
||
.verify-btn:disabled {
|
||
background: #d9d9d9;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.form-select {
|
||
width: 100%;
|
||
height: 56px;
|
||
padding: 0 12px;
|
||
border: 1px solid #D8D8D8;
|
||
font-size: 16px;
|
||
background: white;
|
||
cursor: pointer;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.form-select:focus {
|
||
border-color: #1890ff;
|
||
outline: none;
|
||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
/* 文件上传区域 */
|
||
.file-upload-area {
|
||
width: 100%;
|
||
height: 210px;
|
||
padding: 40px;
|
||
text-align: center;
|
||
transition: border-color 0.3s;
|
||
cursor: pointer;
|
||
border: 2px dashed #D8D8D8;
|
||
}
|
||
|
||
.file-upload-area:hover {
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
.file-input {
|
||
display: none;
|
||
}
|
||
|
||
.upload-placeholder {
|
||
color: #666;
|
||
}
|
||
|
||
.upload-icon {
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.upload-icon-img {
|
||
width: 128px;
|
||
height: 77px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.upload-text {
|
||
font-size: 16px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.upload-text span {
|
||
color: #0088D1;
|
||
}
|
||
|
||
.upload-hint {
|
||
font-size: 12px;
|
||
color: #999;
|
||
}
|
||
|
||
.uploaded-files {
|
||
margin-top: 15px;
|
||
text-align: left;
|
||
}
|
||
|
||
.file-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 8px 12px;
|
||
background: #f5f5f5;
|
||
border-radius: 4px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
|
||
.remove-btn {
|
||
background: #ff4d4f;
|
||
color: white;
|
||
border: none;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.inline-group {
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
.inline-item {
|
||
flex: 1;
|
||
}
|
||
|
||
/* 提交按钮 */
|
||
.form-actions {
|
||
text-align: center;
|
||
margin-top: 30px;
|
||
}
|
||
|
||
.submit-btn {
|
||
width: 320px;
|
||
height: 48px;
|
||
background: #0389D1;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 30px;
|
||
font-size: 16px;
|
||
cursor: pointer;
|
||
transition: background-color 0.3s;
|
||
min-width: 160px;
|
||
}
|
||
|
||
.submit-btn:hover:not(:disabled) {
|
||
background: #40a9ff;
|
||
}
|
||
|
||
.submit-btn:disabled {
|
||
background: #d9d9d9;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.banner-content {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
}
|
||
|
||
.banner-illustration {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.main-title {
|
||
font-size: 28px;
|
||
}
|
||
|
||
.sub-title {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.registration-form {
|
||
padding: 20px;
|
||
}
|
||
}
|
||
</style>
|