Files
property-resident-side/property-uniapp-project/pages/activity-list/activityListDetails.vue
2026-04-18 08:31:55 +08:00

903 lines
19 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="container">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="nav-left" @tap="goBack">
<uni-icons type="left" size="24" color="#000"></uni-icons>
</view>
<view class="nav-title">{{navTitle}}</view>
<view class="nav-right"></view>
</view>
<view style="status_bar"></view>
<!-- 内容区域 -->
<scroll-view class="content" scroll-y>
<!-- 选项卡 -->
<view class="tabs">
<view
class="tab-item"
:class="{ 'active': activeTab === 'detail' }"
@tap="switchTab('detail')"
>
活动详情
</view>
<view
class="tab-item"
:class="{ 'active': activeTab === 'status' }"
@tap="switchTab('status')"
>
活动实况
</view>
</view>
<!-- 活动详情内容 -->
<view v-if="activeTab === 'detail'" class="detail-content">
<!-- 基本信息 -->
<view class="info-section">
<view class="info-item">
<view class="info-label">报名截止时间</view>
<view class="info-value">2023-08-08 23:00</view>
</view>
<view class="info-item">
<view class="info-label">活动时间</view>
<view class="info-value">
<text>2023-08-09 10:00 2023-08-20 16:00</text>
</view>
</view>
<view class="info-item">
<view class="info-label">签到时间</view>
<view class="info-value">
<text>2023-08-09 10:00 2023-08-10 16:00</text>
</view>
</view>
<view class="info-item">
<view class="info-label">活动地点</view>
<view class="info-value">山东省日照市高新区高新管委会大厦前高新公园</view>
</view>
<view class="info-item">
<view class="info-label">活动名额</view>
<view class="info-value">10</view>
</view>
<view class="info-item">
<view class="info-label">主办方</view>
<view class="info-value">山海天社区</view>
</view>
<view class="info-item">
<view class="info-label">联系人</view>
<view class="info-value">赵璐</view>
</view>
<view class="info-item">
<view class="info-label">联系电话</view>
<view class="info-value">15799999999</view>
</view>
<view class="info-item">
<view class="info-label">积分奖励</view>
<view class="info-value">100</view>
</view>
</view>
<!-- 招募要求 -->
<view class="section">
<view class="section-title">招募要求</view>
<view class="section-content">
要求就是要求就是要求就是
</view>
</view>
<!-- 活动详情 -->
<view class="section" style="margin-bottom: 40rpx;">
<view class="section-title">活动详情</view>
<view class="section-content">
<view>1这就是活动详情zhejiushihuodongxiangqing这就是活动详情zhejiushihuodongxiangqing</view>
<view>2活动详情zhejiushuodongxiangqing</view>
</view>
</view>
</view>
<!-- 活动实况内容 -->
<view v-else class="status-content">
<view class="status-header">
<view class="status-title">
<image src="/static/活动/现场实况.png" style="width: 40rpx;height: 30rpx;"></image>
现场实况
</view>
<view class="status-count">{{ liveRecords.length }}</view>
</view>
<!-- 实况列表 -->
<view class="record-list">
<view v-for="(record, index) in liveRecords" :key="index" class="record-item">
<view class="record-user">
<view class="user-avatar">
<uni-icons type="person" size="20" color="#999"></uni-icons>
</view>
<view class="user-info">
<view class="user-name">微信用户</view>
<view class="record-time">{{ record.time }}</view>
<view class="record-content">{{ record.content }}</view>
<!-- 图片展示 -->
<view v-if="record.images && record.images.length > 0" class="record-images">
<view
v-for="(img, imgIndex) in record.images"
:key="imgIndex"
class="image-item"
:style="{ backgroundImage: `url(${img})` }"
>
<image :src="img" style="width: 100%;height: 100%;"></image>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<!-- 未报名状态显示报名按钮 -->
<button
v-if="!hasSigned && activeTab === 'detail'"
class="action-btn signup-btn"
@tap="handleSignup"
>
报名
</button>
<!-- 已报名状态显示取消报名按钮 -->
<button
v-if="hasSigned && activeTab === 'detail'"
class="action-btn cancel-btn"
@tap="handleCancelSignup"
>
取消报名
</button>
<button class="action-btn add-status-btn" v-if="activeTab === 'status'" @click="liveClick">添加实况</button>
<!-- 已报名且在活动实况页显示添加实况按钮 -->
<!-- <button
v-if="hasSigned && activeTab === 'status'"
class="action-btn add-status-btn"
@tap="handleAddStatus"
>
添加实况
</button> -->
</view>
<!-- 报名确认模态框 -->
<view class="modal" :class="{ 'show': showSignupModal }">
<view class="modal-content">
<view class="modal-header">报名确认</view>
<view class="modal-body">
<view>确定要报名参加"社区'小槐花课堂'开课了"</view>
<view class="modal-tip">报名后请按时参加活动</view>
</view>
<view class="modal-footer">
<view class="modal-btn cancel" @tap="hideSignupModal">取消</view>
<view class="modal-btn confirm" @tap="confirmSignup">确定</view>
</view>
</view>
</view>
<!-- 取消报名确认模态框 -->
<view class="modal" :class="{ 'show': showCancelModal }">
<view class="modal-content">
<view class="modal-header">取消报名</view>
<view class="modal-body">
<view>确定要取消报名"社区'小槐花课堂'开课了"</view>
<view class="modal-tip">取消后如需参加需重新报名</view>
</view>
<view class="modal-footer">
<view class="modal-btn cancel" @tap="hideCancelModal">再想想</view>
<view class="modal-btn confirm" @tap="confirmCancel">确定取消</view>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="toast" :class="{ 'show': showToast }">
{{ toastMessage }}
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import {onLoad} from '@dcloudio/uni-app'
import moment from 'moment'
// 响应式数据
const activeTab = ref('detail') // 'detail' 或 'status'
const hasSigned = ref(false) // 是否已报名
const showSignupModal = ref(false)
const showCancelModal = ref(false)
// const showAddStatusModal = ref(false)
const showToast = ref(false)
const toastMessage = ref('')
const newStatusContent = ref('')
// const newStatusImages = ref([])
const navTitle = ref('')
// 实况记录数据
const liveRecords = ref([
{
id: 1,
user: '微信用户',
time: '2023-08-20 16:00:02',
content: '参与活动打卡',
images: []
},
{
id: 2,
user: '微信用户',
time: '2023-08-20 16:20:02',
content: '目前现场的互动氛围很好',
images: ['/static/logo.png', '/static/引导1.png']
}
])
// 接受参数
onLoad((option) =>{
// console.log('dsdsds',option)
navTitle.value = option.title
})
// 切换选项卡
const switchTab = (tab) => {
activeTab.value = tab
}
// 返回上一页
const goBack = () => {
uni.navigateBack()
}
// 处理报名
const handleSignup = () => {
showSignupModal.value = true
}
// 隐藏报名模态框
const hideSignupModal = () => {
showSignupModal.value = false
}
// 确认报名
const confirmSignup = () => {
hasSigned.value = true
hideSignupModal()
showToastMessage('报名成功!')
// 模拟更新名额
// 在实际应用中这里应该调用API更新后端数据
}
// 处理取消报名
const handleCancelSignup = () => {
showCancelModal.value = true
}
// 隐藏取消报名模态框
const hideCancelModal = () => {
showCancelModal.value = false
}
// 确认取消报名
const confirmCancel = () => {
hasSigned.value = false
hideCancelModal()
showToastMessage('已取消报名')
// 模拟更新名额
// 在实际应用中这里应该调用API更新后端数据
}
// 添加实况跳转
const liveClick = () =>{
uni.navigateTo({
url:'/pages/activity-list/live-add'
})
}
// 获取当前时间
const getCurrentTime = () => {
return moment(date).format('YYYY-MM-DD HH:mm:ss')
}
// 显示提示信息
const showToastMessage = (message) => {
toastMessage.value = message
showToast.value = true
setTimeout(() => {
showToast.value = false
}, 2000)
}
// 初始化
onMounted(() => {
// 模拟检查用户是否已报名
// 实际项目中应该从接口获取
setTimeout(() => {
hasSigned.value = false // 默认未报名
}, 100)
})
</script>
<style>
/* 页面容器 */
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
background: linear-gradient(to bottom left, #E2F0FF 0%, #ffffff 50%)
}
/* 顶部导航栏 */
.nav-bar {
height: 90rpx;
/* background: linear-gradient(135deg, #007AFF 0%, #0056cc 100%); */
display: flex;
align-items: center;
padding: 0 30rpx;
color: #fff;
position: sticky;
top: 44px;
z-index: 100;
/* box-shadow: 0 4rpx 12rpx rgba(0, 122, 255, 0.2); */
}
.nav-left {
width: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-title {
flex: 1;
text-align: left;
font-size: 36rpx;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 20rpx;
color: #000;
}
.nav-right {
width: 60rpx;
}
/* 内容区域 */
.content {
flex: 1;
margin-bottom: 120rpx;
}
.status_bar {
height: 46px;
width: 100%;
}
/* 选项卡 */
.tabs {
display: flex;
/* background-color: #fff; */
border-bottom: 1rpx solid #e9ecef;
position: sticky;
top: 90rpx;
z-index: 90;
}
.tab-item {
/* flex: 1; */
text-align: center;
padding: 30rpx 35rpx;
font-size: 32rpx;
color: #666;
position: relative;
transition: all 0.3s;
}
.tab-item.active {
color: #007AFF;
font-weight: 600;
}
/* .tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 80rpx;
height: 6rpx;
background: linear-gradient(90deg, #007AFF, #00aaff);
border-radius: 3rpx 3rpx 0 0;
} */
/* 活动详情内容 */
.detail-content {
/* padding: 30rpx; */
margin-top: 89rpx;
}
/* 基本信息区域 */
.info-section {
/* background-color: #fff; */
border-radius: 16rpx;
padding: 30rpx;
/* margin-bottom: 30rpx; */
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
}
.info-item {
display: flex;
margin-bottom: 30rpx;
padding-bottom: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.info-item:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.info-label {
width: 220rpx;
font-size: 28rpx;
color: #222;
flex-shrink: 0;
}
.info-value {
flex: 1;
font-size: 28rpx;
color: #222;
font-weight: 500;
line-height: 1.4;
}
/* 区块样式 */
.section {
/* background-color: #fff; */
border-radius: 16rpx;
padding: 30rpx;
/* margin-bottom: 30rpx; */
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.section-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
margin-bottom: 20rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.section-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.section-content view {
margin-bottom: 20rpx;
}
.section-content view:last-child {
margin-bottom: 0;
}
/* 活动实况内容 */
.status-content {
padding: 30rpx;
}
/* 实况头部 */
.status-header {
display: flex;
justify-content: space-between;
align-items: center;
/* background-color: #fff; */
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
margin-top: 80rpx;
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
}
.status-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
border-bottom: 1rpx solid #f0f0f0;
}
.status-count {
padding: 8rpx 20rpx;
/* background-color: #007AFF; */
color: #666;
font-size: 24rpx;
border-radius: 20rpx;
font-weight: 500;
}
/* 实况列表 */
.record-list {
/* background-color: #fff; */
border-radius: 16rpx;
overflow: hidden;
/* box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); */
}
.record-item {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
/* .record-item:last-child {
border-bottom: none;
} */
.record-user {
display: flex;
align-items: flex-start;
justify-content: flex-start;
margin-bottom: 20rpx;
}
.user-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background-color: #f8f9fa;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
border: 1rpx solid #e9ecef;
}
.user-info {
/* flex: 1; */
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.user-name {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 8rpx;
}
.record-time {
font-size: 24rpx;
color: #999;
}
.record-content {
font-size: 28rpx;
color: #333;
line-height: 1.5;
/* margin-bottom: 20rpx; */
margin: 25rpx 0rpx;
}
/* 实况图片 */
.record-images {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.image-item {
width: 150rpx;
height: 170rpx;
border-radius: 12rpx;
background-color: #f8f9fa;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border: 1rpx solid #e9ecef;
}
/* 底部操作栏 */
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 30rpx 40rpx;
background-color: #fff;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
z-index: 100;
}
.action-btn {
height: 100rpx;
line-height: 100rpx;
border-radius: 12rpx;
font-size: 34rpx;
font-weight: 600;
width: 100%;
border: none;
transition: all 0.3s;
}
.signup-btn {
background: linear-gradient(135deg, #007AFF 0%, #0056cc 100%);
color: #fff;
box-shadow: 0 8rpx 30rpx rgba(0, 122, 255, 0.3);
}
.signup-btn:active {
background: linear-gradient(135deg, #0056cc 0%, #004199 100%);
transform: translateY(2rpx);
box-shadow: 0 4rpx 20rpx rgba(0, 122, 255, 0.2);
}
.cancel-btn {
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
color: #666;
border: 1rpx solid #e9ecef;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.cancel-btn:active {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
transform: translateY(2rpx);
}
.add-status-btn {
background: linear-gradient(135deg, #007AFF 0%, #0056cc 100%);
color: #fff;
box-shadow: 0 8rpx 30rpx rgba(0, 122, 255, 0.3);
}
.add-status-btn:active {
background: linear-gradient(135deg, #0056cc 0%, #004199 100%);
transform: translateY(2rpx);
box-shadow: 0 4rpx 20rpx rgba(0, 122, 255, 0.2);
}
/* 模态框 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
backdrop-filter: blur(5rpx);
}
.modal.show {
display: flex;
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
background-color: #fff;
border-radius: 20rpx;
width: 600rpx;
overflow: hidden;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.2);
animation: slideUp 0.3s;
}
@keyframes slideUp {
from { transform: translateY(100rpx); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
padding: 40rpx 30rpx 20rpx;
text-align: center;
font-size: 36rpx;
font-weight: 600;
color: #333;
border-bottom: 1rpx solid #f0f0f0;
}
.modal-body {
padding: 40rpx 30rpx;
text-align: center;
font-size: 30rpx;
color: #666;
line-height: 1.5;
}
.modal-tip {
font-size: 24rpx;
color: #999;
margin-top: 20rpx;
}
.modal-footer {
display: flex;
border-top: 1rpx solid #f0f0f0;
}
.modal-btn {
flex: 1;
padding: 30rpx 0;
text-align: center;
font-size: 32rpx;
font-weight: 500;
transition: all 0.2s;
}
.modal-btn.cancel {
color: #666;
border-right: 1rpx solid #f0f0f0;
}
.modal-btn.cancel:active {
background-color: #f8f9fa;
}
.modal-btn.confirm {
color: #007AFF;
font-weight: 600;
}
.modal-btn.confirm:active {
background-color: #f0f7ff;
}
/* 添加实况模态框 */
.add-status-modal {
width: 650rpx;
}
.status-input {
width: 100%;
min-height: 200rpx;
padding: 20rpx;
font-size: 28rpx;
color: #333;
background-color: #f8f9fa;
border-radius: 12rpx;
border: 1rpx solid #e9ecef;
margin-bottom: 20rpx;
}
.input-counter {
text-align: right;
font-size: 24rpx;
color: #999;
margin-bottom: 30rpx;
}
.image-upload-area {
margin-top: 30rpx;
}
.upload-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
text-align: left;
}
.image-preview {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.preview-item {
position: relative;
width: 150rpx;
height: 150rpx;
border-radius: 12rpx;
overflow: hidden;
}
.preview-image {
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-color: #f8f9fa;
}
.remove-btn {
position: absolute;
top: 0;
right: 0;
width: 40rpx;
height: 40rpx;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
border-radius: 0 0 0 12rpx;
}
.upload-btn {
width: 150rpx;
height: 150rpx;
border: 2rpx dashed #e9ecef;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #999;
background-color: #f8f9fa;
}
.upload-text {
font-size: 24rpx;
margin-top: 10rpx;
}
/* 提示信息 */
.toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 20rpx 40rpx;
border-radius: 10rpx;
font-size: 28rpx;
z-index: 1100;
display: none;
backdrop-filter: blur(10rpx);
}
.toast.show {
display: block;
animation: toastFade 2s;
}
@keyframes toastFade {
0% { opacity: 0; transform: translate(-50%, -40%); }
20% { opacity: 1; transform: translate(-50%, -50%); }
80% { opacity: 1; transform: translate(-50%, -50%); }
100% { opacity: 0; transform: translate(-50%, -60%); }
}
/* 适配不同屏幕 */
@media (min-width: 768px) {
.container {
max-width: 500px;
margin: 0 auto;
}
}
</style>