|
|
@@ -0,0 +1,573 @@
|
|
|
+<template>
|
|
|
+ <view class="container">
|
|
|
+ <!-- 加载状态 -->
|
|
|
+ <view v-if="loading" class="loading-wrap">
|
|
|
+ <view class="loading-spinner"></view>
|
|
|
+ <text class="loading-text">加载中...</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 错误状态 -->
|
|
|
+ <view v-else-if="error" class="error-wrap">
|
|
|
+ <text class="error-icon">📋</text>
|
|
|
+ <text class="error-text">{{ errorMsg }}</text>
|
|
|
+ <button class="retry-btn" @click="loadDetail(activityId)">重新加载</button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 活动内容 -->
|
|
|
+ <scroll-view v-else-if="activity.id" scroll-y class="content">
|
|
|
+ <!-- 封面图 -->
|
|
|
+ <image
|
|
|
+ v-if="activity.coverImage"
|
|
|
+ class="cover"
|
|
|
+ :src="activity.coverImage"
|
|
|
+ mode="widthFix"
|
|
|
+ />
|
|
|
+ <image v-else class="cover placeholder-cover" src="/static/default-activity.png" mode="aspectFill" />
|
|
|
+
|
|
|
+ <view class="info-section">
|
|
|
+ <text class="activity-title">{{ activity.title }}</text>
|
|
|
+
|
|
|
+ <!-- 活动状态标签 -->
|
|
|
+ <view class="status-row">
|
|
|
+ <text class="status-tag" :class="'status-' + (activity.status || 'upcoming')">{{ statusText(activity.status) }}</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 活动元信息 -->
|
|
|
+ <view class="meta-list">
|
|
|
+ <view class="meta-item" v-if="activity.startTime">
|
|
|
+ <text class="meta-icon">🕐</text>
|
|
|
+ <text class="meta-text">{{ activity.startTime }}{{ activity.endTime ? ' ~ ' + activity.endTime : '' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meta-item" v-if="activity.location">
|
|
|
+ <text class="meta-icon">📍</text>
|
|
|
+ <text class="meta-text">{{ activity.location }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meta-item" v-if="activity.maxParticipants">
|
|
|
+ <text class="meta-icon">👥</text>
|
|
|
+ <text class="meta-text">{{ activity.currentParticipants || 0 }} / {{ activity.maxParticipants }} 人</text>
|
|
|
+ </view>
|
|
|
+ <view class="meta-item">
|
|
|
+ <text class="meta-icon">💰</text>
|
|
|
+ <text class="meta-text">{{ activity.priceLabel || (activity.price > 0 ? '¥' + activity.price : '免费') }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 活动简介 -->
|
|
|
+ <view class="desc-section" v-if="activity.description">
|
|
|
+ <text class="section-title">活动介绍</text>
|
|
|
+ <text class="desc-text">{{ activity.description }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 底部操作栏 -->
|
|
|
+ <view class="bottom-bar">
|
|
|
+ <view class="price-info">
|
|
|
+ <text class="bottom-type">活动</text>
|
|
|
+ <text class="bottom-vendor" v-if="activity.vendorName">{{ activity.vendorName }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btns">
|
|
|
+ <!-- 报名按钮(仅 requireRegistration=1 时显示) -->
|
|
|
+ <button
|
|
|
+ v-if="activity.requireRegistration === 1 && !registrationStatus"
|
|
|
+ class="btn-register"
|
|
|
+ :class="{ 'btn-register-loading': registrationLoading }"
|
|
|
+ :disabled="registrationLoading"
|
|
|
+ @click="onRegister"
|
|
|
+ >
|
|
|
+ <text v-if="registrationLoading">报名中...</text>
|
|
|
+ <text v-else>立即报名</text>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <!-- 已报名待审核 -->
|
|
|
+ <button
|
|
|
+ v-if="activity.requireRegistration === 1 && registrationStatus === 'pending'"
|
|
|
+ class="btn-register-done"
|
|
|
+ disabled
|
|
|
+ >
|
|
|
+ <text>报名待审核</text>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <!-- 已报名可取消 -->
|
|
|
+ <button
|
|
|
+ v-if="activity.requireRegistration === 1 && registrationStatus === 'approved'"
|
|
|
+ class="btn-cancel"
|
|
|
+ :disabled="registrationLoading"
|
|
|
+ @click="onCancelRegistration"
|
|
|
+ >
|
|
|
+ <text>取消报名</text>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <!-- 签到按钮 -->
|
|
|
+ <button
|
|
|
+ class="btn-checkin"
|
|
|
+ :class="{ 'btn-checkin-done': checkinDone, 'btn-checkin-loading': checkinLoading }"
|
|
|
+ :disabled="checkinLoading || checkinDone"
|
|
|
+ @click="onCheckin"
|
|
|
+ >
|
|
|
+ <text v-if="checkinLoading">签到中...</text>
|
|
|
+ <text v-else-if="checkinDone">已签到 ✓</text>
|
|
|
+ <text v-else>签到</text>
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 能量扣减提示弹窗 -->
|
|
|
+ <modal v-if="showPenaltyModal" class="penalty-modal" :show="showPenaltyModal" @close="showPenaltyModal = false">
|
|
|
+ <view class="penalty-content">
|
|
|
+ <text class="penalty-title">签到成功但已扣能量</text>
|
|
|
+ <text class="penalty-desc">您未报名参加此活动,已被扣除 {{ penaltyAmount }} 点能量值</text>
|
|
|
+ <button class="penalty-btn" @click="showPenaltyModal = false">我知道了</button>
|
|
|
+ </view>
|
|
|
+ </modal>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <view v-else class="empty-wrap">
|
|
|
+ <text class="empty-text">活动不存在或已下架</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { getActivityDetail, activityCheckin, registerActivity, cancelActivityRegistration, getMyActivityRegistrations } from '@/utils/api.js'
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ activityId: null,
|
|
|
+ activity: {},
|
|
|
+ loading: false,
|
|
|
+ error: false,
|
|
|
+ errorMsg: '',
|
|
|
+ checkinLoading: false,
|
|
|
+ checkinDone: false,
|
|
|
+ checkinPoints: 0,
|
|
|
+ registrationStatus: null,
|
|
|
+ registrationLoading: false,
|
|
|
+ showPenaltyModal: false,
|
|
|
+ penaltyAmount: 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad: function(options) {
|
|
|
+ if (options && options.id) {
|
|
|
+ this.activityId = options.id
|
|
|
+ this.loadDetail(options.id)
|
|
|
+ } else {
|
|
|
+ this.error = true
|
|
|
+ this.errorMsg = '缺少活动ID'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否已经签到(从路由参数获取)
|
|
|
+ if (options && options.checkinDone === '1') {
|
|
|
+ this.checkinDone = true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ loadDetail: function(id) {
|
|
|
+ var self = this
|
|
|
+ self.loading = true
|
|
|
+ self.error = false
|
|
|
+ getActivityDetail(id).then(function(res) {
|
|
|
+ self.loading = false
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ self.activity = res.data
|
|
|
+ // Load registration status if logged in and activity requires registration
|
|
|
+ if (self.activity.requireRegistration === 1) {
|
|
|
+ var childId = uni.getStorageSync('currentChildId')
|
|
|
+ if (childId) {
|
|
|
+ getMyActivityRegistrations({ childId: childId, page: 1, size: 50 }).then(function(regRes) {
|
|
|
+ if (regRes && regRes.data && regRes.data.records) {
|
|
|
+ var records = regRes.data.records
|
|
|
+ for (var i = 0; i < records.length; i++) {
|
|
|
+ if (records[i].activityId === self.activity.id) {
|
|
|
+ self.registrationStatus = records[i].status
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).catch(function() {})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ self.error = true
|
|
|
+ self.errorMsg = (res && res.message) || '加载失败'
|
|
|
+ }
|
|
|
+ }).catch(function(err) {
|
|
|
+ self.loading = false
|
|
|
+ self.error = true
|
|
|
+ self.errorMsg = '网络异常,请稍后重试'
|
|
|
+ })
|
|
|
+ },
|
|
|
+ statusText: function(status) {
|
|
|
+ var map = { draft: '草稿', published: '进行中', ended: '已结束' }
|
|
|
+ return map[status] || '未知'
|
|
|
+ },
|
|
|
+ onCheckin: function() {
|
|
|
+ var self = this
|
|
|
+ if (self.checkinLoading || self.checkinDone) return
|
|
|
+
|
|
|
+ var childId = uni.getStorageSync('currentChildId')
|
|
|
+ if (!childId) {
|
|
|
+ uni.showToast({ title: '请选择孩子身份', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ self.checkinLoading = true
|
|
|
+ activityCheckin({ id: self.activity.id, childId: childId }).then(function(res) {
|
|
|
+ self.checkinLoading = false
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ // 检查是否有能量扣减
|
|
|
+ if (res.data.energyPenalty) {
|
|
|
+ self.penaltyAmount = res.data.energyPenalty
|
|
|
+ self.showPenaltyModal = true
|
|
|
+ self.checkinDone = true
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (res.data.alreadyCompleted) {
|
|
|
+ self.checkinDone = true
|
|
|
+ uni.showToast({ title: '已签到', icon: 'success' })
|
|
|
+ } else if (res.data.pointsEarned && res.data.pointsEarned > 0) {
|
|
|
+ self.checkinDone = true
|
|
|
+ self.checkinPoints = res.data.pointsEarned
|
|
|
+ uni.showToast({ title: '签到成功 +' + res.data.pointsEarned + '积分', icon: 'success' })
|
|
|
+ } else {
|
|
|
+ self.checkinDone = true
|
|
|
+ uni.showToast({ title: '签到成功', icon: 'success' })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ var msg = (res && res.message) || '签到失败'
|
|
|
+ // 如果是报名待审核,提示用户
|
|
|
+ if (msg.indexOf('报名') !== -1 || msg.indexOf('审核') !== -1) {
|
|
|
+ uni.showModal({ title: '提示', content: msg, showCancel: false })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: msg, icon: 'none' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).catch(function(err) {
|
|
|
+ self.checkinLoading = false
|
|
|
+ uni.showToast({ title: '网络异常', icon: 'none' })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onRegister: function() {
|
|
|
+ var self = this
|
|
|
+ var childId = uni.getStorageSync('currentChildId')
|
|
|
+ if (!childId) {
|
|
|
+ uni.showToast({ title: '请先选择孩子身份', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ self.registrationLoading = true
|
|
|
+ registerActivity({ id: self.activity.id, childId: childId }).then(function(res) {
|
|
|
+ self.registrationLoading = false
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ self.registrationStatus = 'pending'
|
|
|
+ uni.showToast({ title: '报名成功,请等待审核', icon: 'success' })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: (res && res.message) || '报名失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }).catch(function(err) {
|
|
|
+ self.registrationLoading = false
|
|
|
+ uni.showToast({ title: '网络异常', icon: 'none' })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onCancelRegistration: function() {
|
|
|
+ var self = this
|
|
|
+ uni.showModal({
|
|
|
+ title: '提示',
|
|
|
+ content: '确定要取消报名吗?',
|
|
|
+ success: function(res) {
|
|
|
+ if (res.confirm) {
|
|
|
+ var childId = uni.getStorageSync('currentChildId')
|
|
|
+ self.registrationLoading = true
|
|
|
+ cancelActivityRegistration({ id: self.activity.id, childId: childId }).then(function(res) {
|
|
|
+ self.registrationLoading = false
|
|
|
+ if (res && res.code === 200) {
|
|
|
+ self.registrationStatus = null
|
|
|
+ uni.showToast({ title: '已取消报名', icon: 'success' })
|
|
|
+ } else {
|
|
|
+ uni.showToast({ title: (res && res.message) || '取消失败', icon: 'none' })
|
|
|
+ }
|
|
|
+ }).catch(function() {
|
|
|
+ self.registrationLoading = false
|
|
|
+ uni.showToast({ title: '网络异常', icon: 'none' })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.container {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #FFF7ED;
|
|
|
+}
|
|
|
+
|
|
|
+/* 加载 / 错误 / 空状态 */
|
|
|
+.loading-wrap,
|
|
|
+.error-wrap,
|
|
|
+.empty-wrap {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 120rpx 40rpx;
|
|
|
+}
|
|
|
+.loading-spinner {
|
|
|
+ width: 60rpx;
|
|
|
+ height: 60rpx;
|
|
|
+ border: 4rpx solid #FDE68A;
|
|
|
+ border-top-color: #F97316;
|
|
|
+ border-radius: 50%;
|
|
|
+ animation: spin 0.8s linear infinite;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+@keyframes spin {
|
|
|
+ to { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+.loading-text,
|
|
|
+.error-text,
|
|
|
+.empty-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+.error-icon {
|
|
|
+ font-size: 60rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+.retry-btn {
|
|
|
+ background: #F97316;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 12rpx 40rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+/* 内容区 */
|
|
|
+.content {
|
|
|
+ height: 100vh;
|
|
|
+ padding-bottom: 120rpx;
|
|
|
+}
|
|
|
+.cover {
|
|
|
+ width: 100%;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+.placeholder-cover {
|
|
|
+ height: 400rpx;
|
|
|
+ background: #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 信息区 */
|
|
|
+.info-section {
|
|
|
+ padding: 30rpx;
|
|
|
+}
|
|
|
+.activity-title {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #1f2937;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+.status-row {
|
|
|
+ margin-top: 16rpx;
|
|
|
+}
|
|
|
+.status-tag {
|
|
|
+ display: inline-block;
|
|
|
+ font-size: 22rpx;
|
|
|
+ padding: 4rpx 16rpx;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+.status-draft { background: #F5F5F5; color: #999; }
|
|
|
+.status-published { background: #F0FDF4; color: #22C55E; }
|
|
|
+.status-ended { background: #F5F5F5; color: #999; }
|
|
|
+.status-upcoming { background: #FFF7ED; color: #F97316; }
|
|
|
+
|
|
|
+/* 元信息列表 */
|
|
|
+.meta-list {
|
|
|
+ margin-top: 24rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+}
|
|
|
+.meta-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+.meta-item:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+.meta-icon {
|
|
|
+ font-size: 28rpx;
|
|
|
+ margin-right: 12rpx;
|
|
|
+ width: 32rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.meta-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #4b5563;
|
|
|
+ flex: 1;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+/* 活动介绍 */
|
|
|
+.desc-section {
|
|
|
+ margin-top: 30rpx;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+}
|
|
|
+.section-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+.desc-text {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #4b5563;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部操作栏 */
|
|
|
+.bottom-bar {
|
|
|
+ position: fixed;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: #fff;
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ box-shadow: 0 -2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
+}
|
|
|
+.price-info {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.bottom-type {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+.bottom-vendor {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 4rpx;
|
|
|
+}
|
|
|
+.action-btns {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ gap: 16rpx;
|
|
|
+}
|
|
|
+.btn-checkin {
|
|
|
+ background: linear-gradient(135deg, #F97316, #FB923C);
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 16rpx 48rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1.5;
|
|
|
+ min-width: 160rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.btn-checkin:active {
|
|
|
+ opacity: 0.85;
|
|
|
+}
|
|
|
+.btn-checkin-done {
|
|
|
+ background: #22C55E;
|
|
|
+}
|
|
|
+.btn-checkin-loading {
|
|
|
+ opacity: 0.7;
|
|
|
+}
|
|
|
+
|
|
|
+/* 报名按钮 */
|
|
|
+.btn-register {
|
|
|
+ background: linear-gradient(135deg, #10B981, #34D399);
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 16rpx 32rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1.5;
|
|
|
+ min-width: 140rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.btn-register:active { opacity: 0.85; }
|
|
|
+.btn-register-loading { opacity: 0.7; }
|
|
|
+.btn-register-done {
|
|
|
+ background: #F5F5F5;
|
|
|
+ color: #999;
|
|
|
+ border: none;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 16rpx 32rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ line-height: 1.5;
|
|
|
+ min-width: 140rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.btn-cancel {
|
|
|
+ background: #fff;
|
|
|
+ color: #999;
|
|
|
+ border: 2rpx solid #ddd;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 14rpx 28rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ line-height: 1.5;
|
|
|
+ min-width: 120rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.btn-cancel:active { opacity: 0.7; }
|
|
|
+
|
|
|
+/* 能量扣减弹窗 */
|
|
|
+.penalty-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: 999;
|
|
|
+}
|
|
|
+.penalty-content {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ padding: 48rpx 40rpx;
|
|
|
+ width: 560rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+.penalty-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #EF4444;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+.penalty-desc {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 40rpx;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+.penalty-btn {
|
|
|
+ background: #F97316;
|
|
|
+ color: #fff;
|
|
|
+ border: none;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ padding: 16rpx 60rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+}
|
|
|
+</style>
|