OL-LearnPlatform/src/views/ActivityRegistration.vue

586 lines
13 KiB
Vue
Raw Normal View History

2025-08-01 01:22:09 +08:00
<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">
2025-08-04 02:13:12 +08:00
<div class="banner-image-container">
<img
src="/images/activity/活动报名-切图.png"
alt="活动横幅"
class="banner-image"
/>
2025-08-01 01:22:09 +08:00
</div>
</div>
<!-- 报名表单区域 -->
<div class="registration-form-container">
<div class="container">
<div class="form-section">
<div class="form-header">
<h3 class="form-title">📋 填写信息</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="email"
v-model="formData.email"
class="form-input"
placeholder="请输入邮箱"
required
/>
</div>
<!-- 手机 -->
<div class="form-group">
<label class="form-label required">*手机</label>
<input
type="tel"
v-model="formData.phone"
class="form-input"
placeholder="请输入手机号"
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="text"
v-model="formData.className"
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">附件</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">📎</div>
<p class="upload-text">点击上传文件或拖拽文件到此处</p>
<p class="upload-hint">支持 PDFWord图片格式</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: '',
email: '',
phone: '',
verificationCode: '',
className: '',
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: #f5f5f5;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 面包屑导航 */
.breadcrumb-container {
background: white;
padding: 10px 0;
border-bottom: 1px solid #e0e0e0;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
}
.breadcrumb-item {
color: #1890ff;
text-decoration: none;
}
.breadcrumb-separator {
color: #999;
}
.breadcrumb-current {
color: #333;
}
/* 活动横幅区域 */
.hero-banner {
2025-08-04 02:13:12 +08:00
width: 100%;
2025-08-01 01:22:09 +08:00
position: relative;
overflow: hidden;
}
2025-08-04 02:13:12 +08:00
.banner-image-container {
width: 100%;
height: 400px;
position: relative;
2025-08-01 01:22:09 +08:00
display: flex;
align-items: center;
2025-08-04 02:13:12 +08:00
justify-content: center;
2025-08-01 01:22:09 +08:00
}
2025-08-04 02:13:12 +08:00
.banner-image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
2025-08-01 01:22:09 +08:00
}
.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;
background: #f5f5f5;
}
.form-section {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
}
.form-header {
background: #f8f9fa;
padding: 20px 30px;
border-bottom: 1px solid #e9ecef;
}
.form-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0;
}
.registration-form {
padding: 30px;
}
.form-group {
margin-bottom: 24px;
}
.form-label {
display: block;
font-size: 14px;
color: #333;
margin-bottom: 8px;
font-weight: 500;
}
.form-label.required {
color: #333;
}
.form-label.required::before {
content: '*';
color: #ff4d4f;
margin-right: 4px;
}
.form-input {
width: 100%;
height: 40px;
padding: 0 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
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;
}
.input-group .form-input {
flex: 1;
}
.verify-btn {
background: #1890ff;
color: white;
border: none;
padding: 0 16px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
white-space: nowrap;
transition: background-color 0.3s;
}
.verify-btn:hover:not(:disabled) {
background: #40a9ff;
}
.verify-btn:disabled {
background: #d9d9d9;
cursor: not-allowed;
}
.form-select {
width: 100%;
height: 40px;
padding: 0 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
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 {
border: 2px dashed #d9d9d9;
border-radius: 4px;
padding: 20px;
text-align: center;
transition: border-color 0.3s;
cursor: pointer;
}
.file-upload-area:hover {
border-color: #1890ff;
}
.file-input {
display: none;
}
.upload-placeholder {
color: #666;
}
.upload-icon {
font-size: 24px;
margin-bottom: 10px;
}
.upload-text {
font-size: 14px;
margin-bottom: 5px;
}
.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;
}
/* 提交按钮 */
.form-actions {
text-align: center;
margin-top: 30px;
}
.submit-btn {
background: #1890ff;
color: white;
border: none;
padding: 12px 40px;
border-radius: 4px;
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>