2 Komitmen 0ae5158168 ... 45e110001b

Pembuat SHA1 Pesan Tanggal
  YH_0525 45e110001b Merge remote-tracking branch 'origin/test_dev' into test 4 minggu lalu
  YH_0525 eb4ad56d1a 红娘活动中心 和 我的活动 4 minggu lalu

+ 551 - 0
LiangZhiYUMao/pages/matchmaker-workbench/activities.vue

@@ -0,0 +1,551 @@
+<template>
+	<view class="activities-page">
+		<!-- 自定义导航栏 -->
+		<view class="custom-navbar">
+			<view class="navbar-left" @click="goBack">
+				<text class="back-icon">←</text>
+			</view>
+			<view class="navbar-title">活动中心</view>
+			<view class="navbar-right">
+				<view class="points-display">
+					<text class="points-label">积分</text>
+					<text class="points-value">{{ currentPoints }}</text>
+				</view>
+			</view>
+		</view>
+
+		<!-- 顶部公告 -->
+		<view class="announcement-bar">
+			<text class="announcement-icon">📢</text>
+			<text class="announcement-content">红娘活动报名开始啦!用积分兑换活动名额,积分兑好礼!</text>
+		</view>
+
+		<!-- 活动分类标签 - 横向滚动 -->
+		<scroll-view scroll-x class="category-scroll" show-scrollbar="false">
+			<view class="category-list">
+				<view 
+					v-for="(tab, index) in tabs" 
+					:key="index"
+					class="category-item" 
+					:class="{ active: activeTab === tab.type }"
+					@click="switchTab(tab.type)"
+				>
+					{{ tab.name }}
+				</view>
+			</view>
+		</scroll-view>
+
+		<!-- 活动列表 -->
+		<view class="activity-grid">
+			<view class="activity-card" v-for="(item, index) in activityList" :key="index" @click="goToDetail(item)">
+				<image :src="item.coverImage || item.cover_image" class="activity-image" mode="aspectFill"></image>
+				<view class="activity-info">
+					<view class="activity-name">{{ item.name }}</view>
+					<view class="activity-meta">
+						<text class="activity-location">📍 {{ item.location }}</text>
+					</view>
+					<view class="activity-footer">
+						<view class="activity-points">
+							<text class="points-symbol">💎</text>
+							<text class="points-value">{{ item.points }}</text>
+						</view>
+						<text class="activity-participants">{{ item.participants || 0 }}人参加</text>
+					</view>
+					<view class="activity-btn" 
+						:class="{ 'btn-disabled': hasExchanged(item.id) }"
+						@click.stop="handleActivityAction(item)">
+						{{ hasExchanged(item.id) ? '已报名' : '积分兑换' }}
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<!-- 空状态 -->
+		<view class="empty-state" v-if="activityList.length === 0 && !loading">
+			<image src="https://img.icons8.com/color/96/000000/calendar--v1.png" class="empty-icon"></image>
+			<text class="empty-text">暂无活动</text>
+			<text class="empty-subtext">敬请期待更多精彩活动</text>
+		</view>
+
+		<!-- 加载更多 -->
+		<view class="load-more" v-if="hasMore && activityList.length > 0">
+			<text class="load-text">{{ loading ? '加载中...' : '上拉加载更多' }}</text>
+		</view>
+		<view class="no-more" v-else-if="activityList.length > 0">
+			<text class="no-more-text">没有更多了</text>
+		</view>
+	</view>
+</template>
+
+<script>
+import api from '../../utils/api.js'
+
+export default {
+	data() {
+		return {
+			activityList: [],
+			pageNum: 1,
+			pageSize: 10,
+			hasMore: true,
+			loading: false,
+			currentPoints: 0,
+			makerId: null,
+			exchangedActivities: [],
+			tabs: [
+				{ name: '全部活动', type: 'all' },
+				{ name: '推荐活动', type: 'premium' }
+			],
+			activeTab: 'all'
+		}
+	},
+
+	onLoad() {
+		this.initData()
+	},
+
+	onReachBottom() {
+		if (this.hasMore && !this.loading) {
+			this.pageNum++
+			this.loadActivityList()
+		}
+	},
+
+	methods: {
+		// 初始化数据
+		async initData() {
+			const userInfo = uni.getStorageSync('userInfo')
+			// 兼容多种字段名
+			this.makerId = userInfo && (userInfo.matchmakerId || userInfo.makerId || userInfo.matchmaker_id)
+			
+			// 如果没有makerId,尝试通过userId获取
+			if (!this.makerId && userInfo && userInfo.userId) {
+				try {
+					const res = await api.matchmaker.getByUserId(userInfo.userId)
+					let matchmaker = res
+					if (res && res.data) {
+						matchmaker = res.data
+					}
+					if (matchmaker) {
+						this.makerId = matchmaker.matchmakerId || matchmaker.matchmaker_id
+					}
+				} catch (e) {
+					console.error('获取红娘信息失败:', e)
+				}
+			}
+			
+			if (!this.makerId) {
+				uni.showToast({
+					title: '请先登录红娘账号',
+					icon: 'none'
+				})
+				return
+			}
+			
+			await this.loadMakerInfo()
+			await this.loadExchangedActivities()
+			await this.loadActivityList()
+		},
+
+		// 加载红娘信息(包括积分)
+		async loadMakerInfo() {
+			try {
+				const res = await api.matchmaker.getDetail(this.makerId)
+				// 兼容不同的返回格式
+				const makerInfo = res && res.data ? res.data : res
+				if (makerInfo) {
+					this.currentPoints = makerInfo.points || makerInfo.point || 0
+					console.log('红娘积分:', this.currentPoints)
+				}
+			} catch (error) {
+				console.error('加载红娘信息失败:', error)
+				this.currentPoints = 0
+			}
+		},
+
+		// 加载已兑换的活动列表
+		async loadExchangedActivities() {
+			try {
+				const list = await api.matchmakerActivity.getPurchasedList(this.makerId)
+				if (list && list.length > 0) {
+					this.exchangedActivities = list.map(item => item.activity_id || item.activityId)
+				}
+			} catch (error) {
+				console.error('加载已兑换活动失败:', error)
+				this.exchangedActivities = []
+			}
+		},
+
+		// 加载活动列表
+		async loadActivityList() {
+			if (this.loading) return
+			this.loading = true
+
+			try {
+				const params = {
+					categoryType: this.activeTab
+				}
+				const data = await api.matchmakerActivity.getList(params)
+
+				if (data && data.length > 0) {
+					this.activityList = [...this.activityList, ...data]
+					this.hasMore = data.length >= this.pageSize
+				} else {
+					this.hasMore = false
+				}
+			} catch (error) {
+				console.error('加载活动列表失败:', error)
+				this.hasMore = false
+			} finally {
+				this.loading = false
+			}
+		},
+
+		// 切换分类标签
+		switchTab(type) {
+			if (this.activeTab === type) return
+			this.activeTab = type
+			this.pageNum = 1
+			this.activityList = []
+			this.loadActivityList()
+		},
+
+		// 检查是否已兑换
+		hasExchanged(activityId) {
+			return this.exchangedActivities.includes(activityId)
+		},
+
+		// 处理活动操作(兑换或查看详情)
+		async handleActivityAction(item) {
+			if (this.hasExchanged(item.id)) {
+				// 已兑换,跳转到详情页
+				uni.navigateTo({
+					url: `/pages/matchmaker-workbench/activity-detail?id=${item.id}`
+				})
+			} else {
+				// 未兑换,显示兑换确认
+				uni.showModal({
+					title: '确认兑换',
+					content: `是否用 ${item.points} 积分兑换"${item.name}"活动?`,
+					confirmText: '确认',
+					cancelText: '取消',
+					success: (res) => {
+						if (res.confirm) {
+							this.exchangeActivity(item)
+						}
+					}
+				})
+			}
+		},
+
+		// 兑换活动
+		async exchangeActivity(item) {
+			const pointsNeeded = item.points || 0
+			
+			if (this.currentPoints < pointsNeeded) {
+				uni.showToast({
+					title: '积分不足',
+					icon: 'none'
+				})
+				return
+			}
+
+			try {
+				console.log('兑换参数:', {
+					makerId: this.makerId,
+					activityId: item.id,
+					points: pointsNeeded
+				})
+				
+				const result = await api.matchmakerActivity.exchange({
+					makerId: this.makerId,
+					activityId: item.id,
+					points: pointsNeeded
+				})
+				
+				console.log('兑换结果:', result)
+
+				// API请求成功(request函数已处理code=200的情况,能走到这里说明已成功)
+				uni.showToast({
+					title: '兑换成功',
+					icon: 'success'
+				})
+				this.currentPoints -= pointsNeeded
+				this.exchangedActivities.push(item.id)
+				
+				// 跳转到详情页
+				setTimeout(() => {
+					uni.navigateTo({
+						url: `/pages/matchmaker-workbench/activity-detail?id=${item.id}`
+					})
+				}, 500)
+			} catch (error) {
+				console.error('兑换失败:', error)
+				uni.showToast({
+					title: error.message || '兑换失败',
+					icon: 'none'
+				})
+			}
+		},
+
+		// 跳转到活动详情
+		goToDetail(item) {
+			uni.navigateTo({
+				url: `/pages/matchmaker-workbench/activity-detail?id=${item.id}`
+			})
+		},
+
+		// 返回
+		goBack() {
+			uni.navigateBack()
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+	.activities-page {
+		min-height: 100vh;
+		background-color: #FFF9F9;
+		padding-top: 90rpx;
+	}
+
+	/* 自定义导航栏 */
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		height: 90rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding: 0 20rpx;
+		background: linear-gradient(135deg, #FCE4EC 0%, #F8BBD0 100%);
+		z-index: 999;
+
+		.navbar-left,
+		.navbar-right {
+			width: 80rpx;
+		}
+
+		.back-icon {
+			font-size: 40rpx;
+			color: #333333;
+			font-weight: bold;
+		}
+
+		.navbar-title {
+			flex: 1;
+			text-align: center;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.points-display {
+			display: flex;
+			align-items: center;
+			gap: 8rpx;
+			background-color: rgba(255, 255, 255, 0.8);
+			padding: 8rpx 16rpx;
+			border-radius: 20rpx;
+
+			.points-label {
+				font-size: 24rpx;
+				color: #666666;
+			}
+
+			.points-value {
+				font-size: 28rpx;
+				color: #FF6B8A;
+				font-weight: bold;
+			}
+		}
+	}
+
+	/* 公告栏 */
+	.announcement-bar {
+		display: flex;
+		align-items: center;
+		gap: 12rpx;
+		padding: 16rpx 20rpx;
+		background-color: #FFF3E0;
+		margin: 10rpx 0;
+
+		.announcement-icon {
+			font-size: 28rpx;
+			flex-shrink: 0;
+		}
+
+		.announcement-content {
+			font-size: 24rpx;
+			color: #E65100;
+			flex: 1;
+		}
+	}
+
+	/* 分类标签 - 横向滚动 */
+	.category-scroll {
+		white-space: nowrap;
+		padding: 0 20rpx;
+		margin: 10rpx 0;
+	}
+
+	.category-list {
+		display: flex;
+		gap: 12rpx;
+	}
+
+	.category-item {
+		display: inline-block;
+		padding: 12rpx 24rpx;
+		background-color: #FFFFFF;
+		border-radius: 30rpx;
+		font-size: 26rpx;
+		color: #666666;
+		border: 2rpx solid #EEEEEE;
+		transition: all 0.3s ease;
+
+		&.active {
+			background-color: #9C27B0;
+			color: #FFFFFF;
+			border-color: #9C27B0;
+		}
+	}
+
+	/* 活动列表 - 两列布局 */
+	.activity-grid {
+		display: grid;
+		grid-template-columns: 1fr 1fr;
+		gap: 20rpx;
+		padding: 20rpx;
+
+		.activity-card {
+			position: relative;
+			background-color: #FFFFFF;
+			border-radius: 20rpx;
+			overflow: hidden;
+			box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+
+			.activity-image {
+				width: 100%;
+				height: 240rpx;
+				background-color: #F5F5F5;
+			}
+
+			.activity-info {
+				padding: 20rpx;
+
+				.activity-name {
+					font-size: 28rpx;
+					font-weight: bold;
+					color: #333333;
+					margin-bottom: 10rpx;
+					display: -webkit-box;
+					-webkit-box-orient: vertical;
+					-webkit-line-clamp: 2;
+					overflow: hidden;
+				}
+
+				.activity-meta {
+					margin-bottom: 15rpx;
+
+					.activity-location {
+						font-size: 24rpx;
+						color: #666666;
+					}
+				}
+
+				.activity-footer {
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					margin-bottom: 15rpx;
+
+					.activity-points {
+						display: flex;
+						align-items: center;
+
+						.points-symbol {
+							font-size: 24rpx;
+							margin-right: 5rpx;
+						}
+
+						.points-value {
+							font-size: 26rpx;
+							color: #FF6B8A;
+							font-weight: bold;
+						}
+					}
+
+					.activity-participants {
+						font-size: 22rpx;
+						color: #999999;
+					}
+				}
+
+				.activity-btn {
+					width: 100%;
+					height: 60rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					background-color: #9C27B0;
+					color: #FFFFFF;
+					border-radius: 30rpx;
+					font-size: 26rpx;
+					transition: all 0.3s ease;
+
+					&:active {
+						background-color: #7B1FA2;
+					}
+
+					&.btn-disabled {
+						background-color: #CCCCCC;
+						color: #999999;
+					}
+				}
+			}
+		}
+	}
+
+	/* 空状态 */
+	.empty-state {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		padding: 100rpx 0;
+
+		.empty-icon {
+			width: 120rpx;
+			height: 120rpx;
+			opacity: 0.5;
+			margin-bottom: 20rpx;
+		}
+
+		.empty-text {
+			font-size: 32rpx;
+			color: #666666;
+			margin-bottom: 10rpx;
+		}
+
+		.empty-subtext {
+			font-size: 26rpx;
+			color: #999999;
+		}
+	}
+
+	/* 加载更多 */
+	.load-more,
+	.no-more {
+		padding: 30rpx 0;
+		text-align: center;
+
+		.load-text,
+		.no-more-text {
+			font-size: 24rpx;
+			color: #999999;
+		}
+	}
+</style>

+ 549 - 0
LiangZhiYUMao/pages/matchmaker-workbench/activity-detail.vue

@@ -0,0 +1,549 @@
+<template>
+	<view class="activity-detail-page">
+		<!-- 自定义导航栏 -->
+		<view class="custom-navbar">
+			<view class="navbar-left" @click="goBack">
+				<text class="back-icon">←</text>
+			</view>
+			<view class="navbar-title">活动详情</view>
+			<view class="navbar-right"></view>
+		</view>
+
+		<!-- 活动封面 -->
+		<view class="activity-cover">
+			<image :src="activity.coverImage || activity.cover_image" class="cover-image" mode="aspectFill"></image>
+			<view class="cover-mask">
+				<view class="activity-tag" v-if="activity.isRecommended">⭐ 推荐活动</view>
+			</view>
+		</view>
+
+		<!-- 活动信息 -->
+		<view class="activity-content">
+			<view class="activity-title">{{ activity.name }}</view>
+
+			<view class="info-section">
+				<view class="info-item">
+					<text class="info-icon">⏰</text>
+					<text class="info-label">活动时间:</text>
+					<text class="info-value">{{ formatActivityTime(activity.startTime || activity.start_time, activity.endTime || activity.end_time) }}</text>
+				</view>
+				<view class="info-item">
+					<text class="info-icon">📍</text>
+					<text class="info-label">活动地点:</text>
+					<text class="info-value">{{ activity.location || '待定' }}</text>
+				</view>
+				<view class="info-item">
+					<text class="info-icon">👥</text>
+					<text class="info-label">报名人数:</text>
+					<text class="info-value">{{ activity.participants || 0 }} / {{ activity.capacity || '不限' }}</text>
+				</view>
+				<view class="info-item">
+					<text class="info-icon">💎</text>
+					<text class="info-label">所需积分:</text>
+					<text class="info-value points">{{ activity.points || 0 }}</text>
+				</view>
+			</view>
+
+			<view class="divider"></view>
+
+			<view class="description-section">
+				<view class="section-title">活动介绍</view>
+				<view class="description-text">{{ activity.description || '暂无介绍' }}</view>
+			</view>
+
+			<view class="divider"></view>
+
+			<view class="content-section" v-if="activity.content">
+				<view class="section-title">活动详情</view>
+				<view class="content-text">{{ activity.content }}</view>
+			</view>
+		</view>
+
+		<!-- 底部兑换按钮 -->
+		<view class="bottom-bar" v-if="!hasExchanged">
+			<view class="points-info">
+				<text class="points-label">所需积分</text>
+				<view class="points-value">
+					<text class="points-symbol">💎</text>
+					<text class="points-num">{{ activity.points || 0 }}</text>
+				</view>
+			</view>
+			<view class="exchange-btn" 
+				:class="{ 'btn-disabled': currentPoints < (activity.points || 0) }"
+				@click="handleExchange">
+				<text class="btn-text">{{ currentPoints < (activity.points || 0) ? '积分不足' : '积分兑换报名' }}</text>
+			</view>
+		</view>
+
+		<!-- 已报名状态 -->
+		<view class="bottom-bar" v-else>
+			<view class="registered-status">
+				<text class="status-icon">✓</text>
+				<text class="status-text">已报名</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+import api from '../../utils/api.js'
+
+export default {
+	data() {
+		return {
+			activityId: null,
+			activity: {
+				name: '加载中...',
+				coverImage: 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60',
+				points: 0
+			},
+			currentPoints: 0,
+			makerId: null,
+			hasExchanged: false
+		}
+	},
+
+	onLoad(options) {
+		if (options.id) {
+			this.activityId = options.id
+			this.initData()
+		}
+	},
+
+	methods: {
+		// 初始化数据
+		async initData() {
+			const userInfo = uni.getStorageSync('userInfo')
+			// 兼容多种字段名
+			this.makerId = userInfo && (userInfo.matchmakerId || userInfo.makerId || userInfo.matchmaker_id)
+			
+			// 如果没有makerId,尝试通过userId获取
+			if (!this.makerId && userInfo && userInfo.userId) {
+				try {
+					const res = await api.matchmaker.getByUserId(userInfo.userId)
+					let matchmaker = res
+					if (res && res.data) {
+						matchmaker = res.data
+					}
+					if (matchmaker) {
+						this.makerId = matchmaker.matchmakerId || matchmaker.matchmaker_id
+					}
+				} catch (e) {
+					console.error('获取红娘信息失败:', e)
+				}
+			}
+			
+			await this.loadMakerInfo()
+			await this.loadActivityDetail()
+			await this.checkExchangeStatus()
+		},
+
+		// 加载红娘信息(包括积分)
+		async loadMakerInfo() {
+			try {
+				const res = await api.matchmaker.getDetail(this.makerId)
+				console.log('红娘信息返回:', res)
+				// 兼容不同的返回格式
+				let makerInfo = res
+				if (res && res.data) {
+					makerInfo = res.data
+				}
+				if (makerInfo) {
+					// 兼容 snake_case 和 camelCase
+					this.currentPoints = makerInfo.points ?? makerInfo.total_points ?? 0
+					console.log('当前积分:', this.currentPoints)
+				}
+			} catch (error) {
+				console.error('加载红娘信息失败:', error)
+				this.currentPoints = 0
+			}
+		},
+
+		// 加载活动详情
+		async loadActivityDetail() {
+			try {
+				const data = await api.matchmakerActivity.getDetail(this.activityId)
+				if (data) {
+					this.activity = data
+				}
+			} catch (error) {
+				console.error('加载活动详情失败:', error)
+				uni.showToast({
+					title: '加载失败',
+					icon: 'none'
+				})
+			}
+		},
+
+		// 检查是否已兑换
+		async checkExchangeStatus() {
+			try {
+				console.log('检查兑换状态, makerId:', this.makerId, 'activityId:', this.activityId)
+				const res = await api.matchmakerActivity.getPurchasedList(this.makerId)
+				console.log('已兑换活动列表返回:', res)
+				// 兼容不同的返回格式
+				let list = res
+				if (res && res.data) {
+					list = res.data
+				}
+				if (Array.isArray(list) && list.length > 0) {
+					this.hasExchanged = list.some(item => {
+						const itemActivityId = item.activity_id || item.activityId
+						console.log('比较活动ID:', itemActivityId, '==', this.activityId)
+						return itemActivityId == this.activityId
+					})
+				}
+				console.log('是否已兑换:', this.hasExchanged)
+			} catch (error) {
+				console.error('检查兑换状态失败:', error)
+				this.hasExchanged = false
+			}
+		},
+
+		// 格式化活动时间
+		formatActivityTime(startTime, endTime) {
+			if (!startTime) return '待定'
+			
+			const start = new Date(startTime)
+			const end = endTime ? new Date(endTime) : null
+			
+			const startStr = start.toLocaleDateString('zh-CN') + ' ' + 
+							start.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
+			
+			if (end) {
+				// 判断是否同一天
+				const isSameDay = start.toDateString() === end.toDateString()
+				let endStr
+				if (isSameDay) {
+					// 同一天只显示时间
+					endStr = end.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
+				} else {
+					// 不同天显示完整日期时间
+					endStr = end.toLocaleDateString('zh-CN') + ' ' + 
+							end.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
+				}
+				return `${startStr} - ${endStr}`
+			}
+			
+			return startStr
+		},
+
+		// 处理兑换
+		async handleExchange() {
+			if (this.currentPoints < (this.activity.points || 0)) {
+				uni.showToast({
+					title: '积分不足',
+					icon: 'none'
+				})
+				return
+			}
+
+			uni.showModal({
+				title: '确认兑换',
+				content: `是否用 ${this.activity.points} 积分兑换"${this.activity.name}"活动?`,
+				confirmText: '确认',
+				cancelText: '取消',
+				success: (res) => {
+					if (res.confirm) {
+						this.exchangeActivity()
+					}
+				}
+			})
+		},
+
+		// 兑换活动
+		async exchangeActivity() {
+			try {
+				const result = await api.matchmakerActivity.exchange({
+					makerId: this.makerId,
+					activityId: this.activityId,
+					points: this.activity.points
+				})
+
+				if (result) {
+					uni.showToast({
+						title: '兑换成功',
+						icon: 'success'
+					})
+					this.currentPoints -= this.activity.points
+					this.hasExchanged = true
+					
+					// 更新参与人数
+					if (this.activity.participants) {
+						this.activity.participants++
+					} else {
+						this.activity.participants = 1
+					}
+				}
+			} catch (error) {
+				console.error('兑换失败:', error)
+				uni.showToast({
+					title: error.message || '兑换失败',
+					icon: 'none'
+				})
+			}
+		},
+
+		// 返回
+		goBack() {
+			uni.navigateBack()
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+	.activity-detail-page {
+		min-height: 100vh;
+		background-color: #FFF9F9;
+		padding-top: 90rpx;
+		padding-bottom: 120rpx;
+	}
+
+	/* 自定义导航栏 */
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		height: 90rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding: 0 20rpx;
+		background: linear-gradient(135deg, #FCE4EC 0%, #F8BBD0 100%);
+		z-index: 999;
+
+		.navbar-left,
+		.navbar-right {
+			width: 80rpx;
+		}
+
+		.back-icon {
+			font-size: 40rpx;
+			color: #333333;
+			font-weight: bold;
+		}
+
+		.navbar-title {
+			flex: 1;
+			text-align: center;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+
+	/* 活动封面 */
+	.activity-cover {
+		position: relative;
+		width: 100%;
+		height: 400rpx;
+		overflow: hidden;
+
+		.cover-image {
+			width: 100%;
+			height: 100%;
+			background-color: #F5F5F5;
+		}
+
+		.cover-mask {
+			position: absolute;
+			top: 0;
+			left: 0;
+			right: 0;
+			bottom: 0;
+			display: flex;
+			align-items: flex-start;
+			justify-content: flex-start;
+			padding: 20rpx;
+			background: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, transparent 100%);
+
+			.activity-tag {
+				background-color: rgba(255, 215, 0, 0.9);
+				color: #333333;
+				padding: 8rpx 16rpx;
+				border-radius: 20rpx;
+				font-size: 24rpx;
+				font-weight: bold;
+			}
+		}
+	}
+
+	/* 活动内容 */
+	.activity-content {
+		padding: 30rpx 20rpx;
+
+		.activity-title {
+			font-size: 36rpx;
+			font-weight: bold;
+			color: #333333;
+			margin-bottom: 30rpx;
+		}
+
+		.info-section {
+			background-color: #FFFFFF;
+			border-radius: 12rpx;
+			padding: 20rpx;
+			margin-bottom: 20rpx;
+
+			.info-item {
+				display: flex;
+				align-items: flex-start;
+				margin-bottom: 16rpx;
+
+				&:last-child {
+					margin-bottom: 0;
+				}
+
+				.info-icon {
+					font-size: 28rpx;
+					margin-right: 12rpx;
+					flex-shrink: 0;
+				}
+
+				.info-label {
+					font-size: 26rpx;
+					color: #666666;
+					min-width: 120rpx;
+				}
+
+				.info-value {
+					font-size: 26rpx;
+					color: #333333;
+					flex: 1;
+
+					&.points {
+						color: #FF6B8A;
+						font-weight: bold;
+					}
+				}
+			}
+		}
+
+		.divider {
+			height: 1rpx;
+			background-color: #EEEEEE;
+			margin: 20rpx 0;
+		}
+
+		.description-section,
+		.content-section {
+			background-color: #FFFFFF;
+			border-radius: 12rpx;
+			padding: 20rpx;
+			margin-bottom: 20rpx;
+
+			.section-title {
+				font-size: 28rpx;
+				font-weight: bold;
+				color: #333333;
+				margin-bottom: 16rpx;
+			}
+
+			.description-text,
+			.content-text {
+				font-size: 26rpx;
+				color: #666666;
+				line-height: 1.6;
+				white-space: pre-wrap;
+				word-break: break-word;
+			}
+		}
+	}
+
+	/* 底部栏 */
+	.bottom-bar {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		height: 120rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding: 20rpx;
+		background-color: #FFFFFF;
+		border-top: 1rpx solid #EEEEEE;
+		z-index: 100;
+
+		.points-info {
+			display: flex;
+			flex-direction: column;
+			align-items: flex-start;
+
+			.points-label {
+				font-size: 24rpx;
+				color: #999999;
+				margin-bottom: 8rpx;
+			}
+
+			.points-value {
+				display: flex;
+				align-items: center;
+				gap: 8rpx;
+
+				.points-symbol {
+					font-size: 28rpx;
+				}
+
+				.points-num {
+					font-size: 32rpx;
+					color: #FF6B8A;
+					font-weight: bold;
+				}
+			}
+		}
+
+		.exchange-btn {
+			flex: 1;
+			height: 80rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			background: linear-gradient(135deg, #9C27B0 0%, #7B1FA2 100%);
+			color: #FFFFFF;
+			border-radius: 40rpx;
+			font-size: 28rpx;
+			font-weight: bold;
+			margin-left: 20rpx;
+			transition: all 0.3s ease;
+
+			&:active {
+				transform: scale(0.95);
+			}
+
+			&.btn-disabled {
+				background: #CCCCCC;
+				color: #999999;
+			}
+
+			.btn-text {
+				color: inherit;
+			}
+		}
+
+		.registered-status {
+			flex: 1;
+			height: 80rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			background-color: #E8F5E9;
+			border-radius: 40rpx;
+			margin-left: 20rpx;
+
+			.status-icon {
+				font-size: 40rpx;
+				color: #4CAF50;
+				margin-right: 12rpx;
+			}
+
+			.status-text {
+				font-size: 28rpx;
+				color: #4CAF50;
+				font-weight: bold;
+			}
+		}
+	}
+</style>