buddhism/pages/activity/application.vue
2025-09-19 11:46:26 +08:00

514 lines
13 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>
<view class="page">
<base-background />
<!-- 使用自定义导航栏组件 -->
<custom-navbar ref="customNavbar" title="活动报名" />
<view :style="{ backgroundColor: CommonEnum.BASE_COLOR }" class="header">
<!-- 页面内容将在这里添加 -->
<text>选择活动日期</text>
<scroll-view class="scroll-view" scroll-x="true">
<view
v-for="(date, index) in dateOptions"
:key="index"
:class="{ selected: selectedDate === date.value }"
class="scroll-view-item_date"
@click="selectDate(date.value)"
>
{{ date.label }}
</view>
</scroll-view>
<text>选择活动时段</text>
<scroll-view class="scroll-view" scroll-x="true">
<view
v-for="(time, index) in timeOptions"
:key="index"
:class="{ selected: selectedTime === time.value }"
class="scroll-view-item_time"
@click="selectTime(time.value)"
>
{{ time.label }}
</view>
</scroll-view>
<text>参与活动人数</text>
<!-- <scroll-view class="scroll-view" scroll-x="true">-->
<scroll-view class="scroll-view">
<view
v-for="(number, index) in numberOptions"
:key="index"
:class="{
selected:
selectedNumber === number.value ||
(number.value === 'custom' &&
!['1', '2'].includes(selectedNumber)),
}"
class="scroll-view-item_number"
@click="selectNumber(number.value)"
>
{{ number.label }}
</view>
</scroll-view>
</view>
<view class="contact">
<view class="contact-item">
<view class="info">姓名</view>
<input v-model="formData.name" placeholder="请输入姓名" type="text" />
</view>
<view class="contact-item">
<view class="info">联系号码</view>
<input v-model="formData.phone" placeholder="填写手机号" type="text" />
</view>
</view>
<view class="submit">
<view class="submit-message"
>{{ getSelectedDateLabel() }}
{{ getSelectedNumberLabel() }}
</view>
<view class="submit-button" @click="submitApplication">提交报名</view>
</view>
<!-- 自定义人数弹窗 -->
<custom-number-modal
:visible="showCustomNumberModal"
@close="closeCustomModal"
@confirm="handleCustomNumberConfirm"
/>
</view>
</template>
<script>
import { CommonEnum } from "@/enum/common.js";
import SearchBox from "../../components/search-box/search-box.vue";
import CustomNumberModal from "../../components/custom-number-modal/custom-number-modal.vue";
import activityApi from "@/api/activity/activity.js";
export default {
components: {
MonkSearchBox: SearchBox,
CustomNumberModal,
},
data() {
return {
bgc: {
backgroundColor: "#F5F0E7",
},
CommonEnum,
searchName: "",
// 活动ID
activityId: "",
// 加载状态
loading: false,
// 选择项数据
dateOptions: [],
timeOptions: [],
numberOptions: [
{ label: "1人", value: "1" },
{ label: "2人", value: "2" },
{ label: "自定义", value: "custom" },
],
// 选中的值
selectedDate: "",
selectedTime: "",
selectedNumber: "1",
selectedSlotId: "", // 保存选中的插槽ID
// 表单数据
formData: {
name: "",
phone: "",
},
// 自定义人数弹窗相关
showCustomNumberModal: false,
};
},
onLoad(options) {
// 如果从其他页面传递了活动ID使用传递的ID
if (options.actId) {
this.activityId = parseInt(options.actId);
}
this.fetchActivitySlots();
},
methods: {
// 获取活动插槽数据
async fetchActivitySlots() {
this.loading = true;
try {
const res = await activityApi.getActivitySlots(this.activityId);
if (res.code === 200 && Array.isArray(res.data)) {
this.processSlotData(res.data);
} else {
uni.showToast({
title: res.msg || "获取活动数据失败",
icon: "none",
});
}
} catch (error) {
console.error("获取活动插槽数据失败:", error);
uni.showToast({
title: "网络错误",
icon: "none",
});
} finally {
this.loading = false;
}
},
// 处理插槽数据
processSlotData(data) {
// 处理日期选项
this.dateOptions = data.map((item) => ({
label: this.formatDateLabel(item.label),
value: item.label,
children: item.children,
}));
// 默认选择第一个日期
if (this.dateOptions.length > 0) {
this.selectDate(this.dateOptions[0].value);
}
},
// 格式化日期标签
formatDateLabel(dateStr) {
const date = new Date(dateStr);
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
return `${month}${day}`;
},
// 选择日期
selectDate(value) {
this.selectedDate = value;
this.selectedTime = "";
this.selectedSlotId = "";
// 根据选中的日期更新时段选项
const selectedDateData = this.dateOptions.find(
(item) => item.value === value,
);
if (selectedDateData && selectedDateData.children) {
this.timeOptions = selectedDateData.children.map((item) => ({
label: item.label,
value: item.id,
slotId: item.id,
}));
// 默认选择第一个时段
if (this.timeOptions.length > 0) {
this.selectTime(this.timeOptions[0].value);
}
} else {
this.timeOptions = [];
}
},
// 选择时段
selectTime(value) {
this.selectedTime = value;
this.selectedSlotId = value; // 保存插槽ID
},
// 选择人数
selectNumber(value) {
if (value === "custom") {
this.openCustomNumberModal();
return;
}
this.selectedNumber = value;
},
// 提交报名
async submitApplication() {
if (!this.formData.name.trim()) {
uni.showToast({
title: "请输入姓名",
icon: "none",
});
return;
}
if (!this.formData.phone.trim()) {
uni.showToast({
title: "请输入手机号",
icon: "none",
});
return;
}
if (!this.selectedSlotId) {
uni.showToast({
title: "请选择活动时段",
icon: "none",
});
return;
}
try {
const submitData = {
actId: this.activityId,
slotId: this.selectedSlotId,
number: this.selectedNumber,
userName: this.formData.name,
phone: this.formData.phone,
};
const res = await activityApi.submitActivityApplication(submitData);
if (res.code === 200) {
uni.showToast({
title: "报名成功",
icon: "success",
});
// 跳转到报名成功页面,传递详细数据
setTimeout(() => {
const params = {
date: this.getSelectedDateLabel(),
time: this.getSelectedTimeLabel(),
number: this.getSelectedNumberLabel(),
};
const queryString = Object.keys(params)
.map((key) => `${key}=${encodeURIComponent(params[key])}`)
.join("&");
uni.navigateTo({
url: `/pages/activity/appointmentSuccess?${queryString}`,
});
}, 1500);
} else {
uni.showToast({
title: res.msg || "报名失败",
icon: "none",
});
}
} catch (error) {
console.error("提交报名失败:", error);
uni.showToast({
title: "网络错误",
icon: "none",
});
}
},
// 获取选中的日期标签
getSelectedDateLabel() {
const selectedDate = this.dateOptions.find(
(date) => date.value === this.selectedDate,
);
return selectedDate ? selectedDate.label : "";
},
// 获取选中的时段标签
getSelectedTimeLabel() {
const selectedTime = this.timeOptions.find(
(time) => time.value === this.selectedTime,
);
return selectedTime ? selectedTime.label : "";
},
// 获取选中的人数标签
getSelectedNumberLabel() {
if (
this.selectedNumber === "custom" ||
(this.selectedNumber !== "1" && this.selectedNumber !== "2")
) {
return this.selectedNumber + "人";
}
const selectedNumber = this.numberOptions.find(
(number) => number.value === this.selectedNumber,
);
return selectedNumber ? selectedNumber.label : "";
},
// 去除 HTML 标签,返回纯文本
stripHtmlTags(html) {
if (!html) return ""; // 处理空值
return html.replace(/<[^>]+>/g, ""); // 正则替换所有 HTML 标签
},
// 自定义人数弹窗相关方法
openCustomNumberModal() {
this.showCustomNumberModal = true;
},
closeCustomModal() {
this.showCustomNumberModal = false;
},
handleCustomNumberConfirm(value) {
this.selectedNumber = value;
},
},
};
</script>
<style lang="scss" scoped>
.page {
width: 100%;
display: flex;
align-items: center;
flex-direction: column;
.header {
width: 650rpx;
margin-top: 24rpx;
height: 726rpx;
display: flex;
align-items: flex-start;
flex-direction: column;
padding: 38rpx 50rpx 50rpx 50rpx;
background: #fffbf5;
border-radius: 20rpx 20rpx 20rpx 20rpx;
border: 2rpx solid #c7a26d;
margin-bottom: 40rpx;
.scroll-view {
display: flex;
justify-content: space-between;
white-space: nowrap;
width: 100%;
margin-bottom: 62rpx;
.scroll-view-item_date {
text-align: center;
line-height: 120rpx;
display: inline-block;
width: 162rpx;
height: 120rpx;
background: #fff1dd;
border-radius: 14rpx 14rpx 14rpx 14rpx;
margin-right: 32rpx;
font-weight: 700;
font-size: 28rpx;
color: #c7a26d;
transition: all 0.3s ease;
&.selected {
background: #a24242;
color: #ffffff;
}
}
.scroll-view-item_time {
text-align: center;
line-height: 120rpx;
display: inline-block;
width: 258rpx;
height: 120rpx;
background: #fff1dd;
border-radius: 14rpx 14rpx 14rpx 14rpx;
margin-right: 34rpx;
font-weight: 700;
font-size: 30rpx;
color: #c7a26d;
transition: all 0.3s ease;
&.selected {
background: #a24242;
color: #ffffff;
}
}
.scroll-view-item_number {
text-align: center;
line-height: 64rpx;
display: inline-block;
width: 170rpx;
height: 64rpx;
background: #fffbf5;
border-radius: 48rpx 48rpx 48rpx 48rpx;
border: 2rpx solid #c7a26d;
margin-right: 18rpx;
font-weight: 400;
font-size: 32rpx;
color: #c7a26d;
transition: all 0.3s ease;
&.selected {
background-color: #fff1dd;
color: #695347;
}
}
}
}
.contact {
width: 650rpx;
height: 232rpx;
background: #fffbf5;
border-radius: 20rpx 20rpx 20rpx 20rpx;
border: 2rpx solid #c7a26d;
padding: 0 50rpx 0 54rpx;
margin-bottom: 292rpx;
.contact-item {
width: 100%;
height: 116rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #d8d8d8;
.info {
font-weight: 400;
font-size: 32rpx;
color: #695347;
line-height: 44rpx;
text-align: center;
}
}
}
.submit {
width: 650rpx;
height: 92rpx;
background: #fffbf5;
border-radius: 57rpx 57rpx 57rpx 57rpx;
border: 2rpx solid #c7a26d;
display: flex;
justify-content: space-between;
align-items: center;
.submit-message {
font-weight: 500;
font-size: 28rpx;
color: #695347;
line-height: 38rpx;
margin-left: 62rpx;
}
.submit-button {
width: 224rpx;
height: 72rpx;
background: #a24242;
border-radius: 57rpx 57rpx 57rpx 57rpx;
font-weight: 500;
font-size: 28rpx;
color: #ffffff;
line-height: 72rpx;
text-align: center;
margin-right: 10rpx;
transition: all 0.3s ease;
&:active {
background: #8a3636;
transform: scale(0.98);
}
}
}
}
text {
font-weight: 400;
font-size: 32rpx;
color: #695347;
line-height: 44rpx;
text-align: center;
margin-bottom: 26rpx;
}
</style>