buddhism/pages/activity/activityDetail.vue

476 lines
12 KiB
Vue
Raw Normal View History

2025-08-04 11:47:19 +08:00
<template>
<view class="page">
<custom-navbar title="活动详情" />
<view class="header" :style="{ backgroundColor: CommonEnum.BASE_COLOR }">
<!-- 状态展示 -->
<status-display
v-if="loading"
type="loading"
loading-text="加载中..."
/>
<!-- 错误状态 -->
<status-display
v-if="error"
type="error"
:error-text="error"
@retry="loadPageData"
/>
<!-- 活动详情内容 -->
<view v-if="!loading && !error && activityData" class="activity-detail">
<!-- 活动标题区域 -->
<view class="activity-header">
<view class="title-section">
<text class="main-title">{{ activityData.title }}</text>
<view class="meta-info">
<text class="date">{{ formatDate(activityData.createTime) }}</text>
<text class="read-count">阅读{{ activityData.readNum || 0 }}</text>
</view>
</view>
</view>
<!-- 活动信息卡片 -->
<activity-card
:activity="formattedActivity"
:show-title="false"
:show-register-button="false"
2025-08-04 11:47:19 +08:00
@card-click="handleCardClick"
@register="handleRegister"
/>
<!-- 参与统计 -->
<view class="participation-stats">
<view class="stat-item">
<text class="stat-label">活动参与人数:</text>
<text class="stat-value">{{ activityData.attendance || 0 }}</text>
</view>
<view class="stat-item">
<text class="stat-label">已报名:</text>
<text class="stat-value">{{ activityData.currentBooking || 0 }}</text>
</view>
</view>
<!-- 活动描述 -->
<view class="activity-description" v-if="activityData.content">
<view class="description-title">
<text class="title-text">活动详情</text>
</view>
<view class="description-content">
<rich-text :nodes="activityData.content" class="content-html"></rich-text>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="bottom-actions">
<view class="action-button phone-button" @click="handlePhoneCall">
2025-08-04 16:17:43 +08:00
<image class="button-icon" :src="CommonEnum.PHONE" mode="aspectFit"></image>
2025-08-04 11:47:19 +08:00
<text class="button-text">电话</text>
</view>
<view class="action-button location-button" @click="handleLocation">
2025-08-04 16:17:43 +08:00
<image class="button-icon" :src="CommonEnum.ADDRESS" mode="aspectFit"></image>
2025-08-04 11:47:19 +08:00
<text class="button-text">地址</text>
</view>
<view class="action-button register-button" @click="handleRegister">
<text class="button-text">立即报名</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import CustomNavbar from "../../components/custom-navbar/custom-navbar.vue";
import CommonEnum from "../../enum/common";
import StatusDisplay from "../../components/status-display/status-display.vue";
import ActivityCard from "../../components/activity-card/activity-card.vue";
import activityApi from "../../api/activity/activity.js";
import activityFormatter from "../../utils/activity-data-formatter.js";
export default {
components: {
CustomNavbar,
StatusDisplay,
ActivityCard
},
data() {
return {
CommonEnum,
loading: false,
error: '',
activityData: null,
actId: ''
}
},
computed: {
// 格式化后的活动数据
formattedActivity() {
if (!this.activityData) return null
return activityFormatter.formatActivityDetail(this.activityData)
}
},
onLoad(options) {
// 获取传入的活动ID
if (options.actId) {
this.actId = options.actId
this.loadPageData()
} else {
this.error = '缺少活动ID参数'
}
},
methods: {
// 加载页面数据
async loadPageData() {
if (!this.actId) return
this.loading = true
this.error = ''
try {
const response = await activityApi.getActivityDetail(this.actId)
if (response.code === 200 && response.data) {
this.activityData = response.data
} else {
this.error = response.msg || '获取活动详情失败'
}
} catch (error) {
console.error('获取活动详情失败:', error)
this.error = '网络错误,请稍后重试'
} finally {
this.loading = false
}
},
// 格式化日期
formatDate(dateString) {
if (!dateString) return ''
try {
// 将 "yyyy-MM-dd HH:mm:ss" 格式转换为 "yyyy-MM-ddTHH:mm:ss" 格式以兼容iOS
const iosCompatibleDate = dateString.replace(' ', 'T')
const date = new Date(iosCompatibleDate)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
} catch (error) {
console.error('格式化日期失败:', error)
return dateString
}
},
// 处理卡片点击
handleCardClick(activity) {
console.log('点击活动卡片:', activity)
// 在详情页中点击卡片不执行任何操作
},
// 处理报名
async handleRegister() {
if (!this.activityData) return
console.log('报名活动:', this.activityData)
// 检查用户是否登录
const userInfo = uni.getStorageSync('userInfo')
if (!userInfo) {
uni.showModal({
title: '提示',
content: '请先登录后再报名活动',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
// 跳转到登录页
uni.navigateTo({
url: '/pages/login/login'
})
}
}
})
return
}
// 确认报名
uni.showModal({
title: '确认报名',
content: `确定要报名参加"${this.activityData.title}"活动吗?`,
success: async (res) => {
if (res.confirm) {
try {
const response = await activityApi.registerActivity({
activityId: this.activityData.id,
userId: userInfo.id,
userName: userInfo.userName || userInfo.nickName,
phone: userInfo.phone
})
if (response.code === 200) {
uni.showToast({
title: '报名成功',
icon: 'success'
})
// 刷新活动详情以更新报名状态
this.loadPageData()
} else {
uni.showToast({
title: response.msg || '报名失败',
icon: 'none'
})
}
} catch (error) {
console.error('报名失败:', error)
uni.showToast({
title: '报名失败,请稍后重试',
icon: 'none'
})
}
}
}
})
},
// 处理电话拨打
handlePhoneCall() {
if (!this.activityData || !this.activityData.phone) {
uni.showToast({
title: '暂无联系电话',
icon: 'none'
})
return
}
uni.showModal({
title: '拨打电话',
content: `确定要拨打 ${this.activityData.phone} 吗?`,
success: (res) => {
if (res.confirm) {
uni.makePhoneCall({
phoneNumber: this.activityData.phone,
fail: (err) => {
console.error('拨打电话失败:', err)
uni.showToast({
title: '拨打电话失败',
icon: 'none'
})
}
})
}
}
})
},
// 处理地址查看
handleLocation() {
if (!this.activityData || !this.activityData.address) {
uni.showToast({
title: '暂无地址信息',
icon: 'none'
})
return
}
// 如果有经纬度信息,打开地图
if (this.activityData.lon && this.activityData.lat) {
uni.openLocation({
latitude: this.activityData.lat,
longitude: this.activityData.lon,
name: this.activityData.title,
address: this.activityData.address,
fail: (err) => {
console.error('打开地图失败:', err)
// 如果打开地图失败,显示地址信息
this.showAddressInfo()
}
})
} else {
// 没有经纬度信息,显示地址详情
this.showAddressInfo()
}
},
// 显示地址信息
showAddressInfo() {
uni.showModal({
title: '活动地址',
content: this.activityData.address,
showCancel: false,
confirmText: '知道了'
})
}
}
}
</script>
<style lang="scss">
page {
background: #FAF8F3;
}
.header {
width: 100%;
min-height: 100vh;
display: flex;
align-items: flex-start;
flex-direction: column;
padding: 0 15rpx;
2025-08-04 16:17:43 +08:00
padding-bottom: 200rpx; /* 为固定底部按钮留出空间 */
2025-08-04 11:47:19 +08:00
}
.activity-detail {
width: 100%;
}
.activity-header {
width: 100%;
padding: 30rpx 0 20rpx 24rpx;
.title-section {
.main-title {
font-size: 44rpx;
font-weight: 500;
color: #3D3D3D;
line-height: 60rpx;
margin-bottom: 20rpx;
}
.meta-info {
display: flex;
align-items: center;
gap: 30rpx;
.date {
font-weight: 400;
font-size: 24rpx;
color: #808080;
}
.read-count {
font-weight: 400;
font-size: 24rpx;
color: #808080;
}
}
}
}
.participation-stats {
width: 100%;
display: flex;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.stat-item {
display: flex;
align-items: center;
margin-bottom: 0;
&:last-child {
margin-left: 50rpx;
}
.stat-label {
font-size: 30rpx;
color: #333;
font-weight: 500;
}
.stat-value {
font-size: 30rpx;
color: #E74C3C;
font-weight: bold;
}
}
}
.activity-description {
width: 100%;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.description-title {
margin-bottom: 20rpx;
.title-text {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.description-content {
.content-html {
font-size: 28rpx;
color: #666;
line-height: 1.6;
text-align: justify;
}
}
}
.bottom-actions {
2025-08-04 16:17:43 +08:00
position: fixed;
bottom: 0;
left: 0;
right: 0;
2025-08-04 11:47:19 +08:00
width: 100%;
display: flex;
align-items: center;
gap: 20rpx;
2025-08-04 16:17:43 +08:00
height: 62px;
padding: 30rpx 40rpx;
background: #fff;
border-top: 1rpx solid #f0f0f0;
border-radius: 20rpx 20rpx 0 0;
margin-bottom: 12rpx;
2025-08-04 11:47:19 +08:00
.action-button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 12rpx;
&.phone-button, &.location-button {
flex: 1;
min-height: 120rpx;
2025-08-04 16:17:43 +08:00
background: transparent;
2025-08-04 11:47:19 +08:00
.button-icon {
2025-08-04 16:17:43 +08:00
width: 48rpx;
height: 48rpx;
margin-bottom: 12rpx;
filter: brightness(0) saturate(100%) invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);
2025-08-04 11:47:19 +08:00
}
.button-text {
2025-08-04 16:17:43 +08:00
font-size: 26rpx;
color: #522510;
font-weight: 400;
2025-08-04 11:47:19 +08:00
}
}
&.register-button {
2025-08-04 16:17:43 +08:00
flex: 4;
background: #A24242;
border-radius: 60rpx;
padding: 0 40rpx;
width: 227px;
height: 38px;
2025-08-04 11:47:19 +08:00
.button-text {
font-size: 32rpx;
color: #fff;
font-weight: bold;
}
}
}
}
</style>