展品维保小程序前端代码接口
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

407 lines
10 KiB

<template>
<view class="activity-detail">
<!-- 轮播图 -->
<view class="banner-container">
<swiper class="banner-swiper" height="450rpx" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
<swiper-item v-for="(image, index) in activityData.image && activityData.image.split(',')" :key="index">
<image class="banner-image" :src="image" mode="aspectFill"></image>
</swiper-item>
</swiper>
</view>
<!-- 活动信息 -->
<view class="activity-info">
<!-- 活动标题和标签 -->
<view class="title-section">
<view class="activity-badge">
<text class="badge-text">{{ activityData.score }}积分</text>
</view>
<text class="activity-title">{{ activityData.title }}</text>
</view>
<!-- 活动详细信息 -->
<view class="info-section">
<view class="info-item">
<uv-icon name="calendar" size="16" color="#666"></uv-icon>
<text class="info-label">活动时间</text>
<text class="info-value">{{ activityData.activityTime }}</text>
</view>
<view class="info-item">
<uv-icon name="clock" size="16" color="#666"></uv-icon>
<text class="info-label">报名时间</text>
<text class="info-value">{{ activityData.startTime }}</text>
</view>
<view class="info-item">
<uv-icon name="account-fill" size="16" color="#666"></uv-icon>
<text class="info-label">联系人</text>
<text class="info-value">{{ activityData.contact }}</text>
</view>
<view class="info-item">
<uv-icon name="phone" size="16" color="#666"></uv-icon>
<text class="info-label">取消规则</text>
<text class="info-value">{{ activityData.rule }}</text>
</view>
<view class="info-item">
<uv-icon name="map-fill" size="16" color="#666"></uv-icon>
<text class="info-label">活动地点</text>
<text class="info-value">{{ activityData.address }}</text>
</view>
</view>
<!-- 活动详情 -->
<view class="detail-section">
<view class="section-title">
<text class="title-text">活动详情</text>
</view>
<view class="detail-content">
<rich-text :nodes="activityData.details"></rich-text>
</view>
</view>
<!-- 活动图集 -->
<view class="gallery-section">
<view class="section-title">
<text class="title-text">活动图集</text>
</view>
<view class="gallery-grid">
<image
v-for="(image, index) in activityData.atlas && activityData.atlas.split(',')"
:key="index"
class="gallery-image"
:src="image"
mode="aspectFill"
@click="previewImage(image, activityData.atlas.split(','))"
></image>
</view>
</view>
</view>
<!-- 固定底部操作栏 -->
<view class="bottom-action">
<view class="action-left">
<button class="action-item" open-type="share" >
<uv-icon name="share" size="24" color="#000"></uv-icon>
<text class="action-text">分享</text>
</button>
<view class="action-item" @click="collectActivity">
<uv-icon name="heart-fill" size="24" :color="activityData.isCollection === 1 ? '#ff4757' : '#999'"></uv-icon>
<text class="action-text">收藏</text>
</view>
<view class="action-item">
<text class="participants-count">
<text :style="{'color': activityData.numActivity >= activityData.numLimit ? '#999' : '#1488DB'}">{{ activityData.numActivity }}</text>
/{{ activityData.numLimit }}</text>
<text class="action-text">已报名</text>
</view>
</view>
<view class="action-right">
<!-- 未签到状态 -->
<uv-button
v-if="activityData.isSign === '0' || activityData.isSign === 0"
type="primary"
size="normal"
text="扫码签到"
shape="circle"
@click="scanQRCode"
></uv-button>
<!-- 已签到状态 -->
<uv-button
v-else-if="activityData.isSign === '1' || activityData.isSign === 1"
type="success"
size="normal"
text="已签到"
shape="circle"
:disabled="true"
></uv-button>
<!-- 系统取消状态 -->
<uv-button
v-else-if="activityData.isSign === '2' || activityData.isSign === 2"
type="error"
size="normal"
text="系统取消"
shape="circle"
:disabled="true"
></uv-button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
// status: 'unsigned', // unsigned: 未签到, signed: 已签到, cancelled: 系统取消
activityData: {
},
activityId: null,
}
},
onLoad(options) {
if (options.id) {
this.activityId = options.id
} else {
uni.showToast({
title: '没有给活动id',
icon: 'none'
})
}
},
onShow(){
this.loadActivityDetail(this.activityId)
},
methods: {
// 自定义分享内容
mixinCustomShare() {
return {
desc: '',
title: `邀请您参加${this.activityData.title || ''}`,
imageUrl: this.activityData.image.split(',')[0],
path: '/subPages/index/activityDetail?id=' + this.activityId
}
},
async loadActivityDetail(id) {
// 根据ID加载活动详情
const res = await this.$api.activity.queryActivityById({
activityId: id,
token: uni.getStorageSync('token')
})
this.activityData = res.result
},
previewImage(current, urls) {
uni.previewImage({
current: current,
urls: urls
})
},
async collectActivity() {
const res = await this.$api.activity.collectionActivity({
activityId: this.activityId,
})
await this.loadActivityDetail(this.activityId)
uni.showToast({
title: `${res.message}`,
icon: 'none'
})
},
async scanQRCode() {
// 扫码签到功能
uni.scanCode({
success: async (res) => {
const { activityId } = JSON.parse(res.result)
try{
const scanRes = await this.$api.activity.signActivity({ activityId })
if (scanRes.code === 200) {
this.status = 'signed'
uni.navigateTo({
url: `/subPages/my/signupSuccess?score=${this.activityData.score}`
})
}
}catch(err){
uni.showToast({
title: '签到失败',
icon: 'error'
})
}
},
fail: (err) => {
console.log('扫码失败:', err)
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.activity-detail {
min-height: 100vh;
background: #f8f8f8;
padding-bottom: 120rpx;
.banner-container {
width: 100%;
height: 450rpx;
.banner-swiper {
width: 100%;
height: 100%;
.banner-image {
width: 100%;
height: 100%;
}
}
}
.activity-info {
background: #ffffff;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
.title-section {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.activity-badge {
background: #218CDD;
border-radius: 8rpx;
padding: 4rpx 10rpx;
margin-right: 16rpx;
.badge-text {
color: #ffffff;
font-size: 24rpx;
font-weight: 500;
}
}
.activity-title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
flex: 1;
}
}
.info-section {
background: #F3F7F8;
margin-bottom: 40rpx;
border: 2rpx dashed #F3F7F8;
.info-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 28rpx;
color: #999999;
margin-left: 12rpx;
margin-right: 8rpx;
}
.info-value {
font-size: 28rpx;
color: #999999;
flex: 1;
}
}
}
.detail-section {
margin-bottom: 40rpx;
.section-title {
margin-bottom: 20rpx;
.title-text {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.detail-content {
.detail-text {
display: block;
font-size: 28rpx;
color: #666666;
line-height: 1.6;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
}
}
}
.gallery-section {
.section-title {
margin-bottom: 20rpx;
.title-text {
font-size: 32rpx;
font-weight: bold;
color: #333333;
}
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
.gallery-image {
width: 100%;
height: 200rpx;
border-radius: 12rpx;
}
}
}
}
.bottom-action {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #ffffff;
padding: 20rpx 30rpx;
border-top: 1rpx solid #eeeeee;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 100;
.action-left {
display: flex;
align-items: center;
gap: 100rpx;
.action-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
.action-text {
font-size: 22rpx;
color: #000;
}
.participants-count {
font-size: 24rpx;
color: #333333;
}
}
}
.action-right {
flex-shrink: 0;
}
}
}
</style>