caiyunyi/pages/eventRegistration/registration.vue
ylj20011123 35e40eb558 update
2026-02-28 18:25:12 +08:00

982 lines
31 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">
<!-- 活动基本信息 -->
<div class="event-header" v-if="eventInfo.ACTIVITY_ID">
<div class="event-name">{{ eventInfo.ACTIVITY_NAME }}</div>
<div class="event-meta">
<div class="meta-item">
<span class="meta-icon">📅</span>
<span class="meta-text">{{ eventInfo.ACTIVITY_STARTDATE ? eventInfo.ACTIVITY_STARTDATE : ""
}}{{ eventInfo.ACTIVITY_ENDDATE ? `-` + eventInfo.ACTIVITY_ENDDATE : "" }}</span>
</div>
<div class="meta-item">
<span class="meta-icon">📍</span>
<span class="meta-text">{{ eventInfo.ACTIVITY_LOCATION }}</span>
</div>
<div class="meta-item">
<span class="meta-icon">👥</span>
<span class="meta-text">{{ eventInfo.MAXIMUM_CAPACITY ? '限' + eventInfo.MAXIMUM_CAPACITY : '不限' }}人</span>
</div>
</div>
</div>
<!-- 活动封面 -->
<div class="event-cover" v-if="eventInfo.ACTIVITY_ID">
<swiper>
<swiper-item v-for="(item, imgIndex) in eventInfo.ImageList" :key="imgIndex">
<image class="cover-image" :src="item.ImageUrl" mode="aspectFill" />
</swiper-item>
</swiper>
</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.company" placeholder="请输入您的工作单位/公司" />
</div>
<!-- 性别 -->
<div class="form-item">
<div class="item-label">性别</div>
<picker @change="onGenderChange" :value="genderIndex" :range="genderOptions" range-key="label">
<div class="item-input picker-input">
<span :class="{ 'placeholder-text': !formData.gender }">
{{ genderOptions[genderIndex].label || '请选择您的性别' }}
</span>
<span class="arrow-icon"></span>
</div>
</picker>
</div>
<!-- 年龄 -->
<div class="form-item">
<div class="item-label">年龄</div>
<input class="item-input" v-model="formData.age" type="number" placeholder="请输入您的年龄" maxlength="3" />
</div>
<!-- 参与人数 -->
<div class="form-item">
<div class="item-label">参与人数</div>
<input class="item-input" v-model="formData.participantCount" type="number" placeholder="请输入参与人数" />
</div>
<!-- 可能存在的套餐内容 -->
<div class="form-item">
<div class="item-label">选择套餐</div>
<picker @change="onPackageChange" :value="selectPackage" :range="packageList" range-key="label">
<div class="item-input picker-input">
<span>
{{ packageList[selectPackage].label || '请选择套餐' }}
</span>
<span class="arrow-icon"></span>
</div>
</picker>
</div>
<!-- 可能存在的 额外人数 -->
<div class="form-item">
<div class="item-label">额外人数</div>
<input class="item-input" v-model="formData.extraCount" type="number" 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>
import { mapGetters } from "vuex";
export default {
data() {
return {
eventId: "",
mode: "register", // register: 报名, view: 查看报名信息
eventInfo: {},
formData: {
participantName: "", // 报名人姓名
phoneNumber: "", // 手机号码
company: "", // 单位
gender: "", // 性别
age: "", // 年龄
participantCount: "", // 参与人数
extraCount: "",// 额外人数
remarks: "", // 备注信息
agreement: false // 是否同意条款
},
genderIndex: -1,
genderOptions: [{ label: "男", value: 1 }, { label: "女", value: 2 }, { label: "保密", value: 0 }],
showTermsModal: false,
defaultCover: 'https://picsum.photos/seed/event-registration/400/300.jpg',
selectPackage: -1,//选择的活动套餐
packageList: [],
};
},
computed: {
...mapGetters({
user: "user",
}),
},
onLoad(query) {
if (query.eventId) {
this.eventId = query.eventId;
}
if (query.mode) {
this.mode = query.mode;
}
this.loadEventInfo();
},
methods: {
// 加载活动信息
async loadEventInfo() {
const req = {
ACTIVITYId: this.eventId,
type: 'encryption'
}
uni.showLoading({
title: '加载中...',
mask: true
});
const data = await this.$api.$posMemberPost("/Member/GetACTIVITYDetail", req)
uni.hideLoading();
let detail = data.Result_Data
console.log('详情djaksjda', detail);
if (detail.PACKAGE_RULE_JSON) {
let jsonObj = JSON.parse(detail.PACKAGE_RULE_JSON)
console.log('jsonObj', jsonObj);
let list = []
if (jsonObj.packages && jsonObj.packages.length > 0) {
jsonObj.packages.forEach((item) => {
list.push({
label: item.name,
value: item.code
})
})
}
this.packageList = list
}
this.eventInfo = detail;
},
// 切换同意条款状态
toggleAgreement() {
this.formData.agreement = !this.formData.agreement;
},
// 性别变更
onGenderChange(e) {
this.genderIndex = Number(e.detail.value);
this.formData.gender = this.genderOptions[this.genderIndex].value;
},
onPackageChange(e) {
this.selectPackage = Number(e.detail.value);
},
// 显示条款
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.agreement) {
uni.showToast({
title: "请阅读并同意活动参与条款",
icon: "none",
});
return false;
}
if (this.packageList && this.packageList.length > 0) {
if (this.selectPackage === -1) {
uni.showToast({
title: "请选择套餐",
icon: "none",
});
return false;
}
}
return true;
},
// 提交报名
async handleSubmit() {
if (!this.validateForm()) {
return;
}
if (this.mode === 'view') {
uni.showToast({
title: '这是查看模式,无法修改',
icon: 'none'
});
return;
}
// 准备提交数据
const submitData = {
eventId: this.eventId,
...this.formData
};
// 如果是3000类型的活动 来这里付钱 不然的话 就跟原本一样 正常报名
if (Number(this.eventInfo.ACTIVITY_TYPE) === 3000) {
let currentShopInfo = this.eventInfo.PackageRule.packages[this.selectPackage]
// 判断一下 最小总人数 + 额外人数 是否 小于等于最大人数
if (currentShopInfo.min_total_person + Number(this.formData.extraCount) > currentShopInfo.max_total_person) {
uni.showToast({
title: "抱歉,当前套餐已达最大人数,请选择其他套餐",
icon: "none",
});
return
}
}
const req = {
ACTIVITY_ID: this.eventId,
MEMBERSHIP_ID: this.user.MEMBERSHIP_ID,
MEMBERSHIP_NAME: submitData.participantName,
MEMBERSHIP_MOBILEPHONE: submitData.phoneNumber,
MEMBERSHIP_UNIT: submitData.company,
MEMBERSHIP_GENDER: submitData.gender,
MEMBERSHIP_AGE: submitData.age,
MEMBERSHIP_COUNT: submitData.participantCount,
PACKAGE_CODE: this.packageList[this.selectPackage].value,//选择的套餐name 即value
PACKAGE_NAME: this.packageList[this.selectPackage].label,//选择的套餐code 即label
ACTIVITYDETAIL_DESC: submitData.remarks,
ACTIVITYDETAIL_STATE: Number(this.eventInfo.ACTIVITY_TYPE) === 3000 ? 2 : 1,
STAFF_ID: this.user.MEMBERSHIP_ID,
STAFF_NAME: this.user.MEMBERSHIP_NAME,
OPERATE_DATE: this.$moment.now().format("YYYY-MM-DD HH:mm:ss"),
type: 'encryption'
}
console.log('reqrqe', req);
uni.showLoading({
title: "提交中...",
mask: true,
});
const data = await this.$api.$posMemberPost("/Member/SynchroACTIVITYDETAIL", req)
uni.hideLoading();
console.log('报名结果', data);
if (data.Result_Code === 100) {
if (Number(this.eventInfo.ACTIVITY_TYPE) === 3000) {
// 报名成功之后去付钱
this.createOrder(data.Result_Data.ACTIVITYDETAIL_ID)
} else {
uni.showModal({
title: "报名成功",
content: "您已成功报名该活动,请按时参加!",
showCancel: false,
success: (res) => {
if (res.confirm) {
uni.navigateBack();
}
},
});
}
} else {
uni.showToast({
title: data.Result_Desc,
icon: 'none'
})
}
},
// 实际报名付款的方法
async createOrder(CDK) {
// CDK 报名成功之后 那条记录的id
console.log('selectPackage', this.selectPackage);
console.log('eventInfoeventInfoeventInfo', JSON.parse(JSON.stringify(this.eventInfo)));
// 拿到当前选择了的套餐商品信息
let currentShopInfo = this.eventInfo.PackageRule.packages[this.selectPackage]
console.log('当前选择了的套餐商品信息', currentShopInfo);
// 拿到当前选择的实际商品信息
let currentSelectShop = this.eventInfo.CommodityList[this.selectPackage]
console.log('拿到当前选择的实际商品信息', currentShopInfo);
// 再去拿额外一个人要付多少钱
let extraPrice = this.eventInfo.PackageRule.extra_person_price
console.log('额外一个人要付多少钱', extraPrice);
// 判断一下 最小总人数 + 额外人数 是否 小于等于最大人数
if (currentShopInfo.min_total_person + Number(this.formData.extraCount) > currentShopInfo.max_total_person) {
uni.showToast({
title: "抱歉,当前套餐已达最大人数,请选择其他套餐",
icon: "none",
});
return
}
// 计算总价
let totalPrice = Number(currentShopInfo.price) + Number(this.eventInfo.PackageRule.extra_person_price) * Number(this.formData.extraCount)
console.log('总价', totalPrice);
// 创建订单 需要的商品信息
let t_saleorderdetail = []
t_saleorderdetail.push({
COMMODITY_ID: currentSelectShop.COMMODITY_ID ? currentSelectShop.COMMODITY_ID.toString() : "",
COMMODITY_NAME: currentSelectShop.COMMODITY_NAME ? currentSelectShop.COMMODITY_NAME.toString() : "",
COMMODITY_CODE: currentSelectShop.COMMODITY_CODE ? currentSelectShop.COMMODITY_CODE.toString() : "",
COMMODITY_BARCODE: currentSelectShop.COMMODITY_BARCODE ? currentSelectShop.COMMODITY_BARCODE.toString() : "",
ISMULTI: "",
COMMODITY_UNIT: currentSelectShop.COMMODITY_UNIT ? currentSelectShop.COMMODITY_UNIT.toString() : "",
COMMODITY_RULE: currentSelectShop.COMMODITY_RULE ? currentSelectShop.COMMODITY_RULE.toString() : "",
COMMODITY_RETAILPRICE: currentSelectShop.COMMODITY_RETAILPRICE ? currentSelectShop.COMMODITY_RETAILPRICE.toString() : "",
COMMODITY_PURCHASEPRICE: currentSelectShop.COMMODITY_PURCHASEPRICE ? currentSelectShop.COMMODITY_PURCHASEPRICE.toString() : "",
COMMODITY_MEMBERPRICE: currentSelectShop.COMMODITY_MEMBERPRICE ? currentSelectShop.COMMODITY_MEMBERPRICE.toString() : "",
VIDEOCARD_CDK: CDK,// 报名成功之后才有
COMMODITY_CURRPRICE: currentSelectShop.COMMODITY_MEMBERPRICE ? currentSelectShop.COMMODITY_MEMBERPRICE.toString() : "",
AVERAGE_PRICE: currentSelectShop.COMMODITY_MEMBERPRICE ? currentSelectShop.COMMODITY_MEMBERPRICE.toString() : "",
COMMODITY_STOCK: currentSelectShop.COMMODITY_STOCK ? currentSelectShop.COMMODITY_STOCK.toString() : "",
COMMODITY_STATE: currentSelectShop.COMMODITY_STATE ? currentSelectShop.COMMODITY_STATE.toString() : "",
COMMODITY_DESC: currentSelectShop.COMMODITY_DESC ? currentSelectShop.COMMODITY_DESC.toString() : "",
SCANCODE_ORDER: currentSelectShop.SCANCODE_ORDER ? currentSelectShop.SCANCODE_ORDER.toString() : "",
DUTY_PARAGRAPH: currentSelectShop.DUTY_PARAGRAPH ? currentSelectShop.DUTY_PARAGRAPH.toString() : "",
ORDER_COUNT: 1, // 因为一个活动报名 只能买一个 所以写死1 那么下面的订单金额 也就只用显示单价即可
ORDER_AMOUNT: currentSelectShop.COMMODITY_MEMBERPRICE ? currentSelectShop.COMMODITY_MEMBERPRICE.toString() : "",
// RTCOMMODITY_MULTI_ID: "",
SALEDETAIL_DESC: ""
});
// 这里再加个判断 判断有没有输入额外人数 有的话 再push 额外商品的信息 没有的话 就不push了
if (Number(this.formData.extraCount) > 0) {
// 拿到套餐商品里面的其他商品
let otherShopDetail = this.eventInfo.CommodityList.find((item) => Number(item.COMMODITY_TYPE) === 4011)
console.log('拿到套餐商品里面的其他商品', otherShopDetail);
t_saleorderdetail.push({
COMMODITY_ID: otherShopDetail.COMMODITY_ID ? otherShopDetail.COMMODITY_ID.toString() : "",
COMMODITY_NAME: otherShopDetail.COMMODITY_NAME ? otherShopDetail.COMMODITY_NAME.toString() : "",
COMMODITY_CODE: otherShopDetail.COMMODITY_CODE ? otherShopDetail.COMMODITY_CODE.toString() : "",
COMMODITY_BARCODE: otherShopDetail.COMMODITY_BARCODE ? otherShopDetail.COMMODITY_BARCODE.toString() : "",
ISMULTI: "",
COMMODITY_UNIT: otherShopDetail.COMMODITY_UNIT ? otherShopDetail.COMMODITY_UNIT.toString() : "",
COMMODITY_RULE: otherShopDetail.COMMODITY_RULE ? otherShopDetail.COMMODITY_RULE.toString() : "",
COMMODITY_RETAILPRICE: otherShopDetail.COMMODITY_RETAILPRICE ? otherShopDetail.COMMODITY_RETAILPRICE.toString() : "",
COMMODITY_PURCHASEPRICE: otherShopDetail.COMMODITY_PURCHASEPRICE ? otherShopDetail.COMMODITY_PURCHASEPRICE.toString() : "",
COMMODITY_MEMBERPRICE: otherShopDetail.COMMODITY_MEMBERPRICE ? otherShopDetail.COMMODITY_MEMBERPRICE.toString() : "",
VIDEOCARD_CDK: CDK,// 报名成功之后才有
COMMODITY_CURRPRICE: otherShopDetail.COMMODITY_MEMBERPRICE ? otherShopDetail.COMMODITY_MEMBERPRICE.toString() : "",
AVERAGE_PRICE: otherShopDetail.COMMODITY_MEMBERPRICE ? otherShopDetail.COMMODITY_MEMBERPRICE.toString() : "",
COMMODITY_STOCK: otherShopDetail.COMMODITY_STOCK ? otherShopDetail.COMMODITY_STOCK.toString() : "",
COMMODITY_STATE: otherShopDetail.COMMODITY_STATE ? otherShopDetail.COMMODITY_STATE.toString() : "",
COMMODITY_DESC: otherShopDetail.COMMODITY_DESC ? otherShopDetail.COMMODITY_DESC.toString() : "",
SCANCODE_ORDER: otherShopDetail.SCANCODE_ORDER ? otherShopDetail.SCANCODE_ORDER.toString() : "",
DUTY_PARAGRAPH: otherShopDetail.DUTY_PARAGRAPH ? otherShopDetail.DUTY_PARAGRAPH.toString() : "",
ORDER_COUNT: Number(this.formData.extraCount), // 因为一个活动报名 只能买一个 所以写死1 那么下面的订单金额 也就只用显示单价即可
ORDER_AMOUNT: (Number(this.formData.extraCount) * Number(otherShopDetail.COMMODITY_MEMBERPRICE)).toFixed(2),
// RTCOMMODITY_MULTI_ID: "",
SALEDETAIL_DESC: ""
});
}
let openId = uni.getStorageSync("openId");
const app = getApp();
let req = {
action_type: "ScanOrder",
salebillType: "3000",
provinceCode: this.user.PROVINCE_CODE || "530000",
serverpartShopId: "5634",
takeType: 3000, // 1000 自提 邮寄
salebillDesc: "",
wechatOpenId: openId || "",
wechatUnionId: this.user.USER_UNIONID || "",
addressId: "",
orderPersonTel: this.formData.phoneNumber,//手机号
t_saleorderdetail: JSON.stringify(t_saleorderdetail),
recommendCode: app.globalData.recommendCode || "",
recommendId: app.globalData.recommendId || "",
requestType: "application/x-www-form-urlencoded",
// testPay: testPay
};
console.log('reqreqreq', req);
const data = await this.$api.postCoop(req);
console.log('创建的订单', data);
if (data.ResultCode === "100") {
// 订单创建成功之后 调用支付接口
this.getOrderInfo(data.Data, data.Data.PAY_AMOUNT);
} else {
uni.showModal({
title: "提示",
content: data.ResultDesc,
success: function (res) { },
});
}
},
// 调用支付接口
async getOrderInfo(obj, amount) {
let _this = this;
// 拿到签名
let mchid = "1672298991";
let timeStamp = Math.ceil(new Date().getTime() / 1000);
let nonceStr = Math.random().toString(36).substring(2, 8);
let serial_no = "5BA7C0F427FC042DB5BF299E35B373D5EFCECD35";
// let out_trade_no = this.generateOutTradeNo(32)
let out_trade_no = obj.SALEBILL_CODE;
let req = {
appid: "wxee018fb96955552a", // 公众账号ID
mchid: "1672298991", // 商户号
description: "彩云驿出行", //商品描述
out_trade_no: out_trade_no, // 商户订单号
notify_url:
"https://eshangtech.com:18998/Coop.Merchant/Handler/Handler_Trade.ashx", // 商户回调地址
amount: {
total: amount ? Math.round(parseFloat(Number(amount)) * 100) : 1,
currency: "CNY",
}, // 订单金额
payer: {
openid: _this.user.WECHATAPP_OPENID,
}, // 支付者信息
};
let reqSign = {
parameters:
"POST\n/v3/pay/transactions/jsapi\n" +
timeStamp +
"\n" +
nonceStr +
"\n" +
JSON.stringify(req) +
"\n",
provinceCode: _this.provinceCode || "530000",
};
const data = await this.$api.$get("/WeChat/GenerateSign", reqSign);
let Authorization = `mchid="${mchid}",nonce_str="${nonceStr}",signature="${data.Result_Data}",timestamp="${timeStamp}",serial_no="${serial_no}"`;
let AuthorizationStr = `WECHATPAY2-SHA256-RSA2048 ${Authorization}`;
uni.request({
url: "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi", //仅为示例,并非真实接口地址。
method: "POST",
data: req,
header: {
Authorization: AuthorizationStr,
Accept: "application/json", //自定义请求头信息
"Content-Type": "application/json",
},
success: async (res) => {
_this.text = "request success";
let paySign = "";
let reqSign = {
parameters:
"wxee018fb96955552a\n" +
timeStamp +
"\n" +
nonceStr +
"\nprepay_id=" +
res.data.prepay_id +
"\n",
};
const data = await _this.$api.$get("/WeChat/GenerateSign", reqSign);
paySign = data.Result_Data;
wx.requestPayment({
timeStamp: timeStamp.toString(),
nonceStr: nonceStr,
package: `prepay_id=${res.data.prepay_id}`,
signType: "RSA",
paySign: paySign,
total_fee: amount ? Math.round(parseFloat(Number(amount)) * 100) : 1,
success(res) {
},
fail(res) {
},
complete(res) {
_this.isMakeOrdering = false;
uni.redirectTo({
url: `/pages/order/orderdetail/index?orderInternal=${obj.SALEBILL_ID}`,
});
},
});
},
});
}
}
};
</script>
<style scoped lang="less">
.registration-page {
width: 100vw;
min-height: 100vh;
background: #f8fafc;
overflow-y: scroll;
.event-header {
background: white;
margin: 32rpx 32rpx;
padding: 32rpx;
border-radius: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
.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;
}
}
}
}
.event-cover {
position: relative;
width: calc(100% - 64rpx);
height: 300rpx;
margin: 0 32rpx 32rpx;
border-radius: 24rpx;
overflow: hidden;
.cover-image {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.form-section {
padding: 40rpx 32rpx 24rpx;
background: white;
margin: 0 32rpx 0;
border-radius: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
margin-bottom: calc(160rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
.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;
}
}
.picker-input {
display: flex;
align-items: center;
justify-content: space-between;
line-height: 66rpx;
.placeholder-text {
color: #9ca3af;
}
.arrow-icon {
font-size: 20rpx;
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: #fff;
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;
height: 40rpx;
&.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: linear-gradient(135deg, #22c55e, #16a34a);
color: white;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
text-align: center;
box-sizing: border-box;
}
}
}
}
}
.registration-page::-webkit-scrollbar {
display: none;
}
</style>