caiyunyi/pages/eventRegistration/registration.vue
2025-10-21 18:44:42 +08:00

742 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>