151 lines
5.5 KiB
Vue
151 lines
5.5 KiB
Vue
<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 issues = ref([])
|
||
const rewardsMap = ref({})
|
||
|
||
function statusToText(s) {
|
||
if (s === 1) return '进行中'
|
||
if (s === 0) return '未开始'
|
||
if (s === 2) return '已结束'
|
||
return String(s || '')
|
||
}
|
||
|
||
const statusText = ref('')
|
||
|
||
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> |