2025-11-24 22:37:11 +08:00

153 lines
5.5 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>
<scroll-view class="page" scroll-y>
<view class="banner" v-if="detail.banner">
<image class="banner-img" :src="detail.banner" mode="widthFix" />
</view>
<view class="header">
<view class="title">{{ detail.name || detail.title || '-' }}</view>
<view class="meta">分类{{ detail.category_name || '对对碰' }}</view>
<view class="meta" v-if="detail.price_draw !== undefined">参与价{{ detail.price_draw }}</view>
<view class="meta" v-if="detail.status !== undefined">状态{{ statusText }}</view>
</view>
<view class="actions">
<button class="btn" @click="onPreviewBanner">查看图片</button>
<button class="btn primary" @click="onParticipate">立即参与</button>
</view>
<view class="issues">
<view class="issues-title">期数</view>
<view v-if="issues.length" class="issues-list">
<view class="issue-item" v-for="it in issues" :key="it.id">
<text class="issue-title">{{ it.title || ('第' + (it.no || it.index || it.issue_no || '-') + '期') }}</text>
<text class="issue-status" v-if="it.status_text">{{ it.status_text }}</text>
<view class="rewards" v-if="rewardsMap[it.id] && rewardsMap[it.id].length">
<view class="reward" v-for="rw in rewardsMap[it.id]" :key="rw.id">
<image v-if="rw.image" class="reward-img" :src="rw.image" mode="aspectFill" />
<view class="reward-texts">
<text class="reward-title">{{ rw.title }}</text>
<text class="reward-meta" v-if="rw.rarity || rw.odds">{{ [rw.rarity, rw.odds].filter(Boolean).join(' · ') }}</text>
</view>
</view>
</view>
<view class="rewards-empty" v-else>暂无奖励配置</view>
</view>
</view>
<view v-else class="issues-empty">暂无期数</view>
</view>
</scroll-view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getActivityDetail, getActivityIssues, getActivityIssueRewards } from '../../../api/appUser'
const detail = ref({})
const statusText = ref('')
const issues = ref([])
const rewardsMap = ref({})
function statusToText(s) {
if (s === 1) return '进行中'
if (s === 0) return '未开始'
if (s === 2) return '已结束'
return String(s || '')
}
async function fetchDetail(id) {
const data = await getActivityDetail(id)
detail.value = data || {}
statusText.value = statusToText(detail.value.status)
}
function unwrap(list) {
if (Array.isArray(list)) return list
const obj = list || {}
const data = obj.data || {}
const arr = obj.list || obj.items || data.list || data.items || data
return Array.isArray(arr) ? arr : []
}
function normalizeIssues(list) {
const arr = unwrap(list)
return arr.map((i, idx) => ({
id: i.id ?? String(idx),
title: i.title ?? i.name ?? '',
no: i.no ?? i.index ?? i.issue_no ?? i.issue_number ?? null,
status_text: i.status_text ?? (i.status === 1 ? '进行中' : i.status === 0 ? '未开始' : i.status === 2 ? '已结束' : '')
}))
}
function normalizeRewards(list) {
const arr = unwrap(list)
return arr.map((i, idx) => ({
id: i.id ?? String(idx),
title: i.title ?? i.name ?? '',
image: i.image ?? i.img ?? i.pic ?? i.banner ?? '',
odds: i.odds ?? i.rate ?? i.probability ?? i.prob ?? '',
rarity: i.rarity ?? i.rarity_name ?? ''
}))
}
async function fetchRewardsForIssues(activityId) {
const list = issues.value || []
const promises = list.map(it => getActivityIssueRewards(activityId, it.id))
const results = await Promise.allSettled(promises)
results.forEach((res, i) => {
const issueId = list[i] && list[i].id
if (!issueId) return
const value = res.status === 'fulfilled' ? normalizeRewards(res.value) : []
rewardsMap.value = { ...(rewardsMap.value || {}), [issueId]: value }
})
}
async function fetchIssues(id) {
const data = await getActivityIssues(id)
issues.value = normalizeIssues(data)
await fetchRewardsForIssues(id)
}
function onPreviewBanner() {
const url = detail.value.banner || ''
if (url) uni.previewImage({ urls: [url], current: url })
}
function onParticipate() {
uni.showToast({ title: '功能待接入', icon: 'none' })
}
onLoad((opts) => {
const id = (opts && opts.id) || ''
if (id) {
fetchDetail(id)
fetchIssues(id)
}
})
</script>
<style scoped>
.page { height: 100vh }
.banner { padding: 24rpx }
.banner-img { width: 100% }
.header { padding: 0 24rpx }
.title { font-size: 36rpx; font-weight: 700 }
.meta { margin-top: 8rpx; font-size: 26rpx; color: #666 }
.actions { display: flex; padding: 24rpx; gap: 16rpx }
.btn { flex: 1 }
.primary { background-color: #007AFF; color: #fff }
.issues { background: #fff; border-radius: 12rpx; margin: 0 24rpx 24rpx; padding: 16rpx }
.issues-title { font-size: 30rpx; font-weight: 600; margin-bottom: 12rpx }
.issues-list { }
.issue-item { display: flex; justify-content: space-between; padding: 12rpx 0; border-bottom: 1rpx solid #f0f0f0 }
.issue-item:last-child { border-bottom: 0 }
.issue-title { font-size: 26rpx }
.issue-status { font-size: 24rpx; color: #666 }
.rewards { width: 100%; margin-top: 12rpx }
.reward { display: flex; align-items: center; margin-bottom: 8rpx }
.reward-img { width: 80rpx; height: 80rpx; border-radius: 8rpx; margin-right: 12rpx; background: #f5f5f5 }
.reward-texts { display: flex; flex-direction: column }
.reward-title { font-size: 26rpx }
.reward-meta { font-size: 22rpx; color: #888 }
.rewards-empty { font-size: 24rpx; color: #999 }
.issues-empty { font-size: 24rpx; color: #999 }
</style>