742 lines
18 KiB
Vue
742 lines
18 KiB
Vue
<template>
|
||
<div class="registration-page" :style="{ paddingBottom: `${safeHeight}px` }">
|
||
<!-- 页面标题 -->
|
||
<div class="page-header">
|
||
<div class="header-title">活动报名</div>
|
||
<div class="header-subtitle">请填写以下信息完成报名</div>
|
||
</div>
|
||
|
||
<!-- 活动信息卡片 -->
|
||
<div class="event-info-card" v-if="eventInfo.id">
|
||
<div class="event-cover">
|
||
<image class="cover-image" :src="eventInfo.coverImage || defaultCover" mode="aspectFill" />
|
||
</div>
|
||
<div class="event-summary">
|
||
<div class="event-name">{{ eventInfo.eventName }}</div>
|
||
<div class="event-meta">
|
||
<div class="meta-item">
|
||
<span class="meta-icon">📅</span>
|
||
<span class="meta-text">{{ formatDateTime(eventInfo.eventTime) }}</span>
|
||
</div>
|
||
<div class="meta-item">
|
||
<span class="meta-icon">📍</span>
|
||
<span class="meta-text">{{ eventInfo.eventLocation }}</span>
|
||
</div>
|
||
<div class="meta-item">
|
||
<span class="meta-icon">👥</span>
|
||
<span class="meta-text">限{{ eventInfo.maxParticipants }}人</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 报名表单 -->
|
||
<div class="form-section">
|
||
<!-- 报名人姓名 -->
|
||
<div class="form-item">
|
||
<div class="item-label">
|
||
<span class="required">*</span>
|
||
报名人姓名
|
||
</div>
|
||
<input class="item-input" v-model="formData.participantName" placeholder="请输入您的真实姓名" />
|
||
</div>
|
||
|
||
<!-- 手机号码 -->
|
||
<div class="form-item">
|
||
<div class="item-label">
|
||
<span class="required">*</span>
|
||
手机号码
|
||
</div>
|
||
<input class="item-input" v-model="formData.phoneNumber" type="number" placeholder="请输入手机号码" maxlength="11" />
|
||
</div>
|
||
|
||
<!-- 邮箱地址 -->
|
||
<div class="form-item">
|
||
<div class="item-label">邮箱地址</div>
|
||
<input class="item-input" v-model="formData.email" placeholder="请输入邮箱地址" />
|
||
</div>
|
||
|
||
<!-- 身份证号 -->
|
||
<div class="form-item">
|
||
<div class="item-label">
|
||
<span class="required">*</span>
|
||
身份证号
|
||
</div>
|
||
<input class="item-input" v-model="formData.idCard" placeholder="请输入身份证号码" maxlength="18" />
|
||
</div>
|
||
|
||
<!-- 联系地址 -->
|
||
<div class="form-item">
|
||
<div class="item-label">
|
||
<span class="required">*</span>
|
||
联系地址
|
||
</div>
|
||
<input class="item-input" v-model="formData.address" placeholder="请输入详细联系地址" />
|
||
</div>
|
||
|
||
<!-- 备注信息 -->
|
||
<div class="form-item">
|
||
<div class="item-label">备注信息</div>
|
||
<textarea class="item-textarea" v-model="formData.remarks" placeholder="如有特殊需求请在此填写" :maxlength="500" />
|
||
</div>
|
||
|
||
<!-- 同意条款 -->
|
||
<div class="agreement-section">
|
||
<div class="agreement-item">
|
||
<div class="checkbox-wrapper" @click="toggleAgreement">
|
||
<div class="checkbox" :class="{ checked: formData.agreement }">
|
||
<div class="check-icon" v-if="formData.agreement">✓</div>
|
||
</div>
|
||
</div>
|
||
<span class="agreement-text">
|
||
我已阅读并同意
|
||
<text class="agreement-link" @click="showTerms">《活动参与条款》</text>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 提交按钮 -->
|
||
<div class="action-section">
|
||
<div class="action-btn" :class="[
|
||
mode === 'view' ? 'action-disabled' : 'primary-btn'
|
||
]" @click="handleSubmit">
|
||
<span class="btn-text">提交报名</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 条款弹窗 -->
|
||
<div class="terms-modal" v-if="showTermsModal" @click="hideTerms">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<div class="modal-title">活动参与条款</div>
|
||
<div class="close-btn" @click="hideTerms">×</div>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="terms-content">
|
||
<div class="terms-section">
|
||
<div class="section-title">1. 报名须知</div>
|
||
<div class="section-content">
|
||
• 请确保填写信息真实有效<br>
|
||
• 每人限报名一个活动<br>
|
||
• 报名成功后请按时参加<br>
|
||
• 如需取消报名,请提前24小时联系客服
|
||
</div>
|
||
</div>
|
||
<div class="terms-section">
|
||
<div class="section-title">2. 参与要求</div>
|
||
<div class="section-content">
|
||
• 请携带有效身份证件<br>
|
||
• 遵守现场秩序和工作人员指引<br>
|
||
• 保管好个人财物<br>
|
||
• 禁止携带危险物品入场
|
||
</div>
|
||
</div>
|
||
<div class="terms-section">
|
||
<div class="section-title">3. 免责声明</div>
|
||
<div class="section-content">
|
||
• 参与活动期间,请自行注意人身安全<br>
|
||
• 主办方对意外伤害不承担责任<br>
|
||
• 如遇不可抗力因素,活动可能调整或取消<br>
|
||
• 参与者表示同意上述条款
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<div class="modal-btn" @click="hideTerms">我知道了</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
safeHeight: "",
|
||
eventId: "",
|
||
mode: "register", // register: 报名, view: 查看报名信息
|
||
eventInfo: {},
|
||
formData: {
|
||
participantName: "", // 报名人姓名
|
||
phoneNumber: "", // 手机号码
|
||
email: "", // 邮箱地址
|
||
idCard: "", // 身份证号
|
||
address: "", // 联系地址
|
||
remarks: "", // 备注信息
|
||
agreement: false // 是否同意条款
|
||
},
|
||
showTermsModal: false,
|
||
defaultCover: 'https://picsum.photos/seed/event-registration/400/300.jpg'
|
||
};
|
||
},
|
||
onLoad(query) {
|
||
let systemInfo = uni.getSystemInfoSync();
|
||
let height = systemInfo.safeAreaInsets.bottom;
|
||
this.safeHeight = Number(height);
|
||
|
||
if (query.eventId) {
|
||
this.eventId = query.eventId;
|
||
}
|
||
|
||
if (query.mode) {
|
||
this.mode = query.mode;
|
||
}
|
||
|
||
this.loadEventInfo();
|
||
},
|
||
methods: {
|
||
// 加载活动信息
|
||
async loadEventInfo() {
|
||
try {
|
||
// 这里调用实际接口获取活动信息
|
||
// const res = await this.$api.getEventInfo({
|
||
// eventId: this.eventId
|
||
// });
|
||
|
||
// 模拟数据
|
||
const mockData = {
|
||
id: this.eventId,
|
||
eventName: "春季音乐节",
|
||
eventLocation: "昆明市中心广场露天舞台",
|
||
eventTime: "2024-03-15 19:00:00",
|
||
maxParticipants: 500,
|
||
coverImage: "https://picsum.photos/seed/music-festival-registration/400/300.jpg"
|
||
};
|
||
|
||
this.eventInfo = mockData;
|
||
|
||
// 如果是查看模式,加载已报名信息
|
||
if (this.mode === 'view') {
|
||
this.loadRegistrationInfo();
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('加载活动信息失败:', error);
|
||
uni.showToast({
|
||
title: '加载失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
|
||
// 加载已报名信息
|
||
async loadRegistrationInfo() {
|
||
try {
|
||
// 这里调用接口获取用户的报名信息
|
||
// const res = await this.$api.getRegistrationInfo({
|
||
// eventId: this.eventId
|
||
// });
|
||
|
||
// 模拟已报名数据
|
||
this.formData = {
|
||
participantName: "张三",
|
||
phoneNumber: "13800138000",
|
||
email: "zhangsan@example.com",
|
||
idCard: "530102199001011234",
|
||
address: "云南省昆明市五华区xxx街道xxx号",
|
||
remarks: "需要特殊座位安排",
|
||
agreement: true
|
||
};
|
||
|
||
} catch (error) {
|
||
console.error('加载报名信息失败:', error);
|
||
}
|
||
},
|
||
|
||
// 切换同意条款状态
|
||
toggleAgreement() {
|
||
this.formData.agreement = !this.formData.agreement;
|
||
},
|
||
|
||
// 显示条款
|
||
showTerms() {
|
||
this.showTermsModal = true;
|
||
},
|
||
|
||
// 隐藏条款
|
||
hideTerms() {
|
||
this.showTermsModal = false;
|
||
},
|
||
|
||
// 格式化日期时间
|
||
formatDateTime(dateTime) {
|
||
if (!dateTime) return '';
|
||
try {
|
||
const date = new Date(dateTime);
|
||
const month = date.getMonth() + 1;
|
||
const day = date.getDate();
|
||
const hours = date.getHours().toString().padStart(2, '0');
|
||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||
return `${month}月${day}日 ${hours}:${minutes}`;
|
||
} catch (error) {
|
||
return dateTime;
|
||
}
|
||
},
|
||
|
||
// 验证表单
|
||
validateForm() {
|
||
if (!this.formData.participantName.trim()) {
|
||
uni.showToast({
|
||
title: "请输入报名人姓名",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!this.formData.phoneNumber.trim()) {
|
||
uni.showToast({
|
||
title: "请输入手机号码",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!/^1[3-9]\d{9}$/.test(this.formData.phoneNumber)) {
|
||
uni.showToast({
|
||
title: "请输入正确的手机号码",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!this.formData.idCard.trim()) {
|
||
uni.showToast({
|
||
title: "请输入身份证号",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))\d{3}[0-9Xx]$/.test(this.formData.idCard)) {
|
||
uni.showToast({
|
||
title: "请输入正确的身份证号",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!this.formData.address.trim()) {
|
||
uni.showToast({
|
||
title: "请输入联系地址",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
if (!this.formData.agreement) {
|
||
uni.showToast({
|
||
title: "请阅读并同意活动参与条款",
|
||
icon: "none",
|
||
});
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
},
|
||
|
||
// 提交报名
|
||
handleSubmit() {
|
||
if (!this.validateForm()) {
|
||
return;
|
||
}
|
||
|
||
if (this.mode === 'view') {
|
||
uni.showToast({
|
||
title: '这是查看模式,无法修改',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: "提交中...",
|
||
mask: true,
|
||
});
|
||
|
||
// 准备提交数据
|
||
const submitData = {
|
||
eventId: this.eventId,
|
||
...this.formData
|
||
};
|
||
|
||
// 调用提交接口
|
||
// this.$api.submitRegistration(submitData)
|
||
// .then(res => {
|
||
// uni.hideLoading();
|
||
// uni.showModal({
|
||
// title: "报名成功",
|
||
// content: "您已成功报名该活动,请按时参加!",
|
||
// showCancel: false,
|
||
// success: () => {
|
||
// uni.navigateBack();
|
||
// }
|
||
// });
|
||
// })
|
||
// .catch(error => {
|
||
// uni.hideLoading();
|
||
// uni.showToast({
|
||
// title: "提交失败,请重试",
|
||
// icon: "none"
|
||
// });
|
||
// });
|
||
|
||
// 模拟提交过程
|
||
setTimeout(() => {
|
||
uni.hideLoading();
|
||
uni.showModal({
|
||
title: "报名成功",
|
||
content: "您已成功报名该活动,请按时参加!\n\n活动信息将发送到您的手机。",
|
||
showCancel: false,
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
uni.navigateBack();
|
||
}
|
||
},
|
||
});
|
||
}, 2000);
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="less">
|
||
.registration-page {
|
||
width: 100vw;
|
||
min-height: 100vh;
|
||
background: #f8fafc;
|
||
overflow-y: scroll;
|
||
|
||
.page-header {
|
||
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||
padding: 60rpx 40rpx 40rpx;
|
||
text-align: center;
|
||
|
||
.header-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: white;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.header-subtitle {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
}
|
||
}
|
||
|
||
.event-info-card {
|
||
background: white;
|
||
margin: -20rpx 32rpx 32rpx;
|
||
border-radius: 24rpx 24rpx;
|
||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
||
overflow: hidden;
|
||
|
||
.event-cover {
|
||
width: 100%;
|
||
height: 300rpx;
|
||
overflow: hidden;
|
||
|
||
.cover-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
}
|
||
|
||
.event-summary {
|
||
padding: 32rpx;
|
||
|
||
.event-name {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #1f2937;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.event-meta {
|
||
.meta-item {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.meta-icon {
|
||
font-size: 24rpx;
|
||
margin-right: 12rpx;
|
||
width: 32rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.meta-text {
|
||
font-size: 24rpx;
|
||
color: #6b7280;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-section {
|
||
padding: 40rpx 32rpx 0;
|
||
background: white;
|
||
margin: 0 32rpx 180rpx;
|
||
border-radius: 24rpx;
|
||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||
|
||
.form-item {
|
||
margin-bottom: 24rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.item-label {
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
font-weight: 500;
|
||
margin-bottom: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.required {
|
||
color: #ef4444;
|
||
margin-right: 4rpx;
|
||
}
|
||
}
|
||
|
||
.item-input {
|
||
width: 100%;
|
||
height: 66rpx;
|
||
padding: 0 24rpx;
|
||
border: 2rpx solid #e5e7eb;
|
||
border-radius: 16rpx;
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
background: #f9fafb;
|
||
box-sizing: border-box;
|
||
|
||
&:focus {
|
||
border-color: #22c55e;
|
||
background: white;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: #9ca3af;
|
||
}
|
||
}
|
||
|
||
.item-textarea {
|
||
width: 100%;
|
||
min-height: 160rpx;
|
||
padding: 20rpx 24rpx;
|
||
border: 2rpx solid #e5e7eb;
|
||
border-radius: 16rpx;
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
background: #f9fafb;
|
||
box-sizing: border-box;
|
||
resize: none;
|
||
|
||
&:focus {
|
||
border-color: #22c55e;
|
||
background: white;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: #9ca3af;
|
||
}
|
||
}
|
||
}
|
||
|
||
.agreement-section {
|
||
.agreement-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
padding: 20rpx;
|
||
|
||
.checkbox-wrapper {
|
||
margin-right: 16rpx;
|
||
padding: 4rpx;
|
||
|
||
.checkbox {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
border: 2rpx solid #d1d5db;
|
||
border-radius: 6rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s ease;
|
||
|
||
&.checked {
|
||
background: #22c55e;
|
||
border-color: #22c55e;
|
||
|
||
.check-icon {
|
||
color: white;
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.agreement-text {
|
||
font-size: 24rpx;
|
||
color: #374151;
|
||
line-height: 1.5;
|
||
|
||
.agreement-link {
|
||
color: #22c55e;
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.action-section {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: white;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
padding: 24rpx 32rpx calc(24rpx + env(safe-area-inset-bottom));
|
||
z-index: 100;
|
||
|
||
.action-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24rpx;
|
||
border-radius: 40rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
border: 2rpx solid #e5e7eb;
|
||
|
||
&.primary-btn {
|
||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||
color: white;
|
||
border-color: #22c55e;
|
||
|
||
&:active {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.btn-text {
|
||
margin-right: 12rpx;
|
||
}
|
||
|
||
.btn-icon {
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.terms-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 24rpx;
|
||
margin: 40rpx;
|
||
width: calc(100% - 80rpx);
|
||
max-height: 80vh;
|
||
overflow: hidden;
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 32rpx;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
|
||
.modal-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #1f2937;
|
||
}
|
||
|
||
.close-btn {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
background: #f3f4f6;
|
||
font-size: 32rpx;
|
||
color: #6b7280;
|
||
}
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 32rpx;
|
||
max-height: 60vh;
|
||
overflow-y: auto;
|
||
|
||
.terms-content {
|
||
.terms-section {
|
||
margin-bottom: 32rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #1f2937;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.section-content {
|
||
font-size: 26rpx;
|
||
color: #6b7280;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 32rpx;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
|
||
.modal-btn {
|
||
width: 100%;
|
||
padding: 24rpx;
|
||
background: #3b82f6;
|
||
color: white;
|
||
border-radius: 16rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.registration-page::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
</style> |